Release Healer Man 0.1.21

This commit is contained in:
phenom committed 2026-09-08 10:40:26 -04:00
1 parent 699fc858c9
commit f6f2375145
210 files changed
+976039 -6247

No files matched your search

+95
View File
@@ -0,0 +1,95 @@
import { CuboidCollider, RigidBody } from "@react-three/rapier";
import { useMemo, useSyncExternalStore } from "react";
import type { Object3D } from "three";
import {
activeDungeonEncounterRevision,
subscribeDungeonEncounterSnapshots,
} from "../game/dungeonEncounterRuntime";
import { activeDungeonWorldObjectStates } from "../game/dungeonWorldInteraction";
import {
dungeonWorldObjectState,
type DungeonWorldObjectDefinition,
} from "../game/dungeonWorldObjects";
import {
DUNGEON_PHYSICAL_COLLISION_GROUPS,
DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS,
} from "./dungeonLineOfSight";
import { useGameGLTF } from "./useGameGLTF";
function AssetObject({ definition }: { readonly definition: DungeonWorldObjectDefinition }) {
const gltf = useGameGLTF(definition.visual!.assetUrl!);
const visual = useMemo<Object3D>(() => gltf.scene.clone(true), [gltf.scene]);
return <primitive object={visual} scale={definition.visual?.scale ?? [1, 1, 1]} />;
}
function ProceduralObject({ definition }: { readonly definition: DungeonWorldObjectDefinition }) {
const [x, y, z] = definition.halfExtents;
return (
<mesh castShadow receiveShadow>
<boxGeometry args={[x * 2, y * 2, z * 2]} />
<meshStandardMaterial
color={definition.visual?.color ?? (definition.kind === "switch" ? "#dca24a" : "#65584b")}
emissive={definition.visual?.emissive ?? "#000000"}
roughness={0.72}
/>
</mesh>
);
}
function WorldObject({
definition,
stateId,
}: {
readonly definition: DungeonWorldObjectDefinition;
readonly stateId?: string;
}) {
const state = dungeonWorldObjectState(definition, stateId);
if (!state.visible) return null;
return (
<RigidBody
key={`${definition.id}:${state.id}`}
type="fixed"
colliders={false}
position={definition.position}
rotation={[0, definition.yaw ?? 0, 0]}
name={`dungeon-object:${definition.id}:${state.id}`}
>
{state.blocksMovement && (
<CuboidCollider
args={[...definition.halfExtents]}
collisionGroups={DUNGEON_PHYSICAL_COLLISION_GROUPS}
/>
)}
{state.blocksSight && (
<CuboidCollider
args={[...definition.halfExtents]}
collisionGroups={DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS}
sensor
/>
)}
{definition.visual?.assetUrl
? <AssetObject definition={definition} />
: <ProceduralObject definition={definition} />}
</RigidBody>
);
}
export function DungeonWorldObjects({
definitions,
}: {
readonly definitions: readonly DungeonWorldObjectDefinition[];
}) {
useSyncExternalStore(
subscribeDungeonEncounterSnapshots,
activeDungeonEncounterRevision,
activeDungeonEncounterRevision,
);
const states = activeDungeonWorldObjectStates();
return (
<group name="dungeon-world-objects">
{definitions.map((definition) => (
<WorldObject key={definition.id} definition={definition} stateId={states[definition.id]} />
))}
</group>
);
}
+27 -5
View File
@@ -4,6 +4,7 @@ import {
useMemo,
useRef,
useState,
useSyncExternalStore,
type PointerEvent as ReactPointerEvent,
} from "react";
import { Canvas } from "@react-three/fiber";
@@ -52,6 +53,13 @@ import { numericFrameRateLimit } from "../game/frameRateSettings";
import { useDocumentVisibility } from "../platform/useDocumentVisibility";
import { CappedFrameLoop } from "./CappedFrameLoop";
import { selectDungeonSessionPopulation } from "../game/dungeonSpawnSelection";
import { DungeonWorldObjects } from "./DungeonWorldObjects";
import {
activeDungeonEncounterRevision,
activeDungeonEncounterSpawnGroupIds,
subscribeDungeonEncounterSnapshots,
} from "../game/dungeonEncounterRuntime";
import { activeEncounterSpawnGroupSpawns } from "../game/dungeonEncounterSpawns";
export function GameScene() {
const activeDungeonId = useGameStore((state) => state.activeDungeonId);
@@ -60,6 +68,11 @@ export function GameScene() {
const manastormEncounter = useManastormStore((state) => state.currentEncounter);
const manastormPhase = useManastormStore((state) => state.phase);
const wailingPhase = useWailingEncounterStore((state) => state.phase);
useSyncExternalStore(
subscribeDungeonEncounterSnapshots,
activeDungeonEncounterRevision,
activeDungeonEncounterRevision,
);
const dungeon = requireDungeonDefinition(activeDungeonId);
const cameraFar = Math.max(
950,
@@ -103,7 +116,17 @@ export function GameScene() {
phasedStaticSpawns,
difficultyRoamingPacks,
);
const staticSpawns = sessionPopulation.staticSpawns;
const activeSpawnGroupIds = activeDungeonEncounterSpawnGroupIds();
const encounterSpawns = activeEncounterSpawnGroupSpawns(
dungeon.encounterSpawnGroups ?? [],
activeSpawnGroupIds,
difficultyMask,
sessionPopulation.staticSpawns,
);
const staticSpawns = [
...sessionPopulation.staticSpawns,
...encounterSpawns,
];
const roamingPacks = sessionPopulation.roamingPacks;
const paused = useGameStore((state) => state.paused);
const mapOpen = useGameStore((state) => state.mapOpen);
@@ -180,10 +203,6 @@ export function GameScene() {
};
}, [canvasRevision]);
useEffect(() => {
useWailingEncounterStore.getState().reset();
}, [activeDungeonId, gameMode, sessionRevision]);
useEffect(() => {
setAdaptiveDpr(1.5);
}, [activeDungeonId, sessionRevision]);
@@ -294,6 +313,9 @@ export function GameScene() {
<OnlinePlayerPopulation active={!simulationBlocked} />
<PartyPopulation active={!simulationBlocked} simulate={!sharedOnline || onlineAuthority} />
<GroundEffectTelegraphs />
{gameMode === "dungeon" && (
<DungeonWorldObjects definitions={dungeon.serverGameObjects} />
)}
<MobPopulation
active={!simulationBlocked}
entities={stagePopulation.entities}
+1 -1
View File
@@ -870,7 +870,7 @@ function ProxyMob({
level: gameMode === "manastorm"
? definition.combat?.level
: scaledDungeonEnemyLevel(characterLevel, boss),
hasLoot: definition.hasLoot ?? (boss && bossHasLoot(definition.id)),
hasLoot: Boolean((boss && bossHasLoot(definition.id)) || definition.hasLoot),
lootSourceId: boss ? definition.id : undefined,
healthMultiplier: baseHealthMultiplier * (manastormModifiers?.enemyStatMultiplier ?? 1),
damageMultiplier: baseDamageMultiplier * (manastormModifiers?.enemyStatMultiplier ?? 1),
+2 -1
View File
@@ -120,6 +120,7 @@ function PlayerController({
const mapOpen = useGameStore((state) => state.mapOpen);
const companionOpen = useGameStore((state) => state.companionOpen);
const resetRevision = useGameStore((state) => state.resetRevision);
const relocationRevision = useGameStore((state) => state.relocationRevision);
const reportAccumulator = useRef(0);
const activeDungeonId = useGameStore((state) => state.activeDungeonId);
const gameMode = useGameStore((state) => state.gameMode);
@@ -159,7 +160,7 @@ function PlayerController({
verticalPresentationTimingRef.current = createCharacterVerticalPresentationTiming();
verticalVelocityRef.current = 0;
verticalMotionRef.current = "grounded";
}, [bodyRef, orbitRef, resetRevision, spawn, verticalMotionRef]);
}, [bodyRef, orbitRef, relocationRevision, resetRevision, spawn, verticalMotionRef]);
useFrame((_, delta) => {
const body = bodyRef.current;