#include "scripts.h" #include #include "logging.h" ScriptTerror::ScriptTerror(Director &d) : Dispatch(d) { BUGZ_LOG(warning) << "ScriptTerror()"; init(); } ScriptTerror::~ScriptTerror() { BUGZ_LOG(warning) << "~ScriptTerror()"; } void ScriptTerror::init(void) { BUGZ_LOG(fatal) << "ScriptTerror::init()"; move = std::make_shared(director); md = static_cast(&(*move)); // setup notify functions for results/completion. md->setNotify([this]() { this->move_notify(); }); input = std::make_shared(director); id = static_cast(&(*input)); id->prompt = "Number of loops: "; id->max_length = 4; id->numeric = true; id->setNotify([this]() { this->input_notify(); }); trader = std::make_shared(director); td = static_cast(&(*trader)); td->setNotify([this]() { this->trade_notify(); }); BUGZ_LOG(fatal) << "ScriptTerror::init() completed."; } void ScriptTerror::activate(void) { BUGZ_LOG(warning) << "ScriptTerror::activate()"; // Need: InputDispatch, MoveDispatch, ScriptTrader // Save the trade_end_empty setting, and set to Y if (director.galaxy.config["trade_end_empty"]) { old_trade_end_empty = director.galaxy.config["trade_end_empty"].as(); } else { old_trade_end_empty = "Y"; } director.galaxy.config["trade_end_empty"] = "Y"; // Step 0: Get ship information / # of holds max_loops = loops = -1; to_server("I"); // Step 1: Get number of loops of terror // director.chain = input; // input->activate(); // Step 2: Look for closest trades, try ScriptTrade until none < some // level. Step 3: Move on, unless out of loops (or low on turns) // deactivate(); } void ScriptTerror::deactivate(void) { BUGZ_LOG(warning) << "ScriptTerror::deactivate()"; // restore the original value. director.galaxy.config["trade_end_empty"] = old_trade_end_empty; notify(); } void ScriptTerror::input_notify(void) { if (id->input.empty()) { deactivate(); return; } if (id->aborted) { deactivate(); return; } max_loops = sstoi(id->input, -1); if (max_loops == -1) { deactivate(); return; } id->input.clear(); BUGZ_LOG(warning) << "Loops of terror: " << max_loops; loops = max_loops; // find nearest int stop_percent; if (director.galaxy.config["stop_percent"]) { stop_percent = director.galaxy.config["stop_percent"].as(); } else { stop_percent = 25; director.galaxy.config["stop_percent"] = stop_percent; } ppt = director.galaxy.find_closest_trade(director.current_sector, 3, stop_percent); if (ppt.type == 0) { to_client("No trades found! You've burnt the galaxy!\n\r"); deactivate(); return; } // ok, step 2: move! // md->setNotify([this]() { this->proxy_deactivate(); }); if (director.current_sector != ppt.s1) { BUGZ_LOG(fatal) << "Moving to: " << ppt.s1; md->move_to = ppt.s1; director.chain = move; director.chain->activate(); return; } else { // We're already there! to_client("Ok! Get trading!\n\r"); td->port[0] = ppt.s1; td->port[1] = ppt.s2; td->trades = ppt.trades; td->type = ppt.type; director.chain = trader; director.chain->activate(); return; } } void ScriptTerror::move_notify(void) { BUGZ_LOG(fatal) << "move_notify()"; if (md->aborted) { to_client("Move cancel.\n\r"); deactivate(); return; } // Check for success, and start trading! if (md->success) { to_client("We're here, get trading!\n\r"); td->port[0] = ppt.s1; td->port[1] = ppt.s2; td->trades = ppt.trades; td->type = ppt.type; director.chain = trader; director.chain->activate(); return; } else { to_client("Move FAILED.\n\r"); deactivate(); } } void ScriptTerror::server_prompt(const std::string &prompt) { if ((loops == -1) && (max_loops == -1)) { if (at_command_prompt(prompt)) { // Step 1: Get number of loops of terror director.chain = input; input->activate(); return; } } } void ScriptTerror::trade_notify(void) { // Done trading -- maybe! :P if (td->aborted) { to_client("Trade cancel.\n\r"); deactivate(); return; } if (td->success) { // success! // find nearest int stop_percent; if (director.galaxy.config["stop_percent"]) { stop_percent = director.galaxy.config["stop_percent"].as(); } else { stop_percent = 25; director.galaxy.config["stop_percent"] = stop_percent; } ppt = director.galaxy.find_closest_trade(director.current_sector, 3, stop_percent); if (ppt.type == 0) { to_client("No trades found! You've burnt the galaxy!\n\r"); deactivate(); return; } if ((director.current_sector == ppt.s1) || (director.current_sector == ppt.s2)) { // We're still here... BUGZ_LOG(fatal) << "Trade it again, Sam."; to_client("Keep trading.\n\r"); td->port[0] = ppt.s1; td->port[1] = ppt.s2; td->trades = ppt.trades; td->type = ppt.type; director.chain = trader; director.chain->activate(); return; } // Ok, this isn't a local trade. if (loops == 0) { to_client("We're done terrorizing, for now...\n\r"); deactivate(); return; } --loops; // Move to our next target BUGZ_LOG(fatal) << "Moving to: " << ppt.s1; md->move_to = ppt.s1; director.chain = move; director.chain->activate(); return; } to_client("Ok, trade is done.\n\r"); deactivate(); } ScriptVoyager::ScriptVoyager(Director &d) : Dispatch(d) { BUGZ_LOG(warning) << "ScriptVoyager()"; init(); } ScriptVoyager::~ScriptVoyager() { BUGZ_LOG(warning) << "~ScriptVoyager()"; } void ScriptVoyager::init(void) { move = std::make_shared(director); md = static_cast(&(*move)); md->setNotify([this]() { this->move_notify(); }); input = std::make_shared(director); id = static_cast(&(*input)); id->prompt = "Number of loops/tries: "; id->max_length = 5; id->numeric = true; id->setNotify([this](){ this->input_notify();}); } void ScriptVoyager::activate(void) { director.chain = input; input->activate(); return; } void ScriptVoyager::deactivate(void) { BUGZ_LOG(warning) << "ScriptVoyager::deactivate()"; notify(); } void ScriptVoyager::move_notify(void) { if (md->aborted) { deactivate(); return; } if (md->success) { // Great! next(); return; } else { to_client("No safe moves.\n\r"); deactivate(); } } void ScriptVoyager::input_notify(void) { if (id->input.empty() || id->aborted) { to_client("Ok, maybe later then.\n\r"); deactivate(); return; } loops = sstoi(id->input, -1); if (loops == -1) { to_client("I'm sorry, WHAT?\n\r"); deactivate(); } id->input.clear(); BUGZ_LOG(warning) << "Voyager loops: " << loops; next(); } void ScriptVoyager::next(void) { if (loops == 0) { // ok, stop here. to_client("The voyage ends here, for now.\n\r"); deactivate(); return; } --loops; sector_type s = director.galaxy.find_nearest_unexplored(director.current_sector); if (s == 0) { to_client("I don't see anything else to explorer.\n\r"); BUGZ_LOG(warning) << "find_nearest_unexplored returned 0"; deactivate(); } BUGZ_LOG(warning) << "Next stop: " << s; md->move_to = s; director.chain = move; director.chain->activate(); } // SL: [###### DANGER! You have marked sector 740 to be avoided!] // SP: [Do you really want to warp there? (Y/N) ] void ScriptVoyager::server_prompt(const std::string &prompt) { } ScriptExplore::ScriptExplore(Director &d) : Dispatch(d) { BUGZ_LOG(warning) << "ScriptExplore()"; init(); } ScriptExplore::~ScriptExplore() { BUGZ_LOG(warning) << "~ScriptExplore()"; } void ScriptExplore::init() { move = std::make_shared(director); md = static_cast(&(*move)); md->setNotify([this]() {this->move_notify();}); input = std::make_shared(director); id = static_cast(&(*input)); id->prompt = "Number of sectors to explore: "; id->max_length = 5; id->numeric = true; id->setNotify([this](){this->input_notify();}); state = 0; } void ScriptExplore::activate() { us = director.chain; state = 1; to_server("I"); /* director.chain = input; input->activate(); if(director.galaxy.meta["ship"]) { if(!director.galaxy.meta["ship"]["scanner"]) { to_client("\n\rIt appears your ship doesn't have a long range scanner.\n\r"); deactivate(); } } state = 1; return; */ } void ScriptExplore::deactivate() { BUGZ_LOG(warning) << "ScriptExplore::deactivate()"; us.reset(); notify(); } void ScriptExplore::move_notify() { director.chain = us; if (md->aborted) { deactivate(); return; } if (md->success) { to_server("SD"); state = 3; return; } else { to_client("No safe moves.\n\r"); deactivate(); } } void ScriptExplore::input_notify() { director.chain = us; if (id->input.empty() || id->aborted) { to_client("Maybe next time.\n\r"); deactivate(); return; } loops = sstoi(id->input, -1); if (loops == -1) { to_client("I'm sorry, WHAT?\n\r"); deactivate(); return; } if (loops == 0) { infinite = true; } else { infinite = false; } id->input.clear(); if (!infinite) { BUGZ_LOG(warning) << "Explore loops: " << loops; } else { to_client("Infinite Mode!\n\r"); to_client("[ PRESS A KEY TO STOP ]\n\r"); BUGZ_LOG(warning) << "Explore loops: INFINITE"; } to_server("SD"); state = 3; } void ScriptExplore::next() { if (loops <= 0 && !infinite) { to_client("The exploration ends, for now.\n\r"); deactivate(); return; } if(!infinite) --loops; // Calculate next best sector to goto density_scan & ds = director.galaxy.dscan; density best_sector; for (int x = 0; x < ds.pos; ++x) { 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 << ")"; /* Is this sector prefered over others? * Warp Counts (Number of warps) * Density Check (Is this sector clear, does it contain a port) * NavHaz Check (Avoid sectors with navhaz above X%) */ if(!ds.d[x].known) { BUGZ_LOG(warning) << "Subject: " << ds.d[x].sector; // Compare, Warp counts if (best_sector.sector != 0) { 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))) { if(safe_sector(ds.d[x])) { if(best_sector.sector != 0) { BUGZ_LOG(warning) << "Storing previous best " << best_sector.sector; unknown_warps.push(best_sector.sector); } best_sector = ds.d[x]; } } else { if(safe_sector(ds.d[x])) { BUGZ_LOG(warning) << "Added " << ds.d[x].sector << " to unknown_warps (" << unknown_warps.size() << ")"; unknown_warps.push(ds.d[x].sector); } } } else { best_sector = ds.d[x]; } // Check density for possible port } } BUGZ_LOG(warning) << "Unknown Warps: " << unknown_warps.size(); if (best_sector.sector == 0) { if (unknown_warps.size() == 0) { to_client("No unknown warps."); deactivate(); return; } else { BUGZ_LOG(warning) << "Seeking previous unexplored"; best_sector.sector = unknown_warps.top(); unknown_warps.pop(); } } BUGZ_LOG(warning) << "Targeting sector: " << best_sector.sector; md->move_to = best_sector.sector; director.chain = move; director.chain->activate(); } bool ScriptExplore::safe_sector(density d) { // int sector, int density) { if (d.sector == 0) return false; if (d.anomaly) return false; int dense = d.density; /* http://wiki.classictw.com/index.php?title=Gypsy%27s_Big_Dummy%27s_Guide_to_TradeWars_Text#Trader_Information Density Readings: 0 = Empty Sector or Ferrengi Dreadanought 1 = Marker Beacon 2 = Limpet Type 2 Tracking Mine 5 = Fighter (per Fighter) 10 = Armid Type 1 Mine 21 = Navigation Hazard (Per 1 Percent) 21 = Destroyed Ship (Due to 1 Percent Nav-Haz) 38 = Unmanned Ship 40 = Manned Ship, Alien or Ferrengi Assault Trader 50 = Destroyed Starport (After 25 Percent Nav-Haz Clears) 100 = Starport or Ferrengi Battle Cruiser 210 = Destroyed Planet (Due to 10 Percent Nav-Haz) 462 = Federation Starship under Admiral Nelson 489 = Federation Starship under Captain Zyrain 500 = Planet 512 = Federation Starship under Admiral Clausewitz 575 = Destroyed Port (Before 25% Nav-Haz Clears) */ // Adjust density by upto 5% navhaz (Only if navhaz less than 6%) if(d.navhaz != 0 && d.navhaz <= 5) { dense -= d.navhaz * 21; } // If navhaz above 5% report it unsafe if (d.navhaz > 5) return false; switch (dense) { case 0: case 1: case 100: case 101: return true; } // special case for sector 1: if ((d.sector == 1) && (dense == 601)) return true; return false; } void ScriptExplore::server_prompt(const std::string &prompt) { BUGZ_LOG(warning) << "Explorer State: SP " << state; //next(); if(state == 1) { if(at_command_prompt(prompt)) { if(director.galaxy.meta["ship"]) { if(!director.galaxy.meta["ship"]["scanner"]) { to_client("\n\rIt appears your ship doesn't have a long range scanner.\n\r"); deactivate(); return; } } state = 2; BUGZ_LOG(fatal) << "state = 1, prompting for user input"; director.chain = input; input->activate(); return; } } if (state == 3) { if(at_command_prompt(prompt)) { state = 4; next(); } } }