Commit c5a17ebb authored by Ategon's avatar Ategon Committed by Grant
Browse files

Add a pixel available chime offset setting

parent 7bef4c8a
Loading
Loading
Loading
Loading
Loading
+92 −4
Original line number Diff line number Diff line
import { useCallback, useEffect, useState } from "react";
import { useRef } from "react";
import { Slider } from "@heroui/react";
import { CanvasLib } from "@sc07-canvas/lib/canvas";
import { useCallback, useEffect, useRef, useState } from "react";
import useSound from "use-sound";

import { useAppContext } from "@/contexts/AppContext";
import { useAudio } from "@/contexts/AudioContext";
import { CanvasCore } from "@/lib/canvas";

import network from "../../lib/network";
import African1 from "../../sounds/African1.mp3";
@@ -20,8 +23,11 @@ const _ = (v: boolean) => (v ? "enable" : "disable");

export const AudioSettings = () => {
  const { state, dispatch } = useAudio();
  const { config } = useAppContext<true>();

  const coffee2Ref = useRef<(() => void) | null>(null);
  const delayedAvailableSoundRef = useRef<number | undefined>(undefined);
  const earlyAvailableSoundPlayedRef = useRef(false);

  const [Coffee1Sound] = useSound(Coffee1, { volume: 0.5 });

@@ -44,6 +50,7 @@ export const AudioSettings = () => {
  const [WoodBlock3Sound] = useSound(WoodBlock3, { volume: 0.1 });

  const [pixelsAvailable, setPixelsAvailable] = useState(0);
  const [pixelAvailableOffset, setPixelAvailableOffset] = useState(0);

  const WoodSounds = [WoodBlock1Sound, WoodBlock2Sound, WoodBlock3Sound];

@@ -51,15 +58,41 @@ export const AudioSettings = () => {
    coffee2Ref.current = Coffee2Sound;
  }, [Coffee2Sound]);

  useEffect(() => {
    return () => {
      if (delayedAvailableSoundRef.current !== undefined) {
        window.clearTimeout(delayedAvailableSoundRef.current);
        delayedAvailableSoundRef.current = undefined;
      }
    };
  }, [pixelAvailableOffset, state.pixelAvailable]);

  const handleAvailable = useCallback(
    (available: number, isUndo: boolean) => {
      if (available > pixelsAvailable && state.pixelAvailable && !isUndo) {
        if (pixelAvailableOffset < 0) {
          if (!earlyAvailableSoundPlayedRef.current) Coffee2Sound();
          earlyAvailableSoundPlayedRef.current = false;
        } else if (pixelAvailableOffset === 0) {
          Coffee2Sound();
        } else {
          delayedAvailableSoundRef.current = window.setTimeout(() => {
            Coffee2Sound();
            delayedAvailableSoundRef.current = undefined;
          }, pixelAvailableOffset * 1000);
        }
      } else if (available < pixelsAvailable) {
        earlyAvailableSoundPlayedRef.current = false;
      }

      setPixelsAvailable(available);
    },
    [pixelsAvailable, state.pixelAvailable],
    [
      Coffee2Sound,
      pixelAvailableOffset,
      pixelsAvailable,
      state.pixelAvailable,
    ],
  );

  useEffect(() => {
@@ -70,6 +103,44 @@ export const AudioSettings = () => {
    };
  }, [handleAvailable]);

  useEffect(() => {
    earlyAvailableSoundPlayedRef.current = false;

    if (
      !state.pixelAvailable ||
      pixelAvailableOffset >= 0 ||
      pixelsAvailable >= config.canvas.pixel.maxStack
    ) {
      return;
    }

    const canvas = CanvasCore.get(false);
    if (!canvas?.lastPlace) return;

    const cooldown = CanvasLib.getPixelCooldown(pixelsAvailable + 1, config);
    const availableAt =
      canvas.lastPlace + cooldown * 1000 * (pixelsAvailable + 1);
    const soundAt = availableAt + pixelAvailableOffset * 1000;
    const delay = soundAt - Date.now();

    if (delay <= 0) return;

    const timeout = window.setTimeout(() => {
      earlyAvailableSoundPlayedRef.current = true;
      Coffee2Sound();
    }, delay);

    return () => {
      window.clearTimeout(timeout);
    };
  }, [
    Coffee2Sound,
    config,
    pixelAvailableOffset,
    pixelsAvailable,
    state.pixelAvailable,
  ]);

  const handlePlace = useCallback(() => {
    if (!state.place) return;

@@ -166,6 +237,23 @@ export const AudioSettings = () => {
        >
          Pixel Available
        </Switch>
        {state.pixelAvailable && (
          <Slider
            className="px-2"
            label="Chime Offset"
            step={1}
            minValue={-5}
            maxValue={15}
            value={-pixelAvailableOffset}
            onChange={(value) =>
              setPixelAvailableOffset(-(value as number))
            }
            getValue={(value) => {
              const offset = -(value as number);
              return `${offset > 0 ? "+" : ""}${offset}s`;
            }}
          />
        )}
        <Switch
          silent
          isSelected={state.place}