Unstable 0.1400.0.0
This commit is contained in:
@@ -15,6 +15,7 @@ using Barotrauma.Extensions;
|
||||
using Barotrauma.Steam;
|
||||
using System.Threading.Tasks;
|
||||
using Barotrauma.MapCreatures.Behavior;
|
||||
using static Barotrauma.FabricationRecipe;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -1367,6 +1368,237 @@ namespace Barotrauma
|
||||
}
|
||||
}, isCheat: false));
|
||||
|
||||
commands.Add(new Command("analyzeitem", "analyzeitem: Analyzes one item for exploits.", (string[] args) =>
|
||||
{
|
||||
if (args.Length < 1) return;
|
||||
|
||||
List<FabricationRecipe> fabricableItems = new List<FabricationRecipe>();
|
||||
foreach (ItemPrefab iPrefab in ItemPrefab.Prefabs)
|
||||
{
|
||||
fabricableItems.AddRange(iPrefab.FabricationRecipes);
|
||||
}
|
||||
|
||||
string itemNameOrId = args[0].ToLowerInvariant();
|
||||
|
||||
ItemPrefab itemPrefab =
|
||||
(MapEntityPrefab.Find(itemNameOrId, identifier: null, showErrorMessages: false) ??
|
||||
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
|
||||
|
||||
if (itemPrefab == null)
|
||||
{
|
||||
NewMessage("Item not found for analyzing.");
|
||||
return;
|
||||
}
|
||||
NewMessage("Analyzing item " + itemPrefab.Name + " with base cost " + itemPrefab.DefaultPrice.Price);
|
||||
|
||||
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == itemPrefab);
|
||||
// omega nesting incoming
|
||||
if (fabricationRecipe != null)
|
||||
{
|
||||
foreach (Tuple<string, PriceInfo> itemLocationPrice in itemPrefab.GetSellPricesOver(0))
|
||||
{
|
||||
NewMessage(" If bought at " + itemLocationPrice.Item1 + " it costs " + itemLocationPrice.Item2.Price);
|
||||
int totalPrice = 0;
|
||||
int? totalBestPrice = 0;
|
||||
foreach (var ingredient in fabricationRecipe.RequiredItems)
|
||||
{
|
||||
foreach (ItemPrefab ingredientItemPrefab in ingredient.ItemPrefabs)
|
||||
{
|
||||
NewMessage(" Its ingredient " + ingredientItemPrefab.Name + " has base cost " + ingredientItemPrefab.DefaultPrice.Price);
|
||||
totalPrice += ingredientItemPrefab.DefaultPrice.Price;
|
||||
totalBestPrice += ingredientItemPrefab.GetMinPrice();
|
||||
int basePrice = ingredientItemPrefab.DefaultPrice.Price;
|
||||
foreach (Tuple<string, PriceInfo> ingredientItemLocationPrice in ingredientItemPrefab.GetBuyPricesUnder())
|
||||
{
|
||||
if (basePrice > ingredientItemLocationPrice.Item2.Price)
|
||||
{
|
||||
NewMessage(" Location " + ingredientItemLocationPrice.Item1 + " sells ingredient " + ingredientItemPrefab.Name + " for cheaper, " + ingredientItemLocationPrice.Item2.Price, Color.Yellow);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewMessage(" Location " + ingredientItemLocationPrice.Item1 + " sells ingredient " + ingredientItemPrefab.Name + " for more, " + ingredientItemLocationPrice.Item2.Price, Color.Teal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int costDifference = itemPrefab.DefaultPrice.Price - totalPrice;
|
||||
NewMessage(" Constructing the item from store-bought items provides " + costDifference + " profit with default values.");
|
||||
|
||||
if (totalBestPrice.HasValue)
|
||||
{
|
||||
int? bestDifference = itemLocationPrice.Item2.Price - totalBestPrice;
|
||||
NewMessage(" Constructing the item from store-bought items provides " + bestDifference + " profit with best-case scenario values.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}, isCheat: false));
|
||||
|
||||
commands.Add(new Command("checkcraftingexploits", "checkcraftingexploits: Finds outright item exploits created by buying store-bought ingredients and constructing them into sellable items.", (string[] args) =>
|
||||
{
|
||||
List<FabricationRecipe> fabricableItems = new List<FabricationRecipe>();
|
||||
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
|
||||
{
|
||||
fabricableItems.AddRange(itemPrefab.FabricationRecipes);
|
||||
}
|
||||
List<Tuple<string, int>> costDifferences = new List<Tuple<string, int>>();
|
||||
|
||||
int maximumAllowedCost = 5;
|
||||
|
||||
if (args.Length > 0)
|
||||
{
|
||||
Int32.TryParse(args[0], out maximumAllowedCost);
|
||||
}
|
||||
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
|
||||
{
|
||||
int? defaultCost = itemPrefab.DefaultPrice?.Price;
|
||||
int? fabricationCostStore = null;
|
||||
|
||||
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == itemPrefab);
|
||||
if (fabricationRecipe == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool canBeBought = true;
|
||||
|
||||
foreach (var ingredient in fabricationRecipe.RequiredItems)
|
||||
{
|
||||
int? ingredientPrice = ingredient.ItemPrefabs.Where(p => p.CanBeBought).Min(ip => ip.DefaultPrice?.Price);
|
||||
if (ingredientPrice.HasValue)
|
||||
{
|
||||
if (!fabricationCostStore.HasValue) { fabricationCostStore = 0; }
|
||||
float useAmount = ingredient.UseCondition ? ingredient.MinCondition : 1.0f;
|
||||
fabricationCostStore += (int)(ingredientPrice.Value * ingredient.Amount * useAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
canBeBought = false;
|
||||
}
|
||||
}
|
||||
if (fabricationCostStore.HasValue && defaultCost.HasValue && canBeBought)
|
||||
{
|
||||
int costDifference = defaultCost.Value - fabricationCostStore.Value;
|
||||
if (costDifference > maximumAllowedCost || costDifference < 0f)
|
||||
{
|
||||
float ratio = (float)fabricationCostStore.Value / defaultCost.Value;
|
||||
string message = "Fabricating \"" + itemPrefab.Name + "\" costs " + (int)(ratio * 100) + "% of the price of the item, or " + costDifference + " more. Item price: " + defaultCost.Value + ", ingredient prices: " + fabricationCostStore.Value;
|
||||
costDifferences.Add(new Tuple<string, int>(message, costDifference));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
costDifferences.Sort((x, y) => x.Item2.CompareTo(y.Item2));
|
||||
|
||||
foreach (Tuple<string, int> costDifference in costDifferences)
|
||||
{
|
||||
Color color = Color.Yellow;
|
||||
NewMessage(costDifference.Item1, color);
|
||||
}
|
||||
}, isCheat: false));
|
||||
|
||||
commands.Add(new Command("adjustprice", "adjustprice: Recursively prints out expected price adjustments for items derived from this item.", (string[] args) =>
|
||||
{
|
||||
List<FabricationRecipe> fabricableItems = new List<FabricationRecipe>();
|
||||
foreach (ItemPrefab iP in ItemPrefab.Prefabs)
|
||||
{
|
||||
fabricableItems.AddRange(iP.FabricationRecipes);
|
||||
}
|
||||
if (args.Length < 2)
|
||||
{
|
||||
NewMessage("Item or value not defined.");
|
||||
return;
|
||||
}
|
||||
string itemNameOrId = args[0].ToLowerInvariant();
|
||||
|
||||
ItemPrefab materialPrefab =
|
||||
(MapEntityPrefab.Find(itemNameOrId, identifier: null, showErrorMessages: false) ??
|
||||
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
|
||||
|
||||
if (materialPrefab == null)
|
||||
{
|
||||
NewMessage("Item not found for price adjustment.");
|
||||
return;
|
||||
}
|
||||
|
||||
AdjustItemTypes adjustItemType = AdjustItemTypes.NoAdjustment;
|
||||
if (args.Length > 2)
|
||||
{
|
||||
switch (args[2].ToLowerInvariant())
|
||||
{
|
||||
case "add":
|
||||
adjustItemType = AdjustItemTypes.Additive;
|
||||
break;
|
||||
case "mult":
|
||||
adjustItemType = AdjustItemTypes.Multiplicative;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Int32.TryParse(args[1].ToLowerInvariant(), out int newPrice))
|
||||
{
|
||||
Dictionary<ItemPrefab, int> newPrices = new Dictionary<ItemPrefab, int>();
|
||||
PrintItemCosts(newPrices, materialPrefab, fabricableItems, newPrice, true, adjustItemType: adjustItemType);
|
||||
PrintItemCosts(newPrices, materialPrefab, fabricableItems, newPrice, false, adjustItemType: adjustItemType);
|
||||
}
|
||||
|
||||
}, isCheat: false));
|
||||
|
||||
commands.Add(new Command("deconstructvalue", "deconstructvalue: Views and compares deconstructed component prices for this item.", (string[] args) =>
|
||||
{
|
||||
List<FabricationRecipe> fabricableItems = new List<FabricationRecipe>();
|
||||
foreach (ItemPrefab iP in ItemPrefab.Prefabs)
|
||||
{
|
||||
fabricableItems.AddRange(iP.FabricationRecipes);
|
||||
}
|
||||
if (args.Length < 1)
|
||||
{
|
||||
NewMessage("Item not defined.");
|
||||
return;
|
||||
}
|
||||
string itemNameOrId = args[0].ToLowerInvariant();
|
||||
|
||||
ItemPrefab parentItem =
|
||||
(MapEntityPrefab.Find(itemNameOrId, identifier: null, showErrorMessages: false) ??
|
||||
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
|
||||
|
||||
if (parentItem == null)
|
||||
{
|
||||
NewMessage("Item not found for price adjustment.");
|
||||
return;
|
||||
}
|
||||
|
||||
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == parentItem);
|
||||
int totalValue = 0;
|
||||
NewMessage(parentItem.Name + " has the price " + parentItem.DefaultPrice.Price);
|
||||
if (fabricationRecipe != null)
|
||||
{
|
||||
NewMessage(" It constructs from:");
|
||||
|
||||
foreach (RequiredItem requiredItem in fabricationRecipe.RequiredItems)
|
||||
{
|
||||
foreach (ItemPrefab itemPrefab in requiredItem.ItemPrefabs)
|
||||
{
|
||||
NewMessage(" " + itemPrefab.Name + " has the price " + itemPrefab.DefaultPrice.Price);
|
||||
totalValue += itemPrefab.DefaultPrice.Price;
|
||||
}
|
||||
}
|
||||
NewMessage("Its total value was: " + totalValue);
|
||||
totalValue = 0;
|
||||
}
|
||||
NewMessage(" The item deconstructs into:");
|
||||
foreach (DeconstructItem deconstructItem in parentItem.DeconstructItems)
|
||||
{
|
||||
ItemPrefab itemPrefab =
|
||||
(MapEntityPrefab.Find(deconstructItem.ItemIdentifier, identifier: null, showErrorMessages: false) ??
|
||||
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
|
||||
|
||||
NewMessage(" " + itemPrefab.Name + " has the price " + itemPrefab.DefaultPrice.Price);
|
||||
totalValue += itemPrefab.DefaultPrice.Price;
|
||||
}
|
||||
NewMessage("Its deconstruct value was: " + totalValue);
|
||||
|
||||
}, isCheat: false));
|
||||
|
||||
commands.Add(new Command("setentityproperties", "setentityproperties [property name] [value]: Sets the value of some property on all selected items/structures in the sub editor.", (string[] args) =>
|
||||
{
|
||||
if (args.Length != 2 || Screen.Selected != GameMain.SubEditorScreen) { return; }
|
||||
@@ -2935,5 +3167,155 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private enum AdjustItemTypes
|
||||
{
|
||||
NoAdjustment,
|
||||
Additive,
|
||||
Multiplicative
|
||||
}
|
||||
|
||||
private static void PrintItemCosts(Dictionary<ItemPrefab, int> newPrices, ItemPrefab materialPrefab, List<FabricationRecipe> fabricableItems, int newPrice, bool adjustDown, string depth = "", AdjustItemTypes adjustItemType = AdjustItemTypes.NoAdjustment)
|
||||
{
|
||||
if (newPrice < 1)
|
||||
{
|
||||
NewMessage(depth + materialPrefab.Name + " cannot be adjusted to this price, because it would become less than 1.");
|
||||
return;
|
||||
}
|
||||
|
||||
depth += " ";
|
||||
|
||||
if (newPrice > 0)
|
||||
{
|
||||
newPrices.TryAdd(materialPrefab, newPrice);
|
||||
}
|
||||
|
||||
int componentCost = 0;
|
||||
int newComponentCost = 0;
|
||||
|
||||
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == materialPrefab);
|
||||
|
||||
if (fabricationRecipe != null)
|
||||
{
|
||||
foreach (RequiredItem requiredItem in fabricationRecipe.RequiredItems)
|
||||
{
|
||||
foreach (ItemPrefab itemPrefab in requiredItem.ItemPrefabs)
|
||||
{
|
||||
GetAdjustedPrice(itemPrefab, ref componentCost, ref newComponentCost, newPrices);
|
||||
}
|
||||
}
|
||||
}
|
||||
string componentCostMultiplier = "";
|
||||
if (componentCost > 0)
|
||||
{
|
||||
componentCostMultiplier = $" (Relative difference to component cost {GetComponentCostDifference(materialPrefab.DefaultPrice.Price, componentCost)} => {GetComponentCostDifference(newPrice, newComponentCost)}, or flat profit {(int)(materialPrefab.DefaultPrice.Price - (int)componentCost)} => {newPrice - newComponentCost})";
|
||||
}
|
||||
string priceAdjustment = "";
|
||||
if (newPrice != materialPrefab.DefaultPrice.Price)
|
||||
{
|
||||
priceAdjustment = ", Suggested price adjustment is " + materialPrefab.DefaultPrice.Price + " => " + newPrice;
|
||||
}
|
||||
NewMessage(depth + materialPrefab.Name + "(" + materialPrefab.DefaultPrice.Price + ") " + priceAdjustment + componentCostMultiplier);
|
||||
|
||||
if (adjustDown)
|
||||
{
|
||||
if (componentCost > 0)
|
||||
{
|
||||
double newPriceMult = (double)newPrice / (double)(materialPrefab.DefaultPrice.Price);
|
||||
int newPriceDiff = componentCost + newPrice - materialPrefab.DefaultPrice.Price;
|
||||
|
||||
switch (adjustItemType)
|
||||
{
|
||||
case AdjustItemTypes.Additive:
|
||||
NewMessage(depth + materialPrefab.Name + "'s components should be adjusted " + componentCost + " => " + newPriceDiff);
|
||||
break;
|
||||
case AdjustItemTypes.Multiplicative:
|
||||
NewMessage(depth + materialPrefab.Name + "'s components should be adjusted " + componentCost + " => " + Math.Round(newPriceMult * componentCost));
|
||||
break;
|
||||
}
|
||||
|
||||
if (fabricationRecipe != null)
|
||||
{
|
||||
foreach (RequiredItem requiredItem in fabricationRecipe.RequiredItems)
|
||||
{
|
||||
foreach (ItemPrefab itemPrefab in requiredItem.ItemPrefabs)
|
||||
{
|
||||
if (itemPrefab.DefaultPrice != null)
|
||||
{
|
||||
switch (adjustItemType)
|
||||
{
|
||||
case AdjustItemTypes.NoAdjustment:
|
||||
PrintItemCosts(newPrices, itemPrefab, fabricableItems, itemPrefab.DefaultPrice.Price, adjustDown, depth, adjustItemType);
|
||||
break;
|
||||
case AdjustItemTypes.Additive:
|
||||
PrintItemCosts(newPrices, itemPrefab, fabricableItems, itemPrefab.DefaultPrice.Price + (int)((newPrice - materialPrefab.DefaultPrice.Price) / (double)fabricationRecipe.RequiredItems.Count), adjustDown, depth, adjustItemType);
|
||||
break;
|
||||
case AdjustItemTypes.Multiplicative:
|
||||
PrintItemCosts(newPrices, itemPrefab, fabricableItems, (int)(itemPrefab.DefaultPrice.Price * newPriceMult), adjustDown, depth, adjustItemType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var fabricationRecipes = fabricableItems.Where(f => f.RequiredItems.Any(x => x.ItemPrefabs.Contains(materialPrefab)));
|
||||
|
||||
foreach (FabricationRecipe fabricationRecipeParent in fabricationRecipes)
|
||||
{
|
||||
if (fabricationRecipeParent.TargetItem.DefaultPrice != null)
|
||||
{
|
||||
int targetComponentCost = 0;
|
||||
int newTargetComponentCost = 0;
|
||||
|
||||
foreach (RequiredItem requiredItem in fabricationRecipeParent.RequiredItems)
|
||||
{
|
||||
foreach (ItemPrefab itemPrefab in requiredItem.ItemPrefabs)
|
||||
{
|
||||
GetAdjustedPrice(itemPrefab, ref targetComponentCost, ref newTargetComponentCost, newPrices);
|
||||
}
|
||||
}
|
||||
switch (adjustItemType)
|
||||
{
|
||||
case AdjustItemTypes.NoAdjustment:
|
||||
PrintItemCosts(newPrices, fabricationRecipeParent.TargetItem, fabricableItems, fabricationRecipeParent.TargetItem.DefaultPrice.Price, adjustDown, depth, adjustItemType);
|
||||
break;
|
||||
case AdjustItemTypes.Additive:
|
||||
PrintItemCosts(newPrices, fabricationRecipeParent.TargetItem, fabricableItems, fabricationRecipeParent.TargetItem.DefaultPrice.Price + newPrice - materialPrefab.DefaultPrice.Price, adjustDown, depth, adjustItemType);
|
||||
break;
|
||||
case AdjustItemTypes.Multiplicative:
|
||||
double maintainedMultiplier = GetComponentCostDifference(fabricationRecipeParent.TargetItem.DefaultPrice.Price, targetComponentCost);
|
||||
PrintItemCosts(newPrices, fabricationRecipeParent.TargetItem, fabricableItems, (int)(newTargetComponentCost * maintainedMultiplier), adjustDown, depth, adjustItemType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static double GetComponentCostDifference(int itemCost, int componentCost)
|
||||
{
|
||||
return Math.Round((double)(itemCost / (double)componentCost), 2);
|
||||
}
|
||||
|
||||
private static void GetAdjustedPrice(ItemPrefab itemPrefab, ref int componentCost, ref int newComponentCost, Dictionary<ItemPrefab, int> newPrices)
|
||||
{
|
||||
if (newPrices.TryGetValue(itemPrefab, out int newPrice))
|
||||
{
|
||||
newComponentCost += newPrice;
|
||||
}
|
||||
else if (itemPrefab.DefaultPrice != null)
|
||||
{
|
||||
newComponentCost += itemPrefab.DefaultPrice.Price;
|
||||
}
|
||||
if (itemPrefab.DefaultPrice != null)
|
||||
{
|
||||
componentCost += itemPrefab.DefaultPrice.Price;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user