mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
feat: custom shell functionality
This commit is contained in:
1 parent
9a1c66932a
commit
dbc3d0df3a
6 files changed
+58
-21
No files matched your search
+14
-5
@@ -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,
|
||||
|
||||
+14
-7
@@ -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,
|
||||
|
||||
+15
-8
@@ -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,
|
||||
|
||||
+2
-1
@@ -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,
|
||||
|
||||
+8
@@ -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;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user