|  | @@ -0,0 +1,1363 @@
 | 
	
		
			
				|  |  | +#include "director.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <boost/format.hpp>
 | 
	
		
			
				|  |  | +#include <cctype>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include "ansicolor.h"
 | 
	
		
			
				|  |  | +#include "boxes.h"
 | 
	
		
			
				|  |  | +#include "galaxy.h"
 | 
	
		
			
				|  |  | +#include "logging.h"
 | 
	
		
			
				|  |  | +#include "scripts.h"
 | 
	
		
			
				|  |  | +#include "utils.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Director::Director() {
 | 
	
		
			
				|  |  | +  BUGZ_LOG(warning) << "Director::Director()";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // active = false;
 | 
	
		
			
				|  |  | +  game = 0;  // not in a game
 | 
	
		
			
				|  |  | +  galaxy.reset();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // do everything proxy_deactivate does ...
 | 
	
		
			
				|  |  | +  // proxy_deactivate();
 | 
	
		
			
				|  |  | +  active = false;
 | 
	
		
			
				|  |  | +  // reset everything back to good state
 | 
	
		
			
				|  |  | +  talk_direct = true;
 | 
	
		
			
				|  |  | +  show_client = true;
 | 
	
		
			
				|  |  | +  count = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +  Setup StringFunc for SL_parser:
 | 
	
		
			
				|  |  | +  Construct these once, rather then every single time we need them.
 | 
	
		
			
				|  |  | +  */
 | 
	
		
			
				|  |  | +  SF_cimline = [this](const std::string &s) { this->SL_cimline(s); };
 | 
	
		
			
				|  |  | +  SF_sectorline = [this](const std::string &s) { this->SL_sectorline(s); };
 | 
	
		
			
				|  |  | +  SF_portline = [this](const std::string &s) { this->SL_portline(s); };
 | 
	
		
			
				|  |  | +  SF_warpline = [this](const std::string &s) { this->SL_warpline(s); };
 | 
	
		
			
				|  |  | +  SF_infoline = [this](const std::string &s) { this->SL_infoline(s); };
 | 
	
		
			
				|  |  | +  SF_densityline = [this](const std::string &s) { this->SL_densityline(s); };
 | 
	
		
			
				|  |  | +  SF_computer_portline = [this](const std::string &s) {
 | 
	
		
			
				|  |  | +    this->SL_computer_portline(s);
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  SF_planetline = [this](const std::string &s) { this->SL_planetline(s); };
 | 
	
		
			
				|  |  | +  build_menu();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Director::~Director() { BUGZ_LOG(warning) << "Director::~Director()"; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::client_input(const std::string &input) {
 | 
	
		
			
				|  |  | +  // If we're already active, don't try to activate.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (chain) {
 | 
	
		
			
				|  |  | +    chain->client_input(input);
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (active) {
 | 
	
		
			
				|  |  | +    if (input == "Q" || input == "q") proxy_deactivate();
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  } else if (input == "\x1b" || input == "~") {
 | 
	
		
			
				|  |  | +    std::string &prompt = current_prompt;
 | 
	
		
			
				|  |  | +    BUGZ_LOG(trace) << "ACTIVATE prompt shows: [" << prompt << "]";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (prompt == "Selection (? for menu): ") {
 | 
	
		
			
				|  |  | +      to_client(
 | 
	
		
			
				|  |  | +          "\n\rThere's not much we can do here.  Activate in-game at a "
 | 
	
		
			
				|  |  | +          "Command prompt.\n\r");
 | 
	
		
			
				|  |  | +      to_client(current_raw_prompt);
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // easter-eggs:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (prompt == "Enter your choice: ") {
 | 
	
		
			
				|  |  | +      ANSIColor c1(COLOR::CYAN, ATTR::BOLD);
 | 
	
		
			
				|  |  | +      ANSIColor c2(COLOR::WHITE, ATTR::BOLD);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      to_client(std::string("\n\r") + c1() + "I'd choose " + c2() + "`T`" +
 | 
	
		
			
				|  |  | +                c1() + ", but that's how I was coded.\n\r");
 | 
	
		
			
				|  |  | +      //          "\n\r\x1b[1;36mI'd choose \x1b[1;37m`T`\x1b[1;36m, but "
 | 
	
		
			
				|  |  | +      //          "that's how I was coded.\n\r");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      to_client(current_raw_prompt);
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // easter-egg
 | 
	
		
			
				|  |  | +    if (prompt == "[Pause]") {
 | 
	
		
			
				|  |  | +      ANSIColor c1(COLOR::CYAN, ATTR::BOLD);
 | 
	
		
			
				|  |  | +      to_client(std::string(" ") + c1() + "PAWS" + reset() + "\n\r");
 | 
	
		
			
				|  |  | +      to_client(current_raw_prompt);
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (at_planet_prompt(prompt)) {
 | 
	
		
			
				|  |  | +      // future:  If activated at planet menu, activate the planet upgrade
 | 
	
		
			
				|  |  | +      // script!  (Maybe).  If I can figure out what planet it is/and where.
 | 
	
		
			
				|  |  | +      to_client("\n\r\x1b[0mFUTURE:  Activate the planet upgrade script.\n\r");
 | 
	
		
			
				|  |  | +      to_client(current_raw_prompt);
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (at_command_prompt(prompt)) {
 | 
	
		
			
				|  |  | +      proxy_activate();
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  // Ok...
 | 
	
		
			
				|  |  | +  if (talk_direct) to_server(input);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::server_line(const std::string &line,
 | 
	
		
			
				|  |  | +                           const std::string &raw_line) {
 | 
	
		
			
				|  |  | +  // check for if we entered game/left game
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (line.find("TradeWars Game Server   ") != std::string::npos) {
 | 
	
		
			
				|  |  | +    // Inject our proxy activation message
 | 
	
		
			
				|  |  | +    to_client("\rTradeWars Proxy v2++ READY (~ or ESC to activate)\n\r");
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  | +    There's a delay here when I save the game data.
 | 
	
		
			
				|  |  | +    I've moved it futher down.  Hide it at a prompt, so it isn't so
 | 
	
		
			
				|  |  | +    noticeable.
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    // reset "active game" -- we're at the TWGS main menu
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (line.find("Selection (? for menu): ") != std::string::npos) {
 | 
	
		
			
				|  |  | +    char ch = line[line.length() - 1];
 | 
	
		
			
				|  |  | +    if (ch >= 'A' && ch < 'Q') {
 | 
	
		
			
				|  |  | +      if ((game) && (game != ch)) {
 | 
	
		
			
				|  |  | +        galaxy.save();
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      game = ch;
 | 
	
		
			
				|  |  | +      BUGZ_LOG(warning) << "GAME " << game << " activated!";
 | 
	
		
			
				|  |  | +      // TODO:  Load game data
 | 
	
		
			
				|  |  | +      galaxy.game = game;
 | 
	
		
			
				|  |  | +      galaxy.username = username;
 | 
	
		
			
				|  |  | +      galaxy.load();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // YAML loaded, set sensible default config values (if missing).
 | 
	
		
			
				|  |  | +      if (!galaxy.config.contains("display_lines")) {
 | 
	
		
			
				|  |  | +        galaxy.config["display_lines"] = 20;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      galaxy.meta["help"]["display_lines"] =
 | 
	
		
			
				|  |  | +          "Number of report lines to display";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (!galaxy.config.contains("burnt_percent")) {
 | 
	
		
			
				|  |  | +        galaxy.config["burnt_percent"] = 40;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      galaxy.meta["help"]["burnt_percent"] =
 | 
	
		
			
				|  |  | +          "Don't display ports in report below this percent";
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // not needed (handled by above Game Server check).
 | 
	
		
			
				|  |  | +    if (ch == 'Q') {
 | 
	
		
			
				|  |  | +      if (game) {
 | 
	
		
			
				|  |  | +        // TODO:  Save galaxy data
 | 
	
		
			
				|  |  | +        galaxy.save();
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      game = 0;
 | 
	
		
			
				|  |  | +      galaxy.reset();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (game) {
 | 
	
		
			
				|  |  | +    // in-game parsing here.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  | +      ____                             _     _
 | 
	
		
			
				|  |  | +     / ___|  ___ _ ____   _____ _ __  | |   (_)_ __   ___
 | 
	
		
			
				|  |  | +     \___ \ / _ \ '__\ \ / / _ \ '__| | |   | | '_ \ / _ \
 | 
	
		
			
				|  |  | +      ___) |  __/ |   \ V /  __/ |    | |___| | | | |  __/
 | 
	
		
			
				|  |  | +     |____/ \___|_|    \_/ \___|_|    |_____|_|_| |_|\___|
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      ____                _
 | 
	
		
			
				|  |  | +     |  _ \ __ _ _ __ ___(_)_ __   __ _
 | 
	
		
			
				|  |  | +     | |_) / _` | '__/ __| | '_ \ / _` |
 | 
	
		
			
				|  |  | +     |  __/ (_| | |  \__ \ | | | | (_| |
 | 
	
		
			
				|  |  | +     |_|   \__,_|_|  |___/_|_| |_|\__, |
 | 
	
		
			
				|  |  | +                                  |___/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +   This is where all of the server lines are gleaned for all the
 | 
	
		
			
				|  |  | +   information that we can get out of them.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // When activating the computer
 | 
	
		
			
				|  |  | +    SP: [Command [TL=00:00:00]:[926] (?=Help)? : ]
 | 
	
		
			
				|  |  | +    Sector: 926
 | 
	
		
			
				|  |  | +    CI: [c]
 | 
	
		
			
				|  |  | +    SL: [Command [TL=00:00:00]:[926] (?=Help)? : C]
 | 
	
		
			
				|  |  | +    SL: [<Computer>]
 | 
	
		
			
				|  |  | +    SL: []
 | 
	
		
			
				|  |  | +    SL: [<Computer activated>]
 | 
	
		
			
				|  |  | +    SL: []
 | 
	
		
			
				|  |  | +    SP: [Computer command [TL=00:00:00]:[926] (?=Help)? ]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // deactivating the computer
 | 
	
		
			
				|  |  | +    SL: [Computer command [TL=00:00:00]:[926] (?=Help)? Q]
 | 
	
		
			
				|  |  | +    SL: []
 | 
	
		
			
				|  |  | +    SL: [<Computer deactivated>]
 | 
	
		
			
				|  |  | +    SL: []
 | 
	
		
			
				|  |  | +    */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (line == "<Port>") {
 | 
	
		
			
				|  |  | +      SL_parser = SF_portline;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (line ==
 | 
	
		
			
				|  |  | +            "                           Corporate Planet Scan                  "
 | 
	
		
			
				|  |  | +            "            " ||
 | 
	
		
			
				|  |  | +        line ==
 | 
	
		
			
				|  |  | +            "                           Personal Planet Scan                   "
 | 
	
		
			
				|  |  | +            "           ") {
 | 
	
		
			
				|  |  | +      SL_parser = SF_planetline;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  | +    if (startswith(line, " Items     Status  Trading % of max OnBoard"))
 | 
	
		
			
				|  |  | +      SL_parser = SF_portline;
 | 
	
		
			
				|  |  | +    */
 | 
	
		
			
				|  |  | +    if (endswith(line, "Relative Density Scan")) {
 | 
	
		
			
				|  |  | +      galaxy.dscan.reset(current_sector);
 | 
	
		
			
				|  |  | +      SL_parser = SF_densityline;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (startswith(line, "Sector  : ")) SL_parser = SF_sectorline;
 | 
	
		
			
				|  |  | +    if (line == ": ") SL_parser = SF_cimline;
 | 
	
		
			
				|  |  | +    if (line == "<Info>") SL_parser = SF_infoline;
 | 
	
		
			
				|  |  | +    if (startswith(line, "What sector is the port in? [")) {
 | 
	
		
			
				|  |  | +      // Computer Port Report
 | 
	
		
			
				|  |  | +      // SL: [What sector is the port in? [611] 4]
 | 
	
		
			
				|  |  | +      size_t pos = line.rfind(' ');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      computer_port_sector = stoi(line.substr(pos));
 | 
	
		
			
				|  |  | +      SL_parser = SF_computer_portline;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (SL_parser) {
 | 
	
		
			
				|  |  | +    SL_parser(line);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (chain) {
 | 
	
		
			
				|  |  | +    chain->server_line(line, raw_line);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::server_prompt(const std::string &prompt,
 | 
	
		
			
				|  |  | +                             const std::string &raw_prompt) {
 | 
	
		
			
				|  |  | +  current_prompt = prompt;
 | 
	
		
			
				|  |  | +  current_raw_prompt = raw_prompt;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (game) {
 | 
	
		
			
				|  |  | +    if (prompt == "Selection (? for menu): ") {
 | 
	
		
			
				|  |  | +      galaxy.save();
 | 
	
		
			
				|  |  | +      game = 0;
 | 
	
		
			
				|  |  | +      galaxy.reset();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // in-game parsing here.
 | 
	
		
			
				|  |  | +    // if (startswith(prompt, "Command [") && endswith(prompt, "] (?=Help)? :
 | 
	
		
			
				|  |  | +    // ")) {
 | 
	
		
			
				|  |  | +    if (at_command_prompt(prompt)) {
 | 
	
		
			
				|  |  | +      std::string sector_text;
 | 
	
		
			
				|  |  | +      size_t before, after;
 | 
	
		
			
				|  |  | +      before = prompt.find("]:[") + 3;
 | 
	
		
			
				|  |  | +      after = prompt.find("] (?=Help)");
 | 
	
		
			
				|  |  | +      sector_text = prompt.substr(before, after - before);
 | 
	
		
			
				|  |  | +      current_sector = stoi(sector_text);
 | 
	
		
			
				|  |  | +      BUGZ_LOG(info) << "current_sector = " << current_sector;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +  if (emit_server_prompt)
 | 
	
		
			
				|  |  | +    emit_server_prompt(prompt);
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  if (chain) chain->server_prompt(prompt);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::build_menu(void) {
 | 
	
		
			
				|  |  | +  main_menu = std::make_shared<MenuDispatch>(*this);
 | 
	
		
			
				|  |  | +  MenuDispatch *md = static_cast<MenuDispatch *>(&(*main_menu));
 | 
	
		
			
				|  |  | +  ANSIColor bcolor(COLOR::YELLOW, COLOR::BLUE, ATTR::BOLD);
 | 
	
		
			
				|  |  | +  ANSIColor tcolor(COLOR::WHITE, COLOR::BLUE, ATTR::BOLD);
 | 
	
		
			
				|  |  | +  ANSIColor mocolor(COLOR::CYAN, ATTR::BOLD);
 | 
	
		
			
				|  |  | +  md->menu_box_color = bcolor();   // "\x1b[1;33;44m";
 | 
	
		
			
				|  |  | +  md->menu_text_color = tcolor();  // "\x1b[1;37;44m";
 | 
	
		
			
				|  |  | +  md->menu_title = "Proxy Menu";
 | 
	
		
			
				|  |  | +  md->menu_options_color = mocolor();  // "\x1b[1;36;40m";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  ANSIColor by{1, 33};
 | 
	
		
			
				|  |  | +  ANSIColor cyan{36};
 | 
	
		
			
				|  |  | +  ANSIColor bg{1, 32};
 | 
	
		
			
				|  |  | +  std::string prompt = by() + "M" + cyan() + "ain " + by() + "P" + cyan() +
 | 
	
		
			
				|  |  | +                       "roxy " + bg() + "=>" + reset() + " ";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  md->menu_prompt = prompt;  // "Main Proxy => ";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // "\x1b[0;31;40m\xdb\xb2\xb1\xb0 \x1b[31;40mRED "
 | 
	
		
			
				|  |  | +  // "\x1b[32;40mGREEN\x1b[30;42m\xdb\xb2\xb1\xb0 \x1b[0m : ";
 | 
	
		
			
				|  |  | +  md->lazy = true;
 | 
	
		
			
				|  |  | +  md->menu = {{"C", "Configure"},
 | 
	
		
			
				|  |  | +              {"D", "Display Report"},
 | 
	
		
			
				|  |  | +              {"E", "Export Data/Save"},
 | 
	
		
			
				|  |  | +              {"I", "Information"},
 | 
	
		
			
				|  |  | +              {"P", "Port CIM"},
 | 
	
		
			
				|  |  | +              {"W", "Warp CIM"},
 | 
	
		
			
				|  |  | +              {"T", "Trading Report (same as D)"},
 | 
	
		
			
				|  |  | +              {"S", "Scripts"},
 | 
	
		
			
				|  |  | +              {"X", "eXit"}};
 | 
	
		
			
				|  |  | +  md->setNotify([this]() { this->menu_choice(); });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  cim = std::make_shared<CIMDispatch>(*this);
 | 
	
		
			
				|  |  | +  cim->setNotify([this]() { this->cim_done(); });
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::proxy_activate(void) {
 | 
	
		
			
				|  |  | +  active = true;   // yes, set keep-alive timer.
 | 
	
		
			
				|  |  | +  to_server(" ");  // start keep-alive timer.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // set other values we need
 | 
	
		
			
				|  |  | +  talk_direct = false;
 | 
	
		
			
				|  |  | +  show_client = false;
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +  Wait a minute .. this might be confusing.
 | 
	
		
			
				|  |  | +  Shouldn't I send them the current prompt?
 | 
	
		
			
				|  |  | +  Just in case we abort in the middle of something?!?
 | 
	
		
			
				|  |  | +  */
 | 
	
		
			
				|  |  | +  old_prompt = current_prompt;
 | 
	
		
			
				|  |  | +  old_raw_prompt = current_raw_prompt;
 | 
	
		
			
				|  |  | +  to_client("\x1b[0m\n\r");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +  ╔══════════════════════════════╗
 | 
	
		
			
				|  |  | +  ║    TradeWars Proxy Active    ║
 | 
	
		
			
				|  |  | +  ╚══════════════════════════════╝
 | 
	
		
			
				|  |  | +     -=>
 | 
	
		
			
				|  |  | +  */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  Boxes box(30, 1, true);
 | 
	
		
			
				|  |  | +  box.boxcolor = "\x1b[1;33;44m";
 | 
	
		
			
				|  |  | +  box.textcolor = "\x1b[1;33;44m";
 | 
	
		
			
				|  |  | +  to_client(box.top());
 | 
	
		
			
				|  |  | +  std::string output = "    TradeWars Proxy \x1b[5mActive\x1b[0;1;33;44m    ";
 | 
	
		
			
				|  |  | +  to_client(box.row(output));
 | 
	
		
			
				|  |  | +  to_client(box.bottom());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (galaxy.meta.contains("port_CIM")) {
 | 
	
		
			
				|  |  | +    time_t last_port_cim_report = galaxy.meta["port_CIM"].get<int>();
 | 
	
		
			
				|  |  | +    int seconds_ago = time_t_now() - last_port_cim_report;
 | 
	
		
			
				|  |  | +    int minutes_ago = seconds_ago / 60;
 | 
	
		
			
				|  |  | +    BUGZ_LOG(fatal) << "port_CIM was " << minutes_ago << " minutes ago.";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (minutes_ago >= 60) {
 | 
	
		
			
				|  |  | +      float hours_ago = minutes_ago / 60.0;
 | 
	
		
			
				|  |  | +      std::string message =
 | 
	
		
			
				|  |  | +          str(boost::format(
 | 
	
		
			
				|  |  | +                  "Warning: Last Port CIM Refresh was %1$0.2f hours ago.\n\r") %
 | 
	
		
			
				|  |  | +              hours_ago);
 | 
	
		
			
				|  |  | +      to_client(message);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    BUGZ_LOG(fatal) << "no meta port_CIM value seen.";
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  chain = main_menu;
 | 
	
		
			
				|  |  | +  main_menu->activate();
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +    // Using InputDispatch  -- and see have_input
 | 
	
		
			
				|  |  | +    std::shared_ptr<Dispatch> readline = std::make_shared<InputDispatch>(*this);
 | 
	
		
			
				|  |  | +    chain = readline;
 | 
	
		
			
				|  |  | +    InputDispatch *id = static_cast<InputDispatch *>(&(*readline));
 | 
	
		
			
				|  |  | +    id->prompt = "\x1b[0m\x1b[1;33;44m-=>\x1b[0m \x1b[1;37;44m";
 | 
	
		
			
				|  |  | +    id->max_length = 15;
 | 
	
		
			
				|  |  | +    id->setNotify([this]() { this->have_input(); });
 | 
	
		
			
				|  |  | +    readline->activate();
 | 
	
		
			
				|  |  | +  */
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::menu_choice(void) {
 | 
	
		
			
				|  |  | +  MenuDispatch *md = dynamic_cast<MenuDispatch *>(&(*chain));
 | 
	
		
			
				|  |  | +  if (md) {
 | 
	
		
			
				|  |  | +    if (md->input.empty()) {
 | 
	
		
			
				|  |  | +      to_client("Menu aborted.\n\r");
 | 
	
		
			
				|  |  | +      proxy_deactivate();
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      switch (md->input[0]) {
 | 
	
		
			
				|  |  | +        case 'C':  // configure
 | 
	
		
			
				|  |  | +          config_edit();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +        case 'D':
 | 
	
		
			
				|  |  | +        case 'T':  // display trading report
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +          auto pptv = galaxy.find_best_trades();
 | 
	
		
			
				|  |  | +          std::string output;
 | 
	
		
			
				|  |  | +          galaxy.sort_port_pair_type(pptv);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          int max_display = 20;
 | 
	
		
			
				|  |  | +          if (galaxy.config.contains("display_lines"))
 | 
	
		
			
				|  |  | +            max_display = galaxy.config["display_lines"].get<int>();
 | 
	
		
			
				|  |  | +          else
 | 
	
		
			
				|  |  | +            galaxy.config["display_lines"] = max_display;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          if ((max_display <= 0) || (max_display > 255)) {
 | 
	
		
			
				|  |  | +            max_display = 255;
 | 
	
		
			
				|  |  | +            galaxy.config["display_lines"] = 255;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          const int per_line = 5;
 | 
	
		
			
				|  |  | +          int count = 0;
 | 
	
		
			
				|  |  | +          int line = 0;
 | 
	
		
			
				|  |  | +          std::string display_line;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          ANSIColor by{1, 33};  // yellow
 | 
	
		
			
				|  |  | +          ANSIColor cyan{36};   // cyan
 | 
	
		
			
				|  |  | +          ANSIColor bg{1, 32};  // bright green
 | 
	
		
			
				|  |  | +          ANSIColor bb{1, 34};  // bright blue
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          for (auto const &ppt : pptv) {
 | 
	
		
			
				|  |  | +            output =
 | 
	
		
			
				|  |  | +                str(boost::format("%1%%2$5d%3%:%4%%5$-5d%3%(%6%%7$d%3%) ") %
 | 
	
		
			
				|  |  | +                    by() % ppt.s1 % cyan() % bg() % ppt.s2 % bb() % ppt.type);
 | 
	
		
			
				|  |  | +            display_line.append(output);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            ++count;
 | 
	
		
			
				|  |  | +            if (count == per_line) {
 | 
	
		
			
				|  |  | +              count = 0;
 | 
	
		
			
				|  |  | +              display_line.append("\n\r");
 | 
	
		
			
				|  |  | +              to_client(display_line);
 | 
	
		
			
				|  |  | +              display_line.clear();
 | 
	
		
			
				|  |  | +              ++line;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (line == max_display) break;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          if (count != 0) {
 | 
	
		
			
				|  |  | +            display_line.append("\n\r");
 | 
	
		
			
				|  |  | +            to_client(display_line);
 | 
	
		
			
				|  |  | +            display_line.clear();
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // We got < 5 lines, and max_display is > 5.  Offer suggestion:
 | 
	
		
			
				|  |  | +          if ((line < 5) && (max_display > 5)) {
 | 
	
		
			
				|  |  | +            // suggestion:
 | 
	
		
			
				|  |  | +            to_client(
 | 
	
		
			
				|  |  | +                "HINT: For more lines, try reducing the burnt_percent?\n\r");
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        } break;
 | 
	
		
			
				|  |  | +        case 'E':  // Export Data/Save
 | 
	
		
			
				|  |  | +          to_client("Saving...");
 | 
	
		
			
				|  |  | +          galaxy.save();
 | 
	
		
			
				|  |  | +          to_client("\rSaved....\n\r");
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +        case 'I':  // Information
 | 
	
		
			
				|  |  | +          information();
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +        case 'P':  // Port CIM
 | 
	
		
			
				|  |  | +          // Since we're adding/updating, we don't lose our
 | 
	
		
			
				|  |  | +          // type 0 ports.  Type 9 stays at 9.
 | 
	
		
			
				|  |  | +          galaxy.meta["port_CIM"] = (int)time_t_now();
 | 
	
		
			
				|  |  | +          chain = cim;
 | 
	
		
			
				|  |  | +          to_server("^RQ");
 | 
	
		
			
				|  |  | +          {
 | 
	
		
			
				|  |  | +            std::string text = str(boost::format("Port CIM Report (%1%)\n\r") %
 | 
	
		
			
				|  |  | +                                   galaxy.ports.size());
 | 
	
		
			
				|  |  | +            // to_client("Port CIM Report\n\r");
 | 
	
		
			
				|  |  | +            to_client(text);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          chain->activate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +        case 'W':  // Warp CIM
 | 
	
		
			
				|  |  | +          chain = cim;
 | 
	
		
			
				|  |  | +          to_server("^IQ");
 | 
	
		
			
				|  |  | +          {
 | 
	
		
			
				|  |  | +            std::string text = str(boost::format("Warp CIM Report (%1%)\n\r") %
 | 
	
		
			
				|  |  | +                                   galaxy.warps.size());
 | 
	
		
			
				|  |  | +            // to_client("Warp CIM Report\n\r");
 | 
	
		
			
				|  |  | +            to_client(text);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          chain->activate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +        // case 'T':  // Trading Report
 | 
	
		
			
				|  |  | +        //  break;
 | 
	
		
			
				|  |  | +        case 'S':  // Scripts
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +          init_scripts_menu();
 | 
	
		
			
				|  |  | +          chain = scripts_menu;
 | 
	
		
			
				|  |  | +          chain->activate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +        } break;
 | 
	
		
			
				|  |  | +        case 'X':  // Exit
 | 
	
		
			
				|  |  | +          proxy_deactivate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      /*
 | 
	
		
			
				|  |  | +      std::string text = str(
 | 
	
		
			
				|  |  | +          boost::format("Back from Menu [%1%] was selected.\n\r") %
 | 
	
		
			
				|  |  | +      md->input);
 | 
	
		
			
				|  |  | +      to_client(text);
 | 
	
		
			
				|  |  | +      */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      md->activate();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +MenuDispatch *Director::init_scripts_menu(void) {
 | 
	
		
			
				|  |  | +  MenuDispatch *md;
 | 
	
		
			
				|  |  | +  if (scripts_menu) {
 | 
	
		
			
				|  |  | +    md = dynamic_cast<MenuDispatch *>(&(*scripts_menu));
 | 
	
		
			
				|  |  | +    return md;
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    scripts_menu = std::make_shared<MenuDispatch>(*this);
 | 
	
		
			
				|  |  | +    md = static_cast<MenuDispatch *>(&(*scripts_menu));
 | 
	
		
			
				|  |  | +    md->menu_box_color = "\x1b[0;32;40m";
 | 
	
		
			
				|  |  | +    md->menu_text_color = "\x1b[1;32;40m";
 | 
	
		
			
				|  |  | +    md->menu_title = "Scripts Menu";
 | 
	
		
			
				|  |  | +    md->menu_options_color = "\x1b[1;32;40m";
 | 
	
		
			
				|  |  | +    md->lazy = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ANSIColor by{1, 33};
 | 
	
		
			
				|  |  | +    ANSIColor cyan{36};
 | 
	
		
			
				|  |  | +    ANSIColor bg{1, 32};
 | 
	
		
			
				|  |  | +    std::string prompt = by() + "S" + cyan() + "cript " + by() + "M" + cyan() +
 | 
	
		
			
				|  |  | +                         "enu " + bg() + "=>" + reset() + " ";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    md->menu_prompt = prompt;  // " SCRIPT : ";
 | 
	
		
			
				|  |  | +    md->menu = {{"!", "Terror"},
 | 
	
		
			
				|  |  | +                {"T", "Trade"},
 | 
	
		
			
				|  |  | +                {"S", "Safe Move"},
 | 
	
		
			
				|  |  | +                {"C", "Closest Trade"},
 | 
	
		
			
				|  |  | +                {"N", "Nearest Unexplored"},
 | 
	
		
			
				|  |  | +                {"V", "Voyager Explorer"},
 | 
	
		
			
				|  |  | +                {"E", "Explorer"},
 | 
	
		
			
				|  |  | +                {"U", "Upgrade Planet Pants"},
 | 
	
		
			
				|  |  | +                {"X", "Exit Scripts"}};
 | 
	
		
			
				|  |  | +    md->setNotify([this]() { this->scripts_done(); });
 | 
	
		
			
				|  |  | +    return md;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::scripts_done(void) {
 | 
	
		
			
				|  |  | +  // Was script selected?  If so, run it!
 | 
	
		
			
				|  |  | +  // otherwise, back to the menu we go...
 | 
	
		
			
				|  |  | +  MenuDispatch *md = dynamic_cast<MenuDispatch *>(&(*scripts_menu));
 | 
	
		
			
				|  |  | +  if (md) {
 | 
	
		
			
				|  |  | +    if (md->input.empty()) {
 | 
	
		
			
				|  |  | +      to_client("Scripts aborted.\n\r");
 | 
	
		
			
				|  |  | +      scripts_menu.reset();
 | 
	
		
			
				|  |  | +      proxy_deactivate();
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      switch (md->input[0]) {
 | 
	
		
			
				|  |  | +        case 'T':  // Trade
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +          script = std::make_shared<TraderDispatch>(*this);
 | 
	
		
			
				|  |  | +          TraderDispatch *ts = static_cast<TraderDispatch *>(&((*script)));
 | 
	
		
			
				|  |  | +          ts->setNotify([this]() { this->proxy_deactivate(); });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // Locate best trades
 | 
	
		
			
				|  |  | +          auto found = galaxy.find_trades(current_sector, false);
 | 
	
		
			
				|  |  | +          if (found.empty()) {
 | 
	
		
			
				|  |  | +            to_client(
 | 
	
		
			
				|  |  | +                "No Trades found.  Port burnt (CONFIG: lower burnt_percent?) "
 | 
	
		
			
				|  |  | +                "or no ports around.\n\r");
 | 
	
		
			
				|  |  | +            proxy_deactivate();
 | 
	
		
			
				|  |  | +            return;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          // sort first?
 | 
	
		
			
				|  |  | +          galaxy.sort_port_pair_type(found);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          BUGZ_LOG(fatal) << "Found " << found.size() << " possible trade(s).";
 | 
	
		
			
				|  |  | +          BUGZ_LOG(fatal) << "Best: " << found[0].s1 << "," << found[0].s2
 | 
	
		
			
				|  |  | +                          << " : " << found[0].type;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // Set parameters
 | 
	
		
			
				|  |  | +          ts->port[0] = found[0].s1;
 | 
	
		
			
				|  |  | +          ts->port[1] = found[0].s2;
 | 
	
		
			
				|  |  | +          ts->type = found[0].type;
 | 
	
		
			
				|  |  | +          ts->trades = found[0].trades;
 | 
	
		
			
				|  |  | +          chain = script;
 | 
	
		
			
				|  |  | +          chain->activate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +        } break;
 | 
	
		
			
				|  |  | +        case 'S': {
 | 
	
		
			
				|  |  | +          script = std::make_shared<MoveDispatch>(*this);
 | 
	
		
			
				|  |  | +          MoveDispatch *md = static_cast<MoveDispatch *>(&((*script)));
 | 
	
		
			
				|  |  | +          md->setNotify([this]() { this->proxy_deactivate(); });
 | 
	
		
			
				|  |  | +          md->move_to = 1;
 | 
	
		
			
				|  |  | +          chain = script;
 | 
	
		
			
				|  |  | +          chain->activate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +        } break;
 | 
	
		
			
				|  |  | +        case '!': {
 | 
	
		
			
				|  |  | +          script = std::make_shared<ScriptTerror>(*this);
 | 
	
		
			
				|  |  | +          ScriptTerror *st = static_cast<ScriptTerror *>(&(*script));
 | 
	
		
			
				|  |  | +          st->setNotify([this]() {
 | 
	
		
			
				|  |  | +            script.reset();
 | 
	
		
			
				|  |  | +            this->proxy_deactivate();
 | 
	
		
			
				|  |  | +          });
 | 
	
		
			
				|  |  | +          chain = script;
 | 
	
		
			
				|  |  | +          chain->activate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +        } break;
 | 
	
		
			
				|  |  | +        // }
 | 
	
		
			
				|  |  | +        case 'C': {
 | 
	
		
			
				|  |  | +          auto best = galaxy.find_closest(current_sector);
 | 
	
		
			
				|  |  | +          if (best.type != 0) {
 | 
	
		
			
				|  |  | +            std::string text =
 | 
	
		
			
				|  |  | +                str(boost::format("Best/Closest: %1% with %2% & %3%\n\r") %
 | 
	
		
			
				|  |  | +                    best.type % best.s1 % best.s2);
 | 
	
		
			
				|  |  | +            to_client(text);
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            to_client("I don't see any best trades.\n\r");
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        } break;
 | 
	
		
			
				|  |  | +        case 'N': {
 | 
	
		
			
				|  |  | +          sector_type s = galaxy.find_nearest_unexplored(current_sector);
 | 
	
		
			
				|  |  | +          if (s != 0) {
 | 
	
		
			
				|  |  | +            std::string text = str(boost::format("Sector: %1%\n\r") % s);
 | 
	
		
			
				|  |  | +            to_client(text);
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            to_client("I don't see any unexplored.\n\r");
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        } break;
 | 
	
		
			
				|  |  | +        case 'V': {
 | 
	
		
			
				|  |  | +          script = std::make_shared<ScriptVoyager>(*this);
 | 
	
		
			
				|  |  | +          ScriptVoyager *sv = static_cast<ScriptVoyager *>(&(*script));
 | 
	
		
			
				|  |  | +          sv->setNotify([this]() {
 | 
	
		
			
				|  |  | +            script.reset();
 | 
	
		
			
				|  |  | +            this->proxy_deactivate();
 | 
	
		
			
				|  |  | +          });
 | 
	
		
			
				|  |  | +          chain = script;
 | 
	
		
			
				|  |  | +          chain->activate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +        } break;
 | 
	
		
			
				|  |  | +        case 'E': {
 | 
	
		
			
				|  |  | +          script = std::make_shared<ScriptExplore>(*this);
 | 
	
		
			
				|  |  | +          ScriptExplore *se = static_cast<ScriptExplore *>(&(*script));
 | 
	
		
			
				|  |  | +          se->setNotify([this]() {
 | 
	
		
			
				|  |  | +            script.reset();
 | 
	
		
			
				|  |  | +            this->proxy_deactivate();
 | 
	
		
			
				|  |  | +          });
 | 
	
		
			
				|  |  | +          chain = script;
 | 
	
		
			
				|  |  | +          chain->activate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +        } break;
 | 
	
		
			
				|  |  | +        case 'U': {
 | 
	
		
			
				|  |  | +          script = std::make_shared<ScriptPlanet>(*this);
 | 
	
		
			
				|  |  | +          ScriptPlanet *sp = static_cast<ScriptPlanet *>(&(*script));
 | 
	
		
			
				|  |  | +          sp->setNotify([this]() {
 | 
	
		
			
				|  |  | +            script.reset();
 | 
	
		
			
				|  |  | +            this->proxy_deactivate();
 | 
	
		
			
				|  |  | +          });
 | 
	
		
			
				|  |  | +          chain = script;
 | 
	
		
			
				|  |  | +          chain->activate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +        } break;
 | 
	
		
			
				|  |  | +        case 'Q':
 | 
	
		
			
				|  |  | +          chain = main_menu;
 | 
	
		
			
				|  |  | +          main_menu->activate();
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  proxy_activate();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // And to end scripts, we do .. what exactly?
 | 
	
		
			
				|  |  | +  // DEBUG:  Ok, why does everything work OK if I reset the scripts_menu
 | 
	
		
			
				|  |  | +  // here?? probably do want to destroy scripts here.  ;)
 | 
	
		
			
				|  |  | +  // scripts_menu.reset();
 | 
	
		
			
				|  |  | +  // proxy_deactivate();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief Setup Config Input
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @return DispatchInput*
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +InputDispatch *Director::init_config_input(void) {
 | 
	
		
			
				|  |  | +  InputDispatch *id;
 | 
	
		
			
				|  |  | +  if (config_input) {
 | 
	
		
			
				|  |  | +    // Yes, it has been setup before.
 | 
	
		
			
				|  |  | +    id = dynamic_cast<InputDispatch *>(&(*config_input));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ANSIColor by{1, 33};
 | 
	
		
			
				|  |  | +    ANSIColor cyan{36};
 | 
	
		
			
				|  |  | +    ANSIColor bg{1, 32};
 | 
	
		
			
				|  |  | +    std::string prompt =
 | 
	
		
			
				|  |  | +        by() + "C" + cyan() + "onfig " + bg() + "=>" + reset() + " ";
 | 
	
		
			
				|  |  | +    id->prompt = prompt;  // "Config => ";
 | 
	
		
			
				|  |  | +    id->numeric = true;
 | 
	
		
			
				|  |  | +    id->max_length = 3;
 | 
	
		
			
				|  |  | +    config_item.clear();
 | 
	
		
			
				|  |  | +    return id;
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    // set it up
 | 
	
		
			
				|  |  | +    config_input = std::make_shared<InputDispatch>(*this);
 | 
	
		
			
				|  |  | +    id = static_cast<InputDispatch *>(&(*config_input));
 | 
	
		
			
				|  |  | +    ANSIColor by{1, 33};
 | 
	
		
			
				|  |  | +    ANSIColor cyan{36};
 | 
	
		
			
				|  |  | +    ANSIColor bg{1, 32};
 | 
	
		
			
				|  |  | +    std::string prompt =
 | 
	
		
			
				|  |  | +        by() + "C" + cyan() + "onfig " + bg() + "=>" + reset() + " ";
 | 
	
		
			
				|  |  | +    id->prompt = prompt;  // "Config => ";
 | 
	
		
			
				|  |  | +    id->numeric = true;
 | 
	
		
			
				|  |  | +    id->max_length = 3;
 | 
	
		
			
				|  |  | +    id->setNotify([this]() { this->config_have_input(); });
 | 
	
		
			
				|  |  | +    config_item.clear();
 | 
	
		
			
				|  |  | +    return id;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::config_edit(void) {
 | 
	
		
			
				|  |  | +  // display current config
 | 
	
		
			
				|  |  | +  std::string menu_box_color = "\x1b[1;33;44m";
 | 
	
		
			
				|  |  | +  std::string menu_text_color = "\x1b[1;37;44m";
 | 
	
		
			
				|  |  | +  auto abox = Boxes::alert("   Configuration:   ", menu_box_color,
 | 
	
		
			
				|  |  | +                           menu_text_color, 20, 1, true);
 | 
	
		
			
				|  |  | +  for (auto line : abox) {
 | 
	
		
			
				|  |  | +    to_client(line);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  // to_client("Configuration:\n\r");
 | 
	
		
			
				|  |  | +  int item = 1;
 | 
	
		
			
				|  |  | +  ANSIColor number(COLOR::CYAN);
 | 
	
		
			
				|  |  | +  ANSIColor key(COLOR::GREEN, ATTR::BOLD);
 | 
	
		
			
				|  |  | +  ANSIColor value(COLOR::BLUE, ATTR::BOLD);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (auto const &cfg : galaxy.config.items()) {
 | 
	
		
			
				|  |  | +    // for (auto const &cfg : galaxy.config) {
 | 
	
		
			
				|  |  | +    std::string output =
 | 
	
		
			
				|  |  | +        str(boost::format("%1%%2$2d %3%%4$20s: %5%%6$s%7%\n\r") % number() %
 | 
	
		
			
				|  |  | +            item % key() % cfg.key() % value() % cfg.value() % reset());
 | 
	
		
			
				|  |  | +    to_client(output);
 | 
	
		
			
				|  |  | +    ++item;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  std::string message =
 | 
	
		
			
				|  |  | +      number() + "Enter number to edit, " + key() + "blank to exit.\n\r";
 | 
	
		
			
				|  |  | +  // to_client("Enter number to edit, blank to exit.\n\r");
 | 
	
		
			
				|  |  | +  to_client(message);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // setup call to config_input:
 | 
	
		
			
				|  |  | +  InputDispatch *id = init_config_input();
 | 
	
		
			
				|  |  | +  chain = config_input;
 | 
	
		
			
				|  |  | +  id->activate();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // to return to the menu:
 | 
	
		
			
				|  |  | +  // MenuDispatch *md = dynamic_cast<MenuDispatch *>(&(*chain));
 | 
	
		
			
				|  |  | +  // md->activate();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::config_have_input(void) {
 | 
	
		
			
				|  |  | +  InputDispatch *id = dynamic_cast<InputDispatch *>(&(*config_input));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (config_item.empty()) {
 | 
	
		
			
				|  |  | +    // This is a config menu selection
 | 
	
		
			
				|  |  | +    if (id->input.empty()) {
 | 
	
		
			
				|  |  | +      // We're done here.  Return to menu.
 | 
	
		
			
				|  |  | +      chain = main_menu;
 | 
	
		
			
				|  |  | +      MenuDispatch *md = dynamic_cast<MenuDispatch *>(&(*chain));
 | 
	
		
			
				|  |  | +      md->activate();
 | 
	
		
			
				|  |  | +      // destroy the input?  yes.
 | 
	
		
			
				|  |  | +      config_input.reset();
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      int item = sstoi(id->input);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if ((item < 1) || (item > (int)galaxy.config.size())) {
 | 
	
		
			
				|  |  | +        // selection out of range - redisplay config menu
 | 
	
		
			
				|  |  | +        to_client("What?  I didn't see that item.\n\r");
 | 
	
		
			
				|  |  | +        config_edit();
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        int pos = 1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for (auto const &c : galaxy.config.items()) {
 | 
	
		
			
				|  |  | +          if (pos == item) {
 | 
	
		
			
				|  |  | +            // got it!
 | 
	
		
			
				|  |  | +            ANSIColor key(COLOR::GREEN, ATTR::BOLD);
 | 
	
		
			
				|  |  | +            ANSIColor value(COLOR::BLUE, ATTR::BOLD);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            config_item = c.key();
 | 
	
		
			
				|  |  | +            std::string output =
 | 
	
		
			
				|  |  | +                str(boost::format("%1%%2% : %3%%4%\n\r") % key() % config_item %
 | 
	
		
			
				|  |  | +                    value() % galaxy.meta["help"][config_item]);
 | 
	
		
			
				|  |  | +            to_client(output);
 | 
	
		
			
				|  |  | +            id->max_length = 30;
 | 
	
		
			
				|  |  | +            id->numeric = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            ANSIColor by{1, 33};
 | 
	
		
			
				|  |  | +            ANSIColor cyan{36};
 | 
	
		
			
				|  |  | +            ANSIColor bg{1, 32};
 | 
	
		
			
				|  |  | +            std::string prompt =
 | 
	
		
			
				|  |  | +                by() + "C" + cyan() + "hange to " + bg() + "=>" + reset() + " ";
 | 
	
		
			
				|  |  | +            id->prompt = prompt;
 | 
	
		
			
				|  |  | +            id->activate();
 | 
	
		
			
				|  |  | +            return;
 | 
	
		
			
				|  |  | +          };
 | 
	
		
			
				|  |  | +          ++pos;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        to_client("What?  I didn't find that item?\n\r");
 | 
	
		
			
				|  |  | +        config_edit();
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    // This is a config item edit
 | 
	
		
			
				|  |  | +    if (id->input.empty()) {
 | 
	
		
			
				|  |  | +      to_client("No change.\n\r");
 | 
	
		
			
				|  |  | +      config_edit();
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      BUGZ_LOG(fatal) << "Config EDIT: " << config_item << " = " << id->input;
 | 
	
		
			
				|  |  | +      galaxy.config[config_item] = id->input;
 | 
	
		
			
				|  |  | +      config_edit();
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::have_input(void) {
 | 
	
		
			
				|  |  | +  ++count;
 | 
	
		
			
				|  |  | +  InputDispatch *id = dynamic_cast<InputDispatch *>(&(*chain));
 | 
	
		
			
				|  |  | +  if (id) {
 | 
	
		
			
				|  |  | +    std::string output =
 | 
	
		
			
				|  |  | +        str(boost::format("Your Input (%2%): [%1%]\n\r") % id->input % count);
 | 
	
		
			
				|  |  | +    to_client("\x1b[0m");
 | 
	
		
			
				|  |  | +    to_client(output);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    proxy_deactivate();
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (count > 3) {
 | 
	
		
			
				|  |  | +    proxy_deactivate();
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    chain->activate();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::cim_done(void) {
 | 
	
		
			
				|  |  | +  BUGZ_LOG(info) << "CIM done";
 | 
	
		
			
				|  |  | +  chain = main_menu;
 | 
	
		
			
				|  |  | +  main_menu->activate();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::information(void) {
 | 
	
		
			
				|  |  | +  std::string output;
 | 
	
		
			
				|  |  | +  to_client("I currently know the following:\n\r");
 | 
	
		
			
				|  |  | +  output = str(
 | 
	
		
			
				|  |  | +      boost::format("Ports: %1%, Sectors: %2%, Config: %3%, Meta: %4%\n\r") %
 | 
	
		
			
				|  |  | +      galaxy.ports.size() % galaxy.warps.size() % galaxy.config.size() %
 | 
	
		
			
				|  |  | +      galaxy.meta.size());
 | 
	
		
			
				|  |  | +  to_client(output);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::proxy_deactivate(void) {
 | 
	
		
			
				|  |  | +  active = false;
 | 
	
		
			
				|  |  | +  // reset everything back to good state
 | 
	
		
			
				|  |  | +  talk_direct = true;
 | 
	
		
			
				|  |  | +  show_client = true;
 | 
	
		
			
				|  |  | +  chain.reset();
 | 
	
		
			
				|  |  | +  to_client("\n\r");
 | 
	
		
			
				|  |  | +  to_client(current_raw_prompt);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Server Line Parsing Routines
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::SL_cimline(const std::string &line) {
 | 
	
		
			
				|  |  | +  if (line == ": ENDINTERROG") {
 | 
	
		
			
				|  |  | +    SL_parser = nullptr;
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (line == ": ") {
 | 
	
		
			
				|  |  | +    // do I need to do anything special here for this?
 | 
	
		
			
				|  |  | +    // Maybe -- We would save special ports that don't show up
 | 
	
		
			
				|  |  | +    // (StarDock/Special) before. We don't know (at this point) if this is
 | 
	
		
			
				|  |  | +    // warps or ports.
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (line.empty()) {
 | 
	
		
			
				|  |  | +    SL_parser = nullptr;
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // parse cimline
 | 
	
		
			
				|  |  | +  // size_t pos = line.find('%');
 | 
	
		
			
				|  |  | +  // std::string work = line;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // if (pos == line.npos) {
 | 
	
		
			
				|  |  | +  if (in(line, "%")) {
 | 
	
		
			
				|  |  | +    // portcim
 | 
	
		
			
				|  |  | +    struct port p = parse_portcim(line);
 | 
	
		
			
				|  |  | +    if (p.sector == 0)
 | 
	
		
			
				|  |  | +      BUGZ_LOG(fatal) << "portcim:  FAIL [" << line << "]";
 | 
	
		
			
				|  |  | +    else
 | 
	
		
			
				|  |  | +      BUGZ_LOG(trace) << "portcim: " << p;
 | 
	
		
			
				|  |  | +    galaxy.add_port(p);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    // warpcim
 | 
	
		
			
				|  |  | +    // BUGZ_LOG(fatal) << "warpcim: [" << line << "]";
 | 
	
		
			
				|  |  | +    auto warps = split(line);
 | 
	
		
			
				|  |  | +    sector_warps sw;
 | 
	
		
			
				|  |  | +    for (auto const &w : warps) {
 | 
	
		
			
				|  |  | +      if (sw.sector == 0) {
 | 
	
		
			
				|  |  | +        sw.sector = stoi(w);
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        sw.add(stoi(w));
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    BUGZ_LOG(trace) << "warpcim: " << sw;
 | 
	
		
			
				|  |  | +    galaxy.add_warp(sw);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::SL_thiefline(const std::string &line) {
 | 
	
		
			
				|  |  | +  size_t pos = line.find("Suddenly you're Busted!");
 | 
	
		
			
				|  |  | +  bool busted = pos != line.npos;
 | 
	
		
			
				|  |  | +  if (busted) {
 | 
	
		
			
				|  |  | +    BUGZ_LOG(fatal) << "set bust";
 | 
	
		
			
				|  |  | +    SL_parser = nullptr;
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    pos = line.find("(You realize the guards saw you last time!)");
 | 
	
		
			
				|  |  | +    if (pos != line.npos) SL_parser = nullptr;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Are those the two ways to exit from this state?
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +void Director::SL_sectorline(const std::string &line) {
 | 
	
		
			
				|  |  | +  BUGZ_LOG(fatal) << "sectorline: [" << line << "]";
 | 
	
		
			
				|  |  | +  if (line.empty()) {
 | 
	
		
			
				|  |  | +    SL_parser = nullptr;
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  | +    sectorline: [Sector  : 926 in The Federation.]
 | 
	
		
			
				|  |  | +    sectorline: [Beacon  : FedSpace, FedLaw Enforced]
 | 
	
		
			
				|  |  | +    sectorline: [Ports   : Stargate Alpha I, Class 9 (Special) (StarDock)]
 | 
	
		
			
				|  |  | +    sectorline: [Traders : Civilian phil, w/ 30 ftrs,]
 | 
	
		
			
				|  |  | +    sectorline: [           in Star Stomper (Sverdlov Merchant Cruiser)]
 | 
	
		
			
				|  |  | +    sectorline: [Warps to Sector(s) :  70 - 441 - 575 - 600 - 629 - 711]
 | 
	
		
			
				|  |  | +    sectorline: [Warps to Sector(s) :  70 - (475) - 569]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    What can we get from Traders : line?  Can we get if they are hostile
 | 
	
		
			
				|  |  | +    to us?  We need to respond to "is powering up weapons" ... We can
 | 
	
		
			
				|  |  | +    react faster then a person can!
 | 
	
		
			
				|  |  | +    "phil is powering up weapons systems!"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Also the auto-attack ones Ferrengi -- we need to auto-respond Retreat.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    */
 | 
	
		
			
				|  |  | +    if (in(line, "Sector  :")) {
 | 
	
		
			
				|  |  | +      current_sector = stoi(line.substr(10));
 | 
	
		
			
				|  |  | +      BUGZ_LOG(warning) << "SECTOR: " << current_sector;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (in(line, "Ports   :")) {
 | 
	
		
			
				|  |  | +      std::string port_class;
 | 
	
		
			
				|  |  | +      size_t pos = line.find(", Class ");
 | 
	
		
			
				|  |  | +      if (pos != std::string::npos) {
 | 
	
		
			
				|  |  | +        pos += 8;
 | 
	
		
			
				|  |  | +        int class_ = stoi(line.substr(pos));
 | 
	
		
			
				|  |  | +        BUGZ_LOG(fatal) << "PORT: " << class_;
 | 
	
		
			
				|  |  | +        galaxy.add_port(current_sector, class_);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (in(line, "Warps to Sector(s) :")) {
 | 
	
		
			
				|  |  | +      std::string temp = line.substr(20);
 | 
	
		
			
				|  |  | +      replace(temp, " - ", " ");
 | 
	
		
			
				|  |  | +      // unexplored sectors ()
 | 
	
		
			
				|  |  | +      // Should I track these?
 | 
	
		
			
				|  |  | +      replace(temp, "(", "");
 | 
	
		
			
				|  |  | +      replace(temp, ")", "");
 | 
	
		
			
				|  |  | +      sector_warps sw;
 | 
	
		
			
				|  |  | +      auto warps = split(temp);
 | 
	
		
			
				|  |  | +      sw.sector = current_sector;
 | 
	
		
			
				|  |  | +      // what if there is only one warp?
 | 
	
		
			
				|  |  | +      for (auto const &w : warps) {
 | 
	
		
			
				|  |  | +        sw.add(stoi(w));
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      BUGZ_LOG(fatal) << "WARPS: " << sw;
 | 
	
		
			
				|  |  | +      galaxy.add_warp(sw);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::SL_densityline(const std::string &line) {
 | 
	
		
			
				|  |  | +  BUGZ_LOG(fatal) << "densityline: [" << line << "]";
 | 
	
		
			
				|  |  | +  if (line.empty()) {
 | 
	
		
			
				|  |  | +    SL_parser = nullptr;
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +  // Ensure this really is a density scan and not something else
 | 
	
		
			
				|  |  | +  if (!in(line, "Sector") || !in(line, "Warps") || !in(line, "NavHaz") ||
 | 
	
		
			
				|  |  | +      !in(line, "Anom")) {
 | 
	
		
			
				|  |  | +    BUGZ_LOG(fatal) << "densityline: Invalid line.";
 | 
	
		
			
				|  |  | +    SL_parser = nullptr;
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (not galaxy.meta["density"]) {
 | 
	
		
			
				|  |  | +    galaxy.meta["density"] = YAML::Node();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +   0         1   2                3  4     5 6    7      8     9     10   11 12
 | 
	
		
			
				|  |  | +  "Sector    55  ==>              0  Warps : 4    NavHaz :     0%    Anom : No"
 | 
	
		
			
				|  |  | +  "Sector ( 223) ==>              0  Warps : 3    NavHaz :     0%    Anom : No"
 | 
	
		
			
				|  |  | +  */
 | 
	
		
			
				|  |  | +  if (in(line, "==>")) {
 | 
	
		
			
				|  |  | +    std::string work = line;
 | 
	
		
			
				|  |  | +    replace(work, ":", "");
 | 
	
		
			
				|  |  | +    bool known = !in(work, "(");
 | 
	
		
			
				|  |  | +    replace(work, "(", "");
 | 
	
		
			
				|  |  | +    replace(work, ")", "");
 | 
	
		
			
				|  |  | +    replace(work, "%", "");
 | 
	
		
			
				|  |  | +    auto dense = split(work);
 | 
	
		
			
				|  |  | +    // Parse our data
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    sector_type sector = std::stoi(dense.at(1));
 | 
	
		
			
				|  |  | +    uint16_t density = std::stoi(dense.at(3));
 | 
	
		
			
				|  |  | +    uint16_t warps = std::stoi(dense.at(5));
 | 
	
		
			
				|  |  | +    uint16_t navhaz = std::stoi(dense.at(7));
 | 
	
		
			
				|  |  | +    bool anom = in(dense.at(9), "Yes");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    struct density d = {sector, density, warps, navhaz, anom, known};
 | 
	
		
			
				|  |  | +    galaxy.dscan.add_scan(d);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Commit data
 | 
	
		
			
				|  |  | +    BUGZ_LOG(warning) << "densityline: {sector=" << sector
 | 
	
		
			
				|  |  | +                      << " density=" << density << " warps=" << warps
 | 
	
		
			
				|  |  | +                      << " navhaz=" << navhaz << " anom=" << anom
 | 
	
		
			
				|  |  | +                      << " known=" << known << "}";
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  | +    if (galaxy.meta["density"][sector]) {
 | 
	
		
			
				|  |  | +      galaxy.meta["density"][sector] = YAML::Node();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    */
 | 
	
		
			
				|  |  | +<<<<<<< HEAD
 | 
	
		
			
				|  |  | +    // what():  [json.exception.type_error.305] cannot use operator[] with a
 | 
	
		
			
				|  |  | +    // numeric argument with object
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    std::string sector_text = std::to_string(sector);
 | 
	
		
			
				|  |  | +    galaxy.meta["density"][sector_text]["density"] = density;
 | 
	
		
			
				|  |  | +    galaxy.meta["density"][sector_text]["warps"] = warps;
 | 
	
		
			
				|  |  | +    galaxy.meta["density"][sector_text]["navhaz"] = navhaz;
 | 
	
		
			
				|  |  | +    galaxy.meta["density"][sector_text]["anom"] = anom;
 | 
	
		
			
				|  |  | +    galaxy.meta["density"][sector_text]["known"] = known;
 | 
	
		
			
				|  |  | +=======
 | 
	
		
			
				|  |  | +   // what():  [json.exception.type_error.305] cannot use operator[] with a numeric argument with object
 | 
	
		
			
				|  |  | +   
 | 
	
		
			
				|  |  | +   std::string sector_text = std::to_string(sector);
 | 
	
		
			
				|  |  | +    galaxy.meta["_density"][sector_text]["density"] = density;
 | 
	
		
			
				|  |  | +    galaxy.meta["_density"][sector_text]["warps"] = warps;
 | 
	
		
			
				|  |  | +    galaxy.meta["_density"][sector_text]["navhaz"] = navhaz;
 | 
	
		
			
				|  |  | +    galaxy.meta["_density"][sector_text]["anom"] = anom;
 | 
	
		
			
				|  |  | +    galaxy.meta["_density"][sector_text]["known"] = known;
 | 
	
		
			
				|  |  | +>>>>>>> master
 | 
	
		
			
				|  |  | +    // Add a check to see if density is greater than 500
 | 
	
		
			
				|  |  | +    // Add datetime stamp
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::SL_portline(const std::string &line) {
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +  We take blank lines because we start at <Port>.
 | 
	
		
			
				|  |  | +  Otherwise, we trigger on computer port requests.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (line.empty()) {
 | 
	
		
			
				|  |  | +    SL_parser = nullptr;
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  */
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +  SL: [ Items     Status  Trading % of max OnBoard]
 | 
	
		
			
				|  |  | +  SL: [ -----     ------  ------- -------- -------]
 | 
	
		
			
				|  |  | +  SL: [Fuel Ore   Buying    3000    100%       0]
 | 
	
		
			
				|  |  | +  SL: [Organics   Buying    3000    100%       0]
 | 
	
		
			
				|  |  | +  SL: [Equipment  Buying    3000    100%       0]
 | 
	
		
			
				|  |  | +  SL: []
 | 
	
		
			
				|  |  | +  SL: [Commerce report for: 03:51:56 PM Mon Oct 24, 2033     You can buy:]
 | 
	
		
			
				|  |  | +  SL: [A  Cargo holds     :    650 credits / next hold                0]
 | 
	
		
			
				|  |  | +  SL: [B  Fighters        :    233 credits per fighter               75]
 | 
	
		
			
				|  |  | +  SL: [C  Shield Points   :    116 credits per point                100]
 | 
	
		
			
				|  |  | +  SL: []
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  // BUGZ_LOG(info) << "portline : " << line;
 | 
	
		
			
				|  |  | +  if (in(line, "%")) {
 | 
	
		
			
				|  |  | +    // size_t pos = line.find('%');
 | 
	
		
			
				|  |  | +    // if (pos != line.npos) {
 | 
	
		
			
				|  |  | +    // Ok, this is a valid portline
 | 
	
		
			
				|  |  | +    std::string work = line;
 | 
	
		
			
				|  |  | +    replace(work, "Fuel Ore", "Fuel");
 | 
	
		
			
				|  |  | +    auto parts = split(work);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (parts[0] == "Items") return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    char c = tolower(parts[0][0]);
 | 
	
		
			
				|  |  | +    int pos;
 | 
	
		
			
				|  |  | +    char foe[4] = "foe";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    for (pos = 0; pos < 3; ++pos) {
 | 
	
		
			
				|  |  | +      if (c == foe[pos]) break;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    int amount = stoi(parts[2]);
 | 
	
		
			
				|  |  | +    int percent = stoi(parts[3]);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // update port
 | 
	
		
			
				|  |  | +    auto port = galaxy.ports.find(current_sector);
 | 
	
		
			
				|  |  | +    if (port != galaxy.ports.end()) {
 | 
	
		
			
				|  |  | +      port->second.amount[pos] = amount;
 | 
	
		
			
				|  |  | +      port->second.percent[pos] = percent;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  | +    BUGZ_LOG(fatal) << "portline split:";
 | 
	
		
			
				|  |  | +    for (auto const p : parts) {
 | 
	
		
			
				|  |  | +      BUGZ_LOG(fatal) << p;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Here's the end:
 | 
	
		
			
				|  |  | +    if (parts[0] == "Equipment") SL_parser = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // BUGZ_LOG(fatal) << "portline split : [" << parts << "]";
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::SL_warpline(const std::string &line) {
 | 
	
		
			
				|  |  | +  if (line.empty()) {
 | 
	
		
			
				|  |  | +    SL_parser = nullptr;
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // process warp line
 | 
	
		
			
				|  |  | +  BUGZ_LOG(fatal) << "warpline: [" << line << "]";
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::SL_infoline(const std::string &line) {
 | 
	
		
			
				|  |  | +  static int state;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (line == "<Info>") {
 | 
	
		
			
				|  |  | +    state = 0;
 | 
	
		
			
				|  |  | +    galaxy.meta["info"] = json();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (line.empty()) {
 | 
	
		
			
				|  |  | +    ++state;
 | 
	
		
			
				|  |  | +    if (state == 2) {
 | 
	
		
			
				|  |  | +      SL_parser = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // clear out the existing ship data
 | 
	
		
			
				|  |  | +      galaxy.meta["ship"] = json();
 | 
	
		
			
				|  |  | +      // process the parsed information in meta["info"]
 | 
	
		
			
				|  |  | +      if (galaxy.meta["info"].contains("Total Holds")) {
 | 
	
		
			
				|  |  | +        std::string work = galaxy.meta["info"]["Total Holds"];
 | 
	
		
			
				|  |  | +        replace(work, "Fuel Ore", "Fuel");
 | 
	
		
			
				|  |  | +        auto parts = split(work, " - ");
 | 
	
		
			
				|  |  | +        int total_holds = stoi(parts[0]);
 | 
	
		
			
				|  |  | +        BUGZ_LOG(fatal) << "total holds: " << total_holds;
 | 
	
		
			
				|  |  | +        auto contents = split(parts[1]);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for (auto const &hold : contents) {
 | 
	
		
			
				|  |  | +          auto hold_amount = split(hold, "=");
 | 
	
		
			
				|  |  | +          BUGZ_LOG(fatal) << hold_amount[0] << " with " << hold_amount[1];
 | 
	
		
			
				|  |  | +          std::string key = hold_amount[0];
 | 
	
		
			
				|  |  | +          str_tolower(key);
 | 
	
		
			
				|  |  | +          // equipment = e
 | 
	
		
			
				|  |  | +          // organics = o
 | 
	
		
			
				|  |  | +          // fuel = f
 | 
	
		
			
				|  |  | +          // colonists = c
 | 
	
		
			
				|  |  | +          // empty = empty
 | 
	
		
			
				|  |  | +          if (key != "empty") {
 | 
	
		
			
				|  |  | +            key = key[0];
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          galaxy.meta["ship"]["holds"][key] = stoi(hold_amount[1]);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        galaxy.meta["ship"]["holds"]["total"] = total_holds;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (galaxy.meta["info"].contains("Turns to Warp")) {
 | 
	
		
			
				|  |  | +        // Why is this saying that this is a string?
 | 
	
		
			
				|  |  | +        int warp_turns = sstoi(json_str(galaxy.meta["info"]["Turns to Warp"]));
 | 
	
		
			
				|  |  | +        BUGZ_LOG(fatal) << "Turns to Warp: " << warp_turns;
 | 
	
		
			
				|  |  | +        galaxy.meta["ship"]["warp_turns"] = warp_turns;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (galaxy.meta["info"].contains("LongRange Scan")) {
 | 
	
		
			
				|  |  | +        std::string scanner_text =
 | 
	
		
			
				|  |  | +            galaxy.meta["info"]["LongRange Scan"].get<std::string>();
 | 
	
		
			
				|  |  | +        char scanner = scanner_text[0];
 | 
	
		
			
				|  |  | +        BUGZ_LOG(fatal) << "Scanner: " << scanner;
 | 
	
		
			
				|  |  | +        galaxy.meta["ship"]["scanner"] = scanner;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // turns isn't ship specific
 | 
	
		
			
				|  |  | +      if (galaxy.meta["info"].contains("Turns left")) {
 | 
	
		
			
				|  |  | +        // OR this could be "Unlimited" !!!
 | 
	
		
			
				|  |  | +        std::string text = galaxy.meta["info"]["Turns left"];
 | 
	
		
			
				|  |  | +        if (text == "Unlimited") {
 | 
	
		
			
				|  |  | +          galaxy.meta["turns"] = -1;
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          int turns =
 | 
	
		
			
				|  |  | +              stoi(text);  // galaxy.meta["info"]["Turns left"].as<int>();
 | 
	
		
			
				|  |  | +          BUGZ_LOG(fatal) << "Turns left: " << turns;
 | 
	
		
			
				|  |  | +          galaxy.meta["turns"] = turns;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (galaxy.meta["info"].contains("Current Sector")) {
 | 
	
		
			
				|  |  | +        int sector = sstoi(json_str(galaxy.meta["info"]["Current Sector"]));
 | 
	
		
			
				|  |  | +        BUGZ_LOG(fatal) << "Sector: " << sector;
 | 
	
		
			
				|  |  | +        // it should already be sector ...
 | 
	
		
			
				|  |  | +        current_sector = sector;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (galaxy.meta["info"].contains("Credits")) {
 | 
	
		
			
				|  |  | +        std::string credit_text = galaxy.meta["info"]["Credits"];
 | 
	
		
			
				|  |  | +        replace(credit_text, ",", "");
 | 
	
		
			
				|  |  | +        int credits = stoi(credit_text);
 | 
	
		
			
				|  |  | +        galaxy.meta["credits"] = credits;
 | 
	
		
			
				|  |  | +        BUGZ_LOG(fatal) << "Credits: " << credits;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // info to parse:
 | 
	
		
			
				|  |  | +  size_t pos = line.find(" : ");
 | 
	
		
			
				|  |  | +  if ((!endswith(line, " : ")) && (pos != line.npos)) {
 | 
	
		
			
				|  |  | +    std::string key = line.substr(0, pos);
 | 
	
		
			
				|  |  | +    // Ferrengi ships don't have date built
 | 
	
		
			
				|  |  | +    std::string value = line.substr(pos + 3);
 | 
	
		
			
				|  |  | +    trim(key);
 | 
	
		
			
				|  |  | +    trim(value);
 | 
	
		
			
				|  |  | +    galaxy.meta["info"][key] = value;
 | 
	
		
			
				|  |  | +    BUGZ_LOG(fatal) << "Info: " << key << " : " << value;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  // [Corp           # 1, Galaxy Stomping, Inc.]
 | 
	
		
			
				|  |  | +  if (startswith(line, "Corp  ")) {
 | 
	
		
			
				|  |  | +    pos = line.find(", ");
 | 
	
		
			
				|  |  | +    if (pos != line.npos) {
 | 
	
		
			
				|  |  | +      galaxy.meta["info"]["Corp"] = line.substr(pos + 2);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::SL_computer_portline(const std::string &line) {
 | 
	
		
			
				|  |  | +  if (startswith(line, "What sector is the port in?"))
 | 
	
		
			
				|  |  | +    computer_port_done = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (line == "I have no information about a port in that sector.") {
 | 
	
		
			
				|  |  | +    computer_port_sector = 0;
 | 
	
		
			
				|  |  | +    SL_parser = nullptr;
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (!computer_port_done) {
 | 
	
		
			
				|  |  | +    if (in(line, "Fuel Ore")) computer_port_done = true;
 | 
	
		
			
				|  |  | +    if (in(line, "Cargo holds")) {
 | 
	
		
			
				|  |  | +      // If I want to scan the class type 0 ports:
 | 
	
		
			
				|  |  | +      // computer_port_done = true;
 | 
	
		
			
				|  |  | +      // otherwise:
 | 
	
		
			
				|  |  | +      SL_parser = nullptr;
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (computer_port_done) {
 | 
	
		
			
				|  |  | +    if (line.empty()) {
 | 
	
		
			
				|  |  | +      SL_parser = nullptr;
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // scan for items of interest
 | 
	
		
			
				|  |  | +    // SL: [Fuel Ore   Buying     810    100%       0]
 | 
	
		
			
				|  |  | +    // SL: [Organics   Buying     856     57%       0]
 | 
	
		
			
				|  |  | +    // SL: [Equipment  Selling    922     44%       0]
 | 
	
		
			
				|  |  | +    std::string work = line;
 | 
	
		
			
				|  |  | +    replace(work, "Fuel Ore", "Fuel");
 | 
	
		
			
				|  |  | +    replace(work, "%", "");
 | 
	
		
			
				|  |  | +    auto parts = split(work);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    char c = tolower(parts[0][0]);
 | 
	
		
			
				|  |  | +    int pos;
 | 
	
		
			
				|  |  | +    char foe[4] = "foe";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    for (pos = 0; pos < 3; ++pos) {
 | 
	
		
			
				|  |  | +      if (c == foe[pos]) break;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    int amount = stoi(parts[2]);
 | 
	
		
			
				|  |  | +    int percent = stoi(parts[3]);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // update port
 | 
	
		
			
				|  |  | +    auto port = galaxy.ports.find(computer_port_sector);
 | 
	
		
			
				|  |  | +    if (port != galaxy.ports.end()) {
 | 
	
		
			
				|  |  | +      BUGZ_LOG(info) << "COM PORT " << computer_port_sector << " " << c << " "
 | 
	
		
			
				|  |  | +                     << amount << " " << percent;
 | 
	
		
			
				|  |  | +      port->second.amount[pos] = amount;
 | 
	
		
			
				|  |  | +      port->second.percent[pos] = percent;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void Director::SL_planetline(const std::string &line) {
 | 
	
		
			
				|  |  | +  if (line == "Corporate command [TL=00:00:00]:[344] (?=Help)? Q" ||
 | 
	
		
			
				|  |  | +      line == "Computer command [TL=00:00:00]:[344] (?=Help)? Q") {
 | 
	
		
			
				|  |  | +    SL_parser = nullptr;
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (in(line, "Class ") &&
 | 
	
		
			
				|  |  | +      (in(line, "Level ") || (endswith(line, "No Citadel")))) {
 | 
	
		
			
				|  |  | +    int level;
 | 
	
		
			
				|  |  | +    char c;
 | 
	
		
			
				|  |  | +    sector_type sector;
 | 
	
		
			
				|  |  | +    int number;
 | 
	
		
			
				|  |  | +    std::string name;
 | 
	
		
			
				|  |  | +    std::string work = line;
 | 
	
		
			
				|  |  | +    size_t pos = work.find('#');
 | 
	
		
			
				|  |  | +    std::string temp = work.substr(0, pos);
 | 
	
		
			
				|  |  | +    trim(temp);
 | 
	
		
			
				|  |  | +    sector = sstoi(temp);
 | 
	
		
			
				|  |  | +    work = work.substr(pos + 1);
 | 
	
		
			
				|  |  | +    number = sstoi(work);
 | 
	
		
			
				|  |  | +    pos = work.find(' ');
 | 
	
		
			
				|  |  | +    work = work.substr(pos + 1);
 | 
	
		
			
				|  |  | +    trim(work);
 | 
	
		
			
				|  |  | +    if (endswith(work, "No Citadel")) {
 | 
	
		
			
				|  |  | +      level = 0;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      pos = work.rfind("Level ");
 | 
	
		
			
				|  |  | +      temp = work.substr(pos + 6);
 | 
	
		
			
				|  |  | +      level = sstoi(temp);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    pos = work.rfind("Class ");
 | 
	
		
			
				|  |  | +    temp = work.substr(pos + 6);
 | 
	
		
			
				|  |  | +    c = temp[0];
 | 
	
		
			
				|  |  | +    work = work.substr(0, pos);
 | 
	
		
			
				|  |  | +    trim(work);
 | 
	
		
			
				|  |  | +    name = work;
 | 
	
		
			
				|  |  | +    BUGZ_LOG(warning) << (int)sector << " # " << number << " Class " << c
 | 
	
		
			
				|  |  | +                      << " Level " << level << " name: [" << name << "]";
 | 
	
		
			
				|  |  | +    planet p{sector, number, level, name, c};
 | 
	
		
			
				|  |  | +    galaxy.planets[number] = p;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +  SL: [   344   #4    Enjoy the Silence        Class M, Earth Type Level 3] SL:
 | 
	
		
			
				|  |  | +  [   ---   (4M)            1T   64   25   14T   693   277         2T 10M] SL: [
 | 
	
		
			
				|  |  | +  344   #5    High There!              Class L, Mountainous          Level 2]
 | 
	
		
			
				|  |  | +  SL: [   ---   (5M)            2T    0    6   25T   100   112         2T 6M]
 | 
	
		
			
				|  |  | +  ...
 | 
	
		
			
				|  |  | +  SL: [   ---   (9M)            3T   64   31   39T   793   389         4T ---]
 | 
	
		
			
				|  |  | +  */
 | 
	
		
			
				|  |  | +}
 |