void choke_control(struct ecudata_t* d) { switch(chks.state) { case 0: //Initialization of choke position if (!IOCFG_CHECK(IOP_PWRRELAY)) //Skip initialization if power management is enabled initial_pos(INIT_POS_DIR, d->param.sm_steps); chks.state = 2; break; case 1: //system is being preparing to power-down initial_pos(INIT_POS_DIR, d->param.sm_steps); chks.state = 2; break; case 2: //wait while choke is being initialized if (!stpmot_is_busy()) //ready? { if (chks.pwdn) chks.state = 3; //ready to power-down else chks.state = 5; //normal working chks.smpos = 0; } break; case 3: //power-down if (pwrrelay_get_state()) { chks.pwdn = 0; chks.state = 5; } break; case 5: //normal working mode if (d->choke_testing) { initial_pos(INIT_POS_DIR, d->param.sm_steps); chks.state = 6; //start testing } else { int16_t tmp_pos = (((int32_t)d->param.sm_steps) * choke_closing_lookup(d)) / 200; int16_t rpm_cor = 0, diff; int16_t pos = tmp_pos + rpm_cor; restrict_value_to(&pos, 0, d->param.sm_steps); diff = pos - chks.smpos; if (!stpmot_is_busy() && diff != 0) { stpmot_dir(diff < 0 ? SM_DIR_CW : SM_DIR_CCW); stpmot_run(abs(diff)); //start stepper motor chks.smpos += diff; } } goto check_pwr; // Testing modes case 6: //initialization of choke if (!stpmot_is_busy()) //ready? { stpmot_dir(SM_DIR_CCW); stpmot_run(d->param.sm_steps); chks.state = 7; } goto check_tst; case 7: if (!stpmot_is_busy()) //ready? { stpmot_dir(SM_DIR_CW); stpmot_run(d->param.sm_steps); chks.state = 6; } goto check_tst; default: check_tst: if (!d->choke_testing) chks.state = 1; //exit choke testing mode check_pwr: if (!pwrrelay_get_state()) { //power-down chks.pwdn = 1; chks.state = 1; } break; } }
std::list<MovePathNode> Fleet::MovePath(const std::list<int>& route) const { std::list<MovePathNode> retval; if (route.empty()) return retval; // nowhere to go => empty path // if (route.size() == 1) do nothing special. this fleet is probably on the starlane leading to // its final destination. normal looping to read destination should work fine if (route.size() == 2 && route.front() == route.back()) return retval; // nowhere to go => empty path if (this->Speed() < FLEET_MOVEMENT_EPSILON) { retval.push_back(MovePathNode(this->X(), this->Y(), true, ETA_NEVER, this->SystemID(), INVALID_OBJECT_ID, INVALID_OBJECT_ID)); return retval; // can't move => path is just this system with explanatory ETA } double fuel = Fuel(); double max_fuel = MaxFuel(); //Logger().debugStream() << "Fleet " << this->Name() << " movePath fuel: " << fuel << " sys id: " << this->SystemID(); // determine all systems where fleet(s) can be resupplied if fuel runs out int owner = this->Owner(); const Empire* empire = Empires().Lookup(owner); std::set<int> fleet_supplied_systems; std::set<int> unobstructed_systems; if (empire) { fleet_supplied_systems = empire->FleetSupplyableSystemIDs(); unobstructed_systems = empire->SupplyUnobstructedSystems(); } // determine if, given fuel available and supplyable systems, fleet will ever be able to move if (fuel < 1.0 && this->SystemID() != INVALID_OBJECT_ID && fleet_supplied_systems.find(this->SystemID()) == fleet_supplied_systems.end()) { MovePathNode node(this->X(), this->Y(), true, ETA_OUT_OF_RANGE, this->SystemID(), INVALID_OBJECT_ID, INVALID_OBJECT_ID); retval.push_back(node); return retval; // can't move => path is just this system with explanatory ETA } // get iterator pointing to System* on route that is the first after where this fleet is currently. // if this fleet is in a system, the iterator will point to the system after the current in the route // if this fleet is not in a system, the iterator will point to the first system in the route std::list<int>::const_iterator route_it = route.begin(); if (*route_it == SystemID()) ++route_it; // first system in route is current system of this fleet. skip to the next system if (route_it == route.end()) return retval; // current system of this fleet is the *only* system in the route. path is empty. // get current, previous and next systems of fleet const System* cur_system = GetSystem(this->SystemID()); // may be 0 const System* prev_system = GetSystem(this->PreviousSystemID());// may be 0 if this fleet is not moving or ordered to move const System* next_system = GetSystem(*route_it); // can't use this->NextSystemID() because this fleet may not be moving and may not have a next system. this might occur when a fleet is in a system, not ordered to move or ordered to move to a system, but a projected fleet move line is being calculated to a different system if (!next_system) { Logger().errorStream() << "Fleet::MovePath couldn't get next system with id " << *route_it << " for this fleet " << this->Name(); return retval; } //Logger().debugStream() << "initial cur system: " << (cur_system ? cur_system->Name() : "(none)") << // " prev system: " << (prev_system ? prev_system->Name() : "(none)") << // " next system: " << (next_system ? next_system->Name() : "(none)"); // place initial position MovePathNode MovePathNode initial_pos(this->X(), this->Y(), false /* not an end of turn node */, 0 /* turns taken to reach position of node */, (cur_system ? cur_system->ID() : INVALID_OBJECT_ID), (prev_system ? prev_system->ID() : INVALID_OBJECT_ID), (next_system ? next_system->ID() : INVALID_OBJECT_ID)); retval.push_back(initial_pos); const int TOO_LONG = 100; // limit on turns to simulate. 99 turns max keeps ETA to two digits, making UI work better int turns_taken = 1; double turn_dist_remaining = m_speed; // additional distance that can be travelled in current turn of fleet movement being simulated double cur_x = this->X(); double cur_y = this->Y(); double next_x = next_system->X(); double next_y = next_system->Y(); // simulate fleet movement given known speed, starting position, fuel limit and systems on route // need to populate retval with MovePathNodes that indicate the correct position, whether this // fleet will end a turn at the node, the turns it will take to reach the node, and (when applicable) // the current (if at a system), previous and next system IDs at which the fleet will be. the // previous and next system ids are needed to know what starlane a given node is located on, if any. // nodes at systems don't need previous system ids to be valid, but should have next system ids // valid so that when rendering starlanes using the returned move path, lines departing a system // can be drawn on the correct side of the system icon while (turns_taken < TOO_LONG) { // each loop iteration moves the current position to the next location of interest along the move // path, and then adds a node at that position. //Logger().debugStream() << " starting iteration"; //if (cur_system) // Logger().debugStream() << " at system " << cur_system->Name() << " with id " << cur_system->ID(); //else // Logger().debugStream() << " at (" << cur_x << ", " << cur_y << ")"; // check if fuel limits movement or current system refuels passing fleet if (cur_system) { // check if current system has fuel supply available if (fleet_supplied_systems.find(cur_system->ID()) != fleet_supplied_systems.end()) { // current system has fuel supply. replenish fleet's supply and don't restrict movement fuel = max_fuel; //Logger().debugStream() << " ... at system with fuel supply. replenishing and continuing movement"; } else { // current system has no fuel supply. require fuel to proceed if (fuel >= 1.0) { //Logger().debugStream() << " ... at system without fuel supply. consuming unit of fuel to proceed"; fuel -= 1.0; } else { //Logger().debugStream() << " ... at system without fuel supply. have insufficient fuel to continue moving"; turns_taken = ETA_OUT_OF_RANGE; break; } } } // find distance to next system along path from current position double dist_to_next_system = std::sqrt((next_x - cur_x)*(next_x - cur_x) + (next_y - cur_y)*(next_y - cur_y)); //Logger().debugStream() << " ... dist to next system: " << dist_to_next_system; // move ship as far as it can go this turn, or to next system, whichever is closer, and deduct // distance travelled from distance travellable this turn if (turn_dist_remaining >= FLEET_MOVEMENT_EPSILON) { double dist_travelled_this_step = std::min(turn_dist_remaining, dist_to_next_system); //Logger().debugStream() << " ... fleet moving " << dist_travelled_this_step << " this iteration. dist to next system: " << dist_to_next_system << " and turn_dist_remaining: " << turn_dist_remaining; double x_dist = next_x - cur_x; double y_dist = next_y - cur_y; // dist_to_next_system = std::sqrt(x_dist * x_dist + y_dist * y_dist); // should already equal this distance, so don't need to recalculate double unit_vec_x = x_dist / dist_to_next_system; double unit_vec_y = y_dist / dist_to_next_system; cur_x += unit_vec_x*dist_travelled_this_step; cur_y += unit_vec_y*dist_travelled_this_step; turn_dist_remaining -= dist_travelled_this_step; dist_to_next_system -= dist_travelled_this_step; // if moved away any distance from a system, are no longer in that system if (cur_system && dist_travelled_this_step >= FLEET_MOVEMENT_EPSILON) { prev_system = cur_system; cur_system = 0; } } bool end_turn_at_cur_position = false; // check if fleet can move any further this turn if (turn_dist_remaining < FLEET_MOVEMENT_EPSILON) { //Logger().debugStream() << " ... fleet can't move further this turn."; turn_dist_remaining = 0.0; // to prevent any possible precision-related errors end_turn_at_cur_position = true; } // check if current position is close enough to next system on route to qualify as at that system. if (dist_to_next_system < FLEET_MOVEMENT_EPSILON) { // close enough to be consider to be at next system. // set current position to be exactly at next system to avoid rounding issues cur_system = next_system; cur_x = cur_system->X(); // update positions to ensure no round-off-errors cur_y = cur_system->Y(); //Logger().debugStream() << " ... arrived at system: " << cur_system->Name(); // attempt to get next system on route, to update next system. if new current // system is the end of the route, abort. ++route_it; if (route_it == route.end()) break; // update next system on route and distance to it from current position next_system = GetEmpireKnownSystem(*route_it, owner); if (!next_system) { Logger().errorStream() << "Fleet::MovePath couldn't get system with id " << *route_it; break; } next_x = next_system->X(); next_y = next_system->Y(); } // if new position is an obstructed system, must end turn here if (cur_system && unobstructed_systems.find(cur_system->ID()) == unobstructed_systems.end()) { turn_dist_remaining = 0.0; end_turn_at_cur_position = true; } // if turn done and turns taken is enough, abort simulation if (end_turn_at_cur_position && (turns_taken + 1 >= TOO_LONG)) { // exit loop before placing current node to simplify post-loop processing: now all cases require a post-loop node to be added ++turns_taken; break; } // add MovePathNode for current position (end of turn position and/or system location) MovePathNode cur_pos(cur_x, cur_y, end_turn_at_cur_position, turns_taken, (cur_system ? cur_system->ID() : INVALID_OBJECT_ID), (prev_system ? prev_system->ID() : INVALID_OBJECT_ID), (next_system ? next_system->ID() : INVALID_OBJECT_ID)); retval.push_back(cur_pos); // if the turn ended at this position, increment the turns taken and // reset the distance remaining to be travelled during the current (now // next) turn for the next loop iteration if (end_turn_at_cur_position) { //Logger().debugStream() << " ... end of simulated turn " << turns_taken; ++turns_taken; turn_dist_remaining = m_speed; } } // done looping. may have exited due to reaching end of path, lack of fuel, or turns taken getting too big if (turns_taken == TOO_LONG) turns_taken = ETA_NEVER; MovePathNode final_pos(cur_x, cur_y, true, turns_taken, (cur_system ? cur_system->ID() : INVALID_OBJECT_ID), (prev_system ? prev_system->ID() : INVALID_OBJECT_ID), (next_system ? next_system->ID() : INVALID_OBJECT_ID)); retval.push_back(final_pos); return retval; }