130 lines
5.3 KiB
JavaScript
130 lines
5.3 KiB
JavaScript
const WebSocket = require('ws');
|
|
const pokemon = require('pokemon')
|
|
const pokeTypes = require('./poketypes.json')
|
|
|
|
const wss = new WebSocket.Server({
|
|
port: 5000
|
|
})
|
|
|
|
function flatten(obj) {
|
|
if(obj !== null && obj !== undefined) {
|
|
let ret = {};
|
|
for (let i in obj) {
|
|
ret[i] = obj[i];
|
|
}
|
|
return ret;
|
|
} else {
|
|
return obj
|
|
}
|
|
}
|
|
|
|
function badObjectCopy(values, object) {
|
|
if(values !== undefined && object !== undefined && values !== null && object !== null) {
|
|
for(let i in values) {
|
|
if(typeof values[i] === "object") {
|
|
badObjectCopy(values[i], object[i])
|
|
} else {
|
|
object[i] = values[i]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function flattenObject(obj) {
|
|
return Object.fromEntries(Object.entries(obj).map(([key, val]) => [key, flatten(val)]))
|
|
}
|
|
|
|
wss.on('connection', ws => {
|
|
try {
|
|
const timeStarted = new Date();
|
|
|
|
const Pokemon = {}
|
|
|
|
const types = {
|
|
grass: {type: 'grass' , __proto__: Pokemon},
|
|
fire: {type: 'fire' , __proto__: Pokemon},
|
|
water: {type: 'water' , __proto__: Pokemon},
|
|
poison: {type: 'poison' , __proto__: Pokemon},
|
|
flying: {type: 'flying' , __proto__: Pokemon},
|
|
bug: {type: 'bug' , __proto__: Pokemon},
|
|
normal: {type: 'normal' , __proto__: Pokemon},
|
|
electric: {type: 'electric', __proto__: Pokemon},
|
|
ground: {type: 'ground' , __proto__: Pokemon},
|
|
fairy: {type: 'fairy' , __proto__: Pokemon},
|
|
fighting: {type: 'fighting', __proto__: Pokemon},
|
|
psychic: {type: 'psychic' , __proto__: Pokemon},
|
|
rock: {type: 'rock' , __proto__: Pokemon},
|
|
steel: {type: 'steel' , __proto__: Pokemon},
|
|
ice: {type: 'ice' , __proto__: Pokemon},
|
|
ghost: {type: 'ghost' , __proto__: Pokemon},
|
|
dragon: {type: 'dragon' , __proto__: Pokemon}
|
|
}
|
|
|
|
const pokedex = Object.fromEntries(pokemon.all().slice(0, 151).map(poke => {
|
|
const type = types[pokeTypes[poke]]
|
|
return [poke, {__proto__: type}]
|
|
}))
|
|
|
|
const send = async(msg, data) => await ws.send(JSON.stringify({msg, data}))
|
|
|
|
const checkIfAllCaptured = async () => {
|
|
if(Object.values(pokedex).every(poke => poke["captured"])) {
|
|
const diff = new Date() - timeStarted;
|
|
if(diff < 60000) {
|
|
send("pokedexCompleted", {
|
|
msg: "I can't believe you beat my near impossible 60 second speedrun! It's impossible! I am the best trainer to have ever lived! Urgh... I guess I don't have a choice but to give you this item...\n\n*You obtained the key IGCTF{MissingNo}!*\n\nHave fun with it... I guess.\n\n-Gary"
|
|
})
|
|
} else {
|
|
send("pokedexCompleted", {
|
|
msg: "Hah, you did good, but not nearly as good as I did. You still got a long way to beat my 1 minute run, loser.\n\n-Gary"
|
|
})
|
|
}
|
|
ws.close()
|
|
}
|
|
}
|
|
|
|
let messagesReceived = 0;
|
|
let timeOfLastMessage = 0;
|
|
let poisonMessageSent = false;
|
|
ws.on('message', evt => {
|
|
messagesReceived++;
|
|
const currentTime = new Date()
|
|
console.log(currentTime - timeOfLastMessage)
|
|
if(currentTime - timeOfLastMessage < 500) {
|
|
send("error", {msg: "You are sending messages too fast to the backend. Please slow down."})
|
|
timeOfLastMessage = currentTime
|
|
return
|
|
} else {
|
|
timeOfLastMessage = currentTime
|
|
}
|
|
const {msg, data} = JSON.parse(evt)
|
|
switch (msg) {
|
|
case "initializePokedex": send('pokedexInitialized', flattenObject(pokedex)); break;
|
|
case "updatePokedex": {
|
|
const {pokemon, values} = data;
|
|
|
|
if(pokemon !== '__proto__') {
|
|
if(pokeTypes[pokemon] === 'poison') {
|
|
badObjectCopy(values, pokedex[pokemon].__proto__);
|
|
if(!poisonMessageSent) {
|
|
send("error", {msg: "Dear Pokémon trainer,\n\n There seems to be a bug when adding a Poison type Pokémon: it automatically registers all Poison type Pokémon in the Pokédex as captured! Somehow the poison seems to affect the shared prototype...\n\nYours truly,\nProfessor Oak"})
|
|
poisonMessageSent = true
|
|
}
|
|
} else {
|
|
badObjectCopy(values, pokedex[pokemon]);
|
|
}
|
|
} else {
|
|
send("error", {msg: "I read somewhere that letting the client change the __proto__ property isn't such a good idea, so I'll just add this check here. I sure hope that I didn't forget to check this anywhere else... \n\n -Professor Oak"})
|
|
}
|
|
|
|
send('pokedexUpdated', flattenObject(pokedex))
|
|
checkIfAllCaptured()
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
} catch(e) {
|
|
console.error(e)
|
|
}
|
|
})
|