Dev-harness: Tegn og Gæts skærme med ?game=tegn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,15 +35,19 @@
|
||||
</div>
|
||||
<script>window.WPP_HARNESS = true;</script>
|
||||
<script src="common.js"></script>
|
||||
<script src="tegn.js"></script>
|
||||
<script src="host.js"></script>
|
||||
<script src="play.js"></script>
|
||||
<script src="dev-fixtures.js"></script>
|
||||
<script src="tegn-fixtures.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
var qs = new URLSearchParams(location.search);
|
||||
var phase = qs.get('phase') || 'lobby';
|
||||
var t = qs.get('t');
|
||||
var only = qs.get('only');
|
||||
/* ?game=tegn: Tegn og Gæts skærme (samme storskærm/telefon-kode, egne fixtures) */
|
||||
var FX = qs.get('game') === 'tegn' ? WPPTegnFixtures : WPPFixtures;
|
||||
if (only) document.body.classList.add('only-' + only);
|
||||
if (qs.get('pw')) Array.prototype.forEach.call(document.querySelectorAll('.phonebox'), function (e) { e.style.width = qs.get('pw') + 'px'; });
|
||||
var bar = document.getElementById('bar');
|
||||
@@ -52,9 +56,10 @@
|
||||
|
||||
var cur = null, hostCtx = null;
|
||||
function draw() {
|
||||
var fx = cur = WPPFixtures.build(phase, { t: t, fest: qs.get("fest") === "1" });
|
||||
var fx = cur = FX.build(phase, { t: t, fest: qs.get("fest") === "1" });
|
||||
var hostRoot = document.getElementById('hostroot');
|
||||
hostCtx = { harness: true, sound: qs.get('sound') === '1', send: log, qrSrc: WPPFixtures.qr };
|
||||
if (fx.drawings) WPPTegn.setDrawings(hostRoot, fx.drawings);
|
||||
WPPHost.renderHost(hostRoot, fx.host, hostCtx);
|
||||
fx.phones.forEach(function (ph, i) {
|
||||
var root = document.getElementById('ph' + i);
|
||||
@@ -71,7 +76,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
WPPFixtures.phases.forEach(function (p) {
|
||||
FX.phases.forEach(function (p) {
|
||||
var b = document.createElement('button');
|
||||
b.textContent = p; if (p === phase) b.className = 'on';
|
||||
b.onclick = function () {
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/* Fixture-snapshots for Tegn og Gæt til dev.html?game=tegn (ingen server). window.WPPTegnFixtures.build(phase, opts) */
|
||||
(function () {
|
||||
'use strict';
|
||||
var COLORS = ['#ff4d6d', '#4cc9f0', '#ffd166', '#06d6a0', '#b388ff'];
|
||||
var NAMES = ['Asger', 'Sus', 'Bo', 'Mette', 'Kasper'];
|
||||
var PHASES = ['lobby', 'rules', 'theme', 'word', 'draw', 'guess', 'reveal-wait', 'reveal', 'reveal-guess', 'reveal-end', 'final'];
|
||||
var REAL = { 'reveal-wait': 'reveal', 'reveal-guess': 'reveal', 'reveal-end': 'reveal' };
|
||||
var INK = ['#1d1b2e', '#e63946', '#2a7de1', '#2bb673'];
|
||||
|
||||
function circle(cx, cy, r, n) {
|
||||
var pts = [];
|
||||
for (var i = 0; i <= n; i++) { var a = i / n * Math.PI * 2; pts.push([+(cx + Math.cos(a) * r).toFixed(3), +(cy + Math.sin(a) * r * 4 / 3).toFixed(3)]); }
|
||||
return pts;
|
||||
}
|
||||
function line(a, b) { return [a, b]; }
|
||||
var CAT = [
|
||||
{ color: INK[0], width: 0.012, points: circle(0.5, 0.55, 0.22, 40) },
|
||||
{ color: INK[0], width: 0.012, points: [[0.33, 0.36], [0.36, 0.12], [0.45, 0.28]] },
|
||||
{ color: INK[0], width: 0.012, points: [[0.55, 0.28], [0.64, 0.12], [0.67, 0.36]] },
|
||||
{ color: INK[2], width: 0.024, points: [[0.42, 0.5]] },
|
||||
{ color: INK[2], width: 0.024, points: [[0.58, 0.5]] },
|
||||
{ color: INK[1], width: 0.012, points: [[0.47, 0.6], [0.5, 0.64], [0.53, 0.6]] },
|
||||
{ color: INK[0], width: 0.008, points: line([0.4, 0.62], [0.2, 0.58]) },
|
||||
{ color: INK[0], width: 0.008, points: line([0.4, 0.66], [0.2, 0.7]) },
|
||||
{ color: INK[0], width: 0.008, points: line([0.6, 0.62], [0.8, 0.58]) },
|
||||
{ color: INK[0], width: 0.008, points: line([0.6, 0.66], [0.8, 0.7]) }
|
||||
];
|
||||
var DOG = [
|
||||
{ color: INK[0], width: 0.012, points: circle(0.5, 0.5, 0.2, 40) },
|
||||
{ color: INK[0], width: 0.024, points: [[0.3, 0.32], [0.24, 0.6]] },
|
||||
{ color: INK[0], width: 0.024, points: [[0.7, 0.32], [0.76, 0.6]] },
|
||||
{ color: INK[0], width: 0.024, points: [[0.44, 0.46]] },
|
||||
{ color: INK[0], width: 0.024, points: [[0.56, 0.46]] },
|
||||
{ color: INK[1], width: 0.024, points: [[0.48, 0.66], [0.5, 0.74], [0.52, 0.66]] }
|
||||
];
|
||||
var SOFA = [
|
||||
{ color: INK[3], width: 0.024, points: [[0.15, 0.45], [0.15, 0.75], [0.85, 0.75], [0.85, 0.45]] },
|
||||
{ color: INK[3], width: 0.024, points: [[0.22, 0.6], [0.22, 0.3], [0.78, 0.3], [0.78, 0.6]] },
|
||||
{ color: INK[0], width: 0.012, points: [[0.2, 0.75], [0.2, 0.85]] },
|
||||
{ color: INK[0], width: 0.012, points: [[0.8, 0.75], [0.8, 0.85]] }
|
||||
];
|
||||
|
||||
function players(n, extra) {
|
||||
var out = [];
|
||||
for (var i = 0; i < n; i++) out.push({ id: 'p' + (i + 1), name: NAMES[i], color: COLORS[i], score: 0, connected: true, vip: i === 0, done: false });
|
||||
(extra || []).forEach(function (f, i) { if (out[i]) Object.assign(out[i], f); });
|
||||
return out;
|
||||
}
|
||||
function clone(o) { return JSON.parse(JSON.stringify(o)); }
|
||||
var THEMES = [['dyr', 'Dyr', '🐘'], ['film', 'Film og serier', '🎬'], ['koekken', 'Ting i køkkenet', '🍳'], ['jul', 'Jul', '🎄'], ['sport', 'Sport', '⚽'],
|
||||
['mad', 'Mad', '🍕'], ['strand', 'På stranden', '🏖️'], ['job', 'Job', '👩🚒'], ['skole', 'I skolen', '🏫'], ['eventyr', 'Eventyr', '🏰'],
|
||||
['transport', 'Transport', '🚂'], ['musik', 'Musik', '🎸'], ['danmark', 'Danmark', '🇩🇰'], ['rummet', 'Rummet', '🚀']]
|
||||
.map(function (t) { return { id: t[0], name: t[1], icon: t[2] }; });
|
||||
|
||||
/* fem kæder à fem bidrag: ord, tegning, gæt, tegning, gæt */
|
||||
function chains() {
|
||||
var words = ['kat', 'pizza', 'rumraket', 'juletræ', 'giraf'];
|
||||
var out = [], drawings = {};
|
||||
for (var k = 0; k < 5; k++) {
|
||||
var e = [];
|
||||
for (var t = 0; t < 5; t++) {
|
||||
var by = 'p' + (((k + t) % 5) + 1), id = 'c' + k + 'e' + t;
|
||||
var kind = t === 0 ? 'word' : t % 2 ? 'drawing' : 'guess';
|
||||
var text = kind === 'drawing' ? null : t === 0 ? words[k] : k === 0 ? (t === 2 ? 'hund' : 'sofa') : k === 1 ? 'pizza' : t === 2 ? 'blomst' : 'paraply';
|
||||
e.push({ id: id, kind: kind, by: by, text: text, auto: k === 3 && t === 4, likes: { c0e1: 2, c0e2: 1, c0e3: 3 }[id] || 0 });
|
||||
if (kind === 'drawing') drawings[id] = k === 0 ? (t === 1 ? CAT : DOG) : k === 1 ? SOFA : DOG;
|
||||
}
|
||||
out.push({ owner: 'p' + (k + 1), survived: k === 1, entries: e });
|
||||
}
|
||||
return { chains: out, drawings: drawings };
|
||||
}
|
||||
function plan(chs) {
|
||||
var out = [];
|
||||
chs.forEach(function (c, k) {
|
||||
out.push({ chain: k, entry: -1, ms: 2500, audio: null });
|
||||
c.entries.forEach(function (e, i) { out.push({ chain: k, entry: i, ms: { word: 3000, drawing: 5500, guess: 3000 }[e.kind], audio: null }); });
|
||||
out.push({ chain: k, entry: c.entries.length, ms: 4500, audio: null });
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
function build(phase, opts) {
|
||||
opts = opts || {};
|
||||
var now = Date.now();
|
||||
var real = REAL[phase] || phase;
|
||||
var host = { game: 'tegn', code: 'KLMT', phase: real, server_time: now, deadline: null, join_url: 'https://party.weircon.dk/?code=KLMT',
|
||||
min_players: 3, max_players: 10, round: null, players: players(5), audience_count: 1, fest: false,
|
||||
reactions: ['😂', '😱', '👏', '🤯', '🙈', '🔥'], host: true, phase_key: phase };
|
||||
var drawings = {};
|
||||
var mes = [0, 1, 2].map(function (i) { return { id: 'p' + (i + 1), name: NAMES[i], role: 'player', vip: i === 0, score: 0, task: null, likes: [], can_choose: false }; });
|
||||
var theme = { name: 'Dyr', icon: '🐘' };
|
||||
switch (phase) {
|
||||
case 'rules':
|
||||
host.rules = { items: [
|
||||
{ icon: '✏️', title: 'Skriv et ord', body: 'Alle skriver et ord eller en kort frase inden for temaet.' },
|
||||
{ icon: '🎨', title: 'Tegn det', body: 'Telefonen sender ordet videre. Den næste tegner det.' },
|
||||
{ icon: '🤔', title: 'Gæt tegningen', body: 'Den næste ser kun tegningen og skriver, hvad den forestiller.' },
|
||||
{ icon: '🔁', title: 'Hele vejen rundt', body: 'Skiftevis tegn og gæt, til kæden har været hos alle.' },
|
||||
{ icon: '❤️', title: 'Hjerter og priser', body: 'Giv hjerter til de bedste tegninger og gæt. Point og priser til sidst.' }],
|
||||
started_at: now - 7000, steps_ms: [5000, 5000, 5000, 5000, 5000], audio: null };
|
||||
host.deadline = now + 19000;
|
||||
break;
|
||||
case 'theme':
|
||||
host.theme = { options: THEMES, chosen_id: null };
|
||||
host.deadline = now + 14000;
|
||||
mes[0].can_choose = true;
|
||||
break;
|
||||
case 'word':
|
||||
host.theme = theme; host.step = { index: 0, number: 1, of: 5, kind: 'word' }; host.deadline = now + 22000;
|
||||
host.players = players(5, [{ done: true }, {}, {}, { done: true }]);
|
||||
mes[0].task = { kind: 'word', done: true, from: null, text: null, drawing: null, mine: 'kat', draft: null };
|
||||
mes[1].task = { kind: 'word', done: false, from: null, text: null, drawing: null, mine: null, draft: null };
|
||||
mes[2] = { id: 'u7', name: 'Lis', role: 'audience', vip: false, score: 0, task: null, likes: [], can_choose: false };
|
||||
break;
|
||||
case 'draw':
|
||||
host.theme = theme; host.step = { index: 1, number: 2, of: 5, kind: 'draw' }; host.deadline = now + 61000;
|
||||
host.players = players(5, [{}, { done: true }]);
|
||||
mes[0].task = { kind: 'draw', done: false, from: 'p5', text: 'giraf', drawing: null, mine: null, draft: null };
|
||||
mes[1].task = { kind: 'draw', done: true, from: 'p1', text: 'kat', drawing: null, mine: null, draft: null };
|
||||
mes[2].task = { kind: 'draw', done: false, from: 'p2', text: 'pizza', drawing: null, mine: null, draft: CAT.slice(0, 4) };
|
||||
break;
|
||||
case 'guess':
|
||||
host.theme = theme; host.step = { index: 2, number: 3, of: 5, kind: 'guess' }; host.deadline = now + 18000;
|
||||
mes[0].task = { kind: 'guess', done: false, from: 'p4', text: null, drawing: DOG, mine: null, draft: null };
|
||||
mes[1].task = { kind: 'guess', done: true, from: 'p5', text: null, drawing: CAT, mine: 'hund', draft: null };
|
||||
mes[2].task = { kind: 'guess', done: false, from: 'p1', text: null, drawing: SOFA, mine: null, draft: 'so' };
|
||||
break;
|
||||
case 'reveal-wait':
|
||||
case 'reveal':
|
||||
case 'reveal-guess':
|
||||
case 'reveal-end':
|
||||
var c = chains();
|
||||
drawings = c.drawings;
|
||||
host.theme = theme;
|
||||
var t = opts.t != null ? Number(opts.t) : { reveal: 7000, 'reveal-guess': 12000, 'reveal-end': 23000 }[phase] || 0;
|
||||
host.reveal = { id: 1, started_at: phase === 'reveal-wait' ? null : now - t, plan: plan(c.chains), chains: c.chains };
|
||||
host.deadline = now + 120000;
|
||||
mes[0].likes = ['c0e3'];
|
||||
break;
|
||||
case 'final':
|
||||
host.players = players(5, [{ score: 800 }, { score: 1100 }, { score: 300 }, { score: 500 }, { score: 0 }]);
|
||||
host.final = { ranking: [{ player_id: 'p2', score: 1100, place: 1 }, { player_id: 'p1', score: 800, place: 2 }, { player_id: 'p4', score: 500, place: 3 },
|
||||
{ player_id: 'p3', score: 300, place: 4 }, { player_id: 'p5', score: 0, place: 5 }],
|
||||
awards: [{ title: 'Bedste tegning', player_id: 'p2', detail: '3 hjerter', kind: 'drawing' },
|
||||
{ title: 'Bedste gæt', player_id: 'p3', detail: '"sofa", 2 hjerter', kind: 'guess' },
|
||||
{ title: 'Kæden der overlevede', player_id: 'p2', detail: '"pizza" hele vejen rundt', kind: 'survived' },
|
||||
{ title: 'Største forvandling', player_id: 'p1', detail: '"kat" blev til "sofa"', kind: 'transformed' }] };
|
||||
mes.forEach(function (m) { m.score = { p1: 800, p2: 1100, p3: 300 }[m.id]; });
|
||||
break;
|
||||
}
|
||||
var phones = mes.map(function (me) {
|
||||
var st = clone(host);
|
||||
delete st.host; delete st.phase_key;
|
||||
st.me = me;
|
||||
return { label: me.name + (me.role === 'audience' ? ' (publikum)' : me.vip ? ' (VIP)' : ''), state: st };
|
||||
});
|
||||
return { host: host, phones: phones, drawings: { reveal_id: 1, drawings: drawings } };
|
||||
}
|
||||
|
||||
window.WPPTegnFixtures = { build: build, phases: PHASES, qr: null };
|
||||
})();
|
||||
Reference in New Issue
Block a user