feat: 跟进 2.A 的更改

This commit is contained in:
AncTe committed 2024-04-20 12:27:38 +08:00
1 parent 0dfb7e4b99
commit 86e6e76286
38 files changed
+851 -493

No files matched your search

+48 -120
View File
@@ -4,6 +4,7 @@ import { loading } from '../game';
export interface CurrentEnemy {
enemy: DamageEnemy;
// 这个是干啥的?
onMapEnemy: DamageEnemy[];
}
@@ -16,155 +17,64 @@ export function getEnemy(
return v.x === x && v.y === y;
});
if (!enemy) {
throw new Error(
`Get null when getting enemy on '${x},${y}' in '${floorId}'`
);
return null;
}
return enemy;
}
function init() {
core.enemys.canBattle = function canBattle(
x: number,
x: number | DamageEnemy,
y: number,
floorId: FloorIds = core.status.floorId
) {
const enemy = getEnemy(x, y, floorId);
const enemy = typeof x === 'number' ? getEnemy(x, y, floorId) : x;
if (!enemy) {
throw new Error(
`Cannot get enemy on x:${x}, y:${y}, floor: ${floorId}`
);
}
const { damage } = enemy.calDamage();
return damage < core.status.hero.hp;
};
core.events.battle = function battle(
x: number,
x: number | DamageEnemy,
y: number,
force: boolean = false,
callback?: () => void
) {
core.saveAndStopAutomaticRoute();
const enemy = getEnemy(x, y);
const isLoc = typeof x === 'number';
const enemy = isLoc ? getEnemy(x, y) : x;
if (!enemy) {
throw new Error(
`Cannot battle with enemy since no enemy on ${x},${y}`
);
}
// 非强制战斗
// @ts-ignore
if (!core.canBattle(x, y) && !force && !core.status.event.id) {
core.stopSound();
core.playSound('操作失败');
core.drawTip('你打不过此怪物!', enemy.id);
core.drawTip('你打不过此怪物!', enemy!.id);
return core.clearContinueAutomaticRoute(callback);
}
// 自动存档
if (!core.status.event.id) core.autosave(true);
// 战前事件
// 战后事件
core.afterBattle(enemy, x, y);
core.afterBattle(enemy, isLoc ? x : enemy.x, y);
callback?.();
};
core.events.afterBattle = function afterBattle(
enemy: DamageEnemy,
x?: number,
y?: number
) {
const floorId = core.status.floorId;
const special = enemy.info.special;
const getFacedId = (enemy: DamageEnemy) => {
const e = enemy.enemy;
// 播放战斗动画
let animate: AnimationIds = 'hand';
// 检查当前装备是否存在攻击动画
const equipId = core.getEquip(0);
if (equipId && (core.material.items[equipId].equip || {}).animate)
animate = core.material.items[equipId].equip.animate;
// 检查该动画是否存在SE,如果不存在则使用默认音效
if (!core.material.animates[animate]?.se) core.playSound('attack.mp3');
// 战斗伤害
const info = enemy.calDamage(core.status.hero);
const damage = info.damage;
// 判定是否致死
if (damage >= core.status.hero.hp) {
core.status.hero.hp = 0;
core.updateStatusBar(false, true);
core.events.lose('战斗失败');
return;
}
// 扣减体力值并记录统计数据
core.status.hero.hp -= damage;
core.status.hero.statistics.battleDamage += damage;
core.status.hero.statistics.battle++;
// 智慧之源
if (special.includes(14) && flags.hard === 2) {
core.addFlag(
'inte_' + floorId,
Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10
);
core.status.hero.mdef -=
Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10;
}
// 极昼永夜
if (special.includes(22)) {
flags[`night_${floorId}`] ??= 0;
flags[`night_${floorId}`] -= enemy.enemy.night!;
}
if (special.includes(23)) {
flags[`night_${floorId}`] ??= 0;
flags[`night_${floorId}`] += enemy.enemy.day;
}
// if (core.plugin.skillTree.getSkillLevel(11) > 0) {
// core.plugin.study.declineStudiedSkill();
// }
// 如果是融化怪,需要特殊标记一下
if (special.includes(25) && has(x) && has(y)) {
flags[`melt_${floorId}`] ??= {};
flags[`melt_${floorId}`][`${x},${y}`] = enemy.enemy.melt;
}
// 获得金币
const money = enemy.enemy.money;
core.status.hero.money += money;
core.status.hero.statistics.money += money;
// 获得经验
const exp = enemy.enemy.exp;
core.status.hero.exp += exp;
core.status.hero.statistics.exp += exp;
const hint =
'打败 ' + enemy.enemy.name + ',金币+' + money + ',经验+' + exp;
core.drawTip(hint, enemy.id);
if (core.getFlag('bladeOn') && core.getFlag('blade')) {
core.setFlag('blade', false);
}
if (core.getFlag('shieldOn') && core.getFlag('shield')) {
core.setFlag('shield', false);
}
// 事件的处理
const todo: MotaEvent = [];
// 战后事件
if (has(core.status.floorId)) {
const loc = `${x},${y}` as LocString;
todo.push(
...(core.floors[core.status.floorId].afterBattle[loc] ?? [])
);
}
todo.push(...(enemy.enemy.afterBattle ?? []));
// 如果事件不为空,将其插入
if (todo.length > 0) core.insertAction(todo, x, y);
if (has(x) && has(y)) {
core.drawAnimate(animate, x, y);
core.removeBlock(x, y);
} else core.drawHeroAnimate(animate);
// 如果已有事件正在处理中
if (core.status.event.id == null) core.continueAutomaticRoute();
else core.clearContinueAutomaticRoute();
if (e.displayIdInBook) return e.displayIdInBook;
if (e.faceIds) return e.faceIds.down;
return e.id;
};
core.enemys.getCurrentEnemys = function getCurrentEnemys(
@@ -176,7 +86,8 @@ function init() {
ensureFloorDamage(floorId);
const floor = core.status.maps[floorId];
floor.enemy.list.forEach(v => {
if (!(v.id in used)) {
const id = getFacedId(v);
if (!(id in used)) {
const e = new DamageEnemy(v.enemy);
e.calAttribute();
e.getRealInfo();
@@ -186,9 +97,9 @@ function init() {
onMapEnemy: [v]
};
enemys.push(curr);
used[v.id] = curr.onMapEnemy;
used[id] = curr.onMapEnemy;
} else {
used[v.id].push(v);
used[id].push(v);
}
});
@@ -207,7 +118,7 @@ function init() {
const enemy = getEnemy(data.x, data.y);
beforeBattle.push(...(floor.beforeBattle[loc] ?? []));
beforeBattle.push(...(enemy.enemy.beforeBattle ?? []));
beforeBattle.push(...(enemy!.enemy.beforeBattle ?? []));
if (beforeBattle.length > 0) {
beforeBattle.push({ type: 'battle', x: data.x, y: data.y });
@@ -251,5 +162,22 @@ loading.once('coreInit', init);
declare global {
interface Enemys {
getCurrentEnemys(floorId: FloorIds): CurrentEnemy[];
canBattle(enemy: DamageEnemy, _?: number, floorId?: FloorIds): boolean;
canBattle(x: number, y: number, floorId?: FloorIds): boolean;
}
interface Events {
battle(
enemy: DamageEnemy,
_?: number,
force?: boolean,
callback?: () => void
): void;
battle(
x: number,
y?: number,
force?: boolean,
callback?: () => void
): void;
}
}
+35 -32
View File
@@ -16,15 +16,15 @@ interface HaloType {
};
}
interface EnemyInfo {
interface EnemyInfo extends Partial<Enemy> {
atk: number;
def: number;
hp: number;
special: number[];
damageDecline: number;
atkBuff: number;
defBuff: number;
hpBuff: number;
atkBuff_: number;
defBuff_: number;
hpBuff_: number;
enemy: Enemy;
x?: number;
y?: number;
@@ -65,7 +65,7 @@ interface CriticalDamageDelta extends Omit<DamageDelta, 'info'> {
type HaloFn = (info: EnemyInfo, enemy: Enemy) => void;
/** 光环属性 */
export const haloSpecials: number[] = [8, 21, 25, 26, 27];
export const haloSpecials: Set<number> = new Set([8, 21, 25, 26, 27]);
export class EnemyCollection implements RangeCollection<DamageEnemy> {
floorId: FloorIds;
@@ -302,7 +302,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
info!: EnemyInfo;
/** 向其他怪提供过的光环 */
providedHalo: number[] = [];
providedHalo: Set<number> = new Set();
/**
* 伤害计算进度,0 -> 预平衡光环 -> 1 -> 计算没有光环的属性 -> 2 -> provide inject 光环
@@ -334,16 +334,23 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
def: enemy.def,
special: enemy.special.slice(),
damageDecline: 0,
atkBuff: 0,
defBuff: 0,
hpBuff: 0,
atkBuff_: 0,
defBuff_: 0,
hpBuff_: 0,
enemy: this.enemy,
x: this.x,
y: this.y,
floorId: this.floorId
};
for (const [key, value] of Object.entries(enemy)) {
if (!(key in this.info) && has(value)) {
// @ts-ignore
this.info[key] = value;
}
}
this.progress = 0;
this.providedHalo = [];
this.providedHalo.clear();
}
/**
@@ -370,8 +377,8 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
for (const [loc, per] of Object.entries(flags[`melt_${floorId}`])) {
const [mx, my] = loc.split(',').map(v => parseInt(v));
if (Math.abs(mx - this.x) <= 1 && Math.abs(my - this.y) <= 1) {
info.atkBuff += per as number;
info.defBuff += per as number;
info.atkBuff_ += per as number;
info.defBuff_ += per as number;
}
}
}
@@ -392,9 +399,9 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
// 此时已经inject光环,因此直接计算真实属性
const info = this.info;
info.atk = Math.floor(info.atk * (info.atkBuff / 100 + 1));
info.def = Math.floor(info.def * (info.defBuff / 100 + 1));
info.hp = Math.floor(info.hp * (info.hpBuff / 100 + 1));
info.atk = Math.floor(info.atk * (info.atkBuff_ / 100 + 1));
info.def = Math.floor(info.def * (info.defBuff_ / 100 + 1));
info.hp = Math.floor(info.hp * (info.hpBuff_ / 100 + 1));
return this.info;
}
@@ -404,7 +411,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
if (!has(this.x) || !has(this.y)) return [];
const special = this.info.special ?? this.enemy.special;
const filter = special.filter(v => {
return haloSpecials.includes(v) && !this.providedHalo.includes(v);
return haloSpecials.has(v) && !this.providedHalo.has(v);
});
if (filter.length === 0) return [];
const collection = this.col ?? core.status.maps[this.floorId].enemy;
@@ -448,11 +455,11 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
e.special.includes(8) &&
(e.x !== this.x || this.y !== e.y)
) {
e.atkBuff += enemy.together ?? 0;
e.defBuff += enemy.together ?? 0;
e.atkBuff_ += enemy.together ?? 0;
e.defBuff_ += enemy.together ?? 0;
}
});
this.providedHalo.push(8);
this.providedHalo.add(8);
}
// 冰封光环
@@ -460,7 +467,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
square7.push(e => {
e.damageDecline += this.enemy.iceHalo ?? 0;
});
this.providedHalo.push(21);
this.providedHalo.add(21);
col.haloList.push({
type: 'square',
data: { x: this.x, y: this.y, d: 7 },
@@ -472,9 +479,9 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
// 冰封之核
if (special.includes(26)) {
square5.push(e => {
e.defBuff += this.enemy.iceCore ?? 0;
e.defBuff_ += this.enemy.iceCore ?? 0;
});
this.providedHalo.push(26);
this.providedHalo.add(26);
col.haloList.push({
type: 'square',
data: { x: this.x, y: this.y, d: 5 },
@@ -486,9 +493,9 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
// 火焰之核
if (special.includes(27)) {
square5.push(e => {
e.atkBuff += this.enemy.fireCore ?? 0;
e.atkBuff_ += this.enemy.fireCore ?? 0;
});
this.providedHalo.push(27);
this.providedHalo.add(27);
col.haloList.push({
type: 'square',
data: { x: this.x, y: this.y, d: 5 },
@@ -617,7 +624,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
) {
damage[loc] ??= { damage: 0, type: new Set() };
damage[loc].damage += dam;
damage[loc].type.add(type);
if (type) damage[loc].type.add(type);
}
private calEnemyDamageOf(hero: Partial<HeroStatus>, enemy: EnemyInfo) {
@@ -830,6 +837,9 @@ const skills: [unlock: string, condition: string][] = [
['shieldOn', 'shield']
];
const haloValue: Map<number, SelectKey<Enemy, number | undefined>[]> =
new Map();
/**
* 计算怪物伤害
* @param info 怪物信息
@@ -946,13 +956,6 @@ export function getSingleEnemy(id: EnemyIds) {
}
declare global {
interface PluginDeclaration {
damage: {
Enemy: typeof DamageEnemy;
Collection: typeof EnemyCollection;
};
}
interface Floor {
enemy: EnemyCollection;
}
+31 -14
View File
@@ -84,14 +84,16 @@ export interface GameEvent extends EmitableEvent {
mounted: () => void;
/** Emitted in plugin/ui.js */
statusBarUpdate: () => void;
/** Emitted in libs/events.js */
afterGetItem: (
itemId: AllIdsOf<'items'>,
x: number,
y: number,
isGentleClick: boolean
) => void;
afterOpenDoor: (doorId: AllIdsOf<'animates'>, x: number, y: number) => void;
/** Emitted in core/index.ts */
renderLoaded: () => void;
// /** Emitted in libs/events.js */
// afterGetItem: (
// itemId: AllIdsOf<'items'>,
// x: number,
// y: number,
// isGentleClick: boolean
// ) => void;
// afterOpenDoor: (doorId: AllIdsOf<'animates'>, x: number, y: number) => void;
}
export const hook = new EventEmitter<GameEvent>();
@@ -112,7 +114,7 @@ class GameListener extends EventEmitter<ListenerEvent> {
constructor() {
super();
if (main.replayChecking) return;
if (!!window.core) {
this.init();
} else {
@@ -131,14 +133,19 @@ class GameListener extends EventEmitter<ListenerEvent> {
const getBlockLoc = (px: number, py: number, size: number) => {
return [
Math.floor(((px * 32) / size - core.bigmap.offsetX) / 32),
Math.floor(((py * 32) / size - core.bigmap.offsetY) / 32)
Math.floor(((px * 32) / size + core.bigmap.offsetX) / 32),
Math.floor(((py * 32) / size + core.bigmap.offsetY) / 32)
];
};
// hover & leave & mouseMove
data.addEventListener('mousemove', e => {
if (core.status.lockControl || !core.isPlaying()) return;
if (
core.status.lockControl ||
!core.isPlaying() ||
!core.status.floorId
)
return;
this.emit('mouseMove', e);
const {
x: px,
@@ -164,7 +171,12 @@ class GameListener extends EventEmitter<ListenerEvent> {
}
});
data.addEventListener('mouseleave', e => {
if (core.status.lockControl || !core.isPlaying()) return;
if (
core.status.lockControl ||
!core.isPlaying() ||
!core.status.floorId
)
return;
const blocks = core.getMapBlocksObj();
const lastBlock = blocks[`${lastHoverX},${lastHoverY}`];
if (!!lastBlock) {
@@ -175,7 +187,12 @@ class GameListener extends EventEmitter<ListenerEvent> {
});
// click
data.addEventListener('click', e => {
if (core.status.lockControl || !core.isPlaying()) return;
if (
core.status.lockControl ||
!core.isPlaying() ||
!core.status.floorId
)
return;
const {
x: px,
y: py,
+2 -6
View File
@@ -18,11 +18,7 @@ import type { Keyboard } from '@/core/main/custom/keyboard';
import type { CustomToolbar } from '@/core/main/custom/toolbar';
import type { Focus, GameUi, UiController } from '@/core/main/custom/ui';
import type { gameListener, hook } from './game';
import type {
MotaSetting,
SettingDisplayer,
SettingStorage
} from '@/core/main/setting';
import type { MotaSetting, SettingDisplayer } from '@/core/main/setting';
import type { GameStorage } from '@/core/main/storage';
import type { DamageEnemy, EnemyCollection } from './enemy/damage';
import type { specials } from './enemy/special';
@@ -87,7 +83,7 @@ interface VariableInterface {
sound: SoundController;
resource: ResourceStore<Exclude<ResourceType, 'zip'>>;
zipResource: ResourceStore<'zip'>;
settingStorage: GameStorage<SettingStorage>;
settingStorage: GameStorage;
status: Ref<boolean>;
// 定义于游戏进程,渲染进程依然可用
haloSpecials: number[];