修改勇士属性获取方式,实现勇士自动定位

This commit is contained in:
unanmed 2023-01-09 23:50:28 +08:00
parent a85cef79ec
commit 7465dd92c8
11 changed files with 319 additions and 138 deletions

View File

@ -3056,14 +3056,7 @@ control.prototype.getStatus = function (name) {
if (main.mode == 'editor' && !core.hasFlag('__statistics__')) {
return data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.hero[name];
}
if (name === 'atk' || name === 'def') {
return (
core.status.hero[name] +
(window.flags?.[`night_${core.status.floorId}`] ?? 0)
);
} else {
return core.status.hero[name];
}
return core.status.hero[name];
};
////// 从status中获得属性如果不存在则从勇士属性中获取 //////
@ -3079,9 +3072,7 @@ control.prototype.getRealStatus = function (name) {
////// 从status中获得实际属性增幅后的如果不存在则从勇士属性中获取 //////
control.prototype.getRealStatusOrDefault = function (status, name) {
return Math.floor(
this.getStatusOrDefault(status, name) * this.getBuff(name)
);
return core.getHeroStatusOf(status, name);
};
////// 获得勇士原始属性(无装备和衰弱影响) //////

View File

@ -517,6 +517,7 @@ enemys.prototype._getDamage = function (enemy, hero, x, y, floorId) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
if (enemy == null) return null;
if (x === 9 && y === 3) debugger;
var info = this.getDamageInfo(enemy, hero, x, y, floorId);
if (info == null) return null;
if (typeof info == 'number') return info;

View File

@ -282,7 +282,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"statusLeftBackground": "url(project/images/cave1.jpg)",
"statusTopBackground": "url(project/images/cave2.jpg) no-repeat",
"toolsBackground": "url(project/images/cave2.jpg) no-repeat",
"floorChangingStyle": "background-color: #000000;color:#000000",
"floorChangingStyle": " ",
"statusBarColor": [
255,
255,

View File

@ -61,7 +61,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
// 游戏获胜事件
// 请注意成绩统计时是按照hp进行上传并排名
// 可以先在这里对最终分数进行计算比如将2倍攻击和5倍黄钥匙数量加到分数上
// core.status.hero.hp += 2 * core.getRealStatus('atk') + 5 * core.itemCount('yellowKey');
// 如果不退出,则临时存储数据
if (noexit) {
@ -648,11 +647,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
core.formatBigNumber(
Math.max(
(enemy.value || 0) -
core.getRealStatusOrDefault(
null,
'def'
),
0
core.getHeroStatusOn('def')
)
) +
'点伤害'
@ -762,10 +757,19 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
// floorId该怪物所在的楼层
// 后面三个参数主要是可以在光环等效果上可以适用(也可以按需制作部分范围光环效果)
floorId = floorId || core.status.floorId;
var hero_hp = core.getRealStatusOrDefault(hero, 'hp'),
hero_atk = core.getRealStatusOrDefault(hero, 'atk'),
hero_def = core.getRealStatusOrDefault(hero, 'def'),
hero_mdef = core.getRealStatusOrDefault(hero, 'mdef');
let {
atk: hero_atk,
def: hero_def,
mdef: hero_mdef,
hp: hero_hp
} = core.getHeroStatusOf(
hero,
['atk', 'def', 'mdef', 'hp'],
hero?.x,
hero?.y,
floorId
);
var mon_hp = core.getEnemyValue(enemy, 'hp', x, y, floorId),
mon_atk = core.getEnemyValue(enemy, 'atk', x, y, floorId),
@ -793,7 +797,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
}
// 智慧之源
if (core.hasSpecial(mon_special, 14) && flags.hard == 2) {
if (core.hasSpecial(mon_special, 14) && flags.hard === 2) {
mon_atk += core.getFlag('inte_' + floorId, 0);
}
@ -906,13 +910,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
mon_def *= 1 + def_buff / 100;
}
// TODO可以在这里新增其他的怪物数据变化
// 比如仿攻(怪物攻击不低于勇士攻击):
// if (core.hasSpecial(mon_special, 27) && mon_atk < hero_atk) {
// mon_atk = hero_atk;
// }
// 也可以按需增加各种自定义内容
return {
hp: Math.floor(mon_hp),
atk: Math.floor(mon_atk),
@ -936,19 +933,62 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
// 后面三个参数主要是可以在光环等效果上可以适用
floorId = floorId || core.status.floorId;
function getDamage() {
let hero_hp = core.getRealStatusOrDefault(hero, 'hp'),
hero_atk = core.getRealStatusOrDefault(hero, 'atk'),
hero_def = core.getRealStatusOrDefault(hero, 'def'),
hero_IQ = core.getRealStatusOrDefault(hero, 'mdef'),
hero_recovery = core.getRealStatusOrDefault(hero, 'hpmax'),
hero_extraAtk = core.getRealStatusOrDefault(hero, 'mana'),
origin_hero_hp = core.getStatusOrDefault(hero, 'hp'),
origin_hero_atk = core.getStatusOrDefault(hero, 'atk'),
origin_hero_def = core.getStatusOrDefault(hero, 'def');
// 勇士位置应该在这里进行计算,四个位置依次遍历,去重
let toMap = [];
if (
x !== null &&
x !== void 0 &&
y !== null &&
y !== void 0 &&
floorId !== null &&
floorId !== void 0 &&
flags.autoLocate &&
flags.chapter >= 2
) {
const floor = core.status.maps[floorId];
// 存在坐标,进行遍历
for (const [dir, { x: dx, y: dy }] of Object.entries(
core.utils.scan
)) {
// 只有攻击和防御和特殊光环需要注意,其他的一般都不会随楼层与坐标变化
const nx = x + dx;
const ny = y + dy;
if (
nx < 0 ||
nx >= floor.width ||
ny < 0 ||
ny >= floor.height
) {
continue;
}
if (
core.noPass(nx, ny) ||
!core.canMoveHero(nx, ny, core.backDir(dir), floorId)
) {
continue;
}
const toGet = ['atk', 'def'];
const status = core.getHeroStatusOf(
hero,
toGet,
x,
y,
floorId
);
if (
toMap.some(v =>
toGet.every(vv => v[1][vv] === status[vv])
)
) {
continue;
}
toMap.push([dir, Object.assign({}, status, { x, y })]);
}
} else {
toMap = [['none', core.getHeroStatusOf(hero, ['atk', 'def'])]];
}
// 怪物的各项数据
// 对坚固模仿等处理扔到了脚本编辑-getEnemyInfo之中
function getDamage(h) {
const enemyInfo = core.enemys.getEnemyInfo(
enemy,
hero,
@ -957,10 +997,18 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
floorId
);
let mon_hp = enemyInfo.hp,
mon_atk = enemyInfo.atk,
mon_def = enemyInfo.def,
mon_special = enemyInfo.special;
let {
hp: mon_hp,
atk: mon_atk,
def: mon_def,
special: mon_special
} = enemyInfo;
let { atk: hero_atk, def: hero_def } = h;
let hero_hp = core.getRealStatusOrDefault(hero, 'hp'),
hero_IQ = core.getRealStatusOrDefault(hero, 'mdef'),
hero_recovery = core.getRealStatusOrDefault(hero, 'hpmax'),
hero_extraAtk = core.getRealStatusOrDefault(hero, 'mana');
let damage = 0;
@ -1045,52 +1093,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
turn += 5;
}
// ------ 支援 ----- //
// 这个递归最好想明白为什么flag:__extraTurn__是怎么用的
const guards = core.getFlag(
'__guards__' + x + '_' + y,
enemyInfo.guards
);
const guard_before_current_enemy = true; // ------ 支援怪是先打(true)还是后打(false)
turn += core.getFlag('__extraTurn__', 0);
if (guards.length > 0) {
if (!guard_before_current_enemy) {
// --- 先打当前怪物,记录当前回合数
core.setFlag('__extraTurn__', turn);
}
// 获得那些怪物组成小队战斗
for (var i = 0; i < guards.length; i++) {
var gx = guards[i][0],
gy = guards[i][1],
gid = guards[i][2];
// 递归计算支援怪伤害信息这里不传x,y保证不会重复调用
// 这里的mdef传0因为护盾应该只会被计算一次
var info = core.enemys.getDamageInfo(
core.material.enemys[gid],
{
hp: origin_hero_hp,
atk: origin_hero_atk,
def: origin_hero_def,
mdef: 0
}
);
if (info == null) {
// 小队中任何一个怪物不可战斗直接返回null
core.removeFlag('__extraTurn__');
return null;
}
// 已经进行的回合数
core.setFlag('__extraTurn__', info.turn);
init_damage += info.damage;
}
if (guard_before_current_enemy) {
// --- 先打支援怪物,增加当前回合数
turn += core.getFlag('__extraTurn__', 0);
}
}
core.removeFlag('__extraTurn__');
// ------ 支援END ------ //
// 最终伤害:初始伤害 + 怪物对勇士造成的伤害 + 反击伤害
damage += init_damage + (turn - 1) * per_damage;
// 无上之盾
@ -1113,34 +1115,55 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
};
}
let damageInfo = null;
let damage = Infinity;
const skills = [
['bladeOn', 'blade'],
['shieldOn', 'shield']
];
damageInfo = getDamage();
if (damageInfo) damage = damageInfo.damage;
if (flags.autoSkill) {
for (const [unlock, condition] of skills) {
if (flags[unlock]) {
flags[condition] = true;
const info = getDamage();
const d = info?.damage;
if (d !== null && d !== void 0) {
if (d < damage) {
damage = d;
damageInfo = info;
function autoSkillOf(h) {
if (flags.autoSkill) {
for (const [unlock, condition] of skills) {
if (flags[unlock]) {
flags[condition] = true;
const info = getDamage(h);
const d = info?.damage;
if (d !== null && d !== void 0) {
if (d < damage) {
damage = d;
damageInfo = info;
}
}
flags[condition] = false;
}
flags[condition] = false;
}
} else {
damageInfo = getDamage(h);
if (damageInfo) damage = damageInfo.damage;
}
}
let damageInfo = null;
let damage = Infinity;
if (!flags.autoLocate) {
autoSkillOf(toMap[0][1]);
return damageInfo;
}
if (toMap.length === 1) {
// 单个与多个分开计算,有助于提高性能表现
const h = toMap[0][1];
autoSkillOf(h);
if (damageInfo) {
return Object.assign(damageInfo, { dir: toMap[0][0] });
} else return null;
} else {
return getDamage();
for (const [dir, h] of toMap) {
autoSkillOf(h);
if (damageInfo) {
return Object.assign(damageInfo, { dir });
} else return null;
}
}
}
},

View File

@ -1416,7 +1416,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
// 获取宝石信息 并绘制
this.getItemDetail = function (floorId) {
if (!core.getFlag('itemDetail')) return;
floorId = floorId ?? core.status.thisMap.floorId;
floorId ??= core.status.thisMap.floorId;
let diff = {};
const before = core.status.hero;
const hero = core.clone(core.status.hero);
@ -4306,24 +4306,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
}
};
/**
* 滑动数组
* @param {any[]} arr
* @param {number} delta
*/
this.slide = function (arr, delta) {
if (delta === 0) return arr;
delta %= arr.length;
if (delta > 0) {
arr.unshift(...arr.splice(arr.length - delta, delta));
return arr;
}
if (delta < 0) {
arr.push(...arr.splice(0, -delta));
return arr;
}
};
/**
* 移动地图
* @param {number} delta
@ -4642,5 +4624,92 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
}
ctx.restore();
};
},
hero: function () {
/**
* 获取勇士在某一点的属性
* @param {keyof HeroStatus | 'all'} name
* @param {number} x
* @param {number} y
* @param {FloorIds} floorId
*/
this.getHeroStatusOn = function (name, x, y, floorId) {
return this.getRealStatusOf(core.status.hero, name, x, y, floorId);
};
this.getHeroStatusOf = function (status, name, x, y, floorId) {
return getRealStatus(status, name, x, y, floorId);
};
function getRealStatus(status, name, x, y, floorId) {
if (name instanceof Array) {
return Object.fromEntries(
name.map(v => [
v,
v !== 'all' && getRealStatus(status, v, x, y, floorId)
])
);
}
if (name === 'all') {
return Object.fromEntries(
Object.keys(core.status.hero).map(v => [
v,
v !== 'all' && getRealStatus(status, v, x, y, floorId)
])
);
}
let s = status?.[name] ?? core.status.hero[name];
if (s === null || s === void 0) {
throw new ReferenceError(
`Wrong hero status property name is delivered: ${name}`
);
}
x ??= core.status.hero.loc.x;
y ??= core.status.hero.loc.y;
floorId ??= core.status.floorId;
// 永夜、极昼
if (name === 'atk' || name === 'def') {
s += window.flags?.[`night_${floorId}`] ?? 0;
}
// buff
if (typeof s === 'number') s *= core.getBuff(name);
// 取整
if (typeof s === 'number') s = Math.floor(s);
return s;
}
},
pluginUtils: function () {
/**
* 滑动数组
* @param {any[]} arr
* @param {number} delta
*/
this.slide = function (arr, delta) {
if (delta === 0) return arr;
delta %= arr.length;
if (delta > 0) {
arr.unshift(...arr.splice(arr.length - delta, delta));
return arr;
}
if (delta < 0) {
arr.push(...arr.splice(0, -delta));
return arr;
}
};
this.backDir = function (dir) {
return {
up: 'down',
down: 'up',
left: 'right',
right: 'left'
}[dir];
};
}
};

View File

@ -261,7 +261,7 @@ span#hard {
position: absolute;
text-align: center;
display: none;
color: #fff;
color: transparent;
background-color: #000;
z-index: 230;
user-select: none;

View File

@ -43,6 +43,13 @@
"注当鼠标移动到怪物上时经过200毫秒才会显示信息防止误操作。"
]
},
"autoLocate": {
"text": "自动勇士定位",
"desc": [
"此项会在进入第二章后会起作用。开启后,当勇士处于不同位置打同一个怪物伤害不同时,在地图上使用绿色箭头标出伤害最低的位置,",
"使用红色箭头标出伤害较高的位置,在自动寻路中选择伤害最低的位置。"
]
},
"showStudied": {
"text": "展示已学习技能",
"desc": [

View File

@ -35,6 +35,11 @@ export const showStudied = ref(true);
*/
export const useFixed = ref(true);
/**
* 使
*/
export const autoLocate = ref(true);
watch(transition, n => {
core.plugin.transition.value = n;
core.setLocalStorage('transition', n);
@ -67,6 +72,12 @@ watch(useFixed, n => {
core.setLocalStorage('useFixed', n);
});
watch(autoSkill, n => {
flags.autoLocate = n;
core.updateStatusBar();
core.status.route.push(`set:autoLocate:${n}`);
});
/**
* localStorage读取即可
*/
@ -82,9 +93,11 @@ function reset() {
function resetFlag() {
flags.autoSkill ??= true;
flags.itemDetail ??= true;
flags.autoLocate ??= true;
itemDetail.value = flags.itemDetail ? true : false;
autoSkill.value = flags.autoSkill ? true : false;
autoLocate.value = flags.autoLocate ? true : false;
}
export default function init() {

View File

@ -1,5 +1,5 @@
import { sleep } from 'mutate-animate';
import { Component, markRaw, ref, Ref, watch } from 'vue';
import { Component, markRaw, ref, Ref, shallowReactive, watch } from 'vue';
import Book from '../ui/book.vue';
import Toolbox from '../ui/toolbox.vue';
import Equipbox from '../ui/equipbox.vue';
@ -41,21 +41,22 @@ const UI_LIST: [Ref<boolean>, Component][] = [
];
/** ui栈 */
export const uiStack = ref<Component[]>([]);
export const uiStack = shallowReactive<Component[]>([]);
export default function init() {
app = document.getElementById('root') as HTMLDivElement;
UI_LIST.forEach(([ref, com]) => {
watch(ref, n => {
if (n === true) {
uiStack.value.push(markRaw(com));
uiStack.push(markRaw(com));
showApp();
} else {
const index = uiStack.value.findIndex(v => v === com);
if (uiStack.value.length === 1) {
const index = uiStack.findIndex(v => v === com);
if (index === -1) return;
if (uiStack.length === 1) {
hideApp(index);
} else {
uiStack.value.splice(index, 1);
uiStack.splice(index, 1);
}
}
});
@ -98,7 +99,7 @@ async function hideApp(index: number) {
app.style.transition = '';
app.style.opacity = '0';
}
uiStack.value.splice(index, 1);
uiStack.splice(index, 1);
app.style.display = 'none';
if (!noClosePanel.value) core.closePanel();
noClosePanel.value = false;

67
src/types/plugin.d.ts vendored
View File

@ -19,7 +19,8 @@ interface PluginDeclaration
PluginUis,
PluginUse,
SkillTree,
MiniMap {
MiniMap,
HeroRealStatus {
/**
* 使core.addPop或core.plugin.addPop调用
* @param px
@ -127,6 +128,12 @@ interface PluginUtils {
* @param delta
*/
slide<T>(arr: T[], delta: number): T[];
/**
*
* @param dir
*/
backDir(dir: Dir): Dir;
}
interface PluginUis {
@ -300,6 +307,64 @@ interface Study {
studySkill(enemy: Enemy, num: number): void;
}
interface HeroRealStatus {
/**
*
* @param name
* @param x
* @param y
* @param floorId
*/
getHeroStatusOn(
name: 'all',
x?: number,
y?: number,
floorId?: FloorIds
): HeroStatus;
getHeroStatusOn(
name: (keyof HeroStatus)[],
x?: number,
y?: number,
floorId?: FloorIds
): Partial<HeroStatus>;
getHeroStatusOn<K extends keyof HeroStatus>(
name: K,
x?: number,
y?: number,
floorId?: FloorIds
): HeroStatus[K];
/**
*
* @param status
* @param name
* @param x
* @param y
* @param floorId
*/
getHeroStatusOf(
status: Partial<HeroStatus>,
name: 'all',
x?: number,
y?: number,
floorId?: FloorIds
): HeroStatus;
getHeroStatusOf(
status: Partial<HeroStatus>,
name: (keyof HeroStatus)[],
x?: number,
y?: number,
floorId?: FloorIds
): Partial<HeroStatus>;
getHeroStatusOf<K extends keyof HeroStatus>(
status: Partial<HeroStatus>,
name: K,
x?: number,
y?: number,
floorId?: FloorIds
): HeroStatus[K];
}
type Chapter = 'chapter1' | 'chapter2';
interface Skill {

View File

@ -50,6 +50,14 @@
useFixed ? 'ON' : 'OFF'
}}</span
>
<span
class="selectable"
:selected="selected === 'autoLocate'"
@click="click('autoLocate')"
>勇士自动定位:&nbsp;&nbsp;&nbsp;{{
autoLocate ? 'ON' : 'OFF'
}}</span
>
<span
class="selectable"
:selected="selected === 'showStudied'"
@ -74,7 +82,8 @@ import {
autoScale,
showStudied,
showHalo,
useFixed
useFixed,
autoLocate
} from '../plugin/settings';
import settingInfo from '../data/settings.json';
import { has, splitText } from '../plugin/utils';
@ -113,6 +122,8 @@ function click(id: keyof Settings) {
showStudied.value = !showStudied.value;
} else if (id === 'useFixed') {
useFixed.value = !useFixed.value;
} else if (id === 'autoLocate') {
autoLocate.value = !autoLocate.value;
}
}
</script>