@adatechnology/game-test-room 0.13.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 +165 -17
- package/dist/index.global.js +558 -98
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +510 -92
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -9,6 +9,9 @@ import { createGroundField, createVfx } from "@adatechnology/game-vfx";
|
|
|
9
9
|
import { createGroundPatch, createVfxRenderer } from "@adatechnology/game-vfx-three";
|
|
10
10
|
import { checkAnimation, checkBench, checkDestructible, checkSpec, createEnvironmentBus, shotExtras, useToHit } from "@adatechnology/game-contracts";
|
|
11
11
|
|
|
12
|
+
// src/arena.ts
|
|
13
|
+
import { markKitOrigin } from "@adatechnology/game-contracts";
|
|
14
|
+
|
|
12
15
|
// src/items.ts
|
|
13
16
|
var box = (id, material, size, position, extra = {}) => ({ id, material, shape: { kind: "box", size }, position, ...extra });
|
|
14
17
|
var joint = (a, b, kind, extra = {}) => ({ a, b, kind, ...extra });
|
|
@@ -110,7 +113,7 @@ function resolveScenery(scenery) {
|
|
|
110
113
|
return [...merged.entries()].map(([id, o]) => ({ id, spec: o.spec, position: o.position, rotationY: o.rotationY ?? 0, colors: o.colors, build: o.build, label: o.label, top: o.top, spout: o.spout }));
|
|
111
114
|
}
|
|
112
115
|
function createArena(THREE, size, scene, scenery, tapOption) {
|
|
113
|
-
const group = new THREE.Group();
|
|
116
|
+
const group = markKitOrigin(new THREE.Group(), { owner: "game-test-room", kind: "room" });
|
|
114
117
|
group.name = "test-room-arena";
|
|
115
118
|
scene.background = new THREE.Color(10466504);
|
|
116
119
|
group.add(new THREE.HemisphereLight(13624319, 7037527, 0.75));
|
|
@@ -468,7 +471,7 @@ function buildFromSpec(THREE, spec, options = {}) {
|
|
|
468
471
|
}
|
|
469
472
|
|
|
470
473
|
// src/explosives.ts
|
|
471
|
-
import { backblastEffect, blastEffect, createExplosiveBody, tripwireSegment } from "@adatechnology/game-weapons";
|
|
474
|
+
import { ExplosiveBody, backblastEffect, blastEffect, createExplosiveBody, tripwireSegment } from "@adatechnology/game-weapons";
|
|
472
475
|
|
|
473
476
|
// src/segment-box.ts
|
|
474
477
|
var segmentTouchesBox = (from, to, min, max) => {
|
|
@@ -711,6 +714,14 @@ function createExplosives(context) {
|
|
|
711
714
|
...projectile.fire ? { fire: projectile.fire } : {}
|
|
712
715
|
});
|
|
713
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
|
+
};
|
|
714
725
|
const detonateCharges = () => {
|
|
715
726
|
let count = 0;
|
|
716
727
|
for (const projectile of [...projectiles]) {
|
|
@@ -802,7 +813,172 @@ function createExplosives(context) {
|
|
|
802
813
|
}
|
|
803
814
|
}
|
|
804
815
|
};
|
|
805
|
-
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
|
+
};
|
|
806
982
|
}
|
|
807
983
|
|
|
808
984
|
// src/host-events.ts
|
|
@@ -2234,7 +2410,7 @@ var en = {
|
|
|
2234
2410
|
"hud.throw": "throw",
|
|
2235
2411
|
"hud.tilt": "tilt (hold)",
|
|
2236
2412
|
"hud.equip": "equip {weapon}",
|
|
2237
|
-
"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",
|
|
2238
2414
|
"ui.help.camera": "V: 1st/3rd person (Shift+V: kick)",
|
|
2239
2415
|
"camera.first": "1st person",
|
|
2240
2416
|
"camera.third": "3rd person",
|
|
@@ -2248,6 +2424,32 @@ var en = {
|
|
|
2248
2424
|
"ui.copy_json": "Copy JSON",
|
|
2249
2425
|
"ui.download_ndjson": "Download NDJSON",
|
|
2250
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",
|
|
2251
2453
|
"ui.clear_log": "Clear",
|
|
2252
2454
|
"ui.catalog": "Catalogue",
|
|
2253
2455
|
"ui.clear": "Clear",
|
|
@@ -2515,7 +2717,7 @@ var ptBR = {
|
|
|
2515
2717
|
"hud.throw": "arremessar",
|
|
2516
2718
|
"hud.tilt": "inclinar (segurar)",
|
|
2517
2719
|
"hud.equip": "equipar {weapon}",
|
|
2518
|
-
"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",
|
|
2519
2721
|
"ui.help.camera": "V: 1\xAA/3\xAA pessoa (Shift+V: chute)",
|
|
2520
2722
|
"camera.first": "1\xAA pessoa",
|
|
2521
2723
|
"camera.third": "3\xAA pessoa",
|
|
@@ -2529,6 +2731,32 @@ var ptBR = {
|
|
|
2529
2731
|
"ui.copy_json": "Copiar JSON",
|
|
2530
2732
|
"ui.download_ndjson": "Baixar NDJSON",
|
|
2531
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",
|
|
2532
2760
|
"ui.clear_log": "Limpar",
|
|
2533
2761
|
"ui.catalog": "Cat\xE1logo",
|
|
2534
2762
|
"ui.clear": "Limpar",
|
|
@@ -2870,6 +3098,122 @@ function createBenchPanel(o) {
|
|
|
2870
3098
|
};
|
|
2871
3099
|
}
|
|
2872
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
|
+
|
|
2873
3217
|
// src/ui.ts
|
|
2874
3218
|
var CSS = `
|
|
2875
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}
|
|
@@ -2948,7 +3292,7 @@ var CSS = `
|
|
|
2948
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}}
|
|
2949
3293
|
`;
|
|
2950
3294
|
var fold = (text) => text.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
|
|
2951
|
-
var
|
|
3295
|
+
var mk3 = (tag, cls, text) => {
|
|
2952
3296
|
const e = document.createElement(tag);
|
|
2953
3297
|
if (cls) e.className = cls;
|
|
2954
3298
|
if (text !== void 0) e.textContent = text;
|
|
@@ -2959,7 +3303,7 @@ var thumbSource = (thumbnail) => {
|
|
|
2959
3303
|
return source.replace(/["\\\n\r]/g, (char) => encodeURIComponent(char));
|
|
2960
3304
|
};
|
|
2961
3305
|
var thumb = (thumbnail, credit) => {
|
|
2962
|
-
const e =
|
|
3306
|
+
const e = mk3("span", "tr-thumb");
|
|
2963
3307
|
if (credit) e.title = credit;
|
|
2964
3308
|
else e.setAttribute("aria-hidden", "true");
|
|
2965
3309
|
e.style.setProperty("--tr-thumb", `url("${thumbSource(thumbnail)}")`);
|
|
@@ -2980,42 +3324,43 @@ async function toggleFullscreen() {
|
|
|
2980
3324
|
}
|
|
2981
3325
|
function createUi(o) {
|
|
2982
3326
|
const { t } = o;
|
|
2983
|
-
const style =
|
|
2984
|
-
style.textContent = CSS;
|
|
2985
|
-
const root =
|
|
3327
|
+
const style = mk3("style");
|
|
3328
|
+
style.textContent = CSS + (o.testTable ? TEST_TABLE_CSS : "");
|
|
3329
|
+
const root = mk3("div", "tr-root");
|
|
2986
3330
|
const pos = getComputedStyle?.(o.container)?.position;
|
|
2987
3331
|
if (!pos || pos === "static") o.container.style.position = "relative";
|
|
2988
3332
|
root.appendChild(style);
|
|
2989
3333
|
o.container.appendChild(root);
|
|
2990
|
-
const cross =
|
|
2991
|
-
cross.appendChild(
|
|
2992
|
-
const top =
|
|
2993
|
-
const toolBox =
|
|
2994
|
-
const status =
|
|
2995
|
-
const prog =
|
|
2996
|
-
const progLabel =
|
|
2997
|
-
const progBar =
|
|
2998
|
-
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");
|
|
2999
3343
|
progBar.appendChild(progFill);
|
|
3000
3344
|
prog.append(progLabel, progBar);
|
|
3001
3345
|
top.append(toolBox, status, prog);
|
|
3002
|
-
const bottom =
|
|
3003
|
-
const held =
|
|
3004
|
-
const hotbar =
|
|
3346
|
+
const bottom = mk3("div", "tr-bottom");
|
|
3347
|
+
const held = mk3("div", "tr-held");
|
|
3348
|
+
const hotbar = mk3("div", "tr-hotbar");
|
|
3005
3349
|
bottom.append(held, hotbar);
|
|
3006
|
-
const help =
|
|
3350
|
+
const help = mk3("div", "tr-help");
|
|
3007
3351
|
help.textContent = t("ui.help");
|
|
3008
|
-
const left =
|
|
3009
|
-
const insp =
|
|
3010
|
-
const logPanel =
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
const
|
|
3014
|
-
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");
|
|
3015
3360
|
const filters = { action: true, event: true, check: true };
|
|
3016
3361
|
const filterBtns = [];
|
|
3017
3362
|
for (const ch of ["action", "event", "check"]) {
|
|
3018
|
-
const b =
|
|
3363
|
+
const b = mk3("button", "tr-btn on", t(`ui.filter.${ch}`));
|
|
3019
3364
|
b.type = "button";
|
|
3020
3365
|
b.onclick = () => {
|
|
3021
3366
|
filters[ch] = !filters[ch];
|
|
@@ -3026,8 +3371,8 @@ function createUi(o) {
|
|
|
3026
3371
|
logBar.appendChild(b);
|
|
3027
3372
|
}
|
|
3028
3373
|
let autoscroll = true;
|
|
3029
|
-
const asLabel =
|
|
3030
|
-
const asBox =
|
|
3374
|
+
const asLabel = mk3("label");
|
|
3375
|
+
const asBox = mk3("input");
|
|
3031
3376
|
asBox.type = "checkbox";
|
|
3032
3377
|
asBox.checked = true;
|
|
3033
3378
|
asBox.onchange = () => {
|
|
@@ -3036,7 +3381,7 @@ function createUi(o) {
|
|
|
3036
3381
|
asLabel.append(asBox, document.createTextNode(" " + t("ui.autoscroll")));
|
|
3037
3382
|
logBar.appendChild(asLabel);
|
|
3038
3383
|
const logBtn = (label, fn) => {
|
|
3039
|
-
const b =
|
|
3384
|
+
const b = mk3("button", "tr-btn", label);
|
|
3040
3385
|
b.type = "button";
|
|
3041
3386
|
b.onclick = fn;
|
|
3042
3387
|
logBar.appendChild(b);
|
|
@@ -3044,7 +3389,7 @@ function createUi(o) {
|
|
|
3044
3389
|
logBtn(t("ui.copy_json"), () => {
|
|
3045
3390
|
const text = o.log.toJSON();
|
|
3046
3391
|
const select = () => {
|
|
3047
|
-
const ta =
|
|
3392
|
+
const ta = mk3("textarea");
|
|
3048
3393
|
ta.value = text;
|
|
3049
3394
|
ta.setAttribute("readonly", "");
|
|
3050
3395
|
ta.style.cssText = "position:fixed;left:8px;bottom:8px;width:min(480px,80vw);height:120px;z-index:99999";
|
|
@@ -3078,12 +3423,12 @@ function createUi(o) {
|
|
|
3078
3423
|
const fill = (n, e) => {
|
|
3079
3424
|
n.className = lineClass(e);
|
|
3080
3425
|
n.textContent = "";
|
|
3081
|
-
const tm =
|
|
3426
|
+
const tm = mk3("time", void 0, fmtTime(e.t));
|
|
3082
3427
|
n.append(tm, document.createTextNode(e.text));
|
|
3083
3428
|
};
|
|
3084
3429
|
const addNode = (e) => {
|
|
3085
3430
|
if (!filters[e.channel]) return;
|
|
3086
|
-
const n =
|
|
3431
|
+
const n = mk3("div");
|
|
3087
3432
|
fill(n, e);
|
|
3088
3433
|
nodes.set(e.seq, n);
|
|
3089
3434
|
logBody.appendChild(n);
|
|
@@ -3105,18 +3450,18 @@ function createUi(o) {
|
|
|
3105
3450
|
if (n) fill(n, e);
|
|
3106
3451
|
} else addNode(e);
|
|
3107
3452
|
});
|
|
3108
|
-
const right =
|
|
3109
|
-
const cat =
|
|
3110
|
-
const anim =
|
|
3111
|
-
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");
|
|
3112
3457
|
const benchPanel = createBenchPanel({ t, num: (n, d) => num(n, d), onControl: o.onControl, onLayer: o.onLayer, onAction: o.onAction });
|
|
3113
3458
|
right.append(cat, anim, benchPanel.element, tests);
|
|
3114
|
-
cat.appendChild(
|
|
3115
|
-
const itemSearch =
|
|
3459
|
+
cat.appendChild(mk3("h3", void 0, t("ui.catalog")));
|
|
3460
|
+
const itemSearch = mk3("input", "tr-search");
|
|
3116
3461
|
itemSearch.type = "search";
|
|
3117
3462
|
itemSearch.placeholder = t("ui.search_items");
|
|
3118
|
-
const tabs =
|
|
3119
|
-
const items =
|
|
3463
|
+
const tabs = mk3("div", "tr-tabs");
|
|
3464
|
+
const items = mk3("div", "tr-items");
|
|
3120
3465
|
cat.append(itemSearch, tabs, items);
|
|
3121
3466
|
let activeGroup = "";
|
|
3122
3467
|
const visibleItems = () => {
|
|
@@ -3128,18 +3473,18 @@ function createUi(o) {
|
|
|
3128
3473
|
items.textContent = "";
|
|
3129
3474
|
const searching = itemSearch.value.trim() !== "";
|
|
3130
3475
|
const found = visibleItems();
|
|
3131
|
-
if (!found.length) items.appendChild(
|
|
3476
|
+
if (!found.length) items.appendChild(mk3("div", "tr-empty", t("ui.no_results")));
|
|
3132
3477
|
for (const { item: it, group } of found) {
|
|
3133
|
-
const wrap =
|
|
3134
|
-
const b =
|
|
3135
|
-
if (it.thumbnail) b.append(thumb(it.thumbnail),
|
|
3136
|
-
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));
|
|
3137
3482
|
b.type = "button";
|
|
3138
3483
|
b.title = it.note ?? it.name;
|
|
3139
3484
|
b.onclick = () => o.onSpawn(it.id);
|
|
3140
3485
|
wrap.appendChild(b);
|
|
3141
3486
|
if (it.weapon) {
|
|
3142
|
-
const w =
|
|
3487
|
+
const w = mk3("button", "tr-btn", "\u2694");
|
|
3143
3488
|
w.type = "button";
|
|
3144
3489
|
w.title = t("ui.equip");
|
|
3145
3490
|
w.onclick = () => o.onEquip(it.id);
|
|
@@ -3153,7 +3498,7 @@ function createUi(o) {
|
|
|
3153
3498
|
const groupNames = [...o.groups().keys()];
|
|
3154
3499
|
if (!groupNames.includes(activeGroup)) activeGroup = groupNames[0] ?? "";
|
|
3155
3500
|
for (const g of groupNames) {
|
|
3156
|
-
const b =
|
|
3501
|
+
const b = mk3("button", g === activeGroup ? "tr-btn on" : "tr-btn", g);
|
|
3157
3502
|
b.type = "button";
|
|
3158
3503
|
b.onclick = () => {
|
|
3159
3504
|
activeGroup = g;
|
|
@@ -3166,9 +3511,9 @@ function createUi(o) {
|
|
|
3166
3511
|
renderTabs();
|
|
3167
3512
|
itemSearch.oninput = renderItems;
|
|
3168
3513
|
for (const box2 of [itemSearch]) box2.addEventListener("keydown", (e) => e.stopPropagation());
|
|
3169
|
-
const controls =
|
|
3514
|
+
const controls = mk3("div", "tr-row");
|
|
3170
3515
|
const ctl = (label, fn) => {
|
|
3171
|
-
const b =
|
|
3516
|
+
const b = mk3("button", "tr-btn", label);
|
|
3172
3517
|
b.type = "button";
|
|
3173
3518
|
b.onclick = () => fn(b);
|
|
3174
3519
|
controls.appendChild(b);
|
|
@@ -3193,29 +3538,29 @@ function createUi(o) {
|
|
|
3193
3538
|
fullscreenBtn.title = t("ui.fullscreen.hint");
|
|
3194
3539
|
const blastBtns = ["shelter", "fragmentHits", "confinement"].map((key) => ({ key, b: ctl(t(`ui.blast.${key}`), () => o.onBlast(key)) }));
|
|
3195
3540
|
for (const { key, b } of blastBtns) b.title = t(`ui.blast.${key}.hint`);
|
|
3196
|
-
const qSel =
|
|
3541
|
+
const qSel = mk3("select");
|
|
3197
3542
|
for (const q of ["low", "medium", "high"]) {
|
|
3198
|
-
const op =
|
|
3543
|
+
const op = mk3("option", void 0, t(`ui.quality.${q}`));
|
|
3199
3544
|
op.value = q;
|
|
3200
3545
|
qSel.appendChild(op);
|
|
3201
3546
|
}
|
|
3202
3547
|
qSel.value = o.quality;
|
|
3203
3548
|
qSel.onchange = () => o.onQuality(qSel.value);
|
|
3204
|
-
const qLabel =
|
|
3549
|
+
const qLabel = mk3("label", void 0, t("ui.quality") + " ");
|
|
3205
3550
|
qLabel.appendChild(qSel);
|
|
3206
3551
|
controls.appendChild(qLabel);
|
|
3207
|
-
const count =
|
|
3552
|
+
const count = mk3("span");
|
|
3208
3553
|
controls.appendChild(count);
|
|
3209
3554
|
cat.appendChild(controls);
|
|
3210
|
-
tests.appendChild(
|
|
3211
|
-
const runAll =
|
|
3555
|
+
tests.appendChild(mk3("h3", void 0, t("ui.tests")));
|
|
3556
|
+
const runAll = mk3("button", "tr-btn", t("ui.run_all"));
|
|
3212
3557
|
runAll.type = "button";
|
|
3213
|
-
const summary =
|
|
3214
|
-
const testSearch =
|
|
3558
|
+
const summary = mk3("div", "tr-summary");
|
|
3559
|
+
const testSearch = mk3("input", "tr-search");
|
|
3215
3560
|
testSearch.type = "search";
|
|
3216
3561
|
testSearch.placeholder = t("ui.search_tests");
|
|
3217
3562
|
testSearch.addEventListener("keydown", (e) => e.stopPropagation());
|
|
3218
|
-
const list =
|
|
3563
|
+
const list = mk3("div", "list");
|
|
3219
3564
|
tests.append(runAll, summary, testSearch, list);
|
|
3220
3565
|
testSearch.oninput = () => {
|
|
3221
3566
|
const term = fold(testSearch.value.trim());
|
|
@@ -3238,7 +3583,7 @@ function createUi(o) {
|
|
|
3238
3583
|
list.textContent = "";
|
|
3239
3584
|
scBtns.clear();
|
|
3240
3585
|
for (const s of o.scenarios()) {
|
|
3241
|
-
const b =
|
|
3586
|
+
const b = mk3("button", "tr-btn", s.name);
|
|
3242
3587
|
b.type = "button";
|
|
3243
3588
|
b.onclick = async () => {
|
|
3244
3589
|
if (busy) return;
|
|
@@ -3264,7 +3609,7 @@ function createUi(o) {
|
|
|
3264
3609
|
busy = false;
|
|
3265
3610
|
}
|
|
3266
3611
|
};
|
|
3267
|
-
const toggle =
|
|
3612
|
+
const toggle = mk3("button", "tr-btn tr-toggle", t("ui.panel"));
|
|
3268
3613
|
toggle.type = "button";
|
|
3269
3614
|
const togglePanels = () => {
|
|
3270
3615
|
root.classList.toggle("open");
|
|
@@ -3273,15 +3618,15 @@ function createUi(o) {
|
|
|
3273
3618
|
toggle.onclick = togglePanels;
|
|
3274
3619
|
root.append(cross, top, bottom, help, left, right, toggle);
|
|
3275
3620
|
const bar = (value, max, cls) => {
|
|
3276
|
-
const b =
|
|
3277
|
-
const i =
|
|
3621
|
+
const b = mk3("div", `tr-bar ${cls}`);
|
|
3622
|
+
const i = mk3("i");
|
|
3278
3623
|
i.style.width = `${Math.max(0, Math.min(100, value / Math.max(1e-9, max) * 100))}%`;
|
|
3279
3624
|
b.appendChild(i);
|
|
3280
3625
|
return b;
|
|
3281
3626
|
};
|
|
3282
3627
|
const row = (k, v) => {
|
|
3283
|
-
const r =
|
|
3284
|
-
r.append(
|
|
3628
|
+
const r = mk3("div", "r");
|
|
3629
|
+
r.append(mk3("span", void 0, k), mk3("span", void 0, v));
|
|
3285
3630
|
return r;
|
|
3286
3631
|
};
|
|
3287
3632
|
const num = (n, d = 1) => {
|
|
@@ -3290,13 +3635,13 @@ function createUi(o) {
|
|
|
3290
3635
|
};
|
|
3291
3636
|
const renderInspector = (i) => {
|
|
3292
3637
|
insp.textContent = "";
|
|
3293
|
-
insp.appendChild(
|
|
3638
|
+
insp.appendChild(mk3("h3", void 0, t("ui.inspector")));
|
|
3294
3639
|
if (!i) {
|
|
3295
|
-
insp.appendChild(
|
|
3640
|
+
insp.appendChild(mk3("div", void 0, t("ui.aim_at_something")));
|
|
3296
3641
|
return;
|
|
3297
3642
|
}
|
|
3298
3643
|
if (i.thumbnail) insp.appendChild(thumb(i.thumbnail, i.thumbnailCredit));
|
|
3299
|
-
insp.appendChild(
|
|
3644
|
+
insp.appendChild(mk3("div", "t", `${i.object} \u203A ${i.part}`));
|
|
3300
3645
|
insp.appendChild(row(t("ins.material"), i.material));
|
|
3301
3646
|
insp.appendChild(row(t("ins.status"), i.status + (i.burning ? ` \xB7 ${t("ins.burning")}` : "")));
|
|
3302
3647
|
insp.appendChild(row(t("ins.hp"), `${num(i.hp, 0)} / ${num(i.maxHp, 0)}`));
|
|
@@ -3315,30 +3660,30 @@ function createUi(o) {
|
|
|
3315
3660
|
insp.appendChild(bar(Math.min(i.stress, 1.2), 1.2, i.stress > 1 ? "bad" : i.stress > 0.7 ? "warn" : "hp"));
|
|
3316
3661
|
}
|
|
3317
3662
|
if (i.joints.length) {
|
|
3318
|
-
insp.appendChild(
|
|
3663
|
+
insp.appendChild(mk3("div", void 0, t("ins.joints") + ":"));
|
|
3319
3664
|
for (const j of i.joints) {
|
|
3320
3665
|
const tools = j.tools.length ? j.tools.join(", ") : t("tool.none");
|
|
3321
|
-
insp.appendChild(
|
|
3666
|
+
insp.appendChild(mk3("div", void 0, `\u2022 ${j.kind} (${j.id})${j.open ? ` \xB7 ${t("ins.open")}` : ` \u2192 ${tools}`}`));
|
|
3322
3667
|
}
|
|
3323
3668
|
}
|
|
3324
|
-
if (i.note) insp.appendChild(
|
|
3669
|
+
if (i.note) insp.appendChild(mk3("div", void 0, i.note));
|
|
3325
3670
|
};
|
|
3326
3671
|
let lastAnim = "";
|
|
3327
3672
|
const renderAnimations = (a) => {
|
|
3328
3673
|
anim.textContent = "";
|
|
3329
|
-
anim.appendChild(
|
|
3674
|
+
anim.appendChild(mk3("h3", void 0, t("ui.animations")));
|
|
3330
3675
|
if (!a) {
|
|
3331
|
-
anim.appendChild(
|
|
3676
|
+
anim.appendChild(mk3("div", "sub", t("ui.animations_aim")));
|
|
3332
3677
|
return;
|
|
3333
3678
|
}
|
|
3334
|
-
anim.appendChild(
|
|
3679
|
+
anim.appendChild(mk3("div", "sub", a.name));
|
|
3335
3680
|
if (a.clips.length === 0) {
|
|
3336
|
-
anim.appendChild(
|
|
3681
|
+
anim.appendChild(mk3("div", "sub", t("ui.animations_none")));
|
|
3337
3682
|
return;
|
|
3338
3683
|
}
|
|
3339
|
-
const l =
|
|
3684
|
+
const l = mk3("div", "list");
|
|
3340
3685
|
for (const c of a.clips) {
|
|
3341
|
-
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)`);
|
|
3342
3687
|
b.type = "button";
|
|
3343
3688
|
b.onclick = () => o.onPlay(a.objectId, c.id);
|
|
3344
3689
|
l.appendChild(b);
|
|
@@ -3355,8 +3700,8 @@ function createUi(o) {
|
|
|
3355
3700
|
hud(s) {
|
|
3356
3701
|
toolBox.textContent = "";
|
|
3357
3702
|
toolBox.append(document.createTextNode(s.toolName));
|
|
3358
|
-
if (s.ammo) toolBox.append(
|
|
3359
|
-
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}`)));
|
|
3360
3705
|
const helpText = s.camera ? `${t("ui.help")} \xB7 ${t("ui.help.camera")}` : t("ui.help");
|
|
3361
3706
|
if (help.textContent !== helpText) help.textContent = helpText;
|
|
3362
3707
|
if (s.status) status.textContent = s.status;
|
|
@@ -3379,7 +3724,7 @@ function createUi(o) {
|
|
|
3379
3724
|
];
|
|
3380
3725
|
if (s.held.weapon) keys.push(["H", t("hud.equip", { weapon: s.held.weapon })]);
|
|
3381
3726
|
for (const [k, label] of keys) {
|
|
3382
|
-
held.append(
|
|
3727
|
+
held.append(mk3("kbd", void 0, k), document.createTextNode(` ${label} `));
|
|
3383
3728
|
}
|
|
3384
3729
|
} else held.style.display = "none";
|
|
3385
3730
|
const key = s.slots.join("|") + s.page;
|
|
@@ -3389,9 +3734,9 @@ function createUi(o) {
|
|
|
3389
3734
|
slotsEl.length = 0;
|
|
3390
3735
|
hudPage = s.page - 1;
|
|
3391
3736
|
s.slots.forEach((name, i) => {
|
|
3392
|
-
const b =
|
|
3737
|
+
const b = mk3("button", "tr-slot");
|
|
3393
3738
|
b.type = "button";
|
|
3394
|
-
b.append(
|
|
3739
|
+
b.append(mk3("b", void 0, String((i + 1) % 10)), document.createTextNode(name));
|
|
3395
3740
|
b.title = name;
|
|
3396
3741
|
b.onclick = () => o.onTool(hudPage * 10 + i);
|
|
3397
3742
|
hotbar.appendChild(b);
|
|
@@ -3423,6 +3768,7 @@ function createUi(o) {
|
|
|
3423
3768
|
refresh() {
|
|
3424
3769
|
renderTabs();
|
|
3425
3770
|
renderScenarios();
|
|
3771
|
+
tablePanel?.refresh();
|
|
3426
3772
|
},
|
|
3427
3773
|
showGroup(group) {
|
|
3428
3774
|
activeGroup = group;
|
|
@@ -3437,6 +3783,7 @@ function createUi(o) {
|
|
|
3437
3783
|
},
|
|
3438
3784
|
dispose() {
|
|
3439
3785
|
offLog();
|
|
3786
|
+
tablePanel?.dispose();
|
|
3440
3787
|
if (toastTimer) clearTimeout(toastTimer);
|
|
3441
3788
|
root.remove();
|
|
3442
3789
|
}
|
|
@@ -4626,6 +4973,10 @@ function createTestRoom(options) {
|
|
|
4626
4973
|
heldPiece = null;
|
|
4627
4974
|
heldTilt = 0;
|
|
4628
4975
|
};
|
|
4976
|
+
const handUse = () => {
|
|
4977
|
+
if (heldPiece) grab();
|
|
4978
|
+
else useTool(FIXED_DT, false);
|
|
4979
|
+
};
|
|
4629
4980
|
const grab = () => {
|
|
4630
4981
|
if (heldPiece) {
|
|
4631
4982
|
const name = heldName;
|
|
@@ -5094,10 +5445,10 @@ function createTestRoom(options) {
|
|
|
5094
5445
|
if (tiltKey || heldTilt > 0) {
|
|
5095
5446
|
heldTilt = Math.max(0, Math.min(2.4, heldTilt + (tiltKey ? 2.2 : -3) * dt));
|
|
5096
5447
|
}
|
|
5097
|
-
if (useHeld && !paused) {
|
|
5448
|
+
if ((useHeld || useFirst) && !paused) {
|
|
5098
5449
|
if (tool.def.category === "hand") {
|
|
5099
|
-
if (useFirst)
|
|
5100
|
-
} else useTool(dt, !useFirst);
|
|
5450
|
+
if (useFirst) handUse();
|
|
5451
|
+
} else if (useHeld) useTool(dt, !useFirst);
|
|
5101
5452
|
useFirst = false;
|
|
5102
5453
|
}
|
|
5103
5454
|
if (!paused) followHeld(dt);
|
|
@@ -5652,6 +6003,63 @@ function createTestRoom(options) {
|
|
|
5652
6003
|
const row = (list, gap, z) => list.map((item, index) => spawn(item.id, [(index - (list.length - 1) / 2) * gap, 0, z], 0));
|
|
5653
6004
|
return [...row(front, 1.6, 1.5), ...row(back, 4.5, -4)];
|
|
5654
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
|
+
);
|
|
5655
6063
|
const room = {
|
|
5656
6064
|
world,
|
|
5657
6065
|
renderer,
|
|
@@ -5671,6 +6079,7 @@ function createTestRoom(options) {
|
|
|
5671
6079
|
get scenarios() {
|
|
5672
6080
|
return allScenarios();
|
|
5673
6081
|
},
|
|
6082
|
+
testTable,
|
|
5674
6083
|
spawn,
|
|
5675
6084
|
clear,
|
|
5676
6085
|
resetAll,
|
|
@@ -5678,7 +6087,8 @@ function createTestRoom(options) {
|
|
|
5678
6087
|
useItem,
|
|
5679
6088
|
use(hold = 0) {
|
|
5680
6089
|
if (tool.def.category === "hand") {
|
|
5681
|
-
|
|
6090
|
+
handUse();
|
|
6091
|
+
flush();
|
|
5682
6092
|
return;
|
|
5683
6093
|
}
|
|
5684
6094
|
useTool(FIXED_DT, false);
|
|
@@ -5749,6 +6159,7 @@ function createTestRoom(options) {
|
|
|
5749
6159
|
},
|
|
5750
6160
|
equip,
|
|
5751
6161
|
openArea,
|
|
6162
|
+
modules: () => [...modules.values()].map((m) => ({ id: m.id, name: m.name, group: m.group, hasArea: typeof m.area === "function" })),
|
|
5752
6163
|
openAreaAsync: (area) => loading.busy(t("loading.open_area", { area: areaLabel(area) }), () => openArea(area)),
|
|
5753
6164
|
loading,
|
|
5754
6165
|
busy: (label, work, busyOptions) => loading.busy(label, work, busyOptions),
|
|
@@ -5910,7 +6321,8 @@ function createTestRoom(options) {
|
|
|
5910
6321
|
},
|
|
5911
6322
|
onAction: (id) => {
|
|
5912
6323
|
if (activeBench) slowly(activeBench, id, () => benches.get(activeBench)?.act(id));
|
|
5913
|
-
}
|
|
6324
|
+
},
|
|
6325
|
+
...options.testTable !== false && arena.tops.some((x) => x.id === tableScenery) ? { testTable } : {}
|
|
5914
6326
|
});
|
|
5915
6327
|
ui.hud(hudState());
|
|
5916
6328
|
showBench();
|
|
@@ -5963,19 +6375,25 @@ function structuredCloneSpec(spec) {
|
|
|
5963
6375
|
export {
|
|
5964
6376
|
DEFAULT_HAND_STANCES,
|
|
5965
6377
|
DEFAULT_STRIKE_CLIPS,
|
|
6378
|
+
DEFAULT_TRIALS,
|
|
5966
6379
|
LOADING_CLASS,
|
|
5967
6380
|
LOADING_CSS,
|
|
5968
6381
|
MATERIAL_COLORS,
|
|
6382
|
+
TRIAL_KINDS,
|
|
5969
6383
|
brickWallSpec,
|
|
5970
6384
|
buildFromSpec,
|
|
5971
6385
|
createLoading,
|
|
5972
6386
|
createLog,
|
|
5973
6387
|
createTestRoom,
|
|
6388
|
+
createTestTable,
|
|
5974
6389
|
decodeBenchState,
|
|
5975
6390
|
encodeBenchState,
|
|
6391
|
+
fitRow,
|
|
5976
6392
|
loadingMarkup,
|
|
5977
6393
|
locales,
|
|
5978
6394
|
nextPaint,
|
|
5979
|
-
resolveStrings
|
|
6395
|
+
resolveStrings,
|
|
6396
|
+
rowCentres,
|
|
6397
|
+
trialView
|
|
5980
6398
|
};
|
|
5981
6399
|
//# sourceMappingURL=index.js.map
|