Add city gameplay, snapshot migrations, administration and Compose operations
This commit is contained in:
1 parent
3b1fcd996a
commit
85df37c26e
24 files changed
+1042
-55
No files matched your search
+17
@@ -7,6 +7,7 @@ import type { World } from './types';
|
||||
import { TileLoader } from '../client/tiles';
|
||||
import type { Bounds } from './city/format';
|
||||
import { RoomConnection } from '../client/connection';
|
||||
import { showAdmin } from '../client/admin';
|
||||
import { create, fromBinary, toBinary } from '@bufbuild/protobuf';
|
||||
import { CityJobSchema, CreateCitySchema } from '../client/generated/city_pb';
|
||||
|
||||
@@ -325,6 +326,14 @@ async function showTiledCity(url: string, connection?: RoomConnection) {
|
||||
}
|
||||
const vote = document.createElement('span'); vote.className = 'room-vote'; vote.setAttribute('role','status'); controls.appendChild(vote);
|
||||
tiledViewer.root.querySelector('.viewer-top')!.appendChild(controls);
|
||||
const gameplay = document.createElement('div'); gameplay.className = 'row';
|
||||
const state = document.createElement('span'); state.className = 'room-gameplay'; state.setAttribute('role', 'status'); gameplay.appendChild(state);
|
||||
for (const [action, label] of [['supplies', 'Запасы · 2¤/жит.'], ['meal', 'Обед · 1¤/жит.'], ['rest', 'Отдых · 3¤/жит.']]) {
|
||||
const button = document.createElement('button'); button.className = 'btn'; button.dataset.action = action; button.textContent = label;
|
||||
button.title = 'Общая казна. Одна команда на игровой час; исполнение в следующую игровую минуту.';
|
||||
button.onclick = () => connection.intervene(action); gameplay.appendChild(button);
|
||||
}
|
||||
tiledViewer.root.querySelector('.viewer-top')!.appendChild(gameplay);
|
||||
}
|
||||
(window as any).viewer = viewer;
|
||||
hideProgress();
|
||||
@@ -361,6 +370,13 @@ async function showLobby() {
|
||||
status: text => { status.textContent = text; viewer?.setLoadStatus(text); },
|
||||
clock: c => { const clock = app.querySelector('.room-clock'); if (clock) clock.textContent = `День ${Math.floor(c.gameSeconds / 86400) + 1} · ${String(Math.floor(c.gameSeconds/3600)%24).padStart(2,'0')}:${String(Math.floor(c.gameSeconds/60)%60).padStart(2,'0')} · ×${c.speed}`; },
|
||||
vote: v => { const vote = app.querySelector('.room-vote'); if (vote) vote.textContent = v.active ? `Голосование за ×${v.speed}: ${v.yes}/${v.players}, ${v.remainingSeconds} с` : `${v.players} игроков`; },
|
||||
gameplay: g => {
|
||||
const state = app.querySelector('.room-gameplay');
|
||||
const names: Record<string, string> = { harvest: 'Урожай', illness: 'Болезнь', rain: 'Дождь', supplies: 'Запасы пополнены', meal: 'Общий обед', rest: 'Отдых' };
|
||||
const event = g.events.at(-1);
|
||||
if (state) state.textContent = `Казна ${g.treasury}¤ · Еда ${g.food} · Голод ${g.needs?.hunger ?? 0}% · Усталость ${g.needs?.fatigue ?? 0}% · Настроение ${g.needs?.morale ?? 0}%${g.pending.length ? ' · Команда в очереди' : ''}${event ? ` · ${names[event.kind] ?? event.kind}` : ''}`;
|
||||
for (const button of app.querySelectorAll<HTMLButtonElement>('[data-action]')) button.disabled = g.pending.length > 0 || g.minute < g.nextInterventionMinute;
|
||||
},
|
||||
});
|
||||
roomConnection = connection;
|
||||
};
|
||||
@@ -394,6 +410,7 @@ async function showLobby() {
|
||||
|
||||
(async () => {
|
||||
const params = new URLSearchParams(location.search);
|
||||
if (params.has('admin')) return showAdmin(app);
|
||||
if (params.has('play')) return showLobby();
|
||||
if (params.has('city')) return showTiledCity(params.get('city')!);
|
||||
if (params.has('last') && (await hasWorld())) {
|
||||
|
||||
Reference in new issue
Block a user