51 lines
2.2 KiB
JavaScript
51 lines
2.2 KiB
JavaScript
"use strict";
|
|
|
|
// Layer: physics/impact-core
|
|
// Shared impact constants and link-attachment helpers used by drop impacts,
|
|
// ball collisions, and high-speed tarinai collisions.
|
|
(function (global) {
|
|
const PHYSICAL_DAMAGE_SPEED_THRESHOLD = 165;
|
|
|
|
function physicalDamageFromImpactSpeed(speed = 0, { min = 0, max = 58, scale = 8.6 } = {}) {
|
|
const v = Math.max(0, Number(speed) || 0);
|
|
if (v < PHYSICAL_DAMAGE_SPEED_THRESHOLD) return 0;
|
|
const raw = (v - PHYSICAL_DAMAGE_SPEED_THRESHOLD) / Math.max(1, scale);
|
|
return clamp(raw, min, max);
|
|
}
|
|
|
|
function linkEndpointMatchesItem(endpoint, item) {
|
|
if (!endpoint || !item) return false;
|
|
if (endpoint.kind && endpoint.kind !== "item") return false;
|
|
if (endpoint.id && item.id && endpoint.id === item.id) return true;
|
|
const dx = Number(endpoint.x) - Number(item.x || 0);
|
|
const dy = Number(endpoint.y) - Number(item.y || 0);
|
|
return Number.isFinite(dx) && Number.isFinite(dy) && Math.hypot(dx, dy) <= Math.max(14, (item.r || 18) * 0.75);
|
|
}
|
|
|
|
function itemHasAttachedLink(worldRef, item) {
|
|
if (!worldRef || !item || !item.id) return false;
|
|
const pb = global.TarinaiPhysicsBodySystem || null;
|
|
const links = [];
|
|
if (worldRef.itemsOfType) {
|
|
for (const linkType of ["rope", "rod", "spring"]) {
|
|
for (const link of worldRef.itemsOfType(linkType) || []) if (link && !link.dead) links.push(link);
|
|
}
|
|
} else {
|
|
for (const link of worldRef.items || []) if (link && !link.dead && ["rope", "rod", "spring"].includes(link.type)) links.push(link);
|
|
}
|
|
for (const link of links) {
|
|
const endpoints = [pb?.endpoint?.(link, 0), pb?.endpoint?.(link, 1)];
|
|
const fallback = link.physicsConstraint?.endpoints || link.constraint?.endpoints || [];
|
|
if (!endpoints[0] && fallback[0]) endpoints[0] = fallback[0];
|
|
if (!endpoints[1] && fallback[1]) endpoints[1] = fallback[1];
|
|
if (linkEndpointMatchesItem(endpoints[0], item) || linkEndpointMatchesItem(endpoints[1], item)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
global.TarinaiImpactCoreSystem = Object.freeze({
|
|
PHYSICAL_DAMAGE_SPEED_THRESHOLD,
|
|
physicalDamageFromImpactSpeed,
|
|
itemHasAttachedLink,
|
|
});
|
|
})(typeof window !== "undefined" ? window : globalThis);
|