305 lines
9.8 KiB
TypeScript
305 lines
9.8 KiB
TypeScript
// 掉落物品接口
|
||
export interface DropItem {
|
||
uuid: number; // 物品ID
|
||
num: number; // 数量
|
||
type: number; // 类型
|
||
quality?: number; // 品质
|
||
}
|
||
|
||
// 怪物类型
|
||
export enum MonsterType {
|
||
Normal = 1, // 普通怪
|
||
Elite = 2, // 精英怪
|
||
Boss = 3, // Boss怪
|
||
}
|
||
|
||
// 掉落倍率配置
|
||
export const DropRateConfig = {
|
||
[MonsterType.Normal]: 1,
|
||
[MonsterType.Elite]: 2,
|
||
[MonsterType.Boss]: 10,
|
||
}
|
||
|
||
// Boss掉落示例(最多5个不同英雄的碎片)
|
||
// const bossDrops = getMonsterDrops(50, MonsterType.Boss, 1.2);
|
||
|
||
// 精英怪掉落示例(最多2个不同英雄的碎片)
|
||
// const eliteDrops = getMonsterDrops(50, MonsterType.Elite, 1.2);
|
||
|
||
// 普通怪掉落示例(最多1个英雄的碎片)
|
||
// const normalDrops = getMonsterDrops(50, MonsterType.Normal, 1.2);
|
||
|
||
/**
|
||
* 获取怪物掉落
|
||
* @param monsterLevel 怪物等级
|
||
* @param monsterType 怪物类型
|
||
* @param extraRate 额外倍率(比如玩家的幸运值加成)
|
||
* @returns 掉落物品数组
|
||
*/
|
||
export function getMonsterDrops(
|
||
monsterLevel: number,
|
||
monsterType: MonsterType = MonsterType.Normal,
|
||
extraRate: number = 1
|
||
): DropItem[] {
|
||
const drops: DropItem[] = [];
|
||
const baseMultiplier = getDropMultiplier(monsterLevel);
|
||
const monsterMultiplier = DropRateConfig[monsterType];
|
||
const totalMultiplier = baseMultiplier * monsterMultiplier * extraRate;
|
||
|
||
// 分离英雄碎片和道具配置
|
||
const heroChipConfigs = DropConfigList.filter(config => config.type === dorptype.hero_chip);
|
||
const itemConfigs = DropConfigList.filter(config => config.type === dorptype.items);
|
||
|
||
// 获取当前怪物类型可以掉落的英雄碎片数量
|
||
const maxHeroChips = HeroChipDropCount[monsterType];
|
||
|
||
// 随机选择指定数量的英雄碎片
|
||
const selectedHeroChips = shuffleArray(heroChipConfigs).slice(0, maxHeroChips);
|
||
|
||
// 处理英雄碎片掉落
|
||
for (const config of selectedHeroChips) {
|
||
if (monsterType === MonsterType.Normal) {
|
||
// 普通怪按概率掉落
|
||
if (shouldDrop(config.dropRate * totalMultiplier)) {
|
||
const dropItem = calculateDrop(config, monsterLevel, monsterType);
|
||
if (dropItem) {
|
||
drops.push(dropItem);
|
||
}
|
||
}
|
||
} else {
|
||
// 精英怪和Boss必定掉落
|
||
const dropItem = calculateDrop(config, monsterLevel, monsterType);
|
||
if (dropItem) {
|
||
drops.push(dropItem);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理道具掉落
|
||
for (const config of itemConfigs) {
|
||
if (config.uuid === 9001) {
|
||
// 金币必定掉落
|
||
const dropItem = calculateDrop(config, monsterLevel, monsterType);
|
||
if (dropItem) {
|
||
drops.push(dropItem);
|
||
}
|
||
} else {
|
||
// 其他道具按概率掉落
|
||
if (shouldDrop(config.dropRate * totalMultiplier)) {
|
||
const dropItem = calculateDrop(config, monsterLevel, monsterType);
|
||
if (dropItem) {
|
||
drops.push(dropItem);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return drops;
|
||
}
|
||
|
||
/**
|
||
* 计算是否掉落
|
||
* @param rate 掉落概率
|
||
*/
|
||
function shouldDrop(rate: number): boolean {
|
||
return Math.random() * 100 <= Math.min(rate, 100);
|
||
}
|
||
|
||
/**
|
||
* 计算单个物品掉落
|
||
*/
|
||
function calculateDrop(
|
||
config: typeof DropConfigList[0],
|
||
monsterLevel: number,
|
||
monsterType: MonsterType
|
||
): DropItem | null {
|
||
// 计算掉落数量
|
||
let num = Math.floor(Math.random() * config.num_max) + 1;
|
||
|
||
// Boss额外保底
|
||
if (monsterType === MonsterType.Boss && num < config.num_max * 0.3) {
|
||
num = Math.floor(config.num_max * 0.3);
|
||
}
|
||
|
||
// 根据类型应用不同规则
|
||
if (config.type === dorptype.hero_chip) {
|
||
// 英雄碎片特殊处理
|
||
return {
|
||
uuid: config.uuid,
|
||
num: Math.min(num, 10), // 英雄碎片单次最多10个
|
||
type: config.type,
|
||
quality: getHeroQuality(config.uuid)
|
||
};
|
||
} else if (config.type === dorptype.items) {
|
||
// 普通道具处理
|
||
return {
|
||
uuid: config.uuid,
|
||
num: num,
|
||
type: config.type
|
||
};
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 获取英雄品质(需要和heroSet配置关联)
|
||
*/
|
||
function getHeroQuality(heroId: number): number {
|
||
// 这里可以从heroSet中获取英雄品质
|
||
return 1; // 默认品质
|
||
}
|
||
|
||
/**
|
||
* 获取掉落倍率
|
||
* @param monsterLevel 怪物等级
|
||
*/
|
||
export function getDropMultiplier(monsterLevel: number): number {
|
||
// 基础倍率
|
||
let multiplier = Math.max(1, Math.floor(monsterLevel / 10));
|
||
|
||
// 等级档位加成
|
||
if (monsterLevel >= 50) multiplier *= 1.5;
|
||
if (monsterLevel >= 100) multiplier *= 2;
|
||
|
||
return multiplier;
|
||
}
|
||
|
||
/**
|
||
* 批量生成掉落
|
||
* @param times 掉落次数
|
||
* @param params 掉落参数
|
||
*/
|
||
export function batchGenerateDrops(
|
||
times: number,
|
||
monsterLevel: number,
|
||
monsterType: MonsterType = MonsterType.Normal,
|
||
extraRate: number = 1
|
||
): DropItem[] {
|
||
const allDrops: DropItem[] = [];
|
||
|
||
for (let i = 0; i < times; i++) {
|
||
const drops = getMonsterDrops(monsterLevel, monsterType, extraRate);
|
||
allDrops.push(...drops);
|
||
}
|
||
|
||
// 合并相同物品
|
||
return mergeDrops(allDrops);
|
||
}
|
||
|
||
/**
|
||
* 合并相同物品的掉落
|
||
*/
|
||
function mergeDrops(drops: DropItem[]): DropItem[] {
|
||
const mergedMap = new Map<string, DropItem>();
|
||
|
||
drops.forEach(drop => {
|
||
const key = `${drop.uuid}-${drop.type}`;
|
||
if (mergedMap.has(key)) {
|
||
const existing = mergedMap.get(key)!;
|
||
existing.num += drop.num;
|
||
} else {
|
||
mergedMap.set(key, {...drop});
|
||
}
|
||
});
|
||
|
||
return Array.from(mergedMap.values());
|
||
}
|
||
|
||
/**
|
||
* 随机打乱数组
|
||
*/
|
||
function shuffleArray<T>(array: T[]): T[] {
|
||
const newArray = [...array];
|
||
for (let i = newArray.length - 1; i > 0; i--) {
|
||
const j = Math.floor(Math.random() * (i + 1));
|
||
[newArray[i], newArray[j]] = [newArray[j], newArray[i]];
|
||
}
|
||
return newArray;
|
||
}
|
||
|
||
export const BoxDrop={
|
||
1:[
|
||
{uuid: 9001,dropRate: 10,num_max: 500000,type:0},
|
||
{uuid: 9003,dropRate: 10,num_max: 500,type:0},
|
||
],
|
||
2:[
|
||
{uuid: 5001,dropRate: 5,num_max: 5,type:1}, // 圣盾战 quality 3
|
||
{uuid: 5002,dropRate: 30,num_max: 5,type:1}, // 火女 quality 1
|
||
{uuid: 5003,dropRate: 30,num_max: 5,type:1}, // 牧师 quality 1
|
||
{uuid: 5004,dropRate: 15,num_max: 5,type:1}, // 自愈骑 quality 2
|
||
{uuid: 5005,dropRate: 30,num_max: 5,type:1}, // quality 1
|
||
{uuid: 5006,dropRate: 15,num_max: 5,type:1}, // quality 2
|
||
{uuid: 5007,dropRate: 5,num_max: 5,type:1}, // 召唤师 quality 3
|
||
{uuid: 5008,dropRate: 30,num_max: 5,type:1}, // quality 1
|
||
{uuid: 5009,dropRate: 15,num_max: 5,type:1}, // quality 2
|
||
{uuid: 5010,dropRate: 5,num_max: 5,type:1}, // quality 3
|
||
{uuid: 5011,dropRate: 30,num_max: 5,type:1}, // quality 1
|
||
],
|
||
3:[
|
||
{uuid: 5001,dropRate: 5,num_max: 5,type:1}, // 圣盾战 quality 3
|
||
{uuid: 5002,dropRate: 30,num_max: 5,type:1}, // 火女 quality 1
|
||
{uuid: 5003,dropRate: 30,num_max: 5,type:1}, // 牧师 quality 1
|
||
{uuid: 5004,dropRate: 15,num_max: 5,type:1}, // 自愈骑 quality 2
|
||
{uuid: 5005,dropRate: 30,num_max: 5,type:1}, // quality 1
|
||
{uuid: 5006,dropRate: 15,num_max: 5,type:1}, // quality 2
|
||
{uuid: 5007,dropRate: 5,num_max: 5,type:1}, // 召唤师 quality 3
|
||
{uuid: 5008,dropRate: 30,num_max: 5,type:1}, // quality 1
|
||
{uuid: 5009,dropRate: 15,num_max: 5,type:1}, // quality 2
|
||
{uuid: 5010,dropRate: 5,num_max: 5,type:1}, // quality 3
|
||
{uuid: 5011,dropRate: 30,num_max: 5,type:1}, // quality 1
|
||
],
|
||
}
|
||
export const BoxDropCount={
|
||
1:3,
|
||
2:3,
|
||
3:3,
|
||
}
|
||
export const dorptype={
|
||
hero_chip:1,
|
||
items:2,
|
||
}
|
||
export const HeroChipDropCount={
|
||
1:1,
|
||
2:2,
|
||
3:5,
|
||
}
|
||
//HeroChipList = [5001,5002,5003,5004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,5024,5025,5026,5027]
|
||
//ItemsList=[9001,1003]
|
||
//根据HeroChipList,ItemsList设置掉落概率
|
||
//参考 heroSet.ts 中 HeroInfo对象数据的quality值来修改,DropConfigList中的dropRaten和um_max值,quality值越大,掉落概率越小,数量越少
|
||
export const DropConfigList=[
|
||
{uuid: 5001,dropRate: 5,num_max: 5,type:1}, // 圣盾战 quality 3
|
||
{uuid: 5002,dropRate: 30,num_max: 5,type:1}, // 火女 quality 1
|
||
{uuid: 5003,dropRate: 30,num_max: 5,type:1}, // 牧师 quality 1
|
||
{uuid: 5004,dropRate: 15,num_max: 5,type:1}, // 自愈骑 quality 2
|
||
{uuid: 5005,dropRate: 30,num_max: 5,type:1}, // quality 1
|
||
{uuid: 5006,dropRate: 15,num_max: 5,type:1}, // quality 2
|
||
{uuid: 5007,dropRate: 5,num_max: 5,type:1}, // 召唤师 quality 3
|
||
{uuid: 5008,dropRate: 30,num_max: 5,type:1}, // quality 1
|
||
{uuid: 5009,dropRate: 15,num_max: 5,type:1}, // quality 2
|
||
{uuid: 5010,dropRate: 5,num_max: 5,type:1}, // quality 3
|
||
{uuid: 5011,dropRate: 30,num_max: 5,type:1}, // quality 1
|
||
{uuid: 9001,dropRate: 100,num_max: 5000,type:2},
|
||
{uuid: 1003,dropRate: 20,num_max: 5,type:2},
|
||
]
|
||
// 使用示例:
|
||
/*
|
||
// 单次掉落
|
||
const drops = getMonsterDrops(50, MonsterType.Boss, 1.2);
|
||
|
||
// 批量掉落(比如连续击杀多个怪物)
|
||
const batchDrops = batchGenerateDrops(5, 50, MonsterType.Elite, 1.2);
|
||
|
||
// 处理掉落物品
|
||
drops.forEach(item => {
|
||
if (item.type === dorptype.hero_chip) {
|
||
// 处理英雄碎片
|
||
console.log(`获得英雄碎片: ${item.uuid} x${item.num}`);
|
||
} else if (item.type === dorptype.items) {
|
||
// 处理道具
|
||
console.log(`获得道具: ${item.uuid} x${item.num}`);
|
||
}
|
||
});
|
||
*/
|