Ranked War Reward Split

try to take over the world!

// ==UserScript==
// @name         Ranked War Reward Split
// @namespace    http://tampermonkey.net/
// @version      0.4
// @description  try to take over the world!
// @author       Daviid-P[2851873]
// @match        https://www.torn.com/war.php?step=rankreport&rankID=*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=torn.com
// @grant        none
// @license      GNU GPLv3
// ==/UserScript==

let factionMembers; // Declare factionMembers as a global variable
let totalPoints; // Declare totalPoints as a global variable

(function () {
  "use strict";

  const isElementLoaded = async (selector) => {
    while (document.querySelector(selector) === null) {
      await new Promise((resolve) => requestAnimationFrame(resolve));
    }
    return document.querySelector(selector);
  };

  // Wait for the faction members list to load and then execute the main function
  isElementLoaded("ul.members-list li").then((factions_members_list) => {
    main();
  });
})();

function main() {
  let factions_members_list = document.querySelectorAll("ul.members-list");
  let player_name = document
    .querySelector("script[donator]")
    .getAttribute("name");

  const our_faction_list = Array.from(factions_members_list).find(
    (faction_members_list) =>
      faction_members_list.textContent.includes(player_name)
  );

  const open_dialog_button = createDialogButton(our_faction_list);
  const clearDiv = our_faction_list.parentNode.querySelector("div div.clear");

  // Prepend the button element to the parent of our_faction_list
  if (our_faction_list && our_faction_list.parentNode) {
    our_faction_list.parentNode.insertBefore(
      open_dialog_button,
      our_faction_list
    );
  }

  factionMembers = our_faction_list.querySelectorAll("li");
  totalPoints = Array.from(factionMembers)
    .slice(0, -1)
    .reduce((sum, member) => {
      const memberPoints = parseFloat(
        member.querySelector(".status").textContent
      );
      return sum + memberPoints;
    }, 0);

  const rewardPerAttackHeader = createRewardHeader("1m x Hit");
  const rewardPercentageHeader = createRewardHeader("80/20");

  // Insert column headers before the "clear" div
  clearDiv.parentNode.insertBefore(rewardPerAttackHeader, clearDiv);
  clearDiv.parentNode.insertBefore(rewardPercentageHeader, clearDiv);

  // Initial update of rewards with default values
  updateRewards(0, 0.8, 1000000);
}

// Function to create the open dialog button
function createDialogButton(our_faction_list) {
  const open_dialog_button = document.createElement("button");
  open_dialog_button.textContent = "Open Dialog";
  open_dialog_button.className = "btn btn-primary"; // Add class names
  open_dialog_button.addEventListener("click", () => {
    createDialog();
  });
  return open_dialog_button;
}

// Function to create a column header element
function createRewardHeader(text) {
  const rewardHeader = document.createElement("div");
  rewardHeader.textContent = text;
  rewardHeader.className = "reward-header left";
  rewardHeader.style = "width: 70px; margin-right: 10px;";
  return rewardHeader;
}

// Function to create the dialog element
function createDialog() {
  const dialog = document.createElement("dialog");
  dialog.style.display = "flex";
  dialog.style.flexDirection = "column";
  dialog.style.width = "200px";
  dialog.style.height = "200px";
  dialog.style.justifyContent = "space-around";

  const cacheSellingPriceInputContainer = createNumberInput(
    "Enter reward amount",
    "Reward Amount"
  );
  const rewardDistributionSliderContainer = createSliderInput(
    0,
    100,
    1,
    80,
    "Reward Distribution"
  );
  const pricePerHitInputContainer = createNumberInput(
    "Enter price per hit",
    "Price per Hit"
  );

  const updateButton = document.createElement("button");
  updateButton.textContent = "Update Rewards";
  updateButton.className = "btn btn-primary"; // Add class names
  updateButton.addEventListener("click", () => {
    const cacheSellingPriceInput =
      cacheSellingPriceInputContainer.querySelector("input");
    const rewardDistributionSlider =
      rewardDistributionSliderContainer.querySelector("input");
    const pricePerHitInput = pricePerHitInputContainer.querySelector("input");

      console.error(cacheSellingPriceInput.value)
      console.error(parseLocaleNumber(cacheSellingPriceInput.value))
    const cacheSellingPrice = parseFloat(parseLocaleNumber(cacheSellingPriceInput.value));
    const rewardDistribution = parseFloat(parseLocaleNumber(rewardDistributionSlider.value)) / 100;
    const pricePerHit = parseFloat(parseLocaleNumber(pricePerHitInput.value));
    console.error(
      cacheSellingPrice,
      rewardDistribution,
      pricePerHit
    );

    updateRewards(cacheSellingPrice, rewardDistribution, pricePerHit);

    // Close the dialog after updating the rewards
    dialog.close();
  });

  dialog.appendChild(cacheSellingPriceInputContainer);
  dialog.appendChild(rewardDistributionSliderContainer);
  dialog.appendChild(pricePerHitInputContainer);
  dialog.appendChild(updateButton);

  document.body.appendChild(dialog);
  dialog.showModal();
}

// Function to create a number input element with a label
// Function to create a number input element with a label
function createNumberInput(placeholder, label) {
  const container = document.createElement("div");
  container.style.display = "flex";
  container.style.flexDirection = "column";
  container.style.marginBottom = "10px";

  const labelText = document.createElement("label");
  labelText.textContent = label;

  const numberInput = document.createElement("input");
  numberInput.placeholder = placeholder;
  numberInput.style.padding = "5px";
  numberInput.style.fontSize = "14px";
  numberInput.style.border = "1px solid #ccc";
  numberInput.pattern = "^d{1,3}(,d{3})*(.d+)?$";
  numberInput.dataset.type = "currency";
  numberInput.placeholder = "1,000,000";

  // Add event listeners for formatting the input value with thousands separators
  numberInput.addEventListener("input", formatCurrency);

  container.appendChild(labelText);
  container.appendChild(numberInput);

  return container;
}

// Function to create a slider input element with a label
function createSliderInput(min, max, step, value, label) {
  const container = document.createElement("div");
  container.style.display = "flex";
  container.style.flexDirection = "column";
  container.style.marginBottom = "10px";

  const labelText = document.createElement("label");
  labelText.textContent = label;

  const sliderContainer = document.createElement("div");
  sliderContainer.style.display = "flex";
  sliderContainer.style.alignItems = "center";

  const sliderInput = document.createElement("input");
  sliderInput.type = "range";
  sliderInput.min = min.toString();
  sliderInput.max = max.toString();
  sliderInput.step = step.toString();
  sliderInput.value = value.toString();
  sliderInput.style.flexGrow = "1";

  const valueSpan = document.createElement("span");
  valueSpan.textContent = value.toString();
  valueSpan.style.marginLeft = "10px";

  sliderInput.addEventListener("input", () => {
    valueSpan.textContent = sliderInput.value;
  });

  sliderContainer.appendChild(sliderInput);
  sliderContainer.appendChild(valueSpan);

  container.appendChild(labelText);
  container.appendChild(sliderContainer);

  return container;
}

// Function to update rewards based on the cache selling price, reward distribution, and price per hit
function updateRewards(cacheSellingPrice, rewardDistribution, pricePerHit) {
      const rewardPerAttackHeader = document.querySelector(".reward-header.left");
  const rewardPercentageHeader = document.querySelector(".reward-header.left + .reward-header");

  rewardPerAttackHeader.textContent = `${formatNumberShort(pricePerHit)} x Hit`;
  rewardPercentageHeader.textContent = `${(rewardDistribution * 100).toFixed(0)}/${100-(rewardDistribution * 100).toFixed(0)}`;

  const membersToIterate = Array.from(factionMembers).slice(0, -1);
  membersToIterate.forEach((member) => {
    let clearDiv = member.querySelector("div.clear");
    const memberAttacks = parseFloat(
      member.querySelector(".points").textContent
    );
    const memberPoints = parseFloat(
      member.querySelector(".status").textContent
    );
    const memberId = new URLSearchParams(document.querySelector("div.member a").href).get("ID");

    let rewardPerAttack = member.querySelector(".reward-per-attack");
    let rewardPercentage = member.querySelector(".reward-percentage");

    if (!rewardPerAttack) {
      rewardPerAttack = document.createElement("div");
      rewardPerAttack.className = "reward-per-attack left";
      rewardPerAttack.style =
        "width: 70px; height: 33px; line-height: 36px; text-align: right; padding-right: 10px; margin-right: 10px;";
      member.insertBefore(rewardPerAttack, clearDiv);
    }

    if (!rewardPercentage) {
      rewardPercentage = document.createElement("div");
      rewardPercentage.className = "reward-percentage left";
      rewardPercentage.style =
        "width: 70px; height: 33px; line-height: 36px; text-align: right; padding-right: 10px; margin-right: 10px;";
      member.insertBefore(rewardPercentage, clearDiv);
    }

    const textSpan = document.createElement("span");

    while (rewardPerAttack.firstChild) {
      rewardPerAttack.removeChild(rewardPerAttack.firstChild);
    }
    while (rewardPercentage.firstChild) {
      rewardPercentage.removeChild(rewardPercentage.firstChild);
    }

    const attacks = memberAttacks * pricePerHit;
    rewardPerAttack.textContent = attacks;
    rewardPerAttack.innerHTML = `<a href="https://www.torn.com/factions.php?step=your#/tab=controls&option=pay-day&select=${memberId}&pay=${attacks}">${attacks.toLocaleString()}</a>`;

    const reward = Math.floor(
      (memberPoints / totalPoints) * (cacheSellingPrice * rewardDistribution)
    );
    rewardPercentage.innerHTML = `<a href="https://www.torn.com/factions.php?step=your#/tab=controls&option=pay-day&select=${memberId}&pay=${reward}">${reward.toLocaleString()}</a>`;
  });
}

function parseLocaleNumber(stringNumber) {
  var thousandSeparator = Intl.NumberFormat("en-EN")
    .format(11111)
    .replace(/\p{Number}/gu, "");
  var decimalSeparator = Intl.NumberFormat("en-EN")
    .format(1.1)
    .replace(/\p{Number}/gu, "");

  return parseFloat(
    stringNumber
      .replace(new RegExp("\\" + thousandSeparator, "g"), "")
      .replace(new RegExp("\\" + decimalSeparator), ".")
  );
}

function formatNumber(n) {
  // format number 1000000 to 1,234,567
  return n.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

function formatNumberShort(number) {
const suffixes = ["", "k", "m", "b", "t"];
let suffixIndex = 0;
while (number >= 1000 && suffixIndex < suffixes.length - 1) {
number /= 1000;
suffixIndex++;
}
return number.toLocaleString() + suffixes[suffixIndex];
}

function formatCurrency(event) {
  // appends $ to value, validates decimal side
  // and puts cursor back in right position.

  let input = event.target;
  let blur = event.type;

  // get input value
  var input_val = input.value;

  // dont validate empty input
  if (input_val === "") {
    return;
  }

  // original length
  var original_len = input_val.length;

  // initial caret position
  var caret_pos = input.selectionStart;

  // check for decimal
  if (input_val.indexOf(".") >= 0) {
    // get position of first decimal
    // this prevents multiple decimals from
    // being entered
    var decimal_pos = input_val.indexOf(".");

    // split number by decimal point
    var left_side = input_val.substring(0, decimal_pos);
    var right_side = input_val.substring(decimal_pos);

    // add commas to left side of number
    left_side = formatNumber(left_side);

    // validate right side
    right_side = formatNumber(right_side);

    // On blur make sure 2 numbers after decimal
    if (blur === "blur") {
      right_side += "00";
    }

    // Limit decimal to only 2 digits
    right_side = right_side.substring(0, 2);

    // join number by .
    input_val = left_side + "." + right_side;
  } else {
    // no decimal entered
    // add commas to number
    // remove all non-digits
    input_val = formatNumber(input_val);
    input_val = input_val;

    // final formatting
    if (blur === "blur") {
      input_val += ".00";
    }
  }

  // send updated string to input
  input.value = input_val;

  // put caret back in the right position
  var updated_len = input_val.length;
  caret_pos = updated_len - original_len + caret_pos;
  input.setSelectionRange(caret_pos, caret_pos);
}

function addCustomCSS(css) {
  const styleElement = document.createElement("style");
  styleElement.textContent = css;

  const headElement = document.querySelector("head");
  headElement.appendChild(styleElement);
}

// CSS styles
const customCSS = `
  .btn {
    display: inline-block;
    font-weight: 400;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    user-select: none;
    border: 1px solid transparent;
    padding: 0.375rem 0.75rem;
    font-size: 1rem;
    line-height: 1.5;
    border-radius: 0.25rem;
    cursor: pointer;
    transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
  }

  .btn-primary {
    color: #fff;
    background-color: #007bff;
    border-color: #007bff;
  }

  .reward-per-attack a,
  .reward-percentage a{
    text-decoration: none;
    color: inherit;
  }
`;

// Add custom CSS to the document
addCustomCSS(customCSS);