├── templates
├── malebody.pdn
├── malebody.png
├── sleeves.pdn
├── sleeves.png
├── body_blank.png
├── femalebody.pdn
├── femalebody.png
├── sleeves_blank.png
├── novakid_sleeves.png
└── unxie_template.png
├── OutfitGenerator
├── Resources
│ ├── animatedBackTemplate.png
│ ├── animatedPantsTemplate.png
│ ├── animatedSleevesTemplate.png
│ ├── invisibleAnimatedPantsTemplate.png
│ ├── HatConfig.json
│ ├── HidingHatConfig.json
│ ├── MaskedHatConfig.json
│ ├── HidingPantsConfig.json
│ ├── PantsConfig.json
│ ├── BackConfig.json
│ └── SleevesConfig.json
├── packages.config
├── App.config
├── Mergers
│ ├── ISpriteMerger.cs
│ ├── SleevesMerger.cs
│ └── ChestPantsMerger.cs
├── Generators
│ ├── HidingHatGenerator.cs
│ ├── GeneratorException.cs
│ ├── HidingPantsGenerator.cs
│ ├── MaskedHatGenerator.cs
│ ├── BackGenerator.cs
│ ├── SleeveGenerator.cs
│ ├── PantsGenerator.cs
│ ├── IClothingGenerator.cs
│ ├── ClothingGenerator.cs
│ ├── HatGenerator.cs
│ └── DirectiveGenerator.cs
├── ItemDescriptor.cs
├── Util
│ ├── CommandGenerator.cs
│ ├── JsonResourceManager.cs
│ ├── FileSaver.cs
│ └── ConsoleWriter.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── OutfitGenerator.csproj
└── Program.cs
├── LICENSE
├── Outfit Generator.sln
├── README.md
└── .gitignore
/templates/malebody.pdn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/templates/malebody.pdn
--------------------------------------------------------------------------------
/templates/malebody.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/templates/malebody.png
--------------------------------------------------------------------------------
/templates/sleeves.pdn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/templates/sleeves.pdn
--------------------------------------------------------------------------------
/templates/sleeves.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/templates/sleeves.png
--------------------------------------------------------------------------------
/templates/body_blank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/templates/body_blank.png
--------------------------------------------------------------------------------
/templates/femalebody.pdn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/templates/femalebody.pdn
--------------------------------------------------------------------------------
/templates/femalebody.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/templates/femalebody.png
--------------------------------------------------------------------------------
/templates/sleeves_blank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/templates/sleeves_blank.png
--------------------------------------------------------------------------------
/templates/novakid_sleeves.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/templates/novakid_sleeves.png
--------------------------------------------------------------------------------
/templates/unxie_template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/templates/unxie_template.png
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/animatedBackTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/OutfitGenerator/Resources/animatedBackTemplate.png
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/animatedPantsTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/OutfitGenerator/Resources/animatedPantsTemplate.png
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/animatedSleevesTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/OutfitGenerator/Resources/animatedSleevesTemplate.png
--------------------------------------------------------------------------------
/OutfitGenerator/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/invisibleAnimatedPantsTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silverfeelin/Starbound-OutfitGenerator/HEAD/OutfitGenerator/Resources/invisibleAnimatedPantsTemplate.png
--------------------------------------------------------------------------------
/OutfitGenerator/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/OutfitGenerator/Mergers/ISpriteMerger.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 |
3 | namespace OutfitGenerator.Mergers
4 | {
5 | public interface ISpriteMerger
6 | {
7 | Bitmap Merge(string pathA, string pathB);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/HidingHatGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace OutfitGenerator.Generators
2 | {
3 | class HidingHatGenerator : HatGenerator
4 | {
5 | public override byte[] Config => Properties.Resources.HidingHatConfig;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/GeneratorException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OutfitGenerator
4 | {
5 | public class GeneratorException : Exception
6 | {
7 | public GeneratorException(string message) : base(message) { }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/HidingPantsGenerator.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 |
3 | namespace OutfitGenerator.Generators
4 | {
5 | public class HidingPantsGenerator : PantsGenerator
6 | {
7 | public override Bitmap Template => Properties.Resources.invisibleAnimatedPantsTemplate;
8 |
9 | public override byte[] Config => Properties.Resources.HidingPantsConfig;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/MaskedHatGenerator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace OutfitGenerator.Generators
8 | {
9 | public class MaskedHatGenerator : HatGenerator
10 | {
11 | public override byte[] Config => Properties.Resources.MaskedHatConfig;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/HatConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "descriptor": {
3 | "name": "eyepatchhead",
4 | "count": 1,
5 | "parameters": {
6 | "shortdescription": "Custom Hat",
7 | "description": "Made using the Outfit Generator.",
8 | "inventoryIcon": "head.png",
9 | "directives": "",
10 | "maleFrames": "head.png",
11 | "femaleFrames": "head.png",
12 | "mask": "mask.png",
13 | "statusEffects": []
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/HidingHatConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "descriptor": {
3 | "name": "frogghead",
4 | "count": 1,
5 | "parameters": {
6 | "shortdescription": "Custom Hat",
7 | "description": "Made using the Outfit Generator.",
8 | "inventoryIcon": "head.png",
9 | "directives": "",
10 | "maleFrames": "head.png",
11 | "femaleFrames": "head.png",
12 | "mask": "mask.png",
13 | "statusEffects": []
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/OutfitGenerator/ItemDescriptor.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | namespace OutfitGenerator
4 | {
5 | [JsonObject]
6 | public class ItemDescriptor
7 | {
8 | [JsonProperty("name")]
9 | public string Name { get; set; }
10 |
11 | [JsonProperty("count")]
12 | public int Count { get; set; } = 1;
13 |
14 | [JsonProperty("parameters")]
15 | public JObject Parameters { get; set; } = new JObject();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/OutfitGenerator/Util/CommandGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace OutfitGenerator.Util
2 | {
3 | public static class CommandGenerator
4 | {
5 | public static string SpawnItem(ItemDescriptor descriptor)
6 | {
7 | string parameters = descriptor.Parameters.ToString(Newtonsoft.Json.Formatting.None);
8 | string command = string.Format("/spawnitem {0} {1} '{2}'", descriptor.Name, descriptor.Count, parameters);
9 | return command;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/MaskedHatConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "descriptor": {
3 | "name": "eyepatchhead",
4 | "count": 1,
5 | "parameters": {
6 | "shortdescription": "Custom Hat",
7 | "description": "Made using the Outfit Generator.",
8 | "inventoryIcon": "head.png",
9 | "directives": "",
10 | "maleFrames": "head.png",
11 | "femaleFrames": "head.png",
12 | "mask": "?submask=/items/armors/decorative/hats/eyepatch/mask.png",
13 | "statusEffects": []
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/OutfitGenerator/Util/JsonResourceManager.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Newtonsoft.Json.Linq;
3 |
4 | namespace OutfitGenerator.Util
5 | {
6 | public static class JsonResourceManager
7 | {
8 | public static string GetResource(byte[] resource)
9 | {
10 | return Encoding.UTF8.GetString(resource);
11 | }
12 |
13 | public static JObject GetJsonObject(byte[] resource)
14 | {
15 | return JObject.Parse(GetResource(resource));
16 | }
17 |
18 | public static JArray GetJsonArray(byte[] resource)
19 | {
20 | return JArray.Parse(GetResource(resource));
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/BackGenerator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Drawing;
3 |
4 | namespace OutfitGenerator.Generators
5 | {
6 | public class BackGenerator : ClothingGenerator
7 | {
8 | public override string FileName => "back";
9 |
10 | private readonly ISet _supportedDimensions = new HashSet()
11 | {
12 | new Size(387,301)
13 | };
14 |
15 | public override ISet SupportedDimensions => _supportedDimensions;
16 |
17 | public override Bitmap Template => Properties.Resources.animatedBackTemplate;
18 |
19 | public override byte[] Config => Properties.Resources.BackConfig;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/OutfitGenerator/Util/FileSaver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace OutfitGenerator.Util
5 | {
6 | public static class FileSaver
7 | {
8 | ///
9 | /// Saves the given content to the given directory, using a generated file name.
10 | ///
11 | ///
12 | ///
13 | /// Generated file name.
14 | public static string Save(DirectoryInfo directory, string content, string fileNamePrefix = "generatedPants")
15 | {
16 | string file = string.Format("{0}-{1}.txt", fileNamePrefix, DateTime.Now.ToString("h-mm-ss"));
17 | string path = Path.Combine(directory.FullName, file);
18 | File.WriteAllText(path, content);
19 | return file;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/SleeveGenerator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 |
5 | namespace OutfitGenerator.Generators
6 | {
7 | public class SleeveGenerator : ClothingGenerator
8 | {
9 | public override string FileName => "sleeves";
10 |
11 | private readonly ISet _supportedDimensions = new HashSet()
12 | {
13 | new Size(387,602)
14 | };
15 |
16 | public override ISet SupportedDimensions => _supportedDimensions;
17 |
18 | public override Bitmap Template => Properties.Resources.animatedSleevesTemplate;
19 |
20 | public override byte[] Config => Properties.Resources.SleevesConfig;
21 |
22 | public override ItemDescriptor Generate(Bitmap bitmap)
23 | {
24 | return base.Generate(bitmap);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/PantsGenerator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Drawing;
3 |
4 | namespace OutfitGenerator.Generators
5 | {
6 | public class PantsGenerator : ClothingGenerator
7 | {
8 | public override string FileName => "pants";
9 |
10 | private readonly ISet _supportedDimensions = new HashSet()
11 | {
12 | new Size(387, 258),
13 | new Size(387, 301)
14 | };
15 |
16 | public override ISet SupportedDimensions => _supportedDimensions;
17 |
18 | public override Bitmap Template => Properties.Resources.animatedPantsTemplate;
19 |
20 | public override byte[] Config => Properties.Resources.PantsConfig;
21 |
22 | public override ItemDescriptor Generate(Bitmap bitmap)
23 | {
24 | if (bitmap?.Height == 301)
25 | {
26 | bitmap = Crop(bitmap, 0, 0, bitmap.Width, 258);
27 | }
28 |
29 | return base.Generate(bitmap);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Silverfeelin, KrashV
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The contents of the folder(s) listed below are property of Chucklefish LTD. or adapted versions thereof. As such, they do not fall under this specific license.
13 | - /templates/
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 |
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/IClothingGenerator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Drawing;
3 |
4 | namespace OutfitGenerator.Generators
5 | {
6 | public interface IClothingGenerator
7 | {
8 | ///
9 | /// Format for the exported file name.
10 | ///
11 | string FileName { get; }
12 | ///
13 | /// Gets the supported Bitmap dimensions for the generator, in pixels.
14 | ///
15 | ISet SupportedDimensions { get; }
16 |
17 | ///
18 | /// Gets the template used to generate directives.
19 | ///
20 | Bitmap Template { get; }
21 |
22 | ///
23 | /// Gets the template configuration used to generate item descriptors.
24 | ///
25 | byte[] Config { get; }
26 |
27 | ///
28 | /// Generates an item descriptor from the given image.
29 | ///
30 | /// Expected input and generated output differ per implementation.
31 | ///
32 | ///
33 | /// Non-null Bitmap matching any of .
34 | /// Spawnable Item Descriptor
35 | ItemDescriptor Generate(Bitmap bitmap);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/OutfitGenerator/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("OutfitGenerator")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("OutfitGenerator")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("c0bdd3a6-b257-416e-b550-638f65594676")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/OutfitGenerator/Util/ConsoleWriter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OutfitGenerator
4 | {
5 | ///
6 | /// Simple helper class to write colored text to the standard output.
7 | ///
8 | public class ConsoleWriter
9 | {
10 | public ConsoleColor DefaultColor { get; set; } = ConsoleColor.Cyan;
11 |
12 | public ConsoleWriter() { }
13 |
14 | public ConsoleWriter(ConsoleColor defaultColor)
15 | {
16 | DefaultColor = defaultColor;
17 | }
18 |
19 | public void Write(string str, params object[] args)
20 | {
21 | WriteColored(Console.Write, DefaultColor, str, args);
22 | }
23 |
24 | public void Write(ConsoleColor color, string str, params object[] args)
25 | {
26 | WriteColored(Console.Write, color, str, args);
27 | }
28 |
29 | public void WriteLine(string str, params object[] args)
30 | {
31 | WriteColored(Console.WriteLine, DefaultColor, str, args);
32 | }
33 |
34 | public void WriteLine(ConsoleColor color, string str, params object[] args)
35 | {
36 | WriteColored(Console.WriteLine, color, str, args);
37 | }
38 |
39 | private static void WriteColored(Action writeMethod, ConsoleColor color, string str, params object[] args)
40 | {
41 | ConsoleColor old = Console.ForegroundColor;
42 | Console.ForegroundColor = color;
43 | writeMethod(str, args);
44 |
45 | Console.ResetColor();
46 | Console.ForegroundColor = old;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Outfit Generator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2036
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OutfitGenerator", "OutfitGenerator\OutfitGenerator.csproj", "{C0BDD3A6-B257-416E-B550-638F65594676}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Debug|x64 = Debug|x64
12 | Debug|x86 = Debug|x86
13 | Release|Any CPU = Release|Any CPU
14 | Release|x64 = Release|x64
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {C0BDD3A6-B257-416E-B550-638F65594676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {C0BDD3A6-B257-416E-B550-638F65594676}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {C0BDD3A6-B257-416E-B550-638F65594676}.Debug|x64.ActiveCfg = Debug|Any CPU
21 | {C0BDD3A6-B257-416E-B550-638F65594676}.Debug|x64.Build.0 = Debug|Any CPU
22 | {C0BDD3A6-B257-416E-B550-638F65594676}.Debug|x86.ActiveCfg = Debug|Any CPU
23 | {C0BDD3A6-B257-416E-B550-638F65594676}.Debug|x86.Build.0 = Debug|Any CPU
24 | {C0BDD3A6-B257-416E-B550-638F65594676}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {C0BDD3A6-B257-416E-B550-638F65594676}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {C0BDD3A6-B257-416E-B550-638F65594676}.Release|x64.ActiveCfg = Release|Any CPU
27 | {C0BDD3A6-B257-416E-B550-638F65594676}.Release|x64.Build.0 = Release|Any CPU
28 | {C0BDD3A6-B257-416E-B550-638F65594676}.Release|x86.ActiveCfg = Release|Any CPU
29 | {C0BDD3A6-B257-416E-B550-638F65594676}.Release|x86.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {26701B08-65BA-4FE6-9F55-D2379F567715}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/ClothingGenerator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using Newtonsoft.Json.Linq;
5 | using OutfitGenerator.Util;
6 |
7 | namespace OutfitGenerator.Generators
8 | {
9 | public abstract class ClothingGenerator : IClothingGenerator
10 | {
11 | public abstract string FileName {get;}
12 |
13 | public abstract ISet SupportedDimensions { get; }
14 |
15 | public abstract Bitmap Template { get; }
16 |
17 | public abstract byte[] Config { get; }
18 |
19 | public virtual ItemDescriptor Generate(Bitmap bitmap)
20 | {
21 | // Parse arguments
22 | if (bitmap == null)
23 | {
24 | throw new ArgumentNullException("Bitmap may not be null.");
25 | }
26 |
27 | if (!SupportedDimensions.Contains(bitmap.Size))
28 | {
29 | throw new ArgumentException("Bitmap does not match any of the expected dimensions: " + String.Join(", ", SupportedDimensions));
30 | }
31 |
32 | // Load descriptor
33 | JObject config = JsonResourceManager.GetJsonObject(Config);
34 | ItemDescriptor descriptor = config["descriptor"].ToObject();
35 |
36 | // Generate and apply directives
37 | string directives = descriptor.Parameters["directives"].Value();
38 | directives = directives.Replace("{directives}", DirectiveGenerator.Generate(Template, bitmap));
39 | descriptor.Parameters["directives"] = directives;
40 |
41 | return descriptor;
42 | }
43 |
44 | ///
45 | /// Crops out the bottom (unused) row for larger pants sprites.
46 | /// It's not really necessary, but whatever.
47 | ///
48 | public static Bitmap Crop(Bitmap bmp, int x, int y, int width, int height)
49 | {
50 | return bmp.Clone(new Rectangle(x, y, width, height), bmp.PixelFormat);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/OutfitGenerator/Mergers/SleevesMerger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace OutfitGenerator.Mergers
9 | {
10 | public class SleevesMerger : ISpriteMerger
11 | {
12 | private const int SLEEVES_WIDTH = 387;
13 | private const int SLEEVES_HEIGHT = 301;
14 | private static Size sleevesSize = new Size(SLEEVES_WIDTH, SLEEVES_HEIGHT);
15 |
16 | public Bitmap Merge(string firstPath, string secondPath)
17 | {
18 | Bitmap frontSleeves;
19 | Bitmap backSleeves;
20 |
21 | // Predict the correct order:
22 | if (firstPath.ToLower().Contains("fsleeve") && secondPath.ToLower().Contains("bsleeve"))
23 | {
24 | frontSleeves = new Bitmap(firstPath);
25 | backSleeves = new Bitmap(secondPath);
26 | }
27 | else if (firstPath.ToLower().Contains("bsleeve") && secondPath.ToLower().Contains("fsleeve"))
28 | {
29 | frontSleeves = new Bitmap(secondPath);
30 | backSleeves = new Bitmap(firstPath);
31 | }
32 | else //prediction failed
33 | {
34 | Console.WriteLine("Is the order correct?");
35 | Console.WriteLine("Front sleeve: " + firstPath);
36 | Console.WriteLine("Back sleeve: " + secondPath);
37 | Console.WriteLine("Press Enter if it is, press any key otherwise");
38 |
39 | if (Console.ReadKey(true).Key == ConsoleKey.Enter)
40 | {
41 | frontSleeves = new Bitmap(firstPath);
42 | backSleeves = new Bitmap(secondPath);
43 | }
44 | else
45 | {
46 | frontSleeves = new Bitmap(secondPath);
47 | backSleeves = new Bitmap(firstPath);
48 | }
49 | }
50 |
51 | return ApllyMultingSleeves(frontSleeves, backSleeves);
52 | }
53 |
54 | private static Bitmap ApllyMultingSleeves(Bitmap frontSleeves, Bitmap backSleeves)
55 | {
56 | Bitmap result = new Bitmap(SLEEVES_WIDTH, SLEEVES_HEIGHT * 2);
57 |
58 | Superimpose(result, frontSleeves, 0, 0);
59 | Superimpose(result, backSleeves, 0, SLEEVES_HEIGHT);
60 |
61 | return result;
62 | }
63 |
64 | private static void Superimpose(Bitmap largeBmp, Bitmap smallBmp, int x, int y)
65 | {
66 | Graphics g = Graphics.FromImage(largeBmp);
67 | g.DrawImage(smallBmp, x, y, smallBmp.Width, smallBmp.Height);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/HidingPantsConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "descriptor": {
3 | "name": "froggmerchantlegs",
4 | "count": 1,
5 | "parameters": {
6 | "shortdescription": "Custom Pants",
7 | "description": "Made using the Outfit Generator.",
8 | "inventoryIcon": "pantsm.png:idle.2",
9 | "hideBody": true,
10 | "directives": "?scale=0.4?scale=0.7?scale=0.85?crop;6;1;7;2?replace;45572af4=00a10000;4e6530f8=00a20000;4f6631f7=00a30000;445729f7=00a40000;4f6531f5=00a50000;487035fc=00a60000;445e2df8=00a70000;556733f4=00b10000;4a4122f6=00b20000;425929f0=00b30000;3e2f1cb7=00b40000;664d39bb=00b50000;425b2df2=00b60000;54201e7f=00b70000;56322780=00b80000;675831bb=00c10000;5916192a=00c20000;463c20c0=00c30000;36311bb7=00c40000;313c1ebb=00c50000;561b1a29=00c60000;38642bf4=00c70000;60493180=00c80000;415128bb=00d10000;47562ab9=00d20000;4939207f=00d30000;4f432681=00d40000;5a1e1b25=00d50000;5a1e1c25=00d60000;571a1a25=00d70000;62212413=00d80000;29452424=00e10000;96918a25=00e20000;4567347f=00e30000;5a755681=00e40000;427235f3=00e50000?scale=2?blendscreen=/objects/outpost/customsign/signplaceholder.png?replace;01a10000=2ea10000;00a10100=00a12e00;01a10100=2ea12e00;01a20000=2ea20000;00a20100=00a22e00;01a20100=2ea22e00;01a30000=2ea30000;00a30100=00a32e00;01a30100=2ea32e00;01a40000=2ea40000;00a40100=00a42e00;01a40100=2ea42e00;01a50000=2ea50000;00a50100=00a52e00;01a50100=2ea52e00;01a60000=2ea60000;00a60100=00a62e00;01a60100=2ea62e00;01a70000=2ea70000;00a70100=00a72e00;01a70100=2ea72e00;01b10000=2eb10000;00b10100=00b12e00;01b10100=2eb12e00;01b20000=2eb20000;00b20100=00b22e00;01b20100=2eb22e00;01b30000=2eb30000;00b30100=00b32e00;01b30100=2eb32e00;01b40000=2eb40000;00b40100=00b42e00;01b40100=2eb42e00;01b50000=2eb50000;00b50100=00b52e00;01b50100=2eb52e00;01b60000=2eb60000;00b60100=00b62e00;01b60100=2eb62e00;01b70000=2eb70000;00b70100=00b72e00;01b70100=2eb72e00;01b80000=2eb80000;00b80100=00b82e00;01b80100=2eb82e00;01c10000=2ec10000;00c10100=00c12e00;01c10100=2ec12e00;01c20000=2ec20000;00c20100=00c22e00;01c20100=2ec22e00;01c30000=2ec30000;00c30100=00c32e00;01c30100=2ec32e00;01c40000=2ec40000;00c40100=00c42e00;01c40100=2ec42e00;01c50000=2ec50000;00c50100=00c52e00;01c50100=2ec52e00;01c60000=2ec60000;00c60100=00c62e00;01c60100=2ec62e00;01c70000=2ec70000;00c70100=00c72e00;01c70100=2ec72e00;01c80000=2ec80000;00c80100=00c82e00;01c80100=2ec82e00;01d10000=2ed10000;00d10100=00d12e00;01d10100=2ed12e00;01d20000=2ed20000;00d20100=00d22e00;01d20100=2ed22e00;01d30000=2ed30000;00d30100=00d32e00;01d30100=2ed32e00;01d40000=2ed40000;00d40100=00d42e00;01d40100=2ed42e00;01d50000=2ed50000;00d50100=00d52e00;01d50100=2ed52e00;01d60000=2ed60000;00d60100=00d62e00;01d60100=2ed62e00;01d70000=2ed70000;00d70100=00d72e00;01d70100=2ed72e00;01d80000=2ed80000;00d80100=00d82e00;01d80100=2ed82e00;01e10000=2ee10000;00e10100=00e12e00;01e10100=2ee12e00;01e20000=2ee20000;00e20100=00e22e00;01e20100=2ee22e00;01e30000=2ee30000;00e30100=00e32e00;01e30100=2ee32e00;01e40000=2ee40000;00e40100=00e42e00;01e40100=2ee42e00;01e50000=2ee50000;00e50100=00e52e00;01e50100=2ee52e00?scale=47?crop;1;1;44;44{directives}"
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Starbound Outfit Generator
2 |
3 | >
4 |
5 | A tool that specializes in creating multiplayer compatible custom animated clothing using [Nettle Boy's directives](http://ilovebacons.com/threads/guide-to-re-animating-clothes-with-json.12019/page-5#post-92288) methods.
6 |
7 | #### Why pants?
8 |
9 | Nettle Boy has found a way to create multiplayer-compatible custom clothing that is fully animated. Hats aren't animated, tops contain only a few frames and back items contain a lot of duplicate frames. All of these options don't work all that well with the method.
10 |
11 | To limit the amount of sprites we need to modify, the pants should be used for the main parts of your outfit (chest, pants, back item).
12 | This does come with a limitation; the sprites are rendered between the front arm and body layer of your character. If your outfit comes with sleeves, you'll still need a chest item for this purpose.
13 |
14 | #### Why not put the entire outfit on the chest piece, then?
15 |
16 | The frames on chest pieces are limited. If you compare any chest sprite sheet with any pants sprite sheet, you'll notice the difference. Putting pants on a chest piece would lead to staggered animations.
17 |
18 | #### But I want a custom outfit, not just pants!
19 |
20 | Since the frames cover your full character, you can draw an entire outfit and put them on one item (which are, in fact, simply pants). It is highly recommended to use the [Starbound Hatter](https://silverfeelin.github.io/Starbound-Hatter/) for custom hats, to conserve data. This should increase overall performance for you and other players.
21 |
22 | For the sleeves of your outfit; these should be drawn on separate sprite sheets. The sleeve generator takes care of this part.
23 |
24 | ## Installation
25 |
26 | This tool requires [.NET Framework 4.5](https://www.microsoft.com/en-US/download/details.aspx?id=30653).
27 |
28 | * Download and extract the [latest release](https://github.com/Silverfeelin/Starbound-OutfitGenerator/releases).
29 | * Make sure both files are in the same folder. The sleeves generator depends on the pants generator to work.
30 |
31 | ## Usage
32 |
33 | * Draw your outfit, or use an existing sprite sheet. Templates can be found in the [templates](https://github.com/Silverfeelin/Starbound-OutfitGenerator/tree/master/templates) folder.
34 | * The climb frames are not used, so it is highly recommended to keep them out of your sprite sheet.
35 | * Drag your sprite sheet (preferably a 32-bit depth PNG) on top of the `OutfitGenerator` executable.
36 | * Select whether you want to make pants, sleeves or a back item by pressing the according key.
37 | * Use the generated `/spawnitem` command in-game.
38 | * The command is saved to a file and also copied directly to your clipboard.
39 |
40 | For custom sleeves, it is highly recommended to use a provided template. The front and back sleeve sheets have to be combined into one sheet for the tool. You can also sprite the front and back sleeves separately and merge them later by dragging both files on top of the application.
41 |
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/PantsConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "descriptor": {
3 | "name": "florantier6apants",
4 | "count": 1,
5 | "parameters": {
6 | "shortdescription": "Custom Pants",
7 | "description": "Made using the Outfit Generator.",
8 | "inventoryIcon": "pants.png:idle.2",
9 | "directives": "?replace;ffffff00=ffffff;00000000=ffffff;ffca8a00=ffffff;e0975c00=ffffff;a8563600=ffffff;6f291900=ffffff;9bba3d00=ffffff;48832f00=ffffff;1b4c2a00=ffffff;a4784400=ffffff;754c2300=ffffff;472b1300=ffffff;e7dfbd00=ffffff;320c4000=ffffff?scale=0.4?scale=0.7?replace;a0b03e=00a10000;7e9b35=00a20000;a5ba92=00a30000;769441=00a40000;557743=00a50000;83715c=00a60000;b19c82=00a70000;7c9036=00b10000;757a32=00b20000;91a638=00b30000;748e37=00b40000;746f2c=00b50000;7a8a31=00b60000;608333=00b70000;8f953a=00b80000;736f2f=00c10000;c2d1b4=00c20000;94ae76=00c30000;788e35=00c40000;6f602f=00c50000;6a846e=00c60000;617e34=00c70000;829935=00c80000;d5ddd7=00d10000;a5b4a7=00d20000;a4945f=00d30000;a57f58=00d40000;a98c6c=00d50000;ccc0a4=00d60000;cabb9d=00d70000;a5a381=00d80000;66714c=00e10000;ada788=00e20000;778c34=00e30000;b1917c=00e40000;95ad8f=00e50000?crop;6;2;7;3?scalenearest=2?blendscreen=/objects/outpost/customsign/signplaceholder.png?replace;01a10000=3fa10000;00a10100=00a13f00;01a10100=3fa13f00;01a20000=3fa20000;00a20100=00a23f00;01a20100=3fa23f00;01a30000=3fa30000;00a30100=00a33f00;01a30100=3fa33f00;01a40000=3fa40000;00a40100=00a43f00;01a40100=3fa43f00;01a50000=3fa50000;00a50100=00a53f00;01a50100=3fa53f00;01a60000=3fa60000;00a60100=00a63f00;01a60100=3fa63f00;01a70000=3fa70000;00a70100=00a73f00;01a70100=3fa73f00;01b10000=3fb10000;00b10100=00b13f00;01b10100=3fb13f00;01b20000=3fb20000;00b20100=00b23f00;01b20100=3fb23f00;01b30000=3fb30000;00b30100=00b33f00;01b30100=3fb33f00;01b40000=3fb40000;00b40100=00b43f00;01b40100=3fb43f00;01b50000=3fb50000;00b50100=00b53f00;01b50100=3fb53f00;01b60000=3fb60000;00b60100=00b63f00;01b60100=3fb63f00;01b70000=3fb70000;00b70100=00b73f00;01b70100=3fb73f00;01b80000=3fb80000;00b80100=00b83f00;01b80100=3fb83f00;01c10000=3fc10000;00c10100=00c13f00;01c10100=3fc13f00;01c20000=3fc20000;00c20100=00c23f00;01c20100=3fc23f00;01c30000=3fc30000;00c30100=00c33f00;01c30100=3fc33f00;01c40000=3fc40000;00c40100=00c43f00;01c40100=3fc43f00;01c50000=3fc50000;00c50100=00c53f00;01c50100=3fc53f00;01c60000=3fc60000;00c60100=00c63f00;01c60100=3fc63f00;01c70000=3fc70000;00c70100=00c73f00;01c70100=3fc73f00;01c80000=3fc80000;00c80100=00c83f00;01c80100=3fc83f00;01d10000=3fd10000;00d10100=00d13f00;01d10100=3fd13f00;01d20000=3fd20000;00d20100=00d23f00;01d20100=3fd23f00;01d30000=3fd30000;00d30100=00d33f00;01d30100=3fd33f00;01d40000=3fd40000;00d40100=00d43f00;01d40100=3fd43f00;01d50000=3fd50000;00d50100=00d53f00;01d50100=3fd53f00;01d60000=3fd60000;00d60100=00d63f00;01d60100=3fd63f00;01d70000=3fd70000;00d70100=00d73f00;01d70100=3fd73f00;01d80000=3fd80000;00d80100=00d83f00;01d80100=3fd83f00;01e10000=3fe10000;00e10100=00e13f00;01e10100=3fe13f00;01e20000=3fe20000;00e20100=00e23f00;01e20100=3fe23f00;01e30000=3fe30000;00e30100=00e33f00;01e30100=3fe33f00;01e40000=3fe40000;00e40100=00e43f00;01e40100=3fe43f00;01e50000=3fe50000;00e50100=00e53f00;01e50100=3fe53f00?scale=64?crop;1;1;44;44{directives}"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/HatGenerator.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json.Linq;
2 | using OutfitGenerator.Util;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Drawing;
6 | using System.Text;
7 |
8 | namespace OutfitGenerator.Generators
9 | {
10 | public class HatGenerator : ClothingGenerator
11 | {
12 | public override string FileName => "hat";
13 |
14 | private readonly ISet _supportedDimensions = new HashSet()
15 | {
16 | new Size(86, 215),
17 | new Size(43, 43)
18 | };
19 |
20 | public override ISet SupportedDimensions => _supportedDimensions;
21 |
22 | public override Bitmap Template => null;
23 |
24 | public override byte[] Config => Properties.Resources.HatConfig;
25 |
26 | public override ItemDescriptor Generate(Bitmap bitmap)
27 | {
28 | // Parse arguments
29 | if (bitmap == null)
30 | {
31 | throw new ArgumentNullException("Bitmap may not be null.");
32 | }
33 |
34 | if (!SupportedDimensions.Contains(bitmap.Size))
35 | {
36 | throw new ArgumentException("Bitmap does not match any of the expected dimensions: " + String.Join(", ", SupportedDimensions));
37 | }
38 |
39 | // Crop
40 | if (bitmap?.Height == 215)
41 | {
42 | bitmap = Crop(bitmap, 43, 0, 43, 43);
43 | }
44 |
45 | // Generate
46 | bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
47 |
48 | // 01002B00 2B002B00
49 | // 01000100 2B000100
50 | StringBuilder dir = new StringBuilder("?crop;0;0;2;2?replace;fff0=fff;0000=fff?setcolor=fff" +
51 | "?blendmult=/objects/outpost/customsign/signplaceholder.png" +
52 | "?replace;01000101=01000100;02000101=2B000100?replace;01000201=01002B00;02000201=2B002B00" +
53 | "?scale=43?crop=0;0;43;43");
54 |
55 | dir.Append("?replace");
56 | for (int x = 0; x < 43; x++)
57 | {
58 | for (int y = 0; y < 43; y++)
59 | {
60 | Color pixel = bitmap.GetPixel(x, y);
61 | if (pixel.A == 0) continue;
62 |
63 | dir.AppendFormat(";{0}00{1}00={2}",
64 | x.ToString("X2"),
65 | y.ToString("X2"),
66 | ColorToString(pixel));
67 | }
68 | }
69 |
70 | // Load descriptor
71 | JObject config = JsonResourceManager.GetJsonObject(Config);
72 | ItemDescriptor descriptor = config["descriptor"].ToObject();
73 |
74 | // Generate and apply directives
75 | descriptor.Parameters["directives"] = dir.ToString();
76 |
77 | return descriptor;
78 | }
79 |
80 | public string ColorToString(Color color)
81 | {
82 | return color.R.ToString("X2") +
83 | color.G.ToString("X2") +
84 | color.B.ToString("X2") +
85 | color.A.ToString("X2");
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/BackConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "descriptor": {
3 | "name": "tigertailback",
4 | "count": 1,
5 | "parameters": {
6 | "shortdescription": "Custom Back",
7 | "description": "Made using the Outfit Generator.",
8 | "inventoryIcon": "back.png:idle.1",
9 | "directives": "?scale=0.4?scale=0.7?scale=0.84?crop;4;2;5;3?replace;aa836459=00a10000;bb885e4e=00a20000;cb926431=00a30000;cb95693b=00a40000;cf91601c=00a50000;ce966b4b=00a60000;e6c2a50c=00a70000;cc93662e=00b10000;cc8c5921=00b20000;c1895c3d=00b30000;bf885c41=00b40000;cb8e5d2d=00b50000;c7895728=00b60000;ac7c5558=00b70000;b8a99d5d=00b80000;d796610f=00c10000;dc955b0a=00c20000;de965b06=00c30000;c3885730=00c40000;d9945b0d=00c50000;dc955b08=00c60000;da945b0a=00c70000;dfbca11e=00c80000;ce8e5b23=00d10000;dc945b06=00d20000;cf8f5b23=00d30000;9d74526f=00d40000;d28f5916=00d50000;de965b02=00d60000;e0975c00=00d70000;ecc3a200=00d80000;d08f5b1e=00e10000;da945b08=00e20000;cd905f2f=00e30000;d8955e14=00e40000;cc8d5920=00e50000;59504932=00f10000;655c5509=00f20000;7369631b=00f30000;756c665a=00f40000;62574f32=00f50000;877d7782=00f60000;63595277=00f70000;a19d9959=00f80000?scale=2?blendscreen=/objects/outpost/customsign/signplaceholder.png?replace;01a10000=2ea10000;00a10100=00a12e00;01a10100=2ea12e00;01a20000=2ea20000;00a20100=00a22e00;01a20100=2ea22e00;01a30000=2ea30000;00a30100=00a32e00;01a30100=2ea32e00;01a40000=2ea40000;00a40100=00a42e00;01a40100=2ea42e00;01a50000=2ea50000;00a50100=00a52e00;01a50100=2ea52e00;01a60000=2ea60000;00a60100=00a62e00;01a60100=2ea62e00;01a70000=2ea70000;00a70100=00a72e00;01a70100=2ea72e00;01b10000=2eb10000;00b10100=00b12e00;01b10100=2eb12e00;01b20000=2eb20000;00b20100=00b22e00;01b20100=2eb22e00;01b30000=2eb30000;00b30100=00b32e00;01b30100=2eb32e00;01b40000=2eb40000;00b40100=00b42e00;01b40100=2eb42e00;01b50000=2eb50000;00b50100=00b52e00;01b50100=2eb52e00;01b60000=2eb60000;00b60100=00b62e00;01b60100=2eb62e00;01b70000=2eb70000;00b70100=00b72e00;01b70100=2eb72e00;01b80000=2eb80000;00b80100=00b82e00;01b80100=2eb82e00;01c10000=2ec10000;00c10100=00c12e00;01c10100=2ec12e00;01c20000=2ec20000;00c20100=00c22e00;01c20100=2ec22e00;01c30000=2ec30000;00c30100=00c32e00;01c30100=2ec32e00;01c40000=2ec40000;00c40100=00c42e00;01c40100=2ec42e00;01c50000=2ec50000;00c50100=00c52e00;01c50100=2ec52e00;01c60000=2ec60000;00c60100=00c62e00;01c60100=2ec62e00;01c70000=2ec70000;00c70100=00c72e00;01c70100=2ec72e00;01c80000=2ec80000;00c80100=00c82e00;01c80100=2ec82e00;01d10000=2ed10000;00d10100=00d12e00;01d10100=2ed12e00;01d20000=2ed20000;00d20100=00d22e00;01d20100=2ed22e00;01d30000=2ed30000;00d30100=00d32e00;01d30100=2ed32e00;01d40000=2ed40000;00d40100=00d42e00;01d40100=2ed42e00;01d50000=2ed50000;00d50100=00d52e00;01d50100=2ed52e00;01d60000=2ed60000;00d60100=00d62e00;01d60100=2ed62e00;01d70000=2ed70000;00d70100=00d72e00;01d70100=2ed72e00;01d80000=2ed80000;00d80100=00d82e00;01d80100=2ed82e00;01e10000=2ee10000;00e10100=00e12e00;01e10100=2ee12e00;01e20000=2ee20000;00e20100=00e22e00;01e20100=2ee22e00;01e30000=2ee30000;00e30100=00e32e00;01e30100=2ee32e00;01e40000=2ee40000;00e40100=00e42e00;01e40100=2ee42e00;01e50000=2ee50000;00e50100=00e52e00;01e50100=2ee52e00;01f10000=2ef10000;00f10100=00f12e00;01f10100=2ef12e00;01f20000=2ef20000;00f20100=00f22e00;01f20100=2ef22e00;01f30000=2ef30000;00f30100=00f32e00;01f30100=2ef32e00;01f40000=2ef40000;00f40100=00f42e00;01f40100=2ef42e00;01f50000=2ef50000;00f50100=00f52e00;01f50100=2ef52e00;01f60000=2ef60000;00f60100=00f62e00;01f60100=2ef62e00;01f70000=2ef70000;00f70100=00f72e00;01f70100=2ef72e00;01f80000=2ef80000;00f80100=00f82e00;01f80100=2ef82e00?scale=47?crop;1;1;44;44{directives}"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/OutfitGenerator/Generators/DirectiveGenerator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Text;
5 |
6 | namespace OutfitGenerator.Generators
7 | {
8 | public class DirectiveGenerator
9 | {
10 | ///
11 | /// Alpha 0/1 are considered transparent, but #FFFFFF00 on the source bitmap is ignored regardless of the target color.
12 | ///
13 | public static readonly Color TRANSPARENT = Color.FromArgb(0, 255, 255, 255);
14 |
15 | ///
16 | /// Generates a replace directive to change from into to.
17 | /// If the same color is replaced by multiple different colors, only the last one will be remembered (going row by row, left to right, top to bottom).
18 | ///
19 | /// Source image.
20 | /// Target image.
21 | /// Directive string.
22 | public static string Generate(Bitmap from, Bitmap to)
23 | {
24 | if (from == null || to == null)
25 | {
26 | throw new ArgumentNullException("Bitmaps may not be null.");
27 | }
28 |
29 | if (from.Size != to.Size)
30 | {
31 | throw new ArgumentException(string.Format("Bitmap sizes must match.\n" +
32 | "Source: {0}" +
33 | "Target: {1}",
34 | from.Size,
35 | to.Size));
36 | }
37 |
38 | var size = from.Size;
39 |
40 | Dictionary conversions = new Dictionary();
41 |
42 | for (int y = 0; y < size.Height; y++)
43 | {
44 | for (int x = 0; x < size.Width; x++)
45 | {
46 | Color colorFrom = from.GetPixel(x, y),
47 | colorTo = to.GetPixel(x, y);
48 |
49 | if (colorFrom.Equals(TRANSPARENT)) continue;
50 | if (colorFrom.Equals(colorTo)) continue;
51 | if (colorTo.A == 0) continue;
52 |
53 | conversions[colorFrom] = colorTo;
54 | }
55 | }
56 |
57 | string directives = CreateDirectives(conversions);
58 | return directives;
59 | }
60 |
61 | ///
62 | /// Converts a Color to a hexidecimal color code, formatted RRGGBBAA.
63 | ///
64 | /// Color to convert.
65 | /// Hexadecimal RRGGBBAA color code.
66 | public static string ColorToString(Color c)
67 | {
68 | string r = c.R.ToString("X2"),
69 | g = c.G.ToString("X2"),
70 | b = c.B.ToString("X2"),
71 | a = c.A.ToString("X2");
72 |
73 | return (r + g + b + a).ToLower();
74 | }
75 |
76 | ///
77 | /// Creates a replace directives string that converts all color keys to their respective color values.
78 | /// The order of directives can not be guaranteed, and may not match the order in which entries were added to the dictionary.
79 | ///
80 | /// Table containing all color conversions. Keys are converted to their value counterpart.
81 | /// Replace directives string.
82 | public static string CreateDirectives(Dictionary conversions)
83 | {
84 | StringBuilder directives = new StringBuilder("?replace");
85 | foreach (KeyValuePair conversion in conversions)
86 | {
87 | directives.AppendFormat(";{0}={1}", ColorToString(conversion.Key), ColorToString(conversion.Value));
88 | }
89 | return directives.ToString();
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/OutfitGenerator/OutfitGenerator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C0BDD3A6-B257-416E-B550-638F65594676}
8 | Exe
9 | OutfitGenerator
10 | OutfitGenerator
11 | v4.6.1
12 | 512
13 | true
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 | ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | True
69 | True
70 | Resources.resx
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | ResXFileCodeGenerator
97 | Resources.Designer.cs
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
--------------------------------------------------------------------------------
/OutfitGenerator/Resources/SleevesConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "descriptor": {
3 | "name": "aviantier6schest",
4 | "count": 1,
5 | "parameters": {
6 | "shortdescription": "Custom Sleeves",
7 | "description": "Made using the Outfit Generator.",
8 | "inventoryIcon": "fsleeve.png:idle.1",
9 | "directives": "?replace;0000=000;fff0=ffff;1b4c2a00=1b4c2a;d1e16000=d1e160;9bba3d00=9bba3d;d93a3a00=d93a3a;93262500=932625;60111900=601119?scale=0.4?blendscreen=/objects/outpost/customsign/signplaceholder.png;0;-4?replace;9c4f32=e10000;702450=e10000;a95b3b=008787;c5764b=008787;837655=008787;6d2785=00c3c3;8939a6=00c3c3;aa5538=00a5a5;bab350=00a5a5;8c3b5f=00a5a5;927d48=00a5a5;aa5536=878700;bab34f=878700;8c3b5e=878700;927d47=878700;7a516b=878700?scale=0.7?replace;c6ca57=a50000;9a6534=a50000;cdd95d=a50000;c6ca58=a50000;cbc359=a50000;cdd95e=a50000;b4a84b=00c3c3;c59550=00c3c3;c5ca66=00c3c3;998367=00c3c3;c7d360=00c3c3;625684=00c3c3;afdc72=00c3c3;96d87f=00c3c3;95d87f=00c3c3?scale=0.85?replace;cfd75c=a50000;c1913e=a50000;cbc454=a50000;ccc655=a50000;cad05d=a50000;9e6740=a50000;be9643=a50000;ccc957=a50000?scale=0.925?scale=0.9625?crop;5;4;6;5?replace;ccd85f=00a10000;cdd85f=00a20000;cddb5f=00a30000;c29f45=00a40000;cdda5f=00a50000;a6ba53=00a60000;bcbc5d=00b10000;c6cd61=00b20000;c3ca5e=00b30000;cfdb61=00b40000;d0de5f=00b50000;989558=00b60000;ad9b5a=00c10000;b7a256=00c20000;c6c861=00c30000;cfdd61=00c40000;cfdb60=00c50000;bfc05a=00d10000;d0dd61=00d20000;cadd64=00d30000;ccdc61=00d40000;cfdc60=00d50000;d1de61=00d60000;d1df61=00d70000;a6bb52=00d80000;c1bf5c=00e10000;bfbd58=00e20000;cbd35d=00e30000;b3a051=00e40000;cad15f=00e50000;c6c25f=00e60000;a5af55=00e70000;cdda60=00f10000;a4b754=00f20000;5a4837=00600000;b9b263=00610000;b2a660=00620000;b9b663=00630000;b4ab64=00640000;b5b958=00650000;b2a36c=00660000;b7b068=00670000;bcb768=00680000;a89e5d=00690000;b4ac65=006a0000;bebe60=006b0000;c2c166=006c0000;b9b464=006d0000;a89e5e=006e0000;c0bf61=006f0000;b6b65a=00700000;6e603e=00710000;a58c59=00720000;b6b45b=00730000;c2c062=00740000;b9b85a=00750000;b9bc5b=00760000;c4cb5d=00770000;b7bd57=00780000;70673a=00790000;babb5b=007a0000;b7b65a=007b0000;b8ab50=007c0000;c9cb68=007d0000;b9b75f=007e0000;bec060=007f0000;a89e5c=00800000;b6bb59=00810000;5e3834=ffffff00;aa8344=ffffff00;7e6646=ffffff00;828349=ffffff00;886a48=ffffff00;8d6d50=ffffff00;754f43=ffffff00;9a6639=ffffff00;825e46=ffffff00;848248=ffffff00;9a7051=ffffff00;85644e=ffffff00?scalenearest=2?blendscreen=/objects/outpost/customsign/signplaceholder.png?replace;01a10000=2ea10000;00a10100=00a12e00;01a10100=2ea12e00;01a20000=2ea20000;00a20100=00a22e00;01a20100=2ea22e00;01a30000=2ea30000;00a30100=00a32e00;01a30100=2ea32e00;01a40000=2ea40000;00a40100=00a42e00;01a40100=2ea42e00;01a50000=2ea50000;00a50100=00a52e00;01a50100=2ea52e00;01a60000=2ea60000;00a60100=00a62e00;01a60100=2ea62e00;01b10000=2eb10000;00b10100=00b12e00;01b10100=2eb12e00;01b20000=2eb20000;00b20100=00b22e00;01b20100=2eb22e00;01b30000=2eb30000;00b30100=00b32e00;01b30100=2eb32e00;01b40000=2eb40000;00b40100=00b42e00;01b40100=2eb42e00;01b50000=2eb50000;00b50100=00b52e00;01b50100=2eb52e00;01b60000=2eb60000;00b60100=00b62e00;01b60100=2eb62e00;01c10000=2ec10000;00c10100=00c12e00;01c10100=2ec12e00;01c20000=2ec20000;00c20100=00c22e00;01c20100=2ec22e00;01c30000=2ec30000;00c30100=00c32e00;01c30100=2ec32e00;01c40000=2ec40000;00c40100=00c42e00;01c40100=2ec42e00;01c50000=2ec50000;00c50100=00c52e00;01c50100=2ec52e00;01d10000=2ed10000;00d10100=00d12e00;01d10100=2ed12e00;01d20000=2ed20000;00d20100=00d22e00;01d20100=2ed22e00;01d30000=2ed30000;00d30100=00d32e00;01d30100=2ed32e00;01d40000=2ed40000;00d40100=00d42e00;01d40100=2ed42e00;01d50000=2ed50000;00d50100=00d52e00;01d50100=2ed52e00;01d60000=2ed60000;00d60100=00d62e00;01d60100=2ed62e00;01d70000=2ed70000;00d70100=00d72e00;01d70100=2ed72e00;01d80000=2ed80000;00d80100=00d82e00;01d80100=2ed82e00;01e10000=2ee10000;00e10100=00e12e00;01e10100=2ee12e00;01e20000=2ee20000;00e20100=00e22e00;01e20100=2ee22e00;01e30000=2ee30000;00e30100=00e32e00;01e30100=2ee32e00;01e40000=2ee40000;00e40100=00e42e00;01e40100=2ee42e00;01e50000=2ee50000;00e50100=00e52e00;01e50100=2ee52e00;01e60000=2ee60000;00e60100=00e62e00;01e60100=2ee62e00;01e70000=2ee70000;00e70100=00e72e00;01e70100=2ee72e00;01f10000=2ef10000;00f10100=00f12e00;01f10100=2ef12e00;01f20000=2ef20000;00f20100=00f22e00;01f20100=2ef22e00;01600000=2e600000;00600100=00602e00;01600100=2e602e00;01610000=2e610000;00610100=00612e00;01610100=2e612e00;01620000=2e620000;00620100=00622e00;01620100=2e622e00;01630000=2e630000;00630100=00632e00;01630100=2e632e00;01640000=2e640000;00640100=00642e00;01640100=2e642e00;01650000=2e650000;00650100=00652e00;01650100=2e652e00;01660000=2e660000;00660100=00662e00;01660100=2e662e00;01670000=2e670000;00670100=00672e00;01670100=2e672e00;01680000=2e680000;00680100=00682e00;01680100=2e682e00;01690000=2e690000;00690100=00692e00;01690100=2e692e00;016a0000=2e6a0000;006a0100=006a2e00;016a0100=2e6a2e00;016b0000=2e6b0000;006b0100=006b2e00;016b0100=2e6b2e00;016c0000=2e6c0000;006c0100=006c2e00;016c0100=2e6c2e00;016d0000=2e6d0000;006d0100=006d2e00;016d0100=2e6d2e00;016e0000=2e6e0000;006e0100=006e2e00;016e0100=2e6e2e00;016f0000=2e6f0000;006f0100=006f2e00;016f0100=2e6f2e00;01700000=2e700000;00700100=00702e00;01700100=2e702e00;01710000=2e710000;00710100=00712e00;01710100=2e712e00;01720000=2e720000;00720100=00722e00;01720100=2e722e00;01730000=2e730000;00730100=00732e00;01730100=2e732e00;01740000=2e740000;00740100=00742e00;01740100=2e742e00;01750000=2e750000;00750100=00752e00;01750100=2e752e00;01760000=2e760000;00760100=00762e00;01760100=2e762e00;01770000=2e770000;00770100=00772e00;01770100=2e772e00;01780000=2e780000;00780100=00782e00;01780100=2e782e00;01790000=2e790000;00790100=00792e00;01790100=2e792e00;017a0000=2e7a0000;007a0100=007a2e00;017a0100=2e7a2e00;017b0000=2e7b0000;007b0100=007b2e00;017b0100=2e7b2e00;017c0000=2e7c0000;007c0100=007c2e00;017c0100=2e7c2e00;017d0000=2e7d0000;007d0100=007d2e00;017d0100=2e7d2e00;017e0000=2e7e0000;007e0100=007e2e00;017e0100=2e7e2e00;017f0000=2e7f0000;007f0100=007f2e00;017f0100=2e7f2e00;01800000=2e800000;00800100=00802e00;01800100=2e802e00;01810000=2e810000;00810100=00812e00;01810100=2e812e00?scale=47?crop;1;1;44;44{directives}"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/OutfitGenerator/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 | using Newtonsoft.Json;
11 | using OutfitGenerator.Generators;
12 | using OutfitGenerator.Mergers;
13 | using OutfitGenerator.Util;
14 |
15 | namespace OutfitGenerator
16 | {
17 | class Program
18 | {
19 | private static ConsoleWriter writer;
20 | private static readonly Dictionary visualNames = new Dictionary()
21 | {
22 | { typeof(HatGenerator), "Hat" },
23 | { typeof(MaskedHatGenerator), "Hat (Hide hair)" },
24 | { typeof(HidingHatGenerator), "Hat (Hide body)" },
25 | { typeof(SleeveGenerator), "Sleeves" },
26 | { typeof(PantsGenerator), "Pants" },
27 | { typeof(HidingPantsGenerator), "Pants (Hide body)" },
28 | { typeof(BackGenerator), "Back Item" },
29 |
30 | { typeof(ChestPantsMerger), "Merge Chest & Pants" },
31 | { typeof(SleevesMerger), "Merge Sleeves" }
32 | };
33 |
34 | // TODO: Clean this method up a bit more.
35 | [STAThread]
36 | static void Main(string[] args)
37 | {
38 | writer = new ConsoleWriter(ConsoleColor.Cyan);
39 | writer.WriteLine("= Outfit Generator");
40 | Console.WriteLine();
41 |
42 | writer.WriteLine("Select the desired generator:");
43 |
44 | if (args.Length > 2)
45 | {
46 | WaitAndExit($"Invalid number of parameters: {args.Length}. Expected 1 for outfit generation or 2 for sprite merging.");
47 | return;
48 | }
49 |
50 | // Read images.
51 | Bitmap[] images = new Bitmap[args.Length];
52 | try
53 | {
54 | for (int i = 0; i < args.Length; i++)
55 | {
56 | images[i] = new Bitmap(args[i]);
57 | }
58 | }
59 | catch (Exception exc)
60 | {
61 | WaitAndExit("Couldn't read image file: {0}", exc.Message);
62 | return;
63 | }
64 |
65 | // Prompt generator/merge type.
66 | Type generatorType;
67 | switch (args.Length)
68 | {
69 | case 0:
70 | WaitAndExit("Please drag and drop a valid image on the application (not this window).");
71 | break;
72 | case 1:
73 | // Prompt clothing to generate
74 | generatorType = SelectGenerator(typeof(HatGenerator), typeof(MaskedHatGenerator), typeof(HidingHatGenerator), typeof(SleeveGenerator), typeof(PantsGenerator), typeof(HidingPantsGenerator), typeof(BackGenerator));
75 |
76 | // Generate clothing
77 | IClothingGenerator generator = (IClothingGenerator)Activator.CreateInstance(generatorType);
78 | GenerateClothing(generator, images[0]);
79 | break;
80 | case 2:
81 | // Prompt sprites to merge
82 | generatorType = SelectGenerator(typeof(ChestPantsMerger), typeof(SleevesMerger));
83 |
84 | // Merge sprites
85 | ISpriteMerger merger = (ISpriteMerger)Activator.CreateInstance(generatorType);
86 | MergeSprites(merger, args[0], args[1]);
87 | break;
88 | }
89 | }
90 |
91 | private static Type SelectGenerator(params Type[] typeNames)
92 | {
93 | for (int i = 0; i < typeNames.Length; i++)
94 | {
95 | string visualName = visualNames[typeNames[i]];
96 | writer.WriteLine($"[{i + 1}]: {visualName}");
97 | }
98 |
99 | while (true)
100 | {
101 | ConsoleKeyInfo cki = Console.ReadKey(true);
102 |
103 | if (char.IsNumber(cki.KeyChar))
104 | {
105 | int choice = (cki.KeyChar - '0');
106 |
107 | if (--choice < typeNames.Length)
108 | return typeNames[choice];
109 | }
110 | }
111 | }
112 |
113 | private static void GenerateClothing(IClothingGenerator generator, Bitmap bmp)
114 | {
115 | try
116 | {
117 | ItemDescriptor item = generator.Generate(bmp);
118 | string s = CommandGenerator.SpawnItem(item);
119 | string file = string.Format("{0} {1}.txt", generator.FileName, DateTime.Now.ToString("MM-dd h.mm.ss"));
120 | File.WriteAllText(file, s);
121 | Clipboard.SetText(s);
122 | WaitAndExit("Saved command to {0} and copied into clipboard", file);
123 | }
124 | catch (Exception exc)
125 | {
126 | WaitAndExit("Failed to create clothing: {0}", exc.Message);
127 | }
128 | }
129 |
130 | private static void MergeSprites(ISpriteMerger merger, string a, string b)
131 | {
132 | try
133 | {
134 | Bitmap merged = merger.Merge(a, b);
135 | string file = string.Format("merged {0}.png", DateTime.Now.ToString("MM-dd h.mm.ss"));
136 | merged.Save(file);
137 | Console.WriteLine("Saved image to {0}", file);
138 |
139 | //Propt to work with the saved image
140 | if (PromptWorking())
141 | {
142 | // Prompt clothing to generate
143 | Type generatorType = SelectGenerator(typeof(HatGenerator), typeof(MaskedHatGenerator), typeof(HidingHatGenerator), typeof(SleeveGenerator), typeof(PantsGenerator), typeof(HidingPantsGenerator), typeof(BackGenerator));
144 |
145 | // Generate clothing
146 | IClothingGenerator generator = (IClothingGenerator)Activator.CreateInstance(generatorType);
147 | GenerateClothing(generator, merged);
148 | }
149 | else
150 | {
151 | WaitAndExit("Saved image to {0}", file);
152 | }
153 | }
154 | catch (Exception exc)
155 | {
156 | WaitAndExit("Failed to merge sprites: {0}", exc.Message);
157 | }
158 | }
159 |
160 | private static bool PromptWorking()
161 | {
162 | writer.WriteLine("Would you like to proceed the result? y/n");
163 | string answer = Console.ReadLine();
164 | return answer.ToLower().Equals("y") || answer.ToLower().Equals("yes");
165 | }
166 |
167 | public static void WaitAndExit(string message = null, params object[] args)
168 | {
169 | if (!string.IsNullOrEmpty(message))
170 | {
171 | Console.WriteLine(message, args);
172 | }
173 | writer.WriteLine("Press any key to exit...");
174 |
175 | Console.ReadKey(true);
176 |
177 | Environment.Exit(0);
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/OutfitGenerator/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace OutfitGenerator.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OutfitGenerator.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Drawing.Bitmap.
65 | ///
66 | internal static System.Drawing.Bitmap animatedBackTemplate {
67 | get {
68 | object obj = ResourceManager.GetObject("animatedBackTemplate", resourceCulture);
69 | return ((System.Drawing.Bitmap)(obj));
70 | }
71 | }
72 |
73 | ///
74 | /// Looks up a localized resource of type System.Drawing.Bitmap.
75 | ///
76 | internal static System.Drawing.Bitmap animatedPantsTemplate {
77 | get {
78 | object obj = ResourceManager.GetObject("animatedPantsTemplate", resourceCulture);
79 | return ((System.Drawing.Bitmap)(obj));
80 | }
81 | }
82 |
83 | ///
84 | /// Looks up a localized resource of type System.Drawing.Bitmap.
85 | ///
86 | internal static System.Drawing.Bitmap animatedSleevesTemplate {
87 | get {
88 | object obj = ResourceManager.GetObject("animatedSleevesTemplate", resourceCulture);
89 | return ((System.Drawing.Bitmap)(obj));
90 | }
91 | }
92 |
93 | ///
94 | /// Looks up a localized resource of type System.Byte[].
95 | ///
96 | internal static byte[] BackConfig {
97 | get {
98 | object obj = ResourceManager.GetObject("BackConfig", resourceCulture);
99 | return ((byte[])(obj));
100 | }
101 | }
102 |
103 | ///
104 | /// Looks up a localized resource of type System.Byte[].
105 | ///
106 | internal static byte[] HatConfig {
107 | get {
108 | object obj = ResourceManager.GetObject("HatConfig", resourceCulture);
109 | return ((byte[])(obj));
110 | }
111 | }
112 |
113 | ///
114 | /// Looks up a localized resource of type System.Byte[].
115 | ///
116 | internal static byte[] HidingHatConfig {
117 | get {
118 | object obj = ResourceManager.GetObject("HidingHatConfig", resourceCulture);
119 | return ((byte[])(obj));
120 | }
121 | }
122 |
123 | ///
124 | /// Looks up a localized resource of type System.Byte[].
125 | ///
126 | internal static byte[] HidingPantsConfig {
127 | get {
128 | object obj = ResourceManager.GetObject("HidingPantsConfig", resourceCulture);
129 | return ((byte[])(obj));
130 | }
131 | }
132 |
133 | ///
134 | /// Looks up a localized resource of type System.Drawing.Bitmap.
135 | ///
136 | internal static System.Drawing.Bitmap invisibleAnimatedPantsTemplate {
137 | get {
138 | object obj = ResourceManager.GetObject("invisibleAnimatedPantsTemplate", resourceCulture);
139 | return ((System.Drawing.Bitmap)(obj));
140 | }
141 | }
142 |
143 | ///
144 | /// Looks up a localized resource of type System.Byte[].
145 | ///
146 | internal static byte[] MaskedHatConfig {
147 | get {
148 | object obj = ResourceManager.GetObject("MaskedHatConfig", resourceCulture);
149 | return ((byte[])(obj));
150 | }
151 | }
152 |
153 | ///
154 | /// Looks up a localized resource of type System.Byte[].
155 | ///
156 | internal static byte[] PantsConfig {
157 | get {
158 | object obj = ResourceManager.GetObject("PantsConfig", resourceCulture);
159 | return ((byte[])(obj));
160 | }
161 | }
162 |
163 | ///
164 | /// Looks up a localized resource of type System.Byte[].
165 | ///
166 | internal static byte[] SleevesConfig {
167 | get {
168 | object obj = ResourceManager.GetObject("SleevesConfig", resourceCulture);
169 | return ((byte[])(obj));
170 | }
171 | }
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/OutfitGenerator/Mergers/ChestPantsMerger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.Drawing.Drawing2D;
4 |
5 | namespace OutfitGenerator.Mergers
6 | {
7 | public class ChestPantsMerger : ISpriteMerger
8 | {
9 | private const int FRAME_SIZE = 43;
10 | private const int PANTS_WIDTH = 387;
11 | private const int PANTS_HEIGHT = 258;
12 | private const int PANTS_OLD_HEIGHT = 301;
13 | private const int CHEST_WIDTH = 86;
14 | private const int CHEST_HEIGHT = 258;
15 |
16 | private static Size chestSize = new Size(CHEST_WIDTH, CHEST_HEIGHT);
17 | private static Size pantsSize = new Size(PANTS_WIDTH, PANTS_HEIGHT);
18 | private static Size pantsOldSize = new Size(PANTS_WIDTH, PANTS_OLD_HEIGHT);
19 |
20 | public Bitmap Merge(string firstPath, string secondPath)
21 | {
22 | Bitmap chestBitmap;
23 | Bitmap pantsBitmap;
24 |
25 | // Predict the correct order:
26 | if (firstPath.ToLower().Contains("chest") && secondPath.ToLower().Contains("pants"))
27 | {
28 | chestBitmap = new Bitmap(firstPath);
29 | pantsBitmap = new Bitmap(secondPath);
30 | }
31 | else if (firstPath.ToLower().Contains("pants") && secondPath.ToLower().Contains("chest"))
32 | {
33 | chestBitmap = new Bitmap(secondPath);
34 | pantsBitmap = new Bitmap(firstPath);
35 | }
36 | else //prediction failed
37 | {
38 | Console.WriteLine("Is the order correct?");
39 | Console.WriteLine("Chest image: " + firstPath);
40 | Console.WriteLine("Pants image: " + secondPath);
41 | Console.WriteLine("Press Enter if it is, press any key otherwise");
42 |
43 | if (Console.ReadKey(true).Key == ConsoleKey.Enter)
44 | {
45 | chestBitmap = new Bitmap(firstPath);
46 | pantsBitmap = new Bitmap(secondPath);
47 | }
48 | else
49 | {
50 | chestBitmap = new Bitmap(secondPath);
51 | pantsBitmap = new Bitmap(firstPath);
52 | }
53 | }
54 |
55 | return ApplyMultingChestPants(chestBitmap, pantsBitmap);
56 | }
57 |
58 | private static Bitmap ApplyMultingChestPants(Bitmap chest, Bitmap pants)
59 | {
60 | Bitmap result = new Bitmap(pants);
61 |
62 | Bitmap chestIdle = chest.Clone(new Rectangle(FRAME_SIZE, 0, FRAME_SIZE, FRAME_SIZE), chest.PixelFormat);
63 | Bitmap chestIdle2 = chest.Clone(new Rectangle(0, FRAME_SIZE, FRAME_SIZE, FRAME_SIZE), chest.PixelFormat);
64 | Bitmap chestIdle3 = chest.Clone(new Rectangle(FRAME_SIZE, FRAME_SIZE, FRAME_SIZE, FRAME_SIZE), chest.PixelFormat);
65 |
66 | Bitmap chestRun = chest.Clone(new Rectangle(FRAME_SIZE, FRAME_SIZE * 2, FRAME_SIZE, FRAME_SIZE), chest.PixelFormat);
67 |
68 | Bitmap chestDuck = chest.Clone(new Rectangle(FRAME_SIZE, FRAME_SIZE * 3, FRAME_SIZE, FRAME_SIZE), chest.PixelFormat);
69 |
70 | Bitmap chestClimb = chest.Clone(new Rectangle(FRAME_SIZE, FRAME_SIZE * 4, FRAME_SIZE, FRAME_SIZE), chest.PixelFormat);
71 | Bitmap chestSwim = chest.Clone(new Rectangle(FRAME_SIZE, FRAME_SIZE * 5, FRAME_SIZE, FRAME_SIZE), chest.PixelFormat);
72 |
73 | // Personality 1,5
74 | SuperImpose(result, chestIdle, FRAME_SIZE, 0);
75 | SuperImpose(result, chestIdle, FRAME_SIZE * 5, 0);
76 |
77 | // Personality 2,4
78 | SuperImpose(result, chestIdle2, FRAME_SIZE * 2, 0);
79 | SuperImpose(result, chestIdle2, FRAME_SIZE * 4, 0);
80 |
81 | // Personality 3
82 | SuperImpose(result, chestIdle3, FRAME_SIZE * 3, 0);
83 |
84 | // Duck
85 | SuperImpose(result, chestDuck, 344, 0);
86 |
87 | // Sit
88 | SuperImpose(result, chestIdle, 258, 1);
89 |
90 | // Walking
91 | SuperImpose(result, chestIdle, FRAME_SIZE, FRAME_SIZE + 1);
92 | SuperImpose(result, chestIdle, FRAME_SIZE * 2, FRAME_SIZE + 2);
93 | SuperImpose(result, chestIdle, FRAME_SIZE * 3, FRAME_SIZE + 1);
94 | SuperImpose(result, chestIdle, FRAME_SIZE * 4, FRAME_SIZE);
95 | SuperImpose(result, chestIdle, FRAME_SIZE * 5, FRAME_SIZE + 1);
96 | SuperImpose(result, chestIdle, FRAME_SIZE * 6, FRAME_SIZE + 2);
97 | SuperImpose(result, chestIdle, FRAME_SIZE * 7, FRAME_SIZE + 1);
98 | SuperImpose(result, chestIdle, FRAME_SIZE * 8, FRAME_SIZE);
99 |
100 | // Running
101 | SuperImpose(result, chestRun, FRAME_SIZE, FRAME_SIZE * 2);
102 | SuperImpose(result, chestRun, FRAME_SIZE * 2, FRAME_SIZE * 2 - 1);
103 | SuperImpose(result, chestRun, FRAME_SIZE * 3, FRAME_SIZE * 2);
104 | SuperImpose(result, chestRun, FRAME_SIZE * 4, FRAME_SIZE * 2 + 1);
105 | SuperImpose(result, chestRun, FRAME_SIZE * 5, FRAME_SIZE * 2);
106 | SuperImpose(result, chestRun, FRAME_SIZE * 6, FRAME_SIZE * 2 - 1);
107 | SuperImpose(result, chestRun, FRAME_SIZE * 7, FRAME_SIZE * 2);
108 | SuperImpose(result, chestRun, FRAME_SIZE * 8, FRAME_SIZE * 2 + 1);
109 |
110 | // Jumping
111 | SuperImpose(result, chestIdle, FRAME_SIZE, FRAME_SIZE * 3 - 1);
112 | SuperImpose(result, chestIdle, FRAME_SIZE * 2, FRAME_SIZE * 3 - 1);
113 | SuperImpose(result, chestIdle, FRAME_SIZE * 3, FRAME_SIZE * 3 - 1);
114 | SuperImpose(result, chestIdle, FRAME_SIZE * 4, FRAME_SIZE * 3 - 1);
115 |
116 | // Falling
117 | SuperImpose(result, chestIdle, FRAME_SIZE * 5, FRAME_SIZE * 3 - 1);
118 | SuperImpose(result, chestIdle, FRAME_SIZE * 6, FRAME_SIZE * 3 - 1);
119 | SuperImpose(result, chestIdle, FRAME_SIZE * 7, FRAME_SIZE * 3 - 1);
120 | SuperImpose(result, chestIdle, FRAME_SIZE * 8, FRAME_SIZE * 3 - 1);
121 |
122 | // Climbing
123 | SuperImpose(result, chestClimb, FRAME_SIZE, FRAME_SIZE * 4);
124 | SuperImpose(result, chestClimb, FRAME_SIZE * 2, FRAME_SIZE * 4);
125 | SuperImpose(result, chestClimb, FRAME_SIZE * 3, FRAME_SIZE * 4);
126 | SuperImpose(result, chestClimb, FRAME_SIZE * 4, FRAME_SIZE * 4);
127 | SuperImpose(result, chestClimb, FRAME_SIZE * 5, FRAME_SIZE * 4);
128 | SuperImpose(result, chestClimb, FRAME_SIZE * 6, FRAME_SIZE * 4);
129 | SuperImpose(result, chestClimb, FRAME_SIZE * 7, FRAME_SIZE * 4);
130 | SuperImpose(result, chestClimb, FRAME_SIZE * 8, FRAME_SIZE * 4);
131 |
132 | // Swimming
133 | SuperImpose(result, chestSwim, FRAME_SIZE, FRAME_SIZE * 5);
134 | SuperImpose(result, chestSwim, FRAME_SIZE * 4, FRAME_SIZE * 5);
135 | SuperImpose(result, chestSwim, FRAME_SIZE * 5, FRAME_SIZE * 5 + 1);
136 | SuperImpose(result, chestSwim, FRAME_SIZE * 6, FRAME_SIZE * 5 + 2);
137 | SuperImpose(result, chestSwim, FRAME_SIZE * 7, FRAME_SIZE * 5 + 1);
138 |
139 | return result;
140 | }
141 |
142 | private static void SuperImpose( Bitmap largeBmp, Bitmap smallBmp, int x, int y)
143 | {
144 | Graphics g = Graphics.FromImage(largeBmp);
145 | g.DrawImage(smallBmp, x, y, smallBmp.Width, smallBmp.Height);
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/OutfitGenerator/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\Resources\animatedBackTemplate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
123 |
124 |
125 | ..\Resources\animatedPantsTemplate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
126 |
127 |
128 | ..\Resources\animatedSleevesTemplate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
129 |
130 |
131 | ..\Resources\BackConfig.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
132 |
133 |
134 | ..\Resources\HatConfig.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
135 |
136 |
137 | ..\Resources\invisibleAnimatedPantsTemplate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
138 |
139 |
140 | ..\Resources\PantsConfig.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
141 |
142 |
143 | ..\Resources\SleevesConfig.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
144 |
145 |
146 | ..\Resources\HidingPantsConfig.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
147 |
148 |
149 | ..\Resources\HidingHatConfig.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
150 |
151 |
152 | ..\Resources\MaskedHatConfig.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
153 |
154 |
--------------------------------------------------------------------------------