var color = SkinColor.TintedHues(_rgbSkinColorSelector.Color);
+ CMarkings.CurrentSkinColor = color;
+ Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));
+ break;
+ }
+ case HumanoidSkinColor.VoxFeathers:
+ {
+ if (!_rgbSkinColorContainer.Visible)
+ {
+ _skinColor.Visible = false;
+ _rgbSkinColorContainer.Visible = true;
+ }
+
+ var color = SkinColor.ClosestVoxColor(_rgbSkinColorSelector.Color);
+
CMarkings.CurrentSkinColor = color;
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));
break;
_rgbSkinColorSelector.Color = Profile.Appearance.SkinColor;
break;
}
+ case HumanoidSkinColor.VoxFeathers:
+ {
+ if (!_rgbSkinColorContainer.Visible)
+ {
+ _skinColor.Visible = false;
+ _rgbSkinColorContainer.Visible = true;
+ }
+
+ _rgbSkinColorSelector.Color = SkinColor.ClosestVoxColor(Profile.Appearance.SkinColor);
+
+ break;
+ }
}
}
HumanoidSkinColor.HumanToned => Humanoid.SkinColor.HumanSkinTone(speciesPrototype.DefaultHumanSkinTone),
HumanoidSkinColor.Hues => speciesPrototype.DefaultSkinTone,
HumanoidSkinColor.TintedHues => Humanoid.SkinColor.TintedHues(speciesPrototype.DefaultSkinTone),
- _ => Humanoid.SkinColor.ValidHumanSkinTone
+ HumanoidSkinColor.VoxFeathers => Humanoid.SkinColor.ClosestVoxColor(speciesPrototype.DefaultSkinTone),
+ _ => Humanoid.SkinColor.ValidHumanSkinTone,
};
return new(
case HumanoidSkinColor.TintedHues:
newSkinColor = Humanoid.SkinColor.ValidTintedHuesSkinTone(newSkinColor);
break;
+ case HumanoidSkinColor.VoxFeathers:
+ newSkinColor = Humanoid.SkinColor.ProportionalVoxColor(newSkinColor);
+ break;
}
return new HumanoidCharacterAppearance(newHairStyle, newHairColor, newFacialHairStyle, newHairColor, newEyeColor, newSkinColor, new ());
+using System.Security.Cryptography;
+using Microsoft.VisualBasic.CompilerServices;
+
namespace Content.Shared.Humanoid;
public static class SkinColor
public const float MinHuesLightness = 0.175f;
+ public const float MinFeathersHue = 29f / 360;
+ public const float MaxFeathersHue = 174f / 360;
+ public const float MinFeathersSaturation = 20f / 100;
+ public const float MaxFeathersSaturation = 88f / 100;
+ public const float MinFeathersValue = 36f / 100;
+ public const float MaxFeathersValue = 55f / 100;
+
public static Color ValidHumanSkinTone => Color.FromHsv(new Vector4(0.07f, 0.2f, 1f, 1f));
/// <summary>
return Color.ToHsl(color).Y <= MaxTintedHuesSaturation && Color.ToHsl(color).Z >= MinTintedHuesLightness;
}
+ /// <summary>
+ /// Converts a Color proportionally to the allowed vox color range.
+ /// Will NOT preserve the specific input color even if it is within the allowed vox color range.
+ /// </summary>
+ /// <param name="color">Color to convert</param>
+ /// <returns>Vox feather coloration</returns>
+ public static Color ProportionalVoxColor(Color color)
+ {
+ var newColor = Color.ToHsv(color);
+
+ newColor.X = newColor.X * (MaxFeathersHue - MinFeathersHue) + MinFeathersHue;
+ newColor.Y = newColor.Y * (MaxFeathersSaturation - MinFeathersSaturation) + MinFeathersSaturation;
+ newColor.Z = newColor.Z * (MaxFeathersValue - MinFeathersValue) + MinFeathersValue;
+
+ return Color.FromHsv(newColor);
+ }
+
+ // /// <summary>
+ // /// Ensures the input Color is within the allowed vox color range.
+ // /// </summary>
+ // /// <param name="color">Color to convert</param>
+ // /// <returns>The same Color if it was within the allowed range, or the closest matching Color otherwise</returns>
+ public static Color ClosestVoxColor(Color color)
+ {
+ var hsv = Color.ToHsv(color);
+
+ hsv.X = Math.Clamp(hsv.X, MinFeathersHue, MaxFeathersHue);
+ hsv.Y = Math.Clamp(hsv.Y, MinFeathersSaturation, MaxFeathersSaturation);
+ hsv.Z = Math.Clamp(hsv.Z, MinFeathersValue, MaxFeathersValue);
+
+ return Color.FromHsv(hsv);
+ }
+
+ /// <summary>
+ /// Verify if this color is a valid vox feather coloration, or not.
+ /// </summary>
+ /// <param name="color">The color to verify</param>
+ /// <returns>True if valid, false otherwise</returns>
+ public static bool VerifyVoxFeathers(Color color)
+ {
+ var colorHsv = Color.ToHsv(color);
+
+ if (colorHsv.X < MinFeathersHue || colorHsv.X > MaxFeathersHue)
+ return false;
+
+ if (colorHsv.Y < MinFeathersSaturation || colorHsv.Y > MaxFeathersSaturation)
+ return false;
+
+ if (colorHsv.Z < MinFeathersValue || colorHsv.Z > MaxFeathersValue)
+ return false;
+
+ return true;
+ }
+
/// <summary>
/// This takes in a color, and returns a color guaranteed to be above MinHuesLightness
/// </summary>
/// <param name="color"></param>
- /// <returns>Either the color as-is if it's above MinHuesLightness, or the color with luminosity increased above MinHuesLightness</returns>
+ /// <returns>Either the color as-is if it's above MinHuesLightness, or the color with luminosity increased above MinHuesLightness</returns>
public static Color MakeHueValid(Color color)
{
var manipulatedColor = Color.ToHsv(color);
HumanoidSkinColor.HumanToned => VerifyHumanSkinTone(color),
HumanoidSkinColor.TintedHues => VerifyTintedHues(color),
HumanoidSkinColor.Hues => VerifyHues(color),
+ HumanoidSkinColor.VoxFeathers => VerifyVoxFeathers(color),
_ => false,
};
}
HumanoidSkinColor.HumanToned => ValidHumanSkinTone,
HumanoidSkinColor.TintedHues => ValidTintedHuesSkinTone(color),
HumanoidSkinColor.Hues => MakeHueValid(color),
+ HumanoidSkinColor.VoxFeathers => ClosestVoxColor(color),
_ => color
};
}
{
HumanToned,
Hues,
+ VoxFeathers, // Vox feathers are limited to a specific color range
TintedHues, //This gives a color tint to a humanoid's skin (10% saturation with full hue range).
}
components:
- type: Sprite
sprite: Mobs/Species/Vox/parts.rsi
- state: "torso_m"
+ state: "torso"
- type: Icon
sprite: Mobs/Species/Vox/parts.rsi
- state: "torso_m"
+ state: "torso"
- type: BodyPart
partType: Torso
- type: Extractable
components:
- type: Sprite
sprite: Mobs/Species/Vox/parts.rsi
- state: "head_m"
+ state: "head"
- type: Icon
sprite: Mobs/Species/Vox/parts.rsi
- state: "head_m"
+ state: "head"
- type: BodyPart
partType: Head
vital: true
--- /dev/null
+- type: marking
+ id: VoxBeak
+ bodyPart: Snout
+ markingCategory: Snout
+ forcedColoring: true
+ speciesRestriction: [Vox]
+ sprites:
+ - sprite: Mobs/Customization/vox_parts.rsi
+ state: beak
+ coloring:
+ default:
+ type:
+ !type:SimpleColoring
+ color: "#937e3d"
+
+- type: marking
+ id: VoxLArmScales
+ bodyPart: LArm
+ markingCategory: Arms
+ forcedColoring: true
+ speciesRestriction: [Vox]
+ sprites:
+ - sprite: Mobs/Customization/vox_parts.rsi
+ state: l_arm
+ coloring:
+ default:
+ type:
+ !type:SimpleColoring
+ color: "#937e3d"
+
+- type: marking
+ id: VoxLLegScales
+ bodyPart: LLeg
+ markingCategory: Legs
+ forcedColoring: true
+ speciesRestriction: [Vox]
+ sprites:
+ - sprite: Mobs/Customization/vox_parts.rsi
+ state: l_leg
+ coloring:
+ default:
+ type:
+ !type:SimpleColoring
+ color: "#937e3d"
+
+- type: marking
+ id: VoxRArmScales
+ bodyPart: RArm
+ markingCategory: Arms
+ forcedColoring: true
+ speciesRestriction: [Vox]
+ sprites:
+ - sprite: Mobs/Customization/vox_parts.rsi
+ state: r_arm
+ coloring:
+ default:
+ type:
+ !type:SimpleColoring
+ color: "#937e3d"
+
+- type: marking
+ id: VoxRLegScales
+ bodyPart: RLeg
+ markingCategory: Legs
+ forcedColoring: true
+ speciesRestriction: [Vox]
+ sprites:
+ - sprite: Mobs/Customization/vox_parts.rsi
+ state: r_leg
+ coloring:
+ default:
+ type:
+ !type:SimpleColoring
+ color: "#937e3d"
+
+- type: marking
+ id: VoxRHandScales
+ bodyPart: RHand
+ markingCategory: Arms
+ forcedColoring: true
+ speciesRestriction: [Vox]
+ sprites:
+ - sprite: Mobs/Customization/vox_parts.rsi
+ state: r_hand
+ coloring:
+ default:
+ type:
+ !type:SimpleColoring
+ color: "#937e3d"
+
+- type: marking
+ id: VoxLHandScales
+ bodyPart: LHand
+ markingCategory: Arms
+ forcedColoring: true
+ speciesRestriction: [Vox]
+ sprites:
+ - sprite: Mobs/Customization/vox_parts.rsi
+ state: l_hand
+ coloring:
+ default:
+ type:
+ !type:SimpleColoring
+ color: "#937e3d"
+
+- type: marking
+ id: VoxLFootScales
+ bodyPart: LFoot
+ markingCategory: Legs
+ forcedColoring: true
+ speciesRestriction: [Vox]
+ sprites:
+ - sprite: Mobs/Customization/vox_parts.rsi
+ state: l_foot
+ coloring:
+ default:
+ type:
+ !type:SimpleColoring
+ color: "#937e3d"
+
+- type: marking
+ id: VoxRFootScales
+ bodyPart: RFoot
+ markingCategory: Legs
+ forcedColoring: true
+ speciesRestriction: [Vox]
+ sprites:
+ - sprite: Mobs/Customization/vox_parts.rsi
+ state: r_foot
+ coloring:
+ default:
+ type:
+ !type:SimpleColoring
+ color: "#937e3d"
+
+- type: marking
+ id: VoxTail
+ bodyPart: Tail
+ markingCategory: Tail
+ speciesRestriction: [Vox]
+ forcedColoring: true
+ sprites:
+ - sprite: Mobs/Customization/vox_parts.rsi
+ # Ideally this should use the normal tail sprite and apply an actual mask over it, not just use a butchered sprite
+ state: tail_stenciled
damage:
types:
Slash: 5 # Reduce?
+ - type: Sprite # Need to redefine the whole order to draw the tail over their gas tank
+ layers:
+ - map: [ "enum.HumanoidVisualLayers.Chest" ]
+ - map: [ "enum.HumanoidVisualLayers.Head" ]
+ - map: [ "enum.HumanoidVisualLayers.Snout" ]
+ - map: [ "enum.HumanoidVisualLayers.Eyes" ]
+ - map: [ "enum.HumanoidVisualLayers.RArm" ]
+ - map: [ "enum.HumanoidVisualLayers.LArm" ]
+ - map: [ "enum.HumanoidVisualLayers.RLeg" ]
+ - map: [ "enum.HumanoidVisualLayers.LLeg" ]
+ - map: [ "jumpsuit" ]
+ - map: [ "enum.HumanoidVisualLayers.LFoot" ]
+ - map: [ "enum.HumanoidVisualLayers.RFoot" ]
+ - map: [ "enum.HumanoidVisualLayers.LHand" ]
+ - map: [ "enum.HumanoidVisualLayers.RHand" ]
+ - map: [ "gloves" ]
+ - map: [ "shoes" ]
+ - map: [ "ears" ]
+ - map: [ "outerClothing" ]
+ - map: [ "eyes" ]
+ - map: [ "belt" ]
+ - map: [ "id" ]
+ - map: [ "neck" ]
+ - map: [ "back" ]
+ - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
+ - map: [ "enum.HumanoidVisualLayers.Hair" ]
+ - map: [ "enum.HumanoidVisualLayers.HeadSide" ]
+ - map: [ "enum.HumanoidVisualLayers.HeadTop" ]
+ - map: [ "suitstorage" ] # This is not in the default order
+ - map: [ "enum.HumanoidVisualLayers.Tail" ]
+ - map: [ "mask" ]
+ - map: [ "head" ]
+ - map: [ "pocket1" ]
+ - map: [ "pocket2" ]
+ - map: [ "enum.HumanoidVisualLayers.Handcuffs" ]
+ color: "#ffffff"
+ sprite: Objects/Misc/handcuffs.rsi
+ state: body-overlay-2
+ visible: false
+ - map: [ "clownedon" ]
+ sprite: "Effects/creampie.rsi"
+ state: "creampie_vox" # Not default
+ visible: false
- type: entity
parent: BaseSpeciesDummy
sprites: MobVoxSprites
markingLimits: MobVoxMarkingLimits
dollPrototype: MobVoxDummy
- skinColoration: Hues
+ skinColoration: VoxFeathers
+ defaultSkinTone: "#6c741d"
maleFirstNames: names_vox
femaleFirstNames: names_vox
naming: First
sexes:
- - Unsexed
-
+ - Unsexed
- type: speciesBaseSprites
id: MobVoxSprites
sprites:
Head: MobVoxHead
+ Snout: MobHumanoidAnyMarking
Hair: MobHumanoidAnyMarking
FacialHair: MobHumanoidAnyMarking
Chest: MobVoxTorso
RLeg: MobVoxRLeg
LFoot: MobVoxLFoot
RFoot: MobVoxRFoot
+ Tail: MobHumanoidAnyMarking
- type: markingPoints
id: MobVoxMarkingLimits
FacialHair:
points: 1
required: false
- Chest:
+ Head:
points: 1
- required: false
- Legs:
- points: 2
- required: false
+ required: true
+ Snout:
+ points: 1
+ required: true
+ defaultMarkings: [ VoxBeak ]
Arms:
- points: 2
+ points: 4
+ required: true
+ defaultMarkings: [ VoxLArmScales, VoxRArmScales, VoxRHandScales, VoxLHandScales ]
+ Legs:
+ points: 4
+ required: true
+ defaultMarkings: [ VoxLLegScales, VoxRLegScales, VoxRFootScales, VoxLFootScales ]
+ Chest:
+ points: 1
required: false
+ Tail:
+ points: 1
+ required: true
+ defaultMarkings: [ VoxTail ]
- type: humanoidBaseSprite
id: MobVoxEyes
baseSprite:
- sprite: Mobs/Customization/eyes.rsi
- state: vox_eyes_s
+ sprite: Mobs/Species/Vox/parts.rsi
+ state: eyes
- type: humanoidBaseSprite
id: MobVoxHead
baseSprite:
sprite: Mobs/Species/Vox/parts.rsi
- state: head_m
+ state: head
- type: humanoidBaseSprite
id: MobVoxHeadMale
baseSprite:
sprite: Mobs/Species/Vox/parts.rsi
- state: head_m
+ state: head
- type: humanoidBaseSprite
id: MobVoxHeadFemale
baseSprite:
sprite: Mobs/Species/Vox/parts.rsi
- state: head_f
+ state: head
- type: humanoidBaseSprite
id: MobVoxTorso
baseSprite:
sprite: Mobs/Species/Vox/parts.rsi
- state: torso_m
+ state: torso
- type: humanoidBaseSprite
id: MobVoxTorsoMale
baseSprite:
sprite: Mobs/Species/Vox/parts.rsi
- state: torso_m
+ state: torso
- type: humanoidBaseSprite
id: MobVoxTorsoFemale
baseSprite:
sprite: Mobs/Species/Vox/parts.rsi
- state: torso_f
+ state: torso
- type: humanoidBaseSprite
id: MobVoxLLeg
baseSprite:
sprite: Mobs/Species/Vox/parts.rsi
state: r_foot
-
-#
{
"version": 1,
"license": "CC-BY-SA-3.0",
- "copyright": "Taken from https://github.com/tgstation/tgstation at 0d9c9a8233dfc3fc55edc538955a761a6328bee0. creampie_moth by MilenVolf, creampie_arachnid by PixelTheKermit (Github)",
+ "copyright": "Taken from https://github.com/tgstation/tgstation at 0d9c9a8233dfc3fc55edc538955a761a6328bee0. creampie_moth by MilenVolf, creampie_arachnid by PixelTheKermit (Github), creampie_vox by Errant",
"size": {
"x": 32,
"y": 32
"name": "creampie_standborg",
"directions": 4
},
+ {
+ "name": "creampie_vox",
+ "directions": 4
+ },
{
"name": "creampie_xeno_crit"
},
-{"version": 1, "license": "CC-BY-SA-3.0","copyright": "Vox_eyes Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb and human_eyes taken from https://github.com/tgstation/tgstation/blob/8024397cc81c5f47f74cf4279e35728487d0a1a7/icons/mob/human_parts_greyscale.dmi and modified by DrSmugleaf", "size": {"x": 32, "y": 32}, "states": [{"name": "diona", "directions": 4}, {"name": "eyes", "directions": 4}, {"name":"no_eyes"},{"name": "vox_eyes_s", "directions": 4}]}
+{"version": 1, "license": "CC-BY-SA-3.0","copyright": "human_eyes taken from https://github.com/tgstation/tgstation/blob/8024397cc81c5f47f74cf4279e35728487d0a1a7/icons/mob/human_parts_greyscale.dmi and modified by DrSmugleaf", "size": {"x": 32, "y": 32}, "states": [{"name": "diona", "directions": 4}, {"name": "eyes", "directions": 4}, {"name":"no_eyes"}]}
--- /dev/null
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb, modified by Bhijn, Errant and Flareguy",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "beak",
+ "directions": 4
+ },
+ {
+ "name": "l_arm",
+ "directions": 4
+ },
+ {
+ "name": "l_foot",
+ "directions": 4
+ },
+ {
+ "name": "l_hand",
+ "directions": 4
+ },
+ {
+ "name": "l_leg",
+ "directions": 4
+ },
+ {
+ "name": "r_arm",
+ "directions": 4
+ },
+ {
+ "name": "r_foot",
+ "directions": 4
+ },
+ {
+ "name": "r_hand",
+ "directions": 4
+ },
+ {
+ "name": "r_leg",
+ "directions": 4
+ },
+ {
+ "name": "tail",
+ "directions": 4
+ },
+ {
+ "name": "tail_stenciled",
+ "directions": 4
+ }
+ ]
+}
{
"version": 1,
"license": "CC-BY-SA-3.0",
- "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb",
+ "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb, by Bhijn, Errant and Flareguy",
"size": {
"x": 32,
"y": 32
},
"states": [
{
- "name": "groin_f",
+ "name": "eyes",
"directions": 4
},
{
- "name": "groin_m",
- "directions": 4
+ "name": "full"
},
{
- "name": "head_f",
+ "name": "groin",
"directions": 4
},
{
- "name": "head_m",
+ "name": "head",
"directions": 4
},
{
"directions": 4
},
{
- "name": "torso_f",
- "directions": 4
- },
- {
- "name": "torso_m",
+ "name": "torso",
"directions": 4
},
{