custom map overrides

This commit is contained in:
Freya Murphy 2023-06-29 21:52:26 -04:00
parent c66865d431
commit 484409b64d
10 changed files with 115 additions and 45 deletions

View file

@ -24,29 +24,3 @@ canvas {
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;
}

View file

@ -23,16 +23,16 @@ body {
} }
#center-inner { #center-inner {
width: 100%;
height: 100%; height: 100%;
position: relative; position: relative;
align-items: center;
justify-content: center; justify-content: center;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-left: calc(50% - 20rem / 2);
max-width: 20rem;
} }
#mapeditor { #custommaps, #mapeditor {
margin-top: 2rem; margin-top: 2rem;
} }
@ -87,3 +87,31 @@ input {
p { p {
padding: .25rem; padding: .25rem;
} }
#popup {
background-color: #191919;
position: absolute;
flex-direction: column;
padding: .5rem;
border: 1px solid #fff;
width: 19rem;
}
#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;
}

View file

@ -14,12 +14,24 @@
<input type="text" id="player_name" name="name" placeholder="Player Name"> <input type="text" id="player_name" name="name" placeholder="Player Name">
<input type="submit" value="Join!"/> <input type="submit" value="Join!"/>
</form> </form>
<input id="custommaps" type="button" value="Custom Map Overrides">
<input id="mapeditor" type="button" value="Map Editor"> <input id="mapeditor" type="button" value="Map Editor">
<div id="lobby" style="display: none;"> <div id="lobby" style="display: none;">
<span>Players:</span> <span>Players:</span>
<div id="players"></div> <div id="players"></div>
<input type="button" id="start" value="Start Game"/> <input type="button" id="start" value="Start Game"/>
</div> </div>
<div id="popup" style="display: none">
<input type="button" id="close" value="x" style='margin-bottom: .5rem' onclick="document.getElementById('popup').style.display = 'none'">
Map 1
<textarea id="map1"></textarea>
Map 2
<textarea id="map2"></textarea>
Map 3
<textarea id="map3"> </textarea>
Map 4
<textarea id="map4"></textarea>
</div>
</div> </div>
</div> </div>
<script src="js/main.js" type="module"></script> <script src="js/main.js" type="module"></script>

View file

@ -33,10 +33,17 @@ export const onLogic = (
data.frame = frame data.frame = frame
random(data) random(data)
let startPressed = updatePlayers(data, input); let startPressed = updatePlayers(data, input)
let playersLeft = 0 let playersLeft = 0
for (let id in data.players) { for (let id in data.players) {
let player = data.players[id] let player = data.players[id]
if (!player) {
continue
}
if (player.dead) { if (player.dead) {
player.framesDead++ player.framesDead++
} else { } else {

View file

@ -1,4 +1,5 @@
import { GameState, Input, Key, Rotation } from "../types.js" import { checkMap, decompressMap, genMap } from "../map.js"
import { GAME_MAP_COUNT, GameState, Input, Key, Rotation, Vec2 } from "../types.js"
const canPlayerJoin = (data: GameState) => { const canPlayerJoin = (data: GameState) => {
@ -16,6 +17,27 @@ const canPlayerJoin = (data: GameState) => {
} }
const loadMaps = (maps: {[key: number]: string}): boolean => {
for (let mapId = 0; mapId < GAME_MAP_COUNT; mapId++) {
let {width, height, data} = decompressMap(maps[mapId])
let map = genMap(width, height, data, mapId)
let [success, result] = checkMap(map)
if (!success) {
alert(result)
return false
}
map.spawns = result as Vec2[]
}
return true
}
export const updatePlayers = (data: GameState, input: Input) => { export const updatePlayers = (data: GameState, input: Input) => {
let startPressed = false; let startPressed = false;
@ -62,7 +84,13 @@ export const updatePlayers = (data: GameState, input: Input) => {
} }
startPressed ||= input.players[id].start; if (input.players[id].start) {
let maps = input.players[id].maps
if (loadMaps(maps)) {
startPressed = true
}
}
if (input.players[id].key) if (input.players[id].key)
data.input[id] = input.players[id].key data.input[id] = input.players[id].key

View file

@ -7,11 +7,18 @@ import { checkMap, decompressMap, genMap } from "./map.js";
const join = document.getElementById("join") const join = document.getElementById("join")
const lobby = document.getElementById("lobby") const lobby = document.getElementById("lobby")
const mapeditor = document.getElementById("mapeditor") const mapeditor = document.getElementById("mapeditor")
const custommaps = document.getElementById("custommaps")
const popup = document.getElementById("popup")
const maps = { const defaultMaps = {
[0]: 'MwRgPgTOIDS/dEOU1L1sxgDDX+9CDijSTyzLcFrVabN7EnYXCUnaBOK31xCMyEUSPfg3FZ20trTlTJnPpX4iV6tRLpCOC7bslbVvNQBY41SxesBWE/bYHpTnFPkZjFResG/hpb003RGBEMR0YQQAOSIjYcNDDRntAgNi/Txl/L2CkozgXfWdgtTUANmsQKyrrAHYHFLiI2T1870KgkkzS7N6CLUdmpvbipyV4hv7pQVSe8PGittHllo7J9Z7N5Y9W3Z39uCA' [0]: 'MwRgPgTOIDS/dEOU1L1sxgDDX+9CDijSTyzLcFrVabN7EnYXCUnaBOK31xCMyEUSPfg3FZ20trTlTJnPpX4iV6tRLpCOC7bslbVvNQBY41SxesBWE/bYHpTnFPkZjFResG/hpb003RGBEMR0YQQAOSIjYcNDDRntAgNi/Txl/L2CkozgXfWdgtTUANmsQKyrrAHYHFLiI2T1870KgkkzS7N6CLUdmpvbipyV4hv7pQVSe8PGittHllo7J9Z7N5Y9W3Z39uCA',
[1]: 'MwdgPgTMkDQXD5IQRhgBhm5PF97mptvqQalpWkVbdXQ/Uxo5eeTZly97zy5359h/Euzw1mUgbWIzpCynPHS5I9UpgBOGRpGSGyQZh0HVmxWtYGdfMRYZXuBvbs3P5sthSei3Z6y8Xdz9lIM96KwAWLGI42ISUeKTE+IBWf0cHYyFcu2zAuRzXfMUA4I9CXPKI1nF4NGBvYIN4AA4fBzDG7xVAmt8wo2raosK8idLalHNIyfmxq1mWADZU9ZTN5O2YEEzmJea3fMOxsq6Lk96CuZyK+fvDg+uc02mLyxvw2z9h5+KHiwfgCNDV7FUzqxIU8vst6hIFojBkiRvC/llzpioYE0WROuC8biGjIiUA===',
[2]: 'MzA+CYEZUgaOHyYly2o+rnEAZb6EFJGknFlFyXHUX15b52pk73NqeeO+zjkAnLQ7kaVUXWGcBLcq3kie2Jou6rGNOhPGi2kvSIWZlfEytOLEA2UsMSALPGYvnbgKxj7im/z9zLdTlzAI0RX2M7HR8/WyCDeM16aTUkYAY/AA5/enTQqUNI9Wi5XzjUkqMkCLtg1JQisPiynOLvOAA2N0hXHrcAdi9dUpyzLgsVOrHpoYz9XQXZ7QMp2rX2RvzxvnKU5bbhhNg91u2zwIzzCT4LpPnC72itdsnXjbePnCA===',
[3]: 'MwRgPgTMYgNHD5MS5aAMbXa7zm4BOWfJU8k2YMm0oyiuCgypmtnD17llxX3Gzo9KxIQxHiBzStX552kjIvlc+KiTOmbF2gfRmrB3I1olrjXKbRHDOunXuP6lAFngFPH7yC8BWDQsLM2srS0dbSNQXdXE4CFgEhLilWNxiYRCkOUTYAA5cuBzrTNFwoKjcpJtoh1qnEpNkHAaI0oqjADYfL18e7wB2OqV6yMYm+3Gp80DlYLbZtKNGsTHhrLM7CdSFMIqXZaoF1qdhDJ2t012dvbmbiJWbF2pNm1XL8s+lz84gA=='
} }
export var maps = {}
join.onsubmit = async function(event) { join.onsubmit = async function(event) {
event.preventDefault() event.preventDefault()
@ -29,17 +36,16 @@ join.onsubmit = async function(event) {
} }
for (let mapId = 0; mapId < GAME_MAP_COUNT; mapId++) { for (let mapId = 0; mapId < GAME_MAP_COUNT; mapId++) {
let {width, height, data} = decompressMap(maps[0]) // for now
let map = genMap(width, height, data, mapId)
let [success, result] = checkMap(map)
if (!success) { let id = 'map' + (mapId+1)
alert(result) let content = (document.getElementById(id) as HTMLTextAreaElement).value.trim()
return console.log(id, content)
if (content.length > 0) {
maps[mapId] = content
} else {
maps[mapId] = defaultMaps[mapId]
} }
map.spawns = result as Vec2[]
} }
startGame(room_code, player_name) startGame(room_code, player_name)
@ -49,6 +55,10 @@ mapeditor.onclick = function() {
window.location.href = 'mapeditor.html' window.location.href = 'mapeditor.html'
} }
custommaps.onclick = function() {
popup.style.display = 'flex'
}
const onLoad = (startData: Frame) => { const onLoad = (startData: Frame) => {
if (startData.data.started) { if (startData.data.started) {
@ -64,6 +74,8 @@ const onLoad = (startData: Frame) => {
join.style.display = "none" join.style.display = "none"
mapeditor.style.display = "none" mapeditor.style.display = "none"
custommaps.style.display = "none"
popup.style.display = "none"
lobby.style.display = "" lobby.style.display = ""
return true return true
@ -88,6 +100,7 @@ const startGame = (code: string, name: string) => {
{ {
start: false, start: false,
key: Key.NOTHING, key: Key.NOTHING,
maps: {},
name name
} }
) )

View file

@ -114,7 +114,7 @@ export class Game {
onLoad: (startFrame: Frame) => boolean, onLoad: (startFrame: Frame) => boolean,
onFrame: (data: Frame, frame: number) => void, onFrame: (data: Frame, frame: number) => void,
onLogic: (pastData: GameState, input: Input, frame: number) => GameState, onLogic: (pastData: GameState, input: Input, frame: number) => GameState,
data: PlayerInput = { start: false, key: Key.NOTHING } data: PlayerInput = { start: false, key: Key.NOTHING, maps: {}}
): void { ): void {
const fps = 60; const fps = 60;

View file

@ -1,4 +1,5 @@
import { Key, KeyMap, PlayerInput } from "../types.js" import { Key, KeyMap, PlayerInput } from "../types.js"
import { maps as definedMaps } from '../main.js'
let pressed = {} let pressed = {}
@ -62,9 +63,15 @@ export const startInputListener = (keymap: KeyMap): () => PlayerInput => {
let s = start; let s = start;
start = false; start = false;
let maps = {}
if (s) {
maps = definedMaps
}
return { return {
key, key,
start: s, start: s,
maps
} }
} }
} }

View file

@ -194,6 +194,7 @@ export type Player = {
export type PlayerInput = { export type PlayerInput = {
start: boolean, start: boolean,
key: Key, key: Key,
maps: {[key: number]: string}
name?: string name?: string
} }

View file

@ -7,9 +7,9 @@ RUN apk add musl-dev
RUN cargo build --release RUN cargo build --release
FROM node:alpine AS builder-ts FROM node:alpine AS builder-ts
RUN npm install typescript
COPY client /app/ COPY client /app/
WORKDIR /app WORKDIR /app
RUN npm install typescript
RUN npx tsc RUN npx tsc
FROM alpine FROM alpine