import { Html } from "@react-three/drei";
import { useFrame } from "@react-three/fiber";
import { useMemo, useRef } from "react";
import type { Group, Mesh } from "three";
import { MathUtils } from "three";
import type { ResourceNodeSnapshot } from "../types";
import { hashToUnit } from "./characterUtils";
type ResourceActorProps = {
node: ResourceNodeSnapshot;
isSelected: boolean;
onSelect: () => void;
};
export function ResourceActor({ node, isSelected, onSelect }: ResourceActorProps) {
const pulseRef = useRef(null);
const swayRef = useRef(null);
const animationPhase = useMemo(() => hashToUnit(node.id) * Math.PI * 2, [node.id]);
const color = resourceColor(node.type);
const richness = resourceRichness(node);
useFrame((state) => {
const time = state.clock.elapsedTime + animationPhase;
if (pulseRef.current) {
const pulse = 1 + Math.sin(state.clock.elapsedTime * 4) * 0.08;
pulseRef.current.scale.setScalar(isSelected ? pulse : 0.001);
}
if (swayRef.current) {
swayRef.current.rotation.z = Math.sin(time * 1.4) * 0.035;
swayRef.current.rotation.x = Math.sin(time * 1.1) * 0.025;
}
});
return (
{
event.stopPropagation();
onSelect();
}}
>
{
event.stopPropagation();
onSelect();
}}
>
);
}
function ResourceModel({
type,
swayRef,
}: {
type: string;
swayRef: React.RefObject;
}) {
if (type === "food") {
return ;
}
if (type === "herbs") {
return ;
}
if (type === "wood") {
return ;
}
if (type === "weapon") {
return ;
}
return ;
}
function BerryBush({ swayRef }: { swayRef: React.RefObject }) {
return (
{/* trunk stub */}
{/* foliage blocks */}
{/* berries */}
);
}
function Berry({ x, y, z }: { x: number; y: number; z: number }) {
return (
);
}
function HerbPatch({ swayRef }: { swayRef: React.RefObject }) {
return (
{/* dirt mound */}
);
}
function HerbSprout({ x, z, height }: { x: number; z: number; height: number }) {
return (
);
}
function LogPile() {
return (
);
}
function Log({ x, y, rotationY }: { x: number; y: number; rotationY: number }) {
return (
);
}
function WeaponCache() {
return (
{/* stone block */}
{/* sword blade */}
{/* axe leaning on the stone */}
);
}
function SupplyCrate() {
return (
);
}
export function resourceTitle(type: string): string {
if (!type) {
return "Resource";
}
return `${type.charAt(0).toUpperCase()}${type.slice(1)}`;
}
export function resourceColor(type: string): string {
if (type === "food") {
return "#e3c454";
}
if (type === "herbs") {
return "#58a65c";
}
if (type === "wood") {
return "#7a5234";
}
if (type === "weapon") {
return "#b7bec8";
}
return "#d9d2aa";
}
function resourceRichness(node: ResourceNodeSnapshot): number {
const ratio = node.max_amount
? MathUtils.clamp(node.amount / node.max_amount, 0, 1)
: MathUtils.clamp(node.amount / 10, 0, 1);
return MathUtils.lerp(0.55, 1.15, ratio);
}