New NPC design, minimal compared to original

This commit is contained in:
GMatrixGames 2022-01-06 17:49:27 -05:00
parent 9c2a899c35
commit fb33536c26
No known key found for this signature in database
GPG Key ID: 2621164AAF16CEDF
6 changed files with 302 additions and 19 deletions

@ -1 +1 @@
Subproject commit 3df254b665420e05978f61441659c69d2a40411f
Subproject commit 906641f95baaa7e269d96851c6b17e5fb8059abe

View File

@ -0,0 +1,228 @@
using System;
using System.Windows;
using CUE4Parse.UE4.Assets.Exports;
using CUE4Parse.UE4.Objects.Core.i18N;
using CUE4Parse.UE4.Objects.UObject;
using CUE4Parse.UE4.Versions;
using FModel.Framework;
using FModel.Settings;
using SkiaSharp;
using SkiaSharp.HarfBuzz;
namespace FModel.Creator.Bases.FN
{
public class BaseTandem : BaseIcon
{
private string _generalDescription, _additionalDescription;
public BaseTandem(UObject uObject, EIconStyle style) : base(uObject, style)
{
DefaultPreview = Utils.GetBitmap("FortniteGame/Content/UI/Foundation/Textures/BattleRoyale/FeaturedItems/Outfit/T-AthenaSoldiers-CID-883-Athena-Commando-M-ChOneJonesy.T-AthenaSoldiers-CID-883-Athena-Commando-M-ChOneJonesy");
Margin = 0;
Width = 690;
Height = 1080;
}
public override void ParseForInfo()
{
base.ParseForInfo();
string sidePanel = string.Empty, entryList = string.Empty;
if (Object.TryGetValue(out FSoftObjectPath sidePanelIcon, "SidePanelIcon"))
sidePanel = sidePanelIcon.AssetPathName.Text;
if (Object.TryGetValue(out FSoftObjectPath entryListIcon, "EntryListIcon"))
entryList = entryListIcon.AssetPathName.Text;
// Overrides for generic "default" images Epic uses for Quest-only or unfinished NPCs
if (sidePanel.Contains("Clown") && entryList.Contains("Clown"))
Preview = null;
else if (sidePanel.Contains("Bane") && !Object.Name.Contains("Sorana"))
Preview = Utils.GetBitmap(entryList);
else if (!string.IsNullOrWhiteSpace(sidePanel) && !sidePanel.Contains("Clown"))
Preview = Utils.GetBitmap(sidePanel);
else if ((string.IsNullOrWhiteSpace(sidePanel) || sidePanel.Contains("Clown")) && !string.IsNullOrWhiteSpace(entryList))
Preview = Utils.GetBitmap(entryList);
if (Object.TryGetValue(out FText genDesc, "GeneralDescription"))
_generalDescription = genDesc.Text;
if (Object.TryGetValue(out FText addDesc, "AdditionalDescription"))
_additionalDescription = addDesc.Text;
}
public override SKImage Draw()
{
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
using var c = new SKCanvas(ret);
DrawBackground(c);
DrawPreview(c);
DrawHaze(c);
// Korean is slightly smaller than other languages, so the font size is increased slightly
DrawName(c);
DrawGeneralDescription(c);
DrawAdditionalDescription(c);
return SKImage.FromBitmap(ret);
}
private readonly SKPaint _panelPaint = new() { IsAntialias = true, FilterQuality = SKFilterQuality.High, Color = SKColor.Parse("#0045C7") };
private new void DrawBackground(SKCanvas c)
{
c.DrawBitmap(SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/npcleftside.png"))?.Stream).Resize(Width, Height), 0, 0, new SKPaint { IsAntialias = false, FilterQuality = SKFilterQuality.None, ImageFilter = SKImageFilter.CreateBlur(0, 25) });
using var rect1 = new SKPath { FillType = SKPathFillType.EvenOdd };
_panelPaint.Color = SKColor.Parse("#002A8C");
rect1.MoveTo(29, 0);
rect1.LineTo(62, Height);
rect1.LineTo(Width, Height);
rect1.LineTo(Width, 0);
rect1.LineTo(29, 0);
rect1.Close();
c.DrawPath(rect1, _panelPaint);
_panelPaint.Shader = SKShader.CreateLinearGradient(new SKPoint(29, 0), new SKPoint(Width, Height),
new[] { SKColor.Parse("#002A8C") }, SKShaderTileMode.Clamp);
c.DrawPath(rect1, _panelPaint);
_panelPaint.Shader = SKShader.CreateRadialGradient(new SKPoint(348, 196), 300, new[] { SKColor.Parse("#0049CE"), SKColor.Parse("#002A8C") }, SKShaderTileMode.Clamp);
c.DrawPath(rect1, _panelPaint);
using var rect2 = new SKPath { FillType = SKPathFillType.EvenOdd };
rect2.MoveTo(10, 0);
rect2.LineTo(30, 0);
rect2.LineTo(63, Height);
rect2.LineTo(56, Height);
rect2.LineTo(10, 0);
rect2.Close();
c.DrawPath(rect2, _panelPaint);
_panelPaint.Shader = SKShader.CreateLinearGradient(new SKPoint(10, 0), new SKPoint(62, Height),
new[] { SKColor.Parse("#0045C7") }, SKShaderTileMode.Clamp);
c.DrawPath(rect2, _panelPaint);
}
private new void DrawPreview(SKCanvas c)
{
var previewToUse = Preview ?? DefaultPreview;
if (Preview == null)
{
previewToUse = DefaultPreview;
ImagePaint.BlendMode = SKBlendMode.DstOut;
ImagePaint.Color = SKColor.Parse("#00175F");
}
var x = -125;
switch (previewToUse.Width)
{
case 512 when previewToUse.Height == 1024:
previewToUse = previewToUse.ResizeWithRatio(500, 1000);
x = 100;
break;
case 512 when previewToUse.Height == 512:
previewToUse = previewToUse.Resize(512);
x = 125;
break;
default:
previewToUse = previewToUse.Resize(1000, 1000);
break;
}
c.DrawBitmap(previewToUse, x, 30, ImagePaint);
}
private void DrawHaze(SKCanvas c)
{
using var rect1 = new SKPath { FillType = SKPathFillType.EvenOdd };
rect1.MoveTo(29, 0);
rect1.LineTo(62, Height);
rect1.LineTo(Width, Height);
rect1.LineTo(Width, 0);
rect1.LineTo(29, 0);
rect1.Close();
_panelPaint.Shader = SKShader.CreateLinearGradient(new SKPoint(343, 0), new SKPoint(343, Height),
new[] { SKColors.Transparent, SKColor.Parse("#001E70FF"), SKColor.Parse("#001E70").WithAlpha(200), SKColor.Parse("#001E70").WithAlpha(245), SKColor.Parse("#001E70") }, new[] { 0, (float) .1, (float) .65, (float) .85, 1 }, SKShaderTileMode.Clamp);
c.DrawPath(rect1, _panelPaint);
}
private void DrawName(SKCanvas c)
{
if (string.IsNullOrWhiteSpace(DisplayName)) return;
DisplayNamePaint.TextSize = UserSettings.Default.AssetLanguage switch
{
ELanguage.Korean => 56,
_ => 42
};
DisplayNamePaint.TextScaleX = (float) 1.1;
DisplayNamePaint.Color = SKColors.White;
DisplayNamePaint.TextSkewX = (float) -.25;
DisplayNamePaint.TextAlign = SKTextAlign.Left;
var typeface = Utils.Typefaces.TandemDisplayName;
if (typeface == Utils.Typefaces.Default)
{
DisplayNamePaint.TextSize = 30;
}
DisplayNamePaint.Typeface = typeface;
var shaper = new CustomSKShaper(DisplayNamePaint.Typeface);
c.DrawShapedText(shaper, DisplayName.ToUpper(), 97, 900, DisplayNamePaint);
}
private void DrawGeneralDescription(SKCanvas c)
{
if (string.IsNullOrWhiteSpace(_generalDescription)) return;
DescriptionPaint.TextSize = UserSettings.Default.AssetLanguage switch
{
ELanguage.Korean => 20,
_ => 17
};
DescriptionPaint.Color = SKColor.Parse("#00FFFB");
DescriptionPaint.TextAlign = SKTextAlign.Left;
var typeface = Utils.Typefaces.TandemGenDescription;
if (typeface == Utils.Typefaces.Default)
{
DescriptionPaint.TextSize = 21;
}
DescriptionPaint.Typeface = typeface;
var shaper = new CustomSKShaper(DescriptionPaint.Typeface);
c.DrawShapedText(shaper, _generalDescription.ToUpper(), 97, 930, DescriptionPaint);
}
private void DrawAdditionalDescription(SKCanvas c)
{
if (string.IsNullOrWhiteSpace(_additionalDescription)) return;
DescriptionPaint.TextSize = UserSettings.Default.AssetLanguage switch
{
ELanguage.Korean => 22,
_ => 18
};
DescriptionPaint.Color = SKColor.Parse("#89D8FF");
DescriptionPaint.TextAlign = SKTextAlign.Left;
var typeface = Utils.Typefaces.TandemAddDescription;
if (typeface == Utils.Typefaces.Default)
{
DescriptionPaint.TextSize = 20;
}
DescriptionPaint.Typeface = typeface;
Utils.DrawMultilineText(c, _additionalDescription, Width, 0, SKTextAlign.Left,
new SKRect(97, 960, Width - 10, Height), DescriptionPaint, out _);
}
}
}

View File

@ -112,8 +112,10 @@ namespace FModel.Creator
_ => new BaseIcon(_object, _style)
};
return true;
case "FortTrapItemDefinition":
case "FortTandemCharacterData":
creator = new BaseTandem(_object, _style);
return true;
case "FortTrapItemDefinition":
case "FortSpyTechItemDefinition":
case "FortAccoladeItemDefinition":
case "FortContextTrapItemDefinition":

View File

@ -10,7 +10,7 @@ namespace FModel.Creator
{
public class Typefaces
{
private readonly Uri _BURBANK_BIG_CONDENSED_BOLD = new Uri("pack://application:,,,/Resources/BurbankBigCondensed-Bold.ttf");
private readonly Uri _BURBANK_BIG_CONDENSED_BOLD = new("pack://application:,,,/Resources/BurbankBigCondensed-Bold.ttf");
private const string _EXT = ".ufont";
// FortniteGame
@ -48,7 +48,7 @@ namespace FModel.Creator
private const string _NANUM_GOTHIC = "NanumGothic";
private const string _QUADRAT_BOLD = "Quadrat_Bold";
private const string _SEGOE_BOLD_ITALIC = "Segoe_Bold_Italic";
// WorldExplorers
private const string _BATTLE_BREAKERS_BASE_PATH = "/Game/UMG/Fonts/Faces/";
private const string _HEMIHEAD426 = "HemiHead426";
@ -66,6 +66,9 @@ namespace FModel.Creator
public readonly SKTypeface Bottom; // must be null for non-latin base languages
public readonly SKTypeface Bundle;
public readonly SKTypeface BundleNumber;
public readonly SKTypeface TandemDisplayName;
public readonly SKTypeface TandemGenDescription;
public readonly SKTypeface TandemAddDescription;
public Typefaces(CUE4ParseViewModel viewModel)
{
@ -91,12 +94,11 @@ namespace FModel.Creator
};
if (viewModel.Provider.TrySaveAsset(namePath + _EXT, out data))
{
var m = new MemoryStream(data) {Position = 0};
var m = new MemoryStream(data) { Position = 0 };
DisplayName = SKTypeface.FromStream(m);
}
else DisplayName = Default;
var descriptionPath = _FORTNITE_BASE_PATH +
language switch
{
@ -109,12 +111,11 @@ namespace FModel.Creator
};
if (viewModel.Provider.TrySaveAsset(descriptionPath + _EXT, out data))
{
var m = new MemoryStream(data) {Position = 0};
var m = new MemoryStream(data) { Position = 0 };
Description = SKTypeface.FromStream(m);
}
else Description = Default;
var bottomPath = _FORTNITE_BASE_PATH +
language switch
{
@ -127,20 +128,18 @@ namespace FModel.Creator
};
if (viewModel.Provider.TrySaveAsset(bottomPath + _EXT, out data))
{
var m = new MemoryStream(data) {Position = 0};
var m = new MemoryStream(data) { Position = 0 };
Bottom = SKTypeface.FromStream(m);
}
// else keep it null
if (viewModel.Provider.TrySaveAsset(_FORTNITE_BASE_PATH + _BURBANK_BIG_CONDENSED_BLACK + _EXT, out data))
{
var m = new MemoryStream(data) {Position = 0};
var m = new MemoryStream(data) { Position = 0 };
BundleNumber = SKTypeface.FromStream(m);
}
else BundleNumber = Default;
var bundleNamePath = _FORTNITE_BASE_PATH +
language switch
{
@ -154,11 +153,63 @@ namespace FModel.Creator
};
if (viewModel.Provider.TrySaveAsset(bundleNamePath + _EXT, out data))
{
var m = new MemoryStream(data) {Position = 0};
var m = new MemoryStream(data) { Position = 0 };
Bundle = SKTypeface.FromStream(m);
}
else Bundle = BundleNumber;
var tandemDisplayNamePath = _FORTNITE_BASE_PATH +
language switch
{
ELanguage.Korean => _ASIA_ERINM,
ELanguage.Russian => _BURBANK_BIG_CONDENSED_BLACK,
ELanguage.Japanese => _NIS_JYAU,
ELanguage.Arabic => _NOTO_SANS_ARABIC_BLACK,
ELanguage.TraditionalChinese => _NOTO_SANS_TC_BLACK,
ELanguage.Chinese => _NOTO_SANS_SC_BLACK,
_ => _BURBANK_BIG_REGULAR_BLACK
};
if (viewModel.Provider.TrySaveAsset(tandemDisplayNamePath + _EXT, out data))
{
var m = new MemoryStream(data) { Position = 0 };
TandemDisplayName = SKTypeface.FromStream(m);
}
else TandemDisplayName = Default;
var tandemGeneralDescPath = _FORTNITE_BASE_PATH +
language switch
{
ELanguage.Korean => _ASIA_ERINM,
ELanguage.Japanese => _NIS_JYAU,
ELanguage.Arabic => _NOTO_SANS_ARABIC_BLACK,
ELanguage.TraditionalChinese => _NOTO_SANS_TC_BLACK,
ELanguage.Chinese => _NOTO_SANS_SC_BLACK,
_ => _BURBANK_SMALL_BLACK
};
if (viewModel.Provider.TrySaveAsset(tandemGeneralDescPath + _EXT, out data))
{
var m = new MemoryStream(data) { Position = 0 };
TandemGenDescription = SKTypeface.FromStream(m);
}
else TandemGenDescription = Default;
var tandemAdditionalDescPath = _FORTNITE_BASE_PATH +
language switch
{
ELanguage.Korean => _ASIA_ERINM,
ELanguage.Japanese => _NIS_JYAU,
ELanguage.Arabic => _NOTO_SANS_ARABIC_BLACK,
ELanguage.TraditionalChinese => _NOTO_SANS_TC_BLACK,
ELanguage.Chinese => _NOTO_SANS_SC_BLACK,
_ => _BURBANK_SMALL_BOLD
};
if (viewModel.Provider.TrySaveAsset(tandemAdditionalDescPath + _EXT, out data))
{
var m = new MemoryStream(data) { Position = 0 };
TandemAddDescription = SKTypeface.FromStream(m);
}
else TandemAddDescription = Default;
break;
}
case FGame.WorldExplorers:
@ -174,7 +225,7 @@ namespace FModel.Creator
};
if (viewModel.Provider.TrySaveAsset(namePath + _EXT, out data))
{
var m = new MemoryStream(data) {Position = 0};
var m = new MemoryStream(data) { Position = 0 };
DisplayName = SKTypeface.FromStream(m);
}
else DisplayName = Default;
@ -190,7 +241,7 @@ namespace FModel.Creator
};
if (viewModel.Provider.TrySaveAsset(descriptionPath + _EXT, out data))
{
var m = new MemoryStream(data) {Position = 0};
var m = new MemoryStream(data) { Position = 0 };
Description = SKTypeface.FromStream(m);
}
else Description = Default;
@ -209,14 +260,14 @@ namespace FModel.Creator
{
if (viewModel.Provider.TrySaveAsset(_SPELLBREAK_BASE_PATH + _QUADRAT_BOLD + _EXT, out data))
{
var m = new MemoryStream(data) {Position = 0};
var m = new MemoryStream(data) { Position = 0 };
DisplayName = SKTypeface.FromStream(m);
}
else DisplayName = Default;
if (viewModel.Provider.TrySaveAsset(_SPELLBREAK_BASE_PATH + _MONTSERRAT_SEMIBOLD + _EXT, out data))
{
var m = new MemoryStream(data) {Position = 0};
var m = new MemoryStream(data) { Position = 0 };
Description = SKTypeface.FromStream(m);
}
else Description = Default;
@ -241,8 +292,8 @@ namespace FModel.Creator
public SKTypeface OnTheFly(string path)
{
if (!_viewModel.Provider.TrySaveAsset(path, out var data)) return Default;
var m = new MemoryStream(data) {Position = 0};
var m = new MemoryStream(data) { Position = 0 };
return SKTypeface.FromStream(m);
}
}
}
}

View File

@ -91,6 +91,7 @@
<None Remove="Resources\delete.png" />
<None Remove="Resources\edit.png" />
<None Remove="Resources\go_to_directory.png" />
<None Remove="Resources\npcleftside.png" />
</ItemGroup>
<ItemGroup>
@ -187,6 +188,7 @@
<Resource Include="Resources\edit.png" />
<Resource Include="Resources\go_to_directory.png" />
<Resource Include="Resources\approaching_storm_cubemap.dds" />
<Resource Include="Resources\npcleftside.png" />
</ItemGroup>
<ItemGroup>

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB