完成开箱抽卡 和 怪物掉落设置

This commit is contained in:
2025-01-19 23:43:14 +08:00
parent cebf09a58c
commit d756516cc6
30 changed files with 51192 additions and 38040 deletions

View File

@@ -1,3 +1,222 @@
// 掉落物品接口
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:[
@@ -5,14 +224,62 @@ export const BoxDrop={
{uuid: 9003,dropRate: 10,num_max: 500,type:0},
],
2:[
{uuid: 5001,dropRate: 10,num_max: 10,type:0},
{uuid: 5002,dropRate: 10,num_max: 10,type:0},
{uuid: 5003,dropRate: 50,num_max: 10,type:0},
{uuid: 5001,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5002,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5003,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5004,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5005,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5006,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5007,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5008,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5009,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5010,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5011,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5012,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5013,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5014,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5015,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5016,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5017,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5018,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5019,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5020,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5021,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5022,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5023,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5024,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5025,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5026,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5027,dropRate: 100/7,num_max: 5,type:1},
],
3:[
{uuid: 5001,dropRate: 20,num_max: 10,type:0},
{uuid: 5002,dropRate: 20,num_max: 10,type:0},
{uuid: 5003,dropRate: 50,num_max: 10,type:0},
{uuid: 5001,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5002,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5003,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5004,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5005,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5006,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5007,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5008,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5009,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5010,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5011,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5012,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5013,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5014,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5015,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5016,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5017,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5018,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5019,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5020,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5021,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5022,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5023,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5024,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5025,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5026,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5027,dropRate: 100/7,num_max: 5,type:1},
],
}
export const BoxDropCount={
@@ -20,4 +287,66 @@ export const BoxDropCount={
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]
//根据HeroChipListItemsList设置掉落概率
export const DropConfigList=[
{uuid: 5001,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5002,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5003,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5004,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5005,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5006,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5007,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5008,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5009,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5010,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5011,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5012,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5013,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5014,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5015,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5016,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5017,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5018,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5019,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5020,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5021,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5022,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5023,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5024,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5025,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5026,dropRate: 100/7,num_max: 5,type:1},
{uuid: 5027,dropRate: 100/7,num_max: 5,type:1},
{uuid: 9001,dropRate: 100,num_max: 1000,type:2},
{uuid: 1003,dropRate: 20,num_max: 1,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}`);
}
});
*/