From 6d9e0b3ef4248f524af5f727aa2168f0a005651e Mon Sep 17 00:00:00 2001 From: GayLord Date: Sat, 19 Oct 2024 17:24:11 +0200 Subject: [PATCH] Initial Commit --- .gitignore | 1 + LICENSE | 22 + README.md | 4 + public/assets/css/theme-haxxor.css | 304 ++++++++++++ public/assets/scripts/haxxor.js | 507 +++++++++++++++++++++ public/assets/templates/custom/header.tmpl | 1 + 6 files changed, 839 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 public/assets/css/theme-haxxor.css create mode 100644 public/assets/scripts/haxxor.js create mode 100644 public/assets/templates/custom/header.tmpl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..55c7354 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.etc diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..dcaa9c3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2024 UwU + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..817ff7b --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# Installation +Very straightforward, have fun! + + diff --git a/public/assets/css/theme-haxxor.css b/public/assets/css/theme-haxxor.css new file mode 100644 index 0000000..2c7f9d7 --- /dev/null +++ b/public/assets/css/theme-haxxor.css @@ -0,0 +1,304 @@ +:root { + --is-haxxorman: true; + --is-dark-theme: true; + --color-primary: #54a13c; + --color-primary-contrast: rgb(115, 222, 82); + --color-primary-dark-1: #82ad74; + --color-primary-dark-2: #679cd0; + --color-primary-dark-3: #7aa8d6; + --color-primary-dark-4: #8db5dc; + --color-primary-dark-5: #b3cde7; + --color-primary-dark-6: #d9e6f3; + --color-primary-dark-7: #f4f8fb; + --color-primary-light-1: #3876b3; + --color-primary-light-2: #31699f; + --color-primary-light-3: #2b5c8b; + --color-primary-light-4: #254f77; + --color-primary-light-5: #193450; + --color-primary-light-6: #0c1a28; + --color-primary-light-7: #04080c; + --color-primary-alpha-10: #4183c419; + --color-primary-alpha-20: #4183c433; + --color-primary-alpha-30: #4183c44b; + --color-primary-alpha-40: #4183c466; + --color-primary-alpha-50: #4183c480; + --color-primary-alpha-60: #4183c499; + --color-primary-alpha-70: #4183c4b3; + --color-primary-alpha-80: #4183c4cc; + --color-primary-alpha-90: #4183c4e1; + --color-primary-hover: #172d11; + --color-primary-active: #172d11; + --color-secondary: #224019; + --color-secondary-dark-1: #294c1e; + --color-secondary-dark-2: #284a1d; + --color-secondary-dark-3: #2b5120; + --color-secondary-dark-4: #2d5521; + --color-secondary-dark-5: #305923; + --color-secondary-dark-6: #335e26; + --color-secondary-dark-7: #356428; + --color-secondary-dark-8: #3e762f; + --color-secondary-dark-9: #3c712d; + --color-secondary-dark-10: #b7bfc7; + --color-secondary-dark-11: #c5cbd2; + --color-secondary-dark-12: #cfd4da; + --color-secondary-dark-13: #d2d7dc; + --color-secondary-light-1: #313940; + --color-secondary-light-2: #292f35; + --color-secondary-light-3: #1d2226; + --color-secondary-light-4: #171b1e; + --color-secondary-alpha-10: #3b444c19; + --color-secondary-alpha-20: #3b444c33; + --color-secondary-alpha-30: #3b444c4b; + --color-secondary-alpha-40: #3b444c66; + --color-secondary-alpha-50: #3b444c80; + --color-secondary-alpha-60: #3b444c99; + --color-secondary-alpha-70: #3b444cb3; + --color-secondary-alpha-80: #3b444ccc; + --color-secondary-alpha-90: #3b444ce1; + --color-secondary-button: var(--color-secondary-dark-4); + --color-secondary-hover: var(--color-secondary-dark-3); + --color-secondary-active: var(--color-secondary-dark-2); + /* console colors - used for actions console and console files */ + --color-console-fg: #f7f8f9; + --color-console-fg-subtle: #bdc4cc; + --color-console-bg: #171b1e; + --color-console-border: #2e353b; + --color-console-hover-bg: #272d33; + --color-console-active-bg: #2e353b; + --color-console-menu-bg: #262b31; + --color-console-menu-border: #414b55; + /* named colors */ + --color-red: #cc4848; + --color-orange: #cc580c; + --color-yellow: #cc9903; + --color-olive: #91a313; + --color-green: #87ab63; + --color-teal: #00918a; + --color-blue: #3a8ac6; + --color-violet: #906ae1; + --color-purple: #b259d0; + --color-pink: #d22e8b; + --color-brown: #a47252; + --color-black: #1d2328; + /* light variants - produced via Sass scale-color(color, $lightness: +10%) */ + --color-red-light: #d15a5a; + --color-orange-light: #f6a066; + --color-yellow-light: #eaaf03; + --color-olive-light: #abc016; + --color-green-light: #93b373; + --color-teal-light: #00b6ad; + --color-blue-light: #4e96cc; + --color-violet-light: #9b79e4; + --color-purple-light: #ba6ad5; + --color-pink-light: #d74397; + --color-brown-light: #b08061; + --color-black-light: #424851; + /* dark 1 variants - produced via Sass scale-color(color, $lightness: -10%) */ + --color-red-dark-1: #c23636; + --color-orange-dark-1: #f38236; + --color-yellow-dark-1: #b88a03; + --color-olive-dark-1: #839311; + --color-green-dark-1: #7a9e55; + --color-teal-dark-1: #00837c; + --color-blue-dark-1: #347cb3; + --color-violet-dark-1: #7b4edb; + --color-purple-dark-1: #a742c9; + --color-pink-dark-1: #be297d; + --color-brown-dark-1: #94674a; + --color-black-dark-1: #292e38; + /* dark 2 variants - produced via Sass scale-color(color, $lightness: -20%) */ + --color-red-dark-2: #ad3030; + --color-orange-dark-2: #f16e17; + --color-yellow-dark-2: #a37a02; + --color-olive-dark-2: #74820f; + --color-green-dark-2: #6c8c4c; + --color-teal-dark-2: #00746e; + --color-blue-dark-2: #2e6e9f; + --color-violet-dark-2: #6733d6; + --color-purple-dark-2: #9834b9; + --color-pink-dark-2: #a9246f; + --color-brown-dark-2: #835b42; + --color-black-dark-2: #272930; + /* ansi colors used for actions console and console files */ + --color-ansi-black: #1e2327; + --color-ansi-red: #cc4848; + --color-ansi-green: #87ab63; + --color-ansi-yellow: #cc9903; + --color-ansi-blue: #3a8ac6; + --color-ansi-magenta: #d22e8b; + --color-ansi-cyan: #00918a; + --color-ansi-white: var(--color-console-fg-subtle); + --color-ansi-bright-black: #424851; + --color-ansi-bright-red: #d15a5a; + --color-ansi-bright-green: #93b373; + --color-ansi-bright-yellow: #eaaf03; + --color-ansi-bright-blue: #4e96cc; + --color-ansi-bright-magenta: #d74397; + --color-ansi-bright-cyan: #00b6ad; + --color-ansi-bright-white: var(--color-console-fg); + /* other colors */ + --color-grey: #384149; + --color-grey-light: #818f9e; + --color-gold: #b1983b; + --color-white: #ffffff; + --color-diff-added-linenum-bg: #274227; + --color-diff-added-row-bg: #203224; + --color-diff-added-row-border: #314a37; + --color-diff-added-word-bg: #3c653c; + --color-diff-moved-row-bg: #818044; + --color-diff-moved-row-border: #bcca6f; + --color-diff-removed-linenum-bg: #482121; + --color-diff-removed-row-bg: #301e1e; + --color-diff-removed-row-border: #634343; + --color-diff-removed-word-bg: #6f3333; + --color-diff-inactive: #22282d; + --color-error-border: #a04141; + --color-error-bg: #522; + --color-error-bg-active: #744; + --color-error-bg-hover: #633; + --color-error-text: #f9cbcb; + --color-success-border: #458a57; + --color-success-bg: #284034; + --color-success-text: #6cc664; + --color-warning-border: #bb9d00; + --color-warning-bg: #3a3a30; + --color-warning-text: #fbbd08; + --color-info-border: #306090; + --color-info-bg: #26354c; + --color-info-text: #38a8e8; + --color-red-badge: #db2828; + --color-red-badge-bg: #db28281a; + --color-red-badge-hover-bg: #db28284d; + --color-green-badge: #21ba45; + --color-green-badge-bg: #21ba451a; + --color-green-badge-hover-bg: #21ba454d; + --color-yellow-badge: #fbbd08; + --color-yellow-badge-bg: #fbbd081a; + --color-yellow-badge-hover-bg: #fbbd084d; + --color-orange-badge: #f2711c; + --color-orange-badge-bg: #f2711c1a; + --color-orange-badge-hover-bg: #f2711c4d; + --color-git: #f05133; + /* target-based colors */ + --color-body: #000000; + --color-box-header: #000000; + --color-box-body: #000000; + --color-box-body-highlight: #1b1f1a; + --color-text-dark: #54a13c; + --color-text: #54a13c; + --color-text-light: #54a13c; + --color-text-light-1: #417d2f; + --color-text-light-2: #457636; + --color-text-light-3: #234519; + --color-footer: #000000; + --color-timeline: #343c44; + --color-input-text: var(--color-text-dark); + --color-input-background: #000000; + --color-input-toggle-background: #11210c; + --color-input-border: var(--color-secondary); + --color-input-border-hover: var(--color-secondary-dark-1); + --color-light: #00001728; + --color-light-mimic-enabled: rgba(0, 0, 0, calc(40 / 255 * 222 / 255 / var(--opacity-disabled))); + --color-light-border: #e8f3ff28; + --color-hover: #13240e; + --color-active: #101f0c; + --color-menu: #000000; + --color-card: #000000; + --color-markup-table-row: #e8f3ff0f; + --color-markup-code-block: #e8f3ff12; + --color-markup-code-inline: #e8f3ff28; + --color-button: #171a1e; + --color-code-bg: #14171a; + --color-shadow: #00001758; + --color-secondary-bg: #000; + --color-expand-button: #2f363d; + --color-placeholder-text: var(--color-text-light-3); + --color-editor-line-highlight: var(--color-primary-light-5); + --color-project-board-bg: var(--color-secondary-light-2); + --color-caret: var(--color-text); /* should ideally be --color-text-dark, see #15651 */ + --color-reaction-bg: #e8f3ff12; + --color-reaction-hover-bg: var(--color-primary-light-4); + --color-reaction-active-bg: var(--color-primary-light-5); + --color-tooltip-text: #f9fafb; + --color-tooltip-bg: #000b17f0; + --color-nav-bg: #000000; + --color-nav-hover-bg: #0d160a; + --color-nav-text: #54a13c; + --color-secondary-nav-bg: #000000; + --color-label-text: var(--color-text); + --color-label-bg: #7282924b; + --color-label-hover-bg: #728292a0; + --color-label-active-bg: #728292ff; + --color-accent: var(--color-primary-light-1); + --color-small-accent: var(--color-primary-light-5); + --color-highlight-fg: #87651e; + --color-highlight-bg: #352c1c; + --color-overlay-backdrop: #080808c0; + accent-color: #54a13c; + color-scheme: dark; +} + + +.ui.input { + animation: glow 800ms ease-out infinite alternate; +} + +@keyframes glow { + 0% { + border-color: #393; + box-shadow: 0 0 5px rgba(0,255,0,.2), inset 0 0 5px rgba(0,255,0,.1), 0 2px 0 #000; + } + 100% { + border-color: #6f6; + box-shadow: 0 0 20px rgba(0,255,0,.6), inset 0 0 10px rgba(0,255,0,.4), 0 2px 0 #000; + } +} + + +.ui.primary.button { + background: #000000 +} + +.ui.ui.ui.ui.small.button { + background: #000000 +} + + +@keyframes bg-animation { + 0% { transform: translate(0,0) } + 10% { transform: translate(-5%,-5%) } + 20% { transform: translate(-10%,5%) } + 30% { transform: translate(5%,-10%) } + 40% { transform: translate(-5%,15%) } + 50% { transform: translate(-10%,5%) } + 60% { transform: translate(15%,0) } + 70% { transform: translate(0,10%) } + 80% { transform: translate(-15%,0) } + 90% { transform: translate(10%,5%) } + 100% { transform: translate(5%,0) } +} + +/* invert emojis that are hard to read otherwise */ +.emoji[aria-label="check mark"], +.emoji[aria-label="currency exchange"], +.emoji[aria-label="TOP arrow"], +.emoji[aria-label="END arrow"], +.emoji[aria-label="ON! arrow"], +.emoji[aria-label="SOON arrow"], +.emoji[aria-label="heavy dollar sign"], +.emoji[aria-label="copyright"], +.emoji[aria-label="registered"], +.emoji[aria-label="trade mark"], +.emoji[aria-label="multiply"], +.emoji[aria-label="plus"], +.emoji[aria-label="minus"], +.emoji[aria-label="divide"], +.emoji[aria-label="curly loop"], +.emoji[aria-label="double curly loop"], +.emoji[aria-label="wavy dash"], +.emoji[aria-label="paw prints"], +.emoji[aria-label="musical note"], +.emoji[aria-label="musical notes"] { + color: #54a13c; + /*filter: invert(100%) hue-rotate(180deg);*/ +} diff --git a/public/assets/scripts/haxxor.js b/public/assets/scripts/haxxor.js new file mode 100644 index 0000000..ba9fd53 --- /dev/null +++ b/public/assets/scripts/haxxor.js @@ -0,0 +1,507 @@ +// Stolen from https://codepen.io/loktar00/pen/BaGqXY +// However has modifications to work good as a theme + +"use strict"; +function createTetris() { + var tetrominos = [ + { + // box + colors: ["rgb(00, 00, 00)", "#47ba23", "rgb(00, 00, 00)"], + data: [ + [0, 0, 0, 0], + [0, 1, 1, 0], + [0, 1, 1, 0], + [0, 0, 0, 0], + ], + }, + { + // stick + colors: ["rgb(00, 00, 00)", "#47ba23", "rgb(00, 00, 00)"], + data: [ + [0, 0, 0, 0], + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + ], + }, + { + // z + colors: ["rgb(00, 00, 00)", "#47ba23", "rgb(00, 00, 00)"], + data: [ + [0, 0, 0, 0], + [0, 1, 1, 0], + [0, 0, 1, 1], + [0, 0, 0, 0], + ], + }, + { + // T + colors: ["rgb(00, 00, 00)", "#47ba23", "rgb(00, 00, 00)"], + data: [ + [0, 0, 0, 0], + [0, 1, 1, 1], + [0, 0, 1, 0], + [0, 0, 0, 0], + ], + }, + { + // s + colors: ["rgb(00, 00, 00)", "#47ba23", "rgb(00, 00, 00)"], + data: [ + [0, 0, 0, 0], + [0, 1, 1, 0], + [1, 1, 0, 0], + [0, 0, 0, 0], + ], + }, + { + // backwards L + colors: ["rgb(00, 00, 00)", "#47ba23", "rgb(00, 00, 00)"], + data: [ + [0, 0, 1, 0], + [0, 0, 1, 0], + [0, 1, 1, 0], + [0, 0, 0, 0], + ], + }, + { + // L + colors: ["rgb(00, 00, 00)", "#47ba23", "rgb(00, 00, 00)"], + data: [ + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 1, 0], + [0, 0, 0, 0], + ], + }, + ]; + + var Tetris = function (x, y, width, height) { + this.posX = x || 0; + this.posY = y || 0; + + this.width = width || window.innerWidth; + this.height = height || window.innerHeight; + + this.bgCanvas = document.createElement("canvas"); + this.fgCanvas = document.createElement("canvas"); + + this.bgCanvas.width = this.fgCanvas.width = this.width; + this.bgCanvas.height = this.fgCanvas.height = this.height; + + this.bgCtx = this.bgCanvas.getContext("2d"); + this.fgCtx = this.fgCanvas.getContext("2d"); + + this.bgCanvas.style.left = this.posX + "px"; + this.bgCanvas.style.top = this.posY + "px"; + + // Stay in background + this.bgCanvas.style.position = "absolute"; + this.fgCanvas.style.position = "absolute"; + + this.fgCanvas.style.left = this.posX + "px"; + this.fgCanvas.style.top = this.posY + "px"; + + document.body.insertBefore(this.fgCanvas, document.body.firstChild); + document.body.insertBefore(this.bgCanvas, document.body.firstChild); + this.init(); + }; + + Tetris.prototype.init = function () { + this.curPiece = { + data: null, + colors: [0, 0, 0], + x: 0, + y: 0, + }; + + this.lastMove = Date.now(); + this.curSpeed = 50 + Math.random() * 50; + this.unitSize = 20; + this.linesCleared = 0; + this.level = 0; + this.loseBlock = 0; + + // init the board + this.board = []; + this.boardWidth = Math.floor(this.width / this.unitSize); + this.boardHeight = Math.floor(this.height / this.unitSize); + + var board = this.board, + boardWidth = this.boardWidth, + boardHeight = this.boardHeight, + halfHeight = boardHeight / 2, + curPiece = this.curPiece, + x = 0, + y = 0; + + // init board + for (x = 0; x <= boardWidth; x++) { + board[x] = []; + for (y = 0; y <= boardHeight; y++) { + board[x][y] = { + data: 0, + colors: ["rgb(0,0,0)", "rgb(0,0,0)", "rgb(0,0,0)"], + }; + + if (Math.random() > 0.15 && y > halfHeight) { + board[x][y] = { + data: 1, + colors: + tetrominos[Math.floor(Math.random() * tetrominos.length)].colors, + }; + } + } + } + + // collapse the board a bit + for (x = 0; x <= boardWidth; x++) { + for (y = boardHeight - 1; y > -1; y--) { + if (board[x][y].data === 0 && y > 0) { + for (var yy = y; yy > 0; yy--) { + if (board[x][yy - 1].data) { + board[x][yy].data = 1; + board[x][yy].colors = board[x][yy - 1].colors; + + board[x][yy - 1].data = 0; + board[x][yy - 1].colors = [ + "rgb(0,0,0)", + "rgb(0,0,0)", + "rgb(0,0,0)", + ]; + } + } + } + } + } + + var self = this; + + window.addEventListener("keydown", function (e) { + switch (e.keyCode) { + case 37: + if (self.checkMovement(curPiece, -1, 0)) { + curPiece.x--; + } + break; + case 39: + if (self.checkMovement(curPiece, 1, 0)) { + curPiece.x++; + } + break; + case 40: + if (self.checkMovement(curPiece, 0, 1)) { + curPiece.y++; + } + break; + case 32: + case 38: + curPiece.data = self.rotateTetrimono(curPiece); + break; + } + }); + + // render the board + this.checkLines(); + this.renderBoard(); + + // assign the first tetri + this.newTetromino(); + this.update(); + }; + + Tetris.prototype.update = function () { + var curPiece = this.curPiece; + + if (!this.checkMovement(curPiece, 0, 1)) { + if (curPiece.y < -1) { + // you lose + this.loseScreen(); + return true; + } else { + this.fillBoard(curPiece); + this.newTetromino(); + } + } else { + if (Date.now() > this.lastMove) { + this.lastMove = Date.now() + this.curSpeed; + if (this.checkMovement(curPiece, 0, 1)) { + curPiece.y++; + } else { + this.fillBoard(curPiece); + this.newTetromino(); + } + } + } + + this.render(); + + var self = this; + requestAnimationFrame(function () { + self.update(); + }); + }; + + // render only the board. + Tetris.prototype.renderBoard = function () { + var canvas = this.bgCanvas, + ctx = this.bgCtx, + unitSize = this.unitSize, + board = this.board, + boardWidth = this.boardWidth, + boardHeight = this.boardHeight; + + ctx.clearRect(0, 0, canvas.width, canvas.height); + for (var x = 0; x <= boardWidth; x++) { + for (var y = 0; y <= boardHeight; y++) { + if (board[x][y].data !== 0) { + var bX = x * unitSize, + bY = y * unitSize; + //ctx.shadowBlur = 5; + //ctx.shadowColor = "rgba(0,255,0,.6)"; + ctx.fillStyle = board[x][y].colors[0]; + ctx.fillRect(bX, bY, unitSize, unitSize); + + ctx.fillStyle = board[x][y].colors[1]; + ctx.fillRect(bX + 2, bY + 2, unitSize - 4, unitSize - 4); + + ctx.fillStyle = board[x][y].colors[2]; + ctx.fillRect(bX + 4, bY + 4, unitSize - 8, unitSize - 8); + } + } + } + }; + + // Render the current active piece + Tetris.prototype.render = function () { + var canvas = this.fgCanvas, + ctx = this.fgCtx, + unitSize = this.unitSize, + curPiece = this.curPiece; + + ctx.clearRect(0, 0, canvas.width, canvas.height); + + for (var x = 0; x < 4; x++) { + for (var y = 0; y < 4; y++) { + if (curPiece.data[x][y] === 1) { + var xPos = (curPiece.x + x) * unitSize, + yPos = (curPiece.y + y) * unitSize; + + if (yPos > -1) { + ctx.shadowBlur = 10; + ctx.shadowColor = "rgba(0,255,0,.6)"; + ctx.fillStyle = curPiece.colors[0]; + ctx.fillRect(xPos, yPos, unitSize, unitSize); + + ctx.fillStyle = curPiece.colors[1]; + ctx.fillRect(xPos + 2, yPos + 2, unitSize - 4, unitSize - 4); + + ctx.fillStyle = curPiece.colors[2]; + ctx.fillRect(xPos + 4, yPos + 4, unitSize - 8, unitSize - 8); + } + } + } + } + }; + + // Make sure we can mov where we want. + Tetris.prototype.checkMovement = function (curPiece, newX, newY) { + var piece = curPiece.data, + posX = curPiece.x, + posY = curPiece.y, + board = this.board, + boardWidth = this.boardWidth, + boardHeight = this.boardHeight; + + for (var x = 0; x < 4; x++) { + for (var y = 0; y < 4; y++) { + if (piece[x][y] === 1) { + if (!board[posX + x + newX]) { + board[posX + x + newX] = []; + } + + if (!board[posX + x + newX][y + posY + newY]) { + board[posX + x + newX][y + posY + newY] = { + data: 0, + }; + } + + if ( + posX + x + newX >= boardWidth || + posX + x + newX < 0 || + board[posX + x + newX][y + posY + newY].data == 1 + ) { + return false; + } + + if (posY + y + newY > boardHeight) { + return false; + } + } + } + } + return true; + }; + + // checks for completed lines and clears them + Tetris.prototype.checkLines = function () { + var board = this.board, + boardWidth = this.boardWidth, + boardHeight = this.boardHeight, + linesCleared = this.linesCleared, + level = this.level, + y = boardHeight + 1; + + while (y--) { + var x = boardWidth, + lines = 0; + + while (x--) { + if (board[x][y].data === 1) { + lines++; + } + } + + if (lines === boardWidth) { + linesCleared++; + level = Math.round(linesCleared / 20) * 20; + + var lineY = y; + while (lineY) { + for (x = 0; x <= boardWidth; x++) { + if (lineY - 1 > 0) { + board[x][lineY].data = board[x][lineY - 1].data; + board[x][lineY].colors = board[x][lineY - 1].colors; + } + } + lineY--; + } + y++; + } + } + }; + + // Lose animation + Tetris.prototype.loseScreen = function () { + var ctx = this.bgCtx, + unitSize = this.unitSize, + boardWidth = this.boardWidth, + boardHeight = this.boardHeight, + y = boardHeight - this.loseBlock; + + for (var x = 0; x < boardWidth; x++) { + var bX = x * unitSize, + bY = y * unitSize; + + ctx.fillStyle = "rgb(0,0,0)"; + ctx.fillRect(bX, bY, unitSize, unitSize); + + ctx.fillStyle = "#54a13c"; + ctx.fillRect(bX + 2, bY + 2, unitSize - 4, unitSize - 4); + + ctx.fillStyle = "rgb(0,0,0)"; + ctx.fillRect(bX + 4, bY + 4, unitSize - 8, unitSize - 8); + } + + if (this.loseBlock <= boardHeight + 1) { + this.loseBlock++; + + var self = this; + requestAnimationFrame(function () { + self.loseScreen(); + }); + } else { + this.init(); + } + }; + + // adds the piece as part of the board + Tetris.prototype.fillBoard = function (curPiece) { + var piece = curPiece.data, + posX = curPiece.x, + posY = curPiece.y, + board = this.board; + + for (var x = 0; x < 4; x++) { + for (var y = 0; y < 4; y++) { + if (piece[x][y] === 1) { + board[x + posX][y + posY].data = 1; + board[x + posX][y + posY].colors = curPiece.colors; + } + } + } + + this.checkLines(); + this.renderBoard(); + }; + + // rotate a piece + Tetris.prototype.rotateTetrimono = function (curPiece) { + var rotated = []; + + for (var x = 0; x < 4; x++) { + rotated[x] = []; + for (var y = 0; y < 4; y++) { + rotated[x][y] = curPiece.data[3 - y][x]; + } + } + + if ( + !this.checkMovement( + { + data: rotated, + x: curPiece.x, + y: curPiece.y, + }, + 0, + 0 + ) + ) { + rotated = curPiece.data; + } + + return rotated; + }; + + // assign the player a new peice + Tetris.prototype.newTetromino = function () { + var pieceNum = Math.floor(Math.random() * tetrominos.length), + curPiece = this.curPiece; + + curPiece.data = tetrominos[pieceNum].data; + curPiece.colors = tetrominos[pieceNum].colors; + curPiece.x = Math.floor( + Math.random() * (this.boardWidth - curPiece.data.length + 1) + ); + curPiece.y = -4; + }; + + var width = window.innerWidth, + boardDiv = 20 * Math.round(window.innerWidth / 20), + boards = 8, + bWidth = boardDiv / boards, + tetrisInstances = []; + + for (var w = 0; w < boards; w++) { + tetrisInstances.push( + new Tetris(20 * Math.round((w * bWidth) / 20), 0, bWidth) + ); + } +} + + + +function main() { + if (!isActive()) { + return; + } + + createTetris(); +} + +function isActive() { + let style = getComputedStyle(document.body); + return style.getPropertyValue("--is-haxxorman") == "true" +} + +document.addEventListener("DOMContentLoaded", main); \ No newline at end of file diff --git a/public/assets/templates/custom/header.tmpl b/public/assets/templates/custom/header.tmpl new file mode 100644 index 0000000..429023c --- /dev/null +++ b/public/assets/templates/custom/header.tmpl @@ -0,0 +1 @@ + \ No newline at end of file