@adatechnology/game-test-room 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/index.d.ts +158 -17
- package/dist/index.global.js +548 -96
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +505 -91
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -471,7 +471,7 @@ function buildFromSpec(THREE, spec, options = {}) {
|
|
|
471
471
|
}
|
|
472
472
|
|
|
473
473
|
// src/explosives.ts
|
|
474
|
-
import { backblastEffect, blastEffect, createExplosiveBody, tripwireSegment } from "@adatechnology/game-weapons";
|
|
474
|
+
import { ExplosiveBody, backblastEffect, blastEffect, createExplosiveBody, tripwireSegment } from "@adatechnology/game-weapons";
|
|
475
475
|
|
|
476
476
|
// src/segment-box.ts
|
|
477
477
|
var segmentTouchesBox = (from, to, min, max) => {
|
|
@@ -714,6 +714,14 @@ function createExplosives(context) {
|
|
|
714
714
|
...projectile.fire ? { fire: projectile.fire } : {}
|
|
715
715
|
});
|
|
716
716
|
};
|
|
717
|
+
const blastAt = (weapon, explosive, point) => {
|
|
718
|
+
const def = arsenal.explosives.get(explosive);
|
|
719
|
+
if (!def) return false;
|
|
720
|
+
const event = new ExplosiveBody({ explosive: def, origin: point, triggers: ["remote"], rules: arsenal.rules.explosives }).trigger("remote");
|
|
721
|
+
if (event?.type !== "detonate") return false;
|
|
722
|
+
detonate({ weapon }, event.detonation);
|
|
723
|
+
return true;
|
|
724
|
+
};
|
|
717
725
|
const detonateCharges = () => {
|
|
718
726
|
let count = 0;
|
|
719
727
|
for (const projectile of [...projectiles]) {
|
|
@@ -805,7 +813,172 @@ function createExplosives(context) {
|
|
|
805
813
|
}
|
|
806
814
|
}
|
|
807
815
|
};
|
|
808
|
-
return { throwUse, placeUse, backblastUse, detonateCharges, update, clear };
|
|
816
|
+
return { throwUse, placeUse, backblastUse, detonateCharges, blastAt, update, clear };
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// src/test-table.ts
|
|
820
|
+
var TRIAL_KINDS = ["shot", "punch", "stab", "fire", "blast"];
|
|
821
|
+
var DEFAULT_TRIALS = {
|
|
822
|
+
shot: { weapon: "pistol_9mm", distance: 2.5, lift: 0.5 },
|
|
823
|
+
punch: { weapon: "fists", distance: 0.3, lift: 0.15 },
|
|
824
|
+
stab: { weapon: "knife", distance: 0.22, lift: 0.1 },
|
|
825
|
+
fire: { weapon: "flamethrower", distance: 1.6, lift: 0.4, hold: 0.8 },
|
|
826
|
+
blast: { weapon: "frag_grenade", distance: 0.3, lift: 1, watch: 6 }
|
|
827
|
+
};
|
|
828
|
+
var resolveTrials = (overrides = {}) => Object.fromEntries(TRIAL_KINDS.map((kind) => [kind, { ...DEFAULT_TRIALS[kind], ...overrides[kind] }]));
|
|
829
|
+
function fitRow(width, start, total, length, gap) {
|
|
830
|
+
let used = 0;
|
|
831
|
+
let count = 0;
|
|
832
|
+
for (let i = start; i < total; i++) {
|
|
833
|
+
const w = width(i);
|
|
834
|
+
const next = count === 0 ? w : used + gap + w;
|
|
835
|
+
if (count > 0 && next > length) break;
|
|
836
|
+
used = next;
|
|
837
|
+
count++;
|
|
838
|
+
}
|
|
839
|
+
return count;
|
|
840
|
+
}
|
|
841
|
+
function rowCentres(widths, centreX, gap) {
|
|
842
|
+
const length = widths.reduce((sum, w) => sum + w, 0) + gap * Math.max(0, widths.length - 1);
|
|
843
|
+
let x = centreX - length / 2;
|
|
844
|
+
return widths.map((w) => {
|
|
845
|
+
const centre = x + w / 2;
|
|
846
|
+
x += w + gap;
|
|
847
|
+
return centre;
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
function trialView(tool, kind, min, max) {
|
|
851
|
+
const target = [(min[0] + max[0]) / 2, (min[1] + max[1]) / 2, (min[2] + max[2]) / 2];
|
|
852
|
+
const away = kind === "blast" ? tool.watch ?? 6 : tool.distance;
|
|
853
|
+
return { eye: [target[0], target[1] + tool.lift, max[2] + away], target };
|
|
854
|
+
}
|
|
855
|
+
function createTestTable(context, options = {}) {
|
|
856
|
+
const gap = options.gap ?? 0.12;
|
|
857
|
+
const margin = options.margin ?? 0.1;
|
|
858
|
+
const trials = resolveTrials(options.trials);
|
|
859
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
860
|
+
let current = null;
|
|
861
|
+
const itemsOf = (group) => context.groups().get(group) ?? [];
|
|
862
|
+
const emit = () => {
|
|
863
|
+
const page = state();
|
|
864
|
+
for (const listener of [...listeners]) listener(page);
|
|
865
|
+
return page;
|
|
866
|
+
};
|
|
867
|
+
const state = () => {
|
|
868
|
+
if (!current) return null;
|
|
869
|
+
const total = itemsOf(current.group).length;
|
|
870
|
+
const live = current.objects.filter((o) => context.box(o.objectId));
|
|
871
|
+
return {
|
|
872
|
+
group: current.group,
|
|
873
|
+
page: current.page,
|
|
874
|
+
first: current.first,
|
|
875
|
+
total,
|
|
876
|
+
objects: live,
|
|
877
|
+
selected: current.selected,
|
|
878
|
+
hasPrev: current.page > 0,
|
|
879
|
+
hasNext: current.first + current.objects.length < total
|
|
880
|
+
};
|
|
881
|
+
};
|
|
882
|
+
const bounds = /* @__PURE__ */ new Map();
|
|
883
|
+
const widthOf = (itemId) => context.measure(itemId).w;
|
|
884
|
+
const boundsUntil = (group, length, until) => {
|
|
885
|
+
const items = itemsOf(group);
|
|
886
|
+
const known = bounds.get(group) ?? [0];
|
|
887
|
+
bounds.set(group, known);
|
|
888
|
+
while (known[known.length - 1] < items.length && !until(known)) {
|
|
889
|
+
const first = known[known.length - 1];
|
|
890
|
+
known.push(first + fitRow((i) => widthOf(items[i].id), first, items.length, length, gap));
|
|
891
|
+
}
|
|
892
|
+
return known;
|
|
893
|
+
};
|
|
894
|
+
const lengthOf = (top) => top.maxX - top.minX - 2 * margin;
|
|
895
|
+
const lay = (group, page, top) => {
|
|
896
|
+
const items = itemsOf(group);
|
|
897
|
+
const known = boundsUntil(group, lengthOf(top), (b) => b.length > page + 1);
|
|
898
|
+
const index = Math.max(0, Math.min(page, known.length - 2));
|
|
899
|
+
const first = known[index];
|
|
900
|
+
const laid = items.slice(first, known[index + 1]);
|
|
901
|
+
context.clear();
|
|
902
|
+
const sizes = laid.map((item) => context.measure(item.id));
|
|
903
|
+
const centres = rowCentres(sizes.map((size) => size.w), (top.minX + top.maxX) / 2, gap);
|
|
904
|
+
const objects = laid.map((item, i) => {
|
|
905
|
+
const d = Math.min(sizes[i].d, top.maxZ - top.minZ);
|
|
906
|
+
const { objectId } = context.spawn(item.id, [centres[i], top.top, top.maxZ - margin / 2 - d / 2]);
|
|
907
|
+
return { objectId, itemId: item.id, name: item.name };
|
|
908
|
+
});
|
|
909
|
+
current = { group, page: index, first, objects, selected: objects[0]?.objectId ?? null };
|
|
910
|
+
context.log("test_table", context.translate("act.test_table", { group, from: first + 1, to: first + laid.length, total: items.length }), { group, page: index, items: laid.map((i) => i.id) });
|
|
911
|
+
return emit();
|
|
912
|
+
};
|
|
913
|
+
const open = (group, page = 0) => {
|
|
914
|
+
const top = context.top();
|
|
915
|
+
if (!itemsOf(group).length || !top) return null;
|
|
916
|
+
return lay(group, page, top);
|
|
917
|
+
};
|
|
918
|
+
const find = (itemId) => {
|
|
919
|
+
const top = context.top();
|
|
920
|
+
const group = [...context.groups()].find(([, items]) => items.some((i) => i.id === itemId))?.[0];
|
|
921
|
+
if (group === void 0 || !top) return null;
|
|
922
|
+
const index = itemsOf(group).findIndex((i) => i.id === itemId);
|
|
923
|
+
const known = boundsUntil(group, lengthOf(top), (b) => b[b.length - 1] > index);
|
|
924
|
+
lay(group, known.findIndex((bound, i) => bound <= index && index < known[i + 1]), top);
|
|
925
|
+
const target = current?.objects.find((o) => o.itemId === itemId);
|
|
926
|
+
if (current && target) current.selected = target.objectId;
|
|
927
|
+
return emit();
|
|
928
|
+
};
|
|
929
|
+
const selected = (objectId) => {
|
|
930
|
+
const id = objectId ?? current?.selected ?? null;
|
|
931
|
+
return id && context.box(id) ? id : null;
|
|
932
|
+
};
|
|
933
|
+
const trial = (kind, objectId) => {
|
|
934
|
+
const id = selected(objectId);
|
|
935
|
+
const box2 = id ? context.box(id) : null;
|
|
936
|
+
if (!id || !box2) return false;
|
|
937
|
+
const tool = trials[kind];
|
|
938
|
+
if (!context.equip(tool.weapon)) return false;
|
|
939
|
+
const view = trialView(tool, kind, box2.min, box2.max);
|
|
940
|
+
context.look(view.eye, view.target);
|
|
941
|
+
const name = current?.objects.find((o) => o.objectId === id)?.name ?? id;
|
|
942
|
+
context.log("trial", context.translate(`act.trial.${kind}`, { name }), { kind, objectId: id, weapon: tool.weapon });
|
|
943
|
+
if (kind === "blast") {
|
|
944
|
+
const point = [view.target[0], box2.min[1] + 0.05, box2.min[2] - tool.distance];
|
|
945
|
+
return context.blastAt(tool.weapon, point);
|
|
946
|
+
}
|
|
947
|
+
context.use(tool.hold ?? 0);
|
|
948
|
+
emit();
|
|
949
|
+
return true;
|
|
950
|
+
};
|
|
951
|
+
return {
|
|
952
|
+
groups: () => [...context.groups()].filter(([, items]) => items.length > 0).map(([group]) => group),
|
|
953
|
+
items: () => [...context.groups()].flatMap(([group, items]) => items.map((item) => ({ id: item.id, name: item.name, group }))),
|
|
954
|
+
open,
|
|
955
|
+
find,
|
|
956
|
+
next: () => {
|
|
957
|
+
const page = state();
|
|
958
|
+
return page?.hasNext ? open(page.group, page.page + 1) : page;
|
|
959
|
+
},
|
|
960
|
+
prev: () => {
|
|
961
|
+
const page = state();
|
|
962
|
+
return page?.hasPrev ? open(page.group, page.page - 1) : page;
|
|
963
|
+
},
|
|
964
|
+
relay: () => {
|
|
965
|
+
if (!current) return null;
|
|
966
|
+
context.resetAll();
|
|
967
|
+
return open(current.group, current.page);
|
|
968
|
+
},
|
|
969
|
+
state,
|
|
970
|
+
select: (objectId) => {
|
|
971
|
+
if (!current || !current.objects.some((o) => o.objectId === objectId) || !context.box(objectId)) return false;
|
|
972
|
+
current.selected = objectId;
|
|
973
|
+
emit();
|
|
974
|
+
return true;
|
|
975
|
+
},
|
|
976
|
+
trial,
|
|
977
|
+
on: (listener) => {
|
|
978
|
+
listeners.add(listener);
|
|
979
|
+
return () => listeners.delete(listener);
|
|
980
|
+
}
|
|
981
|
+
};
|
|
809
982
|
}
|
|
810
983
|
|
|
811
984
|
// src/host-events.ts
|
|
@@ -2237,7 +2410,7 @@ var en = {
|
|
|
2237
2410
|
"hud.throw": "throw",
|
|
2238
2411
|
"hud.tilt": "tilt (hold)",
|
|
2239
2412
|
"hud.equip": "equip {weapon}",
|
|
2240
|
-
"ui.help": "Click: look \xB7 WASD: walk \xB7 Shift: run \xB7 C: crouch \xB7 Space: jump \xB7 1-0 / wheel: tool \xB7 LMB: use \xB7 E: grab/drop \xB7 G or RMB: throw \xB7 R: reload \xB7 Q: fire mode \xB7 X: clear a jam \xB7 B: safety \xB7 Y: detonate charges set down \xB7 Tab: panels \xB7 Esc: free the mouse",
|
|
2413
|
+
"ui.help": "Click: look \xB7 WASD: walk \xB7 Shift: run \xB7 C: crouch \xB7 Space: jump \xB7 1-0 / wheel: tool \xB7 LMB: use (bare hands: punch) \xB7 E: grab/drop \xB7 G or RMB: throw \xB7 R: reload \xB7 Q: fire mode \xB7 X: clear a jam \xB7 B: safety \xB7 Y: detonate charges set down \xB7 Tab: panels \xB7 Esc: free the mouse",
|
|
2241
2414
|
"ui.help.camera": "V: 1st/3rd person (Shift+V: kick)",
|
|
2242
2415
|
"camera.first": "1st person",
|
|
2243
2416
|
"camera.third": "3rd person",
|
|
@@ -2251,6 +2424,32 @@ var en = {
|
|
|
2251
2424
|
"ui.copy_json": "Copy JSON",
|
|
2252
2425
|
"ui.download_ndjson": "Download NDJSON",
|
|
2253
2426
|
"ui.download_txt": "Download TXT",
|
|
2427
|
+
"ui.test_table": "Test table",
|
|
2428
|
+
"ui.test_table.group": "Group to lay on the table",
|
|
2429
|
+
"ui.test_table.lay": "Lay",
|
|
2430
|
+
"ui.test_table.prev": "Previous items",
|
|
2431
|
+
"ui.test_table.next": "Next items",
|
|
2432
|
+
"ui.test_table.relay": "Put back",
|
|
2433
|
+
"ui.test_table.search": "Find an item to put on the table",
|
|
2434
|
+
"ui.test_table.hint": "Pick a group and lay it on the table, then pick an item and try it.",
|
|
2435
|
+
"ui.test_table.page": "Items {from}\u2013{to} of {total}. Pick one, then a trial:",
|
|
2436
|
+
"ui.trial.shot": "Shot",
|
|
2437
|
+
"ui.trial.punch": "Punch",
|
|
2438
|
+
"ui.trial.stab": "Knife",
|
|
2439
|
+
"ui.trial.fire": "Fire",
|
|
2440
|
+
"ui.trial.blast": "Blast",
|
|
2441
|
+
"ui.trial.shot.hint": "A 9 mm round from 2.5 m",
|
|
2442
|
+
"ui.trial.punch.hint": "A punch, up close",
|
|
2443
|
+
"ui.trial.stab.hint": "A knife blow, up close",
|
|
2444
|
+
"ui.trial.fire.hint": "A flamethrower burst from 1.6 m",
|
|
2445
|
+
"ui.trial.blast.hint": "A fragmentation grenade goes off just behind it (it reaches the neighbours too)",
|
|
2446
|
+
"act.test_table": "Test table: {group}, items {from}\u2013{to} of {total}",
|
|
2447
|
+
"act.trial.shot": "Trial: shooting {name}",
|
|
2448
|
+
"act.trial.punch": "Trial: punching {name}",
|
|
2449
|
+
"act.trial.stab": "Trial: stabbing {name}",
|
|
2450
|
+
"act.trial.fire": "Trial: setting fire to {name}",
|
|
2451
|
+
"act.trial.blast": "Trial: a blast beside {name}",
|
|
2452
|
+
"arena.test_table": "Test table",
|
|
2254
2453
|
"ui.clear_log": "Clear",
|
|
2255
2454
|
"ui.catalog": "Catalogue",
|
|
2256
2455
|
"ui.clear": "Clear",
|
|
@@ -2518,7 +2717,7 @@ var ptBR = {
|
|
|
2518
2717
|
"hud.throw": "arremessar",
|
|
2519
2718
|
"hud.tilt": "inclinar (segurar)",
|
|
2520
2719
|
"hud.equip": "equipar {weapon}",
|
|
2521
|
-
"ui.help": "Clique: olhar \xB7 WASD: andar \xB7 Shift: correr \xB7 C: agachar \xB7 Espa\xE7o: pular \xB7 1-0 / roda: ferramenta \xB7 bot\xE3o esquerdo: usar \xB7 E: pegar/soltar \xB7 G ou bot\xE3o direito: arremessar \xB7 R: recarregar \xB7 Q: modo de tiro \xB7 X: destravar \xB7 B: trava \xB7 Y: detonar cargas postas \xB7 Tab: pain\xE9is \xB7 Esc: soltar o mouse",
|
|
2720
|
+
"ui.help": "Clique: olhar \xB7 WASD: andar \xB7 Shift: correr \xB7 C: agachar \xB7 Espa\xE7o: pular \xB7 1-0 / roda: ferramenta \xB7 bot\xE3o esquerdo: usar (m\xE3o livre: soco) \xB7 E: pegar/soltar \xB7 G ou bot\xE3o direito: arremessar \xB7 R: recarregar \xB7 Q: modo de tiro \xB7 X: destravar \xB7 B: trava \xB7 Y: detonar cargas postas \xB7 Tab: pain\xE9is \xB7 Esc: soltar o mouse",
|
|
2522
2721
|
"ui.help.camera": "V: 1\xAA/3\xAA pessoa (Shift+V: chute)",
|
|
2523
2722
|
"camera.first": "1\xAA pessoa",
|
|
2524
2723
|
"camera.third": "3\xAA pessoa",
|
|
@@ -2532,6 +2731,32 @@ var ptBR = {
|
|
|
2532
2731
|
"ui.copy_json": "Copiar JSON",
|
|
2533
2732
|
"ui.download_ndjson": "Baixar NDJSON",
|
|
2534
2733
|
"ui.download_txt": "Baixar TXT",
|
|
2734
|
+
"ui.test_table": "Mesa de testes",
|
|
2735
|
+
"ui.test_table.group": "Grupo para p\xF4r na mesa",
|
|
2736
|
+
"ui.test_table.lay": "P\xF4r na mesa",
|
|
2737
|
+
"ui.test_table.prev": "Itens anteriores",
|
|
2738
|
+
"ui.test_table.next": "Pr\xF3ximos itens",
|
|
2739
|
+
"ui.test_table.relay": "Repor",
|
|
2740
|
+
"ui.test_table.search": "Buscar item para p\xF4r na mesa",
|
|
2741
|
+
"ui.test_table.hint": "Escolha um grupo e ponha na mesa; depois escolha um item e teste.",
|
|
2742
|
+
"ui.test_table.page": "Itens {from}\u2013{to} de {total}. Escolha um e um teste:",
|
|
2743
|
+
"ui.trial.shot": "Tiro",
|
|
2744
|
+
"ui.trial.punch": "Soco",
|
|
2745
|
+
"ui.trial.stab": "Faca",
|
|
2746
|
+
"ui.trial.fire": "Fogo",
|
|
2747
|
+
"ui.trial.blast": "Explos\xE3o",
|
|
2748
|
+
"ui.trial.shot.hint": "Um tiro de 9 mm a 2,5 m",
|
|
2749
|
+
"ui.trial.punch.hint": "Um soco, de perto",
|
|
2750
|
+
"ui.trial.stab.hint": "Um golpe de faca, de perto",
|
|
2751
|
+
"ui.trial.fire.hint": "Uma rajada de lan\xE7a-chamas a 1,6 m",
|
|
2752
|
+
"ui.trial.blast.hint": "Uma granada de fragmenta\xE7\xE3o explode logo atr\xE1s dele (pega os vizinhos tamb\xE9m)",
|
|
2753
|
+
"act.test_table": "Mesa de testes: {group}, itens {from}\u2013{to} de {total}",
|
|
2754
|
+
"act.trial.shot": "Teste: tiro em {name}",
|
|
2755
|
+
"act.trial.punch": "Teste: soco em {name}",
|
|
2756
|
+
"act.trial.stab": "Teste: faca em {name}",
|
|
2757
|
+
"act.trial.fire": "Teste: fogo em {name}",
|
|
2758
|
+
"act.trial.blast": "Teste: explos\xE3o ao lado de {name}",
|
|
2759
|
+
"arena.test_table": "Mesa de testes",
|
|
2535
2760
|
"ui.clear_log": "Limpar",
|
|
2536
2761
|
"ui.catalog": "Cat\xE1logo",
|
|
2537
2762
|
"ui.clear": "Limpar",
|
|
@@ -2873,6 +3098,122 @@ function createBenchPanel(o) {
|
|
|
2873
3098
|
};
|
|
2874
3099
|
}
|
|
2875
3100
|
|
|
3101
|
+
// src/test-table-panel.ts
|
|
3102
|
+
var TEST_TABLE_CSS = `
|
|
3103
|
+
.tr-table{flex:0 0 auto;max-height:42%}
|
|
3104
|
+
.tr-table .sub{color:#9aa3b2;margin:4px 0}
|
|
3105
|
+
.tr-table .list{display:flex;flex-wrap:wrap;gap:3px}
|
|
3106
|
+
.tr-table .list .tr-btn{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
3107
|
+
.tr-table select{flex:1;min-width:0;max-width:55%}
|
|
3108
|
+
.tr-table .tr-search{margin:6px 0 0}
|
|
3109
|
+
.tr-root .tr-table button.tr-btn.on{background:#3b3a14;border-color:#ffd23f;color:#fff}
|
|
3110
|
+
`;
|
|
3111
|
+
var mk2 = (tag, cls, text) => {
|
|
3112
|
+
const e = document.createElement(tag);
|
|
3113
|
+
if (cls) e.className = cls;
|
|
3114
|
+
if (text !== void 0) e.textContent = text;
|
|
3115
|
+
return e;
|
|
3116
|
+
};
|
|
3117
|
+
function createTestTablePanel(table, t) {
|
|
3118
|
+
const element = mk2("div", "tr-panel tr-table");
|
|
3119
|
+
element.appendChild(mk2("h3", void 0, t("ui.test_table")));
|
|
3120
|
+
const head = mk2("div", "tr-row");
|
|
3121
|
+
const select = mk2("select");
|
|
3122
|
+
select.setAttribute("aria-label", t("ui.test_table.group"));
|
|
3123
|
+
const lay = mk2("button", "tr-btn", t("ui.test_table.lay"));
|
|
3124
|
+
const prev = mk2("button", "tr-btn", "\u25C0");
|
|
3125
|
+
const next = mk2("button", "tr-btn", "\u25B6");
|
|
3126
|
+
prev.title = t("ui.test_table.prev");
|
|
3127
|
+
next.title = t("ui.test_table.next");
|
|
3128
|
+
for (const b of [lay, prev, next]) b.type = "button";
|
|
3129
|
+
head.append(select, lay, prev, next);
|
|
3130
|
+
const search = mk2("input", "tr-search");
|
|
3131
|
+
search.type = "search";
|
|
3132
|
+
search.placeholder = t("ui.test_table.search");
|
|
3133
|
+
const found = mk2("div", "list");
|
|
3134
|
+
const sub = mk2("div", "sub", t("ui.test_table.hint"));
|
|
3135
|
+
const list = mk2("div", "list");
|
|
3136
|
+
const trials = mk2("div", "tr-row");
|
|
3137
|
+
const trialButtons = TRIAL_KINDS.map((kind) => {
|
|
3138
|
+
const b = mk2("button", "tr-btn", t(`ui.trial.${kind}`));
|
|
3139
|
+
b.type = "button";
|
|
3140
|
+
b.dataset.trial = kind;
|
|
3141
|
+
b.title = t(`ui.trial.${kind}.hint`);
|
|
3142
|
+
b.onclick = () => table.trial(kind);
|
|
3143
|
+
trials.appendChild(b);
|
|
3144
|
+
return b;
|
|
3145
|
+
});
|
|
3146
|
+
const relay = mk2("button", "tr-btn", t("ui.test_table.relay"));
|
|
3147
|
+
relay.type = "button";
|
|
3148
|
+
relay.onclick = () => table.relay();
|
|
3149
|
+
trials.appendChild(relay);
|
|
3150
|
+
element.append(head, search, found, sub, list, trials);
|
|
3151
|
+
const groups = () => {
|
|
3152
|
+
const keep = select.value;
|
|
3153
|
+
select.textContent = "";
|
|
3154
|
+
for (const group of table.groups()) {
|
|
3155
|
+
const op = mk2("option", void 0, group);
|
|
3156
|
+
op.value = group;
|
|
3157
|
+
select.appendChild(op);
|
|
3158
|
+
}
|
|
3159
|
+
if ([...select.options].some((o) => o.value === keep)) select.value = keep;
|
|
3160
|
+
};
|
|
3161
|
+
const render = (page) => {
|
|
3162
|
+
list.textContent = "";
|
|
3163
|
+
prev.disabled = !page?.hasPrev;
|
|
3164
|
+
next.disabled = !page?.hasNext;
|
|
3165
|
+
for (const b of [...trialButtons, relay]) b.disabled = !page?.selected;
|
|
3166
|
+
if (!page) {
|
|
3167
|
+
sub.textContent = t("ui.test_table.hint");
|
|
3168
|
+
return;
|
|
3169
|
+
}
|
|
3170
|
+
if (select.value !== page.group) select.value = page.group;
|
|
3171
|
+
sub.textContent = t("ui.test_table.page", { from: page.first + 1, to: page.first + page.objects.length, total: page.total });
|
|
3172
|
+
for (const o of page.objects) {
|
|
3173
|
+
const b = mk2("button", o.objectId === page.selected ? "tr-btn on" : "tr-btn", o.name);
|
|
3174
|
+
b.type = "button";
|
|
3175
|
+
b.title = o.itemId;
|
|
3176
|
+
b.onclick = () => table.select(o.objectId);
|
|
3177
|
+
list.appendChild(b);
|
|
3178
|
+
}
|
|
3179
|
+
};
|
|
3180
|
+
const fold2 = (text) => text.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
|
|
3181
|
+
search.oninput = () => {
|
|
3182
|
+
found.textContent = "";
|
|
3183
|
+
const term = fold2(search.value.trim());
|
|
3184
|
+
if (!term) return;
|
|
3185
|
+
const hits = table.items().filter((item) => fold2(`${item.name} ${item.id}`).includes(term)).slice(0, 8);
|
|
3186
|
+
for (const item of hits) {
|
|
3187
|
+
const b = mk2("button", "tr-btn", item.name);
|
|
3188
|
+
b.type = "button";
|
|
3189
|
+
b.title = `${item.group} \xB7 ${item.id}`;
|
|
3190
|
+
b.onclick = () => {
|
|
3191
|
+
search.value = "";
|
|
3192
|
+
found.textContent = "";
|
|
3193
|
+
table.find(item.id);
|
|
3194
|
+
};
|
|
3195
|
+
found.appendChild(b);
|
|
3196
|
+
}
|
|
3197
|
+
if (!hits.length) found.appendChild(mk2("div", "sub", t("ui.no_results")));
|
|
3198
|
+
};
|
|
3199
|
+
lay.onclick = () => table.open(select.value);
|
|
3200
|
+
prev.onclick = () => table.prev();
|
|
3201
|
+
next.onclick = () => table.next();
|
|
3202
|
+
select.onchange = () => table.open(select.value);
|
|
3203
|
+
for (const box2 of [select, search]) box2.addEventListener("keydown", (e) => e.stopPropagation());
|
|
3204
|
+
const off = table.on(render);
|
|
3205
|
+
groups();
|
|
3206
|
+
render(table.state());
|
|
3207
|
+
return {
|
|
3208
|
+
element,
|
|
3209
|
+
refresh: () => {
|
|
3210
|
+
groups();
|
|
3211
|
+
render(table.state());
|
|
3212
|
+
},
|
|
3213
|
+
dispose: off
|
|
3214
|
+
};
|
|
3215
|
+
}
|
|
3216
|
+
|
|
2876
3217
|
// src/ui.ts
|
|
2877
3218
|
var CSS = `
|
|
2878
3219
|
.tr-root{position:absolute;inset:0;pointer-events:none;font:12px/1.35 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;color:#e8eaee;overflow:hidden}
|
|
@@ -2951,7 +3292,7 @@ var CSS = `
|
|
|
2951
3292
|
@media (max-width:980px){.tr-left,.tr-right{display:none}.tr-root.open .tr-left,.tr-root.open .tr-right{display:flex}.tr-toggle{display:block;pointer-events:auto}.tr-root.open .tr-toggle{right:min(310px,34vw)}.tr-left{width:min(400px,46vw)}.tr-help{display:none}}
|
|
2952
3293
|
`;
|
|
2953
3294
|
var fold = (text) => text.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
|
|
2954
|
-
var
|
|
3295
|
+
var mk3 = (tag, cls, text) => {
|
|
2955
3296
|
const e = document.createElement(tag);
|
|
2956
3297
|
if (cls) e.className = cls;
|
|
2957
3298
|
if (text !== void 0) e.textContent = text;
|
|
@@ -2962,7 +3303,7 @@ var thumbSource = (thumbnail) => {
|
|
|
2962
3303
|
return source.replace(/["\\\n\r]/g, (char) => encodeURIComponent(char));
|
|
2963
3304
|
};
|
|
2964
3305
|
var thumb = (thumbnail, credit) => {
|
|
2965
|
-
const e =
|
|
3306
|
+
const e = mk3("span", "tr-thumb");
|
|
2966
3307
|
if (credit) e.title = credit;
|
|
2967
3308
|
else e.setAttribute("aria-hidden", "true");
|
|
2968
3309
|
e.style.setProperty("--tr-thumb", `url("${thumbSource(thumbnail)}")`);
|
|
@@ -2983,42 +3324,43 @@ async function toggleFullscreen() {
|
|
|
2983
3324
|
}
|
|
2984
3325
|
function createUi(o) {
|
|
2985
3326
|
const { t } = o;
|
|
2986
|
-
const style =
|
|
2987
|
-
style.textContent = CSS;
|
|
2988
|
-
const root =
|
|
3327
|
+
const style = mk3("style");
|
|
3328
|
+
style.textContent = CSS + (o.testTable ? TEST_TABLE_CSS : "");
|
|
3329
|
+
const root = mk3("div", "tr-root");
|
|
2989
3330
|
const pos = getComputedStyle?.(o.container)?.position;
|
|
2990
3331
|
if (!pos || pos === "static") o.container.style.position = "relative";
|
|
2991
3332
|
root.appendChild(style);
|
|
2992
3333
|
o.container.appendChild(root);
|
|
2993
|
-
const cross =
|
|
2994
|
-
cross.appendChild(
|
|
2995
|
-
const top =
|
|
2996
|
-
const toolBox =
|
|
2997
|
-
const status =
|
|
2998
|
-
const prog =
|
|
2999
|
-
const progLabel =
|
|
3000
|
-
const progBar =
|
|
3001
|
-
const progFill =
|
|
3334
|
+
const cross = mk3("div", "tr-cross");
|
|
3335
|
+
cross.appendChild(mk3("i"));
|
|
3336
|
+
const top = mk3("div", "tr-top");
|
|
3337
|
+
const toolBox = mk3("div", "tr-tool");
|
|
3338
|
+
const status = mk3("div", "tr-status");
|
|
3339
|
+
const prog = mk3("div", "tr-prog");
|
|
3340
|
+
const progLabel = mk3("b");
|
|
3341
|
+
const progBar = mk3("div", "tr-bar");
|
|
3342
|
+
const progFill = mk3("i");
|
|
3002
3343
|
progBar.appendChild(progFill);
|
|
3003
3344
|
prog.append(progLabel, progBar);
|
|
3004
3345
|
top.append(toolBox, status, prog);
|
|
3005
|
-
const bottom =
|
|
3006
|
-
const held =
|
|
3007
|
-
const hotbar =
|
|
3346
|
+
const bottom = mk3("div", "tr-bottom");
|
|
3347
|
+
const held = mk3("div", "tr-held");
|
|
3348
|
+
const hotbar = mk3("div", "tr-hotbar");
|
|
3008
3349
|
bottom.append(held, hotbar);
|
|
3009
|
-
const help =
|
|
3350
|
+
const help = mk3("div", "tr-help");
|
|
3010
3351
|
help.textContent = t("ui.help");
|
|
3011
|
-
const left =
|
|
3012
|
-
const insp =
|
|
3013
|
-
const logPanel =
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
const
|
|
3017
|
-
const
|
|
3352
|
+
const left = mk3("div", "tr-left");
|
|
3353
|
+
const insp = mk3("div", "tr-panel tr-insp");
|
|
3354
|
+
const logPanel = mk3("div", "tr-panel tr-log");
|
|
3355
|
+
const tablePanel = o.testTable ? createTestTablePanel(o.testTable, t) : null;
|
|
3356
|
+
left.append(insp, ...tablePanel ? [tablePanel.element] : [], logPanel);
|
|
3357
|
+
const logTitle = mk3("h3", void 0, t("ui.log"));
|
|
3358
|
+
const logBar = mk3("div", "tr-logbar");
|
|
3359
|
+
const logBody = mk3("div", "tr-logbody");
|
|
3018
3360
|
const filters = { action: true, event: true, check: true };
|
|
3019
3361
|
const filterBtns = [];
|
|
3020
3362
|
for (const ch of ["action", "event", "check"]) {
|
|
3021
|
-
const b =
|
|
3363
|
+
const b = mk3("button", "tr-btn on", t(`ui.filter.${ch}`));
|
|
3022
3364
|
b.type = "button";
|
|
3023
3365
|
b.onclick = () => {
|
|
3024
3366
|
filters[ch] = !filters[ch];
|
|
@@ -3029,8 +3371,8 @@ function createUi(o) {
|
|
|
3029
3371
|
logBar.appendChild(b);
|
|
3030
3372
|
}
|
|
3031
3373
|
let autoscroll = true;
|
|
3032
|
-
const asLabel =
|
|
3033
|
-
const asBox =
|
|
3374
|
+
const asLabel = mk3("label");
|
|
3375
|
+
const asBox = mk3("input");
|
|
3034
3376
|
asBox.type = "checkbox";
|
|
3035
3377
|
asBox.checked = true;
|
|
3036
3378
|
asBox.onchange = () => {
|
|
@@ -3039,7 +3381,7 @@ function createUi(o) {
|
|
|
3039
3381
|
asLabel.append(asBox, document.createTextNode(" " + t("ui.autoscroll")));
|
|
3040
3382
|
logBar.appendChild(asLabel);
|
|
3041
3383
|
const logBtn = (label, fn) => {
|
|
3042
|
-
const b =
|
|
3384
|
+
const b = mk3("button", "tr-btn", label);
|
|
3043
3385
|
b.type = "button";
|
|
3044
3386
|
b.onclick = fn;
|
|
3045
3387
|
logBar.appendChild(b);
|
|
@@ -3047,7 +3389,7 @@ function createUi(o) {
|
|
|
3047
3389
|
logBtn(t("ui.copy_json"), () => {
|
|
3048
3390
|
const text = o.log.toJSON();
|
|
3049
3391
|
const select = () => {
|
|
3050
|
-
const ta =
|
|
3392
|
+
const ta = mk3("textarea");
|
|
3051
3393
|
ta.value = text;
|
|
3052
3394
|
ta.setAttribute("readonly", "");
|
|
3053
3395
|
ta.style.cssText = "position:fixed;left:8px;bottom:8px;width:min(480px,80vw);height:120px;z-index:99999";
|
|
@@ -3081,12 +3423,12 @@ function createUi(o) {
|
|
|
3081
3423
|
const fill = (n, e) => {
|
|
3082
3424
|
n.className = lineClass(e);
|
|
3083
3425
|
n.textContent = "";
|
|
3084
|
-
const tm =
|
|
3426
|
+
const tm = mk3("time", void 0, fmtTime(e.t));
|
|
3085
3427
|
n.append(tm, document.createTextNode(e.text));
|
|
3086
3428
|
};
|
|
3087
3429
|
const addNode = (e) => {
|
|
3088
3430
|
if (!filters[e.channel]) return;
|
|
3089
|
-
const n =
|
|
3431
|
+
const n = mk3("div");
|
|
3090
3432
|
fill(n, e);
|
|
3091
3433
|
nodes.set(e.seq, n);
|
|
3092
3434
|
logBody.appendChild(n);
|
|
@@ -3108,18 +3450,18 @@ function createUi(o) {
|
|
|
3108
3450
|
if (n) fill(n, e);
|
|
3109
3451
|
} else addNode(e);
|
|
3110
3452
|
});
|
|
3111
|
-
const right =
|
|
3112
|
-
const cat =
|
|
3113
|
-
const anim =
|
|
3114
|
-
const tests =
|
|
3453
|
+
const right = mk3("div", "tr-right");
|
|
3454
|
+
const cat = mk3("div", "tr-panel tr-cat");
|
|
3455
|
+
const anim = mk3("div", "tr-panel tr-anim");
|
|
3456
|
+
const tests = mk3("div", "tr-panel tr-tests");
|
|
3115
3457
|
const benchPanel = createBenchPanel({ t, num: (n, d) => num(n, d), onControl: o.onControl, onLayer: o.onLayer, onAction: o.onAction });
|
|
3116
3458
|
right.append(cat, anim, benchPanel.element, tests);
|
|
3117
|
-
cat.appendChild(
|
|
3118
|
-
const itemSearch =
|
|
3459
|
+
cat.appendChild(mk3("h3", void 0, t("ui.catalog")));
|
|
3460
|
+
const itemSearch = mk3("input", "tr-search");
|
|
3119
3461
|
itemSearch.type = "search";
|
|
3120
3462
|
itemSearch.placeholder = t("ui.search_items");
|
|
3121
|
-
const tabs =
|
|
3122
|
-
const items =
|
|
3463
|
+
const tabs = mk3("div", "tr-tabs");
|
|
3464
|
+
const items = mk3("div", "tr-items");
|
|
3123
3465
|
cat.append(itemSearch, tabs, items);
|
|
3124
3466
|
let activeGroup = "";
|
|
3125
3467
|
const visibleItems = () => {
|
|
@@ -3131,18 +3473,18 @@ function createUi(o) {
|
|
|
3131
3473
|
items.textContent = "";
|
|
3132
3474
|
const searching = itemSearch.value.trim() !== "";
|
|
3133
3475
|
const found = visibleItems();
|
|
3134
|
-
if (!found.length) items.appendChild(
|
|
3476
|
+
if (!found.length) items.appendChild(mk3("div", "tr-empty", t("ui.no_results")));
|
|
3135
3477
|
for (const { item: it, group } of found) {
|
|
3136
|
-
const wrap =
|
|
3137
|
-
const b =
|
|
3138
|
-
if (it.thumbnail) b.append(thumb(it.thumbnail),
|
|
3139
|
-
if (searching) b.appendChild(
|
|
3478
|
+
const wrap = mk3("div", "tr-item");
|
|
3479
|
+
const b = mk3("button", it.thumbnail ? "tr-btn has-thumb" : "tr-btn", it.thumbnail ? void 0 : it.name);
|
|
3480
|
+
if (it.thumbnail) b.append(thumb(it.thumbnail), mk3("span", "tr-name", it.name));
|
|
3481
|
+
if (searching) b.appendChild(mk3("small", void 0, group));
|
|
3140
3482
|
b.type = "button";
|
|
3141
3483
|
b.title = it.note ?? it.name;
|
|
3142
3484
|
b.onclick = () => o.onSpawn(it.id);
|
|
3143
3485
|
wrap.appendChild(b);
|
|
3144
3486
|
if (it.weapon) {
|
|
3145
|
-
const w =
|
|
3487
|
+
const w = mk3("button", "tr-btn", "\u2694");
|
|
3146
3488
|
w.type = "button";
|
|
3147
3489
|
w.title = t("ui.equip");
|
|
3148
3490
|
w.onclick = () => o.onEquip(it.id);
|
|
@@ -3156,7 +3498,7 @@ function createUi(o) {
|
|
|
3156
3498
|
const groupNames = [...o.groups().keys()];
|
|
3157
3499
|
if (!groupNames.includes(activeGroup)) activeGroup = groupNames[0] ?? "";
|
|
3158
3500
|
for (const g of groupNames) {
|
|
3159
|
-
const b =
|
|
3501
|
+
const b = mk3("button", g === activeGroup ? "tr-btn on" : "tr-btn", g);
|
|
3160
3502
|
b.type = "button";
|
|
3161
3503
|
b.onclick = () => {
|
|
3162
3504
|
activeGroup = g;
|
|
@@ -3169,9 +3511,9 @@ function createUi(o) {
|
|
|
3169
3511
|
renderTabs();
|
|
3170
3512
|
itemSearch.oninput = renderItems;
|
|
3171
3513
|
for (const box2 of [itemSearch]) box2.addEventListener("keydown", (e) => e.stopPropagation());
|
|
3172
|
-
const controls =
|
|
3514
|
+
const controls = mk3("div", "tr-row");
|
|
3173
3515
|
const ctl = (label, fn) => {
|
|
3174
|
-
const b =
|
|
3516
|
+
const b = mk3("button", "tr-btn", label);
|
|
3175
3517
|
b.type = "button";
|
|
3176
3518
|
b.onclick = () => fn(b);
|
|
3177
3519
|
controls.appendChild(b);
|
|
@@ -3196,29 +3538,29 @@ function createUi(o) {
|
|
|
3196
3538
|
fullscreenBtn.title = t("ui.fullscreen.hint");
|
|
3197
3539
|
const blastBtns = ["shelter", "fragmentHits", "confinement"].map((key) => ({ key, b: ctl(t(`ui.blast.${key}`), () => o.onBlast(key)) }));
|
|
3198
3540
|
for (const { key, b } of blastBtns) b.title = t(`ui.blast.${key}.hint`);
|
|
3199
|
-
const qSel =
|
|
3541
|
+
const qSel = mk3("select");
|
|
3200
3542
|
for (const q of ["low", "medium", "high"]) {
|
|
3201
|
-
const op =
|
|
3543
|
+
const op = mk3("option", void 0, t(`ui.quality.${q}`));
|
|
3202
3544
|
op.value = q;
|
|
3203
3545
|
qSel.appendChild(op);
|
|
3204
3546
|
}
|
|
3205
3547
|
qSel.value = o.quality;
|
|
3206
3548
|
qSel.onchange = () => o.onQuality(qSel.value);
|
|
3207
|
-
const qLabel =
|
|
3549
|
+
const qLabel = mk3("label", void 0, t("ui.quality") + " ");
|
|
3208
3550
|
qLabel.appendChild(qSel);
|
|
3209
3551
|
controls.appendChild(qLabel);
|
|
3210
|
-
const count =
|
|
3552
|
+
const count = mk3("span");
|
|
3211
3553
|
controls.appendChild(count);
|
|
3212
3554
|
cat.appendChild(controls);
|
|
3213
|
-
tests.appendChild(
|
|
3214
|
-
const runAll =
|
|
3555
|
+
tests.appendChild(mk3("h3", void 0, t("ui.tests")));
|
|
3556
|
+
const runAll = mk3("button", "tr-btn", t("ui.run_all"));
|
|
3215
3557
|
runAll.type = "button";
|
|
3216
|
-
const summary =
|
|
3217
|
-
const testSearch =
|
|
3558
|
+
const summary = mk3("div", "tr-summary");
|
|
3559
|
+
const testSearch = mk3("input", "tr-search");
|
|
3218
3560
|
testSearch.type = "search";
|
|
3219
3561
|
testSearch.placeholder = t("ui.search_tests");
|
|
3220
3562
|
testSearch.addEventListener("keydown", (e) => e.stopPropagation());
|
|
3221
|
-
const list =
|
|
3563
|
+
const list = mk3("div", "list");
|
|
3222
3564
|
tests.append(runAll, summary, testSearch, list);
|
|
3223
3565
|
testSearch.oninput = () => {
|
|
3224
3566
|
const term = fold(testSearch.value.trim());
|
|
@@ -3241,7 +3583,7 @@ function createUi(o) {
|
|
|
3241
3583
|
list.textContent = "";
|
|
3242
3584
|
scBtns.clear();
|
|
3243
3585
|
for (const s of o.scenarios()) {
|
|
3244
|
-
const b =
|
|
3586
|
+
const b = mk3("button", "tr-btn", s.name);
|
|
3245
3587
|
b.type = "button";
|
|
3246
3588
|
b.onclick = async () => {
|
|
3247
3589
|
if (busy) return;
|
|
@@ -3267,7 +3609,7 @@ function createUi(o) {
|
|
|
3267
3609
|
busy = false;
|
|
3268
3610
|
}
|
|
3269
3611
|
};
|
|
3270
|
-
const toggle =
|
|
3612
|
+
const toggle = mk3("button", "tr-btn tr-toggle", t("ui.panel"));
|
|
3271
3613
|
toggle.type = "button";
|
|
3272
3614
|
const togglePanels = () => {
|
|
3273
3615
|
root.classList.toggle("open");
|
|
@@ -3276,15 +3618,15 @@ function createUi(o) {
|
|
|
3276
3618
|
toggle.onclick = togglePanels;
|
|
3277
3619
|
root.append(cross, top, bottom, help, left, right, toggle);
|
|
3278
3620
|
const bar = (value, max, cls) => {
|
|
3279
|
-
const b =
|
|
3280
|
-
const i =
|
|
3621
|
+
const b = mk3("div", `tr-bar ${cls}`);
|
|
3622
|
+
const i = mk3("i");
|
|
3281
3623
|
i.style.width = `${Math.max(0, Math.min(100, value / Math.max(1e-9, max) * 100))}%`;
|
|
3282
3624
|
b.appendChild(i);
|
|
3283
3625
|
return b;
|
|
3284
3626
|
};
|
|
3285
3627
|
const row = (k, v) => {
|
|
3286
|
-
const r =
|
|
3287
|
-
r.append(
|
|
3628
|
+
const r = mk3("div", "r");
|
|
3629
|
+
r.append(mk3("span", void 0, k), mk3("span", void 0, v));
|
|
3288
3630
|
return r;
|
|
3289
3631
|
};
|
|
3290
3632
|
const num = (n, d = 1) => {
|
|
@@ -3293,13 +3635,13 @@ function createUi(o) {
|
|
|
3293
3635
|
};
|
|
3294
3636
|
const renderInspector = (i) => {
|
|
3295
3637
|
insp.textContent = "";
|
|
3296
|
-
insp.appendChild(
|
|
3638
|
+
insp.appendChild(mk3("h3", void 0, t("ui.inspector")));
|
|
3297
3639
|
if (!i) {
|
|
3298
|
-
insp.appendChild(
|
|
3640
|
+
insp.appendChild(mk3("div", void 0, t("ui.aim_at_something")));
|
|
3299
3641
|
return;
|
|
3300
3642
|
}
|
|
3301
3643
|
if (i.thumbnail) insp.appendChild(thumb(i.thumbnail, i.thumbnailCredit));
|
|
3302
|
-
insp.appendChild(
|
|
3644
|
+
insp.appendChild(mk3("div", "t", `${i.object} \u203A ${i.part}`));
|
|
3303
3645
|
insp.appendChild(row(t("ins.material"), i.material));
|
|
3304
3646
|
insp.appendChild(row(t("ins.status"), i.status + (i.burning ? ` \xB7 ${t("ins.burning")}` : "")));
|
|
3305
3647
|
insp.appendChild(row(t("ins.hp"), `${num(i.hp, 0)} / ${num(i.maxHp, 0)}`));
|
|
@@ -3318,30 +3660,30 @@ function createUi(o) {
|
|
|
3318
3660
|
insp.appendChild(bar(Math.min(i.stress, 1.2), 1.2, i.stress > 1 ? "bad" : i.stress > 0.7 ? "warn" : "hp"));
|
|
3319
3661
|
}
|
|
3320
3662
|
if (i.joints.length) {
|
|
3321
|
-
insp.appendChild(
|
|
3663
|
+
insp.appendChild(mk3("div", void 0, t("ins.joints") + ":"));
|
|
3322
3664
|
for (const j of i.joints) {
|
|
3323
3665
|
const tools = j.tools.length ? j.tools.join(", ") : t("tool.none");
|
|
3324
|
-
insp.appendChild(
|
|
3666
|
+
insp.appendChild(mk3("div", void 0, `\u2022 ${j.kind} (${j.id})${j.open ? ` \xB7 ${t("ins.open")}` : ` \u2192 ${tools}`}`));
|
|
3325
3667
|
}
|
|
3326
3668
|
}
|
|
3327
|
-
if (i.note) insp.appendChild(
|
|
3669
|
+
if (i.note) insp.appendChild(mk3("div", void 0, i.note));
|
|
3328
3670
|
};
|
|
3329
3671
|
let lastAnim = "";
|
|
3330
3672
|
const renderAnimations = (a) => {
|
|
3331
3673
|
anim.textContent = "";
|
|
3332
|
-
anim.appendChild(
|
|
3674
|
+
anim.appendChild(mk3("h3", void 0, t("ui.animations")));
|
|
3333
3675
|
if (!a) {
|
|
3334
|
-
anim.appendChild(
|
|
3676
|
+
anim.appendChild(mk3("div", "sub", t("ui.animations_aim")));
|
|
3335
3677
|
return;
|
|
3336
3678
|
}
|
|
3337
|
-
anim.appendChild(
|
|
3679
|
+
anim.appendChild(mk3("div", "sub", a.name));
|
|
3338
3680
|
if (a.clips.length === 0) {
|
|
3339
|
-
anim.appendChild(
|
|
3681
|
+
anim.appendChild(mk3("div", "sub", t("ui.animations_none")));
|
|
3340
3682
|
return;
|
|
3341
3683
|
}
|
|
3342
|
-
const l =
|
|
3684
|
+
const l = mk3("div", "list");
|
|
3343
3685
|
for (const c of a.clips) {
|
|
3344
|
-
const b =
|
|
3686
|
+
const b = mk3("button", a.playing === c.id ? "tr-btn on" : "tr-btn", `\u25B6 ${t(`anim.${c.id}`) === `anim.${c.id}` ? c.id : t(`anim.${c.id}`)} (${num(c.duration, 1)} s)`);
|
|
3345
3687
|
b.type = "button";
|
|
3346
3688
|
b.onclick = () => o.onPlay(a.objectId, c.id);
|
|
3347
3689
|
l.appendChild(b);
|
|
@@ -3358,8 +3700,8 @@ function createUi(o) {
|
|
|
3358
3700
|
hud(s) {
|
|
3359
3701
|
toolBox.textContent = "";
|
|
3360
3702
|
toolBox.append(document.createTextNode(s.toolName));
|
|
3361
|
-
if (s.ammo) toolBox.append(
|
|
3362
|
-
if (s.camera) toolBox.append(
|
|
3703
|
+
if (s.ammo) toolBox.append(mk3("small", void 0, s.ammo));
|
|
3704
|
+
if (s.camera) toolBox.append(mk3("small", void 0, t(`camera.${s.camera}`)));
|
|
3363
3705
|
const helpText = s.camera ? `${t("ui.help")} \xB7 ${t("ui.help.camera")}` : t("ui.help");
|
|
3364
3706
|
if (help.textContent !== helpText) help.textContent = helpText;
|
|
3365
3707
|
if (s.status) status.textContent = s.status;
|
|
@@ -3382,7 +3724,7 @@ function createUi(o) {
|
|
|
3382
3724
|
];
|
|
3383
3725
|
if (s.held.weapon) keys.push(["H", t("hud.equip", { weapon: s.held.weapon })]);
|
|
3384
3726
|
for (const [k, label] of keys) {
|
|
3385
|
-
held.append(
|
|
3727
|
+
held.append(mk3("kbd", void 0, k), document.createTextNode(` ${label} `));
|
|
3386
3728
|
}
|
|
3387
3729
|
} else held.style.display = "none";
|
|
3388
3730
|
const key = s.slots.join("|") + s.page;
|
|
@@ -3392,9 +3734,9 @@ function createUi(o) {
|
|
|
3392
3734
|
slotsEl.length = 0;
|
|
3393
3735
|
hudPage = s.page - 1;
|
|
3394
3736
|
s.slots.forEach((name, i) => {
|
|
3395
|
-
const b =
|
|
3737
|
+
const b = mk3("button", "tr-slot");
|
|
3396
3738
|
b.type = "button";
|
|
3397
|
-
b.append(
|
|
3739
|
+
b.append(mk3("b", void 0, String((i + 1) % 10)), document.createTextNode(name));
|
|
3398
3740
|
b.title = name;
|
|
3399
3741
|
b.onclick = () => o.onTool(hudPage * 10 + i);
|
|
3400
3742
|
hotbar.appendChild(b);
|
|
@@ -3426,6 +3768,7 @@ function createUi(o) {
|
|
|
3426
3768
|
refresh() {
|
|
3427
3769
|
renderTabs();
|
|
3428
3770
|
renderScenarios();
|
|
3771
|
+
tablePanel?.refresh();
|
|
3429
3772
|
},
|
|
3430
3773
|
showGroup(group) {
|
|
3431
3774
|
activeGroup = group;
|
|
@@ -3440,6 +3783,7 @@ function createUi(o) {
|
|
|
3440
3783
|
},
|
|
3441
3784
|
dispose() {
|
|
3442
3785
|
offLog();
|
|
3786
|
+
tablePanel?.dispose();
|
|
3443
3787
|
if (toastTimer) clearTimeout(toastTimer);
|
|
3444
3788
|
root.remove();
|
|
3445
3789
|
}
|
|
@@ -4629,6 +4973,10 @@ function createTestRoom(options) {
|
|
|
4629
4973
|
heldPiece = null;
|
|
4630
4974
|
heldTilt = 0;
|
|
4631
4975
|
};
|
|
4976
|
+
const handUse = () => {
|
|
4977
|
+
if (heldPiece) grab();
|
|
4978
|
+
else useTool(FIXED_DT, false);
|
|
4979
|
+
};
|
|
4632
4980
|
const grab = () => {
|
|
4633
4981
|
if (heldPiece) {
|
|
4634
4982
|
const name = heldName;
|
|
@@ -5097,10 +5445,10 @@ function createTestRoom(options) {
|
|
|
5097
5445
|
if (tiltKey || heldTilt > 0) {
|
|
5098
5446
|
heldTilt = Math.max(0, Math.min(2.4, heldTilt + (tiltKey ? 2.2 : -3) * dt));
|
|
5099
5447
|
}
|
|
5100
|
-
if (useHeld && !paused) {
|
|
5448
|
+
if ((useHeld || useFirst) && !paused) {
|
|
5101
5449
|
if (tool.def.category === "hand") {
|
|
5102
|
-
if (useFirst)
|
|
5103
|
-
} else useTool(dt, !useFirst);
|
|
5450
|
+
if (useFirst) handUse();
|
|
5451
|
+
} else if (useHeld) useTool(dt, !useFirst);
|
|
5104
5452
|
useFirst = false;
|
|
5105
5453
|
}
|
|
5106
5454
|
if (!paused) followHeld(dt);
|
|
@@ -5655,6 +6003,63 @@ function createTestRoom(options) {
|
|
|
5655
6003
|
const row = (list, gap, z) => list.map((item, index) => spawn(item.id, [(index - (list.length - 1) / 2) * gap, 0, z], 0));
|
|
5656
6004
|
return [...row(front, 1.6, 1.5), ...row(back, 4.5, -4)];
|
|
5657
6005
|
};
|
|
6006
|
+
const catalogGroups = () => {
|
|
6007
|
+
const m = /* @__PURE__ */ new Map();
|
|
6008
|
+
for (const i of catalog) {
|
|
6009
|
+
const g = m.get(i.group) ?? [];
|
|
6010
|
+
g.push(i);
|
|
6011
|
+
m.set(i.group, g);
|
|
6012
|
+
}
|
|
6013
|
+
return m;
|
|
6014
|
+
};
|
|
6015
|
+
const tableOptions = options.testTable === false ? {} : options.testTable ?? {};
|
|
6016
|
+
const tableScenery = tableOptions.scenery ?? "test_table";
|
|
6017
|
+
const measured = /* @__PURE__ */ new Map();
|
|
6018
|
+
const testTable = createTestTable(
|
|
6019
|
+
{
|
|
6020
|
+
groups: catalogGroups,
|
|
6021
|
+
top: () => {
|
|
6022
|
+
const top = arena.tops.find((x) => x.id === tableScenery);
|
|
6023
|
+
return top && topOk(top) ? top : null;
|
|
6024
|
+
},
|
|
6025
|
+
measure: (itemId) => {
|
|
6026
|
+
let size = measured.get(itemId);
|
|
6027
|
+
if (!size) {
|
|
6028
|
+
const item = catalogMap.get(itemId);
|
|
6029
|
+
const box2 = item ? new THREE.Box3().setFromObject(buildRoot(item)) : null;
|
|
6030
|
+
size = box2 && !box2.isEmpty() ? { w: box2.max.x - box2.min.x, d: box2.max.z - box2.min.z } : { w: 0.3, d: 0.3 };
|
|
6031
|
+
measured.set(itemId, size);
|
|
6032
|
+
}
|
|
6033
|
+
return size;
|
|
6034
|
+
},
|
|
6035
|
+
spawn: (itemId, position) => spawn(itemId, position, 0),
|
|
6036
|
+
clear,
|
|
6037
|
+
resetAll,
|
|
6038
|
+
box: (objectId) => {
|
|
6039
|
+
const e = entries.get(objectId);
|
|
6040
|
+
if (!e || !world.has(objectId)) return null;
|
|
6041
|
+
const box2 = new THREE.Box3().setFromObject(e.so.root);
|
|
6042
|
+
return box2.isEmpty() ? null : { min: [box2.min.x, box2.min.y, box2.min.z], max: [box2.max.x, box2.max.y, box2.max.z] };
|
|
6043
|
+
},
|
|
6044
|
+
equip: (weapon) => {
|
|
6045
|
+
if (!arsenal.weapons.has(weapon)) return false;
|
|
6046
|
+
if (heldEntry) releaseHeld();
|
|
6047
|
+
equip(weapon);
|
|
6048
|
+
room.waitUntilReady();
|
|
6049
|
+
return true;
|
|
6050
|
+
},
|
|
6051
|
+
look: (eye, target) => player.look(eye, target),
|
|
6052
|
+
use: (hold) => room.use(hold),
|
|
6053
|
+
blastAt: (weapon, point) => {
|
|
6054
|
+
const def = arsenal.weapons.get(weapon);
|
|
6055
|
+
const explosive = def?.action.kind === "throwable" ? def.action.explosive : def?.action.kind === "launcher" ? def.action.projectile : void 0;
|
|
6056
|
+
return explosive !== void 0 && explosives.blastAt(weapon, explosive, point);
|
|
6057
|
+
},
|
|
6058
|
+
log: (type, text, data) => action(type, text, { data }),
|
|
6059
|
+
translate: t
|
|
6060
|
+
},
|
|
6061
|
+
tableOptions
|
|
6062
|
+
);
|
|
5658
6063
|
const room = {
|
|
5659
6064
|
world,
|
|
5660
6065
|
renderer,
|
|
@@ -5674,6 +6079,7 @@ function createTestRoom(options) {
|
|
|
5674
6079
|
get scenarios() {
|
|
5675
6080
|
return allScenarios();
|
|
5676
6081
|
},
|
|
6082
|
+
testTable,
|
|
5677
6083
|
spawn,
|
|
5678
6084
|
clear,
|
|
5679
6085
|
resetAll,
|
|
@@ -5681,7 +6087,8 @@ function createTestRoom(options) {
|
|
|
5681
6087
|
useItem,
|
|
5682
6088
|
use(hold = 0) {
|
|
5683
6089
|
if (tool.def.category === "hand") {
|
|
5684
|
-
|
|
6090
|
+
handUse();
|
|
6091
|
+
flush();
|
|
5685
6092
|
return;
|
|
5686
6093
|
}
|
|
5687
6094
|
useTool(FIXED_DT, false);
|
|
@@ -5914,7 +6321,8 @@ function createTestRoom(options) {
|
|
|
5914
6321
|
},
|
|
5915
6322
|
onAction: (id) => {
|
|
5916
6323
|
if (activeBench) slowly(activeBench, id, () => benches.get(activeBench)?.act(id));
|
|
5917
|
-
}
|
|
6324
|
+
},
|
|
6325
|
+
...options.testTable !== false && arena.tops.some((x) => x.id === tableScenery) ? { testTable } : {}
|
|
5918
6326
|
});
|
|
5919
6327
|
ui.hud(hudState());
|
|
5920
6328
|
showBench();
|
|
@@ -5967,19 +6375,25 @@ function structuredCloneSpec(spec) {
|
|
|
5967
6375
|
export {
|
|
5968
6376
|
DEFAULT_HAND_STANCES,
|
|
5969
6377
|
DEFAULT_STRIKE_CLIPS,
|
|
6378
|
+
DEFAULT_TRIALS,
|
|
5970
6379
|
LOADING_CLASS,
|
|
5971
6380
|
LOADING_CSS,
|
|
5972
6381
|
MATERIAL_COLORS,
|
|
6382
|
+
TRIAL_KINDS,
|
|
5973
6383
|
brickWallSpec,
|
|
5974
6384
|
buildFromSpec,
|
|
5975
6385
|
createLoading,
|
|
5976
6386
|
createLog,
|
|
5977
6387
|
createTestRoom,
|
|
6388
|
+
createTestTable,
|
|
5978
6389
|
decodeBenchState,
|
|
5979
6390
|
encodeBenchState,
|
|
6391
|
+
fitRow,
|
|
5980
6392
|
loadingMarkup,
|
|
5981
6393
|
locales,
|
|
5982
6394
|
nextPaint,
|
|
5983
|
-
resolveStrings
|
|
6395
|
+
resolveStrings,
|
|
6396
|
+
rowCentres,
|
|
6397
|
+
trialView
|
|
5984
6398
|
};
|
|
5985
6399
|
//# sourceMappingURL=index.js.map
|