# Task 1C+1D: 防御塔系统 + 怪物波次系统

## 任务概要
在已完成的 Phaser.js 游戏框架基础上，实现完整的防御塔系统（4种塔+部署逻辑+精力管理）和怪物波次系统（4种怪物+路径寻路+战斗逻辑+KPI扣减）。

**前置条件**：Task 1A+1B 已完成，`game/` 目录已存在，`game/GameScene.ts`、`game/constants.ts`、`game/GameManager.ts` 等已实现。

## 技术架构

```
game/
├── constants.ts          ← 已存在
├── config.ts             ← 已存在  
├── GameScene.ts          ← 已存在，需要集成新系统
├── GameManager.ts        ← 已存在
├── towers/
│   ├── TowerBase.ts      ← 新建
│   ├── InternTower.ts    ← 新建（00后实习生）
│   ├── SeniorDevTower.ts ← 新建（P6资深开发）
│   ├── PPTMasterTower.ts ← 新建（PPT大师）
│   ├── HRBPTower.ts      ← 新建（HRBP辅助塔）
│   └── TowerManager.ts   ← 新建
├── enemies/
│   ├── EnemyBase.ts      ← 新建
│   ├── FreshGraduate.ts  ← 新建（校招应届生）
│   ├── OldEmployee.ts    ← 新建（35岁老员工）
│   ├── TroubleMaker.ts   ← 新建（职业碰瓷王）
│   ├── BossVP.ts         ← 新建（空降VP）
│   ├── EnemyPool.ts      ← 新建（对象池）
│   └── WaveManager.ts    ← 新建（波次管理器）
└── ui/
    ├── TowerPanel.ts     ← 新建（底部塔选择面板）
    └── HUD.ts            ← 新建（升级 GameScene 中的 HUD 逻辑）
```

## 实现规范

### 防御塔系统

**`game/towers/TowerBase.ts`**：
```typescript
export abstract class TowerBase {
  protected scene: Phaser.Scene
  public gridX: number
  public gridY: number
  protected sprite: Phaser.GameObjects.Graphics  // 用 Graphics 绘制（无美术资源）
  protected staminaBar: Phaser.GameObjects.Graphics
  
  // 数值属性
  public readonly cost: number
  public readonly attackRange: number     // 格子单位
  public readonly attackDamage: number
  public readonly attackSpeed: number     // 每秒攻击次数
  public readonly maxStamina: number = 100
  public stamina: number = 100
  
  protected attackCooldown: number = 0
  protected staminaRegen: number = 5  // 每秒恢复量（不攻击时）
  protected isActive: boolean = true  // false = 摸鱼状态
  
  constructor(scene, gridX, gridY) { ... }
  
  // 每帧更新
  update(delta: number, enemies: EnemyBase[]): void {
    this.attackCooldown -= delta
    
    if (this.stamina <= 0) {
      this.isActive = false
    }
    
    if (!this.isActive) {
      // 摸鱼：恢复精力
      this.stamina = Math.min(this.maxStamina, this.stamina + this.staminaRegen * delta / 1000)
      if (this.stamina > 0) this.isActive = true
      this.updateStaminaBar()
      return
    }
    
    // 找目标并攻击
    const target = this.findTarget(enemies)
    if (target && this.attackCooldown <= 0) {
      this.attack(target)
      this.stamina -= 5  // 攻击消耗精力
      this.attackCooldown = 1000 / this.attackSpeed
      this.updateStaminaBar()
    } else if (!target) {
      // 没有目标时恢复精力
      this.stamina = Math.min(this.maxStamina, this.stamina + this.staminaRegen * delta / 1000)
      this.updateStaminaBar()
    }
  }
  
  abstract attack(target: EnemyBase): void
  abstract drawSprite(): void  // 用 Graphics 绘制塔的外观
  
  protected findTarget(enemies: EnemyBase[]): EnemyBase | null {
    // 找射程内血量最多的怪（或最近怪）
    ...
  }
  
  protected updateStaminaBar(): void {
    // 更新精力条颜色和宽度
    ...
  }
  
  // 玩家点击塔时调用：花费10HC购买咖啡
  buyCoffee(): boolean {
    const manager = GameManager.getInstance()
    if (manager.spendHC(COFFEE_COST)) {
      this.stamina = this.maxStamina
      this.isActive = true
      this.updateStaminaBar()
      return true
    }
    return false
  }
  
  destroy(): void { ... }
}
```

**4 种塔的具体实现：**

`InternTower`（00后实习生，50HC）：
- 视觉：绿色小人形状（Graphics 画）
- 攻击：近战（射程1格），单体，15伤害，1.5/s
- 特殊技能"整顿职场"：每次攻击5%概率秒杀（血量<500的）普通怪物
- 被动：每秒1%概率直接离场（调用 destroy，退还 25HC）
- 攻击方式：直接扣血（近战，不需要弹幕）

`SeniorDevTower`（P6资深开发，120HC）：
- 视觉：深蓝色方形，顶部有 `</>` 符号
- 攻击：远程直线，30伤害，1.0/s，射程5格
- 特殊技能"代码屎山"：子弹命中后附加 DOT（10伤害/秒，持续3秒）
- 攻击方式：发射子弹（Graphics 绘制的绿色代码块），直线飞行

`PPTMasterTower`（PPT大师，100HC）：
- 视觉：橙色圆形，有 PPT 图标
- 攻击：范围AOE，5伤害，1.5/s，射程3格（圆形区域）
- 特殊技能"黑话领域"：攻击命中的怪物移速降低40%，持续2秒
- 攻击方式：爆炸效果（Graphics 绘制的扩散圆圈），范围内所有怪物受伤

`HRBPTower`（HRBP，80HC）：
- 视觉：粉色，心形图案
- 攻击：无直接伤害（辅助塔）
- 特殊技能"打鸡血"：每0.5秒给周围1格内的塔攻速+20%（叠加BUFF），每次BUFF消耗自身5精力
- 辅助方式：周期性扫描周围格子，找到塔就给BUFF

**`game/towers/TowerManager.ts`**：
- 维护所有已部署塔的数组
- 处理建塔请求：检查格子合法性（非路径+未占用），扣除HC
- 每帧调用所有塔的 update(delta, enemies)
- 处理塔的点击事件（显示购买咖啡的提示）

**`game/ui/TowerPanel.ts`**（底部塔选择面板，在 Phaser Scene 内用 DOM 或 Phaser.GameObjects 实现）：
- 优先使用 HTML DOM 覆盖层（`document.createElement`），绝对定位在 Canvas 底部
- 4个塔卡片，显示：像素风格图标 + 名称 + 成本
- 当前选中的塔有高亮边框
- HC 不足时显示灰色不可点击状态
- 点击塔卡片后，鼠标进入"建塔模式"，下一次点击地图格子时放置塔

---

### 怪物波次系统

**`game/enemies/EnemyBase.ts`**：
```typescript
export abstract class EnemyBase {
  protected scene: Phaser.Scene
  protected sprite: Phaser.GameObjects.Graphics
  protected healthBar: Phaser.GameObjects.Graphics
  protected quoteText: Phaser.GameObjects.Text  // 头顶语录
  
  public maxHp: number
  public hp: number
  public speed: number  // 像素/秒
  public readonly kpiDamage: number  // 到达终点扣除的 KPI
  public readonly hcReward: number   // 死亡奖励的 HC
  
  // 路径相关
  protected pathPoints: { x: number, y: number }[]  // 像素坐标路径
  protected currentPathIndex: number = 0
  protected distanceTraveled: number = 0
  
  // 状态
  public isDead: boolean = false
  public isActive: boolean = true
  public dotEffects: { damage: number, duration: number, timer: number }[] = []  // DOT效果
  public slowEffect: number = 0  // 减速百分比（0~1）
  public slowTimer: number = 0
  public shieldCount: number = 0  // 护盾层数（老员工专用）
  
  constructor(scene, pathPoints) { ... }
  
  update(delta: number): void {
    if (this.isDead || !this.isActive) return
    
    // 处理DOT效果
    this.processDOT(delta)
    
    // 处理减速
    if (this.slowTimer > 0) {
      this.slowTimer -= delta
      if (this.slowTimer <= 0) this.slowEffect = 0
    }
    
    // 沿路径移动
    this.moveAlongPath(delta)
    
    // 更新血条位置
    this.updateHealthBar()
    this.updateQuoteText()
  }
  
  protected moveAlongPath(delta: number): void {
    if (this.currentPathIndex >= this.pathPoints.length - 1) {
      // 到达终点
      this.reachEnd()
      return
    }
    
    const target = this.pathPoints[this.currentPathIndex + 1]
    const currentSpeed = this.speed * (1 - this.slowEffect)
    const distance = currentSpeed * delta / 1000
    
    // 向目标移动
    ...向 target 方向移动 distance 像素...
    
    // 到达当前路径点后切换到下一个
    ...
  }
  
  takeDamage(damage: number): void {
    if (this.shieldCount > 0) {
      this.shieldCount--
      return  // 护盾吸收
    }
    this.hp -= damage
    this.updateHealthBar()
    if (this.hp <= 0) {
      this.die()
    }
  }
  
  addDOT(damage: number, duration: number): void {
    this.dotEffects.push({ damage, duration, timer: duration })
  }
  
  addSlow(percent: number, duration: number): void {
    this.slowEffect = Math.max(this.slowEffect, percent)
    this.slowTimer = Math.max(this.slowTimer, duration)
  }
  
  protected die(): void {
    this.isDead = true
    const manager = GameManager.getInstance()
    manager.addHC(this.hcReward)
    this.onDeath()  // 子类可重写（碰瓷王扣HC）
    this.destroy()
  }
  
  protected reachEnd(): void {
    const manager = GameManager.getInstance()
    manager.reduceKPI(this.kpiDamage)
    this.isDead = true
    this.destroy()
  }
  
  protected onDeath(): void {}  // 子类重写
  
  abstract drawSprite(): void
  abstract getQuote(): string  // 返回该怪物的语录
  
  destroy(): void {
    this.sprite?.destroy()
    this.healthBar?.destroy()
    this.quoteText?.destroy()
  }
}
```

**4 种怪物：**

`FreshGraduate`（校招应届生）：
- HP: 30, 速度: 120px/s, KPI扣减: 2%, HC奖励: 10
- 护盾: 0
- 视觉：小绿点（Graphics 小圆）
- 语录随机：["求转正！", "我愿意加班！", "卷！卷！卷！"]

`OldEmployee`（35岁老员工）：
- HP: 150, 速度: 50px/s, KPI扣减: 8%, HC奖励: 30
- 护盾: 3层（shieldCount=3，前3次攻击无效）
- 视觉：大蓝方块
- 语录：["我为公司立过功！", "我有10年经验！", "年龄不是问题！"]

`TroubleMaker`（职业碰瓷王）：
- HP: 80, 速度: 80px/s, KPI扣减: 5%, HC奖励: 20
- 特殊：死亡时重写 `onDeath()` 扣玩家20 HC（劳动仲裁）
- 视觉：红色叹号形状
- 语录：["录音笔已开启", "这是违法的！", "我要仲裁！"]

`BossVP`（空降VP）：
- HP: 800, 速度: 40px/s, KPI扣减: 30%, HC奖励: 150
- 技能"组织架构调整"：每20秒触发一次，随机摧毁场上一个防御塔
- 视觉：大金色六边形，周围有特效
- 语录：["我来教大家怎么做事", "你们缺乏战略眼光", "这不是执行力的问题"]
- BOSS出现时：全屏红色闪光效果（Phaser Camera flash）

**`game/enemies/EnemyPool.ts`**（对象池）：
简单实现：维护一个 inactive 数组，acquire 时取出复用，release 时放回。

**`game/enemies/WaveManager.ts`**（波次管理器）：
```typescript
// 6波配置
const WAVE_CONFIG = [
  { enemies: [{ type: 'FreshGraduate', count: 10, interval: 800 }] },  // 第1波
  { enemies: [{ type: 'FreshGraduate', count: 8, interval: 800 }, { type: 'OldEmployee', count: 3, interval: 2000 }] },
  { enemies: [{ type: 'OldEmployee', count: 5, interval: 2000 }, { type: 'TroubleMaker', count: 3, interval: 1500 }] },  // 周报前
  { enemies: [{ type: 'FreshGraduate', count: 12, interval: 600 }, { type: 'TroubleMaker', count: 2, interval: 1500 }] },
  { enemies: [{ type: 'OldEmployee', count: 6, interval: 1500 }, { type: 'TroubleMaker', count: 3, interval: 1500 }] },
  { enemies: [{ type: 'BossVP', count: 1, interval: 0 }, { type: 'OldEmployee', count: 4, interval: 2000 }] },  // Boss波
]

export class WaveManager {
  private currentWave: number = 0
  private isSpawning: boolean = false
  private waveComplete: boolean = false
  
  // 周报触发：第3波结束后
  private onWave3Complete: () => void
  // 胜利：第6波全部消灭
  private onAllWavesComplete: () => void
  
  startNextWave(): void { ... }
  private spawnEnemy(type: string): EnemyBase { ... }
  update(delta: number): void { ... }  // 每帧更新所有活跃怪物
  
  getAllActiveEnemies(): EnemyBase[] { ... }
}
```

**路径像素坐标计算**：
PATH_WAYPOINTS 是格子坐标，需要转换为 Phaser Canvas 像素坐标：
```typescript
// 格子坐标转像素坐标（格子中心）
function gridToPixel(gridX, gridY): { x, y } {
  return {
    x: gridX * TILE_SIZE + TILE_SIZE / 2,
    y: gridY * TILE_SIZE + TILE_SIZE / 2 + HUD_HEIGHT  // 加上顶部HUD高度
  }
}
```

完整路径像素坐标通过对 PATH_WAYPOINTS 相邻点之间插值生成：
```typescript
// 将 PATH_WAYPOINTS 扩展为完整的转折路径（每个转折点都在路径中）
function buildFullPath(): { x, y }[] {
  const points = []
  for (let i = 0; i < PATH_WAYPOINTS.length - 1; i++) {
    const from = gridToPixel(PATH_WAYPOINTS[i].x, PATH_WAYPOINTS[i].y)
    const to = gridToPixel(PATH_WAYPOINTS[i+1].x, PATH_WAYPOINTS[i+1].y)
    points.push(from)
    points.push(to)
  }
  // 去重相邻相同点
  return points.filter((p, i, arr) => 
    i === 0 || p.x !== arr[i-1].x || p.y !== arr[i-1].y
  )
}
```

---

### HUD 与战斗整合

更新 `game/GameScene.ts`，集成两个新系统：
1. 在场景 `create()` 中初始化 TowerManager 和 WaveManager
2. 在场景 `update(time, delta)` 中：
   - 调用 `towerManager.update(delta, waveManager.getAllActiveEnemies())`
   - 调用 `waveManager.update(delta)`
   - 更新 HUD（KPI条、HC显示）
3. 处理格子点击事件：若处于"建塔模式"，调用 `towerManager.placeTower(gridX, gridY, selectedTowerType)`
4. 添加"开始下一波"按钮（按钮文字"召唤下一波"）
5. 波次开始时显示波次提示文字（"第X波来袭！"）

---

### 视觉规范（Graphics 绘制指南，无美术资源）

所有游戏对象用 Phaser.GameObjects.Graphics 绘制：

| 对象 | 形状 | 颜色 |
|------|------|------|
| 00后实习生 | 小圆(r=12) + 十字形身体 | `#22C55E`（绿） |
| P6资深开发 | 方块(24x24) + `</>` 文字 | `#3B82F6`（蓝） |
| PPT大师 | 圆(r=16) + 圆心白点 | `#F59E0B`（橙） |
| HRBP | 菱形(16x16) | `#EC4899`（粉） |
| 校招应届生 | 小圆(r=8) | `#86EFAC`（浅绿） |
| 35岁老员工 | 方块(20x20) + 护盾外框 | `#93C5FD`（浅蓝） |
| 职业碰瓷王 | 三角形 | `#FCA5A5`（浅红） |
| 空降VP | 六边形(r=30) + 金色外框 | `#FBBF24`（金色） |

塔的精力条：宽 40px，高 4px，黄色 `#F59E0B`，底部深灰 `#374151`
怪物血条：宽 30px，高 4px，绿→红渐变（按血量百分比）

---

## 验收标准

1. 可以在地图格子上部署 4 种塔，扣除正确 HC
2. 点击已部署的塔显示精力信息，可以花 10HC 购买咖啡
3. 点击"召唤下一波"按钮，怪物从起点出现并沿 S 型路径移动到终点
4. 塔会自动攻击射程内的怪物
5. 怪物被消灭后奖励 HC，到达终点后扣除 KPI
6. KPI 条和 HC 显示实时更新
7. 35岁老员工前 3 次攻击不掉血（护盾）
8. 职业碰瓷王死亡时扣除玩家 20 HC
9. 完整 6 波可以正常触发

## 相关上下文
- 设计系统：`design-system/大厂保卫战/MASTER.md`
- PRD：`.docs/prd-tower-defense-game.md`
- 计划文档：`.docs/plans/2026-03-21-tower-defense-game.md`
- Task 1A+1B 的产出（已在 `game/` 目录中）
- 开发规范：`@rules/dev-best-practices.md`（**必须先阅读**）

完成开发后，按 `@rules/atomic-commit.md` 规范，将变更按逻辑模块分组提交（禁止 `git add .`），确保所有文件均已 commit 后再结束任务。
