## ADDED Requirements ### Requirement: Hero Entity 数据模型 系统 MUST 为每个英雄实例提供一个 `Hero` 实体,挂在玩家的 `HeroComponent` 下。每个 `Hero` 实体 MUST 持有以下基础字段:英雄 configId、当前等级、当前经验、当前星级、当前升星经验、招募时间、击杀数、技能等级数组(5 个槽位)、当前天赋页索引、3 套天赋树数据、8 个装备槽引用。 #### Scenario: 创建一个新英雄 - **WHEN** 服务端处理 `C2G_SummonHero` 成功后 - **THEN** 在玩家 `HeroComponent` 下创建一个新的 `Hero` Entity,等级初始为 1、经验为 0、星级为 configId 对应 HeroConfig 的 `initStar`、所有技能等级为 1、装备槽为空 - **AND** 新 `Hero` Entity 的 Id 是分布式唯一 ID - **AND** 服务端 MUST 推送 `Hero_HeroInfo` 给客户端 #### Scenario: 查询英雄数据 - **WHEN** 客户端通过 `HeroComponent.GetHero(heroId)` 查询 - **THEN** 返回对应 `Hero` Entity;若不存在返回 null ### Requirement: 英雄招募 玩家 MUST 能通过消耗碎片道具招募一个新英雄。招募 MUST 满足以下条件:碎片数量 >= HeroConfig.getItemNum;玩家未达到当前英雄招募上限(HeroConfig.getLimit);玩家未已持有该英雄(每个英雄唯一)。 #### Scenario: 招募成功 - **WHEN** 玩家碎片足够且未持有该英雄 - **AND** 客户端发送 `C2G_SummonHero { configId }` - **THEN** 服务端扣除 `HeroConfig.getItemNum` 数量的对应碎片 - **AND** 创建新 `Hero` Entity - **AND** 返回 `R2C_SummonHero { error: 0, hero: HeroInfo }` - **AND** 推送 `Item_ItemInfo` 同步碎片数量变化 #### Scenario: 碎片不足招募失败 - **WHEN** 玩家碎片数量 < HeroConfig.getItemNum - **THEN** 服务端 MUST 拒绝并返回 `R2C_SummonHero { error: ItemNotEnough }` - **AND** 不扣道具、不创建英雄 #### Scenario: 重复招募已有英雄 - **WHEN** 玩家已持有该 configId 的英雄 - **THEN** 服务端 MUST 拒绝并返回 `R2C_SummonHero { error: HeroAlreadyOwned }` ### Requirement: 英雄经验升级 玩家 MUST 能消耗经验道具提升英雄等级。系统 MUST 强制以下约束:等级上限受当前星级约束(`Hero.level <= StarConfig.starLimit`);经验溢出 MUST 顺延到下一级;满级时溢出经验 MUST 被丢弃。 #### Scenario: 单次升级 - **WHEN** 玩家发送 `C2G_HeroAddExp { heroId, itemId, count }` - **AND** 玩家拥有足够道具,且英雄未到星级限定等级 - **THEN** 服务端按 `ItemConfig.exp * count` 累加经验 - **AND** 经验超过 `HeroLevelConfig.exp` 时升级(可连升) - **AND** 推送更新后的 `Hero_HeroInfo` + `Item_ItemInfo` #### Scenario: 满级丢弃溢出 - **WHEN** 英雄已达星级等级上限 - **THEN** 服务端 MUST 拒绝升级请求或保持经验不增长,返回相应错误码 ### Requirement: 英雄升星 玩家 MUST 能消耗"升星材料"道具提升英雄星级。每次提交 MUST 累加升星经验 `Hero.starExp`,达到阈值后升星,并提供"幸运暴击"机制(按 `HeroStarExpConfig.lucky` 概率多算经验)。 #### Scenario: 升星积累经验 - **WHEN** 玩家发送 `C2G_HeroStarUp { heroId, itemId, count }` - **THEN** 服务端按 `HeroStarExpConfig.exp` 计算经验值,乘以幸运系数 - **AND** 累加到 `Hero.starExp` - **AND** 若 `starExp >= HeroStarConfig.starExpRequired` 则 `star += 1`,`starExp -= 该阈值` #### Scenario: 满星拒绝 - **WHEN** `Hero.star >= HeroConfig.star`(最大星级) - **THEN** 服务端 MUST 拒绝升星请求并返回 `StarMaxLevel` ### Requirement: 英雄技能升级 每个英雄 MUST 有 5 个技能槽(前 4 个初始解锁、第 5 个需觉醒解锁)。玩家 MUST 能消耗指定材料按等级升级单个技能;技能等级 MUST 受 `HeroSkillConfig.maxLevel` 上限约束。 #### Scenario: 升级第 1-4 技能 - **WHEN** 玩家发送 `C2G_HeroSkillUp { heroId, skillIndex }` 且 skillIndex ∈ [0,3] - **AND** 拥有 `HeroSkillLevelConfig.costItem`(按英雄稀有度选择不同 costItem 字段) - **THEN** 服务端扣道具,技能等级 +1 - **AND** 推送 `Hero_HeroInfo` 更新 #### Scenario: 升级第 5 技能要求觉醒 - **WHEN** 玩家发送 `C2G_HeroSkillUp { heroId, skillIndex: 4 }` - **AND** `Hero.isAwakening == false` - **THEN** 服务端 MUST 拒绝并返回 `NeedAwakening` ### Requirement: 英雄觉醒 玩家 MUST 在前 4 个技能全部满级时才能觉醒英雄。觉醒后 `Hero.isAwakening = true`,解锁第 5 个技能(initial level = 1)。 #### Scenario: 觉醒成功 - **WHEN** 玩家发送 `C2G_HeroAwake { heroId }` - **AND** Hero 前 4 个技能都达到 `HeroSkillConfig.maxLevel` - **AND** 玩家拥有觉醒材料道具 - **THEN** 服务端扣道具,设置 `Hero.isAwakening = true`,第 5 技能等级置 1 - **AND** 推送 `Hero_HeroInfo` #### Scenario: 觉醒前置不满足 - **WHEN** 前 4 个技能未全部满级 - **THEN** 拒绝并返回 `SkillNotMaxBeforeAwake` ### Requirement: 天赋树 每个英雄 MUST 有 3 套天赋页(pageIndex 0/1/2),玩家 MUST 能:当前页学习/升级单个天赋;切换当前页(消耗道具或钻石);重置某一页天赋(返还点数)。 #### Scenario: 学习天赋 - **WHEN** 玩家发送 `C2G_TalentUp { heroId, pageIndex, talentNodeId }` - **AND** 当前天赋页剩余点数 >= 该节点消耗 - **AND** 满足前置节点依赖(`HeroTalentDefine` 中定义) - **THEN** 服务端扣减剩余点数,节点等级 +1 - **AND** 推送 `Hero_HeroInfo` 更新 talentTrees[pageIndex] #### Scenario: 切换天赋页 - **WHEN** 玩家发送 `C2G_ChangeTalentIndex { heroId, targetIndex }` - **THEN** 服务端按规则扣消耗(道具或钻石) - **AND** 更新 `Hero.talentIndex = targetIndex` #### Scenario: 重置天赋 - **WHEN** 玩家发送 `C2G_ResetTalent { heroId, pageIndex }` - **THEN** 服务端清空该页所有节点等级 - **AND** 返还消耗的点数(或按规则按比例返还道具) ### Requirement: 英雄属性与战力计算 系统 MUST 提供英雄"总战力"计算,等于:`baseScore + levelScore + skillScore + talentScore + equipScore`。每个分项 MUST 可独立计算: - baseScore = `HeroConfig.score` - levelScore = `HeroLevelConfig(rareGroup, lv).score` - skillScore = 5 个技能各自 `HeroSkillEffectConfig(skillId, level).score` 之和 - talentScore = 已学习天赋节点 score 之和 - equipScore = 已穿戴装备的属性折算 score(由 `equipment-system` 提供接口) #### Scenario: 计算单个英雄战力 - **WHEN** 客户端调用 `HeroExtensions.GetPower(hero)` - **THEN** 返回 5 个分项之和 #### Scenario: 计算所有英雄总战力 - **WHEN** 客户端调用 `HeroComponentExtensions.GetTotalPower()` - **THEN** 返回所有 `Hero` Entity 的战力之和 ### Requirement: 英雄排序与筛选 客户端 MUST 提供英雄排序能力,支持以下排序类型:Rare(稀有度)/ Star(星级)/ Level(等级)/ Power(战力)/ Recomend(推荐分)。排序 MUST 输出三个分组:已拥有 / 可召唤(碎片够但未招募)/ 未集齐。 #### Scenario: 按战力排序已拥有列表 - **WHEN** 客户端调用 `HeroComponentExtensions.GetHerosBySort(SortType.Power)` - **THEN** 返回 `(ownedList, canSummonList, fragmentList)` 三个列表 - **AND** ownedList 按战力降序排列 - **AND** canSummonList 包含所有 `碎片数 >= getItemNum && !已拥有 && !达到招募上限` 的英雄 ### Requirement: 英雄红点 系统 MUST 提供以下红点接口(基于 `cn.etetet.yiuireddot` 包): - 有英雄可招募 - 有英雄有技能可升级(道具足够升满) - 有英雄装备可升级 - 有英雄天赋有剩余点数 #### Scenario: 检测可招募英雄红点 - **WHEN** 客户端访问 `HeroComponentExtensions.GetCanSummonHeroCount()` - **THEN** 返回当前可立即招募的英雄数量 #### Scenario: 检测可升级技能红点 - **WHEN** 客户端访问 `HeroComponentExtensions.GetCanSkillUpHeroCount()` - **THEN** 返回当前任一英雄存在"道具足够升一级且未满级"的技能时计数 + 1 ### Requirement: 客户端英雄数据同步 客户端 `HeroComponent` MUST 持有服务端推送的全部英雄数据快照。任何 `Hero_HeroInfo` 推送 MUST:若 heroId 已存在则更新;若不存在则创建新缓存。 #### Scenario: 全量同步(登录后) - **WHEN** 玩家登录成功,服务端发送 `Hero_HeroInfoList { heroes }` - **THEN** 客户端 `HeroComponent` 清空旧缓存 - **AND** 为每个 HeroInfo 创建客户端 `Hero` Entity 缓存 - **AND** 触发 `OnHeroListUpdated` 事件 #### Scenario: 增量同步 - **WHEN** 服务端推送 `Hero_HeroInfo { hero }` - **THEN** 客户端找到对应缓存并更新 - **AND** 触发 `OnHeroUpdated(heroId)` 事件