mirror of
https://github.com/motajs/template.git
synced 2026-10-11 15:10:17 +08:00
feat: 添加裸怪物临界计算
This commit is contained in:
parent
1d0c7db3cc
commit
751f206829
@ -14,6 +14,7 @@
|
||||
"@user/client-system": "workspace:*",
|
||||
"@user/data-common": "workspace:*",
|
||||
"@user/data-base": "workspace:*",
|
||||
"@user/data-system": "workspace:*",
|
||||
"@user/data-state": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@ -677,7 +677,7 @@ describe('真实大地图战斗场景性能', () => {
|
||||
const record = measureCase('全图怪物单次临界计算', label, () => {
|
||||
for (const entry of fixture.state.enemyContext.iterateEnemy()) {
|
||||
const view = entry[1];
|
||||
for (const _critical of fixture.damageSystem.calculateCritical(
|
||||
for (const _critical of fixture.damageSystem.calculateViewCritical(
|
||||
view,
|
||||
'atk'
|
||||
)) {
|
||||
|
||||
@ -5,8 +5,8 @@ import {
|
||||
IReadonlyEnemyHandler
|
||||
} from '@user/data-system';
|
||||
import { IEnemyAttr, IHeroAttr } from '@user/data-common';
|
||||
import { IVampireValue } from './special';
|
||||
import { logger } from '@motajs/common';
|
||||
import { ISpecial9Value } from './special';
|
||||
|
||||
export class MainDamageCalculator implements IDamageCalculator<
|
||||
IEnemyAttr,
|
||||
@ -51,7 +51,7 @@ export class MainDamageCalculator implements IDamageCalculator<
|
||||
}
|
||||
|
||||
// 吸血
|
||||
const vampire = enemy.getSpecial<IVampireValue>(11);
|
||||
const vampire = enemy.getSpecial<ISpecial9Value>(11);
|
||||
if (vampire) {
|
||||
const value = (vampire.value.vampire / 100) * hp;
|
||||
damage += value;
|
||||
|
||||
@ -253,7 +253,7 @@ describe('临界计算性能', () => {
|
||||
|
||||
measureCase('临界计算', String(count), () => {
|
||||
for (let i = 0; i < count; i++) {
|
||||
for (const _ of damageContext.calculateCritical(
|
||||
for (const _ of damageContext.calculateViewCritical(
|
||||
fixture.view,
|
||||
'atk'
|
||||
)) {
|
||||
@ -275,7 +275,7 @@ describe('临界计算性能', () => {
|
||||
|
||||
measureCase('临界计算', String(count), () => {
|
||||
for (let i = 0; i < count; i++) {
|
||||
for (const _ of damageContext.calculateCritical(
|
||||
for (const _ of damageContext.calculateViewCritical(
|
||||
fixture.view,
|
||||
'atk'
|
||||
)) {
|
||||
@ -297,7 +297,7 @@ describe('临界计算性能', () => {
|
||||
|
||||
measureCase('临界计算', String(count), () => {
|
||||
for (let i = 0; i < count; i++) {
|
||||
for (const _ of damageContext.calculateCritical(
|
||||
for (const _ of damageContext.calculateViewCritical(
|
||||
fixture.view,
|
||||
'atk'
|
||||
)) {
|
||||
|
||||
@ -514,7 +514,7 @@ describe('DamageContext critical generation', () => {
|
||||
);
|
||||
|
||||
const first = context
|
||||
.calculateCritical(fixture.view, 'atk')
|
||||
.calculateViewCritical(fixture.view, 'atk')
|
||||
.next().value!;
|
||||
|
||||
expect(first.baseValue).toBe(0);
|
||||
@ -533,7 +533,7 @@ describe('DamageContext critical generation', () => {
|
||||
fixture.hero
|
||||
);
|
||||
|
||||
const results = [...context.calculateCritical(fixture.view, 'atk')];
|
||||
const results = [...context.calculateViewCritical(fixture.view, 'atk')];
|
||||
|
||||
expect(results).toEqual([]);
|
||||
});
|
||||
@ -558,13 +558,16 @@ describe('DamageContext critical generation', () => {
|
||||
);
|
||||
|
||||
const heroResult = modules.logger.catch(() => [
|
||||
...noHero.calculateCritical(fixture.view, 'atk')
|
||||
...noHero.calculateViewCritical(fixture.view, 'atk')
|
||||
]);
|
||||
const calculatorResult = modules.logger.catch(() => [
|
||||
...noCalculator.calculateCritical(fixture.view, 'atk')
|
||||
...noCalculator.calculateViewCritical(fixture.view, 'atk')
|
||||
]);
|
||||
const locatorResult = modules.logger.catch(() => [
|
||||
...withLocator.calculateCritical(createUnknownView(fixture), 'atk')
|
||||
...withLocator.calculateViewCritical(
|
||||
createUnknownView(fixture),
|
||||
'atk'
|
||||
)
|
||||
]);
|
||||
|
||||
expect(heroResult.ret).toEqual([]);
|
||||
@ -585,7 +588,7 @@ describe('DamageContext critical generation', () => {
|
||||
);
|
||||
|
||||
const first = context
|
||||
.calculateCritical(fixture.view, 'atk')
|
||||
.calculateViewCritical(fixture.view, 'atk')
|
||||
.next().value!;
|
||||
|
||||
expect(first.nextValue).toBe(1);
|
||||
|
||||
@ -10,7 +10,8 @@ import {
|
||||
IEnemyDamageInfo,
|
||||
IReadonlyEnemyHandler,
|
||||
IEnemyView,
|
||||
IEnemyDamageInfoBase
|
||||
IEnemyDamageInfoBase,
|
||||
IReadonlyDamageHandler
|
||||
} from './types';
|
||||
import {
|
||||
IHeroAttribute,
|
||||
@ -57,9 +58,9 @@ export class DamageContext<TEnemy, THero> implements IDamageContext<
|
||||
*/
|
||||
private createReadonlyHandler(
|
||||
enemy: IReadonlyEnemy<TEnemy>,
|
||||
locator: ITileLocator,
|
||||
locator: ITileLocator | null,
|
||||
hero: IReadonlyHeroAttribute<THero>
|
||||
): IReadonlyEnemyHandler<TEnemy, THero> {
|
||||
): IReadonlyDamageHandler<TEnemy, THero> {
|
||||
return {
|
||||
enemy,
|
||||
context: this.context,
|
||||
@ -144,7 +145,7 @@ export class DamageContext<TEnemy, THero> implements IDamageContext<
|
||||
* @param maxIterations 最大迭代数量
|
||||
*/
|
||||
private findNextCritical(
|
||||
handler: IReadonlyEnemyHandler<TEnemy, THero>,
|
||||
handler: IReadonlyDamageHandler<TEnemy, THero>,
|
||||
hero: IHeroAttribute<THero>,
|
||||
attribute: CriticalableHeroStatus<THero>,
|
||||
currentValue: number,
|
||||
@ -181,7 +182,7 @@ export class DamageContext<TEnemy, THero> implements IDamageContext<
|
||||
};
|
||||
}
|
||||
|
||||
*calculateCritical(
|
||||
*calculateViewCritical(
|
||||
view: IEnemyView<TEnemy>,
|
||||
attribute: CriticalableHeroStatus<THero>,
|
||||
precision: number = 12
|
||||
@ -196,9 +197,31 @@ export class DamageContext<TEnemy, THero> implements IDamageContext<
|
||||
}
|
||||
|
||||
const locator = this.context.getEnemyLocatorByView(view);
|
||||
if (!locator) return;
|
||||
|
||||
const enemy = view.getComputedEnemy();
|
||||
|
||||
yield* this.calculateEnemyCritical(
|
||||
enemy,
|
||||
attribute,
|
||||
locator,
|
||||
precision
|
||||
);
|
||||
}
|
||||
|
||||
*calculateEnemyCritical(
|
||||
enemy: IReadonlyEnemy<TEnemy>,
|
||||
attribute: CriticalableHeroStatus<THero>,
|
||||
locator: ITileLocator | null,
|
||||
precision: number = 12
|
||||
): Generator<IEnemyCritical, void, void> {
|
||||
if (!this.heroStatus) {
|
||||
logger.warn(107);
|
||||
return;
|
||||
}
|
||||
if (!this.calculator) {
|
||||
logger.warn(106);
|
||||
return;
|
||||
}
|
||||
|
||||
const hero = this.heroStatus.getModifiableClone();
|
||||
const handler = this.createReadonlyHandler(enemy, locator, hero);
|
||||
|
||||
|
||||
@ -36,6 +36,20 @@ export interface IReadonlyEnemyHandler<
|
||||
readonly hero: IReadonlyHeroAttribute<THero>;
|
||||
}
|
||||
|
||||
export interface IReadonlyDamageHandler<
|
||||
TEnemy,
|
||||
THero
|
||||
> extends IDataBaseExtended {
|
||||
/** 怪物属性信息 */
|
||||
readonly enemy: IReadonlyEnemy<TEnemy>;
|
||||
/** 怪物上下文 */
|
||||
readonly context: IReadonlyEnemyContext<TEnemy, THero>;
|
||||
/** 怪物定位符 */
|
||||
readonly locator: ITileLocator | null;
|
||||
/** 勇士属性信息 */
|
||||
readonly hero: IReadonlyHeroAttribute<THero>;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region 怪物对象
|
||||
@ -369,7 +383,7 @@ export interface IEnemyDamageInfoBase {
|
||||
|
||||
export interface IEnemyDamageInfo<TEnemy, THero> extends IEnemyDamageInfoBase {
|
||||
/** 信息对象 */
|
||||
readonly handler: IReadonlyEnemyHandler<TEnemy, THero>;
|
||||
readonly handler: IReadonlyDamageHandler<TEnemy, THero>;
|
||||
}
|
||||
|
||||
export interface IEnemyCritical {
|
||||
@ -397,7 +411,7 @@ export interface IDamageCalculator<TEnemy, THero> {
|
||||
* @param handler 信息对象
|
||||
*/
|
||||
calculate(
|
||||
handler: IReadonlyEnemyHandler<TEnemy, THero>
|
||||
handler: IReadonlyDamageHandler<TEnemy, THero>
|
||||
): IEnemyDamageInfoBase;
|
||||
|
||||
/**
|
||||
@ -406,7 +420,7 @@ export interface IDamageCalculator<TEnemy, THero> {
|
||||
* @param attribute 勇士的临界属性
|
||||
*/
|
||||
getCriticalLimit(
|
||||
handler: IReadonlyEnemyHandler<TEnemy, THero>,
|
||||
handler: IReadonlyDamageHandler<TEnemy, THero>,
|
||||
attribute: CriticalableHeroStatus<THero>
|
||||
): number;
|
||||
}
|
||||
@ -442,11 +456,25 @@ export interface IDamageContext<TEnemy, THero> extends IDataBaseExtended {
|
||||
* @param attribute 计算临界的目标勇士属性,比如计算攻击临界、自定义属性的临界等等
|
||||
* @param precision 临界计算精度,表示会进行多少次二分计算,一般填写 `12-16` 之间的数即可,默认是 12
|
||||
*/
|
||||
calculateCritical(
|
||||
calculateViewCritical(
|
||||
enemy: IEnemyView<TEnemy>,
|
||||
attribute: CriticalableHeroStatus<THero>,
|
||||
precision?: number
|
||||
): Generator<IEnemyCritical, void, void>;
|
||||
|
||||
/**
|
||||
* 计算怪物在指定勇士属性下的临界
|
||||
* @param enemy 怪物只读对象
|
||||
* @param attribute 计算临界的目标勇士属性,比如计算攻击临界、自定义属性的临界等等
|
||||
* @param locator 怪物所在位置
|
||||
* @param precision 临界计算精度,表示会进行多少次二分计算,一般填写 `12-16` 之间的数即可,默认是 12
|
||||
*/
|
||||
calculateEnemyCritical(
|
||||
enemy: IReadonlyEnemy<TEnemy>,
|
||||
attribute: CriticalableHeroStatus<THero>,
|
||||
locator: ITileLocator | null,
|
||||
precision?: number
|
||||
): Generator<IEnemyCritical, void, void>;
|
||||
}
|
||||
|
||||
export interface IDamageSystem<TEnemy, THero> extends IDamageContext<
|
||||
|
||||
@ -461,6 +461,9 @@ importers:
|
||||
'@user/data-state':
|
||||
specifier: workspace:*
|
||||
version: link:../data-state
|
||||
'@user/data-system':
|
||||
specifier: workspace:*
|
||||
version: link:../data-system
|
||||
|
||||
packages-user/client-system:
|
||||
dependencies:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user