From 7471d215db804df08e078cffad181357b71435f4 Mon Sep 17 00:00:00 2001 From: Alayan Date: Wed, 10 Oct 2018 22:50:27 +0200 Subject: [PATCH] Check and remember if a challenge's supertux requirement (esp. time) have been met at a lower difficulty --- src/challenges/challenge_data.cpp | 30 ++++++++++++++----- src/challenges/challenge_data.hpp | 6 ++-- src/challenges/challenge_status.cpp | 15 ++++++---- src/challenges/challenge_status.hpp | 20 +++++++++++++ src/challenges/story_mode_status.cpp | 8 +++++ src/replay/replay_play.hpp | 3 ++ .../dialogs/select_challenge.cpp | 4 +-- 7 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/challenges/challenge_data.cpp b/src/challenges/challenge_data.cpp index f4c434458..d797da5c1 100644 --- a/src/challenges/challenge_data.cpp +++ b/src/challenges/challenge_data.cpp @@ -457,8 +457,12 @@ void ChallengeData::setRace(RaceManager::Difficulty d) const // ---------------------------------------------------------------------------- /** Returns true if this (non-GP) challenge is fulfilled. + * \param check_best : if true, check if the requirement + * for the best difficulty are met at a lower one. + * (requires SuperTux challenges to have a time + รน requirement to make sense) */ -bool ChallengeData::isChallengeFulfilled() const +bool ChallengeData::isChallengeFulfilled(bool check_best) const { // GP's use the grandPrixFinished() function, // so they can't be fulfilled here. @@ -469,15 +473,16 @@ bool ChallengeData::isChallengeFulfilled() const World *world = World::getWorld(); std::string track_name = Track::getCurrentTrack()->getIdent(); - int d = race_manager->getDifficulty(); + int d = (check_best) ? RaceManager::DIFFICULTY_BEST : + race_manager->getDifficulty(); AbstractKart* kart = world->getPlayerKart(0); - if (kart->isEliminated() ) return false; - if (track_name != m_track_id ) return false; - if ((int)world->getNumKarts() < m_default_num_karts[d] ) return false; - if (m_energy[d] > 0 && kart->getEnergy() < m_energy[d] ) return false; - if (m_position[d] > 0 && kart->getPosition() > m_position[d]) return false; + if (kart->isEliminated() ) return false; + if (track_name != m_track_id ) return false; + if (((int)world->getNumKarts() < m_default_num_karts[d]) && !check_best) return false; + if (m_energy[d] > 0 && kart->getEnergy() < m_energy[d] ) return false; + if (m_position[d] > 0 && kart->getPosition() > m_position[d] ) return false; // Follow the leader // ----------------- @@ -501,6 +506,17 @@ bool ChallengeData::isChallengeFulfilled() const // too slow if (m_time[d] > 0.0f && kart->getFinishTime() > m_time[d]) return false; + // too slow + if (m_is_ghost_replay) + { + ReplayPlay::get()->addReplayFile(file_manager + ->getAsset(FileManager::REPLAY, m_replay_files[d]), + true/*custom_replay*/); + const ReplayPlay::ReplayData& rd = ReplayPlay::get()->getCurrentReplayData(); + if (kart->getFinishTime() > rd.m_min_time) + return false; + } + if (m_ai_superpower[d] != RaceManager::SUPERPOWER_NONE && race_manager->getAISuperPower() != m_ai_superpower[d]) { diff --git a/src/challenges/challenge_data.hpp b/src/challenges/challenge_data.hpp index e95f7101b..5e50e4795 100644 --- a/src/challenges/challenge_data.hpp +++ b/src/challenges/challenge_data.hpp @@ -135,7 +135,7 @@ public: void setRace(RaceManager::Difficulty d) const; virtual void check() const; - virtual bool isChallengeFulfilled() const; + virtual bool isChallengeFulfilled(bool check_best=false) const; virtual GPLevel isGPFulfilled() const; void addUnlockTrackReward(const std::string &track_name); void addUnlockModeReward(const std::string &internal_mode_name, @@ -238,10 +238,10 @@ public: // ------------------------------------------------------------------------ /** Returns the maximum time in which the kart must finish. */ - float getTime(RaceManager::Difficulty difficulty) const + float getTimeRequirement(RaceManager::Difficulty difficulty) const { return m_time[difficulty]; - } // getTime + } // getTimeRequirement // ------------------------------------------------------------------------ /** Return the energy that a kart must at least have at the end of a race. */ diff --git a/src/challenges/challenge_status.cpp b/src/challenges/challenge_status.cpp index 1397422ea..d4cc05ca8 100644 --- a/src/challenges/challenge_status.cpp +++ b/src/challenges/challenge_status.cpp @@ -73,7 +73,8 @@ void ChallengeStatus::load(const XMLNode* challenges_node) m_state[3] = CH_SOLVED; } } // if has 'solved' attribute - + if (!node->get("best_while_slower", &m_max_req_in_lower_diff)) + m_max_req_in_lower_diff = false; } // load //----------------------------------------------------------------------------- @@ -106,13 +107,15 @@ void ChallengeStatus::save(UTFWriter& writer) { writer << " <" << m_data->getChallengeId(); if (isSolved(RaceManager::DIFFICULTY_BEST)) - writer << " solved=\"best\"/>\n"; + writer << " solved=\"best\""; else if (isSolved(RaceManager::DIFFICULTY_HARD)) - writer << " solved=\"hard\"/>\n"; + writer << " solved=\"hard\""; else if (isSolved(RaceManager::DIFFICULTY_MEDIUM)) - writer << " solved=\"medium\"/>\n"; + writer << " solved=\"medium\""; else if (isSolved(RaceManager::DIFFICULTY_EASY)) - writer << " solved=\"easy\"/>\n"; + writer << " solved=\"easy\""; else - writer << " solved=\"none\"/>\n"; + writer << " solved=\"none\""; + + writer << " best_while_slower=\"" << m_max_req_in_lower_diff << "\"/>\n"; } // save diff --git a/src/challenges/challenge_status.hpp b/src/challenges/challenge_status.hpp index 2fe5fa549..65eda0678 100644 --- a/src/challenges/challenge_status.hpp +++ b/src/challenges/challenge_status.hpp @@ -60,6 +60,10 @@ private: m_state[RaceManager::DIFFICULTY_COUNT]; + // If the challenge's SuperTux time requirement has been beaten + // in a (s)lower difficulty. + bool m_max_req_in_lower_diff; + /** Pointer to the original challenge data. */ const ChallengeData* m_data; @@ -71,6 +75,7 @@ public: m_state[RaceManager::DIFFICULTY_MEDIUM] = CH_INACTIVE; m_state[RaceManager::DIFFICULTY_HARD] = CH_INACTIVE; m_state[RaceManager::DIFFICULTY_BEST] = CH_INACTIVE; + m_max_req_in_lower_diff = false; } virtual ~ChallengeStatus() {}; void load(const XMLNode* config); @@ -114,6 +119,21 @@ public: /** Returns if this challenge is a grand prix */ bool isGrandPrix(); // ------------------------------------------------------------------------ + /** Used when a challenge's requirement in the hardest difficulty are + * matched in a lower difficulty. Don't apply to GP */ + void setMaxReqInLowerDiff() + { + if (!isGrandPrix() && !isUnlockList()) + m_max_req_in_lower_diff = true; + } // setMaxReqInLowerDiff + // ------------------------------------------------------------------------ + /** Returns if the hardest difficulty requirements have been met in a lower + * difficulty. */ + bool areMaxReqMetInLowerDiff() const + { + return m_max_req_in_lower_diff; + } // areMaxReqMetInLowerDiff + // ------------------------------------------------------------------------ /** Returns a pointer to the actual Challenge data. */ const ChallengeData* getData() const { return m_data; } diff --git a/src/challenges/story_mode_status.cpp b/src/challenges/story_mode_status.cpp index d576625d2..7f1bc4426 100644 --- a/src/challenges/story_mode_status.cpp +++ b/src/challenges/story_mode_status.cpp @@ -301,6 +301,14 @@ void StoryModeStatus::setCurrentChallenge(const std::string &challenge_id) */ void StoryModeStatus::raceFinished() { + if(m_current_challenge && + race_manager->getDifficulty() != RaceManager::DIFFICULTY_BEST && + m_current_challenge->getData()->isChallengeFulfilled(true /*best*/)) + { + ChallengeStatus* c = const_cast(m_current_challenge); + c->setMaxReqInLowerDiff(); + } + if(m_current_challenge && m_current_challenge->isActive(race_manager->getDifficulty()) && m_current_challenge->getData()->isChallengeFulfilled() ) diff --git a/src/replay/replay_play.hpp b/src/replay/replay_play.hpp index 2a476a72f..768f62b7a 100644 --- a/src/replay/replay_play.hpp +++ b/src/replay/replay_play.hpp @@ -161,6 +161,9 @@ public: const ReplayData& getReplayData(unsigned int n) const { return m_replay_file_list.at(n); } // ------------------------------------------------------------------------ + const ReplayData& getCurrentReplayData() const + { return m_replay_file_list.at(m_current_replay_file); } + // ------------------------------------------------------------------------ const unsigned int getNumReplayFile() const { return (unsigned int)m_replay_file_list.size(); } // ------------------------------------------------------------------------ diff --git a/src/states_screens/dialogs/select_challenge.cpp b/src/states_screens/dialogs/select_challenge.cpp index 8a1c5757a..d3513e808 100644 --- a/src/states_screens/dialogs/select_challenge.cpp +++ b/src/states_screens/dialogs/select_challenge.cpp @@ -51,11 +51,11 @@ core::stringw getLabel(RaceManager::Difficulty difficulty, const ChallengeData* if (label.size() > 0) label.append(L"\n"); label.append( _("Required Rank: %i", r) ); } - if (c->getTime(difficulty) > 0) + if (c->getTimeRequirement(difficulty) > 0) { if (label.size() > 0) label.append(L"\n"); label.append( _("Required Time: %i", - StringUtils::timeToString(c->getTime(difficulty)).c_str()) ); + StringUtils::timeToString(c->getTimeRequirement(difficulty)).c_str()) ); } if (c->getEnergy(difficulty) > 0) {