2023-07-08 23:42:42 +03:00
|
|
|
using Comfort.Common;
|
|
|
|
using EFT;
|
|
|
|
using EFT.InventoryLogic;
|
|
|
|
using EFT.UI;
|
|
|
|
using IcyClawz.CustomInteractions;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
using UnityEngine;
|
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
using ILightTemplate = GInterface357;
|
|
|
|
using ISightTemplate = GInterface365;
|
|
|
|
using GlobalEvents = GClass3400;
|
2023-07-08 23:42:42 +03:00
|
|
|
|
2024-03-05 22:48:21 +02:00
|
|
|
namespace IcyClawz.ItemContextMenuExt;
|
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
internal static class SightComponentExtensions
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
public static int[] GetScopeCalibrationDistances(this SightComponent instance, int scopeIndex) =>
|
|
|
|
((ISightTemplate)instance.Item.Template).CalibrationDistances[scopeIndex];
|
2023-07-08 23:42:42 +03:00
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
public static float[] GetScopeZooms(this SightComponent instance, int scopeIndex) =>
|
|
|
|
((ISightTemplate)instance.Item.Template).Zooms[scopeIndex];
|
2024-03-05 22:48:21 +02:00
|
|
|
}
|
2023-07-08 23:42:42 +03:00
|
|
|
|
2024-03-05 22:48:21 +02:00
|
|
|
internal static class LightComponentExtensions
|
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
public static int GetModesCount(this LightComponent instance) =>
|
|
|
|
((ILightTemplate)instance.Item.Template).ModesCount;
|
2024-03-05 22:48:21 +02:00
|
|
|
}
|
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
internal sealed class CustomInteractionsProvider : ICustomInteractionsProvider
|
2024-03-05 22:48:21 +02:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
private const string IconsPrefix = "Characteristics/Icons/";
|
|
|
|
private static StaticIcons StaticIcons => EFTHardSettings.Instance.StaticIcons;
|
2023-07-08 23:42:42 +03:00
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
public IEnumerable<CustomInteraction> GetCustomInteractions(ItemUiContext context, EItemViewType viewType, Item item)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
if (viewType is EItemViewType.Inventory)
|
|
|
|
{
|
|
|
|
FireModeComponent fireModeComponent = item.GetItemComponent<FireModeComponent>();
|
|
|
|
if (fireModeComponent is not null)
|
|
|
|
return GetFireModeInteractions(context, fireModeComponent);
|
|
|
|
|
|
|
|
SightComponent sightComponent = item.GetItemComponent<SightComponent>();
|
|
|
|
if (sightComponent is not null)
|
|
|
|
return GetSightInteractions(context, sightComponent);
|
2023-07-08 23:42:42 +03:00
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
LightComponent lightComponent = item.GetItemComponent<LightComponent>();
|
|
|
|
if (lightComponent is not null)
|
|
|
|
return GetLightInteractions(context, lightComponent);
|
|
|
|
}
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
private IEnumerable<CustomInteraction> GetFireModeInteractions(ItemUiContext context, FireModeComponent component)
|
|
|
|
{
|
|
|
|
if (component.AvailableEFireModes.Length > 1)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
yield return new(context)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-03-05 22:48:21 +02:00
|
|
|
Caption = () => "Firing mode",
|
|
|
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.Weapon),
|
2024-12-02 15:59:14 +02:00
|
|
|
SubMenu = () => GetFireModeSubInteractions(context, component),
|
2024-03-05 22:48:21 +02:00
|
|
|
};
|
|
|
|
}
|
2024-12-02 15:59:14 +02:00
|
|
|
}
|
2024-03-05 22:48:21 +02:00
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
private IEnumerable<CustomInteraction> GetFireModeSubInteractions(ItemUiContext context, FireModeComponent component)
|
|
|
|
{
|
|
|
|
foreach (Weapon.EFireMode fireMode in component.AvailableEFireModes)
|
2024-03-05 22:48:21 +02:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
yield return new(context)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
Caption = () => fireMode.ToString().Localized(),
|
2024-03-05 22:48:21 +02:00
|
|
|
Action = () =>
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-03-05 22:48:21 +02:00
|
|
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
2024-12-02 15:59:14 +02:00
|
|
|
ComponentUtils.SetFireMode(component, fireMode);
|
2024-10-25 20:55:26 +03:00
|
|
|
},
|
2024-12-02 15:59:14 +02:00
|
|
|
Enabled = () => fireMode != component.FireMode,
|
2024-03-05 22:48:21 +02:00
|
|
|
};
|
2024-12-02 15:59:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private IEnumerable<CustomInteraction> GetSightInteractions(ItemUiContext context, SightComponent component)
|
|
|
|
{
|
|
|
|
if (component.ScopesCount > 1)
|
|
|
|
{
|
|
|
|
yield return new(context)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
Caption = () => "Active scope",
|
2024-03-05 22:48:21 +02:00
|
|
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
|
2024-12-02 15:59:14 +02:00
|
|
|
SubMenu = () => GetScopeIndexSubInteractions(context, component),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (component.GetScopeModesCount(component.SelectedScope) > 1)
|
|
|
|
{
|
|
|
|
yield return new(context)
|
|
|
|
{
|
|
|
|
Caption = () => "Active mode",
|
|
|
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
|
|
|
|
SubMenu = () => GetScopeModeSubInteractions(context, component),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (component.GetScopeCalibrationDistances(component.SelectedScope).Length > 1)
|
|
|
|
{
|
|
|
|
yield return new(context)
|
|
|
|
{
|
|
|
|
Caption = () => "Zero distance",
|
|
|
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
|
|
|
|
SubMenu = () => GetScopeCalibSubInteractions(context, component),
|
2024-03-05 22:48:21 +02:00
|
|
|
};
|
2023-07-08 23:42:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
private IEnumerable<CustomInteraction> GetScopeIndexSubInteractions(ItemUiContext context, SightComponent component)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
foreach (int scopeIndex in Enumerable.Range(0, component.ScopesCount))
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
yield return new(context)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
Caption = () => $"Scope {scopeIndex + 1}",
|
|
|
|
Action = () =>
|
|
|
|
{
|
|
|
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
|
|
|
ComponentUtils.SetScopeIndex(component, scopeIndex);
|
|
|
|
},
|
|
|
|
Enabled = () => scopeIndex != component.SelectedScope,
|
|
|
|
};
|
|
|
|
}
|
2023-07-08 23:42:42 +03:00
|
|
|
}
|
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
private IEnumerable<CustomInteraction> GetScopeModeSubInteractions(ItemUiContext context, SightComponent component)
|
|
|
|
{
|
|
|
|
int scopeIndex = component.SelectedScope;
|
|
|
|
float[] scopeZooms = component.GetScopeZooms(scopeIndex);
|
|
|
|
foreach (int scopeMode in Enumerable.Range(0, component.GetScopeModesCount(scopeIndex)))
|
|
|
|
{
|
|
|
|
float scopeZoom = scopeZooms.Length > 0 ? scopeZooms[scopeMode] : 0f;
|
|
|
|
yield return new(context)
|
|
|
|
{
|
|
|
|
Caption = () => $"Mode {scopeMode + 1} ({scopeZoom}x)",
|
|
|
|
Action = () =>
|
|
|
|
{
|
|
|
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
|
|
|
ComponentUtils.SetScopeMode(component, scopeMode);
|
|
|
|
},
|
|
|
|
Enabled = () => scopeMode != component.ScopesSelectedModes[scopeIndex],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private IEnumerable<CustomInteraction> GetScopeCalibSubInteractions(ItemUiContext context, SightComponent component)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
int scopeIndex = component.SelectedScope;
|
|
|
|
int[] scopeCalibDistances = component.GetScopeCalibrationDistances(scopeIndex);
|
|
|
|
foreach (int scopeCalibIndex in Enumerable.Range(0, scopeCalibDistances.Length))
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
yield return new(context)
|
|
|
|
{
|
|
|
|
Caption = () => $"{scopeCalibDistances[scopeCalibIndex]}",
|
|
|
|
Action = () =>
|
|
|
|
{
|
|
|
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
|
|
|
ComponentUtils.SetScopeCalibIndex(component, scopeCalibIndex);
|
|
|
|
},
|
|
|
|
Enabled = () => scopeCalibIndex != component.ScopesCurrentCalibPointIndexes[scopeIndex],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private IEnumerable<CustomInteraction> GetLightInteractions(ItemUiContext context, LightComponent component)
|
|
|
|
{
|
|
|
|
yield return new(context)
|
|
|
|
{
|
|
|
|
Caption = () => component.IsActive ? "Turn off" : "Turn on",
|
|
|
|
Icon = () => CacheResourcesPopAbstractClass.Pop<Sprite>(IconsPrefix + (component.IsActive ? "TurnOff" : "TurnOn")),
|
2024-03-05 22:48:21 +02:00
|
|
|
Action = () =>
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-03-05 22:48:21 +02:00
|
|
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
2024-12-02 15:59:14 +02:00
|
|
|
ComponentUtils.SetLightActive(component, !component.IsActive);
|
|
|
|
GlobalEvents.RequestGlobalRedraw();
|
2024-03-05 22:48:21 +02:00
|
|
|
},
|
2024-12-02 15:59:14 +02:00
|
|
|
};
|
|
|
|
if (component.GetModesCount() > 1)
|
|
|
|
{
|
|
|
|
yield return new(context)
|
|
|
|
{
|
|
|
|
Caption = () => "Active mode",
|
|
|
|
Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
|
|
|
|
SubMenu = () => GetLightModeSubInteractions(context, component),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private IEnumerable<CustomInteraction> GetLightModeSubInteractions(ItemUiContext context, LightComponent component)
|
|
|
|
{
|
|
|
|
foreach (int lightMode in Enumerable.Range(0, component.GetModesCount()))
|
|
|
|
{
|
|
|
|
yield return new(context)
|
|
|
|
{
|
|
|
|
Caption = () => $"Mode {lightMode + 1}",
|
|
|
|
Action = () =>
|
|
|
|
{
|
|
|
|
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.MenuContextMenu);
|
|
|
|
ComponentUtils.SetLightMode(component, lightMode);
|
|
|
|
},
|
|
|
|
Enabled = () => lightMode != component.SelectedMode,
|
|
|
|
};
|
|
|
|
}
|
2023-07-08 23:42:42 +03:00
|
|
|
}
|
2024-03-05 22:48:21 +02:00
|
|
|
}
|
2023-07-08 23:42:42 +03:00
|
|
|
|
2024-03-05 22:48:21 +02:00
|
|
|
internal static class ComponentUtils
|
|
|
|
{
|
|
|
|
public static void SetFireMode(FireModeComponent component, Weapon.EFireMode fireMode)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-03-05 22:48:21 +02:00
|
|
|
Player player = GamePlayerOwner.MyPlayer;
|
|
|
|
|
|
|
|
if (player is not null && player.HandsController is Player.FirearmController fc && component.Item == fc.Item)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
if (fc.Item.MalfState.State is not Weapon.EMalfunctionState.None)
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-03-05 22:48:21 +02:00
|
|
|
fc.FirearmsAnimator.MisfireSlideUnknown(false);
|
2024-12-02 15:59:14 +02:00
|
|
|
player.InventoryController.ExamineMalfunction(fc.Item, false);
|
|
|
|
return;
|
2023-07-08 23:42:42 +03:00
|
|
|
}
|
2024-12-02 15:59:14 +02:00
|
|
|
|
|
|
|
fc.ChangeFireMode(fireMode);
|
2024-03-05 22:48:21 +02:00
|
|
|
return;
|
2023-07-08 23:42:42 +03:00
|
|
|
}
|
|
|
|
|
2024-03-05 22:48:21 +02:00
|
|
|
component.SetFireMode(fireMode);
|
|
|
|
}
|
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
public static void SetScopeIndex(SightComponent component, int scopeIndex)
|
|
|
|
{
|
|
|
|
SetScopeState(component, new()
|
|
|
|
{
|
|
|
|
Id = component.Item.Id,
|
|
|
|
ScopeIndexInsideSight = scopeIndex,
|
|
|
|
ScopeMode = component.ScopesSelectedModes[scopeIndex],
|
|
|
|
ScopeCalibrationIndex = component.ScopesCurrentCalibPointIndexes[scopeIndex],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void SetScopeMode(SightComponent component, int scopeMode)
|
|
|
|
{
|
|
|
|
int scopeIndex = component.SelectedScope;
|
|
|
|
SetScopeState(component, new()
|
|
|
|
{
|
|
|
|
Id = component.Item.Id,
|
|
|
|
ScopeIndexInsideSight = scopeIndex,
|
|
|
|
ScopeMode = scopeMode,
|
|
|
|
ScopeCalibrationIndex = component.ScopesCurrentCalibPointIndexes[scopeIndex],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void SetScopeCalibIndex(SightComponent component, int scopeCalibIndex)
|
|
|
|
{
|
|
|
|
int scopeIndex = component.SelectedScope;
|
|
|
|
SetScopeState(component, new()
|
|
|
|
{
|
|
|
|
Id = component.Item.Id,
|
|
|
|
ScopeIndexInsideSight = scopeIndex,
|
|
|
|
ScopeMode = component.ScopesSelectedModes[scopeIndex],
|
|
|
|
ScopeCalibrationIndex = scopeCalibIndex,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void SetScopeState(SightComponent component, FirearmScopeStateStruct scopeState)
|
|
|
|
{
|
|
|
|
Player player = GamePlayerOwner.MyPlayer;
|
|
|
|
|
|
|
|
if (player is not null && player.HandsController is Player.FirearmController fc && component.Item.IsChildOf(fc.Item))
|
|
|
|
{
|
|
|
|
fc.SetScopeMode([scopeState]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int scopeIndex = scopeState.ScopeIndexInsideSight;
|
|
|
|
component.SelectedScope = scopeIndex;
|
|
|
|
component.ScopesSelectedModes[scopeIndex] = scopeState.ScopeMode;
|
|
|
|
component.ScopesCurrentCalibPointIndexes[scopeIndex] = scopeState.ScopeCalibrationIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void SetLightActive(LightComponent component, bool isActive)
|
|
|
|
{
|
|
|
|
SetLightState(component, new()
|
|
|
|
{
|
|
|
|
Id = component.Item.Id,
|
|
|
|
IsActive = isActive,
|
|
|
|
LightMode = component.SelectedMode,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void SetLightMode(LightComponent component, int lightMode)
|
|
|
|
{
|
|
|
|
SetLightState(component, new()
|
|
|
|
{
|
|
|
|
Id = component.Item.Id,
|
|
|
|
IsActive = component.IsActive,
|
|
|
|
LightMode = lightMode,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void SetLightState(LightComponent component, FirearmLightStateStruct lightState)
|
2024-03-05 22:48:21 +02:00
|
|
|
{
|
|
|
|
Player player = GamePlayerOwner.MyPlayer;
|
|
|
|
|
|
|
|
if (player is not null && player.HandsController is Player.FirearmController fc && component.Item.IsChildOf(fc.Item))
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-12-02 15:59:14 +02:00
|
|
|
fc.SetLightsState([lightState]);
|
2024-03-05 22:48:21 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-07-08 23:42:42 +03:00
|
|
|
|
2024-12-02 15:59:14 +02:00
|
|
|
component.IsActive = lightState.IsActive;
|
|
|
|
component.SelectedMode = lightState.LightMode;
|
2023-07-08 23:42:42 +03:00
|
|
|
|
2024-03-05 22:48:21 +02:00
|
|
|
if (player is not null)
|
|
|
|
{
|
|
|
|
foreach (TacticalComboVisualController tcvc in player.GetComponentsInChildren<TacticalComboVisualController>())
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-03-05 22:48:21 +02:00
|
|
|
if (ReferenceEquals(tcvc.LightMod, component))
|
2023-07-08 23:42:42 +03:00
|
|
|
{
|
2024-03-05 22:48:21 +02:00
|
|
|
tcvc.UpdateBeams();
|
|
|
|
break;
|
2023-07-08 23:42:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|