mota-js/libs/enemys.js
2020-05-06 14:40:18 +08:00

373 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// <reference path="../runtime.d.ts" />
"use strict";
function enemys() {
this._init();
}
////// 初始化 //////
enemys.prototype._init = function () {
this.enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80;
this.enemydata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.enemys;
if (main.mode == 'play') {
this.enemydata.hasSpecial = function (a, b) {
return core.enemys.hasSpecial(a, b)
};
for (var enemyId in this.enemys) {
this.enemys[enemyId].id = enemyId;
}
}
}
enemys.prototype.getEnemys = function () {
var enemys = core.clone(this.enemys);
var enemyInfo = core.getFlag('enemyInfo');
if (enemyInfo) {
for (var id in enemyInfo) {
for (var name in enemyInfo[id]) {
enemys[id][name] = core.clone(enemyInfo[id][name]);
}
}
}
return enemys;
}
////// 判断是否含有某特殊属性 //////
enemys.prototype.hasSpecial = function (special, test) {
if (special == null) return false;
if (special instanceof Array) {
return special.indexOf(test) >= 0;
}
if (typeof special == 'number') {
return special === test;
}
if (typeof special == 'string') {
return this.hasSpecial(core.material.enemys[special], test);
}
if (special.special != null) {
return this.hasSpecial(special.special, test);
}
return false;
}
enemys.prototype.getSpecials = function () {
return this.enemydata.getSpecials();
}
////// 获得所有特殊属性的名称 //////
enemys.prototype.getSpecialText = function (enemy) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
if (!enemy) return [];
var special = enemy.special;
var text = [];
var specials = this.getSpecials();
if (specials) {
for (var i = 0; i < specials.length; i++) {
if (this.hasSpecial(special, specials[i][0]))
text.push(this._calSpecialContent(enemy, specials[i][1]));
}
}
return text;
}
////// 获得每个特殊属性的说明 //////
enemys.prototype.getSpecialHint = function (enemy, special) {
var specials = this.getSpecials();
if (special == null) {
if (specials == null) return [];
var hints = [];
for (var i = 0; i < specials.length; i++) {
if (this.hasSpecial(enemy, specials[i][0]))
hints.push(this._calSpecialContent(enemy, specials[i][1]) + "" + this._calSpecialContent(enemy, specials[i][2]));
}
return hints;
}
if (specials == null) return "";
for (var i = 0; i < specials.length; i++) {
if (special == specials[i][0])
return this._calSpecialContent(enemy, specials[i][1]) + "" + this._calSpecialContent(enemy, specials[i][2]);
}
return "";
}
enemys.prototype._calSpecialContent = function (enemy, content) {
if (typeof content == 'string') return content;
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
if (content instanceof Function) {
return content(enemy);
}
return "";
}
////// 能否获胜 //////
enemys.prototype.canBattle = function (enemy, x, y, floorId) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var damage = this.getDamage(enemy, x, y, floorId);
return damage != null && damage < core.status.hero.hp;
}
enemys.prototype.getDamageString = function (enemy, x, y, floorId) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var damage = this.getDamage(enemy, x, y, floorId);
var color = '#000000';
if (damage == null) {
damage = "???";
color = '#FF0000';
}
else {
if (damage <= 0) color = '#00FF00';
else if (damage < core.status.hero.hp / 3) color = '#FFFFFF';
else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00';
else if (damage < core.status.hero.hp) color = '#FF7F00';
else color = '#FF0000';
damage = core.formatBigNumber(damage, true);
if (core.enemys.hasSpecial(enemy, 19))
damage += "+";
if (core.enemys.hasSpecial(enemy, 21))
damage += "-";
if (core.enemys.hasSpecial(enemy, 11))
damage += "^";
}
return {
"damage": damage,
"color": color
};
}
////// 接下来N个临界值和临界减伤计算 //////
enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
number = number || 1;
if (this.hasSpecial(enemy.special, 10)) return []; // 模仿怪物临界
var info = this.getDamageInfo(enemy, null, x, y, floorId);
if (info == null || this.hasSpecial(enemy.special, 3)) { // 未破防,或是坚固怪
info = this.getEnemyInfo(enemy, null, x, y, floorId);
if (core.status.hero.atk <= info.def) {
return [[info.def + 1 - core.status.hero.atk, '?']];
}
return [];
}
// getDamageInfo直接返回数字0伤且无负伤
if (typeof info == 'number' || (info.damage <= 0 && !core.flags.enableNegativeDamage)) {
return [[0, 0]];
}
if (core.flags.useLoop) {
var LOOP_MAX_VALUE = 1;
if (core.status.hero.atk <= LOOP_MAX_VALUE) {
return this._nextCriticals_useLoop(enemy, info, number, x, y, floorId);
}
else {
return this._nextCriticals_useBinarySearch(enemy, info, number, x, y, floorId);
}
}
else {
return this._nextCriticals_useTurn(enemy, info, number, x, y, floorId);
}
}
enemys.prototype._nextCriticals_useLoop = function (enemy, info, number, x, y, floorId) {
var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, pre = info.damage;
var list = [];
for (var atk = hero_atk + 1; atk <= mon_hp + mon_def; atk++) {
var nextInfo = this.getDamageInfo(enemy, {"atk": atk}, x, y, floorId);
if (nextInfo == null || (typeof nextInfo == 'number')) break;
if (pre > nextInfo.damage) {
pre = nextInfo.damage;
list.push([atk - hero_atk, info.damage - nextInfo.damage]);
if (nextInfo.damage <= 0 && !core.flags.enableNegativeDamage) break;
if (list.length >= number) break;
}
}
if (list.length == 0) list.push([0, 0]);
return list;
}
enemys.prototype._nextCriticals_useBinarySearch = function (enemy, info, number, x, y, floorId) {
var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, pre = info.damage;
var list = [];
var calNext = function (currAtk, maxAtk) {
var start = Math.floor(currAtk), end = Math.floor(maxAtk);
if (start > end) return null;
while (start < end) {
var mid = Math.floor((start + end) / 2);
var nextInfo = core.enemys.getDamageInfo(enemy, {"atk": mid}, x, y, floorId);
if (nextInfo == null || (typeof nextInfo == 'number')) return null;
if (pre > nextInfo.damage) end = mid;
else start = mid + 1;
}
var nextInfo = core.enemys.getDamageInfo(enemy, {"atk": start}, x, y, floorId);
return nextInfo == null || (typeof nextInfo == 'number') || nextInfo.damage >= pre ? null : [start, nextInfo.damage];
}
var currAtk = hero_atk;
while (true) {
var next = calNext(currAtk + 1, mon_hp + mon_def, pre);
if (next == null) break;
currAtk = next[0];
pre = next[1];
list.push([currAtk - hero_atk, info.damage - pre]);
if (pre <= 0 && !core.flags.enableNegativeDamage) break;
if (list.length >= number) break;
}
if (list.length == 0) list.push([0, 0]);
return list;
}
enemys.prototype._nextCriticals_useTurn = function (enemy, info, number, x, y, floorId) {
var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, turn = info.turn;
// ------ 超大回合数强制使用二分算临界
// 以避免1攻10e回合2攻5e回合导致下述循环卡死问题
if (turn >= 1e6) { // 100w回合以上强制二分计算临界
return this._nextCriticals_useBinarySearch(enemy, info, number, x, y, floorId);
}
var list = [], pre = null;
for (var t = turn - 1; t >= 1; t--) {
var nextAtk = Math.ceil(mon_hp / t) + mon_def;
// 装备提升比例的计算临界
nextAtk = Math.ceil(nextAtk / core.getBuff('atk'));
if (nextAtk <= hero_atk) break;
if (nextAtk != pre) {
var nextInfo = this.getDamageInfo(enemy, {"atk": nextAtk}, x, y, floorId);
if (nextInfo == null || (typeof nextInfo == 'number')) break;
list.push([nextAtk - hero_atk, Math.floor(info.damage - nextInfo.damage)]);
if (nextInfo.damage <= 0 && !core.flags.enableNegativeDamage) break;
pre = nextAtk;
}
if (list.length >= number)
break;
}
if (list.length == 0) list.push([0, 0]);
return list;
}
////// N防减伤计算 //////
enemys.prototype.getDefDamage = function (enemy, k, x, y, floorId) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
k = k || 1;
var nowDamage = this._getDamage(enemy, null, x, y, floorId);
var nextDamage = this._getDamage(enemy, {"def": core.status.hero.def + k}, x, y, floorId);
if (nowDamage == null || nextDamage == null) return "???";
return nowDamage - nextDamage;
}
enemys.prototype.getEnemyInfo = function (enemy, hero, x, y, floorId) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
return this.enemydata.getEnemyInfo(enemy, hero, x, y, floorId)
}
////// 获得战斗伤害信息(实际伤害计算函数) //////
enemys.prototype.getDamageInfo = function (enemy, hero, x, y, floorId) {
// 移动到了脚本编辑 - getDamageInfo中
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
return this.enemydata.getDamageInfo(enemy, hero, x, y, floorId);
}
////// 获得在某个勇士属性下怪物伤害 //////
enemys.prototype.getDamage = function (enemy, x, y, floorId) {
return this._getDamage(enemy, null, x, y, floorId);
}
enemys.prototype._getDamage = function (enemy, hero, x, y, floorId) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var info = this.getDamageInfo(enemy, hero, x, y, floorId);
if (info == null) return null;
if (typeof info == 'number') return info;
return info.damage;
}
////// 获得当前楼层的怪物列表 //////
enemys.prototype.getCurrentEnemys = function (floorId) {
floorId = floorId || core.status.floorId;
var enemys = [], used = {};
var mapBlocks = core.status.maps[floorId].blocks;
for (var b = 0; b < mapBlocks.length; b++) {
if (!mapBlocks[b].disable && mapBlocks[b].event.cls.indexOf('enemy') == 0) {
this._getCurrentEnemys_addEnemy(mapBlocks[b].event.id, enemys, used, floorId);
}
}
return this._getCurrentEnemys_sort(enemys);
}
enemys.prototype._getCurrentEnemys_getEnemy = function (enemyId) {
var enemy = core.material.enemys[enemyId];
if (!enemy) return null;
// 检查displayIdInBook
return core.material.enemys[enemy.displayIdInBook] || enemy;
}
enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, floorId) {
var enemy = this._getCurrentEnemys_getEnemy(enemyId);
if (enemy == null || used[enemy.id]) return;
var enemyInfo = this.getEnemyInfo(enemy, null, null, null, floorId);
var specialText = core.enemys.getSpecialText(enemy);
if (specialText.length >= 3) specialText = "多属性...";
else specialText = specialText.join(" ");
var critical = this.nextCriticals(enemy, 1, null, null, floorId);
if (critical.length > 0) critical = critical[0];
var e = core.clone(enemy);
for (var x in enemyInfo) {
e[x] = enemyInfo[x];
}
e.specialText = specialText;
e.damage = this.getDamage(enemy, null, null, floorId);
e.critical = critical[0];
e.criticalDamage = critical[1];
e.defDamage = this.getDefDamage(enemy, 1, null, null, floorId);
enemys.push(e);
used[enemy.id] = true;
}
enemys.prototype._getCurrentEnemys_sort = function (enemys) {
return enemys.sort(function (a, b) {
if (a.damage == b.damage) {
return a.money - b.money;
}
if (a.damage == null) {
return 1;
}
if (b.damage == null) {
return -1;
}
return a.damage - b.damage;
});
}
enemys.prototype.hasEnemyLeft = function (enemyId, floorId) {
if (floorId == null) floorId = core.status.floorId;
if (!(floorId instanceof Array)) floorId = [floorId];
var enemyMap = {};
if (enemyId instanceof Array) enemyId.forEach(function(v) { enemyMap[v] = true;});
else if (enemyId) enemyMap[enemyId] = true;
else enemyMap = null;
for (var i = 0; i < floorId.length; i++) {
var mapBlocks = core.status.maps[floorId[i]].blocks;
for (var b = 0; b < mapBlocks.length; b++) {
if (!mapBlocks[b].disable && mapBlocks[b].event.cls.indexOf('enemy') === 0) {
if (enemyMap === null || enemyMap[mapBlocks[b].event.id]) return true;
}
}
}
return false;
}