feat: custom shell functionality

This commit is contained in:
tresabhi committed 2024-11-10 20:59:01 -06:00
1 parent 9a1c66932a
commit dbc3d0df3a
6 files changed
+58 -21

No files matched your search

@@ -1,5 +1,4 @@
import {
type ShellDefinition,
canSplash,
isExplosive,
resolvePenetrationCoefficient,
@@ -11,6 +10,7 @@ import { degToRad } from 'three/src/math/MathUtils.js';
import { hasEquipment } from '../../../../core/blitzkit/hasEquipment';
import { jsxTree } from '../../../../core/blitzkit/jsxTree';
import { Duel, type EquipmentMatrix } from '../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../stores/tankopediaEphemeral';
import { TankopediaPersistent } from '../../../../stores/tankopediaPersistent';
import fragmentShader from './shaders/fragment.glsl?raw';
import vertexShader from './shaders/vertex.glsl?raw';
@@ -31,6 +31,7 @@ export function PrimaryArmorSceneComponent({
}: PrimaryArmorSceneComponentProps) {
const tankopediaPersistentStore = TankopediaPersistent.useStore();
const duelStore = Duel.useStore();
const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
const material = new ShaderMaterial({
fragmentShader,
vertexShader,
@@ -58,7 +59,11 @@ export function PrimaryArmorSceneComponent({
});
useEffect(() => {
async function handleShellChange(shell: ShellDefinition) {
async function handleShellChange() {
const duel = duelStore.getState();
const tankopediaEphemeral = tankopediaEphemeralStore.getState();
const shell = tankopediaEphemeral.customShell ?? duel.antagonist.shell;
material.uniforms.caliber.value = shell.caliber;
material.uniforms.ricochet.value = degToRad(
isExplosive(shell.type) ? 90 : shell.ricochet!,
@@ -71,7 +76,6 @@ export function PrimaryArmorSceneComponent({
material.uniforms.damage.value = shell.armor_damage;
material.uniforms.explosionRadius.value = shell.explosion_radius;
const duel = duelStore.getState();
await handleProtagonistEquipmentChange(duel.protagonist.equipmentMatrix);
await handleAntagonistEquipmentChange(duel.antagonist.equipmentMatrix);
invalidate();
@@ -104,7 +108,8 @@ export function PrimaryArmorSceneComponent({
}
async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) {
const duel = duelStore.getState();
const shell = duel.antagonist.shell;
const tankopediaEphemeral = tankopediaEphemeralStore.getState();
const shell = tankopediaEphemeral.customShell ?? duel.antagonist.shell;
const penetration = shell.penetration.near;
const hasCalibratedShells = await hasEquipment(
103,
@@ -119,7 +124,7 @@ export function PrimaryArmorSceneComponent({
invalidate();
}
handleShellChange(duelStore.getState().antagonist.shell);
handleShellChange();
handleGreenPenetrationChange(
tankopediaPersistentStore.getState().greenPenetration,
);
@@ -134,6 +139,10 @@ export function PrimaryArmorSceneComponent({
const unsubscribes = [
duelStore.subscribe((state) => state.antagonist.shell, handleShellChange),
tankopediaEphemeralStore.subscribe(
(state) => state.customShell,
handleShellChange,
),
tankopediaPersistentStore.subscribe(
(state) => state.greenPenetration,
handleGreenPenetrationChange,
@@ -1,7 +1,4 @@
import {
resolvePenetrationCoefficient,
type ShellDefinition,
} from '@blitzkit/core';
import { resolvePenetrationCoefficient } from '@blitzkit/core';
import { invalidate } from '@react-three/fiber';
import { useEffect } from 'react';
import {
@@ -15,6 +12,7 @@ import type { ArmorUserData, ExternalModuleVariant } from '../..';
import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment';
import { jsxTree } from '../../../../../../core/blitzkit/jsxTree';
import { Duel, type EquipmentMatrix } from '../../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
import { ArmorType } from '../../../SpacedArmorScene';
import fragmentShader from './shaders/fragment.glsl?raw';
import vertexShader from './shaders/vertex.glsl?raw';
@@ -32,6 +30,7 @@ export function SpacedArmorSubExternal({
variant,
clip,
}: SpacedArmorSubExternalProps) {
const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
const duelStore = Duel.useStore();
const material = new ShaderMaterial({
fragmentShader,
@@ -50,7 +49,10 @@ export function SpacedArmorSubExternal({
});
useEffect(() => {
function handleShellChange(shell: ShellDefinition) {
function handleShellChange() {
const duel = duelStore.getState();
const tankopediaEphemeral = tankopediaEphemeralStore.getState();
const shell = tankopediaEphemeral.customShell ?? duel.antagonist.shell;
material.uniforms.penetration.value = shell.penetration.near;
invalidate();
}
@@ -71,7 +73,8 @@ export function SpacedArmorSubExternal({
}
async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) {
const duel = duelStore.getState();
const shell = duel.antagonist.shell;
const tankopediaEphemeral = tankopediaEphemeralStore.getState();
const shell = tankopediaEphemeral.customShell ?? duel.antagonist.shell;
const penetration = shell.penetration.near;
const hasCalibratedShells = await hasEquipment(
103,
@@ -86,7 +89,7 @@ export function SpacedArmorSubExternal({
invalidate();
}
handleShellChange(duelStore.getState().antagonist.shell);
handleShellChange();
handleProtagonistEquipmentChange(
duelStore.getState().protagonist.equipmentMatrix,
);
@@ -96,6 +99,10 @@ export function SpacedArmorSubExternal({
const unsubscribes = [
duelStore.subscribe((state) => state.antagonist.shell, handleShellChange),
tankopediaEphemeralStore.subscribe(
(state) => state.customShell,
handleShellChange,
),
duelStore.subscribe(
(state) => state.protagonist.equipmentMatrix,
handleProtagonistEquipmentChange,
@@ -1,8 +1,4 @@
import {
isExplosive,
resolvePenetrationCoefficient,
type ShellDefinition,
} from '@blitzkit/core';
import { isExplosive, resolvePenetrationCoefficient } from '@blitzkit/core';
import { invalidate } from '@react-three/fiber';
import { useEffect } from 'react';
import {
@@ -16,6 +12,7 @@ import type { ArmorUserData } from '../..';
import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment';
import { jsxTree } from '../../../../../../core/blitzkit/jsxTree';
import { Duel, type EquipmentMatrix } from '../../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
import { ArmorType } from '../../../SpacedArmorScene';
import fragmentShader from './shaders/fragment.glsl?raw';
import vertexShader from './shaders/vertex.glsl?raw';
@@ -34,6 +31,7 @@ export function SpacedArmorSubSpaced({
node,
thickness,
}: SpacedArmorSubSpacedProps) {
const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
const duelStore = Duel.useStore();
const material = new ShaderMaterial({
fragmentShader,
@@ -53,7 +51,11 @@ export function SpacedArmorSubSpaced({
});
useEffect(() => {
function handleShellChange(shell: ShellDefinition) {
function handleShellChange() {
const duel = duelStore.getState();
const tankopediaEphemeral = tankopediaEphemeralStore.getState();
const shell = tankopediaEphemeral.customShell ?? duel.antagonist.shell;
material.uniforms.penetration.value = shell.penetration.near;
material.uniforms.caliber.value = shell.caliber;
material.uniforms.ricochet.value = degToRad(
@@ -82,7 +84,8 @@ export function SpacedArmorSubSpaced({
}
async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) {
const duel = duelStore.getState();
const shell = duelStore.getState().antagonist.shell;
const tankopediaEphemeral = tankopediaEphemeralStore.getState();
const shell = tankopediaEphemeral.customShell ?? duel.antagonist.shell;
const penetration = shell.penetration.near;
const hasCalibratedShells = await hasEquipment(
103,
@@ -97,7 +100,7 @@ export function SpacedArmorSubSpaced({
invalidate();
}
handleShellChange(duelStore.getState().antagonist.shell);
handleShellChange();
handleProtagonistEquipmentChange(
duelStore.getState().protagonist.equipmentMatrix,
);
@@ -107,6 +110,10 @@ export function SpacedArmorSubSpaced({
const unsubscribes = [
duelStore.subscribe((state) => state.antagonist.shell, handleShellChange),
tankopediaEphemeralStore.subscribe(
(state) => state.customShell,
handleShellChange,
),
duelStore.subscribe(
(state) => state.protagonist.equipmentMatrix,
handleProtagonistEquipmentChange,
@@ -88,7 +88,8 @@ export function SpacedArmorSceneComponent({
remainingPenetrationInput?: number,
) => {
const { antagonist, protagonist } = duelStore.getState();
const shell = antagonist.shell;
const { customShell } = tankopediaEphemeralStore.getState();
const shell = customShell ?? antagonist.shell;
const cameraNormal = camera.position.clone().sub(point).normalize();
const shot: Shot = {
splashRadius: shell.explosion_radius,
@@ -200,6 +200,14 @@ export function CustomShellButton() {
Cancel
</Button>
</Dialog.Close>
<Button
color="red"
onClick={() => {
setCustomShellDraft(antagonistShell);
}}
>
Reset
</Button>
<Dialog.Close>
<Button
onClick={() => {
@@ -6,6 +6,7 @@ import { NAVBAR_HEIGHT } from '../../../constants/navbar';
import { Var } from '../../../core/radix/var';
import { useFullScreen } from '../../../hooks/useFullScreen';
import { Duel } from '../../../stores/duel';
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
import type { MaybeSkeletonComponentProps } from '../../../types/maybeSkeletonComponentProps';
import type { ThicknessRange } from '../../Armor/components/StaticArmor';
import { classIcons } from '../../ClassIcon';
@@ -46,6 +47,7 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
}, [protagonist]);
const duelStore = Duel.useStore();
const mutateDuel = Duel.useMutation();
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
useEffect(() => {
function handleKeyDown(event: KeyboardEvent) {
@@ -57,6 +59,9 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
mutateDuel((draft) => {
draft.antagonist.shell = shells[index];
});
mutateTankopediaEphemeral((draft) => {
draft.customShell = undefined;
});
}
});
}