Repair context menu, other cleanup

This commit is contained in:
Tyfon
2024-06-02 19:32:36 -07:00
parent 1de058badd
commit 70e9cf1a84
5 changed files with 320 additions and 129 deletions

8
GlobalSuppressions.cs Normal file
View File

@@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Style", "IDE0028:Simplify collection initialization", Justification = "<Pending>", Scope = "member", Target = "~M:UIFixes.Settings.Init(BepInEx.Configuration.ConfigFile)")]

104
InsuranceInteractions.cs Normal file
View File

@@ -0,0 +1,104 @@
using Comfort.Common;
using EFT.InventoryLogic;
using EFT.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static RootMotion.FinalIK.InteractionTrigger.Range;
namespace UIFixes
{
public class InsuranceInteractions(Item item, ItemUiContext uiContext, int playerRubles) : ItemInfoInteractionsAbstractClass<InsuranceInteractions.EInsurers>(uiContext)
{
private readonly InsuranceCompanyClass insurance = uiContext.Session.InsuranceCompany;
private readonly Item item = item;
private readonly int playerRubles = playerRubles;
private List<ItemClass> items;
private readonly Dictionary<string, int> prices = [];
public void LoadAsync(Action callback)
{
ItemClass itemClass = ItemClass.FindOrCreate(item);
items = insurance.GetItemChildren(itemClass).Flatten(insurance.GetItemChildren).Concat([itemClass])
.Where(i => insurance.ItemTypeAvailableForInsurance(i) && !insurance.InsuredItems.Contains(i))
.ToList();
insurance.GetInsurePriceAsync(items, _ =>
{
foreach (var insurer in insurance.Insurers)
{
int price = this.items.Select(i => insurance.InsureSummary[insurer.Id][i]).Where(s => s.Loaded).Sum(s => s.Amount);
prices[insurer.Id] = price;
string priceColor = price > playerRubles ? "#FF0000" : "#ADB8BC";
string text = string.Format("<b><color=#C6C4B2>{0}</color> <color={1}>({2} ₽)</color></b>", insurer.LocalizedName, priceColor, price);
base.method_2(MakeInteractionId(insurer.Id), text, () => this.Insure(insurer.Id));
}
callback();
});
}
private void Insure(string insurerId)
{
insurance.SelectedInsurerId = insurerId;
insurance.InsureItems(this.items, result => { });
}
public IResult GetButtonInteraction(string interactionId)
{
string traderId = interactionId.Split(':')[1];
if (prices[traderId] > playerRubles)
{
return new FailedResult("ragfair/Not enough money", 0);
}
return SuccessfulResult.New;
}
public override void ExecuteInteractionInternal(EInsurers interaction)
{
}
public override bool IsActive(EInsurers button)
{
return button == EInsurers.None && !this.insurance.Insurers.Any();
}
public override IResult IsInteractive(EInsurers button)
{
return new FailedResult("No insurers??", 0);
}
public override bool HasIcons
{
get { return false; }
}
public enum EInsurers
{
None
}
private static string MakeInteractionId(string traderId)
{
return "UIFixesInsurerId:" + traderId;
}
public static bool IsInsuranceInteractionId(string id)
{
return id.StartsWith("UIFixesInsurerId:");
}
}
public static class InsuranceExtensions
{
public static bool IsInsuranceInteraction(this DynamicInteractionClass interaction)
{
return interaction.Id.StartsWith("UIFixesInsurerId:");
}
}
}

View File

@@ -242,27 +242,14 @@ namespace UIFixes
private static void UpdateColumnHeaders(FiltersPanel filtersPanel, ESortType sortType, bool sortDirection)
{
var wrappedFiltersPanel = filtersPanel.R();
RagfairFilterButton button;
switch (sortType)
RagfairFilterButton button = sortType switch
{
case ESortType.Barter:
button = wrappedFiltersPanel.BarterButton;
break;
case ESortType.Rating:
button = wrappedFiltersPanel.RatingButton;
break;
case ESortType.OfferItem:
button = wrappedFiltersPanel.OfferItemButton;
break;
case ESortType.ExpirationDate:
button = wrappedFiltersPanel.ExpirationButton;
break;
case ESortType.Price:
default: // Default to price if somehow this falls through
button = wrappedFiltersPanel.PriceButton;
break;
}
ESortType.Barter => wrappedFiltersPanel.BarterButton,
ESortType.Rating => wrappedFiltersPanel.RatingButton,
ESortType.OfferItem => wrappedFiltersPanel.OfferItemButton,
ESortType.ExpirationDate => wrappedFiltersPanel.ExpirationButton,
_ => wrappedFiltersPanel.PriceButton,
};
wrappedFiltersPanel.SortDescending = sortDirection;
filtersPanel.method_4(button);
}

View File

@@ -17,10 +17,9 @@ namespace UIFixes
private static Type TradingRootInteractionsType;
private static FieldInfo TradingRootInteractionsItemField;
private static int PlayerRubles;
private static InsuranceInteractions CurrentInsuranceInteractions = null;
private static string CreatedContextMenuButtonTraderId = null;
private static RepairInteractions CurrentRepairInteractions = null;
private static string CreatedButtonInteractionId = null;
private static readonly HashSet<EItemInfoButton> TradingRootInteractions =
[
@@ -84,7 +83,7 @@ namespace UIFixes
[PatchPostfix]
public static void Postfix(ref IEnumerable<EItemInfoButton> __result)
{
__result = __result.Append(EItemInfoButton.Insure);
__result = __result.Append(EItemInfoButton.Repair).Append(EItemInfoButton.Insure);
}
}
@@ -98,17 +97,25 @@ namespace UIFixes
[PatchPrefix]
public static bool Prefix(EItemInfoButton parentInteraction, ISubInteractions subInteractionsWrapper, Item ___item_0, ItemUiContext ___itemUiContext_1)
{
Dictionary<ECurrencyType, int> playerCurrencies = R.Money.GetMoneySums(___itemUiContext_1.R().InventoryController.Inventory.Stash.Grid.ContainedItems.Keys);
int playerRubles = playerCurrencies[ECurrencyType.RUB];
if (parentInteraction == EItemInfoButton.Insure)
{
Dictionary<ECurrencyType, int> playerCurrencies = R.Money.GetMoneySums(___itemUiContext_1.R().InventoryController.Inventory.Stash.Grid.ContainedItems.Keys);
PlayerRubles = playerCurrencies[ECurrencyType.RUB];
CurrentInsuranceInteractions = new(___item_0, ___itemUiContext_1);
CurrentInsuranceInteractions = new(___item_0, ___itemUiContext_1, playerRubles);
CurrentInsuranceInteractions.LoadAsync(() => subInteractionsWrapper.SetSubInteractions(CurrentInsuranceInteractions));
return false;
}
if (parentInteraction == EItemInfoButton.Repair)
{
CurrentRepairInteractions = new(___item_0, ___itemUiContext_1, playerRubles);
subInteractionsWrapper.SetSubInteractions(CurrentRepairInteractions);
return false;
}
return true;
}
}
@@ -123,7 +130,7 @@ namespace UIFixes
[PatchPostfix]
public static void Postfix(ref IEnumerable<EItemInfoButton> __result)
{
__result = __result.Append(EItemInfoButton.Insure);
__result = __result.Append(EItemInfoButton.Repair).Append(EItemInfoButton.Insure);
}
}
@@ -137,20 +144,28 @@ namespace UIFixes
[PatchPrefix]
public static bool Prefix(object __instance, EItemInfoButton parentInteraction, ISubInteractions subInteractionsWrapper, ItemUiContext ___itemUiContext_0)
{
Dictionary<ECurrencyType, int> playerCurrencies = R.Money.GetMoneySums(___itemUiContext_0.R().InventoryController.Inventory.Stash.Grid.ContainedItems.Keys);
int playerRubles = playerCurrencies[ECurrencyType.RUB];
// CreateSubInteractions is only on the base class here, which doesn't have an Item. But __instance is actually a GClass3032
Item item = (Item)TradingRootInteractionsItemField.GetValue(__instance);
if (parentInteraction == EItemInfoButton.Insure)
{
Dictionary<ECurrencyType, int> playerCurrencies = R.Money.GetMoneySums(___itemUiContext_0.R().InventoryController.Inventory.Stash.Grid.ContainedItems.Keys);
PlayerRubles = playerCurrencies[ECurrencyType.RUB];
// CreateSubInteractions is only on the base class here, which doesn't have an Item. But __instance is actually a GClass3032
Item item = (Item)TradingRootInteractionsItemField.GetValue(__instance);
CurrentInsuranceInteractions = new(item, ___itemUiContext_0);
CurrentInsuranceInteractions = new(item, ___itemUiContext_0, playerRubles);
CurrentInsuranceInteractions.LoadAsync(() => subInteractionsWrapper.SetSubInteractions(CurrentInsuranceInteractions));
return false;
}
if (parentInteraction == EItemInfoButton.Repair)
{
CurrentRepairInteractions = new(item, ___itemUiContext_0, playerRubles);
subInteractionsWrapper.SetSubInteractions(CurrentRepairInteractions);
return false;
}
return true;
}
}
@@ -165,16 +180,16 @@ namespace UIFixes
[PatchPrefix]
public static void Prefix(DynamicInteractionClass interaction)
{
if (interaction.IsInsuranceInteraction())
if (interaction.IsInsuranceInteraction() || interaction.IsRepairInteraction())
{
CreatedContextMenuButtonTraderId = interaction.GetTraderId();
CreatedButtonInteractionId = interaction.Id;
}
}
[PatchPostfix]
public static void Postfix()
{
CreatedContextMenuButtonTraderId = null;
CreatedButtonInteractionId = null;
}
}
@@ -188,9 +203,16 @@ namespace UIFixes
[PatchPrefix]
public static void Prefix(SimpleContextMenuButton button)
{
if (!String.IsNullOrEmpty(CreatedContextMenuButtonTraderId) && CurrentInsuranceInteractions != null)
if (!String.IsNullOrEmpty(CreatedButtonInteractionId))
{
button.SetButtonInteraction(CurrentInsuranceInteractions.GetButtonInteraction(CreatedContextMenuButtonTraderId));
if (InsuranceInteractions.IsInsuranceInteractionId(CreatedButtonInteractionId) && CurrentInsuranceInteractions != null)
{
button.SetButtonInteraction(CurrentInsuranceInteractions.GetButtonInteraction(CreatedButtonInteractionId));
}
else if (RepairInteractions.IsRepairInteractionId(CreatedButtonInteractionId) && CurrentRepairInteractions != null)
{
button.SetButtonInteraction(CurrentRepairInteractions.GetButtonInteraction(CreatedButtonInteractionId));
}
}
}
}
@@ -208,93 +230,5 @@ namespace UIFixes
CurrentInsuranceInteractions = null;
}
}
public class InsuranceInteractions(Item item, ItemUiContext uiContext) : ItemInfoInteractionsAbstractClass<InsuranceInteractions.EInsurers>(uiContext)
{
private readonly InsuranceCompanyClass insurance = uiContext.Session.InsuranceCompany;
private readonly Item item = item;
private List<ItemClass> items;
private readonly Dictionary<string, int> prices = [];
public void LoadAsync(Action callback)
{
ItemClass itemClass = ItemClass.FindOrCreate(item);
items = insurance.GetItemChildren(itemClass).Flatten(insurance.GetItemChildren).Concat([itemClass])
.Where(i => insurance.ItemTypeAvailableForInsurance(i) && !insurance.InsuredItems.Contains(i))
.ToList();
insurance.GetInsurePriceAsync(items, _ =>
{
foreach (var insurer in insurance.Insurers)
{
int price = this.items.Select(i => insurance.InsureSummary[insurer.Id][i]).Where(s => s.Loaded).Sum(s => s.Amount);
prices[insurer.Id] = price;
string priceColor = price > PlayerRubles ? "#FF0000" : "#ADB8BC";
string text = string.Format("<b><color=#C6C4B2>{0}</color> <color={1}>({2} ₽)</color></b>", insurer.LocalizedName, priceColor, price);
base.method_2(MakeInteractionId(insurer.Id), text, () => this.Insure(insurer.Id));
}
callback();
});
}
public void Insure(string insurerId)
{
insurance.SelectedInsurerId = insurerId;
insurance.InsureItems(this.items, result => { });
}
public IResult GetButtonInteraction(string traderId)
{
if (prices[traderId] > PlayerRubles)
{
return new FailedResult("ragfair/Not enough money", 0);
}
return SuccessfulResult.New;
}
public override void ExecuteInteractionInternal(EInsurers interaction)
{
}
public override bool IsActive(EInsurers button)
{
return button == EInsurers.None && !this.insurance.Insurers.Any();
}
public override IResult IsInteractive(EInsurers button)
{
return new FailedResult("No insurers??", 0);
}
public override bool HasIcons
{
get { return false; }
}
public enum EInsurers
{
None
}
}
private static string MakeInteractionId(string traderId)
{
return "UIFixesInsurerId:" + traderId;
}
private static bool IsInsuranceInteraction(this DynamicInteractionClass interaction)
{
return interaction.Id.StartsWith("UIFixesInsurerId:");
}
private static string GetTraderId(this DynamicInteractionClass interaction)
{
return interaction.Id.Split(':')[1];
}
}
}

158
RepairInteractions.cs Normal file
View File

@@ -0,0 +1,158 @@
using Comfort.Common;
using EFT.Communications;
using EFT.InventoryLogic;
using EFT.UI;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace UIFixes
{
public class RepairInteractions : ItemInfoInteractionsAbstractClass<RepairInteractions.ERepairers>
{
private readonly RepairControllerClass repairController;
private readonly int playerRubles;
private readonly GInterface33 repairStrategy;
public RepairInteractions(Item item, ItemUiContext uiContext, int playerRubles) : base(uiContext)
{
repairController = uiContext.Session.RepairController;
// Add empty action because otherwise RepairControllerClass.action_0 is null and it pukes on successful repair
repairController.OnSuccessfulRepairChangedEvent += () => {};
this.playerRubles = playerRubles;
repairStrategy = item.GetItemComponent<ArmorHolderComponent>() != null ?
new GClass804(item, repairController) :
new GClass803(item, repairController);
Load();
}
private void Load()
{
foreach (IRepairer repairer in repairStrategy.Repairers)
{
repairStrategy.CurrentRepairer = repairer;
float repairAmount = repairStrategy.HowMuchRepairScoresCanAccept();
string text;
if (repairer is GClass802 repairKit)
{
float pointsLeft = repairKit.GetRepairPoints();
double amount = repairStrategy.GetRepairPrice(repairAmount, repairKit);
string costColor = amount > pointsLeft ? "#FF0000" : "#ADB8BC";
text = string.Format("<b><color=#C6C4B2>{0}</color> <color={1}>({2} {3})</color></b>", repairer.LocalizedName, costColor, Math.Round(amount, 2).ToString(CultureInfo.InvariantCulture), "RP".Localized());
}
else
{
int price = repairStrategy.GetCurrencyPrice(repairAmount);
string priceColor = price > playerRubles ? "#FF0000" : "#ADB8BC";
text = string.Format("<b><color=#C6C4B2>{0}</color> <color={1}>({2} ₽)</color></b>", repairer.LocalizedName, priceColor, price);
}
base.method_2(MakeInteractionId(repairer.RepairerId), text, () => this.Repair(repairer.RepairerId));
}
}
private async void Repair(string repairerId)
{
repairStrategy.CurrentRepairer = repairStrategy.Repairers.Single(r => r.RepairerId == repairerId);
IResult result = await repairStrategy.RepairItem(repairStrategy.HowMuchRepairScoresCanAccept(), null);
if (result.Succeed)
{
Singleton<GUISounds>.Instance.PlayUISound(EUISoundType.RepairComplete);
NotificationManagerClass.DisplayMessageNotification(string.Format("{0} {1:F1}", "Item successfully repaired to".Localized(null), repairStrategy.Durability()), ENotificationDurationType.Default, ENotificationIconType.Default, null);
}
}
public IResult GetButtonInteraction(string interactionId)
{
string repairerId = interactionId.Split(':')[1];
IRepairer repairer = repairStrategy.Repairers.Single(r => r.RepairerId == repairerId);
repairStrategy.CurrentRepairer = repairer;
float repairAmount = repairStrategy.HowMuchRepairScoresCanAccept();
if (repairer is GClass802 repairKit)
{
float pointsLeft = repairKit.GetRepairPoints();
double amount = repairStrategy.GetRepairPrice(repairAmount, repairKit);
if (amount > pointsLeft)
{
return new FailedResult(ERepairStatusWarning.NotEnoughRepairPoints.ToString());
}
}
else
{
int price = repairStrategy.GetCurrencyPrice(repairAmount);
if (price > playerRubles)
{
return new FailedResult(ERepairStatusWarning.NotEnoughMoney.ToString());
}
}
if (repairAmount < float.Epsilon)
{
return new FailedResult(ERepairStatusWarning.NothingToRepair.ToString());
}
if (repairStrategy.BrokenItemError())
{
return new FailedResult(ERepairStatusWarning.BrokenItem.ToString());
}
if (repairStrategy.IsNoCorrespondingArea())
{
return new FailedResult(ERepairStatusWarning.NoCorrespondingArea.ToString());
}
return SuccessfulResult.New;
}
public override void ExecuteInteractionInternal(ERepairers interaction)
{
}
public override bool IsActive(ERepairers button)
{
return button == ERepairers.None && !this.repairController.TraderRepairers.Any();
}
public override IResult IsInteractive(ERepairers button)
{
return new FailedResult("No repairers??", 0);
}
public override bool HasIcons
{
get { return false; }
}
public enum ERepairers
{
None
}
private static string MakeInteractionId(string traderId)
{
return "UIFixesRepairerId:" + traderId;
}
public static bool IsRepairInteractionId(string id)
{
return id.StartsWith("UIFixesRepairerId:");
}
}
public static class RepairExtensions
{
public static bool IsRepairInteraction(this DynamicInteractionClass interaction)
{
return interaction.Id.StartsWith("UIFixesRepairerId:");
}
}
}