Files
wownerogue/src/multiplayer/appearance.js
T

137 lines
4.0 KiB
JavaScript

const COLOR_AVATARS = ['default', 'green', 'amber', 'red'];
const PREMIUM_SKINS = ['monero-knight', 'wownero-rogue', 'cypher-operative'];
const MODEL3D_AVATARS = ['kenney-survivor-male', 'kenney-survivor-female'];
const CHAR_AVATARS = [
'char-villager', 'char-elder', 'char-barbarian', 'char-monk', 'char-ranger',
'char-bard', 'char-rogue', 'char-merchant', 'char-wizard', 'char-goblin'
];
const CHAR_TINTS = ['none', 'rose', 'teal', 'moss', 'gold', 'violet', 'ash'];
const CHAR_SKIN_TONES = ['natural', 'fair', 'warm', 'umber', 'olive', 'ash'];
const CHAR_HAIR_COLORS = ['copper', 'brown', 'black', 'blond', 'silver', 'violet'];
const CHAR_EQUIPMENT_SLOTS = ['body', 'head', 'shield', 'weapon'];
const CHAR_EQUIPMENT = {
body: ['none', 'robe', 'jerkin', 'mail', 'sash'],
head: ['none', 'hood', 'helm', 'horns', 'cap'],
shield: ['none', 'round', 'kite', 'tower', 'buckler'],
weapon: ['none', 'staff', 'sword', 'axe', 'bow']
};
const ALL_AVATARS = [...COLOR_AVATARS, ...PREMIUM_SKINS, ...CHAR_AVATARS, ...MODEL3D_AVATARS];
const AVATAR_PACKS = Object.freeze({
...PREMIUM_SKINS.reduce((out, id) => {
out[id] = 'generated-skins';
return out;
}, {}),
...MODEL3D_AVATARS.reduce((out, id) => {
out[id] = 'kenney-3d-characters';
return out;
}, {})
});
const DEFAULT_EQUIPMENT = CHAR_EQUIPMENT_SLOTS.reduce((out, slot) => {
out[slot] = 'none';
return out;
}, {});
const DEFAULT_COLORS = Object.freeze({
base: 'none',
skin: 'natural',
hair: 'copper',
body: 'none',
head: 'none',
shield: 'none',
weapon: 'none'
});
function includes(list, id) {
return list.indexOf(id) !== -1;
}
function isValidAvatar(id) {
return includes(ALL_AVATARS, id);
}
function isCharAvatar(id) {
return includes(CHAR_AVATARS, id);
}
function isPremiumAvatar(id) {
return !!AVATAR_PACKS[id];
}
function avatarPack(id) {
return AVATAR_PACKS[id] || null;
}
function normalizeEquipment(input = {}) {
const out = {};
for (const slot of CHAR_EQUIPMENT_SLOTS) {
const id = input && typeof input[slot] === 'string' ? input[slot] : 'none';
out[slot] = includes(CHAR_EQUIPMENT[slot], id) ? id : 'none';
}
return out;
}
function validTint(id, fallback = 'none') {
return includes(CHAR_TINTS, id) ? id : fallback;
}
function normalizeColors(input = {}, legacyTint = 'none') {
const colors = input && typeof input === 'object' ? input : {};
const tintFor = slot => validTint(
Object.prototype.hasOwnProperty.call(colors, slot) ? colors[slot] : legacyTint
);
return {
base: tintFor('base'),
skin: includes(CHAR_SKIN_TONES, colors.skin) ? colors.skin : DEFAULT_COLORS.skin,
hair: includes(CHAR_HAIR_COLORS, colors.hair) ? colors.hair : DEFAULT_COLORS.hair,
body: tintFor('body'),
head: tintFor('head'),
shield: tintFor('shield'),
weapon: tintFor('weapon')
};
}
function normalizeAppearance(input = {}) {
if (input && input.appearance && !input.avatar) input = input.appearance;
if (typeof input === 'string') input = { avatar: input };
if (!input || typeof input !== 'object') input = {};
let avatar = input.avatar || input.id || 'default';
if (!isValidAvatar(avatar)) avatar = 'default';
if (!isCharAvatar(avatar)) {
return { avatar, tint: 'none', equipment: { ...DEFAULT_EQUIPMENT } };
}
const colors = normalizeColors(input.colors, input.tint);
return {
avatar,
tint: colors.base,
equipment: normalizeEquipment(input.equipment),
colors
};
}
module.exports = {
COLOR_AVATARS,
PREMIUM_SKINS,
MODEL3D_AVATARS,
CHAR_AVATARS,
CHAR_TINTS,
CHAR_SKIN_TONES,
CHAR_HAIR_COLORS,
CHAR_EQUIPMENT,
CHAR_EQUIPMENT_SLOTS,
DEFAULT_EQUIPMENT,
DEFAULT_COLORS,
avatarIds: () => ALL_AVATARS.slice(),
premiumAvatarIds: () => Object.keys(AVATAR_PACKS),
avatarPack,
isValidAvatar,
isCharAvatar,
isPremiumAvatar,
normalizeEquipment,
normalizeColors,
normalizeAppearance
};