This commit is contained in:
GDColon 2020-06-28 22:27:32 -04:00
commit 3bc525233a
48 changed files with 109 additions and 76 deletions

View file

@ -5,6 +5,8 @@ const path = require('path');
const icons = require('../icons/gameSheet.json');
const colors = require('../misc/colors.json');
const forms = require('../icons/forms.json')
const offsets = require('../icons/offsets.json');
const { finished } = require('stream');
function recolor(img, col) {
return img.scan(0, 0, img.bitmap.width, img.bitmap.height, function (x, y, idx) {
@ -16,16 +18,10 @@ function recolor(img, col) {
})
}
/*
Caveat of genFileName is that if there are any falsey values in the arguments they are ignored.
This is usually a good thing though - avoid issues by not putting something like 0 instead of '0'
*/
function genFileName(...args) {
return args.filter(function(val) {return val}).join('_')+'_001.png';
}
function fromIcons(filename) {
return `./icons/${filename}`;
}
/* Caveat of genFileName is that if there are any falsey values in the arguments they are ignored.
This is usually a good thing though - avoid issues by not putting something like 0 instead of '0' */
function genFileName(...args) { return args.filter(function(val) {return val}).join('_') +'_001.png' }
function fromIcons(filename) { return `./icons/${filename}` }
let cache = {};
module.exports = async (app, req, res) => {
@ -43,6 +39,11 @@ module.exports = async (app, req, res) => {
let col2 = req.query.col2 || account[11] || 3;
let outline = req.query.glow || account[28] || "0";
// meant for debugging robot/spider offsets, but i'll leave it in anyways
let glowOffset = (req.query.off || "").split(",").map(x => Number(x))
if (!glowOffset.some(x => x != 0)) glowOffset = []
let topless = form == "bird" && req.query.topless
let sizeParam = req.query.size && !isNaN(req.query.size)
if (outline == "0") outline = false;
@ -71,9 +72,9 @@ module.exports = async (app, req, res) => {
if (!colors[col1]) col1 = 0
if (!colors[col2]) col2 = 3
let iconCode = `${req.query.form == "cursed" ? "cursed" : form}-${iconID}-${col1}-${col2}-${outline ? 1 : 0}`
let iconCode = `${req.query.form == "cursed" ? "cursed" : form}${topless ? "topless" : ""}-${iconID}-${col1}-${col2}-${outline ? 1 : 0}`
if (!sizeParam && cache[iconCode]) {
if (!sizeParam && !glowOffset.length && cache[iconCode]) {
clearTimeout(cache[iconCode].timeoutID);
cache[iconCode].timeoutID = setTimeout(function() {delete cache[iconCode]}, 600000);
return res.end(cache[iconCode].value);
@ -82,11 +83,13 @@ module.exports = async (app, req, res) => {
let useExtra = false
let originalOffset = icons[icon].spriteOffset;
const minusOrigOffset = function(x, y) { return x - originalOffset[y] }
let minusOrigOffset = function(x, y) { return x - originalOffset[y] }
let offset = icons[glow].spriteOffset.map(minusOrigOffset);
let robotLeg1, robotLeg2, robotLeg3, robotLeg3b, robotLeg2b, robotLeg1b, robotLeg1c;
let robotOffset1, robotOffset2, robotOffset3, robotOffset1b, robotOffset2b, robotOffset3b;
let robotGlow1, robotGlow2, robotGlow3;
let robotGlow1, robotGlow2, robotGlow3
let ufoTop, ufoOffset, ufoCoords, ufoSprite
if (isSpecial) {
const legs = [1,2,3].map(function(val) {return genImageName(`0${val+1}`)});
const glows = [1,2,3].map(function(val) {return genImageName(`0${val+1}`, '2')});
@ -101,6 +104,8 @@ module.exports = async (app, req, res) => {
robotLeg1 = new Jimp(fromIcons(legs[0])); robotGlow1 = new Jimp(fromIcons(glows[0]))
robotLeg2 = new Jimp(fromIcons(legs[1])); robotGlow2 = new Jimp(fromIcons(glows[1]))
robotLeg3 = new Jimp(fromIcons(legs[2])); robotGlow3 = new Jimp(fromIcons(glows[2]))
if (!glowOffset.length) glowOffset = offsets[form][+iconID] || []
}
res.contentType('image/png');
@ -126,10 +131,14 @@ module.exports = async (app, req, res) => {
recolor(ic, col1)
ic.composite(glow, (iconSize[0] / 2) - (size[0] / 2) + offset[0], (iconSize[1] / 2) - (size[1] / 2) - offset[1], { mode: Jimp.BLEND_DESTINATION_OVER })
if (form == "ufo") { //ufo top WIP
ic.contain(iconSize[0], iconSize[1] * 1.1, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE)
//ic.contain(iconSize[0], 300, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_BOTTOM)
//ic.composite(ufoTop, (iconSize[0] / 2) - (size[0] / 2) + 7, iconSize[1] + topOffset[3] + 30, {mode: Jimp.BLEND_DESTINATION_OVER})
if (form == "bird" && !topless) {
ufoTop = genImageName('3')
ufoOffset = icons[ufoTop].spriteOffset.map(minusOrigOffset).concat(icons[ufoTop].spriteSize);
ufoCoords = [imgOff + (iconSize[0] / 2) - (ufoOffset[2] / 2) + ufoOffset[0], (iconSize[1] / 2) - (ufoOffset[3] / 2) - ufoOffset[1] + 300 - iconSize[1]]
ufoSprite = fromIcons(ufoTop)
ic.contain(iconSize[0], 300, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_BOTTOM)
// Only add dome if there's no glow, otherwise the dome will be outlined as well
if (!outline) ic.composite(await Jimp.read(ufoSprite), ufoCoords[0], ufoCoords[1], {mode: Jimp.BLEND_DESTINATION_OVER})
}
if (form == "robot" || req.query.form == "cursed") {
@ -154,14 +163,14 @@ module.exports = async (app, req, res) => {
await Jimp.read(new Jimp(robotLeg1)).then(rob => {
rob.rotate(-45)
recolor(rob, col1)
rob.composite(robotGlow1, (robotOffset1[2] - robotOffset1b[2]) + 1, (robotOffset1[3] - robotOffset1b[3]) / 2, { mode: Jimp.BLEND_DESTINATION_OVER })
rob.composite(robotGlow1, (robotOffset1[2] - robotOffset1b[2]) + (glowOffset[0] || 1), ((robotOffset1[3] - robotOffset1b[3]) / 2) + (glowOffset[1] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
robotLeg1 = rob
})
await Jimp.read(new Jimp(robotLeg2)).then(rob => {
rob.rotate(45)
recolor(rob, col1)
rob.composite(robotGlow2, (robotOffset2[2] - robotOffset2b[2]) / 2, (robotOffset2[3] - robotOffset2b[3]) / 2, { mode: Jimp.BLEND_DESTINATION_OVER })
rob.composite(robotGlow2, ((robotOffset2[2] - robotOffset2b[2]) / 4) + (glowOffset[4] || 0), ((robotOffset2[3] - robotOffset2b[3]) / 2) + (glowOffset[5] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
robotLeg2 = rob
})
@ -171,7 +180,7 @@ module.exports = async (app, req, res) => {
await Jimp.read(new Jimp(robotLeg3)).then(rob => {
recolor(rob, col1)
rob.composite(robotGlow3, (robotOffset3[2] - robotOffset3b[2]) / 2 - 2, (robotOffset3[3] - robotOffset3b[3]) / 2, { mode: Jimp.BLEND_DESTINATION_OVER })
rob.composite(robotGlow3, ((robotOffset3[2] - robotOffset3b[2]) / 2) + (glowOffset[2] || 0), ((robotOffset3[3] - robotOffset3b[3]) / 2) + (glowOffset[3] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
robotLeg3 = rob
})
@ -187,7 +196,6 @@ module.exports = async (app, req, res) => {
}
else if (form == "spider") {
let spiderBody;
@ -223,13 +231,13 @@ module.exports = async (app, req, res) => {
await Jimp.read(new Jimp(robotLeg1)).then(rob => {
recolor(rob, col1)
rob.composite(robotGlow1, (robotOffset1[2] - robotOffset1b[2]) / 2, (robotOffset1[3] - robotOffset1b[3]) / 4, { mode: Jimp.BLEND_DESTINATION_OVER })
rob.composite(robotGlow1, ((robotOffset1[2] - robotOffset1b[2]) / 2) + (glowOffset[2] || 0), ((robotOffset1[3] - robotOffset1b[3]) / 4) + (glowOffset[3] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
robotLeg1 = rob
})
await Jimp.read(new Jimp(robotLeg2)).then(rob => {
recolor(rob, col1)
rob.composite(robotGlow2, (robotOffset2[2] - robotOffset2b[2]) / 6, (robotOffset2[3] - robotOffset2b[3]) / 6, { mode: Jimp.BLEND_DESTINATION_OVER })
rob.composite(robotGlow2, ((robotOffset2[2] - robotOffset2b[2]) / 6) + (glowOffset[0] || 0), ((robotOffset2[3] - robotOffset2b[3]) / 6) + (glowOffset[1] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
rob.rotate(-40)
robotLeg2 = rob
})
@ -244,7 +252,7 @@ module.exports = async (app, req, res) => {
await Jimp.read(new Jimp(robotLeg3)).then(rob => {
recolor(rob, col1)
rob.composite(robotGlow3, (robotOffset3[2] - robotOffset3b[2]) / 2, (robotOffset3[3] - robotOffset3b[3]) / 2, { mode: Jimp.BLEND_DESTINATION_OVER })
rob.composite(robotGlow3, ((robotOffset3[2] - robotOffset3b[2]) / 2) + (glowOffset[4] || 0), ((robotOffset3[3] - robotOffset3b[3]) / 2) + (glowOffset[5] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
robotLeg3 = rob
})
@ -255,7 +263,6 @@ module.exports = async (app, req, res) => {
ic.composite(robotLeg3, 100 + (iconSize[0] / 2) - (robotOffset3[2]) + (robotOffset3[0]), (iconSize[1] / 2) - (robotOffset2[3]) - robotOffset2[1] + 77)
ic.composite(robotLeg1b, 100 + (iconSize[0] / 2) - (robotOffset1[2]) + robotOffset1[0] + 35, (iconSize[1] / 2) - (robotOffset1[3]) - robotOffset1[1] + 70)
ic.composite(robotLeg1c, 100 + (iconSize[0] / 2) - (robotOffset1[2]) + robotOffset1[0] + 75, (iconSize[1] / 2) - (robotOffset1[3]) - robotOffset1[1] + 70)
// ^ BELOW
ic.composite(spiderBody, 0, 0)
// v ABOVE
@ -263,39 +270,38 @@ module.exports = async (app, req, res) => {
ic.composite(robotLeg1, 100 + (iconSize[0] / 2) - (robotOffset1[2]) + robotOffset1[0] + 7, (iconSize[1] / 2) - (robotOffset1[3]) - robotOffset1[1] + 70)
}
if (useExtra) ic.composite(extra, imgOff + (iconSize[0] / 2) - (size2[0] / 2) + offset2[0], (iconSize[1] / 2) - (size2[1] / 2) - offset2[1])
if (form != "ufo") ic.autocrop(0.01, false)
if (form == "swing") ic.resize(120, 111)
if (ic.bitmap.height == '300') ic.autocrop(1, false)
if (!outline && sizeParam) {
let imgSize = Math.round(req.query.size)
if (imgSize < 32) imgSize = 32
if (imgSize > 512) imgSize = 512
ic.resize(imgSize, imgSize)
}
if (sizeParam) {
if (ic.bitmap.width > ic.bitmap.height) ic.contain(ic.bitmap.width, ic.bitmap.width, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE)
else if (ic.bitmap.width < ic.bitmap.height) ic.contain(ic.bitmap.height, ic.bitmap.height, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE)
}
if (useExtra) ic.composite(extra, imgOff + (iconSize[0] / 2) - (size2[0] / 2) + offset2[0], (iconSize[1] / 2) - (size2[1] / 2) - offset2[1] + (form == "bird" && !req.query.topless ? 300 - iconSize[1] : 0))
let finalSize = [ic.bitmap.width, ic.bitmap.height]
ic.getBuffer(Jimp.AUTO, function (err, buff) {
if (!outline) {
if (!sizeParam) {
function finish(img) {
img.autocrop(0.01, false)
if (form == "swing") img.resize(120, 111)
if (img.bitmap.height == 300) ic.autocrop(1, false)
if (sizeParam) {
let imgSize = Math.round(req.query.size)
if (imgSize < 32) imgSize = 32
if (imgSize > 512) imgSize = 512
if (img.bitmap.width > img.bitmap.height) img.contain(img.bitmap.width, img.bitmap.width, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE)
else if (img.bitmap.width < img.bitmap.height) img.contain(img.bitmap.height, img.bitmap.height, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE)
img.resize(imgSize, Jimp.AUTO)
}
img.getBuffer(Jimp.AUTO, (err, buffer) => {
if (!sizeParam && !glowOffset.length) {
cache[iconCode] = {
value: buff,
value: buffer,
timeoutID: setTimeout(function() {delete cache[iconCode]}, 600000)
}
}
return res.end(buff)
}
return res.end(buffer, 'base64')
})
}
else {
if (!outline) return finish(ic)
else {
ic.getBuffer(Jimp.AUTO, function (err, buff) {
const Canvas = require('canvas')
, Image = Canvas.Image
@ -318,35 +324,25 @@ module.exports = async (app, req, res) => {
ctx.globalCompositeOperation = "source-over";
ctx.imageSmoothingEnabled = false;
// Add UFO top last so it doesn't get glow'd
if (form == "bird" && !topless) {
const dome = new Image()
dome.src = ufoSprite
ctx.drawImage(dome, ufoCoords[0]+5, ufoCoords[1]+5)
}
ctx.drawImage(img, x, y)
}
img.onerror = err => { throw err }
img.src = buff;
const buffer = canvas.toBuffer();
img.src = buff
if (!sizeParam) {
cache[iconCode] = {
value: buffer,
timeoutID: setTimeout(function() {delete cache[iconCode]}, 600000)
}
return res.end(buffer, 'base64')
}
else {
let imgSize = Math.round(req.query.size)
if (imgSize < 32) imgSize = 32
if (imgSize > 512) imgSize = 512
Jimp.read(buffer).then(i => {
i.resize(imgSize, imgSize)
i.getBuffer(Jimp.AUTO, (err, b) => res.end(b))
})
}
}
})
Jimp.read(canvas.toBuffer()).then(b => {
return finish(b)
})
})
}
})
})
}

View file

@ -722,6 +722,7 @@
<p>col2: The ID of the secondary color to use</p>
<p>glow: If the icon should have a glow/outline (0 = off, anything else = on)</p>
<p>size: The size (in pixels) the icon should be, in case you don't want the default. Will always be square</p>
<p>topless: Removes the glass 'dome' from generated UFOs (legacy)</p>
<p>noUser: Disables fetching the icon from the GD servers. Slightly faster, but comes at the cost of having to build icons from the ground up using the parameters listed above. It completely ignores the entered username and always returns the default icon</p>
</div>

View file

@ -32,7 +32,8 @@
<div id="col1"></div>
<div id="col2"></div>
</div><br>
<p style="color: rgb(20, 20, 20); margin-top: 3;">All sprites/assets belong to <a href="http://robtopgames.com">RobTop Games</a>.</p>
<p style="color: rgb(20, 20, 20); margin-top: 3;">All sprites/assets belong to <a target=_blank href="http://robtopgames.com">RobTop Games</a>.</p>
<p><a target=_blank href="https://gdbrowser.com/api#icons">API Reference</a></p>
<div style="position:absolute; top: 2%; left: -1.95%; width: 10%; height: 25%; pointer-events: none">
<img class="gdButton" style="pointer-events: all" id="backButton" src="../assets/back.png" height="30%" onclick="backButton()">

View file

@ -95,7 +95,7 @@
<img src="../icon/[[USERNAME]]?form=cube" title="Cube [[ICON]]">
<img src="../icon/[[USERNAME]]?form=ship" title="Ship [[SHIP]]" style="height: 8%">
<img src="../icon/[[USERNAME]]?form=ball" title="Ball [[BALL]]" >
<img src="../icon/[[USERNAME]]?form=ufo" title="UFO [[UFO]]" style="height: 6%">
<img src="../icon/[[USERNAME]]?form=ufo" title="UFO [[UFO]]">
<img src="../icon/[[USERNAME]]?form=wave" title="Wave [[WAVE]]" style="height: 7%">
<img src="../icon/[[USERNAME]]?form=robot" title="Robot [[ROBOT]]" >
<img src="../icon/[[USERNAME]]?form=spider" title="Spider [[SPIDER]]">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

35
icons/offsets.json Normal file
View file

@ -0,0 +1,35 @@
{
"robot": {
"3": [-2, 0, 0, 0, -100],
"5": [4, -4, 10, 8, -100],
"6": [5, -1, 0, 0, -100],
"7": [-23, -2, 14, 5],
"8": [5, -2, -3, 0, -100],
"9": [5, -3],
"10": [-22, -2, 12, 3],
"11": [-1, 0, -2],
"12": [5, -2, 6, 5],
"13": [-3, 2, -7, -4],
"15": [0, 0, -7, -2],
"16": [1, 0, 0, 0, -100],
"17": [1, 0, 0, 0, -100],
"18": [-6, 4, -4, 0, -100],
"19": [-21, 0, 14, 4],
"20": [1, 0, 10, 5],
"21": [10, -8, 12, 3, -5, 2],
"22": [-10, 6, -12, 3, -100],
"23": [-18, 16, -4],
"24": [4, -2, -4],
"25": [12, -9, -1, 2],
"26": [-1, 0, 5]
},
"spider": {
"9": [0, 3],
"10": [8, 5],
"11": [1, 3],
"14": [2, 1],
"15": [3, 20, 0, 14],
"17": [1, 1]
}
}