/** * 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 game The saved game information. * @param globe The earth globe, required to get access to land checks. */ void AlienMission::ufoLifting(Ufo &ufo, SavedGame &game, const Globe &globe) { switch (ufo.getStatus()) { case Ufo::FLYING: assert(0 && "Ufo is already on the air!"); break; case Ufo::LANDED: { // base missions only get points when they are completed. if (_rule.getPoints() > 0 && _rule.getObjective() != OBJECTIVE_BASE) { addScore(ufo.getLongitude(), ufo.getLatitude(), game); } ufo.setAltitude("STR_VERY_LOW"); ufo.setSpeed((int)(ufo.getRules()->getMaxSpeed() * ufo.getTrajectory().getSpeedPercentage(ufo.getTrajectoryPoint()))); } break; case Ufo::CRASHED: // Mission expired ufo.setDetected(false); ufo.setStatus(Ufo::DESTROYED); break; case Ufo::DESTROYED: assert(0 && "UFO can't fly!"); break; } }
/** * Returns the current altitude of the craft. * @return Altitude. */ std::string Craft::getAltitude() const { Ufo *u = dynamic_cast<Ufo*>(_dest); if (u && u->getAltitude() != "STR_GROUND") { return u->getAltitude(); } else { return "STR_VERY_LOW"; } }
/** * Returns if a certain target is detected by the craft's * radar, taking in account the range and chance. * @param target Pointer to target to compare. * @return True if it's detected, False otherwise. */ bool Craft::detect(Target *target) const { if (_rules->getRadarRange() == 0 || !insideRadarRange(target)) return false; // backward compatibility with vanilla if (_rules->getRadarChance() == 100) return true; Ufo *u = dynamic_cast<Ufo*>(target); int chance = _rules->getRadarChance() * (100 + u->getVisibility()) / 100; return RNG::percent(chance); }
/** * Enters the mission. * @param action Pointer to an action. */ void ConfirmLandingState::btnYesClick(Action *) { _game->popState(); _state->musicStop(); Ufo* u = dynamic_cast<Ufo*>(_craft->getDestination()); TerrorSite* t = dynamic_cast<TerrorSite*>(_craft->getDestination()); AlienBase* b = dynamic_cast<AlienBase*>(_craft->getDestination()); size_t month = _game->getSavedGame()->getMonthsPassed(); if (month > _game->getRuleset()->getAlienItemLevels().size()-1) month = _game->getRuleset()->getAlienItemLevels().size()-1; SavedBattleGame *bgame = new SavedBattleGame(); _game->getSavedGame()->setBattleGame(bgame); BattlescapeGenerator bgen = BattlescapeGenerator(_game); bgen.setWorldTexture(_texture); bgen.setWorldShade(_shade); bgen.setCraft(_craft); if (u != 0) { if(u->getStatus() == Ufo::CRASHED) bgame->setMissionType("STR_UFO_CRASH_RECOVERY"); else bgame->setMissionType("STR_UFO_GROUND_ASSAULT"); bgen.setUfo(u); bgen.setAlienRace(u->getAlienRace()); } else if (t != 0) { bgame->setMissionType("STR_TERROR_MISSION"); bgen.setTerrorSite(t); bgen.setAlienRace(t->getAlienRace()); } else if (b != 0) { bgame->setMissionType("STR_ALIEN_BASE_ASSAULT"); bgen.setAlienBase(b); bgen.setAlienRace(b->getAlienRace()); } else { throw Exception("No mission available!"); } bgen.setAlienItemlevel(_game->getRuleset()->getAlienItemLevels().at(month).at(RNG::generate(0,9))); bgen.run(); _game->pushState(new BriefingState(_game, _craft)); }
/** * Enters the mission. * @param action Pointer to an action. */ void ConfirmLandingState::btnYesClick(Action *) { _game->popState(); Ufo* u = dynamic_cast<Ufo*>(_craft->getDestination()); MissionSite* m = dynamic_cast<MissionSite*>(_craft->getDestination()); AlienBase* b = dynamic_cast<AlienBase*>(_craft->getDestination()); SavedBattleGame *bgame = new SavedBattleGame(); _game->getSavedGame()->setBattleGame(bgame); BattlescapeGenerator bgen(_game); bgen.setWorldTexture(_texture); bgen.setWorldShade(_shade); bgen.setCraft(_craft); if (u != 0) { if (u->getStatus() == Ufo::CRASHED) bgame->setMissionType("STR_UFO_CRASH_RECOVERY"); else bgame->setMissionType("STR_UFO_GROUND_ASSAULT"); bgen.setUfo(u); bgen.setAlienRace(u->getAlienRace()); } else if (m != 0) { bgame->setMissionType(m->getDeployment()->getType()); bgen.setMissionSite(m); bgen.setAlienRace(m->getAlienRace()); } else if (b != 0) { bgame->setMissionType(b->getDeployment()->getType()); bgen.setAlienBase(b); bgen.setAlienRace(b->getAlienRace()); bgen.setWorldTexture(0); } else { throw Exception("No mission available!"); } bgen.run(); _game->pushState(new BriefingState(_craft)); }
/** * This function is called when one of the mission's UFOs is shot down (crashed or destroyed). * Currently the only thing that happens is delaying the next UFO in the mission sequence. * @param ufo The UFO that was shot down. * @param engine The game engine, unused for now. * @param globe The earth globe, unused for now. */ void AlienMission::ufoShotDown(Ufo &ufo, Game &, const Globe &) { switch (ufo.getStatus()) { case Ufo::FLYING: case Ufo::LANDED: assert(0 && "Ufo seems ok!"); break; case Ufo::CRASHED: case Ufo::DESTROYED: if (_nextWave != _rule.getWaveCount()) { // Delay next wave _spawnCountdown += 30 * (RNG::generate(0, 48) + 400); } break; } }
/** * 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")); } } } }
/** * This function will spawn a UFO according the the mission rules. * Some code is duplicated between cases, that's ok for now. It's on different * code paths and the function is MUCH easier to read written this way. * @param game The saved game information. * @param ruleset The ruleset. * @param globe The globe, for land checks. * @param ufoRule The rule for the desired UFO. * @param trajectory The rule for the desired trajectory. * @return Pointer to the spawned UFO. If the mission does not desire to spawn a UFO, 0 is returned. */ Ufo *AlienMission::spawnUfo(const SavedGame &game, const Ruleset &ruleset, const Globe &globe, const RuleUfo &ufoRule, const UfoTrajectory &trajectory) { if (_rule.getType() == "STR_ALIEN_RETALIATION") { const RuleRegion ®ionRules = *ruleset.getRegion(_region); std::vector<Base *>::const_iterator found = std::find_if(game.getBases()->begin(), game.getBases()->end(), FindMarkedXCOMBase(regionRules)); if (found != game.getBases()->end()) { // Spawn a battleship straight for the XCOM base. const RuleUfo &battleshipRule = *ruleset.getUfo("STR_BATTLESHIP"); const UfoTrajectory &assaultTrajectory = *ruleset.getUfoTrajectory("__RETALIATION_ASSAULT_RUN"); Ufo *ufo = new Ufo(const_cast<RuleUfo*>(&battleshipRule)); ufo->setMissionInfo(this, &assaultTrajectory); std::pair<double, double> pos; if (trajectory.getAltitude(0) == "STR_GROUND") { pos = getLandPoint(globe, regionRules, trajectory.getZone(0)); } else { pos = regionRules.getRandomPoint(trajectory.getZone(0)); } ufo->setAltitude(assaultTrajectory.getAltitude(0)); ufo->setSpeed(assaultTrajectory.getSpeedPercentage(0) * ufoRule.getMaxSpeed()); ufo->setLongitude(pos.first); ufo->setLatitude(pos.second); Waypoint *wp = new Waypoint(); wp->setLongitude((*found)->getLongitude()); wp->setLatitude((*found)->getLatitude()); ufo->setDestination(wp); return ufo; } } else if (_rule.getType() == "STR_ALIEN_SUPPLY") { Log(LOG_DEBUG) << __FILE__ << ':' << __LINE__ << ' ' << _base; if (ufoRule.getType() == "STR_SUPPLY_SHIP" && !_base) { // No base to supply! return 0; } // Our destination is always an alien base. Ufo *ufo = new Ufo(const_cast<RuleUfo*>(&ufoRule)); ufo->setMissionInfo(this, &trajectory); const RuleRegion ®ionRules = *ruleset.getRegion(_region); std::pair<double, double> pos; if (trajectory.getAltitude(0) == "STR_GROUND") { pos = getLandPoint(globe, regionRules, trajectory.getZone(0)); } else { pos = regionRules.getRandomPoint(trajectory.getZone(0)); } ufo->setAltitude(trajectory.getAltitude(0)); ufo->setSpeed(trajectory.getSpeedPercentage(0) * ufoRule.getMaxSpeed()); ufo->setLongitude(pos.first); ufo->setLatitude(pos.second); Waypoint *wp = new Waypoint(); if (trajectory.getAltitude(1) == "STR_GROUND") { if (ufoRule.getType() == "STR_SUPPLY_SHIP") { // Supply ships on supply missions land on bases, ignore trajectory zone. pos.first = _base->getLongitude(); pos.second = _base->getLatitude(); } else { // Other ships can land where they want. pos = getLandPoint(globe, regionRules, trajectory.getZone(1)); } } else { pos = regionRules.getRandomPoint(trajectory.getZone(1)); } wp->setLongitude(pos.first); wp->setLatitude(pos.second); ufo->setDestination(wp); return ufo; } // Spawn according to sequence. Ufo *ufo = new Ufo(const_cast<RuleUfo*>(&ufoRule)); ufo->setMissionInfo(this, &trajectory); const RuleRegion ®ionRules = *ruleset.getRegion(_region); std::pair<double, double> pos; if (trajectory.getAltitude(0) == "STR_GROUND") { pos = getLandPoint(globe, regionRules, trajectory.getZone(0)); } else { pos = regionRules.getRandomPoint(trajectory.getZone(0)); } ufo->setAltitude(trajectory.getAltitude(0)); ufo->setSpeed(trajectory.getSpeedPercentage(0) * ufoRule.getMaxSpeed()); ufo->setLongitude(pos.first); ufo->setLatitude(pos.second); Waypoint *wp = new Waypoint(); if (trajectory.getAltitude(1) == "STR_GROUND") { pos = getLandPoint(globe, regionRules, trajectory.getZone(1)); } else { pos = regionRules.getRandomPoint(trajectory.getZone(1)); } wp->setLongitude(pos.first); wp->setLatitude(pos.second); ufo->setDestination(wp); return ufo; }
/** * Loads a saved game's contents from a YAML file. * @note Assumes the saved game is blank. * @param filename YAML filename. * @param rule Ruleset for the saved game. */ void SavedGame::load(const std::string &filename, Ruleset *rule) { std::string s = Options::getUserFolder() + filename + ".sav"; std::ifstream fin(s.c_str()); if (!fin) { throw Exception("Failed to load savegame"); } YAML::Parser parser(fin); YAML::Node doc; // Get brief save info parser.GetNextDocument(doc); std::string v; doc["version"] >> v; if (v != Options::getVersion()) { throw Exception("Version mismatch"); } _time->load(doc["time"]); // Get full save data parser.GetNextDocument(doc); int a = 0; doc["difficulty"] >> a; _difficulty = (GameDifficulty)a; doc["funds"] >> _funds; for (YAML::Iterator i = doc["countries"].begin(); i != doc["countries"].end(); ++i) { std::string type; (*i)["type"] >> type; Country *c = new Country(rule->getCountry(type), false); c->load(*i); _countries.push_back(c); } for (YAML::Iterator i = doc["regions"].begin(); i != doc["regions"].end(); ++i) { std::string type; (*i)["type"] >> type; Region *r = new Region(rule->getRegion(type)); r->load(*i); _regions.push_back(r); } for (YAML::Iterator i = doc["ufos"].begin(); i != doc["ufos"].end(); ++i) { std::string type; (*i)["type"] >> type; Ufo *u = new Ufo(rule->getUfo(type)); u->load(*i); _ufos.push_back(u); } doc["craftId"] >> _craftId; for (YAML::Iterator i = doc["waypoints"].begin(); i != doc["waypoints"].end(); ++i) { Waypoint *w = new Waypoint(); w->load(*i); _waypoints.push_back(w); } doc["ufoId"] >> _ufoId; doc["waypointId"] >> _waypointId; doc["soldierId"] >> _soldierId; for (YAML::Iterator i = doc["bases"].begin(); i != doc["bases"].end(); ++i) { Base *b = new Base(rule); b->load(*i, this); _bases.push_back(b); } for(YAML::Iterator it=doc["discovered"].begin();it!=doc["discovered"].end();++it) { std::string research; *it >> research; _discovered.push_back(rule->getResearchProject(research)); } if (const YAML::Node *pName = doc.FindValue("battleGame")) { _battleGame = new SavedBattleGame(); _battleGame->load(*pName, rule, this); } fin.close(); }
/** * Initializes all the elements in the Geoscape Craft window. * @param game Pointer to the core game. * @param craft Pointer to the craft to display. * @param globe Pointer to the Geoscape globe. * @param waypoint Pointer to the last UFO position (if redirecting the craft). */ GeoscapeCraftState::GeoscapeCraftState(Game *game, Craft *craft, Globe *globe, Waypoint *waypoint) : State(game), _craft(craft), _globe(globe), _waypoint(waypoint) { _screen = false; // Create objects _window = new Window(this, 240, 184, 8, 8, POPUP_BOTH); _btnBase = new TextButton(192, 12, 32, 124); _btnTarget = new TextButton(192, 12, 32, 140); _btnPatrol = new TextButton(192, 12, 32, 156); _btnCancel = new TextButton(192, 12, 32, 172); _txtTitle = new Text(200, 16, 32, 20); _txtStatus = new Text(200, 9, 32, 36); _txtBase = new Text(200, 9, 32, 52); _txtSpeed = new Text(200, 9, 32, 60); _txtMaxSpeed = new Text(200, 9, 32, 68); _txtAltitude = new Text(200, 9, 32, 76); _txtFuel = new Text(200, 9, 32, 84); _txtW1Name = new Text(120, 9, 32, 92); _txtW1Ammo = new Text(60, 9, 164, 92); _txtW2Name = new Text(120, 9, 32, 100); _txtW2Ammo = new Text(60, 9, 164, 100); _txtRedirect = new Text(230, 16, 13, 108); // Set palette _game->setPalette(_game->getResourcePack()->getPalette("BACKPALS.DAT")->getColors(Palette::blockOffset(4)), Palette::backPos, 16); add(_window); add(_btnBase); add(_btnTarget); add(_btnPatrol); add(_btnCancel); add(_txtTitle); add(_txtStatus); add(_txtBase); add(_txtSpeed); add(_txtMaxSpeed); add(_txtAltitude); add(_txtFuel); add(_txtW1Name); add(_txtW1Ammo); add(_txtW2Name); add(_txtW2Ammo); add(_txtRedirect); // Set up objects _window->setColor(Palette::blockOffset(15)-1); _window->setBackground(_game->getResourcePack()->getSurface("BACK12.SCR")); _btnBase->setColor(Palette::blockOffset(8)+5); _btnBase->setText(_game->getLanguage()->getString("STR_RETURN_TO_BASE")); _btnBase->onMouseClick((ActionHandler)&GeoscapeCraftState::btnBaseClick); _btnTarget->setColor(Palette::blockOffset(8)+5); _btnTarget->setText(_game->getLanguage()->getString("STR_SELECT_NEW_TARGET")); _btnTarget->onMouseClick((ActionHandler)&GeoscapeCraftState::btnTargetClick); _btnPatrol->setColor(Palette::blockOffset(8)+5); _btnPatrol->setText(_game->getLanguage()->getString("STR_PATROL")); _btnPatrol->onMouseClick((ActionHandler)&GeoscapeCraftState::btnPatrolClick); _btnCancel->setColor(Palette::blockOffset(8)+5); _btnCancel->setText(_game->getLanguage()->getString("STR_CANCEL_UC")); _btnCancel->onMouseClick((ActionHandler)&GeoscapeCraftState::btnCancelClick); _txtTitle->setColor(Palette::blockOffset(15)-1); _txtTitle->setBig(); _txtTitle->setText(_craft->getName(_game->getLanguage())); _txtStatus->setColor(Palette::blockOffset(15)-1); _txtStatus->setSecondaryColor(Palette::blockOffset(8)+10); std::wstringstream ss; ss << _game->getLanguage()->getString("STR_STATUS_") << L'\x01'; if (_waypoint != 0) { ss << _game->getLanguage()->getString("STR_INTERCEPTING_UFO") << _waypoint->getId(); } else if (_craft->getLowFuel()) { ss << _game->getLanguage()->getString("STR_LOW_FUEL_RETURNING_TO_BASE"); } else if (_craft->getDestination() == 0) { ss << _game->getLanguage()->getString("STR_PATROLLING"); } else if (_craft->getDestination() == (Target*)_craft->getBase()) { ss << _game->getLanguage()->getString("STR_RETURNING_TO_BASE"); } else { Ufo *u = dynamic_cast<Ufo*>(_craft->getDestination()); if (u != 0) { if (!u->isCrashed()) { ss << _game->getLanguage()->getString("STR_INTERCEPTING_UFO") << u->getId(); } else { ss << _game->getLanguage()->getString("STR_DESTINATION_UC") << u->getName(_game->getLanguage()); } } else { ss << _game->getLanguage()->getString("STR_DESTINATION_UC") << _craft->getDestination()->getName(_game->getLanguage()); } } _txtStatus->setText(ss.str()); _txtBase->setColor(Palette::blockOffset(15)-1); _txtBase->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss2; ss2 << _game->getLanguage()->getString("STR_BASE_UC_") << L'\x01' << _craft->getBase()->getName(); _txtBase->setText(ss2.str()); _txtSpeed->setColor(Palette::blockOffset(15)-1); _txtSpeed->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss3; ss3 << _game->getLanguage()->getString("STR_SPEED_") << L'\x01' << _craft->getSpeed(); _txtSpeed->setText(ss3.str()); _txtMaxSpeed->setColor(Palette::blockOffset(15)-1); _txtMaxSpeed->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss4; ss4 << _game->getLanguage()->getString("STR_MAXIMUM_SPEED_UC") << L'\x01' << _craft->getRules()->getMaxSpeed(); _txtMaxSpeed->setText(ss4.str()); _txtAltitude->setColor(Palette::blockOffset(15)-1); _txtAltitude->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss5; ss5 << _game->getLanguage()->getString("STR_ALTITUDE_") << L'\x01' << _game->getLanguage()->getString(_craft->getAltitude()); _txtAltitude->setText(ss5.str()); _txtFuel->setColor(Palette::blockOffset(15)-1); _txtFuel->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss6; ss6 << _game->getLanguage()->getString("STR_FUEL") << L'\x01' << _craft->getFuelPercentage() << "%"; _txtFuel->setText(ss6.str()); _txtW1Name->setColor(Palette::blockOffset(15)-1); _txtW1Name->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss7; ss7 << _game->getLanguage()->getString("STR_WEAPON_1") << L'\x01'; _txtW1Ammo->setColor(Palette::blockOffset(15)-1); _txtW1Ammo->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss8; ss8 << _game->getLanguage()->getString("STR_ROUNDS_") << L'\x01'; if (_craft->getRules()->getWeapons() > 0 && _craft->getWeapons()->at(0) != 0) { CraftWeapon *w1 = _craft->getWeapons()->at(0); ss7 << _game->getLanguage()->getString(w1->getRules()->getType()); _txtW1Name->setText(ss7.str()); ss8 << w1->getAmmo(); _txtW1Ammo->setText(ss8.str()); } else { ss7 << _game->getLanguage()->getString("STR_NONE_UC"); _txtW1Name->setText(ss7.str()); _txtW1Ammo->setVisible(false); } _txtW2Name->setColor(Palette::blockOffset(15)-1); _txtW2Name->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss9; ss9 << _game->getLanguage()->getString("STR_WEAPON_2") << L'\x01'; _txtW2Ammo->setColor(Palette::blockOffset(15)-1); _txtW2Ammo->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss10; ss10 << _game->getLanguage()->getString("STR_ROUNDS_") << L'\x01'; if (_craft->getRules()->getWeapons() > 1 && _craft->getWeapons()->at(1) != 0) { CraftWeapon *w2 = _craft->getWeapons()->at(1); ss9 << _game->getLanguage()->getString(w2->getRules()->getType()); _txtW2Name->setText(ss9.str()); ss10 << w2->getAmmo(); _txtW2Ammo->setText(ss10.str()); } else { ss9 << _game->getLanguage()->getString("STR_NONE_UC"); _txtW2Name->setText(ss9.str()); _txtW2Ammo->setVisible(false); } _txtRedirect->setColor(Palette::blockOffset(15)-1); _txtRedirect->setBig(); _txtRedirect->setAlign(ALIGN_CENTER); _txtRedirect->setText(_game->getLanguage()->getString("STR_REDIRECT_CRAFT")); if (_waypoint == 0) { _txtRedirect->setVisible(false); } else { _btnCancel->setText(_game->getLanguage()->getString("STR_GO_TO_LAST_KNOWN_UFO_POSITION")); } if (_craft->getLowFuel()) { _btnBase->setVisible(false); _btnTarget->setVisible(false); _btnPatrol->setVisible(false); } }
/** * Starts the battle. * @param action Pointer to an action. */ void NewBattleState::btnOkClick(Action *) { save(); if (_missionTypes[_cbxMission->getSelected()] != "STR_BASE_DEFENSE" && _craft->getNumSoldiers() == 0 && _craft->getNumVehicles() == 0) { return; } SavedBattleGame *bgame = new SavedBattleGame(); _game->getSavedGame()->setBattleGame(bgame); bgame->setMissionType(_missionTypes[_cbxMission->getSelected()]); BattlescapeGenerator bgen = BattlescapeGenerator(_game); Base *base = 0; bgen.setTerrain(_game->getMod()->getTerrain(_terrainTypes[_cbxTerrain->getSelected()])); // base defense if (_missionTypes[_cbxMission->getSelected()] == "STR_BASE_DEFENSE") { base = _craft->getBase(); bgen.setBase(base); _craft = 0; } // alien base else if (_game->getMod()->getDeployment(bgame->getMissionType())->isAlienBase()) { AlienBase *b = new AlienBase(_game->getMod()->getDeployment(bgame->getMissionType())); b->setId(1); b->setAlienRace(_alienRaces[_cbxAlienRace->getSelected()]); _craft->setDestination(b); bgen.setAlienBase(b); _game->getSavedGame()->getAlienBases()->push_back(b); } // ufo assault else if (_craft && _game->getMod()->getUfo(_missionTypes[_cbxMission->getSelected()])) { Ufo *u = new Ufo(_game->getMod()->getUfo(_missionTypes[_cbxMission->getSelected()])); u->setId(1); _craft->setDestination(u); bgen.setUfo(u); // either ground assault or ufo crash if (RNG::generate(0,1) == 1) { u->setStatus(Ufo::LANDED); bgame->setMissionType("STR_UFO_GROUND_ASSAULT"); } else { u->setStatus(Ufo::CRASHED); bgame->setMissionType("STR_UFO_CRASH_RECOVERY"); } _game->getSavedGame()->getUfos()->push_back(u); } // mission site else { const AlienDeployment *deployment = _game->getMod()->getDeployment(bgame->getMissionType()); const RuleAlienMission *mission = _game->getMod()->getAlienMission(_game->getMod()->getAlienMissionList().front()); // doesn't matter MissionSite *m = new MissionSite(mission, deployment); m->setId(1); m->setAlienRace(_alienRaces[_cbxAlienRace->getSelected()]); _craft->setDestination(m); bgen.setMissionSite(m); _game->getSavedGame()->getMissionSites()->push_back(m); } if (_craft) { _craft->setSpeed(0); bgen.setCraft(_craft); } _game->getSavedGame()->setDifficulty((GameDifficulty)_cbxDifficulty->getSelected()); bgen.setWorldShade(_slrDarkness->getValue()); bgen.setAlienRace(_alienRaces[_cbxAlienRace->getSelected()]); bgen.setAlienItemlevel(_slrAlienTech->getValue()); bgame->setDepth(_slrDepth->getValue()); bgen.run(); _game->popState(); _game->popState(); _game->pushState(new BriefingState(_craft, base)); _craft = 0; }
/** * Initializes all the elements in the Geoscape Craft window. * @param game Pointer to the core game. * @param craft Pointer to the craft to display. * @param globe Pointer to the Geoscape globe. * @param waypoint Pointer to the last UFO position (if redirecting the craft). */ GeoscapeCraftState::GeoscapeCraftState(Game *game, Craft *craft, Globe *globe, Waypoint *waypoint) : State(game), _craft(craft), _globe(globe), _waypoint(waypoint) { _screen = false; // Create objects _window = new Window(this, 240, 184, 8, 8, POPUP_BOTH); _btnBase = new TextButton(192, 12, 32, 124); _btnTarget = new TextButton(192, 12, 32, 140); _btnPatrol = new TextButton(192, 12, 32, 156); _btnCancel = new TextButton(192, 12, 32, 172); _txtTitle = new Text(200, 17, 32, 20); _txtStatus = new Text(210, 17, 32, 36); _txtBase = new Text(200, 9, 32, 52); _txtSpeed = new Text(200, 9, 32, 60); _txtMaxSpeed = new Text(200, 9, 32, 68); _txtAltitude = new Text(200, 9, 32, 76); _txtFuel = new Text(120, 9, 32, 84); _txtDamage = new Text(75, 9, 164, 84); _txtW1Name = new Text(120, 9, 32, 92); _txtW1Ammo = new Text(80, 9, 164, 92); _txtW2Name = new Text(120, 9, 32, 100); _txtW2Ammo = new Text(80, 9, 164, 100); _txtRedirect = new Text(230, 17, 13, 108); _txtSoldier = new Text(60, 9, 164, 68); _txtHWP = new Text(80, 9, 164, 76); // Set palette _game->setPalette(_game->getResourcePack()->getPalette("BACKPALS.DAT")->getColors(Palette::blockOffset(4)), Palette::backPos, 16); add(_window); add(_btnBase); add(_btnTarget); add(_btnPatrol); add(_btnCancel); add(_txtTitle); add(_txtStatus); add(_txtBase); add(_txtSpeed); add(_txtMaxSpeed); add(_txtAltitude); add(_txtFuel); add(_txtDamage); add(_txtW1Name); add(_txtW1Ammo); add(_txtW2Name); add(_txtW2Ammo); add(_txtRedirect); add(_txtSoldier); add(_txtHWP); centerAllSurfaces(); // Set up objects _window->setColor(Palette::blockOffset(15)-1); _window->setBackground(_game->getResourcePack()->getSurface("BACK12.SCR")); _btnBase->setColor(Palette::blockOffset(8)+5); _btnBase->setText(tr("STR_RETURN_TO_BASE")); _btnBase->onMouseClick((ActionHandler)&GeoscapeCraftState::btnBaseClick); _btnTarget->setColor(Palette::blockOffset(8)+5); _btnTarget->setText(tr("STR_SELECT_NEW_TARGET")); _btnTarget->onMouseClick((ActionHandler)&GeoscapeCraftState::btnTargetClick); _btnPatrol->setColor(Palette::blockOffset(8)+5); _btnPatrol->setText(tr("STR_PATROL")); _btnPatrol->onMouseClick((ActionHandler)&GeoscapeCraftState::btnPatrolClick); _btnCancel->setColor(Palette::blockOffset(8)+5); _btnCancel->setText(tr("STR_CANCEL_UC")); _btnCancel->onMouseClick((ActionHandler)&GeoscapeCraftState::btnCancelClick); _btnCancel->onKeyboardPress((ActionHandler)&GeoscapeCraftState::btnCancelClick, (SDLKey)Options::getInt("keyCancel")); _txtTitle->setColor(Palette::blockOffset(15)-1); _txtTitle->setBig(); _txtTitle->setText(_craft->getName(_game->getLanguage())); _txtStatus->setColor(Palette::blockOffset(15)-1); _txtStatus->setSecondaryColor(Palette::blockOffset(8)+10); _txtStatus->setWordWrap(true); std::wstring status; if (_waypoint != 0) { status = tr("STR_INTERCEPTING_UFO").arg(_waypoint->getId()); } else if (_craft->getLowFuel()) { status = tr("STR_LOW_FUEL_RETURNING_TO_BASE"); } else if (_craft->getDestination() == 0) { status = tr("STR_PATROLLING"); } else if (_craft->getDestination() == (Target*)_craft->getBase()) { status = tr("STR_RETURNING_TO_BASE"); } else { Ufo *u = dynamic_cast<Ufo*>(_craft->getDestination()); if (u != 0) { if (_craft->isInDogfight()) { status = tr("STR_TAILING_UFO"); } else if (u->getStatus() == Ufo::FLYING) { status = tr("STR_INTERCEPTING_UFO").arg(u->getId()); } else { status = tr("STR_DESTINATION_UC_").arg(u->getName(_game->getLanguage())); } } else { status = tr("STR_DESTINATION_UC_").arg(_craft->getDestination()->getName(_game->getLanguage())); } } _txtStatus->setText(tr("STR_STATUS_").arg(status)); _txtBase->setColor(Palette::blockOffset(15)-1); _txtBase->setSecondaryColor(Palette::blockOffset(8)+5); _txtBase->setText(tr("STR_BASE_UC").arg(_craft->getBase()->getName())); _txtSpeed->setColor(Palette::blockOffset(15)-1); _txtSpeed->setSecondaryColor(Palette::blockOffset(8)+5); _txtSpeed->setText(tr("STR_SPEED_").arg(Text::formatNumber(_craft->getSpeed()))); _txtMaxSpeed->setColor(Palette::blockOffset(15)-1); _txtMaxSpeed->setSecondaryColor(Palette::blockOffset(8)+5); _txtMaxSpeed->setText(tr("STR_MAXIMUM_SPEED_UC").arg(Text::formatNumber(_craft->getRules()->getMaxSpeed()))); _txtAltitude->setColor(Palette::blockOffset(15)-1); _txtAltitude->setSecondaryColor(Palette::blockOffset(8)+5); std::string altitude = _craft->getAltitude() == "STR_GROUND" ? "STR_GROUNDED" : _craft->getAltitude(); _txtAltitude->setText(tr("STR_ALTITUDE_").arg(tr(altitude))); _txtFuel->setColor(Palette::blockOffset(15)-1); _txtFuel->setSecondaryColor(Palette::blockOffset(8)+5); _txtFuel->setText(tr("STR_FUEL").arg(Text::formatPercentage(_craft->getFuelPercentage()))); _txtDamage->setColor(Palette::blockOffset(15)-1); _txtDamage->setSecondaryColor(Palette::blockOffset(8)+5); _txtDamage->setText(tr("STR_DAMAGE_UC_").arg(Text::formatPercentage(_craft->getDamagePercentage()))); _txtW1Name->setColor(Palette::blockOffset(15)-1); _txtW1Name->setSecondaryColor(Palette::blockOffset(8)+5); _txtW1Ammo->setColor(Palette::blockOffset(15)-1); _txtW1Ammo->setSecondaryColor(Palette::blockOffset(8)+5); if (_craft->getRules()->getWeapons() > 0 && _craft->getWeapons()->at(0) != 0) { CraftWeapon *w1 = _craft->getWeapons()->at(0); _txtW1Name->setText(tr("STR_WEAPON_ONE").arg(tr(w1->getRules()->getType()))); _txtW1Ammo->setText(tr("STR_ROUNDS_").arg(w1->getAmmo())); } else { _txtW1Name->setText(tr("STR_WEAPON_ONE").arg(tr("STR_NONE_UC"))); _txtW1Ammo->setVisible(false); } _txtW2Name->setColor(Palette::blockOffset(15)-1); _txtW2Name->setSecondaryColor(Palette::blockOffset(8)+5); _txtW2Ammo->setColor(Palette::blockOffset(15)-1); _txtW2Ammo->setSecondaryColor(Palette::blockOffset(8)+5); if (_craft->getRules()->getWeapons() > 1 && _craft->getWeapons()->at(1) != 0) { CraftWeapon *w2 = _craft->getWeapons()->at(1); _txtW2Name->setText(tr("STR_WEAPON_TWO").arg(tr(w2->getRules()->getType()))); _txtW2Ammo->setText(tr("STR_ROUNDS_").arg(w2->getAmmo())); } else { _txtW2Name->setText(tr("STR_WEAPON_TWO").arg(tr("STR_NONE_UC"))); _txtW2Ammo->setVisible(false); } _txtRedirect->setColor(Palette::blockOffset(15)-1); _txtRedirect->setBig(); _txtRedirect->setAlign(ALIGN_CENTER); _txtRedirect->setText(tr("STR_REDIRECT_CRAFT")); _txtSoldier->setColor(Palette::blockOffset(15)-1); _txtSoldier->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss11; ss11 << tr("STR_SOLDIERS_UC") << ">" << L'\x01' << _craft->getNumSoldiers(); _txtSoldier->setText(ss11.str()); _txtHWP->setColor(Palette::blockOffset(15)-1); _txtHWP->setSecondaryColor(Palette::blockOffset(8)+5); std::wstringstream ss12; ss12 << tr("STR_HWPS") << ">" << L'\x01' << _craft->getNumVehicles(); _txtHWP->setText(ss12.str()); if (_waypoint == 0) { _txtRedirect->setVisible(false); } else { _btnCancel->setText(tr("STR_GO_TO_LAST_KNOWN_UFO_POSITION")); } if (_craft->getLowFuel()) { _btnBase->setVisible(false); _btnTarget->setVisible(false); _btnPatrol->setVisible(false); } if (_craft->getRules()->getSoldiers() == 0) _txtSoldier->setVisible(false); if (_craft->getRules()->getVehicles() == 0) _txtHWP->setVisible(false); }
/** * Initializes all the elements in the Geoscape Craft window. * @param game Pointer to the core game. * @param craft Pointer to the craft to display. * @param globe Pointer to the Geoscape globe. * @param waypoint Pointer to the last UFO position (if redirecting the craft). */ GeoscapeCraftState::GeoscapeCraftState(Craft *craft, Globe *globe, Waypoint *waypoint) : _craft(craft), _globe(globe), _waypoint(waypoint) { _screen = false; // Create objects _window = new Window(this, 240, 184, 8, 8, POPUP_BOTH); _btnBase = new TextButton(212, 12, 22, 124); _btnTarget = new TextButton(212, 12, 22, 140); _btnPatrol = new TextButton(212, 12, 22, 156); _btnCancel = new TextButton(212, 12, 22, 172); _txtTitle = new Text(210, 17, 32, 20); _txtStatus = new Text(210, 17, 32, 36); _txtBase = new Text(210, 9, 32, 52); _txtSpeed = new Text(210, 9, 32, 60); _txtMaxSpeed = new Text(210, 9, 32, 68); _txtAltitude = new Text(210, 9, 32, 76); _txtFuel = new Text(130, 9, 32, 84); _txtDamage = new Text(80, 9, 164, 84); _txtW1Name = new Text(130, 9, 32, 92); _txtW1Ammo = new Text(80, 9, 164, 92); _txtW2Name = new Text(130, 9, 32, 100); _txtW2Ammo = new Text(80, 9, 164, 100); _txtRedirect = new Text(230, 17, 13, 108); _txtSoldier = new Text(60, 9, 164, 68); _txtHWP = new Text(80, 9, 164, 76); // Set palette setInterface("geoCraft"); add(_window, "window", "geoCraft"); add(_btnBase, "button", "geoCraft"); add(_btnTarget, "button", "geoCraft"); add(_btnPatrol, "button", "geoCraft"); add(_btnCancel, "button", "geoCraft"); add(_txtTitle, "text1", "geoCraft"); add(_txtStatus, "text1", "geoCraft"); add(_txtBase, "text3", "geoCraft"); add(_txtSpeed, "text3", "geoCraft"); add(_txtMaxSpeed, "text3", "geoCraft"); add(_txtAltitude, "text3", "geoCraft"); add(_txtFuel, "text3", "geoCraft"); add(_txtDamage, "text3", "geoCraft"); add(_txtW1Name, "text3", "geoCraft"); add(_txtW1Ammo, "text3", "geoCraft"); add(_txtW2Name, "text3", "geoCraft"); add(_txtW2Ammo, "text3", "geoCraft"); add(_txtRedirect, "text3", "geoCraft"); add(_txtSoldier, "text3", "geoCraft"); add(_txtHWP, "text3", "geoCraft"); centerAllSurfaces(); // Set up objects _window->setBackground(_game->getMod()->getSurface("BACK12.SCR")); _btnBase->setText(tr("STR_RETURN_TO_BASE")); _btnBase->onMouseClick((ActionHandler)&GeoscapeCraftState::btnBaseClick); _btnTarget->setText(tr("STR_SELECT_NEW_TARGET")); _btnTarget->onMouseClick((ActionHandler)&GeoscapeCraftState::btnTargetClick); _btnPatrol->setText(tr("STR_PATROL")); _btnPatrol->onMouseClick((ActionHandler)&GeoscapeCraftState::btnPatrolClick); _btnCancel->setText(tr("STR_CANCEL_UC")); _btnCancel->onMouseClick((ActionHandler)&GeoscapeCraftState::btnCancelClick); _btnCancel->onKeyboardPress((ActionHandler)&GeoscapeCraftState::btnCancelClick, Options::keyCancel); _txtTitle->setBig(); _txtTitle->setText(_craft->getName(_game->getLanguage())); _txtStatus->setWordWrap(true); std::wstring status; if (_waypoint != 0) { status = tr("STR_INTERCEPTING_UFO").arg(_waypoint->getId()); } else if (_craft->getLowFuel()) { status = tr("STR_LOW_FUEL_RETURNING_TO_BASE"); } else if (_craft->getMissionComplete()) { status = tr("STR_MISSION_COMPLETE_RETURNING_TO_BASE"); } else if (_craft->getDestination() == 0) { status = tr("STR_PATROLLING"); } else if (_craft->getDestination() == (Target*)_craft->getBase()) { status = tr("STR_RETURNING_TO_BASE"); } else { Ufo *u = dynamic_cast<Ufo*>(_craft->getDestination()); if (u != 0) { if (_craft->isInDogfight()) { status = tr("STR_TAILING_UFO"); } else if (u->getStatus() == Ufo::FLYING) { status = tr("STR_INTERCEPTING_UFO").arg(u->getId()); } else { status = tr("STR_DESTINATION_UC_").arg(u->getName(_game->getLanguage())); } } else { status = tr("STR_DESTINATION_UC_").arg(_craft->getDestination()->getName(_game->getLanguage())); } } _txtStatus->setText(tr("STR_STATUS_").arg(status)); _txtBase->setText(tr("STR_BASE_UC").arg(_craft->getBase()->getName())); int speed = _craft->getSpeed(); if (_craft->isInDogfight()) { Ufo *ufo = dynamic_cast<Ufo*>(_craft->getDestination()); if (ufo) { speed = ufo->getSpeed(); } } _txtSpeed->setText(tr("STR_SPEED_").arg(Text::formatNumber(speed))); _txtMaxSpeed->setText(tr("STR_MAXIMUM_SPEED_UC").arg(Text::formatNumber(_craft->getRules()->getMaxSpeed()))); std::string altitude = _craft->getAltitude() == "STR_GROUND" ? "STR_GROUNDED" : _craft->getAltitude(); if (_craft->getRules()->isWaterOnly() && !_globe->insideLand(_craft->getLongitude(), _craft->getLatitude())) { altitude = "STR_AIRBORNE"; } _txtAltitude->setText(tr("STR_ALTITUDE_").arg(tr(altitude))); _txtFuel->setText(tr("STR_FUEL").arg(Text::formatPercentage(_craft->getFuelPercentage()))); _txtDamage->setText(tr("STR_DAMAGE_UC_").arg(Text::formatPercentage(_craft->getDamagePercentage()))); if (_craft->getRules()->getWeapons() > 0 && _craft->getWeapons()->at(0) != 0) { CraftWeapon *w1 = _craft->getWeapons()->at(0); _txtW1Name->setText(tr("STR_WEAPON_ONE").arg(tr(w1->getRules()->getType()))); _txtW1Ammo->setText(tr("STR_ROUNDS_").arg(w1->getAmmo())); } else { _txtW1Name->setText(tr("STR_WEAPON_ONE").arg(tr("STR_NONE_UC"))); _txtW1Ammo->setVisible(false); } if (_craft->getRules()->getWeapons() > 1 && _craft->getWeapons()->at(1) != 0) { CraftWeapon *w2 = _craft->getWeapons()->at(1); _txtW2Name->setText(tr("STR_WEAPON_TWO").arg(tr(w2->getRules()->getType()))); _txtW2Ammo->setText(tr("STR_ROUNDS_").arg(w2->getAmmo())); } else { _txtW2Name->setText(tr("STR_WEAPON_TWO").arg(tr("STR_NONE_UC"))); _txtW2Ammo->setVisible(false); } _txtRedirect->setBig(); _txtRedirect->setAlign(ALIGN_CENTER); _txtRedirect->setText(tr("STR_REDIRECT_CRAFT")); std::wostringstream ss11; ss11 << tr("STR_SOLDIERS_UC") << ">" << L'\x01' << _craft->getNumSoldiers(); _txtSoldier->setText(ss11.str()); std::wostringstream ss12; ss12 << tr("STR_HWPS") << ">" << L'\x01' << _craft->getNumVehicles(); _txtHWP->setText(ss12.str()); if (_waypoint == 0) { _txtRedirect->setVisible(false); } else { _btnCancel->setText(tr("STR_GO_TO_LAST_KNOWN_UFO_POSITION")); } if (_craft->getLowFuel() || _craft->getMissionComplete()) { _btnBase->setVisible(false); _btnTarget->setVisible(false); _btnPatrol->setVisible(false); } if (_craft->getRules()->getSoldiers() == 0) _txtSoldier->setVisible(false); if (_craft->getRules()->getVehicles() == 0) _txtHWP->setVisible(false); }
/** * 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(); const size_t curWaypoint = ufo.getTrajectoryPoint(); const size_t nextWaypoint = curWaypoint + 1; const UfoTrajectory &trajectory = ufo.getTrajectory(); int waveNumber = _nextWave - 1; if (waveNumber < 0) { waveNumber = _rule.getWaveCount() - 1; } const MissionWave &wave = _rule.getWave(waveNumber); if (nextWaypoint >= trajectory.getWaypointCount()) { ufo.setDetected(false); ufo.setStatus(Ufo::DESTROYED); return; } ufo.setAltitude(trajectory.getAltitude(nextWaypoint)); ufo.setTrajectoryPoint(nextWaypoint); const RuleRegion ®ionRules = *rules.getRegion(_region); std::pair<double, double> pos = getWaypoint(trajectory, nextWaypoint, globe, regionRules); Waypoint *wp = new Waypoint(); wp->setLongitude(pos.first); wp->setLatitude(pos.second); ufo.setDestination(wp); if (ufo.getAltitude() != "STR_GROUND") { if (ufo.getLandId() != 0) { ufo.setLandId(0); } // Set next waypoint. ufo.setSpeed((int)(ufo.getRules()->getMaxSpeed() * trajectory.getSpeedPercentage(nextWaypoint))); } else { // UFO landed. if (wave.objective && trajectory.getZone(curWaypoint) == (size_t)(_rule.getSpawnZone())) { // Remove UFO, replace with MissionSite. addScore(ufo.getLongitude(), ufo.getLatitude(), game); ufo.setStatus(Ufo::DESTROYED); MissionArea area = regionRules.getMissionPoint(trajectory.getZone(curWaypoint), &ufo); Texture *texture = rules.getGlobe()->getTexture(area.texture); AlienDeployment *deployment = rules.getDeployment(texture->getDeployment()); MissionSite *missionSite = new MissionSite(&_rule, deployment); missionSite->setLongitude(ufo.getLongitude()); missionSite->setLatitude(ufo.getLatitude()); missionSite->setId(game.getId(deployment->getMarkerName())); missionSite->setSecondsRemaining(RNG::generate(deployment->getDurationMin(), deployment->getDurationMax()) * 3600); missionSite->setAlienRace(_race); missionSite->setTexture(area.texture); missionSite->setCity(area.name); game.getMissionSites()->push_back(missionSite); 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(missionSite); t = ufo.getFollowers()->begin(); } else { ++t; } } } else if (trajectory.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(trajectory.groundTimer()*5); if (ufo.getDetected() && ufo.getLandId() == 0) { ufo.setLandId(engine.getSavedGame()->getId("STR_LANDING_SITE")); } } } }
/** * This function will spawn a UFO according the the mission rules. * Some code is duplicated between cases, that's ok for now. It's on different * code paths and the function is MUCH easier to read written this way. * @param game The saved game information. * @param ruleset The ruleset. * @param globe The globe, for land checks. * @param wave The wave for the desired UFO. * @param trajectory The rule for the desired trajectory. * @return Pointer to the spawned UFO. If the mission does not desire to spawn a UFO, 0 is returned. */ Ufo *AlienMission::spawnUfo(const SavedGame &game, const Ruleset &ruleset, const Globe &globe, const MissionWave &wave, const UfoTrajectory &trajectory) { RuleUfo &ufoRule = *ruleset.getUfo(wave.ufoType); if (_rule.getObjective() == OBJECTIVE_RETALIATION) { const RuleRegion ®ionRules = *ruleset.getRegion(_region); std::vector<Base *>::const_iterator found = std::find_if (game.getBases()->begin(), game.getBases()->end(), FindMarkedXCOMBase(regionRules)); if (found != game.getBases()->end()) { // Spawn a battleship straight for the XCOM base. const RuleUfo &battleshipRule = *ruleset.getUfo(_rule.getSpawnUfo()); const UfoTrajectory &assaultTrajectory = *ruleset.getUfoTrajectory("__RETALIATION_ASSAULT_RUN"); Ufo *ufo = new Ufo(&battleshipRule); ufo->setMissionInfo(this, &assaultTrajectory); std::pair<double, double> pos; if (trajectory.getAltitude(0) == "STR_GROUND") { pos = getLandPoint(globe, regionRules, trajectory.getZone(0)); } else { pos = regionRules.getRandomPoint(trajectory.getZone(0)); } ufo->setAltitude(assaultTrajectory.getAltitude(0)); ufo->setSpeed(assaultTrajectory.getSpeedPercentage(0) * battleshipRule.getMaxSpeed()); ufo->setLongitude(pos.first); ufo->setLatitude(pos.second); Waypoint *wp = new Waypoint(); wp->setLongitude((*found)->getLongitude()); wp->setLatitude((*found)->getLatitude()); ufo->setDestination(wp); return ufo; } } else if (_rule.getObjective() == OBJECTIVE_SUPPLY) { if (wave.objective && !_base) { // No base to supply! return 0; } // Our destination is always an alien base. Ufo *ufo = new Ufo(&ufoRule); ufo->setMissionInfo(this, &trajectory); const RuleRegion ®ionRules = *ruleset.getRegion(_region); std::pair<double, double> pos; if (trajectory.getAltitude(0) == "STR_GROUND") { pos = getLandPoint(globe, regionRules, trajectory.getZone(0)); } else { pos = regionRules.getRandomPoint(trajectory.getZone(0)); } ufo->setAltitude(trajectory.getAltitude(0)); ufo->setSpeed(trajectory.getSpeedPercentage(0) * ufoRule.getMaxSpeed()); ufo->setLongitude(pos.first); ufo->setLatitude(pos.second); Waypoint *wp = new Waypoint(); if (trajectory.getAltitude(1) == "STR_GROUND") { if (wave.objective) { // Supply ships on supply missions land on bases, ignore trajectory zone. pos.first = _base->getLongitude(); pos.second = _base->getLatitude(); } else { // Other ships can land where they want. pos = getLandPoint(globe, regionRules, trajectory.getZone(1)); } } else { pos = regionRules.getRandomPoint(trajectory.getZone(1)); } wp->setLongitude(pos.first); wp->setLatitude(pos.second); ufo->setDestination(wp); return ufo; } // Spawn according to sequence. Ufo *ufo = new Ufo(&ufoRule); ufo->setMissionInfo(this, &trajectory); const RuleRegion ®ionRules = *ruleset.getRegion(_region); std::pair<double, double> pos = getWaypoint(trajectory, 0, globe, regionRules); ufo->setAltitude(trajectory.getAltitude(0)); if (trajectory.getAltitude(0) == "STR_GROUND") { ufo->setSecondsRemaining(trajectory.groundTimer()*5); } ufo->setSpeed(trajectory.getSpeedPercentage(0) * ufoRule.getMaxSpeed()); ufo->setLongitude(pos.first); ufo->setLatitude(pos.second); Waypoint *wp = new Waypoint(); pos = getWaypoint(trajectory, 1, globe, regionRules); wp->setLongitude(pos.first); wp->setLatitude(pos.second); ufo->setDestination(wp); return ufo; }
/** * 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; } }
/** * Loads the UFO from a YAML file. * @param node YAML node. * @param mod The game mod. Use to access the trajectory rules. * @param game The game data. Used to find the UFO's mission. */ void Ufo::load(const YAML::Node &node, const Mod *mod, SavedGame *game, Ufo *escorting) { MovingTarget::load(node); _id = node["id"].as<int>(_id); _escorting = escorting; _escortId = node["escortId"].as<int>(_escortId); _escortingId = node["escortingId"].as<int>(_escortingId); _crashId = node["crashId"].as<int>(_crashId); _landId = node["landId"].as<int>(_landId); _damage = node["damage"].as<int>(_damage); _shield = node["shield"].as<int>(_shield); _shieldRechargeHandle = node["shieldRechargeHandle"].as<int>(_shieldRechargeHandle); _altitude = node["altitude"].as<std::string>(_altitude); _direction = node["direction"].as<std::string>(_direction); _detected = node["detected"].as<bool>(_detected); _hyperDetected = node["hyperDetected"].as<bool>(_hyperDetected); _secondsRemaining = node["secondsRemaining"].as<size_t>(_secondsRemaining); _inBattlescape = node["inBattlescape"].as<bool>(_inBattlescape); double lon = _lon; double lat = _lat; if (const YAML::Node &dest = node["dest"]) { lon = dest["lon"].as<double>(); lat = dest["lat"].as<double>(); } _dest = new Waypoint(); _dest->setLongitude(lon); _dest->setLatitude(lat); if (const YAML::Node &status = node["status"]) { _status = (UfoStatus)status.as<int>(); } else { if (_damage >= _stats.damageMax) { _status = DESTROYED; } else if (_damage >= _stats.damageMax / 2) { _status = CRASHED; } else if (_altitude == "STR_GROUND") { _status = LANDED; } else { _status = FLYING; } } if (game->getMonthsPassed() != -1 && node["mission"]) { int missionID = node["mission"].as<int>(); std::vector<AlienMission *>::const_iterator found = std::find_if (game->getAlienMissions().begin(), game->getAlienMissions().end(), matchMissionID(missionID)); if (found == game->getAlienMissions().end()) { // Corrupt save file. throw Exception("Unknown UFO mission, save file is corrupt."); } _mission = *found; _stats += _rules->getRaceBonus(_mission->getRace()); std::string tid = node["trajectory"].as<std::string>(); _trajectory = mod->getUfoTrajectory(tid); if (_trajectory == 0) { // Corrupt save file. throw Exception("Unknown UFO trajectory, save file is corrupt."); } _trajectoryPoint = node["trajectoryPoint"].as<size_t>(_trajectoryPoint); } _fireCountdown = node["fireCountdown"].as<int>(_fireCountdown); _escapeCountdown = node["escapeCountdown"].as<int>(_escapeCountdown); _retreating = node["retreating"].as<bool>(_retreating); for (YAML::const_iterator ii = node["escorts"].begin(); ii != node["escorts"].end(); ++ii) { std::string type = (*ii)["type"].as<std::string>(); if (mod->getUfo(type)) { Ufo *u = new Ufo(mod->getUfo(type), false); u->load(*ii, mod, game, this); _escorts.push_back(u); } /*else { Log(LOG_ERROR) << "Failed to load UFO " << type; }*/ } if (_inBattlescape) setSpeed(0); }
/** * Initializes all the elements in the Briefing screen. * @param game Pointer to the core game. * @param craft Pointer to the craft in the mission. * @param base Pointer to the base in the mission. */ BriefingState::BriefingState(Craft *craft, Base *base) { _screen = true; // Create objects _window = new Window(this, 320, 200, 0, 0); _btnOk = new TextButton(120, 18, 100, 164); _txtTitle = new Text(300, 32, 16, 24); _txtTarget = new Text(300, 17, 16, 40); _txtCraft = new Text(300, 17, 16, 56); _txtBriefing = new Text(274, 64, 16, 72); std::string mission = _game->getSavedGame()->getSavedBattle()->getMissionType(); AlienDeployment *deployment = _game->getRuleset()->getDeployment(mission); Ufo * ufo = 0; if (!deployment && craft) { ufo = dynamic_cast <Ufo*> (craft->getDestination()); if (ufo) // landing site or crash site. { deployment = _game->getRuleset()->getDeployment(ufo->getRules()->getType()); } } std::string title = mission; std::string desc = title + "_BRIEFING"; if (!deployment) // none defined - should never happen, but better safe than sorry i guess. { setPalette("PAL_GEOSCAPE", 0); _musicId = "GMDEFEND"; _window->setBackground(_game->getResourcePack()->getSurface("BACK16.SCR")); } else { BriefingData data = deployment->getBriefingData(); setPalette("PAL_GEOSCAPE", data.palette); _window->setBackground(_game->getResourcePack()->getSurface(data.background)); _txtCraft->setY(56 + data.textOffset); _txtBriefing->setY(72 + data.textOffset); _txtTarget->setVisible(data.showTarget); _txtCraft->setVisible(data.showCraft); _cutsceneId = data.cutscene; _musicId = data.music; if (!data.title.empty()) { title = data.title; } if (!data.desc.empty()) { desc = data.desc; } } add(_window, "window", "briefing"); add(_btnOk, "button", "briefing"); add(_txtTitle, "text", "briefing"); add(_txtTarget, "text", "briefing"); add(_txtCraft, "text", "briefing"); add(_txtBriefing, "text", "briefing"); centerAllSurfaces(); // Set up objects _btnOk->setText(tr("STR_OK")); _btnOk->onMouseClick((ActionHandler)&BriefingState::btnOkClick); _btnOk->onKeyboardPress((ActionHandler)&BriefingState::btnOkClick, Options::keyOk); _btnOk->onKeyboardPress((ActionHandler)&BriefingState::btnOkClick, Options::keyCancel); _txtTitle->setBig(); _txtTarget->setBig(); _txtCraft->setBig(); std::wstring s; if (craft) { if (craft->getDestination()) { _txtTarget->setText(craft->getDestination()->getName(_game->getLanguage())); } s = tr("STR_CRAFT_").arg(craft->getName(_game->getLanguage())); } else if (base) { s = tr("STR_BASE_UC_").arg(base->getName()); } _txtCraft->setText(s); _txtTitle->setText(tr(title)); _txtBriefing->setWordWrap(true); _txtBriefing->setText(tr(desc)); if (mission == "STR_BASE_DEFENSE") { // And make sure the base is unmarked. base->setRetaliationTarget(false); } }
/** * Loads a saved game's contents from a YAML file. * @note Assumes the saved game is blank. * @param filename YAML filename. * @param rule Ruleset for the saved game. */ void SavedGame::load(const std::string &filename, Ruleset *rule) { unsigned int size = 0; std::string s = USER_DIR + filename + ".sav"; std::ifstream fin(s.c_str()); if (!fin) { throw Exception("Failed to load savegame"); } YAML::Parser parser(fin); YAML::Node doc; // Get brief save info parser.GetNextDocument(doc); std::string v; doc["version"] >> v; if (v != "0.2") { throw Exception("Version mismatch"); } _time->load(doc["time"]); // Get full save data parser.GetNextDocument(doc); int a; doc["difficulty"] >> a; _difficulty = (GameDifficulty)a; doc["funds"] >> _funds; size = doc["countries"].size(); for (unsigned int i = 0; i < size; i++) { std::string type; doc["countries"][i]["type"] >> type; Country *c = new Country(rule->getCountry(type), false); c->load(doc["countries"][i]); _countries.push_back(c); } size = doc["regions"].size(); for (unsigned int i = 0; i < size; i++) { std::string type; doc["regions"][i]["type"] >> type; Region *r = new Region(rule->getRegion(type)); r->load(doc["regions"][i]); _regions.push_back(r); } size = doc["ufos"].size(); for (unsigned int i = 0; i < size; i++) { std::string type; doc["ufos"][i]["type"] >> type; Ufo *u = new Ufo(rule->getUfo(type)); u->load(doc["ufos"][i]); _ufos.push_back(u); } doc["craftId"] >> _craftId; size = doc["waypoints"].size(); for (unsigned int i = 0; i < size; i++) { Waypoint *w = new Waypoint(); w->load(doc["waypoints"][i]); _waypoints.push_back(w); } doc["ufoId"] >> _ufoId; doc["waypointId"] >> _waypointId; size = doc["bases"].size(); for (unsigned int i = 0; i < size; i++) { Base *b = new Base(rule); b->load(doc["bases"][i], this); _bases.push_back(b); } if (const YAML::Node *pName = doc.FindValue("battleGame")) { _battleGame = new SavedBattleGame(); _battleGame->load(*pName); } fin.close(); }