/** * Select a destination based on the criteria of our trajectory and desired waypoint. * @param trajectory the trajectory in question. * @param nextWaypoint the next logical waypoint in sequence (0 for newly spawned UFOs) * @param globe The earth globe, required to get access to land checks. * @param region the ruleset for the region of our mission. * @return a set of lon and lat coordinates based on the criteria of the trajectory. */ std::pair<double, double> AlienMission::getWaypoint(const UfoTrajectory &trajectory, const size_t nextWaypoint, const Globe &globe, const RuleRegion ®ion) { /* LOOK MA! NO HANDS! if (trajectory.getAltitude(nextWaypoint) == "STR_GROUND") { return getLandPoint(globe, region, trajectory.getZone(nextWaypoint)); } else */ return region.getRandomPoint(trajectory.getZone(nextWaypoint)); }
/** * This function is called when one of the mission's UFOs has finished it's time on the ground. * It takes care of sending the UFO to the next waypoint and marking them for removal as required. * It must set the game data in a way that the rest of the code understands what to do. * @param ufo The UFO that reached it's waypoint. * @param engine The game engine, required to get access to game data and game rules. * @param globe The earth globe, required to get access to land checks. */ void AlienMission::ufoLifting(Ufo &ufo, Game &engine, const Globe &globe) { const Ruleset &rules = *engine.getRuleset(); switch (ufo.getStatus()) { case Ufo::FLYING: assert(0 && "Ufo is already on the air!"); break; case Ufo::LANDED: { if ((ufo.getRules()->getType() == "STR_HARVESTER" && _rule.getType() == "STR_ALIEN_HARVEST") || (ufo.getRules()->getType() == "STR_ABDUCTOR" && _rule.getType() == "STR_ALIEN_ABDUCTION")) { addScore(ufo.getLongitude(), ufo.getLatitude(), engine); } assert(ufo.getTrajectoryPoint() != ufo.getTrajectory().getWaypointCount() - 1); ufo.setSpeed((int)(ufo.getRules()->getMaxSpeed() * ufo.getTrajectory().getSpeedPercentage(ufo.getTrajectoryPoint()))); ufo.setAltitude("STR_VERY_LOW"); // Set next waypoint. Waypoint *wp = new Waypoint(); RuleRegion *region = rules.getRegion(_region); std::pair<double, double> pos; if (ufo.getTrajectory().getAltitude(ufo.getTrajectoryPoint() + 1) == "STR_GROUND") { pos = getLandPoint(globe, *region, ufo.getTrajectory().getZone(ufo.getTrajectoryPoint() + 1)); } else { pos = region->getRandomPoint(ufo.getTrajectory().getZone(ufo.getTrajectoryPoint() + 1)); } wp->setLongitude(pos.first); wp->setLatitude(pos.second); ufo.setDestination(wp); ufo.setTrajectoryPoint(ufo.getTrajectoryPoint() + 1); } break; case Ufo::CRASHED: // Mission expired ufo.setDetected(false); ufo.setStatus(Ufo::DESTROYED); break; case Ufo::DESTROYED: assert(0 && "UFO can't fly!"); break; } }
/** * Get a random point inside the given region zone. * The point will be used to land a UFO, so it HAS to be on land. */ std::pair<double, double> AlienMission::getLandPoint(const Globe &globe, const RuleRegion ®ion, size_t zone) { int tries = 0; std::pair<double, double> pos; do { pos = region.getRandomPoint(zone); ++tries; } while (!(globe.insideLand(pos.first, pos.second) && region.insideRegion(pos.first, pos.second)) && tries < 100); if (tries == 100) { Log(LOG_DEBUG) << "Region: " << region.getType() << " Longitude: " << pos.first << " Lattitude: " << pos.second << " invalid zone: " << zone << " ufo forced to land on water!"; } return pos; }
/** * This function is called when one of the mission's UFOs arrives at it's current destination. * It takes care of sending the UFO to the next waypoint, landing UFOs and * marking them for removal as required. It must set the game data in a way that the rest of the code * understands what to do. * @param ufo The UFO that reached it's waypoint. * @param engine The game engine, required to get access to game data and game rules. * @param globe The earth globe, required to get access to land checks. */ void AlienMission::ufoReachedWaypoint(Ufo &ufo, Game &engine, const Globe &globe) { const Ruleset &rules = *engine.getRuleset(); SavedGame &game = *engine.getSavedGame(); if (ufo.getTrajectoryPoint() == ufo.getTrajectory().getWaypointCount() - 1) { ufo.setDetected(false); ufo.setStatus(Ufo::DESTROYED); return; } ufo.setAltitude(ufo.getTrajectory().getAltitude(ufo.getTrajectoryPoint() + 1)); if (ufo.getAltitude() != "STR_GROUND") { if (ufo.getLandId() != 0) { ufo.setLandId(0); } ufo.setTrajectoryPoint(ufo.getTrajectoryPoint() + 1); // Set next waypoint. Waypoint *wp = new Waypoint(); RuleRegion *region = rules.getRegion(_region); ufo.setSpeed((int)(ufo.getRules()->getMaxSpeed() * ufo.getTrajectory().getSpeedPercentage(ufo.getTrajectoryPoint()))); std::pair<double, double> pos; if (ufo.getTrajectory().getAltitude(ufo.getTrajectoryPoint()) == "STR_GROUND") { pos = getLandPoint(globe, *region, ufo.getTrajectory().getZone(ufo.getTrajectoryPoint())); } else { pos = region->getRandomPoint(ufo.getTrajectory().getZone(ufo.getTrajectoryPoint())); } wp->setLongitude(pos.first); wp->setLatitude(pos.second); ufo.setDestination(wp); } else { // UFO landed. if (ufo.getRules()->getType() == "STR_TERROR_SHIP" && _rule.getType() == "STR_ALIEN_TERROR" && ufo.getTrajectory().getZone(ufo.getTrajectoryPoint()) == 0) { // Specialized: STR_ALIEN_TERROR // Remove UFO, replace with TerrorSite. addScore(ufo.getLongitude(), ufo.getLatitude(), engine); ufo.setStatus(Ufo::DESTROYED); TerrorSite *terrorSite = new TerrorSite(); terrorSite->setLongitude(ufo.getLongitude()); terrorSite->setLatitude(ufo.getLatitude()); terrorSite->setId(game.getId("STR_TERROR_SITE")); terrorSite->setSecondsRemaining(4 * 3600 + RNG::generate(0, 6) * 3600); terrorSite->setAlienRace(_race); const City *city = rules.locateCity(ufo.getLongitude(), ufo.getLatitude()); assert(city); game.getTerrorSites()->push_back(terrorSite); for (std::vector<Target*>::iterator t = ufo.getFollowers()->begin(); t != ufo.getFollowers()->end();) { Craft* c = dynamic_cast<Craft*>(*t); if (c && c->getNumSoldiers() != 0) { c->setDestination(terrorSite); t = ufo.getFollowers()->begin(); } else { ++t; } } } else if (_rule.getType() == "STR_ALIEN_RETALIATION" && ufo.getTrajectory().getID() == "__RETALIATION_ASSAULT_RUN") { // Ignore what the trajectory might say, this is a base assault. // Remove UFO, replace with Base defense. ufo.setDetected(false); std::vector<Base *>::const_iterator found = std::find_if(game.getBases()->begin(), game.getBases()->end(), MatchBaseCoordinates(ufo.getLongitude(), ufo.getLatitude())); if (found == game.getBases()->end()) { ufo.setStatus(Ufo::DESTROYED); // Only spawn mission if the base is still there. return; } ufo.setDestination(*found); } else { // Set timer for UFO on the ground. ufo.setSecondsRemaining(ufo.getTrajectory().groundTimer()); if (ufo.getDetected() && ufo.getLandId() == 0) { ufo.setLandId(engine.getSavedGame()->getId("STR_LANDING_SITE")); } } } }