2021-09-05 20:54:44 +01:00
|
|
|
|
using AssortGenerator.Common;
|
|
|
|
|
using AssortGenerator.Common.Helpers;
|
|
|
|
|
using AssortGenerator.Models.Input;
|
|
|
|
|
using AssortGenerator.Models.Other;
|
|
|
|
|
using AssortGenerator.Models.Output;
|
|
|
|
|
using Common;
|
2023-01-08 15:06:37 +00:00
|
|
|
|
using System;
|
2021-09-05 20:54:44 +01:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text.Json;
|
2023-08-02 20:32:57 +01:00
|
|
|
|
using static AssortGenerator.Common.Helpers.QuestHelper;
|
2021-09-05 20:54:44 +01:00
|
|
|
|
|
|
|
|
|
namespace AssortGenerator
|
|
|
|
|
{
|
2021-09-18 22:32:56 +01:00
|
|
|
|
public class Program
|
2021-09-05 20:54:44 +01:00
|
|
|
|
{
|
|
|
|
|
static void Main(string[] args)
|
|
|
|
|
{
|
|
|
|
|
var assortsPath = CreateWorkingFolders();
|
|
|
|
|
InputFileHelper.SetInputFiles(assortsPath);
|
|
|
|
|
|
|
|
|
|
// Get trader assort files from assorts input folder
|
|
|
|
|
var traderAssortFilePaths = InputFileHelper.GetInputFilePaths().Where(x => TraderHelper.GetTraders().Values.Any(x.Contains)).ToList();
|
2023-07-09 11:36:00 +01:00
|
|
|
|
var finalisedQuestData = QuestHelper.GetFinalisedQuestData();
|
2023-08-02 20:32:57 +01:00
|
|
|
|
var missingQuestAssortPrices = QuestHelper.GetMissingTraderQuestPrices();
|
2021-09-05 20:54:44 +01:00
|
|
|
|
foreach (var trader in TraderHelper.GetTraders())
|
|
|
|
|
{
|
|
|
|
|
// Get relevant trader dump
|
2023-01-03 10:46:33 +00:00
|
|
|
|
var assortDumpPath = traderAssortFilePaths.Find(x => x.Contains($"getTraderAssort.{trader.Value}"));
|
2023-07-09 11:36:00 +01:00
|
|
|
|
assortDumpPath ??= traderAssortFilePaths.Find(x => x.Contains($"{trader.Value}") && x.Contains("getTraderAssort"));
|
2021-09-05 20:54:44 +01:00
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
// Convert input dump json into object
|
2021-09-05 20:54:44 +01:00
|
|
|
|
var json = File.ReadAllText(assortDumpPath);
|
|
|
|
|
var jsonObject = JsonDocument.Parse(json);
|
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
// Find root data node
|
2023-01-28 12:01:59 +00:00
|
|
|
|
var data = jsonObject.RootElement;
|
2021-09-05 20:54:44 +01:00
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
// Find assort items node and parse into list
|
2021-09-05 20:54:44 +01:00
|
|
|
|
string itemsJson = data.GetProperty("items").ToString();
|
|
|
|
|
List<Item> items = JsonSerializer.Deserialize<List<Item>>(itemsJson);
|
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
// Fix items that have ran out of stock in the dump and give stack size
|
|
|
|
|
FixZeroSizedStackAssorts(items, 100);
|
2022-07-24 22:22:53 +01:00
|
|
|
|
|
2023-01-08 15:06:37 +00:00
|
|
|
|
FixFullyPurchasedStackLimits(items);
|
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
// Find barter scheme node and parse into dictionary
|
2021-09-05 20:54:44 +01:00
|
|
|
|
var barterSchemeJson = data.GetProperty("barter_scheme").ToString();
|
2023-07-09 11:36:00 +01:00
|
|
|
|
var barterSchemeItems = JsonSerializer.Deserialize<Dictionary<string, List<List<BarterObject>>>>(barterSchemeJson);
|
2021-09-05 20:54:44 +01:00
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
// Find loyalty level node and parse into dictionary
|
2021-09-05 20:54:44 +01:00
|
|
|
|
var loyaltyLevelItemsJson = data.GetProperty("loyal_level_items").ToString();
|
|
|
|
|
var loyaltyLevelItems = JsonSerializer.Deserialize<Dictionary<string, int>>(loyaltyLevelItemsJson);
|
|
|
|
|
|
2023-08-02 20:32:57 +01:00
|
|
|
|
WriteOutputFilesForTrader(trader, items, barterSchemeItems, loyaltyLevelItems, finalisedQuestData, missingQuestAssortPrices);
|
2021-09-05 20:54:44 +01:00
|
|
|
|
}
|
2023-07-09 11:36:00 +01:00
|
|
|
|
|
|
|
|
|
JsonWriter.WriteJson(finalisedQuestData, "", Directory.GetCurrentDirectory(), "quests");
|
2021-09-05 20:54:44 +01:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
private static void FixZeroSizedStackAssorts(List<Item> items, int defaultStackSize)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in items
|
|
|
|
|
.Where(item => item.upd?.StackObjectsCount == 0 && item.slotId == "hideout"))
|
|
|
|
|
{
|
|
|
|
|
LoggingHelpers.LogError($"item {item._tpl} found with stack count of 0, changing to {defaultStackSize}");
|
2023-01-08 15:20:13 +00:00
|
|
|
|
|
|
|
|
|
if (item.upd?.BuyRestrictionMax != null)
|
|
|
|
|
{
|
|
|
|
|
var parsedRestrictionMax = int.Parse(item.upd?.BuyRestrictionMax.ToString());
|
|
|
|
|
if (parsedRestrictionMax > defaultStackSize)
|
|
|
|
|
{
|
|
|
|
|
item.upd.StackObjectsCount = parsedRestrictionMax;
|
2023-01-08 16:32:31 +00:00
|
|
|
|
continue;
|
2023-01-08 15:20:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-08 16:32:31 +00:00
|
|
|
|
item.upd.StackObjectsCount = defaultStackSize;
|
2023-01-03 10:46:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-08 15:06:37 +00:00
|
|
|
|
private static void FixFullyPurchasedStackLimits(List<Item> items)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in items
|
|
|
|
|
.Where(item => item.upd?.BuyRestrictionCurrent > 0 && item.slotId == "hideout"))
|
|
|
|
|
{
|
|
|
|
|
LoggingHelpers.LogError($"item {item._tpl} found with stack count > 0, changing to 0");
|
|
|
|
|
item.upd.BuyRestrictionCurrent = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create input/assorts/output/traders folders
|
|
|
|
|
/// </summary>
|
2021-09-05 20:54:44 +01:00
|
|
|
|
private static string CreateWorkingFolders()
|
|
|
|
|
{
|
|
|
|
|
var workingPath = Directory.GetCurrentDirectory();
|
|
|
|
|
// create input folder
|
|
|
|
|
var inputPath = $"{workingPath}//input";
|
|
|
|
|
DiskHelpers.CreateDirIfDoesntExist(inputPath);
|
|
|
|
|
|
|
|
|
|
// create sub folder in input called assorts
|
|
|
|
|
var assortsPath = $"{inputPath}//assorts";
|
|
|
|
|
DiskHelpers.CreateDirIfDoesntExist(assortsPath);
|
|
|
|
|
|
|
|
|
|
// create output folder
|
|
|
|
|
var outputPath = $"{workingPath}//output";
|
|
|
|
|
DiskHelpers.CreateDirIfDoesntExist(outputPath);
|
|
|
|
|
|
|
|
|
|
// create traders sub-folder
|
|
|
|
|
var tradersPath = $"{outputPath}//traders";
|
|
|
|
|
DiskHelpers.CreateDirIfDoesntExist(tradersPath);
|
|
|
|
|
|
|
|
|
|
return assortsPath;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse raw tradersettings dump file into BaseRoot object
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="filesInAssortsFolder">list of file paths</param>
|
|
|
|
|
/// <returns>BaseRoot</returns>
|
2021-09-05 20:54:44 +01:00
|
|
|
|
private static BaseRoot GetTraderData(IEnumerable<string> filesInAssortsFolder)
|
|
|
|
|
{
|
|
|
|
|
var traderDataPath = filesInAssortsFolder.FirstOrDefault(x => x.Contains("resp.client.trading.api.traderSettings"));
|
|
|
|
|
var traderDataJson = File.ReadAllText(traderDataPath);
|
|
|
|
|
return JsonSerializer.Deserialize<BaseRoot>(traderDataJson);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
private static void WriteOutputFilesForTrader(
|
|
|
|
|
KeyValuePair<Trader, string> trader,
|
2021-09-05 20:54:44 +01:00
|
|
|
|
List<Item> items,
|
2023-07-09 11:36:00 +01:00
|
|
|
|
Dictionary<string, List<List<BarterObject>>> barterSchemeItems,
|
|
|
|
|
Dictionary<string, int> loyaltyLevelItems,
|
2023-08-02 20:32:57 +01:00
|
|
|
|
Dictionary<string, Quest> finalisedQuestData,
|
|
|
|
|
Dictionary<string, MissingAssortPrice> missingQuestAssortPrices
|
|
|
|
|
)
|
2021-09-05 20:54:44 +01:00
|
|
|
|
{
|
|
|
|
|
var workingPath = Directory.GetCurrentDirectory();
|
|
|
|
|
|
|
|
|
|
var traderData = GetTraderData(InputFileHelper.GetInputFilePaths());
|
|
|
|
|
var traderFolderPath = $"traders\\{trader.Value}";
|
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
// Create assort file, serialise into json and save into output folder
|
2021-09-05 20:54:44 +01:00
|
|
|
|
var outputAssortFile = new AssortRoot
|
|
|
|
|
{
|
|
|
|
|
items = items,
|
|
|
|
|
barter_scheme = barterSchemeItems,
|
|
|
|
|
loyal_level_items = loyaltyLevelItems
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// create base file, serialise into json and save into output folder
|
|
|
|
|
var outputBaseFile = traderData.data.Find(x => x._id == trader.Value);
|
|
|
|
|
|
2023-08-02 13:05:34 +01:00
|
|
|
|
QuestAssort questAssort = GenerateQuestAssortForTrader(trader.Key, outputAssortFile, out List<AssortUnlocks> missingQuestAssorts);
|
2023-08-02 20:32:57 +01:00
|
|
|
|
AttemptToAddMissingQuestAssorts(outputAssortFile, questAssort, missingQuestAssorts, missingQuestAssortPrices);
|
2023-08-02 13:05:34 +01:00
|
|
|
|
|
|
|
|
|
JsonWriter.WriteJson(outputBaseFile, traderFolderPath, workingPath, "base");
|
|
|
|
|
JsonWriter.WriteJson(outputAssortFile, traderFolderPath, workingPath, "assort");
|
2021-09-05 20:54:44 +01:00
|
|
|
|
JsonWriter.WriteJson(questAssort, traderFolderPath, workingPath, "questassort");
|
|
|
|
|
|
2023-08-02 13:05:34 +01:00
|
|
|
|
//UpdateQuestAssortUnlockIds(trader.Value, questAssort, finalisedQuestData, outputAssortFile);
|
|
|
|
|
|
2021-09-05 20:54:44 +01:00
|
|
|
|
// create suits file for ragman
|
|
|
|
|
if (trader.Key == Trader.Ragman)
|
|
|
|
|
{
|
2023-01-03 10:46:33 +00:00
|
|
|
|
CreateRagmanSuitsFile(workingPath, traderFolderPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-05 20:54:44 +01:00
|
|
|
|
|
2023-08-09 18:56:10 +01:00
|
|
|
|
private static void AttemptToAddMissingQuestAssorts(
|
|
|
|
|
AssortRoot outputAssortFile,
|
|
|
|
|
QuestAssort questAssort,
|
|
|
|
|
List<AssortUnlocks> missingQuestAssorts,
|
|
|
|
|
Dictionary<string, MissingAssortPrice> missingQuestAssortPrices)
|
2023-08-02 13:05:34 +01:00
|
|
|
|
{
|
2023-09-12 14:29:29 +01:00
|
|
|
|
|
|
|
|
|
var questData = QuestHelper.GetFinalisedQuestData();
|
2023-08-02 13:05:34 +01:00
|
|
|
|
// iterate over each missing assort
|
|
|
|
|
foreach (var missingQuestAssort in missingQuestAssorts)
|
|
|
|
|
{
|
|
|
|
|
// Single item, maybe we can add one in (skip complex items like guns/ammo boxes etc)
|
2023-08-09 18:56:10 +01:00
|
|
|
|
var isSimpleItem = missingQuestAssort.Items.Count == 1;
|
2023-08-02 13:05:34 +01:00
|
|
|
|
|
2023-08-09 18:56:10 +01:00
|
|
|
|
if (outputAssortFile.items.Any(x => x._id == missingQuestAssort.Items[0]._id))
|
|
|
|
|
{
|
|
|
|
|
LoggingHelpers.LogError("OH NO, DUPE ID FOUND");
|
|
|
|
|
}
|
2023-08-02 13:05:34 +01:00
|
|
|
|
|
2023-08-09 18:56:10 +01:00
|
|
|
|
// Find price data
|
|
|
|
|
var hasPriceData = missingQuestAssortPrices.TryGetValue(missingQuestAssort.AssortUnlockId, out var priceData);
|
|
|
|
|
if (isSimpleItem)
|
|
|
|
|
{
|
2023-08-02 13:05:34 +01:00
|
|
|
|
// We can add it
|
2023-08-09 18:56:10 +01:00
|
|
|
|
var itemToAdd = new Item
|
2023-08-02 13:05:34 +01:00
|
|
|
|
{
|
|
|
|
|
_tpl = missingQuestAssort.Items[0]._tpl,
|
|
|
|
|
_id = missingQuestAssort.Items[0]._id,
|
|
|
|
|
parentId = "hideout",
|
2023-08-02 20:32:57 +01:00
|
|
|
|
slotId = "hideout"
|
2023-08-02 13:05:34 +01:00
|
|
|
|
};
|
2023-08-02 20:32:57 +01:00
|
|
|
|
|
2023-08-09 18:56:10 +01:00
|
|
|
|
// Set stack/buy max counts
|
|
|
|
|
if (hasPriceData && priceData.itemTpl == missingQuestAssort.Items[0]._tpl)
|
2023-08-02 20:32:57 +01:00
|
|
|
|
{
|
2023-08-09 18:56:10 +01:00
|
|
|
|
itemToAdd.upd = priceData.itemUpd;
|
2023-08-02 20:32:57 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-08-09 18:56:10 +01:00
|
|
|
|
itemToAdd.upd = new Upd() { StackObjectsCount = 10 };
|
2023-08-02 20:32:57 +01:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-09 18:56:10 +01:00
|
|
|
|
outputAssortFile.items.Add(itemToAdd);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// multi-item assort!
|
|
|
|
|
var itemsToAdd = ConvertRewardToItems(missingQuestAssort.Items);
|
2023-08-02 20:32:57 +01:00
|
|
|
|
|
2023-08-09 18:56:10 +01:00
|
|
|
|
// Set stack/buy max counts
|
|
|
|
|
if (hasPriceData && priceData.itemTpl == missingQuestAssort.Items[0]._tpl)
|
2023-08-02 13:05:34 +01:00
|
|
|
|
{
|
2023-08-09 18:56:10 +01:00
|
|
|
|
if (itemsToAdd.First().upd == null)
|
|
|
|
|
{
|
|
|
|
|
itemsToAdd.First().upd = new Upd();
|
|
|
|
|
}
|
|
|
|
|
if (priceData.itemUpd.StackObjectsCount.HasValue)
|
|
|
|
|
{
|
|
|
|
|
itemsToAdd.First().upd.StackObjectsCount = priceData.itemUpd.StackObjectsCount.Value;
|
|
|
|
|
}
|
|
|
|
|
if (priceData.itemUpd.BuyRestrictionMax != null)
|
|
|
|
|
{
|
|
|
|
|
itemsToAdd.First().upd.BuyRestrictionMax = ((JsonElement)priceData.itemUpd.BuyRestrictionMax).GetInt32();
|
|
|
|
|
itemsToAdd.First().upd.BuyRestrictionCurrent = 0;
|
|
|
|
|
}
|
2023-08-02 20:32:57 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
2023-08-02 13:05:34 +01:00
|
|
|
|
{
|
2023-09-12 14:29:29 +01:00
|
|
|
|
var firstItem = itemsToAdd.First();
|
|
|
|
|
firstItem.upd ??= new Upd();
|
|
|
|
|
|
2023-08-09 18:56:10 +01:00
|
|
|
|
// no value in json, set stack count to 10
|
2023-09-12 14:29:29 +01:00
|
|
|
|
firstItem.upd.StackObjectsCount = 10;
|
2023-08-02 20:32:57 +01:00
|
|
|
|
}
|
2023-08-02 13:05:34 +01:00
|
|
|
|
|
2023-08-09 18:56:10 +01:00
|
|
|
|
outputAssortFile.items.AddRange(itemsToAdd);
|
|
|
|
|
}
|
2023-08-02 13:05:34 +01:00
|
|
|
|
|
2023-08-09 18:56:10 +01:00
|
|
|
|
var barterItemListInner = new List<BarterObject>();
|
|
|
|
|
if (hasPriceData && priceData.itemTpl == missingQuestAssort.Items[0]._tpl)
|
|
|
|
|
{
|
|
|
|
|
barterItemListInner.AddRange(priceData.barterScheme);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-09-12 14:29:29 +01:00
|
|
|
|
// Default to 6969 roubles
|
|
|
|
|
barterItemListInner.Add(new BarterObject() { _tpl = "5449016a4bdc2d6f028b456f", count = 6969 });
|
2023-08-09 18:56:10 +01:00
|
|
|
|
}
|
2023-08-02 13:05:34 +01:00
|
|
|
|
|
2023-08-09 18:56:10 +01:00
|
|
|
|
var barterItemListOuter = new List<List<BarterObject>> { barterItemListInner };
|
|
|
|
|
outputAssortFile.barter_scheme.Add(missingQuestAssort.Items[0]._id, barterItemListOuter);
|
|
|
|
|
|
|
|
|
|
outputAssortFile.loyal_level_items[missingQuestAssort.Items[0]._id] = missingQuestAssort.LoyaltyLevel;
|
|
|
|
|
|
|
|
|
|
var associatedQuestAssort = questAssort.success.FirstOrDefault(x => x.Value == missingQuestAssort.QuestId && x.Key.StartsWith("UnknownAssortId"));
|
|
|
|
|
if (associatedQuestAssort.Key != null)
|
|
|
|
|
{
|
2023-09-12 14:29:29 +01:00
|
|
|
|
LoggingHelpers.LogWarning($"Able to replace missing quest: {missingQuestAssort.QuestId} {questData.FirstOrDefault(x => x.Key == missingQuestAssort.QuestId).Value.QuestName} assort with placeholder");
|
2023-08-09 18:56:10 +01:00
|
|
|
|
questAssort.success.Remove(associatedQuestAssort.Key);
|
|
|
|
|
questAssort.success.Add(missingQuestAssort.Items[0]._id, missingQuestAssort.QuestId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IEnumerable<Item> ConvertRewardToItems(List<QuestRewardItem> rewardToConvert)
|
|
|
|
|
{
|
|
|
|
|
var output = new List<Item>();
|
|
|
|
|
foreach (var rewardItem in rewardToConvert)
|
|
|
|
|
{
|
|
|
|
|
var item = new Item()
|
|
|
|
|
{
|
|
|
|
|
_id = rewardItem._id,
|
|
|
|
|
_tpl = rewardItem._tpl,
|
|
|
|
|
parentId = rewardItem.parentId ?? "hideout",
|
|
|
|
|
slotId = rewardItem.slotId ?? "hideout"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (rewardItem.upd != null)
|
|
|
|
|
{
|
|
|
|
|
item.upd = (Upd)((JsonElement)rewardItem.upd).Deserialize(typeof(Upd));
|
2023-08-02 13:05:34 +01:00
|
|
|
|
}
|
2023-08-09 18:56:10 +01:00
|
|
|
|
|
|
|
|
|
output.Add(item);
|
2023-08-02 13:05:34 +01:00
|
|
|
|
}
|
2023-08-09 18:56:10 +01:00
|
|
|
|
|
|
|
|
|
return output;
|
2023-08-02 13:05:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void UpdateQuestAssortUnlockIds(string traderId, QuestAssort traderQuestAssort, Dictionary<string, Quest> finalisedQuestData, AssortRoot traderAssortRoot)
|
|
|
|
|
{
|
|
|
|
|
var alreadyMatchedAssortIds = new List<string>();
|
2023-11-22 14:24:58 +00:00
|
|
|
|
var assortUnlocks = QuestHelper.GetAssortUnlocks(finalisedQuestData).Where(x => x.TraderId == traderId);
|
2023-08-02 13:05:34 +01:00
|
|
|
|
foreach (var assort in assortUnlocks)
|
|
|
|
|
{
|
|
|
|
|
// Find quest that matches quest assort key
|
|
|
|
|
Quest matchingQuest = finalisedQuestData.FirstOrDefault(x => x.Key == assort.QuestId).Value;
|
|
|
|
|
if (matchingQuest == null)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RewardStatus matchingReward = null;
|
|
|
|
|
switch (assort.Criteria)
|
|
|
|
|
{
|
|
|
|
|
case "Success":
|
|
|
|
|
matchingReward = matchingQuest.rewards.Success.Single(x => x.id == assort.AssortUnlockId);
|
|
|
|
|
break;
|
|
|
|
|
case "Started":
|
|
|
|
|
matchingReward = matchingQuest.rewards.Started.Single(x => x.id == assort.AssortUnlockId);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try to find assort with an _id of the quests target value
|
|
|
|
|
var matchingAssortInTrader = traderAssortRoot.items.SingleOrDefault(x => x._id == matchingReward.target);
|
|
|
|
|
if (matchingAssortInTrader == null)
|
|
|
|
|
{
|
|
|
|
|
// Mismatch! quest reward has a target that doesnt exist in trader assort
|
|
|
|
|
// Update to match quest
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dictionary<string,string> matching = null;
|
|
|
|
|
switch (assort.Criteria)
|
|
|
|
|
{
|
|
|
|
|
case "Success":
|
|
|
|
|
matching = traderQuestAssort.success;
|
|
|
|
|
break;
|
|
|
|
|
case "Started":
|
|
|
|
|
matching = traderQuestAssort.started;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
var kvp = matching.FirstOrDefault(x => x.Value == matchingQuest._id && !alreadyMatchedAssortIds.Contains(x.Value));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
matchingReward.target = kvp.Key;
|
|
|
|
|
|
|
|
|
|
// Quests can have multiple unlocks per quest, keep track of processed assort ids
|
|
|
|
|
alreadyMatchedAssortIds.Add(kvp.Key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// merges bear and usec ragman clothing dumps into one file
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="trader"></param>
|
|
|
|
|
/// <param name="workingPath"></param>
|
|
|
|
|
/// <param name="traderFolderPath"></param>
|
|
|
|
|
private static void CreateRagmanSuitsFile(string workingPath, string traderFolderPath)
|
|
|
|
|
{
|
|
|
|
|
var suitFileNames = new List<string>();
|
|
|
|
|
suitFileNames.Add("usec.resp.client.trading.customization.");
|
|
|
|
|
suitFileNames.Add("bear.resp.client.trading.customization.");
|
|
|
|
|
var outputSuitData = new List<Suit>();
|
|
|
|
|
foreach (var suitSideFilename in suitFileNames)
|
|
|
|
|
{
|
|
|
|
|
var customisationFilePath = InputFileHelper.GetInputFilePaths().FirstOrDefault(x => x.Contains(suitSideFilename));
|
|
|
|
|
if (string.IsNullOrEmpty(customisationFilePath))
|
|
|
|
|
{
|
|
|
|
|
LoggingHelpers.LogWarning($"no suit file found: {suitSideFilename}, skipped");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-09-05 20:54:44 +01:00
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
var traderDataJson = File.ReadAllText(customisationFilePath);
|
|
|
|
|
if (traderDataJson != null)
|
|
|
|
|
{
|
|
|
|
|
var suitData = JsonSerializer.Deserialize<CustomisationRoot>(traderDataJson);
|
|
|
|
|
outputSuitData.AddRange(suitData.data);
|
|
|
|
|
}
|
2021-09-05 20:54:44 +01:00
|
|
|
|
}
|
2023-01-03 10:46:33 +00:00
|
|
|
|
|
|
|
|
|
JsonWriter.WriteJson(outputSuitData, traderFolderPath, workingPath, "suits");
|
2021-09-05 20:54:44 +01:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create quest assort file that links quest completions to trader assort unlocks
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="trader"></param>
|
|
|
|
|
/// <param name="assortRoot"></param>
|
|
|
|
|
/// <returns></returns>
|
2023-08-02 13:05:34 +01:00
|
|
|
|
private static QuestAssort GenerateQuestAssortForTrader(Trader trader, AssortRoot assortRoot, out List<AssortUnlocks> missingQuestAssorts)
|
2021-09-05 20:54:44 +01:00
|
|
|
|
{
|
2023-08-02 13:05:34 +01:00
|
|
|
|
missingQuestAssorts = new List<AssortUnlocks>();
|
|
|
|
|
|
2021-09-05 20:54:44 +01:00
|
|
|
|
var result = new QuestAssort();
|
2023-11-22 14:24:58 +00:00
|
|
|
|
var questData = QuestHelper.GetFinalisedQuestData();
|
2021-09-05 20:54:44 +01:00
|
|
|
|
|
2023-01-03 10:46:33 +00:00
|
|
|
|
// Find assort unlocks
|
2023-11-22 14:24:58 +00:00
|
|
|
|
List<AssortUnlocks> assortUnlocks = QuestHelper.GetAssortUnlocks(questData);
|
2023-01-31 17:32:55 +00:00
|
|
|
|
|
|
|
|
|
// Store already matched items
|
2023-08-02 13:05:34 +01:00
|
|
|
|
var matchedAssortItemIds = new List<string>();
|
2023-07-09 11:36:00 +01:00
|
|
|
|
int unknownCount = 1;
|
2021-09-05 20:54:44 +01:00
|
|
|
|
foreach (var assortUnlock in assortUnlocks.Where(x => x.TraderType == trader))
|
|
|
|
|
{
|
2023-01-31 17:32:55 +00:00
|
|
|
|
// Get unlock item details
|
|
|
|
|
var assortItemDetailsDB = ItemTemplateHelper.Items.FirstOrDefault(x => x.Key == assortUnlock.ItemUnlockedTemplateId);
|
|
|
|
|
var ItemName = assortItemDetailsDB.Value._name;
|
2023-07-09 11:36:00 +01:00
|
|
|
|
var assortItemModsFromQuest = assortUnlock.Items.Where(x => x.parentId == assortUnlock.ItemUnlockedId);
|
2021-09-05 20:54:44 +01:00
|
|
|
|
|
2023-07-09 11:36:00 +01:00
|
|
|
|
// Get matching assorts from trader
|
2023-08-02 13:05:34 +01:00
|
|
|
|
var results = GetMatchingTraderAssortsWithScore(assortRoot, assortUnlock, trader, matchedAssortItemIds);
|
|
|
|
|
|
|
|
|
|
// No matches, add a placeholder to output file
|
2023-07-09 11:36:00 +01:00
|
|
|
|
if (results.Keys.Count == 0)
|
2023-01-28 13:42:56 +00:00
|
|
|
|
{
|
2023-07-09 11:36:00 +01:00
|
|
|
|
// no assort found for this unlock, add to questassort with a placeholder value instead of assort id
|
|
|
|
|
LoggingHelpers.LogError($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. no assortId found");
|
2021-09-05 21:35:28 +01:00
|
|
|
|
|
2023-07-09 11:36:00 +01:00
|
|
|
|
result.success.Add($"UnknownAssortId{unknownCount}", assortUnlock.QuestId);
|
|
|
|
|
unknownCount++;
|
2023-01-31 17:32:55 +00:00
|
|
|
|
|
2023-08-02 13:05:34 +01:00
|
|
|
|
missingQuestAssorts.Add(assortUnlock);
|
|
|
|
|
|
2023-07-09 11:36:00 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-01-31 17:32:55 +00:00
|
|
|
|
|
2023-08-02 13:05:34 +01:00
|
|
|
|
// All the assorts found have a matching score below 0 - very bad
|
2023-07-31 14:23:13 +01:00
|
|
|
|
if (results.Values.All( x => x < 0))
|
|
|
|
|
{
|
|
|
|
|
LoggingHelpers.LogError($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. Only negative scored matches found");
|
|
|
|
|
|
|
|
|
|
result.success.Add($"UnknownAssortId{unknownCount}", assortUnlock.QuestId);
|
|
|
|
|
unknownCount++;
|
|
|
|
|
|
2023-08-02 13:05:34 +01:00
|
|
|
|
missingQuestAssorts.Add(assortUnlock);
|
|
|
|
|
|
2023-07-31 14:23:13 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-02 13:05:34 +01:00
|
|
|
|
// get highest scoring match
|
|
|
|
|
var highestScoringAssortIdMatch = results.OrderByDescending(x => x.Value).First().Key;
|
2023-01-28 13:42:56 +00:00
|
|
|
|
|
2023-07-09 11:36:00 +01:00
|
|
|
|
// Add assort item id to blacklist so it wont be matched again
|
2023-08-02 13:05:34 +01:00
|
|
|
|
matchedAssortItemIds.Add(highestScoringAssortIdMatch);
|
2023-01-28 13:42:56 +00:00
|
|
|
|
|
2023-07-09 11:36:00 +01:00
|
|
|
|
if (result.success.ContainsKey(highestScoringAssortIdMatch))
|
2023-01-28 13:42:56 +00:00
|
|
|
|
{
|
2023-01-31 17:32:55 +00:00
|
|
|
|
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. ALREADY EXISTS. SKIPPING");
|
2023-01-28 13:42:56 +00:00
|
|
|
|
continue;
|
2021-09-05 20:54:44 +01:00
|
|
|
|
}
|
2023-01-03 10:46:33 +00:00
|
|
|
|
|
2023-01-31 17:32:55 +00:00
|
|
|
|
LoggingHelpers.LogSuccess($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. ADDING TO QUEST-ASSORT");
|
2023-01-28 13:42:56 +00:00
|
|
|
|
|
|
|
|
|
if (assortUnlock.Criteria == "Success")
|
|
|
|
|
{
|
2023-07-09 11:36:00 +01:00
|
|
|
|
result.success.Add(highestScoringAssortIdMatch, assortUnlock.QuestId);
|
2023-01-28 13:42:56 +00:00
|
|
|
|
}
|
|
|
|
|
else if (assortUnlock.Criteria == "Started")
|
2023-01-03 10:46:33 +00:00
|
|
|
|
{
|
2023-07-09 11:36:00 +01:00
|
|
|
|
result.started.Add(highestScoringAssortIdMatch, assortUnlock.QuestId);
|
2023-01-03 10:46:33 +00:00
|
|
|
|
}
|
2023-01-28 13:42:56 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LoggingHelpers.LogError($"{assortUnlock.Criteria} quest criteria not handled");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
//if (assortUnlock.Criteria.ToLower() == "fail")
|
|
|
|
|
//{
|
|
|
|
|
// LoggingHelpers.LogError("Fail quest criteria not handled");
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
//if (assortUnlock.Criteria.ToLower() == "started")
|
|
|
|
|
//{
|
|
|
|
|
// LoggingHelpers.LogError("started quest criteria not handled");
|
|
|
|
|
//}
|
2021-09-05 20:54:44 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2023-07-09 11:36:00 +01:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get a list of matching assorts with a score of how well they match the quest assort requirements
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="traderAssortRoot">Traders assort items/barter/loyalty</param>
|
|
|
|
|
/// <param name="assortUnlock"></param>
|
|
|
|
|
/// <param name="trader"></param>
|
|
|
|
|
/// <param name="assortItemsThatMatchBlackList"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private static Dictionary<string, int> GetMatchingTraderAssortsWithScore(
|
|
|
|
|
AssortRoot traderAssortRoot,
|
|
|
|
|
AssortUnlocks assortUnlock,
|
|
|
|
|
Trader trader,
|
|
|
|
|
IEnumerable<string> assortItemsThatMatchBlackList)
|
|
|
|
|
{
|
|
|
|
|
var quests = QuestHelper.GetFinalisedQuestData();
|
|
|
|
|
var assortItemDetailsDB = ItemTemplateHelper.Items.FirstOrDefault(x => x.Key == assortUnlock.ItemUnlockedTemplateId);
|
|
|
|
|
var assortItemName = assortItemDetailsDB.Value._name;
|
|
|
|
|
var assortItemModsFromQuest = assortUnlock.Items.Where(x => x.parentId == assortUnlock.ItemUnlockedId);
|
|
|
|
|
|
|
|
|
|
// assort id + score
|
|
|
|
|
var matchScores = new Dictionary<string, int>();
|
|
|
|
|
List<Item> assortItemsThatMatch = traderAssortRoot.items
|
|
|
|
|
.Where(x => x._tpl == assortUnlock.ItemUnlockedTemplateId && x.slotId == "hideout")
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
if (assortItemsThatMatch?.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
LoggingHelpers.LogError($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId}. questId: {assortUnlock.QuestId}. No matches found. ");
|
|
|
|
|
return matchScores;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (assortItemsThatMatch?.Count > 2)
|
|
|
|
|
{
|
|
|
|
|
var questData = quests.FirstOrDefault(x => x.Key == assortUnlock.QuestId);
|
|
|
|
|
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId}. questId: {questData.Value.QuestName}. multiple matches found. ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var assortItemMatch in assortItemsThatMatch)
|
|
|
|
|
{
|
|
|
|
|
matchScores[assortItemMatch._id] = 0;
|
|
|
|
|
var itemBarter = traderAssortRoot.barter_scheme[assortItemMatch._id];
|
|
|
|
|
var barterItems = itemBarter.First();
|
|
|
|
|
if (barterItems.Count == 1 && TplIsMoney(barterItems[0]._tpl))
|
|
|
|
|
{
|
|
|
|
|
matchScores[assortItemMatch._id] += 2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
matchScores[assortItemMatch._id] += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Look up item in Loyalty Level array
|
|
|
|
|
var associatedLoyaltyLevelItem = traderAssortRoot.loyal_level_items
|
|
|
|
|
.FirstOrDefault(x => x.Key == assortItemMatch._id);
|
|
|
|
|
|
|
|
|
|
if (associatedLoyaltyLevelItem.Value == assortUnlock.LoyaltyLevel)
|
|
|
|
|
{
|
|
|
|
|
// Loyalty level matches
|
|
|
|
|
matchScores[assortItemMatch._id] += 5;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
matchScores[assortItemMatch._id] -= 25;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (assortItemsThatMatchBlackList.Contains(associatedLoyaltyLevelItem.Key))
|
|
|
|
|
{
|
|
|
|
|
// Not the item we want, its already been matched
|
|
|
|
|
matchScores[assortItemMatch._id] -= 25;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try matching by mods on item if they exist
|
|
|
|
|
if (assortItemModsFromQuest.Any())
|
|
|
|
|
{
|
|
|
|
|
var matchedItemMods = traderAssortRoot.items.Where(x => x.parentId == assortItemMatch._id).ToList();
|
|
|
|
|
if (assortItemModsFromQuest.Count() == matchedItemMods.Count)
|
|
|
|
|
{
|
|
|
|
|
// mod count from quest matches trader assort
|
|
|
|
|
matchScores[assortItemMatch._id] += 10;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. mismatch of mod count, skipping");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var desiredMod in assortItemModsFromQuest)
|
|
|
|
|
{
|
|
|
|
|
// Compare each mod item in turn
|
|
|
|
|
var matchingModInCurrentMatch = matchedItemMods.FirstOrDefault(x => x._tpl == desiredMod._tpl);
|
|
|
|
|
if (matchingModInCurrentMatch != null)
|
|
|
|
|
{
|
|
|
|
|
matchScores[assortItemMatch._id] += 2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. mismatch of mods, skipping");
|
|
|
|
|
matchScores[assortItemMatch._id] -= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return matchScores;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool TplIsMoney(string tpl)
|
|
|
|
|
{
|
|
|
|
|
var moneyTpls = new string[] { "5449016a4bdc2d6f028b456f", "569668774bdc2da2298b4568", "5696686a4bdc2da3298b456a" };
|
|
|
|
|
return moneyTpls.Contains(tpl);
|
|
|
|
|
}
|
2021-09-05 20:54:44 +01:00
|
|
|
|
}
|
|
|
|
|
}
|