@adatechnology/game-characters 0.1.5 → 0.2.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.
@@ -47,6 +47,9 @@ var GameCharacters = (() => {
47
47
  PENETRATION_MODELS: () => PENETRATION_MODELS,
48
48
  PERSON_PRESET: () => PERSON_PRESET,
49
49
  PHYSICAL_PENETRATION: () => PHYSICAL_PENETRATION,
50
+ POSE_CHANNEL_JOINTS: () => POSE_CHANNEL_JOINTS,
51
+ POSE_CLIPS: () => POSE_CLIPS,
52
+ POSE_CLIP_LOCALES: () => POSE_CLIP_LOCALES,
50
53
  PROTECTION_PRESETS: () => PROTECTION_PRESETS,
51
54
  REGION_HIT_POINTS: () => REGION_HIT_POINTS,
52
55
  REGION_SEGMENTS: () => REGION_SEGMENTS,
@@ -63,12 +66,14 @@ var GameCharacters = (() => {
63
66
  applyPreset: () => applyPreset,
64
67
  bleedRateAt: () => bleedRateAt,
65
68
  blendMoves: () => blendMoves,
69
+ clipEventsBetween: () => clipEventsBetween,
66
70
  crawlPose: () => crawlPose,
67
71
  createBloodStream: () => createBloodStream,
68
72
  createBodySpec: () => createBodySpec,
69
73
  createCharacters: () => createCharacters,
70
74
  createConditionTimeline: () => createConditionTimeline,
71
75
  createCorpseLedger: () => createCorpseLedger,
76
+ createPoseClipRegistry: () => createPoseClipRegistry,
72
77
  createRig: () => createRig,
73
78
  createRng: () => createRng,
74
79
  cutOf: () => cutOf,
@@ -80,6 +85,7 @@ var GameCharacters = (() => {
80
85
  emptySample: () => emptySample,
81
86
  encodePoseHeight: () => encodePoseHeight,
82
87
  energyKept: () => energyKept,
88
+ filterPoseChannels: () => filterPoseChannels,
83
89
  humanPose: () => humanPose,
84
90
  isBodyRegion: () => isBodyRegion,
85
91
  isSegmentId: () => isSegmentId,
@@ -87,6 +93,7 @@ var GameCharacters = (() => {
87
93
  layersOn: () => layersOn,
88
94
  lerpPose: () => lerpPose,
89
95
  mergeById: () => mergeById,
96
+ mirrorPoseClip: () => mirrorPoseClip,
90
97
  moveBlendOf: () => moveBlendOf,
91
98
  penetrateLine: () => penetrateLine,
92
99
  penetrationForce: () => penetrationForce,
@@ -96,6 +103,8 @@ var GameCharacters = (() => {
96
103
  removeIds: () => removeIds,
97
104
  resolveDamageRules: () => resolveDamageRules,
98
105
  resolvePoints: () => resolvePoints,
106
+ sampleFirstPersonClip: () => sampleFirstPersonClip,
107
+ samplePoseClip: () => samplePoseClip,
99
108
  segmentNode: () => segmentNode,
100
109
  segmentResistance: () => segmentResistance,
101
110
  segmentsBelow: () => segmentsBelow,
@@ -294,6 +303,13 @@ var GameCharacters = (() => {
294
303
  }
295
304
  return removed;
296
305
  },
306
+ remove(index) {
307
+ const entry = entries[index];
308
+ if (!entry) return void 0;
309
+ entries[index] = entries[entries.length - 1];
310
+ entries.pop();
311
+ return entry.data;
312
+ },
297
313
  clear() {
298
314
  entries.length = 0;
299
315
  }
@@ -1356,7 +1372,15 @@ var GameCharacters = (() => {
1356
1372
  };
1357
1373
 
1358
1374
  // src/damage/blast.ts
1359
- var shares = (params, targets, pivot) => targets.map((target) => ({ target, points: params.points * Math.max(0, 1 - distance(params.jointOf(pivot(target)), params.center) / params.radius) })).filter((share) => share.points > params.ops.rules.blast.minimumPoints).sort((a, b) => b.points - a.points);
1375
+ var INJURY_POINTS = 15;
1376
+ var pointsAt = (params, metres) => {
1377
+ const { points, radius, lethalRadius, ops } = params;
1378
+ if (lethalRadius === void 0 || lethalRadius >= radius) return points * Math.max(0, 1 - metres / radius);
1379
+ if (metres <= lethalRadius) return points;
1380
+ const injury = Math.min(points, ops.rules.blast.injuryPoints ?? INJURY_POINTS);
1381
+ return injury * Math.max(0, 1 - (metres - lethalRadius) / (radius - lethalRadius));
1382
+ };
1383
+ var shares = (params, targets, pivot) => targets.map((target) => ({ target, points: pointsAt(params, distance(params.jointOf(pivot(target)), params.center)) })).filter((share) => share.points > params.ops.rules.blast.minimumPoints).sort((a, b) => b.points - a.points);
1360
1384
  var segmentBlast = (params) => {
1361
1385
  const { ops, rule, blow } = params;
1362
1386
  const { blast: blast2, segments } = ops.rules;
@@ -1608,7 +1632,7 @@ var GameCharacters = (() => {
1608
1632
  };
1609
1633
  var blast = ({ ops, hit, setup, localPoint, jointOf }) => {
1610
1634
  const points = hit.points ?? pointsFromEnergy(hit.energy ?? 0, setup.rules);
1611
- const base = { ops, center: localPoint, points, radius: hit.radius ?? 1, jointOf };
1635
+ const base = { ops, center: localPoint, points, radius: hit.radius ?? 1, ...hit.lethalRadius !== void 0 ? { lethalRadius: hit.lethalRadius } : {}, jointOf };
1612
1636
  const common = { cut: hit.cut ?? setup.rules.defaultCut.explosive, damageType: hit.type, model: setup.model, headResistance: HEAD_RESISTANCE };
1613
1637
  const rule = SEGMENT_RULES[setup.rules.segmentRule] ?? kitRule;
1614
1638
  const result = ops.body.detail === "regions" ? regionBlast({ ...base, blow: { ...common, protection: NO_PROTECTION } }) : segmentBlast({ ...base, rule, blow: { ...common, limbFactor: ops.spec.limbFactor } });
@@ -2443,6 +2467,494 @@ var GameCharacters = (() => {
2443
2467
  const apron = random() < APRON_SHARE;
2444
2468
  return { sleeve, hair, headWidth, headHeight, jaw, nose, beard, glasses, cap, capColor, bag, bagColor, torn, apron };
2445
2469
  };
2470
+
2471
+ // src/pose-clips/pose-clip.ts
2472
+ var samplePoseClip = (clip, time) => {
2473
+ const keys = clip.keys;
2474
+ if (keys.length === 0) return {};
2475
+ if (keys.length === 1) return { ...keys[0].pose };
2476
+ let index = 0;
2477
+ while (index < keys.length - 2 && time > keys[index + 1].t) index++;
2478
+ const a = keys[index];
2479
+ const b = keys[index + 1];
2480
+ const k = Math.min(1, Math.max(0, (time - a.t) / (b.t - a.t)));
2481
+ const eased = k * k * (3 - 2 * k);
2482
+ return lerpPose(a.pose, b.pose, eased);
2483
+ };
2484
+ var clipEventsBetween = (clip, from, to) => (clip.events ?? []).filter((event) => event.t > from && event.t <= to).sort((x, y) => x.t - y.t);
2485
+ var POSE_CHANNEL_JOINTS = {
2486
+ full: void 0,
2487
+ upper: ["lean", "twist", "side", "headX", "headY", "headZ", "armR", "armL", "elbR", "elbL", "armRz", "armLz"],
2488
+ lower: ["drop", "legL", "legR", "kneeL", "kneeR"]
2489
+ };
2490
+ var filterPoseChannels = (pose, channels = "full") => {
2491
+ const allowed = POSE_CHANNEL_JOINTS[channels];
2492
+ if (!allowed) return pose;
2493
+ const out = {};
2494
+ for (const name of allowed) if (pose[name] !== void 0) out[name] = pose[name];
2495
+ return out;
2496
+ };
2497
+ var MIRROR_PAIRS = [["armR", "armL"], ["elbR", "elbL"], ["armRz", "armLz"], ["legR", "legL"], ["kneeR", "kneeL"]];
2498
+ var MIRROR_NEGATED = /* @__PURE__ */ new Set(["side", "twist", "headY", "headZ"]);
2499
+ var mirrorPoseClip = (clip, id) => ({
2500
+ ...clip,
2501
+ id,
2502
+ keys: clip.keys.map((key) => {
2503
+ const pose = {};
2504
+ for (const [name, value] of Object.entries(key.pose)) pose[name] = MIRROR_NEGATED.has(name) ? -value : value;
2505
+ for (const [a, b] of MIRROR_PAIRS) {
2506
+ const va = key.pose[a];
2507
+ const vb = key.pose[b];
2508
+ const sign = a === "armRz" ? -1 : 1;
2509
+ if (vb !== void 0) pose[a] = sign * vb;
2510
+ else delete pose[a];
2511
+ if (va !== void 0) pose[b] = sign * va;
2512
+ else delete pose[b];
2513
+ }
2514
+ return { t: key.t, pose };
2515
+ }),
2516
+ ...clip.events ? { events: clip.events.map((event) => ({ ...event })) } : {}
2517
+ });
2518
+
2519
+ // src/presets/pose-clips.json
2520
+ var pose_clips_default = {
2521
+ clips: [
2522
+ {
2523
+ id: "grabbed_bitten_human",
2524
+ source: {
2525
+ file: "site/pages/zumbis-personagens/bestiario.html",
2526
+ scene: "ataque (Agarr\xE3o e mordida)",
2527
+ variable: "HK"
2528
+ },
2529
+ duration: 8,
2530
+ loop: false,
2531
+ channels: "full",
2532
+ keys: [
2533
+ {
2534
+ t: 0,
2535
+ pose: {
2536
+ lean: 0,
2537
+ headY: 0,
2538
+ armL: -0.1,
2539
+ armR: 0.05,
2540
+ elbL: -0.2,
2541
+ elbR: -0.2,
2542
+ drop: 0,
2543
+ kneeL: 0.05,
2544
+ kneeR: 0.05,
2545
+ legL: -0.05,
2546
+ legR: 0.05,
2547
+ headX: 0
2548
+ }
2549
+ },
2550
+ {
2551
+ t: 1.5,
2552
+ pose: {
2553
+ lean: -0.1,
2554
+ headY: -0.6,
2555
+ armL: -0.1,
2556
+ armR: 0.05,
2557
+ elbL: -0.2,
2558
+ elbR: -0.2,
2559
+ drop: 0,
2560
+ kneeL: 0.05,
2561
+ kneeR: 0.05,
2562
+ legL: -0.05,
2563
+ legR: 0.05,
2564
+ headX: -0.1
2565
+ }
2566
+ },
2567
+ {
2568
+ t: 2.1,
2569
+ pose: {
2570
+ lean: -0.3,
2571
+ headY: -0.2,
2572
+ armL: -1.3,
2573
+ armR: -1.2,
2574
+ elbL: -1.4,
2575
+ elbR: -1.5,
2576
+ drop: -0.04,
2577
+ kneeL: 0.25,
2578
+ kneeR: 0.2,
2579
+ legL: -0.3,
2580
+ legR: 0.25,
2581
+ headX: -0.25
2582
+ }
2583
+ },
2584
+ {
2585
+ t: 3.6,
2586
+ pose: {
2587
+ lean: -0.35,
2588
+ headY: 0.3,
2589
+ armL: -1.5,
2590
+ armR: -1,
2591
+ elbL: -0.6,
2592
+ elbR: -1.8,
2593
+ drop: -0.05,
2594
+ kneeL: 0.3,
2595
+ kneeR: 0.2,
2596
+ legL: -0.4,
2597
+ legR: 0.35,
2598
+ headX: -0.2
2599
+ }
2600
+ },
2601
+ {
2602
+ t: 4.3,
2603
+ pose: {
2604
+ lean: -0.2,
2605
+ headY: 0.7,
2606
+ headZ: -0.5,
2607
+ armL: -0.6,
2608
+ armR: -1.9,
2609
+ elbL: -0.4,
2610
+ elbR: -1.2,
2611
+ drop: -0.06,
2612
+ kneeL: 0.3,
2613
+ kneeR: 0.3,
2614
+ legL: -0.3,
2615
+ legR: 0.3,
2616
+ headX: -0.3
2617
+ }
2618
+ },
2619
+ {
2620
+ t: 5.6,
2621
+ pose: {
2622
+ lean: 0.55,
2623
+ headY: 0.4,
2624
+ headZ: -0.3,
2625
+ armL: -0.3,
2626
+ armR: -0.5,
2627
+ elbL: -0.6,
2628
+ elbR: -0.8,
2629
+ drop: -0.5,
2630
+ kneeL: 1.9,
2631
+ kneeR: 1.7,
2632
+ legL: -1.1,
2633
+ legR: -0.9,
2634
+ headX: 0.3
2635
+ }
2636
+ },
2637
+ {
2638
+ t: 8,
2639
+ pose: {
2640
+ lean: 0.6,
2641
+ headY: 0.4,
2642
+ headZ: -0.3,
2643
+ armL: -0.25,
2644
+ armR: -0.45,
2645
+ elbL: -0.6,
2646
+ elbR: -0.8,
2647
+ drop: -0.52,
2648
+ kneeL: 1.95,
2649
+ kneeR: 1.75,
2650
+ legL: -1.1,
2651
+ legR: -0.95,
2652
+ headX: 0.4
2653
+ }
2654
+ }
2655
+ ],
2656
+ events: [
2657
+ {
2658
+ t: 0,
2659
+ type: "phase",
2660
+ data: {
2661
+ label: "pose_clip.grab_bite.phase.approach"
2662
+ }
2663
+ },
2664
+ {
2665
+ t: 1.7,
2666
+ type: "phase",
2667
+ data: {
2668
+ label: "pose_clip.grab_bite.phase.pounce"
2669
+ }
2670
+ },
2671
+ {
2672
+ t: 2.1,
2673
+ type: "phase",
2674
+ data: {
2675
+ label: "pose_clip.grab_bite.phase.grab"
2676
+ }
2677
+ },
2678
+ {
2679
+ t: 4.3,
2680
+ type: "phase",
2681
+ data: {
2682
+ label: "pose_clip.grab_bite.phase.bite"
2683
+ }
2684
+ },
2685
+ {
2686
+ t: 5.6,
2687
+ type: "phase",
2688
+ data: {
2689
+ label: "pose_clip.grab_bite.phase.fall"
2690
+ }
2691
+ },
2692
+ {
2693
+ t: 4.4,
2694
+ type: "impact",
2695
+ data: {
2696
+ kind: "bite",
2697
+ source: "bite.visible=T>4.4 in the scene's step()"
2698
+ }
2699
+ }
2700
+ ]
2701
+ },
2702
+ {
2703
+ id: "grab_bite_zombie",
2704
+ source: {
2705
+ file: "site/pages/zumbis-personagens/bestiario.html",
2706
+ scene: "ataque (Agarr\xE3o e mordida)",
2707
+ variable: "ZK"
2708
+ },
2709
+ duration: 8,
2710
+ loop: false,
2711
+ channels: "full",
2712
+ keys: [
2713
+ {
2714
+ t: 0,
2715
+ pose: {
2716
+ x: -6,
2717
+ lean: 0.75,
2718
+ armL: -1.35,
2719
+ armR: -1.05,
2720
+ elbL: -0.08,
2721
+ elbR: -0.12,
2722
+ headX: -0.55,
2723
+ drop: -0.1,
2724
+ run: 1
2725
+ }
2726
+ },
2727
+ {
2728
+ t: 1.7,
2729
+ pose: {
2730
+ x: -0.9,
2731
+ lean: 0.75,
2732
+ armL: -1.35,
2733
+ armR: -1.05,
2734
+ elbL: -0.08,
2735
+ elbR: -0.12,
2736
+ headX: -0.55,
2737
+ drop: -0.1,
2738
+ run: 1
2739
+ }
2740
+ },
2741
+ {
2742
+ t: 2.1,
2743
+ pose: {
2744
+ x: -0.32,
2745
+ lean: 0.45,
2746
+ armL: -1.65,
2747
+ armR: -1.6,
2748
+ elbL: -0.25,
2749
+ elbR: -0.3,
2750
+ headX: -0.3,
2751
+ drop: -0.08,
2752
+ legL: -0.6,
2753
+ legR: 0.4,
2754
+ kneeL: 0.5,
2755
+ kneeR: 0.6,
2756
+ run: 0
2757
+ }
2758
+ },
2759
+ {
2760
+ t: 3.6,
2761
+ pose: {
2762
+ x: -0.2,
2763
+ lean: 0.35,
2764
+ armL: -1.5,
2765
+ armR: -1.45,
2766
+ elbL: -1.1,
2767
+ elbR: -1.2,
2768
+ headX: -0.2,
2769
+ drop: -0.06,
2770
+ legL: -0.4,
2771
+ legR: 0.3,
2772
+ kneeL: 0.4,
2773
+ kneeR: 0.4,
2774
+ run: 0
2775
+ }
2776
+ },
2777
+ {
2778
+ t: 4.3,
2779
+ pose: {
2780
+ x: -0.1,
2781
+ lean: 0.5,
2782
+ armL: -1.4,
2783
+ armR: -1.3,
2784
+ elbL: -1.5,
2785
+ elbR: -1.5,
2786
+ headX: 0.35,
2787
+ headY: 0.35,
2788
+ drop: -0.08,
2789
+ legL: -0.35,
2790
+ legR: 0.3,
2791
+ kneeL: 0.4,
2792
+ kneeR: 0.4,
2793
+ run: 0
2794
+ }
2795
+ },
2796
+ {
2797
+ t: 5.6,
2798
+ pose: {
2799
+ x: 0,
2800
+ lean: 0.95,
2801
+ armL: -1.2,
2802
+ armR: -1,
2803
+ elbL: -1.4,
2804
+ elbR: -1.3,
2805
+ headX: 0.5,
2806
+ headY: 0.3,
2807
+ drop: -0.45,
2808
+ legL: -1.2,
2809
+ legR: -0.8,
2810
+ kneeL: 1.8,
2811
+ kneeR: 1.5,
2812
+ run: 0
2813
+ }
2814
+ },
2815
+ {
2816
+ t: 8,
2817
+ pose: {
2818
+ x: 0,
2819
+ lean: 1,
2820
+ armL: -1.15,
2821
+ armR: -0.95,
2822
+ elbL: -1.4,
2823
+ elbR: -1.3,
2824
+ headX: 0.55,
2825
+ headY: 0.3,
2826
+ drop: -0.47,
2827
+ legL: -1.2,
2828
+ legR: -0.8,
2829
+ kneeL: 1.85,
2830
+ kneeR: 1.5,
2831
+ run: 0
2832
+ }
2833
+ }
2834
+ ],
2835
+ events: [
2836
+ {
2837
+ t: 0,
2838
+ type: "phase",
2839
+ data: {
2840
+ label: "pose_clip.grab_bite.phase.approach"
2841
+ }
2842
+ },
2843
+ {
2844
+ t: 1.7,
2845
+ type: "phase",
2846
+ data: {
2847
+ label: "pose_clip.grab_bite.phase.pounce"
2848
+ }
2849
+ },
2850
+ {
2851
+ t: 2.1,
2852
+ type: "phase",
2853
+ data: {
2854
+ label: "pose_clip.grab_bite.phase.grab"
2855
+ }
2856
+ },
2857
+ {
2858
+ t: 4.3,
2859
+ type: "phase",
2860
+ data: {
2861
+ label: "pose_clip.grab_bite.phase.bite"
2862
+ }
2863
+ },
2864
+ {
2865
+ t: 5.6,
2866
+ type: "phase",
2867
+ data: {
2868
+ label: "pose_clip.grab_bite.phase.fall"
2869
+ }
2870
+ }
2871
+ ]
2872
+ }
2873
+ ],
2874
+ locales: {
2875
+ "pt-BR": {
2876
+ "pose_clip.grab_bite.phase.approach": "1. Aproxima\xE7\xE3o",
2877
+ "pose_clip.grab_bite.phase.pounce": "2. O bote",
2878
+ "pose_clip.grab_bite.phase.grab": "3. Agarr\xE3o: 3 s para se soltar",
2879
+ "pose_clip.grab_bite.phase.bite": "4. Mordida: infec\xE7\xE3o 100%",
2880
+ "pose_clip.grab_bite.phase.fall": "5. Queda"
2881
+ },
2882
+ en: {
2883
+ "pose_clip.grab_bite.phase.approach": "1. Approach",
2884
+ "pose_clip.grab_bite.phase.pounce": "2. The pounce",
2885
+ "pose_clip.grab_bite.phase.grab": "3. Grab: 3 s to break free",
2886
+ "pose_clip.grab_bite.phase.bite": "4. Bite: 100% infection",
2887
+ "pose_clip.grab_bite.phase.fall": "5. The fall"
2888
+ }
2889
+ }
2890
+ };
2891
+
2892
+ // src/pose-clips/registry.ts
2893
+ var createPoseClipRegistry = (initial = []) => {
2894
+ const clips = /* @__PURE__ */ new Map();
2895
+ const registry = {
2896
+ register(clip) {
2897
+ clips.set(clip.id, clip);
2898
+ return registry;
2899
+ },
2900
+ get: (id) => clips.get(id),
2901
+ list: () => [...clips.values()],
2902
+ remove: (id) => clips.delete(id)
2903
+ };
2904
+ for (const clip of initial) registry.register(clip);
2905
+ return registry;
2906
+ };
2907
+ var POSE_CLIPS = pose_clips_default.clips;
2908
+ var POSE_CLIP_LOCALES = pose_clips_default.locales;
2909
+
2910
+ // src/pose-clips/first-person-clip.ts
2911
+ var ease = (k) => k * k * (3 - 2 * k);
2912
+ var mix = (a, b, k) => a + (b - a) * k;
2913
+ var mixTriple = (a, b, k) => [mix(a[0], b[0], k), mix(a[1], b[1], k), mix(a[2], b[2], k)];
2914
+ var trackOf = (clip, side) => {
2915
+ const out = [];
2916
+ for (const key of clip.keys) {
2917
+ if (side === "L") {
2918
+ if (key.L === "mirror") {
2919
+ if (key.R) out.push({ t: key.t, key: key.R, mirror: true });
2920
+ } else if (key.L) out.push({ t: key.t, key: key.L, mirror: false });
2921
+ } else {
2922
+ const entry = key[side];
2923
+ if (entry) out.push({ t: key.t, key: entry, mirror: false });
2924
+ }
2925
+ }
2926
+ return out.sort((a, b) => a.t - b.t);
2927
+ };
2928
+ var sampleTrack = (track, time) => {
2929
+ if (track.length === 0) return void 0;
2930
+ const first = track[0];
2931
+ const last = track[track.length - 1];
2932
+ const of = (entry) => ({ p: [...entry.key.p], r: [...entry.key.r], grip: entry.key.grip, w: entry.key.w ?? 1, mirror: entry.mirror });
2933
+ if (time <= first.t) return of(first);
2934
+ if (time >= last.t) return of(last);
2935
+ let index = 0;
2936
+ while (index < track.length - 2 && time > track[index + 1].t) index++;
2937
+ const a = track[index];
2938
+ const b = track[index + 1];
2939
+ const k = ease(Math.min(1, Math.max(0, (time - a.t) / (b.t - a.t))));
2940
+ const ga = a.key.grip;
2941
+ const gb = b.key.grip;
2942
+ return {
2943
+ p: mixTriple(a.key.p, b.key.p, k),
2944
+ r: mixTriple(a.key.r, b.key.r, k),
2945
+ grip: ga === void 0 ? gb : gb === void 0 ? ga : mix(ga, gb, k),
2946
+ w: mix(a.key.w ?? 1, b.key.w ?? 1, k),
2947
+ mirror: a.mirror
2948
+ };
2949
+ };
2950
+ var sampleFirstPersonClip = (clip, time) => {
2951
+ const out = {};
2952
+ for (const side of ["R", "L", "F"]) {
2953
+ const sample = sampleTrack(trackOf(clip, side), time);
2954
+ if (sample) out[side] = sample;
2955
+ }
2956
+ return out;
2957
+ };
2446
2958
  return __toCommonJS(index_exports);
2447
2959
  })();
2448
2960
  //# sourceMappingURL=index.global.js.map