1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363 |
- #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 ---]
- */
- }
|