import { TOWER_COSTS, type TowerType } from '../towers/TowerManager' import { GameManager } from '../GameManager' const TOWER_META: { type: TowerType name: string desc: string color: string icon: string }[] = [ { type: 'intern', name: '00后实习生', desc: '近战 15伤 1.5/s', color: '#22C55E', icon: '🧑‍💻', }, { type: 'senior', name: 'P6资深开发', desc: '远程 30伤 5格', color: '#3B82F6', icon: '', }, { type: 'ppt', name: 'PPT大师', desc: 'AOE 5伤 减速', color: '#F59E0B', icon: '📊', }, { type: 'hrbp', name: 'HRBP', desc: '辅助 +攻速', color: '#EC4899', icon: '❤', }, ] export class TowerPanel { private container: HTMLElement private cards: Map = new Map() private selectedType: TowerType | null = null private onSelectCallback?: (type: TowerType | null) => void constructor(parentId: string) { this.container = document.createElement('div') this.container.id = 'tower-panel' this.applyContainerStyles() this.buildCards() const parent = document.getElementById(parentId) if (parent) { parent.style.position = 'relative' parent.appendChild(this.container) } else { document.body.appendChild(this.container) } // 监听 HC 变化更新可用状态 GameManager.getInstance().onHCChange.push(() => this.refreshCardStates()) this.refreshCardStates() } private applyContainerStyles(): void { Object.assign(this.container.style, { position: 'absolute', bottom: '0', left: '50%', transform: 'translateX(-50%)', display: 'flex', gap: '8px', padding: '8px 12px', background: 'rgba(10,22,40,0.92)', borderTop: '2px solid #1e3a5f', zIndex: '100', borderRadius: '8px 8px 0 0', pointerEvents: 'auto', }) } private buildCards(): void { for (const meta of TOWER_META) { const card = document.createElement('div') card.id = `tower-card-${meta.type}` this.applyCardStyles(card, meta.color) const icon = document.createElement('div') icon.textContent = meta.icon icon.style.fontSize = '20px' icon.style.textAlign = 'center' const name = document.createElement('div') name.textContent = meta.name name.style.fontSize = '11px' name.style.fontWeight = 'bold' name.style.color = meta.color name.style.fontFamily = 'VT323, monospace' name.style.textAlign = 'center' const cost = document.createElement('div') cost.id = `tower-cost-${meta.type}` cost.textContent = `${TOWER_COSTS[meta.type]} HC` cost.style.fontSize = '10px' cost.style.color = '#A78BFA' cost.style.textAlign = 'center' const desc = document.createElement('div') desc.textContent = meta.desc desc.style.fontSize = '10px' desc.style.color = '#94A3B8' desc.style.textAlign = 'center' card.appendChild(icon) card.appendChild(name) card.appendChild(cost) card.appendChild(desc) card.addEventListener('click', (e) => { e.stopPropagation() this.onCardClick(meta.type) }) this.container.appendChild(card) this.cards.set(meta.type, card) } } private applyCardStyles(card: HTMLElement, accentColor: string): void { Object.assign(card.style, { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '2px', padding: '6px 10px', background: '#0F1B2D', border: `2px solid #1e3a5f`, borderRadius: '6px', cursor: 'pointer', minWidth: '80px', transition: 'all 0.15s ease', userSelect: 'none', }) card.setAttribute('data-accent', accentColor) card.addEventListener('mouseenter', () => { if (!card.classList.contains('disabled') && !card.classList.contains('selected')) { card.style.background = '#1e3a5f' card.style.transform = 'translateY(-2px)' } }) card.addEventListener('mouseleave', () => { if (!card.classList.contains('selected')) { card.style.background = '#0F1B2D' card.style.transform = 'translateY(0)' } }) } private onCardClick(type: TowerType): void { const card = this.cards.get(type) if (!card || card.classList.contains('disabled')) return if (this.selectedType === type) { this.clearSelection() } else { this.setSelected(type) } } private setSelected(type: TowerType): void { this.clearSelection() this.selectedType = type const card = this.cards.get(type) if (card) { const accent = card.getAttribute('data-accent') ?? '#7C3AED' card.classList.add('selected') card.style.border = `2px solid ${accent}` card.style.background = '#1e3a5f' card.style.boxShadow = `0 0 8px ${accent}88` } this.onSelectCallback?.(type) } private clearSelection(): void { if (this.selectedType) { const card = this.cards.get(this.selectedType) if (card) { card.classList.remove('selected') card.style.border = '2px solid #1e3a5f' card.style.background = '#0F1B2D' card.style.boxShadow = '' card.style.transform = 'translateY(0)' } } this.selectedType = null this.onSelectCallback?.(null) } refreshCardStates(): void { const hc = GameManager.getInstance().hc for (const meta of TOWER_META) { const card = this.cards.get(meta.type) if (!card) continue const affordable = hc >= TOWER_COSTS[meta.type] if (!affordable) { card.classList.add('disabled') card.style.opacity = '0.4' card.style.cursor = 'not-allowed' } else { card.classList.remove('disabled') card.style.opacity = '1' card.style.cursor = 'pointer' } } } onSelect(cb: (type: TowerType | null) => void): void { this.onSelectCallback = cb } getSelectedType(): TowerType | null { return this.selectedType } deselect(): void { this.clearSelection() } destroy(): void { this.container.remove() } }