using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; // ============================================================ // 文件:BossKillParam.cs // 职责:Boss 爆奖(击杀奖励)param 的客户端专用解析模型。 // 对应《Boss爆浆数据前端对接文档》第三节各 Boss 的 param 结构。 // 所有数据由服务端 RoomKillNotice.param 直接下发,客户端只负责 // 解析和渲染,不做任何随机计算(旧 BossConfig 的 GetResponse 已全部删除)。 // // param 结构速查(按 Boss 类型): // 1. 幸运轮盘/小丑扑克/弹药箱 → { res:[{optionId,triggerRate,score}], count } 总倍数=score之和 // 2. 幸运飞碟 → { res:[内层,外层], count:2 } 总倍数=内层×外层 // 3. 星际巡航/烈焰风暴 → { isKill, beishu, fishId } 多次死亡 // 4. 破坏球 → { beishu, type } type=2 为最终死亡 // 5. 神龙转盘 → { res:{ option:[...], beizhu } } beizhu=最终倍数 // 6. 概率击杀 → param 直接是整数(倍数) // 7. 全屏/范围秒怪 → param = null // ============================================================ namespace Assets.MyGame.Scripts.Net.WebResponses { /// Boss 爆奖 param 类型(由 BossKillParamParser.DetectType 判定) public enum BossKillParamType { /// 无 param(普通鱼 / 全屏秒怪 / 范围秒怪) None = 0, /// 选项数组类:幸运轮盘 / 小丑扑克 / 幸运飞碟 / 弹药箱(res 是数组) Options = 1, /// 多次死亡:星际巡航 / 烈焰风暴(含 isKill + fishId) MultiDeath = 2, /// 破坏球(含 type,无 isKill) Bomb = 3, /// 神龙转盘(res 是对象,含 option 数组) Dragon = 4, /// 概率击杀(param 直接是整数倍数) Probability = 5, } /// /// 选项数组项:幸运轮盘/小丑扑克/幸运飞碟/弹药箱的 res 数组元素。 /// JSON: { "optionId": 2, "triggerRate": 30, "score": 3 } /// [Serializable] public class BossKillOption { /// 选项编号(转盘位置/扑克牌编号/飞碟内外层索引) public double optionId; /// 触发权重(客户端一般用不到,仅透传) public int triggerRate; /// 该项倍数/分值 public double score; public BossKillOption() { } public BossKillOption(double optionId, int triggerRate, double score = 0) { this.optionId = optionId; this.triggerRate = triggerRate; this.score = score; } } /// /// 选项数组类 param:幸运轮盘/小丑扑克/幸运飞碟/弹药箱。 /// JSON: { "res": [...], "count": N } /// [Serializable] public class BossOptionsParam { /// 选中的选项数组(长度=转动/抽取次数;飞碟固定2:res[0]=内层 res[1]=外层) public List res = new List(); /// 选项个数(= res.Length) public int count; } /// /// 多次死亡 param:星际巡航(最多3次)/ 烈焰风暴(最多2次)。 /// JSON: { "isKill": true, "beishu": 155, "fishId": "13009-3-3" } /// [Serializable] public class BossMultiDeathParam { /// true=最终击杀(鱼死亡爆炸);false=未死(鱼复活继续打) public bool isKill; /// 本次奖励倍数 public int beishu; /// 鱼ID,格式:原ID-总次数-当前次数(如 13009-3-2) public string fishId = ""; /// 从 fishId 解析总死亡次数(解析失败返回 0) public int TotalCount { get { var parts = fishId?.Split('-'); return parts != null && parts.Length >= 3 && int.TryParse(parts[1], out int v) ? v : 0; } } /// 从 fishId 解析当前第几次死亡(解析失败返回 0) public int CurrentCount { get { var parts = fishId?.Split('-'); return parts != null && parts.Length >= 3 && int.TryParse(parts[2], out int v) ? v : 0; } } } /// /// 破坏球 param。 /// JSON: { "beishu": 420, "type": 1 } /// [Serializable] public class BossBombParam { /// 本次奖励倍数 public int beishu; /// 死亡类型:1=第一次死亡(鱼继续存活),2=第二次死亡(最终死亡,鱼爆炸) public int type; /// 是否最终死亡(type==2) public bool IsFinalKill => type >= 2; } /// /// 神龙转盘 param。 /// JSON: { "res": { "option": [80, 160], "beizhu": 160 } } /// option 数组长度=停靠圈数(1~3):外圈先判定,-1 则继续中圈,再 -1 判定内圈。 /// [Serializable] public class BossDragonParam { /// 转盘结果(内层结构) public DragonRes res = new DragonRes(); [Serializable] public class DragonRes { /// 各圈数值结果(外→中→内,-1 表示未停靠该圈) public List option = new List(); /// 最终倍数(取最内层已停靠圈的数值) public int beizhu; } } // ============================================================ // 解析器 // ============================================================ /// /// BossKillNotice.param 解析器(客户端专用,只解析不随机)。 /// 用法: /// var type = BossKillParamParser.DetectType(notice.param); /// switch (type) { /// case BossKillParamType.MultiDeath: var p = BossKillParamParser.ParseMultiDeath(notice.param); ... /// } /// public static class BossKillParamParser { /// /// 判定 param 类型(对齐文档第四节 JS 判定逻辑)。 /// public static BossKillParamType DetectType(JToken param) { if (param == null || param.Type == JTokenType.Null) return BossKillParamType.None; // 整数 = 概率击杀 if (param.Type == JTokenType.Integer || param.Type == JTokenType.Float) return BossKillParamType.Probability; if (param is JObject obj) { // 多次死亡:isKill + fishId if (obj["isKill"] != null && obj["fishId"] != null) return BossKillParamType.MultiDeath; // 破坏球:type if (obj["type"] != null) return BossKillParamType.Bomb; // 神龙转盘:res 是对象且含 option if (obj["res"] is JObject resObj && resObj["option"] != null) return BossKillParamType.Dragon; // 选项数组类:res 是数组 if (obj["res"] is JArray) return BossKillParamType.Options; } return BossKillParamType.None; } /// 解析选项数组类(幸运轮盘/小丑扑克/幸运飞碟/弹药箱),失败返回空对象 public static BossOptionsParam ParseOptions(JToken param) { try { if (param is JObject obj) { var result = obj.ToObject(); if (result != null) return result; } } catch (Exception e) { UnityEngine.Debug.LogWarning($"[BossKillParam] ParseOptions 失败: {e.Message}"); } return new BossOptionsParam(); } /// 解析多次死亡(星际巡航/烈焰风暴),失败返回 null public static BossMultiDeathParam ParseMultiDeath(JToken param) { try { if (param is JObject obj) return obj.ToObject(); } catch (Exception e) { UnityEngine.Debug.LogWarning($"[BossKillParam] ParseMultiDeath 失败: {e.Message}"); } return null; } /// 解析破坏球,失败返回 null public static BossBombParam ParseBomb(JToken param) { try { if (param is JObject obj) return obj.ToObject(); } catch (Exception e) { UnityEngine.Debug.LogWarning($"[BossKillParam] ParseBomb 失败: {e.Message}"); } return null; } /// 解析神龙转盘,失败返回 null public static BossDragonParam ParseDragon(JToken param) { try { if (param is JObject obj) return obj.ToObject(); } catch (Exception e) { UnityEngine.Debug.LogWarning($"[BossKillParam] ParseDragon 失败: {e.Message}"); } return null; } /// 解析概率击杀(param 直接是整数倍数),失败返回 0 public static int ParseProbability(JToken param) { try { if (param != null && (param.Type == JTokenType.Integer || param.Type == JTokenType.Float)) return (int)param.Value(); } catch (Exception e) { UnityEngine.Debug.LogWarning($"[BossKillParam] ParseProbability 失败: {e.Message}"); } return 0; } } }