This commit is contained in:
biglyderv 2025-01-15 12:28:57 -05:00
commit 8c889222ce
10 changed files with 4525 additions and 0 deletions

291
static/gridwar.css Normal file
View file

@ -0,0 +1,291 @@
:root {
--dark-1: #2b2f36;
--dark-2: #d8d8d8;
--light-1: #ffffff;
--light-2: #f8f8f8;
--red-1: rgb(245, 108, 108);
--purple-1: rgb(187, 112, 236);
--blue-1: rgb(112, 169, 235);
--shadow-1: 0px 0px 2px 2px var(--dark-2);
--border-1: solid var(--dark-2) 5px;
font-family: 'Noto Sans';
}
body {
width: 100vw;
height: 100vh;
margin: 0;
padding: 0;
background: var(--light-1);
}
a {
color: var(--blue-1);
text-decoration: none;
}
input:not([type='file']):not([type='checkbox']),
textarea {
border: 0;
border: solid var(--dark-2) 2px;
border-radius: 5px;
font-size: 0.8rem;
padding: 0.5rem;
width: 200px;
margin: 10px;
}
#content {
height: 100vh;
width: 100vw;
overflow-y: auto;
padding-top: 0px;
}
.button {
min-width: 150px;
height: 30px;
background: var(--red-1);
color: var(--light-1);
font-weight: bold;
}
.button a {
color: white;
}
.area,
input:not([type='file']),
textarea {
border: var(--border-1);
}
textarea,
.button,
#content,
.wrapper,
.postie {
display: flex;
flex-direction: column;
}
input:not([type='file']),
.area {
display: inline-block;
}
.area,
input:not([type='file']),
textarea,
.button {
border-radius: 10px;
padding: 5px;
justify-content: center;
}
.header div {
padding: 10px;
}
#content,
.button {
text-align: center;
}
#content {
align-items: center;
}
.area {
width: 500px;
min-height: 175px;
}
.area,
.button,
.header {
margin: 5px;
}
.header.header-first>.post,
.header.header-last>.post {
width: min(500px, 90vw);
}
.header {
position: sticky;
font-weight: bold;
}
.header.header-first {
top: 0;
z-index: 10;
}
.header.header-last {
position: absolute;
bottom: 0;
z-index: 10;
}
.header .menu,
.dropdown {
border: none;
background: var(--blue-1);
display: flex;
align-items: center;
border-radius: 10px;
}
.header a {
color: var(--light-1);
height: 1.5em;
display: flex;
align-items: center;
justify-content: center;
}
.menu {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.header span {
color: var(--light-1);
}
.dropdown {
position: absolute;
margin-top: 3em;
margin-left: 0px;
background: var(--purple-1);
color: inherit;
width: 10em;
text-align: center;
justify-content: center;
opacity: 0;
font-size: 0.8em;
height: 0.8em;
transition: 0.3s ease-in-out opacity;
}
a:hover>.dropdown {
opacity: 1;
}
.icon {
width: 2em;
max-height: 2em;
margin: 0.2em;
}
#post-area {
width: 500px;
min-height: 200px;
display: block;
resize: none;
}
.left {
text-align: left;
}
.hwrap,
.area.postie {
display: flex;
justify-content: space-between;
}
.hwrap>span {
display: flex;
align-items: center;
}
form {
text-align: left;
}
.pfp {
background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0.7)), var(--img) center / cover
}
#grid {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
svg text, .header-first, .header-last {
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
z-index: 1;
}
svg text {
opacity: 0.75;
}
.info {
top: 15px;
left: 15px;
font-weight: bold;
position: absolute;
z-index: 100;
user-select: none;
}
.info2 {
top: 15px;
right: 15px;
font-weight: bold;
position: absolute;
z-index: 100;
user-select: none;
}
svg text {
pointer-events: none;
}
input:not([type='file']):not([type='checkbox'])[type='color'] {
width: 50px;
height: 50px;
}
.postie .icon {
border-radius: 100%;
height: 2em;
object-fit: cover;
}
#content > p {
max-width: 600px;
}

292
static/gridwar.js Normal file
View file

@ -0,0 +1,292 @@
let area = document.querySelector('#grid');
let group = document.querySelector('#group');
let mpos = [0, 0];
let translate = "";
let width = 0;
let height = 0;
let center = [0, 0];
let lastPos = [0, 0];
let isMouse = false;
let zoom = 0.8;
genTrans();
function mouseMove(e) {
lastPos = [e.clientX, e.clientY];
if (!isMouse) return;
mpos[0] += e.clientX - center[0];
mpos[1] += e.clientY - center[1];
center = lastPos;
genTrans();
}
function mouseUp(e) {
isMouse = false;
}
function mouseDown(e) {
isMouse = true;
center = [e.clientX, e.clientY];
}
function wheel(e) {
mpos[0] -= lastPos[0];
mpos[1] -= lastPos[1];
mpos[0] *= 1.005 ** -e.deltaY;
mpos[1] *= 1.005 ** -e.deltaY;
mpos[0] += lastPos[0];
mpos[1] += lastPos[1];
zoom *= 1.005 ** -e.deltaY;
genTrans();
}
function genTrans() {
group.setAttribute('transform', `translate(${mpos[0]},${mpos[1]}), scale(${zoom},${zoom})`);
}
window.onwheel = wheel;
window.onmousemove = mouseMove;
window.onmouseup = mouseUp;
window.onmousedown = mouseDown;
window.ondblclick = doubleClick;
let tiles = {};
let colors = {
'!nobody': 'rgb(255,255,255)'
};
let amounts = {
'!nobody': -1
};
let areas = {};
function doubleClick(e) {
let data = e.target.id.split('|').pop();
data = data.split('_');
if (e.target.id.startsWith('grid-claimed')) {
socket.emit('conquer', { x: data[0], y: data[1] })
} else if (e.target.id.startsWith('grid-select')) {
socket.emit('claim', { x: data[0], y: data[1] })
}
}
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
function renderRect(x, y, h, w) {
let elem = document.createElementNS("http://www.w3.org/2000/svg", 'rect');
elem.setAttribute('x', x);
elem.setAttribute('y', y);
elem.setAttribute('width', w);
elem.setAttribute('height', h);
elem.setAttribute('fill', 'white');
elem.setAttribute('stroke', 'black');
elem.setAttribute('stroke-width', '3.5');
group.appendChild(elem);
return elem;
}
function renderSelect(key, val) {
let elem = renderRect(key[0] * 125, key[1] * 125, 125, 125);
elem.id = `grid-select|${key[0]}_${key[1]}`;
}
function renderClaimed(key, val, data2) {
for (let i in val.data) {
if (i.startsWith('_')) continue;
let space = val.data[i];
let innerGroup = (space != '!nobody') ? document.querySelector(`g#${space}`) : false;
let userData = data2[`_user_${space}`];
colors[space] = userData ? userData.color : colors[space];
if (space == '!nobody') {
colors[space] = 'rgb(255,255,255)';
}
if (!colors[space]) {
colors[space] = `hsl(${Math.random() * 360}deg,${Math.random() * 30 + 65}%,${Math.random() * 30 + 60}%)`
}
if (!amounts[space]) {
amounts[space] = 0;
areas[space] = [];
}
let x = i % 5;
let y = Math.floor(i / 5);
if (areas[space]) {
let x2 = key[0] * 125 + x * 25;
let y2 = key[1] * 125 + y * 25;
let filter = areas[space].filter((a) => {
return a.findIndex(([x, y]) => Math.abs(x2 - x) + Math.abs(y2 - y) < 2 * 25) != -1
});
let noFilter = areas[space].filter((a) => {
return a.findIndex(([x, y]) => Math.abs(x2 - x) + Math.abs(y2 - y) < 2 * 25) == -1
});
areas[space] = [];
areas[space].push(...noFilter);
filter = [filter.flat(1)];
areas[space].push(...(filter));
if (filter.length == 0) {
areas[space].push([[x2, y2]]);
} else {
areas[space][areas[space].length - 1].push([x2, y2]);
}
}
amounts[space]++;
if (!innerGroup && space != '!nobody') {
let elem = document.createElementNS("http://www.w3.org/2000/svg", 'g');
elem.id = space;
group.appendChild(elem);
innerGroup = elem;
}
let elem = renderRect(key[0] * 125 + x * 25, key[1] * 125 + y * 25, 25, 25);
if (innerGroup) innerGroup.appendChild(elem);
elem.setAttribute('fill', colors[space]);
elem.id = `grid-claimed|${key[0] * 5 + x}_${key[1] * 5 + y}`;
}
}
let biggestBox = (thing) => {
let xVal = thing.map(x => Math.min(...x.map(y => y[0])));
let yVal = thing.map(x => Math.min(...x.map(y => y[1])));
let wVal = thing.map(x => Math.max(...x.map(y => y[0])) - Math.min(...x.map(y => y[0])));
let hVal = thing.map(x => Math.max(...x.map(y => y[1])) - Math.min(...x.map(y => y[1])));
let sVal = thing.map(x => (Math.max(...x.map(y => y[0])) - Math.min(...x.map(y => y[0]))) * ((Math.max(...x.map(y => y[1])) - Math.min(...x.map(y => y[1])))));
let i = sVal.indexOf(Math.max(...sVal));
return {
x: xVal[i],
y: yVal[i],
width: wVal[i] + 25,
height: hVal[i] + 25
}
}
const socket = io(host);
socket.emit('area', { area: 'grid' });
var token = getCookie('token');
var noauth = false;
setTimeout(() => {
if (!token) window.location.href = 'https://nbg.dervland.net/login.php?next=' + encodeURIComponent(window.location.href);
if (token && window.location.search != '') window.location.href = '/';
socket.emit('join', { token });
}, 800);
socket.on('data', (data) => {
if (data == 'noauth') {
noauth = true;
}
group.innerHTML = '';
for (let key in data) {
let val = data[key];
let keyDecomp = key.split(',');
if (val.type == 'select') {
renderSelect(keyDecomp, val);
} else if (val.type == 'claimed') {
renderClaimed(keyDecomp, val, data);
}
}
let groups = document.querySelectorAll(`g g`);
for (let group of groups) {
let box = biggestBox(areas[group.id])
let id = group.id;
let elem = document.createElementNS("http://www.w3.org/2000/svg", 'text');
elem.setAttribute("x", box.x + box.width / 2);
elem.setAttribute("y", box.y + box.height / 2 - box.width / 4);
elem.setAttribute("font-size", box.width / 8 + "px");
elem.setAttribute("stroke", "white");
elem.setAttribute("stroke-width", box.width / 35)
elem.setAttribute("paint-order", "stroke")
elem.setAttribute('text-anchor', 'middle')
let lines = [id, amounts[id]];
for (let line of lines) {
let tspan = document.createElementNS("http://www.w3.org/2000/svg", 'tspan');
tspan.textContent = line;
tspan.setAttribute('x', box.x + box.width / 2);
tspan.setAttribute('dy', box.width / 6);
elem.appendChild(tspan);
}
document.querySelector('svg > g').appendChild(elem);
amounts[id] = 0;
}
})
let cooldown = 0;
let lastTurn = 'nobody';
socket.on('cooldown', (cooldownIn) => {
cooldown = cooldownIn;
})
socket.on('turn', (cooldownIn) => {
lastTurn = cooldownIn;
})
setInterval(() => {
let distance = new Date(cooldown) - new Date();
if (distance < 0) {
document.querySelector('.info').textContent = `The next turn is now, last turn was by ${lastTurn || 'nobody'}`;
} else {
document.querySelector('.info').textContent = `The next turn is in ${Math.floor(distance / 1000)} seconds, last turn was by ${lastTurn || 'nobody'}`;
}
}, 100);
document.querySelector('#color').onchange = (e) => {
socket.emit('color', e.target.value)
}

31
static/index.html Normal file
View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" href="/img/icon.svg" />
<link href='/gridwar.css' rel='stylesheet'>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet">
</head>
<body>
<span class='info'>
Your cooldown
</span>
<span class='info2'>
<div>Your grid color</div>
<input type="color" id="color" value="#e66465">
</span>
<svg id="grid">
<g transform="" id='group'>
</g>
</svg>
<script>
let host = '/';
</script>
<script src="./socket.io/socket.io.js"></script>
<script src='/gridwar.js'></script>
</body>