mirror of
https://github.com/Terncode/pixel.horse.git
synced 2026-09-25 22:25:53 +02:00
588 lines
20 KiB
TypeScript
588 lines
20 KiB
TypeScript
import * as sprites from '../generated/sprites';
|
|
import { releasePalette, createPalette } from '../graphics/paletteManager';
|
|
import {
|
|
PonyInfo, SpriteSet, PalettePonyInfo, PaletteSpriteSet, PaletteManager, Palette, ColorExtraSets, PonyInfoBase,
|
|
PonyInfoNumber, ColorExtra
|
|
} from './interfaces';
|
|
import { toInt, array, includes, att } from './utils';
|
|
import { CM_SIZE } from './constants';
|
|
import { parseColorFast, getR, getAlpha, colorFromRGBA, getG, getB, colorToHexRGB } from './color';
|
|
import { BLACK, fillToOutline, fillToOutlineColor, WHITE, TRANSPARENT, fillToOutlineWithDarken } from './colors';
|
|
import {
|
|
mergedManes, mergedBackManes, mergedFacialHair, mergedEarAccessories, mergedChestAccessories,
|
|
SLEEVED_ACCESSORIES, mergedBackAccessories, mergedExtraAccessories, mergedHeadAccessories
|
|
} from '../client/ponyUtils';
|
|
|
|
const MAX_COLORS = 6;
|
|
const FILLS = ['1e90ff', '32cd32', 'da70d6', 'dc143c', '7fffd4'];
|
|
|
|
const frontHooves = sprites.frontLegHooves[1] as ColorExtraSets;
|
|
const backHooves = sprites.backLegHooves[1] as ColorExtraSets;
|
|
const frontLegAccessories = sprites.frontLegAccessories[1] as ColorExtraSets;
|
|
const backLegAccessories = sprites.backLegAccessories[1] as ColorExtraSets;
|
|
const frontLegSleeves = sprites.frontLegSleeves[1] as ColorExtraSets;
|
|
|
|
type Arr<T> = (T | undefined)[] | undefined;
|
|
type PonyInfoGeneric<T> = PonyInfoBase<T, SpriteSet<T>>;
|
|
|
|
export const mockPaletteManager: PaletteManager = {
|
|
add(colors: number[]): Palette {
|
|
return this.addArray(new Uint32Array(colors));
|
|
},
|
|
addArray(colors: Uint32Array): Palette {
|
|
return createPalette(colors);
|
|
},
|
|
init() {
|
|
}
|
|
};
|
|
|
|
export function spriteSet(type: number, lockFirstFill = true, fill = 'ffd700', otherFills = FILLS): SpriteSet<string> {
|
|
if (otherFills.length !== (MAX_COLORS - 1))
|
|
throw new Error('Invalid fills count');
|
|
|
|
const fills = [fill, ...otherFills];
|
|
const outlines = fills.map(fillToOutline);
|
|
|
|
return {
|
|
type,
|
|
pattern: 0,
|
|
fills,
|
|
outlines,
|
|
lockFills: [lockFirstFill, ...array(MAX_COLORS - 1, false)],
|
|
lockOutlines: array(MAX_COLORS, true),
|
|
};
|
|
}
|
|
|
|
export function createDefaultPony(): PonyInfo {
|
|
const pony = createBasePony();
|
|
pony.mane!.type = 2;
|
|
pony.backMane!.type = 1;
|
|
pony.tail!.type = 1;
|
|
return pony;
|
|
}
|
|
|
|
export function createBasePony(): PonyInfo {
|
|
return syncLockedPonyInfo({
|
|
head: spriteSet(0, true, 'ff0000', ['800000', '32cd32', 'da70d6', 'dc143c', '7fffd4']),
|
|
nose: spriteSet(0, true, 'ff0000', ['800000', '32cd32', 'da70d6', 'dc143c', '7fffd4']),
|
|
ears: spriteSet(0, true, 'ff0000'),
|
|
horn: spriteSet(0, true, 'ff0000'),
|
|
wings: spriteSet(0, true, 'ff0000'),
|
|
frontHooves: spriteSet(0, false, 'ffa500', ['ffff00', '32cd32', 'da70d6', 'dc143c', '7fffd4']),
|
|
backHooves: spriteSet(0, true, 'ffa500'),
|
|
|
|
mane: spriteSet(0, false),
|
|
backMane: spriteSet(0),
|
|
tail: spriteSet(0),
|
|
facialHair: spriteSet(0),
|
|
|
|
headAccessory: spriteSet(0, false, 'ee82ee'),
|
|
earAccessory: spriteSet(0, false, '808080'),
|
|
faceAccessory: spriteSet(0, false, '000000'),
|
|
neckAccessory: spriteSet(0, false, 'ee82ee'),
|
|
frontLegAccessory: spriteSet(0, false, 'ee82ee'),
|
|
backLegAccessory: spriteSet(0, false, 'ee82ee'),
|
|
frontLegAccessoryRight: spriteSet(0, false, 'ee82ee'),
|
|
backLegAccessoryRight: spriteSet(0, false, 'ee82ee'),
|
|
lockBackLegAccessory: true,
|
|
unlockFrontLegAccessory: false,
|
|
unlockBackLegAccessory: false,
|
|
backAccessory: spriteSet(0, false, 'ee82ee'),
|
|
waistAccessory: spriteSet(0, false, '95856f', ['674b43', '4f4f4f', '525252', 'c37850', '8a3d34']),
|
|
chestAccessory: spriteSet(0, false, 'ee82ee'),
|
|
sleeveAccessory: spriteSet(0, true, 'ee82ee'),
|
|
extraAccessory: {
|
|
...spriteSet(0, true, 'ff0000', ['daa520', 'ffd700', 'ffd700', 'ffd700', 'ffd700']),
|
|
lockFills: array(5, true),
|
|
},
|
|
|
|
coatFill: 'ff0000',
|
|
coatOutline: '8b0000',
|
|
lockCoatOutline: true,
|
|
|
|
eyelashes: 0,
|
|
eyeColorLeft: 'daa520',
|
|
eyeColorRight: 'daa520',
|
|
eyeWhitesLeft: 'ffffff',
|
|
eyeWhites: 'ffffff',
|
|
eyeOpennessLeft: 1,
|
|
eyeOpennessRight: 1,
|
|
eyeshadow: false,
|
|
eyeshadowColor: '000000',
|
|
lockEyes: true,
|
|
lockEyeColor: true,
|
|
unlockEyeWhites: false,
|
|
unlockEyelashColor: false,
|
|
eyelashColor: '000000',
|
|
eyelashColorLeft: '000000',
|
|
|
|
fangs: 0,
|
|
muzzle: 0,
|
|
freckles: 0,
|
|
frecklesColor: '8b0000',
|
|
magicColor: 'ffffff',
|
|
|
|
cm: [],
|
|
cmFlip: false,
|
|
|
|
customOutlines: false,
|
|
freeOutlines: false,
|
|
darkenLockedOutlines: false,
|
|
});
|
|
}
|
|
|
|
// sync
|
|
|
|
type FillToOutline<T> = (fill: T | undefined) => T | undefined;
|
|
|
|
export function getBaseFill<T>(set?: SpriteSet<T>): T | undefined {
|
|
return set && set.fills && set.fills[0];
|
|
}
|
|
|
|
export function getBaseOutline<T>(set?: SpriteSet<T>): T | undefined {
|
|
return set && set.outlines && set.outlines[0];
|
|
}
|
|
|
|
export function syncLockedSpriteSet<T>(
|
|
set: SpriteSet<T> | undefined, customOutlines: boolean, fillToOutline: FillToOutline<T>, baseFill?: T,
|
|
baseOutline?: T
|
|
) {
|
|
if (set === undefined)
|
|
return;
|
|
|
|
const fills = set.fills;
|
|
|
|
if (!fills)
|
|
return;
|
|
|
|
const lockFills = set.lockFills;
|
|
|
|
if (lockFills) {
|
|
for (let i = 0; i < lockFills.length; i++) {
|
|
if (lockFills[i]) {
|
|
fills[i] = i === 0 ? baseFill : fills[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
const outlines = set.outlines;
|
|
const lockOutlines = set.lockOutlines;
|
|
|
|
if (outlines && lockOutlines) {
|
|
for (let i = 0; i < lockOutlines.length; i++) {
|
|
if (!customOutlines) {
|
|
lockOutlines[i] = true;
|
|
}
|
|
|
|
if (lockOutlines[i]) {
|
|
if (i === 0 && baseOutline && lockFills && lockFills[i]) {
|
|
outlines[i] = baseOutline;
|
|
} else {
|
|
outlines[i] = fillToOutline(fills[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function syncLockedSpritesSet2<T>(
|
|
set: SpriteSet<T> | undefined, fillToOutline: FillToOutline<T>, baseFills: (T | undefined)[],
|
|
baseOutlines: (T | undefined)[]
|
|
) {
|
|
if (set && set.fills && set.lockFills) {
|
|
set.lockFills.forEach((locked, i) => {
|
|
if (locked) {
|
|
set.fills![i] = baseFills[i];
|
|
}
|
|
});
|
|
}
|
|
|
|
if (set && set.fills && set.outlines && set.lockOutlines) {
|
|
set.lockOutlines.forEach((locked, i) => {
|
|
if (locked) {
|
|
if (baseOutlines[i] && set.lockFills && set.lockFills[i]) {
|
|
set.outlines![i] = baseOutlines[i];
|
|
} else {
|
|
set.outlines![i] = fillToOutline(set.fills![i]);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function getFillOf2<T>(set: SpriteSet<T> | undefined, defaultColor: T): T | undefined {
|
|
return set && set.type && set.fills && set.fills[0] || defaultColor;
|
|
}
|
|
|
|
function getOutlineOf2<T>(set: SpriteSet<T> | undefined, defaultColor: T): T | undefined {
|
|
return set && set.type && set.outlines && set.outlines[0] || defaultColor;
|
|
}
|
|
|
|
function syncLockedBasePonyInfo<T>(
|
|
info: PonyInfoGeneric<T>, fillToOutline: FillToOutline<T>, defaultColor: T
|
|
): PonyInfoGeneric<T> {
|
|
const customOutlines = !!info.customOutlines;
|
|
|
|
if (!customOutlines || info.lockCoatOutline) {
|
|
info.coatOutline = fillToOutline(info.coatFill);
|
|
}
|
|
|
|
if (info.lockEyes) {
|
|
info.eyeOpennessLeft = info.eyeOpennessRight;
|
|
}
|
|
|
|
if (info.lockEyeColor) {
|
|
info.eyeColorLeft = info.eyeColorRight;
|
|
}
|
|
|
|
if (!info.unlockEyeWhites) {
|
|
info.eyeWhitesLeft = info.eyeWhites;
|
|
}
|
|
|
|
if (!info.unlockEyelashColor) {
|
|
info.eyelashColorLeft = info.eyelashColor;
|
|
}
|
|
|
|
syncLockedSpriteSet<T>(info.head, customOutlines, fillToOutline, info.coatFill, info.coatOutline);
|
|
syncLockedSpriteSet<T>(info.nose, customOutlines, fillToOutline, info.coatFill, info.coatOutline);
|
|
syncLockedSpriteSet<T>(info.ears, customOutlines, fillToOutline, info.coatFill, info.coatOutline);
|
|
syncLockedSpriteSet<T>(info.horn, customOutlines, fillToOutline, info.coatFill, info.coatOutline);
|
|
syncLockedSpriteSet<T>(info.wings, customOutlines, fillToOutline, info.coatFill, info.coatOutline);
|
|
syncLockedSpriteSet<T>(info.frontHooves, customOutlines, fillToOutline, info.coatFill, info.coatOutline);
|
|
syncLockedSpriteSet<T>(
|
|
info.backHooves, customOutlines, fillToOutline, getBaseFill(info.frontHooves), getBaseOutline(info.frontHooves));
|
|
|
|
syncLockedSpriteSet<T>(info.mane, customOutlines, fillToOutline);
|
|
|
|
const baseManeFill = getBaseFill(info.mane);
|
|
const baseManeOutline = getBaseOutline(info.mane);
|
|
|
|
syncLockedSpriteSet<T>(info.backMane, customOutlines, fillToOutline, baseManeFill, baseManeOutline);
|
|
syncLockedSpriteSet<T>(info.tail, customOutlines, fillToOutline, baseManeFill, baseManeOutline);
|
|
syncLockedSpriteSet<T>(info.facialHair, customOutlines, fillToOutline, baseManeFill, baseManeOutline);
|
|
|
|
syncLockedSpriteSet<T>(info.headAccessory, customOutlines, fillToOutline);
|
|
syncLockedSpriteSet<T>(info.earAccessory, customOutlines, fillToOutline);
|
|
syncLockedSpriteSet<T>(info.faceAccessory, customOutlines, fillToOutline);
|
|
syncLockedSpriteSet<T>(info.neckAccessory, customOutlines, fillToOutline);
|
|
syncLockedSpriteSet<T>(info.frontLegAccessory, customOutlines, fillToOutline);
|
|
syncLockedSpriteSet<T>(info.backLegAccessory, customOutlines, fillToOutline);
|
|
syncLockedSpriteSet<T>(info.frontLegAccessoryRight, customOutlines, fillToOutline);
|
|
syncLockedSpriteSet<T>(info.backLegAccessoryRight, customOutlines, fillToOutline);
|
|
syncLockedSpriteSet<T>(info.backAccessory, customOutlines, fillToOutline);
|
|
syncLockedSpriteSet<T>(info.waistAccessory, customOutlines, fillToOutline);
|
|
syncLockedSpriteSet<T>(info.chestAccessory, customOutlines, fillToOutline);
|
|
|
|
if (info.chestAccessory && !info.sleeveAccessory && includes(SLEEVED_ACCESSORIES, info.chestAccessory.type)) {
|
|
info.sleeveAccessory = {
|
|
type: 0,
|
|
pattern: 0,
|
|
fills: [],
|
|
outlines: [],
|
|
lockFills: array(MAX_COLORS, true),
|
|
lockOutlines: array(MAX_COLORS, true),
|
|
};
|
|
}
|
|
|
|
syncLockedSpriteSet<T>(
|
|
info.sleeveAccessory, customOutlines, fillToOutline, getBaseFill(info.chestAccessory), getBaseOutline(info.chestAccessory));
|
|
|
|
syncLockedSpritesSet2<T>(info.extraAccessory, fillToOutline, [
|
|
info.coatFill,
|
|
info.eyeColorRight,
|
|
getFillOf2(info.mane, defaultColor),
|
|
getFillOf2(info.backMane, defaultColor),
|
|
getFillOf2(info.tail, defaultColor),
|
|
], [
|
|
info.coatOutline,
|
|
info.eyeColorRight,
|
|
getOutlineOf2(info.mane, defaultColor),
|
|
getOutlineOf2(info.backMane, defaultColor),
|
|
getOutlineOf2(info.tail, defaultColor),
|
|
]);
|
|
|
|
return info;
|
|
}
|
|
|
|
export function syncLockedPonyInfo(info: PonyInfo): PonyInfo {
|
|
const darkenLocked = !!info.freeOutlines && !!info.darkenLockedOutlines;
|
|
const fillToOutlineFunc = darkenLocked ? fillToOutlineWithDarken : fillToOutline;
|
|
return syncLockedBasePonyInfo<string>(info, fillToOutlineFunc, '000000');
|
|
}
|
|
|
|
function fillToOutlineSafe(color: number | undefined) {
|
|
return fillToOutlineColor((color === undefined || color === 0) ? BLACK : color);
|
|
}
|
|
|
|
function fillToOutlineSafeWithDarken(color: number | undefined) {
|
|
return darkenForOutline(fillToOutlineColor((color === undefined || color === 0) ? BLACK : color));
|
|
}
|
|
|
|
export function syncLockedPonyInfoNumber(info: PonyInfoNumber): PonyInfoNumber {
|
|
const darkenLocked = !!info.freeOutlines && !!info.darkenLockedOutlines;
|
|
const fillToOutlineFunc = darkenLocked ? fillToOutlineSafeWithDarken : fillToOutlineSafe;
|
|
return syncLockedBasePonyInfo<number>(info, fillToOutlineFunc, BLACK);
|
|
}
|
|
|
|
// PalettePonyInfo
|
|
|
|
function parseFast(color: string | undefined): number {
|
|
return color ? parseColorFast(color) : BLACK;
|
|
}
|
|
|
|
function parseCMColor(color: string): number {
|
|
return color ? parseColorFast(color) : TRANSPARENT;
|
|
}
|
|
|
|
export function toColorList(colors: (string | undefined)[]): Uint32Array {
|
|
const result = new Uint32Array(colors.length + 1);
|
|
|
|
for (let i = 0; i < colors.length; i++) {
|
|
result[i + 1] = parseFast(colors[i]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
export function darkenForOutline(color: number) {
|
|
const mult = (159 / 255);
|
|
const r = (mult * getR(color)) | 0;
|
|
const g = (mult * getG(color)) | 0;
|
|
const b = (mult * getB(color)) | 0;
|
|
const a = getAlpha(color);
|
|
return colorFromRGBA(r, g, b, a);
|
|
}
|
|
|
|
function getColorsGeneric(
|
|
fillColors: Arr<string>, outlineColors: Arr<string>, defaultColor: string, length: number, darken: boolean
|
|
): string[] {
|
|
const fills = fillColors || [];
|
|
const outlines = outlineColors || [];
|
|
const colors = array(length * 2, defaultColor);
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
colors[i * 2] = fills[i] || defaultColor;
|
|
|
|
if (darken) {
|
|
colors[i * 2 + 1] = outlines[i] ? colorToHexRGB(darkenForOutline(parseColorFast(outlines[i]!))) : defaultColor;
|
|
} else {
|
|
colors[i * 2 + 1] = outlines[i] || defaultColor;
|
|
}
|
|
}
|
|
|
|
return colors;
|
|
}
|
|
|
|
export function getColorsFromSet({ fills, outlines }: SpriteSet<string>, defaultColor: string, darken: boolean): string[] {
|
|
const length = Math.max(fills ? fills.length : 0, outlines ? outlines.length : 0);
|
|
return getColorsGeneric(fills, outlines, defaultColor, length, darken);
|
|
}
|
|
|
|
export function toColorListNumber(colors: (number | undefined)[]): Uint32Array {
|
|
const result = new Uint32Array(colors.length + 1);
|
|
|
|
for (let i = 0; i < colors.length; i++) {
|
|
result[i + 1] = colors[i] || BLACK;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
export type GetColorsForSet<T> = (set: SpriteSet<T>, count: number, darken: boolean) => Uint32Array;
|
|
|
|
export const getColorsForSet: GetColorsForSet<string> = (set, count, darken) => {
|
|
const t = getColorsGeneric(set.fills, set.outlines, '000000', count, darken);
|
|
return toColorList(t);
|
|
};
|
|
|
|
const emptyArray: number[] = [];
|
|
|
|
export const getColorsForSetNumber: GetColorsForSet<number> = (set, length, darken) => {
|
|
const fills = set.fills || emptyArray;
|
|
const outlines = set.outlines || emptyArray;
|
|
const result = new Uint32Array(length * 2 + 1);
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
result[((i << 1) + 1) | 0] = i < fills.length ? (fills[i] || BLACK) : BLACK;
|
|
|
|
if (darken) {
|
|
result[((i << 1) + 2) | 0] = i < outlines.length ? darkenForOutline(outlines[i] || BLACK) : BLACK;
|
|
} else {
|
|
result[((i << 1) + 2) | 0] = i < outlines.length ? (outlines[i] || BLACK) : BLACK;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
function getExtraPalette(pattern: ColorExtra | undefined, manager: PaletteManager): Palette | undefined {
|
|
const extraPalette = pattern && pattern.palettes && pattern.palettes[0];
|
|
return extraPalette && manager.addArray(new Uint32Array(extraPalette));
|
|
}
|
|
|
|
export function toPaletteSet<T>(
|
|
set: SpriteSet<T>, sets: ColorExtraSets, manager: PaletteManager, getColorsForSet: GetColorsForSet<T>,
|
|
hasExtra: boolean, darken: boolean
|
|
): PaletteSpriteSet | undefined {
|
|
const pattern = att(att(sets, set.type), set.pattern);
|
|
const colorCount = pattern !== undefined && pattern.colors !== undefined ? ((pattern.colors - 1) >> 1) : 0;
|
|
const colors = getColorsForSet(set, colorCount, darken);
|
|
|
|
return {
|
|
type: toInt(set.type),
|
|
pattern: toInt(set.pattern),
|
|
palette: manager.addArray(colors),
|
|
extraPalette: hasExtra ? getExtraPalette(pattern, manager) : undefined,
|
|
};
|
|
}
|
|
|
|
function createCMPalette<T>(
|
|
cm: T[] | undefined, manager: PaletteManager, parseColor: (color: T) => number
|
|
): Palette | undefined {
|
|
const size = CM_SIZE * CM_SIZE;
|
|
|
|
if (cm === undefined || cm.length === 0 || cm.length > size)
|
|
return undefined;
|
|
|
|
const result = new Uint32Array(size);
|
|
|
|
for (let i = 0; i < cm.length; i++) {
|
|
result[i] = parseColor(cm[i]);
|
|
}
|
|
|
|
return manager.addArray(result);
|
|
}
|
|
|
|
export type ToSet<T> = (set: SpriteSet<T> | undefined, sets: ColorExtraSets, extra?: boolean) => PaletteSpriteSet | undefined;
|
|
|
|
const defaultPalette = new Uint32Array(sprites.defaultPalette);
|
|
|
|
export const createToPaletteSet =
|
|
<T>(manager: PaletteManager, getColorsForSet: GetColorsForSet<T>, extra: boolean, darken: boolean): ToSet<T> =>
|
|
(set, sets) => set === undefined ? undefined : toPaletteSet(set, sets, manager, getColorsForSet, extra, darken);
|
|
|
|
export function toPaletteGeneric<T>(
|
|
info: PonyInfoGeneric<T>, manager: PaletteManager, toColorList: (color: (T | undefined)[]) => Uint32Array,
|
|
getColorsForSet: GetColorsForSet<T>, blackColor: T, whiteColor: T, parseCMColor: (color: T) => number
|
|
): PalettePonyInfo {
|
|
const darken = !info.freeOutlines;
|
|
const toSet = createToPaletteSet(manager, getColorsForSet, false, darken);
|
|
const toSetExtra = createToPaletteSet(manager, getColorsForSet, true, darken);
|
|
|
|
const defaultSet = { type: 0, pattern: 0, fills: [info.coatFill], outlines: [info.coatOutline] };
|
|
// const defaultSet = { type: 0, pattern: 1, fills: [info.coatFill, whiteColor], outlines: [info.coatOutline, blackColor] };
|
|
|
|
return {
|
|
body: toSet(defaultSet, sprites.body[1]),
|
|
head: toSet(info.head || defaultSet, sprites.head0[1]),
|
|
nose: toSet(info.nose, sprites.noses[0]),
|
|
ears: toSet(info.ears || defaultSet, sprites.ears),
|
|
horn: toSet(info.horn, sprites.horns),
|
|
wings: toSet(info.wings, sprites.wings[0]),
|
|
frontLegs: toSet(defaultSet, sprites.frontLegs[1]),
|
|
backLegs: toSet(defaultSet, sprites.backLegs[1]),
|
|
frontHooves: toSet(info.frontHooves, frontHooves),
|
|
backHooves: toSet(info.backHooves, backHooves),
|
|
|
|
mane: toSet(info.mane, mergedManes),
|
|
backMane: toSet(info.backMane, mergedBackManes),
|
|
tail: toSet(info.tail, sprites.tails[0]),
|
|
facialHair: toSet(info.facialHair, mergedFacialHair),
|
|
|
|
headAccessory: toSet(info.headAccessory, mergedHeadAccessories),
|
|
earAccessory: toSet(info.earAccessory, mergedEarAccessories),
|
|
faceAccessory: toSetExtra(info.faceAccessory, sprites.faceAccessories),
|
|
// faceAccessoryExtraPalette: getExtraPartPalette(info.faceAccessory, sprites.faceAccessoriesExtra, manager),
|
|
neckAccessory: toSet(info.neckAccessory, sprites.neckAccessories[1]),
|
|
frontLegAccessory: toSet(
|
|
info.frontLegAccessory, frontLegAccessories),
|
|
backLegAccessory: toSet(
|
|
info.lockBackLegAccessory ? info.frontLegAccessory : info.backLegAccessory, backLegAccessories),
|
|
frontLegAccessoryRight: toSet(
|
|
info.unlockFrontLegAccessory ? info.frontLegAccessoryRight : info.frontLegAccessory, frontLegAccessories),
|
|
backLegAccessoryRight: toSet(
|
|
info.lockBackLegAccessory ?
|
|
(info.unlockFrontLegAccessory ? info.frontLegAccessoryRight : info.frontLegAccessory) :
|
|
(info.unlockBackLegAccessory ? info.backLegAccessoryRight : info.backLegAccessory), backLegAccessories),
|
|
lockBackLegAccessory: info.lockBackLegAccessory,
|
|
unlockFrontLegAccessory: info.unlockFrontLegAccessory,
|
|
unlockBackLegAccessory: info.unlockBackLegAccessory,
|
|
backAccessory: toSet(info.backAccessory, mergedBackAccessories),
|
|
waistAccessory: toSet(info.waistAccessory, sprites.waistAccessories[1]),
|
|
chestAccessory: toSet(info.chestAccessory, mergedChestAccessories),
|
|
sleeveAccessory: toSet(info.sleeveAccessory, frontLegSleeves),
|
|
extraAccessory: toSet(info.extraAccessory, mergedExtraAccessories),
|
|
|
|
coatPalette: manager.addArray(toColorList([info.coatFill, info.coatOutline])),
|
|
coatFill: undefined,
|
|
coatOutline: undefined,
|
|
lockCoatOutline: !!info.lockCoatOutline,
|
|
|
|
eyelashes: toInt(info.eyelashes),
|
|
eyePaletteLeft: manager.addArray(toColorList([
|
|
info.eyeWhitesLeft || whiteColor,
|
|
info.eyelashColor || blackColor
|
|
])),
|
|
eyePalette: manager.addArray(toColorList([
|
|
info.eyeWhites || whiteColor,
|
|
(info.unlockEyelashColor ? info.eyelashColorLeft : info.eyelashColor) || blackColor
|
|
])),
|
|
eyeColorLeft: manager.addArray(toColorList([info.eyeColorLeft])),
|
|
eyeColorRight: manager.addArray(toColorList([info.eyeColorRight])),
|
|
eyeWhitesLeft: undefined,
|
|
eyeWhites: undefined,
|
|
eyeOpennessLeft: toInt(info.eyeOpennessLeft),
|
|
eyeOpennessRight: toInt(info.eyeOpennessRight),
|
|
eyeshadow: info.eyeshadow,
|
|
eyeshadowColor: manager.addArray(toColorList([info.eyeshadowColor])),
|
|
lockEyes: !!info.lockEyes,
|
|
lockEyeColor: !!info.lockEyeColor,
|
|
unlockEyeWhites: !!info.unlockEyeWhites,
|
|
unlockEyelashColor: !!info.unlockEyelashColor,
|
|
eyelashColor: undefined,
|
|
eyelashColorLeft: undefined,
|
|
|
|
fangs: toInt(info.fangs),
|
|
muzzle: toInt(info.muzzle),
|
|
freckles: 0, // remove
|
|
frecklesColor: undefined, // TODO: remove
|
|
magicColor: undefined,
|
|
magicColorValue: typeof info.magicColor === 'string' ? parseColorFast(info.magicColor) : toInt(info.magicColor),
|
|
|
|
cm: undefined,
|
|
cmFlip: !!info.cmFlip,
|
|
cmPalette: createCMPalette<T>(info.cm, manager, parseCMColor),
|
|
|
|
customOutlines: !!info.customOutlines,
|
|
freeOutlines: !!info.freeOutlines,
|
|
darkenLockedOutlines: !!info.darkenLockedOutlines,
|
|
defaultPalette: manager.addArray(defaultPalette),
|
|
waterPalette: manager.addArray(sprites.pony_wake_1.palette),
|
|
};
|
|
}
|
|
|
|
export function toPalette(info: PonyInfo, manager = mockPaletteManager): PalettePonyInfo {
|
|
return toPaletteGeneric(info, manager, toColorList, getColorsForSet, '000000', 'ffffff', parseCMColor);
|
|
}
|
|
|
|
export function toPaletteNumber(info: PonyInfoNumber, manager = mockPaletteManager): PalettePonyInfo {
|
|
return toPaletteGeneric<number>(info, manager, toColorListNumber, getColorsForSetNumber, BLACK, WHITE, x => x);
|
|
}
|
|
|
|
export function releasePalettes(info: PalettePonyInfo): void {
|
|
for (const key of Object.keys(info)) {
|
|
const value = (info as any)[key]; // undefined | number | string | PaletteSpriteSet | Palette;
|
|
|
|
if (value && typeof value === 'object') {
|
|
if ('refs' in value) {
|
|
const palette = value as Palette;
|
|
releasePalette(palette);
|
|
} else if ('palette' in value) {
|
|
const set = value as PaletteSpriteSet;
|
|
releasePalette(set.palette);
|
|
releasePalette(set.extraPalette);
|
|
}
|
|
}
|
|
}
|
|
}
|