Showing
2 changed files
with
201 additions
and
8 deletions
app/node/model/weapon.js
0 → 100644
| 1 | +module.exports = { | ||
| 2 | + '한손검': 1.2, | ||
| 3 | + '한손도끼': 1.2, | ||
| 4 | + '한손둔기': 1.2, | ||
| 5 | + '스태프': 1, | ||
| 6 | + '완드': 1, | ||
| 7 | + '샤이닝 로드': 1.2, | ||
| 8 | + '단검': 1.3, | ||
| 9 | + '케인': 1.3, | ||
| 10 | + '데스페라도': 1.3, | ||
| 11 | + '에너지소드': 1.5, | ||
| 12 | + '소울 슈터': 1.7, | ||
| 13 | + 'ESP 리미터': 1.2, | ||
| 14 | + '체인': 1.3, | ||
| 15 | + '매직 건틀렛': 1.2, | ||
| 16 | + '부채': 1.3, | ||
| 17 | + '튜너': 1.3, | ||
| 18 | + '두손검': 1.34, | ||
| 19 | + '두손도끼': 1.34, | ||
| 20 | + '두손둔기': 1.34, | ||
| 21 | + '창': 1.34, | ||
| 22 | + '폴암': 1.49, | ||
| 23 | + '태도': 1.34, | ||
| 24 | + '건틀렛 리볼버': 1.7, | ||
| 25 | + '활': 1.3, | ||
| 26 | + '석궁': 1.35, | ||
| 27 | + '듀얼 보우건': 1.3, | ||
| 28 | + '에인션트 보우': 1.3, | ||
| 29 | + '아대': 1.75, | ||
| 30 | + '건': 1.5, | ||
| 31 | + '너클': 1.7, | ||
| 32 | + '핸드캐논': 1.5 | ||
| 33 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -144,6 +144,7 @@ const analyzeEquipment = async function(nickname, characterCode, job) { | ... | @@ -144,6 +144,7 @@ const analyzeEquipment = async function(nickname, characterCode, job) { |
| 144 | let damagePercent = 0; | 144 | let damagePercent = 0; |
| 145 | let majorPercent = 0; | 145 | let majorPercent = 0; |
| 146 | let attackPowerPercent = 0; | 146 | let attackPowerPercent = 0; |
| 147 | + let weapon = undefined; | ||
| 147 | const equipmentURLs = []; | 148 | const equipmentURLs = []; |
| 148 | $(".tab01_con_wrap .weapon_wrap .item_pot li span a").each(async function() { | 149 | $(".tab01_con_wrap .weapon_wrap .item_pot li span a").each(async function() { |
| 149 | equipmentURLs.push("https://maplestory.nexon.com" + $(this).attr("href")); | 150 | equipmentURLs.push("https://maplestory.nexon.com" + $(this).attr("href")); |
| ... | @@ -159,13 +160,18 @@ const analyzeEquipment = async function(nickname, characterCode, job) { | ... | @@ -159,13 +160,18 @@ const analyzeEquipment = async function(nickname, characterCode, job) { |
| 159 | const equipmentDom = new JSDOM(equipmentResp.data.view); | 160 | const equipmentDom = new JSDOM(equipmentResp.data.view); |
| 160 | const $equipment = (require('jquery'))(equipmentDom.window); | 161 | const $equipment = (require('jquery'))(equipmentDom.window); |
| 161 | 162 | ||
| 163 | + const equipmentType = $equipment(".item_ability .ablilty02:eq(1) .job_name em").text(); | ||
| 164 | + if (equipmentType.indexOf("손무기") >= 0 && equipmentType.indexOf("블레이드") < 0 && equipmentType.indexOf("대검") < 0) { | ||
| 165 | + weapon = equipmentType.split(" (")[0]; | ||
| 166 | + } | ||
| 167 | + | ||
| 162 | $equipment(".stet_info ul li").each(function() { | 168 | $equipment(".stet_info ul li").each(function() { |
| 163 | - const regexMajor1 = new RegExp(`${jobModel[job].major} : \\+(\\d)%`); | 169 | + const regexMajor1 = new RegExp(`${jobModel[job].major} : \\+(\\d+)%`); |
| 164 | - const regexMajor2 = new RegExp(`올스탯 : \\+(\\d)%`); | 170 | + const regexMajor2 = new RegExp(`올스탯 : \\+(\\d+)%`); |
| 165 | const regexAttackPower = (jobModel[job].major == "INT") ? | 171 | const regexAttackPower = (jobModel[job].major == "INT") ? |
| 166 | - new RegExp(`마력 : \\+(\\d)%`) : | 172 | + new RegExp(`마력 : \\+(\\d+)%`) : |
| 167 | - new RegExp(`공격력 : \\+(\\d)%`); | 173 | + new RegExp(`공격력 : \\+(\\d+)%`); |
| 168 | - const regexDamage = new RegExp(`데미지 : \\+(\\d)%`); | 174 | + const regexDamage = new RegExp(`^데미지 : \\+(\\d+)%`); |
| 169 | 175 | ||
| 170 | if ($(this).find(".stet_th span").text() == "올스탯") { | 176 | if ($(this).find(".stet_th span").text() == "올스탯") { |
| 171 | majorPercent += parseInt($(this).find(".point_td font:eq(0)").text().substring(1)); | 177 | majorPercent += parseInt($(this).find(".point_td font:eq(0)").text().substring(1)); |
| ... | @@ -191,7 +197,8 @@ const analyzeEquipment = async function(nickname, characterCode, job) { | ... | @@ -191,7 +197,8 @@ const analyzeEquipment = async function(nickname, characterCode, job) { |
| 191 | majorArcane: majorArcane, | 197 | majorArcane: majorArcane, |
| 192 | majorPercent: majorPercent, | 198 | majorPercent: majorPercent, |
| 193 | attackPowerPercent: attackPowerPercent, | 199 | attackPowerPercent: attackPowerPercent, |
| 194 | - damagePercent: damagePercent | 200 | + damagePercent: damagePercent, |
| 201 | + weapon: weapon | ||
| 195 | }; | 202 | }; |
| 196 | } catch (error) { | 203 | } catch (error) { |
| 197 | console.log(error); | 204 | console.log(error); |
| ... | @@ -199,6 +206,146 @@ const analyzeEquipment = async function(nickname, characterCode, job) { | ... | @@ -199,6 +206,146 @@ const analyzeEquipment = async function(nickname, characterCode, job) { |
| 199 | } | 206 | } |
| 200 | } | 207 | } |
| 201 | 208 | ||
| 209 | +const analyzeStats = function(characterInfo, analysisEquipment) { | ||
| 210 | + const jobModel = require('../model/job'); | ||
| 211 | + const job = jobModel[characterInfo.character.job]; | ||
| 212 | + const jobDefault = jobModel.default; | ||
| 213 | + const weaponConst = require('../model/weapon')[analysisEquipment.weapon] || 1; | ||
| 214 | + const stats = { | ||
| 215 | + major: { | ||
| 216 | + pure: 0, | ||
| 217 | + percent: analysisEquipment.majorPercent + | ||
| 218 | + job.stats.passive.major.percent + | ||
| 219 | + jobDefault.stats.passive.major.percent, | ||
| 220 | + added: 0 | ||
| 221 | + }, | ||
| 222 | + minor: characterInfo.stats.minor, | ||
| 223 | + damage: { | ||
| 224 | + all: characterInfo.stats.damageHyper + | ||
| 225 | + analysisEquipment.damagePercent + | ||
| 226 | + job.stats.passive.damage.all + | ||
| 227 | + jobDefault.stats.passive.damage.all, | ||
| 228 | + boss: characterInfo.stats.bossAttackDamage | ||
| 229 | + }, | ||
| 230 | + finalDamage: job.stats.passive.finalDamage, | ||
| 231 | + criticalDamage: characterInfo.stats.criticalDamage, | ||
| 232 | + attackPower: { | ||
| 233 | + pure: 0, | ||
| 234 | + percent: analysisEquipment.attackPowerPercent + | ||
| 235 | + job.stats.passive.attackPower.percent | ||
| 236 | + }, | ||
| 237 | + ignoreGuard: characterInfo.stats.ignoreGuard | ||
| 238 | + }; | ||
| 239 | + | ||
| 240 | + stats.major.added = characterInfo.stats.majorHyper + | ||
| 241 | + analysisEquipment.majorArcane; | ||
| 242 | + stats.major.pure = (characterInfo.stats.major - stats.major.added) / (1 + stats.major.percent / 100); | ||
| 243 | + | ||
| 244 | + stats.attackPower.pure = characterInfo.stats.statAttackPower * 100 / (characterInfo.stats.major * 4 + stats.minor) / job.jobConst / weaponConst / (1 + stats.attackPower.percent / 100) / (1 + stats.damage.all / 100) / (1 + stats.finalDamage / 100); | ||
| 245 | + | ||
| 246 | + return stats; | ||
| 247 | +} | ||
| 248 | + | ||
| 249 | +const calculateEfficiency = function(stats, job, weapon) { | ||
| 250 | + const efficiency = { | ||
| 251 | + major: { | ||
| 252 | + pure: 1, | ||
| 253 | + percent: 0 | ||
| 254 | + }, | ||
| 255 | + attackPower: { | ||
| 256 | + pure: 0, | ||
| 257 | + percent: 0, | ||
| 258 | + }, | ||
| 259 | + damage: 0, | ||
| 260 | + criticalDamage: 0, | ||
| 261 | + ignoreGuard: 0 | ||
| 262 | + }; | ||
| 263 | + | ||
| 264 | + const defaultPower = calculatePower(stats, job, weapon); | ||
| 265 | + | ||
| 266 | + stats.major.pure += 1; | ||
| 267 | + const majorPure = calculatePower(stats, job, weapon) - defaultPower; | ||
| 268 | + stats.major.pure -= 1; | ||
| 269 | + | ||
| 270 | + if (majorPure == 0) | ||
| 271 | + return efficiency; | ||
| 272 | + | ||
| 273 | + stats.major.percent += 1; | ||
| 274 | + efficiency.major.percent = (calculatePower(stats, job, weapon) - defaultPower) / majorPure; | ||
| 275 | + stats.major.percent -= 1; | ||
| 276 | + | ||
| 277 | + stats.attackPower.pure += 1; | ||
| 278 | + efficiency.attackPower.pure = (calculatePower(stats, job, weapon) - defaultPower) / majorPure; | ||
| 279 | + stats.attackPower.pure -= 1; | ||
| 280 | + | ||
| 281 | + stats.attackPower.percent += 1; | ||
| 282 | + efficiency.attackPower.percent = (calculatePower(stats, job, weapon) - defaultPower) / majorPure; | ||
| 283 | + stats.attackPower.percent -= 1; | ||
| 284 | + | ||
| 285 | + stats.damage.all += 1; | ||
| 286 | + efficiency.damage = (calculatePower(stats, job, weapon) - defaultPower) / majorPure; | ||
| 287 | + stats.damage.all -= 1; | ||
| 288 | + | ||
| 289 | + stats.criticalDamage += 1; | ||
| 290 | + efficiency.criticalDamage = (calculatePower(stats, job, weapon) - defaultPower) / majorPure; | ||
| 291 | + stats.criticalDamage -= 1; | ||
| 292 | + | ||
| 293 | + // 곱연산 | ||
| 294 | + const ignoreGuardSaved = stats.ignoreGuard; | ||
| 295 | + stats.ignoreGuard = (1 - (1 - stats.ignoreGuard / 100) * 0.99) * 100; | ||
| 296 | + efficiency.ignoreGuard = (calculatePower(stats, job, weapon) - defaultPower) / majorPure; | ||
| 297 | + stats.ignoreGuard = ignoreGuardSaved; | ||
| 298 | + | ||
| 299 | + return efficiency; | ||
| 300 | +} | ||
| 301 | + | ||
| 302 | +// 버프 적용 스탯 구하기 | ||
| 303 | +const getBuffStats = function(stats, job) { | ||
| 304 | + const jobModel = require('../model/job'); | ||
| 305 | + const buff = jobModel[job].stats.active; | ||
| 306 | + const defaultBuff = jobModel.default.stats.active; | ||
| 307 | + | ||
| 308 | + return { | ||
| 309 | + major: { | ||
| 310 | + pure: stats.major.pure + buff.major.pure, | ||
| 311 | + percent: stats.major.percent + buff.major.percent, | ||
| 312 | + added: stats.major.added | ||
| 313 | + }, | ||
| 314 | + minor: stats.minor, | ||
| 315 | + damage: { | ||
| 316 | + all: stats.damage.all + buff.damage.all + defaultBuff.damage.all, | ||
| 317 | + boss: stats.damage.boss + buff.damage.boss + defaultBuff.damage.boss | ||
| 318 | + }, | ||
| 319 | + finalDamage: stats.finalDamage, | ||
| 320 | + criticalDamage: stats.criticalDamage + buff.criticalDamage + defaultBuff.criticalDamage, | ||
| 321 | + attackPower: { | ||
| 322 | + pure: stats.attackPower.pure + buff.attackPower.pure, | ||
| 323 | + percent: stats.attackPower.percent + buff.attackPower.percent + defaultBuff.attackPower.percent | ||
| 324 | + }, | ||
| 325 | + ignoreGuard: (1 - (1 - (stats.ignoreGuard / 100)) * (1 - (buff.ignoreGuard / 100)) * (1 - (defaultBuff.ignoreGuard / 100))) * 100 | ||
| 326 | + }; | ||
| 327 | +} | ||
| 328 | + | ||
| 329 | +// 크리티컬 데미지, 보스 공격력, 방어율 무시를 반영하여 방어율 300% 몬스터 공격시 데미지 산출 값 | ||
| 330 | +const calculatePower = function(stats, job, weapon) { | ||
| 331 | + const jobConst = require('../model/job')[job].jobConst; | ||
| 332 | + const weaponConst = require('../model/weapon')[weapon]; | ||
| 333 | + return Math.max( | ||
| 334 | + ( | ||
| 335 | + (stats.major.pure * (1 + stats.major.percent / 100) + stats.major.added) * 4 + | ||
| 336 | + stats.minor | ||
| 337 | + ) * | ||
| 338 | + 0.01 * | ||
| 339 | + (stats.attackPower.pure * (1 + stats.attackPower.percent / 100)) * | ||
| 340 | + jobConst * | ||
| 341 | + weaponConst * | ||
| 342 | + (1 + stats.damage.all / 100 + stats.damage.boss / 100) * | ||
| 343 | + (1 + stats.finalDamage / 100) * | ||
| 344 | + (1.2 + stats.criticalDamage / 100) * | ||
| 345 | + (1 - 3 * (1 - stats.ignoreGuard / 100)), | ||
| 346 | + 1); | ||
| 347 | +} | ||
| 348 | + | ||
| 202 | module.exports = { | 349 | module.exports = { |
| 203 | getCharacter: async function(req, res) { | 350 | getCharacter: async function(req, res) { |
| 204 | if (!req.query.nickname) { | 351 | if (!req.query.nickname) { |
| ... | @@ -225,8 +372,21 @@ module.exports = { | ... | @@ -225,8 +372,21 @@ module.exports = { |
| 225 | res.status(403).send(); | 372 | res.status(403).send(); |
| 226 | return; | 373 | return; |
| 227 | } | 374 | } |
| 228 | - console.log(analysisEquipment); | ||
| 229 | 375 | ||
| 230 | - res.send(characterInfo); | 376 | + const stats = analyzeStats(characterInfo, analysisEquipment); |
| 377 | + const buffStats = getBuffStats(stats, characterInfo.character.job); | ||
| 378 | + const efficiency = calculateEfficiency(stats, characterInfo.character.job, analysisEquipment.weapon); | ||
| 379 | + const buffEfficiency = calculateEfficiency(buffStats, characterInfo.character.job, analysisEquipment.weapon); | ||
| 380 | + | ||
| 381 | + res.send({ | ||
| 382 | + default: { | ||
| 383 | + stats: stats, | ||
| 384 | + efficiency: efficiency | ||
| 385 | + }, | ||
| 386 | + buff: { | ||
| 387 | + stats: buffStats, | ||
| 388 | + efficiency: buffEfficiency | ||
| 389 | + } | ||
| 390 | + }); | ||
| 231 | } | 391 | } |
| 232 | }; | 392 | }; |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or login to post a comment