#include "scripts.h" #include #include "logging.h" ScriptTerror::ScriptTerror(Director &d, const char *called) : Dispatch(d, called) { BUGZ_LOG(warning) << "ScriptTerror()"; if (called == nullptr) name = "Terror"; init(); } ScriptTerror::~ScriptTerror() { BUGZ_LOG(warning) << "~ScriptTerror()"; } void ScriptTerror::init(void) { BUGZ_LOG(fatal) << "ScriptTerror::init()"; move = std::make_shared(director, "TerrorMove"); md = static_cast(&(*move)); // setup notify functions for results/completion. md->setNotify([this]() { this->move_notify(); }); input = std::make_shared(director, "TerrorInput"); 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, "TerrorTrader"); 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.contains("trade_end_empty")) { old_trade_end_empty = director.galaxy.config["trade_end_empty"]; } 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.contains("stop_percent")) { stop_percent = director.galaxy.config["stop_percent"].get(); } 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 { std::string message = "Move FAILED. " + md->why_failed + "\n\r"; // to_client("Move FAILED.\n\r"); to_client(message); 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.contains("stop_percent")) { stop_percent = director.galaxy.config["stop_percent"].get(); } 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; } else { std::string message = "Trade done: " + td->why_failed + "\n\r"; to_client(message); } // to_client("Ok, trade is done.\n\r"); deactivate(); } ScriptVoyager::ScriptVoyager(Director &d, const char *called) : Dispatch(d, called) { BUGZ_LOG(warning) << "ScriptVoyager()"; if (called == nullptr) name = "Voyager"; init(); } ScriptVoyager::~ScriptVoyager() { BUGZ_LOG(warning) << "~ScriptVoyager()"; } void ScriptVoyager::init(void) { move = std::make_shared(director, "VoyagerMove"); md = static_cast(&(*move)); md->setNotify([this]() { this->move_notify(); }); input = std::make_shared(director, "VoyagerInput"); 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 { std::string message = "No safe moves. " + md->why_failed + "\n\r"; to_client(message); 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, const char *called) : Dispatch(d, called) { BUGZ_LOG(warning) << "ScriptExplore()"; if (called == nullptr) name = "Explore"; init(); } ScriptExplore::~ScriptExplore() { BUGZ_LOG(warning) << "~ScriptExplore()"; } void ScriptExplore::init() { move = std::make_shared(director, "ExploreMove"); md = static_cast(&(*move)); md->setNotify([this]() { this->move_notify(); }); input = std::make_shared(director, "ExploreInput"); 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; target = 0; if (!director.galaxy.config.contains("prefer_ports")) { director.galaxy.config["prefer_ports"] = "Y"; prefer_ports = true; } else { prefer_ports = startswith(json_str(director.galaxy.config["prefer_ports"]), "Y"); } if (!director.galaxy.meta["help"].contains("prefer_ports")) { director.galaxy.meta["help"]["prefer_ports"] = "Explorer prefers to find ports"; } if (!director.galaxy.config.contains("use_nearest_unknown")) { director.galaxy.config["use_nearest_unknown"] = "Y"; use_nearest_unknown = true; } else { use_nearest_unknown = startswith( json_str(director.galaxy.config["use_nearest_unknown"]), "Y"); } if (!director.galaxy.meta["help"].contains("use_nearest_unknown")) { director.galaxy.meta["help"]["use_nearest_unknown"] = "Explorer will find nearest unknown when out of known sectors to " "explore"; } BUGZ_LOG(warning) << "Prefer Ports: " << prefer_ports; } void ScriptExplore::activate() { us = director.chain; state = 1; to_server("I"); } 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 { if (unknown_warps.size() != 0) { BUGZ_LOG(warning) << "Seeking previous unexplored (Unsafe Dest.)"; state = 4; target = unknown_warps.top(); unknown_warps.pop(); std::string message = "UNSAFE DESTINATION"; ANSIColor alert(COLOR::WHITE, COLOR::RED, ATTR::BOLD); to_client(" " + alert() + message + reset() + "\n\r"); BUGZ_LOG(warning) << "Target = " << target; next(); } else { std::string message = "Move failed: " + md->why_failed + "\n\r"; BUGZ_LOG(warning) << message; to_client(message); 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; } bool has_port(const density d) { int den = d.density; if (d.navhaz <= 5) { den -= 21 * d.navhaz; } return den == 100 || den == 101; } bool sort_ports(const density a, const density b) { if (has_port(a) && has_port(b)) { return a.warps > b.warps; } else { if ((has_port(a) && !has_port(b)) || (!has_port(a) && has_port(b))) { return has_port(a); } return a.warps > b.warps; } } bool sort_warps(const density a, const density b) { if ((has_port(a) && !has_port(b)) || (!has_port(a) && has_port(b))) { return has_port(a) && a.warps > b.warps; } return a.warps > b.warps; } 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; best_sector.sector = 0; std::array sectors = ds.d; for (int x = 0; x < 6; ++x) { if (sectors[x].known || !density_clear(sectors[x].sector, sectors[x].density, sectors[x].navhaz)) { sectors[x].sector = 0; sectors[x].density = 0; sectors[x].warps = 0; sectors[x].navhaz = 0; sectors[x].known = false; sectors[x].anomaly = false; } } if (prefer_ports) { std::sort(sectors.begin(), sectors.end(), sort_ports); } else { std::sort(sectors.begin(), sectors.end(), sort_warps); } for (int x = 0; x < 6; ++x) { BUGZ_LOG(trace) << "[" << sectors[x].sector << ", " << sectors[x].density << ", " << sectors[x].warps << ", " << sectors[x].anomaly << ", " << sectors[x].known << "]"; } BUGZ_LOG(warning) << "Best Sector: " << sectors[0].sector; best_sector = sectors[0]; for (int x = 1; x < 6; ++x) { if (sectors[x].sector != 0 && sectors[x].sector != best_sector.sector) { unknown_warps.push(sectors[x].sector); BUGZ_LOG(info) << "Added " << sectors[x].sector << " to unknown_warps (" << unknown_warps.size() << ")"; } } if (target != 0) { BUGZ_LOG(info) << "Using: " << target; best_sector.sector = target; target = 0; } BUGZ_LOG(warning) << "Unknown Warps: " << unknown_warps.size(); if (best_sector.sector == 0) { if (unknown_warps.size() == 0) { if (!use_nearest_unknown) { to_client("No unknown warps."); deactivate(); return; } else { BUGZ_LOG(warning) << "Seeking nearest unknown"; std::string message = "Finding nearest unexplored"; ANSIColor alert(COLOR::WHITE, COLOR::RED, ATTR::BOLD); to_client(" " + alert() + message + reset() + "\n\r"); best_sector.sector = director.galaxy.find_nearest_unexplored(director.current_sector); if (best_sector.sector == 0) { to_client("No unknown warps in the galaxy!"); deactivate(); return; } } } else { BUGZ_LOG(warning) << "Seeking previous unexplored"; best_sector.sector = unknown_warps.top(); unknown_warps.pop(); std::string message = "DEAD END"; ANSIColor alert(COLOR::WHITE, COLOR::RED, ATTR::BOLD); to_client(" " + alert() + message + reset() + "\n\r"); } } BUGZ_LOG(warning) << "Targeting sector: " << best_sector.sector; if (director.current_sector != best_sector.sector) { md->move_to = best_sector.sector; director.chain = move; director.chain->activate(); } else { BUGZ_LOG(warning) << "Targeting current sector!"; state = 3; to_server("SD"); } } void ScriptExplore::server_prompt(const std::string &prompt) { BUGZ_LOG(info) << "Explorer State: SP " << state; // next(); if (state == 1) { if (at_command_prompt(prompt)) { if (director.galaxy.meta.contains("ship")) { if (!director.galaxy.meta["ship"].contains("scanner")) { to_client( "\n\rIt appears your ship doesn't have a long range " "scanner.\n\r"); deactivate(); return; } } state = 2; BUGZ_LOG(trace) << "state = 1, prompting for user input"; director.chain = input; input->activate(); return; } } if (state == 3) { if (at_command_prompt(prompt)) { state = 4; BUGZ_LOG(trace) << "state = 3, calculating next sector"; next(); } } } ScriptPlanet::ScriptPlanet(Director &d, const char *called) : Dispatch(d, called) { BUGZ_LOG(warning) << "ScriptPlanet()"; if (called == nullptr) name = "Planet"; init(); } ScriptPlanet::~ScriptPlanet() { BUGZ_LOG(warning) << "~ScriptPlanet()"; } void ScriptPlanet::init() { move = std::make_shared(director, "PlanetMove"); md = static_cast(&(*move)); md->setNotify([this]() { this->move_notify(); }); md->use_express = true; trader = std::make_shared(director, "PlanetTrader"); td = static_cast(&(*trader)); td->setNotify([this]() { this->trade_notify(); }); input = std::make_shared(director, "PlanetInput"); id = static_cast(&(*input)); id->prompt = "Which planet would you like to upgrade => "; id->max_length = 3; id->numeric = true; id->setNotify([this]() { this->input_notify(); }); state = 0; } void ScriptPlanet::activate() { us = director.chain; aborted = false; // FUTURE: handle special case here, where we activate at planet/citadel // prompt /* States: 1 = Team List Planets 2 = List Planets 3 = Input Which planet to upgrade? 4 = Move to Planet 5 = Land, get planet information 6 = CU Citadel build/upgrade 7 = Parse Citadel needs 8 = Construct/upgrade ? 9 = to terra! 10 = back to the planet! 11 = unloading... 12 = resources 13 = moving to buyer 14 = moving to planet 15 = product unloaded */ state = 1; // clear out the planets list -- we're refreshing. director.galaxy.planets.clear(); // get planet lists to_server("TLQ"); } void ScriptPlanet::deactivate() { BUGZ_LOG(warning) << "ScriptPlanet::deactivate()"; us.reset(); notify(); } void ScriptPlanet::clear_amounts(void) { // clear amounts for (int x = 0; x < 3; x++) { population[x] = 0; amount[x] = 0; needs[x] = 0; ship[x] = 0; to_make_one[x] = 0; } total_population = 0; support_construction = 0; days = 0; } /** * @brief Best place to put colonists * * Where is the best place to put colonists? * * That would be in production where they produce the most product. * Where the number to make one is the least. * * @return int */ int ScriptPlanet::place_colonists(void) { int best = 1000; int pos = 0; for (int x = 0; x < 3; x++) { if (to_make_one[x] != 0) { if (to_make_one[x] < best) { best = to_make_one[x]; pos = x; } } } return pos; } void ScriptPlanet::input_notify() { // deactivate(); director.chain = us; if (id->input.empty()) { deactivate(); return; } int selected = sstoi(id->input); if (selected == 0) { deactivate(); return; } // find the planet in our list auto pos = director.galaxy.planets.find(selected); if (pos == director.galaxy.planets.end()) { to_client("Sorry, I can't find that planet #.\n\r"); deactivate(); return; } // Check planet level, if already max, don't bother! // Ok, we're off to planet # selected! planet = selected; sector = pos->second.sector; current_level = pos->second.level; if (director.current_sector == sector) { // We're already there! state = 5; // clear out numbers clear_amounts(); // Landing ... to_server("L"); return; } else { // Let's get to the planet state = 4; md->move_to = sector; director.chain = move; move->activate(); return; } } void ScriptPlanet::move_notify() { director.chain = us; if (md->success) { // Ok, we're here if (state == 4) { state = 5; // clear out numbers clear_amounts(); to_server("L"); return; } else if (state == 9) { // Ok, we're at terra to_server("LT\r"); return; } else if (state == 10) { // Back at the planet - Land and unload to_server("L"); return; } else if (state == 13) { // Ok, we're here! td->port[0] = current_buyfrom; td->port[1] = 0; for (int x = 0; x < 3; x++) { td->port_buysell[0].foe[x] = false; td->port_buysell[1].foe[x] = false; td->trades.foe[x] = false; } td->port_buysell[0].foe[current_product] = true; td->trades.foe[current_product] = true; director.chain = trader; td->activate(); return; } else if (state == 14) { // We're at the planet! Time to unload! to_server("L"); return; } return; } else { std::string message = "MOVE FAILED: "; message.append(md->why_failed); message.append("\n\r"); to_client(message); deactivate(); return; } } void ScriptPlanet::trade_notify() { director.chain = us; if (td->success) { if (state == 13) { // Ok, we have what we came from, return to the planet. state = 14; md->move_to = sector; director.chain = move; move->activate(); return; } } else { to_client("Trade failed.\n\r"); deactivate(); return; } } void ScriptPlanet::server_prompt(const std::string &prompt) { if (state == 1) { if (at_command_prompt(prompt)) { state = 2; to_server("CYQ"); return; } } else if (state == 2) { if (at_command_prompt(prompt)) { state = 3; if (director.galaxy.planets.empty()) { to_client("Sorry, I don't see that you have any planets!\n\r"); deactivate(); return; } for (auto const &planet : director.galaxy.planets) { std::string text = str( boost::format("%1$3d <%2$5d> Class %3% Level %4% Name %5%\n\r") % planet.first % planet.second.sector % planet.second.c % planet.second.level % planet.second.name); to_client(text); } director.chain = input; director.chain->activate(); return; } } else if (state == 5) { // Are they prompting us for which planet to land on? // SP: [Land on which planet ? ] if (prompt == "Land on which planet ? ") { std::string text = std::to_string(planet) + "\r"; to_server(text); return; } // SP: [Planet command (?=help) [D] ] if (prompt == "Planet command (?=help) [D] ") { // Ok, we're here on the planet. (Did we capture the planet info on // landing?) BUGZ_LOG(fatal) << "Total population: " << total_population; // FIXUP: Empty out the ship holds if they aren't empty. for (int x = 0; x < 3; ++x) { if (ship[x] != 0) { std::string message = str( boost::format("Transfer ship cargo %1% (%2%) to planet.\n\r") % foe[x] % ship[x]); to_client(message); std::string transfer = "TNL"; transfer.append(std::to_string(x + 1)); transfer.append("\r"); to_server(transfer); ship[x] = 0; return; } } // citadel, upgrade // what is the message when you don't have a citadel yet? state = 6; to_server("CU"); return; } } else if (state == 8) { // SP: [Do you wish to construct one? ] if (startswith(prompt, "Do you wish to construct ") && endswith(prompt, "? ")) { // Do we have what we need? bool ready = true; if (total_population < support_construction) { ready = false; state = 9; std::string message = str(boost::format("Planet has %1% people, need %2%.\n\r") % total_population % support_construction); to_client(message); BUGZ_LOG(fatal) << "Need people [" << support_construction - total_population << "]"; } for (int x = 0; x < 3; ++x) { if (needs[x] > amount[x]) { if (ready) { ready = false; state = 12; } std::string message = str(boost::format("Has %1% of %2%, needs %3%\n\r") % amount[x] % foe[x] % needs[x]); to_client(message); BUGZ_LOG(fatal) << "Need " << x << " :" << needs[x] - amount[x]; } } if (ready) { to_server("Y"); deactivate(); return; } // NNY! if (current_level > 0) { to_server("NQQ"); } else to_server("NQ"); // Ok, time to start moving! if (state == 9) { md->move_to = 1; director.chain = move; md->activate(); return; } if (state == 12) { // Need resources current_product = -1; for (int x = 0; x < 3; ++x) { if (needs[x] > amount[x]) { current_product = x; break; } } if (current_product == -1) { // I think we have everything. BUGZ_LOG(fatal) << "I think we've got it..."; to_server("CUY"); deactivate(); return; } else { // Ok, let's find where we need to go current_buyfrom = director.galaxy.find_nearest_selling( director.current_sector, current_product); if (current_buyfrom == 0) { to_client("We weren't able to locate a port selling.\n\r"); deactivate(); return; } state = 13; md->move_to = current_buyfrom; director.chain = move; md->activate(); return; } } } } else if (state == 9) { if (at_command_prompt(prompt)) { // Ok! We have colonists ... back to the planet! state = 10; md->move_to = sector; director.chain = move; md->activate(); return; } } else if (state == 10) { if (prompt == "Land on which planet ? ") { std::string text = std::to_string(planet) + "\r"; to_server(text); return; } if (prompt == "Planet command (?=help) [D] ") { // Ok, on the planet. state = 11; int place = place_colonists(); std::string unload = "SNL"; unload.append(std::to_string(place + 1)); unload.append("\r"); to_server(unload); return; } } else if (state == 11) { if (prompt == "Planet command (?=help) [D] ") { if (total_population < support_construction) { // Need More - we're not in citadel. to_server("Q"); state = 9; md->move_to = 1; director.chain = move; md->activate(); return; } // Ok, we're ready for the next step: // checking the resources. // Need resources current_product = -1; for (int x = 0; x < 3; ++x) { if (needs[x] > amount[x]) { current_product = x; break; } } if (current_product == -1) { // I think we have everything. BUGZ_LOG(fatal) << "I think we've got it..."; to_server("CUY"); deactivate(); return; } else { // Ok, let's find where we need to go current_buyfrom = director.galaxy.find_nearest_selling( director.current_sector, current_product); if (current_buyfrom == 0) { to_client("We weren't able to locate a port selling.\n\r"); deactivate(); return; } to_server("Q"); state = 13; md->move_to = current_buyfrom; director.chain = move; md->activate(); return; } // ending here for now. (not in citadel) // to_server("Q"); // deactivate(); // return; } } else if (state == 14) { if (prompt == "Land on which planet ? ") { std::string text = std::to_string(planet) + "\r"; to_server(text); return; } if (prompt == "Planet command (?=help) [D] ") { state = 15; std::string command = "TNL"; command.append(std::to_string(current_product + 1)); command.append("\r"); to_server(command); return; } } else if (state == 15) { if (prompt == "Planet command (?=help) [D] ") { // Ok, we're done unloading ... what do we need next? // Need resources current_product = -1; for (int x = 0; x < 3; ++x) { if (needs[x] > amount[x]) { current_product = x; break; } } if (current_product == -1) { // I think we have everything. BUGZ_LOG(fatal) << "I think we've got it..."; to_server("CUY"); deactivate(); return; } else { // Ok, let's find where we need to go current_buyfrom = director.galaxy.find_nearest_selling( director.current_sector, current_product); if (current_buyfrom == 0) { to_client("We weren't able to locate a port selling.\n\r"); deactivate(); return; } to_server("Q"); state = 13; md->move_to = current_buyfrom; director.chain = move; md->activate(); return; } } } } void ScriptPlanet::server_line(const std::string &line, const std::string &raw_line) { // because I'm not sending this to the client, this is all hidden from them. if (state == 5) { // Save the planet information /* SL: [ ------- --------- --------- --------- --------- --------- ---------] SL: [Fuel Ore 4,950 2 2,475 28,135 0 200,000] SL: [Organics 0 5 0 100 0 200,000] SL: [Equipment 128 20 6 120 0 100,000] SL: [Fighters N/A 24 206 2,395 200 1,000,000] */ std::string work = line; replace(work, "Fuel Ore", "Fuel"); replace(work, ",", ""); auto parts = split(work); if (parts.size() == 7) { int pos = -1; if (parts[0] == "Fuel") { pos = 0; } else if (parts[0] == "Organics") { pos = 1; } else if (parts[0] == "Equipment") { pos = 2; } // To save: if (pos >= 0) { population[pos] = sstoi(parts[1]); to_make_one[pos] = sstoi(parts[2]); total_population += population[pos]; amount[pos] = sstoi(parts[4]); // What do we have on-board the ship? ship[pos] = sstoi(parts[5]); BUGZ_LOG(fatal) << pos << " : pop " << population[pos] << " 2M1 " << to_make_one[pos] << " amount " << amount[pos] << " ship: " << ship[pos]; } } } else if (state == 6) { // [Be patient, your Citadel is not yet finished.] if ((line == "Be patient, your Citadel is not yet finished.") || (startswith(line, "You may not upgrade while"))) { // We're already upgrading! std::string work = raw_line; work += "\n\r"; to_client(work); if (current_level > 0) { to_server("QQ"); // exit citadel, exit planet } else { to_server("Q"); // exit planet }; deactivate(); return; } // Citadel upgrade information (possibly) /* SL: [Citadel construction on this type of planet requires the following:] SL: [ 400,000 Colonists to support the construction,] SL: [ 150 units of Fuel Ore,] SL: [ 100 units of Organics,] SL: [ 150 units of Equipment and] SL: [ 2 days to construct.] [Construction of a Combat Control Computer on this type of planet requires] */ if ((line == "Citadel construction on this type of planet requires the " "following:") || (endswith(line, " on this type of planet requires"))) { state = 7; } } else if (state == 7) { if (line.empty()) { state = 8; } else { // Display the upgrade information to the client std::string work = raw_line; work += "\n\r"; to_client(work); work = line; replace(work, ",", ""); trim(work); auto pos = work.find(" Colonists to support"); if (pos != std::string::npos) { support_construction = sstoi(work) / 1000; return; } pos = work.find(" units of Fuel"); if (pos != std::string::npos) { needs[0] = sstoi(work); return; } pos = work.find(" units of Organics"); if (pos != std::string::npos) { needs[1] = sstoi(work); return; } pos = work.find(" units of Equipment"); if (pos != std::string::npos) { needs[2] = sstoi(work); return; } pos = work.find(" days to construct"); if (pos != std::string::npos) { days = sstoi(work); return; } } } else if (state == 9) { bool output = false; if (startswith(line, "How many groups of Colonist")) output = true; if (startswith(line, "The Colonists file aboard your ship")) output = true; if (output) { // output to client std::string work = raw_line; work += "\n\r"; to_client(work); } } else if (state == 11) { // SL: [How many groups of Colonists do you want to leave ([125] on board) // ? ] bool output = false; if (startswith(line, "How many groups of Colonists do you want to leave")) { std::string work = line.substr(line.find('[') + 1); int amount = sstoi(work); total_population += amount; output = true; BUGZ_LOG(fatal) << "Population now: " << total_population; } if (startswith(line, "The Colonists disembark")) output = true; if (output) { // output to client std::string work = raw_line; work += "\n\r"; to_client(work); } } else if (state == 15) { bool output = false; // SL: [How many holds of Organics do you want to leave ([250] on board) ? ] if (startswith(line, "How many holds of ") && endswith(line, "] on board) ? ")) { std::string work = line.substr(line.find('[') + 1); int amount_moved = sstoi(work); amount[current_product] += amount_moved; output = true; BUGZ_LOG(fatal) << "Planet " << current_product << " +" << amount_moved << " = " << amount[current_product]; } if (startswith(line, "You unload the ")) output = true; if (output) { // output to client std::string work = raw_line; work += "\n\r"; to_client(work); } } } void ScriptPlanet::client_input(const std::string &input) { deactivate(); }