Release v0.1.2 2026-07-11

This commit is contained in:
Warren H
2026-07-11 00:12:57 -04:00
parent 6726c600e4
commit 076f6cf97c
16 changed files with 556 additions and 21 deletions
+48 -12
View File
@@ -17,6 +17,7 @@ const SPIDER_TEXTURE_URLS: Record<string, string> = {
"haar_detail_NRM.jpg": new URL("../../game_assets/models/downloaded/low-poly-spider/textures/haar_detail_NRM.jpg", import.meta.url).href,
};
const DRAGON_URL = new URL("../../game_assets/models/claudecraft/creatures/dragonevolved.glb", import.meta.url).href;
const EMBER_MANTIS_URL = new URL("../../game_assets/models/original/bosses/ember-mantis-duelist/ember_mantis_duelist.glb", import.meta.url).href;
const PARTY_MODEL_URLS: Record<MemberId, string> = {
aelia: new URL("../../game_assets/models/claudecraft/chars/players/druid.glb", import.meta.url).href,
brann: new URL("../../game_assets/models/claudecraft/chars/players/knight.glb", import.meta.url).href,
@@ -491,7 +492,7 @@ function BossFallback({ bossIndex }: { bossIndex: number }) {
return (
<mesh castShadow position={[position[0], 1.1, position[1]]}>
<dodecahedronGeometry args={[1.1, 0]} />
<meshStandardMaterial color={bossId === "vexa" ? "#56306f" : bossId === "cindermaw" ? "#9d4c24" : "#7b3928"} emissive="#3a100c" emissiveIntensity={0.5} />
<meshStandardMaterial color={bossId === "vexa" ? "#56306f" : bossId === "cindermaw" ? "#9d4c24" : bossId === "ember-mantis-duelist" ? "#a42d18" : "#7b3928"} emissive="#3a100c" emissiveIntensity={0.5} />
</mesh>
);
}
@@ -580,7 +581,7 @@ function BullBoss({ bossIndex }: { bossIndex: number }) {
);
}
type AlternateBossKind = "vexa" | "cindermaw";
type AlternateBossKind = "vexa" | "cindermaw" | "ember-mantis-duelist";
const ALTERNATE_BOSS_CONFIG = {
vexa: {
@@ -605,6 +606,17 @@ const ALTERNATE_BOSS_CONFIG = {
light: "#ff8742",
rotationOffset: 0,
},
"ember-mantis-duelist": {
url: EMBER_MANTIS_URL,
scale: 0.78,
idle: "Idle",
move: "Sidestep",
attack: "LineSlash",
special: "CrossSlash",
death: "Death",
light: "#ff5a24",
rotationOffset: 0,
},
} as const;
function AlternateBoss({ kind, bossIndex }: { kind: AlternateBossKind; bossIndex: number }) {
@@ -634,27 +646,43 @@ function AlternateBoss({ kind, bossIndex }: { kind: AlternateBossKind; bossIndex
const clipName = phase === "victory" || defeated
? config.death
: motionMode === "skyfall"
? config.move
: motionMode === "breath_telegraph" || motionMode === "breath_sweeping"
? config.special
: motionMode === "tethering" || motionMode === "venom_cast"
: kind === "ember-mantis-duelist"
? motionMode === "mantis_sidestep"
? config.move
: motionMode === "mantis_line_telegraph"
? config.attack
: config.idle;
: motionMode === "mantis_cross_telegraph"
? config.special
: motionMode === "mantis_recover"
? "Recover"
: config.idle
: motionMode === "skyfall"
? config.move
: motionMode === "breath_telegraph" || motionMode === "breath_sweeping"
? config.special
: motionMode === "tethering" || motionMode === "venom_cast"
? config.attack
: config.idle;
useEffect(() => {
const next = actions[clipName];
if (!next) return;
for (const action of Object.values(actions)) action?.fadeOut(0.16);
next.reset().setEffectiveWeight(1).fadeIn(0.16).play();
if (phase === "victory" || defeated) {
const timeScale = kind === "ember-mantis-duelist" && motionMode === "mantis_line_telegraph"
? 0.55
: kind === "ember-mantis-duelist" && motionMode === "mantis_cross_telegraph"
? 0.6
: 1;
next.reset().setEffectiveWeight(1).setEffectiveTimeScale(timeScale).fadeIn(0.16).play();
const emberOneShot = kind === "ember-mantis-duelist" && clipName !== config.idle;
if (phase === "victory" || defeated || emberOneShot) {
next.setLoop(THREE.LoopOnce, 1);
next.clampWhenFinished = true;
} else {
next.setLoop(THREE.LoopRepeat, Number.POSITIVE_INFINITY);
}
return () => { next.fadeOut(0.16); };
}, [actions, clipName, defeated, phase]);
}, [actions, clipName, config.idle, defeated, kind, motionMode, phase]);
useFrame((_, delta) => {
if (!group.current) return;
@@ -672,6 +700,13 @@ function AlternateBoss({ kind, bossIndex }: { kind: AlternateBossKind; bossIndex
);
if (kind === "cindermaw" && (motion.mode === "breath_telegraph" || motion.mode === "breath_sweeping")) {
targetAngle = motion.breathAngle;
} else if (kind === "ember-mantis-duelist" && (
motion.mode === "mantis_sidestep"
|| motion.mode === "mantis_line_telegraph"
|| motion.mode === "mantis_cross_telegraph"
)) {
const target = state.partyPositions[motion.chargeTargetId];
targetAngle = Math.atan2(target[0] - motion.position[0], target[1] - motion.position[1]);
}
const difference = Math.atan2(
Math.sin(targetAngle - group.current.rotation.y),
@@ -877,7 +912,7 @@ function FxBurst({ kind, targetId }: { kind: PulseKind; targetId?: MemberId }) {
const state = useGameStore.getState();
const worldPosition = isBossFx ? targetBossMotion(state).position : targetId ? state.partyPositions[targetId] : [0, 0];
const position: [number, number, number] = [worldPosition[0], 0.15, worldPosition[1]];
const color = kind === "boss" || kind === "debuff" || kind === "charge" || kind === "pounce" ? "#ff643c" : kind === "shield" ? "#62bdff" : kind === "purify" ? "#c39bff" : "#ffe087";
const color = kind === "boss" || kind === "debuff" || kind === "charge" || kind === "pounce" || kind === "slash" ? "#ff643c" : kind === "shield" ? "#62bdff" : kind === "purify" ? "#c39bff" : "#ffe087";
useFrame((_, delta) => {
age.current += delta;
if (!ring.current || !material.current) return;
@@ -926,6 +961,7 @@ export function GameScene() {
}
useGLTF.preload(BULL_URL, false, true);
useGLTF.preload(EMBER_MANTIS_URL, false, true);
for (const modelUrl of Object.values(PARTY_MODEL_URLS)) useGLTF.preload(modelUrl, false, true);
for (const loadout of Object.values(PARTY_WEAPON_URLS)) {
useGLTF.preload(loadout.right, false, true);