diff --git a/data/achievements.xml b/data/achievements.xml
index feb017a98..d7bc2a542 100644
--- a/data/achievements.xml
+++ b/data/achievements.xml
@@ -1,6 +1,6 @@
-
@@ -13,21 +13,20 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/src/achievements/achievement.cpp b/src/achievements/achievement.cpp
index 8e07dd60b..ff85fc138 100644
--- a/src/achievements/achievement.cpp
+++ b/src/achievements/achievement.cpp
@@ -179,6 +179,15 @@ void Achievement::onRaceEnd()
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.
*/
diff --git a/src/achievements/achievement.hpp b/src/achievements/achievement.hpp
index ec3790aad..9f7239d98 100644
--- a/src/achievements/achievement.hpp
+++ b/src/achievements/achievement.hpp
@@ -69,7 +69,8 @@ public:
virtual void reset();
virtual irr::core::stringw getProgressAsString() const;
- void onRaceEnd();
+ void onRaceEnd();
+ void onLapEnd();
// ------------------------------------------------------------------------
/** Returns the id of this achievement. */
uint32_t getID() const { return m_id; }
diff --git a/src/achievements/achievement_info.cpp b/src/achievements/achievement_info.cpp
index 98602cd32..f5d93b88c 100644
--- a/src/achievements/achievement_info.cpp
+++ b/src/achievements/achievement_info.cpp
@@ -31,7 +31,7 @@
*/
AchievementInfo::AchievementInfo(const XMLNode * input)
{
- m_reset_after_race = false;
+ m_reset_type = NEVER;
m_id = 0;
m_title = "";
m_description = "";
@@ -47,10 +47,22 @@ AchievementInfo::AchievementInfo(const XMLNode * input)
"ID %d title '%s' description '%s'", m_id, m_title.c_str(),
m_description.c_str());
}
- input->get("reset-after-race", &m_reset_after_race);
- m_check_type = AC_ALL_AT_LEAST;
+ // 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")
+ m_reset_type = NEVER;
+ else
+ 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;
diff --git a/src/achievements/achievement_info.hpp b/src/achievements/achievement_info.hpp
index 5e52989bf..da3ffdf82 100644
--- a/src/achievements/achievement_info.hpp
+++ b/src/achievements/achievement_info.hpp
@@ -58,6 +58,17 @@ public:
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. */
@@ -75,8 +86,8 @@ private:
/** The target values needed to be reached. */
std::map m_goal_values;
- /** True if the achievement needs to be reset after each race. */
- bool m_reset_after_race;
+ /** Determines when the achievement needs to be reset */
+ ResetType m_reset_type;
public:
AchievementInfo(const XMLNode * input);
@@ -96,7 +107,9 @@ public:
/** Returns the title of this achievement. */
irr::core::stringw getTitle() const { return m_title; }
// ------------------------------------------------------------------------
- bool needsResetAfterRace() const { return m_reset_after_race; }
+ 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; }
diff --git a/src/achievements/achievements_manager.cpp b/src/achievements/achievements_manager.cpp
index e13af174e..ec59095cf 100644
--- a/src/achievements/achievements_manager.cpp
+++ b/src/achievements/achievements_manager.cpp
@@ -95,14 +95,6 @@ AchievementsStatus*
return status;
} // createAchievementStatus
-// ----------------------------------------------------------------------------
-void AchievementsManager::onRaceEnd()
-{
- //reset all values that need to be reset
- PlayerManager::get()->getCurrentPlayer()
- ->getAchievementsStatus()->onRaceEnd();
-} // onRaceEnd
-
// ----------------------------------------------------------------------------
AchievementInfo * AchievementsManager::getAchievementInfo(uint32_t id) const
{
diff --git a/src/achievements/achievements_manager.hpp b/src/achievements/achievements_manager.hpp
index 67cebf888..d138cb151 100644
--- a/src/achievements/achievements_manager.hpp
+++ b/src/achievements/achievements_manager.hpp
@@ -71,7 +71,6 @@ public:
} // destroy
// ========================================================================
- void onRaceEnd();
AchievementInfo* getAchievementInfo(uint32_t id) const;
AchievementsStatus* createAchievementsStatus(const XMLNode *node=NULL);
// ------------------------------------------------------------------------
diff --git a/src/achievements/achievements_status.cpp b/src/achievements/achievements_status.cpp
index 40aa3d34d..74bf54724 100644
--- a/src/achievements/achievements_status.cpp
+++ b/src/achievements/achievements_status.cpp
@@ -132,3 +132,12 @@ void AchievementsStatus::onRaceEnd()
iter->second->onRaceEnd();
}
} // onRaceEnd
+
+void AchievementsStatus::onLapEnd()
+{
+ //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();
+ }
+} // onRaceEnd
\ No newline at end of file
diff --git a/src/achievements/achievements_status.hpp b/src/achievements/achievements_status.hpp
index e956dd99b..7aa8edefa 100644
--- a/src/achievements/achievements_status.hpp
+++ b/src/achievements/achievements_status.hpp
@@ -60,6 +60,7 @@ public :
void add(Achievement *achievement);
void sync(const std::vector & achieved_ids);
void onRaceEnd();
+ void onLapEnd();
// ------------------------------------------------------------------------
const std::map& getAllAchievements()
{
diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp
index 865e995be..43334bde7 100644
--- a/src/modes/linear_world.cpp
+++ b/src/modes/linear_world.cpp
@@ -17,6 +17,8 @@
#include "modes/linear_world.hpp"
+#include "achievements/achievements_manager.hpp"
+#include "config/player_manager.hpp"
#include "audio/music_manager.hpp"
#include "audio/sfx_base.hpp"
#include "audio/sfx_manager.hpp"
@@ -236,6 +238,14 @@ void LinearWorld::newLap(unsigned int kart_index)
KartInfo &kart_info = m_kart_info[kart_index];
AbstractKart *kart = m_karts[kart_index];
+ // Reset reset-after-lap achievements
+ StateManager::ActivePlayer *c = kart->getController()->getPlayer();
+ PlayerProfile *p = PlayerManager::get()->getCurrentPlayer();
+ if (c && c->getConstProfile() == p)
+ {
+ PlayerManager::get()->getCurrentPlayer()->getAchievementsStatus()->onLapEnd();
+ }
+
// Only update the kart controller if a kart that has already finished
// the race crosses the start line again. This avoids 'fastest lap'
// messages if the end controller does a fastest lap, but especially