updating buff and debuff icons. separated COA classes from WoW classes on the character creation screen

This commit is contained in:
phenom committed 2026-08-16 11:16:51 -04:00
1 parent b5c9bce1aa
commit c00f3211ea
39 files changed
+2037 -208

No files matched your search

+90 -9
View File
@@ -13,7 +13,12 @@ import { useShellStore } from "../app/shellStore";
import type { CharacterProfile } from "../app/types";
import { CharacterModel } from "../avatar/CharacterModel";
import { ProceduralAvatar } from "../avatar/ProceduralAvatar";
import { consumeMouseLook, readInputSnapshot } from "../game/inputManager";
import {
clearJumpRequest,
consumeJumpRequest,
consumeMouseLook,
readInputSnapshot,
} from "../game/inputManager";
import { useCombatStore } from "../game/combatStore";
import type { CharacterCombatAnimationEvent } from "../game/combatAnimation";
import {
@@ -33,6 +38,18 @@ import {
isBelowDungeonRecoveryPlane,
isBelowManastormRecoveryPlane,
} from "../game/playerRecovery";
import {
PLAYER_GROUND_PROBE_DISTANCE,
PLAYER_JUMP_VELOCITY,
PLAYER_LANDING_PRESENTATION_MS,
bufferPlayerJump,
cancelBufferedPlayerJump,
characterVerticalMotion,
createPlayerJumpTiming,
isWalkableGroundHit,
updatePlayerJumpTiming,
type CharacterVerticalMotion,
} from "../game/playerJump";
import { activeManastormStageAssetPackage } from "../game/manastormStageLoader";
import { useGameStore } from "../game/store";
@@ -62,6 +79,7 @@ interface PlayerControllerProps extends PlayerRigRefs {
identity: CharacterProfile | null;
equipmentItems: readonly InventoryItem[];
movingRef: React.MutableRefObject<boolean>;
verticalMotionRef: React.MutableRefObject<CharacterVerticalMotion>;
animationEventRef: React.MutableRefObject<CharacterCombatAnimationEvent | null>;
}
@@ -85,6 +103,7 @@ function PlayerController({
identity,
equipmentItems,
movingRef,
verticalMotionRef,
animationEventRef,
}: PlayerControllerProps) {
const paused = useGameStore((state) => state.paused);
@@ -98,11 +117,24 @@ function PlayerController({
const spawn = useGameStore((state) => state.activeSpawn);
const dungeon = requireDungeonDefinition(activeDungeonId);
const lastReported = useRef<[number, number, number]>([...spawn.footPosition]);
const { rapier, world } = useRapier();
const groundRay = useMemo(
() => new rapier.Ray({ x: 0, y: 0, z: 0 }, { x: 0, y: -1, z: 0 }),
[rapier],
);
const jumpTimingRef = useRef(createPlayerJumpTiming());
const wasGroundedRef = useRef(true);
const landingUntilRef = useRef(Number.NEGATIVE_INFINITY);
useEffect(() => {
if (bodyRef.current) placeAtActiveSpawn(bodyRef.current, orbitRef.current);
lastReported.current = [...spawn.footPosition];
}, [bodyRef, orbitRef, resetRevision, spawn]);
clearJumpRequest();
jumpTimingRef.current = createPlayerJumpTiming(performance.now());
wasGroundedRef.current = true;
landingUntilRef.current = Number.NEGATIVE_INFINITY;
verticalMotionRef.current = "grounded";
}, [bodyRef, orbitRef, resetRevision, spawn, verticalMotionRef]);
useFrame((_, delta) => {
const body = bodyRef.current;
@@ -131,18 +163,68 @@ function PlayerController({
}
const velocity = body.linvel();
if (paused || mapOpen || companionOpen || controlledUntil > Date.now()) {
const translation = body.translation();
if (![translation.x, translation.y, translation.z].every(Number.isFinite)) {
placeAtActiveSpawn(body, orbit);
return;
}
const nowMs = performance.now();
groundRay.origin.x = translation.x;
groundRay.origin.y = translation.y;
groundRay.origin.z = translation.z;
const groundProbeLength = PLAYER_CENTER_HEIGHT + PLAYER_GROUND_PROBE_DISTANCE;
const groundHit = world.castRayAndGetNormal(
groundRay,
groundProbeLength,
true,
rapier.QueryFilterFlags.EXCLUDE_SENSORS | rapier.QueryFilterFlags.EXCLUDE_DYNAMIC,
undefined,
undefined,
body,
);
let grounded = velocity.y <= 0.5 && isWalkableGroundHit(groundHit, groundProbeLength);
const requestedAtMs = consumeJumpRequest();
const gameplayBlocked = paused || mapOpen || companionOpen || controlledUntil > Date.now();
if (gameplayBlocked) {
cancelBufferedPlayerJump(jumpTimingRef.current);
movingRef.current = false;
verticalMotionRef.current = characterVerticalMotion(
grounded,
velocity.y,
nowMs,
landingUntilRef.current,
);
body.setLinvel({ x: 0, y: velocity.y, z: 0 }, true);
return;
}
if (requestedAtMs !== null) bufferPlayerJump(jumpTimingRef.current, requestedAtMs);
const shouldJump = updatePlayerJumpTiming(
jumpTimingRef.current,
nowMs,
grounded,
velocity.y,
);
const verticalVelocity = shouldJump ? PLAYER_JUMP_VELOCITY : velocity.y;
if (shouldJump) grounded = false;
if (grounded && !wasGroundedRef.current) {
landingUntilRef.current = nowMs + PLAYER_LANDING_PRESENTATION_MS;
}
wasGroundedRef.current = grounded;
verticalMotionRef.current = characterVerticalMotion(
grounded,
verticalVelocity,
nowMs,
landingUntilRef.current,
);
const [worldX, worldZ] = cameraRelativeMovement(
snapshot.moveX,
snapshot.moveForward,
orbit.yaw,
);
body.setLinvel({ x: worldX * MOVE_SPEED, y: velocity.y, z: worldZ * MOVE_SPEED }, true);
body.setLinvel({ x: worldX * MOVE_SPEED, y: verticalVelocity, z: worldZ * MOVE_SPEED }, true);
const moving = Math.hypot(worldX, worldZ) > 0.05;
movingRef.current = moving;
@@ -152,11 +234,6 @@ function PlayerController({
avatarRef.current.rotation.y += difference * (1 - Math.exp(-14 * delta));
}
const translation = body.translation();
if (![translation.x, translation.y, translation.z].every(Number.isFinite)) {
placeAtActiveSpawn(body, orbit);
return;
}
const activeManastormPackage = gameMode === "manastorm"
? activeManastormStageAssetPackage()
: null;
@@ -185,6 +262,7 @@ function PlayerController({
position: footPosition,
yaw: orbit.yaw,
distanceDelta,
grounded,
});
lastReported.current = footPosition;
}
@@ -214,6 +292,7 @@ function PlayerController({
equipment={equipmentItems}
active={!paused && !mapOpen && !companionOpen}
movingRef={movingRef}
verticalMotionRef={verticalMotionRef}
animationEventRef={animationEventRef}
fallback={<ProceduralAvatar accent={classById(identity?.classId ?? "priest").color} />}
/>
@@ -331,6 +410,7 @@ export function PlayerRig() {
const bodyRef = useRef<RapierRigidBody>(null);
const avatarRef = useRef<Object3D>(null);
const movingRef = useRef(false);
const verticalMotionRef = useRef<CharacterVerticalMotion>("grounded");
const animationEventRef = useRef<CharacterCombatAnimationEvent | null>(animationEvent);
animationEventRef.current = animationEvent;
const activeDungeonId = useGameStore((state) => state.activeDungeonId);
@@ -349,6 +429,7 @@ export function PlayerRig() {
identity={activeCharacter}
equipmentItems={equipmentItems}
movingRef={movingRef}
verticalMotionRef={verticalMotionRef}
animationEventRef={animationEventRef}
/>
<ThirdPersonCamera bodyRef={bodyRef} orbitRef={orbitRef} avatarRef={avatarRef} />