director.cpp.orig 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363
  1. #include "director.h"
  2. #include <boost/format.hpp>
  3. #include <cctype>
  4. #include "ansicolor.h"
  5. #include "boxes.h"
  6. #include "galaxy.h"
  7. #include "logging.h"
  8. #include "scripts.h"
  9. #include "utils.h"
  10. Director::Director() {
  11. BUGZ_LOG(warning) << "Director::Director()";
  12. // active = false;
  13. game = 0; // not in a game
  14. galaxy.reset();
  15. // do everything proxy_deactivate does ...
  16. // proxy_deactivate();
  17. active = false;
  18. // reset everything back to good state
  19. talk_direct = true;
  20. show_client = true;
  21. count = 0;
  22. /*
  23. Setup StringFunc for SL_parser:
  24. Construct these once, rather then every single time we need them.
  25. */
  26. SF_cimline = [this](const std::string &s) { this->SL_cimline(s); };
  27. SF_sectorline = [this](const std::string &s) { this->SL_sectorline(s); };
  28. SF_portline = [this](const std::string &s) { this->SL_portline(s); };
  29. SF_warpline = [this](const std::string &s) { this->SL_warpline(s); };
  30. SF_infoline = [this](const std::string &s) { this->SL_infoline(s); };
  31. SF_densityline = [this](const std::string &s) { this->SL_densityline(s); };
  32. SF_computer_portline = [this](const std::string &s) {
  33. this->SL_computer_portline(s);
  34. };
  35. SF_planetline = [this](const std::string &s) { this->SL_planetline(s); };
  36. build_menu();
  37. }
  38. Director::~Director() { BUGZ_LOG(warning) << "Director::~Director()"; }
  39. void Director::client_input(const std::string &input) {
  40. // If we're already active, don't try to activate.
  41. if (chain) {
  42. chain->client_input(input);
  43. return;
  44. }
  45. if (active) {
  46. if (input == "Q" || input == "q") proxy_deactivate();
  47. return;
  48. } else if (input == "\x1b" || input == "~") {
  49. std::string &prompt = current_prompt;
  50. BUGZ_LOG(trace) << "ACTIVATE prompt shows: [" << prompt << "]";
  51. if (prompt == "Selection (? for menu): ") {
  52. to_client(
  53. "\n\rThere's not much we can do here. Activate in-game at a "
  54. "Command prompt.\n\r");
  55. to_client(current_raw_prompt);
  56. return;
  57. }
  58. // easter-eggs:
  59. if (prompt == "Enter your choice: ") {
  60. ANSIColor c1(COLOR::CYAN, ATTR::BOLD);
  61. ANSIColor c2(COLOR::WHITE, ATTR::BOLD);
  62. to_client(std::string("\n\r") + c1() + "I'd choose " + c2() + "`T`" +
  63. c1() + ", but that's how I was coded.\n\r");
  64. // "\n\r\x1b[1;36mI'd choose \x1b[1;37m`T`\x1b[1;36m, but "
  65. // "that's how I was coded.\n\r");
  66. to_client(current_raw_prompt);
  67. return;
  68. }
  69. // easter-egg
  70. if (prompt == "[Pause]") {
  71. ANSIColor c1(COLOR::CYAN, ATTR::BOLD);
  72. to_client(std::string(" ") + c1() + "PAWS" + reset() + "\n\r");
  73. to_client(current_raw_prompt);
  74. return;
  75. }
  76. if (at_planet_prompt(prompt)) {
  77. // future: If activated at planet menu, activate the planet upgrade
  78. // script! (Maybe). If I can figure out what planet it is/and where.
  79. to_client("\n\r\x1b[0mFUTURE: Activate the planet upgrade script.\n\r");
  80. to_client(current_raw_prompt);
  81. return;
  82. }
  83. if (at_command_prompt(prompt)) {
  84. proxy_activate();
  85. return;
  86. }
  87. }
  88. // Ok...
  89. if (talk_direct) to_server(input);
  90. }
  91. void Director::server_line(const std::string &line,
  92. const std::string &raw_line) {
  93. // check for if we entered game/left game
  94. if (line.find("TradeWars Game Server ") != std::string::npos) {
  95. // Inject our proxy activation message
  96. to_client("\rTradeWars Proxy v2++ READY (~ or ESC to activate)\n\r");
  97. /*
  98. There's a delay here when I save the game data.
  99. I've moved it futher down. Hide it at a prompt, so it isn't so
  100. noticeable.
  101. */
  102. // reset "active game" -- we're at the TWGS main menu
  103. }
  104. if (line.find("Selection (? for menu): ") != std::string::npos) {
  105. char ch = line[line.length() - 1];
  106. if (ch >= 'A' && ch < 'Q') {
  107. if ((game) && (game != ch)) {
  108. galaxy.save();
  109. }
  110. game = ch;
  111. BUGZ_LOG(warning) << "GAME " << game << " activated!";
  112. // TODO: Load game data
  113. galaxy.game = game;
  114. galaxy.username = username;
  115. galaxy.load();
  116. // YAML loaded, set sensible default config values (if missing).
  117. if (!galaxy.config.contains("display_lines")) {
  118. galaxy.config["display_lines"] = 20;
  119. }
  120. galaxy.meta["help"]["display_lines"] =
  121. "Number of report lines to display";
  122. if (!galaxy.config.contains("burnt_percent")) {
  123. galaxy.config["burnt_percent"] = 40;
  124. }
  125. galaxy.meta["help"]["burnt_percent"] =
  126. "Don't display ports in report below this percent";
  127. }
  128. // not needed (handled by above Game Server check).
  129. if (ch == 'Q') {
  130. if (game) {
  131. // TODO: Save galaxy data
  132. galaxy.save();
  133. }
  134. game = 0;
  135. galaxy.reset();
  136. }
  137. }
  138. if (game) {
  139. // in-game parsing here.
  140. /*
  141. ____ _ _
  142. / ___| ___ _ ____ _____ _ __ | | (_)_ __ ___
  143. \___ \ / _ \ '__\ \ / / _ \ '__| | | | | '_ \ / _ \
  144. ___) | __/ | \ V / __/ | | |___| | | | | __/
  145. |____/ \___|_| \_/ \___|_| |_____|_|_| |_|\___|
  146. ____ _
  147. | _ \ __ _ _ __ ___(_)_ __ __ _
  148. | |_) / _` | '__/ __| | '_ \ / _` |
  149. | __/ (_| | | \__ \ | | | | (_| |
  150. |_| \__,_|_| |___/_|_| |_|\__, |
  151. |___/
  152. This is where all of the server lines are gleaned for all the
  153. information that we can get out of them.
  154. // When activating the computer
  155. SP: [Command [TL=00:00:00]:[926] (?=Help)? : ]
  156. Sector: 926
  157. CI: [c]
  158. SL: [Command [TL=00:00:00]:[926] (?=Help)? : C]
  159. SL: [<Computer>]
  160. SL: []
  161. SL: [<Computer activated>]
  162. SL: []
  163. SP: [Computer command [TL=00:00:00]:[926] (?=Help)? ]
  164. // deactivating the computer
  165. SL: [Computer command [TL=00:00:00]:[926] (?=Help)? Q]
  166. SL: []
  167. SL: [<Computer deactivated>]
  168. SL: []
  169. */
  170. if (line == "<Port>") {
  171. SL_parser = SF_portline;
  172. }
  173. if (line ==
  174. " Corporate Planet Scan "
  175. " " ||
  176. line ==
  177. " Personal Planet Scan "
  178. " ") {
  179. SL_parser = SF_planetline;
  180. }
  181. /*
  182. if (startswith(line, " Items Status Trading % of max OnBoard"))
  183. SL_parser = SF_portline;
  184. */
  185. if (endswith(line, "Relative Density Scan")) {
  186. galaxy.dscan.reset(current_sector);
  187. SL_parser = SF_densityline;
  188. }
  189. if (startswith(line, "Sector : ")) SL_parser = SF_sectorline;
  190. if (line == ": ") SL_parser = SF_cimline;
  191. if (line == "<Info>") SL_parser = SF_infoline;
  192. if (startswith(line, "What sector is the port in? [")) {
  193. // Computer Port Report
  194. // SL: [What sector is the port in? [611] 4]
  195. size_t pos = line.rfind(' ');
  196. computer_port_sector = stoi(line.substr(pos));
  197. SL_parser = SF_computer_portline;
  198. }
  199. }
  200. if (SL_parser) {
  201. SL_parser(line);
  202. }
  203. if (chain) {
  204. chain->server_line(line, raw_line);
  205. }
  206. }
  207. void Director::server_prompt(const std::string &prompt,
  208. const std::string &raw_prompt) {
  209. current_prompt = prompt;
  210. current_raw_prompt = raw_prompt;
  211. if (game) {
  212. if (prompt == "Selection (? for menu): ") {
  213. galaxy.save();
  214. game = 0;
  215. galaxy.reset();
  216. }
  217. // in-game parsing here.
  218. // if (startswith(prompt, "Command [") && endswith(prompt, "] (?=Help)? :
  219. // ")) {
  220. if (at_command_prompt(prompt)) {
  221. std::string sector_text;
  222. size_t before, after;
  223. before = prompt.find("]:[") + 3;
  224. after = prompt.find("] (?=Help)");
  225. sector_text = prompt.substr(before, after - before);
  226. current_sector = stoi(sector_text);
  227. BUGZ_LOG(info) << "current_sector = " << current_sector;
  228. }
  229. }
  230. /*
  231. if (emit_server_prompt)
  232. emit_server_prompt(prompt);
  233. */
  234. if (chain) chain->server_prompt(prompt);
  235. }
  236. void Director::build_menu(void) {
  237. main_menu = std::make_shared<MenuDispatch>(*this);
  238. MenuDispatch *md = static_cast<MenuDispatch *>(&(*main_menu));
  239. ANSIColor bcolor(COLOR::YELLOW, COLOR::BLUE, ATTR::BOLD);
  240. ANSIColor tcolor(COLOR::WHITE, COLOR::BLUE, ATTR::BOLD);
  241. ANSIColor mocolor(COLOR::CYAN, ATTR::BOLD);
  242. md->menu_box_color = bcolor(); // "\x1b[1;33;44m";
  243. md->menu_text_color = tcolor(); // "\x1b[1;37;44m";
  244. md->menu_title = "Proxy Menu";
  245. md->menu_options_color = mocolor(); // "\x1b[1;36;40m";
  246. ANSIColor by{1, 33};
  247. ANSIColor cyan{36};
  248. ANSIColor bg{1, 32};
  249. std::string prompt = by() + "M" + cyan() + "ain " + by() + "P" + cyan() +
  250. "roxy " + bg() + "=>" + reset() + " ";
  251. md->menu_prompt = prompt; // "Main Proxy => ";
  252. // "\x1b[0;31;40m\xdb\xb2\xb1\xb0 \x1b[31;40mRED "
  253. // "\x1b[32;40mGREEN\x1b[30;42m\xdb\xb2\xb1\xb0 \x1b[0m : ";
  254. md->lazy = true;
  255. md->menu = {{"C", "Configure"},
  256. {"D", "Display Report"},
  257. {"E", "Export Data/Save"},
  258. {"I", "Information"},
  259. {"P", "Port CIM"},
  260. {"W", "Warp CIM"},
  261. {"T", "Trading Report (same as D)"},
  262. {"S", "Scripts"},
  263. {"X", "eXit"}};
  264. md->setNotify([this]() { this->menu_choice(); });
  265. cim = std::make_shared<CIMDispatch>(*this);
  266. cim->setNotify([this]() { this->cim_done(); });
  267. }
  268. void Director::proxy_activate(void) {
  269. active = true; // yes, set keep-alive timer.
  270. to_server(" "); // start keep-alive timer.
  271. // set other values we need
  272. talk_direct = false;
  273. show_client = false;
  274. /*
  275. Wait a minute .. this might be confusing.
  276. Shouldn't I send them the current prompt?
  277. Just in case we abort in the middle of something?!?
  278. */
  279. old_prompt = current_prompt;
  280. old_raw_prompt = current_raw_prompt;
  281. to_client("\x1b[0m\n\r");
  282. /*
  283. ╔══════════════════════════════╗
  284. ║ TradeWars Proxy Active ║
  285. ╚══════════════════════════════╝
  286. -=>
  287. */
  288. Boxes box(30, 1, true);
  289. box.boxcolor = "\x1b[1;33;44m";
  290. box.textcolor = "\x1b[1;33;44m";
  291. to_client(box.top());
  292. std::string output = " TradeWars Proxy \x1b[5mActive\x1b[0;1;33;44m ";
  293. to_client(box.row(output));
  294. to_client(box.bottom());
  295. if (galaxy.meta.contains("port_CIM")) {
  296. time_t last_port_cim_report = galaxy.meta["port_CIM"].get<int>();
  297. int seconds_ago = time_t_now() - last_port_cim_report;
  298. int minutes_ago = seconds_ago / 60;
  299. BUGZ_LOG(fatal) << "port_CIM was " << minutes_ago << " minutes ago.";
  300. if (minutes_ago >= 60) {
  301. float hours_ago = minutes_ago / 60.0;
  302. std::string message =
  303. str(boost::format(
  304. "Warning: Last Port CIM Refresh was %1$0.2f hours ago.\n\r") %
  305. hours_ago);
  306. to_client(message);
  307. }
  308. } else {
  309. BUGZ_LOG(fatal) << "no meta port_CIM value seen.";
  310. }
  311. chain = main_menu;
  312. main_menu->activate();
  313. /*
  314. // Using InputDispatch -- and see have_input
  315. std::shared_ptr<Dispatch> readline = std::make_shared<InputDispatch>(*this);
  316. chain = readline;
  317. InputDispatch *id = static_cast<InputDispatch *>(&(*readline));
  318. id->prompt = "\x1b[0m\x1b[1;33;44m-=>\x1b[0m \x1b[1;37;44m";
  319. id->max_length = 15;
  320. id->setNotify([this]() { this->have_input(); });
  321. readline->activate();
  322. */
  323. }
  324. void Director::menu_choice(void) {
  325. MenuDispatch *md = dynamic_cast<MenuDispatch *>(&(*chain));
  326. if (md) {
  327. if (md->input.empty()) {
  328. to_client("Menu aborted.\n\r");
  329. proxy_deactivate();
  330. return;
  331. } else {
  332. switch (md->input[0]) {
  333. case 'C': // configure
  334. config_edit();
  335. return;
  336. break;
  337. case 'D':
  338. case 'T': // display trading report
  339. {
  340. auto pptv = galaxy.find_best_trades();
  341. std::string output;
  342. galaxy.sort_port_pair_type(pptv);
  343. int max_display = 20;
  344. if (galaxy.config.contains("display_lines"))
  345. max_display = galaxy.config["display_lines"].get<int>();
  346. else
  347. galaxy.config["display_lines"] = max_display;
  348. if ((max_display <= 0) || (max_display > 255)) {
  349. max_display = 255;
  350. galaxy.config["display_lines"] = 255;
  351. }
  352. const int per_line = 5;
  353. int count = 0;
  354. int line = 0;
  355. std::string display_line;
  356. ANSIColor by{1, 33}; // yellow
  357. ANSIColor cyan{36}; // cyan
  358. ANSIColor bg{1, 32}; // bright green
  359. ANSIColor bb{1, 34}; // bright blue
  360. for (auto const &ppt : pptv) {
  361. output =
  362. str(boost::format("%1%%2$5d%3%:%4%%5$-5d%3%(%6%%7$d%3%) ") %
  363. by() % ppt.s1 % cyan() % bg() % ppt.s2 % bb() % ppt.type);
  364. display_line.append(output);
  365. ++count;
  366. if (count == per_line) {
  367. count = 0;
  368. display_line.append("\n\r");
  369. to_client(display_line);
  370. display_line.clear();
  371. ++line;
  372. }
  373. if (line == max_display) break;
  374. }
  375. if (count != 0) {
  376. display_line.append("\n\r");
  377. to_client(display_line);
  378. display_line.clear();
  379. }
  380. // We got < 5 lines, and max_display is > 5. Offer suggestion:
  381. if ((line < 5) && (max_display > 5)) {
  382. // suggestion:
  383. to_client(
  384. "HINT: For more lines, try reducing the burnt_percent?\n\r");
  385. }
  386. } break;
  387. case 'E': // Export Data/Save
  388. to_client("Saving...");
  389. galaxy.save();
  390. to_client("\rSaved....\n\r");
  391. break;
  392. case 'I': // Information
  393. information();
  394. break;
  395. case 'P': // Port CIM
  396. // Since we're adding/updating, we don't lose our
  397. // type 0 ports. Type 9 stays at 9.
  398. galaxy.meta["port_CIM"] = (int)time_t_now();
  399. chain = cim;
  400. to_server("^RQ");
  401. {
  402. std::string text = str(boost::format("Port CIM Report (%1%)\n\r") %
  403. galaxy.ports.size());
  404. // to_client("Port CIM Report\n\r");
  405. to_client(text);
  406. }
  407. chain->activate();
  408. return;
  409. break;
  410. case 'W': // Warp CIM
  411. chain = cim;
  412. to_server("^IQ");
  413. {
  414. std::string text = str(boost::format("Warp CIM Report (%1%)\n\r") %
  415. galaxy.warps.size());
  416. // to_client("Warp CIM Report\n\r");
  417. to_client(text);
  418. }
  419. chain->activate();
  420. return;
  421. break;
  422. // case 'T': // Trading Report
  423. // break;
  424. case 'S': // Scripts
  425. {
  426. init_scripts_menu();
  427. chain = scripts_menu;
  428. chain->activate();
  429. return;
  430. } break;
  431. case 'X': // Exit
  432. proxy_deactivate();
  433. return;
  434. }
  435. /*
  436. std::string text = str(
  437. boost::format("Back from Menu [%1%] was selected.\n\r") %
  438. md->input);
  439. to_client(text);
  440. */
  441. md->activate();
  442. }
  443. }
  444. }
  445. MenuDispatch *Director::init_scripts_menu(void) {
  446. MenuDispatch *md;
  447. if (scripts_menu) {
  448. md = dynamic_cast<MenuDispatch *>(&(*scripts_menu));
  449. return md;
  450. } else {
  451. scripts_menu = std::make_shared<MenuDispatch>(*this);
  452. md = static_cast<MenuDispatch *>(&(*scripts_menu));
  453. md->menu_box_color = "\x1b[0;32;40m";
  454. md->menu_text_color = "\x1b[1;32;40m";
  455. md->menu_title = "Scripts Menu";
  456. md->menu_options_color = "\x1b[1;32;40m";
  457. md->lazy = false;
  458. ANSIColor by{1, 33};
  459. ANSIColor cyan{36};
  460. ANSIColor bg{1, 32};
  461. std::string prompt = by() + "S" + cyan() + "cript " + by() + "M" + cyan() +
  462. "enu " + bg() + "=>" + reset() + " ";
  463. md->menu_prompt = prompt; // " SCRIPT : ";
  464. md->menu = {{"!", "Terror"},
  465. {"T", "Trade"},
  466. {"S", "Safe Move"},
  467. {"C", "Closest Trade"},
  468. {"N", "Nearest Unexplored"},
  469. {"V", "Voyager Explorer"},
  470. {"E", "Explorer"},
  471. {"U", "Upgrade Planet Pants"},
  472. {"X", "Exit Scripts"}};
  473. md->setNotify([this]() { this->scripts_done(); });
  474. return md;
  475. }
  476. }
  477. void Director::scripts_done(void) {
  478. // Was script selected? If so, run it!
  479. // otherwise, back to the menu we go...
  480. MenuDispatch *md = dynamic_cast<MenuDispatch *>(&(*scripts_menu));
  481. if (md) {
  482. if (md->input.empty()) {
  483. to_client("Scripts aborted.\n\r");
  484. scripts_menu.reset();
  485. proxy_deactivate();
  486. return;
  487. } else {
  488. switch (md->input[0]) {
  489. case 'T': // Trade
  490. {
  491. script = std::make_shared<TraderDispatch>(*this);
  492. TraderDispatch *ts = static_cast<TraderDispatch *>(&((*script)));
  493. ts->setNotify([this]() { this->proxy_deactivate(); });
  494. // Locate best trades
  495. auto found = galaxy.find_trades(current_sector, false);
  496. if (found.empty()) {
  497. to_client(
  498. "No Trades found. Port burnt (CONFIG: lower burnt_percent?) "
  499. "or no ports around.\n\r");
  500. proxy_deactivate();
  501. return;
  502. }
  503. // sort first?
  504. galaxy.sort_port_pair_type(found);
  505. BUGZ_LOG(fatal) << "Found " << found.size() << " possible trade(s).";
  506. BUGZ_LOG(fatal) << "Best: " << found[0].s1 << "," << found[0].s2
  507. << " : " << found[0].type;
  508. // Set parameters
  509. ts->port[0] = found[0].s1;
  510. ts->port[1] = found[0].s2;
  511. ts->type = found[0].type;
  512. ts->trades = found[0].trades;
  513. chain = script;
  514. chain->activate();
  515. return;
  516. } break;
  517. case 'S': {
  518. script = std::make_shared<MoveDispatch>(*this);
  519. MoveDispatch *md = static_cast<MoveDispatch *>(&((*script)));
  520. md->setNotify([this]() { this->proxy_deactivate(); });
  521. md->move_to = 1;
  522. chain = script;
  523. chain->activate();
  524. return;
  525. } break;
  526. case '!': {
  527. script = std::make_shared<ScriptTerror>(*this);
  528. ScriptTerror *st = static_cast<ScriptTerror *>(&(*script));
  529. st->setNotify([this]() {
  530. script.reset();
  531. this->proxy_deactivate();
  532. });
  533. chain = script;
  534. chain->activate();
  535. return;
  536. } break;
  537. // }
  538. case 'C': {
  539. auto best = galaxy.find_closest(current_sector);
  540. if (best.type != 0) {
  541. std::string text =
  542. str(boost::format("Best/Closest: %1% with %2% & %3%\n\r") %
  543. best.type % best.s1 % best.s2);
  544. to_client(text);
  545. } else {
  546. to_client("I don't see any best trades.\n\r");
  547. }
  548. } break;
  549. case 'N': {
  550. sector_type s = galaxy.find_nearest_unexplored(current_sector);
  551. if (s != 0) {
  552. std::string text = str(boost::format("Sector: %1%\n\r") % s);
  553. to_client(text);
  554. } else {
  555. to_client("I don't see any unexplored.\n\r");
  556. }
  557. } break;
  558. case 'V': {
  559. script = std::make_shared<ScriptVoyager>(*this);
  560. ScriptVoyager *sv = static_cast<ScriptVoyager *>(&(*script));
  561. sv->setNotify([this]() {
  562. script.reset();
  563. this->proxy_deactivate();
  564. });
  565. chain = script;
  566. chain->activate();
  567. return;
  568. } break;
  569. case 'E': {
  570. script = std::make_shared<ScriptExplore>(*this);
  571. ScriptExplore *se = static_cast<ScriptExplore *>(&(*script));
  572. se->setNotify([this]() {
  573. script.reset();
  574. this->proxy_deactivate();
  575. });
  576. chain = script;
  577. chain->activate();
  578. return;
  579. } break;
  580. case 'U': {
  581. script = std::make_shared<ScriptPlanet>(*this);
  582. ScriptPlanet *sp = static_cast<ScriptPlanet *>(&(*script));
  583. sp->setNotify([this]() {
  584. script.reset();
  585. this->proxy_deactivate();
  586. });
  587. chain = script;
  588. chain->activate();
  589. return;
  590. } break;
  591. case 'Q':
  592. chain = main_menu;
  593. main_menu->activate();
  594. return;
  595. break;
  596. }
  597. }
  598. }
  599. proxy_activate();
  600. // And to end scripts, we do .. what exactly?
  601. // DEBUG: Ok, why does everything work OK if I reset the scripts_menu
  602. // here?? probably do want to destroy scripts here. ;)
  603. // scripts_menu.reset();
  604. // proxy_deactivate();
  605. }
  606. /**
  607. * @brief Setup Config Input
  608. *
  609. * @return DispatchInput*
  610. */
  611. InputDispatch *Director::init_config_input(void) {
  612. InputDispatch *id;
  613. if (config_input) {
  614. // Yes, it has been setup before.
  615. id = dynamic_cast<InputDispatch *>(&(*config_input));
  616. ANSIColor by{1, 33};
  617. ANSIColor cyan{36};
  618. ANSIColor bg{1, 32};
  619. std::string prompt =
  620. by() + "C" + cyan() + "onfig " + bg() + "=>" + reset() + " ";
  621. id->prompt = prompt; // "Config => ";
  622. id->numeric = true;
  623. id->max_length = 3;
  624. config_item.clear();
  625. return id;
  626. } else {
  627. // set it up
  628. config_input = std::make_shared<InputDispatch>(*this);
  629. id = static_cast<InputDispatch *>(&(*config_input));
  630. ANSIColor by{1, 33};
  631. ANSIColor cyan{36};
  632. ANSIColor bg{1, 32};
  633. std::string prompt =
  634. by() + "C" + cyan() + "onfig " + bg() + "=>" + reset() + " ";
  635. id->prompt = prompt; // "Config => ";
  636. id->numeric = true;
  637. id->max_length = 3;
  638. id->setNotify([this]() { this->config_have_input(); });
  639. config_item.clear();
  640. return id;
  641. }
  642. }
  643. void Director::config_edit(void) {
  644. // display current config
  645. std::string menu_box_color = "\x1b[1;33;44m";
  646. std::string menu_text_color = "\x1b[1;37;44m";
  647. auto abox = Boxes::alert(" Configuration: ", menu_box_color,
  648. menu_text_color, 20, 1, true);
  649. for (auto line : abox) {
  650. to_client(line);
  651. }
  652. // to_client("Configuration:\n\r");
  653. int item = 1;
  654. ANSIColor number(COLOR::CYAN);
  655. ANSIColor key(COLOR::GREEN, ATTR::BOLD);
  656. ANSIColor value(COLOR::BLUE, ATTR::BOLD);
  657. for (auto const &cfg : galaxy.config.items()) {
  658. // for (auto const &cfg : galaxy.config) {
  659. std::string output =
  660. str(boost::format("%1%%2$2d %3%%4$20s: %5%%6$s%7%\n\r") % number() %
  661. item % key() % cfg.key() % value() % cfg.value() % reset());
  662. to_client(output);
  663. ++item;
  664. }
  665. std::string message =
  666. number() + "Enter number to edit, " + key() + "blank to exit.\n\r";
  667. // to_client("Enter number to edit, blank to exit.\n\r");
  668. to_client(message);
  669. // setup call to config_input:
  670. InputDispatch *id = init_config_input();
  671. chain = config_input;
  672. id->activate();
  673. // to return to the menu:
  674. // MenuDispatch *md = dynamic_cast<MenuDispatch *>(&(*chain));
  675. // md->activate();
  676. }
  677. void Director::config_have_input(void) {
  678. InputDispatch *id = dynamic_cast<InputDispatch *>(&(*config_input));
  679. if (config_item.empty()) {
  680. // This is a config menu selection
  681. if (id->input.empty()) {
  682. // We're done here. Return to menu.
  683. chain = main_menu;
  684. MenuDispatch *md = dynamic_cast<MenuDispatch *>(&(*chain));
  685. md->activate();
  686. // destroy the input? yes.
  687. config_input.reset();
  688. return;
  689. } else {
  690. int item = sstoi(id->input);
  691. if ((item < 1) || (item > (int)galaxy.config.size())) {
  692. // selection out of range - redisplay config menu
  693. to_client("What? I didn't see that item.\n\r");
  694. config_edit();
  695. return;
  696. } else {
  697. int pos = 1;
  698. for (auto const &c : galaxy.config.items()) {
  699. if (pos == item) {
  700. // got it!
  701. ANSIColor key(COLOR::GREEN, ATTR::BOLD);
  702. ANSIColor value(COLOR::BLUE, ATTR::BOLD);
  703. config_item = c.key();
  704. std::string output =
  705. str(boost::format("%1%%2% : %3%%4%\n\r") % key() % config_item %
  706. value() % galaxy.meta["help"][config_item]);
  707. to_client(output);
  708. id->max_length = 30;
  709. id->numeric = false;
  710. ANSIColor by{1, 33};
  711. ANSIColor cyan{36};
  712. ANSIColor bg{1, 32};
  713. std::string prompt =
  714. by() + "C" + cyan() + "hange to " + bg() + "=>" + reset() + " ";
  715. id->prompt = prompt;
  716. id->activate();
  717. return;
  718. };
  719. ++pos;
  720. }
  721. to_client("What? I didn't find that item?\n\r");
  722. config_edit();
  723. return;
  724. }
  725. }
  726. } else {
  727. // This is a config item edit
  728. if (id->input.empty()) {
  729. to_client("No change.\n\r");
  730. config_edit();
  731. return;
  732. } else {
  733. BUGZ_LOG(fatal) << "Config EDIT: " << config_item << " = " << id->input;
  734. galaxy.config[config_item] = id->input;
  735. config_edit();
  736. return;
  737. }
  738. }
  739. }
  740. void Director::have_input(void) {
  741. ++count;
  742. InputDispatch *id = dynamic_cast<InputDispatch *>(&(*chain));
  743. if (id) {
  744. std::string output =
  745. str(boost::format("Your Input (%2%): [%1%]\n\r") % id->input % count);
  746. to_client("\x1b[0m");
  747. to_client(output);
  748. } else {
  749. proxy_deactivate();
  750. return;
  751. }
  752. if (count > 3) {
  753. proxy_deactivate();
  754. } else {
  755. chain->activate();
  756. }
  757. }
  758. void Director::cim_done(void) {
  759. BUGZ_LOG(info) << "CIM done";
  760. chain = main_menu;
  761. main_menu->activate();
  762. }
  763. void Director::information(void) {
  764. std::string output;
  765. to_client("I currently know the following:\n\r");
  766. output = str(
  767. boost::format("Ports: %1%, Sectors: %2%, Config: %3%, Meta: %4%\n\r") %
  768. galaxy.ports.size() % galaxy.warps.size() % galaxy.config.size() %
  769. galaxy.meta.size());
  770. to_client(output);
  771. }
  772. void Director::proxy_deactivate(void) {
  773. active = false;
  774. // reset everything back to good state
  775. talk_direct = true;
  776. show_client = true;
  777. chain.reset();
  778. to_client("\n\r");
  779. to_client(current_raw_prompt);
  780. }
  781. /*
  782. Server Line Parsing Routines
  783. */
  784. void Director::SL_cimline(const std::string &line) {
  785. if (line == ": ENDINTERROG") {
  786. SL_parser = nullptr;
  787. return;
  788. }
  789. if (line == ": ") {
  790. // do I need to do anything special here for this?
  791. // Maybe -- We would save special ports that don't show up
  792. // (StarDock/Special) before. We don't know (at this point) if this is
  793. // warps or ports.
  794. return;
  795. }
  796. if (line.empty()) {
  797. SL_parser = nullptr;
  798. return;
  799. }
  800. // parse cimline
  801. // size_t pos = line.find('%');
  802. // std::string work = line;
  803. // if (pos == line.npos) {
  804. if (in(line, "%")) {
  805. // portcim
  806. struct port p = parse_portcim(line);
  807. if (p.sector == 0)
  808. BUGZ_LOG(fatal) << "portcim: FAIL [" << line << "]";
  809. else
  810. BUGZ_LOG(trace) << "portcim: " << p;
  811. galaxy.add_port(p);
  812. } else {
  813. // warpcim
  814. // BUGZ_LOG(fatal) << "warpcim: [" << line << "]";
  815. auto warps = split(line);
  816. sector_warps sw;
  817. for (auto const &w : warps) {
  818. if (sw.sector == 0) {
  819. sw.sector = stoi(w);
  820. } else {
  821. sw.add(stoi(w));
  822. }
  823. }
  824. BUGZ_LOG(trace) << "warpcim: " << sw;
  825. galaxy.add_warp(sw);
  826. }
  827. }
  828. void Director::SL_thiefline(const std::string &line) {
  829. size_t pos = line.find("Suddenly you're Busted!");
  830. bool busted = pos != line.npos;
  831. if (busted) {
  832. BUGZ_LOG(fatal) << "set bust";
  833. SL_parser = nullptr;
  834. } else {
  835. pos = line.find("(You realize the guards saw you last time!)");
  836. if (pos != line.npos) SL_parser = nullptr;
  837. }
  838. // Are those the two ways to exit from this state?
  839. }
  840. void Director::SL_sectorline(const std::string &line) {
  841. BUGZ_LOG(fatal) << "sectorline: [" << line << "]";
  842. if (line.empty()) {
  843. SL_parser = nullptr;
  844. } else {
  845. /*
  846. sectorline: [Sector : 926 in The Federation.]
  847. sectorline: [Beacon : FedSpace, FedLaw Enforced]
  848. sectorline: [Ports : Stargate Alpha I, Class 9 (Special) (StarDock)]
  849. sectorline: [Traders : Civilian phil, w/ 30 ftrs,]
  850. sectorline: [ in Star Stomper (Sverdlov Merchant Cruiser)]
  851. sectorline: [Warps to Sector(s) : 70 - 441 - 575 - 600 - 629 - 711]
  852. sectorline: [Warps to Sector(s) : 70 - (475) - 569]
  853. What can we get from Traders : line? Can we get if they are hostile
  854. to us? We need to respond to "is powering up weapons" ... We can
  855. react faster then a person can!
  856. "phil is powering up weapons systems!"
  857. Also the auto-attack ones Ferrengi -- we need to auto-respond Retreat.
  858. */
  859. if (in(line, "Sector :")) {
  860. current_sector = stoi(line.substr(10));
  861. BUGZ_LOG(warning) << "SECTOR: " << current_sector;
  862. }
  863. if (in(line, "Ports :")) {
  864. std::string port_class;
  865. size_t pos = line.find(", Class ");
  866. if (pos != std::string::npos) {
  867. pos += 8;
  868. int class_ = stoi(line.substr(pos));
  869. BUGZ_LOG(fatal) << "PORT: " << class_;
  870. galaxy.add_port(current_sector, class_);
  871. }
  872. }
  873. if (in(line, "Warps to Sector(s) :")) {
  874. std::string temp = line.substr(20);
  875. replace(temp, " - ", " ");
  876. // unexplored sectors ()
  877. // Should I track these?
  878. replace(temp, "(", "");
  879. replace(temp, ")", "");
  880. sector_warps sw;
  881. auto warps = split(temp);
  882. sw.sector = current_sector;
  883. // what if there is only one warp?
  884. for (auto const &w : warps) {
  885. sw.add(stoi(w));
  886. }
  887. BUGZ_LOG(fatal) << "WARPS: " << sw;
  888. galaxy.add_warp(sw);
  889. }
  890. }
  891. }
  892. void Director::SL_densityline(const std::string &line) {
  893. BUGZ_LOG(fatal) << "densityline: [" << line << "]";
  894. if (line.empty()) {
  895. SL_parser = nullptr;
  896. return;
  897. }
  898. /*
  899. // Ensure this really is a density scan and not something else
  900. if (!in(line, "Sector") || !in(line, "Warps") || !in(line, "NavHaz") ||
  901. !in(line, "Anom")) {
  902. BUGZ_LOG(fatal) << "densityline: Invalid line.";
  903. SL_parser = nullptr;
  904. return;
  905. }
  906. if (not galaxy.meta["density"]) {
  907. galaxy.meta["density"] = YAML::Node();
  908. }
  909. */
  910. /*
  911. 0 1 2 3 4 5 6 7 8 9 10 11 12
  912. "Sector 55 ==> 0 Warps : 4 NavHaz : 0% Anom : No"
  913. "Sector ( 223) ==> 0 Warps : 3 NavHaz : 0% Anom : No"
  914. */
  915. if (in(line, "==>")) {
  916. std::string work = line;
  917. replace(work, ":", "");
  918. bool known = !in(work, "(");
  919. replace(work, "(", "");
  920. replace(work, ")", "");
  921. replace(work, "%", "");
  922. auto dense = split(work);
  923. // Parse our data
  924. sector_type sector = std::stoi(dense.at(1));
  925. uint16_t density = std::stoi(dense.at(3));
  926. uint16_t warps = std::stoi(dense.at(5));
  927. uint16_t navhaz = std::stoi(dense.at(7));
  928. bool anom = in(dense.at(9), "Yes");
  929. struct density d = {sector, density, warps, navhaz, anom, known};
  930. galaxy.dscan.add_scan(d);
  931. // Commit data
  932. BUGZ_LOG(warning) << "densityline: {sector=" << sector
  933. << " density=" << density << " warps=" << warps
  934. << " navhaz=" << navhaz << " anom=" << anom
  935. << " known=" << known << "}";
  936. /*
  937. if (galaxy.meta["density"][sector]) {
  938. galaxy.meta["density"][sector] = YAML::Node();
  939. }
  940. */
  941. <<<<<<< HEAD
  942. // what(): [json.exception.type_error.305] cannot use operator[] with a
  943. // numeric argument with object
  944. std::string sector_text = std::to_string(sector);
  945. galaxy.meta["density"][sector_text]["density"] = density;
  946. galaxy.meta["density"][sector_text]["warps"] = warps;
  947. galaxy.meta["density"][sector_text]["navhaz"] = navhaz;
  948. galaxy.meta["density"][sector_text]["anom"] = anom;
  949. galaxy.meta["density"][sector_text]["known"] = known;
  950. =======
  951. // what(): [json.exception.type_error.305] cannot use operator[] with a numeric argument with object
  952. std::string sector_text = std::to_string(sector);
  953. galaxy.meta["_density"][sector_text]["density"] = density;
  954. galaxy.meta["_density"][sector_text]["warps"] = warps;
  955. galaxy.meta["_density"][sector_text]["navhaz"] = navhaz;
  956. galaxy.meta["_density"][sector_text]["anom"] = anom;
  957. galaxy.meta["_density"][sector_text]["known"] = known;
  958. >>>>>>> master
  959. // Add a check to see if density is greater than 500
  960. // Add datetime stamp
  961. }
  962. }
  963. void Director::SL_portline(const std::string &line) {
  964. /*
  965. We take blank lines because we start at <Port>.
  966. Otherwise, we trigger on computer port requests.
  967. if (line.empty()) {
  968. SL_parser = nullptr;
  969. return;
  970. }
  971. */
  972. /*
  973. SL: [ Items Status Trading % of max OnBoard]
  974. SL: [ ----- ------ ------- -------- -------]
  975. SL: [Fuel Ore Buying 3000 100% 0]
  976. SL: [Organics Buying 3000 100% 0]
  977. SL: [Equipment Buying 3000 100% 0]
  978. SL: []
  979. SL: [Commerce report for: 03:51:56 PM Mon Oct 24, 2033 You can buy:]
  980. SL: [A Cargo holds : 650 credits / next hold 0]
  981. SL: [B Fighters : 233 credits per fighter 75]
  982. SL: [C Shield Points : 116 credits per point 100]
  983. SL: []
  984. */
  985. // BUGZ_LOG(info) << "portline : " << line;
  986. if (in(line, "%")) {
  987. // size_t pos = line.find('%');
  988. // if (pos != line.npos) {
  989. // Ok, this is a valid portline
  990. std::string work = line;
  991. replace(work, "Fuel Ore", "Fuel");
  992. auto parts = split(work);
  993. if (parts[0] == "Items") return;
  994. char c = tolower(parts[0][0]);
  995. int pos;
  996. char foe[4] = "foe";
  997. for (pos = 0; pos < 3; ++pos) {
  998. if (c == foe[pos]) break;
  999. }
  1000. int amount = stoi(parts[2]);
  1001. int percent = stoi(parts[3]);
  1002. // update port
  1003. auto port = galaxy.ports.find(current_sector);
  1004. if (port != galaxy.ports.end()) {
  1005. port->second.amount[pos] = amount;
  1006. port->second.percent[pos] = percent;
  1007. }
  1008. /*
  1009. BUGZ_LOG(fatal) << "portline split:";
  1010. for (auto const p : parts) {
  1011. BUGZ_LOG(fatal) << p;
  1012. }
  1013. */
  1014. // Here's the end:
  1015. if (parts[0] == "Equipment") SL_parser = nullptr;
  1016. // BUGZ_LOG(fatal) << "portline split : [" << parts << "]";
  1017. }
  1018. }
  1019. void Director::SL_warpline(const std::string &line) {
  1020. if (line.empty()) {
  1021. SL_parser = nullptr;
  1022. return;
  1023. }
  1024. // process warp line
  1025. BUGZ_LOG(fatal) << "warpline: [" << line << "]";
  1026. }
  1027. void Director::SL_infoline(const std::string &line) {
  1028. static int state;
  1029. if (line == "<Info>") {
  1030. state = 0;
  1031. galaxy.meta["info"] = json();
  1032. }
  1033. if (line.empty()) {
  1034. ++state;
  1035. if (state == 2) {
  1036. SL_parser = nullptr;
  1037. // clear out the existing ship data
  1038. galaxy.meta["ship"] = json();
  1039. // process the parsed information in meta["info"]
  1040. if (galaxy.meta["info"].contains("Total Holds")) {
  1041. std::string work = galaxy.meta["info"]["Total Holds"];
  1042. replace(work, "Fuel Ore", "Fuel");
  1043. auto parts = split(work, " - ");
  1044. int total_holds = stoi(parts[0]);
  1045. BUGZ_LOG(fatal) << "total holds: " << total_holds;
  1046. auto contents = split(parts[1]);
  1047. for (auto const &hold : contents) {
  1048. auto hold_amount = split(hold, "=");
  1049. BUGZ_LOG(fatal) << hold_amount[0] << " with " << hold_amount[1];
  1050. std::string key = hold_amount[0];
  1051. str_tolower(key);
  1052. // equipment = e
  1053. // organics = o
  1054. // fuel = f
  1055. // colonists = c
  1056. // empty = empty
  1057. if (key != "empty") {
  1058. key = key[0];
  1059. }
  1060. galaxy.meta["ship"]["holds"][key] = stoi(hold_amount[1]);
  1061. }
  1062. galaxy.meta["ship"]["holds"]["total"] = total_holds;
  1063. }
  1064. if (galaxy.meta["info"].contains("Turns to Warp")) {
  1065. // Why is this saying that this is a string?
  1066. int warp_turns = sstoi(json_str(galaxy.meta["info"]["Turns to Warp"]));
  1067. BUGZ_LOG(fatal) << "Turns to Warp: " << warp_turns;
  1068. galaxy.meta["ship"]["warp_turns"] = warp_turns;
  1069. }
  1070. if (galaxy.meta["info"].contains("LongRange Scan")) {
  1071. std::string scanner_text =
  1072. galaxy.meta["info"]["LongRange Scan"].get<std::string>();
  1073. char scanner = scanner_text[0];
  1074. BUGZ_LOG(fatal) << "Scanner: " << scanner;
  1075. galaxy.meta["ship"]["scanner"] = scanner;
  1076. }
  1077. // turns isn't ship specific
  1078. if (galaxy.meta["info"].contains("Turns left")) {
  1079. // OR this could be "Unlimited" !!!
  1080. std::string text = galaxy.meta["info"]["Turns left"];
  1081. if (text == "Unlimited") {
  1082. galaxy.meta["turns"] = -1;
  1083. } else {
  1084. int turns =
  1085. stoi(text); // galaxy.meta["info"]["Turns left"].as<int>();
  1086. BUGZ_LOG(fatal) << "Turns left: " << turns;
  1087. galaxy.meta["turns"] = turns;
  1088. }
  1089. }
  1090. if (galaxy.meta["info"].contains("Current Sector")) {
  1091. int sector = sstoi(json_str(galaxy.meta["info"]["Current Sector"]));
  1092. BUGZ_LOG(fatal) << "Sector: " << sector;
  1093. // it should already be sector ...
  1094. current_sector = sector;
  1095. }
  1096. if (galaxy.meta["info"].contains("Credits")) {
  1097. std::string credit_text = galaxy.meta["info"]["Credits"];
  1098. replace(credit_text, ",", "");
  1099. int credits = stoi(credit_text);
  1100. galaxy.meta["credits"] = credits;
  1101. BUGZ_LOG(fatal) << "Credits: " << credits;
  1102. }
  1103. }
  1104. return;
  1105. }
  1106. // info to parse:
  1107. size_t pos = line.find(" : ");
  1108. if ((!endswith(line, " : ")) && (pos != line.npos)) {
  1109. std::string key = line.substr(0, pos);
  1110. // Ferrengi ships don't have date built
  1111. std::string value = line.substr(pos + 3);
  1112. trim(key);
  1113. trim(value);
  1114. galaxy.meta["info"][key] = value;
  1115. BUGZ_LOG(fatal) << "Info: " << key << " : " << value;
  1116. }
  1117. // [Corp # 1, Galaxy Stomping, Inc.]
  1118. if (startswith(line, "Corp ")) {
  1119. pos = line.find(", ");
  1120. if (pos != line.npos) {
  1121. galaxy.meta["info"]["Corp"] = line.substr(pos + 2);
  1122. }
  1123. }
  1124. }
  1125. void Director::SL_computer_portline(const std::string &line) {
  1126. if (startswith(line, "What sector is the port in?"))
  1127. computer_port_done = false;
  1128. if (line == "I have no information about a port in that sector.") {
  1129. computer_port_sector = 0;
  1130. SL_parser = nullptr;
  1131. return;
  1132. }
  1133. if (!computer_port_done) {
  1134. if (in(line, "Fuel Ore")) computer_port_done = true;
  1135. if (in(line, "Cargo holds")) {
  1136. // If I want to scan the class type 0 ports:
  1137. // computer_port_done = true;
  1138. // otherwise:
  1139. SL_parser = nullptr;
  1140. return;
  1141. }
  1142. }
  1143. if (computer_port_done) {
  1144. if (line.empty()) {
  1145. SL_parser = nullptr;
  1146. return;
  1147. }
  1148. // scan for items of interest
  1149. // SL: [Fuel Ore Buying 810 100% 0]
  1150. // SL: [Organics Buying 856 57% 0]
  1151. // SL: [Equipment Selling 922 44% 0]
  1152. std::string work = line;
  1153. replace(work, "Fuel Ore", "Fuel");
  1154. replace(work, "%", "");
  1155. auto parts = split(work);
  1156. char c = tolower(parts[0][0]);
  1157. int pos;
  1158. char foe[4] = "foe";
  1159. for (pos = 0; pos < 3; ++pos) {
  1160. if (c == foe[pos]) break;
  1161. }
  1162. int amount = stoi(parts[2]);
  1163. int percent = stoi(parts[3]);
  1164. // update port
  1165. auto port = galaxy.ports.find(computer_port_sector);
  1166. if (port != galaxy.ports.end()) {
  1167. BUGZ_LOG(info) << "COM PORT " << computer_port_sector << " " << c << " "
  1168. << amount << " " << percent;
  1169. port->second.amount[pos] = amount;
  1170. port->second.percent[pos] = percent;
  1171. }
  1172. }
  1173. }
  1174. void Director::SL_planetline(const std::string &line) {
  1175. if (line == "Corporate command [TL=00:00:00]:[344] (?=Help)? Q" ||
  1176. line == "Computer command [TL=00:00:00]:[344] (?=Help)? Q") {
  1177. SL_parser = nullptr;
  1178. return;
  1179. }
  1180. if (in(line, "Class ") &&
  1181. (in(line, "Level ") || (endswith(line, "No Citadel")))) {
  1182. int level;
  1183. char c;
  1184. sector_type sector;
  1185. int number;
  1186. std::string name;
  1187. std::string work = line;
  1188. size_t pos = work.find('#');
  1189. std::string temp = work.substr(0, pos);
  1190. trim(temp);
  1191. sector = sstoi(temp);
  1192. work = work.substr(pos + 1);
  1193. number = sstoi(work);
  1194. pos = work.find(' ');
  1195. work = work.substr(pos + 1);
  1196. trim(work);
  1197. if (endswith(work, "No Citadel")) {
  1198. level = 0;
  1199. } else {
  1200. pos = work.rfind("Level ");
  1201. temp = work.substr(pos + 6);
  1202. level = sstoi(temp);
  1203. }
  1204. pos = work.rfind("Class ");
  1205. temp = work.substr(pos + 6);
  1206. c = temp[0];
  1207. work = work.substr(0, pos);
  1208. trim(work);
  1209. name = work;
  1210. BUGZ_LOG(warning) << (int)sector << " # " << number << " Class " << c
  1211. << " Level " << level << " name: [" << name << "]";
  1212. planet p{sector, number, level, name, c};
  1213. galaxy.planets[number] = p;
  1214. }
  1215. /*
  1216. SL: [ 344 #4 Enjoy the Silence Class M, Earth Type Level 3] SL:
  1217. [ --- (4M) 1T 64 25 14T 693 277 2T 10M] SL: [
  1218. 344 #5 High There! Class L, Mountainous Level 2]
  1219. SL: [ --- (5M) 2T 0 6 25T 100 112 2T 6M]
  1220. ...
  1221. SL: [ --- (9M) 3T 64 31 39T 793 389 4T ---]
  1222. */
  1223. }