| @@ -271,6 +271,43 @@ | |||
| content: " sec"; | |||
| } | |||
| .dialog-hp-detail .dialog-title::before | |||
| { | |||
| content: "HP Range Reduction Details"; | |||
| } | |||
| .hp-range-table .hp-range th::before | |||
| { | |||
| content: "HP Range"; | |||
| } | |||
| .hp-range-table .reduce-scale .reduce-probability:before | |||
| { | |||
| content: "Odds "; | |||
| } | |||
| .hp-range-table caption::before | |||
| { | |||
| content: "All Attribute Enemy"; | |||
| } | |||
| .hp-range-table[data-attr="0"] caption::before | |||
| { | |||
| content: "Fire Attribute Enemy"; | |||
| } | |||
| .hp-range-table[data-attr="1"] caption::before | |||
| { | |||
| content: "Water Attribute Enemy"; | |||
| } | |||
| .hp-range-table[data-attr="2"] caption::before | |||
| { | |||
| content: "Wood Attribute Enemy"; | |||
| } | |||
| .hp-range-table[data-attr="3"] caption::before | |||
| { | |||
| content: "Light Attribute Enemy"; | |||
| } | |||
| .hp-range-table[data-attr="4"] caption::before | |||
| { | |||
| content: "Dark Attribute Enemy"; | |||
| } | |||
| .setting-box .row-mon-id .open-search::before{ | |||
| content: "Simple Search"; | |||
| } | |||
| @@ -263,6 +263,43 @@ | |||
| content: " 秒"; | |||
| } | |||
| .dialog-hp-detail .dialog-title::before | |||
| { | |||
| content: "HP 範囲減傷の詳細"; | |||
| } | |||
| .hp-range-table .hp-range th::before | |||
| { | |||
| content: "HP 範囲"; | |||
| } | |||
| .hp-range-table .reduce-scale .reduce-probability:before | |||
| { | |||
| content: "確率 "; | |||
| } | |||
| .hp-range-table caption::before | |||
| { | |||
| content: "すべての属性の敵"; | |||
| } | |||
| .hp-range-table[data-attr="0"] caption::before | |||
| { | |||
| content: "火属性の敵"; | |||
| } | |||
| .hp-range-table[data-attr="1"] caption::before | |||
| { | |||
| content: "水属性の敵"; | |||
| } | |||
| .hp-range-table[data-attr="2"] caption::before | |||
| { | |||
| content: "木属性の敵"; | |||
| } | |||
| .hp-range-table[data-attr="3"] caption::before | |||
| { | |||
| content: "光属性の敵"; | |||
| } | |||
| .hp-range-table[data-attr="4"] caption::before | |||
| { | |||
| content: "暗属性の敵"; | |||
| } | |||
| .setting-box .row-mon-id .open-search::before{ | |||
| content: "簡単な検索"; | |||
| } | |||
| @@ -260,6 +260,43 @@ | |||
| content: " 초"; | |||
| } | |||
| .dialog-hp-detail .dialog-title::before | |||
| { | |||
| content: "HP 범위 손상 감소 세부 정보"; | |||
| } | |||
| .hp-range-table .hp-range th::before | |||
| { | |||
| content: "HP 범위"; | |||
| } | |||
| .hp-range-table .reduce-scale .reduce-probability:before | |||
| { | |||
| content: "확률 "; | |||
| } | |||
| .hp-range-table caption::before | |||
| { | |||
| content: "모든 속성의 적"; | |||
| } | |||
| .hp-range-table[data-attr="0"] caption::before | |||
| { | |||
| content: "화재 속성의 적"; | |||
| } | |||
| .hp-range-table[data-attr="1"] caption::before | |||
| { | |||
| content: "물 속성의 적"; | |||
| } | |||
| .hp-range-table[data-attr="2"] caption::before | |||
| { | |||
| content: "나무 속성의 적"; | |||
| } | |||
| .hp-range-table[data-attr="3"] caption::before | |||
| { | |||
| content: "빛의 속성의 적"; | |||
| } | |||
| .hp-range-table[data-attr="4"] caption::before | |||
| { | |||
| content: "숨겨진 속성의 적"; | |||
| } | |||
| .setting-box .row-mon-id .open-search::before{ | |||
| content: "간단한 검색"; | |||
| } | |||
| @@ -36,9 +36,9 @@ function findFullSkill(subSkill) { | |||
| } | |||
| //document.querySelector(".edit-box .row-mon-id .m-id").type = "number"; | |||
| /* 快速搜索指定类型的技能 | |||
| var result = Skills.filter(s=>{const sk = s.params; return s.type == 156;}).map(findFullSkill); | |||
| console.table(result); | |||
| var result = Skills.filter(s=>{const sk = s.params; return [130,131].includes(s.type);}).map(findFullSkill); | |||
| showSearch(result.map(o=>o.card).filter(c=>c)); | |||
| console.table(result); | |||
| */ | |||
| //返回flag里值为true的数组,如[1,4,7] | |||
| @@ -266,6 +266,43 @@ | |||
| content: " 秒"; | |||
| } | |||
| .dialog-hp-detail .dialog-title::before | |||
| { | |||
| content: "HP 階段減傷詳情"; | |||
| } | |||
| .hp-range-table .hp-range th::before | |||
| { | |||
| content: "HP 範圍"; | |||
| } | |||
| .hp-range-table .reduce-scale .reduce-probability:before | |||
| { | |||
| content: "幾率 "; | |||
| } | |||
| .hp-range-table caption::before | |||
| { | |||
| content: "全屬性敵人"; | |||
| } | |||
| .hp-range-table[data-attr="0"] caption::before | |||
| { | |||
| content: "火屬性敵人"; | |||
| } | |||
| .hp-range-table[data-attr="1"] caption::before | |||
| { | |||
| content: "水屬性敵人"; | |||
| } | |||
| .hp-range-table[data-attr="2"] caption::before | |||
| { | |||
| content: "木屬性敵人"; | |||
| } | |||
| .hp-range-table[data-attr="3"] caption::before | |||
| { | |||
| content: "光屬性敵人"; | |||
| } | |||
| .hp-range-table[data-attr="4"] caption::before | |||
| { | |||
| content: "暗屬性敵人"; | |||
| } | |||
| .setting-box .row-mon-id .open-search::before{ | |||
| content: "簡易搜索"; | |||
| } | |||
| @@ -265,6 +265,43 @@ | |||
| content: " 秒"; | |||
| } | |||
| .dialog-hp-detail .dialog-title::before | |||
| { | |||
| content: "HP 階段減傷詳情"; | |||
| } | |||
| .hp-range-table .hp-range th::before | |||
| { | |||
| content: "HP 范围"; | |||
| } | |||
| .hp-range-table .reduce-scale .reduce-probability:before | |||
| { | |||
| content: "几率 "; | |||
| } | |||
| .hp-range-table caption::before | |||
| { | |||
| content: "全属性敵人"; | |||
| } | |||
| .hp-range-table[data-attr="0"] caption::before | |||
| { | |||
| content: "火属性敵人"; | |||
| } | |||
| .hp-range-table[data-attr="1"] caption::before | |||
| { | |||
| content: "水属性敵人"; | |||
| } | |||
| .hp-range-table[data-attr="2"] caption::before | |||
| { | |||
| content: "木属性敵人"; | |||
| } | |||
| .hp-range-table[data-attr="3"] caption::before | |||
| { | |||
| content: "光属性敵人"; | |||
| } | |||
| .hp-range-table[data-attr="4"] caption::before | |||
| { | |||
| content: "暗属性敵人"; | |||
| } | |||
| .setting-box .row-mon-id .open-search::before{ | |||
| content: "简易搜索"; | |||
| } | |||
| @@ -83,6 +83,7 @@ var formation = new Formation(teamsCount,5); | |||
| <span class="reduce-scale"></span> | |||
| <span class="general"></span> | |||
| <span class="awoken-bind"></span> | |||
| <canvas height="20" width="100" class="reduce-details display-none"></canvas> | |||
| </span> | |||
| </div> | |||
| <div class="tIf-effect"> | |||
| @@ -596,6 +597,11 @@ var formation = new Formation(teamsCount,5); | |||
| </ul> | |||
| </div> | |||
| <div class="detail-box edit"><textarea class="detail" placeholder="输入说明"></textarea><div class="detail-display"></div></div> | |||
| <div class="dialog dialog-hp-detail display-none"> | |||
| <div class="dialog-title"></div> | |||
| <div class="dialog-content"></div> | |||
| <div class="dialog-control"><button class="dialog-close brown-button"></button></div> | |||
| </div> | |||
| </div> | |||
| <div class="edit-box display-none"> | |||
| <div class="edit-box-title"><!--修改怪物--></div> | |||
| @@ -52,10 +52,20 @@ Number.prototype.prefixInteger = function(length, useGrouping = false) { | |||
| minimumIntegerDigits: length | |||
| }); | |||
| } | |||
| //大数字缩短长度,默认返回本地定义字符串 | |||
| //大数字缩短长度,默认返回本地定义字符串 | |||
| Number.prototype.bigNumberToString = function() { | |||
| return this.toLocaleString(); | |||
| } | |||
| //将二进制flag转为数组 | |||
| function flags(num) { | |||
| const arr = []; | |||
| for (let i = 0; i < 32; i++) { | |||
| if (num & (1 << i)) { | |||
| arr.push(i); | |||
| } | |||
| } | |||
| return arr; | |||
| } | |||
| //数组删除自己尾部的空元素 | |||
| Array.prototype.DeleteLatter = function(item = null) { | |||
| @@ -553,15 +563,6 @@ function countTeamHp(memberArr, leader1id, leader2id, solo, noAwoken = false) { | |||
| //console.log('单个队伍血量:',mHpArr,mHpArr.reduce((p,c)=>p+c)); | |||
| function memberHpMul(card, ls, memberArr, solo) { | |||
| function flags(num) { | |||
| const arr = []; | |||
| for (let i = 0; i < 32; i++) { | |||
| if (num & (1 << i)) { | |||
| arr.push(i); | |||
| } | |||
| } | |||
| return arr; | |||
| } | |||
| function hpMul(parm, scale) { | |||
| if (scale == undefined || scale == 0) return 1; | |||
| @@ -842,8 +843,75 @@ function countMoveTime(team, leader1id, leader2id, teamIdx) { | |||
| return moveTime; | |||
| } | |||
| //获取盾减伤比例 | |||
| function getReduceScale(leaderid, allAttr = false, noHPneed = false, noProbability = false) { | |||
| //将盾减伤比例组叠加为一个减伤范围组 | |||
| function getReduceRange(reduceScales) | |||
| { | |||
| class reduceRange{ | |||
| constructor(obj) | |||
| { | |||
| this.min = 0; | |||
| this.max = 100; | |||
| this.scale = 0; | |||
| this.probability = 1; | |||
| if (typeof obj == "object") Object.assign(this, obj); | |||
| } | |||
| } | |||
| const ranges = [new reduceRange()]; | |||
| const attrsRanges = new Array(5).fill(ranges); //5中属性的,默认填充第一个ranges的指针 | |||
| function processingRanges(ranges, scale) | |||
| { | |||
| //先找scale.min在某个范围内的 | |||
| const rgLessIdx = ranges.findIndex(range=>scale.hp.min > range.min && scale.hp.min < range.max), | |||
| //再找scale.max在某个范围内的 | |||
| rgMoreIdx = ranges.findIndex(range=>scale.hp.max > range.min && scale.hp.max < range.max); | |||
| //先只拆分不乘比例 | |||
| if (rgLessIdx >= 0) | |||
| { | |||
| const range = ranges[rgLessIdx]; | |||
| ranges.splice(rgLessIdx, 1, | |||
| new reduceRange({min:range.min, max:scale.hp.min, scale: range.scale}), | |||
| new reduceRange({min:scale.hp.min, max:range.max, scale: range.scale}) | |||
| ); | |||
| } | |||
| if (rgMoreIdx >= 0) | |||
| { | |||
| const range = ranges[rgMoreIdx]; | |||
| ranges.splice(rgMoreIdx, 1, | |||
| new reduceRange({min:range.min, max:scale.hp.max, scale: range.scale}), | |||
| new reduceRange({min:scale.hp.max, max:range.max, scale: range.scale}) | |||
| ); | |||
| } | |||
| const needChangeScaleRanges = ranges.filter(range=>range.min >= scale.hp.min && range.max <= scale.hp.max); | |||
| needChangeScaleRanges.forEach(range=>{ | |||
| range.scale = 1 - (1 - range.scale) * (1 - scale.scale); | |||
| range.probability *= scale.probability; | |||
| }); | |||
| } | |||
| //对scale进行排序,将所有全属性减伤的靠前,部分属性的靠后,这样前面的就只需要计算一次,后面的计算多次 | |||
| reduceScales.sort((a,b)=>b.attrs - a.attrs); | |||
| reduceScales.forEach(scale=>{ | |||
| if (scale.attrs == 0) //没有属性的 | |||
| { | |||
| return; | |||
| } | |||
| else if ((scale.attrs & 31) != 31) //不符合全属性的 | |||
| { | |||
| const attrs = flags(scale.attrs); //得到属性数组 | |||
| attrs.forEach(n=>{ | |||
| attrsRanges[n] = attrsRanges[n].map(range=>new reduceRange(range)); //复制一个新数组 | |||
| processingRanges(attrsRanges[n], scale); //计算这个数组的减伤比例 | |||
| }); | |||
| } | |||
| else | |||
| { //只处理第一数组 | |||
| processingRanges(ranges, scale); | |||
| } | |||
| }); | |||
| return attrsRanges; | |||
| } | |||
| //获取盾减伤比例组 | |||
| function getReduceScales(leaderid) { | |||
| const searchTypeArray = [16, 17, 36, 38, 43, 129, 163, 130, 131, 151, 169, 198, 170, 182, 193, 171, 183]; | |||
| const lss = getCardLeaderSkills(Cards[leaderid], searchTypeArray); | |||
| @@ -865,11 +933,11 @@ function getReduceScale(leaderid, allAttr = false, noHPneed = false, noProbabili | |||
| break; | |||
| case 17: //单属性盾 | |||
| reduce.scale = sk[1] / 100; | |||
| reduce.attr = 0 | sk[0] >= 0 ? 1 << sk[0] : 0; | |||
| reduce.attrs = 0 | (sk[0] >= 0 ? 1 << sk[0] : 0); | |||
| break; | |||
| case 36: //2个属性盾 | |||
| reduce.scale = sk[2] / 100; | |||
| reduce.attr = 0 | sk[0] >= 0 ? 1 << sk[0] : 0 | sk[1] >= 0 ? 1 << sk[1] : 0; | |||
| reduce.attrs = 0 | (sk[0] >= 0 ? 1 << sk[0] : 0) | (sk[1] >= 0 ? 1 << sk[1] : 0); | |||
| break; | |||
| case 38: //血线下 + 可能几率 | |||
| case 43: //血线上 + 可能几率 | |||
| @@ -884,11 +952,11 @@ function getReduceScale(leaderid, allAttr = false, noHPneed = false, noProbabili | |||
| if(ls.type == 38) | |||
| { | |||
| reduce.hp.max = sk[0]; | |||
| reduce.hp.mix = 0; | |||
| reduce.hp.min = 0; | |||
| }else | |||
| { | |||
| reduce.hp.max = 100; | |||
| reduce.hp.mix = sk[0]; | |||
| reduce.hp.min = sk[0]; | |||
| } | |||
| } | |||
| break; | |||
| @@ -897,7 +965,7 @@ function getReduceScale(leaderid, allAttr = false, noHPneed = false, noProbabili | |||
| case 130: //血线下 + 属性个数不固定 | |||
| case 131: //血线上 + 属性个数不固定 | |||
| reduce.scale = (sk[6] || 0) / 100; | |||
| reduce.attr = 0 | sk[5]; | |||
| reduce.attrs = 0 | sk[5]; | |||
| if (ls.type == 130 || ls.type == 131) | |||
| { | |||
| if (sk[0] == 100) | |||
| @@ -909,11 +977,11 @@ function getReduceScale(leaderid, allAttr = false, noHPneed = false, noProbabili | |||
| if(ls.type == 130) | |||
| { | |||
| reduce.hp.max = sk[0]; | |||
| reduce.hp.mix = 0; | |||
| reduce.hp.min = 0; | |||
| }else | |||
| { | |||
| reduce.hp.max = 100; | |||
| reduce.hp.mix = sk[0]; | |||
| reduce.hp.min = sk[0]; | |||
| } | |||
| } | |||
| } | |||
| @@ -940,62 +1008,12 @@ function getReduceScale(leaderid, allAttr = false, noHPneed = false, noProbabili | |||
| }else | |||
| { | |||
| reduce.hp.max = 100; | |||
| reduce.hp.mix = sk[2]; | |||
| reduce.hp.min = sk[2]; | |||
| } | |||
| break; | |||
| default: | |||
| } | |||
| return reduce; | |||
| } | |||
| return lss.map(leaderReduceScale); | |||
| const sk = ls.params; | |||
| let scale = 0; | |||
| const skills = getActuallySkills(ls); | |||
| switch (ls.type) { | |||
| case 16: //无条件盾 | |||
| scale = sk[0] / 100; | |||
| break; | |||
| case 17: //单属性盾 | |||
| scale = allAttr ? 0 : sk[1] / 100; | |||
| break; | |||
| case 36: //2个属性盾 | |||
| scale = allAttr ? 0 : sk[2] / 100; | |||
| break; | |||
| case 38: //血线下 + 可能几率 | |||
| case 43: //血线上 + 可能几率 | |||
| scale = (noHPneed || noProbability && sk[1] !== 100) ? 0 : sk[2] / 100; | |||
| break; | |||
| case 129: //无条件盾,属性个数不固定 | |||
| case 163: //无条件盾,属性个数不固定 | |||
| scale = (allAttr && (sk[5] & 31) != 31) ? 0 : sk[6] / 100; | |||
| break; | |||
| case 130: //血线下 + 属性个数不固定 | |||
| case 131: //血线上 + 属性个数不固定 | |||
| scale = (noHPneed || allAttr && (sk[5] & 31) != 31) ? 0 : sk[6] / 100; | |||
| break; | |||
| case 151: //十字心触发 | |||
| case 169: //C触发 | |||
| case 198: //回血触发 | |||
| scale = sk[2] / 100; | |||
| break; | |||
| case 170: //多色触发 | |||
| case 182: //长串触发 | |||
| case 193: //L触发 | |||
| scale = sk[3] / 100; | |||
| break; | |||
| case 171: //多串触发 | |||
| scale = sk[6] / 100; | |||
| break; | |||
| case 183: //又是个有两段血线的队长技 | |||
| scale = noHPneed ? 0 : sk[4] / 100; | |||
| break; | |||
| case 138: //调用其他队长技 | |||
| scale = sk.reduce((pmul, skid) => 1 - (1 - pmul) * (1 - getReduceScale(Skills[skid], allAttr, noHPneed)), 0); | |||
| break; | |||
| default: | |||
| } | |||
| return scale || 0; | |||
| return lss.map(leaderReduceScale).filter(re=>re.scale > 0); | |||
| } | |||
| @@ -1073,6 +1073,103 @@ function initialize() { | |||
| badges.forEach(badge => badge.onclick = setBadge); | |||
| }); | |||
| //显示HP的详细值 | |||
| const hpDetailDialog = formationBox.querySelector(".dialog-hp-detail"); | |||
| hpDetailDialog.show = function(reduceAttrRanges, tHP, tHPNoAwoken) | |||
| { | |||
| const dialogContent = this.querySelector(".dialog-content"); | |||
| const fragment = document.createDocumentFragment(); | |||
| function insertHpRangeTable(reduceRanges, tHP, tHPNoAwoken, attr) | |||
| { | |||
| const table = document.createElement("table"); | |||
| table.className = "hp-range-table"; | |||
| table.setAttribute("data-attr", attr); | |||
| table.createCaption(); | |||
| const tHead = table.createTHead(); | |||
| const tBody = table.createTBody(); | |||
| const rangeRow = tHead.insertRow(); | |||
| rangeRow.className = "hp-range"; | |||
| rangeRow.appendChild(document.createElement("th")); | |||
| const rageHpRow = tBody.insertRow(); | |||
| rageHpRow.className = "general"; | |||
| rageHpRow.appendChild(document.createElement("th")); | |||
| const rageHpNoAwokenRow = tBody.insertRow(); | |||
| rageHpNoAwokenRow.className = "awoken-bind"; | |||
| rageHpNoAwokenRow.appendChild(document.createElement("th")); | |||
| const reduceRow = tBody.insertRow(); | |||
| reduceRow.className = "reduce-scale"; | |||
| reduceRow.appendChild(document.createElement("th")); | |||
| const reduceHpRow = tBody.insertRow(); | |||
| reduceHpRow.className = "reduce-general"; | |||
| reduceHpRow.appendChild(document.createElement("th")); | |||
| const reduceHpNoAwokenRow = tBody.insertRow(); | |||
| reduceHpNoAwokenRow.className = "reduce-awoken-bind"; | |||
| reduceHpNoAwokenRow.appendChild(document.createElement("th")); | |||
| reduceRanges.forEach(range=>{ | |||
| const hpRange = rangeRow.insertCell(); | |||
| const hpRangeMin = hpRange.appendChild(document.createElement("span")); | |||
| hpRangeMin.className = "hp-range-min"; | |||
| hpRangeMin.textContent = range.min; | |||
| hpRange.appendChild(document.createTextNode(" ~ ")); | |||
| const hpRangeMax = hpRange.appendChild(document.createElement("span")); | |||
| hpRangeMax.className = "hp-range-max"; | |||
| hpRangeMax.textContent = range.max; | |||
| const hpGeneral = rageHpRow.insertCell(); | |||
| hpGeneral.textContent = `${Math.round(tHP * (range.min / 100))} ~ ${Math.round(tHP * (range.max/100))}`; | |||
| const hpAwokenBind = rageHpNoAwokenRow.insertCell(); | |||
| hpAwokenBind.textContent = `${Math.round(tHPNoAwoken * (range.min / 100))} ~ ${Math.round(tHPNoAwoken * (range.max/100))}`; | |||
| const reduce = reduceRow.insertCell(); | |||
| const reduceScale = reduce.appendChild(document.createElement("span")); | |||
| reduceScale.textContent = `${parseFloat((range.scale * 100).toFixed(2))}`; | |||
| if (range.probability < 1) | |||
| { | |||
| reduce.appendChild(document.createTextNode("(")); | |||
| const reduceProb = reduce.appendChild(document.createElement("span")); | |||
| reduceProb.className = "reduce-probability"; | |||
| reduceProb.textContent = `${(range.probability * 100).toFixed(0)}`; | |||
| reduce.appendChild(document.createTextNode(")")); | |||
| } | |||
| const reduceGeneral = reduceHpRow.insertCell(); | |||
| reduceGeneral.textContent = `${Math.round(tHP * (range.min / 100) / (1 - range.scale))} ~ ${Math.round(tHP * (range.max/100) / (1 - range.scale))}`; | |||
| const reduceAwokenBind = reduceHpNoAwokenRow.insertCell(); | |||
| reduceAwokenBind.textContent = `${Math.round(tHPNoAwoken * (range.min / 100) / (1 - range.scale))} ~ ${Math.round(tHPNoAwoken * (range.max/100) / (1 - range.scale))}`; | |||
| }); | |||
| return table; | |||
| } | |||
| if (reduceAttrRanges.some(r=>r != reduceAttrRanges[0])) //有指定属性减伤 | |||
| { | |||
| reduceAttrRanges.forEach((reduceRanges, ridx)=>fragment.appendChild(insertHpRangeTable(reduceRanges, tHP, tHPNoAwoken, ridx))); | |||
| } | |||
| else //只有阶梯盾 | |||
| { | |||
| const reduceRanges = reduceAttrRanges[0]; | |||
| fragment.appendChild(insertHpRangeTable(reduceRanges, tHP, tHPNoAwoken, 31)); | |||
| } | |||
| dialogContent.innerHTML = ""; | |||
| dialogContent.appendChild(fragment); | |||
| this.classList.remove(className_displayNone); | |||
| } | |||
| hpDetailDialog.close = function() | |||
| { | |||
| this.classList.add(className_displayNone); | |||
| } | |||
| const hpDetailDialog_Close = hpDetailDialog.querySelector(".dialog-close"); | |||
| hpDetailDialog_Close.onclick = function(){hpDetailDialog.close();}; | |||
| teamBigBoxs.forEach(teamBigBox => { | |||
| const reduceDetails = teamBigBox.querySelector(".tIf-total-hp .reduce-details"); | |||
| reduceDetails.onclick = function(){ | |||
| hpDetailDialog.show(this.reduceAttrRanges, this.tHP, this.tHPNoAwoken); | |||
| }; | |||
| }); | |||
| //编辑框 | |||
| editBox.mid = null; //储存怪物id | |||
| editBox.latent = []; //储存潜在觉醒 | |||
| @@ -2008,7 +2105,7 @@ function initialize() { | |||
| teamData[editBox.memberIdx[1]][editBox.memberIdx[2]] = mon; | |||
| mon.id = parseInt(monstersID.value, 10); | |||
| mon.id = editBox.mid; | |||
| const card = Cards[mon.id] || Cards[0]; | |||
| const skill = Skills[card.activeSkillId]; | |||
| @@ -3067,6 +3164,43 @@ function setTextContentAndAttribute(dom,str) | |||
| dom.setAttribute(dataAttrName, str); | |||
| } | |||
| function drawHpInfo(hpBarDom, reduceAttrRanges) | |||
| { | |||
| const width = hpBarDom.width, height = hpBarDom.height; | |||
| let ctx = hpBarDom.getContext("2d"); | |||
| console.log(reduceAttrRanges) | |||
| if (reduceAttrRanges.some(r=>r != reduceAttrRanges[0])) //有指定属性减伤 | |||
| { | |||
| const attrColors = ['crimson','cornflowerblue','green','goldenrod','purple']; | |||
| reduceAttrRanges.forEach((reduceRanges, ridx)=>{ | |||
| //console.table(reduceRanges); | |||
| ctx.fillStyle = attrColors[ridx]; | |||
| ctx.fillRect(0, height / 5 * ridx, width, height / 5 * (ridx + 1)); | |||
| reduceRanges.forEach(range=>{ | |||
| ctx.fillStyle = `rgba(0, 0, 0, 0.5)`; | |||
| ctx.fillRect(width * (range.min / 100), height / 5 * ridx, width * (range.max / 100), height / 5 * (1 - range.scale)); | |||
| }); | |||
| }); | |||
| } | |||
| else //只有阶梯盾 | |||
| { | |||
| const reduceRanges = reduceAttrRanges[0]; | |||
| //创建线性颜色渐变对象 | |||
| const canvasGradient = ctx.createLinearGradient(0, 0, 0, height); | |||
| canvasGradient.addColorStop(0, "#EE99AA"); | |||
| canvasGradient.addColorStop(0.4, "#FFDDEE"); | |||
| canvasGradient.addColorStop(1, "#EE9999"); | |||
| ctx.fillStyle = canvasGradient; | |||
| ctx.fillRect(0, 0, width, height); | |||
| reduceRanges.forEach(range=>{ | |||
| ctx.fillStyle = `rgba(204, 0 ,85, 0.5)`; | |||
| ctx.fillRect(width * (range.min / 100), 0, width * ((range.max - range.min) / 100), height * (1 - range.scale)); | |||
| }); | |||
| } | |||
| } | |||
| //刷新队伍能力值合计 | |||
| function refreshTeamTotalHP(totalDom, team, teamIdx) { | |||
| //计算总的生命值 | |||
| @@ -3081,9 +3215,24 @@ function refreshTeamTotalHP(totalDom, team, teamIdx) { | |||
| const leader2id = teamsCount===2 ? (teamIdx === 1 ? teams[0][0][0].id : teams[1][0][0].id) : team[0][5].id; | |||
| if (tHpDom) { | |||
| const reduceScale1 = getReduceScale(leader1id,true,true,true); | |||
| const reduceScale2 = getReduceScale(leader2id,true,true,true); | |||
| const totalReduce = 1 - (1 - reduceScale1) * (1 - reduceScale2); | |||
| const reduceScales1 = getReduceScales(leader1id); | |||
| const reduceScales2 = getReduceScales(leader2id); | |||
| const reduceAttrRanges = getReduceRange(reduceScales1.concat(reduceScales2)); | |||
| //将所有范围平铺,然后选择盾最少那个作为基础盾值 | |||
| const leastScale = reduceAttrRanges.flat().sort((a,b)=>a.scale-b.scale)[0]; | |||
| const hpBar = totalDom.querySelector(".reduce-details"); | |||
| if (reduceAttrRanges.some(r=>r != reduceAttrRanges[0]) || reduceAttrRanges[0].length > 1 || reduceAttrRanges[0][0].probability < 1) //有阶梯盾或者有指定属性减伤或者减伤比例不是100% | |||
| { | |||
| drawHpInfo(hpBar, reduceAttrRanges); | |||
| hpBar.classList.remove(className_displayNone); | |||
| }else | |||
| { | |||
| hpBar.classList.add(className_displayNone); | |||
| } | |||
| const totalReduce = leastScale.scale; | |||
| const teamHPArr = countTeamHp(team[0], leader1id, leader2id, solo); | |||
| const teamHPNoAwokenArr = countTeamHp(team[0], leader1id, leader2id, solo, true); | |||
| @@ -3092,7 +3241,6 @@ function refreshTeamTotalHP(totalDom, team, teamIdx) { | |||
| let tHP = teamHPArr.reduce((pv, v) => pv + v); //队伍计算的总HP | |||
| let tHPNoAwoken = teamHPNoAwokenArr.reduce((pv, v) => pv + v); //队伍计算的总HP无觉醒 | |||
| const teamHPAwoken = awokenCountInTeam(team, 46, solo, teamsCount); //全队大血包个数 | |||
| let badgeHPScale = 1; //徽章倍率 | |||
| @@ -3105,8 +3253,13 @@ function refreshTeamTotalHP(totalDom, team, teamIdx) { | |||
| tHP = Math.round(Math.round(tHP * (1 + 0.05 * teamHPAwoken)) * badgeHPScale); | |||
| tHPNoAwoken = Math.round(Math.round(tHPNoAwoken) * badgeHPScale); | |||
| const tReduceHP = Math.round(tHP / (1 - reduceScale1) / (1 - reduceScale2)); //队伍正常满血加上盾能承受的最大伤害 | |||
| const tReduceHPNoAwoken = Math.round(tHPNoAwoken / (1 - reduceScale1) / (1 - reduceScale2)); //队伍封觉醒满血加上盾能承受的最大伤害 | |||
| //记录到bar中,方便打开详情时调用 | |||
| hpBar.reduceAttrRanges = reduceAttrRanges; | |||
| hpBar.tHP = tHP; | |||
| hpBar.tHPNoAwoken = tHPNoAwoken; | |||
| const tReduceHP = Math.round(tHP / (1 - totalReduce)); //队伍正常满血加上盾能承受的最大伤害 | |||
| const tReduceHPNoAwoken = Math.round(tHPNoAwoken / (1 - totalReduce)); //队伍封觉醒满血加上盾能承受的最大伤害 | |||
| const tHpDom_general = tHpDom.querySelector(".general"); | |||
| const tHpDom_noAwoken = tHpDom.querySelector(".awoken-bind"); | |||
| @@ -3201,9 +3354,24 @@ function refreshFormationTotalHP(totalDom, teams) { | |||
| if (tHpDom) { | |||
| const reduceScale1 = getReduceScale(leader1id,true,true,true); | |||
| const reduceScale2 = getReduceScale(leader2id,true,true,true); | |||
| const totalReduce = 1 - (1 - reduceScale1) * (1 - reduceScale2); | |||
| const reduceScales1 = getReduceScales(leader1id); | |||
| const reduceScales2 = getReduceScales(leader2id); | |||
| const reduceAttrRanges = getReduceRange(reduceScales1.concat(reduceScales2)); | |||
| //将所有范围平铺,然后选择盾最少那个作为基础盾值 | |||
| const leastScale = reduceAttrRanges.flat().sort((a,b)=>a.scale-b.scale)[0]; | |||
| const hpBar = totalDom.querySelector(".reduce-details"); | |||
| if (reduceAttrRanges.some(r=>r != reduceAttrRanges[0]) || reduceAttrRanges[0].length > 1 || reduceAttrRanges[0][0].probability < 1) //有阶梯盾或者有指定属性减伤或者减伤比例不是100% | |||
| { | |||
| drawHpInfo(hpBar, reduceAttrRanges); | |||
| hpBar.classList.remove(className_displayNone); | |||
| }else | |||
| { | |||
| hpBar.classList.add(className_displayNone); | |||
| } | |||
| const totalReduce = leastScale.scale; | |||
| const tHPArr = teams.map(function(team) { | |||
| const teamHPArr = countTeamHp(team[0], leader1id, leader2id, solo); | |||
| @@ -3223,6 +3391,11 @@ function refreshFormationTotalHP(totalDom, teams) { | |||
| const tHP = tHPArr.reduce((pv, v) => pv + v); | |||
| const tHPNoAwoken = tHPNoAwokenArr.reduce((pv, v) => pv + v); | |||
| //记录到bar中,方便打开详情时调用 | |||
| hpBar.reduceAttrRanges = reduceAttrRanges; | |||
| hpBar.tHP = tHP; | |||
| hpBar.tHPNoAwoken = tHPNoAwoken; | |||
| const tReduceHP = Math.round(tHP / (1 - reduceScale1) / (1 - reduceScale2)); //队伍正常满血加上盾能承受的最大伤害 | |||
| const tReduceHPNoAwoken = Math.round(tHPNoAwoken / (1 - reduceScale1) / (1 - reduceScale2)); //队伍封觉醒满血加上盾能承受的最大伤害 | |||
| @@ -83,6 +83,7 @@ var formation = new Formation(teamsCount,6); | |||
| <span class="reduce-scale"></span> | |||
| <span class="general"></span> | |||
| <span class="awoken-bind"></span> | |||
| <canvas height="20" width="100" class="reduce-details display-none"></canvas> | |||
| </span> | |||
| </div> | |||
| <div class="tIf-total-move"> | |||
| @@ -476,6 +477,11 @@ var formation = new Formation(teamsCount,6); | |||
| </li> | |||
| </ul> | |||
| <div class="detail-box edit"><textarea class="detail" placeholder="输入说明"></textarea><div class="detail-display"></div></div> | |||
| <div class="dialog dialog-hp-detail display-none"> | |||
| <div class="dialog-title"></div> | |||
| <div class="dialog-content"></div> | |||
| <div class="dialog-control"><button class="dialog-close brown-button"></button></div> | |||
| </div> | |||
| </div> | |||
| <div class="edit-box display-none"> | |||
| <div class="edit-box-title"><!--修改怪物--></div> | |||
| @@ -594,35 +594,45 @@ ul{ | |||
| .tIf-total-move .awoken-bind::before, | |||
| .tIf-total-move.fixed-move-time::after, | |||
| .tIf-effect icon::before, | |||
| icon.poison-no-effect::after | |||
| icon.poison-no-effect::after, | |||
| .hp-range-table th::before | |||
| { | |||
| content: " "; | |||
| background-size: cover; | |||
| display: inline-block; | |||
| width: 20px; | |||
| height: 20px; | |||
| vertical-align: top; | |||
| vertical-align: bottom; | |||
| } | |||
| .tIf-total-hp .awoken-bind::before, | |||
| .tIf-total-hp .reduce .awoken-bind::before, | |||
| .tIf-total-move .awoken-bind::before | |||
| .tIf-total-move .awoken-bind::before, | |||
| .hp-range-table .awoken-bind th::before, | |||
| .hp-range-table .reduce-awoken-bind th::before | |||
| { | |||
| background-image: url(images/icon-awoken-bind.png); | |||
| } | |||
| .tIf-total-hp .general::before, | |||
| .tIf-total-hp .reduce .general::before | |||
| .tIf-total-hp .reduce .general::before, | |||
| .hp-range-table .general th::before, | |||
| .hp-range-table .reduce-general th::before | |||
| { | |||
| background-image: url(images/icon-HP.png); | |||
| } | |||
| .tIf-total-hp .reduce .reduce-scale::before{ | |||
| .tIf-total-hp .reduce .reduce-scale::before, | |||
| .hp-range-table .reduce-scale th::before | |||
| { | |||
| background-image: url(images/icon-reduce.png); | |||
| } | |||
| .tIf-total-hp .reduce .reduce-scale::after{ | |||
| content: "%⇔"; | |||
| } | |||
| .tIf-total-hp .reduce.no-reduce .reduce-scale::after{ | |||
| .tIf-total-hp .reduce.no-reduce .reduce-scale::after, | |||
| .hp-range-table .hp-range td span:after, | |||
| .hp-range-table .reduce-scale td span:after | |||
| { | |||
| content: "%"; | |||
| } | |||
| .tIf-total-hp .reduce.no-reduce .general, | |||
| @@ -631,6 +641,57 @@ icon.poison-no-effect::after | |||
| display: none; | |||
| } | |||
| .reduce-details | |||
| { | |||
| cursor: pointer; | |||
| vertical-align: bottom; | |||
| } | |||
| .reduce-details:hover | |||
| { | |||
| box-shadow: red 0 0 3px; | |||
| } | |||
| .hp-range-table | |||
| { | |||
| font-family: var(--font-family); | |||
| border: 1px solid white; | |||
| background-color: saddlebrown; | |||
| } | |||
| .hp-range-table caption::before | |||
| { | |||
| font-family: var(--game-font-family); | |||
| } | |||
| .hp-range-table td, | |||
| .hp-range-table th | |||
| { | |||
| border: 1px solid white; | |||
| padding: 0 4px; | |||
| } | |||
| .hp-range-table .hp-range th::before | |||
| { | |||
| width: unset; | |||
| height: unset; | |||
| } | |||
| .hp-range-table[data-attr="0"] | |||
| { | |||
| background-color: crimson; | |||
| } | |||
| .hp-range-table[data-attr="1"] | |||
| { | |||
| background-color: cornflowerblue; | |||
| } | |||
| .hp-range-table[data-attr="2"] | |||
| { | |||
| background-color: green; | |||
| } | |||
| .hp-range-table[data-attr="3"] | |||
| { | |||
| background-color: goldenrod; | |||
| } | |||
| .hp-range-table[data-attr="4"] | |||
| { | |||
| background-color: purple; | |||
| } | |||
| .tIf-total-move .general::before{ | |||
| background-image: url(images/icon-orb-move-time.png); | |||
| } | |||
| @@ -2434,6 +2495,7 @@ table .orb-icon | |||
| /*弹出窗口相关*/ | |||
| .dialog | |||
| { | |||
| color: white; | |||
| position: absolute; | |||
| padding: 5px; | |||
| border: 2px ridge #D1D398; | |||
| @@ -2441,7 +2503,6 @@ table .orb-icon | |||
| background-image: linear-gradient(to bottom,#788321f0,#3E4D14f0); | |||
| border-radius: 6px; | |||
| box-shadow: black 2px 0px 1px,black 0px 2px 1px,black -2px 0px 1px,black 0px -2px 1px; | |||
| width: 260px; | |||
| margin-left: calc(50% - 130px); | |||
| margin-top: 30px; | |||
| font-family: var(--game-font-family); | |||
| @@ -2508,6 +2569,10 @@ table .orb-icon | |||
| content: "关闭"; | |||
| } | |||
| */ | |||
| .dialog-search-string | |||
| { | |||
| width: 260px; | |||
| } | |||
| .dialog-search-string .string-copy, | |||
| .dialog-search-string .string-search | |||
| { | |||
| @@ -98,6 +98,7 @@ var formation = new Formation(teamsCount,6); | |||
| <span class="reduce-scale"></span> | |||
| <span class="general"></span> | |||
| <span class="awoken-bind"></span> | |||
| <canvas height="20" width="100" class="reduce-details display-none"></canvas> | |||
| </span> | |||
| </div> | |||
| <div class="tIf-total-move"> | |||
| @@ -518,6 +519,7 @@ var formation = new Formation(teamsCount,6); | |||
| <span class="reduce-scale"></span> | |||
| <span class="general"></span> | |||
| <span class="awoken-bind"></span> | |||
| <canvas height="20" width="100" class="reduce-details display-none"></canvas> | |||
| </span> | |||
| </div> | |||
| <div class="tIf-total-move"> | |||
| @@ -938,6 +940,7 @@ var formation = new Formation(teamsCount,6); | |||
| <span class="reduce-scale"></span> | |||
| <span class="general"></span> | |||
| <span class="awoken-bind"></span> | |||
| <canvas height="20" width="100" class="reduce-details display-none"></canvas> | |||
| </span> | |||
| </div> | |||
| <div class="tIf-total-move"> | |||
| @@ -1331,6 +1334,11 @@ var formation = new Formation(teamsCount,6); | |||
| </li> | |||
| </ul> | |||
| <div class="detail-box edit"><textarea class="detail" placeholder="输入说明"></textarea><div class="detail-display"></div></div> | |||
| <div class="dialog dialog-hp-detail display-none"> | |||
| <div class="dialog-title"></div> | |||
| <div class="dialog-content"></div> | |||
| <div class="dialog-control"><button class="dialog-close brown-button"></button></div> | |||
| </div> | |||
| </div> | |||
| <div class="edit-box display-none"> | |||
| <div class="edit-box-title"><!--修改怪物--></div> | |||