Unstable v0.1300.0.0 (February 19th 2021)

This commit is contained in:
Joonas Rikkonen
2021-02-25 13:44:23 +02:00
parent b772654326
commit 24cbef485a
441 changed files with 21343 additions and 8562 deletions
@@ -0,0 +1,262 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.IO;
using Barotrauma.Items.Components;
namespace Barotrauma
{
public class SpreadsheetExport
{
private const char separator = ',';
private const string debugIdentifier = "_spreadsheet";
public static void Export()
{
XDocument doc = new XDocument();
if (doc.Root == null)
{
doc.Add(new XElement("Content"));
}
XElement root = doc.Root!;
foreach (ItemPrefab prefab in ItemPrefab.Prefabs)
{
XElement itemElement = new XElement("Item",
new XAttribute("identifier", prefab.Identifier),
new XAttribute("name", prefab.Name),
new XAttribute("tags", FormatArray(prefab.Tags)),
new XAttribute("value", prefab.DefaultPrice?.Price ?? 0)
);
itemElement.Add(ParseRecipe(prefab));
itemElement.Add(ParseDecon(prefab));
itemElement.Add(ParseMedical(prefab));
itemElement.Add(ParseWeapon(prefab));
root.Add(itemElement);
}
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings
{
Indent = false,
NewLineOnAttributes = false
};
using XmlWriter? writer = XmlWriter.Create("spreadsheetdata.xml", settings);
doc.SaveSafe(writer);
}
private static XElement ParseRecipe(ItemPrefab prefab)
{
FabricationRecipe? recipe = prefab.FabricationRecipes.FirstOrDefault();
List<ItemPrefab> ingredients = recipe?.RequiredItems.SelectMany(ri => ri.ItemPrefabs).Distinct().ToList() ?? new List<ItemPrefab>();
Skill? skill = recipe?.RequiredSkills.FirstOrDefault();
return new XElement("Recipe",
new XAttribute("amount", recipe?.Amount ?? 0),
new XAttribute("time", recipe?.RequiredTime ?? 0),
new XAttribute("skillname", skill?.Identifier ?? ""),
new XAttribute("skillamount", (int?) skill?.Level ?? 0),
new XAttribute("ingredients", FormatArray(ingredients.Select(ip => ip.Name))),
new XAttribute("values", FormatArray(ingredients.Select(ip => ip.DefaultPrice?.Price ?? 0)))
);
}
private static XElement ParseDecon(ItemPrefab prefab)
{
List<ItemPrefab> deconOutput = prefab.DeconstructItems.Select(item => ItemPrefab.Find(null, item.ItemIdentifier)).Where(outputPrefab => outputPrefab != null).ToList();
return new XElement("Deconstruct",
new XAttribute("time", prefab.DeconstructTime),
new XAttribute("outputs", FormatArray(deconOutput.Select(ip => ip.Name))),
new XAttribute("values", FormatArray(deconOutput.Select(ip => ip.DefaultPrice?.Price ?? 0)))
);
}
private static XElement ParseMedical(ItemPrefab prefab)
{
XElement? itemMeleeWeapon = prefab.ConfigElement.GetChildElement(nameof(MeleeWeapon));
// affliction, amount, duration
List<Tuple<string, float, float>> onSuccessAfflictions = new List<Tuple<string, float, float>>();
List<Tuple<string, float, float>> onFailureAfflictions = new List<Tuple<string, float, float>>();
int medicalRequiredSkill = 0;
if (itemMeleeWeapon != null)
{
List<StatusEffect> statusEffects = new List<StatusEffect>();
foreach (XElement subElement in itemMeleeWeapon.Elements())
{
string name = subElement.Name.ToString();
if (name.Equals(nameof(StatusEffect), StringComparison.OrdinalIgnoreCase))
{
StatusEffect statusEffect = StatusEffect.Load(subElement, debugIdentifier);
if (statusEffect == null || !statusEffect.HasTag("medical")) { continue; }
statusEffects.Add(statusEffect);
}
else if (IsRequiredSkill(subElement, out Skill? skill) && skill != null)
{
medicalRequiredSkill = (int) skill.Level;
}
}
List<StatusEffect> successEffects = statusEffects.Where(se => se.type == ActionType.OnUse).ToList();
List<StatusEffect> failureEffects = statusEffects.Where(se => se.type == ActionType.OnFailure).ToList();
foreach (StatusEffect statusEffect in successEffects)
{
float duration = statusEffect.Duration;
onSuccessAfflictions.AddRange(statusEffect.ReduceAffliction.Select(pair => Tuple.Create(GetAfflictionName(pair.First), -pair.Second, duration)));
onSuccessAfflictions.AddRange(statusEffect.Afflictions.Select(affliction => Tuple.Create(affliction.Prefab.Name, affliction.NonClampedStrength, duration)));
}
foreach (StatusEffect statusEffect in failureEffects)
{
float duration = statusEffect.Duration;
onFailureAfflictions.AddRange(statusEffect.ReduceAffliction.Select(pair => Tuple.Create(GetAfflictionName(pair.First), -pair.Second, duration)));
onFailureAfflictions.AddRange(statusEffect.Afflictions.Select(affliction => Tuple.Create(affliction.Prefab.Name, affliction.NonClampedStrength, duration)));
}
}
return new XElement("Medical",
new XAttribute("skillamount", medicalRequiredSkill),
new XAttribute("successafflictions", FormatArray(onSuccessAfflictions.Select(tpl => tpl.Item1))),
new XAttribute("successamounts", FormatArray(onSuccessAfflictions.Select(tpl => FormatFloat(tpl.Item2)))),
new XAttribute("successdurations", FormatArray(onSuccessAfflictions.Select(tpl => FormatFloat(tpl.Item3)))),
new XAttribute("failureafflictions", FormatArray(onFailureAfflictions.Select(tpl => tpl.Item1))),
new XAttribute("failureamounts", FormatArray(onFailureAfflictions.Select(tpl => FormatFloat(tpl.Item2)))),
new XAttribute("failuredurations", FormatArray(onFailureAfflictions.Select(tpl => FormatFloat(tpl.Item3))))
);
}
private static XElement ParseWeapon(ItemPrefab prefab)
{
float stun = 0;
bool isAoE = false;
float? structDamage = null;
int skillRequirement = 0;
// affliction, amount
List<Tuple<string, float>> damages = new List<Tuple<string, float>>();
string[] validNames = { nameof(Projectile), nameof(MeleeWeapon), nameof(RepairTool), nameof(ItemComponent), nameof(RangedWeapon) };
foreach (XElement icElement in prefab.ConfigElement.Elements())
{
string icName = icElement.Name.ToString();
if (!validNames.Any(name => icName.Equals(name, StringComparison.OrdinalIgnoreCase))) { continue; }
foreach (XElement icChildElement in icElement.Elements())
{
string name = icChildElement.Name.ToString();
if (IsRequiredSkill(icChildElement, out Skill? skill) && skill != null)
{
skillRequirement = (int) skill.Level;
}
else if (name.Equals(nameof(Attack), StringComparison.OrdinalIgnoreCase))
{
ParseAttack(new Attack(icChildElement, debugIdentifier));
}
else if (name.Equals(nameof(Explosion), StringComparison.OrdinalIgnoreCase))
{
ParseExplosion(new[] { new Explosion(icChildElement, debugIdentifier) });
}
else if (name.Equals(nameof(StatusEffect), StringComparison.OrdinalIgnoreCase))
{
ParseStatusEffect(new[] { StatusEffect.Load(icChildElement, debugIdentifier) });
}
void ParseStatusEffect(IEnumerable<StatusEffect> statusEffects)
{
foreach (StatusEffect effect in statusEffects)
{
if (effect.HasTargetType(StatusEffect.TargetType.Character)) { continue; }
ParseAfflictions(effect.Afflictions);
ParseExplosion(effect.Explosions);
}
}
void ParseExplosion(IEnumerable<Explosion> explosions)
{
foreach (Explosion explosion in explosions)
{
isAoE = true;
ParseAttack(explosion.Attack);
ParseStatusEffect(explosion.Attack.StatusEffects);
}
}
void ParseAttack(Attack attack)
{
structDamage ??= attack.StructureDamage;
ParseAfflictions(attack.Afflictions.Keys);
ParseStatusEffect(attack.StatusEffects);
}
void ParseAfflictions(IEnumerable<Affliction> afflictions)
{
foreach (Affliction affliction in afflictions)
{
// Exclude stuns
if (affliction.Prefab == AfflictionPrefab.Stun)
{
stun += affliction.NonClampedStrength;
continue;
}
damages.Add(Tuple.Create(affliction.Prefab.Name, affliction.NonClampedStrength));
}
}
}
}
return new XElement("Weapon",
new XAttribute("damagenames", FormatArray(damages.Select(tpl => tpl.Item1))),
new XAttribute("damageamounts", FormatArray(damages.Select(tpl => FormatFloat(tpl.Item2)))),
new XAttribute("isaoe", isAoE),
new XAttribute("structuredamage", structDamage ?? 0),
new XAttribute("stun", FormatFloat(stun)),
new XAttribute("skillrequirement", skillRequirement)
);
}
private static string GetAfflictionName(string identifier)
{
return AfflictionPrefab.Prefabs.Find(prefab => prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase))?.Name ?? CultureInfo.CurrentCulture.TextInfo.ToTitleCase(identifier.ToLower());
}
private static string FormatFloat(float value)
{
return value.ToString("0.00", CultureInfo.InvariantCulture);
}
private static string FormatArray<T>(IEnumerable<T> array)
{
return string.Join(separator, array);
}
private static bool IsRequiredSkill(XElement element, out Skill? skill)
{
string name = element.Name.ToString();
bool isSkill = name.Equals("RequiredSkill", StringComparison.OrdinalIgnoreCase) ||
name.Equals("RequiredSkills", StringComparison.OrdinalIgnoreCase);
if (isSkill)
{
string identifier = element.GetAttributeString(nameof(Skill.Identifier).ToLowerInvariant(), string.Empty);
float level = element.GetAttributeFloat(nameof(Skill.Level).ToLowerInvariant(), 0f);
skill = new Skill(identifier, level);
}
else
{
skill = null;
}
return isSkill;
}
}
}
@@ -19,6 +19,8 @@ namespace Barotrauma
private set;
}
private static volatile bool cancelAll = false;
public static void Init(GraphicsDevice graphicsDevice, bool needsBmp = false)
{
_graphicsDevice = graphicsDevice;
@@ -36,6 +38,11 @@ namespace Barotrauma
});
}
public static void CancelAll()
{
cancelAll = true;
}
private static byte[] CompressDxt5(byte[] data, int width, int height)
{
using (System.IO.MemoryStream mstream = new System.IO.MemoryStream())
@@ -220,6 +227,7 @@ namespace Barotrauma
Texture2D tex = null;
CrossThread.RequestExecutionOnMainThread(() =>
{
if (cancelAll) { return; }
tex = new Texture2D(_graphicsDevice, width, height, mipmap, format);
tex.SetData(textureData);
});
@@ -99,6 +99,94 @@ namespace Barotrauma
if (hue < 240) return q1 + (q2 - q1) * (240 - hue) / 60;
return q1;
}
/// <summary>
/// Convert a HSV value into a RGB value.
/// </summary>
/// <param name="hue">Value between 0 and 360</param>
/// <param name="saturation">Value between 0 and 1</param>
/// <param name="value">Value between 0 and 1</param>
/// <see href="https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB">Reference</see>
/// <returns></returns>
public static Color HSVToRGB(float hue, float saturation, float value)
{
float c = value * saturation;
float h = Math.Clamp(hue, 0, 360) / 60f;
float x = c * (1 - Math.Abs(h % 2 - 1));
float r = 0,
g = 0,
b = 0;
if (0 <= h && h <= 1) { r = c; g = x; b = 0; }
else if (1 < h && h <= 2) { r = x; g = c; b = 0; }
else if (2 < h && h <= 3) { r = 0; g = c; b = x; }
else if (3 < h && h <= 4) { r = 0; g = x; b = c; }
else if (4 < h && h <= 5) { r = x; g = 0; b = c; }
else if (5 < h && h <= 6) { r = c; g = 0; b = x; }
float m = value - c;
return new Color(r + m, g + m, b + m);
}
/// <summary>
/// Convert a RGB value into a HSV value.
/// </summary>
/// <param name="color"></param>
/// <see href="https://www.cs.rit.edu/~ncs/color/t_convert.html">Reference</see>
/// <returns>
/// Vector3 where X is the hue (0-360 or NaN)
/// Y is the saturation (0-1)
/// Z is the value (0-1)
/// </returns>
public static Vector3 RGBToHSV(Color color)
{
float r = color.R / 255f,
g = color.G / 255f,
b = color.B / 255f;
float h, s;
float min = Math.Min(r, Math.Min(g, b));
float max = Math.Max(r, Math.Max(g, b));
float v = max;
float delta = max - min;
if (max != 0)
{
s = delta / max;
}
else
{
s = 0;
h = -1;
return new Vector3(h, s, v);
}
if (MathUtils.NearlyEqual(r, max))
{
h = (g - b) / delta;
}
else if (MathUtils.NearlyEqual(g, max))
{
h = 2 + (b - r) / delta;
}
else
{
h = 4 + (r - g) / delta;
}
h *= 60;
if (h < 0) { h += 360; }
return new Vector3(h, s, v);
}
public static Color Add(this Color sourceColor, Color color)
{
@@ -235,6 +323,7 @@ namespace Barotrauma
{
linePos = splitSize = 0.0f;
splitWord[k] = splitWord[k].Remove(splitWord[k].Length - 1) + "\n";
if (splitWord[k].Length <= 1) { break; }
j--;
splitWord.Add(string.Empty);
k++;
@@ -0,0 +1,160 @@
using Barotrauma.IO;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Text;
namespace Barotrauma
{
static class WikiImage
{
public static Rectangle CalculateBoundingBox(Character character)
{
Rectangle boundingBox = new Rectangle(character.WorldPosition.ToPoint(), Point.Zero);
void addPointsToBBox(float extentX, float extentY, Vector2 worldPos, Vector2 origin, float rotation)
{
float sinRotation = (float)Math.Sin((double)rotation);
float cosRotation = (float)Math.Cos((double)rotation);
origin = new Vector2(
origin.X * cosRotation + origin.Y * sinRotation,
origin.X * sinRotation - origin.Y * cosRotation);
var limbPos = worldPos.ToPoint();
boundingBox.AddPoint(limbPos);
Vector2 xExtend = new Vector2((extentX * cosRotation), (extentX * sinRotation));
Vector2 yExtend = new Vector2((extentY * sinRotation), (-extentY * cosRotation));
boundingBox.AddPoint(limbPos + (xExtend + yExtend - origin).ToPoint());
boundingBox.AddPoint(limbPos + (xExtend - yExtend - origin).ToPoint());
boundingBox.AddPoint(limbPos + (-xExtend - yExtend - origin).ToPoint());
boundingBox.AddPoint(limbPos + (-xExtend + yExtend - origin).ToPoint());
}
foreach (Limb limb in character.AnimController.Limbs)
{
if (limb.ActiveSprite == null) { continue; }
float extentX = (float)limb.ActiveSprite.size.X * limb.Scale * limb.TextureScale * 0.5f;
//extentX = ConvertUnits.ToDisplayUnits(extentX);
float extentY = (float)limb.ActiveSprite.size.Y * limb.Scale * limb.TextureScale * 0.5f;
//extentY = ConvertUnits.ToDisplayUnits(extentY);
Vector2 origin = (limb.ActiveSprite.Origin - (limb.ActiveSprite.SourceRect.Size.ToVector2() * 0.5f)) * limb.Scale * limb.TextureScale;
addPointsToBBox(extentX, extentY, limb.WorldPosition, origin, limb.body.Rotation);
}
if (character.Inventory != null)
{
foreach (var item in character.Inventory.AllItems)
{
if (item?.Sprite != null && item?.body != null)
{
float extentX = (float)item.Sprite.size.X * item.Scale * 0.5f;
//extentX = ConvertUnits.ToDisplayUnits(extentX);
float extentY = (float)item.Sprite.size.Y * item.Scale * 0.5f;
//extentY = ConvertUnits.ToDisplayUnits(extentY);
Vector2 origin = (item.Sprite.Origin - (item.Sprite.SourceRect.Size.ToVector2() * 0.5f)) * item.Scale;
addPointsToBBox(extentX, extentY, item.WorldPosition, origin, item.body.Rotation);
}
}
}
boundingBox.X -= 25; boundingBox.Y -= 25;
boundingBox.Width += 50; boundingBox.Height += 50;
return boundingBox;
}
public static void Create(Character character)
{
Rectangle boundingBox = CalculateBoundingBox(character);
int texWidth = Math.Clamp((int)(boundingBox.Width * 2.5f), 512, 4096);
float zoom = (float)texWidth / (float)boundingBox.Width;
int texHeight = (int)(zoom * boundingBox.Height);
Camera cam = new Camera();
cam.SetResolution(new Point(texWidth, texHeight));
cam.MaxZoom = zoom;
cam.MinZoom = zoom * 0.5f;
cam.Zoom = zoom;
cam.Position = boundingBox.Center.ToVector2();
cam.UpdateTransform(false);
using (RenderTarget2D rt = new RenderTarget2D(
GameMain.Instance.GraphicsDevice,
texWidth, texHeight, false, SurfaceFormat.Color, DepthFormat.None))
{
using (SpriteBatch spriteBatch = new SpriteBatch(GameMain.Instance.GraphicsDevice))
{
Viewport prevViewport = GameMain.Instance.GraphicsDevice.Viewport;
GameMain.Instance.GraphicsDevice.Viewport = new Viewport(0, 0, texWidth, texHeight);
GameMain.Instance.GraphicsDevice.SetRenderTarget(rt);
GameMain.Instance.GraphicsDevice.Clear(Color.Transparent);
spriteBatch.Begin(SpriteSortMode.BackToFront, transformMatrix: cam.Transform);
character.Draw(spriteBatch, cam);
if (character.Inventory != null)
{
foreach (var item in character.Inventory.AllItems)
{
if (item != null)
{
item.Draw(spriteBatch, false, false);
item.Draw(spriteBatch, false, true);
}
}
}
spriteBatch.End();
GameMain.Instance.GraphicsDevice.SetRenderTarget(null);
GameMain.Instance.GraphicsDevice.Viewport = prevViewport;
using (FileStream fs = File.Open("wikiimage.png", System.IO.FileMode.Create))
{
rt.SaveAsPng(fs, boundingBox.Width, boundingBox.Height);
}
}
}
}
public static void Create(Submarine sub)
{
int width = 4096; int height = 4096;
Rectangle subDimensions = sub.CalculateDimensions(false);
Vector2 viewPos = subDimensions.Center.ToVector2();
float scale = Math.Min(width / (float)subDimensions.Width, height / (float)subDimensions.Height);
var viewMatrix = Matrix.CreateTranslation(new Vector3(width / 2.0f, height / 2.0f, 0));
var transform = Matrix.CreateTranslation(
new Vector3(-viewPos.X, viewPos.Y, 0)) *
Matrix.CreateScale(new Vector3(scale, scale, 1)) *
viewMatrix;
using (RenderTarget2D rt = new RenderTarget2D(
GameMain.Instance.GraphicsDevice,
width, height, false, SurfaceFormat.Color, DepthFormat.None))
using (SpriteBatch spriteBatch = new SpriteBatch(GameMain.Instance.GraphicsDevice))
{
Viewport prevViewport = GameMain.Instance.GraphicsDevice.Viewport;
GameMain.Instance.GraphicsDevice.Viewport = new Viewport(0, 0, width, height);
GameMain.Instance.GraphicsDevice.SetRenderTarget(rt);
GameMain.Instance.GraphicsDevice.Clear(Color.Transparent);
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, null, null, null, transform);
Submarine.Draw(spriteBatch);
Submarine.DrawFront(spriteBatch);
Submarine.DrawDamageable(spriteBatch, null);
spriteBatch.End();
GameMain.Instance.GraphicsDevice.SetRenderTarget(null);
GameMain.Instance.GraphicsDevice.Viewport = prevViewport;
using (FileStream fs = File.Open("wikiimage.png", System.IO.FileMode.Create))
{
rt.SaveAsPng(fs, width, height);
}
}
}
}
}