Ruined
This commit is contained in:
@@ -14,23 +14,23 @@ const pixel = (im,tile,x,y)=> {
|
||||
};
|
||||
const alpha = im=>im.data.reduce((n,value,i)=>n+(i%4===3 && value===255 ? 1 : 0),0);
|
||||
|
||||
test('exact public option IDs and 170 deterministic filenames include every Cartesian combination',()=> {
|
||||
test('exact public option IDs and deterministic filenames include every Cartesian combination',()=> {
|
||||
assert.deepEqual(O,{
|
||||
bodies:['compact','balanced','broad'],skin:['porcelain','sand','honey','olive','umber','ebony'],
|
||||
faces:['calm','angular','soft','weathered'],eyes:['hazel','brown','green','blue','grey'],
|
||||
hairStyles:['cropped','sidepart','wavy','braids','long','shaved','none'],
|
||||
bodies:['compact','lean','balanced','broad','sturdy'],skin:['porcelain','sand','honey','olive','umber','ebony'],
|
||||
faces:['calm','angular','soft','weathered','lined'],eyes:['hazel','brown','green','blue','grey'],
|
||||
hairStyles:['cropped','sidepart','wavy','braids','long','shaved','none','curly','topknot','undercut'],
|
||||
hairColors:['ash','flax','chestnut','auburn','black','silver'],
|
||||
facialHair:['none','stubble','moustache','short_beard','full_beard'],
|
||||
garments:['tunic','workshirt','jerkin','coat'],clothColors:['sage','teal','slate','mauve','ochre','rust','linen','charcoal'],
|
||||
facialHair:['none','stubble','moustache','short_beard','full_beard','goatee','braided_beard'],
|
||||
garments:['tunic','workshirt','jerkin','coat','hooded_cloak','travel_coat','wool_mantle'],clothColors:['sage','teal','slate','mauve','ochre','rust','linen','charcoal'],
|
||||
trousers:['earth','slate','moss','charcoal'],boots:['walnut','black','tan'],
|
||||
accents:['none','scarf','apron','sash','vest'],details:['none','freckles','scar','freckles_scar'],
|
||||
accents:['none','scarf','apron','sash','vest','satchel','tool_belt','pauldrons','hood'],details:['none','freckles','scar','freckles_scar','birthmark'],
|
||||
});
|
||||
const specs=[['skin',O.skin],['face',O.faces],['eyes',O.eyes],['hair',O.hairStyles,O.hairColors],
|
||||
['beard',O.facialHair,O.hairColors],['garment',O.garments,O.clothColors],['trousers',O.trousers],
|
||||
['boots',O.boots],['accent',O.accents,O.clothColors],['detail',O.details]];
|
||||
const expected=specs.flatMap(([kind,ids,colors])=>ids.flatMap(id=>(colors||[null]).map(color=>
|
||||
`hearth_char_${kind}_${id}${color ? '_'+color : ''}.png`)));
|
||||
assert.equal(M.length,170); assert.equal(new Set(expected).size,170);
|
||||
assert.equal(M.length,expected.length); assert.equal(new Set(expected).size,expected.length);
|
||||
assert.deepEqual(M.map(r=>r.filename),expected);
|
||||
assert.ok(Object.isFrozen(O) && Object.values(O).every(Object.isFrozen) && M.every(Object.isFrozen));
|
||||
assert.deepEqual([...characterArt().keys()],expected);
|
||||
@@ -59,7 +59,7 @@ test('all layers are native 64 RGBA, crisp alpha, no hidden RGB; only named none
|
||||
test('overlays paint only their semantic UV tiles, never held metal, wood, wrap or unused atlas space',()=> {
|
||||
const allowed={face:['face'],eyes:['face'],hair:['face','hair','side','back','sleeve'],
|
||||
beard:['face','side'],garment:['tunic','back','sleeve'],trousers:['trousers'],boots:['boot'],
|
||||
accent:['tunic','back','sleeve'],detail:['face']};
|
||||
accent:['tunic','back','sleeve','face','hair','side'],detail:['face']};
|
||||
for (const r of M.filter(r=>r.kind!=='skin')) {
|
||||
const im=characterLayer(r.filename), tiles=new Set(allowed[r.kind].map(t=>ATLAS[t].join(',')));
|
||||
for (let y=0;y<64;y++) for (let x=0;x<64;x++) if (im.data[(y*64+x)*4+3])
|
||||
@@ -116,10 +116,10 @@ test('layer names and order match Luanti composition; garments cannot erase long
|
||||
assert.deepEqual(names,[
|
||||
'hearth_char_skin_sand.png','hearth_char_face_calm.png','hearth_char_eyes_hazel.png',
|
||||
'hearth_char_garment_coat_rust.png','hearth_char_trousers_earth.png','hearth_char_boots_walnut.png',
|
||||
'hearth_char_accent_scarf_sage.png','hearth_char_hair_long_chestnut.png',
|
||||
'hearth_char_beard_none_chestnut.png','hearth_char_detail_none.png']);
|
||||
'hearth_char_hair_long_chestnut.png','hearth_char_beard_none_chestnut.png',
|
||||
'hearth_char_accent_scarf_sage.png','hearth_char_detail_none.png']);
|
||||
assert.equal(characterTexture({hair:'long',garment:'coat',cloth:'rust'}),names.join('^'));
|
||||
const im=compositeCharacter({hair:'long',garment:'coat',cloth:'rust'}), hair=characterLayer(names[7]);
|
||||
const im=compositeCharacter({hair:'long',garment:'coat',cloth:'rust'}), hair=characterLayer(names[6]);
|
||||
assert.deepEqual(pixel(im,'back',3,2),pixel(hair,'back',3,2));
|
||||
assert.deepEqual(pixel(im,'sleeve',0,1),pixel(hair,'sleeve',0,1));
|
||||
assert.equal(alpha(im),4096);
|
||||
@@ -150,7 +150,7 @@ test('clothing has tailored collars, rolled cuffs, leather seams, plackets, boot
|
||||
assert.notDeepEqual(pixel(garment('jerkin'),'tunic',1,3),pixel(garment('jerkin'),'tunic',2,3),'leather panel seam');
|
||||
assert.notDeepEqual(pixel(garment('coat'),'tunic',3,3),pixel(garment('coat'),'tunic',2,3),'coat opening');
|
||||
const masks=O.accents.map(style=>characterLayer(`hearth_char_accent_${style}_sage.png`).data.filter((_,i)=>i%4===3));
|
||||
assert.equal(new Set(masks.map(bytes=>createHash('sha256').update(bytes).digest('hex'))).size,5);
|
||||
assert.equal(new Set(masks.map(bytes=>createHash('sha256').update(bytes).digest('hex'))).size,O.accents.length);
|
||||
for (const id of O.boots) assert.deepEqual(pixel(characterLayer(`hearth_char_boots_${id}.png`),'boot',0,7),[30,28,26,255]);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user