Release v0.1.10 2026-07-13
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "i-want-to-heal",
|
||||
"private": true,
|
||||
"version": "0.1.9",
|
||||
"version": "0.1.10",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"predev": "pnpm assets:sync-basis-transcoder",
|
||||
|
||||
@@ -29,6 +29,7 @@ import { useGameStore } from "../game/store";
|
||||
import type { BossId, MemberId, PulseKind } from "../game/types";
|
||||
import { BossRoom } from "./BossRoom";
|
||||
import { BossMechanicIndicators } from "./boss/BossMechanicIndicators";
|
||||
import { bossBurrowPositionY, bossIsBurrowing } from "./boss/bossBurrowVisuals";
|
||||
import { bossCanTrackTarget, bossDeathOpacity } from "./boss/bossDeathVisuals";
|
||||
import { GameAssetProvider, LEGACY_GAME_ASSETS_FORCED, selectedGameAssetUrl, useGameGLTF } from "./GameAssetProvider";
|
||||
|
||||
@@ -130,8 +131,11 @@ function createBossRenderModel(source: THREE.Object3D) {
|
||||
? object.material.map(cloneMaterial)
|
||||
: cloneMaterial(object.material);
|
||||
});
|
||||
model.updateMatrixWorld(true);
|
||||
const modelTopY = new THREE.Box3().setFromObject(model).max.y;
|
||||
return {
|
||||
model,
|
||||
modelTopY,
|
||||
fadeMaterials: [...materialClones.values()].map((material): BossFadeMaterial => ({
|
||||
material,
|
||||
baseOpacity: material.opacity,
|
||||
@@ -834,9 +838,10 @@ function AlternateBoss({ kind, bossIndex }: { kind: AlternateBossKind; bossIndex
|
||||
const light = useRef<THREE.PointLight>(null);
|
||||
const assetUrl = selectedGameAssetUrl(config.url, config.optimizedUrl ?? config.url);
|
||||
const gltf = useGameGLTF(assetUrl);
|
||||
const { model, fadeMaterials } = useMemo(() => createBossRenderModel(gltf.scene), [gltf.scene]);
|
||||
const { model, modelTopY, fadeMaterials } = useMemo(() => createBossRenderModel(gltf.scene), [gltf.scene]);
|
||||
const { actions } = useAnimations(gltf.animations, model);
|
||||
const targetPosition = useMemo(() => new THREE.Vector3(), []);
|
||||
const burrowPositionY = bossBurrowPositionY(modelTopY, config.scale);
|
||||
|
||||
useEffect(() => {
|
||||
return () => { for (const entry of fadeMaterials) entry.material.dispose(); };
|
||||
@@ -873,9 +878,9 @@ function AlternateBoss({ kind, bossIndex }: { kind: AlternateBossKind; bossIndex
|
||||
if (!current) return;
|
||||
const motion = current.motion;
|
||||
const airborne = archetype === "sky-sweeper" && motion.mode === "skyfall";
|
||||
const burrowed = archetype === "burrower" && motion.activeMechanicId === "burrow-rush" && motion.mode === "charging";
|
||||
const burrowing = archetype === "burrower" && bossIsBurrowing(motion.activeMechanicId, motion.mode);
|
||||
const floatingHeight = config.floating ? 0.2 : 0.03;
|
||||
targetPosition.set(motion.position[0], airborne ? 3.2 : burrowed ? -0.58 : floatingHeight, motion.position[1]);
|
||||
targetPosition.set(motion.position[0], airborne ? 3.2 : burrowing ? burrowPositionY : floatingHeight, motion.position[1]);
|
||||
group.current.position.lerp(targetPosition, 1 - Math.pow(0.00001, delta));
|
||||
if (!bossCanTrackTarget(current.boss.hp)) return;
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { BOSS_BURROW_CLEARANCE, bossBurrowPositionY, bossIsBurrowing } from "./bossBurrowVisuals";
|
||||
|
||||
describe("boss burrow visuals", () => {
|
||||
it("places the scaled top of the model below the arena floor", () => {
|
||||
const modelTopY = 2.8371768724243784;
|
||||
const modelScale = 0.82;
|
||||
const positionY = bossBurrowPositionY(modelTopY, modelScale);
|
||||
|
||||
expect(positionY + modelTopY * modelScale).toBeCloseTo(-BOSS_BURROW_CLEARANCE, 6);
|
||||
});
|
||||
|
||||
it("starts sinking during the warning and remains submerged through the charge", () => {
|
||||
expect(bossIsBurrowing("burrow-rush", "telegraph")).toBe(true);
|
||||
expect(bossIsBurrowing("burrow-rush", "charging")).toBe(true);
|
||||
expect(bossIsBurrowing("burrow-rush", "holding")).toBe(false);
|
||||
expect(bossIsBurrowing("bull-charge", "charging")).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { BossMechanicId, BossMotionMode } from "../../game/types";
|
||||
|
||||
export const BOSS_BURROW_CLEARANCE = 0.58;
|
||||
|
||||
export function bossBurrowPositionY(
|
||||
modelTopY: number,
|
||||
modelScale: number,
|
||||
clearance = BOSS_BURROW_CLEARANCE,
|
||||
): number {
|
||||
return -(Math.max(0, modelTopY) * Math.max(0, modelScale) + Math.max(0, clearance));
|
||||
}
|
||||
|
||||
export function bossIsBurrowing(
|
||||
activeMechanicId: BossMechanicId | null,
|
||||
mode: BossMotionMode,
|
||||
): boolean {
|
||||
return activeMechanicId === "burrow-rush" && (mode === "telegraph" || mode === "charging");
|
||||
}
|
||||
Reference in New Issue
Block a user