From 32cbd0e8052f40457ca2062ca199135b8b754d32 Mon Sep 17 00:00:00 2001 From: GGod <46885632+GGodPL@users.noreply.github.com> Date: Thu, 15 Feb 2024 21:14:20 +0100 Subject: [PATCH] add moreViews.js mod (without dynamic lights) --- mods/VCR_OSD_MONO.ttf | Bin 0 -> 22584 bytes mods/moreViews.js | 481 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 481 insertions(+) create mode 100644 mods/VCR_OSD_MONO.ttf create mode 100644 mods/moreViews.js diff --git a/mods/VCR_OSD_MONO.ttf b/mods/VCR_OSD_MONO.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9322814923c784c0ac4bcc12ff6c960d63931025 GIT binary patch literal 22584 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 dH0 { + if (n <= views.length - 1 && n > 1) { + view = n; + } else { + view = null; + } + setSetting('view', parseInt(view)); + document.querySelector('span[setting="view"]').children[0].value = view ?? 0; +} + +for (const i in views) { + if (i < 5) continue; + const option = document.createElement("option"); + option.setAttribute("value", i); + option.innerText = views[i]; + document.querySelector('.setting-span[setting="view"]').querySelector("select").appendChild(option); + viewKey[i] = views[i]; +} + +const vcrFont = new FontFace("VCR", "url(mods/VCR_OSD_MONO.ttf)"); +vcrFont.load().then(font => { + console.log(font); + document.fonts.add(font); +}) + +function blending(color, color2, t = 0.5) { + const [r, g, b] = parseColor(color).replace("#", "").match(/../g).map(a => parseInt(a, 16)); + const [r2, g2, b2] = parseColor(color2).replace("#", "").match(/../g).map(a => parseInt(a, 16)); + if ([r, g, b].includes(undefined) || [r, g, b, t].includes(NaN)) console.log([r, g, b, t], parseColor(color), color); + return `#${[ + (1 - t) * r + t * r2, + (1 - t) * g + t * g2, + (1 - t) * b + t * b2 + ].map(a => Math.floor(a).toString(16).padStart(2, "0")).join("")}`; +} + +const cache = new Map(); + +function mixColors(color, color2) { + if (cache.has(`${color}_${color2}`) || cache.has(`${color2}_${color}`)) return cache.get(`${color}_${color2}`) ?? cache.get(`${color2}_${color}`); + const [r, g, b] = parseColor(color).replace("#", "").match(/../g).map(a => parseInt(a, 16)); + const [r2, g2, b2] = parseColor(color2).replace("#", "").match(/../g).map(a => parseInt(a, 16)); + const res = [ + Math.max(r, r2), + Math.max(g, g2), + Math.max(b, b2) + ]; + cache.set(`${color}_${color2}`, `#${res.map(a => (Math.floor(a) % 256).toString(16).padStart(2, "0")).join("")}`); + return `#${res.map(a => (Math.floor(a) % 256).toString(16).padStart(2, "0")).join("")}`; +} + +const parseColor = (colorString) => { + if (colorString instanceof Array) return parseColor(colorString[0]); + if (typeof colorString != "string") return "#ffffff"; + if (colorString.startsWith("rgb(")) { + const color = colorString.replace("rgb(", "").replace(")", ""); + return `#${color.split(",").map(a => parseInt(a).toString(16).length == 1 ? `0${parseInt(a).toString(16)}` : parseInt(a).toString(16)).join("")}`; + } else if (colorString.startsWith("rgba(")) { + const color = colorString.replace("rgba(", "").replace(")", ""); + return `#${color.split(",").filter((_, i) => i <= 2).map(a => parseInt(a).toString(16).length == 1 ? `0${parseInt(a).toString(16)}` : parseInt(a).toString(16)).join("")}`; + } else { + if (colorString.startsWith("#")) { + const color = colorString.slice(1); + if (color.length == 3) return `#${color.split(a => a.repeat(2)).join()}`; + else if (color.length >= 6) return `#${color.slice(0, 6)}`; + else return `#${color}`; + } + } +} + +const rgbToHsl = (r, g, b) => { + const r1 = r / 255; + const g1 = g / 255; + const b1 = b / 255; + + const cmax = Math.max(r1, g1, b1); + const cmin = Math.min(r1, g1, b1); + + const delta = cmax - cmin; + const l = (cmax + cmin) / 2; + const s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); + let h = 0; + if (delta != 0) { + switch (cmax) { + case r1: + h = 60 * (((g1 - b1) / delta) % 6); + break; + case g1: + h = 60 * ((b1 - r1) / delta + 2); + break; + default: + h = 60 * ((r1 - g1) / delta + 4); + } + } + + return {h, s, l}; +} + +const thetaSetting = new Setting("3D View Angle (0-90)", "theta", settingType.NUMBER, false, parseFloat((Math.atan(2) * 180 / Math.PI).toPrecision(3))); + +const tab = new SettingsTab("moreViews.js"); +tab.registerSetting(thetaSetting); + +let maxDistance = -1; +const colorCache = new Map(); + +function getModeColor(color, distance = 0) { + if (!colorCache.has(view)) colorCache.set(view, new Map()); + if (view == 18) { + if (colorCache.get(view).has(color) && colorCache.get(view).get(color).has(distance)) return colorCache.get(view).get(color).get(distance); + } else if (colorCache.get(view).has(color)) return colorCache.get(view).get(color); + switch (view) { + case 6: { + const newColor = "#" + (parseInt(`0x1${parseColor(color).slice(1)}`) ^ 0xffffff).toString(16).slice(1); + colorCache.get(view).set(color, newColor); + return newColor; + } + case 7: { + const newColor = blending(pixel.color, "#000000"); + colorCache.get(view).set(color, newColor); + return newColor; + } + case 8: { + const newColor = blending(pixel.color, "#ffffff"); + colorCache.get(view).set(color, newColor); + return newColor; + } + case 9: { + const [r, g, b] = parseColor(color).slice(1).match(/.{1,2}/g).map(a => parseInt(a, 16)).slice(0, 3); + const {h, l} = rgbToHsl(r, g, b); + const newColor = `hsl(${Math.round(h)}, 0%, ${Math.round(l * 100)}%)`; + colorCache.get(view).set(color, newColor); + return newColor; + } + case 10: { + const [r, g, b] = parseColor(color).replace("#", "").match(/../g).map(a => parseInt(a, 16)); + const [r2, g2, b2] = [ + Math.min(255, (r * 0.393) + (g * 0.769) + (b * 0.189)), + Math.min(255, (r * 0.349) + (g * 0.686) + (b * 0.168)), + Math.min(255, (r * 0.272) + (g * 0.534) + (b * 0.131)) + ]; + const newColor = `#${Math.floor(r2).toString(16).padStart(2, "0")}${Math.floor(g2).toString(16).padStart(2, "0")}${Math.floor(b2).toString(16).padStart(2, "0")}`; + colorCache.get(view).set(color, newColor); + return newColor; + } + case 11: { + const [r, g, b] = parseColor(color).slice(1).match(/.{1,2}/g).map(a => parseInt(a, 16)).slice(0, 3); + const {h, s, l} = rgbToHsl(r, g, b); + const newColor = `hsl(${(Math.round(h) + 180 % 360)}, ${Math.round(s * 100)}%, ${Math.round(l * 100)}%)`; + colorCache.get(view).set(color, newColor); + return newColor; + } + case 12: { + const [r, g, b] = parseColor(color).slice(1).match(/.{1,2}/g).map(a => parseInt(a, 16)).slice(0, 3); + const {h, s, l} = rgbToHsl(r, g, b); + const newColor = `hsl(${Math.round(h)}, ${Math.round(s * 100) * 4}%, ${Math.round(l * 100)}%)`; + colorCache.get(view).set(color, newColor); + return newColor; + } + case 15: { + const [r, g, b] = parseColor(color).replace("#", "").match(/../g); + const [r2, g2, b2] = [parseInt(r, 16) * 0.75, parseInt(g, 16) * 0.75, parseInt(b, 16) * 0.75]; + const newColor = `rgb(${r2}, ${g2}, ${b2})`; + colorCache.get(view).set(color, newColor); + return newColor; + } + case 18: { + const newColor = blending(pixel.color, "#000000", (1 / maxDistance) * distance); + colorCache.get(view).has(color) + ? colorCache.get(view).get(color).set(distance, newColor) + : colorCache.get(view).set(color, new Map([[distance, newColor]])); + return newColor; + } + } + return color; +} + +settingsManager.registerTab(tab); + +runAfterLoadList.push(() => drawPixels = (function() { + const oldDrawPixels = drawPixels; + + return function(forceTick = false) { + if (view >= 5) { + if (maxDistance = -1) maxDistance = Math.sqrt((width / 2) ** 2 + (height / 2) ** 2) * 2; + + const canvas = document.getElementById("game"); + const ctx = canvas.getContext("2d"); + var newCurrentPixels = currentPixels.slice(); + var pixelsFirst = []; + var pixelsLast = []; + if (!paused || forceTick) { + shuffleArray(newCurrentPixels); + } + + for (var i = 0; i < newCurrentPixels.length; i++) { + pixel = newCurrentPixels[i]; + if (pixel.del) {continue} + if (!paused || forceTick) { + if (elements[pixel.element].tick) { + elements[pixel.element].tick(pixel); + } + if (pixel.del) {continue} + if (elements[pixel.element].behavior) { + pixelTick(pixel); + } + }; + if (pixel.con) { pixel = pixel.con } + if (elements[pixel.element].isGas || elements[pixel.element].glow) { + pixelsLast.push(pixel); + } + else { + pixelsFirst.push(pixel); + } + } + + if (hiding) { + if (ctx.globalAlpha < 1) { + ctx.globalAlpha = 1; + } + + if (elements[currentElement].maxSize < mouseSize) { + var mouseOffset = Math.trunc(elements[currentElement].maxSize/2); + } + else { + var mouseOffset = Math.trunc(mouseSize/2); + } + var topLeft = [mousePos.x-mouseOffset,mousePos.y-mouseOffset]; + var bottomRight = [mousePos.x+mouseOffset,mousePos.y+mouseOffset]; + + ctx.strokeStyle = "white"; + ctx.strokeRect(topLeft[0]*pixelSize,topLeft[1]*pixelSize,(bottomRight[0]-topLeft[0]+1)*pixelSize,(bottomRight[1]-topLeft[1]+1)*pixelSize); + + if (settings.precision) { + ctx.fillStyle = "rgba(255,255,255,0.5)"; + ctx.fillRect(mousePos.x*pixelSize,mousePos.y*pixelSize,pixelSize,pixelSize); + } + if ((!paused) || forceTick) {pixelTicks++}; + return; + } + + if (!settings["bg"]) {ctx.clearRect(0, 0, canvas.width, canvas.height)} + else { + ctx.fillStyle = settings["bg"]; + ctx.fillRect(0, 0, canvas.width, canvas.height); + } + var pixelDrawList = pixelsFirst.concat(pixelsLast); + for (var i = 0; i < pixelDrawList.length; i++) { + pixel = pixelDrawList[i]; + if (pixelMap[pixel.x][pixel.y] == undefined) {continue} + if (pixel.con) { pixel = pixel.con }; + ctx.fillStyle = getModeColor(pixel.color, view == 18 ? Math.sqrt((width / 2 - pixel.x) ** 2 + (height / 2 - pixel.y) ** 2) : 0); + // 3D VIEW + if (view == 5) { + const neighborRight = !outOfBounds(pixel.x + 1, pixel.y) && !!pixelMap[pixel.x + 1][pixel.y]; + const neighborUp = !outOfBounds(pixel.x, pixel.y - 1) && !!pixelMap[pixel.x][pixel.y - 1]; + const neighborUpRight = !outOfBounds(pixel.x + 1, pixel.y - 1) && !!pixelMap[pixel.x + 1][pixel.y - 1]; + let size = 0; + let currentY = pixel.y; + while (!outOfBounds(pixel.x, currentY) && pixelMap[pixel.x][currentY] && pixelMap[pixel.x][currentY].element == pixel.element) { + currentY++; + size++; + } + ctx.globalAlpha = 1; + ctx.fillStyle = pixel.color; + ctx.fillRect(pixel.x * pixelSize, pixel.y * pixelSize, pixelSize, pixelSize); + const px = pixel.x * pixelSize; + const py = pixel.y * pixelSize; + const theta = Math.max(Math.min(thetaSetting.get(), 90), 0) * Math.PI / 180; + const a = Math.cos(theta); + const b = Math.sin(theta); + const w = pixelSize; + const px2 = px + a * w; + const py2 = py - b * w; + const parts = [[[px, py], [[px2, py2], [px + w, py2], [px + w, py]], !neighborUp], [[px + w, py + w], [[px2 + w, py2 + w], [px2 + w, py], [px + w, py]], !neighborRight], [[px + w, py], [[px + w, py2], [px2 + w, py2], [px + w, py]], !neighborUp && !neighborUpRight], [[px + w, py], [[px2 + w, py2], [px2 + w, py], [px + w, py]], !neighborRight && !neighborUpRight]] + for (const part of parts.filter(p => p[2])) { + ctx.fillStyle = blending(pixel.color, "#000000"); + ctx.beginPath(); + ctx.moveTo(...part[0]); + for (const v of part[1]) { + ctx.lineTo(...v); + } + ctx.closePath(); + ctx.fill(); + } + } else if (view == 13) { + const hue = 225 - (Math.log(pixel.start) / Math.log(pixelTicks)) * 225; + ctx.globalAlpha = 1; + ctx.fillStyle = `hsl(${Math.min(Math.round(hue), 250)}, 100%, 50%)`; + ctx.fillRect(pixel.x * pixelSize, pixel.y * pixelSize, pixelSize, pixelSize); + } else if (view == 14) { + ctx.globalAlpha = 1; + ctx.fillStyle = pixel.color; + ctx.fillRect(pixel.x * pixelSize, pixel.y * pixelSize, pixelSize, pixelSize); + + if (outOfBounds(pixel.x - 1, pixel.y) || !pixelMap[pixel.x - 1][pixel.y]) { + ctx.fillStyle = "#ff0000"; + ctx.globalAlpha = 0.5; + ctx.fillRect(pixel.x * pixelSize - 0.5 * pixelSize, pixel.y * pixelSize, pixelSize, pixelSize); + } + if (outOfBounds(pixel.x + 1, pixel.y) || !pixelMap[pixel.x + 1][pixel.y]) { + ctx.fillStyle = "#00ffff"; + ctx.globalAlpha = 0.5; + ctx.fillRect(pixel.x * pixelSize + 0.5 * pixelSize, pixel.y * pixelSize, pixelSize, pixelSize); + } + } else if (view == 15) { + const [r, g, b] = parseColor(pixel.color).replace("#", "").match(/../g); + const [r2, g2, b2] = [parseInt(r, 16) * 0.75, parseInt(g, 16) * 0.75, parseInt(b, 16) * 0.75] + // scrolling effect + const offset = (pixelTicks + 6) % height >= pixel.y && (pixelTicks - 3) % height <= pixel.y + || (pixelTicks + 66) % height >= pixel.y && (pixelTicks - 57) % height <= pixel.y; + if (!pixelMap[pixel.x - 1] || !pixelMap[pixel.x - 1][pixel.y]) { + ctx.globalAlpha = 0.5; + ctx.fillStyle = `#${r.padStart(2, "0")}0000`; + ctx.fillRect(pixel.x * pixelSize - 0.75 * pixelSize - (offset ? 0.5 * pixelSize : 0) , pixel.y * pixelSize, pixelSize, pixelSize); + } + if (!pixelMap[pixel.x + 1] || !pixelMap[pixel.x + 1][pixel.y]) { + ctx.globalAlpha = 0.5; + ctx.fillStyle = `#0000${b.padStart(2, "0")}`; + ctx.fillRect(pixel.x * pixelSize + 0.75 * pixelSize - (offset ? 0.5 * pixelSize : 0), pixel.y * pixelSize, pixelSize, pixelSize); + } + ctx.globalAlpha = 1; + ctx.fillStyle = `rgb(${r2}, ${g2}, ${b2})` + ctx.fillRect(pixel.x * pixelSize - (offset ? 0.5 * pixelSize : 0), pixel.y * pixelSize, pixelSize, pixelSize); + ctx.globalAlpha = 1; + // i fucking hate it but at least it works + // and i dont feel like finding something that is fast and pretty + } else if (view == 16) { + ctx.globalAlpha = 1; + ctx.strokeStyle = pixel.color; + ctx.lineWidth = 2; + const cond1 = outOfBounds(pixel.x - 1, pixel.y) + || !pixelMap[pixel.x - 1][pixel.y] + || pixelMap[pixel.x - 1][pixel.y].element != pixel.element; + const cond2 = outOfBounds(pixel.x + 1, pixel.y) + || !pixelMap[pixel.x + 1][pixel.y] + || pixelMap[pixel.x + 1][pixel.y].element != pixel.element; + const cond3 = outOfBounds(pixel.x, pixel.y - 1) + || !pixelMap[pixel.x][pixel.y - 1] + || pixelMap[pixel.x][pixel.y - 1].element != pixel.element; + const cond4 = outOfBounds(pixel.x, pixel.y + 1) + || !pixelMap[pixel.x][pixel.y + 1] + || pixelMap[pixel.x][pixel.y + 1].element != pixel.element; + const cond5 = outOfBounds(pixel.x - 1, pixel.y - 1) + || !pixelMap[pixel.x - 1][pixel.y - 1] + || pixelMap[pixel.x - 1][pixel.y - 1].element != pixel.element; + const cond6 = outOfBounds(pixel.x + 1, pixel.y - 1) + || !pixelMap[pixel.x + 1][pixel.y - 1] + || pixelMap[pixel.x + 1][pixel.y - 1].element != pixel.element; + const cond7 = outOfBounds(pixel.x - 1, pixel.y + 1) + || !pixelMap[pixel.x - 1][pixel.y + 1] + || pixelMap[pixel.x - 1][pixel.y + 1].element != pixel.element; + const cond8 = outOfBounds(pixel.x + 1, pixel.y + 1) + || !pixelMap[pixel.x + 1][pixel.y + 1] + || pixelMap[pixel.x + 1][pixel.y + 1].element != pixel.element; + + if (cond1) { + ctx.beginPath(); + ctx.moveTo(pixel.x * pixelSize + ctx.lineWidth / 2, pixel.y * pixelSize); + ctx.lineTo(pixel.x * pixelSize + ctx.lineWidth / 2, (pixel.y + 1) * pixelSize); + ctx.stroke(); + } + if (cond2) { + ctx.beginPath(); + ctx.moveTo((pixel.x + 1) * pixelSize - ctx.lineWidth / 2, pixel.y * pixelSize); + ctx.lineTo((pixel.x + 1) * pixelSize - ctx.lineWidth / 2, (pixel.y + 1) * pixelSize); + ctx.stroke(); + } + if (cond3) { + ctx.beginPath(); + ctx.moveTo(pixel.x * pixelSize, pixel.y * pixelSize + ctx.lineWidth / 2); + ctx.lineTo((pixel.x + 1) * pixelSize, pixel.y * pixelSize + ctx.lineWidth / 2); + ctx.stroke(); + } + if (cond4) { + ctx.beginPath(); + ctx.moveTo(pixel.x * pixelSize, (pixel.y + 1) * pixelSize - ctx.lineWidth / 2); + ctx.lineTo((pixel.x + 1) * pixelSize, (pixel.y + 1) * pixelSize - ctx.lineWidth / 2); + ctx.stroke(); + } + if (!cond2 && !cond4 && cond8) ctx.fillRect((pixel.x + 1) * pixelSize - ctx.lineWidth, (pixel.y + 1) * pixelSize - ctx.lineWidth, ctx.lineWidth, ctx.lineWidth); + if (!cond2 && !cond3 && cond6) ctx.fillRect((pixel.x + 1) * pixelSize - ctx.lineWidth, pixel.y * pixelSize, ctx.lineWidth, ctx.lineWidth); + if (!cond1 && !cond3 && cond5) ctx.fillRect(pixel.x * pixelSize, pixel.y * pixelSize, ctx.lineWidth, ctx.lineWidth); + if (!cond1 && !cond4 && cond7) ctx.fillRect(pixel.x * pixelSize, (pixel.y + 1) * pixelSize - ctx.lineWidth, ctx.lineWidth, ctx.lineWidth); + } else if (view == 17) { + ctx.fillRect(pixel.x * pixelSize, (height - pixel.y) * pixelSize, pixelSize, pixelSize); + } else { + ctx.fillRect(pixel.x*pixelSize, pixel.y*pixelSize, pixelSize, pixelSize); + } + if (pixel.charge && view !== 2) { // Yellow glow on charge + if (!elements[pixel.element].colorOn) { + ctx.fillStyle = "rgba(255,255,0,0.5)"; + ctx.fillRect(pixel.x*pixelSize, pixel.y*pixelSize, pixelSize, pixelSize); + } + } + } + if (view == 15) { + // TRACK READ NOISE + for (let n = 0; n < 3; n++) { + const number = Math.floor(Math.random() * height); + ctx.globalAlpha = Math.random(); + ctx.fillStyle = "#fff"; + ctx.fillRect(0, (number + 0.5) * pixelSize, width * pixelSize, 0.2); + ctx.globalAlpha = 1; + } + const {font, textAlign} = ctx; + ctx.font = "30px VCR"; + ctx.textAlign = "start"; + ctx.fillText(paused ? "PAUSE" : "PLAY", (0.025 * width) * pixelSize, (0.025 * width) * pixelSize + 15); + if (paused) { + ctx.fillRect((0.05 * width) * pixelSize + ctx.measureText("PAUSE").width, (0.025 * width) * pixelSize - 7.5, 5, 22.5); + ctx.fillRect((0.05 * width) * pixelSize + ctx.measureText("PAUSE").width + 8, (0.025 * width) * pixelSize - 7.5, 5, 22.5); + } else { + ctx.fillStyle = "#fff"; + ctx.beginPath(); + ctx.moveTo((0.05 * width) * pixelSize + ctx.measureText("PLAY").width, (0.025 * width) * pixelSize - 7.5); + ctx.lineTo((0.05 * width) * pixelSize + ctx.measureText("PLAY").width, (0.025 * width) * pixelSize + 15); + ctx.lineTo((0.05 * width) * pixelSize + ctx.measureText("PLAY").width + 17.5, (0.025 * width) * pixelSize + 3.75); + ctx.lineTo((0.05 * width) * pixelSize + ctx.measureText("PLAY").width, (0.025 * width) * pixelSize - 7.5); + ctx.fill(); + } + const base = Math.floor(pixelTicks / tps); + const seconds = base % 60 + ""; + const minutes = Math.floor(base / 60) % 60 + ""; + const hours = Math.floor(base / 60 / 60) + ""; + ctx.textAlign = "end"; + ctx.fillText(`${hours.padStart(2, "0")}:${minutes.padStart(2, "0")}:${seconds.padStart(2, "0")}`, (0.975 * width) * pixelSize, (0.025 * width) * pixelSize + 15); + ctx.font = font; + ctx.textAlign = textAlign; + } + if (ctx.globalAlpha < 1) { + ctx.globalAlpha = 1; + } + + if (elements[currentElement].maxSize < mouseSize) { + var mouseOffset = Math.trunc(elements[currentElement].maxSize/2); + } + else { + var mouseOffset = Math.trunc(mouseSize/2); + } + var topLeft = [mousePos.x-mouseOffset,mousePos.y-mouseOffset]; + var bottomRight = [mousePos.x+mouseOffset,mousePos.y+mouseOffset]; + // Draw a square around the mouse + ctx.strokeStyle = "white"; + ctx.strokeRect(topLeft[0]*pixelSize,topLeft[1]*pixelSize,(bottomRight[0]-topLeft[0]+1)*pixelSize,(bottomRight[1]-topLeft[1]+1)*pixelSize); + // draw one transparent pixel in the center + if (settings.precision) { + ctx.fillStyle = "rgba(255,255,255,0.5)"; + ctx.fillRect(mousePos.x*pixelSize,mousePos.y*pixelSize,pixelSize,pixelSize); + } + if ((!paused) || forceTick) {pixelTicks++}; + } else oldDrawPixels.apply(this, arguments); + } +}())); +} \ No newline at end of file