消消方块阵换皮表情
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

2064 lines
83 KiB

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<string, FieldExtractor>;
// 具体的业务解析逻辑
parser: (params: any) => ChapterPlayData;
}
/**
* 项目动态数据
* 大部分通用的动态数据在gg.data中已经实现了
* 根据项目自定义数据获取实现方式在这个脚本里写,方便统一管理和调用
*/
export class ConfigProjectData extends Singleton {
///////////////////////----------------道具相关-------------------///////////////////////
//#region 道具
/**将id相同的道具合并 */
mergeSameItem(items: ItemData[]) {
let itemMap = new Map<number, ItemData>();
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<number, ITableWeapon2> = new Map();
/**获取所有武器ID */
private _weaponDataList: ITableWeapon2[] = [];
/**获取所有武器ID */
private _weaponIds: number[] = [];
/**获取所有武器数据 */
getWeaponDataList() {
if (this._weaponDataList.length <= 0) {
this._weaponDataList = gg.data.table.getTableList<ITableWeapon2>(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<ITableWeapon3>(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<ITableSkill>(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<ITableWeapon4>(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<ITableChapter>(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<ITableChapter>(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<ITableChapter>(TableNames.Chapter, chapterId);
return chapterConfig;
} catch (error) {
return null;
}
}
/**获取最大章节id */
getMaxChapterId() {
try {
let chapterConfigList = gg.data.table.getTableList<ITableChapter>(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<ITableChapter>(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<ITablePlaymode>(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<ITableObstacle>(TableNames.Obstacle).filter(x => obstacleArr.includes(x.id));
// return obstacleConfigList;
}
private _monsterList: ITableMonster[] = [];
private _monsterMap: Map<number, ITableMonster> = new Map();
/**获取所有怪物配置 */
getAllMonsterList1() {
if (this._monsterList.length == 0) {
this._monsterList = gg.data.table.getTableList<ITableMonster>(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<ITableChapter_weight>(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<ITableReplica>(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<ChapterNewPlayTypeEnum, ChapterPlayData>()
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<Record<ChapterNewPlayTypeEnum, PlayConfigDescriptor>> = {
[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<string, any> = {};
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<ITableBattleCube>(TableNames.BattleCube) || [];
const waveTables = gg.data.table.getTableList<ITableTetriWaveWeight>(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<number>();
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<string>();
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<ITableBattleCube>(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<ITableTetriWaveWeight>(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<ITableBattleCube>(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<ITableTetriWaveWeight>(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<number, number> | 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<number, number>();
//计算已经拥有的所有乘区类型的值
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,
}