mirror of
https://github.com/Terncode/pixel.horse.git
synced 2026-09-24 21:55:52 +02:00
172 lines
6.3 KiB
TypeScript
172 lines
6.3 KiB
TypeScript
/// <reference path="../../typings/my.d.ts" />
|
|
|
|
import { range, dropRight, compact, max, zip } from 'lodash';
|
|
import {
|
|
Eye, Iris, Muzzle, ExpressionExtra, Sprite, ColorExtraSets, PonyInfoBase, SpriteSetBase, ColorExtra, ColorExtraSet
|
|
} from './interfaces';
|
|
import * as sprites from '../generated/sprites';
|
|
import { HEAD_ACCESSORY_OFFSETS, EXTRA_ACCESSORY_OFFSETS, EAR_ACCESSORY_OFFSETS } from './offsets';
|
|
|
|
export const PONY_WIDTH = 80;
|
|
export const PONY_HEIGHT = 70;
|
|
export const BLINK_FRAMES = [2, 6, 6, 4, 2];
|
|
export const SLEEVED_ACCESSORIES = [2, 3, 4];
|
|
export const SLEEVED_BACK_ACCESSORIES = [5, 6];
|
|
export const CHEST_ACCESSORIES_IN_FRONT = [1];
|
|
export const NO_MANE_HEAD_ACCESSORIES = [0, 16];
|
|
// export const FRONT_NECK_ACCESSORIES = [2, 10];
|
|
|
|
export type Sprites = (Sprite | undefined)[];
|
|
export type Sets = ColorExtraSets[]; // [frame][type][pattern]
|
|
|
|
export const headCenter = [
|
|
undefined,
|
|
[[0].map(i => sprites.head[2]![0]![i])],
|
|
];
|
|
|
|
export const claws: Sets = sprites.frontLegHooves
|
|
.map(f => f && [undefined, undefined, undefined, f[4], undefined, undefined]);
|
|
export const frontHooves: Sets = sprites.frontLegHooves
|
|
.map(f => f && [...f.slice(0, 4), ...f.slice(5)]);
|
|
|
|
export const frontHoovesInFront = [false, false, true, true, false, false];
|
|
export const backHoovesInFront = [false, false, true, false, false];
|
|
|
|
const bodyFrames = sprites.body.length;
|
|
|
|
export const wings = createCompleteSets(sprites.wings, 3 + 10);
|
|
export const tails = createCompleteSets(sprites.tails, 3);
|
|
export const chest = createCompleteSets(sprites.chestAccessories, bodyFrames);
|
|
export const chestBehind = createCompleteSets(sprites.chestAccessoriesBehind, bodyFrames);
|
|
export const backAccessories = createCompleteSets(sprites.backAccessories, bodyFrames);
|
|
export const neckAccessories = createCompleteSets(sprites.neckAccessories, bodyFrames);
|
|
export const waistAccessories = createCompleteSets(sprites.waistAccessories, bodyFrames + 1);
|
|
|
|
function frameType(sets: Sets, frame: number, type: number) {
|
|
const set = sets[frame];
|
|
return set && set[type];
|
|
}
|
|
|
|
function createCompleteSets(sets: Sets, frameCount: number): Sets {
|
|
const typeCount = sets.reduce((max, s) => Math.max(max, s ? s.length : 0), 0);
|
|
const typeRange = range(0, typeCount);
|
|
const result: Sets = [];
|
|
|
|
for (let frame = 0; frame < frameCount; frame++) {
|
|
result.push(typeRange.map(type => frameType(sets, frame, type) || frameType(result, frame - 1, type)));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
export function canFly(info: PonyInfoBase<any, SpriteSetBase>) {
|
|
const type = info.wings && info.wings.type || 0;
|
|
return type > 0;
|
|
}
|
|
|
|
export function canMagic(info: PonyInfoBase<any, SpriteSetBase>) {
|
|
const type = info.horn && info.horn.type || 0;
|
|
return type === 1 || type === 2 || type === 3 || type === 14;
|
|
}
|
|
|
|
export function flipIris(iris: Iris): Iris {
|
|
if (iris === Iris.Left || iris === Iris.UpLeft) {
|
|
return iris + 1;
|
|
} else if (iris === Iris.Right || iris === Iris.UpRight) {
|
|
return iris - 1;
|
|
} else {
|
|
return iris;
|
|
}
|
|
}
|
|
|
|
export function flipFaceAccessoryType(type: number) {
|
|
if (type === 6) return 7;
|
|
if (type === 7) return 6;
|
|
|
|
if (type === 9) return 10;
|
|
if (type === 10) return 9;
|
|
|
|
return type;
|
|
}
|
|
|
|
export function flipFaceAccessoryPattern(type: number, pattern: number) {
|
|
if (type === 2) { // dark glasses
|
|
if (pattern === 1) return 2;
|
|
if (pattern === 2) return 1;
|
|
} else if (type === 11) { // large dark glasses
|
|
if (pattern === 1) return 2;
|
|
if (pattern === 2) return 1;
|
|
}
|
|
|
|
return pattern;
|
|
}
|
|
|
|
export const defaultExpression = {
|
|
left: Eye.Neutral,
|
|
leftIris: Iris.Forward,
|
|
right: Eye.Neutral,
|
|
rightIris: Iris.Forward,
|
|
muzzle: Muzzle.Neutral,
|
|
extra: ExpressionExtra.None,
|
|
};
|
|
|
|
export const blinkFrames: Eye[][] = [];
|
|
|
|
function setupBlinkFrames(frames: Eye[]) {
|
|
dropRight(frames, 1).forEach((f, i) => blinkFrames[f] = blinkFrames[f] || frames.slice(i + 1));
|
|
}
|
|
|
|
setupBlinkFrames([Eye.Neutral, Eye.Neutral2, Eye.Neutral3, Eye.Neutral4, Eye.Neutral5, Eye.Closed]);
|
|
setupBlinkFrames([Eye.Frown, Eye.Frown2, Eye.Frown3, Eye.Frown4, Eye.Closed]);
|
|
setupBlinkFrames([Eye.Sad, Eye.Sad2, Eye.Sad3, Eye.Sad4, Eye.Neutral5, Eye.Closed]);
|
|
setupBlinkFrames([Eye.Angry, Eye.Angry2, Eye.Neutral4, Eye.Neutral5, Eye.Closed]);
|
|
|
|
// sets
|
|
|
|
function mergeColorExtras(sprites: (ColorExtra | undefined)[]): ColorExtra | undefined {
|
|
const filtered = compact(sprites);
|
|
|
|
return {
|
|
...filtered[0],
|
|
colors: max(filtered.map(x => x.colors || 0)),
|
|
colorMany: filtered.length > 1 ? filtered.map(x => x.color) : undefined,
|
|
};
|
|
}
|
|
|
|
function mergeSprites(sets: ColorExtraSet[]): ColorExtraSet {
|
|
return zip(...sets).map(mergeColorExtras);
|
|
}
|
|
|
|
function mergeSpriteSets(...sets: ColorExtraSets[]): ColorExtraSets {
|
|
return zip(...sets).map(mergeSprites);
|
|
}
|
|
|
|
export const backLegSleeves: Sets = sprites.backLegSleeves
|
|
.map(sets => sets && [undefined, undefined, undefined, undefined, undefined, ...sets]);
|
|
|
|
export const mergedManes = mergeSpriteSets(sprites.behindManes, sprites.topManes, sprites.frontManes)!;
|
|
export const mergedBackManes = mergeSpriteSets(sprites.backBehindManes, sprites.backFrontManes)!;
|
|
export const mergedFacialHair = mergeSpriteSets(sprites.facialHairBehind, sprites.facialHair)!;
|
|
export const mergedEarAccessories = mergeSpriteSets(sprites.earAccessoriesBehind, sprites.earAccessories)!;
|
|
export const mergedHeadAccessories = mergeSpriteSets(sprites.headAccessoriesBehind, sprites.headAccessories)!;
|
|
export const mergedFaceAccessories = mergeSpriteSets(sprites.faceAccessories, sprites.faceAccessories2)!;
|
|
export const mergedChestAccessories = mergeSpriteSets(sprites.chestAccessoriesBehind[1], sprites.chestAccessories[1])!;
|
|
export const mergedBackAccessories = mergeSpriteSets(
|
|
backAccessories[1], [undefined, undefined, undefined, undefined, undefined, ...sprites.backLegSleeves[1]!])!;
|
|
export const mergedExtraAccessories = mergeSpriteSets(sprites.extraAccessoriesBehind, sprites.extraAccessories)!
|
|
.slice(0, DEVELOPMENT ? 100 : 2);
|
|
|
|
if (DEVELOPMENT) {
|
|
assertSizes('HEAD_ACCESSORY_OFFSETS', HEAD_ACCESSORY_OFFSETS, mergedManes);
|
|
assertSizes('EXTRA_ACCESSORY_OFFSETS', EXTRA_ACCESSORY_OFFSETS, mergedManes);
|
|
assertSizes('EAR_ACCESSORY_OFFSETS', EAR_ACCESSORY_OFFSETS, sprites.ears);
|
|
assertSizes('frontHoovesInFront', frontHoovesInFront, frontHooves[1]!);
|
|
assertSizes('backHoovesInFront', backHoovesInFront, sprites.backLegHooves[1]!);
|
|
}
|
|
|
|
function assertSizes(name: string, a: any[], b: any[]) {
|
|
if (a.length !== b.length) {
|
|
throw new Error(`Invalid ${name} length (${a.length} !== ${b.length})`);
|
|
}
|
|
}
|