diff --git a/data/achievements.xml b/data/achievements.xml index ae27dce55..71bdf7865 100644 --- a/data/achievements.xml +++ b/data/achievements.xml @@ -75,8 +75,7 @@ skidding-1race skidding-1lap --> - + @@ -99,49 +98,38 @@ - + - + - + - + - + - + - + - + - + - + - + diff --git a/src/achievements/achievement.cpp b/src/achievements/achievement.cpp index 7aa60397b..3c64e6303 100644 --- a/src/achievements/achievement.cpp +++ b/src/achievements/achievement.cpp @@ -35,7 +35,6 @@ Achievement::Achievement(const AchievementInfo * info) : m_achievement_info(info) { - m_id = info->getID(); m_achieved = false; } // Achievement @@ -47,43 +46,21 @@ Achievement::~Achievement() // ---------------------------------------------------------------------------- /** Loads the value from an XML node. * \param input*/ -void Achievement::load(const XMLNode *node) +void Achievement::loadProgress(const XMLNode *node) { - node->get("id", &m_id ); node->get("achieved", &m_achieved); - - for (unsigned int i = 0; i < node->getNumNodes(); i++) - { - const XMLNode *n = node->getNode(i); - std::string key = n->getName(); - int value = 0; - n->get("value", &value); - m_progress_map[key] = value; - } } // load // ---------------------------------------------------------------------------- /** Saves the achievement status to a file. * \param Output stream. */ -void Achievement::save(UTFWriter &out) +void Achievement::saveProgress(UTFWriter &out) { - out << " \n"; - return; - } - - out << ">\n"; - std::map::iterator i; - for (i = m_progress_map.begin(); i != m_progress_map.end(); ++i) - { - out << " <" << i->first - << " value=\"" << i->second << "\"/>\n"; - } - out << " \n"; + + out << "/>\n"; } // save // ---------------------------------------------------------------------------- @@ -122,24 +99,11 @@ irr::core::stringw Achievement::getProgressAsString() const if (m_achieved) return getInfo()->toString() +"/" + getInfo()->toString(); - switch (m_achievement_info->getCheckType()) - { - case AchievementInfo::AC_ALL_AT_LEAST: - for (iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter) - { - progress += iter->second; - } - break; - case AchievementInfo::AC_ONE_AT_LEAST: - for (iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter) - { - if(iter->second>progress) progress = iter->second; - } - break; - default: - Log::fatal("Achievement", "Missing getProgressAsString for type %d.", - m_achievement_info->getCheckType()); - } + for (iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter) + { + progress += iter->second; + } + return StringUtils::toWString(progress) + "/" + getInfo()->toString(); } // getProgressAsString @@ -171,24 +135,6 @@ void Achievement::increase(const std::string & key, check(); } // increase -// ---------------------------------------------------------------------------- -/** Called at the end of a race to potentially reset values. - */ -void Achievement::onRaceEnd() -{ - if(m_achievement_info->needsResetAfterRace()) - reset(); -} // onRaceEnd - -// ---------------------------------------------------------------------------- -/** Called at the end of a lap to potentially reset values. -*/ -void Achievement::onLapEnd() -{ - if (m_achievement_info->needsResetAfterLap()) - reset(); -} // onLapEnd - // ---------------------------------------------------------------------------- /** Checks if this achievement has been achieved. */ @@ -215,7 +161,7 @@ void Achievement::check() { Online::HTTPRequest * request = new Online::HTTPRequest(true); PlayerManager::setUserDetails(request, "achieving"); - request->addParameter("achievementid", m_id); + request->addParameter("achievementid", getID()); request->queue(); } diff --git a/src/achievements/achievement.hpp b/src/achievements/achievement.hpp index 5802d963b..8ef354cae 100644 --- a/src/achievements/achievement.hpp +++ b/src/achievements/achievement.hpp @@ -20,6 +20,7 @@ #ifndef HEADER_ACHIEVEMENT_HPP #define HEADER_ACHIEVEMENT_HPP +#include "achievements/achievement_info.hpp" #include "utils/types.hpp" #include @@ -30,8 +31,9 @@ class UTFWriter; class XMLNode; // ============================================================================ -/** This is the base class for any achievement. It allows achievement status - * to be saved, and detects when an achievement is fulfilled. It provides +/** This class tracks the progress of an achievement for a player, whose + * definition is stored by an associated AchievementInfo. It allows achievement + * status to be saved, and detects when an achievement is fulfilled. It provides * storage for state information by a generic key-value mapping. The values * are stored as strings, but can be used to store numerical values. E.g. * you can call increase("key", 10) for an achievement, which will convert @@ -44,9 +46,6 @@ class AchievementInfo; class Achievement { private: - /** The id of this achievement. */ - uint32_t m_id; - /** True if this achievement has been achieved. */ bool m_achieved; @@ -62,27 +61,19 @@ public: Achievement(const AchievementInfo * info); virtual ~Achievement(); - virtual void load(const XMLNode *node); - virtual void save(UTFWriter &out); + virtual void loadProgress(const XMLNode *node); + virtual void saveProgress(UTFWriter &out); virtual int getValue(const std::string & key); void increase(const std::string & key, const std::string &goal_key, int increase = 1); virtual void reset(); virtual irr::core::stringw getProgressAsString() const; - void onRaceEnd(); - void onLapEnd(); - // ------------------------------------------------------------------------ - /** Returns the id of this achievement. */ - uint32_t getID() const { return m_id; } - // ------------------------------------------------------------------------ - /** Returns the AchievementInfo for this achievement. */ + + uint32_t getID() const { return m_achievement_info->getID(); } const AchievementInfo * getInfo() const { return m_achievement_info; } - // ------------------------------------------------------------------------ - /** Sets this achievement to be fulfilled. */ + void setAchieved() { m_achieved = true; }; - // ------------------------------------------------------------------------ - /** Returns if this achievement has been fulfilled. */ bool isAchieved() const { return m_achieved; } // ------------------------------------------------------------------------ const std::map& getProgress() const diff --git a/src/achievements/achievement_info.cpp b/src/achievements/achievement_info.cpp index d732abe83..c4e647e69 100644 --- a/src/achievements/achievement_info.cpp +++ b/src/achievements/achievement_info.cpp @@ -17,6 +17,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include "achievements/achievement.hpp" #include "achievements/achievement_info.hpp" #include "utils/log.hpp" @@ -29,7 +30,6 @@ */ AchievementInfo::AchievementInfo(const XMLNode * input) { - m_reset_type = NEVER; m_id = 0; m_name = ""; m_description = ""; @@ -47,27 +47,6 @@ AchievementInfo::AchievementInfo(const XMLNode * input) m_description.c_str()); } - // Load the reset-type - std::string s; - input->get("reset-type", &s); - if (s == "race") - m_reset_type = AFTER_RACE; - else if (s == "lap") - m_reset_type = AFTER_LAP; - else if (s != "never") - Log::warn("AchievementInfo", "Achievement check type '%s' unknown.", - s.c_str()); - - // Load check-type - m_check_type = AC_ALL_AT_LEAST; - input->get("check-type", &s); - if (s == "all-at-least") - m_check_type = AC_ALL_AT_LEAST; - else if (s == "one-at-least") - m_check_type = AC_ONE_AT_LEAST; - else - Log::warn("AchievementInfo", "Achievement check type '%s' unknown.", - s.c_str()); input->get("secret", &m_is_secret); // Now load the goal nodes @@ -82,13 +61,6 @@ AchievementInfo::AchievementInfo(const XMLNode * input) if (m_goal_values.size() != input->getNumNodes()) Log::fatal("AchievementInfo", "Duplicate keys for the entries of a MapAchievement found."); - - if (m_check_type == AC_ONE_AT_LEAST) - { - if (m_goal_values.size() != 1) - Log::fatal("AchievementInfo", - "A one-at-least achievement must have exactly one goal."); - } } // AchievementInfo // ---------------------------------------------------------------------------- @@ -99,23 +71,13 @@ irr::core::stringw AchievementInfo::toString() const { int count = 0; std::map::const_iterator iter; - switch (m_check_type) + + // If all values need to be reached, add up all goal values + for (iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++) { - case AC_ALL_AT_LEAST: - // If all values need to be reached, add up all goal values - for (iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++) - { - count += iter->second; - } - break; - case AC_ONE_AT_LEAST: - // Only one goal is defined for a one-at-least - count = m_goal_values.begin()->second; - break; - default: - Log::fatal("AchievementInfo", "Missing toString for type %d.", - m_check_type); + count += iter->second; } + return StringUtils::toWString(count); } // toString @@ -125,34 +87,12 @@ bool AchievementInfo::checkCompletion(Achievement * achievement) const { std::map::const_iterator iter; - switch (m_check_type) + for (iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++) { - case AC_ALL_AT_LEAST: - for (iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++) - { - if (achievement->getValue(iter->first) < iter->second) - return false; - } - return true; - case AC_ONE_AT_LEAST: - { - // Test all progress values the kart has. - const std::map &progress = achievement->getProgress(); - for (iter = progress.begin(); iter != progress.end(); iter++) - { - // A one-at-least achievement has only one goal, so use it - if (iter->second >= m_goal_values.begin()->second) - return true; - } - return false; + if (achievement->getValue(iter->first) < iter->second) + return false; } - default: - Log::fatal("AchievementInfo", "Missing check for type %d.", - m_check_type); - } // switch - - // Avoid compiler warning - return false; + return true; } // ---------------------------------------------------------------------------- int AchievementInfo::getGoalValue(const std::string &key) const diff --git a/src/achievements/achievement_info.hpp b/src/achievements/achievement_info.hpp index 05f090384..37a8adb8e 100644 --- a/src/achievements/achievement_info.hpp +++ b/src/achievements/achievement_info.hpp @@ -20,7 +20,6 @@ #ifndef HEADER_ACHIEVEMENT_INFO_HPP #define HEADER_ACHIEVEMENT_INFO_HPP -#include "achievements/achievement.hpp" #include "io/xml_node.hpp" #include "utils/translation.hpp" #include "utils/types.hpp" @@ -32,9 +31,10 @@ class Achievement; -/** This is the base class for storing the definition of an achievement, e.g. - * title, description (which is common for all achievements), but also how - * to achieve this achievement. +/** This class stores an achievement definition from the xml file, including + * title, description, but also how to achieve this achievement. + * Constrat with the Achievement class, which is a player-specific instance + * tracking the progress of the achievement. * \ingroup achievements */ class AchievementInfo @@ -56,27 +56,6 @@ public: ACHIEVE_UNSTOPPABLE = 12 }; - /** Achievement check type: - * ALL_AT_LEAST: All goal values must be reached (or exceeded). - * ONE_AT_LEAST: At least one current value reaches or exceedes the goal. - */ - enum AchievementCheckType - { - AC_ALL_AT_LEAST, - AC_ONE_AT_LEAST - }; - /** Achievement reset type: - * AFTER_LAP: Achievement needs to be reset after each lap. - * AFTER_RACE: Achievement needs to be reset after each race. - * NEVER: Achievement does not need to be reset - */ - enum ResetType - { - AFTER_LAP = 1, - AFTER_RACE = 2, - NEVER = 3 - }; - private: /** The id of this Achievement. */ uint32_t m_id; @@ -87,15 +66,9 @@ private: /** The description of this achievement. */ irr::core::stringw m_description; - /** Determines how this achievement is checked if it is successful. */ - AchievementCheckType m_check_type; - /** The target values needed to be reached. */ std::map m_goal_values; - /** Determines when the achievement needs to be reset */ - ResetType m_reset_type; - /** A secret achievement has its progress not shown. */ bool m_is_secret; @@ -107,26 +80,10 @@ public: virtual bool checkCompletion(Achievement * achievement) const; int getGoalValue(const std::string &key) const; - // ------------------------------------------------------------------------ - /** Returns the id of this achievement. */ - uint32_t getID() const { return m_id; } - // ------------------------------------------------------------------------ - /** Returns the description of this achievement. */ + uint32_t getID() const { return m_id; } irr::core::stringw getDescription() const { return _(m_description.c_str()); } - // ------------------------------------------------------------------------ - /** Returns the name of this achievement. */ - irr::core::stringw getName() const { return _LTR(m_name.c_str()); } - // ------------------------------------------------------------------------ - bool needsResetAfterRace() const { return m_reset_type == AFTER_RACE; } - // ------------------------------------------------------------------------ - bool needsResetAfterLap() const { return m_reset_type == AFTER_LAP; } - // ------------------------------------------------------------------------ - /** Returns the check type for this achievement. */ - AchievementCheckType getCheckType() const { return m_check_type; } - // ------------------------------------------------------------------------ - /** Returns if this achievement is a secret achievement. */ - bool isSecret() const { return m_is_secret; } - // ------------------------------------------------------------------------ + irr::core::stringw getName() const { return _LTR(m_name.c_str()); } + bool isSecret() const { return m_is_secret; } }; // class AchievementInfo diff --git a/src/achievements/achievements_status.cpp b/src/achievements/achievements_status.cpp index 8e998f4c8..3123f03ba 100644 --- a/src/achievements/achievements_status.cpp +++ b/src/achievements/achievements_status.cpp @@ -99,7 +99,7 @@ void AchievementsStatus::load(const XMLNode * input) "achievement. Discarding."); continue; } - achievement->load(xml_achievements[i]); + achievement->loadProgress(xml_achievements[i]); } // for i in xml_achievements // Load achievement data @@ -193,7 +193,7 @@ void AchievementsStatus::save(UTFWriter &out) for(i = m_achievements.begin(); i != m_achievements.end(); i++) { if (i->second != NULL) - i->second->save(out); + i->second->saveProgress(out); } out << " \n"; for(int i=0;i & achieved_ids) } // sync /* This function checks over achievements to update their goals + * \param type - the data type triggering the update, used to know + * to what enum the enum_id refers to. + * \param enum_id - the id of the enum identifying the change triggering + * the update. FIXME It is currently hard-coded to specific achievements, until it can entirely supersedes the previous system and removes its complications. FIXME : a data id don't cover some situations, and the function itself ignores it */ -void AchievementsStatus::updateAchievementsProgress(unsigned int achieve_data_id) +void AchievementsStatus::updateAchievementsProgress(UpdateType type, unsigned int enum_id) { Achievement *beyond_luck = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_BEYOND_LUCK); if (!beyond_luck->isAchieved()) @@ -393,7 +397,7 @@ void AchievementsStatus::increaseDataVar(unsigned int achieve_data_id, int incre if (m_variables[achieve_data_id].counter > 10000000) m_variables[achieve_data_id].counter = 10000000; - updateAchievementsProgress(achieve_data_id); + updateAchievementsProgress(UP_ACHIEVEMENT_DATA, achieve_data_id); } #ifdef DEBUG else @@ -425,13 +429,7 @@ void AchievementsStatus::onRaceEnd(bool aborted) { onLapEnd(); - updateAchievementsProgress(0); - - //reset all values that need to be reset - std::map::iterator iter; - for ( iter = m_achievements.begin(); iter != m_achievements.end(); ++iter ) { - iter->second->onRaceEnd(); - } + updateAchievementsProgress(UP_ACHIEVEMENT_DATA, 0); m_variables[POWERUP_USED_1RACE].counter = 0; m_variables[BANANA_1RACE].counter = 0; @@ -451,13 +449,7 @@ void AchievementsStatus::onRaceEnd(bool aborted) // ---------------------------------------------------------------------------- void AchievementsStatus::onLapEnd() { - updateAchievementsProgress(0); - - //reset all values that need to be reset - std::map::iterator iter; - for (iter = m_achievements.begin(); iter != m_achievements.end(); ++iter) { - iter->second->onLapEnd(); - } + updateAchievementsProgress(UP_ACHIEVEMENT_DATA, 0); m_variables[SKIDDING_1LAP].counter = 0; } // onLapEnd @@ -510,5 +502,5 @@ void AchievementsStatus::resetKartHits(int num_karts) void AchievementsStatus::addKartHit(int kart_id) { m_kart_hits[kart_id]++; - updateAchievementsProgress(0); + updateAchievementsProgress(UP_KART_HITS, 0); } // addKartHit diff --git a/src/achievements/achievements_status.hpp b/src/achievements/achievements_status.hpp index c9aabbe0c..3241f2da5 100644 --- a/src/achievements/achievements_status.hpp +++ b/src/achievements/achievements_status.hpp @@ -178,6 +178,16 @@ private: // Reset at the beginning of a race std::vector m_kart_hits; + // To avoid updating achievement progress being + // too computationally wasteful, we restrain + // what is checked on an update + enum UpdateType + { + UP_ACHIEVEMENT_DATA = 0, + UP_TRACK_DATA = 1, + UP_KART_HITS = 2, + }; + bool m_online; bool m_valid; @@ -195,7 +205,7 @@ public : void save(UTFWriter &out); void add(Achievement *achievement); void sync(const std::vector & achieved_ids); - void updateAchievementsProgress(unsigned int achieve_data_id); + void updateAchievementsProgress(UpdateType type, unsigned int enum_id); void increaseDataVar(unsigned int achieve_data_id, int increase); void resetDataVar(unsigned int achieve_data_id); void onRaceEnd(bool aborted=false); diff --git a/src/items/powerup.cpp b/src/items/powerup.cpp index 24ce4c9e0..2a2e4dd85 100644 --- a/src/items/powerup.cpp +++ b/src/items/powerup.cpp @@ -18,11 +18,9 @@ #include "items/powerup.hpp" -#include "achievements/achievement_info.hpp" -#include "config/player_manager.hpp" - #include "audio/sfx_base.hpp" #include "audio/sfx_manager.hpp" +#include "config/player_manager.hpp" #include "config/stk_config.hpp" #include "items/attachment.hpp" #include "items/item_manager.hpp" diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 8f2e0d62b..7f534a78c 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -18,7 +18,6 @@ #include "modes/world.hpp" -#include "achievements/achievement_info.hpp" #include "audio/music_manager.hpp" #include "audio/sfx_base.hpp" #include "audio/sfx_manager.hpp" diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index fc76d8e27..58c80b2d6 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -18,7 +18,6 @@ #include "physics/physics.hpp" -#include "achievements/achievement_info.hpp" #include "animations/three_d_animation.hpp" #include "config/player_manager.hpp" #include "config/player_profile.hpp"