export and load maps

This commit is contained in:
Freya Murphy 2023-06-17 22:48:56 -04:00
parent fa2d9b6f91
commit 97c78292fe
12 changed files with 672 additions and 109 deletions

View file

@ -7,15 +7,43 @@ canvas {
position: absolute; position: absolute;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border: 1px solid; border: 1px solid #fff;
padding: 1rem; padding: 1rem;
} }
#mapgen { #mapgen {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: absolute;
} }
#export { #export {
margin-top: 1rem; margin-top: 1rem;
} }
#popup {
background-color: #191919;
position: absolute;
flex-direction: column;
padding: .5rem;
border: 1px solid #fff;
}
#popup textarea {
margin: .5rem 0;
height: 5rem;
background-color: transparent;
color: white;
border: 1px solid #fff;
}
#popup input {
margin: 0;
}
#close {
width: .3rem;
height: .3rem;
font-size: .6rem;
line-height: 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View file

@ -2,7 +2,6 @@
<html> <html>
<head> <head>
<link rel="stylesheet" href="css/main.css"/> <link rel="stylesheet" href="css/main.css"/>
<script>var exports = {};</script>
</head> </head>
<body> <body>
<img src="img/atlas.png" id="atlas" style="display: none;"/> <img src="img/atlas.png" id="atlas" style="display: none;"/>

View file

@ -15,10 +15,16 @@
<input type="text" id="height" name="height" placeholder="Map Height"> <input type="text" id="height" name="height" placeholder="Map Height">
<input type="submit" value="Create"/> <input type="submit" value="Create"/>
</form> </form>
<div id="popup" style="display: none">
<input type="button" id="close" value="x" onclick="document.getElementById('popup').style.display = 'none'">
<textarea id="textarea" disabled='true'></textarea>
<input type="button" id="copy" value="Copy to clipboard">
</div>
</div> </div>
<div id="sidebar" style="display: none;"> <div id="sidebar" style="display: none;">
<p>W: Place Wall</p> <p>W: Place Wall</p>
<p>G: Place Ghost Wall</p> <p>G: Place Ghost Wall</p>
<p>H: Place Ghost Spawn</p>
<p>F: Place Food</p> <p>F: Place Food</p>
<p>1: Place Pac Spawn 1</p> <p>1: Place Pac Spawn 1</p>
<p>2: Place Pac Spawn 2</p> <p>2: Place Pac Spawn 2</p>

View file

@ -1,11 +1,11 @@
import { genMap } from "./map.js" import { genMap, compressMap, decompressMap } from "./map.js"
import { startGraphicsUpdater } from "./renderer.js" import { startGraphicsUpdater } from "./renderer.js"
import { GameState, Vec2, Tile } from "./types.js" import { GameState, Vec2, Tile } from "./types.js"
const mapgen = document.getElementById("mapgen") const mapgen = document.getElementById("mapgen")
const sidebar = document.getElementById("sidebar") const sidebar = document.getElementById("sidebar")
mapgen.onsubmit = async function(event) { mapgen.onsubmit = async (event) => {
event.preventDefault() event.preventDefault()
const width_str = (<HTMLInputElement>document.getElementById("width")).value const width_str = (<HTMLInputElement>document.getElementById("width")).value
@ -86,31 +86,33 @@ const getTilePos = (width: number, height: number, mousePos: Vec2): Vec2 => {
} }
const checkInputs = (pressed: {[key: string]: boolean}): Tile => { const checkInputs = (pressed: {[key: string]: boolean}): [Tile, boolean] => {
if (pressed["KeyW"]) { if (pressed["KeyW"]) {
return Tile.WALL return [Tile.WALL, false]
} else if (pressed["KeyG"]) { } else if (pressed["KeyG"]) {
return Tile.GHOST_WALL return [Tile.GHOST_WALL, false]
} else if (pressed["KeyH"]) {
return [Tile.GHOST_SPAWN, true]
} else if (pressed["KeyF"]) { } else if (pressed["KeyF"]) {
return Tile.FOOD return [Tile.FOOD, false]
} else if (pressed["Digit1"]) { } else if (pressed["Digit1"]) {
return Tile.PLAYER_SPAWN_1 return [Tile.PLAYER_SPAWN_1, true]
} else if (pressed["Digit2"]) { } else if (pressed["Digit2"]) {
return Tile.PLAYER_SPAWN_2 return [Tile.PLAYER_SPAWN_2, true]
} else if (pressed["Digit3"]) { } else if (pressed["Digit3"]) {
return Tile.PLAYER_SPAWN_3 return [Tile.PLAYER_SPAWN_3, true]
} else if (pressed["Digit4"]) { } else if (pressed["Digit4"]) {
return Tile.PLAYER_SPAWN_4 return [Tile.PLAYER_SPAWN_4, true]
} else if (pressed["KeyT"]) { } else if (pressed["KeyT"]) {
return Tile.THICC_DOT return [Tile.THICC_DOT, false]
} else if (pressed["KeyI"]) { } else if (pressed["KeyI"]) {
return Tile.INITIAL_DOT return [Tile.INITIAL_DOT, false]
} else if (pressed["KeyC"]) { } else if (pressed["KeyC"]) {
return Tile.EMPTY return [Tile.EMPTY, false]
} }
return undefined return [undefined, undefined]
} }
const checkBounds = (tilePos: Vec2, width: number, height: number) => { const checkBounds = (tilePos: Vec2, width: number, height: number) => {
@ -124,7 +126,7 @@ const runMapEditor = (width: number, height: number) => {
let data: number[] = new Array(width * height).fill(0) let data: number[] = new Array(width * height).fill(0)
genMap(width, height, data, Tile.EMPTY) let map = genMap(width, height, data, Tile.EMPTY)
let state: GameState = { let state: GameState = {
started: true, started: true,
@ -145,13 +147,19 @@ const runMapEditor = (width: number, height: number) => {
const tilePos = getTilePos(width, height, mousePos) const tilePos = getTilePos(width, height, mousePos)
const pressed = getInput() const pressed = getInput()
const tile = checkInputs(pressed) const [tile, unique] = checkInputs(pressed)
if (tile !== undefined && checkBounds(tilePos, width, height)) { if (tile !== undefined && checkBounds(tilePos, width, height)) {
let current = data[tilePos.y * width + tilePos.x]; let current = data[tilePos.y * width + tilePos.x];
if (current != tile) { if (current != tile && (current == Tile.EMPTY || tile == Tile.EMPTY)) {
if (unique) {
data = data.map(t => {
if (t == tile) return Tile.EMPTY
else return t
})
}
data[tilePos.y * width + tilePos.x] = tile data[tilePos.y * width + tilePos.x] = tile
genMap(width, height, data, 0) map = genMap(width, height, data, 0)
} }
} }
@ -162,4 +170,16 @@ const runMapEditor = (width: number, height: number) => {
requestAnimationFrame(loop) requestAnimationFrame(loop)
document.getElementById("export").onclick = () => {
let encoded = compressMap(map)
document.getElementById("textarea").textContent = encoded
document.getElementById("popup").style.display = 'flex'
console.log(decompressMap(encoded))
}
document.getElementById("copy").onclick = () => {
navigator.clipboard.writeText(document.getElementById("textarea").textContent)
}
} }

505
client/src/lib/lz-string.ts Normal file
View file

@ -0,0 +1,505 @@
export namespace LZString {
// private property
var f = String.fromCharCode;
var keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$";
var baseReverseDic = {};
function getBaseValue(alphabet: any, character: any) {
if (!baseReverseDic[alphabet]) {
baseReverseDic[alphabet] = {};
for (var i = 0; i < alphabet.length; i++) {
baseReverseDic[alphabet][alphabet.charAt(i)] = i;
}
}
return baseReverseDic[alphabet][character];
}
export function compressToBase64(input:string) {
if (input == null) return "";
var res = _compress(input, 6, function (a: any) {
return keyStrBase64.charAt(a);
});
switch (res.length % 4) { // To produce valid Base64
default: // When could this happen ?
case 0:
return res;
case 1:
return res + "===";
case 2:
return res + "==";
case 3:
return res + "=";
}
}
export function decompressFromBase64(input:string) {
if (input == null) return "";
if (input == "") return null;
return _decompress(input.length, 32, function (index: any) {
return getBaseValue(keyStrBase64, input.charAt(index));
});
}
export function compressToUTF16(input:string) {
if (input == null) return "";
return _compress(input, 15, function (a: any) {
return f(a + 32);
}) + " ";
}
export function decompressFromUTF16(compressed:string) {
if (compressed == null) return "";
if (compressed == "") return null;
return _decompress(compressed.length, 16384, function (index: any) {
return compressed.charCodeAt(index) - 32;
});
}
//compress into uint8array (UCS-2 big endian format)
export function compressToUint8Array(uncompressed:string) {
var compressed = compress(uncompressed);
var buf = new Uint8Array(compressed.length * 2); // 2 bytes per character
for (var i = 0, TotalLen = compressed.length; i < TotalLen; i++) {
var current_value = compressed.charCodeAt(i);
buf[i * 2] = current_value >>> 8;
buf[i * 2 + 1] = current_value % 256;
}
return buf;
}
//decompress from uint8array (UCS-2 big endian format)
export function decompressFromUint8Array(compressed: any) {
if (compressed === null || compressed === undefined) {
return decompress(compressed);
} else {
var buf = new Array(compressed.length / 2); // 2 bytes per character
for (var i = 0, TotalLen = buf.length; i < TotalLen; i++) {
buf[i] = compressed[i * 2] * 256 + compressed[i * 2 + 1];
}
var result = [];
buf.forEach(function (c) {
result.push(f(c));
});
return decompress(result.join(''));
}
}
//compress into a string that is already URI encoded
export function compressToEncodedURIComponent(input:string) {
if (input == null) return "";
return _compress(input, 6, function (a: any) {
return keyStrUriSafe.charAt(a);
});
}
//decompress from an output of compressToEncodedURIComponent
export function decompressFromEncodedURIComponent(input:string) {
if (input == null) return "";
if (input == "") return null;
input = input.replace(/ /g, "+");
return _decompress(input.length, 32, function (index: any) {
return getBaseValue(keyStrUriSafe, input.charAt(index));
});
}
export function compress(uncompressed:string) {
return _compress(uncompressed, 16, function (a: any) {
return f(a);
});
}
function _compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any) {
if (uncompressed == null) return "";
var i: any, value: any,
context_dictionary = {},
context_dictionaryToCreate = {},
context_c = "",
context_wc = "",
context_w = "",
context_enlargeIn = 2, // Compensate for the first entry which should not count
context_dictSize = 3,
context_numBits = 2,
context_data = [],
context_data_val = 0,
context_data_position = 0,
ii: any;
for (ii = 0; ii < uncompressed.length; ii += 1) {
context_c = uncompressed.charAt(ii);
if (!Object.prototype.hasOwnProperty.call(context_dictionary, context_c)) {
context_dictionary[context_c] = context_dictSize++;
context_dictionaryToCreate[context_c] = true;
}
context_wc = context_w + context_c;
if (Object.prototype.hasOwnProperty.call(context_dictionary, context_wc)) {
context_w = context_wc;
} else {
if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
if (context_w.charCodeAt(0) < 256) {
for (i = 0; i < context_numBits; i++) {
context_data_val = (context_data_val << 1);
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
}
value = context_w.charCodeAt(0);
for (i = 0; i < 8; i++) {
context_data_val = (context_data_val << 1) | (value & 1);
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
} else {
value = 1;
for (i = 0; i < context_numBits; i++) {
context_data_val = (context_data_val << 1) | value;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = 0;
}
value = context_w.charCodeAt(0);
for (i = 0; i < 16; i++) {
context_data_val = (context_data_val << 1) | (value & 1);
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
}
context_enlargeIn--;
if (context_enlargeIn == 0) {
context_enlargeIn = Math.pow(2, context_numBits);
context_numBits++;
}
delete context_dictionaryToCreate[context_w];
} else {
value = context_dictionary[context_w];
for (i = 0; i < context_numBits; i++) {
context_data_val = (context_data_val << 1) | (value & 1);
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
}
context_enlargeIn--;
if (context_enlargeIn == 0) {
context_enlargeIn = Math.pow(2, context_numBits);
context_numBits++;
}
// Add wc to the dictionary.
context_dictionary[context_wc] = context_dictSize++;
context_w = String(context_c);
}
}
// Output the code for w.
if (context_w !== "") {
if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
if (context_w.charCodeAt(0) < 256) {
for (i = 0; i < context_numBits; i++) {
context_data_val = (context_data_val << 1);
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
}
value = context_w.charCodeAt(0);
for (i = 0; i < 8; i++) {
context_data_val = (context_data_val << 1) | (value & 1);
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
} else {
value = 1;
for (i = 0; i < context_numBits; i++) {
context_data_val = (context_data_val << 1) | value;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = 0;
}
value = context_w.charCodeAt(0);
for (i = 0; i < 16; i++) {
context_data_val = (context_data_val << 1) | (value & 1);
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
}
context_enlargeIn--;
if (context_enlargeIn == 0) {
context_enlargeIn = Math.pow(2, context_numBits);
context_numBits++;
}
delete context_dictionaryToCreate[context_w];
} else {
value = context_dictionary[context_w];
for (i = 0; i < context_numBits; i++) {
context_data_val = (context_data_val << 1) | (value & 1);
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
}
context_enlargeIn--;
if (context_enlargeIn == 0) {
context_enlargeIn = Math.pow(2, context_numBits);
context_numBits++;
}
}
// Mark the end of the stream
value = 2;
for (i = 0; i < context_numBits; i++) {
context_data_val = (context_data_val << 1) | (value & 1);
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
// Flush the last char
while (true) {
context_data_val = (context_data_val << 1);
if (context_data_position == bitsPerChar - 1) {
context_data.push(getCharFromInt(context_data_val));
break;
} else context_data_position++;
}
return context_data.join('');
}
export function decompress(compressed:string) {
if (compressed == null) return "";
if (compressed == "") return null;
return _decompress(compressed.length, 32768, function (index: any) {
return compressed.charCodeAt(index);
});
}
function _decompress(length: any, resetValue: any, getNextValue: any) {
var dictionary = [],
next: any,
enlargeIn = 4,
dictSize = 4,
numBits = 3,
entry = "",
result = [],
i: any,
w: any,
bits: any, resb: any, maxpower: any, power: any,
c: any,
data = {
val: getNextValue(0),
position: resetValue,
index: 1
};
for (i = 0; i < 3; i += 1) {
dictionary[i] = i;
}
bits = 0;
maxpower = Math.pow(2, 2);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
switch (next = bits) {
case 0:
bits = 0;
maxpower = Math.pow(2, 8);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
c = f(bits);
break;
case 1:
bits = 0;
maxpower = Math.pow(2, 16);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
c = f(bits);
break;
case 2:
return "";
}
dictionary[3] = c;
w = c;
result.push(c);
while (true) {
if (data.index > length) {
return "";
}
bits = 0;
maxpower = Math.pow(2, numBits);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
switch (c = bits) {
case 0:
bits = 0;
maxpower = Math.pow(2, 8);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
dictionary[dictSize++] = f(bits);
c = dictSize - 1;
enlargeIn--;
break;
case 1:
bits = 0;
maxpower = Math.pow(2, 16);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
dictionary[dictSize++] = f(bits);
c = dictSize - 1;
enlargeIn--;
break;
case 2:
return result.join('');
}
if (enlargeIn == 0) {
enlargeIn = Math.pow(2, numBits);
numBits++;
}
if (dictionary[c]) {
entry = dictionary[c];
} else {
if (c === dictSize) {
entry = w + w.charAt(0);
} else {
return null;
}
}
result.push(entry);
// Add w+entry[0] to the dictionary.
dictionary[dictSize++] = w + entry.charAt(0);
enlargeIn--;
w = entry;
if (enlargeIn == 0) {
enlargeIn = Math.pow(2, numBits);
numBits++;
}
}
}
};

View file

@ -1,10 +1,13 @@
import { genItems, loadMap, getMap } from "../map.js"; import { genItems, genMap, getMap, decompressMap } from "../map.js";
import { updatePlayers } from "./players.js" import { updatePlayers } from "./players.js"
import { updateUI } from "./ui.js" import { updateUI } from "./ui.js"
import { updateMovement } from "./movement.js" import { updateMovement } from "./movement.js"
import { updateItems } from "./items.js" import { updateItems } from "./items.js"
import { GameState, Input } from "../types.js"; import { GameState, Input } from "../types.js";
const maps = {
[0]: 'EwRgPqYgNDew+TEuW6AGT2u59mPI/PeLZclSys1AhSgThJcJb2bdq7p5rupV2DYaVFCKI9HwFDiWACyxyK5WpCqArOPSCeuqfUnzDwaGbMyT3FAGZT0ABznD9ybWv0LLq61kz4S0M9WRMANnVVDUi1AHYdQxt+dyNEhJNiNk8A3npkiVSmcUEM6E5C/wL86rlivLqxaVymltggA='
}
export const InitialState: GameState = { export const InitialState: GameState = {
started: false, started: false,
@ -32,7 +35,7 @@ export const onLogic = (
} }
if (startPressed && !data.started) { if (startPressed && !data.started) {
initMap(data) initMap(data, 0)
data.started = true; data.started = true;
} }
@ -40,41 +43,16 @@ export const onLogic = (
} }
const initMap = (data: GameState) => { const initMap = (gameData: GameState, mapId: number) => {
document.getElementById("lobby").style.display = "none" gameData.mapId = mapId
data.mapId = 0 let map = getMap(mapId)
if (!map) {
if (getMap(0)) return let {width, height, data} = decompressMap(maps[mapId])
map = genMap(width, height, data, mapId)
let width = 21 }
let height = 21
let m_data = [ gameData.items = genItems(map)
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,
1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,
1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,
1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,
1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,
1,0,0,0,0,0,1,0,1,2,2,2,1,0,1,0,0,0,0,0,1,
1,0,1,1,1,0,1,0,1,2,2,2,1,0,1,0,1,1,1,0,1,
1,0,0,0,0,0,1,0,1,2,2,2,1,0,1,0,0,0,0,0,1,
1,1,1,0,1,0,1,0,1,1,2,1,1,0,1,0,1,0,1,1,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,
1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,
1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,
1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,
1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,
1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
]
loadMap(width, height, m_data) // cursed temp thing
data.items = genItems(getMap(0))
} }

View file

@ -1,7 +1,7 @@
import { Game } from "./net/game.js"; import { Game } from "./net/game.js";
import { InitialState, onLogic } from "./logic/logic.js"; import { InitialState, onLogic } from "./logic/logic.js";
import { startGraphicsUpdater } from "./renderer.js"; import { startGraphicsUpdater } from "./renderer.js";
import { GameKeyMap, Frame, Key } from "./types.js"; import { GameKeyMap, Frame, Key, Player } from "./types.js";
const join = document.getElementById("join") const join = document.getElementById("join")
const lobby = document.getElementById("lobby") const lobby = document.getElementById("lobby")
@ -42,7 +42,7 @@ const onLoad = (startData: Frame) => {
return false return false
} }
let players = Object.values(startData.data.players).filter(p => { return p !== null && p.name !== undefined }) let players = Object.values(startData.data.players).filter((p: Player): boolean => p !== null && p.name !== undefined)
if (players.length >= 4) { if (players.length >= 4) {
alert('Room is full') alert('Room is full')
return false return false
@ -59,7 +59,6 @@ const onFrame = (data: Frame, frame: number) => {
} }
const startGame = (code: string, name: string) => { const startGame = (code: string, name: string) => {
const game = new Game(3000) const game = new Game(3000)

View file

@ -1,4 +1,5 @@
import { Wall, ItemType, Map, Maps, Items } from "./types.js" import { Wall, ItemType, Map, Maps, Items, Tile } from "./types.js"
import { LZString } from "./lib/lz-string.js"
export const getItemKey = ( export const getItemKey = (
x: number, x: number,
@ -90,6 +91,8 @@ const genWalls = (
return walls return walls
} }
const canItem = (tile: Tile): boolean => tile != Tile.WALL && tile != Tile.GHOST_WALL && tile != Tile.GHOST_SPAWN
export const genItems = (map: Map): Items => { export const genItems = (map: Map): Items => {
let width = map.width let width = map.width
@ -101,21 +104,35 @@ export const genItems = (map: Map): Items => {
for (let y = 0; y < height; y++) { for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) { for (let x = 0; x < width; x++) {
let tile = getPoint(width, height, data, x, y) let tile = getPoint(width, height, data, x, y)
if (tile != 0) continue if (!canItem(tile)) continue
let item_key = getItemKey(x, y, width) let item_key = getItemKey(x, y, width)
items[item_key] = {type: ItemType.DOT, pos: {x, y}}
let type: ItemType
if (tile == Tile.FOOD)
type = ItemType.FOOD
else if (tile == Tile.THICC_DOT)
type = ItemType.THICC_DOT
else
type = ItemType.DOT
items[item_key] = {type, pos: {x, y}}
if (type == ItemType.DOT || type == ItemType.THICC_DOT) {
type = ItemType.DOT
let tile_south = getPoint(width, height, data, x, y + 1) let tile_south = getPoint(width, height, data, x, y + 1)
if (tile_south == 0) { if (canItem(tile_south) && tile_south != Tile.FOOD) {
item_key = getItemKey(x, y + .5, width) item_key = getItemKey(x, y + .5, width)
items[item_key] = {type: ItemType.DOT, pos: {x, y: y + .5}} items[item_key] = {type, pos: {x, y: y + .5}}
} }
let tile_east = getPoint(width, height, data, x + 1, y) let tile_east = getPoint(width, height, data, x + 1, y)
if (tile_east == 0) { if (canItem(tile_east) && tile_east != Tile.FOOD) {
item_key = getItemKey(x + .5, y, width) item_key = getItemKey(x + .5, y, width)
items[item_key] = {type: ItemType.DOT, pos: {x: x + .5, y}} items[item_key] = {type, pos: {x: x + .5, y}}
}
} }
} }
} }
@ -124,7 +141,6 @@ export const genItems = (map: Map): Items => {
} }
let mapData: Maps = {} let mapData: Maps = {}
let id: number = 0
export const genMap = ( export const genMap = (
width: number, width: number,
@ -144,26 +160,22 @@ export const genMap = (
return mapData[mapId] return mapData[mapId]
} }
export const loadMap = (
width: number,
height: number,
data: number[]
): number => {
let mapId = id++
mapData[mapId] = {
data: structuredClone(data),
walls: genWalls(width, height, data),
width,
height,
id: mapId
}
return mapId
}
export const getMap = (mapId: number): Map | undefined => { export const getMap = (mapId: number): Map | undefined => {
if (mapId == undefined) return undefined if (mapId == undefined) return undefined
return mapData[mapId] return mapData[mapId]
} }
export const compressMap = (map: Map): string => {
let encoded = map.width + '|' + map.height + '|' + map.data.map(n => n + ',').join('').slice(0, -1)
return LZString.compressToBase64(encoded)
}
export const decompressMap = (encoded: string): {width: number, height: number, data: number[]} => {
let decoded = LZString.decompressFromBase64(encoded)
let values = decoded.split('|')
let width = parseInt(values[0])
let height = parseInt(values[1])
let data = values[2].split(',').map(c => parseInt(c))
return {width, height, data}
}

View file

@ -137,9 +137,17 @@ const draw_items = (
let width: number, atlas_index: [number, number] let width: number, atlas_index: [number, number]
switch (item.type) { switch (item.type) {
case ItemType.DOT: case ItemType.DOT:
width = .2, width = .2
atlas_index = [2, 3] atlas_index = [2, 3]
break break
case ItemType.THICC_DOT:
width = .4
atlas_index = [2, 3]
break
case ItemType.FOOD:
width = 1
atlas_index = [3, 3]
break
default: default:
continue continue
} }
@ -267,6 +275,7 @@ const draw_debug_sprites = (
let tile_type = map.data[y * map.width + x] let tile_type = map.data[y * map.width + x]
let size = 1
let atlas_index: [number, number]; let atlas_index: [number, number];
switch (tile_type) { switch (tile_type) {
case Tile.EMPTY: case Tile.EMPTY:
@ -275,9 +284,12 @@ const draw_debug_sprites = (
case Tile.GHOST_WALL: case Tile.GHOST_WALL:
atlas_index = [4, 0] atlas_index = [4, 0]
break break
case Tile.FOOD: case Tile.GHOST_SPAWN:
atlas_index = [3, 0] atlas_index = [3, 0]
break break
case Tile.FOOD:
atlas_index = [3, 3]
break
case Tile.PLAYER_SPAWN_1: case Tile.PLAYER_SPAWN_1:
atlas_index = [3, 1] atlas_index = [3, 1]
break break
@ -291,10 +303,12 @@ const draw_debug_sprites = (
atlas_index = [4, 2] atlas_index = [4, 2]
break break
case Tile.THICC_DOT: case Tile.THICC_DOT:
atlas_index = [4, 3] atlas_index = [2, 3]
size = .4
break break
case Tile.INITIAL_DOT: case Tile.INITIAL_DOT:
atlas_index = [3, 3] atlas_index = [2, 3]
size = .2
break break
} }
@ -302,7 +316,7 @@ const draw_debug_sprites = (
ctx, ctx,
x, x,
y, y,
1, size,
atlas, atlas,
atlas_index, atlas_index,
ATLAS_TILE_WIDTH, ATLAS_TILE_WIDTH,

View file

@ -2,17 +2,17 @@
export const ATLAS_TILE_WIDTH = 32 export const ATLAS_TILE_WIDTH = 32
export enum Tile { export enum Tile {
EMPTY, EMPTY = 0,
WALL, WALL = 1,
GHOST_WALL, GHOST_WALL = 2,
FOOD, FOOD = 3,
PLAYER_SPAWN_1, PLAYER_SPAWN_1 = 4,
PLAYER_SPAWN_2, PLAYER_SPAWN_2 = 5,
PLAYER_SPAWN_3, PLAYER_SPAWN_3 = 6,
PLAYER_SPAWN_4, PLAYER_SPAWN_4 = 7,
GHOST_SPAWN, GHOST_SPAWN = 8,
THICC_DOT, THICC_DOT = 9,
INITIAL_DOT INITIAL_DOT = 10
} }
export enum Wall { export enum Wall {
@ -36,7 +36,9 @@ export enum Wall {
} }
export enum ItemType { export enum ItemType {
DOT DOT,
THICC_DOT,
FOOD
} }
export enum Key { export enum Key {

View file

@ -5,7 +5,7 @@
"outDir": "./js", "outDir": "./js",
"allowJs": false, "allowJs": false,
"module": "es6", "module": "es6",
"target": "es6" "target": "es2017"
}, },
"include": ["./**/*"] "include": ["./**/*"]
} }