From c43d648279cd9e64ba5565ed2b5318f5b1e0ecb9 Mon Sep 17 00:00:00 2001 From: Izwzyzx <184772711+Izwzyzx@users.noreply.github.com> Date: Tue, 1 Apr 2025 23:01:39 -0500 Subject: [PATCH] Native PvN implementation --- Onequestionmark.hx | 162 +++++++++++++++++++++++++++++++++++++-------- hxbuild.hxml | 1 + 2 files changed, 134 insertions(+), 29 deletions(-) diff --git a/Onequestionmark.hx b/Onequestionmark.hx index e32739c..7845f58 100644 --- a/Onequestionmark.hx +++ b/Onequestionmark.hx @@ -6,6 +6,7 @@ import haxe.Timer; import haxe.Json; import sys.io.File; import sys.FileSystem; +import BigInt; import izzcomlib.IzzComLib.*; using StringTools; @@ -504,50 +505,153 @@ class Onequestionmark { /** - * This function scrapes PVN and replies with the appropriate results. + * This function performs the *Pirate vs Ninja* stat calculations and replies with the appropriate results. * @param choice `p`, `n`, `pvn`, or `nvp`. - * @param query The string to search. - */ + * @param query The name of the character. For dual-character choices, separate names with a pipe. + */ public static function pvn(choice:String,query:String,m:Message) { if (choice.length > 1) { + var splitQuery:Array = []; if (query.contains(" | ")) { - var splitQuery = query.split(" | "); - query = '${splitQuery[0].urlEncode()}&n2=${splitQuery[1].urlEncode()}'; + splitQuery = query.split(" | "); } else { - m.reply({content:'$choice: Must choose two combatants.'}, false); - return; + splitQuery.push(query); + splitQuery.push(query); + } + if (choice == "pvn") { + var pirate = getPirate(splitQuery[0]); + var ninja = getNinja(splitQuery[1]); + printPirate(pirate,m); + printNinja(ninja,m); + + if (pirate.total > ninja.total) { + m.reply({content:'## ${pirate.rank} ${pirate.name} wins!'}, false); + } else if (pirate.total < ninja.total) { + m.reply({content:'## ${ninja.rank} ${ninja.name} wins!'}, false); + } else { + m.reply({content:'## It\'s a TIE!'}, false); + } + } else if (choice == "nvp") { + var ninja = getNinja(splitQuery[0]); + var pirate = getPirate(splitQuery[1]); + printNinja(ninja,m); + printPirate(pirate,m); + + if (pirate.total > ninja.total) { + m.reply({content:'## ${pirate.rank} ${pirate.name} wins!'}, false); + } else if (pirate.total < ninja.total) { + m.reply({content:'## ${ninja.rank} ${ninja.name} wins!'}, false); + } else { + m.reply({content:'## It\'s a TIE!'}, false); + } } } else { - query = query.urlEncode(); + if (choice == "p") {printPirate(getPirate(query),m);} + if (choice == "n") {printNinja(getNinja(query),m);} } - var req = new haxe.Http('https://majcher.com/project/pvn/pvn.cgi?a=${choice.urlEncode()}&n1=${query}'); + } - req.onData = function (request) { - var data = new HtmlDocument(request); - var search = data.find("table>tr>td"); + public static function getPirate(name) { + var pirate:Dynamic = {}; + pirate.name = name; - try { - m.reply({content:'## ${search[0].innerText}\n${search[2].innerText} ${search[3].innerText}\n${search[4].innerText} ${search[5].innerText}\n${search[6].innerText} ${search[7].innerText}\n${search[8].innerText} ${search[9].innerText}\n**${search[10].innerText} ${search[11].innerText}**'}, false); - - if (choice.length > 1) { - var result = data.find('div#result'); + var pweapons = ['Cutlass', 'Pistol', 'Broken Bottle', 'Cannon', 'Attack Parrot', 'Hook Hand', 'Belaying Pin', 'Dagger', 'Grappling Hook', 'A Mean Streak A Mile Wide']; + pirate.swash = (hashString(name, "swashbuckling", 20) + 1); + pirate.drunk = (hashString(name, 'drunkenness', 20) + 1); + pirate.booty = (hashString(name, 'booty', 20) + 1); - m.reply({content:'## ${search[12].innerText}\n${search[14].innerText} ${search[15].innerText}\n${search[16].innerText} ${search[17].innerText}\n${search[18].innerText} ${search[19].innerText}\n${search[20].innerText} ${search[21].innerText}\n**${search[22].innerText} ${search[23].innerText}**'}, false); - - m.reply({content:'## ${result[0].innerText}'}, false); - } - } catch(e) { - m.reply({content:'$choice: Error - $e'}, false); - Sys.println('[${timestamp()}] $choice: Error - $e'); - } + var weapons:Array = []; + var wnum = (hashString(name, "pweapons", 5) - 1); + while (wnum > 0) { + var wsel = pweapons[hashString(name, '$wnum pweapon', pweapons.length - 1)]; + if (!weapons.contains(wsel)) {weapons.push(wsel);} + wnum--; } - req.onError = function (error) { - m.reply({content:'Error in PVN: $error'}, false); - Sys.println('[${timestamp()}] $choice: Error - $error, request was $query'); + pirate.weapons = ""; + for (i in 0...weapons.length) { + if (Std.string(pirate.weapons).length != 0) {pirate.weapons += ", ";} + pirate.weapons = pirate.weapons + weapons[i]; } - req.request(); + pirate.total = pirate.swash + pirate.drunk + pirate.booty + weapons.length; + pirate.rank = "Cabin Boy"; + if (pirate.total > 15) {pirate.rank = 'Pirate';} + if (pirate.total > 30) {pirate.rank = 'Dread Pirate';} + if (pirate.total > 45) {pirate.rank = 'Captain';} + if (pirate.total >= 60) {pirate.rank = 'Pirate King';} + + return(pirate); + } + + public static function getNinja(name) { + var ninja:Dynamic = {}; + ninja.name = name; + + var nweapons = ['Shuriken', 'Katana', 'Poison Dart', 'Death Touch', 'Ninja-To', 'Smoke Bomb', 'Thousand Blossom Finger', 'A Pointy Stick', 'Jo Stick', 'Nunchaku']; + ninja.sneak = (hashString(name, "sneakiness", 20) + 1); + ninja.peejs = (hashString(name, 'pajamas', 20) + 1); + ninja.point = (hashString(name, 'pointy things', 20) + 1); + + var weapons:Array = []; + var wnum = (hashString(name, "nweapons", 5) - 1); + while (wnum > 0) { + var wsel = nweapons[hashString(name, '$wnum nweapon', nweapons.length - 1)]; + if (!weapons.contains(wsel)) {weapons.push(wsel);} + wnum--; + } + + ninja.weapons = ""; + for (i in 0...weapons.length) { + if (Std.string(ninja.weapons).length != 0) {ninja.weapons += ", ";} + ninja.weapons = ninja.weapons + weapons[i]; + } + + ninja.total = ninja.sneak + ninja.peejs + ninja.point + weapons.length; + ninja.rank = "Apprentice"; + if (ninja.total > 15) {ninja.rank = 'Ninja';} + if (ninja.total > 30) {ninja.rank = 'Deadly Ninja';} + if (ninja.total > 45) {ninja.rank = 'Ninja Master';} + if (ninja.total >= 60) {ninja.rank = 'Grandmaster';} + + return(ninja); + } + + public static function printPirate(pirate, m:Message) { + m.reply({content:'## ${pirate.rank} ${pirate.name}\nSwashbuckling: ${pirate.swash}\nDrunkenness: ${pirate.drunk}\nBooty: ${pirate.booty}\nWeapons: ${pirate.weapons}\n**Total: ${pirate.total}**'}, false); + } + + public static function printNinja(ninja, m:Message) { + m.reply({content:'## ${ninja.rank} ${ninja.name}\nSneakiness: ${ninja.sneak}\nPajamas: ${ninja.peejs}\nPointy Things: ${ninja.point}\nWeapons: ${ninja.weapons}\n**Total: ${ninja.total}**'}, false); + } + + /** + * Marc Majcher's string hasher from *Pirate vs Ninja!* + * @param input The input string. + * @param seed An identifying salt to make strings come out differently for different, but same-sized lists. + * @param num The number of buckets you wish to hash into. + */ + public static function hashString(input:String, seed:String, num:BigInt) { + var count:BigInt = 0; + var total:BigInt = 0; + var xorResult = ""; + + // Pad strings until they're equal in length + input = StringTools.rpad(input, String.fromCharCode(0), seed.length); + seed = StringTools.rpad(seed, String.fromCharCode(0), input.length); + + // XOR the input and seed + for (i in 0...(input.length)) { + xorResult = xorResult + String.fromCharCode(input.charCodeAt(i) ^ seed.charCodeAt(i)); + } + + // Calculate stats + for (i in 0...xorResult.length) { + total += (xorResult.charCodeAt(i):BigInt) * ((128:BigInt).pow(count)); + count++; + } + + return(((total * (total + (523:BigInt))) % num).toInt()); } diff --git a/hxbuild.hxml b/hxbuild.hxml index 65e83b1..abbfc8c 100644 --- a/hxbuild.hxml +++ b/hxbuild.hxml @@ -2,6 +2,7 @@ -L hxdiscord -L IzzComLib -L HtmlParser +-L littleBigInt # hxdiscord uses deprecated functions -D no-deprecation-warnings --neko export/onequestionmark.n