export and load maps
This commit is contained in:
parent
fa2d9b6f91
commit
97c78292fe
12 changed files with 672 additions and 109 deletions
|
@ -7,15 +7,43 @@ canvas {
|
|||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid;
|
||||
border: 1px solid #fff;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
#mapgen {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#export {
|
||||
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 |
|
@ -2,7 +2,6 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="css/main.css"/>
|
||||
<script>var exports = {};</script>
|
||||
</head>
|
||||
<body>
|
||||
<img src="img/atlas.png" id="atlas" style="display: none;"/>
|
||||
|
|
|
@ -15,10 +15,16 @@
|
|||
<input type="text" id="height" name="height" placeholder="Map Height">
|
||||
<input type="submit" value="Create"/>
|
||||
</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 id="sidebar" style="display: none;">
|
||||
<p>W: Place Wall</p>
|
||||
<p>G: Place Ghost Wall</p>
|
||||
<p>H: Place Ghost Spawn</p>
|
||||
<p>F: Place Food</p>
|
||||
<p>1: Place Pac Spawn 1</p>
|
||||
<p>2: Place Pac Spawn 2</p>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { genMap } from "./map.js"
|
||||
import { genMap, compressMap, decompressMap } from "./map.js"
|
||||
import { startGraphicsUpdater } from "./renderer.js"
|
||||
import { GameState, Vec2, Tile } from "./types.js"
|
||||
|
||||
const mapgen = document.getElementById("mapgen")
|
||||
const sidebar = document.getElementById("sidebar")
|
||||
|
||||
mapgen.onsubmit = async function(event) {
|
||||
mapgen.onsubmit = async (event) => {
|
||||
event.preventDefault()
|
||||
|
||||
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"]) {
|
||||
return Tile.WALL
|
||||
return [Tile.WALL, false]
|
||||
} 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"]) {
|
||||
return Tile.FOOD
|
||||
return [Tile.FOOD, false]
|
||||
} else if (pressed["Digit1"]) {
|
||||
return Tile.PLAYER_SPAWN_1
|
||||
return [Tile.PLAYER_SPAWN_1, true]
|
||||
} else if (pressed["Digit2"]) {
|
||||
return Tile.PLAYER_SPAWN_2
|
||||
return [Tile.PLAYER_SPAWN_2, true]
|
||||
} else if (pressed["Digit3"]) {
|
||||
return Tile.PLAYER_SPAWN_3
|
||||
return [Tile.PLAYER_SPAWN_3, true]
|
||||
} else if (pressed["Digit4"]) {
|
||||
return Tile.PLAYER_SPAWN_4
|
||||
return [Tile.PLAYER_SPAWN_4, true]
|
||||
} else if (pressed["KeyT"]) {
|
||||
return Tile.THICC_DOT
|
||||
return [Tile.THICC_DOT, false]
|
||||
} else if (pressed["KeyI"]) {
|
||||
return Tile.INITIAL_DOT
|
||||
return [Tile.INITIAL_DOT, false]
|
||||
} else if (pressed["KeyC"]) {
|
||||
return Tile.EMPTY
|
||||
return [Tile.EMPTY, false]
|
||||
}
|
||||
|
||||
return undefined
|
||||
return [undefined, undefined]
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
genMap(width, height, data, Tile.EMPTY)
|
||||
let map = genMap(width, height, data, Tile.EMPTY)
|
||||
|
||||
let state: GameState = {
|
||||
started: true,
|
||||
|
@ -145,13 +147,19 @@ const runMapEditor = (width: number, height: number) => {
|
|||
const tilePos = getTilePos(width, height, mousePos)
|
||||
|
||||
const pressed = getInput()
|
||||
const tile = checkInputs(pressed)
|
||||
const [tile, unique] = checkInputs(pressed)
|
||||
|
||||
if (tile !== undefined && checkBounds(tilePos, width, height)) {
|
||||
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
|
||||
genMap(width, height, data, 0)
|
||||
map = genMap(width, height, data, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,4 +170,16 @@ const runMapEditor = (width: number, height: number) => {
|
|||
|
||||
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
505
client/src/lib/lz-string.ts
Normal 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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 { updateUI } from "./ui.js"
|
||||
import { updateMovement } from "./movement.js"
|
||||
import { updateItems } from "./items.js"
|
||||
import { GameState, Input } from "../types.js";
|
||||
|
||||
const maps = {
|
||||
[0]: 'EwRgPqYgNDew+TEuW6AGT2u59mPI/PeLZclSys1AhSgThJcJb2bdq7p5rupV2DYaVFCKI9HwFDiWACyxyK5WpCqArOPSCeuqfUnzDwaGbMyT3FAGZT0ABznD9ybWv0LLq61kz4S0M9WRMANnVVDUi1AHYdQxt+dyNEhJNiNk8A3npkiVSmcUEM6E5C/wL86rlivLqxaVymltggA='
|
||||
}
|
||||
|
||||
export const InitialState: GameState = {
|
||||
started: false,
|
||||
|
@ -32,7 +35,7 @@ export const onLogic = (
|
|||
}
|
||||
|
||||
if (startPressed && !data.started) {
|
||||
initMap(data)
|
||||
initMap(data, 0)
|
||||
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
|
||||
|
||||
if (getMap(0)) return
|
||||
|
||||
let width = 21
|
||||
let height = 21
|
||||
let m_data = [
|
||||
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))
|
||||
let map = getMap(mapId)
|
||||
if (!map) {
|
||||
let {width, height, data} = decompressMap(maps[mapId])
|
||||
map = genMap(width, height, data, mapId)
|
||||
}
|
||||
|
||||
gameData.items = genItems(map)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Game } from "./net/game.js";
|
||||
import { InitialState, onLogic } from "./logic/logic.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 lobby = document.getElementById("lobby")
|
||||
|
@ -42,7 +42,7 @@ const onLoad = (startData: Frame) => {
|
|||
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) {
|
||||
alert('Room is full')
|
||||
return false
|
||||
|
@ -59,7 +59,6 @@ const onFrame = (data: Frame, frame: number) => {
|
|||
|
||||
}
|
||||
|
||||
|
||||
const startGame = (code: string, name: string) => {
|
||||
|
||||
const game = new Game(3000)
|
||||
|
|
|
@ -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 = (
|
||||
x: number,
|
||||
|
@ -90,6 +91,8 @@ const genWalls = (
|
|||
return walls
|
||||
}
|
||||
|
||||
const canItem = (tile: Tile): boolean => tile != Tile.WALL && tile != Tile.GHOST_WALL && tile != Tile.GHOST_SPAWN
|
||||
|
||||
export const genItems = (map: Map): Items => {
|
||||
|
||||
let width = map.width
|
||||
|
@ -101,21 +104,35 @@ export const genItems = (map: Map): Items => {
|
|||
for (let y = 0; y < height; y++) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
let tile = getPoint(width, height, data, x, y)
|
||||
if (tile != 0) continue
|
||||
if (!canItem(tile)) continue
|
||||
|
||||
let item_key = getItemKey(x, y, width)
|
||||
items[item_key] = {type: ItemType.DOT, pos: {x, y}}
|
||||
|
||||
let tile_south = getPoint(width, height, data, x, y + 1)
|
||||
if (tile_south == 0) {
|
||||
item_key = getItemKey(x, y + .5, width)
|
||||
items[item_key] = {type: ItemType.DOT, pos: {x, y: y + .5}}
|
||||
}
|
||||
let type: ItemType
|
||||
|
||||
let tile_east = getPoint(width, height, data, x + 1, y)
|
||||
if (tile_east == 0) {
|
||||
item_key = getItemKey(x + .5, y, width)
|
||||
items[item_key] = {type: ItemType.DOT, pos: {x: x + .5, y}}
|
||||
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)
|
||||
if (canItem(tile_south) && tile_south != Tile.FOOD) {
|
||||
item_key = getItemKey(x, y + .5, width)
|
||||
items[item_key] = {type, pos: {x, y: y + .5}}
|
||||
}
|
||||
|
||||
let tile_east = getPoint(width, height, data, x + 1, y)
|
||||
if (canItem(tile_east) && tile_east != Tile.FOOD) {
|
||||
item_key = getItemKey(x + .5, y, width)
|
||||
items[item_key] = {type, pos: {x: x + .5, y}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +141,6 @@ export const genItems = (map: Map): Items => {
|
|||
}
|
||||
|
||||
let mapData: Maps = {}
|
||||
let id: number = 0
|
||||
|
||||
export const genMap = (
|
||||
width: number,
|
||||
|
@ -144,26 +160,22 @@ export const genMap = (
|
|||
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 => {
|
||||
if (mapId == undefined) return undefined
|
||||
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}
|
||||
}
|
||||
|
|
|
@ -137,9 +137,17 @@ const draw_items = (
|
|||
let width: number, atlas_index: [number, number]
|
||||
switch (item.type) {
|
||||
case ItemType.DOT:
|
||||
width = .2,
|
||||
width = .2
|
||||
atlas_index = [2, 3]
|
||||
break
|
||||
case ItemType.THICC_DOT:
|
||||
width = .4
|
||||
atlas_index = [2, 3]
|
||||
break
|
||||
case ItemType.FOOD:
|
||||
width = 1
|
||||
atlas_index = [3, 3]
|
||||
break
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
@ -267,6 +275,7 @@ const draw_debug_sprites = (
|
|||
let tile_type = map.data[y * map.width + x]
|
||||
|
||||
|
||||
let size = 1
|
||||
let atlas_index: [number, number];
|
||||
switch (tile_type) {
|
||||
case Tile.EMPTY:
|
||||
|
@ -275,9 +284,12 @@ const draw_debug_sprites = (
|
|||
case Tile.GHOST_WALL:
|
||||
atlas_index = [4, 0]
|
||||
break
|
||||
case Tile.FOOD:
|
||||
case Tile.GHOST_SPAWN:
|
||||
atlas_index = [3, 0]
|
||||
break
|
||||
case Tile.FOOD:
|
||||
atlas_index = [3, 3]
|
||||
break
|
||||
case Tile.PLAYER_SPAWN_1:
|
||||
atlas_index = [3, 1]
|
||||
break
|
||||
|
@ -291,10 +303,12 @@ const draw_debug_sprites = (
|
|||
atlas_index = [4, 2]
|
||||
break
|
||||
case Tile.THICC_DOT:
|
||||
atlas_index = [4, 3]
|
||||
atlas_index = [2, 3]
|
||||
size = .4
|
||||
break
|
||||
case Tile.INITIAL_DOT:
|
||||
atlas_index = [3, 3]
|
||||
atlas_index = [2, 3]
|
||||
size = .2
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -302,7 +316,7 @@ const draw_debug_sprites = (
|
|||
ctx,
|
||||
x,
|
||||
y,
|
||||
1,
|
||||
size,
|
||||
atlas,
|
||||
atlas_index,
|
||||
ATLAS_TILE_WIDTH,
|
||||
|
|
|
@ -2,17 +2,17 @@
|
|||
export const ATLAS_TILE_WIDTH = 32
|
||||
|
||||
export enum Tile {
|
||||
EMPTY,
|
||||
WALL,
|
||||
GHOST_WALL,
|
||||
FOOD,
|
||||
PLAYER_SPAWN_1,
|
||||
PLAYER_SPAWN_2,
|
||||
PLAYER_SPAWN_3,
|
||||
PLAYER_SPAWN_4,
|
||||
GHOST_SPAWN,
|
||||
THICC_DOT,
|
||||
INITIAL_DOT
|
||||
EMPTY = 0,
|
||||
WALL = 1,
|
||||
GHOST_WALL = 2,
|
||||
FOOD = 3,
|
||||
PLAYER_SPAWN_1 = 4,
|
||||
PLAYER_SPAWN_2 = 5,
|
||||
PLAYER_SPAWN_3 = 6,
|
||||
PLAYER_SPAWN_4 = 7,
|
||||
GHOST_SPAWN = 8,
|
||||
THICC_DOT = 9,
|
||||
INITIAL_DOT = 10
|
||||
}
|
||||
|
||||
export enum Wall {
|
||||
|
@ -36,7 +36,9 @@ export enum Wall {
|
|||
}
|
||||
|
||||
export enum ItemType {
|
||||
DOT
|
||||
DOT,
|
||||
THICC_DOT,
|
||||
FOOD
|
||||
}
|
||||
|
||||
export enum Key {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"outDir": "./js",
|
||||
"allowJs": false,
|
||||
"module": "es6",
|
||||
"target": "es6"
|
||||
"target": "es2017"
|
||||
},
|
||||
"include": ["./**/*"]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue