import { color } from "cc"; import { Singleton } from "../../mx/tools/Singleton"; import { BattleType, ChapterDataManager, ChapterDifficulty } from "../manager/ChapterDataManager"; import { SkillMultiplyType, TableNames } from "./ConfigTableData"; import { DEBUG, DEV, EDITOR } from "cc/env"; import MTools from "../../mx/tools/MTools"; import { ConstReplicaEnum } from "../manager/ConstReplicaManager"; import { ChapterNewPlayTypeEnum, ChapterPlayData, IAccelerateGateProperty, IBloodBagAddHpProperty, IBloodMoonProperty, IColdFireProperty, IFogAndWindProperty, IMagicEyeProperty, INightAndLightProperty, IParatroopsProperty, IWitchProperty } from "./ChapterPlayTypes"; import { ItemNumType, OtherDataType, StatisticsType, StatusType } from "./GameData"; ///////////////////////----------------新机制-------------------/////////////////////// /**是否有章节新机制 */ type FieldExtractor = (rawData: any, isPropMode: boolean) => any; interface PlayConfigDescriptor { constKey: number; needsFilter?: boolean; // 定义该玩法需要的参数映射关系 // key: 传给 parser 的参数名,value: 如何从 excel 行数据中提取该参数 paramMapping: Record; // 具体的业务解析逻辑 parser: (params: any) => ChapterPlayData; } /** * 项目动态数据 * 大部分通用的动态数据在gg.data中已经实现了 * 根据项目自定义数据获取实现方式在这个脚本里写,方便统一管理和调用 */ export class ConfigProjectData extends Singleton { ///////////////////////----------------道具相关-------------------/////////////////////// //#region 道具 /**将id相同的道具合并 */ mergeSameItem(items: ItemData[]) { let itemMap = new Map(); for (let i = 0; i < items.length; i++) { let item = items[i]; let itemData = itemMap.get(item.id); if (itemData) { itemData.num += item.num; } else { itemMap.set(item.id, item); } } items = []; itemMap.forEach((value, key) => { items.push(value); }); return items; } //#endregion ///////////////////////----------------体力相关-------------------/////////////////////// //#region 体力 /** * 扣除体力后同步自动回复计时锚点:从「达到上限」首次降到「未满」时记录 AutoAddVigourTime。 * 实际扣体力走 gg.data.subVigour,须在其 subItemNum 之后调用本方法(project.subVigour 也会调用)。 */ syncAutoAddVigourTimeAfterConsume(count: number) { let curentVigour = gg.data.getItemNum(ItemNumType.vigour); let maxVigour = gg.data.table.getConst(ConstNumType.VigourAutoAddLimit); if (curentVigour < maxVigour && curentVigour + count >= maxVigour) { gg.data.setStatistics(StatisticsType.AutoAddVigourTime, gg.data.getCurentTime()); } } /**消耗体力(仅扣道具;任务/事件请用 gg.data.subVigour) */ subVigour(count: number) { gg.data.subItemNum(ItemNumType.vigour, count); this.syncAutoAddVigourTimeAfterConsume(count); // gg.data.saveToServer(); } /**获取下一次自动增加体力的剩余时间(单位秒) */ getAddVigourTime() { let lastAddTime = gg.data.getStatistics(StatisticsType.AutoAddVigourTime); let curTime = gg.data.getCurentTime(); let maxTime = gg.data.table.getConst(ConstNumType.VigourAutoAddTime); let maxVigour = gg.data.table.getConst(ConstNumType.VigourAutoAddLimit); let curentVigour = gg.data.getItemNum(ItemNumType.vigour); // 已满:不进入倒计时,返回满间隔,避免 lastAddTime=0 时用 (curTime-0) 算出约 -1775151515 这类无意义值 if (curentVigour >= maxVigour) { return maxTime; } // 未满但锚点未初始化或异常(0、过小、非毫秒级时间戳):写入当前时刻,从满一个周期开始计 const anchorOk = lastAddTime > 1e11 && lastAddTime <= curTime + 60000; if (!anchorOk) { gg.data.setStatistics(StatisticsType.AutoAddVigourTime, curTime); return maxTime; } let time = maxTime - Math.floor((curTime - lastAddTime) / 1000); return time; } /**验证是否显示体力恢复时间 */ checkShowAddVigourTime() { let time = this.getAddVigourTime(); let maxVigour = gg.data.table.getConst(ConstNumType.VigourAutoAddLimit); let curentVigour = gg.data.getItemNum(ItemNumType.vigour); return time <= 0 && curentVigour < maxVigour; } /**自动恢复体力 */ autoAddVigour() { let time = this.getAddVigourTime(); //console.log("自动恢复体力时间", time); let maxVigour = gg.data.table.getConst(ConstNumType.VigourAutoAddLimit); let maxTime = gg.data.table.getConst(ConstNumType.VigourAutoAddTime); let curentVigour = gg.data.getItemNum(ItemNumType.vigour); if (time <= 0 && curentVigour < maxVigour) { let count = Math.floor(Math.abs(time) / maxTime) + 1; if (count + curentVigour > maxVigour) count = maxVigour - curentVigour; console.log("自动恢复体力", count); gg.data.addItemNum(ItemNumType.vigour, count); gg.data.setStatistics(StatisticsType.AutoAddVigourTime, gg.data.getCurentTime()); // gg.data.saveToServer(); } } //#endregion ///////////////////////----------------武器相关-------------------/////////////////////// //#region 武器 /**武器配置map索引 */ private _weaponDataMap: Map = new Map(); /**获取所有武器ID */ private _weaponDataList: ITableWeapon2[] = []; /**获取所有武器ID */ private _weaponIds: number[] = []; /**获取所有武器数据 */ getWeaponDataList() { if (this._weaponDataList.length <= 0) { this._weaponDataList = gg.data.table.getTableList(TableNames.Weapon2); } return this._weaponDataList; } /**根据类型获取武器数据 */ getWeaponListByType(type: number) { return this.getWeaponDataList().filter(item => item.type == type); } /**根据武器id获取武器数据 */ getWeaponDataByWeaponId(weaponId: number) { return this.getWeaponDataList().find(item => item.weaponid == weaponId); } /**获取所有武器ID */ getWeaponIds() { if (this._weaponIds.length <= 0) { this._weaponIds = this.getWeaponDataList().map(item => item.weaponid); } return this._weaponIds; } /**获取武器数据 */ getWeaponData(weaponId: number) { if (this._weaponDataMap.size <= 0) { let arr = this.getWeaponDataList(); for (let i = 0; i < arr.length; i++) { let item = arr[i]; this._weaponDataMap.set(item.weaponid, item); } } let weaponData = this._weaponDataMap.get(weaponId); return weaponData; } /**获取已经拥有的武器id数组 */ getHaveWeaponIds() { let weaponIds = gg.data.getArrayData(OtherDataType.HaveWeapon); return weaponIds.map(item => Number(item)); } /**设置已拥有的武器id数组 */ setHaveWeaponIds(weaponIds: any[]) { gg.data.setArrayData(OtherDataType.HaveWeapon, weaponIds); } /**获取已经拥有的武器数据列表 */ getHaveWeaponDataList() { let haveWeaponIds = this.getHaveWeaponIds(); let haveWeaponDataList = haveWeaponIds.map(item => this.getWeaponData(Number(item))); return haveWeaponDataList; } /**获取未拥有的武器数据列表 */ getNoHaveWeaponDataList() { let haveWeaponIds = this.getHaveWeaponIds(); let weaponIds = this.getWeaponIds(); let noHaveWeaponIds = weaponIds.filter(item => haveWeaponIds.indexOf(item) < 0); //排除101和102的武器,因为这两个武器没有升级和技能 //noHaveWeaponIds = noHaveWeaponIds.filter(item => item != 101 && item != 102); //排除isshow==1的武器 noHaveWeaponIds = noHaveWeaponIds.filter(item => this.getWeaponData(Number(item)).isshow != 1); let noHaveWeaponDataList = noHaveWeaponIds.map(item => this.getWeaponData(Number(item))); return noHaveWeaponDataList; } /**解锁武器 */ unlockWeapon(weaponId: number) { let haveWeaponIds = this.getHaveWeaponIds(); if (haveWeaponIds.indexOf(weaponId) < 0) { haveWeaponIds.push(weaponId); } this.setHaveWeaponIds(haveWeaponIds); } /**解除拥有武器 */ removeHaveWeapon(weaponId: number) { let haveWeaponIds = this.getHaveWeaponIds(); let index = haveWeaponIds.indexOf(weaponId); if (index >= 0) { haveWeaponIds.splice(index, 1); } this.setHaveWeaponIds(haveWeaponIds); } /**判断武器是否解锁 */ isWeaponUnlocked(weaponId: number) { let haveWeaponIds = this.getHaveWeaponIds(); return haveWeaponIds.indexOf(weaponId) >= 0; } /**获取武器等级 */ getWeaponLevel(weaponId: number) { let level = 1; let weaponLevel = gg.data.getkeyKeyValue(OtherDataType.WeaponLevel, weaponId); level = weaponLevel && weaponLevel != "" ? parseInt(weaponLevel) : 1; return level; } /**设置武器等级 */ setWeaponLevel(weaponId: number, level: number) { gg.data.setkeyKeyValue(OtherDataType.WeaponLevel, weaponId, level); } /**武器升级 */ upgradeWeapon(weaponId: number) { let level = this.getWeaponLevel(weaponId); level++; this.setWeaponLevel(weaponId, level); } /**获取上阵武器状态 */ getEquipWeaponStatus() { let arr = gg.data.getArrayData(OtherDataType.EquipWeapon); return arr.map((item) => Number(item)); } /**设置上阵武器状态,目前8个状态位,例如:[1,2,3,4,5,6,7,8] */ setEquipWeaponStatus(weaponIds: number[]) { gg.data.setArrayData(OtherDataType.EquipWeapon, weaponIds); } /**上阵武器 */ equipWeapon(weaponId: number, index: number) { let equipWeapons = this.getEquipWeaponStatus(); if (equipWeapons.length <= index) { equipWeapons.push(weaponId); } else { equipWeapons[index] = weaponId; } this.setEquipWeaponStatus(equipWeapons); } /**下阵武器 */ unequipWeapon(index: number) { let equipWeapons = this.getEquipWeaponStatus(); if (equipWeapons.length > index) { equipWeapons[index] = 0; } this.setEquipWeaponStatus(equipWeapons); } /**获取上阵武器id */ getEquipWeaponId(index: number) { let equipWeapons = this.getEquipWeaponStatus(); if (equipWeapons.length > index) { return equipWeapons[index]; } return 0; } /**判断武器是否已经上阵 * 返回上阵索引位置 */ isWeaponEquipped(weaponId: number) { let equipWeapons = this.getEquipWeaponStatus(); return equipWeapons.indexOf(weaponId); } /**获取所有已经上阵的武器 */ getEquipWeaponIds() { let equipWeapons = this.getEquipWeaponStatus(); return equipWeapons.filter((item) => item > 0); } /**获取所有已经上阵的武器数据列表 */ getEquippedWeaponDataList() { let equipWeapons = this.getEquipWeaponIds(); let equipWeaponDataList = equipWeapons.map(item => this.getWeaponData(item)); return equipWeaponDataList; } /**获取空位 */ getEmptyPos() { let equipWeapons = this.getEquipWeaponStatus(); let index = equipWeapons.indexOf(0); return index; } /** * 获取level等级的level_para配置的level_para参数 * @param id 武器id * @param level 武器等级 * @returns */ public getLevelParaByWeaponLevel(level: number, weaponId: number) { let list = gg.data.table.getTableList(TableNames.Weapon3); let config = list.find(x => x.id == level) if (config) { return config.level_para } console.log('获取level_para参数失败==level=', weaponId, level) return 0 } /**根据武器id数组获取所有已经解锁的技能 */ public getAllUnlockedSkillByWeaponIds(weaponIds: ITableWeapon2[]) { let skillIdArr: number[] = [] for (let weapon of weaponIds) { let arr = weapon.base_skill.split(',').map(item => parseInt(item)); skillIdArr.push(...arr); skillIdArr.push(...this.getAllCanUseSkillByWeaponLevel(weapon.weaponid, this.getWeaponLevel(weapon.weaponid))) } let resull: ITableSkill[] = []; for (let skillId of skillIdArr) { resull.push(gg.data.table.getTableData(TableNames.Skill, skillId)) } return resull } /** * 根据武器等级获取可用的所有技能 * @param id 武器id * @param level 武器等级 */ public getAllCanUseSkillByWeaponLevel(id: number, level: number) { let config = this.getWeaponData(id); // //如果当前模式是武器模式获取所有武器技能书 // let weaponArray = gg.data.getCurWeaponModelChapterId(gg.game.CurentSelectChapterId) // if (weaponArray && weaponArray.length > 0) { // //设置技能等级7级就会获取所有的技能 // level = 7 // } // //宝箱模式 // if (gg.game.CurentSelectBattleType == BattleType.BoxMode) { // level = 11 // } let skillIdArr = [] //base_skill技能都可以使用, skill技能通过比较等级等级之前的都需要加入, 1,52;2,48;2,49;2,50;3,53;4,54;5,55;6,56 if (config.base_skill.length > 0) { let t = config.base_skill.split(',') for (let vaule of t) { skillIdArr.push(parseInt(vaule)) } } if (config.skill.length > 0) { let skillArray = config.skill.split(';') for (let skill of skillArray) { let t = skill.split(',') if (level >= parseInt(t[0])) { skillIdArr.push(parseInt(t[1])) } } } //去重 skillIdArr = skillIdArr.filter((item, index) => skillIdArr.indexOf(item) === index); //console.log('去重之后的所有可用技能==', skillIdArr) return skillIdArr } //通过武器等级获取当前升级需要的武器碎片 public getWeaponFlagNumByLevel(weaponId: number) { let level = this.getWeaponLevel(weaponId) let conf = this.getWeaponData(weaponId) let item_num = conf.item_num //武器的配置item_num分组获取武器升级需要的碎片 if (item_num) { let list = gg.data.table.getTableList(TableNames.Weapon4); let data = list.find(x => x.id == level) if (item_num == 1) { return data.item_num1 } else if (item_num == 2) { return data.item_num2 } else if (item_num == 3) { return data.item_num3 } else if (item_num == 4) { return data.item_num4 } else { console.log('item_num 未配置,返回默认配置', weaponId, item_num) return data.item_num1 } } else { return -1 } } /**获取紫色及以上武器最大等级 */ public getMaxLevelPurpleWeapon() { let list = this.getWeaponDataList().filter(x => x.quality >= 3); let maxlevel = 1; let haveArr = this.getHaveWeaponDataList(); for (let i = 0; i < list.length; i++) { if (haveArr.find(x => x.weaponid == list[i].weaponid) == null) { continue; } let level = this.getWeaponLevel(list[i].weaponid); if (level > maxlevel) { maxlevel = level; } } if (DEV || DEBUG || EDITOR) console.log('紫色及以上武器最大等级==', maxlevel); return maxlevel } /*获取已装备的武器id和等级*/ public getEquippedWeaponIdAndLevel() { let arr = gg.data.project.getHaveWeaponDataList(); let result: number[][] = []; for (let i = 0; i < arr.length; i++) { let item = arr[i]; let weaponId = parseInt(item[0]); let weaponLevel = parseInt(item[1]); result.push([weaponId, weaponLevel]); } return result; } /**获取武器最大等级 */ public getMaxLevelWeapon() { let list = this.getWeaponDataList() let maxlevel = 1; let haveArr = this.getHaveWeaponDataList(); for (let i = 0; i < list.length; i++) { if (haveArr.find(x => x.weaponid == list[i].weaponid) == null) { continue; } let level = this.getWeaponLevel(list[i].weaponid); if (level > maxlevel) { maxlevel = level; } } if (DEV || DEBUG || EDITOR) console.log('当前武器最大等级==', maxlevel); return maxlevel } //指定品质武器 public getMaxLevelWeaponByQuality(quality: number) { let list = this.getWeaponDataList().filter(x => x.quality == quality); let maxlevel = 1; let haveArr = this.getHaveWeaponDataList(); for (let i = 0; i < list.length; i++) { if (haveArr.find(x => x.weaponid == list[i].weaponid) == null) { continue; } let level = this.getWeaponLevel(list[i].weaponid); if (level > maxlevel) { maxlevel = level; } } if (DEV || DEBUG || EDITOR) console.log('指定品质武器最大等级==', maxlevel); return maxlevel } //#endregion ///////////////////////----------------闯关相关-------------------/////////////////////// //#region 闯关 /**根据章节ID、难度和宝箱索引设置宝箱奖励领取状态:0-未达成,1-已达成未领取,2-已达成已领取 */ setChapterStatus(chapterId: number, difficulty: ChapterDifficulty, index: number, status: number) { gg.data.setkeyKeyValue(OtherDataType.ChapterBoxStatus, chapterId + '&' + difficulty + '&' + index, status); gg.targetTaskManager.checkTask()//任务领取状态依赖其他模块不需要统计数据 } /**根据章节ID、难度和宝箱索引获取宝箱奖励领取状态:0-未达成,1-已达成未领取,2-已达成已领取 */ getChapterStatus(chapterId: number, difficulty: ChapterDifficulty, index: number) { let status = gg.data.getkeyKeyValue(OtherDataType.ChapterBoxStatus, chapterId + '&' + difficulty + '&' + index); if (status == '') { status = "0"; } return Number(status); } /**根据章节ID、难度和章节进度保存状态(仅更新 25%/50% 宝箱;100% 宝箱与通关共用 index=2,仅胜利时写入) */ setChapterStatusByProgress(chapterId: number, difficulty: ChapterDifficulty, progress: number) { let targetProgress = this.getChapterBoxProgress(chapterId, difficulty); // index=2(100%)与 isChapterComplete 共用,禁止在失败/暂停进度里提前写入 for (let i = 0; i < 2; i++) { let curentStatus = this.getChapterStatus(chapterId, difficulty, i); if (curentStatus == 0) { if (progress >= targetProgress[i]) { this.setChapterStatus(chapterId, difficulty, i, 1); } } } } /**根据章节获取配置的宝箱进度百分比 */ getChapterBoxProgress(chapterId: number, difficulty: ChapterDifficulty) { return [0.25, 0.5, 1]; } /**根据章节id,难度判断是否可以挑战 */ isChapterCanChallenge(chapterId: number, difficulty: ChapterDifficulty) { let curentId = this.getCurentLevelChapterId(difficulty); if (curentId == 0) return false; if (difficulty == ChapterDifficulty.Hard) { let id1 = this.getCurentLevelChapterId(ChapterDifficulty.Normal); let id2 = this.getCurentLevelChapterId(ChapterDifficulty.Hard); return chapterId <= id1 - 1 && chapterId <= id2; } if (difficulty == ChapterDifficulty.Hell) { let id1 = this.getCurentLevelChapterId(ChapterDifficulty.Hard); let id2 = this.getCurentLevelChapterId(ChapterDifficulty.Hell); return chapterId <= id1 - 1 && chapterId <= id2; } return curentId >= chapterId; } /**根据章节id和难度判断是否已通关 */ isChapterComplete(chapterId: number, difficulty: ChapterDifficulty) { if (difficulty == ChapterDifficulty.Normal) { return chapterId < gg.data.doc.chapter; } let status = this.getChapterStatus(chapterId, difficulty, 2); return status > 0; } /** * 校正普通难度章节进度(仅修复历史脏数据:胜利写入过 index=2 但 chapter 未+1)。 * 不再用 isChapterComplete 判断,避免把「失败满进度」误判为已通关。 */ syncNormalChapterProgress(): boolean { const maxId = this.getMaxChapterId(); let changed = false; while (gg.data.doc.chapter < maxId && this.getChapterStatus(gg.data.doc.chapter, ChapterDifficulty.Normal, 2) > 0) { gg.data.doc.chapter += 1; this.setCurSelectSaveChapterId(gg.data.doc.chapter); changed = true; } if (changed) { gg.game.CurentSelectChapterId = gg.data.doc.chapter; console.log('[ConfigProjectData] syncNormalChapterProgress -> chapter', gg.data.doc.chapter); } return changed; } /**根据章节id和难度判断是否已领取 */ isChapterFinishGet(chapterId: number, difficulty: ChapterDifficulty) { let status = this.getChapterStatus(chapterId, difficulty, 2); return status > 1; } /**根据章节id和难度判断是否可领取宝箱奖励 */ isCanGetChapterBox(chapterId: number, difficulty: ChapterDifficulty, index: number) { let status = this.getChapterStatus(chapterId, difficulty, index); return status == 1; } /**是否有关卡宝箱可领取 */ isCanGetLevelBox() { let chapters = gg.data.table.getTableList(TableNames.Chapter).filter(x => x.type == BattleType.Level); for (let i = 0; i < chapters.length; i++) { let chapter = chapters[i]; for (let j = 0; j < 3; j++) { let status = this.getChapterStatus(chapter.id, ChapterDifficulty.Normal, j); if (status == 1) return true; status = this.getChapterStatus(chapter.id, ChapterDifficulty.Hard, j); if (status == 1) return true; status = this.getChapterStatus(chapter.id, ChapterDifficulty.Hell, j); if (status == 1) return true; } if (chapter.id == gg.data.doc.chapter) break; } return false; } /**根据当前章节判断前面或者后面是否有可领取的宝箱奖励 */ isCanGetBoxBeforeOrAfter(chapterId: number, difficulty: ChapterDifficulty, isBefore: boolean) { let chapters = gg.data.table.getTableList(TableNames.Chapter).filter(x => x.type == BattleType.Level); if (isBefore) chapters = chapters.filter(x => x.id < chapterId); else chapters = chapters.filter(x => x.id > chapterId && x.id < gg.data.doc.chapter); for (let i = 0; i < chapters.length; i++) { let chapter = chapters[i]; let status = this.getChapterStatus(chapter.id, difficulty, 0); if (status == 1) return true; status = this.getChapterStatus(chapter.id, difficulty, 1); if (status == 1) return true; status = this.getChapterStatus(chapter.id, difficulty, 2); if (status == 1) return true; } return false; } /**获取当前选择的章节ID */ getCurSelectSaveChapterId() { return gg.data.getStatus(StatusType.CurSelectSaveChapterId); } /**设置当前选择的章节ID */ setCurSelectSaveChapterId(chapterId: number) { gg.data.setStatus(StatusType.CurSelectSaveChapterId, chapterId); } /**获取当前选中的章节难度 */ getCurSelectSaveChapterDifficulty() { return gg.data.getStatus(StatusType.CurSelectSaveChapterDifficulty); } /**设置当前选中的章节难度 */ setCurSelectSaveChapterDifficulty(difficulty: ChapterDifficulty) { gg.data.setStatus(StatusType.CurSelectSaveChapterDifficulty, difficulty); } /**根据难度获取当前闯关的章节id */ getCurentLevelChapterId(difficulty: ChapterDifficulty) { if (difficulty == ChapterDifficulty.Normal) return gg.data.doc.chapter; if (difficulty !== ChapterDifficulty.Hard && difficulty !== ChapterDifficulty.Hell) return 0; let chapterConfigList = this.getChapterConfigByType(BattleType.Level); let chapterId = 0; for (let i = chapterConfigList.length - 1; i >= 0; i--) { let chapterConfig = chapterConfigList[i]; if (this.isChapterComplete(chapterConfig.id, difficulty)) { if (difficulty == ChapterDifficulty.Hard) { if (this.isChapterComplete(chapterConfig.id, ChapterDifficulty.Normal)) { break; } } else if (difficulty == ChapterDifficulty.Hell) { if (this.isChapterComplete(chapterConfig.id, ChapterDifficulty.Hard)) { break; } } else break; } // if (i == 0) // chapterId = 1; // else chapterId = chapterConfig.id; } return chapterId; } /**根据章节id和难度获取连续失败次数 */ getFailCount(chapterId: number, type: BattleType, difficulty: ChapterDifficulty) { let failCount = 0; let str = ""; if (type == BattleType.Level) { str = gg.data.getkeyKeyValue(OtherDataType.FailContinuousCount, `l${chapterId}&${type}&${difficulty}`); } else { str = gg.data.getkeyKeyValue(OtherDataType.FailContinuousCount, `r${type}&${difficulty}`); } if (str == null || str == "") failCount = 0; else failCount = parseInt(str); return failCount; } /**设置连续失败次数 */ setFailCount(chapterId: number, type: BattleType, difficulty: ChapterDifficulty, failCount: number) { let str = ""; if (type == BattleType.Level) { str = `l${chapterId}&${type}&${difficulty}`; } else { str = `r${type}&${difficulty}`; } gg.data.setkeyKeyValue(OtherDataType.FailContinuousCount, str, failCount.toString()); } /**增加失败次数 */ addFailCount(chapterId: number, type: BattleType, difficulty: ChapterDifficulty) { let failCount = this.getFailCount(chapterId, type, difficulty); failCount++; console.log('增加失败次数', failCount); this.setFailCount(chapterId, type, difficulty, failCount); } /**根据章节id,难度获取通关奖励字符串 */ getChapterRewardStr(chapterId: number, difficulty: ChapterDifficulty) { let chapterConfig = this.getChapterConfig(chapterId); if (chapterConfig) { return chapterConfig.reward } return ''; } /**根据章节id,难度,宝箱索引获取宝箱奖励字符串 */ getChapterBoxRewardStr(chapterId: number, difficulty: ChapterDifficulty, index: number) { let chapterConfig = this.getChapterConfig(chapterId); if (chapterConfig) { let difficultIndex = chapterConfig.difficult; if (difficultIndex < 0) difficultIndex = 0; let rewardStr = ''; if (index == 1) rewardStr = chapterConfig.box_reward1; else if (index == 2) rewardStr = chapterConfig.box_reward2; else if (index == 3) rewardStr = chapterConfig.box_reward3; if (rewardStr == null || rewardStr == "") return ''; // let rewardArr = rewardStr.split('#'); // return rewardArr[difficultIndex]; return rewardStr; } return ''; } //#endregion ///////////////////////----------------战斗相关-------------------/////////////////////// //#region 战斗 /**消耗体力 */ vigourCost: number = 3; /**获取章节配置 */ getChapterConfig(chapterId: number) { try { let chapterConfig = gg.data.table.getTableData(TableNames.Chapter, chapterId); return chapterConfig; } catch (error) { return null; } } /**获取最大章节id */ getMaxChapterId() { try { let chapterConfigList = gg.data.table.getTableList(TableNames.Chapter).filter(x => x.type == BattleType.Level); //排除id大于1000的章节 chapterConfigList = chapterConfigList.filter(x => x.id <= 1000); let maxId = chapterConfigList[chapterConfigList.length - 1].id; return maxId; } catch (error) { return 0; } } /**根据类型获取章节配置列表 */ getChapterConfigByType(type: BattleType) { try { let chapterConfigList = gg.data.table.getTableList(TableNames.Chapter).filter(x => x.type == type); return chapterConfigList; } catch (error) { return null; } } /**获取推荐战力 */ getRecommendPower(chapterId: number, difficulty: ChapterDifficulty) { try { let chapterConfig = this.getChapterConfig(chapterId) if (chapterConfig) { //let index = 0; return chapterConfig.power } return 0; } catch (error) { console.error('获取章节推荐战力失败', error); return 0; } } /**验证体力是否足够 */ checkVigourEnough(battleType: BattleType) { let curentVigour = gg.data.getVigour(); let needVigour = this.vigourCost; if (curentVigour < needVigour) { return false; } return true; } /**判断战力是否足够 */ checkPowerEnough(chapterId: number, type: BattleType, difficulty: ChapterDifficulty) { //判断战力是否足够 if (type == BattleType.Level) { let curentPower = gg.data.getCurPower(); let needPower = this.getRecommendPower(chapterId, difficulty); if (curentPower * 1.5 <= needPower && gg.data.doc.chapter > 9) { return false; } return true; } return true; } /**根据章节id获取新机制数组 */ getNewPlayArr(chapterId: number) { let chapterConfig = this.getChapterConfig(chapterId); if (chapterConfig) { let newPlayArr = chapterConfig.new_play.split(',').map((item) => Number(item)); return newPlayArr; } return []; } /**根据章节id获取新障碍物数组 */ getNewObstacleArr(chapterId: number) { let chapterConfig = this.getChapterConfig(chapterId); if (chapterConfig) { let newObstacleArr = chapterConfig.obstacleId.split(',').map((item) => Number(item)); return newObstacleArr; } return []; } /**获取章节所有机制配置 */ getChapterAllMechanismConfig(chapterId: number) { return [] // let newPlayArr = this.getNewPlayArr(chapterId); // let mechanismConfigList = gg.data.table.getTableList(TableNames.Playmode).filter(x => newPlayArr.includes(x.id)); // return mechanismConfigList; } /**获取章节所有障碍物配置 */ getChapterAllObstacleConfig(chapterId: number) { return [] // let obstacleArr = this.getNewObstacleArr(chapterId); // let obstacleConfigList = gg.data.table.getTableList(TableNames.Obstacle).filter(x => obstacleArr.includes(x.id)); // return obstacleConfigList; } private _monsterList: ITableMonster[] = []; private _monsterMap: Map = new Map(); /**获取所有怪物配置 */ getAllMonsterList1() { if (this._monsterList.length == 0) { this._monsterList = gg.data.table.getTableList(TableNames.Monster); } return this._monsterList; } /**根据怪物id获取怪物数据 */ getMonsterDataByID(monsterId: number) { if (this._monsterMap.size == 0) { let monsterList = this.getAllMonsterList1(); for (let i = 0; i < monsterList.length; i++) { const element = monsterList[i]; this._monsterMap.set(element.id, element); } } return this._monsterMap.get(monsterId); } /**获取章节初始怪物组 */ getChapterInitMonsterGroup(chapterId: number, type: BattleType, difficulty: ChapterDifficulty) { try { let chapterConfig = this.getChapterConfig(chapterId) if (chapterConfig) { return chapterConfig.monster_group } return 0; } catch (error) { console.error('获取章节初始怪物组失败', error); return 0; } } /**获取当前章节用户用到的怪物id数组 */ getChapterUserMonsterIdArr(chapterId: number) { let idArr = [] // 章节配置 let config: ITableChapter = this.getChapterConfig(chapterId) idArr = idArr.concat(this.spawnMonsterCall1(config.monster1)); idArr = idArr.concat(this.spawnMonsterCall1(config.monster2_1)); idArr = idArr.concat(this.spawnMonsterCall1(config.monster2_2)); idArr = idArr.concat(this.spawnMonsterCall1(config.monster2_3)); idArr = idArr.concat(this.spawnMonsterCall1(config.monster2_4)); idArr = idArr.concat(this.spawnMonsterCall1(config.monster2_5)); idArr = idArr.concat(this.spawnMonsterCall2(config.monster3_1)); idArr = idArr.concat(this.spawnMonsterCall2(config.monster3_2)); if (gg.game.CurentSelectBattleType == BattleType.Level && gg.game.CurentSelectBattleDifficulty == ChapterDifficulty.Hell) { idArr = idArr.concat(this.spawnMonsterCall2(config.monster3_3)); } // let haveMonsterArr = [] // if (gg.game.CurentSelectBattleType == BattleType.Level && gg.game.CurentSelectBattleDifficulty == ChapterDifficulty.Normal) { // let array = config.monster3_4.split(',') // haveMonsterArr = gg.zombie.getZombieNormalMonsterIdList() // let id = Number(array[2]) // if (haveMonsterArr.indexOf(id) == -1) { // idArr = idArr.concat(this.spawnMonsterCall2(config.monster3_4)); // } // } else if (gg.game.CurentSelectBattleType == BattleType.Level && gg.game.CurentSelectBattleDifficulty == ChapterDifficulty.Hard) { // let array = config.monster3_5.split(',') // haveMonsterArr = gg.zombie.getZombieHardMonsterIdList() // let id = Number(array[2]) // if (haveMonsterArr.indexOf(id) == -1) { // idArr = idArr.concat(this.spawnMonsterCall2(config.monster3_5)); // } // } else if (gg.game.CurentSelectBattleType == BattleType.Level && gg.game.CurentSelectBattleDifficulty == ChapterDifficulty.Hell) { // let array = config.monster3_6.split(',') // haveMonsterArr = gg.zombie.getZombieHellMonsterIdList() // let id = Number(array[2]) // if (haveMonsterArr.indexOf(id) == -1) { // idArr = idArr.concat(this.spawnMonsterCall2(config.monster3_6)); // } // } idArr = idArr.distinct(); let monsterModelArr = [] for (let i = 0; i < idArr.length; i++) { let id = idArr[i]; let monsterData = this.getMonsterDataByID(id); if (monsterData && monsterModelArr.indexOf(monsterData.model) == -1) { monsterModelArr.push(monsterData.model) } } return monsterModelArr } /**解析出怪扣配置信息 */ spawnMonsterCall1(monsterStr: string) { let idArr = [] if (monsterStr == '') { return idArr } let t = monsterStr.split('|') for (let i = 0; i < t.length; i++) { if (t[i] == '') { continue } let s = t[i].split(';') for (let j = 0; j < s.length; j++) { let id = s[j].split(',')[0] if (idArr.indexOf(id) == -1) { idArr.push(Number(id)) } } } return idArr } spawnMonsterCall2(monsterStr) { let idArr = [] if (monsterStr == '') { return idArr } let t = monsterStr.split('|') for (let i = 0; i < t.length; i++) { let id = t[i].split(',')[2] if (gg.game.CurentSelectBattleType == BattleType.BoxMode || gg.game.CurentSelectBattleType == BattleType.GachaMode) { if (id == 30011 || id == 40011) { continue; } } if (idArr.indexOf(id) == -1) { idArr.push(Number(id)) } } return idArr; } /**根据难度值获取难度称呼 */ getDifficultyName(difficulty: number) { switch (difficulty) { case 1: return '简单'; case 2: return '普通'; case 3: return '困难'; case 4: return '地狱'; case 5: return '末世'; default: return '普通'; } } /**根据品质权重配置组id和危险系数获取章节权重配置 */ getChapterWeightConfig(qualityGroupId: number, dangerCoefficient: number) { let group = gg.data.table.getTableList(TableNames.Chapter_weight).filter(item => item.danger_group == qualityGroupId); if (group.length > 0) { for (let i = 0; i < group.length; i++) { let d = group[i]; if (d.danger_para >= dangerCoefficient) { return d; } } } return null; } /**获取玩家当前暴击率 */ getPlayerCritRate(weaponId: number) { return 0 } /**获取玩家当前暴击伤害 */ getPlayerCritDamage(weaponId: number) { return 0 } /**根据地图id和格子索引获取格子是否被修复 */ getGridIsRepair(mapId: number, gridIndex: number) { let isRepair = gg.data.getkeyKeyValue(OtherDataType.GridIsRepair, mapId + '&' + gridIndex); if (isRepair == '') isRepair = "0"; return Number(isRepair); } /**根据地图id和格子索引设置格子是否被修复 */ setGridIsRepair(mapId: number, gridIndex: number, isRepair: number) { gg.data.setkeyKeyValue(OtherDataType.GridIsRepair, mapId + '&' + gridIndex, isRepair); } //#endregion ///////////////////////----------------副本相关-------------------/////////////////////// //#region 副本 /**根据副本id获取副本配置 */ getReplicaConfig(id: number): ITableReplica { let config = gg.data.table.getTableData(TableNames.Replica, id); return config; } /**根据副本id和难度获取通关次数 */ getReplicaPassCount(id: number, difficulty: ChapterDifficulty) { let passCount = gg.data.getkeyKeyValue(OtherDataType.ReplicaPassCount, id + '&' + difficulty); if (passCount == '') passCount = "0"; return Number(passCount); } /**根据副本id和难度设置通关次数 */ setReplicaPassCount(id: number, difficulty: ChapterDifficulty, passCount: number) { gg.data.setkeyKeyValue(OtherDataType.ReplicaPassCount, id + '&' + difficulty, passCount); } /**根据副本类型和难度增加通关次数 */ addReplicaPassCount(id: number, difficulty: ChapterDifficulty, passCount: number = 1) { let curentCount = this.getReplicaPassCount(id, difficulty); this.setReplicaPassCount(id, difficulty, curentCount + passCount); this.addReplicaPassCountToday(id, difficulty, passCount); } /**根据副本id和难度判断是否已通关 */ isReplicaComplete(id: number, difficulty: ChapterDifficulty) { let passCount = this.getReplicaPassCount(id, difficulty); return passCount > 0; } /**根据副本id和难度获取今日通关次数 */ getReplicaPassCountToday(id: number, difficulty: ChapterDifficulty) { let passCount = gg.data.getkeyKeyValue(OtherDataType.ReplicaPassCountToday, id + '&' + difficulty); if (passCount == '') passCount = "0"; return Number(passCount); } /**根据副本id和难度设置今日通关次数 */ setReplicaPassCountToday(id: number, difficulty: ChapterDifficulty, passCount: number) { gg.data.setkeyKeyValue(OtherDataType.ReplicaPassCountToday, id + '&' + difficulty, passCount); } /**根据副本id和难度增加今日通关次数 */ addReplicaPassCountToday(id: number, difficulty: ChapterDifficulty, passCount: number = 1) { let curentCount = this.getReplicaPassCountToday(id, difficulty); this.setReplicaPassCountToday(id, difficulty, curentCount + passCount); } /**根据副本类型和难度判断今日是否已通关 */ isReplicaCompleteToday(id: number, difficulty: ChapterDifficulty) { let passCount = this.getReplicaPassCountToday(id, difficulty); return passCount > 0; } //#endregion //#region 新玩法 chapterNewPlayInfo = new Map() newPlayIdArr: string[] = [] private generateTimeSequence( startTime: number, countMin: number, countMax: number, intervalMin: number, intervalMax: number ): number[] { const randomLimit = MTools.getRandomValue(countMin, countMax); // 封装随机整数 const timeArr: number[] = []; let curTime = startTime; for (let j = 0; j < randomLimit; j++) { curTime += MTools.getRandomValue(intervalMin, intervalMax); timeArr.push(curTime); } return timeArr; } private generateNumSequence( countMin: number, countMax: number, intervalMin: number, intervalMax: number ): number[] { const randomLimit = MTools.getRandomValue(countMin, countMax); // 封装随机整数 const timeArr: number[] = []; for (let j = 0; j < randomLimit; j++) { timeArr.push(MTools.getRandomValue(intervalMin, intervalMax)); } return timeArr; } // --- 核心优化:策略映射表 --- // 定义每个玩法的配置解析器 private readonly playConfigHandlers: Partial> = { [ChapterNewPlayTypeEnum.ThunderRemoveObstacle]: { constKey: ChapterNewPlayTypeEnum.ThunderRemoveObstacle, needsFilter: true, paramMapping: { startTime: (row, isProp) => parseInt(row.starttime.split('|')[isProp ? 1 : 0]), limits: (row, isProp) => row.timeslimit.split('|')[isProp ? 1 : 0].split(',').map(Number), intervals: (row, isProp) => row.cd.split('|')[isProp ? 1 : 0].split(',').map(Number), }, parser: (p) => { // p.limits = [min, max], p.intervals = [min, max] return this.generateTimeSequence(p.startTime, p.limits[0], p.limits[1], p.intervals[0], p.intervals[1]); } }, // --- 2. 加速门 (AccelerateGate) --- [ChapterNewPlayTypeEnum.AccelerateGate]: { constKey: ChapterNewPlayTypeEnum.AccelerateGate, paramMapping: { startTime: (row, isProp) => parseInt(row.starttime.split('|')[isProp ? 1 : 0]), limits: (row, isProp) => row.timeslimit.split('|')[isProp ? 1 : 0].split(',').map(Number), intervals: (row, isProp) => row.cd.split('|')[isProp ? 1 : 0].split(',').map(Number), // par1: "门存在时间,加速倍速,buff 时间" duration: (row, isProp) => parseInt(row.duration.split('|')[isProp ? 1 : 0]), extraParams: (row, isProp) => row.par1.split('|')[isProp ? 1 : 0].split(',').map(Number), }, parser: (p) => { const info = new IAccelerateGateProperty(); info.gateExistTime = p.duration; info.accelerateSpeed = p.extraParams[0]; info.buffTime = p.extraParams[1]; info.timeArr = this.generateTimeSequence(p.startTime, p.limits[0], p.limits[1], p.intervals[0], p.intervals[1]); return info; } }, // --- 3. 藤蔓草地 (VinesGrass) --- [ChapterNewPlayTypeEnum.VinesGrass]: { constKey: ChapterNewPlayTypeEnum.VinesGrass, paramMapping: { startTime: (row, isProp) => parseInt(row.starttime.split('|')[isProp ? 1 : 0]), limits: (row, isProp) => row.timeslimit.split('|')[isProp ? 1 : 0].split(',').map(Number), intervals: (row, isProp) => row.cd.split('|')[isProp ? 1 : 0].split(',').map(Number), }, parser: (p) => { return this.generateTimeSequence(p.startTime, p.limits[0], p.limits[1], p.intervals[0], p.intervals[1]); } }, // --- 4. 伞兵 (Paratroops) --- [ChapterNewPlayTypeEnum.Paratroops]: { constKey: ChapterNewPlayTypeEnum.Paratroops, needsFilter: true, paramMapping: { startTime: (row, isProp) => parseInt(row.starttime.split('|')[isProp ? 1 : 0]), limits: (row, isProp) => row.timeslimit.split('|')[isProp ? 1 : 0].split(',').map(Number), // 用于时间生成 intervals: (row, isProp) => row.cd.split('|')[isProp ? 1 : 0].split(',').map(Number), // 用于时间生成 monsterId: (row, isProp) => parseInt(row.par1.split('|')[isProp ? 1 : 0]), // par2: "数量下限,数量上限" (注意:原逻辑里这里可能复用了某些字段,请根据实际Excel调整) // 假设 par2 是 "numMin,numMax",如果原逻辑是用 cd 的区间做数量,请在此调整 numRange: (row, isProp) => { // 根据你的原代码:info.numArr = this.generateNumSequence(limitMin, limitMax, numMin, numMax); // 这里假设 par2 提供了 numMin, numMax const val = row.par2 ? row.par2.split('|')[isProp ? 1 : 0] : "1,1"; return val.split(',').map(Number); } }, parser: (p) => { const info = new IParatroopsProperty(); info.monsterId = p.monsterId; info.timeArr = this.generateTimeSequence(p.startTime, p.limits[0], p.limits[1], p.intervals[0], p.intervals[1]); // 注意:原代码逻辑 generateNumSequence(limitMin, limitMax, numMin, numMax) // 这里的参数顺序需严格对应你原有的 generateNumSequence 定义 info.numArr = this.generateNumSequence(p.limits[0], p.limits[1], p.numRange[0], p.numRange[1]); return info; } }, // --- 5. 血月 (BloodMoon) --- [ChapterNewPlayTypeEnum.BloodMoon]: { constKey: ChapterNewPlayTypeEnum.BloodMoon, paramMapping: { startTime: (row, isProp) => parseInt(row.starttime.split('|')[isProp ? 1 : 0]), intervalTime: (row, isProp) => parseInt(row.cd.split('|')[isProp ? 1 : 0]), // 假设间隔在 cd 列 durationRange: (row, isProp) => row.duration.split('|')[isProp ? 1 : 0].split(',').map(Number), // 持续时间范围 accelerateSpeed: (row, isProp) => parseFloat(row.par1.split('|')[isProp ? 1 : 0]), }, parser: (p) => { const info = new IBloodMoonProperty(); info.startTime = p.startTime; info.accelerateSpeed = p.accelerateSpeed; info.openTimeArr = []; info.closeTimeArr = []; let openTime = p.startTime; // 循环次数可配置,这里保持原逻辑 100 次 for (let j = 0; j < 100; j++) { const randTime = MTools.getRandomValue(p.durationRange[0], p.durationRange[1]); info.openTimeArr.push(openTime); const closeTime = openTime + randTime; info.closeTimeArr.push(closeTime); openTime = closeTime + p.intervalTime; } return info; } }, // --- 6. 魔法眼 (MagicEye) --- [ChapterNewPlayTypeEnum.MagicEye]: { constKey: ChapterNewPlayTypeEnum.MagicEye, paramMapping: { startTime: (row, isProp) => parseInt(row.starttime.split('|')[isProp ? 1 : 0]), intervalTime: (row, isProp) => parseInt(row.cd.split('|')[isProp ? 1 : 0]), existTime: (row, isProp) => parseInt(row.duration.split('|')[isProp ? 1 : 0].split(',')[0]), // 假设取第一个 effectRange: (row, isProp) => row.par1.split('|')[isProp ? 1 : 0].split(',').map(Number), // shieldCoeff: (row, isProp) => parseFloat(row.par2.split('|')[isProp ? 1 : 0]), }, parser: (p) => { const info = new IMagicEyeProperty(); info.startTime = p.startTime; info.intervalTime = p.intervalTime; info.existTime = p.existTime; info.effectTimeLowerLimit = p.effectRange[0]; info.effectTimeUpperLimit = p.effectRange[1]; info.shieldHpCoefficient = p.effectRange[2]; return info; } }, // --- 7. 女巫 (Witch) --- [ChapterNewPlayTypeEnum.Witch]: { constKey: ChapterNewPlayTypeEnum.Witch, paramMapping: { startTime: (row, isProp) => parseInt(row.starttime.split('|')[isProp ? 1 : 0]), intervalTime: (row, isProp) => parseInt(row.cd.split('|')[isProp ? 1 : 0]), existTime: (row, isProp) => parseInt(row.duration.split('|')[isProp ? 1 : 0].split(',')[0]), effectRange: (row, isProp) => row.par1.split('|')[isProp ? 1 : 0].split(',').map(Number), // maxMonsterNum: (row, isProp) => parseInt(row.par2.split('|')[isProp ? 1 : 0].split(',')[0]), // addHpCoeff: (row, isProp) => parseFloat(row.par2.split('|')[isProp ? 1 : 0].split(',')[1] || "0"), }, parser: (p) => { const info = new IWitchProperty(); info.startTime = p.startTime; info.intervalTime = p.intervalTime; info.existTime = p.existTime; info.effectTimeLowerLimit = p.effectRange[0]; info.effectTimeUpperLimit = p.effectRange[1]; info.maxAddHpMonsterNum = p.effectRange[2]; info.addHpCoefficient = p.effectRange[3]; return info; } }, // --- 8. 血包加血 (BloodBagAddHp) --- [ChapterNewPlayTypeEnum.BloodBagAddHp]: { constKey: ChapterNewPlayTypeEnum.BloodBagAddHp, paramMapping: { startTime: (row, isProp) => parseInt(row.starttime.split('|')[isProp ? 1 : 0]), limits: (row, isProp) => row.timeslimit.split('|')[isProp ? 1 : 0].split(',').map(Number), intervals: (row, isProp) => row.cd.split('|')[isProp ? 1 : 0].split(',').map(Number), gateExistTime: (row, isProp) => parseInt(row.duration.split('|')[isProp ? 1 : 0]), addHpCoeff: (row, isProp) => parseFloat(row.par1.split('|')[isProp ? 1 : 0]), }, parser: (p) => { const info = new IBloodBagAddHpProperty(); info.gateExistTime = p.gateExistTime; info.addHpCoefficient = p.addHpCoeff; info.timeArr = this.generateTimeSequence(p.startTime, p.limits[0], p.limits[1], p.intervals[0], p.intervals[1]); return info; } }, // --- 9. Boss 空投 (BossAirdrop) --- [ChapterNewPlayTypeEnum.BossAirdrop]: { constKey: ChapterNewPlayTypeEnum.BossAirdrop, needsFilter: true, paramMapping: { startTime: (row, isProp) => parseInt(row.starttime.split('|')[isProp ? 1 : 0]), limits: (row, isProp) => row.timeslimit.split('|')[isProp ? 1 : 0].split(',').map(Number), intervals: (row, isProp) => row.cd.split('|')[isProp ? 1 : 0].split(',').map(Number), monsterId: (row, isProp) => parseInt(row.par1.split('|')[isProp ? 1 : 0]), numRange: (row, isProp) => { const val = row.par2 ? row.par2.split('|')[isProp ? 1 : 0] : "1,1"; return val.split(',').map(Number); } }, parser: (p) => { const info = new IParatroopsProperty(); // 复用伞兵属性类?如果是新类请替换 info.monsterId = p.monsterId; info.timeArr = this.generateTimeSequence(p.startTime, p.limits[0], p.limits[1], p.intervals[0], p.intervals[1]); info.numArr = this.generateNumSequence(p.limits[0], p.limits[1], p.numRange[0], p.numRange[1]); return info; } }, //新机制寒冬 [ChapterNewPlayTypeEnum.ColdFire]: { constKey: ChapterNewPlayTypeEnum.ColdFire, needsFilter: true, paramMapping: { timeInterval: (row, isProp) => parseInt(row.cd.split('|')[isProp ? 1 : 0]), subTemperatureArr: (row, isProp) => row.par1.split('|')[isProp ? 1 : 0].split(',').map(Number), subHpByTemperatureArr: (row, isProp) => row.par2.split('|')[isProp ? 1 : 0].split('&')[0].split(',').map(Number), subHpArr: (row, isProp) => row.par2.split('|')[isProp ? 1 : 0].split('&')[1].split(',').map(Number), }, parser: (p) => { const info = new IColdFireProperty(); // 复用伞兵属性类?如果是新类请替换 info.startTemperature = 0; info.timeInterval = p.timeInterval; info.subTemperatureArr = p.subTemperatureArr; info.subHpByTemperatureArr = p.subHpByTemperatureArr; info.subHpArr = p.subHpArr; return info; } }, //新机制大雾 [ChapterNewPlayTypeEnum.FogAndWind]: { constKey: ChapterNewPlayTypeEnum.FogAndWind, needsFilter: true, paramMapping: { intervals: (row, isProp) => parseInt(row.cd.split('|')[isProp ? 1 : 0]), limitNum: (row, isProp) => parseInt(row.timeslimit.split('|')[isProp ? 1 : 0]), fogDownDistance: (row, isProp) => parseInt(row.par1.split('|')[isProp ? 1 : 0]), }, parser: (p) => { const info = new IFogAndWindProperty(); // 复用伞兵属性类?如果是新类请替换 info.timeInterval = p.intervals; info.limitNum = p.limitNum; info.fogDownDistance = p.fogDownDistance; return info; } }, //新机制黑夜 [ChapterNewPlayTypeEnum.NightAndLight]: { constKey: ChapterNewPlayTypeEnum.NightAndLight, needsFilter: true, paramMapping: { intervals: (row, isProp) => parseInt(row.cd.split('|')[isProp ? 1 : 0]), existTime: (row, isProp) => parseInt(row.duration.split('|')[isProp ? 1 : 0]), }, parser: (p) => { const info = new INightAndLightProperty(); // 复用伞兵属性类?如果是新类请替换 info.timeInterval = p.intervals; info.durationTime = p.existTime; return info; } }, }; initChapterNewPlayInfo() { this.chapterNewPlayInfo.clear(); const chapterConfig = gg.game.CurentBattle.CurentConfigChapter2 || gg.game.CurentBattle.CurentConfigChapter; // 1. 初始化 ID 列表 if (!chapterConfig.new_play) { this.newPlayIdArr = []; } else { this.newPlayIdArr = (chapterConfig.new_play + '').split(','); } const currentBattleType = gg.game.CurentBattle.BattleType; // 3. 处理全局过滤逻辑 (GachaMode) if (currentBattleType === BattleType.GachaMode) { this.newPlayIdArr = this.newPlayIdArr.filter(idStr => { const id = parseInt(idStr); const handler = this.playConfigHandlers[id]; if (handler && handler.needsFilter) { return false; } return true; }); } // 4. 【核心优化】遍历并自动解析配置 for (const idStr of this.newPlayIdArr) { const playType = parseInt(idStr); const descriptor = this.playConfigHandlers[playType]; if (!descriptor) { console.warn(`⚠️ 未知的玩法类型 ID: ${playType},请在 playConfigHandlers 中注册`); continue; } // 获取完整的配置行对象 (fullStr 现在是对象) const rowData = gg.constMechanism.getConfigDataById(descriptor.constKey); if (!rowData) { console.error(`❌ 找不到配置 ID: ${descriptor.constKey}`); continue; } // 【自动化】根据 paramMapping 提取并清洗所有参数 const extractedParams: Record = {}; const resultData = descriptor.parser(extractedParams); console.log('resultData===', playType, resultData) this.chapterNewPlayInfo.set(playType, resultData); // 调用业务解析器 // try { // const resultData = descriptor.parser(extractedParams); // this.chapterNewPlayInfo.set(playType, resultData); // } catch (e) { // console.error(`❌ 玩法 [${playType}] 业务解析失败:`, e); // } } } getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.Paratroops): IParatroopsProperty | undefined; getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.AccelerateGate): IAccelerateGateProperty | undefined; getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.BloodBagAddHp): IBloodBagAddHpProperty | undefined; getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.BloodMoon): IBloodMoonProperty | undefined; getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.MagicEye): IMagicEyeProperty | undefined; getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.Witch): IWitchProperty | undefined; getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.BloodBagAddHp): IBloodBagAddHpProperty | undefined; getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.BossAirdrop): IParatroopsProperty | undefined; // 3. 新机制寒冬 getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.ColdFire): IColdFireProperty | undefined; getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.ThunderRemoveObstacle): number[] | undefined; getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.VinesGrass): number[] | undefined; // 4. 新机制大雾/吹风机 getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.FogAndWind): IFogAndWindProperty | undefined; // 5. 新机制黑夜/灯塔 getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum.NightAndLight): INightAndLightProperty | undefined; // 2. 通用签名 (兜底,返回联合类型) getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum): ChapterPlayData | undefined; getChapterNewPlayInfo(type: ChapterNewPlayTypeEnum) { return this.chapterNewPlayInfo.get(type) } haveNewPlayInfo() { let arrayNew: ChapterNewPlayTypeEnum[] = [] //解析new_play(与枚举比较需为 number,否则 includes(枚举) 因 "15" !== 15 恒为 false) for (let i = 0; i < this.newPlayIdArr.length; i++) { let id = parseInt(this.newPlayIdArr[i], 10) if (id >= ChapterNewPlayTypeEnum.ThunderRemoveObstacle) { arrayNew.push(id) } } return arrayNew } /**是否有移除障碍物道具机制 */ isHaveRemoveObsProp() { return this.newPlayIdArr.indexOf(ChapterNewPlayTypeEnum.RemoveObstacleProp + '') >= 0 } /**是否有炸弹道具 */ isHaveBombProp() { return this.newPlayIdArr.indexOf(ChapterNewPlayTypeEnum.PlaceBombProp + '') >= 0 } //#endregion /*** * 俄罗斯方块需要加载的资源 */ getTetriResource() { // 仅收敛到“当前章节 cube_group 在波次权重里可能抽到的 type”,避免全量方块预加载 const tables = gg.data.table.getTableList(TableNames.BattleCube) || []; const waveTables = gg.data.table.getTableList(TableNames.TetriWaveWeight) || []; const chapterId = gg.game?.CurentBattle?.ChapterId || gg.data?.doc?.chapter || 1; const chapter = this.getChapterConfig(chapterId) as ITableChapter; const cubeGroupField = chapter?.cube_group; const typeSet = new Set(); if (cubeGroupField && waveTables.length > 0) { for (let i = 0; i < waveTables.length; i++) { const wt = (waveTables[i] as any)?.[cubeGroupField] as string; if (!wt) continue; const parts = wt.split(',').map(x => (x ?? '').trim()).filter(Boolean); for (let j = 0; j < parts.length; j++) { const [vStr, wStr] = parts[j].split('|').map(x => (x ?? '').trim()); const v = Number(vStr); const w = Number(wStr); if (Number.isFinite(v) && Number.isFinite(w) && w >= 0) { typeSet.add(v); } } } } const cubeNameSet = new Set(); for (let i = 0; i < tables.length; i++) { const table = tables[i]; if (!table?.cubename) continue; if (typeSet.size > 0) { if (table.weight > 0 && typeSet.has(table.type)) { cubeNameSet.add(table.cubename); } } else { // 回退:章节/权重异常时保持旧行为,避免资源缺失 cubeNameSet.add(table.cubename); } } return Array.from(cubeNameSet); } /**方块类型2动态权重值 */ private _type2Weight: number = 0; /** * 橙武单通:BattleCube.type==1(基础武器)或 type==5(藤蔓武器形状)按 weapontype(1~6) 过滤,仅保留 ModechooseTetriType; * 其它 type(无重力/金币/治疗等)为功能块,不过滤。 */ private _filterOrangeDanWeaponCubeList(tetriCategoryType: number, list: ITableBattleCube[]): ITableBattleCube[] { if (!list?.length) return list; if (gg.game?.CurentBattle?.BattleType !== BattleType.OrangeWeaponMode_Dan) return list; const allow = gg.game.CurentBattle.ModechooseTetriType; if (!allow?.length) return list; if (tetriCategoryType !== 1 && tetriCategoryType !== 5) return list; const filtered = list.filter((item) => { const wt = item.weapontype; if (!Number.isFinite(wt) || wt < 1 || wt > 6) return true; return allow.indexOf(wt) !== -1; }); return filtered.length ? filtered : list; } //根据战斗的波次获取俄罗斯方块的配置 getTetriConfigByWave(wave: number, chapter: ITableChapter) { let cubeTables = gg.data.table.getTableList(TableNames.BattleCube) if (gg.data.doc.chapter == 1) { //cubeTables中ischapter1 == 1的方块去掉 cubeTables = cubeTables.filter(item => item.ischapter1 != 1) //console.log('cubeTables 111 ', cubeTables) } let waveTables = gg.data.table.getTableList(TableNames.TetriWaveWeight) let data = waveTables.find(item => item.id == wave) if (!cubeTables || cubeTables.length == 0) return null if (!waveTables || waveTables.length == 0) return null if (!data || !data[chapter.cube_group]) return null let typeweight = data[chapter.cube_group]; //根据权重获取type值。 ( 1|100, 2|100, 3|100 )type值为1,2,3,权重为100,100,100 const randomByWeightString = (s: string): number | null => { const parts = (s ?? '').split(',').map(x => x.trim()).filter(Boolean) if (parts.length == 0) return null let total = 0 const pairs: { v: number, w: number }[] = [] // if (gg.game.noGravityWallProbability > 0) { let have2 = false for (let i = 0; i < parts.length; i++) { const [vStr, wStr] = parts[i].split('|').map(x => (x ?? '').trim()) const v = Number(vStr) if (v == 2) { have2 = true break } } if (!have2) { let str2 = '2|' + Math.floor(gg.game.noGravityWallProbability); parts.push(str2) } } for (let i = 0; i < parts.length; i++) { const [vStr, wStr] = parts[i].split('|').map(x => (x ?? '').trim()) const v = Number(vStr) let w = Number(wStr) if (v == 2 && gg.game.noGravityWallProbability > 0) { w = Math.floor(gg.game.noGravityWallProbability); } if (Number.isFinite(v) && Number.isFinite(w) && w > 0) { pairs.push({ v, w }) total += w } } if (pairs.length == 0 || total <= 0) return null let r = Math.random() * total for (let i = 0; i < pairs.length; i++) { r -= pairs[i].w if (r <= 0) return pairs[i].v } return pairs[pairs.length - 1].v } const type = randomByWeightString(typeweight) if (type == null) return null let list = cubeTables.filter(item => item.type == type && item.weight > 0) list = this._filterOrangeDanWeaponCubeList(type, list) if (!list || list.length == 0) return null let total = 0 for (let i = 0; i < list.length; i++) { total += (list[i].weight || 0) } if (total <= 0) return list[0] let r = Math.random() * total for (let i = 0; i < list.length; i++) { r -= (list[i].weight || 0) if (r <= 0) return list[i] } return list[list.length - 1] } /** * 指定波次与方块 type,仅在 BattleCube 表内按 weight 随机一条(不走 TetriWaveWeight 的 typeweight)。 * 用于广告刷新等需要「必出某一类」的场景。 */ getTetriConfigByWaveForceType(wave: number, forceType: number): ITableBattleCube | null { let cubeTables = gg.data.table.getTableList(TableNames.BattleCube) if (gg.data.doc.chapter == 1) { //cubeTables中ischapter1 == 1的方块去掉 cubeTables = cubeTables.filter(item => item.ischapter1 != 1) //console.log('cubeTables', cubeTables) } const waveTables = gg.data.table.getTableList(TableNames.TetriWaveWeight) if (!cubeTables?.length || !waveTables?.length) return null const data = waveTables.find(item => item.id == wave) if (!data) return null const list = cubeTables.filter(item => item.type == forceType && item.weight > 0) if (!list?.length) return null let total = 0 for (let i = 0; i < list.length; i++) { total += (list[i].weight || 0) } if (total <= 0) return list[0] let r = Math.random() * total for (let i = 0; i < list.length; i++) { r -= (list[i].weight || 0) if (r <= 0) return list[i] } return list[list.length - 1] } /**根据战斗的波次获取俄罗斯方块的配置(取多个;每次独立随机,允许重复) */ getTetriConfigsByWave(wave: number, count: number = 3, chapter: ITableChapter) { if (count <= 0) return [] const picked: ITableBattleCube[] = [] for (let i = 0; i < count; i++) { let one = this.getTetriConfigByWave(wave, chapter) while (one && one.type != 1 && picked.find(item => item.type != 1) != null) { one = this.getTetriConfigByWave(wave, chapter) } if (one) picked.push(one) } return picked } /**广告「神奇方块」刷新:与 getTetriConfigsByWave 同数量;其中必含 1 张 type=2,且该张 price=0(免费),其余仍按波次权重随机(顺序:先免费 type2,再随机补满) */ getTetriConfigsAd(wave: number, count: number = 3, chapter: ITableChapter) { const picked: ITableBattleCube[] = [] const type2 = this.getTetriConfigByWaveForceType(wave, 2) if (type2) { picked.push({ ...(type2 as object), price: 0 } as ITableBattleCube) } while (picked.length < count) { const one = this.getTetriConfigByWave(wave, chapter) if (one) picked.push(one) else break } return picked } getAllDps(skills: ITableSkill[], weaponIDs: number[], stackSumOverride?: Map | null) { let all = 0; for (let i = 0; i < weaponIDs.length; i++) { let weaponID = weaponIDs[i]; let weaponData = gg.data.project.getWeaponData(weaponID); if (!weaponData) continue; //武器方块数(可选:三选一预览时传入假设叠层,与场上绑定变更一致) let cubeCount = stackSumOverride != null ? (stackSumOverride.get(weaponID) ?? 0) : gg.game.CurentBattle.getTetrStackLevelSum(weaponID); // 仅统计该武器技能 + 全局技能(weapon<=0);排除银币技能 type=3 const skillsForWeapon = (skills ?? []).filter((s) => { if (!s || s.type === 3) return false; const wid = s.weapon; return !wid || wid <= 0 || wid === weaponID; }); //单一武器技能倍数 let dps = this.calculateDPSWeight(skillsForWeapon, weaponID); //武器攻击力 let weaponLevel = gg.data.project.getWeaponLevel(weaponID); let levelPara = gg.data.project.getLevelParaByWeaponLevel(weaponLevel, weaponID); let attackCoefficient = gg.data.getPlayerAtkCoefficient() let allAttack = weaponData.weapon_para * attackCoefficient * levelPara; //武器CD let cdNum = gg.data.getPlayerCoolCoefficient() let jisuanCd = weaponData.cd / (1 + cdNum / 10000) if (!(jisuanCd > 0)) continue; //单一武器DPS=单一武器方块数*单一武器技能倍数*武器攻击力/武器CD // weaponpar:表「秒伤」系数;weapon_para:攻击力系数(二者不同字段) let weaponDps = cubeCount * dps * allAttack / jisuanCd * (weaponData.weaponpar || 1); // console.log(`weaponDps:`, weaponDps, cubeCount, dps, allAttack, jisuanCd); all += weaponDps; } //console.log(`allDps:`, all); return all; } /**计算一组技能的DPS倍数 */ private calculateDPSWeight(arr: ITableSkill[], weaponId: number) { //计算已经拥有的所有乘区类型 let typeArr = gg.data.project.getAllMultiplyType(arr); //this.showLog(`所有乘区类型:`, JSON.stringify(typeArr)); let multDataMap = new Map(); //计算已经拥有的所有乘区类型的值 for (let j = 0; j < typeArr.length; j++) { let type = typeArr[j]; let value = gg.data.project.getSumValueBySkills(arr, type); multDataMap.set(type, value); } //let tempArr = Array.from(multDataMap.values()).map((item) => item); //this.showLog(`所有乘区类型的值:`, tempArr); //当前暴击率 let critRate = multDataMap.get(SkillMultiplyType.CritRate) || 0; //this.showLog(`乘区当前暴击率:`, critRate); //当前暴击伤害 let critDamage = multDataMap.get(SkillMultiplyType.CritDamage) || 0; //this.showLog(`乘区当前暴击伤害:`, critDamage); //当前其他乘区类型乘区值的总乘积 let otherTypeProduct = 1; multDataMap.forEach((value, key) => { if (key != SkillMultiplyType.CritRate && key != SkillMultiplyType.CritDamage) { otherTypeProduct *= (value + 1); } }); //this.showLog(`当前其他乘区类型乘区值的总乘积:`, otherTypeProduct); multDataMap.clear(); let dps = this.calculateDPS(critRate, critDamage, otherTypeProduct, weaponId); return dps; } /**根据一组技能获取所有乘区类型 */ getAllMultiplyType(skillArr: ITableSkill[]) { let typeArr: number[] = []; for (let i = 0; i < skillArr.length; i++) { let skill = skillArr[i]; let t1 = skill.multiply_type1; let t2 = skill.multiply_type2; if (typeArr.indexOf(t1) == -1 && t1 > 0) { typeArr.push(t1); } if (typeArr.indexOf(t2) == -1 && t2 > 0) { typeArr.push(t2); } } return typeArr; } /**根据一组技能计算指定类型乘区值总和 */ getSumValueBySkills(skillArr: ITableSkill[], type: number) { let sum = 0; for (let i = 0; i < skillArr.length; i++) { let skill = skillArr[i]; let t1 = skill.multiply_type1; let v1 = skill.multiply_num1; if (t1 == type) { sum += v1; } let t2 = skill.multiply_type2; let v2 = skill.multiply_num2; if (t2 == type) { sum += v2; } } return sum; } /**根据乘区暴击率,乘区暴击伤害,其他乘区类型乘区值的总乘积,计算当前技能的DPS */ private calculateDPS(critRate: number, critDamage: number, otherType: number, weaponId: number) { let weaponData = gg.data.project.getWeaponData(weaponId); //基础暴击率 let baseCritRate = weaponData.critical_chance / 10000; //this.showLog(`武器[${weaponId}]基础暴击率:`, baseCritRate); //玩家当前暴击率 let playerCritRate = gg.data.getPlayerCritCoefficient() / 10000; //this.showLog(`武器[${weaponId}]玩家当前暴击率:`, playerCritRate); //所有暴击率 let allCritRate = baseCritRate + playerCritRate + critRate; //this.showLog(`武器[${weaponId}]所有暴击率:`, allCritRate); //基础暴击伤害 let baseCritDamage = weaponData.critical_dam / 10000; //this.showLog(`武器[${weaponId}]基础暴击伤害:`, baseCritDamage); //玩家当前暴击伤害 let playerCritDamage = 0;//gg.data.project.getPlayerCritDamage(weaponId) / 10000; //this.showLog(`武器[${weaponId}]玩家当前暴击伤害:`, playerCritDamage); //所有暴击伤害 let allCritDamage = baseCritDamage + playerCritDamage + critDamage; //this.showLog(`武器[${weaponId}]所有暴击伤害:`, allCritDamage); //暴击率期望值=max(1,玩家当前暴击率*玩家当前暴击伤害+(1-玩家当前暴击率)) let critRateExpect = Math.max(1, allCritRate * allCritDamage + (1 - allCritRate)); //this.showLog(`武器[${weaponId}]暴击率期望值:`, critRateExpect); //DPS倍数=暴击率期望*其他乘区相乘 let dps = critRateExpect * otherType; return dps; } } /** * 道具绑定数据项 */ export class ItemData { constructor(id, num = 1, data: ITableItem = null) { this.id = id; this.num = Math.floor(num); this.staticData = data; } /**道具id */ id: number; /**数量 */ num: number; //是否是碎片ID转获取武器 isFragment: boolean = false; /**静态配表数据 */ staticData: ITableItem; } /** * 全局常量类型 */ export enum ConstNumType { /**基础生命值 */ BaseHp = 1, /**默认出怪间隔 */ DefaultMonsterInterval = 4, /**复活增加银币数 */ ReviveAddCoin = 6, /**波次预警提前时间 20s(第1关) */ MonsterWarnTime = 7, /**波次预警提前时间 15s(大于1关) */ MonsterWarnTime2 = 8, /**看广告增加银币数量 */ VideoAddCoin = 10, /**广告出现频率20秒*/ AdFrequency = 11, /**看广告增加银币次数 */ VideoAddCoinTimes = 13, guideSkill1 = 21,//关卡1引导第1个白银宝箱技能 guideSkill2 = 25,//关卡1引导第2个白银宝箱技能 /**体力自动恢复上限 */ VigourAutoAddLimit = 22, /**体力自动恢复时间 */ VigourAutoAddTime = 23, /**宠物钥匙价格 */ PetKeyPrice = 55, /**绿色宠物显示概率 */ GreenPetShowProb = 56, /**蓝色宠物显示概率 */ BluePetShowProb = 57, /**紫色宠物显示概率 */ PurplePetShowProb = 58, /**橙色宠物显示概率 */ OrangePetShowProb = 59, /**普通绿色宠物显示概率 */ NormalGreenPetShowProb = 60, /**普通蓝色宠物显示概率 */ NormalBluePetShowProb = 61, /**普通紫色宠物显示概率 */ NormalPurplePetShowProb = 62, /**普通橙色宠物显示概率 */ NormalOrangePetShowProb = 63, /**广告回血的触发血量 */ AdAddHp = 64, /**广告回血 回血次数限制*/ AdAddHpLimit = 65, /**普通——X关后开始产升级卡 */ NCardChapter = 66, /**困难——X关后开始产升级卡 */ HCardChapter = 67, /**地狱级——X关后开始产升级卡 */ HellCardChapter = 68, /**引导使用榴莲的等级 */ GuideUseLianLevel = 69,//引导使用榴莲的等级 /**提示功能看视频次数 */ GuidePosADTimes = 70, /**弹武器宝箱次数组 */ IsOpenSkillSelect = 71, /**20波之后,怪物血量系数增长基础值 */ InfiniteModeHpBaseMultiple = 72, /**20波之后,怪物攻击力增长基础值 */ InfiniteModeAtkBaseMultiple = 73, /**宝箱波次掉落组,1:掉落,2:不掉 */ BoxWaveDrop = 74, /**银币刷新消耗*/ CoinRefreshCost = 75, /**第一关首波刷新方块 */ FirstWaveTetri = 76, /**第二关首波刷新方块 */ SecondWaveTetri = 77, /** 怪物刷新无法被选中时间*/ MonsterRefreshUnselectableTime = 78, /**第2关首波刷新方块*/ FirstWaveTetri2 = 79, /**橙武副本宝箱波次掉落组,1:掉落,0:不掉*/ OrangeWeaponMode_DanBoxWaveDrop = 80, } export const ColorDefance = { /**全局字体统一默认颜色 */ defaultColor: color(138, 94, 68, 255), defaultBlue: color(45, 123, 161, 255), defaultYellow: color(171, 109, 31, 255), warnColor: color(192, 87, 23, 255), defaultGreen: color(25, 103, 23, 255), defaultRed: color(146, 32, 29, 255), defaultOutLineGreen: color(8, 126, 8, 255), qualityColor: [ color().fromHEX("#8A5E44"), color().fromHEX("#E5DCC2"), color().fromHEX("#1a85f0ff"), color().fromHEX("#fa12eeff"), color().fromHEX("#ffef0aff"), color().fromHEX("#FDE77A"), ] } /**商店类型 */ export enum ShopType { /**人才抽取 */ talent = 1, /**废品回收 */ waste = 2, /**商店 */ shop = 3, /**拍卖 */ auction = 4, } /**道具池类型 */ export enum PoolType { /**普通 */ common = 1, /**高级 */ high = 2, /**人才碎片任务基础池子 */ talentTaskBase = 3, /**人才碎片任务高级池子 */ talentTaskHigh = 4, /**人才碎片章节基础池子 */ talentChapterBase = 5, /**人才碎片章节高级池子 */ talentChapterHigh = 6, /**废品站任务基础池子 */ WasteTaskBase = 7, /**废品站任务高级池子 */ WasteTaskHigh = 8, } /**俄罗斯方块武器类型 用于确定武器替换*/ export enum TetriWeaponType { Tetris_Weapon_1 = 1, Tetris_Weapon_2 = 2, Tetris_Weapon_3 = 3, Tetris_Weapon_4 = 4, Tetris_Weapon_5 = 5, Tetris_Weapon_6 = 6, Tetris_Weapon_7 = 7, Tetris_Weapon_8 = 8, Tetris_Weapon_9 = 9, Tetris_Weapon_10 = 10, Tetris_Weapon_11 = 11, Tetris_Weapon_12 = 12, Tetris_Weapon_13 = 13, Tetris_Weapon_14 = 14, } /**俄罗斯方块的类型 * "类型id 1:基础方块 2:无重力方块 3:经济武器 4:回复武器 5:藤曼方块 */ export enum TetriType { Tetris_Baseattk = 1, Tetris_Basefloor = 2, Tetris_BaseGold = 3, Tetris_Baseheal = 4, Tetris_Basevine = 5, } /**俄罗斯的方块的形状类型cubetype */ export enum CubeType { Tetris_att_I = 1, Tetris_att_1_1 = 2, Tetris_att_J1 = 3, Tetris_att_J2 = 4, Tetris_att_J3 = 5, Tetris_att_J = 6, Tetris_att_L1 = 7, Tetris_att_L2 = 8, Tetris_att_L3 = 9, Tetris_att_L = 10, Tetris_att_Z1_1 = 11, Tetris_att_Z1 = 12, Tetris_att_Z2_1 = 13, Tetris_att_Z2 = 14, Tetris_att_凸_1 = 15, Tetris_att_凸_2 = 16, Tetris_att_凸_3 = 17, Tetris_att_凸 = 18, Tetris_floor_1a = 101, Tetris_floor_1b = 102, Tetris_floor_1c = 103, Tetris_floor_1d = 104, Tetris_floor_2a = 105, Tetris_floor_2b = 106, Tetris_floor_2c = 107, Tetris_floor_2d = 108, Tetris_floor_3a = 109, Tetris_floor_3b = 110, Tetris_floor_3c = 111, Tetris_floor_3d = 112, Tetris_floor_4a = 113, Tetris_floor_4b = 114, Tetris_floor_5a = 115, Tetris_floor_5b = 116, Tetris_floor_6a = 117, Tetris_floor_7a = 118, Tetris_floor_7b = 119, Tetris_floor_7c = 120, Tetris_floor_7d = 121, Tetris_coin_1 = 19, Tetris_heal_1 = 20, }