12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310 |
- #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["display_lines"]) {
- galaxy.config["display_lines"] = 20;
- }
- galaxy.meta["help"]["display_lines"] =
- "Number of report lines to display";
- if (!galaxy.config["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)? : ")) {
- 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());
- 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["display_lines"])
- max_display = galaxy.config["display_lines"].as<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.
- 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 '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) {
- std::string output =
- str(boost::format("%1%%2$2d %3%%4$20s: %5%%6$s%7%\n\r") % number() %
- item % key() % cfg.first % value() % cfg.second % 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;
- const YAML::Node &config = galaxy.config;
- for (auto const &c : config) {
- if (pos == item) {
- // got it!
- ANSIColor key(COLOR::GREEN, ATTR::BOLD);
- ANSIColor value(COLOR::BLUE, ATTR::BOLD);
- config_item = c.first.as<std::string>();
- 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();
- }
- */
- galaxy.meta["density"][sector]["density"] = density;
- galaxy.meta["density"][sector]["warps"] = warps;
- galaxy.meta["density"][sector]["navhaz"] = navhaz;
- galaxy.meta["density"][sector]["anom"] = anom;
- galaxy.meta["density"][sector]["known"] = known;
- // 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"] = YAML::Node();
- }
- if (line.empty()) {
- ++state;
- if (state == 2) {
- SL_parser = nullptr;
- // clear out the existing ship data
- galaxy.meta["ship"] = YAML::Node();
- // process the parsed information in meta["info"]
- if (galaxy.meta["info"]["Total Holds"]) {
- std::string work = galaxy.meta["info"]["Total Holds"].as<std::string>();
- 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"]["Turns to Warp"]) {
- int warp_turns = galaxy.meta["info"]["Turns to Warp"].as<int>();
- BUGZ_LOG(fatal) << "Turns to Warp: " << warp_turns;
- galaxy.meta["ship"]["warp_turns"] = warp_turns;
- }
- if (galaxy.meta["info"]["LongRange Scan"]) {
- std::string scanner_text =
- galaxy.meta["info"]["LongRange Scan"].as<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"]["Turns left"]) {
- // OR this could be "Unlimited" !!!
- std::string text = galaxy.meta["info"]["Turns left"].as<std::string>();
- 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"]["Current Sector"]) {
- int sector = galaxy.meta["info"]["Current Sector"].as<int>();
- BUGZ_LOG(fatal) << "Sector: " << sector;
- // it should already be sector ...
- current_sector = sector;
- }
- if (galaxy.meta["info"]["Credits"]) {
- std::string credit_text =
- galaxy.meta["info"]["Credits"].as<std::string>();
- 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;
- }
- }
- 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 << "]";
- }
- /*
- 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 ---]
- */
- }
|