NATION

PASSWORD

Wolfram and Hart - Sleeping Beauty

Talk about regional management and politics, raider/defender gameplay, and other game-related matters.
Not a roleplaying forum.

Advertisement

Remove ads

User avatar
Wolfram and Hart
Secretary
 
Posts: 35
Founded: Jul 06, 2017
Father Knows Best State

Postby Wolfram and Hart » Thu Oct 25, 2018 2:53 pm

Sleeping Beauty

What
This code logs in your puppets, and answers their issues according to pre-defined rules.

When setting up the code, the user gives it a target completion time. This is initially set to 60 minutes, though is easily changed. The code will try to answer issues for all your puppets within this time frame. It may finish sooner. Depending on the number of puppets, it may take longer. Your PC must be switched on the entire time the code is running, else some puppets may not get processed.

The code randomly chooses a time to log in each puppet, subject to the target completion time you give.

The code logs into a puppet, records which region the puppet is in, how many unread notifications, telegrams, RMB posts, and issues there are. If the nation is your WA nation, it will be displayed in red. The code then starts answering issues according to pre-defined rules. The code tries to leave gaps of 20 to 80 seconds between answering issues. The purpose of this delay is to try and make it look like a real player is making considered decisions.

If your target completion time is short, then a keen observer may notice that your puppets log in and answer issues at similar times. If your target completion time is longer, then it is harder for an observer to associate your puppets with each other.

The code allows for puppets to be processed concurrently - so Puppet1 can answer issues inbetween Puppet2's answers to their own issues. This behaviour aims to make it look more like the puppets are controlled by different players.

At the end of processing, the code should display a pop-up stating "Done".

The available pre-defined rules are:
1st: The code will always select the first issue answer that is available to the puppet.
2nd: The code will always select the second issue answer that is available to the puppet.
2nd last: The code will always select the second last issue answer that is available to the puppet.
last: The code will always select the last issue answer that is available to the puppet.
random: The code will always select a random issue answer that is available to the puppet.
If you give the code an unrecognised value for the rule (eg you tell the code to use "first" instead of "1st"), the code will not answer issues for that puppet.

These rules will not allow your puppets to follow a consistent political ideology, or to maximise a particular census score. To do so would require rules that can identify which issue answer was appropriate for your objective, for each of the 1000+ issues.


How
On your PC or laptop, open a text editor, like Notepad. Copy the code (below) into the editor.

Put your own email address in the code (place indicated by all the asterisks).

Put your own Nation names, passwords, and issue-answering styles (pre-defined rules) in the code (place indicated by all the asterisks).

Set your own target completion time (in minutes) in the code (place indicated by all the asterisks).

REMEMBER: If you share your computer, then potentially someone else will have access to your passwords.

Save the file as “SleepingBeauty.html”

Check the filename. If it saved as “SleepingBeauty.html.txt” or similar, rename it to “SleepingBeauty.html”.

When you open the file again, it should get opened in your browser by default. You should see a black page with “Wolfram & Hart” written across the top.

When you click the button, the code should send login requests to NS. NS then sends a response back, which will be displayed on your webpage.


Why
If you don't know why, this code probably isn't for you!


Feedback
If you use this, the Telegram script, or the PuppetMaster Login script, please drop me a telegram. It would be interesting to know how widely these were used.
Any suggestions for improvements and enhancements are welcome.

Code: Select all
<!DOCTYPE html>

<!-- Wolfram & Hart Sleeping Beauty v1.0

     Version | Date        | Name           | Comment
     1.0     | 25 Oct 2018 | Wolfram & Hart | Created

     This code is not warranted in any way.  Use at your own risk.

     Use and modify this code as suits.
     Make sure you comply with the NationStates API rules.
     See:  https://www.nationstates.net/pages/api.html

     Feedback: If you use this script, please drop [nation]Wolfram & Hart[/nation] a telegram. 
     It would be interesting to know how widely this was used (if at all!)
     Any suggestions for improvements and enhancements are welcome.
-->

<head>
  <title>W&H Sleeping Beauty</title>
  <style>
    body {background-color: black;}
    div {
      text-align: center;
      color: white;
      font-family: times;
    }
    table,th,td {
      border : 1px solid white;
      border-collapse: collapse;
    }
    th,td {
      padding: 5px;
    }
  </style>
</head>

<body>
  <div>
    <h1><span style="font-size:120%;">W</span>OLFRAM <span style="color:red; font-size:120%;">&</span> <span style="font-size:120%;">H</span>ART</h1>
    <h3>Sleeping Beauty</h3>
    <br>
    <button type="button" onclick="fMain()">Process Puppets</button>
    <p><i>(Click table header to sort data)</i></p>
    <p id="log"></p>
    <p id="err"></p>
    <table id="msg" align=center><tr>
      <th onclick="fSortNtns('ntn')">Nation</th>
      <th onclick="fSortNtns('rgn')">Region</th>
      <th onclick="fSortNtns('ntc')">Notices</th>
      <th onclick="fSortNtns('tgs')">Telegrams</th>
      <th onclick="fSortNtns('rmb')">RMB</th>
      <th onclick="fSortNtns('iss')">Issues</th>
    </tr></table>
  </div>

  <!-- This is the JavaScript that will be run when the button is pressed -->
  <script>


    /* **********************CHANGE THIS TO USE YOUR OWN EMAIL ADDRESS********************** */
    /* NationStates require a 'UserAgent', so you can be contacted if something goes wrong   */
    var strUserAgent = "myname@email.com";
    /* ************************************************************************************* */


    /* ***********CHANGE THIS ARRAY TO INCLUDE YOUR NATIONS, PASSWORDS, AND STYLES********** */
    var aobjNtns = [
      {nation:"Nation 1", password:"Password1", style:"1st"},
      {nation:"Nation 2", password:"Password2", style:"2nd"},
      {nation:"Nation 3", password:"Password3", style:"2nd last"},
      {nation:"Nation 4", password:"Password4", style:"last"},
      {nation:"Last Nation", password:"LastPassword", style:"random"}
    ];
    /*
    var aobjNtns = [
    ];
    */
    /* ************************************************************************************* */


    /* *****************SET THE TIME (IN MINUTES) TO TRY AND FINISH BY********************** */
    var intEnd = 60;
    /* ************************************************************************************* */


    var strPasswordType = "X-Password";   // Tell NS the format of the above passwords.  This info is needed by NS
    var dteNow;            // Used at various points to record the current time
    var strNtnLast = "";      // Record the last nation processed to determine whether Pin or Password is used for next login.

    var strErr;            // Set variables to record the nations processed.  These are used to update the html.
    var strMsg;
    var strHdr = document.getElementById("msg").innerHTML;
    var strSort = "";

    /* The fMain function:
       Convert the target end time, intEnd, to millisecconds, and subtract estimated required processing times.
       After this convertion, intEnd represents the latest time that the code should start handling a nation.
       Reset the 'msg' table to being blank.
       Put the list of nations into a random order, then adds them to the request queue.
       Tell the code to login the first nation in the queue.
    */
    function fMain() {
      dteNow = new Date().getTime();               // Note the time.  Used when adding nations to the request queue
      intEnd = (intEnd * 60000) - (aobjNtns.length * 1200) - 400000;   // Convert target end time to ms and adjust
      if (intEnd < 0) { intEnd = 1000; };            // Make sure the new end time is at least one second long!
      strErr = "";                     // Reset the message strings and blank out the html
      strMsg = strHdr;
      document.getElementById("err").innerHTML = strErr;
      document.getElementById("msg").innerHTML = strMsg;
      aobjNtns = aobjNtns.map(fRemapNtns);            // Add some extra detail to the nation records
      aobjRqst = aobjNtns.map(fAddNtnsToRqstQueue);         // Add the nations to the request queue
      aobjRqst.sort(fSortWhen);                  // Sort requests into the order in which they'll be made
      fGetXml();                     // Request the first item in the request queue
    }

    /* fRemapNtns expands each Nation object to hold the data that will be returned from NS */
    function fRemapNtns(value, index, array) {
      return {
        name: value.nation,
        ntn: value.nation.toLowerCase().replace(/ /g, "_"),
        styl: value.style.toLowerCase(),
        pwrdtyp: strPasswordType,
        pwrd: value.password,
        pin: "",
        wa: "",
        rgn: "?",
        ntc: -1,
        tgs: -1,
        rmb: -1,
        iss: -1
      };
    }

    /* fAddNtnsToRqstQueue takes the list of nations and passwords, and adds them to a queue of requests to be sent to NS
       Set a random time, based on intEnd, to start handling the nation.
    */
    function fAddNtnsToRqstQueue(value, index, array) {
      return {
        ntn: value.ntn,
        rqst: "&q=wa+name+region+unread+issues",
        pwrdtyp: value.pwrdtyp,
        pwrd: value.pwrd,
        when: dteNow + intEnd * Math.random()
      };
    }

    /* function to sort array by scheduled request time */
    function fSortWhen(a,b) {
      return a.when - b.when;
    }

    /* fGetXml takes the first request to be processed, then requests the XML from NS
       When the result is back, call fProcessXml.
    */
    function fGetXml() {
      if (aobjRqst.length > 0) {
        var objRqst = aobjRqst.shift();            // Take the first item in the queue
        var objXhttp = new XMLHttpRequest();                    // Create an object to send the details to NS
        objXhttp.onreadystatechange = function() {
          if (objXhttp.readyState == 4) {
            if (objXhttp.status == 200) {
              fProcessXml(this);            // When a response is received from NS, process it
            } else {
              if (objXhttp.status == 403) {
                strErr = objRqst.ntn + ": Forbidden (incorrect password?)<br>" + strErr;
              } else if (objXhttp.status == 404) {
                strErr = objRqst.ntn + ": Not Found (nation CTEd / misspelled / doesn't exist?)<br>" + strErr;
              } else if (objXhttp.status == 429) {
                strErr = objRqst.ntn + ": Too Many Requests.  Processing stopped<br>" + strErr;
              } else {
                strErr = objRqst.ntn + ": Error " + objXhttp.status + "<br>" + strErr;
              };
              document.getElementById("err").innerHTML = strErr;
            };
          };
        };
        // Set the details of the request:
        objXhttp.open("GET", "https://www.nationstates.net/cgi-bin/api.cgi?nation=" + objRqst.ntn + objRqst.rqst, true);
        if (objRqst.ntn == strNtnLast) {
          var i = 0;
          while (aobjNtns[i].ntn != strNtnLast) { i++; };         // Find the matching nation in aobjNtns
          objXhttp.setRequestHeader("X-Pin", aobjNtns[i].pin);         // If this request is for the same nation as the last,
          objXhttp.setRequestHeader(objRqst.pwrdtyp, objRqst.pwrd);      // use the Pin.  Send password as well, just in case
        } else {
          objXhttp.setRequestHeader(objRqst.pwrdtyp, objRqst.pwrd);      // Else set to use the password, and
          strNtnLast = objRqst.ntn;                  // record that this nation is now the latest nation
        };
        objXhttp.setRequestHeader("User-Agent", strUserAgent);         // Set to send the User-Agent too
        objXhttp.send();                     // Send the request to NS
      };
    }

    /* fProcess:
       Reads in the XML data.
       Updates the nation with the new Pin
       Works out when to call the routine that sends the next request
    */
    function fProcessXml(objXhttp) {
      dteNow = new Date().getTime();
      var objXML = objXhttp.responseXML;               // Read in the body of the returned data
      var strNtn = objXML.getElementsByTagName("NATION")[0].getAttribute("id");   // Read the nation ID
      var i = 0;
      while (aobjNtns[i].ntn != strNtn) { i++; };            // Find the matching nation in aobjNtns
      var strPin = objXhttp.getResponseHeader("X-Pin");            // Read in the pin from returned data header
      if (strPin != null) { aobjNtns[i].pin = strPin; };         // Assign the pin to the nation
      if (objXML.getElementsByTagName("UNREAD").length > 0) {
        fProcessFirst(objXhttp, strNtn, i);         // If this was the first request for the nation, process accordingly
      } else {
        fProcessIssue(objXML, i);            // If this was the result of answering an issue, process accordingly
      };
      if (aobjRqst.length > 0) {
        var intWhen = aobjRqst[0].when - dteNow;      // If there are more requests in the queue, work out when to send the next
        if (intWhen < 1200) { intWhen = 1200; };
        setTimeout(function(){ fGetXml() }, intWhen);
      } else {
        window.alert("Done");               // Else notify the user that the job is complete
      };
    }

    /* fProcess reads in the XML data.
    */
    function fProcessFirst(objXhttp, strNtn, i) {
      var dteWhen = dteNow;
      var strTmp
      var objXML = objXhttp.responseXML;                     // Read in the body of the returned data
      aobjNtns[i].pwrdtyp = "X-Autologin";
      var strPwrd = objXhttp.getResponseHeader("X-Autologin");               // Read in the password from returned data header
      aobjNtns[i].pwrd = strPwrd;                        // Update the nation with the returned data
      aobjNtns[i].wa = objXML.getElementsByTagName("UNSTATUS")[0].childNodes[0].nodeValue;
      aobjNtns[i].rgn = objXML.getElementsByTagName("REGION")[0].childNodes[0].nodeValue;
      aobjNtns[i].ntc = objXML.getElementsByTagName("NOTICES")[0].childNodes[0].nodeValue;
      aobjNtns[i].tgs = objXML.getElementsByTagName("TELEGRAMS")[0].childNodes[0].nodeValue;
      aobjNtns[i].rmb = objXML.getElementsByTagName("RMB")[0].childNodes[0].nodeValue;
      aobjNtns[i].iss = objXML.getElementsByTagName("ISSUES")[0].childNodes[0].nodeValue;
      var aobjIss = objXML.getElementsByTagName("ISSUE");               // Create an array of the issues data
      var strOpt = "ignore";
      for (var j = 0; j < aobjIss.length; j++) {
        var aobjOpts = aobjIss[j].getElementsByTagName('OPTION');            // For each issue, find the options & choose response
        switch (aobjNtns[i].styl) {
          case "random":
            strOpt = aobjOpts[Math.floor(Math.random() * aobjOpts.length)].getAttribute('id');   // Choose a random answer
            break;
          case "1st":
            strOpt = aobjOpts[0].getAttribute('id');                  // Choose the first available answer
            break;
          case "2nd":
            strOpt = aobjOpts[1].getAttribute('id');                  // Choose the second available answer
            break;
          case "2nd last":
            strOpt = aobjOpts[aobjOpts.length - 2].getAttribute('id');            // Choose the second last answer
            break;
          case "last":
            strOpt = aobjOpts[aobjOpts.length - 1].getAttribute('id');            // Choose the last answer
            break;
        };                                 // Else the default treatment is to ignore issues
        if (strOpt != "ignore") {
          dteWhen = dteWhen + 20000 + 60000 * Math.random();               // Set the gap between issue answers to 20 to 80 seconds
          var objRqst = {
            ntn: strNtn,
            rqst: "&c=issue&issue=" + aobjIss[j].getAttribute("id") + "&option=" + strOpt,
            pwrdtyp: "X-Autologin",
            pwrd: strPwrd,
            when: dteWhen
          };
          aobjRqst.push(objRqst);                        // Add the nation, issue, and answer to the request queue
        };   
      };
      aobjRqst.sort(fSortWhen);                           // Make sure the request queue is in the right order     
      fSortNtns(strSort);                           // Update the visible HTML table
    }   

    /* fProcessIssue:
       Reduces the nation's issue count by one, if an issue was successfully answered
    */
    function fProcessIssue(objXML, i) {
      if (objXML.getElementsByTagName("OK").length > 0) {
        aobjNtns[i].iss = aobjNtns[i].iss - 1;            // If the issue was successfully answered, reduce the number of outstanding issues
        fSortNtns(strSort);                  // Update the visible HTML table
      };
    }

    function fSortNtns(strBy) {
      strSort = strBy; 
      switch (strBy) {
        case "ntn":
          aobjNtns.sort(fSortNtn);
          break;
        case "rgn":
          aobjNtns.sort(fSortRgn);
          break;
        case "ntc":
          aobjNtns.sort(fSortNtc);
          break;
        case "tgs":
          aobjNtns.sort(fSortTgs);
          break;
        case "rmb":
          aobjNtns.sort(fSortRmb);
          break;
        case "iss":
          aobjNtns.sort(fSortIss);
          break;
      };
      fUpdateTable();
    }

    /* function to sort array by nation */
    function fSortNtn(a,b) {
      var x = a.ntn.toLowerCase();
      var y = b.ntn.toLowerCase();
      if (x < y) { return -1; };
      if (x > y) { return 1; };
      return 0;
    }

    /* function to sort array by region */
    function fSortRgn(a,b) {
      var x = a.rgn.toLowerCase();
      var y = b.rgn.toLowerCase();
      if (x < y) { return -1; };
      if (x > y) { return 1; };
      return 0;
    }

    /* function to sort array by nation sort order */
    function fSortNtc(a,b) {
      return b.ntc - a.ntc;
    }

    /* function to sort array by nation sort order */
    function fSortTgs(a,b) {
      return b.tgs - a.tgs;
    }

    /* function to sort array by nation sort order */
    function fSortRmb(a,b) {
      return b.rmb - a.rmb;
    }

    /* function to sort array by nation sort order */
    function fSortIss(a,b) {
      return b.iss - a.iss;
    }

    /*
    */
    function fUpdateTable() {
      var i;
      var strMsg = strHdr;                     // Set the table header
      var strNtc;
      var strTgs;
      var strRmb;
      var strIss;
      for (i = 0; i < aobjNtns.length; i++) {
        if (aobjNtns[i].wa == "WA Member") {
          strMsg = strMsg + "<tr style='color:red;'>";            // Set to display any WA nation in red
        } else {
          strMsg = strMsg + "<tr>";
        };
        strNtc = aobjNtns[i].ntc;                  // If 'unread' counts are unknown, display them as "?"
        if (strNtc < 0) { strNtc = "?" };
        strTgs= aobjNtns[i].tgs;
        if (strTgs < 0) { strTgs = "?" };
        strRmb = aobjNtns[i].rmb;
        if (strRmb < 0) { strRmb = "?" };
        strIss = aobjNtns[i].iss;
        if (strIss < 0) { strIss = "?" };
        strMsg = strMsg + "<td>"
          + aobjNtns[i].name + "</td><td>" + aobjNtns[i].rgn + "</td><td>"
          + strNtc + "</td><td>" + strTgs + "</td><td>"
          + strRmb + "</td><td>" + strIss + "</td></tr>";         // Add details of each nation
      };
      document.getElementById("msg").innerHTML = strMsg;         // Output the complete data to the HTML table
    }
  </script>
</body>
</html>


Edit: Version 1.2. Returns SPDR for each nation. Code skips over unrecognised / CTEd nations instead of stopping.

Code: Select all
<!DOCTYPE html>

<!-- Wolfram & Hart Sleeping Beauty v1.2

     Version | Date        | Name           | Comment
     1.0     | 25 Oct 2018 | Wolfram & Hart | Created
     1.2     | 19 Nov 2018 | Wolfram & Hart | Included SPDR. Continues processing if nation or password invalid.

     This code is not warranted in any way.  Use at your own risk.

     Use and modify this code as suits.
     Make sure you comply with the NationStates API rules.
     See:  https://www.nationstates.net/pages/api.html
-->

<head>
  <title>W&H Sleeping Beauty</title>
  <style>
    body {background-color: black;}
    div {
      text-align: center;
      color: white;
      font-family: times;
    }
    table,th,td {
      border : 1px solid white;
      border-collapse: collapse;
    }
    th,td {
      padding: 5px;
    }
  </style>
</head>

<body>
  <div>
    <h1><span style="font-size:120%;">W</span>OLFRAM <span style="color:red; font-size:120%;">&</span> <span style="font-size:120%;">H</span>ART</h1>
    <h3>Sleeping Beauty</h3>
    <br>
    <button type="button" onclick="fMain()">Process Puppets</button>
    <p><i>(Click table header to sort data)</i></p>
    <p id="log"></p>
    <p id="err"></p>
    <table id="msg" align=center><tr>
      <th onclick="fSortNtns('ntn')">Nation</th>
      <th onclick="fSortNtns('rgn')">Region</th>
      <th onclick="fSortNtns('ntc')">Notices</th>
      <th onclick="fSortNtns('tgs')">Telegrams</th>
      <th onclick="fSortNtns('rmb')">RMB</th>
      <th onclick="fSortNtns('iss')">Issues</th>
      <th onclick="fSortNtns('spdr')">Influence</th>
    </tr></table>
  </div>

  <!-- This is the JavaScript that will be run when the button is pressed -->
  <script>


    /* **********************CHANGE THIS TO USE YOUR OWN EMAIL ADDRESS********************** */
    /* NationStates require a 'UserAgent', so you can be contacted if something goes wrong   */
    var strUserAgent = "myname@email.com";
    /* ************************************************************************************* */


    /* ***********CHANGE THIS ARRAY TO INCLUDE YOUR NATIONS, PASSWORDS, AND STYLES********** */
    var aobjNtns = [
      {nation:"Nation 1", password:"Password1", style:"1st"},
      {nation:"Nation 2", password:"Password2", style:"2nd"},
      {nation:"Nation 3", password:"Password3", style:"2nd last"},
      {nation:"Nation 4", password:"Password4", style:"last"},
      {nation:"Last Nation", password:"LastPassword", style:"random"}
    ];
    /* ************************************************************************************* */


    /* *****************SET THE TIME (IN MINUTES) TO TRY AND FINISH BY********************** */
    var intEnd = 60;
    /* ************************************************************************************* */


    var strPasswordType = "X-Password";   // Tell NS the format of the above passwords.  This info is needed by NS
    var dteNow;            // Used at various points to record the current time
    var strNtnLast = "";      // Record the last nation processed to determine whether Pin or Password is used for next login.

    var strErr;            // Set variables to record the nations processed.  These are used to update the html.
    var strMsg;
    var strHdr = document.getElementById("msg").innerHTML;
    var strSort = "";

    /* The fMain function:
       Convert the target end time, intEnd, to millisecconds, and subtract estimated required processing times.
       After this convertion, intEnd represents the latest time that the code should start handling a nation.
       Reset the 'msg' table to being blank.
       Put the list of nations into a random order, then adds them to the request queue.
       Tell the code to login the first nation in the queue.
    */
    function fMain() {
      dteNow = new Date().getTime();               // Note the time.  Used when adding nations to the request queue
      intEnd = (intEnd * 60000) - (aobjNtns.length * 1200) - 400000;   // Convert target end time to ms and adjust
      if (intEnd < 0) { intEnd = 1000; };            // Make sure the new end time is at least one second long!
      strErr = "";                     // Reset the message strings and blank out the html
      strMsg = strHdr;
      document.getElementById("err").innerHTML = strErr;
      document.getElementById("msg").innerHTML = strMsg;
      aobjNtns = aobjNtns.map(fRemapNtns);            // Add some extra detail to the nation records
      aobjRqst = aobjNtns.map(fAddNtnsToRqstQueue);         // Add the nations to the request queue
      aobjRqst.sort(fSortWhen);                  // Sort requests into the order in which they'll be made
      fGetXml();                     // Request the first item in the request queue
    }

    /* fRemapNtns expands each Nation object to hold the data that will be returned from NS */
    function fRemapNtns(value, index, array) {
      return {
        name: value.nation,
        ntn: value.nation.toLowerCase().replace(/ /g, "_"),
        styl: value.style.toLowerCase(),
        pwrdtyp: strPasswordType,
        pwrd: value.password,
        pin: "",
        wa: "",
        rgn: "?",
        ntc: -1,
        tgs: -1,
        rmb: -1,
        iss: -1,
        spdr: -1
      };
    }

    /* fAddNtnsToRqstQueue takes the list of nations and passwords, and adds them to a queue of requests to be sent to NS
       Set a random time, based on intEnd, to start handling the nation.
    */
    function fAddNtnsToRqstQueue(value, index, array) {
      return {
        ntn: value.ntn,
        rqst: "&q=wa+name+region+unread+issues+census;scale=65;mode=score",
        pwrdtyp: value.pwrdtyp,
        pwrd: value.pwrd,
        when: dteNow + intEnd * Math.random()
      };
    }

    /* function to sort array by scheduled request time */
    function fSortWhen(a,b) {
      return a.when - b.when;
    }

    /* fGetXml takes the first request to be processed, then requests the XML from NS
       When the result is back, call fProcessXml.
    */
    function fGetXml() {
      if (aobjRqst.length > 0) {
        var objRqst = aobjRqst.shift();            // Take the first item in the queue
        var objXhttp = new XMLHttpRequest();                    // Create an object to send the details to NS
        objXhttp.onreadystatechange = function() {
          if (objXhttp.readyState == 4) {
            if (objXhttp.status == 200) {
              fProcessXml(this);            // When a response is received from NS, process it
            } else {
              if (objXhttp.status == 403) {
                strErr = objRqst.ntn + ": Forbidden (incorrect password?)<br>" + strErr;
                fGetNext();
              } else if (objXhttp.status == 404) {
                strErr = objRqst.ntn + ": Not Found (nation CTEd / misspelled / doesn't exist?)<br>" + strErr;
                fGetNext();
              } else if (objXhttp.status == 429) {
                strErr = objRqst.ntn + ": Too Many Requests.  Processing stopped<br>" + strErr;
              } else {
                strErr = objRqst.ntn + ": Error " + objXhttp.status + "<br>" + strErr;
              };
              document.getElementById("err").innerHTML = strErr;
            };
          };
        };
        // Set the details of the request:
        objXhttp.open("GET", "https://www.nationstates.net/cgi-bin/api.cgi?nation=" + objRqst.ntn + objRqst.rqst, true);
        if (objRqst.ntn == strNtnLast) {
          var i = 0;
          while (aobjNtns[i].ntn != strNtnLast) { i++; };         // Find the matching nation in aobjNtns
          objXhttp.setRequestHeader("X-Pin", aobjNtns[i].pin);         // If this request is for the same nation as the last,
          objXhttp.setRequestHeader(objRqst.pwrdtyp, objRqst.pwrd);      // use the Pin.  Send password as well, just in case
        } else {
          objXhttp.setRequestHeader(objRqst.pwrdtyp, objRqst.pwrd);      // Else set to use the password, and
          strNtnLast = objRqst.ntn;                  // record that this nation is now the latest nation
        };
        objXhttp.setRequestHeader("User-Agent", strUserAgent);         // Set to send the User-Agent too
        objXhttp.send();                     // Send the request to NS
      };
    }

    /* fGetNext sets up when to call fGetXML again */
    function fGetNext() {
      dteNow = new Date().getTime();
      if (aobjRqst.length > 0) {
        var intWhen = aobjRqst[0].when - dteNow;      // If there are more requests in the queue, work out when to send the next
        if (intWhen < 1200) { intWhen = 1200; };
        setTimeout(function(){ fGetXml() }, intWhen);
      } else {
        window.alert("Done");               // Else notify the user that the job is complete
      };
    }

    /* fProcess:
       Reads in the XML data.
       Updates the nation with the new Pin
       Works out when to call the routine that sends the next request
    */
    function fProcessXml(objXhttp) {
      // dteNow = new Date().getTime();
      var objXML = objXhttp.responseXML;               // Read in the body of the returned data
      var strNtn = objXML.getElementsByTagName("NATION")[0].getAttribute("id");   // Read the nation ID
      var i = 0;
      while (aobjNtns[i].ntn != strNtn) { i++; };            // Find the matching nation in aobjNtns
      var strPin = objXhttp.getResponseHeader("X-Pin");            // Read in the pin from returned data header
      if (strPin != null) { aobjNtns[i].pin = strPin; };         // Assign the pin to the nation
      if (objXML.getElementsByTagName("UNREAD").length > 0) {
        fProcessFirst(objXhttp, strNtn, i);         // If this was the first request for the nation, process accordingly
      } else {
        fProcessIssue(objXML, i);            // If this was the result of answering an issue, process accordingly
      };
      fGetNext();
    }

    /* fProcess reads in the XML data.
    */
    function fProcessFirst(objXhttp, strNtn, i) {
      var dteWhen = dteNow;
      var strTmp
      var objXML = objXhttp.responseXML;                     // Read in the body of the returned data
      aobjNtns[i].pwrdtyp = "X-Autologin";
      var strPwrd = objXhttp.getResponseHeader("X-Autologin");               // Read in the password from returned data header
      aobjNtns[i].pwrd = strPwrd;                        // Update the nation with the returned data
      aobjNtns[i].wa = objXML.getElementsByTagName("UNSTATUS")[0].childNodes[0].nodeValue;
      aobjNtns[i].rgn = objXML.getElementsByTagName("REGION")[0].childNodes[0].nodeValue;
      aobjNtns[i].ntc = objXML.getElementsByTagName("NOTICES")[0].childNodes[0].nodeValue;
      aobjNtns[i].tgs = objXML.getElementsByTagName("TELEGRAMS")[0].childNodes[0].nodeValue;
      aobjNtns[i].rmb = objXML.getElementsByTagName("RMB")[0].childNodes[0].nodeValue;
      aobjNtns[i].iss = objXML.getElementsByTagName("ISSUES")[0].childNodes[0].nodeValue;
      aobjNtns[i].spdr = Number(objXML.getElementsByTagName("SCORE")[0].childNodes[0].nodeValue);
      var aobjIss = objXML.getElementsByTagName("ISSUE");               // Create an array of the issues data
      var strOpt = "ignore";
      for (var j = 0; j < aobjIss.length; j++) {
        var aobjOpts = aobjIss[j].getElementsByTagName('OPTION');            // For each issue, find the options & choose response
        switch (aobjNtns[i].styl) {
          case "random":
            strOpt = aobjOpts[Math.floor(Math.random() * aobjOpts.length)].getAttribute('id');   // Choose a random answer
            break;
          case "1st":
            strOpt = aobjOpts[0].getAttribute('id');                  // Choose the first available answer
            break;
          case "2nd":
            strOpt = aobjOpts[1].getAttribute('id');                  // Choose the second available answer
            break;
          case "2nd last":
            strOpt = aobjOpts[aobjOpts.length - 2].getAttribute('id');            // Choose the second last answer
            break;
          case "last":
            strOpt = aobjOpts[aobjOpts.length - 1].getAttribute('id');            // Choose the last answer
            break;
        };                                 // Else the default treatment is to ignore issues
        if (strOpt != "ignore") {
          dteWhen = dteWhen + 20000 + 60000 * Math.random();               // Set the gap between issue answers to 20 to 80 seconds
          var objRqst = {
            ntn: strNtn,
            rqst: "&c=issue&issue=" + aobjIss[j].getAttribute("id") + "&option=" + strOpt,
            pwrdtyp: "X-Autologin",
            pwrd: strPwrd,
            when: dteWhen
          };
          aobjRqst.push(objRqst);                        // Add the nation, issue, and answer to the request queue
        };   
      };
      aobjRqst.sort(fSortWhen);                           // Make sure the request queue is in the right order     
      fSortNtns(strSort);                           // Update the visible HTML table
    }   

    /* fProcessIssue:
       Reduces the nation's issue count by one, if an issue was successfully answered
    */
    function fProcessIssue(objXML, i) {
      if (objXML.getElementsByTagName("OK").length > 0) {
        aobjNtns[i].iss = aobjNtns[i].iss - 1;            // If the issue was successfully answered, reduce the number of outstanding issues
        fSortNtns(strSort);                  // Update the visible HTML table
      };
    }

    function fSortNtns(strBy) {
      strSort = strBy; 
      switch (strBy) {
        case "ntn":
          aobjNtns.sort(fSortNtn);
          break;
        case "rgn":
          aobjNtns.sort(fSortRgn);
          break;
        case "ntc":
          aobjNtns.sort(fSortNtc);
          break;
        case "tgs":
          aobjNtns.sort(fSortTgs);
          break;
        case "rmb":
          aobjNtns.sort(fSortRmb);
          break;
        case "iss":
          aobjNtns.sort(fSortIss);
          break;
        case "spdr":
          aobjNtns.sort(fSortSpdr);
          break;
      };
      fUpdateTable();
    }

    /* function to sort array by nation */
    function fSortNtn(a,b) {
      var x = a.ntn.toLowerCase();
      var y = b.ntn.toLowerCase();
      if (x < y) { return -1; };
      if (x > y) { return 1; };
      return 0;
    }

    /* function to sort array by region */
    function fSortRgn(a,b) {
      var x = a.rgn.toLowerCase();
      var y = b.rgn.toLowerCase();
      if (x < y) { return -1; };
      if (x > y) { return 1; };
      return 0;
    }

    /* function to sort array by notices */
    function fSortNtc(a,b) {
      return b.ntc - a.ntc;
    }

    /* function to sort array by telegrams */
    function fSortTgs(a,b) {
      return b.tgs - a.tgs;
    }

    /* function to sort array by RMB posts */
    function fSortRmb(a,b) {
      return b.rmb - a.rmb;
    }

    /* function to sort array by Issues */
    function fSortIss(a,b) {
      return b.iss - a.iss;
    }

    /* function to sort array by SPDR */
    function fSortSpdr(a,b) {
      return b.spdr - a.spdr;
    }

    /*
    */
    function fUpdateTable() {
      var i;
      var strMsg = strHdr;                     // Set the table header
      var strNtc;
      var strTgs;
      var strRmb;
      var strIss;
      var strSpdr;
      for (i = 0; i < aobjNtns.length; i++) {
        if (aobjNtns[i].wa == "WA Member") {
          strMsg = strMsg + "<tr style='color:red;'>";            // Set to display any WA nation in red
        } else {
          strMsg = strMsg + "<tr>";
        };
        strNtc = aobjNtns[i].ntc;                  // If 'unread' counts are unknown, display them as "?"
        if (strNtc < 0) { strNtc = "?" };
        strTgs= aobjNtns[i].tgs;
        if (strTgs < 0) { strTgs = "?" };
        strRmb = aobjNtns[i].rmb;
        if (strRmb < 0) { strRmb = "?" };
        strIss = aobjNtns[i].iss;
        if (strIss < 0) { strIss = "?" };
        strSpdr = aobjNtns[i].spdr;
        if (strSpdr < 0) { strSpdr = "?" };
        strMsg = strMsg + "<td>"
          + aobjNtns[i].name + "</td><td>" + aobjNtns[i].rgn + "</td><td>"
          + strNtc + "</td><td>" + strTgs + "</td><td>"
          + strRmb + "</td><td>" + strIss + "</td><td>"
          + strSpdr + "</td></tr>";                  // Add details of each nation
      };
      document.getElementById("msg").innerHTML = strMsg;         // Output the complete data to the HTML table
    }
  </script>
</body>
</html>
Last edited by Wolfram and Hart on Mon Nov 19, 2018 2:48 pm, edited 2 times in total.

User avatar
Wolfram and Hart
Secretary
 
Posts: 35
Founded: Jul 06, 2017
Father Knows Best State

Postby Wolfram and Hart » Mon Nov 19, 2018 2:50 pm

Sleeping Beauty updated following feedback. Thanks for the new ideas!

User avatar
Augustus Rex
Lobbyist
 
Posts: 23
Founded: Feb 11, 2018
Ex-Nation

Postby Augustus Rex » Mon Nov 19, 2018 5:28 pm

As an ex-raider, thank you for this tool! Keeps the raiding fun w/o needing to answer drab issues
Formerly known as Gibraltarica

Previous

Return to Gameplay

Who is online

Users browsing this forum: Alnorud, Dead I Jack, East Meranopirus

Advertisement

Remove ads