scripts.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. #include "scripts.h"
  2. #include <boost/format.hpp>
  3. #include "logging.h"
  4. ScriptTerror::ScriptTerror(Director &d) : Dispatch(d) {
  5. BUGZ_LOG(warning) << "ScriptTerror()";
  6. init();
  7. }
  8. ScriptTerror::~ScriptTerror() { BUGZ_LOG(warning) << "~ScriptTerror()"; }
  9. void ScriptTerror::init(void) {
  10. BUGZ_LOG(fatal) << "ScriptTerror::init()";
  11. move = std::make_shared<MoveDispatch>(director);
  12. md = static_cast<MoveDispatch *>(&(*move));
  13. // setup notify functions for results/completion.
  14. md->setNotify([this]() { this->move_notify(); });
  15. input = std::make_shared<InputDispatch>(director);
  16. id = static_cast<InputDispatch *>(&(*input));
  17. id->prompt = "Number of loops: ";
  18. id->max_length = 4;
  19. id->numeric = true;
  20. id->setNotify([this]() { this->input_notify(); });
  21. trader = std::make_shared<TraderDispatch>(director);
  22. td = static_cast<TraderDispatch *>(&(*trader));
  23. td->setNotify([this]() { this->trade_notify(); });
  24. BUGZ_LOG(fatal) << "ScriptTerror::init() completed.";
  25. }
  26. void ScriptTerror::activate(void) {
  27. BUGZ_LOG(warning) << "ScriptTerror::activate()";
  28. // Need: InputDispatch, MoveDispatch, ScriptTrader
  29. // Save the trade_end_empty setting, and set to Y
  30. if (director.galaxy.config["trade_end_empty"]) {
  31. old_trade_end_empty =
  32. director.galaxy.config["trade_end_empty"].as<std::string>();
  33. } else {
  34. old_trade_end_empty = "Y";
  35. }
  36. director.galaxy.config["trade_end_empty"] = "Y";
  37. // Step 0: Get ship information / # of holds
  38. max_loops = loops = -1;
  39. to_server("I");
  40. // Step 1: Get number of loops of terror
  41. // director.chain = input;
  42. // input->activate();
  43. // Step 2: Look for closest trades, try ScriptTrade until none < some
  44. // level. Step 3: Move on, unless out of loops (or low on turns)
  45. // deactivate();
  46. }
  47. void ScriptTerror::deactivate(void) {
  48. BUGZ_LOG(warning) << "ScriptTerror::deactivate()";
  49. // restore the original value.
  50. director.galaxy.config["trade_end_empty"] = old_trade_end_empty;
  51. notify();
  52. }
  53. void ScriptTerror::input_notify(void) {
  54. if (id->input.empty()) {
  55. deactivate();
  56. return;
  57. }
  58. if (id->aborted) {
  59. deactivate();
  60. return;
  61. }
  62. max_loops = sstoi(id->input, -1);
  63. if (max_loops == -1) {
  64. deactivate();
  65. return;
  66. }
  67. id->input.clear();
  68. BUGZ_LOG(warning) << "Loops of terror: " << max_loops;
  69. loops = max_loops;
  70. // find nearest
  71. int stop_percent;
  72. if (director.galaxy.config["stop_percent"]) {
  73. stop_percent = director.galaxy.config["stop_percent"].as<int>();
  74. } else {
  75. stop_percent = 25;
  76. director.galaxy.config["stop_percent"] = stop_percent;
  77. }
  78. ppt = director.galaxy.find_closest_trade(director.current_sector, 3,
  79. stop_percent);
  80. if (ppt.type == 0) {
  81. to_client("No trades found! You've burnt the galaxy!\n\r");
  82. deactivate();
  83. return;
  84. }
  85. // ok, step 2: move!
  86. // md->setNotify([this]() { this->proxy_deactivate(); });
  87. if (director.current_sector != ppt.s1) {
  88. BUGZ_LOG(fatal) << "Moving to: " << ppt.s1;
  89. md->move_to = ppt.s1;
  90. director.chain = move;
  91. director.chain->activate();
  92. return;
  93. } else {
  94. // We're already there!
  95. to_client("Ok! Get trading!\n\r");
  96. td->port[0] = ppt.s1;
  97. td->port[1] = ppt.s2;
  98. td->trades = ppt.trades;
  99. td->type = ppt.type;
  100. director.chain = trader;
  101. director.chain->activate();
  102. return;
  103. }
  104. }
  105. void ScriptTerror::move_notify(void) {
  106. BUGZ_LOG(fatal) << "move_notify()";
  107. if (md->aborted) {
  108. to_client("Move cancel.\n\r");
  109. deactivate();
  110. return;
  111. }
  112. // Check for success, and start trading!
  113. if (md->success) {
  114. to_client("We're here, get trading!\n\r");
  115. td->port[0] = ppt.s1;
  116. td->port[1] = ppt.s2;
  117. td->trades = ppt.trades;
  118. td->type = ppt.type;
  119. director.chain = trader;
  120. director.chain->activate();
  121. return;
  122. } else {
  123. to_client("Move FAILED.\n\r");
  124. deactivate();
  125. }
  126. }
  127. void ScriptTerror::server_prompt(const std::string &prompt) {
  128. if ((loops == -1) && (max_loops == -1)) {
  129. if (at_command_prompt(prompt)) {
  130. // Step 1: Get number of loops of terror
  131. director.chain = input;
  132. input->activate();
  133. return;
  134. }
  135. }
  136. }
  137. void ScriptTerror::trade_notify(void) {
  138. // Done trading -- maybe! :P
  139. if (td->aborted) {
  140. to_client("Trade cancel.\n\r");
  141. deactivate();
  142. return;
  143. }
  144. if (td->success) {
  145. // success!
  146. // find nearest
  147. int stop_percent;
  148. if (director.galaxy.config["stop_percent"]) {
  149. stop_percent = director.galaxy.config["stop_percent"].as<int>();
  150. } else {
  151. stop_percent = 25;
  152. director.galaxy.config["stop_percent"] = stop_percent;
  153. }
  154. ppt = director.galaxy.find_closest_trade(director.current_sector, 3,
  155. stop_percent);
  156. if (ppt.type == 0) {
  157. to_client("No trades found! You've burnt the galaxy!\n\r");
  158. deactivate();
  159. return;
  160. }
  161. if ((director.current_sector == ppt.s1) ||
  162. (director.current_sector == ppt.s2)) {
  163. // We're still here...
  164. BUGZ_LOG(fatal) << "Trade it again, Sam.";
  165. to_client("Keep trading.\n\r");
  166. td->port[0] = ppt.s1;
  167. td->port[1] = ppt.s2;
  168. td->trades = ppt.trades;
  169. td->type = ppt.type;
  170. director.chain = trader;
  171. director.chain->activate();
  172. return;
  173. }
  174. // Ok, this isn't a local trade.
  175. if (loops == 0) {
  176. to_client("We're done terrorizing, for now...\n\r");
  177. deactivate();
  178. return;
  179. }
  180. --loops;
  181. // Move to our next target
  182. BUGZ_LOG(fatal) << "Moving to: " << ppt.s1;
  183. md->move_to = ppt.s1;
  184. director.chain = move;
  185. director.chain->activate();
  186. return;
  187. }
  188. to_client("Ok, trade is done.\n\r");
  189. deactivate();
  190. }
  191. ScriptVoyager::ScriptVoyager(Director &d) : Dispatch(d) {
  192. BUGZ_LOG(warning) << "ScriptVoyager()";
  193. init();
  194. }
  195. ScriptVoyager::~ScriptVoyager() {
  196. BUGZ_LOG(warning) << "~ScriptVoyager()";
  197. }
  198. void ScriptVoyager::init(void) {
  199. move = std::make_shared<MoveDispatch>(director);
  200. md = static_cast<MoveDispatch *>(&(*move));
  201. md->setNotify([this]() { this->move_notify(); });
  202. input = std::make_shared<InputDispatch>(director);
  203. id = static_cast<InputDispatch *>(&(*input));
  204. id->prompt = "Number of loops/tries: ";
  205. id->max_length = 5;
  206. id->numeric = true;
  207. id->setNotify([this](){ this->input_notify();});
  208. }
  209. void ScriptVoyager::activate(void) {
  210. director.chain = input;
  211. input->activate();
  212. return;
  213. }
  214. void ScriptVoyager::deactivate(void) {
  215. BUGZ_LOG(warning) << "ScriptVoyager::deactivate()";
  216. notify();
  217. }
  218. void ScriptVoyager::move_notify(void) {
  219. if (md->aborted) {
  220. deactivate();
  221. return;
  222. }
  223. if (md->success) {
  224. // Great!
  225. next();
  226. return;
  227. } else {
  228. to_client("No safe moves.\n\r");
  229. deactivate();
  230. }
  231. }
  232. void ScriptVoyager::input_notify(void) {
  233. if (id->input.empty() || id->aborted) {
  234. to_client("Ok, maybe later then.\n\r");
  235. deactivate();
  236. return;
  237. }
  238. loops = sstoi(id->input, -1);
  239. if (loops == -1) {
  240. to_client("I'm sorry, WHAT?\n\r");
  241. deactivate();
  242. }
  243. id->input.clear();
  244. BUGZ_LOG(warning) << "Voyager loops: " << loops;
  245. next();
  246. }
  247. void ScriptVoyager::next(void) {
  248. if (loops == 0) {
  249. // ok, stop here.
  250. to_client("The voyage ends here, for now.\n\r");
  251. deactivate();
  252. return;
  253. }
  254. --loops;
  255. sector_type s = director.galaxy.find_nearest_unexplored(director.current_sector);
  256. if (s == 0) {
  257. to_client("I don't see anything else to explorer.\n\r");
  258. BUGZ_LOG(warning) << "find_nearest_unexplored returned 0";
  259. deactivate();
  260. }
  261. BUGZ_LOG(warning) << "Next stop: " << s;
  262. md->move_to = s;
  263. director.chain = move;
  264. director.chain->activate();
  265. }
  266. // SL: [###### DANGER! You have marked sector 740 to be avoided!]
  267. // SP: [Do you really want to warp there? (Y/N) ]
  268. void ScriptVoyager::server_prompt(const std::string &prompt) {
  269. }
  270. ScriptExplore::ScriptExplore(Director &d) : Dispatch(d) {
  271. BUGZ_LOG(warning) << "ScriptExplore()";
  272. init();
  273. }
  274. ScriptExplore::~ScriptExplore() {
  275. BUGZ_LOG(warning) << "~ScriptExplore()";
  276. }
  277. void ScriptExplore::init() {
  278. move = std::make_shared<MoveDispatch>(director);
  279. md = static_cast<MoveDispatch *>(&(*move));
  280. md->setNotify([this]() {this->move_notify();});
  281. input = std::make_shared<InputDispatch>(director);
  282. id = static_cast<InputDispatch *>(&(*input));
  283. id->prompt = "Number of sectors to explore: ";
  284. id->max_length = 5;
  285. id->numeric = true;
  286. id->setNotify([this](){this->input_notify();});
  287. state = 0;
  288. }
  289. void ScriptExplore::activate() {
  290. us = director.chain;
  291. state = 1;
  292. to_server("I");
  293. /*
  294. director.chain = input;
  295. input->activate();
  296. if(director.galaxy.meta["ship"]) {
  297. if(!director.galaxy.meta["ship"]["scanner"]) {
  298. to_client("\n\rIt appears your ship doesn't have a long range scanner.\n\r");
  299. deactivate();
  300. }
  301. }
  302. state = 1;
  303. return;
  304. */
  305. }
  306. void ScriptExplore::deactivate() {
  307. BUGZ_LOG(warning) << "ScriptExplore::deactivate()";
  308. us.reset();
  309. notify();
  310. }
  311. void ScriptExplore::move_notify() {
  312. director.chain = us;
  313. if (md->aborted) {
  314. deactivate();
  315. return;
  316. }
  317. if (md->success) {
  318. to_server("SD");
  319. state = 3;
  320. return;
  321. } else {
  322. to_client("No safe moves.\n\r");
  323. deactivate();
  324. }
  325. }
  326. void ScriptExplore::input_notify() {
  327. director.chain = us;
  328. if (id->input.empty() || id->aborted) {
  329. to_client("Maybe next time.\n\r");
  330. deactivate();
  331. return;
  332. }
  333. loops = sstoi(id->input, -1);
  334. if (loops == -1) {
  335. to_client("I'm sorry, WHAT?\n\r");
  336. deactivate();
  337. return;
  338. }
  339. if (loops == 0) {
  340. infinite = true;
  341. } else {
  342. infinite = false;
  343. }
  344. id->input.clear();
  345. if (!infinite) {
  346. BUGZ_LOG(warning) << "Explore loops: " << loops;
  347. } else {
  348. to_client("Infinite Mode!\n\r");
  349. to_client("[ PRESS A KEY TO STOP ]\n\r");
  350. BUGZ_LOG(warning) << "Explore loops: INFINITE";
  351. }
  352. to_server("SD");
  353. state = 3;
  354. }
  355. void ScriptExplore::next() {
  356. if (loops <= 0 && !infinite) {
  357. to_client("The exploration ends, for now.\n\r");
  358. deactivate();
  359. return;
  360. }
  361. if(!infinite)
  362. --loops;
  363. // Calculate next best sector to goto
  364. density_scan & ds = director.galaxy.dscan;
  365. density best_sector;
  366. for (int x = 0; x < ds.pos; ++x) {
  367. BUGZ_LOG(warning) << "Comparing: " << ds.d[x].sector << " (" << ds.d[x].density << ", " << ds.d[x].known <<") to " << best_sector.sector << " (" << best_sector.density << ", " << best_sector.known << ")";
  368. /* Is this sector prefered over others?
  369. * Warp Counts (Number of warps)
  370. * Density Check (Is this sector clear, does it contain a port)
  371. * NavHaz Check (Avoid sectors with navhaz above X%)
  372. */
  373. if(!ds.d[x].known) {
  374. BUGZ_LOG(warning) << "Subject: " << ds.d[x].sector;
  375. // Compare, Warp counts
  376. if (best_sector.sector != 0) {
  377. if((ds.d[x].warps >= best_sector.warps) || ((ds.d[x].density == 100 || ds.d[x].density == 101) && (best_sector.density != 100 || best_sector.density != 101))) {
  378. if(safe_sector(ds.d[x])) {
  379. if(best_sector.sector != 0) {
  380. BUGZ_LOG(warning) << "Storing previous best " << best_sector.sector;
  381. unknown_warps.push(best_sector.sector);
  382. }
  383. best_sector = ds.d[x];
  384. }
  385. } else {
  386. if(safe_sector(ds.d[x])) {
  387. BUGZ_LOG(warning) << "Added " << ds.d[x].sector << " to unknown_warps (" << unknown_warps.size() << ")";
  388. unknown_warps.push(ds.d[x].sector);
  389. }
  390. }
  391. } else {
  392. best_sector = ds.d[x];
  393. }
  394. // Check density for possible port
  395. }
  396. }
  397. BUGZ_LOG(warning) << "Unknown Warps: " << unknown_warps.size();
  398. if (best_sector.sector == 0) {
  399. if (unknown_warps.size() == 0) {
  400. to_client("No unknown warps.");
  401. deactivate();
  402. return;
  403. } else {
  404. BUGZ_LOG(warning) << "Seeking previous unexplored";
  405. best_sector.sector = unknown_warps.top();
  406. unknown_warps.pop();
  407. }
  408. }
  409. BUGZ_LOG(warning) << "Targeting sector: " << best_sector.sector;
  410. md->move_to = best_sector.sector;
  411. director.chain = move;
  412. director.chain->activate();
  413. }
  414. bool ScriptExplore::safe_sector(density d) { // int sector, int density) {
  415. if (d.sector == 0) return false;
  416. if (d.anomaly) return false;
  417. int dense = d.density;
  418. /*
  419. http://wiki.classictw.com/index.php?title=Gypsy%27s_Big_Dummy%27s_Guide_to_TradeWars_Text#Trader_Information
  420. Density Readings:
  421. 0 = Empty Sector or Ferrengi Dreadanought
  422. 1 = Marker Beacon
  423. 2 = Limpet Type 2 Tracking Mine
  424. 5 = Fighter (per Fighter)
  425. 10 = Armid Type 1 Mine
  426. 21 = Navigation Hazard (Per 1 Percent)
  427. 21 = Destroyed Ship (Due to 1 Percent Nav-Haz)
  428. 38 = Unmanned Ship
  429. 40 = Manned Ship, Alien or Ferrengi Assault Trader
  430. 50 = Destroyed Starport (After 25 Percent Nav-Haz Clears)
  431. 100 = Starport or Ferrengi Battle Cruiser
  432. 210 = Destroyed Planet (Due to 10 Percent Nav-Haz)
  433. 462 = Federation Starship under Admiral Nelson
  434. 489 = Federation Starship under Captain Zyrain
  435. 500 = Planet
  436. 512 = Federation Starship under Admiral Clausewitz
  437. 575 = Destroyed Port (Before 25% Nav-Haz Clears)
  438. */
  439. // Adjust density by upto 5% navhaz (Only if navhaz less than 6%)
  440. if(d.navhaz != 0 && d.navhaz <= 5) {
  441. dense -= d.navhaz * 21;
  442. }
  443. // If navhaz above 5% report it unsafe
  444. if (d.navhaz > 5) return false;
  445. switch (dense) {
  446. case 0:
  447. case 1:
  448. case 100:
  449. case 101:
  450. return true;
  451. }
  452. // special case for sector 1:
  453. if ((d.sector == 1) && (dense == 601)) return true;
  454. return false;
  455. }
  456. void ScriptExplore::server_prompt(const std::string &prompt) {
  457. BUGZ_LOG(warning) << "Explorer State: SP " << state;
  458. //next();
  459. if(state == 1) {
  460. if(at_command_prompt(prompt)) {
  461. if(director.galaxy.meta["ship"]) {
  462. if(!director.galaxy.meta["ship"]["scanner"]) {
  463. to_client("\n\rIt appears your ship doesn't have a long range scanner.\n\r");
  464. deactivate();
  465. return;
  466. }
  467. }
  468. state = 2;
  469. BUGZ_LOG(fatal) << "state = 1, prompting for user input";
  470. director.chain = input;
  471. input->activate();
  472. return;
  473. }
  474. }
  475. if (state == 3) {
  476. if(at_command_prompt(prompt)) {
  477. state = 4;
  478. next();
  479. }
  480. }
  481. }