import * as THREE from 'three'; import { Weapon } from './Weapon'; import { Player } from './Player'; import { Fireball } from './Fireball'; import { playSound } from './SoundManager'; import { loadGLB } from './MeshLoader'; import { fireballDamage, fireballCooldown, fireballRadius, teleportCooldown } from './Skills'; export class Staff extends Weapon { constructor() { super(); this.COOLDOWN1_TIME = 5; this.COOLDOWN2_TIME = 50; // Fallback geometry const shaftGeom = new THREE.CylinderGeometry(0.04, 0.05, 1.0, 8); const crystalGeom = new THREE.OctahedronGeometry(0.08); const woodMat = new THREE.MeshToonMaterial({ color: 0x8B4513 }); const crystalMat = new THREE.MeshToonMaterial({ color: 0x4488ff }); const shaft = new THREE.Mesh(shaftGeom, woodMat); shaft.position.y = 0.3; shaft.castShadow = true; const crystal = new THREE.Mesh(crystalGeom, crystalMat); crystal.position.y = 0.9; this.mesh.add(shaft); this.mesh.add(crystal); this.mesh.position.set(0.35, 0.3, 0.35); this.mesh.scale.set(0.35, 0.35, 0.35); this.mesh.rotation.set(-0.2, 0, -0.2); } async init() { try { const gltf = await loadGLB('staff'); const model = gltf.scene; const staffTexture = new THREE.TextureLoader().load('./textures/staff1.png'); staffTexture.flipY = false; staffTexture.colorSpace = THREE.SRGBColorSpace; model.traverse((child) => { if (child instanceof THREE.Mesh) { child.castShadow = true; child.material = new THREE.MeshToonMaterial({ map: staffTexture }); } }); while (this.mesh.children.length > 0) { this.mesh.remove(this.mesh.children[0]); } this.mesh.add(model); } catch { // Keep fallback } } skill1(groundPoint: THREE.Vector3, player: Player): void { const level = player.game.skillSystem.getLevel('fireball'); if (level <= 0) return; if (this.cooldown1 > 0) return; this.COOLDOWN1_TIME = fireballCooldown(level); this.cooldown1 = this.COOLDOWN1_TIME; // Spawn at staff height, fly toward the cursor point const spawnPos = player.body.position.clone(); spawnPos.y += 0.8; const dir = new THREE.Vector3() .subVectors(groundPoint, spawnPos) .normalize() .multiplyScalar(25); dir.setY(0); const fb = new Fireball(spawnPos, dir); fb.damage = fireballDamage(level); fb.explosionRadius = fireballRadius(level); player.game.scene.add(fb.body); player.game.fireballs.push(fb); playSound('fireball', 0.5); } skill2(groundPoint: THREE.Vector3, player: Player): void { const level = player.game.skillSystem.getLevel('teleport'); if (level <= 0) return; if (this.cooldown2 > 0) return; this.COOLDOWN2_TIME = teleportCooldown(level); this.cooldown2 = this.COOLDOWN2_TIME; const newPos = groundPoint.clone(); newPos.y = 0.5; newPos.x = Math.max(-47, Math.min(47, newPos.x)); newPos.z = Math.max(-47, Math.min(47, newPos.z)); player.body.position.copy(newPos); playSound('teleport', 0.5); } }