diff --git a/A3A/addons/core/functions/Base/fn_initPetros.sqf b/A3A/addons/core/functions/Base/fn_initPetros.sqf index 6ec9cf0c51..0bcb396a13 100644 --- a/A3A/addons/core/functions/Base/fn_initPetros.sqf +++ b/A3A/addons/core/functions/Base/fn_initPetros.sqf @@ -100,4 +100,7 @@ petros addMPEventHandler ["mpkilled", [] spawn {sleep 120; petros allowDamage true;}; [petros] call A3A_fnc_unitAmbient; // adds ambient sounds and animations to petros +private _marker = "respawn_guerrila"; +_marker setMarkerType "A3AU_RebalHQ_mrk"; + Info("initPetros completed"); \ No newline at end of file diff --git a/A3A/addons/core/functions/Base/fn_mrkUpdate.sqf b/A3A/addons/core/functions/Base/fn_mrkUpdate.sqf index 7aefb918f0..6e663572d8 100644 --- a/A3A/addons/core/functions/Base/fn_mrkUpdate.sqf +++ b/A3A/addons/core/functions/Base/fn_mrkUpdate.sqf @@ -1,64 +1,466 @@ #include "..\..\script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: A3A_fnc_mrkUpdate + +Description: + Refreshes marker visuals and hover metadata so the strategic map shows the + correct icon, color, text, and tooltip information for a location. + + Marker commands are kept local on purpose to avoid unnecessary network + traffic and JIP queue growth. This function should therefore run on each + client that needs the updated marker state. + +Parameters: + 0: _markerName - Marker name to refresh + +Optional: + None. + +Example: + ["marker_1"] call A3A_fnc_mrkUpdate; + +Returns: + Nothing + +Environment: + Client, Unscheduled + +Author: + ? + Maxx +---------------------------------------------------------------------------- */ FIX_LINE_NUMBERS() -params ["_marker"]; +// Existing A3U_* missionNamespace keys are kept for compatibility with the +// current hover/browser/context-menu integration and existing runtime state. + +if !assert(params [ + ["_markerName", nil, [""]] +]) exitWith {}; + +private _managedMarkers = ( + milAdministrationsX + + destroyedSites + + watchpostsFIA + + roadblocksFIA + + hmgpostsFIA + + resourcesX + + aapostsFIA + + atpostsFIA + + airportsX + + factories + + outposts + + seaports + + milbases + + citiesX +) - controlsX; + +private _markerNameLower = toLowerANSI _markerName; +private _specialMarkers = ["synd_hq", "tradermarker", "rallypointmarker"]; + +private _isManagedMarker = (_markerName in _managedMarkers)|| {_markerNameLower in _specialMarkers}; + +if (!_isManagedMarker) exitWith { + Warning_1("Marker %1 is not in the allowed list. (Skipping)", _markerName); +}; + +private _dummyMarkerName = format ["Dum%1", _markerName]; +private _hasDummyMarker = markerShape _dummyMarkerName isNotEqualTo ""; +private _visibleMarkerName = [_markerName, _dummyMarkerName] select _hasDummyMarker; + +private _getOriginalMarkerName = { + if !assert(params [["_name", nil, [""]]]) exitWith {""}; + + if ((_name find "Dum") == 0) exitWith {[_name, 3] call CBA_fnc_substr;}; + + _name; +}; + +private _ensureHashMap = { + param [0, createHashMap, [createHashMap]]; +}; + +private _getHashMapValue = { + params ["_hashMap", "_key", "_defaultValue"]; + + if !(_hashMap isEqualType createHashMap) exitWith {_defaultValue}; + + _hashMap getOrDefault [_key, _defaultValue] +}; + +private _findNearestMarkerName = { + params ["_markerNames", "_position"]; + + if (_markerNames isEqualTo []) exitWith {""}; + + private _nearestMarker = [_markerNames, _position] call BIS_fnc_nearestPosition; + + if !assert(_nearestMarker isEqualType "") exitWith {""}; + + _nearestMarker; +}; -private _mrkD = format ["Dum%1",_marker]; -private _mrkSide = sidesX getVariable _marker; -private _faction = Faction(_mrkSide); +private _occupantFaction = [missionNamespace getVariable ["A3A_faction_occ", createHashMap]] call _ensureHashMap; +private _invaderFaction = [missionNamespace getVariable ["A3A_faction_inv", createHashMap]] call _ensureHashMap; +private _rebelFaction = [missionNamespace getVariable ["A3A_faction_reb", createHashMap]] call _ensureHashMap; +private _civilianFaction = [missionNamespace getVariable ["A3A_faction_civ", createHashMap]] call _ensureHashMap; -if (_marker in airportsX) then { - _mrkD setMarkerTypeLocal (_faction get "flagMarkerType"); - _mrkD setMarkerColorLocal "Default"; +private _getFactionBySide = { + params ["_markerSide"]; + + switch (_markerSide) do { + case Occupants: {_occupantFaction}; + case Invaders: {_invaderFaction}; + case teamPlayer; + case resistance: {_rebelFaction}; + case civilian: {_civilianFaction}; + default {createHashMap}; + }; +}; + +private _isMarkerHidden = { + params ["_name"]; + + if !(_name isEqualType "") exitWith {false}; + + private _originalMarkerName = [_name] call _getOriginalMarkerName; + private _revealedZones = RETDEF(revealedZones,[]); + private _immuneMarkers = RETDEF(immuneMarkers,[]); + private _hideEnemyMarkers = RETDEF(hideEnemyMarkers,false); + + if (_originalMarkerName == "") exitWith {false}; + if (!_hideEnemyMarkers) exitWith {false}; + if (_originalMarkerName in _revealedZones) exitWith {false}; + if (_originalMarkerName in _immuneMarkers) exitWith {false}; + if ("cont" in _originalMarkerName) exitWith {false}; + if (_originalMarkerName in citiesX|| {_originalMarkerName in airportsX}) exitWith {false}; + + private _markerSide = sidesX getVariable [_originalMarkerName, sideUnknown]; + _markerSide isNotEqualTo sideUnknown + && {_markerSide isNotEqualTo resistance} +}; + +private _isSyndicateHeadquarters = _markerNameLower == "synd_hq"; +private _isTraderMarker = _markerNameLower == "tradermarker"; +private _isRallyPointMarker = _markerNameLower == "rallypointmarker"; +private _isMilitaryAdministration = _markerName in milAdministrationsX; +private _markerPosition = getMarkerPos _visibleMarkerName; + +private _markerSide = sidesX getVariable [ + _markerName, + if (_isSyndicateHeadquarters || {_isRallyPointMarker}) then {teamPlayer} else {civilian}]; + +private _markerFaction = [_markerSide] call _getFactionBySide; +private _factionName = [_markerFaction, "name", ""] call _getHashMapValue; + +private _destroyedMilitaryAdministrations = RETDEF(A3A_destroyedMilAdministrations,[]); +private _isMilitaryAdministrationDestroyed = _isMilitaryAdministration && { + _destroyedMilitaryAdministrations findIf { + !isNull _x && {_markerPosition distance2D _x < 30} + } != -1 +}; + +private _markerType = ""; +private _markerColor = ""; + +if (_markerName in airportsX) then { + _markerType = if (_markerSide == teamPlayer) then { + [_rebelFaction, "flagMarkerType", ""] call _getHashMapValue + } else { + if (_markerSide == Invaders) then { + [_invaderFaction, "flagMarkerType", ""] call _getHashMapValue + } else { + [_occupantFaction, "flagMarkerType", ""] call _getHashMapValue + }; + }; } else { - if (_marker in destroyedSites and _marker in citiesX) exitWith { _mrkD setMarkerColorLocal "ColorBlack" }; - if (_mrkSide == teamPlayer) exitWith { - if (_marker in milbases) then { - _mrkD setMarkerTypeLocal "n_hq"; + if (_isMilitaryAdministration && {_isMilitaryAdministrationDestroyed}) then { + _markerType = "A3AU_Miladmin_dead_mrk"; + _markerColor = "ColorGrey"; + } else { + if (_isMilitaryAdministration) then {_markerType = "A3AU_miladmin_mrk";}; + if (_markerName in citiesX) then {_markerType = "A3AU_city_mrk";}; + if (_markerSide == teamPlayer) then { + if (_isSyndicateHeadquarters) then {_markerType = "A3AU_RebalHQ_mrk";}; + if (_markerName in milbases) then {_markerType = "A3AU_milbase_mrk";}; + if (_markerName in seaports) then {_markerType = "A3AU_seaport_mrk";}; + if (_markerName in watchpostsFIA) then {_markerType = "A3AU_watchpost_mrk";}; + if (_markerName in roadblocksFIA) then {_markerType = "A3AU_roadblock_mrk";}; + if (_markerName in aapostsFIA) then {_markerType = "A3AU_antiair_mrk";}; + if (_markerName in atpostsFIA) then {_markerType = "A3AU_antitank_mrk";}; + if (_markerName in hmgpostsFIA) then {_markerType = "A3AU_hmg_mrk";}; + + _markerColor = colorTeamPlayer; + } else { + if (_markerName in milbases) then {_markerType = "A3AU_milbase_mrk";}; + if (_markerName in seaports) then { + _markerType = "A3AU_seaport_mrk"; + }; + if (_markerName in destroyedSites && {_markerName in citiesX}) then { + _markerColor = "ColorBlack"; + } else { + _markerColor = [colorOccupants,colorInvaders] select (_markerSide == Invaders); + }; }; - if (_marker in seaports) then { - _mrkD setMarkerTypeLocal "n_naval"; + }; +}; + +if (_markerType != "") then {_visibleMarkerName setMarkerTypeLocal _markerType;}; +if (_markerColor != "") then {_visibleMarkerName setMarkerColorLocal _markerColor;}; + +private _markerTitle = call { + if (_isSyndicateHeadquarters) exitWith {format [localize "STR_A3U_HOVER_RESISTANCE_HQ", _factionName]}; + if (_isTraderMarker) exitWith {localize "STR_A3U_HOVER_BLACK_MARKET"}; + if (_markerName in citiesX) exitWith {markerText _markerName}; + + if (_isRallyPointMarker) exitWith { + private _rallyCount = str RETDEF(rallyPointSpawnCount,0); + + format [localize "STR_marker_RP", _rallyCount] + }; + + if (_isMilitaryAdministration) exitWith { + private _nearestCityMarkerName = + [citiesX, _markerPosition] call _findNearestMarkerName; + format [localize "STR_milAdministration", _nearestCityMarkerName] + }; + + if (_markerName in airportsX) exitWith { + private _airfieldNames = + (localize "STR_A3AU_airfieldNames") splitString "|"; + private _markerIndex = airportsX find _markerName; + private _airfieldName = if ( + _markerIndex >= 0 + && {_markerIndex < count _airfieldNames} + ) then { + _airfieldNames select _markerIndex + } else { + "" }; - _mrkD setMarkerColorLocal colorTeamPlayer; + + format [localize "STR_airbase", _factionName, _airfieldName] }; - if (_marker in milbases) then { - private _markerType = if (_mrkSide == Invaders) then {"o_hq"} else {"b_hq"}; - _mrkD setMarkerTypeLocal _markerType; + if (_markerName in outposts) exitWith { + private _outpostNames = + (localize "STR_A3AU_outpostNames") splitString "|"; + private _markerIndex = outposts find _markerName; + private _outpostName = if ( + _markerIndex >= 0 + && {_markerIndex < count _outpostNames} + ) then { + _outpostNames select _markerIndex + } else { + "" + }; + + format [localize "STR_outpost", _outpostName] }; - if (_marker in seaports) then { - private _markerType = if (_mrkSide == Invaders) then {"o_naval"} else {"b_naval"}; - _mrkD setMarkerTypeLocal _markerType; + + if (_markerName in resourcesX) exitWith { + private _nearestCityMarkerName = + [citiesX, _markerPosition] call _findNearestMarkerName; + format [localize "STR_resources", _nearestCityMarkerName] }; - _mrkD setMarkerColorLocal ([colorOccupants, colorInvaders] select (_mrkSide == Invaders)); -}; + if (_markerName in factories) exitWith { + private _nearestCityMarkerName = + [citiesX, _markerPosition] call _findNearestMarkerName; + format [localize "STR_factory", _nearestCityMarkerName] + }; + + if (_markerName in milbases) exitWith { + private _militaryBaseNames = + (localize "STR_A3AU_milbaseNames") splitString "|"; + private _markerIndex = milbases find _markerName; + private _militaryBaseName = if ( + _markerIndex >= 0 + && {_markerIndex < count _militaryBaseNames} + ) then { + _militaryBaseNames select _markerIndex + } else { + "" + }; + + format [localize "STR_milbase", _militaryBaseName] + }; + + if (_markerName in seaports) exitWith { + private _seaportNames = + (localize "STR_A3AU_seaportNames") splitString "|"; + private _markerIndex = seaports find _markerName; + private _seaportName = if ( + _markerIndex >= 0 + && {_markerIndex < count _seaportNames} + ) then { + _seaportNames select _markerIndex + } else { + "" + }; -private _mrkText = call { - if (_marker in airportsX) exitWith { format [localize "STR_airbase", _faction get "name"] }; - if (_marker in outposts) exitWith { format [localize "STR_outpost", _faction get "name"] }; - if (_marker in resourcesX) exitWith { localize "STR_resources" }; - if (_marker in factories) exitWith { localize "STR_factory" }; - if (_marker in milbases) exitWith { format [localize "STR_milbase", _faction get "name"] }; - if (_marker in seaports) exitWith { if (toLowerANSI worldName in ["enoch", "vn_khe_sanh", "esseker"]) then { - localize "STR_port_river" + format [localize "STR_port_river", _seaportName] } else { - localize "STR_port_sea" + format [localize "STR_port_sea", _seaportName] }; }; - ""; // city + + if (_markerName in watchpostsFIA) exitWith {format [localize "STR_marker_watchpost", _factionName]}; + if (_markerName in roadblocksFIA) exitWith {format [localize "STR_marker_roadblock", _factionName]}; + if (_markerName in aapostsFIA) exitWith {format [localize "STR_marker_aa_empl", _factionName]}; + if (_markerName in atpostsFIA) exitWith {format [localize "STR_marker_at_empl", _factionName]}; + if (_markerName in hmgpostsFIA) exitWith {format [localize "STR_marker_hmg_empl", _factionName]}; + + "" +}; + +private _markerLabelOnly = _markerTitle; +private _civilianCurrencySymbol = + [_civilianFaction, "currencySymbol", ""] call _getHashMapValue; + +private _additionalDescription = call { + if (_isMilitaryAdministration) exitWith { + if (_isMilitaryAdministrationDestroyed) then {localize "STR_A3U_HOVER_DESTROYED_SITE"} else {localize "STR_A3U_HOVER_MILADMIN_DESC"}; + }; + if (_isSyndicateHeadquarters) exitWith {localize "STR_A3U_HOVER_RESISTANCE_HQ_DESC"}; + if (_isTraderMarker) exitWith {localize "STR_A3U_HOVER_BLACK_MARKET_DESC"}; + if (_isRallyPointMarker) exitWith {localize "STR_A3U_HOVER_RALLY_DESC"}; + if (_markerName in watchpostsFIA) exitWith {localize "STR_A3U_HOVER_WATCHPOST_DESC"}; + if (_markerName in roadblocksFIA) exitWith {localize "STR_A3U_HOVER_ROADBLOCK_DESC"}; + if (_markerName in aapostsFIA) exitWith {localize "STR_A3U_HOVER_ANTIAIR_DESC"}; + if (_markerName in atpostsFIA) exitWith {localize "STR_A3U_HOVER_ANTITANK_DESC"}; + if (_markerName in hmgpostsFIA) exitWith {localize "STR_A3U_HOVER_HMG_DESC"}; + if (_markerName in outposts) exitWith { + if (_markerSide == teamPlayer) then { _markerTitle} else {localize "STR_A3U_HOVER_OUTPOST_DESC"}; + }; + if (_markerName in resourcesX) exitWith {format [localize "STR_A3U_HOVER_RESOURCE_SITE",_civilianCurrencySymbol]}; + if (_markerName in factories) exitWith {localize "STR_A3U_HOVER_FACTORY_SITE"}; + if (_markerName in seaports) exitWith {localize "STR_A3U_HOVER_SEAPORT_DESC"}; + if (_markerName in milbases) exitWith {localize "STR_A3U_HOVER_MILBASE_DESC"}; + if (_markerName in airportsX) exitWith {localize "STR_A3U_HOVER_AIRPORT_CAPTURED"}; + if (_markerName in citiesX) exitWith { + if (_markerName in destroyedSites) exitWith {localize "STR_A3U_HOVER_DESTROYED_SITE"}; + + private _cityData = server getVariable [_markerName, [0, 0, 0, 0]]; + _cityData params ["_numberOfCivilians", "_numberOfVehicles", "_governmentSupport", "_rebelSupport"]; + + _governmentSupport = _governmentSupport max 0 min 100; + _rebelSupport = _rebelSupport max 0 min 100; + + private _rebelPopulation = _numberOfCivilians * (_rebelSupport / 100); + private _governmentPopulation = _numberOfCivilians * (_governmentSupport / 100); + + format [ + localize "STR_A3U_HOVER_CITY_SUPPORT", + _numberOfCivilians, + round _rebelSupport, + round _rebelPopulation, + round _governmentSupport, + round _governmentPopulation + ] + }; + + "" }; -if (_mrkSide == teamPlayer) then { - private _numTroops = count (garrison getVariable [_marker, []]); - private _limit = [_marker] call A3A_fnc_getGarrisonLimit; - if (_numTroops > 0) then { - _mrkText = format ["%1: %2%3", - _mrkText, - _numTroops, - if (_limit != -1) then {format ["/%1", _limit]} else {""} - ]; +if (_markerSide == teamPlayer) then { + private _numberOfTroops = count (garrison getVariable [_markerName, []]); + private _garrisonLimit = [_markerName] call A3A_fnc_getGarrisonLimit; + + private _garrisonDescription = format [localize "STR_A3U_HOVER_GARRISON", _numberOfTroops, + if (_garrisonLimit != -1) then {format ["/%1", _garrisonLimit]} else {""} + ]; + + _additionalDescription = _additionalDescription + _garrisonDescription; +}; + +if (_additionalDescription != "") then { + _markerTitle = format ["%1
%2", _markerTitle, _additionalDescription]; +}; + +private _flagMarkerType = [_markerFaction, "flagMarkerType", ""] call _getHashMapValue; + +private _hoverMetaMap = missionNamespace getVariable ["A3U_mrkHoverMetaMap",createHashMap]; +private _hoverMarkers = missionNamespace getVariable ["A3U_hoverMarkers", []]; + +if ([_markerName] call _isMarkerHidden) then { + _hoverMetaMap deleteAt _dummyMarkerName; + _hoverMetaMap deleteAt _markerName; + _hoverMarkers = _hoverMarkers - [_dummyMarkerName, _markerName]; +} else { + _hoverMetaMap set [_dummyMarkerName, [_markerTitle, _flagMarkerType]]; + _hoverMetaMap set [_markerName, [_markerTitle, _flagMarkerType]]; + _hoverMarkers pushBackUnique _dummyMarkerName; + _hoverMarkers pushBackUnique _markerName; +}; + +missionNamespace setVariable ["A3U_mrkHoverMetaMap", _hoverMetaMap]; + +private _ensureSpecialHoverMetadata = { + params ["_name", "_side"]; + + if !(_name in allMapMarkers) exitWith {}; + + private _nameLower = toLowerANSI _name; + private _dummyName = format ["Dum%1", _name]; + private _specialFaction = [_side] call _getFactionBySide; + private _specialFactionName = + [_specialFaction, "name", ""] call _getHashMapValue; + + private _specialFlagMarkerType = + [_specialFaction, "flagMarkerType", ""] call _getHashMapValue; + if !(_specialFlagMarkerType isEqualType "") then {_specialFlagMarkerType = "";}; + + if (_nameLower == "tradermarker") then {_specialFlagMarkerType = "A3AU_dealer_flag";}; + + private _specialTitle = switch (_nameLower) do { + case "synd_hq": {format [localize "STR_A3U_HOVER_RESISTANCE_HQ",_specialFactionName]}; + case "tradermarker": {localize "STR_A3U_HOVER_BLACK_MARKET"}; + case "rallypointmarker": { + private _rallyCount = if (isNil "rallyPointSpawnCount") then {"0"} else {str rallyPointSpawnCount}; + format [localize "STR_marker_RP", _rallyCount] + }; + default {_name}; + }; + + private _specialDescription = switch (_nameLower) do { + case "synd_hq": {localize "STR_A3U_HOVER_RESISTANCE_HQ_DESC"}; + case "tradermarker": {localize "STR_A3U_HOVER_BLACK_MARKET_DESC"}; + case "rallypointmarker": {localize "STR_A3U_HOVER_RALLY_DESC"}; + default {""}; + }; + + private _specialText = if (_specialDescription != "") then { + format [ + "%1
%2", + _specialTitle, + _specialDescription + ] + } else { + _specialTitle }; + + _hoverMetaMap set [_name, [_specialText, _specialFlagMarkerType]]; + _hoverMarkers pushBackUnique _name; + + if (_dummyName in allMapMarkers) then { + _hoverMetaMap set [_dummyName, [_specialText, _specialFlagMarkerType]]; + _hoverMarkers pushBackUnique _dummyName; + }; +}; + +["Synd_HQ", teamPlayer] call _ensureSpecialHoverMetadata; +["synd_hq", teamPlayer] call _ensureSpecialHoverMetadata; +["TraderMarker", civilian] call _ensureSpecialHoverMetadata; +["tradermarker", civilian] call _ensureSpecialHoverMetadata; +["RallyPointMarker", teamPlayer] call _ensureSpecialHoverMetadata; +["rallypointmarker", teamPlayer] call _ensureSpecialHoverMetadata; + +missionNamespace setVariable ["A3U_mrkHoverMetaMap", _hoverMetaMap]; +missionNamespace setVariable ["A3U_hoverMarkers", _hoverMarkers]; + +if (A3AU_setting_alwaysShowMarkerName || {_markerName in (airportsX + milbases)}) then { + _visibleMarkerName setMarkerTextLocal _markerLabelOnly; +} else { + _visibleMarkerName setMarkerTextLocal ""; }; -_mrkD setMarkerText _mrkText; diff --git a/A3A/addons/core/functions/Base/fn_rebuildRadioTower.sqf b/A3A/addons/core/functions/Base/fn_rebuildRadioTower.sqf index 9cd4953657..24d6e2e0f1 100644 --- a/A3A/addons/core/functions/Base/fn_rebuildRadioTower.sqf +++ b/A3A/addons/core/functions/Base/fn_rebuildRadioTower.sqf @@ -17,8 +17,8 @@ antennas pushBack _antenna; publicVariable "antennas"; private _mrkFinal = createMarker [format ["Ant%1", mapGridPosition _antenna], getPos _antenna]; _mrkFinal setMarkerShape "ICON"; -_mrkFinal setMarkerType "loc_Transmitter"; -_mrkFinal setMarkerColor "ColorBlack"; +_mrkFinal setMarkerType "A3AU_radiotower_mrk"; +_mrkFinal setMarkerColor "ColorWhite"; _mrkFinal setMarkerText (localize "STR_radiotower"); mrkAntennas pushBack _mrkFinal; publicVariable "mrkAntennas"; diff --git a/A3A/addons/core/functions/Dialogs/fn_fastTravelRadio.sqf b/A3A/addons/core/functions/Dialogs/fn_fastTravelRadio.sqf index ce6904a225..19457af065 100644 --- a/A3A/addons/core/functions/Dialogs/fn_fastTravelRadio.sqf +++ b/A3A/addons/core/functions/Dialogs/fn_fastTravelRadio.sqf @@ -1,3 +1,7 @@ +params [ + ["_quickMarker", "", [""]] +]; + private _markersX = markersX + [respawnTeamPlayer]; // private _titleStr = localize "STR_A3A_fn_dialogs_ftradio_title"; @@ -57,10 +61,19 @@ if (_units findIf { positionTel = []; -[localize "STR_A3A_Dialogs_fast_travel_header", localize "STR_A3A_Dialogs_fast_travel_click"] call A3A_fnc_customHint; +if (_quickMarker == "") then {[localize "STR_A3A_Dialogs_fast_travel_header", localize "STR_A3A_Dialogs_fast_travel_click"] call A3A_fnc_customHint;}; if (!visibleMap) then {openMap true}; showCommandingMenu ""; -onMapSingleClick "positionTel = _pos; true"; +if !(_quickMarker == "") then { + private _quickMarkerPosition = getMarkerPos _quickMarker; + + _quickMarkerPosition set [0, (_quickMarkerPosition select 0) + 0.1]; + _quickMarkerPosition set [1, (_quickMarkerPosition select 1) + 0.1]; + // I have to add a slight offset because this shit will take a different marker if its set exactly on the marker i want to tp to.... + positionTel = _quickMarkerPosition; +} else { + onMapSingleClick "positionTel = _pos; true"; +}; waitUntil {sleep 1; (count positionTel > 0) or {not visiblemap}}; onMapSingleClick ""; @@ -227,6 +240,7 @@ if (_positionTel distance getMarkerPos _base < 500) then { sleep 5; {_x allowDamage true} forEach _ftUnits; + ['off'] call SCRT_fnc_ui_toggleMenuBlur; } else { [localize "STR_A3A_Dialogs_fast_travel_header", localize "STR_A3A_Dialogs_fast_travel_missclick"] call SCRT_fnc_misc_deniedHint; }; diff --git a/A3A/addons/core/functions/Missions/fn_ENC_Trader.sqf b/A3A/addons/core/functions/Missions/fn_ENC_Trader.sqf index 37d260ee40..bd211e6ac8 100644 --- a/A3A/addons/core/functions/Missions/fn_ENC_Trader.sqf +++ b/A3A/addons/core/functions/Missions/fn_ENC_Trader.sqf @@ -117,9 +117,9 @@ traderPosition = _traderPosition; publicVariable "traderPosition"; _traderMarker = createMarkerLocal ["TraderMarker", _traderPosition]; -_traderMarker setMarkerTypeLocal "hd_objective"; +_traderMarker setMarkerTypeLocal "A3AU_dealer_mrk"; _traderMarker setMarkerSizeLocal [1, 1]; -_traderMarker setMarkerTextLocal (localize "STR_marker_arms_dealer"); +_traderMarker setMarkerTextLocal ""; _traderMarker setMarkerColorLocal "ColorUNKNOWN"; _traderMarker setMarkerAlpha 1; traderMarker = _traderMarker; diff --git a/A3A/addons/core/functions/Save/fn_loadServer.sqf b/A3A/addons/core/functions/Save/fn_loadServer.sqf index 5fb1b67b41..102acb5f00 100644 --- a/A3A/addons/core/functions/Save/fn_loadServer.sqf +++ b/A3A/addons/core/functions/Save/fn_loadServer.sqf @@ -99,9 +99,7 @@ if (isServer) then { }; } forEach controlsX; - { - [_x] call A3A_fnc_mrkUpdate - } forEach (markersX - controlsX); + [markersX - controlsX] call A3U_fnc_mrkUpdateBulk; if (count watchpostsFIA > 0) then { markersX = markersX + watchpostsFIA; diff --git a/A3A/addons/core/functions/Save/fn_loadStat.sqf b/A3A/addons/core/functions/Save/fn_loadStat.sqf index 922c1dacd6..30988c9246 100644 --- a/A3A/addons/core/functions/Save/fn_loadStat.sqf +++ b/A3A/addons/core/functions/Save/fn_loadStat.sqf @@ -579,93 +579,103 @@ if (_varName in specialVarLoads) then { case 'watchpostsFIA': { if (count (_varValue select 0) == 2) then { { - _positionX = _x select 0; - _garrison = _x select 1; - _mrk = createMarker [format ["FIAWatchpost%1", random 1000], _positionX]; - _mrk setMarkerShape "ICON"; - _mrk setMarkerType "n_recon"; - _mrk setMarkerColor colorTeamPlayer; - _mrk setMarkerText format [localize "STR_marker_watchpost",FactionGet(reb,"name")]; - spawner setVariable [_mrk,2,true]; - if (count _garrison > 0) then {garrison setVariable [_mrk,_garrison,true]}; - watchpostsFIA pushBack _mrk; - sidesX setVariable [_mrk,teamPlayer,true]; - } forEach _varvalue; + _positionX = _x select 0; + _garrison = _x select 1; + _mrk = createMarker [format ["FIAWatchpost%1", random 1000], _positionX]; + _mrk setMarkerShapeLocal "ICON"; + _mrk setMarkerTypeLocal "A3AU_watchpost_mrk"; + _mrk setMarkerColorLocal colorTeamPlayer; + _mrk setMarkerText ""; + spawner setVariable [_mrk,2,true]; + if (count _garrison > 0) then {garrison setVariable [_mrk,_garrison,true]}; + sidesX setVariable [_mrk,teamPlayer,true]; + watchpostsFIA pushBack _mrk; + } forEach _varvalue; + + if !(watchpostsFIA isEqualTo []) then {[watchpostsFIA] remoteExec ["A3U_fnc_mrkUpdateBulk", 0, true]}; }; }; case 'roadblocksFIA': { if (count (_varValue select 0) == 2) then { - { - _positionX = _x select 0; - _garrison = _x select 1; - _mrk = createMarker [format ["FIARoadblock%1", random 1000], _positionX]; - _mrk setMarkerShape "ICON"; - _mrk setMarkerType "n_support"; - _mrk setMarkerColor colorTeamPlayer; - _mrk setMarkerText format [localize "STR_marker_roadblock",FactionGet(reb,"name")]; - spawner setVariable [_mrk,2,true]; - if (count _garrison > 0) then {garrison setVariable [_mrk,_garrison,true]}; - roadblocksFIA pushBack _mrk; - sidesX setVariable [_mrk,teamPlayer,true]; - } forEach _varvalue; - }; + { + _positionX = _x select 0; + _garrison = _x select 1; + _mrk = createMarker [format ["FIARoadblock%1", random 1000], _positionX]; + _mrk setMarkerShapeLocal "ICON"; + _mrk setMarkerTypeLocal "A3AU_roadblock_mrk"; + _mrk setMarkerColorLocal colorTeamPlayer; + _mrk setMarkerText ""; + spawner setVariable [_mrk,2,true]; + if (count _garrison > 0) then {garrison setVariable [_mrk,_garrison,true]}; + sidesX setVariable [_mrk,teamPlayer,true]; + roadblocksFIA pushBack _mrk; + } forEach _varvalue; + + if !(roadblocksFIA isEqualTo []) then {[roadblocksFIA] remoteExec ["A3U_fnc_mrkUpdateBulk", 0, true]}; + }; }; case 'aapostsFIA': { if (count (_varValue select 0) >= 2) then { { - _positionX = _x select 0; - _garrison = _x select 1; - _staticPositions = _x select 2; - _mrk = createMarker [format ["FIAAApost%1", random 1000], _positionX]; - _mrk setMarkerShape "ICON"; - _mrk setMarkerType "n_antiair"; - _mrk setMarkerColor colorTeamPlayer; - _mrk setMarkerText format [localize "STR_marker_aa_empl",FactionGet(reb,"name")]; - spawner setVariable [_mrk,2,true]; - if (count _garrison > 0) then {garrison setVariable [_mrk,_garrison,true]}; - if (count _staticPositions > 0) then {staticPositions setVariable [_mrk,_staticPositions,true]}; - aapostsFIA pushBack _mrk; - sidesX setVariable [_mrk,teamPlayer,true]; - } forEach _varvalue; + _positionX = _x select 0; + _garrison = _x select 1; + _staticPositions = _x select 2; + _mrk = createMarker [format ["FIAAApost%1", random 1000], _positionX]; + _mrk setMarkerShapeLocal "ICON"; + _mrk setMarkerTypeLocal "A3AU_antiair_mrk"; + _mrk setMarkerColorLocal colorTeamPlayer; + _mrk setMarkerText ""; + spawner setVariable [_mrk,2,true]; + if (count _garrison > 0) then {garrison setVariable [_mrk,_garrison,true]}; + if (count _staticPositions > 0) then {staticPositions setVariable [_mrk,_staticPositions,true]}; + sidesX setVariable [_mrk,teamPlayer,true]; + aapostsFIA pushBack _mrk; + } forEach _varvalue; + + if !(aapostsFIA isEqualTo []) then {[aapostsFIA] remoteExec ["A3U_fnc_mrkUpdateBulk", 0, true]}; }; }; case 'atpostsFIA': { if (count (_varValue select 0) >= 2) then { { - _positionX = _x select 0; - _garrison = _x select 1; - _staticPositions = _x select 2; - _mrk = createMarker [format ["FIAATpost%1", random 1000], _positionX]; - _mrk setMarkerShape "ICON"; - _mrk setMarkerType "n_armor"; - _mrk setMarkerColor colorTeamPlayer; - _mrk setMarkerText format [localize "STR_marker_at_empl", FactionGet(reb,"name")]; - spawner setVariable [_mrk,2,true]; - if (count _garrison > 0) then {garrison setVariable [_mrk,_garrison,true]}; - if (count _staticPositions > 0) then {staticPositions setVariable [_mrk,_staticPositions,true]}; - atpostsFIA pushBack _mrk; - sidesX setVariable [_mrk,teamPlayer,true]; - } forEach _varvalue; + _positionX = _x select 0; + _garrison = _x select 1; + _staticPositions = _x select 2; + _mrk = createMarker [format ["FIAATpost%1", random 1000], _positionX]; + _mrk setMarkerShapeLocal "ICON"; + _mrk setMarkerTypeLocal "A3AU_antitank_mrk"; + _mrk setMarkerColorLocal colorTeamPlayer; + _mrk setMarkerText ""; + spawner setVariable [_mrk,2,true]; + if (count _garrison > 0) then {garrison setVariable [_mrk,_garrison,true]}; + if (count _staticPositions > 0) then {staticPositions setVariable [_mrk,_staticPositions,true]}; + sidesX setVariable [_mrk,teamPlayer,true]; + atpostsFIA pushBack _mrk; + } forEach _varvalue; + + if !(atpostsFIA isEqualTo []) then {[atpostsFIA] remoteExec ["A3U_fnc_mrkUpdateBulk", 0, true]}; }; }; case 'hmgpostsFIA': { if (count (_varValue select 0) >= 2) then { { - _positionX = _x select 0; - _garrison = _x select 1; - _staticPositions = _x select 2; - _mrk = createMarker [format ["FIAHmgpost%1", random 1000], _positionX]; - _mrk setMarkerShape "ICON"; - _mrk setMarkerType "n_unknown"; - _mrk setMarkerColor colorTeamPlayer; - _mrk setMarkerText format [localize "STR_marker_hmg_empl", FactionGet(reb,"name")]; - spawner setVariable [_mrk,2,true]; - if (count _garrison > 0) then {garrison setVariable [_mrk,_garrison,true]}; - if (count _staticPositions > 0) then {staticPositions setVariable [_mrk,_staticPositions,true]}; - hmgpostsFIA pushBack _mrk; - sidesX setVariable [_mrk,teamPlayer,true]; - } forEach _varvalue; - } + _positionX = _x select 0; + _garrison = _x select 1; + _staticPositions = _x select 2; + _mrk = createMarker [format ["FIAHmgpost%1", random 1000], _positionX]; + _mrk setMarkerShapeLocal "ICON"; + _mrk setMarkerTypeLocal "A3AU_hmg_mrk"; + _mrk setMarkerColorLocal colorTeamPlayer; + _mrk setMarkerText ""; + spawner setVariable [_mrk,2,true]; + if (count _garrison > 0) then {garrison setVariable [_mrk,_garrison,true]}; + if (count _staticPositions > 0) then {staticPositions setVariable [_mrk,_staticPositions,true]}; + sidesX setVariable [_mrk,teamPlayer,true]; + hmgpostsFIA pushBack _mrk; + } forEach _varvalue; + + if !(hmgpostsFIA isEqualTo []) then {[hmgpostsFIA] remoteExec ["A3U_fnc_mrkUpdateBulk", 0, true]}; + }; }; case 'rebelLoadouts': { diff --git a/A3A/addons/core/functions/Supports/fn_SUP_orbitalStrikeRoutine.sqf b/A3A/addons/core/functions/Supports/fn_SUP_orbitalStrikeRoutine.sqf index 6d51e22828..d715a0d330 100644 --- a/A3A/addons/core/functions/Supports/fn_SUP_orbitalStrikeRoutine.sqf +++ b/A3A/addons/core/functions/Supports/fn_SUP_orbitalStrikeRoutine.sqf @@ -119,6 +119,8 @@ sleep 8; deleteVehicle _beamLight; deleteVehicle _strikeObject; +private _bulkMarkerUpdate = []; + private _citiesInRange = (citiesX - destroyedSites) select {((getMarkerPos _x) distance2D _impactPosition) < 200}; { ["TaskFailed", ["", format [localize "STR_notifiers_orbitalStrike_destruct", [_x] call A3A_fnc_localizar]]] remoteExec ["BIS_fnc_showNotification",teamPlayer]; @@ -126,7 +128,8 @@ private _citiesInRange = (citiesX - destroyedSites) select {((getMarkerPos _x) d publicVariable "destroyedSites"; sidesX setVariable [_x, Invaders, true]; garrison setVariable [_x, [], true]; - [_x] call A3A_fnc_mrkUpdate; + _bulkMarkerUpdate pushBack _x; sleep 10; } forEach _citiesInRange; +[_bulkMarkerUpdate] call A3U_fnc_mrkUpdateBulk; diff --git a/A3A/addons/core/functions/init/fn_initBases.sqf b/A3A/addons/core/functions/init/fn_initBases.sqf index f703982874..7d7836d378 100644 --- a/A3A/addons/core/functions/init/fn_initBases.sqf +++ b/A3A/addons/core/functions/init/fn_initBases.sqf @@ -26,12 +26,12 @@ private _fnc_initMarkerList = }; case (_x in milbases): { - _mrkD setMarkerTypeLocal (["b_hq", "o_hq"] select _isInvader); + _mrkD setMarkerTypeLocal (["A3AU_milbase_mrk", "A3AU_milbase_mrk"] select _isInvader); _mrkD setMarkerColorLocal ([colorOccupants, colorInvaders] select _isInvader); }; case (_x in seaports): { - _mrkD setMarkerTypeLocal (["b_naval", "o_naval"] select _isInvader); + _mrkD setMarkerTypeLocal "A3AU_seaport_mrk"; _mrkD setMarkerColorLocal ([colorOccupants, colorInvaders] select _isInvader); }; default @@ -72,10 +72,10 @@ private _controlsNATO = controlsX - _controlsCSAT; private _roadblockPositions = controlsX apply { markerPos _x }; [_mrkCSAT, airportsX, "flag_NATO", localize "STR_airbase", true] call _fnc_initMarkerList; -[_mrkCSAT, resourcesX, "loc_rock", localize "STR_resources"] call _fnc_initMarkerList; -[_mrkCSAT, factories, "u_installation", localize "STR_factory"] call _fnc_initMarkerList; -[_mrkCSAT, outposts, "loc_bunker", localize "STR_outpost", true] call _fnc_initMarkerList; -[_mrkCSAT, milbases, "b_hq", localize "STR_milbase", true] call _fnc_initMarkerList; +[_mrkCSAT, resourcesX, "A3AU_resource_mrk", localize "STR_resources"] call _fnc_initMarkerList; +[_mrkCSAT, factories, "A3AU_factory_mrk", localize "STR_factory"] call _fnc_initMarkerList; +[_mrkCSAT, outposts, "A3AU_outpost_mrk", localize "STR_outpost", true] call _fnc_initMarkerList; +[_mrkCSAT, milbases, "A3AU_milbase_mrk", localize "STR_milbase", true] call _fnc_initMarkerList; private _portName = [ localize "STR_port_sea", diff --git a/A3A/addons/core/functions/init/fn_initClient.sqf b/A3A/addons/core/functions/init/fn_initClient.sqf index ea3e123676..44275be6d1 100644 --- a/A3A/addons/core/functions/init/fn_initClient.sqf +++ b/A3A/addons/core/functions/init/fn_initClient.sqf @@ -679,4 +679,17 @@ if (staminaEnabled isEqualTo false) then { private _newWeaponSway = swayEnabled / 100; player setCustomAimCoef _newWeaponSway; +addMissionEventHandler ["Map", { + params ["_opened"]; + Verbose_1("[A3U HOVER DEBUG] Map EH opened=%1",_opened); + [false] call A3U_fnc_markerBrowser; // always force close on open & close + + if (_opened) then { + [true] call A3U_fnc_mapHover; + } else { + [false] call A3U_fnc_mapHover; + ['off'] call SCRT_fnc_ui_toggleMenuBlur; + }; +}]; + [CBA_EVENT_CLIENT_INIT_DONE, []] call FUNCMAIN(triggerLocalEvent); diff --git a/A3A/addons/core/functions/init/fn_initGarrisons.sqf b/A3A/addons/core/functions/init/fn_initGarrisons.sqf index 88cc32362c..5e3c14499f 100644 --- a/A3A/addons/core/functions/init/fn_initGarrisons.sqf +++ b/A3A/addons/core/functions/init/fn_initGarrisons.sqf @@ -30,7 +30,7 @@ if (gameMode == 3) then _updateMarkers pushBackUnique _x; } forEach (markersX - ["Synd_HQ"]); }; -{ _x call A3A_fnc_mrkUpdate } forEach _updateMarkers; +[_updateMarkers] call A3U_fnc_mrkUpdateBulk; private _occGroups = ((A3A_faction_occ get "groupsTierSquads") apply {_x select 1}) + ((A3A_faction_occ get "groupsTierMedium") apply {_x select 1}); diff --git a/A3A/addons/core/functions/init/fn_initZones.sqf b/A3A/addons/core/functions/init/fn_initZones.sqf index 26a32453e6..f271d13c8d 100644 --- a/A3A/addons/core/functions/init/fn_initZones.sqf +++ b/A3A/addons/core/functions/init/fn_initZones.sqf @@ -126,7 +126,7 @@ _cityConfigs apply { _dmrk = createMarkerLocal [format ["Dum%1", _nameX], _pos]; _dmrk setMarkerShapeLocal "ICON"; - _dmrk setMarkerTypeLocal "loc_Ruin"; + _dmrk setMarkerTypeLocal "A3AU_city_mrk"; _dmrk setMarkerColor colorOccupants; sidesX setVariable [_mrk, Occupants, true]; @@ -193,9 +193,10 @@ if (!_hardCodedAntennas) then { antennas apply { _mrkFinal = createMarker [format ["Ant%1", mapGridPosition _x], position _x]; _mrkFinal setMarkerShapeLocal "ICON"; - _mrkFinal setMarkerTypeLocal "loc_Transmitter"; - _mrkFinal setMarkerColorLocal "ColorBlack"; - _mrkFinal setMarkerText localize "STR_radiotower"; + _mrkFinal setMarkerTypeLocal "A3AU_radiotower_mrk"; + _mrkFinal setMarkerColorLocal "ColorWhite"; + _mrkFinal setMarkerText ""; + _mrkFinal setMarkerShadow false; mrkAntennas pushBack _mrkFinal; _x addEventHandler [ "Killed", @@ -240,9 +241,10 @@ if (count _posAntennas > 0) then { antennas pushBack _antenna; _mrkFinal = createMarker [format ["Ant%1", mapGridPosition _antenna], _posAntennas select _i]; _mrkFinal setMarkerShapeLocal "ICON"; - _mrkFinal setMarkerTypeLocal "loc_Transmitter"; - _mrkFinal setMarkerColorLocal "ColorBlack"; - _mrkFinal setMarkerText localize "STR_radiotower"; + _mrkFinal setMarkerTypeLocal "A3AU_radiotower_mrk"; + _mrkFinal setMarkerColorLocal "ColorWhite"; + _mrkFinal setMarkerText ""; + _mrkFinal setMarkerShadow false; mrkAntennas pushBack _mrkFinal; _antenna addEventHandler [ @@ -323,50 +325,63 @@ A3A_milAdministrations = []; A3A_destroyedMilAdministrations = []; private _milAdministrationTypes = [ - "Land_zachytka_nov", - "Land_zachytka", - "Land_PoliceStation_01_F", - "Land_i_Barracks_V1_F", - "Land_Barracks_01_dilapidated_F", - "Land_Barracks_01_grey_F", - "Land_Barracks_01_camo_F", - "Land_i_Barracks_V2_F", - "Land_u_Barracks_V2_F", - "Land_vn_i_barracks_v1_f", - "Land_vn_barracks_01_dilapidated_f", - "Land_vn_barracks_01_grey_f", - "Land_vn_barracks_01_camo_f", - "Land_vn_i_barracks_v2_f", - "land_gm_euro_office_02" + "Land_zachytka_nov", + "Land_zachytka", + "Land_PoliceStation_01_F", + "Land_i_Barracks_V1_F", + "Land_Barracks_01_dilapidated_F", + "Land_Barracks_01_grey_F", + "Land_Barracks_01_camo_F", + "Land_i_Barracks_V2_F", + "Land_u_Barracks_V2_F", + "Land_vn_i_barracks_v1_f", + "Land_vn_barracks_01_dilapidated_f", + "Land_vn_barracks_01_grey_f", + "Land_vn_barracks_01_camo_f", + "Land_vn_i_barracks_v2_f", + "land_gm_euro_office_02" ]; private _milAdminPositions = getArray (_mapInfo/"milAdministrations"); +private _milAdminMarkersToUpdate = []; -{ - private _milAdmins = (nearestObjects [_x, _milAdministrationTypes, 30]) select {!isObjectHidden _x && {alive _x}}; - if (_milAdmins isEqualTo []) then { - continue; - }; +_milAdminPositions apply { + private _milAdmins = (nearestObjects [_x, _milAdministrationTypes, 30]) select { + !isObjectHidden _x && {alive _x} + }; + if (_milAdmins isEqualTo []) then { + continue; + }; + + private _administration = _milAdmins select 0; + A3A_milAdministrations pushBack _administration; - private _administration = _milAdmins select 0; - A3A_milAdministrations pushBack _administration; + private _mrkAdm = createMarker [format ["MilAdm%1", mapGridPosition _administration], position _administration]; + _mrkAdm setMarkerShapeLocal "ICON"; + _mrkAdm setMarkerTypeLocal "A3AU_miladmin_mrk"; + _mrkAdm setMarkerColorLocal colorOccupants; + _mrkAdm setMarkerTextLocal ""; + _mrkAdm setMarkerAlphaLocal 0.75; + _mrkAdm setMarkerShadow false; - private _mrkAdm = createMarker [format ["MilAdm%1", mapGridPosition _administration], position _administration]; - _mrkAdm setMarkerShapeLocal "ICON"; - _mrkAdm setMarkerTypeLocal "loc_MilAdministration"; - _mrkAdm setMarkerColorLocal colorOccupants; - _mrkAdm setMarkerTextLocal localize "STR_milAdministration"; - _mrkAdm setMarkerAlpha 0.75; + _administration setVariable ["A3A_milAdminMarker", _mrkAdm]; - sidesX setVariable [_mrkAdm, Occupants, true]; + sidesX setVariable [_mrkAdm, Occupants, true]; - spawner setVariable [_mrkAdm, 2, true]; + milAdministrationsX pushBack _mrkAdm; + _milAdminMarkersToUpdate pushBack _mrkAdm; - milAdministrationsX pushBack _mrkAdm; + spawner setVariable [_mrkAdm, 2, true]; + + _administration addEventHandler ["Killed", { + params ["_killed"]; + + private _markerName = _killed getVariable ["A3A_milAdminMarker", ""]; + + [_killed, "DESTROY"] call SCRT_fnc_location_removeMilAdmin; + }]; +}; - _administration addEventHandler ["Killed", { - [(this select 0), "DESTROY"] call SCRT_fnc_location_removeMilAdmin; - }]; -} forEach _milAdminPositions; +if !(_milAdminMarkersToUpdate isEqualTo []) then {[_milAdminMarkersToUpdate] call A3U_fnc_mrkUpdateBulk;}; // markersX append milAdministrationsX; diff --git a/A3A/addons/gui/dialogues/controls.hpp b/A3A/addons/gui/dialogues/controls.hpp index 820a42b977..467b7608f5 100644 --- a/A3A/addons/gui/dialogues/controls.hpp +++ b/A3A/addons/gui/dialogues/controls.hpp @@ -281,25 +281,25 @@ class A3A_Button : A3A_Text // Sounds soundClick[] = { - "\A3\ui_f\data\sound\RscButton\soundClick", + "\A3\ui_f\data\sound\RscButton\soundClick.wss", 0.09, 1 }; soundEnter[] = { - "\A3\ui_f\data\sound\RscButton\soundEnter", + "\A3\ui_f\data\sound\RscButton\soundEnter.wss", 0.09, 1 }; soundPush[] = { - "\A3\ui_f\data\sound\RscButton\soundPush", + "\A3\ui_f\data\sound\RscButton\soundPush.wss", 0.09, 1 }; soundEscape[] = { - "\A3\ui_f\data\sound\RscButton\soundEscape", + "\A3\ui_f\data\sound\RscButton\soundEscape.wss", 0.09, 1 }; @@ -371,25 +371,25 @@ class A3A_ShortcutButton : A3A_CtrlDefault // Sounds soundEnter[] = { - "\A3\ui_f\data\sound\RscButton\soundEnter", + "\A3\ui_f\data\sound\RscButton\soundEnter.wss", 0.09, 1 }; soundPush[] = { - "\A3\ui_f\data\sound\RscButton\soundPush", + "\A3\ui_f\data\sound\RscButton\soundPush.wss", 0.09, 1 }; soundClick[] = { - "\A3\ui_f\data\sound\RscButton\soundClick", + "\A3\ui_f\data\sound\RscButton\soundClick.wss", 0.09, 1 }; soundEscape[] = { - "\A3\ui_f\data\sound\RscButton\soundEscape", + "\A3\ui_f\data\sound\RscButton\soundEscape.wss", 0.09, 1 }; @@ -464,25 +464,25 @@ class A3A_ActiveText : A3A_CtrlDefault // Sounds soundEnter[] = { - "\A3\ui_f\data\sound\RscButton\soundEnter", + "\A3\ui_f\data\sound\RscButton\soundEnter.wss", 0.09, 1 }; soundPush[] = { - "\A3\ui_f\data\sound\RscButton\soundPush", + "\A3\ui_f\data\sound\RscButton\soundPush.wss", 0.09, 1 }; soundClick[] = { - "\A3\ui_f\data\sound\RscButton\soundClick", + "\A3\ui_f\data\sound\RscButton\soundClick.wss", 0.09, 1 }; soundEscape[] = { - "\A3\ui_f\data\sound\RscButton\soundEscape", + "\A3\ui_f\data\sound\RscButton\soundEscape.wss", 0.09, 1 }; @@ -1245,4 +1245,47 @@ class A3A_ComboBox_Small_BM : A3A_ComboBox_Small { colorBackground[] = {0,0,0,1}; SizeEx = GUI_TEXT_SIZE_MEDIUM; +}; + +class A3U_RscContextButton : A3A_Button +{ + sizeEx = GUI_TEXT_SIZE_EXTRA_SMALL; + colorText[] = {1,1,1,1}; + colorDisabled[] = {1,1,1,0.35}; + + colorBackground[] = {0,0,0,0.8}; + colorBackgroundDisabled[] = {0,0,0,0.8}; + + colorBackgroundActive[] = {0.10,0.60,1.00,0.60}; + colorFocused[] = {0.10,0.60,1.00,0.60}; + + colorShadow[] = {0,0,0,0}; + colorBorder[] = {0,0,0,0}; + borderSize = 0; + + // Sounds + soundEnter[] = + { + "\A3\ui_f\data\sound\RscButton\soundEnter.wss", + 0.09, + 1 + }; + soundPush[] = + { + "\A3\ui_f\data\sound\RscButton\soundPush.wss", + 0.09, + 1 + }; + soundClick[] = + { + "\A3\ui_f\data\sound\RscButton\soundClick.wss", + 0.09, + 1 + }; + soundEscape[] = + { + "\A3\ui_f\data\sound\RscButton\soundEscape.wss", + 0.09, + 1 + }; }; \ No newline at end of file diff --git a/A3A/addons/gui/dialogues/defines.hpp b/A3A/addons/gui/dialogues/defines.hpp index 0beaafe85d..6d0178535e 100644 --- a/A3A/addons/gui/dialogues/defines.hpp +++ b/A3A/addons/gui/dialogues/defines.hpp @@ -138,6 +138,7 @@ Maintainer: DoomMetal #define CENTER_Y(n) ((getResolution select 3) * 0.5 * pixelH) - (0.5 * (PX_H(n))) // Text sizes +#define GUI_TEXT_SIZE_EXTRA_SMALL (GRID_H * 2.5) #define GUI_TEXT_SIZE_SMALL (GRID_H * 3.2) // Fits inside 3*GRID_H #define GUI_TEXT_SIZE_SPECIAL (GRID_H * 3.5) // Fits inside alright) #define GUI_TEXT_SIZE_MEDIUM (GRID_H * 4.2) // Fits inside 4*GRID_H diff --git a/A3A/addons/scrt/Location/fn_location_removeMilAdmin.sqf b/A3A/addons/scrt/Location/fn_location_removeMilAdmin.sqf index c283b3cfca..b384b90232 100644 --- a/A3A/addons/scrt/Location/fn_location_removeMilAdmin.sqf +++ b/A3A/addons/scrt/Location/fn_location_removeMilAdmin.sqf @@ -35,6 +35,7 @@ _milAdministration removeAllEventHandlers "Killed"; A3A_destroyedMilAdministrations pushBack _milAdministration; private _mrk = [milAdministrationsX, _milAdministration] call BIS_fnc_nearestPosition; _mrk setMarkerColor "ColorBlack"; +_mrk setMarkerType "A3AU_miladmin_dead_mrk"; sidesX setVariable [_mrk, teamPlayer, true]; //otherwise it will be looped diff --git a/A3A/addons/scrt/Outpost/fn_outpost_createAa.sqf b/A3A/addons/scrt/Outpost/fn_outpost_createAa.sqf index 80e35a961d..d996686d4f 100644 --- a/A3A/addons/scrt/Outpost/fn_outpost_createAa.sqf +++ b/A3A/addons/scrt/Outpost/fn_outpost_createAa.sqf @@ -75,14 +75,15 @@ switch (true) do { publicVariable "markersX"; spawner setVariable [_marker,2,true]; _nul = [-5,5,_position] remoteExec ["A3A_fnc_citySupportChange",2]; - _marker setMarkerType "n_antiair"; + _marker setMarkerType "A3AU_antiair_mrk"; _marker setMarkerColor colorTeamPlayer; - _marker setMarkerText _textX; + _marker setMarkerText ""; _garrison = A3A_faction_reb get "groupAaEmpl"; garrison setVariable [_marker,_garrison,true]; staticPositions setVariable [_marker, [_position, _direction], true]; [_taskId, "outpostTask", "SUCCEEDED"] call A3A_fnc_taskSetState; ["RebelControlCreated", [_marker, "aaemplacement"]] call EFUNC(Events,triggerEvent); + [_marker] remoteExec ["A3A_fnc_mrkUpdate", 0, true]; }; default { [_taskId, "outpostTask", "FAILED"] call A3A_fnc_taskSetState; diff --git a/A3A/addons/scrt/Outpost/fn_outpost_createAt.sqf b/A3A/addons/scrt/Outpost/fn_outpost_createAt.sqf index 378ef7ac67..5730816c90 100644 --- a/A3A/addons/scrt/Outpost/fn_outpost_createAt.sqf +++ b/A3A/addons/scrt/Outpost/fn_outpost_createAt.sqf @@ -76,14 +76,15 @@ switch (true) do { spawner setVariable [_marker,2,true]; [_taskId, "outpostTask", "SUCCEEDED"] call A3A_fnc_taskSetState; _nul = [-5,5,_position] remoteExec ["A3A_fnc_citySupportChange",2]; - _marker setMarkerType "n_armor"; + _marker setMarkerType "A3AU_antitank_mrk"; _marker setMarkerColor colorTeamPlayer; - _marker setMarkerText _textX; + _marker setMarkerText ""; _garrison = A3A_faction_reb get "groupAtEmpl"; garrison setVariable [_marker,_garrison,true]; staticPositions setVariable [_marker, [_position, _direction], true]; [_taskId, "outpostTask", "SUCCEEDED"] call A3A_fnc_taskSetState; ["RebelControlCreated", [_marker, "atemplacement"]] call EFUNC(Events,triggerEvent); + [_marker] remoteExec ["A3A_fnc_mrkUpdate", 0, true]; }; default { [_taskId, "outpostTask", "FAILED"] call A3A_fnc_taskSetState; diff --git a/A3A/addons/scrt/Outpost/fn_outpost_createHmg.sqf b/A3A/addons/scrt/Outpost/fn_outpost_createHmg.sqf index 0a049f5b86..9ab01a6fb0 100644 --- a/A3A/addons/scrt/Outpost/fn_outpost_createHmg.sqf +++ b/A3A/addons/scrt/Outpost/fn_outpost_createHmg.sqf @@ -75,14 +75,15 @@ switch (true) do { publicVariable "markersX"; spawner setVariable [_marker,2,true]; _nul = [-5,5,_position] remoteExec ["A3A_fnc_citySupportChange",2]; - _marker setMarkerType "n_unknown"; + _marker setMarkerType "A3AU_hmg_mrk"; _marker setMarkerColor colorTeamPlayer; - _marker setMarkerText _textX; + _marker setMarkerText ""; _garrison = A3A_faction_reb get "groupHmgEmpl"; garrison setVariable [_marker,_garrison,true]; staticPositions setVariable [_marker, [_position, _direction], true]; [_taskId, "outpostTask", "SUCCEEDED"] call A3A_fnc_taskSetState; ["RebelControlCreated", [_marker, "hmgemplacement"]] call EFUNC(Events,triggerEvent); + [_marker] remoteExec ["A3A_fnc_mrkUpdate", 0, true]; }; default { [_taskId, "outpostTask", "FAILED"] call A3A_fnc_taskSetState; diff --git a/A3A/addons/scrt/Outpost/fn_outpost_createRoadblock.sqf b/A3A/addons/scrt/Outpost/fn_outpost_createRoadblock.sqf index 49464b9cc7..167d59dec2 100644 --- a/A3A/addons/scrt/Outpost/fn_outpost_createRoadblock.sqf +++ b/A3A/addons/scrt/Outpost/fn_outpost_createRoadblock.sqf @@ -78,13 +78,14 @@ switch (true) do { publicVariable "markersX"; spawner setVariable [_marker,2,true]; _nul = [-5,5,_position] remoteExec ["A3A_fnc_citySupportChange",2]; - _marker setMarkerType "n_support"; + _marker setMarkerType "A3AU_roadblock_mrk"; _marker setMarkerColor colorTeamPlayer; - _marker setMarkerText _textX; + _marker setMarkerText ""; _garrison = [_riflemanType] + _squadType; garrison setVariable [_marker,_garrison,true]; [_taskId, "outpostTask", "SUCCEEDED"] call A3A_fnc_taskSetState; ["RebelControlCreated", [_marker, "roadblock"]] call EFUNC(Events,triggerEvent); + [_marker] remoteExec ["A3A_fnc_mrkUpdate", 0, true]; }; default { [_taskId, "outpostTask", "FAILED"] call A3A_fnc_taskSetState; diff --git a/A3A/addons/scrt/Outpost/fn_outpost_createWatchpost.sqf b/A3A/addons/scrt/Outpost/fn_outpost_createWatchpost.sqf index b576c1f777..e48481ad14 100644 --- a/A3A/addons/scrt/Outpost/fn_outpost_createWatchpost.sqf +++ b/A3A/addons/scrt/Outpost/fn_outpost_createWatchpost.sqf @@ -77,11 +77,12 @@ switch (true) do { publicVariable "markersX"; spawner setVariable [_marker,2,true]; _nul = [-5,5,_position] remoteExec ["A3A_fnc_citySupportChange",2]; - _marker setMarkerType "n_recon"; + _marker setMarkerType "A3AU_watchpost_mrk"; _marker setMarkerColor colorTeamPlayer; - _marker setMarkerText _textX; + _marker setMarkerText ""; [_taskId, "outpostTask", "SUCCEEDED"] call A3A_fnc_taskSetState; ["RebelControlCreated", [_marker, "watchpost"]] call EFUNC(Events,triggerEvent); + [_marker] remoteExec ["A3A_fnc_mrkUpdate", 0, true]; }; default { [_taskId, "outpostTask", "FAILED"] call A3A_fnc_taskSetState; diff --git a/A3A/addons/scrt/Rally/fn_rally_placeRallyPoint.sqf b/A3A/addons/scrt/Rally/fn_rally_placeRallyPoint.sqf index 4814448e52..3397159b6e 100644 --- a/A3A/addons/scrt/Rally/fn_rally_placeRallyPoint.sqf +++ b/A3A/addons/scrt/Rally/fn_rally_placeRallyPoint.sqf @@ -45,14 +45,16 @@ _ammobox setDir 115; [rallyPointRoot, [0, 0, -0.5], 0.2] remoteExec ["SCRT_fnc_common_attachLightSource", 0, rallyPointRoot]; rallyPointMarker = createMarker ["RallyPointMarker", _rootPos]; -rallyPointMarker setMarkerType "hd_join"; +rallyPointMarker setMarkerType "A3AU_fasttravel_mrk"; rallyPointMarker setMarkerSize [1, 1]; -rallyPointMarker setMarkerText (format [localize "STR_marker_RP", str rallyPointSpawnCount]); +rallyPointMarker setMarkerText ""; rallyPointMarker setMarkerColor "colorIndependent"; rallyPointMarker setMarkerAlpha 1; sidesX setVariable [rallyPointMarker,teamPlayer,true]; publicVariable "rallyPointMarker"; +[rallyPointMarker] remoteExec ["A3A_fnc_mrkUpdate", 0, true]; + rallyProps append [_backpack1, _backpack2, _bag, _ammobox]; publicVariable "rallyProps"; diff --git a/A3A/addons/scrt/Stringtable.xml b/A3A/addons/scrt/Stringtable.xml index da6eee22d5..4bc3b9a3ff 100644 --- a/A3A/addons/scrt/Stringtable.xml +++ b/A3A/addons/scrt/Stringtable.xml @@ -8413,44 +8413,39 @@ %1 Karakolu - %1 Airbase - Авиабаза %1 - %1 空军基地 - %1 공군 기지 - Base aérienne %1 - %1 Hava Üssü + %1 %2 Airbase + Авиабаза %1 %2 + %1 %2 空军基地 + %1 %2 공군 기지 + Base aérienne %1 %2 - Resources - Ресурсы - 资源 - 자원채취소 - Ressources - Kaynaklar + %1 Resources + %1 Ресурсы + %1 资源 + %1 자원채취소 + %1 Ressources - Factory - Фабрика - 工厂 - 공장 - Usine - Fabrika + %1 Factory + %1 Фабрика + %1 工厂 + %1 공장 + %1 Usine - River Port - Речной порт - 河港 - 강항 - Port fluvial - Nehir Limanı + %1 River Port + %1 Речной порт + %1 河港 + %1 강항 + %1 Port fluvial - Sea Port - Морской порт - 海港 - 항구 - Port maritime - Deniz Limanı + %1 Sea Port + %1 Морской порт + %1 海港 + %1 항구 + %1 Port maritime %1 Military Base @@ -8485,20 +8480,18 @@ Akaryakıt İstasyonu - Military Administration - Военная администрация - 军事管理机构 - 군 행정부 - Administration militaire - Askeri İdare + %1 Military Administration + %1 Военная администрация + %1 军事管理机构 + %1 군 행정부 + %1 Administration militaire - Your Headquarters - Штаб - 당신의 본부 - Votre QG - 你的总部 - Karargahınız + %1 Headquarters + %1 Штаб + %1 본부 + %1 Quartier général + %1 总部 diff --git a/A3A/addons/scrt/Trader/fn_trader_createTrader.sqf b/A3A/addons/scrt/Trader/fn_trader_createTrader.sqf index 5b115286d8..326696d9ed 100644 --- a/A3A/addons/scrt/Trader/fn_trader_createTrader.sqf +++ b/A3A/addons/scrt/Trader/fn_trader_createTrader.sqf @@ -17,9 +17,9 @@ traderObjects = []; if (isTraderQuestCompleted) then { traderMarker = createMarker ["TraderMarker", _position]; - traderMarker setMarkerType "hd_objective"; + traderMarker setMarkerType "A3AU_dealer_mrk"; traderMarker setMarkerSize [1, 1]; - traderMarker setMarkerText (localize "STR_marker_arms_dealer"); + traderMarker setMarkerText ""; traderMarker setMarkerColor "ColorUNKNOWN"; traderMarker setMarkerAlpha 1; sidesX setVariable [traderMarker,teamPlayer,true]; diff --git a/A3A/addons/ultimate/CfgFunctions.hpp b/A3A/addons/ultimate/CfgFunctions.hpp index 6e9264bcb1..d7e7761e13 100644 --- a/A3A/addons/ultimate/CfgFunctions.hpp +++ b/A3A/addons/ultimate/CfgFunctions.hpp @@ -36,6 +36,16 @@ class CfgFunctions class isInMenu {}; class menuImage {}; }; + class map + { + file = QPATHTOFOLDER(functions\map); + class mapHover {}; + class mapTooltip {}; + class tooltipCreate {}; + class markerBrowser {}; + class markerContextMenu {}; + class mrkUpdateBulk {}; + }; class REINF { file = QPATHTOFOLDER(functions\REINF); diff --git a/A3A/addons/ultimate/CfgMarkerColors.hpp b/A3A/addons/ultimate/CfgMarkerColors.hpp new file mode 100644 index 0000000000..6e9b6ac287 --- /dev/null +++ b/A3A/addons/ultimate/CfgMarkerColors.hpp @@ -0,0 +1,20 @@ +class A3AU_Color_Light_Gray +{ + scope = 0; + name = "A3AU Light Gray Color"; + color[] = {0.8, 0.8, 0.8, 1}; +}; + +class A3AU_Color_Dark_Purple +{ + scope = 0; + name = "A3AU Dark Purple Color"; + color[] = {0.45, 0.2, 0.6, 1}; +}; + +class A3AU_Color_Tan +{ + scope = 0; + name = "A3AU Tan Color"; + color[] = {0.55, 0.4, 0.2, 1}; +}; \ No newline at end of file diff --git a/A3A/addons/ultimate/CfgMarkers.hpp b/A3A/addons/ultimate/CfgMarkers.hpp new file mode 100644 index 0000000000..4f78c684ee --- /dev/null +++ b/A3A/addons/ultimate/CfgMarkers.hpp @@ -0,0 +1,157 @@ + +class n_unknown; +class flag_NATO; + +class A3AU_Factory_mrk : n_unknown +{ + scope = 2; + name = "Antistasi Factory"; + icon = QPATHTOFOLDER(data\A3AU_factory_mrk); + texture = QPATHTOFOLDER(data\A3AU_factory_mrk); + color[] = { 0, 0, 0, 1 }; + shadow = 0; + markerClass = "A3AU_MRK"; + size = 24; + showEditorMarkerColor = 0; +}; + +class A3AU_city_mrk : A3AU_Factory_mrk +{ + name = "Antistasi City"; + icon = QPATHTOFOLDER(data\A3AU_city_mrk); + texture = QPATHTOFOLDER(data\A3AU_city_mrk); + markerClass = "A3AU_MRK"; + size = 20; +}; + +class A3AU_Resource_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Resource"; + icon = QPATHTOFOLDER(data\A3AU_resource_mrk); + texture = QPATHTOFOLDER(data\A3AU_resource_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_outpost_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Outpost"; + icon = QPATHTOFOLDER(data\A3AU_outpost_mrk); + texture = QPATHTOFOLDER(data\A3AU_outpost_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_milbase_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Military Base"; + icon = QPATHTOFOLDER(data\A3AU_milbase_mrk); + texture = QPATHTOFOLDER(data\A3AU_milbase_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_seaport_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Seaport"; + icon = QPATHTOFOLDER(data\A3AU_seaport_mrk); + texture = QPATHTOFOLDER(data\A3AU_seaport_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_RebalHQ_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Rebal HQ"; + icon = QPATHTOFOLDER(data\A3AU_RebalHQ_mrk); + texture = QPATHTOFOLDER(data\A3AU_RebalHQ_mrk); + markerClass = "A3AU_MRK"; + size = 36; +}; + +class A3AU_dealer_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Arms Dealer"; + icon = QPATHTOFOLDER(data\A3AU_dealer_mrk); + texture = QPATHTOFOLDER(data\A3AU_dealer_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_radiotower_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Radio Tower"; + icon = QPATHTOFOLDER(data\A3AU_radiotower_mrk); + texture = QPATHTOFOLDER(data\A3AU_radiotower_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_miladmin_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Military Admin"; + icon = QPATHTOFOLDER(data\A3AU_miladmin_mrk); + texture = QPATHTOFOLDER(data\A3AU_miladmin_mrk); + markerClass = "A3AU_MRK"; + size = 30; +}; + +class A3AU_miladmin_dead_mrk : A3AU_miladmin_mrk +{ + name = "Antistasi Military Admin (Dead)"; + icon = QPATHTOFOLDER(data\A3AU_miladmin_dead_mrk); + texture = QPATHTOFOLDER(data\A3AU_miladmin_dead_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_watchpost_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Watchpost"; + icon = QPATHTOFOLDER(data\A3AU_watchpost_mrk); + texture = QPATHTOFOLDER(data\A3AU_watchpost_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_roadblock_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Roadblock"; + icon = QPATHTOFOLDER(data\A3AU_roadblock_mrk); + texture = QPATHTOFOLDER(data\A3AU_roadblock_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_antiair_mrk : A3AU_Factory_mrk +{ + name = "Antistasi AA Emplacement"; + icon = QPATHTOFOLDER(data\A3AU_antiair_mrk); + texture = QPATHTOFOLDER(data\A3AU_antiair_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_antitank_mrk : A3AU_Factory_mrk +{ + name = "Antistasi AT Emplacement"; + icon = QPATHTOFOLDER(data\A3AU_antitank_mrk); + texture = QPATHTOFOLDER(data\A3AU_antitank_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_hmg_mrk : A3AU_Factory_mrk +{ + name = "Antistasi HMG Emplacement"; + icon = QPATHTOFOLDER(data\A3AU_hmg_mrk); + texture = QPATHTOFOLDER(data\A3AU_hmg_mrk); + markerClass = "A3AU_MRK"; +}; + +class A3AU_fasttravel_mrk : A3AU_Factory_mrk +{ + name = "Antistasi Fast Travel"; + icon = QPATHTOFOLDER(data\A3AU_fasttravel_mrk); + texture = QPATHTOFOLDER(data\A3AU_fasttravel_mrk); + markerClass = "A3AU_MRK"; + size = 32; +}; + +class A3AU_dealer_flag: flag_NATO +{ + scope = 1; + name = "Arms Dealer Flag"; + icon = QPATHTOFOLDER(data\A3AU_dealer_flag); + texture = QPATHTOFOLDER(data\A3AU_dealer_flag); + markerClass = "A3AU_MRK"; +}; diff --git a/A3A/addons/ultimate/Stringtable.xml b/A3A/addons/ultimate/Stringtable.xml index 8516dba5c1..0c6ccbd5bc 100644 --- a/A3A/addons/ultimate/Stringtable.xml +++ b/A3A/addons/ultimate/Stringtable.xml @@ -336,6 +336,386 @@ Ce kit contient un outil de crochetage à usage unique pour déverrouiller les véhicules si vous n'êtes pas ingénieur. + + + Ironclad|Vanguard|Resolute|Thunder Ridge|Liberty Crest|Sentinel|Granite Watch|Falcon’s Reach|Redstone|Blackwater|Dominion|Silver Spear|Iron Summit|Stormbreaker|Eagle’s Rest|Frosthaven|Shadow Ridge|Ironwood|Highpoint|Warfield|Steadfast|Valor|Coldwater|Bastion|Granite Pass|Torchlight|Iron Vale|Watchtower|Emberfall|Hawk’s Landing|Blackridge|Silver Creek|Northwind|Crimson Bluff|Stonewall|Titan|Red Horizon|Ironwatch|Blue Mesa|Frontier|Iron Peak|Steelhaven|White Ridge|Vanguard Heights|Ironhaven|Stormwatch|Gray Sentinel|Obsidian Point|Iron Frontier|Copperhead|Raven Rock|Thunderhead|Silver Dawn|Iron Bastion|Wolf Creek|Falcon Crest|Granite Shield|Iron Harbor|Red Mesa|Nightfall|High Sentinel|Iron Dominion|Stormhold|Black Summit|Frostpoint|Eagle Crest|Iron Citadel|Shadowfall|Northpoint|Steel Ridge|Iron Horizon|Redwatch|Silent Peak|Granite Dawn|Stormridge|Iron Resolve|Wolf Ridge|Black Harbor|Falcon Watch|Silver Ridge|Ironcliff|Ember Ridge|Cold Harbor|Iron Thunder|Sentinel Peak|Red Valley|Granite Point|Stormfront|Iron Crown|Hawk Ridge|Blackstone|Frost Ridge|Iron Watchpoint|Silver Horizon|Thunderwatch|Iron Bastille|Shadowpoint|Steel Summit + Железный Клинок|Авангард|Решимость|Громовой Хребет|Гребень Свободы|Страж|Гранитный Дозор|Соколиный Рубеж|Красный Камень|Чёрные Воды|Господство|Серебряное Копьё|Железная Вершина|Громовержец|Орлиный Приют|Морозная Гавань|Теневой Хребет|Железный Бор|Высота|Поле Боя|Стойкость|Доблесть|Холодные Воды|Бастион|Гранитный Перевал|Факел|Железная Долина|Смотровая Башня|Пепельная Долина|Соколиная Гавань|Чёрный Кряж|Серебряный Ручей|Северный Ветер|Багровый Утёс|Каменный Вал|Титан|Красный Горизонт|Железный Дозор|Синяя Меса|Рубеж|Железный Пик|Стальная Гавань|Белый Хребет|Высоты Авангарда|Железная Гавань|Штормовой Дозор|Серый Страж|Обсидиановый Пункт|Железный Рубеж|Медноголовый|Воронья Скала|Грозовая Туча|Серебряный Рассвет|Железный Бастион|Волчий Ручей|Соколиный Гребень|Гранитный Щит|Железная Бухта|Красная Меса|Сумерки|Верховный Страж|Железное Господство|Штормовая Твердыня|Чёрная Вершина|Морозная Точка|Орлиный Гребень|Железная Цитадель|Тенепад|Северная Точка|Стальной Хребет|Железный Горизонт|Красный Дозор|Тихая Вершина|Гранитный Рассвет|Штормовой Хребет|Железная Решимость|Волчий Хребет|Чёрная Гавань|Соколиный Дозор|Серебряный Хребет|Железный Утёс|Пепельный Хребет|Холодная Гавань|Железный Гром|Вершина Стража|Красная Долина|Гранитная Точка|Штормовой Фронт|Железная Корона|Соколиный Хребет|Чёрный Камень|Морозный Хребет|Железный Наблюдательный Пункт|Серебряный Горизонт|Грозовой Дозор|Железная Бастилия|Теневая Точка|Стальная Вершина + Forteresse Fer|Avant-Garde|Résolution|Crête du Tonnerre|Cime de Liberté|Sentinelle|Veille de Granit|Portée du Faucon|Pierre Rouge|Eaux Noires|Dominion|Lance d’Argent|Sommet de Fer|Brise-Tempête|Repos de l’Aigle|Havre de Givre|Crête de l’Ombre|Bois de Fer|Haut-Point|Champ de Guerre|Inébranlable|Vaillance|Eaux Froides|Bastion|Passage de Granit|Flambeau|Val de Fer|Tour de Veille|Chute des Braises|Atterrissage du Faucon|Crête Noire|Ruisseau d’Argent|Vent du Nord|Falaise Pourpre|Muraille|Titan|Horizon Rouge|Veille de Fer|Mesa Bleue|Frontière|Pic de Fer|Havre d’Acier|Crête Blanche|Hauteurs de l’Avant-Garde|Havre de Fer|Veille Tempête|Sentinelle Grise|Pointe Obsidienne|Frontière de Fer|Tête-de-Cuivre|Rocher du Corbeau|Tête du Tonnerre|Aube d’Argent|Bastion de Fer|Ruisseau du Loup|Crête du Faucon|Bouclier de Granit|Port de Fer|Mesa Rouge|Crépuscule|Haute Sentinelle|Dominion de Fer|Fort Tempête|Sommet Noir|Pointe de Givre|Crête de l’Aigle|Citadelle de Fer|Chute d’Ombre|Pointe Nord|Crête d’Acier|Horizon de Fer|Veille Rouge|Pic Silencieux|Aube de Granit|Crête Tempête|Résolution de Fer|Crête du Loup|Port Noir|Veille du Faucon|Crête d’Argent|Falaise de Fer|Crête des Braises|Port Froid|Tonnerre de Fer|Pic de la Sentinelle|Vallée Rouge|Pointe de Granit|Front de Tempête|Couronne de Fer|Crête du Faucon|Pierre Noire|Crête de Givre|Point de Veille de Fer|Horizon d’Argent|Veille du Tonnerre|Bastille de Fer|Pointe d’Ombre|Sommet d’Acier + Festung Eisen|Vorhut|Entschlossenheit|Donnergrat|Freiheitskamm|Wächter|Granitwacht|Falkenreich|Rotstein|Schwarzwasser|Herrschaft|Silberspeer|Eisengipfel|Sturmspalter|Adlerhorst|Frosthafen|Schattenkamm|Eisenwald|Hochpunkt|Kriegsfeld|Standhaft|Tapferkeit|Kaltwasser|Bastion|Granitpass|Fackellicht|Eisental|Wachturm|Glutfall|Falkenlandung|Schwarzgrat|Silberbach|Nordwind|Purpurklippe|Steinwall|Titan|Rothorizont|Eisenwacht|Blaue Mesa|Grenzposten|Eisenpeak|Stahlhafen|Weißgrat|Vorhuthöhen|Eisenhafen|Sturmwacht|Grauer Wächter|Obsidianpunkt|Eisengrenze|Kupferkopf|Rabenspitze|Donnerkopf|Silberdämmerung|Eisenbastion|Wolfbach|Falkenkamm|Granitschild|Eisenhafen|Rotmesa|Nachtfall|Hoher Wächter|Eisendominion|Sturmfeste|Schwarzgipfel|Frostpunkt|Adlerkamm|Eisenzitadelle|Schattenfall|Nordpunkt|Stahlgrat|Eisenhorizont|Rotwacht|Stillgipfel|Granitaue|Sturmgrat|Eisenentschlossen|Wolfgrat|Schwarzhafen|Falkenwacht|Silbergrat|Eisenkliff|Glutgrat|Kalthafen|Eisendonner|Wächtergipfel|Rotetal|Granitpunkt|Sturmfront|Eisenkrone|Habichtgrat|Schwarzstein|Frostgrat|Eisenbeobachtung|Silberhorizont|Donnerwacht|Eisenbastille|Schattenpunkt|Stahlgipfel + Železná Pevnost|Předvoj|Odhodlání|Hromový Hřeben|Hřeben Svobody|Stráž|Granitová Hlídka|Sokolí Dosah|Rudý Kámen|Černé Vody|Nadvláda|Stříbrné Kopí|Železný Vrchol|Lamač Bouří|Orlí Útočiště|Mrazavý Přístav|Stínový Hřeben|Železný Les|Vyhlídka|Válečné Pole|Neochvějný|Udatnost|Studené Vody|Bastion|Granitový Průsmyk|Pochodeň|Železné Údolí|Věž Hlídky|Pád Žhavých Uhlíků|Sokolí Přistání|Černý Hřbet|Stříbrný Potok|Severní Vítr|Karmínový Útes|Kamenná Hradba|Titan|Rudý Horizont|Železná Hlídka|Modrá Mesa|Hranice|Železný Štít|Ocelový Přístav|Bílý Hřeben|Výšiny Předvoje|Železný Přístav|Bouřná Hlídka|Šedý Strážce|Obsidiánový Bod|Železná Hranice|Měděná Hlava|Havraní Skála|Hromová Hlava|Stříbrné Svítání|Železný Bastion|Vlčí Potok|Sokolí Hřeben|Granitový Štít|Železný Přístav|Rudá Mesa|Soumrak|Vysoká Hlídka|Železná Nadvláda|Bouřná Pevnost|Černý Vrchol|Mrazivý Bod|Orlí Hřeben|Železná Citadela|Pád Stínu|Severní Bod|Ocelový Hřeben|Železný Horizont|Rudá Hlídka|Tichý Vrchol|Granitové Svítání|Bouřný Hřeben|Železné Odhodlání|Vlčí Hřeben|Černý Přístav|Sokolí Hlídka|Stříbrný Hřeben|Železný Útes|Žhavý Hřeben|Studený Přístav|Železný Hrom|Vrchol Strážce|Rudé Údolí|Granitový Bod|Bouřná Fronta|Železná Koruna|Jestřábí Hřeben|Černý Kámen|Mrazivý Hřeben|Železný Pozorovací Bod|Stříbrný Horizont|Hromová Hlídka|Železná Bastila|Stínový Bod|Ocelový Vrchol + 铁壁|先锋|决意|雷霆岭|自由冠|哨兵|花岗守望|猎隼之境|赤石|黑水|统御|银枪|铁峰|破风暴|鹰栖|霜港|暗影岭|铁木|高点|战域|不屈|勇武|冷水|堡垒|花岗隘口|火炬|铁谷|瞭望塔|余烬坠|鹰隼着陆|黑岭|银溪|北风|绯红崖|石墙|泰坦|赤色天际|铁守|蓝台地|边境|铁巅|钢港|白岭|先锋高地|铁港|风暴守望|灰哨|黑曜点|铁前线|铜头|渡鸦岩|雷顶|银曙|铁堡|狼溪|猎隼冠|花岗盾|铁港湾|红台地|夜幕|高哨|铁统御|风暴堡|黑峰|霜点|鹰冠|铁要塞|影坠|北点|钢岭|铁天际|红守|静峰|花岗曙|风暴岭|铁决意|狼岭|黑港|猎隼守|银岭|铁崖|余烬岭|冷港|铁雷|哨峰|红谷|花岗点|风暴前沿|铁冠|鹰岭|黑石|霜岭|铁观察点|银天际|雷守|铁巴士底|影点|钢峰 + 철벽|전위|결의|천둥능선|자유마루|센티널|화강암감시|팔콘리치|레드스톤|블랙워터|도미니언|실버스피어|아이언서밋|스톰브레이커|이글레스트|프로스트헤이븐|섀도리지|아이언우드|하이포인트|워필드|스테드패스트|밸러|콜드워터|바스티온|화강암고개|토치라이트|아이언베일|워치타워|엠버폴|호크랜딩|블랙리지|실버크릭|노스윈드|크림슨블러프|스톤월|타이탄|레드호라이즌|아이언워치|블루메사|프런티어|아이언피크|스틸헤이븐|화이트리지|뱅가드하이츠|아이언헤이븐|스톰워치|그레이센티널|옵시디언포인트|아이언프런티어|코퍼헤드|레이븐록|선더헤드|실버던|아이언바스티온|울프크릭|팔콘크레스트|그래나이트실드|아이언하버|레드메사|나이트폴|하이센티널|아이언도미니언|스톰홀드|블랙서밋|프로스트포인트|이글크레스트|아이언시타델|섀도폴|노스포인트|스틸리지|아이언호라이즌|레드워치|사일런트피크|그래나이트던|스톰리지|아이언리졸브|울프리지|블랙하버|팔콘워치|실버리지|아이언클리프|엠버리지|콜드하버|아이언선더|센티널피크|레드밸리|그래나이트포인트|스톰프런트|아이언크라운|호크리지|블랙스톤|프로스트리지|아이언워치포인트|실버호라이즌|선더워치|아이언바스틸|섀도포인트|스틸서밋 + Roccaforte di Ferro|Avanguardia|Risoluto|Cresta del Tuono|Cima della Libertà|Sentinella|Guardia di Granito|Portata del Falco|Pietrarossa|Acque Nere|Dominio|Lancia d’Argento|Vetta di Ferro|Spezza-Tempesta|Riposo dell’Aquila|Rifugio di Ghiaccio|Cresta d’Ombra|Bosco di Ferro|Punto Alto|Campo di Guerra|Incrollabile|Valore|Acque Fredde|Bastione|Passo di Granito|Luce di Torcia|Valle di Ferro|Torre di Guardia|Caduta di Brace|Approdo del Falco|Cresta Nera|Ruscello d’Argento|Vento del Nord|Falesia Cremisi|Muro di Pietra|Titano|Orizzonte Rosso|Guardia di Ferro|Mesa Blu|Frontiera|Picco di Ferro|Rifugio d’Acciaio|Cresta Bianca|Alture Avanguardia|Rifugio di Ferro|Guardia Tempesta|Sentinella Grigia|Punto d’Ossidiana|Frontiera di Ferro|Testa di Rame|Roccia del Corvo|Testa del Tuono|Alba d’Argento|Bastione di Ferro|Ruscello del Lupo|Cresta del Falco|Scudo di Granito|Porto di Ferro|Mesa Rossa|Calare della Notte|Alta Sentinella|Dominio di Ferro|Forte Tempesta|Vetta Nera|Punto di Gelo|Cresta dell’Aquila|Cittadella di Ferro|Caduta d’Ombra|Punta Nord|Cresta d’Acciaio|Orizzonte di Ferro|Guardia Rossa|Picco Silente|Alba di Granito|Cresta Tempesta|Ferro Risoluto|Cresta del Lupo|Porto Nero|Guardia del Falco|Cresta d’Argento|Falesia di Ferro|Cresta di Brace|Porto Freddo|Tuono di Ferro|Picco Sentinella|Valle Rossa|Punto di Granito|Fronte Tempesta|Corona di Ferro|Cresta del Falco|Pietra Nera|Cresta di Gelo|Punto di Vedetta Ferro|Orizzonte d’Argento|Guardia del Tuono|Bastiglia di Ferro|Punto d’Ombra|Vetta d’Acciaio + Fortaleza de Hierro|Vanguardia|Resuelto|Cresta del Trueno|Cima de la Libertad|Centinela|Vigía de Granito|Alcance del Halcón|Piedra Roja|Aguas Negras|Dominio|Lanza de Plata|Cima de Hierro|Rompe-Tormentas|Descanso del Águila|Refugio Helado|Cresta Sombría|Bosque de Hierro|Punto Alto|Campo de Guerra|Inquebrantable|Valor|Aguas Frías|Bastión|Paso de Granito|Antorcha|Valle de Hierro|Torre Vigía|Caída de Brasas|Aterrizaje del Halcón|Cresta Negra|Arroyo de Plata|Viento del Norte|Risco Carmesí|Muralla de Piedra|Titán|Horizonte Rojo|Vigía de Hierro|Mesa Azul|Frontera|Pico de Hierro|Refugio de Acero|Cresta Blanca|Alturas Vanguardia|Refugio de Hierro|Vigía de Tormenta|Centinela Gris|Punta Obsidiana|Frontera de Hierro|Cabeza de Cobre|Roca del Cuervo|Cabeza del Trueno|Alba de Plata|Bastión de Hierro|Arroyo del Lobo|Cresta del Halcón|Escudo de Granito|Puerto de Hierro|Mesa Roja|Ocaso|Alto Centinela|Dominio de Hierro|Fuerte Tormenta|Cima Negra|Punto Helado|Cresta del Águila|Ciudadela de Hierro|Caída Sombría|Punta Norte|Cresta de Acero|Horizonte de Hierro|Vigía Roja|Pico Silente|Alba de Granito|Cresta Tormenta|Hierro Resuelto|Cresta del Lobo|Puerto Negro|Vigía del Halcón|Cresta de Plata|Acantilado de Hierro|Cresta de Brasas|Puerto Frío|Trueno de Hierro|Pico Centinela|Valle Rojo|Punta de Granito|Frente de Tormenta|Corona de Hierro|Cresta del Halcón|Piedra Negra|Cresta Helada|Punto de Vigía de Hierro|Horizonte de Plata|Vigía del Trueno|Bastilla de Hierro|Punta Sombría|Cima de Acero + Żelazna Twierdza|Awangarda|Niezłomny|Grzmotny Grzbiet|Grań Wolności|Strażnik|Granitowa Warta|Zasięg Sokoła|Czerwony Kamień|Czarne Wody|Dominion|Srebrna Włócznia|Żelazny Szczyt|Łamacz Burz|Orli Spoczynek|Mroźna Przystań|Cienisty Grzbiet|Żelazny Las|Wysoki Punkt|Pole Bitwy|Niewzruszony|Męstwo|Zimne Wody|Bastion|Granitowa Przełęcz|Pochodnia|Żelazna Dolina|Wieża Straży|Żaropad|Lądowisko Jastrzębia|Czarny Grzbiet|Srebrny Potok|Północny Wiatr|Szkarłatny Urwisko|Kamienny Mur|Tytan|Czerwony Horyzont|Żelazna Warta|Niebieska Mesa|Pogranicze|Żelazny Szczyt|Stalowa Przystań|Biała Grań|Wzgórza Awangardy|Żelazna Przystań|Warta Burzy|Szary Strażnik|Obsydianowy Punkt|Żelazne Pogranicze|Miedziogłowy|Krucza Skała|Gromogłowy|Srebrny Świt|Żelazny Bastion|Wilczy Potok|Sokoli Grzbiet|Granitowa Tarcza|Żelazny Port|Czerwona Mesa|Zmierzch|Wysoki Strażnik|Żelazne Dominion|Twierdza Burzy|Czarny Szczyt|Mroźny Punkt|Orli Grzbiet|Żelazna Cytadela|Cienisty Zmierzch|Północny Punkt|Stalowy Grzbiet|Żelazny Horyzont|Czerwona Warta|Cichy Szczyt|Granitowy Świt|Burzowy Grzbiet|Żelazna Determinacja|Wilczy Grzbiet|Czarny Port|Sokola Warta|Srebrny Grzbiet|Żelazny Klif|Żarzący Grzbiet|Zimny Port|Żelazny Grzmot|Szczyt Strażnika|Czerwona Dolina|Granitowy Punkt|Front Burzy|Żelazna Korona|Jastrzębi Grzbiet|Czarny Kamień|Mroźny Grzbiet|Żelazny Punkt Obserwacyjny|Srebrny Horyzont|Warta Gromu|Żelazna Bastyliа|Cienisty Punkt|Stalowy Szczyt + + + Dreadnought|Iron Sentinel|Crimson Bastion|Stormhold|Ravencrest|Steel Horizon|Thunderfall|Blackreach|Stoneguard|Emberwatch|Grimward|Frostguard|Ironcliff|Nightwatch|Redspire|Stormspire|Graywatch|Ironmoor|Wolfguard|Highwatch|Shadowmoor|Coldfire|Bronze Citadel|Ashen Ridge|Iron Vanguard|Falconspire|Blackridge Hold|Stormguard|Steel Bastion|Redwatch Point|Ironhaven Reach|Frostspire|Thunderpoint|Obsidian Ridge|Granitestone|Ironward|Crimson Watch|Northguard|Shadowspire|Iron Summit Reach|Wolfspire|Stormward|Blackstone Hold|Emberguard|Silverwatch|Ironfront|Dusk Ridge|Steelwatch|Redhold|Highspire + Дредноут|Железный Страж|Багровый Бастион|Штормовая Твердыня|Вороний Гребень|Стальной Горизонт|Громопад|Чёрный Предел|Каменный Страж|Пепельный Дозор|Мрачный Рубеж|Морозный Страж|Железный Утёс|Ночной Дозор|Красный Шпиль|Штормовой Шпиль|Серый Дозор|Железная Пустошь|Волчий Страж|Высокий Дозор|Теневая Пустошь|Холодное Пламя|Бронзовая Цитадель|Пепельный Хребет|Железный Авангард|Соколиный Шпиль|Чёрный Кряж Твердыня|Штормовой Страж|Стальной Бастион|Красный Дозорный Пункт|Железная Гавань Рубеж|Морозный Шпиль|Громовая Точка|Обсидиановый Хребет|Гранитный Камень|Железный Рубеж|Багровый Дозор|Северный Страж|Теневой Шпиль|Железная Вершина Рубеж|Волчий Шпиль|Штормовой Рубеж|Чёрный Камень Твердыня|Пепельный Страж|Серебряный Дозор|Железный Фронт|Сумеречный Хребет|Стальной Дозор|Красная Твердыня|Высокий Шпиль + Cuirassé|Sentinelle de Fer|Bastion Pourpre|Fort Tempête|Crête du Corbeau|Horizon d’Acier|Chute du Tonnerre|Portée Noire|Garde de Pierre|Veille des Braises|Garde Sombre|Garde de Givre|Falaise de Fer|Veille de Nuit|Aiguille Rouge|Aiguille de Tempête|Veille Grise|Marais de Fer|Garde du Loup|Haute Veille|Marais d’Ombre|Feu Froid|Citadelle de Bronze|Crête Cendrée|Avant-Garde de Fer|Aiguille du Faucon|Fort Noir-Crête|Garde de Tempête|Bastion d’Acier|Pointe Veille Rouge|Portée de Fer-Havre|Aiguille de Givre|Pointe du Tonnerre|Crête Obsidienne|Pierre de Granit|Garde-Fer|Veille Pourpre|Garde du Nord|Aiguille d’Ombre|Portée Sommet de Fer|Aiguille du Loup|Garde-Bourrasque|Fort Noir-Pierre|Garde des Braises|Veille d’Argent|Front de Fer|Crête du Crépuscule|Veille d’Acier|Fort Rouge|Haute Aiguille + Dreadnought|Eisenwächter|Purpurbastion|Sturmfeste|Rabenkranz|Stahlhorizont|Donnerfall|Schwarzrand|Steinwacht|Glutwacht|Düsterwacht|Frostwacht|Eisenkliff|Nachtwacht|Rotspitze|Sturmspitze|Grauwacht|Eisenmoor|Wolfwacht|Hochwacht|Schattenmoor|Kaltfeuer|Bronzezitadelle|Aschengrat|Eisenvorhut|Falkenspitze|Schwarzgrat-Feste|Sturmwacht|Stahlbastion|Rotwachtpunkt|Eisenhafen-Reich|Frostspitze|Donnerpunkt|Obsidiangrat|Granitstein|Eisenwacht|Purpurwacht|Nordwacht|Schattenstachel|Eisengipfel-Reich|Wolfstachel|Sturmwachtung|Schwarzstein-Feste|Glutwacht|Silberwacht|Eisenfront|Dämmergrat|Stahlwacht|Rotfeste|Hochstachel + Dreadnought|Železný Strážce|Karmínový Bastion|Bouřná Pevnost|Havraní Hřeben|Ocelový Horizont|Hromopád|Černý Dosah|Kamenná Stráž|Žhavá Hlídka|Ponurá Hlídka|Mrazová Stráž|Železný Útes|Noční Hlídka|Rudý Špičák|Bouřný Špičák|Šedá Hlídka|Železné Močály|Vlčí Stráž|Vysoká Hlídka|Stínové Močály|Studený Oheň|Bronzová Citadela|Popelavý Hřeben|Železný Předvoj|Sokolí Špičák|Černý Hřeben Pevnost|Bouřná Stráž|Ocelový Bastion|Bod Rudé Hlídky|Železný Přístav Dosah|Mrazový Špičák|Hromový Bod|Obsidiánový Hřeben|Granitový Kámen|Železná Hlídka|Karmínová Hlídka|Severní Stráž|Stínový Špičák|Dosah Železného Vrcholu|Vlčí Špičák|Bouřná Hlídka|Černý Kámen Pevnost|Žhavá Stráž|Stříbrná Hlídka|Železná Fronta|Soumračný Hřeben|Ocelová Hlídka|Rudá Pevnost|Vysoký Špičák + 无畏|铁哨|绯红堡垒|风暴堡|渡鸦冠|钢天际|雷落|黑域|石卫|余烬守望|冷酷卫|霜卫|铁崖|夜守|赤尖|风暴尖|灰守|铁沼|狼卫|高守|影沼|冷焰|青铜要塞|灰烬岭|铁先锋|猎隼尖|黑岭堡|风暴卫|钢堡|红守点|铁港之境|霜尖|雷点|黑曜岭|花岗石|铁卫|绯红守|北卫|影尖|铁峰之境|狼尖|风暴卫戍|黑石堡|余烬卫|银守|铁前线|暮色岭|钢守|红堡|高尖 + 드레드노트|아이언센티널|크림슨바스티온|스톰홀드|레이븐크레스트|스틸호라이즌|선더폴|블랙리치|스톤가드|엠버워치|그림워드|프로스트가드|아이언클리프|나이트워치|레드스파이어|스톰스파이어|그레이워치|아이언무어|울프가드|하이워치|섀도무어|콜드파이어|브론즈시타델|애신리지|아이언뱅가드|팔콘스파이어|블랙리지홀드|스톰가드|스틸바스티온|레드워치포인트|아이언헤이븐리치|프로스트스파이어|선더포인트|옵시디언리지|그래나이트스톤|아이언워드|크림슨워치|노스가드|섀도스파이어|아이언서밋리치|울프스파이어|스톰워드|블랙스톤홀드|엠버가드|실버워치|아이언프런트|더스크리지|스틸워치|레드홀드|하이스파이어 + Corazzata|Sentinella di Ferro|Bastione Cremisi|Forte Tempesta|Cresta del Corvo|Orizzonte d’Acciaio|Caduta del Tuono|Confine Nero|Guardia di Pietra|Guardia delle Braci|Presidio Cupo|Guardia del Gelo|Falesia di Ferro|Guardia Notturna|Guglia Rossa|Guglia di Tempesta|Guardia Grigia|Palude di Ferro|Guardia del Lupo|Alta Guardia|Palude d’Ombra|Fuoco Freddo|Citadella di Bronzo|Cresta Cinerea|Avanguardia di Ferro|Guglia del Falco|Forte Nero-Cresta|Guardia di Tempesta|Bastione d’Acciaio|Punto Guardia Rossa|Portata di Ferro-Haven|Guglia del Gelo|Punta del Tuono|Cresta d’Ossidiana|Pietra di Granito|Presidio di Ferro|Guardia Cremisi|Guardia del Nord|Guglia d’Ombra|Portata del Sommet di Ferro|Guglia del Lupo|Presidio di Tempesta|Forte Pietranera|Guardia delle Braci|Guardia d’Argento|Fronte di Ferro|Cresta del Crepuscolo|Guardia d’Acciaio|Forte Rosso|Alta Guglia + Acorazado|Centinela de Hierro|Bastión Carmesí|Fuerte Tormenta|Cresta del Cuervo|Horizonte de Acero|Caída del Trueno|Alcance Negro|Guardia de Piedra|Vigía de Brasas|Guardián Sombrío|Guardia de Escarcha|Acantilado de Hierro|Vigía Nocturna|Aguja Roja|Aguja de Tormenta|Vigía Gris|Páramo de Hierro|Guardia del Lobo|Alta Vigía|Páramo Sombrío|Fuego Frío|Ciudadela de Bronce|Cresta Ceniza|Vanguardia de Hierro|Aguja del Halcón|Fuerte Cresta Negra|Guardia de Tormenta|Bastión de Acero|Punto Vigía Roja|Alcance de Puerto Hierro|Aguja de Escarcha|Punto del Trueno|Cresta Obsidiana|Piedra de Granito|Guardia de Hierro|Vigía Carmesí|Guardia del Norte|Aguja Sombría|Alcance Cima de Hierro|Aguja del Lobo|Guardia de Tempestad|Fuerte Piedra Negra|Guardia de Brasas|Vigía de Plata|Frente de Hierro|Cresta del Ocaso|Vigía de Acero|Fuerte Rojo|Alta Aguja + Pancernik|Żelazny Strażnik|Szkarłatny Bastion|Twierdza Burzy|Krucza Grań|Stalowy Horyzont|Gromopad|Czarny Zasięg|Kamienna Straż|Żarowa Warta|Ponury Posterunek|Mroźna Straż|Żelazny Klif|Nocna Warta|Czerwony Kolec|Burzowy Kolec|Szara Warta|Żelazne Mokradła|Wilcza Straż|Wysoka Warta|Cieniste Mokradła|Zimny Ogień|Brązowa Cytadela|Popielaty Grzbiet|Żelazna Awangarda|Sokoli Kolec|Czarny Grzbiet Twierdza|Burzowa Straż|Stalowy Bastion|Punkt Czerwonej Warty|Zasięg Żelaznej Przystani|Mroźny Kolec|Punkt Gromu|Obsydianowy Grzbiet|Granitowy Kamień|Żelazny Posterunek|Szkarłatna Warta|Północna Straż|Cienisty Kolec|Zasięg Żelaznego Szczytu|Wilczy Kolec|Burzowy Posterunek|Czarny Kamień Twierdza|Żarowa Straż|Srebrna Warta|Żelazny Front|Zmierzchowy Grzbiet|Stalowa Warta|Czerwona Twierdza|Wysoki Kolec + + + Skywatch|Iron Runway|Falcon Field|Storm Airstrip|Eagle Crest Field|Highwind Base|Thunder Run|Cloudbreak Field|Skyguard|Raven Airfield|Steel Wing|Northwind Field|Red Sky Station|Ironhawk|Blue Horizon Field|Stormflight|Silver Wing Field|Skyhold|Crimson Skies|Iron Flightline|Falcon Reach Field|Highpoint Airstrip|Shadow Wing|Frostwind Field|Stratos Watch + Небесный Дозор|Железная Взлётная Полоса|Соколиное Поле|Штормовая ВПП|Поле Орлиного Гребня|База Высоких Ветров|Громовой Разбег|Поле Прорыва Облаков|Небесный Страж|Вороний Аэродром|Стальное Крыло|Поле Северного Ветра|Станция Красного Неба|Железный Ястреб|Поле Синего Горизонта|Штормовой Полёт|Поле Серебряного Крыла|Небесная Твердыня|Багровые Небеса|Железная Линия Полёта|Поле Соколиного Рубежа|Высотная ВПП|Теневое Крыло|Поле Морозного Ветра|Стратосферный Дозор + Veille du Ciel|Piste de Fer|Terrain du Faucon|Bande Tempête|Terrain Crête de l’Aigle|Base Haut-Vent|Course du Tonnerre|Terrain Brise-Nuages|Garde du Ciel|Aérodrome du Corbeau|Aile d’Acier|Terrain Vent du Nord|Station Ciel Rouge|Faucon de Fer|Terrain Horizon Bleu|Vol Tempête|Terrain Aile d’Argent|Fort Céleste|Cieux Pourpres|Ligne de Vol de Fer|Terrain Portée du Faucon|Bande Haut-Point|Aile d’Ombre|Terrain Vent de Givre|Veille Stratos + Himmelswacht|Eisenpiste|Falkenfeld|Sturmpiste|Adlerkamm-Feld|Hochwind-Basis|Donnerlauf|Wolkenbruch-Feld|Himmelswache|Rabenflugplatz|Stahlflügel|Nordwind-Feld|Rothimmel-Station|Eisenhabicht|Blauhorizont-Feld|Sturmflug|Silberflügel-Feld|Himmelsfeste|Purpurhimmel|Eisenfluglinie|Falkenreich-Feld|Hochpunkt-Piste|Schattenflügel|Frostwind-Feld|Stratoswacht + Nebeská Hlídka|Železná Dráha|Sokolí Letiště|Bouřná Dráha|Letiště Orlího Hřebene|Základna Vysokých Větrů|Hromový Rozběh|Letiště Průlom Mraků|Nebeský Strážce|Havraní Letiště|Ocelové Křídlo|Letiště Severního Větru|Stanice Rudé Oblohy|Železný Jestřáb|Letiště Modrého Horizontu|Bouřný Let|Letiště Stříbrného Křídla|Nebeská Pevnost|Karmínová Nebesa|Železná Letová Linie|Letiště Sokolího Dosahu|Dráha Vyhlídky|Stínové Křídlo|Letiště Mrazivého Větru|Stratosférická Hlídka + 天际守望|铁跑道|猎隼机场|风暴简易机场|鹰冠机场|高风基地|雷霆跑道|破云机场|天空卫|渡鸦机场|钢翼|北风机场|红天站|铁鹰|蓝天际机场|风暴航线|银翼机场|天空堡|绯红苍穹|铁航线|猎隼之境机场|高点跑道|影翼|霜风机场|平流层守望 + 스카이워치|아이언런웨이|팔콘필드|스톰에어스트립|이글크레스트필드|하이윈드기지|선더런|클라우드브레이크필드|스카이가드|레이븐에어필드|스틸윙|노스윈드필드|레드스카이스테이션|아이언호크|블루호라이즌필드|스톰플라이트|실버윙필드|스카이홀드|크림슨스카이즈|아이언플라이트라인|팔콘리치필드|하이포인트에어스트립|섀도윙|프로스트윈드필드|스트라토스워치 + Vedetta del Cielo|Pista di Ferro|Campo del Falco|Pista Tempesta|Campo Cresta dell’Aquila|Base Alto Vento|Corsa del Tuono|Campo Spacca-Nuvole|Guardia del Cielo|Campo del Corvo|Ala d’Acciaio|Campo Vento del Nord|Stazione Cielo Rosso|Falco di Ferro|Campo Orizzonte Blu|Volo Tempesta|Campo Ala d’Argento|Forte del Cielo|Cieli Cremisi|Linea di Volo di Ferro|Campo Portata del Falco|Pista Alto Punto|Ala d’Ombra|Campo Vento di Gelo|Vedetta Stratos + Vigía del Cielo|Pista de Hierro|Campo del Halcón|Pista Tormenta|Campo Cresta del Águila|Base Alto Viento|Carrera del Trueno|Campo Rompe-Nubes|Guardia del Cielo|Aeródromo del Cuervo|Ala de Acero|Campo Viento del Norte|Estación Cielo Rojo|Halcón de Hierro|Campo Horizonte Azul|Vuelo Tormenta|Campo Ala de Plata|Fuerte del Cielo|Cielos Carmesí|Línea de Vuelo de Hierro|Campo Alcance del Halcón|Pista Alto Punto|Ala Sombría|Campo Viento Helado|Vigía Estratos + Niebiańska Warta|Żelazny Pas|Sokole Pole|Burzowy Pas|Pole Orlej Grani|Baza Wysokiego Wiatru|Gromowy Rozbieg|Pole Przebicia Chmur|Straż Nieba|Krukowe Lotnisko|Stalowe Skrzydło|Pole Północnego Wiatru|Stacja Czerwonego Nieba|Żelazny Jastrząb|Pole Błękitnego Horyzontu|Burzowy Lot|Pole Srebrnego Skrzydła|Niebiańska Twierdza|Szkarłatne Niebo|Żelazna Linia Lotu|Pole Sokolego Zasięgu|Pas Wysokiego Punktu|Cieniste Skrzydło|Pole Mroźnego Wiatru|Warta Stratosfery + + + Harborwatch|Iron Harbor|Storm Anchorage|Blackwater Quay|Seaguard|Breakwater Point|Red Tide Port|Deepwater Bastion|Anchorhold|Bluewater Station|Harbormaster|Iron Anchorage|Storm Pier|Seawatch|Northport Reach|Harbor Sentinel|Graywater Dockyard|Crimson Anchorage|Wavecrest Port|Steel Wharf|Outer Harbor|Trident Point|Seagate|Harbor Bastion|Black Reef Port|Stormbreak Harbor|Ironclad Quay|Saltwind Port|Harborfront|Deepwave Anchorage|Redwater Pier|Frost Harbor|Tidewatch|Seabastion|Anchorpoint|Harbor Reach|Westport Sentinel|Blue Harbor|Iron Dockyard|Stormtide Port|Highwater Quay|Sea Shield|Harbor Crown|Northwater Pier|Granite Harbor|Waveguard|Southport Watch|Trident Harbor|Coldwater Anchorage|Iron Breakwater + Портовый Дозор|Железная Гавань|Штормовая Якорная Стоянка|Причал Чёрных Вод|Морской Страж|Мыс Волнолома|Порт Красного Прилива|Глубоководный Бастион|Якорная Твердыня|Станция Синих Вод|Начальник Порта|Железная Якорная Стоянка|Штормовой Пирс|Морской Дозор|Северный Порт Рубеж|Страж Гавани|Серые Воды Верфь|Багровая Якорная Стоянка|Порт Гребня Волны|Стальной Причал|Внешняя Гавань|Мыс Трезубца|Морские Ворота|Портовый Бастион|Порт Чёрного Рифа|Гавань Штормового Прорыва|Железный Причал|Порт Солёного Ветра|Портовый Фронт|Глубинная Якорная Стоянка|Пирс Красных Вод|Морозная Гавань|Дозор Прилива|Морской Бастион|Якорная Точка|Рубеж Гавани|Страж Западного Порта|Синяя Гавань|Железная Верфь|Порт Штормового Прилива|Причал Высокой Воды|Морской Щит|Корона Гавани|Северный Пирс|Гранитная Гавань|Страж Волны|Дозор Южного Порта|Гавань Трезубца|Холодная Якорная Стоянка|Железный Волнолом + Veille du Port|Port de Fer|Mouillage Tempête|Quai Eaux Noires|Garde de Mer|Pointe du Brise-Lames|Port Marée Rouge|Bastion Grand-Large|Fort Ancre|Station Eaux Bleues|Capitainerie|Mouillage de Fer|Jetée Tempête|Veille de Mer|Port Nord Portée|Sentinelle du Port|Chantier Eaux Grises|Mouillage Pourpre|Port Crête des Vagues|Quai d’Acier|Avant-Port|Pointe du Trident|Porte de Mer|Bastion du Port|Port Récif Noir|Port Brise-Tempête|Quai Ironclad|Port Vent Salé|Front de Quai|Mouillage Vague-Profonde|Jetée Eaux Rouges|Port de Givre|Veille des Marées|Bastion Marin|Pointe d’Ancre|Portée du Port|Sentinelle Ouest-Port|Port Bleu|Chantier de Fer|Port Marée-Tempête|Quai Hautes Eaux|Bouclier Marin|Couronne du Port|Jetée Nord-Eaux|Port Granit|Garde des Vagues|Veille Sud-Port|Port Trident|Mouillage Eaux Froides|Brise-Lames de Fer + Hafenwacht|Eisenhafen|Sturmankerplatz|Schwarzwasser-Kai|Seewacht|Wellenbrecher-Punkt|Rotflut-Hafen|Tiefwasser-Bastion|Ankerfeste|Blauwasser-Station|Hafenmeister|Eisenankerplatz|Sturmsteg|Seewacht|Nordport-Reich|Hafenwächter|Grauwasser-Werft|Purpurankerplatz|Wellenkamm-Hafen|Stahlpier|Außenhafen|Dreizack-Punkt|Seetor|Hafenbastion|Schwarzes-Riff-Hafen|Sturmbruch-Hafen|Eisenpanzer-Kai|Salzwind-Hafen|Hafenvorfeld|Tiefwellen-Ankerplatz|Rotwasser-Steg|Frosthafen|Gezeitenwacht|Seebastion|Ankerpunkt|Hafenreich|Westport-Wächter|Blauhafen|Eisendock|Sturmflut-Hafen|Hochwasser-Kai|Seeschild|Hafenkrone|Nordwasser-Steg|Granit-Hafen|Wellenwacht|Südport-Wacht|Dreizack-Hafen|Kaltwasser-Ankerplatz|Eisenwellenbrecher + Přístavní Hlídka|Železný Přístav|Bouřné Kotviště|Molo Černých Vod|Mořská Stráž|Bod Vlnolamu|Přístav Rudého Přílivu|Hlubokovodní Bastion|Kotvící Pevnost|Stanice Modrých Vod|Správce Přístavu|Železné Kotviště|Bouřné Molo|Mořská Hlídka|Dosah Severního Přístavu|Přístavní Strážce|Loděnice Šedých Vod|Karmínové Kotviště|Přístav Hřbetu Vln|Ocelové Molo|Vnější Přístav|Bod Trojzubce|Mořská Brána|Přístavní Bastion|Přístav Černého Útesu|Přístav Bouřného Zlomu|Železný Kaj|Přístav Slaného Větru|Přístavní Fronta|Kotviště Hlubokých Vln|Molo Rudých Vod|Mrazivý Přístav|Hlídka Přílivu|Mořský Bastion|Kotvící Bod|Dosah Přístavu|Stráž Západního Přístavu|Modrý Přístav|Železná Loděnice|Přístav Bouřného Přílivu|Molo Vysokých Vod|Mořský Štít|Koruna Přístavu|Molo Severních Vod|Granitový Přístav|Stráž Vln|Hlídka Jižního Přístavu|Trojzubcový Přístav|Studené Kotviště|Železný Vlnolam + 港口守望|铁港|风暴锚地|黑水码头|海卫|防波点|红潮港|深水堡垒|锚固堡|蓝水站|港务官|铁锚地|风暴栈桥|海望|北港之境|港口哨|灰水船坞|绯红锚地|浪冠港|钢码头|外港|三叉点|海门|港口堡|黑礁港|破风暴港|铁甲码头|盐风港|港前沿|深浪锚地|红水栈桥|霜港|潮汐守望|海堡|锚点|港之境|西港哨|蓝港|铁船坞|风暴潮港|高水码头|海盾|港之冠|北水栈桥|花岗港|浪卫|南港望|三叉港|冷水锚地|铁防波 + 하버워치|아이언하버|스톰앵커리지|블랙워터키|시가드|브레이크워터포인트|레드타이드포트|딥워터바스티온|앵커홀드|블루워터스테이션|하버마스터|아이언앵커리지|스톰피어|시워치|노스포트리치|하버센티널|그레이워터도크야드|크림슨앵커리지|웨이브크레스트포트|스틸워프|아우터하버|트라이던트포인트|시게이트|하버바스티온|블랙리프포트|스톰브레이크하버|아이언클래드키|솔트윈드포트|하버프런트|딥웨이브앵커리지|레드워터피어|프로스트하버|타이드워치|시바스티온|앵커포인트|하버리치|웨스트포트센티널|블루하버|아이언도크야드|스톰타이드포트|하이워터키|시실드|하버크라운|노스워터피어|그래나이트하버|웨이브가드|사우스포트워치|트라이던트하버|콜드워터앵커리지|아이언브레이크워터 + Vedetta del Porto|Porto di Ferro|Ancoraggio Tempesta|Banchina Acque Nere|Guardia del Mare|Punta Frangiflutti|Porto Marea Rossa|Bastione Profondo|Forte Ancoraggio|Stazione Acque Blu|Capitano del Porto|Ancoraggio di Ferro|Molo Tempesta|Vedetta del Mare|Portata Porto Nord|Sentinella del Porto|Cantiere Acque Grigie|Ancoraggio Cremisi|Porto Cresta d’Onda|Banchina d’Acciaio|Porto Esterno|Punta Tridente|Porta del Mare|Bastione del Porto|Porto Scogliera Nera|Porto Spacca-Tempesta|Banchina Ironclad|Porto Vento Salato|Fronte Porto|Ancoraggio Onda Profonda|Molo Acque Rosse|Porto del Gelo|Vedetta di Marea|Bastione Marino|Punto d’Ancoraggio|Portata del Porto|Sentinella di Porto Ovest|Porto Blu|Cantiere di Ferro|Porto Marea di Tempesta|Banchina Alte Acque|Scudo del Mare|Corona del Porto|Molo Acque del Nord|Porto di Granito|Guardia delle Onde|Vedetta Porto Sud|Porto Tridente|Ancoraggio Acque Fredde|Frangiflutti di Ferro + Vigía del Puerto|Puerto de Hierro|Fondeadero Tormenta|Muelle Aguas Negras|Guardia del Mar|Punta Rompeolas|Puerto Marea Roja|Bastión de Aguas Profundas|Fuerte Ancla|Estación Aguas Azules|Capitán de Puerto|Fondeadero de Hierro|Muelle Tormenta|Vigía del Mar|Alcance Puerto Norte|Centinela del Puerto|Astillero Aguas Grises|Fondeadero Carmesí|Puerto Cresta de Ola|Muelle de Acero|Puerto Exterior|Punta Tridente|Puerta del Mar|Bastión del Puerto|Puerto Arrecife Negro|Puerto Rompe-Tormentas|Muelle Ironclad|Puerto Viento Salado|Frente del Puerto|Fondeadero Ola Profunda|Muelle Aguas Rojas|Puerto de Escarcha|Vigía de Marea|Bastión Marino|Punto de Ancla|Alcance del Puerto|Centinela Puerto Oeste|Puerto Azul|Astillero de Hierro|Puerto Marea de Tormenta|Muelle Alta Marea|Escudo del Mar|Corona del Puerto|Muelle Aguas del Norte|Puerto de Granito|Guardia de Olas|Vigía Puerto Sur|Puerto Tridente|Fondeadero Aguas Frías|Rompeolas de Hierro + Warta Portu|Żelazny Port|Kotwicowisko Burzy|Nabrzeże Czarnych Wód|Straż Morza|Punkt Falochronu|Port Czerwonego Przypływu|Bastion Głębin|Kotwiczna Twierdza|Stacja Błękitnych Wód|Bosman Portu|Żelazne Kotwicowisko|Molo Burzy|Morska Warta|Zasięg Portu Północnego|Portowy Strażnik|Stocznia Szarych Wód|Szkarłatne Kotwicowisko|Port Grzbietu Fali|Stalowe Nabrzeże|Zewnętrzny Port|Punkt Trójzębu|Brama Morza|Portowy Bastion|Port Czarnej Rafy|Port Sztormowego Przełomu|Żelazny Kaj|Port Słonego Wiatru|Front Portu|Kotwicowisko Głębokiej Fali|Molo Czerwonych Wód|Mroźny Port|Warta Pływów|Morski Bastion|Punkt Kotwicy|Zasięg Portu|Strażnik Portu Zachodniego|Błękitny Port|Żelazna Stocznia|Port Sztormowego Przypływu|Nabrzeże Wysokiej Wody|Morska Tarcza|Korona Portu|Molo Północnych Wód|Granitowy Port|Straż Fal|Warta Portu Południowego|Port Trójzębu|Kotwicowisko Zimnych Wód|Żelazny Falochron + + + <br /><t color='#CFCFCF'>Garrison: %1%2</t> + <br /><t color='#CFCFCF'>Garnison : %1%2</t> + <br /><t color='#CFCFCF'>Garnison: %1%2</t> + <br /><t color='#CFCFCF'>Posádka: %1%2</t> + <br /><t color='#CFCFCF'>驻军:%1%2</t> + <br /><t color='#CFCFCF'>주둔 병력: %1%2</t> + <br /><t color='#CFCFCF'>Гарнизон: %1%2</t> + <br /><t color='#CFCFCF'>Guarnigione: %1%2</t> + <br /><t color='#CFCFCF'>Guarnición: %1%2</t> + <br /><t color='#CFCFCF'>Garnizon: %1%2</t> + + + %1<br /><t color='#CFCFCF'>-Intelligence unavailable</t> + %1<br /><t color='#CFCFCF'>-Renseignements indisponibles</t> + %1<br /><t color='#CFCFCF'>-Keine Aufklärungsdaten verfügbar</t> + %1<br /><t color='#CFCFCF'>-Zpravodajské informace nejsou dostupné</t> + %1<br /><t color='#CFCFCF'>-情报不可用</t> + %1<br /><t color='#CFCFCF'>-정보 확보 불가</t> + %1<br /><t color='#CFCFCF'>-Разведданные недоступны</t> + %1<br /><t color='#CFCFCF'>-Dati di intelligence non disponibili</t> + %1<br /><t color='#CFCFCF'>-Inteligencia no disponible</t> + %1<br /><t color='#CFCFCF'>-Dane wywiadowcze niedostępne</t> + + + Resource Site<br /><t color='#CFCFCF'>Generates 300%1 every resource tick</t> + Site de ressources<br /><t color='#CFCFCF'>Génère 300%1 à chaque cycle de ressources</t> + Ressourcenstandort<br /><t color='#CFCFCF'>Erzeugt 300%1 pro Ressourcenzyklus</t> + Zdroj surovin<br /><t color='#CFCFCF'>Generuje 300%1 při každém cyklu zdrojů</t> + 资源点<br /><t color='#CFCFCF'>每个资源周期生成 300%1</t> + 자원 거점<br /><t color='#CFCFCF'>자원 주기마다 300%1 생성</t> + Ресурсная точка<br /><t color='#CFCFCF'>Производит 300%1 за каждый ресурсный цикл</t> + Sito Risorse<br /><t color='#CFCFCF'>Genera 300%1 a ogni ciclo risorse</t> + Sitio de Recursos<br /><t color='#CFCFCF'>Genera 300%1 en cada ciclo de recursos</t> + Punkt Surowców<br /><t color='#CFCFCF'>Generuje 300%1 przy każdym cyklu zasobów</t> + + + Factory<br /><t color='#CFCFCF'>Multiplies a single resource by 1.2 per factory</t> + Usine<br /><t color='#CFCFCF'>Multiplie une ressource par 1,2 par usine</t> + Fabrik<br /><t color='#CFCFCF'>Multipliziert eine Ressource pro Fabrik mit 1,2</t> + Továrna<br /><t color='#CFCFCF'>Násobí jeden zdroj hodnotou 1,2 za továrnu</t> + 工厂<br /><t color='#CFCFCF'>每座工厂将单一资源乘以 1.2</t> + 공장<br /><t color='#CFCFCF'>공장당 단일 자원을 1.2배로 증가</t> + Завод<br /><t color='#CFCFCF'>Умножает один ресурс на 1.2 за каждый завод</t> + Fabbrica<br /><t color='#CFCFCF'>Moltiplica una risorsa per 1,2 per fabbrica</t> + Fábrica<br /><t color='#CFCFCF'>Multiplica un recurso por 1,2 por fábrica</t> + Fabryka<br /><t color='#CFCFCF'>Mnoży jeden zasób przez 1,2 za każdą fabrykę</t> + + + When captured:<br />-Allows usage of stored air assets<br />-Enables the use of air supports + Une fois capturé :<br />-Permet l'utilisation des aéronefs stockés<br />-Active les soutiens aériens + Nach Einnahme:<br />-Erlaubt die Nutzung gespeicherter Luftfahrzeuge<br />-Ermöglicht Luftunterstützung + Po obsazení:<br />-Umožňuje použití uložených leteckých prostředků<br />-Povoluje leteckou podporu + 占领后:<br />-允许使用存储的空中载具<br />-启用空中支援 + 점령 시:<br />-저장된 항공 자산 사용 가능<br />-항공 지원 활성화 + После захвата:<br />-Позволяет использовать сохранённую авиацию<br />-Открывает доступ к авиационной поддержке + Una volta catturato:<br />-Permette l'uso dei mezzi aerei immagazzinati<br />-Abilita il supporto aereo + Al capturarlo:<br />-Permite usar los activos aéreos almacenados<br />-Habilita el apoyo aéreo + Po przejęciu:<br />-Pozwala używać przechowywanych środków lotniczych<br />-Odblokowuje wsparcie lotnicze + + + Destroyed site: population eliminated (no support) + Site détruit : population éliminée (aucun soutien) + Zerstörter Standort: Bevölkerung ausgelöscht (keine Unterstützung) + Zničené místo: populace zlikvidována (bez podpory) + 已摧毁地点:人口已消灭(无支持) + 파괴된 지역: 인구 제거됨 (지원 없음) + Уничтоженный объект: население уничтожено (поддержки нет) + Sito distrutto: popolazione eliminata (nessun supporto) + Sitio destruido: población eliminada (sin apoyo) + Zniszczone miejsce: populacja wyeliminowana (brak wsparcia) + + + Cannot fast travel to a destroyed military administration. + Cannot fast travel to a destroyed military administration. + Zu einer zerstörten Militärverwaltung ist keine Schnellreise möglich. + Impossible de voyager rapidement vers une administration militaire détruite. + No se puede viajar rápido a una administración militar destruida. + Impossibile viaggiare rapidamente verso un’amministrazione militare distrutta. + Nie można odbyć szybkiej podróży do zniszczonej administracji wojskowej. + Нельзя быстро переместиться к разрушенной военной администрации. + Nelze rychle cestovat do zničené vojenské správy. + Yok edilmiş bir askerî idareye hızlı seyahat edilemez. + 无法快速前往已被摧毁的军事管理区。 + 破壊された軍政施設にはファストトラベルできません。 + + + Population: %1<br />Support — Rebels: %2%% (%3)<br />Support — Government: %4%% (%5)<br />To gain more support capture surrounding zones and/or deliver supplies + Population : %1<br />Soutien — Rebelles : %2%% (%3)<br />Soutien — Gouvernement : %4%% (%5)<br />Pour augmenter le soutien, capturez les zones voisines et/ou livrez des fournitures + Bevölkerung: %1<br />Unterstützung — Rebellen: %2%% (%3)<br />Unterstützung — Regierung: %4%% (%5)<br />Für mehr Unterstützung umliegende Zonen erobern und/oder Nachschub liefern + Populace: %1<br />Podpora — Povstalci: %2%% (%3)<br />Podpora — Vláda: %4%% (%5)<br />Pro zvýšení podpory obsazujte okolní zóny a/nebo doručujte zásoby + 人口:%1<br />支持度 — 叛军:%2%% (%3)<br />支持度 — 政府:%4%% (%5)<br />要获得更多支持,请占领周边区域和/或运送补给 + 인구: %1<br />지지도 — 반군: %2%% (%3)<br />지지도 — 정부: %4%% (%5)<br />지지도를 높이려면 주변 지역을 점령하거나 보급품을 전달하세요 + Население: %1<br />Поддержка — Повстанцы: %2%% (%3)<br />Поддержка — Правительство: %4%% (%5)<br />Чтобы увеличить поддержку, захватывайте соседние зоны и/или доставляйте припасы + Popolazione: %1<br />Supporto — Ribelli: %2%% (%3)<br />Supporto — Governo: %4%% (%5)<br />Per aumentare il supporto cattura le zone circostanti e/o consegna rifornimenti + Población: %1<br />Apoyo — Rebeldes: %2%% (%3)<br />Apoyo — Gobierno: %4%% (%5)<br />Para ganar más apoyo captura zonas cercanas y/o entrega suministros + Populacja: %1<br />Poparcie — Rebelianci: %2%% (%3)<br />Poparcie — Rząd: %4%% (%5)<br />Aby zwiększyć poparcie przejmuj okoliczne strefy i/lub dostarczaj zaopatrzenie + + + %1 Headquarters + Quartier Général %1 + %1 Hauptquartier + Velitelství %1 + %1 总部 + %1 본부 + Штаб %1 + Quartier Generale %1 + Cuartel General %1 + Kwatera Główna %1 + + + Respawn location<br /><t color='#CFCFCF'>- Here you can request missions, access garage and change game settings. + Point de réapparition<br /><t color='#CFCFCF'>- Ici, vous pouvez demander des missions, accéder au garage et modifier les paramètres du jeu. + Respawn-Punkt<br /><t color='#CFCFCF'>- Hier können Missionen angefordert, die Garage genutzt und Spieleinstellungen geändert werden. + Místo znovuzrození<br /><t color='#CFCFCF'>- Zde můžete žádat o mise, vstoupit do garáže a měnit nastavení hry. + 重生点<br /><t color='#CFCFCF'>- 在这里可以请求任务、进入车库并更改游戏设置。 + 리스폰 위치<br /><t color='#CFCFCF'>- 여기에서 임무를 요청하고, 차고에 접근하며, 게임 설정을 변경할 수 있습니다. + Точка возрождения<br /><t color='#CFCFCF'>- Здесь можно запрашивать задания, пользоваться гаражом и изменять настройки игры. + Punto di respawn<br /><t color='#CFCFCF'>- Qui puoi richiedere missioni, accedere al garage e modificare le impostazioni di gioco. + Punto de reaparición<br /><t color='#CFCFCF'>- Aquí puedes solicitar misiones, acceder al garaje y cambiar la configuración del juego. + Punkt odrodzenia<br /><t color='#CFCFCF'>- Tutaj możesz przyjmować misje, korzystać z garażu i zmieniać ustawienia gry. + + + Black Market Trader + Marché Noir + Schwarzmarkthändler + Obchodník na černém trhu + 黑市商人 + 암시장 상인 + Торговец чёрного рынка + Mercante del Mercato Nero + Comerciante del Mercado Negro + Handlarz z Czarnego Rynku + + + Buy and sell equipment here<br /><t color='#CFCFCF'>To unlock more vehicles capture more zones. + Achetez et vendez de l'équipement ici<br /><t color='#CFCFCF'>Pour débloquer plus de véhicules, capturez davantage de zones. + Hier Ausrüstung kaufen und verkaufen<br /><t color='#CFCFCF'>Um mehr Fahrzeuge freizuschalten, erobern Sie weitere Zonen. + Zde můžete nakupovat a prodávat vybavení<br /><t color='#CFCFCF'>Pro odemknutí dalších vozidel obsazujte více zón. + 在此购买和出售装备<br /><t color='#CFCFCF'>占领更多区域以解锁更多载具。 + 여기에서 장비를 사고팔 수 있습니다<br /><t color='#CFCFCF'>더 많은 차량을 해금하려면 더 많은 구역을 점령하십시오. + Здесь можно покупать и продавать снаряжение<br /><t color='#CFCFCF'>Чтобы открыть больше техники, захватывайте больше зон. + Compra e vendi equipaggiamento qui<br /><t color='#CFCFCF'>Per sbloccare più veicoli, conquista più zone. + Compra y vende equipo aquí<br /><t color='#CFCFCF'>Para desbloquear más vehículos, captura más zonas. + Kupuj i sprzedawaj wyposażenie tutaj<br /><t color='#CFCFCF'>Aby odblokować więcej pojazdów, przejmuj kolejne strefy. + + + A forward lookout position used to monitor enemy movement and report contacts. + Une position d'observation avancée utilisée pour surveiller les mouvements ennemis et signaler les contacts. + Ein vorgeschobener Beobachtungsposten zur Überwachung feindlicher Bewegungen und Meldung von Kontakten. + Předsunuté pozorovací stanoviště sloužící ke sledování pohybu nepřítele a hlášení kontaktů. + 用于监视敌军动向并报告接触情况的前沿观察哨。 + 적의 움직임을 감시하고 접촉 상황을 보고하기 위한 전방 관측 초소입니다. + Передовой наблюдательный пост для отслеживания передвижений противника и доклада о контактах. + Una postazione avanzata di osservazione usata per monitorare i movimenti nemici e segnalare i contatti. + Un puesto de observación avanzado usado para vigilar los movimientos enemigos e informar de contactos. + Wysunięty punkt obserwacyjny służący do śledzenia ruchów wroga i meldowania kontaktów. + + + A defensive checkpoint built to slow, stop, or inspect passing vehicles and infantry. + Un point de contrôle défensif conçu pour ralentir, arrêter ou inspecter les véhicules et l'infanterie de passage. + Ein defensiver Kontrollpunkt, der vorbeifahrende Fahrzeuge und Infanterie verlangsamen, stoppen oder kontrollieren soll. + Obranné kontrolní stanoviště určené ke zpomalení, zastavení nebo kontrole projíždějících vozidel a pěchoty. + 用于减缓、拦停或检查过往车辆和步兵的防御检查点。 + 통과하는 차량과 보병을 지연, 정지 또는 검문하기 위해 설치된 방어 검문소입니다. + Оборонительный блокпост, предназначенный для замедления, остановки или досмотра проходящей техники и пехоты. + Un posto di blocco difensivo costruito per rallentare, fermare o ispezionare veicoli e fanteria di passaggio. + Un puesto de control defensivo construido para ralentizar, detener o inspeccionar vehículos e infantería en tránsito. + Punkt blokadowy przeznaczony do spowalniania, zatrzymywania lub kontrolowania przejeżdżających pojazdów i piechoty. + + + A fortified weapon position designed to engage hostile aircraft. + Une position d'arme fortifiée conçue pour engager les aéronefs hostiles. + Eine befestigte Waffenstellung zur Bekämpfung feindlicher Luftfahrzeuge. + Opevněné palebné postavení určené k boji proti nepřátelským letadlům. + 用于打击敌方飞行器的加固武器阵地。 + 적 항공기를 공격하도록 설계된 방어화된 화기 진지입니다. + Укреплённая огневая позиция, предназначенная для поражения вражеской авиации. + Una postazione d'arma fortificata progettata per ingaggiare velivoli ostili. + Una posición fortificada de armas diseñada para enfrentarse a aeronaves hostiles. + Ufortyfikowane stanowisko ogniowe przeznaczone do zwalczania wrogich statków powietrznych. + + + A defensive position equipped to destroy or deter armored vehicles. + Une position défensive équipée pour détruire ou dissuader les véhicules blindés. + Eine Verteidigungsstellung, die zur Zerstörung oder Abschreckung gepanzerter Fahrzeuge ausgerüstet ist. + Obranné postavení vybavené k ničení nebo odrazování obrněných vozidel. + 用于摧毁或阻止装甲车辆的防御阵地。 + 장갑차량을 파괴하거나 저지하도록 갖춰진 방어 진지입니다. + Оборонительная позиция, оснащённая для уничтожения или сдерживания бронетехники. + Una posizione difensiva equipaggiata per distruggere o scoraggiare i veicoli corazzati. + Una posición defensiva equipada para destruir o disuadir vehículos blindados. + Pozycja obronna wyposażona do niszczenia lub powstrzymywania pojazdów opancerzonych. + + + A fixed heavy machine gun position for suppressing infantry, light vehicles, and low-flying targets. + Une position fixe de mitrailleuse lourde destinée à neutraliser l'infanterie, les véhicules légers et les cibles volant à basse altitude. + Eine feste Stellung mit schwerem Maschinengewehr zur Bekämpfung von Infanterie, leichten Fahrzeugen und tief fliegenden Zielen. + Pevné postavení těžkého kulometu určené k potlačování pěchoty, lehkých vozidel a nízko letících cílů. + 用于压制步兵、轻型载具和低空目标的固定重机枪阵地。 + 보병, 경차량, 저공 비행 목표를 제압하기 위한 고정식 중기관총 진지입니다. + Стационарная позиция крупнокалиберного пулемёта для подавления пехоты, лёгкой техники и низколетящих целей. + Una postazione fissa di mitragliatrice pesante per sopprimere fanteria, veicoli leggeri e bersagli a bassa quota. + Una posición fija de ametralladora pesada para suprimir infantería, vehículos ligeros y objetivos a baja altura. + Stałe stanowisko ciężkiego karabinu maszynowego do tłumienia piechoty, lekkich pojazdów i nisko lecących celów. + + + Enemy stronghold that may include helicopters, armored vehicles, and mortars.<br />Contains 2 loot crates and can only be captured from War Tier 3+. + Feindliche Festung mit möglichen Helikoptern, gepanzerten Fahrzeugen und Mörsern.<br />Enthält 2 Beutekisten und kann erst ab Kriegsstufe 3 erobert werden. + Place forte ennemie pouvant inclure des hélicoptères, des véhicules blindés et des mortiers.<br />Contient 2 caisses de butin et ne peut être capturée qu’à partir du niveau de guerre 3+. + Fortificación enemiga que puede incluir helicópteros, vehículos blindados y morteros.<br />Contiene 2 cajas de botín y solo puede capturarse a partir del Nivel de Guerra 3+. + Roccaforte nemica che può includere elicotteri, veicoli corazzati e mortai.<br />Contiene 2 casse di bottino e può essere catturata solo dal Livello di Guerra 3+. + Wrogi bastion, w którym mogą znajdować się śmigłowce, pojazdy opancerzone i moździerze.<br />Zawiera 2 skrzynie z łupem i można go przejąć dopiero od Poziomu Wojny 3+. + Вражеский опорный пункт, где могут быть вертолёты, бронетехника и миномёты.<br />Содержит 2 ящика с добычей и может быть захвачен только с уровня войны 3+. + Nepřátelská pevnost, která může obsahovat vrtulníky, obrněná vozidla a minomety.<br />Obsahuje 2 bedny s kořistí a lze ji obsadit až od úrovně války 3+. + Helikopterler, zırhlı araçlar ve havanlar içerebilen düşman kalesi.<br />2 ganimet sandığı içerir ve yalnızca Savaş Seviyesi 3+’ten itibaren ele geçirilebilir. + 敌方据点,可能有直升机、装甲车辆和迫击炮。<br />包含2个战利品箱,并且只能在战争等级3及以上夺取。 + ヘリコプター、装甲車両、迫撃砲が配置されている可能性のある敵の拠点。<br />戦利品箱が2つあり、戦争ティア3以上でのみ制圧可能。 + + + The most common enemy-held location.<br />Contains a loot crate and may provide extra intel. + Der häufigste feindlich gehaltene Ort.<br />Enthält eine Beutekiste und kann zusätzliche Informationen liefern. + Le lieu le plus couramment tenu par l’ennemi.<br />Contient une caisse de butin et peut fournir des renseignements supplémentaires. + La ubicación enemiga más común.<br />Contiene una caja de botín y puede proporcionar información adicional. + La posizione nemica più comune.<br />Contiene una cassa di bottino e può fornire informazioni aggiuntive. + Najczęściej spotykana lokacja zajęta przez wroga.<br />Zawiera skrzynię z łupem i może dostarczyć dodatkowych informacji. + Самая распространённая точка, удерживаемая противником.<br />Содержит ящик с добычей и может дать дополнительные разведданные. + Nejběžnější nepřátelské stanoviště.<br />Obsahuje bednu s kořistí a může poskytnout další informace. + Haritada en yaygın düşman mevzisi.<br />Bir ganimet sandığı içerir ve ek istihbarat sağlayabilir. + 地图上最常见的敌方据点。<br />包含一个战利品箱,并可能提供额外情报。 + 敵が占拠している最も一般的な拠点。<br />戦利品箱があり、追加の情報を入手できることがあります。 + + + Coastal hub that may have a patrolling enemy boat.<br />Contains a loot crate and makes it easier to destroy stored boats. + Küstenknotenpunkt, der ein patrouillierendes feindliches Boot haben kann.<br />Enthält eine Beutekiste und erleichtert das Zerstören gelagerter Boote. + Point côtier pouvant avoir un bateau ennemi en patrouille.<br />Contient une caisse de butin et facilite la destruction des bateaux stockés. + Centro costero que puede tener un barco enemigo patrullando.<br />Contiene una caja de botín y facilita destruir barcos almacenados. + Hub costiero che può avere una barca nemica in pattuglia.<br />Contiene una cassa di bottino e rende più facile distruggere le barche immagazzinate. + Nadmorski punkt, przy którym może patrolować wroga łódź.<br />Zawiera skrzynię z łupem i ułatwia niszczenie przechowywanych łodzi. + Прибрежный узел, где может патрулировать вражеский катер.<br />Содержит ящик с добычей и упрощает уничтожение хранимых лодок. + Pobřežní uzel, kde může hlídkovat nepřátelský člun.<br />Obsahuje bednu s kořistí a usnadňuje ničení uložených lodí. + Devriye gezen bir düşman botu bulunabilen kıyı merkezi.<br />Bir ganimet sandığı içerir ve depolanmış botları imha etmeyi kolaylaştırır. + 沿海据点,可能有敌方巡逻艇。<br />包含一个战利品箱,并使摧毁存放的船只更容易。 + 敵の巡回艇がいる可能性のある沿岸拠点。<br />戦利品箱があり、保管されている船を破壊しやすくなります。 + + + Only available for player-controlled markers. + Disponible uniquement pour les marqueurs contrôlés par le joueur. + Nur für spielerkontrollierte Marker verfügbar. + Dostupné pouze pro hráčem ovládané markery. + 仅适用于玩家控制的标记。 + 플레이어가 통제하는 마커에서만 사용할 수 있습니다. + Доступно только для маркеров, контролируемых игроком. + Disponibile solo per i marcatori controllati dal giocatore. + Solo disponible para marcadores controlados por el jugador. + Dostępne tylko dla znaczników kontrolowanych przez gracza. + + + Garrison is not available for the Black Market Trader. + La garnison n'est pas disponible pour le Marchand du marché noir. + Garnison ist für den Schwarzmarkthändler nicht verfügbar. + Posádka není pro obchodníka na černém trhu k dispozici. + 黑市商人不可使用驻军功能。 + 암시장 상인에게는 주둔지 기능을 사용할 수 없습니다. + Гарнизон недоступен для торговца чёрного рынка. + La guarnigione non è disponibile per il Mercante del Mercato Nero. + La guarnición no está disponible para el Comerciante del Mercado Negro. + Garnizon nie jest dostępny dla handlarza z czarnego rynku. + + + Garrison is not available for FIA-built emplacements. + La garnison n'est pas disponible pour les fortifications construites par la FIA. + Garnison ist für von der FIA errichtete Stellungen nicht verfügbar. + Posádka není k dispozici pro postavení vybudovaná FIA. + FIA建造的阵地不可使用驻军功能。 + FIA가 건설한 진지에는 주둔지 기능을 사용할 수 없습니다. + Гарнизон недоступен для укреплений, построенных FIA. + La guarnigione non è disponibile per le postazioni costruite dalla FIA. + La guarnición no está disponible para los emplazamientos construidos por la FIA. + Garnizon nie jest dostępny dla umocnień zbudowanych przez FIA. + + + Requires Default Commander and player-controlled marker. + Nécessite le commandant par défaut et un marqueur contrôlé par le joueur. + Erfordert den Standardkommandanten und einen spielerkontrollierten Marker. + Vyžaduje výchozího velitele a hráčem ovládaný marker. + 需要默认指挥官身份以及玩家控制的标记。 + 기본 지휘관이며 플레이어가 통제하는 마커여야 합니다. + Требуется командир по умолчанию и маркер, контролируемый игроком. + Richiede il Comandante predefinito e un marcatore controllato dal giocatore. + Requiere el comandante predeterminado y un marcador controlado por el jugador. + Wymaga domyślnego dowódcy oraz znacznika kontrolowanego przez gracza. + + + Allows fast travel to a location set by the Commander. + Ermöglicht Schnellreise zu einem vom Kommandanten festgelegten Ort. + Permet le voyage rapide vers un lieu défini par le commandant. + Permite viajar rápido a una ubicación establecida por el comandante. + Consente il viaggio rapido verso una posizione impostata dal comandante. + Umożliwia szybką podróż do lokalizacji wyznaczonej przez dowódcę. + Позволяет быстро переместиться к месту, заданному командиром. + Umožňuje rychlé cestování na místo určené velitelem. + Komutan tarafından belirlenen bir konuma hızlı seyahate izin verir. + 允许快速前往由指挥官设定的位置。 + 指揮官が設定した場所へファストトラベルできます。 + + + Eliminate the commander to destroy the administration.<br />Inside, you can find a small supply crate to loot and prisoners who can be rescued to join your faction. + Schalte den Kommandanten aus, um die Verwaltung zu zerstören.<br />Im Inneren findest du eine kleine Versorgungskiste zum Plündern sowie Gefangene, die du retten kannst und die sich deiner Fraktion anschließen. + Éliminez le commandant pour détruire l’administration.<br />À l’intérieur, vous pouvez trouver une petite caisse de ravitaillement à piller et des prisonniers à secourir qui rejoindront votre faction. + Elimina al comandante para destruir la administración.<br />Dentro puedes encontrar una pequeña caja de suministros para saquear y prisioneros que puedes rescatar para que se unan a tu facción. + Elimina il comandante per distruggere l’amministrazione.<br />All’interno puoi trovare una piccola cassa di rifornimenti da saccheggiare e prigionieri che puoi salvare e che si uniranno alla tua fazione. + Wyeliminuj dowódcę, aby zniszczyć administrację.<br />W środku znajdziesz małą skrzynię z zaopatrzeniem do zrabowania oraz więźniów, których możesz uwolnić — dołączą do twojej frakcji. + Устраните командира, чтобы уничтожить администрацию.<br />Внутри вы найдёте небольшой ящик с припасами для добычи и пленников, которых можно освободить — они присоединятся к вашей фракции. + Zlikviduj velitele a znič administrativu.<br />Uvnitř najdeš malou bednu se zásobami k vybrání a vězně, které můžeš osvobodit — přidají se k tvé frakci. + İdareyi yok etmek için komutanı etkisiz hâle getirin.<br />İçeride yağmalayabileceğiniz küçük bir erzak sandığı ve kurtarılınca fraksiyonunuza katılacak mahkûmlar bulabilirsiniz. + 消灭指挥官即可摧毁该管理区。<br />内部有一只小型补给箱可供搜刮,还有可营救的囚犯,获救后将加入你的阵营。 + 指揮官を排除すると施設を破壊できます。<br />中には少量の補給箱があり、救出できる捕虜もいて、救出後はあなたの勢力に加わります。 + + + Cant garrison units on rally point + Impossible de mettre des unités en garnison sur le point de ralliement. + Einheiten können am Sammelpunkt nicht in Garnison stationiert werden. + Na shromaždišti nelze umístit jednotky do posádky. + 无法在集结点驻扎单位。 + 집결 지점에는 유닛을 주둔시킬 수 없습니다. + Нельзя разместить гарнизон на точке сбора. + Non è possibile assegnare unità alla guarnigione sul punto di raccolta. + No se pueden guarnecer unidades en el punto de reunión. + Nie można umieszczać jednostek w garnizonie na punkcie zbornym. + Enable Init Messages diff --git a/A3A/addons/ultimate/config.cpp b/A3A/addons/ultimate/config.cpp index 3135428f01..df3e88c6bf 100644 --- a/A3A/addons/ultimate/config.cpp +++ b/A3A/addons/ultimate/config.cpp @@ -43,3 +43,21 @@ class CfgVehicles { #include "CfgVehicles.hpp" }; + +class CfgMarkerClasses +{ + class A3AU_MRK + { + displayName="Antistasi Ultimate Markers"; + }; +}; + +class CfgMarkers +{ + #include "CfgMarkers.hpp" +}; + +class CfgMarkerColors +{ + #include "CfgMarkerColors.hpp" +}; \ No newline at end of file diff --git a/A3A/addons/ultimate/data/A3AU_Miladmin_dead_mrk.paa b/A3A/addons/ultimate/data/A3AU_Miladmin_dead_mrk.paa new file mode 100644 index 0000000000..e82f3b9e74 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_Miladmin_dead_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_RebalHQ_mrk.paa b/A3A/addons/ultimate/data/A3AU_RebalHQ_mrk.paa new file mode 100644 index 0000000000..759505747a Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_RebalHQ_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_antiair_mrk.paa b/A3A/addons/ultimate/data/A3AU_antiair_mrk.paa new file mode 100644 index 0000000000..cc518c3bc2 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_antiair_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_antitank_mrk.paa b/A3A/addons/ultimate/data/A3AU_antitank_mrk.paa new file mode 100644 index 0000000000..63f7b00f52 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_antitank_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_city_mrk.paa b/A3A/addons/ultimate/data/A3AU_city_mrk.paa new file mode 100644 index 0000000000..ae8ab53631 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_city_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_dealer_flag.paa b/A3A/addons/ultimate/data/A3AU_dealer_flag.paa new file mode 100644 index 0000000000..59f99b37ff Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_dealer_flag.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_dealer_mrk.paa b/A3A/addons/ultimate/data/A3AU_dealer_mrk.paa new file mode 100644 index 0000000000..0b2d93a8c1 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_dealer_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_factory_mrk.paa b/A3A/addons/ultimate/data/A3AU_factory_mrk.paa new file mode 100644 index 0000000000..3348e48edf Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_factory_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_fasttravel_mrk.paa b/A3A/addons/ultimate/data/A3AU_fasttravel_mrk.paa new file mode 100644 index 0000000000..2a11005c52 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_fasttravel_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_hmg_mrk.paa b/A3A/addons/ultimate/data/A3AU_hmg_mrk.paa new file mode 100644 index 0000000000..58728e2b97 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_hmg_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_hover_icon.paa b/A3A/addons/ultimate/data/A3AU_hover_icon.paa new file mode 100644 index 0000000000..98d3d1f0c1 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_hover_icon.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_miladmin_mrk.paa b/A3A/addons/ultimate/data/A3AU_miladmin_mrk.paa new file mode 100644 index 0000000000..5bd93048e4 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_miladmin_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_milbase_mrk.paa b/A3A/addons/ultimate/data/A3AU_milbase_mrk.paa new file mode 100644 index 0000000000..45f6edc3ad Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_milbase_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_outpost_mrk.paa b/A3A/addons/ultimate/data/A3AU_outpost_mrk.paa new file mode 100644 index 0000000000..61b075ba1e Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_outpost_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_radiotower_mrk.paa b/A3A/addons/ultimate/data/A3AU_radiotower_mrk.paa new file mode 100644 index 0000000000..42a414fceb Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_radiotower_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_resource_mrk.paa b/A3A/addons/ultimate/data/A3AU_resource_mrk.paa new file mode 100644 index 0000000000..ce66735c62 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_resource_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_roadblock_mrk.paa b/A3A/addons/ultimate/data/A3AU_roadblock_mrk.paa new file mode 100644 index 0000000000..f1f8cd09ff Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_roadblock_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_seaport_mrk.paa b/A3A/addons/ultimate/data/A3AU_seaport_mrk.paa new file mode 100644 index 0000000000..89fe378ff8 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_seaport_mrk.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_search_icon.paa b/A3A/addons/ultimate/data/A3AU_search_icon.paa new file mode 100644 index 0000000000..9a246901ff Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_search_icon.paa differ diff --git a/A3A/addons/ultimate/data/A3AU_watchpost_mrk.paa b/A3A/addons/ultimate/data/A3AU_watchpost_mrk.paa new file mode 100644 index 0000000000..1e902da079 Binary files /dev/null and b/A3A/addons/ultimate/data/A3AU_watchpost_mrk.paa differ diff --git a/A3A/addons/ultimate/functions/cba/fn_settings.sqf b/A3A/addons/ultimate/functions/cba/fn_settings.sqf index 678aa34abd..084a5e674f 100644 --- a/A3A/addons/ultimate/functions/cba/fn_settings.sqf +++ b/A3A/addons/ultimate/functions/cba/fn_settings.sqf @@ -92,6 +92,46 @@ } ] call CBA_fnc_addSetting; +private _namesOfBlindness = ["Standard Vision","Protanopia","Deuteranopia","Tritanopia"]; +private _blindnessColors = [ + "ColorBLUFOR|ColorOPFOR|ColorCIV|ColorGUER|ColorBrown", // Standard + "ColorBLUFOR|ColorOrange|A3AU_Color_Light_Gray|ColorYellow|A3AU_Color_Dark_Purple", // Protanopia + "ColorBLUFOR|ColorOrange|A3AU_Color_Light_Gray|ColorYellow|A3AU_Color_Tan", // Deuteranopia + "ColorOrange|ColorOPFOR|A3AU_Color_Light_Gray|ColorGUER|ColorCivilian" // Tritanopia +]; +[ + "A3AU_setting_colorBlindness", + "LIST", + "Color Blindness Settings (Requires Restart!)", + ["Antistasi Ultimate", "Accessibility Settings"], + [_blindnessColors, _namesOfBlindness, 0], + false, + { + params ["_value"]; + missionNamespace setVariable ["A3AU_setting_colorBlindness",_value,true]; + + private _factionColor = _value splitString "|"; + colorOccupants = _factionColor select 0; + colorInvaders = _factionColor select 1; + colorCivilian = _factionColor select 2; + colorTeamPlayer = _factionColor select 3; + colorRivals = _factionColor select 4; + } +] call CBA_fnc_addSetting; + +[ + "A3AU_setting_alwaysShowMarkerName", + "CHECKBOX", + "Always show marker names on map (Requires Restart!)", + ["Antistasi Ultimate", "Accessibility Settings"], + false, + false, + { + params ["_value"]; + missionNamespace setVariable ["A3AU_setting_alwaysShowMarkerName",_value,true]; + } +] call CBA_fnc_addSetting; + if (["tts_emission"] call A3U_fnc_hasAddon) then { [ "A3U_setting_emissionMinimum", // Internal setting name, should always contain a tag! This will be the global variable which takes the value of the setting. diff --git a/A3A/addons/ultimate/functions/map/fn_mapHover.sqf b/A3A/addons/ultimate/functions/map/fn_mapHover.sqf new file mode 100644 index 0000000000..4be51f04a0 --- /dev/null +++ b/A3A/addons/ultimate/functions/map/fn_mapHover.sqf @@ -0,0 +1,259 @@ +#include "..\..\script_component.hpp" +FIX_LINE_NUMBERS() +/* ---------------------------------------------------------------------------- +Function: A3U_fnc_mapHover + +Description: + Enables or disables the strategic map hover tooltip system, including the + hover update handler, click interaction, and context menu cleanup. + +Parameters: + None. + +Optional: + 0: _attachTooltip - Whether to attach or remove the hover UI system + (default: true) + +Example: + [true] call A3U_fnc_mapHover; + +Returns: + Nothing + +Environment: + Client, Unscheduled + +Author: + Maxx +---------------------------------------------------------------------------- */ + +// Existing A3U_fnc_* public function name kept for backwards compatibility. + +private _attachTooltip = param [0, true, [true]]; + +private _mapDisplay = findDisplay 12; +if (isNull _mapDisplay) exitWith {}; + +// Legacy A3U_* display-variable keys are kept for compatibility with the +// existing hover/menu code that already reads and writes these values. + +private _clearContextMenus = { + params ["_display"]; + + if (isNull _display) exitWith {}; + + private _menuGroup = _display getVariable ["A3U_mrkMenu_grp", controlNull]; + if (!isNull _menuGroup) then { + ctrlDelete _menuGroup; + _display setVariable ["A3U_mrkMenu_grp", controlNull]; + _display setVariable ["A3U_mrkMenu_marker", ""]; + }; + + private _garrisonGroup = _display getVariable + ["A3U_mrkMenu_garrGrp", controlNull]; + if (!isNull _garrisonGroup) then { + ctrlDelete _garrisonGroup; + _display setVariable ["A3U_mrkMenu_garrGrp", controlNull]; + }; +}; + +private _clearHoverState = { + params ["_display"]; + + _display setVariable ["A3U_tipLastMrk", ""]; + _display setVariable ["A3U_tipFadeInStart", -1]; + _display setVariable ["A3U_tipFadeOutStart", -1]; + _display setVariable ["A3U_tipRippleStart", -1]; + _display setVariable ["A3U_tipHoverScreen", []]; +}; + +private _mapControl = _mapDisplay displayCtrl 51; +if (isNull _mapControl) exitWith {}; + +if (_attachTooltip) then { + private _existingClickHandler = _mapDisplay getVariable ["A3U_tipClickEH", -1]; + if (_existingClickHandler >= 0) then { + _mapControl ctrlRemoveEventHandler + ["MouseButtonDown", _existingClickHandler]; + _mapDisplay setVariable ["A3U_tipClickEH", -1]; + }; + + private _existingPerFrameHandler = _mapDisplay getVariable + ["A3U_tipperFrameHandler", -1]; + if (_existingPerFrameHandler >= 0) then { + [_existingPerFrameHandler] call CBA_fnc_removePerFrameHandler; + _mapDisplay setVariable ["A3U_tipperFrameHandler", -1]; + }; + + private _tooltipControls = [_mapDisplay] call A3U_fnc_tooltipCreate; + _tooltipControls params [ + ["_tooltipControl", controlNull, [controlNull]], + ["_hoverRingControl", controlNull, [controlNull]], + ["_rippleControl", controlNull, [controlNull]] + ]; + + _mapDisplay setVariable ["A3U_tooltipCtrl", _tooltipControl]; + _mapDisplay setVariable ["A3U_tooltipRingCtrl", _hoverRingControl]; + _mapDisplay setVariable ["A3U_tooltipRippleCtrl", _rippleControl]; + + [_mapDisplay] call _clearHoverState; + + private _clickHandlerId = _mapControl ctrlAddEventHandler + ["MouseButtonDown", { + params ["_clickedMapControl", "_button"]; + + private _display = ctrlParent _clickedMapControl; + if (isNull _display) exitWith {}; + + private _menuGroup = _display getVariable + ["A3U_mrkMenu_grp", controlNull]; + private _garrisonGroup = _display getVariable + ["A3U_mrkMenu_garrGrp", controlNull]; + + if (!isNull _menuGroup || {!isNull _garrisonGroup}) then { + private _mousePosition = getMousePosition; + + private _mouseInsideMenu = false; + if (!isNull _menuGroup) then { + private _menuPosition = ctrlPosition _menuGroup; + _mouseInsideMenu = + (_mousePosition # 0) >= (_menuPosition # 0) + && {(_mousePosition # 0) + <= ((_menuPosition # 0) + (_menuPosition # 2))} + && {(_mousePosition # 1) >= (_menuPosition # 1)} + && {(_mousePosition # 1) + <= ((_menuPosition # 1) + (_menuPosition # 3))}; + }; + + private _mouseInsideGarrison = false; + if (!isNull _garrisonGroup) then { + private _garrisonPosition = ctrlPosition _garrisonGroup; + _mouseInsideGarrison = + (_mousePosition # 0) >= (_garrisonPosition # 0) + && {(_mousePosition # 0) + <= ((_garrisonPosition # 0) + + (_garrisonPosition # 2))} + && {(_mousePosition # 1) >= (_garrisonPosition # 1)} + && {(_mousePosition # 1) + <= ((_garrisonPosition # 1) + + (_garrisonPosition # 3))}; + }; + + if (_mouseInsideMenu || {_mouseInsideGarrison}) exitWith {}; + + if (!isNull _menuGroup) then { + ctrlDelete _menuGroup; + }; + + if (!isNull _garrisonGroup) then { + ctrlDelete _garrisonGroup; + }; + + _display setVariable ["A3U_mrkMenu_grp", controlNull]; + _display setVariable ["A3U_mrkMenu_garrGrp", controlNull]; + _display setVariable ["A3U_mrkMenu_marker", ""]; + }; + + if (_button != 0) exitWith {}; + + private _hoveredMarker = _display getVariable ["A3U_tipLastMrk", ""]; + private _hoverScreenPosition = _display getVariable + ["A3U_tipHoverScreen", []]; + if (_hoveredMarker == "" || {_hoverScreenPosition isEqualTo []}) exitWith {}; + + private _originalMarker = _hoveredMarker; + while { + (count _originalMarker) >= 3 + && {(_originalMarker select [0, 3]) == "Dum"} + } do { + _originalMarker = _originalMarker select + [3, (count _originalMarker) - 3]; + }; + + private _revealedZones = if (isNil "revealedZones") then { + [] + } else { + revealedZones + }; + + private _immuneMarkers = if (isNil "markersImmune") then { + [] + } else { + markersImmune + }; + + private _markerSide = sidesX getVariable + [_originalMarker, sideUnknown]; + + private _hideEnemyMarkers = missionNamespace getVariable + ["hideEnemyMarkers", false]; + + private _isMarkerHidden = _hideEnemyMarkers + && {!(_originalMarker in _revealedZones)} + && {!(_originalMarker in _immuneMarkers)} + && {!("cont" in _originalMarker)} + && {!(_originalMarker in citiesX)} + && {!(_originalMarker in airportsX)} + && {_markerSide isNotEqualTo sideUnknown} + && {_markerSide isNotEqualTo resistance}; + + if (_isMarkerHidden) exitWith { + _display setVariable ["A3U_tipLastMrk", ""]; + _display setVariable ["A3U_tipHoverScreen", []]; + }; + + [_hoveredMarker, _hoverScreenPosition] + call A3U_fnc_markerContextMenu; + _display setVariable ["A3U_tipRippleStart", diag_tickTime]; + }]; + + _mapDisplay setVariable ["A3U_tipClickEH", _clickHandlerId]; + + private _hoverThresholdPixels = 32; + private _updateIntervalSeconds = 0.05; + + private _perFrameHandlerId = [{ + _this call A3U_fnc_mapTooltip; + }, _updateIntervalSeconds, [ + _mapDisplay, + _mapControl, + _hoverThresholdPixels + ]] call CBA_fnc_addPerFrameHandler; + + _mapDisplay setVariable ["A3U_tipperFrameHandler", _perFrameHandlerId]; +} else { + private _tooltipControl = _mapDisplay getVariable + ["A3U_tooltipCtrl", controlNull]; + if (!isNull _tooltipControl) then { + _tooltipControl ctrlShow false; + }; + + private _hoverRingControl = _mapDisplay getVariable + ["A3U_tooltipRingCtrl", controlNull]; + if (!isNull _hoverRingControl) then { + _hoverRingControl ctrlShow false; + }; + + private _rippleControl = _mapDisplay getVariable + ["A3U_tooltipRippleCtrl", controlNull]; + if (!isNull _rippleControl) then { + _rippleControl ctrlShow false; + }; + + [_mapDisplay] call _clearContextMenus; + + private _clickHandlerId = _mapDisplay getVariable ["A3U_tipClickEH", -1]; + if (_clickHandlerId >= 0) then { + _mapControl ctrlRemoveEventHandler ["MouseButtonDown", _clickHandlerId]; + _mapDisplay setVariable ["A3U_tipClickEH", -1]; + }; + + private _perFrameHandlerId = _mapDisplay getVariable + ["A3U_tipperFrameHandler", -1]; + if (_perFrameHandlerId >= 0) then { + [_perFrameHandlerId] call CBA_fnc_removePerFrameHandler; + _mapDisplay setVariable ["A3U_tipperFrameHandler", -1]; + }; + + [_mapDisplay] call _clearHoverState; +}; diff --git a/A3A/addons/ultimate/functions/map/fn_mapTooltip.sqf b/A3A/addons/ultimate/functions/map/fn_mapTooltip.sqf new file mode 100644 index 0000000000..a49badfeb5 --- /dev/null +++ b/A3A/addons/ultimate/functions/map/fn_mapTooltip.sqf @@ -0,0 +1,433 @@ +#include "..\..\script_component.hpp" +FIX_LINE_NUMBERS() +/* ---------------------------------------------------------------------------- +Function: A3U_fnc_mapTooltip + +Description: + Updates the hover tooltip, marker highlight ring, and click ripple for the + map marker currently closest to the mouse cursor. + +Parameters: + 0: _arguments - Per-frame handler arguments + [display, map control, threshold] + 1: _handle - Per-frame handler id supplied by the scheduler + +Optional: + None. + +Example: + [[findDisplay 12, (findDisplay 12) displayCtrl 51, 32], -1] + call A3U_fnc_mapTooltip; + +Returns: + Nothing + +Environment: + Client, Unscheduled + +Author: + Maxx +---------------------------------------------------------------------------- */ + +// Existing A3U_fnc_* public function name kept for backwards compatibility. + +if !assert(params [ + ["_arguments", nil, [[]]], + ["_handle", nil, [0]] +]) exitWith {}; + +if !assert(_arguments isEqualTypeParams [displayNull, controlNull, 0]) exitWith {}; + +_arguments params ["_mapDisplay", "_mapControl", "_thresholdPixels"]; + +private _resetHoverUi = { + params ["_display", "_tooltipControl", "_hoverRingControl"]; + + if (!isNull _tooltipControl) then { + _tooltipControl ctrlShow false; + }; + + if (!isNull _hoverRingControl) then { + _hoverRingControl ctrlShow false; + }; + + _display setVariable ["A3U_tipLastMrk", ""]; + _display setVariable ["A3U_tipAnimStart", 0]; +}; + +if ( + isNull _mapDisplay + || {isNull _mapControl} + || {!visibleMap} +) exitWith { + if (!isNull _mapDisplay) then { + private _tooltipControl = _mapDisplay getVariable + ["A3U_tooltipCtrl", controlNull]; + private _hoverRingControl = _mapDisplay getVariable + ["A3U_tooltipRingCtrl", controlNull]; + + [_mapDisplay, _tooltipControl, _hoverRingControl] call _resetHoverUi; + }; +}; + +// Legacy A3U_* hover-cache keys are kept for compatibility with the existing +// hover/browser/context-menu code path that shares this state. + +private _tooltipControl = _mapDisplay getVariable + ["A3U_tooltipCtrl", controlNull]; +private _hoverRingControl = _mapDisplay getVariable + ["A3U_tooltipRingCtrl", controlNull]; +private _rippleControl = _mapDisplay getVariable + ["A3U_tooltipRippleCtrl", controlNull]; + +if ( + isNull _tooltipControl + || {isNull _hoverRingControl} + || {isNull _rippleControl} +) then { + private _tooltipControls = [_mapDisplay] call A3U_fnc_tooltipCreate; + if (_tooltipControls isEqualType []) then { + _tooltipControls params [ + ["_newTooltipControl", controlNull, [controlNull]], + ["_newHoverRingControl", controlNull, [controlNull]], + ["_newRippleControl", controlNull, [controlNull]] + ]; + + if (isNull _tooltipControl) then { + _tooltipControl = _newTooltipControl; + }; + + if (isNull _hoverRingControl) then { + _hoverRingControl = _newHoverRingControl; + }; + + if (isNull _rippleControl) then { + _rippleControl = _newRippleControl; + }; + }; + + _mapDisplay setVariable ["A3U_tooltipCtrl", _tooltipControl]; + _mapDisplay setVariable ["A3U_tooltipRingCtrl", _hoverRingControl]; + _mapDisplay setVariable ["A3U_tooltipRippleCtrl", _rippleControl]; +}; + +private _hoverMarkers = missionNamespace getVariable ["A3U_hoverMarkers", []]; +if (_hoverMarkers isEqualTo []) exitWith { + [_mapDisplay, _tooltipControl, _hoverRingControl] call _resetHoverUi; +}; + +private _hoverMetaMap = missionNamespace getVariable + ["A3U_mrkHoverMetaMap", createHashMap]; +private _hideEnemyMarkers = missionNamespace getVariable + ["hideEnemyMarkers", false]; + +private _getOriginalMarkerName = { + params ["_markerName"]; + + private _originalMarkerName = _markerName; + while { + (count _originalMarkerName) >= 3 + && {(_originalMarkerName select [0, 3]) == "Dum"} + } do { + _originalMarkerName = _originalMarkerName select + [3, (count _originalMarkerName) - 3]; + }; + + _originalMarkerName +}; + +private _isMarkerHidden = { + params ["_markerName"]; + + private _originalMarkerName = [_markerName] call _getOriginalMarkerName; + if (!_hideEnemyMarkers) exitWith { + false + }; + + private _revealedZones = if (isNil "revealedZones") then { + [] + } else { + revealedZones + }; + + private _immuneMarkers = if (isNil "markersImmune") then { + [] + } else { + markersImmune + }; + + if (_originalMarkerName in _revealedZones) exitWith { + false + }; + + if (_originalMarkerName in _immuneMarkers) exitWith { + false + }; + + if ("cont" in _originalMarkerName) exitWith { + false + }; + + if ( + _originalMarkerName in citiesX + || {_originalMarkerName in airportsX} + ) exitWith { + false + }; + + private _markerSide = sidesX getVariable + [_originalMarkerName, sideUnknown]; + _markerSide isNotEqualTo sideUnknown + && {_markerSide isNotEqualTo resistance} +}; + +private _mousePosition = getMousePosition; +private _nearestMarker = ""; +private _nearestDistanceSquared = 1e12; +private _nearestScreenPosition = []; + +private _selectionThreshold = (_thresholdPixels / 1000) max 0.01; + +{ + if ([_x] call _isMarkerHidden) then { + continue; + }; + + private _screenPosition = + _mapControl ctrlMapWorldToScreen (getMarkerPos _x); + if (_screenPosition isEqualTo []) then { + continue; + }; + + private _distanceX = (_screenPosition # 0) - (_mousePosition # 0); + private _distanceY = (_screenPosition # 1) - (_mousePosition # 1); + private _distanceSquared = + (_distanceX * _distanceX) + (_distanceY * _distanceY); + + if (_distanceSquared < _nearestDistanceSquared) then { + _nearestDistanceSquared = _distanceSquared; + _nearestMarker = _x; + _nearestScreenPosition = _screenPosition; + }; +} forEach _hoverMarkers; + +if ( + _nearestMarker != "" + && {_nearestDistanceSquared <= (_selectionThreshold * _selectionThreshold)} +) then { + if ([_nearestMarker] call _isMarkerHidden) exitWith { + [_mapDisplay, _tooltipControl, _hoverRingControl] call _resetHoverUi; + }; + + private _markerMetadata = _hoverMetaMap getOrDefault [_nearestMarker, []]; + if (_markerMetadata isEqualTo [] || {count _markerMetadata < 1}) exitWith { + [_mapDisplay, _tooltipControl, _hoverRingControl] call _resetHoverUi; + }; + + _markerMetadata params ["_hoverTextRaw", ["_flagMarkerType", ""]]; + + private _hoverTitle = _hoverTextRaw; + private _lineBreakIndex = _hoverTextRaw find "
"; + if (_lineBreakIndex > -1) then { + _hoverTitle = _hoverTextRaw select [0, _lineBreakIndex]; + }; + + if (_hoverTextRaw == "") exitWith { + [_mapDisplay, _tooltipControl, _hoverRingControl] call _resetHoverUi; + }; + + private _iconPath = ""; + if (_flagMarkerType != "") then { + _iconPath = getText + (configFile >> "CfgMarkers" >> _flagMarkerType >> "icon"); + }; + + private _lastMarker = _mapDisplay getVariable ["A3U_tipLastMrk", ""]; + if (_lastMarker != _nearestMarker) then { + _mapDisplay setVariable ["A3U_tipLastMrk", _nearestMarker]; + _mapDisplay setVariable ["A3U_tipFadeInStart", diag_tickTime]; + _mapDisplay setVariable ["A3U_tipFadeOutStart", -1]; + }; + + _mapDisplay setVariable ["A3U_tipHoverScreen", _nearestScreenPosition]; + _mapDisplay setVariable ["A3U_tipFadeOutStart", -1]; + + if ((_mapDisplay getVariable ["A3U_tipFadeInStart", -1]) < 0) then { + _mapDisplay setVariable ["A3U_tipFadeInStart", diag_tickTime]; + }; + + _mapDisplay setVariable ["A3U_tipFadeOutStart", -1]; + + if (!A3AU_setting_alwaysShowMarkerName) then { + private _tooltipStructuredText = if (_iconPath != "") then { + format [ + " %2", + _iconPath, + _hoverTitle + ] + } else { + format [ + "%1", + _hoverTitle + ] + }; + + _tooltipControl ctrlSetStructuredText + (parseText _tooltipStructuredText); + + private _tooltipWidth = 0.40; + private _tooltipHeight = (ctrlTextHeight _tooltipControl) + 0.02; + + private _tooltipPositionX = (_nearestScreenPosition # 0) + 0.018; + private _tooltipPositionY = + (_nearestScreenPosition # 1) - (_tooltipHeight * 0.5); + + _tooltipControl ctrlSetPosition [ + _tooltipPositionX, + _tooltipPositionY, + _tooltipWidth, + _tooltipHeight + ]; + + private _fadeInStartTime = _mapDisplay getVariable + ["A3U_tipFadeInStart", diag_tickTime]; + private _fadeInProgress = + ((diag_tickTime - _fadeInStartTime) / 0.12) min 1 max 0; + + _tooltipControl ctrlSetFade (1 - _fadeInProgress); + _tooltipControl ctrlCommit 0; + _tooltipControl ctrlShow true; + } else { + if (!isNull _tooltipControl) then { + _tooltipControl ctrlShow false; + _tooltipControl ctrlSetFade 1; + _tooltipControl ctrlCommit 0; + }; + }; + + if (!isNull _hoverRingControl) then { + private _baseRingSize = 0.07; + private _fadeInStartTime = _mapDisplay getVariable + ["A3U_tipFadeInStart", -1]; + + if (_fadeInStartTime < 0) then { + _fadeInStartTime = diag_tickTime; + _mapDisplay setVariable ["A3U_tipFadeInStart", _fadeInStartTime]; + }; + + private _fadeInDuration = 0.12; + private _fadeInAlpha = + ((diag_tickTime - _fadeInStartTime) / _fadeInDuration) min 1 max 0; + + private _pulseFrequency = 0.7; + private _pulseAmount = 0.08; + private _pulseDegrees = diag_tickTime * _pulseFrequency * 360; + private _pulseScale = 1 + ((sin _pulseDegrees) * _pulseAmount); + private _ringSize = _baseRingSize * _pulseScale; + + private _ringPositionX = (_nearestScreenPosition # 0) - (_ringSize * 0.5); + private _ringPositionY = (_nearestScreenPosition # 1) - (_ringSize * 0.5); + + _hoverRingControl ctrlSetPosition [ + _ringPositionX, + _ringPositionY, + _ringSize, + _ringSize + ]; + _hoverRingControl ctrlCommit 0; + _hoverRingControl ctrlSetAngle [0, 0.5, 0.5]; + _hoverRingControl ctrlSetTextColor [0.8, 0.8, 0.8, 0.55 * _fadeInAlpha]; + _hoverRingControl ctrlShow true; + }; +} else { + if ((_mapDisplay getVariable ["A3U_tipLastMrk", ""]) != "") then { + if ((_mapDisplay getVariable ["A3U_tipFadeOutStart", -1]) < 0) then { + _mapDisplay setVariable ["A3U_tipFadeOutStart", diag_tickTime]; + }; + }; + + private _fadeOutDuration = 0.12; + private _fadeOutStartTime = _mapDisplay getVariable + ["A3U_tipFadeOutStart", -1]; + + if (_fadeOutStartTime >= 0) then { + private _fadeOutAlpha = + 1 - (((diag_tickTime - _fadeOutStartTime) / _fadeOutDuration) min 1 max 0); + + if (!isNull _hoverRingControl) then { + _hoverRingControl ctrlSetTextColor + [0.8, 0.8, 0.8, 0.55 * _fadeOutAlpha]; + if (_fadeOutAlpha <= 0) then { + _hoverRingControl ctrlShow false; + }; + }; + + if (!isNull _tooltipControl) then { + _tooltipControl ctrlSetFade (1 - _fadeOutAlpha); + _tooltipControl ctrlCommit 0; + if (_fadeOutAlpha <= 0) then { + _tooltipControl ctrlShow false; + }; + }; + + if (_fadeOutAlpha <= 0) then { + _mapDisplay setVariable ["A3U_tipLastMrk", ""]; + _mapDisplay setVariable ["A3U_tipFadeOutStart", -1]; + _mapDisplay setVariable ["A3U_tipHoverScreen", []]; + }; + } else { + if (!isNull _tooltipControl) then { + _tooltipControl ctrlShow false; + }; + + if (!isNull _hoverRingControl) then { + _hoverRingControl ctrlShow false; + }; + }; +}; + +if (!isNull _rippleControl) then { + private _rippleStartTime = _mapDisplay getVariable + ["A3U_tipRippleStart", -1]; + if (_rippleStartTime >= 0) then { + private _rippleDuration = 0.30; + private _elapsedTime = diag_tickTime - _rippleStartTime; + + private _rippleCenter = _mapDisplay getVariable + ["A3U_tipHoverScreen", []]; + if (_rippleCenter isEqualTo []) exitWith { + _rippleControl ctrlShow false; + _mapDisplay setVariable ["A3U_tipRippleStart", -1]; + }; + + if (_elapsedTime >= _rippleDuration) then { + _rippleControl ctrlShow false; + _mapDisplay setVariable ["A3U_tipRippleStart", -1]; + } else { + private _progress = (_elapsedTime / _rippleDuration) min 1 max 0; + private _startSize = 0.035; + private _endSize = 0.110; + private _rippleSize = + _startSize + ((_endSize - _startSize) * _progress); + + private _ripplePositionX = + (_rippleCenter # 0) - (_rippleSize * 0.5); + private _ripplePositionY = + (_rippleCenter # 1) - (_rippleSize * 0.5); + private _rippleAlpha = (1 - _progress) * 0.65; + + _rippleControl ctrlSetPosition [ + _ripplePositionX, + _ripplePositionY, + _rippleSize, + _rippleSize + ]; + _rippleControl ctrlCommit 0; + _rippleControl ctrlSetAngle [0, 0.5, 0.5]; + _rippleControl ctrlSetTextColor [1, 1, 1, _rippleAlpha]; + _rippleControl ctrlShow true; + }; + } else { + _rippleControl ctrlShow false; + }; +}; diff --git a/A3A/addons/ultimate/functions/map/fn_markerBrowser.sqf b/A3A/addons/ultimate/functions/map/fn_markerBrowser.sqf new file mode 100644 index 0000000000..14711d8a7f --- /dev/null +++ b/A3A/addons/ultimate/functions/map/fn_markerBrowser.sqf @@ -0,0 +1,1190 @@ +#include "..\..\script_component.hpp" +FIX_LINE_NUMBERS() +/* ---------------------------------------------------------------------------- +Function: A3U_fnc_markerBrowser + +Description: + Toggles the location browser UI, lets the player filter known map markers, + and animates the map to the selected location. + +Parameters: + None. + +Optional: + 0: _toggle - Whether to open or close the browser (default: true) + 1: _zoom - Target zoom level used when jumping to a marker + (default: 0.04) + 2: _animationTime - Map animation duration in seconds + (default: 1) + 3: _selectedCategoryKey - Preselected category key + (default: "__ALL__") + 4: _selectedFactionKey - Preselected faction key + (default: "__ALL__") + 5: _searchFilterText - Preselected search text + (default: "") + 6: _refreshOnly - Whether to refresh the existing list only + (default: false) + +Example: + [true, 0.04, 1] call A3U_fnc_markerBrowser; + +Returns: + Nothing + +Environment: + Client, Unscheduled + +Author: + Maxx +---------------------------------------------------------------------------- */ + +// Existing A3U_fnc_* public function name kept for backwards compatibility. + +if !assert(_this isEqualType []) exitWith {}; + +private _toggle = param [0, true, [true]]; +private _zoom = param [1, 0.04, [0]]; +private _animationTime = param [2, 1, [0]]; +private _selectedCategoryKey = param [3, "__ALL__", [""]]; +private _selectedFactionKey = param [4, "__ALL__", [""]]; +private _searchFilterText = param [5, "", [""]]; +private _refreshOnly = param [6, false, [true]]; + +private _mapDisplay = findDisplay 12; +if (isNull _mapDisplay) exitWith {}; + +private _searchPlaceholderText = "Search locations..."; + +// Legacy A3U_* browser keys are kept for compatibility with the existing +// browser/hover code that shares state through display variables. + +private _getOriginalMarkerName = { + params ["_markerName"]; + + if !(_markerName isEqualType "") exitWith { + "" + }; + + private _originalMarkerName = _markerName; + while { + (count _originalMarkerName) >= 3 + && {(_originalMarkerName select [0, 3]) == "Dum"} + } do { + _originalMarkerName = _originalMarkerName select + [3, (count _originalMarkerName) - 3]; + }; + + _originalMarkerName +}; + +private _toDummyMarkerName = { + params ["_markerName"]; + + if !(_markerName isEqualType "") exitWith { + "" + }; + + if ( + (count _markerName) >= 3 + && {(_markerName select [0, 3]) == "Dum"} + ) exitWith { + _markerName + }; + + format ["Dum%1", _markerName] +}; + +private _asHashMap = { + params ["_value"]; + + if (_value isEqualType createHashMap) exitWith { + _value + }; + + createHashMap +}; + +private _getMapValue = { + params ["_hashMap", "_key", "_defaultValue"]; + + if !(_hashMap isEqualType createHashMap) exitWith { + _defaultValue + }; + + _hashMap getOrDefault [_key, _defaultValue] +}; + +private _occupierFaction = [ + missionNamespace getVariable ["A3A_faction_occ", createHashMap] +] call _asHashMap; + +private _invaderFaction = [ + missionNamespace getVariable ["A3A_faction_inv", createHashMap] +] call _asHashMap; + +private _rebelFaction = [ + missionNamespace getVariable ["A3A_faction_reb", createHashMap] +] call _asHashMap; + +private _readHoverMetadata = { + params ["_markerName"]; + + if !(_markerName isEqualType "") exitWith { + [] + }; + + private _hoverMetaMap = missionNamespace getVariable + ["A3U_mrkHoverMetaMap", createHashMap]; + + private _markerMetadata = _hoverMetaMap getOrDefault [_markerName, []]; + if !(_markerMetadata isEqualTo []) exitWith { + _markerMetadata + }; + + private _originalMarkerName = [_markerName] call _getOriginalMarkerName; + if (_originalMarkerName == "") exitWith { + [] + }; + + _markerMetadata = _hoverMetaMap getOrDefault [_originalMarkerName, []]; + if !(_markerMetadata isEqualTo []) exitWith { + _markerMetadata + }; + + private _dummyMarkerName = [_originalMarkerName] call _toDummyMarkerName; + _hoverMetaMap getOrDefault [_dummyMarkerName, []] +}; + +private _readSideFromStore = { + params ["_markerName"]; + + if !(_markerName isEqualType "") exitWith { + nil + }; + + if (_markerName == "") exitWith { + nil + }; + + private _sidesVariableSource = missionNamespace getVariable + ["sidesX", objNull]; + + if (isNull _sidesVariableSource) exitWith { + nil + }; + + _sidesVariableSource getVariable [_markerName, nil] +}; + +private _getMarkerSideFromColor = { + params ["_markerName"]; + + if !(_markerName isEqualType "") exitWith { + sideUnknown + }; + + if !(_markerName in allMapMarkers) exitWith { + sideUnknown + }; + + private _markerColor = markerColor _markerName; + + if (_markerColor == colorTeamPlayer) exitWith { + teamPlayer + }; + + if (_markerColor == colorOccupants) exitWith { + Occupants + }; + + if (_markerColor == colorInvaders) exitWith { + Invaders + }; + + sideUnknown +}; + +private _getMarkerSideFromMetadata = { + params ["_markerName"]; + + private _markerMetadata = [_markerName] call _readHoverMetadata; + if (_markerMetadata isEqualTo [] || {count _markerMetadata < 2}) exitWith { + sideUnknown + }; + + private _flagMarkerType = _markerMetadata # 1; + if !(_flagMarkerType isEqualType "") exitWith { + sideUnknown + }; + + if (_flagMarkerType == "") exitWith { + sideUnknown + }; + + private _rebelFlagMarkerType = + [_rebelFaction, "flagMarkerType", ""] call _getMapValue; + private _occupierFlagMarkerType = + [_occupierFaction, "flagMarkerType", ""] call _getMapValue; + private _invaderFlagMarkerType = + [_invaderFaction, "flagMarkerType", ""] call _getMapValue; + + if (_flagMarkerType == _rebelFlagMarkerType) exitWith { + teamPlayer + }; + + if (_flagMarkerType == _occupierFlagMarkerType) exitWith { + Occupants + }; + + if (_flagMarkerType == _invaderFlagMarkerType) exitWith { + Invaders + }; + + sideUnknown +}; + +private _getMarkerSide = { + params ["_markerName"]; + + if !(_markerName isEqualType "") exitWith { + sideUnknown + }; + + private _originalMarkerName = [_markerName] call _getOriginalMarkerName; + if (_originalMarkerName == "") then { + _originalMarkerName = _markerName; + }; + + if (_originalMarkerName in milAdministrationsX) exitWith { + Occupants + }; + + private _markerNameLower = toLowerANSI _originalMarkerName; + if ( + _markerNameLower == "synd_hq" + || {_markerNameLower == "rallypointmarker"} + ) exitWith { + teamPlayer + }; + + private _markerSide = [_markerName] call _readSideFromStore; + if (!isNil "_markerSide") exitWith { + _markerSide + }; + + _markerSide = [_originalMarkerName] call _readSideFromStore; + if (!isNil "_markerSide") exitWith { + _markerSide + }; + + private _dummyMarkerName = [_originalMarkerName] call _toDummyMarkerName; + _markerSide = [_dummyMarkerName] call _readSideFromStore; + if (!isNil "_markerSide") exitWith { + _markerSide + }; + + _markerSide = [_markerName] call _getMarkerSideFromMetadata; + if (_markerSide isNotEqualTo sideUnknown) exitWith { + _markerSide + }; + + _markerSide = [_originalMarkerName] call _getMarkerSideFromMetadata; + if (_markerSide isNotEqualTo sideUnknown) exitWith { + _markerSide + }; + + _markerSide = [_dummyMarkerName] call _getMarkerSideFromMetadata; + if (_markerSide isNotEqualTo sideUnknown) exitWith { + _markerSide + }; + + _markerSide = [_markerName] call _getMarkerSideFromColor; + if (_markerSide isNotEqualTo sideUnknown) exitWith { + _markerSide + }; + + _markerSide = [_originalMarkerName] call _getMarkerSideFromColor; + if (_markerSide isNotEqualTo sideUnknown) exitWith { + _markerSide + }; + + _markerSide = [_dummyMarkerName] call _getMarkerSideFromColor; + if (_markerSide isNotEqualTo sideUnknown) exitWith { + _markerSide + }; + + sideUnknown +}; + +private _isMarkerHidden = { + params ["_markerName"]; + + if !(_markerName isEqualType "") exitWith { + false + }; + + private _originalMarkerName = [_markerName] call _getOriginalMarkerName; + if (_originalMarkerName == "") exitWith { + false + }; + + private _hideEnemyMarkers = if (isNil "hideEnemyMarkers") then { + false + } else { + hideEnemyMarkers + }; + + if (!_hideEnemyMarkers) exitWith { + false + }; + + private _revealedZones = if (isNil "revealedZones") then { + [] + } else { + revealedZones + }; + + private _immuneMarkers = if (isNil "markersImmune") then { + [] + } else { + markersImmune + }; + + if (_originalMarkerName in _revealedZones) exitWith { + false + }; + + if (_originalMarkerName in _immuneMarkers) exitWith { + false + }; + + if ("cont" in _originalMarkerName) exitWith { + false + }; + + if ( + _originalMarkerName in citiesX + || {_originalMarkerName in airportsX} + ) exitWith { + false + }; + + private _markerSide = [_originalMarkerName] call _getMarkerSide; + _markerSide isNotEqualTo sideUnknown + && {_markerSide isNotEqualTo resistance} +}; + +private _getFactionDisplayNameBySide = { + params ["_markerSide"]; + + private _factionData = switch (_markerSide) do { + case Occupants: { + _occupierFaction + }; + case Invaders: { + _invaderFaction + }; + case teamPlayer; + case resistance: { + _rebelFaction + }; + default { + createHashMap + }; + }; + + private _factionName = [_factionData, "name", ""] call _getMapValue; + if (_factionName == "") then { + _factionName = [_factionData, "shortName", ""] call _getMapValue; + }; + + if (_factionName == "") then { + _factionName = [_factionData, "displayName", ""] call _getMapValue; + }; + + _factionName +}; + +private _getFactionName = { + params ["_markerName"]; + + private _markerSide = [_markerName] call _getMarkerSide; + private _factionName = [_markerSide] call _getFactionDisplayNameBySide; + + switch (_markerSide) do { + case teamPlayer; + case resistance: { + if (_factionName == "") then { + _factionName = "Rebels"; + }; + + format ["%1 (reb)", _factionName] + }; + case Occupants: { + if (_factionName == "") then { + _factionName = "Occupiers"; + }; + + format ["%1 (occ)", _factionName] + }; + case Invaders: { + if (_factionName == "") then { + _factionName = "Invaders"; + }; + + format ["%1 (inv)", _factionName] + }; + default { + "Unknown" + }; + }; +}; + +private _getMarkerLabelFromMetadata = { + params ["_markerName"]; + + private _hoverMetaMap = missionNamespace getVariable + ["A3U_mrkHoverMetaMap", createHashMap]; + + private _markerMetadata = _hoverMetaMap getOrDefault [_markerName, []]; + if (_markerMetadata isEqualTo [] || {count _markerMetadata < 1}) then { + private _originalMarkerName = [_markerName] call _getOriginalMarkerName; + private _dummyMarkerName = [_originalMarkerName] call _toDummyMarkerName; + + _markerMetadata = _hoverMetaMap getOrDefault [_originalMarkerName, []]; + if (_markerMetadata isEqualTo [] || {count _markerMetadata < 1}) then { + _markerMetadata = _hoverMetaMap getOrDefault [_dummyMarkerName, []]; + }; + }; + + if !(_markerMetadata isEqualTo [] || {count _markerMetadata < 1}) then { + private _markerText = _markerMetadata # 0; + private _lineBreakIndex = _markerText find "= 0) then { + _markerText = _markerText select [0, _lineBreakIndex]; + }; + + _markerText + } else { + private _originalMarkerName = [_markerName] call _getOriginalMarkerName; + private _markerText = markerText _originalMarkerName; + if (_markerText != "") exitWith { + _markerText + }; + + _originalMarkerName + }; +}; + +private _getMarkerIconFromMetadata = { + params ["_markerName"]; + + private _hoverMetaMap = missionNamespace getVariable + ["A3U_mrkHoverMetaMap", createHashMap]; + private _markerMetadata = _hoverMetaMap getOrDefault [_markerName, []]; + + if (_markerMetadata isEqualTo [] || {count _markerMetadata < 2}) exitWith { + "" + }; + + private _flagMarkerType = _markerMetadata # 1; + if (_flagMarkerType == "") exitWith { + "" + }; + + getText (configFile >> "CfgMarkers" >> _flagMarkerType >> "icon") +}; + +private _getPlainMarkerLabel = { + params ["_markerName"]; + + private _markerLabel = [_markerName] call _getMarkerLabelFromMetadata; + if !(_markerLabel isEqualType "") then { + _markerLabel = str _markerLabel; + }; + + private _originalMarkerName = [_markerName] call _getOriginalMarkerName; + + if (_markerLabel == "" || {_markerLabel find "<" >= 0}) then { + private _fallbackLabel = markerText _originalMarkerName; + if (_fallbackLabel != "") exitWith { + _fallbackLabel + }; + + _originalMarkerName + }; + + _markerLabel +}; + +private _getSearchFilterText = { + params ["_editControl"]; + + if (isNull _editControl) exitWith { + "" + }; + + if (_editControl getVariable ["A3U_markerBrowser_placeholderActive", false]) exitWith { + "" + }; + + ctrlText _editControl +}; + +private _applySearchPlaceholder = { + params ["_editControl", "_searchText"]; + + _editControl setVariable + ["A3U_markerBrowser_placeholderText", _searchPlaceholderText]; + + if (_searchText == "") exitWith { + _editControl ctrlSetText _searchPlaceholderText; + _editControl ctrlSetTextColor [0.65, 0.65, 0.65, 1]; + _editControl setVariable ["A3U_markerBrowser_placeholderActive", true]; + }; + + _editControl ctrlSetText _searchText; + _editControl ctrlSetTextColor [1, 1, 1, 1]; + _editControl setVariable ["A3U_markerBrowser_placeholderActive", false]; +}; + +private _setComboSelectionByData = { + params ["_comboControl", "_wantedData"]; + + private _selectedIndex = 0; + for "_index" from 0 to ((lbSize _comboControl) - 1) do { + if ((_comboControl lbData _index) == _wantedData) exitWith { + _selectedIndex = _index; + }; + }; + + _comboControl lbSetCurSel _selectedIndex; +}; + +private _markerBuckets = [ + ["Cities", "Cities", citiesX apply { [_x] call _toDummyMarkerName }], + ["Resources", "Resources", resourcesX apply { [_x] call _toDummyMarkerName }], + ["Factories", "Factories", factories apply { [_x] call _toDummyMarkerName }], + ["Outposts", "Outpost", outposts apply { [_x] call _toDummyMarkerName }], + ["Seaports", "Seaports", seaports apply { [_x] call _toDummyMarkerName }], + ["Military Bases", "Military Bases", milbases apply { + [_x] call _toDummyMarkerName + }], + ["Air Bases", "Air Bases", airportsX apply { [_x] call _toDummyMarkerName }], + ["Military Administrations", "Military Administrations", +milAdministrationsX] +]; + +private _refreshList = { + private _listControl = _mapDisplay getVariable + ["A3U_markerBrowser_lnb", controlNull]; + private _searchEdit = _mapDisplay getVariable + ["A3U_markerBrowser_search", controlNull]; + private _categoryCombo = _mapDisplay getVariable + ["A3U_markerBrowser_cbCat", controlNull]; + private _factionCombo = _mapDisplay getVariable + ["A3U_markerBrowser_cbFac", controlNull]; + + if ( + isNull _listControl + || {isNull _searchEdit} + || {isNull _categoryCombo} + || {isNull _factionCombo} + ) exitWith {}; + + lnbClear _listControl; + + private _searchText = toLowerANSI ([_searchEdit] call _getSearchFilterText); + private _currentCategoryKey = _categoryCombo lbData (lbCurSel _categoryCombo); + private _currentFactionKey = _factionCombo lbData (lbCurSel _factionCombo); + + _mapDisplay setVariable ["A3U_markerBrowser_selCat", _currentCategoryKey]; + _mapDisplay setVariable ["A3U_markerBrowser_selFac", _currentFactionKey]; + _mapDisplay setVariable + ["A3U_markerBrowser_searchText", [_searchEdit] call _getSearchFilterText]; + + private _addHeaderRow = { + params ["_headerTitle"]; + + private _rowIndex = _listControl lnbAddRow + [format ["— %1 —", _headerTitle], ""]; + _listControl lnbSetData [[_rowIndex, 0], ""]; + _listControl lnbSetColor [[_rowIndex, 0], [0.85, 0.85, 0.85, 1]]; + _listControl lnbSetColor [[_rowIndex, 1], [0.85, 0.85, 0.85, 1]]; + }; + + private _passesFactionFilter = { + params ["_markerName"]; + + if (_currentFactionKey == "__ALL__") exitWith { + true + }; + + private _markerSide = [_markerName] call _getMarkerSide; + if (_markerSide isEqualTo sideUnknown) exitWith { + false + }; + + switch (_currentFactionKey) do { + case "__REB__": { + _markerSide isEqualTo teamPlayer + }; + case "__OCC__": { + _markerSide isEqualTo Occupants + }; + case "__INV__": { + _markerSide isEqualTo Invaders + }; + default { + true + }; + }; + }; + + private _addMarkerRow = { + params ["_markerName"]; + + if ([_markerName] call _isMarkerHidden) exitWith {}; + + if !([_markerName] call _passesFactionFilter) exitWith {}; + + private _markerLabel = [_markerName] call _getPlainMarkerLabel; + if !(_markerLabel isEqualType "") then { + _markerLabel = str _markerLabel; + }; + + if (_markerLabel == "") exitWith {}; + + if ( + _searchText != "" + && {(toLowerANSI _markerLabel) find _searchText < 0} + ) exitWith {}; + + private _factionName = [_markerName] call _getFactionName; + private _rowIndex = _listControl lnbAddRow [_markerLabel, _factionName]; + + _listControl lnbSetData [[_rowIndex, 0], _markerName]; + _listControl lnbSetColor [[_rowIndex, 0], [1, 1, 1, 1]]; + _listControl lnbSetColor [[_rowIndex, 1], [1, 1, 1, 1]]; + + private _iconPath = [_markerName] call _getMarkerIconFromMetadata; + if (_iconPath != "") then { + _listControl lnbSetPicture [[_rowIndex, 0], _iconPath]; + }; + }; + + if (_currentCategoryKey != "__ALL__") then { + { + _x params ["_headerTitle", "_bucketKey", "_markerNames"]; + + if (_bucketKey == _currentCategoryKey) exitWith { + [_headerTitle] call _addHeaderRow; + _markerNames apply { + [_x] call _addMarkerRow; + }; + }; + } forEach _markerBuckets; + } else { + { + _x params ["_headerTitle", "_bucketKey", "_markerNames"]; + + private _bucketHasVisibleEntries = false; + { + private _markerName = _x; + + if ([_markerName] call _isMarkerHidden) then { + continue; + }; + + if !([_markerName] call _passesFactionFilter) then { + continue; + }; + + private _markerLabel = [_markerName] call _getPlainMarkerLabel; + if !(_markerLabel isEqualType "") then { + _markerLabel = str _markerLabel; + }; + + if (_markerLabel == "") then { + continue; + }; + + if ( + _searchText != "" + && {(toLowerANSI _markerLabel) find _searchText < 0} + ) then { + continue; + }; + + _bucketHasVisibleEntries = true; + break; + } forEach _markerNames; + + if (_bucketHasVisibleEntries) then { + [_headerTitle] call _addHeaderRow; + _markerNames apply { + [_x] call _addMarkerRow; + }; + }; + } forEach _markerBuckets; + }; +}; + +private _browserButton = _mapDisplay getVariable + ["A3U_markerBrowser_btn", controlNull]; + +if (isNull _browserButton) then { + _browserButton = _mapDisplay ctrlCreate ["RscStructuredText", 88011]; + if (!isNull _browserButton) then { + private _iconPath = + "\x\A3A\addons\ultimate\data\A3AU_search_icon.paa"; + private _buttonText = format [ + "" + + " Location Browser", + _iconPath + ]; + + _browserButton ctrlSetStructuredText (parseText _buttonText); + _browserButton ctrlSetPosition [0, 0, 0.5, 0.1]; + _browserButton ctrlCommit 0; + + private _horizontalPadding = 0.008; + private _verticalPadding = 4 * pixelH; + private _buttonWidth = + (ctrlTextWidth _browserButton) + _horizontalPadding; + private _buttonHeight = + (ctrlTextHeight _browserButton) + _verticalPadding; + private _buttonPositionX = + safeZoneX + (safeZoneW / 2) - (_buttonWidth / 2); + private _buttonPositionY = safeZoneY + (2 * pixelH); + + _browserButton ctrlSetPosition [ + _buttonPositionX, + _buttonPositionY, + _buttonWidth, + _buttonHeight + ]; + _browserButton ctrlSetBackgroundColor [0, 0, 0, 0.45]; + _browserButton ctrlCommit 0; + + _browserButton setVariable ["A3U_btn_colNormal", [0, 0, 0, 0.45]]; + _browserButton setVariable ["A3U_btn_colHover", [0.10, 0.60, 1.00, 0.60]]; + + _browserButton ctrlAddEventHandler ["MouseEnter", { + params ["_control"]; + + _control ctrlSetBackgroundColor ( + _control getVariable ["A3U_btn_colHover", [0.10, 0.60, 1.00, 0.60]] + ); + }]; + + _browserButton ctrlAddEventHandler ["MouseExit", { + params ["_control"]; + + _control ctrlSetBackgroundColor ( + _control getVariable ["A3U_btn_colNormal", [0, 0, 0, 0.45]] + ); + }]; + + _browserButton ctrlAddEventHandler ["MouseButtonDown", { + params ["_control", "_button"]; + + if (_button != 0) exitWith {}; + + private _display = ctrlParent _control; + if (isNull _display) exitWith {}; + + private _existingBrowserGroup = _display getVariable + ["A3U_markerBrowser_grp", controlNull]; + + private _zoom = _display getVariable ["A3U_markerBrowser_zoom", 0.04]; + private _animationTime = _display getVariable + ["A3U_markerBrowser_anim", 1]; + private _storedCategoryKey = _display getVariable + ["A3U_markerBrowser_selCat", "__ALL__"]; + private _storedFactionKey = _display getVariable + ["A3U_markerBrowser_selFac", "__ALL__"]; + private _storedSearchText = _display getVariable + ["A3U_markerBrowser_searchText", ""]; + + if (isNull _existingBrowserGroup) then { + [ + true, + _zoom, + _animationTime, + _storedCategoryKey, + _storedFactionKey, + _storedSearchText, + false + ] call A3U_fnc_markerBrowser; + } else { + [false] call A3U_fnc_markerBrowser; + }; + }]; + + _mapDisplay setVariable ["A3U_markerBrowser_btn", _browserButton]; + }; +}; + +private _existingBrowserGroup = _mapDisplay getVariable + ["A3U_markerBrowser_grp", controlNull]; + +if (!_toggle) exitWith { + if (!isNull _existingBrowserGroup) then { + ctrlDelete _existingBrowserGroup; + _mapDisplay setVariable ["A3U_markerBrowser_grp", controlNull]; + _mapDisplay setVariable ["A3U_markerBrowser_cbCat", controlNull]; + _mapDisplay setVariable ["A3U_markerBrowser_cbFac", controlNull]; + _mapDisplay setVariable ["A3U_markerBrowser_search", controlNull]; + _mapDisplay setVariable ["A3U_markerBrowser_lnb", controlNull]; + }; +}; + +_mapDisplay setVariable ["A3U_markerBrowser_zoom", _zoom]; +_mapDisplay setVariable ["A3U_markerBrowser_anim", _animationTime]; + +if (_refreshOnly && {!isNull _existingBrowserGroup}) exitWith { + call _refreshList; +}; + +if (!isNull _existingBrowserGroup) then { + ctrlDelete _existingBrowserGroup; + _mapDisplay setVariable ["A3U_markerBrowser_grp", controlNull]; + _mapDisplay setVariable ["A3U_markerBrowser_cbCat", controlNull]; + _mapDisplay setVariable ["A3U_markerBrowser_cbFac", controlNull]; + _mapDisplay setVariable ["A3U_markerBrowser_search", controlNull]; + _mapDisplay setVariable ["A3U_markerBrowser_lnb", controlNull]; +}; + +private _groupWidth = 0.36 * safeZoneW; +private _groupHeight = 0.34 * safeZoneH; +private _currentBrowserButton = _mapDisplay getVariable + ["A3U_markerBrowser_btn", controlNull]; +private _groupPositionY = safeZoneY + (0.02 * safeZoneH); + +if (!isNull _currentBrowserButton) then { + private _buttonPosition = ctrlPosition _currentBrowserButton; + _groupPositionY = + (_buttonPosition # 1) + (_buttonPosition # 3) + (4 * pixelH); +}; + +private _groupPositionX = safeZoneX + (safeZoneW / 2) - (_groupWidth / 2); + +private _browserGroup = _mapDisplay ctrlCreate + ["RscControlsGroupNoScrollbars", -1]; +_browserGroup ctrlSetPosition [ + _groupPositionX, + _groupPositionY, + _groupWidth, + _groupHeight +]; +_browserGroup ctrlCommit 0; +_mapDisplay setVariable ["A3U_markerBrowser_grp", _browserGroup]; + +private _backgroundControl = _mapDisplay ctrlCreate + ["RscText", -1, _browserGroup]; +_backgroundControl ctrlSetPosition [0, 0, _groupWidth, _groupHeight]; +_backgroundControl ctrlSetBackgroundColor [0, 0, 0, 0.40]; +_backgroundControl ctrlCommit 0; + +private _titleHeight = 0.035 * safeZoneH; +private _titleControl = _mapDisplay ctrlCreate + ["RscText", -1, _browserGroup]; +_titleControl ctrlSetPosition [0, 0, _groupWidth, _titleHeight]; +_titleControl ctrlSetText "Location Browser"; +_titleControl ctrlSetBackgroundColor [0.05, 0.05, 0.05, 1]; +_titleControl ctrlCommit 0; + +private _rowHeight = 0.028 * safeZoneH; +private _paddingX = 0.010 * safeZoneW; +private _dropdownPositionY = _titleHeight + 0.008 * safeZoneH; + +private _categoryCombo = _mapDisplay ctrlCreate + ["RscCombo", -1, _browserGroup]; +_categoryCombo ctrlSetPosition [ + _paddingX, + _dropdownPositionY, + 0.16 * safeZoneW, + _rowHeight +]; +_categoryCombo ctrlCommit 0; +_mapDisplay setVariable ["A3U_markerBrowser_cbCat", _categoryCombo]; + +private _factionCombo = _mapDisplay ctrlCreate + ["RscCombo", -1, _browserGroup]; +_factionCombo ctrlSetPosition [ + _paddingX + (0.18 * safeZoneW), + _dropdownPositionY, + 0.16 * safeZoneW, + _rowHeight +]; +_factionCombo ctrlCommit 0; +_mapDisplay setVariable ["A3U_markerBrowser_cbFac", _factionCombo]; + +private _searchPositionY = _dropdownPositionY + _rowHeight + (0.006 * safeZoneH); +private _searchHeight = 0.028 * safeZoneH; + +private _searchEdit = _mapDisplay ctrlCreate ["RscEdit", -1, _browserGroup]; +_searchEdit ctrlSetPosition [ + _paddingX, + _searchPositionY, + _groupWidth - (2 * _paddingX), + _searchHeight +]; +_searchEdit ctrlCommit 0; +[_searchEdit, _searchFilterText] call _applySearchPlaceholder; +_mapDisplay setVariable ["A3U_markerBrowser_search", _searchEdit]; + +_searchEdit ctrlAddEventHandler ["SetFocus", { + params ["_control"]; + + if (_control getVariable ["A3U_markerBrowser_placeholderActive", false]) then { + _control ctrlSetText ""; + _control ctrlSetTextColor [1, 1, 1, 1]; + _control setVariable ["A3U_markerBrowser_placeholderActive", false]; + }; +}]; + +_searchEdit ctrlAddEventHandler ["KillFocus", { + params ["_control"]; + + if ((ctrlText _control) == "") then { + private _placeholderText = _control getVariable + ["A3U_markerBrowser_placeholderText", "Search locations..."]; + + _control ctrlSetText _placeholderText; + _control ctrlSetTextColor [0.65, 0.65, 0.65, 1]; + _control setVariable ["A3U_markerBrowser_placeholderActive", true]; + }; +}]; + +private _listControl = _mapDisplay ctrlCreate + ["RscListNBox", -1, _browserGroup]; +_listControl ctrlSetPosition [ + _paddingX, + _searchPositionY + _searchHeight + (0.008 * safeZoneH), + _groupWidth - (2 * _paddingX), + _groupHeight - (_searchPositionY + _searchHeight + (0.018 * safeZoneH)) +]; +_listControl ctrlCommit 0; +_listControl lnbSetColumnsPos [0.00, 0.70]; +_mapDisplay setVariable ["A3U_markerBrowser_lnb", _listControl]; + +lbClear _categoryCombo; +[ + ["All", "__ALL__"], + ["Cities", "Cities"], + ["Resources", "Resources"], + ["Factories", "Factories"], + ["Outposts", "Outpost"], + ["Seaports", "Seaports"], + ["Military Bases", "Military Bases"], + ["Air Bases", "Air Bases"], + ["Military Administrations", "Military Administrations"] +] apply { + _x params ["_label", "_categoryKey"]; + + private _rowIndex = _categoryCombo lbAdd _label; + _categoryCombo lbSetData [_rowIndex, _categoryKey]; +}; + +lbClear _factionCombo; + +private _allFactionIndex = _factionCombo lbAdd "All"; +_factionCombo lbSetData [_allFactionIndex, "__ALL__"]; + +private _rebelFactionLabel = [teamPlayer] call _getFactionDisplayNameBySide; +if (_rebelFactionLabel == "") then { + _rebelFactionLabel = "Rebels"; +}; +_rebelFactionLabel = format ["%1 (reb)", _rebelFactionLabel]; + +private _occupierFactionLabel = [Occupants] call _getFactionDisplayNameBySide; +if (_occupierFactionLabel == "") then { + _occupierFactionLabel = "Occupiers"; +}; +_occupierFactionLabel = format ["%1 (occ)", _occupierFactionLabel]; + +private _invaderFactionLabel = [Invaders] call _getFactionDisplayNameBySide; +if (_invaderFactionLabel == "") then { + _invaderFactionLabel = "Invaders"; +}; +_invaderFactionLabel = format ["%1 (inv)", _invaderFactionLabel]; + +private _rebelsFactionIndex = _factionCombo lbAdd _rebelFactionLabel; +_factionCombo lbSetData [_rebelsFactionIndex, "__REB__"]; + +private _occupiersFactionIndex = _factionCombo lbAdd _occupierFactionLabel; +_factionCombo lbSetData [_occupiersFactionIndex, "__OCC__"]; + +private _invadersFactionIndex = _factionCombo lbAdd _invaderFactionLabel; +_factionCombo lbSetData [_invadersFactionIndex, "__INV__"]; + +[_categoryCombo, _selectedCategoryKey] call _setComboSelectionByData; +[_factionCombo, _selectedFactionKey] call _setComboSelectionByData; + +call _refreshList; + +_categoryCombo ctrlAddEventHandler ["LBSelChanged", { + params ["_control", "_selectedIndex"]; + + private _display = findDisplay 12; + if (isNull _display) exitWith {}; + + private _factionCombo = _display getVariable + ["A3U_markerBrowser_cbFac", controlNull]; + private _searchEdit = _display getVariable + ["A3U_markerBrowser_search", controlNull]; + + private _categoryKey = _control lbData _selectedIndex; + private _factionKey = if (isNull _factionCombo) then { + "__ALL__" + } else { + _factionCombo lbData (lbCurSel _factionCombo) + }; + private _searchText = if (isNull _searchEdit) then { + "" + } else { + if (_searchEdit getVariable ["A3U_markerBrowser_placeholderActive", false]) then { + "" + } else { + ctrlText _searchEdit + } + }; + + private _zoom = _display getVariable ["A3U_markerBrowser_zoom", 0.04]; + private _animationTime = _display getVariable + ["A3U_markerBrowser_anim", 1]; + + [ + true, + _zoom, + _animationTime, + _categoryKey, + _factionKey, + _searchText, + true + ] call A3U_fnc_markerBrowser; +}]; + +_factionCombo ctrlAddEventHandler ["LBSelChanged", { + params ["_control", "_selectedIndex"]; + + private _display = findDisplay 12; + if (isNull _display) exitWith {}; + + private _categoryCombo = _display getVariable + ["A3U_markerBrowser_cbCat", controlNull]; + private _searchEdit = _display getVariable + ["A3U_markerBrowser_search", controlNull]; + + private _categoryKey = if (isNull _categoryCombo) then { + "__ALL__" + } else { + _categoryCombo lbData (lbCurSel _categoryCombo) + }; + private _factionKey = _control lbData _selectedIndex; + private _searchText = if (isNull _searchEdit) then { + "" + } else { + if (_searchEdit getVariable ["A3U_markerBrowser_placeholderActive", false]) then { + "" + } else { + ctrlText _searchEdit + } + }; + + private _zoom = _display getVariable ["A3U_markerBrowser_zoom", 0.04]; + private _animationTime = _display getVariable + ["A3U_markerBrowser_anim", 1]; + + [ + true, + _zoom, + _animationTime, + _categoryKey, + _factionKey, + _searchText, + true + ] call A3U_fnc_markerBrowser; +}]; + +_searchEdit ctrlAddEventHandler ["KeyUp", { + params ["_control"]; + + private _display = findDisplay 12; + if (isNull _display) exitWith {}; + + private _categoryCombo = _display getVariable + ["A3U_markerBrowser_cbCat", controlNull]; + private _factionCombo = _display getVariable + ["A3U_markerBrowser_cbFac", controlNull]; + + private _categoryKey = if (isNull _categoryCombo) then { + "__ALL__" + } else { + _categoryCombo lbData (lbCurSel _categoryCombo) + }; + private _factionKey = if (isNull _factionCombo) then { + "__ALL__" + } else { + _factionCombo lbData (lbCurSel _factionCombo) + }; + private _searchText = if ( + _control getVariable ["A3U_markerBrowser_placeholderActive", false] + ) then { + "" + } else { + ctrlText _control + }; + + private _zoom = _display getVariable ["A3U_markerBrowser_zoom", 0.04]; + private _animationTime = _display getVariable + ["A3U_markerBrowser_anim", 1]; + + [ + true, + _zoom, + _animationTime, + _categoryKey, + _factionKey, + _searchText, + true + ] call A3U_fnc_markerBrowser; +}]; + +_listControl ctrlAddEventHandler ["LBSelChanged", { + params ["_control", "_rowIndex"]; + + if (_rowIndex < 0) exitWith {}; + + private _markerName = _control lnbData [_rowIndex, 0]; + if (_markerName == "") exitWith {}; + + private _display = ctrlParent _control; + private _mapControl = _display displayCtrl 51; + if (isNull _mapControl) exitWith {}; + + private _zoom = _display getVariable ["A3U_markerBrowser_zoom", 0.04]; + private _animationTime = _display getVariable + ["A3U_markerBrowser_anim", 1]; + + private _targetMarkerName = _markerName; + if !(_targetMarkerName in allMapMarkers) then { + private _originalMarkerName = _targetMarkerName; + while { + (count _originalMarkerName) >= 3 + && {(_originalMarkerName select [0, 3]) == "Dum"} + } do { + _originalMarkerName = _originalMarkerName select + [3, (count _originalMarkerName) - 3]; + }; + + _targetMarkerName = _originalMarkerName; + }; + + if !(_targetMarkerName in allMapMarkers) exitWith {}; + + _mapControl ctrlMapAnimAdd + [_animationTime, _zoom, getMarkerPos _targetMarkerName]; + ctrlMapAnimCommit _mapControl; +}]; \ No newline at end of file diff --git a/A3A/addons/ultimate/functions/map/fn_markerContextMenu.sqf b/A3A/addons/ultimate/functions/map/fn_markerContextMenu.sqf new file mode 100644 index 0000000000..ac7a23da6d --- /dev/null +++ b/A3A/addons/ultimate/functions/map/fn_markerContextMenu.sqf @@ -0,0 +1,679 @@ +#include "..\..\script_component.hpp" +FIX_LINE_NUMBERS() +/* ---------------------------------------------------------------------------- +Function: A3U_fnc_markerContextMenu + +Description: + Builds and toggles the contextual action menu for a hovered strategic map + marker, including optional marker info and garrison details. + +Parameters: + 0: _markerName - Marker name or dummy marker name to open the menu for + + +Optional: + 1: _screenPosition - Screen position used to anchor the menu + (default: []) + +Example: + ["marker_1", getMousePosition] call A3U_fnc_markerContextMenu; + +Returns: + Nothing + +Environment: + Client, Unscheduled + +Author: + Maxx +---------------------------------------------------------------------------- */ + +// Existing A3U_fnc_* public function name kept for backwards compatibility. + +if !assert(params [ + ["_markerName", nil, [""]] +]) exitWith {}; + +private _screenPosition = param [1, [], [[]]]; + +private _mapDisplay = findDisplay 12; +if (isNull _mapDisplay || {_markerName == ""}) exitWith {}; + +private _mapControl = _mapDisplay displayCtrl 51; +if (isNull _mapControl) exitWith {}; + +// Legacy A3U_* display-variable keys are kept for compatibility with the +// existing hover/menu code that already shares these values across files. + +private _getOriginalMarkerName = { + params ["_name"]; + + private _originalMarkerName = _name; + while { + (count _originalMarkerName) >= 3 + && {(_originalMarkerName select [0, 3]) == "Dum"} + } do { + _originalMarkerName = _originalMarkerName select + [3, (count _originalMarkerName) - 3]; + }; + + _originalMarkerName +}; + +private _findSubstringIndex = { + params ["_text", "_substring"]; + + private _textLength = count _text; + private _substringLength = count _substring; + if (_substringLength == 0 || {_textLength < _substringLength}) exitWith { + -1 + }; + + private _substringIndex = -1; + for "_index" from 0 to (_textLength - _substringLength) do { + if ((_text select [_index, _substringLength]) == _substring) exitWith { + _substringIndex = _index; + }; + }; + + _substringIndex +}; + +private _setButtonState = { + params [ + "_buttonControl", + "_enabled", + ["_tooltipText", "", [""]] + ]; + + _buttonControl ctrlEnable _enabled; + + if (_enabled) then { + _buttonControl ctrlSetTextColor [1, 1, 1, 1]; + _buttonControl ctrlSetTooltip ""; + } else { + _buttonControl ctrlSetTextColor [1, 1, 1, 0.35]; + if (_tooltipText != "") then { + _buttonControl ctrlSetTooltip _tooltipText; + }; + }; +}; + +private _deleteGarrisonPanel = { + params ["_display"]; + + if (isNull _display) exitWith {}; + + private _garrisonGroup = _display getVariable + ["A3U_mrkMenu_garrGrp", controlNull]; + if (!isNull _garrisonGroup) then { + ctrlDelete _garrisonGroup; + }; + + _display setVariable ["A3U_mrkMenu_garrGrp", controlNull]; +}; + +private _originalMarkerName = [_markerName] call _getOriginalMarkerName; +private _markerSide = sidesX getVariable [_originalMarkerName, sideUnknown]; +private _isPlayerControlled = _markerSide == teamPlayer; + +private _isRallyPoint = + (toLowerANSI _originalMarkerName) isEqualTo "rallypointmarker"; +private _isMilitaryAdministration = + _originalMarkerName in milAdministrationsX; + +private _destroyedMilitaryAdministrations = + if (isNil "A3A_destroyedMilAdministrations") then { + [] + } else { + A3A_destroyedMilAdministrations + }; + +private _originalMarkerPosition = getMarkerPos _originalMarkerName; + +private _isMilitaryAdministrationDestroyed = _isMilitaryAdministration && { + _destroyedMilitaryAdministrations findIf { + !isNull _x && {_originalMarkerPosition distance2D _x < 30} + } != -1 +}; + +private _revealedZones = if (isNil "revealedZones") then { + [] +} else { + revealedZones +}; + +private _immuneMarkers = if (isNil "markersImmune") then { + [] +} else { + markersImmune +}; + +private _hiddenCheckSide = sidesX getVariable [_originalMarkerName, sideUnknown]; + +private _hideEnemyMarkers = missionNamespace getVariable + ["hideEnemyMarkers", false]; + +private _isHiddenMarker = _hideEnemyMarkers + && {!(_originalMarkerName in _revealedZones)} + && {!(_originalMarkerName in _immuneMarkers)} + && {!("cont" in _originalMarkerName)} + && {!(_originalMarkerName in citiesX)} + && {!(_originalMarkerName in airportsX)} + && {_hiddenCheckSide isNotEqualTo sideUnknown} + && {_hiddenCheckSide isNotEqualTo resistance}; + +if (_isHiddenMarker) exitWith {}; + +private _hoverMetaMap = missionNamespace getVariable + ["A3U_mrkHoverMetaMap", createHashMap]; +private _markerMetadata = _hoverMetaMap getOrDefault [ + _markerName, + (_hoverMetaMap getOrDefault [_originalMarkerName, []]) +]; + +private _bodyText = if ( + _markerMetadata isEqualTo [] + || {count _markerMetadata < 1} +) then { + private _markerLabel = markerText _originalMarkerName; + if (_markerLabel == "") then { + format ["%1", _originalMarkerName] + } else { + _markerLabel + } +} else { + _markerMetadata # 0 +}; + +private _flagMarkerType = if ( + _markerMetadata isEqualTo [] + || {count _markerMetadata < 2} +) then { + "" +} else { + _markerMetadata # 1 +}; + +private _flagIconPath = ""; +if (_flagMarkerType != "") then { + _flagIconPath = getText + (configFile >> "CfgMarkers" >> _flagMarkerType >> "icon"); +}; + +private _lineBreakToken = "
"; +private _firstLineBreakIndex = + [_bodyText, _lineBreakToken] call _findSubstringIndex; + +private _titleLabel = if (_firstLineBreakIndex >= 0) then { + _bodyText select [0, _firstLineBreakIndex] +} else { + _bodyText +}; + +if (_titleLabel == "") then { + _titleLabel = markerText _originalMarkerName; + + if (_titleLabel == "") then { + _titleLabel = _originalMarkerName; + }; + + if (_titleLabel == _originalMarkerName) then { + private _markerLabel = markerText _markerName; + if (_markerLabel != "") then { + _titleLabel = _markerLabel; + }; + }; + + if (_titleLabel == "" || {_titleLabel == _originalMarkerName}) then { + _titleLabel = _markerName; + }; +}; + +private _informationText = ""; +if (_firstLineBreakIndex >= 0) then { + _informationText = _bodyText select [ + _firstLineBreakIndex + (count _lineBreakToken), + (count _bodyText) - (_firstLineBreakIndex + (count _lineBreakToken)) + ]; +}; + +if (_informationText == "") then { + _informationText = "No additional info."; +}; + +private _existingMenuGroup = _mapDisplay getVariable + ["A3U_mrkMenu_grp", controlNull]; +private _openMarkerName = _mapDisplay getVariable ["A3U_mrkMenu_marker", ""]; + +if (!isNull _existingMenuGroup && {_openMarkerName == _markerName}) exitWith { + ctrlDelete _existingMenuGroup; + [_mapDisplay] call _deleteGarrisonPanel; + _mapDisplay setVariable ["A3U_mrkMenu_grp", controlNull]; + _mapDisplay setVariable ["A3U_mrkMenu_marker", ""]; +}; + +if (!isNull _existingMenuGroup) then { + ctrlDelete _existingMenuGroup; + [_mapDisplay] call _deleteGarrisonPanel; + _mapDisplay setVariable ["A3U_mrkMenu_grp", controlNull]; +}; + +private _resolvedScreenPosition = _screenPosition; +if (_resolvedScreenPosition isEqualTo []) then { + _resolvedScreenPosition = + _mapControl ctrlMapWorldToScreen (getMarkerPos _markerName); +}; + +if (_resolvedScreenPosition isEqualTo []) then { + _resolvedScreenPosition = getMousePosition; +}; + +private _groupWidth = 0.22 * safeZoneW; +private _groupHeight = 0.16 * safeZoneH; +private _titleBarHeight = 0.028 * safeZoneH; + +private _groupPositionX = (_resolvedScreenPosition # 0) + 0.012; +private _groupPositionY = (_resolvedScreenPosition # 1) + 0.018; + +private _maximumPositionX = + safeZoneX + safeZoneW - _groupWidth - (2 * pixelW); +private _maximumPositionY = + safeZoneY + safeZoneH - _groupHeight - (2 * pixelH); + +_groupPositionX = + (_groupPositionX max (safeZoneX + (2 * pixelW))) min _maximumPositionX; +_groupPositionY = + (_groupPositionY max (safeZoneY + (2 * pixelH))) min _maximumPositionY; + +private _menuGroup = _mapDisplay ctrlCreate ["RscControlsGroupNoScrollbars", -1]; +_menuGroup ctrlSetPosition [ + _groupPositionX, + _groupPositionY, + _groupWidth, + _groupHeight +]; +_menuGroup ctrlCommit 0; + +_mapDisplay setVariable ["A3U_mrkMenu_grp", _menuGroup]; +_mapDisplay setVariable ["A3U_mrkMenu_marker", _markerName]; +_mapDisplay setVariable ["A3U_mrkMenu_markerOrig", _originalMarkerName]; + +private _backgroundControl = _mapDisplay ctrlCreate ["RscText", -1, _menuGroup]; +_backgroundControl ctrlSetPosition [0, 0, _groupWidth, _groupHeight]; +_backgroundControl ctrlSetBackgroundColor [0, 0, 0, 0.55]; +_backgroundControl ctrlCommit 0; + +private _profileBackgroundColor = [ + profileNamespace getVariable ["GUI_BCG_RGB_R", 0.376], + profileNamespace getVariable ["GUI_BCG_RGB_G", 0.125], + profileNamespace getVariable ["GUI_BCG_RGB_B", 0.043], + 1 +]; + +private _titleBarControl = _mapDisplay ctrlCreate ["RscText", -1, _menuGroup]; +_titleBarControl ctrlSetPosition [0, 0, _groupWidth, _titleBarHeight]; +_titleBarControl ctrlSetBackgroundColor _profileBackgroundColor; +_titleBarControl ctrlCommit 0; + +private _titleControl = _mapDisplay ctrlCreate + ["RscStructuredText", -1, _menuGroup]; + +private _titleStructuredText = if (_flagIconPath != "") then { + format [ + " %2", + _flagIconPath, + _titleLabel + ] +} else { + format [ + "%1", + _titleLabel + ] +}; + +_titleControl ctrlSetStructuredText (parseText _titleStructuredText); + +private _titlePositionX = 0.006 * safeZoneW; +private _titleWidth = _groupWidth - (0.012 * safeZoneW); +_titleControl ctrlSetPosition [_titlePositionX, 0, _titleWidth, _titleBarHeight]; +_titleControl ctrlCommit 0; + +private _titleTextHeight = ctrlTextHeight _titleControl; +if (_titleTextHeight <= 0) then { + _titleTextHeight = _titleBarHeight; +}; + +_titleTextHeight = _titleTextHeight min _titleBarHeight; + +private _titlePositionY = (_titleBarHeight - _titleTextHeight) / 2; +_titleControl ctrlSetPosition [ + _titlePositionX, + _titlePositionY, + _titleWidth, + _titleTextHeight +]; +_titleControl ctrlCommit 0; + +private _paddingX = 0.006 * safeZoneW; +private _paddingY = 0.006 * safeZoneH; + +private _contentPositionY = _titleBarHeight + _paddingY; +private _contentHeight = _groupHeight - _titleBarHeight - (2 * _paddingY); + +private _leftColumnWidth = (_groupWidth - (3 * _paddingX)) / 3; +private _rightColumnWidth = (_groupWidth - (3 * _paddingX)) - _leftColumnWidth; + +private _leftColumnPositionX = _paddingX; +private _rightColumnPositionX = + _paddingX + _leftColumnWidth + _paddingX; + +private _leftColumnBackground = _mapDisplay ctrlCreate + ["RscText", -1, _menuGroup]; +_leftColumnBackground ctrlSetPosition [ + _leftColumnPositionX, + _contentPositionY, + _leftColumnWidth, + _contentHeight +]; +_leftColumnBackground ctrlSetBackgroundColor [0, 0, 0, 0.25]; +_leftColumnBackground ctrlCommit 0; + +private _rightColumnBackground = _mapDisplay ctrlCreate + ["RscText", -1, _menuGroup]; +_rightColumnBackground ctrlSetPosition [ + _rightColumnPositionX, + _contentPositionY, + _rightColumnWidth, + _contentHeight +]; +_rightColumnBackground ctrlSetBackgroundColor [0, 0, 0, 0.10]; +_rightColumnBackground ctrlCommit 0; + +private _informationControl = _mapDisplay ctrlCreate + ["RscStructuredText", -1, _menuGroup]; +_informationControl ctrlSetPosition [ + _rightColumnPositionX + (_paddingX * 0.5), + _contentPositionY + (_paddingY * 0.5), + _rightColumnWidth - _paddingX, + _contentHeight - _paddingY +]; +_informationControl ctrlSetStructuredText (parseText _informationText); +_informationControl ctrlCommit 0; + +[_mapDisplay] call _deleteGarrisonPanel; + +private _garrisonCount = + count (garrison getVariable [_originalMarkerName, []]); +if ( + !_isRallyPoint + && {!_isMilitaryAdministration} + && {_isPlayerControlled} + && {_garrisonCount > 0} +) then { + private _garrisonInfoRaw = + [_originalMarkerName] call A3A_fnc_garrisonInfo; + private _garrisonInfoText = _garrisonInfoRaw; + + private _garrisonStartIndex = + [_garrisonInfoRaw, "Squad Leaders:"] call _findSubstringIndex; + if (_garrisonStartIndex >= 0) then { + _garrisonInfoText = _garrisonInfoRaw select [ + _garrisonStartIndex, + (count _garrisonInfoRaw) - _garrisonStartIndex + ]; + }; + + if (_garrisonInfoText != "") then { + private _garrisonGap = 0.003 * safeZoneW; + private _garrisonGroupWidth = 0.10 * safeZoneW; + private _garrisonGroupHeight = 0.31 * safeZoneH; + private _garrisonTitleHeight = _titleBarHeight; + + private _garrisonPositionX = + _groupPositionX + _groupWidth + _garrisonGap; + if ( + (_garrisonPositionX + _garrisonGroupWidth) + > (safeZoneX + safeZoneW - (2 * pixelW)) + ) then { + _garrisonPositionX = + _groupPositionX - _garrisonGap - _garrisonGroupWidth; + }; + + private _garrisonPositionY = _groupPositionY; + private _garrisonMaximumX = + safeZoneX + safeZoneW - _garrisonGroupWidth - (2 * pixelW); + private _garrisonMaximumY = + safeZoneY + safeZoneH - _garrisonGroupHeight - (2 * pixelH); + + _garrisonPositionX = + (_garrisonPositionX max (safeZoneX + (2 * pixelW))) + min _garrisonMaximumX; + _garrisonPositionY = + (_garrisonPositionY max (safeZoneY + (2 * pixelH))) + min _garrisonMaximumY; + + private _garrisonGroup = _mapDisplay ctrlCreate + ["RscControlsGroupNoScrollbars", -1]; + _garrisonGroup ctrlSetPosition [ + _garrisonPositionX, + _garrisonPositionY, + _garrisonGroupWidth, + _garrisonGroupHeight + ]; + _garrisonGroup ctrlCommit 0; + + private _garrisonBackground = _mapDisplay ctrlCreate + ["RscText", -1, _garrisonGroup]; + _garrisonBackground ctrlSetPosition + [0, 0, _garrisonGroupWidth, _garrisonGroupHeight]; + _garrisonBackground ctrlSetBackgroundColor [0, 0, 0, 0.55]; + _garrisonBackground ctrlCommit 0; + + private _garrisonTitleBar = _mapDisplay ctrlCreate + ["RscText", -1, _garrisonGroup]; + _garrisonTitleBar ctrlSetPosition + [0, 0, _garrisonGroupWidth, _garrisonTitleHeight]; + _garrisonTitleBar ctrlSetBackgroundColor _profileBackgroundColor; + _garrisonTitleBar ctrlCommit 0; + + private _garrisonTitleControl = _mapDisplay ctrlCreate + ["RscStructuredText", -1, _garrisonGroup]; + private _garrisonTitleText = format [ + "%1", + localize "STR_A3A_garrison_header" + ]; + _garrisonTitleControl ctrlSetStructuredText + (parseText _garrisonTitleText); + + private _garrisonTitlePositionX = 0.006 * safeZoneW; + private _garrisonTitleWidth = + _garrisonGroupWidth - (0.012 * safeZoneW); + _garrisonTitleControl ctrlSetPosition [ + _garrisonTitlePositionX, + 0, + _garrisonTitleWidth, + _garrisonTitleHeight + ]; + _garrisonTitleControl ctrlCommit 0; + + private _garrisonTitleTextHeight = + ctrlTextHeight _garrisonTitleControl; + if (_garrisonTitleTextHeight <= 0) then { + _garrisonTitleTextHeight = _garrisonTitleHeight; + }; + + _garrisonTitleTextHeight = + _garrisonTitleTextHeight min _garrisonTitleHeight; + + private _garrisonTitlePositionY = + (_garrisonTitleHeight - _garrisonTitleTextHeight) / 2; + _garrisonTitleControl ctrlSetPosition [ + _garrisonTitlePositionX, + _garrisonTitlePositionY, + _garrisonTitleWidth, + _garrisonTitleTextHeight + ]; + _garrisonTitleControl ctrlCommit 0; + + private _garrisonPaddingX = 0.006 * safeZoneW; + private _garrisonPaddingY = 0.006 * safeZoneH; + + private _garrisonInfoControl = _mapDisplay ctrlCreate + ["RscStructuredText", -1, _garrisonGroup]; + _garrisonInfoControl ctrlSetPosition [ + _garrisonPaddingX, + _garrisonTitleHeight + _garrisonPaddingY, + _garrisonGroupWidth - (2 * _garrisonPaddingX), + _garrisonGroupHeight - _garrisonTitleHeight + - (2 * _garrisonPaddingY) + ]; + _garrisonInfoControl ctrlSetStructuredText + (parseText _garrisonInfoText); + _garrisonInfoControl ctrlCommit 0; + + _mapDisplay setVariable ["A3U_mrkMenu_garrGrp", _garrisonGroup]; + }; +}; + +private _isCommander = player isEqualTo theBoss; + +private _buttonCount = 4; +private _buttonGap = 0.004 * safeZoneH; + +private _buttonHeight = + (_contentHeight - (_buttonGap * (_buttonCount - 1))) / _buttonCount; +private _buttonWidth = _leftColumnWidth - _paddingX; +private _buttonPositionX = _leftColumnPositionX + (_paddingX * 0.5); + +private _topBottomPadding = _paddingY * 0.5; +private _buttonPositionY = _contentPositionY + _topBottomPadding; + +private _fastTravelButton = _mapDisplay ctrlCreate + ["A3U_RscContextButton", -1, _menuGroup]; +_fastTravelButton ctrlSetPosition [ + _buttonPositionX, + _buttonPositionY, + _buttonWidth, + _buttonHeight +]; +_fastTravelButton ctrlSetText + localize "STR_antistasi_dialogs_main_fast_travel"; +_fastTravelButton ctrlCommit 0; + +_fastTravelButton ctrlAddEventHandler ["ButtonClick", { + params ["_control"]; + + private _display = ctrlParent _control; + private _markerName = _display getVariable ["A3U_mrkMenu_markerOrig", ""]; + if (_markerName == "") exitWith {}; + + [_markerName] spawn A3A_fnc_fastTravelRadio; +}]; + +private _fastTravelAllowed = + _isPlayerControlled && {!_isMilitaryAdministrationDestroyed}; + +private _fastTravelTooltip = if (_isMilitaryAdministrationDestroyed) then { + localize "STR_A3U_HOVER_DESTROYED_MILADMIN" +} else { + localize "STR_A3U_CONTEXT_FASTTRAVEL_PLAYER_ONLY" +}; + +[_fastTravelButton, _fastTravelAllowed, _fastTravelTooltip] + call _setButtonState; + +_buttonPositionY = _buttonPositionY + _buttonHeight + _buttonGap; + +private _garrisonButton = _mapDisplay ctrlCreate + ["A3U_RscContextButton", -1, _menuGroup]; +_garrisonButton ctrlSetPosition [ + _buttonPositionX, + _buttonPositionY, + _buttonWidth, + _buttonHeight +]; +_garrisonButton ctrlSetText localize "STR_A3A_garrison_header"; +_garrisonButton ctrlCommit 0; + +_garrisonButton ctrlAddEventHandler ["ButtonClick", { + params ["_control"]; + + private _display = ctrlParent _control; + private _markerName = _display getVariable ["A3U_mrkMenu_markerOrig", ""]; + if (_markerName == "") exitWith {}; + + ["add", _markerName] spawn A3A_fnc_garrisonDialog; + ["off"] call SCRT_fnc_ui_toggleMenuBlur; +}]; + +private _isBlackMarketTrader = + (toLowerANSI _originalMarkerName) isEqualTo "tradermarker"; + +private _isFiaBuildZone = _originalMarkerName in ( + watchpostsFIA + + roadblocksFIA + + aapostsFIA + + atpostsFIA + + hmgpostsFIA +); + +private _garrisonAllowed = _isPlayerControlled + && {_isCommander} + && {!_isRallyPoint} + && {!_isBlackMarketTrader} + && {!_isFiaBuildZone} + && {!_isMilitaryAdministration}; + +private _garrisonTooltip = localize (switch true do { + case _isRallyPoint: { + "STR_A3U_CONTEXT_GARRISON_RALLYPOINT_BLOCKED" + }; + case _isBlackMarketTrader: { + "STR_A3U_CONTEXT_GARRISON_TRADER_BLOCKED" + }; + case _isFiaBuildZone: { + "STR_A3U_CONTEXT_GARRISON_FIA_BLOCKED" + }; + default { + "STR_A3U_CONTEXT_GARRISON_REQUIREMENTS" + }; +}); + +[_garrisonButton, _garrisonAllowed, _garrisonTooltip] + call _setButtonState; + +private _closeButtonPositionY = + _contentPositionY + _contentHeight - _topBottomPadding - _buttonHeight; + +private _closeButton = _mapDisplay ctrlCreate + ["A3U_RscContextButton", -1, _menuGroup]; +_closeButton ctrlSetPosition [ + _buttonPositionX, + _closeButtonPositionY, + _buttonWidth, + _buttonHeight +]; +_closeButton ctrlSetText "Close"; +_closeButton ctrlCommit 0; + +_closeButton ctrlAddEventHandler ["ButtonClick", { + params ["_control"]; + + private _display = ctrlParent _control; + private _menuGroup = _display getVariable ["A3U_mrkMenu_grp", controlNull]; + private _garrisonGroup = _display getVariable + ["A3U_mrkMenu_garrGrp", controlNull]; + + if (!isNull _menuGroup) then { + ctrlDelete _menuGroup; + }; + + if (!isNull _garrisonGroup) then { + ctrlDelete _garrisonGroup; + }; + + _display setVariable ["A3U_mrkMenu_grp", controlNull]; + _display setVariable ["A3U_mrkMenu_garrGrp", controlNull]; + _display setVariable ["A3U_mrkMenu_marker", ""]; +}]; diff --git a/A3A/addons/ultimate/functions/map/fn_mrkUpdateBulk.sqf b/A3A/addons/ultimate/functions/map/fn_mrkUpdateBulk.sqf new file mode 100644 index 0000000000..8e3ae753ac --- /dev/null +++ b/A3A/addons/ultimate/functions/map/fn_mrkUpdateBulk.sqf @@ -0,0 +1,43 @@ +#include "..\..\script_component.hpp" +FIX_LINE_NUMBERS() +/* ---------------------------------------------------------------------------- +Function: A3U_fnc_mrkUpdateBulk + +Description: + Refreshes marker visuals and hover metadata for multiple markers in a single + remote execution / JIP entry. + +Parameters: + 0: _markerNames - Marker names to refresh + +Optional: + None. + +Example: + [citiesX + airportsX] call A3U_fnc_mrkUpdateBulk; + +Returns: + Nothing + +Environment: + Client, Unscheduled + +Author: + Maxx +---------------------------------------------------------------------------- */ + +if !assert(params [ + ["_markerNames", nil, [[]]] +]) exitWith {}; + +private _uniqueMarkerNames = []; + +_markerNames apply { + if (_x isEqualType "" && {_x != ""}) then { + _uniqueMarkerNames pushBackUnique _x; + }; +}; + +_uniqueMarkerNames apply { + [_x] call A3A_fnc_mrkUpdate; +}; \ No newline at end of file diff --git a/A3A/addons/ultimate/functions/map/fn_tooltipCreate.sqf b/A3A/addons/ultimate/functions/map/fn_tooltipCreate.sqf new file mode 100644 index 0000000000..1464566182 --- /dev/null +++ b/A3A/addons/ultimate/functions/map/fn_tooltipCreate.sqf @@ -0,0 +1,72 @@ +#include "..\..\script_component.hpp" +FIX_LINE_NUMBERS() +/* ---------------------------------------------------------------------------- +Function: A3U_fnc_tooltipCreate + +Description: + Creates or reuses the tooltip controls used by the hover system on the map + display and returns them for later updates. + +Parameters: + 0: _mapDisplay - Map display that owns the tooltip controls + +Optional: + None. + +Example: + [findDisplay 12] call A3U_fnc_tooltipCreate; + +Returns: + Tooltip, ring, and ripple controls + +Environment: + Client, Unscheduled + +Author: + Maxx +---------------------------------------------------------------------------- */ + +// Existing A3U_fnc_* public function name kept for backwards compatibility. + +if !assert(params [ + ["_mapDisplay", nil, [displayNull]] +]) exitWith { + [controlNull, controlNull, controlNull] +}; + +private _tooltipControlId = 88001; +private _hoverRingControlId = 88002; +private _rippleControlId = 88003; + +private _tooltipControl = _mapDisplay displayCtrl _tooltipControlId; +private _hoverRingControl = _mapDisplay displayCtrl _hoverRingControlId; +private _rippleControl = _mapDisplay displayCtrl _rippleControlId; + +if (isNull _hoverRingControl) then { + _hoverRingControl = _mapDisplay ctrlCreate + ["RscPictureKeepAspect", _hoverRingControlId]; + _hoverRingControl ctrlShow false; + _hoverRingControl ctrlSetText + "\x\A3A\addons\ultimate\data\A3AU_hover_icon.paa"; + _hoverRingControl ctrlSetPosition [0, 0, 0, 0]; + _hoverRingControl ctrlCommit 0; +}; + +if (isNull _rippleControl) then { + _rippleControl = _mapDisplay ctrlCreate + ["RscPictureKeepAspect", _rippleControlId]; + _rippleControl ctrlShow false; + _rippleControl ctrlSetText + "\x\A3A\addons\ultimate\data\A3AU_hover_icon.paa"; + _rippleControl ctrlSetPosition [0, 0, 0, 0]; + _rippleControl ctrlCommit 0; +}; + +if (isNull _tooltipControl) then { + _tooltipControl = _mapDisplay ctrlCreate + ["RscStructuredText", _tooltipControlId]; + _tooltipControl ctrlShow false; + _tooltipControl ctrlSetBackgroundColor [0, 0, 0, 0]; +}; + +[_tooltipControl, _hoverRingControl, _rippleControl]