|
@@ -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 ---]
|
|
|
+ */
|
|
|
+}
|