common.js (27911B)
1 const data = require("../Data/data.json"); 2 const QuickChart = require("quickchart-js"); 3 const nmDt = require("../Data/aliases.json"); 4 const weaponActualName = nmDt.weaponActualName; 5 const weaponAlliasName = nmDt.weaponAlliasName; 6 Object.defineProperty(String.prototype, "Simplify", { 7 // Function to remove all characters except 0-9 and a-z 8 // Eg "AK-47" -> "ak47" 9 value: function Simplify() { 10 return this.toLowerCase().replace(/[^0-9a-z]/g, ""); 11 }, 12 writable: true, 13 configurable: true, 14 }); 15 16 Object.defineProperty(Number.prototype, "IsPositive", { 17 // Function to check the number is positive or not 18 value: function IsPositive() { 19 if (this > 0) return true; 20 else return false; 21 }, 22 writable: true, 23 configurable: true, 24 }); 25 26 Object.defineProperty(Number.prototype, "IsNegative", { 27 // Function to check the number is negative or not 28 value: function IsNegative() { 29 if (this < 0) return true; 30 else return false; 31 }, 32 writable: true, 33 configurable: true, 34 }); 35 36 Object.defineProperty(Number.prototype, "ToBool", { 37 // Function to check the number is one or not 38 value: function ToBool() { 39 if (this == 1) return true; 40 else return false; 41 }, 42 writable: true, 43 configurable: true, 44 }); 45 46 Object.defineProperty(Number.prototype, "PlusHL", { 47 value: function PlusHL() { 48 if (this.toString()[0] == "-") { 49 return parseFloat(this.toFixed(2)).toString(); 50 } 51 return `+${parseFloat(this.toFixed(2)).toString()}`; 52 }, 53 writable: true, 54 configurable: true, 55 }); 56 57 /* Function to fix the input statement */ 58 function inpFixer(inpmsg) { 59 const parts = PartSpliter(inpmsg); 60 // parts will be an array 61 //eg: ["fennec", "akimbo, mono"] 62 nmDt.attachmentAlliasName[0].map((x, i) => 63 // x is the content of each index, i is the number of each index 64 x.map(y => { 65 if (parts[0].startsWith(y + " ") || parts[0].endsWith(" " + y)) { 66 inpmsg = 67 parts[0].replace(y + " ", "").replace(" " + y, "") + 68 (parts[1] ? ", " : " + ") + 69 nmDt.attachmentActualName[0][i]; 70 } 71 }) 72 ); 73 // so it fking only fix akimbo and stopping power wtf 74 return inpmsg; 75 } 76 // Function to split weapon name and the attachments from the input statement 77 function PartSpliter(inpmsg) { 78 if (inpmsg.includes(" + ")) { 79 // If the input statement has multiple attachments joined by "+", split them and output them as an array of strings [0] is the weapon name, [1] is the attachments 80 // Eg: "M4A1 + Silencer + Flashlight" -> ["M4A1", "Silencer + Flashlight"] 81 const out = inpmsg 82 .split(" + ") 83 .map(x => x.split("+")) 84 .flat(); 85 return [out.shift(), out.join(", ")]; 86 } 87 // If there is only one attachment, output it as an array of strings [0] is the weapon name, [1] is the attachment 88 // Eg: "M4A1 with Flashlight" -> ["M4A1", "Flashlight"] 89 return inpmsg.split(" with "); 90 } 91 92 function hasAttachments(inpmsg) { 93 inpmsg = inpFixer(inpmsg); 94 // If the input statement has multiple attachments joined by "+" or "with", split them and output them as an array of strings [0] is the weapon name, [1] is the attachments 95 if ( 96 inpmsg.split(" with ").filter(x => x.Simplify()).length > 1 || 97 inpmsg.split(" + ").filter(x => x.Simplify()).length > 1 98 ) { 99 return true; 100 } 101 return false; 102 } 103 104 function isolator(inpmsg) { 105 return PartSpliter(inpFixer(inpmsg)); 106 } 107 // identifying the weapon 108 function weaponIdentifier(inpmsg) { 109 const inpWeaponName = isolator(inpmsg)[0]; 110 // ["ak", "mono"] -> inpWeaponName: "ak" 111 // if weapon name is too short, return the error 112 if (inpWeaponName.length < 2) { 113 return inpmsg.trim().length 114 ? `The name ${inpmsg.trim()} is too short.` 115 : "There isn't any weapon name."; 116 } 117 let probableWeapons = []; 118 // Loop through all the weapons to find the probable weapons 119 // Eg: "ak" 120 for (let i = 0; i < data.cguns.length; i++) { 121 if (inpWeaponName.Simplify() == data.cguns[i].gunname.Simplify()) { 122 // if the simplified name of the weapon is the same as the weapon name in the database, return the only one stats object 123 return JSON.parse(JSON.stringify(data.cguns[i])); 124 } else if ( 125 data.cguns[i].gunname.Simplify().includes(inpWeaponName.Simplify()) 126 ) { 127 // If the weapon name is included in the actual name of the weapon 128 // push the weapon to the probableWeapons array 129 probableWeapons.push(i); 130 } 131 } 132 // if there is only one probable weapon, mean the gun has already been identified 133 if (probableWeapons.length == 1) { 134 // if there is only one probable weapon, return the only one stats object 135 return JSON.parse(JSON.stringify(data.cguns[probableWeapons[0]])); 136 } 137 // continue loop when there is no identified weapons or there are more than one identfied weaponds 138 // detecting aliases 139 // getting total number of weapons that had added aliases 140 for (let i = 0; i < weaponAlliasName.length; i++) { 141 // getting the number of aliases of each weapon 142 for (let j = 0; j < weaponAlliasName[i].length; j++) { 143 // weaponAliases[i][j] is the each alias of each weapon 144 // finding if simplified alias is same as input weapon name 145 if (weaponAlliasName[i][j].Simplify() == inpWeaponName.Simplify()) { 146 // if simplified alias is same as input weapon name 147 // eg "mow" == "mow", run the loop 148 for (let i2 = 0; i2 < data.cguns.length; i2++) { 149 if (weaponActualName[i] == data.cguns[i2].gunname) { 150 // use the actual name of the weapon to find the weapon 151 return JSON.parse(JSON.stringify(data.cguns[i2])); 152 } 153 } 154 } 155 } 156 } 157 // removing duplicates in the array 158 probableWeapons = [...new Set(probableWeapons)]; 159 // if there is only one probable weapon, return the only one stats object 160 if (probableWeapons.length == 1) 161 return JSON.parse(JSON.stringify(data.cguns[probableWeapons[0]])); 162 else if (probableWeapons.length > 1) { 163 // reply with the question of probable weapons 164 return `Did you mean ${probableWeapons 165 .map(x => data.cguns[x].gunname) 166 .reduce((out, x, i) => 167 [out, x].join(i === probableWeapons.length - 1 ? "` or `" : "`, `") 168 )} 169 ?`; 170 } else return `Couldn't identify the weapon: "${inpWeaponName}"`; 171 } 172 // identifying attachments and return array or error 173 function attachmentsIdentifier(inpmsg, gun) { 174 if (!hasAttachments(inpmsg)) return []; 175 // no need for isolator because using slash commands, we get individual attachment 176 let inputAttachmentsNames = isolator(inpmsg)[1] 177 .split(/ & |, |,| and /) 178 .filter(x => x); 179 180 const tooSmall = inputAttachmentsNames.filter(x => x.length < 3); 181 // filter all elements thats shorter than 2 characters 182 inputAttachmentsNames = inputAttachmentsNames.filter(x => !(x.length < 3)); 183 let errorMsgs = "", 184 errors = [], 185 unidentifined = []; 186 187 if (inputAttachmentsNames.length == 0) 188 errorMsgs += "\nAttachments are missing!\n"; 189 // if (inputAttachmentsNames.length >= 10) return "Cocaineeeeee"; ????????? 190 191 // Can directly use args[] to return, no need for isolator, partExtractor, inpFixer 192 const splitAttachmentsDataName = [], 193 outAttachments = []; 194 195 for (let i = 0; i < gun.aments.length; i++) { 196 // Eg: "Stippled Grip Tape" -> ["Stippled", "Grip", "Tape"] 197 splitAttachmentsDataName.push([ 198 ...new Set( 199 gun.aments[i].name 200 .split(" ") 201 .filter(x => x) 202 .map(x => x.trim()) 203 ), 204 ]); 205 206 // splitAttachmentsDataName[i] = ["Stippled", "Grip", "Tape"] 207 for (let j = 0; j < splitAttachmentsDataName[i].length; j++) { 208 // simplify the attachments name 209 // Eg: ["Stippled", "Grip", "Tape"] -> ["stippled", "grip", "tape"] 210 splitAttachmentsDataName[i][j] = 211 splitAttachmentsDataName[i][j].Simplify(); 212 } 213 } 214 // inputAttachmentsNames = [["stippled", "grip", "tape"] 215 for (let i = 0; i < inputAttachmentsNames.length; i++) { 216 let probables = []; 217 // loop through all the input attachments and split them into words 218 var splitInputAttachmentsName = inputAttachmentsNames[i] 219 .split(" ") 220 .filter(x => x); 221 222 function finder() { 223 //splitInputAttachmentsName = [["stippled", "grip", "tape"], ["545", "ammo"], ["owc","lazer", "tactical"]] 224 for (let j = 0; j < splitAttachmentsDataName.length; j++) { 225 for (let i2 = 0; i2 < splitAttachmentsDataName[j].length; i2++) { 226 for (let i3 = 0; i3 < splitInputAttachmentsName.length; i3++) { 227 // if simplified input attachment name is included in the real attachments name 228 if ( 229 splitAttachmentsDataName[j][i2].includes( 230 splitInputAttachmentsName[i3].Simplify() 231 ) 232 ) { 233 // if probables list doesn't include the attachment, push 234 let probablePushed = false; 235 for (let i4 = 0; i4 < probables.length; i4++) { 236 // push another attachment that also probable to the probables list to the same array that identified last loop 237 // Eg: probables = [ [32]] // as user input mag and first loop it identfified extended mag 238 // then as it got more possible, it will push large extended mag to the same array -> [ [32,33] ] 239 if (!probables[i4].includes(j)) { 240 probables[i4].push(j); 241 // make it true so that it doesn't push again in the next condition 242 probablePushed = true; 243 break; 244 } 245 } 246 // push if the attachment isn't been identified yet 247 if (!probablePushed) probables.push([j]); 248 } 249 } 250 } 251 } 252 } 253 finder(); 254 // finding magazines attachments 255 if ( 256 (inputAttachmentsNames[i].includes(" rounds mag") || 257 inputAttachmentsNames[i].includes(" round mag") || 258 inputAttachmentsNames[i].includes(" round") || 259 inputAttachmentsNames[i].includes(" rounds")) && 260 inputAttachmentsNames[i].startsWith( 261 inputAttachmentsNames[i].replace(/\D/g, "") 262 ) 263 ) { 264 var tmp1 = parseInt(inputAttachmentsNames[i]); 265 // calculating the sum of number of rounds and see if it matches the input number of rounds 266 const tmp2 = gun.aments.filter( 267 x => 268 x.type === 8 && x.effects[27] + x.effects[28] + gun.stats[17] === tmp1 269 ); 270 // push if the magazine is found 271 if (tmp2.length === 1) { 272 outAttachments.push(tmp2[0]); 273 continue; 274 } 275 } 276 // if probables is empty or there is more than one identified attachment 277 if ( 278 probables.length === 0 || 279 probables[probables.length - 1].length !== 1 || 280 probables.length < splitInputAttachmentsName.length 281 ) { 282 // empty probables as can't indentify the attachment 283 probables = []; 284 // the splitInputAttachmentsName isn't simplified pls rmb 285 splitInputAttachmentsName.map((x, i5) => { 286 // finding aliases 287 nmDt.attachmentAlliasName[1].map((y, i6) => { 288 y.map(z => { 289 if (z.Simplify().includes(x.Simplify())) { 290 splitInputAttachmentsName[i5] = nmDt.attachmentActualName[1][i6]; 291 } 292 }); 293 }); 294 }); 295 // simple iteration to make the array again 296 splitInputAttachmentsName = splitInputAttachmentsName 297 .join(" ") 298 .split(" ") 299 .filter(x => x); 300 // find one more time as we do aliases already 301 finder(); 302 if ( 303 probables.length === 0 || 304 probables[probables.length - 1].length !== 1 || 305 probables.length < splitInputAttachmentsName.length 306 ) { 307 probables = []; 308 splitInputAttachmentsName = inputAttachmentsNames[i] 309 .split(" ") 310 .filter(x => x); 311 finder(); 312 } 313 } 314 if (probables.length === 0) { 315 // push to unidentifined list as can't be identified after serveral times 316 unidentifined.push(inputAttachmentsNames[i]); 317 continue; 318 } 319 // curr is the most probable attachment 320 var curr = probables[probables.length - 1]; 321 const temp1 = probables[probables.length - 1].filter( 322 x => gun.aments[x].name.Simplify() == inputAttachmentsNames[i].Simplify() 323 ); 324 // see if the length of the array is the same or not 325 // Eg: splitAttachmentsDataName[x] = ["stippled", "grip", "tape"] and splitInputAttachmentsName = ["stippled", "grip", "tape"] 326 // then it it equal 327 const temp2 = probables[probables.length - 1].filter( 328 x => 329 splitAttachmentsDataName[x].length == splitInputAttachmentsName.length 330 ); 331 332 // if found probable, push it 333 if (temp1.length === 1 && temp2.length !== 1) { 334 probables.push([temp1]); 335 } else if (temp1.length !== 1 && temp2.length === 1) { 336 probables.push([temp2]); 337 } else if ( 338 temp1.length === 1 && 339 temp2.length === 1 && 340 temp1[0] == temp2[0] 341 ) { 342 probables.push([temp1]); 343 } 344 if ( 345 probables[probables.length - 1].length != 1 || 346 probables.length < splitInputAttachmentsName.length 347 ) { 348 // ask the user if he means xxx = which attachment 349 errors.push( 350 "`" + 351 curr 352 .map(x => gun.aments[x].name) 353 .reduce((out, x, i) => 354 [out, x].join(i === curr.length - 1 ? "` or `" : "`, `") 355 ) + 356 '` by `"' + 357 inputAttachmentsNames[i] + 358 '"`' 359 ); 360 } 361 // push the attachment to the output list 362 outAttachments.push(gun.aments[probables[probables.length - 1][0]]); 363 } 364 365 const outAttachmentsTypes = outAttachments.map(x => x.type - 1), 366 t1 = outAttachments 367 .map(x => x.effects[35]) 368 .reduce((t, x) => t + x, 0) 369 .toString() 370 .padStart(11, "0") 371 .toString() 372 .split("") 373 .map((x, i) => 374 parseInt(x) !== 0 && outAttachmentsTypes.includes(i) ? parseInt(i) : -1 375 ) 376 .filter(x => x !== -1); 377 378 errorMsgs += t1.length 379 ? "Can't equip `" + 380 t1 381 .map(x => data.attachmentTypes[x]) 382 .reduce((out, x, i, a) => 383 [out, x].join(i === a.length - 1 ? "` or `" : "`, `") 384 ) + 385 "` with " + 386 outAttachments 387 .filter(x => x.effects[35]) 388 .map(x => x.name) 389 .reduce((out, x, i, a) => 390 [out, x].join(i === a.length - 1 ? " and " : ", ") 391 ) 392 : ""; 393 errorMsgs += errors.length ? `\nDid you mean ${errors.join(";\n")}?\n` : ""; 394 errorMsgs += unidentifined.length 395 ? `\nCouldn't identify the attachment(${ 396 unidentifined.length === 1 ? "" : "s" 397 }): \`"${unidentifined.join('"`, `"')}"\`\n` 398 : ""; 399 errorMsgs += 400 outAttachments.length > 5 ? "\nCan't equip more than 5 attachments!\n" : ""; 401 errorMsgs += outAttachments.filter((x, i, a) => a.indexOf(x) !== i).length 402 ? "\nMultiple of same attachments found!\n" 403 : ""; 404 errorMsgs += outAttachments 405 .map(x => x.type) 406 .filter((x, i, a) => a.indexOf(x) !== i).length 407 ? "\nMultiple of attachments the same type found!\n" 408 : ""; 409 errorMsgs += tooSmall.length 410 ? "\nThe name" + 411 (tooSmall.length === 1 ? "" : "s") + 412 ': `"' + 413 tooSmall.reduce((out, x, i) => 414 [out, x].join(i === curr.length - 1 ? '"` and `"' : '"`, `"') 415 ) + 416 '"` ' + 417 (tooSmall.length === 1 ? "is" : "are") + 418 " too short\n" 419 : ""; 420 return errorMsgs ? errorMsgs.trim() : outAttachments; 421 } 422 // console.log(attachmentsIdentifier("chopper with heavy handle, red sight, granulated", data.cguns[38].aments)); makeError(); 423 // console.log(attachmentsIdentifier("ak + 5mw lazer", data.cguns[0].aments)); makeError(); 424 // console.log(attachmentsIdentifier("117 + 40 round mag", data.cguns[0].aments, data.cguns[0].stats)); makeError(); 425 // console.log(attachmentsIdentifier("117 + rtc muzzle brake, rubberized griptape, tac lazer sight, 40 round mag, no stock", data.cguns[1].aments)); makeError(); 426 // console.log(attachmentsIdentifier("47 + stipplied grip tape", data.cguns[0])); 427 // makeError(); 428 function damageHandler( 429 currDmgs, 430 currRngs, 431 damageMulti, 432 hp, 433 tbs, 434 tbb, 435 bib, 436 pellets 437 ) { 438 currDmgs = [...currDmgs]; 439 currRngs = [...currRngs]; 440 441 currRngs = currRngs.filter(x => x < 100).map(x => Math.round(x)); 442 currDmgs.length = currRngs.length + 1; 443 currDmgs = currDmgs.map(x => Math.round(x * damageMulti)); 444 let currSTKs = currDmgs.map(x => stk(x)), 445 currTTKs = currDmgs.map(x => ttk(x)), 446 currPDmg = null, 447 n = Math.max(...currTTKs.map(x => x.toString().length)); 448 n = n < 3 ? 3 : n; 449 function worker1(inp) { 450 return inp.map(x => x.toString().padStart(n)).join(" -- ") + "\n"; 451 } 452 function worker2(inp) { 453 return ( 454 "".padStart(n + 1) + 455 inp.map(x => x.toString().padStart(2)).join("".padStart(n + 2)) + 456 "\n" 457 ); 458 } 459 function stk(dmg) { 460 let out; 461 if (!pellets) out = Math.ceil(hp / dmg); 462 else out = Math.ceil(hp / (dmg * pellets)); 463 return out == Infinity ? "∞" : out; 464 } 465 function ttk(dmg) { 466 const stkVal = stk(dmg); 467 if (stkVal == "∞") return stkVal; 468 if (!bib) return Math.round((stkVal - 1) * tbs); 469 470 let out = 0; 471 if (dmg > 0) { 472 if (stkVal % bib == 0) { 473 for (var i = 0; i < Math.floor(stkVal / bib) - 1; i++) { 474 out += tbs * (bib - 1) + tbb; 475 } 476 out = out + tbs * (bib - 1); 477 } else if (stkVal % bib != 0) { 478 for (var i = 0; i <= Math.floor(stkVal / bib) - 1; i++) { 479 out += tbs * (bib - 1) + tbb; 480 } 481 for (var i = 0; i < (stkVal % bib) - 1; i++) { 482 out += tbs; 483 } 484 } 485 out = Math.round(out); 486 if (out == Infinity) { 487 return "∞"; 488 } 489 } else { 490 out = "No"; 491 } 492 return out; 493 } 494 if (pellets) { 495 currPDmg = currDmgs.map(x => x + "×" + pellets); 496 n = Math.max(...currPDmg.map(x => x.toString().length)); 497 } 498 return ( 499 "```swift\n" + 500 "Damage : " + 501 worker1(currPDmg || currDmgs) + 502 (pellets ? "Total : " + worker1(currDmgs.map(x => x * pellets)) : "") + 503 "STK : " + 504 worker1(currSTKs) + 505 "TTK : " + 506 worker1(currTTKs) + 507 "Range : " + 508 (currRngs.length ? worker2(currRngs) : worker1(["∞"])) + 509 "```" 510 ); 511 } 512 // console.log(damageHandler([30, 25, 20], [10, 20], 1, 100, 60000 / 720, 0, 0)); makeError(); 513 // console.log(damageHandler([ 33, 23 ], [ 39 ], 1, 100, 109.0909090909091, 0, 0 )); makeError(); 514 515 function recoilHandler( 516 xRecoil, 517 yRecoil, 518 xMultiplier, 519 yMultiplier, 520 bulletCount 521 ) { 522 if (xRecoil.length != yRecoil.length) return "err"; 523 524 const recoilLength = xRecoil.length; 525 if (recoilLength == 0) return "none"; 526 527 const recoilPattern = [ 528 { 529 x: 0, 530 y: 0, 531 }, 532 ]; 533 let recoilObj; 534 for (let i = 0; i < bulletCount; i++) { 535 const xContinuationVal = 536 xRecoil[recoilLength - 1] - xRecoil[recoilLength - 2]; 537 const yContinuationVal = 538 yRecoil[recoilLength - 1] - yRecoil[recoilLength - 2]; 539 if (i < recoilLength) { 540 recoilObj = { 541 x: xRecoil[i] * (1 + xMultiplier / 100), 542 y: yRecoil[i] * (1 + yMultiplier / 100), 543 }; 544 } else { 545 recoilObj = { 546 x: 547 (recoilPattern[recoilPattern.length - 1].x + xContinuationVal) * 548 xMultiplier, 549 y: 550 (recoilPattern[recoilPattern.length - 1].y + yContinuationVal) * 551 yMultiplier, 552 }; 553 } 554 recoilPattern.push(recoilObj); 555 } 556 const chart = new QuickChart(); 557 chart 558 .setConfig({ 559 type: "scatter", 560 data: { 561 datasets: [ 562 { 563 data: recoilPattern, 564 showLine: true, 565 fill: false, 566 pointRadius: 3, 567 backgroundColor: "rgba(056,205,255,1.00)", // "#38CDFF" fully transparent 568 borderColor: "rgba(056,205,255,0.75)", // "#38CDFF" 75% transparent 569 }, 570 ], 571 }, 572 options: { 573 plugins: { 574 backgroundImageUrl: "https://i.imgur.com/jFAFaWF.png", 575 }, 576 legend: { 577 display: false, 578 }, 579 scales: { 580 yAxes: [ 581 { 582 ticks: { 583 display: false, 584 min: 0, 585 max: 5050, 586 }, 587 }, 588 ], 589 xAxes: [ 590 { 591 ticks: { 592 display: false, 593 min: -4495, 594 max: 4495, 595 }, 596 }, 597 ], 598 }, 599 }, 600 }) 601 .setWidth(1780) 602 .setHeight(1000); 603 604 return chart; 605 } 606 607 function updateStatswithEffects(inpEffects, inpStats) { 608 const l = inpStats[18] / inpStats[17]; 609 const outStats = [...inpStats]; 610 611 var inpStatsarr = [1, 2, 5, 11, 14, 15, 20, 21, 22, 26, 27, 31]; 612 var inpEfecsarr = [17, 18, 16, 19, 1, 10, 14, 14, 14, 6, 7, 42]; // Efecs is short for Effects 613 for (let i = 0; i < inpEffects.length; i++) { 614 if (inpEffects[inpEfecsarr[i]] != 0) { 615 outStats[inpStatsarr[i]] *= (inpEffects[inpEfecsarr[i]] + 100) / 100; 616 } 617 } 618 var inpStatsarr = [3, 4, 16, 28, 29, 30]; 619 var inpEfecsarr = [20, 38, 0, 39, 40, 41]; 620 for (let i = 0; i < inpEffects.length; i++) { 621 if (inpEffects[inpEfecsarr[i]] != 0) { 622 outStats[inpStatsarr[i]] = inpEffects[inpEfecsarr[i]]; 623 } 624 } 625 var inpStatsarr = [0, 17, 25]; 626 var inpEfecsarr = [29, 27, 9]; 627 for (let i = 0; i < inpEffects.length; i++) { 628 if (inpEffects[inpEfecsarr[i]] != 0) { 629 outStats[inpStatsarr[i]] += inpEffects[inpEfecsarr[i]]; 630 } 631 } 632 633 if (inpEffects[4] != 0) { 634 outStats[10] = 11 - (11 - inpStats[10]) * (1 + inpEffects[4] / 100); // 635 } 636 if (inpEffects[43] != 0 && inpStats[8] != -1) { 637 outStats[8] *= (inpEffects[43] + 100) / 100; 638 } 639 if (inpEffects[16] != 0) { 640 outStats[7] *= inpEffects[16] / -100 + 1; 641 } 642 outStats[18] = inpStats[17] * l; 643 return outStats; 644 } 645 646 function attachmentHandler(currEffects, currStats) { 647 const pos = [], 648 neg = [], 649 atr = []; 650 if (currEffects[0] > currStats[16]) { 651 pos.push( 652 currEffects[0] + 653 "% zoom (+" + 654 (currEffects[0] - currStats[16]) + 655 "% zoom)" 656 ); 657 } else if (currEffects[0] != 0 && currEffects[0] != currStats[16]) { 658 neg.push( 659 currEffects[0] + 660 "% zoom (-" + 661 (currStats[16] - currEffects[0]) + 662 "% zoom)" 663 ); 664 } 665 if (currEffects[0] != 0 && currStats[16] <= 110) { 666 atr.push("Easier to Aim"); 667 } 668 negGood1(1, "ADS time"); 669 negGood1(2, "Vertical Recoil"); 670 negGood1(3, "Horizontal Recoil"); 671 negGood1(4, "Bullet Spread"); 672 negGood1(5, "Moving Bullet Spread"); 673 posGood1(6, "Mobility"); 674 posGood1(7, "ADS Mobility"); 675 negGood1(8, "Recoil when Crouched or Prone"); 676 posGood1(9, "Sprint Mobility"); 677 negGood1(10, "Sprint to Fire Time"); 678 negGood1(11, "Flinch"); 679 negGood1(12, "Hipfire Spread"); 680 posGood1(13, "Damage Range"); 681 negGood1(14, "Reload Time"); 682 posGood1(15, "Headshot Damage"); 683 posGood1(16, "Rate of Fire"); 684 posGood1(17, "Detonation Range"); 685 posGood1(18, "Explosion Radius"); 686 negGood1(19, "Idle Sway"); 687 if (currEffects[20] > currStats[3]) { 688 pos.push( 689 currEffects[20].ToString().Replace(".", " ~ ") + " Explosion Damage" 690 ); 691 } else if (currEffects[20] != 0 && currEffects[20] != currStats[3]) { 692 neg.push( 693 currEffects[20].ToString().Replace(".", " ~ ") + " Explosion Damage" 694 ); 695 } 696 atrPush3(21, "Visible Laser when not ADS-ed"); 697 atrPush3(22, "Visible Laser when ADS-ed"); 698 atrPush3(23, "Visible Laser"); 699 atrPush3(24, "Silenced Gunfire"); 700 atrPush3(25, "Hidden Muzzle Flash"); 701 posGood2(27, "Rounds/Mag"); 702 posGood2(28, "Rounds/Tube"); 703 posGood2(29, "Pellets per Shot"); 704 posGood2(30, "Damage Over Time"); 705 atrPush3(32, "Reworked ADS"); 706 atrPush3(33, "Faster Melee QTE"); 707 if (currEffects[35]) { 708 atr.push( 709 "Can Not use " + 710 currEffects[35] 711 .toString() 712 .padStart(11, "0") 713 .toString() 714 .split("") 715 .map((x, i) => (parseInt(x) !== 0 ? data.attachmentTypes[i] : 0)) 716 .filter(x => x) 717 ); 718 } 719 atrPush3(36, "Can't ADS"); 720 if (currEffects[37] != 0) { 721 atr.push("New Lethality Profile"); 722 } 723 if (currEffects[38] != 0 && currEffects[38] < currStats[4]) { 724 pos.push("Turns to " + data.firingModes[currEffects[38] - 1]); 725 } else if (currEffects[38] != 0 && currEffects[38] != currStats[4]) { 726 neg.push("Turns to " + data.firingModes[currEffects[38] - 1]); 727 } 728 posGood2(39, "Tick Damage"); 729 posGood2(40, "Ticks"); 730 negGood2(41, "ms Tick Interval"); 731 posGood2(42, "Breath Holding Time"); 732 posGood1(43, "Bullet Speed"); 733 if (currEffects[44] == 1) { 734 atr.push("Higher Penetraion Damage"); 735 } else if (currEffects[44] == -1) { 736 atr.push("Lower Penetraion Damage"); 737 } 738 posGood2(45, `Round ${currEffects[45] - 1 ? "s" : ""} in Reserve`); 739 740 function posGood1(i, ext) { 741 if (currEffects[i].IsPositive()) { 742 pos.push(currEffects[i].PlusHL() + "% " + ext); 743 } else if (currEffects[i].IsNegative()) { 744 neg.push(currEffects[i].PlusHL() + "% " + ext); 745 } 746 } 747 748 function negGood1(i, ext) { 749 if (currEffects[i].IsNegative()) { 750 pos.push(currEffects[i].PlusHL() + "% " + ext); 751 } else if (currEffects[i].IsPositive()) { 752 neg.push(currEffects[i].PlusHL() + "% " + ext); 753 } 754 } 755 756 function posGood2(i, ext) { 757 if (currEffects[i].IsPositive()) { 758 pos.push(currEffects[i].PlusHL() + " " + ext); 759 } else if (currEffects[i].IsNegative()) { 760 neg.push(currEffects[i].PlusHL() + " " + ext); 761 } 762 } 763 764 function negGood2(i, ext) { 765 if (currEffects[i].IsNegative()) { 766 pos.push(currEffects[i].PlusHL() + " " + ext); 767 } else if (currEffects[i].IsPositive()) { 768 neg.push(currEffects[i].PlusHL() + " " + ext); 769 } 770 } 771 772 function atrPush3(i, ext) { 773 if (currEffects[i].ToBool()) { 774 atr.push(ext); 775 } 776 } 777 // Return the attributes when there is and use algorithms to join them 778 return [ 779 pos.length 780 ? { 781 name: "**Positives:**", 782 value: `\`\`\`ini\n[${pos.join("]\n[")}]\n\`\`\``, 783 inline: true, 784 } 785 : 0, 786 neg.length 787 ? { 788 name: "**Negatives:**", 789 value: `\`\`\`css\n[${neg.join("]\n[")}]\n\`\`\``, 790 inline: true, 791 } 792 : 0, 793 atr.length 794 ? { 795 name: "**Attributes:**", 796 value: `\`\`\`fix\n[${atr.join("]\n[")}]\n\`\`\``, 797 } 798 : 0, 799 ].filter(x => x); 800 } 801 802 function interpretioner(inpAttachments) { 803 return inpAttachments.length 804 ? " with " + inpAttachments.map(x => x.name).join(", ") 805 : ""; 806 } 807 808 function totaler(inpAttachments) { 809 const totalEffects = inpAttachments[0].effects; 810 for (let j = 1; j < inpAttachments.length; j++) { 811 for (let i2 = 0; i2 < totalEffects.length; i2++) { 812 totalEffects[i2] += inpAttachments[j].effects[i2]; 813 } 814 } 815 return totalEffects; 816 } 817 818 function makeError() { 819 undefined.split("L"); 820 } 821 822 module.exports = { 823 weaponIdentifier, 824 attachmentsIdentifier, 825 recoilHandler, 826 attachmentHandler, 827 updateStatswithEffects, 828 makeError, 829 interpretioner, 830 damageHandler, 831 isolator, 832 totaler, 833 hasAttachments, 834 };