Display the number of goals fullfiled, and if only one goal, its value progress
This commit is contained in:
parent
ff5bb8792e
commit
cd3bf122e6
@ -19,8 +19,10 @@
|
||||
|
||||
|
||||
#include "achievements/achievement.hpp"
|
||||
|
||||
#include "achievements/achievements_manager.hpp"
|
||||
#include "achievements/achievement_info.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
#include "guiengine/message_queue.hpp"
|
||||
#include "io/utf_writer.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
@ -65,24 +67,133 @@ void Achievement::saveProgress(UTFWriter &out)
|
||||
} // save
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns how much of an achievement has been achieved in the form n/m.
|
||||
* The AchievementInfo adds up the number of goals if there are several,
|
||||
* or take the target value of the goal if there is only one.
|
||||
* This do the same, but with achieved value or fullfilled goals.
|
||||
/** Returns how many goals of an achievement have been achieved,
|
||||
* in the form n/m.
|
||||
*/
|
||||
irr::core::stringw Achievement::getProgressAsString()
|
||||
irr::core::stringw Achievement::getGoalProgressAsString()
|
||||
{
|
||||
//TODO : add a progress computation function.
|
||||
int progress = 0;
|
||||
irr::core::stringw target = getInfo()->toString();
|
||||
irr::core::stringw target = getInfo()->goalString();
|
||||
|
||||
// For now return N/N in case of an achieved achievement.
|
||||
// Return N/N in case of an achieved achievement.
|
||||
if (m_achieved)
|
||||
return target + "/" + target;
|
||||
|
||||
int fullfiled_goals = computeFullfiledGoals(m_progress_goal_tree, m_achievement_info->m_goal_tree);
|
||||
|
||||
return StringUtils::toWString(fullfiled_goals) + "/" + target;
|
||||
} // getGoalProgressAsString
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
int Achievement::computeFullfiledGoals(AchievementInfo::goalTree &progress, AchievementInfo::goalTree &reference)
|
||||
{
|
||||
|
||||
if (progress.children.size() != 1)
|
||||
{
|
||||
// This always returns 0 if the achievement has not been completed
|
||||
if (progress.children[0].type == "OR")
|
||||
{
|
||||
bool completed = false;
|
||||
for (unsigned int i=0;i<progress.children.size();i++)
|
||||
{
|
||||
if (recursiveCompletionCheck(progress.children[i], reference.children[i]))
|
||||
{
|
||||
completed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (completed) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int goals_completed = 0;
|
||||
for (unsigned int i=0;i<progress.children.size();i++)
|
||||
{
|
||||
if (recursiveCompletionCheck(progress.children[i], reference.children[i]))
|
||||
goals_completed++;
|
||||
}
|
||||
return goals_completed;
|
||||
}
|
||||
}
|
||||
else if (progress.children[0].type == "AND" ||
|
||||
progress.children[0].type == "AND-AT-ONCE" ||
|
||||
progress.children[0].type == "OR")
|
||||
{
|
||||
return computeFullfiledGoals(progress.children[0], reference.children[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (recursiveCompletionCheck(progress.children[0], reference.children[0])) ? 1 : 0;
|
||||
}
|
||||
} // recursiveGoalCount
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns how much of an achievement has been achieved in the form n/m.
|
||||
* ONLY applicable for single goal achievements. Returns a string with a single
|
||||
* space if there are multiple goals.
|
||||
*/
|
||||
irr::core::stringw Achievement::getProgressAsString()
|
||||
{
|
||||
irr::core::stringw target = getInfo()->progressString();
|
||||
irr::core::stringw empty = " ";// See issue #3081
|
||||
|
||||
if (target == "-1")
|
||||
return empty;
|
||||
|
||||
// Return N/N in case of an achieved achievement.
|
||||
if (m_achieved)
|
||||
return target + "/" + target;
|
||||
|
||||
int progress = computeGoalProgress(m_progress_goal_tree, m_achievement_info->m_goal_tree);
|
||||
|
||||
return StringUtils::toWString(progress) + "/" + target;
|
||||
} // getProgressAsString
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Should ONLY be called if the achievement has one goal (a sum counts as one goal).
|
||||
* Returning an error code with a number is not full-proof because a sum goal can
|
||||
* legitimately be negative (a counter can be chosen to count against the
|
||||
* achievement's fullfilment). */
|
||||
int Achievement::computeGoalProgress(AchievementInfo::goalTree &progress, AchievementInfo::goalTree &reference)
|
||||
{
|
||||
if (progress.children.size() != 1)
|
||||
{
|
||||
// This should NOT happen
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
else if (progress.children[0].type == "AND" ||
|
||||
progress.children[0].type == "AND-AT-ONCE" ||
|
||||
progress.children[0].type == "OR")
|
||||
{
|
||||
return computeGoalProgress(progress.children[0], reference.children[0]);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//TODO : find a more automatic way
|
||||
if (progress.children[0].type == "race-started-all" ||
|
||||
progress.children[0].type == "race-finished-all" ||
|
||||
progress.children[0].type == "race-won-all" ||
|
||||
progress.children[0].type == "race-finished-reverse-all" ||
|
||||
progress.children[0].type == "race-finished-alone-all" ||
|
||||
progress.children[0].type == "less-laps-all" ||
|
||||
progress.children[0].type == "more-laps-all" ||
|
||||
progress.children[0].type == "twice-laps-all" ||
|
||||
progress.children[0].type == "egg-hunt-started-all" ||
|
||||
progress.children[0].type == "egg-hunt-finished-all")
|
||||
{
|
||||
// Compare against the target value (in the reference tree) !
|
||||
// Progress is only shown for the current local accuont, so we can use the current achievements status
|
||||
return PlayerManager::getCurrentAchievementsStatus()
|
||||
->getNumTracksAboveValue(reference.children[0].value, reference.children[0].type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return progress.children[0].value;
|
||||
}
|
||||
}
|
||||
} // computeGoalProgress
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Set any leaf of the progress goal tree whose type matches the
|
||||
* goal_string to the value passed as parameter.
|
||||
|
@ -57,6 +57,9 @@ private:
|
||||
bool recursiveSetGoalValue(AchievementInfo::goalTree &tree, const std::string &goal_string, int value,
|
||||
bool and_or, bool sum_andatonce);
|
||||
bool recursiveCompletionCheck(AchievementInfo::goalTree &progress, AchievementInfo::goalTree &reference);
|
||||
|
||||
int computeFullfiledGoals(AchievementInfo::goalTree &progress, AchievementInfo::goalTree &reference);
|
||||
int computeGoalProgress(AchievementInfo::goalTree &progress, AchievementInfo::goalTree &reference);
|
||||
public:
|
||||
|
||||
Achievement(AchievementInfo * info);
|
||||
@ -65,6 +68,7 @@ public:
|
||||
virtual void saveProgress(UTFWriter &out);
|
||||
|
||||
virtual irr::core::stringw getProgressAsString();
|
||||
virtual irr::core::stringw getGoalProgressAsString();
|
||||
|
||||
uint32_t getID() const { return m_achievement_info->getID(); }
|
||||
AchievementInfo * getInfo() { return m_achievement_info; }
|
||||
|
@ -17,8 +17,11 @@
|
||||
// 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 "achievements/achievement.hpp"
|
||||
#include "achievements/achievements_status.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#include <sstream>
|
||||
@ -147,26 +150,75 @@ void AchievementInfo::copyGoalTree(goalTree ©, goalTree &model, bool set_val
|
||||
} // copyGoalTree
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns a string with a numerical value to display the progress of
|
||||
* this achievement.
|
||||
* If it has multiple goal, it returns the number of goals. If it has
|
||||
* only one (it can be a sum), it returns the required value for that goal.
|
||||
* FIXME : don't work well for "all tracks" goals.
|
||||
/** Returns a string with the number of goals to fullfil to
|
||||
* get this achievements.
|
||||
*/
|
||||
irr::core::stringw AchievementInfo::toString()
|
||||
irr::core::stringw AchievementInfo::goalString()
|
||||
{
|
||||
return StringUtils::toWString(recursiveGoalCount(m_goal_tree));
|
||||
} // toString
|
||||
} // goalString
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
int AchievementInfo::recursiveGoalCount(goalTree &parent)
|
||||
{
|
||||
if (parent.children.size() != 1)
|
||||
{
|
||||
if (parent.children[0].type == "OR")
|
||||
return 1;
|
||||
else
|
||||
return m_goal_tree.children.size();
|
||||
}
|
||||
else if (parent.children[0].type == "AND" ||
|
||||
parent.children[0].type == "AND-AT-ONCE" ||
|
||||
parent.children[0].type == "OR")
|
||||
{
|
||||
return recursiveGoalCount(parent.children[0]);
|
||||
}
|
||||
else
|
||||
return parent.children[0].value;
|
||||
return 1;
|
||||
} // recursiveGoalCount
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns a string with the target of the goal if the
|
||||
* achievement has only one goal (a sum counts as one goal).
|
||||
*/
|
||||
irr::core::stringw AchievementInfo::progressString()
|
||||
{
|
||||
return StringUtils::toWString(recursiveProgressCount(m_goal_tree));
|
||||
} // progressString
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
int AchievementInfo::recursiveProgressCount(goalTree &parent)
|
||||
{
|
||||
if (parent.children.size() != 1)
|
||||
{
|
||||
return -1; // signal that this is invalid.
|
||||
}
|
||||
else if (parent.children[0].type == "AND" ||
|
||||
parent.children[0].type == "AND-AT-ONCE" ||
|
||||
parent.children[0].type == "OR")
|
||||
{
|
||||
return recursiveGoalCount(parent.children[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO : find a more automatic way
|
||||
if (parent.children[0].type == "race-started-all" ||
|
||||
parent.children[0].type == "race-finished-all" ||
|
||||
parent.children[0].type == "race-won-all" ||
|
||||
parent.children[0].type == "race-finished-reverse-all" ||
|
||||
parent.children[0].type == "race-finished-alone-all" ||
|
||||
parent.children[0].type == "less-laps-all" ||
|
||||
parent.children[0].type == "more-laps-all" ||
|
||||
parent.children[0].type == "twice-laps-all" ||
|
||||
parent.children[0].type == "egg-hunt-started-all" ||
|
||||
parent.children[0].type == "egg-hunt-finished-all")
|
||||
{
|
||||
return PlayerManager::getCurrentAchievementsStatus()->getNumAchieveTracks();
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent.children[0].value;
|
||||
}
|
||||
}
|
||||
} // recursiveProgressCount
|
||||
|
@ -72,6 +72,7 @@ private:
|
||||
|
||||
void parseGoals(const XMLNode * input, goalTree &parent);
|
||||
int recursiveGoalCount(goalTree &parent);
|
||||
int recursiveProgressCount(goalTree &parent);
|
||||
protected:
|
||||
friend class Achievement;
|
||||
/** The tree storing all goals */
|
||||
@ -81,7 +82,8 @@ public:
|
||||
AchievementInfo(const XMLNode * input);
|
||||
virtual ~AchievementInfo() {};
|
||||
|
||||
virtual irr::core::stringw toString();
|
||||
virtual irr::core::stringw goalString();
|
||||
virtual irr::core::stringw progressString();
|
||||
|
||||
uint32_t getID() const { return m_id; }
|
||||
irr::core::stringw getDescription() const { return _(m_description.c_str()); }
|
||||
|
@ -374,6 +374,63 @@ void AchievementsStatus::sync(const std::vector<uint32_t> & achieved_ids)
|
||||
}
|
||||
} // sync
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/* This function returns for how many tracks the requested goal type
|
||||
* is matched or exceeded. Addons tracks are ignored.
|
||||
* It returns -1 if the goal type is invalid.
|
||||
* \param value - the value to match or exceed
|
||||
* \param goal_string - the identifier of the value to check. */
|
||||
int AchievementsStatus::getNumTracksAboveValue(int value, std::string goal_string)
|
||||
{
|
||||
int counter = 0;
|
||||
int enum_id = -1;
|
||||
|
||||
for (int i=0;i<2*(int)TR_DATA_NUM;i++)
|
||||
{
|
||||
if (m_tr_enum_to_xml[i] == goal_string)
|
||||
enum_id = i%(int)TR_DATA_NUM;
|
||||
}
|
||||
|
||||
if (enum_id == -1)
|
||||
{
|
||||
Log::warn("AchievementsStatus",
|
||||
"Number of matching tracks requested for a non-existent "
|
||||
"data value.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (unsigned int i=0;i<m_track_stats.size();i++)
|
||||
{
|
||||
// ignore addons tracks (compare returns 0 when the values are equal)
|
||||
// Note: non-official tracks installed directly in the tracks folder
|
||||
// are considered as officials by this method.
|
||||
if (m_track_stats[i].ident.compare(0 /*start of sub-string*/,5/*length*/,"addon") == 0)
|
||||
continue;
|
||||
|
||||
if (m_track_stats[i].track_data[enum_id] >= value)
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
} // getNumTracksAboveValue
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/* This function returns the number of tracks valid for by-track achievements. */
|
||||
int AchievementsStatus::getNumAchieveTracks()
|
||||
{
|
||||
int num_tracks = 0;
|
||||
for (unsigned int i=0;i<m_track_stats.size();i++)
|
||||
{
|
||||
// TODO : have a generic function to call instead
|
||||
// ignore addons tracks (compare returns 0 when the values are equal)
|
||||
if (m_track_stats[i].ident.compare(0 /*start of sub-string*/,5/*length*/,"addon") == 0)
|
||||
continue;
|
||||
|
||||
num_tracks++;
|
||||
}
|
||||
return num_tracks;
|
||||
} //getNumAchieveTracks
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/* 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.
|
||||
|
@ -230,6 +230,8 @@ public :
|
||||
void resetKartHits(int num_karts);
|
||||
void addKartHit(int kart_id);
|
||||
void updateAllAchievementsProgress();
|
||||
int getNumTracksAboveValue(int value, std::string goal_string);
|
||||
int getNumAchieveTracks();
|
||||
// ------------------------------------------------------------------------
|
||||
std::map<uint32_t, Achievement *>& getAllAchievements()
|
||||
{
|
||||
|
@ -74,6 +74,7 @@ void BaseOnlineProfileAchievements::beforeAddingWidget()
|
||||
// = NULL) user achievement progress will also be displayed
|
||||
if(!m_visiting_profile || m_visiting_profile->isCurrentUser())
|
||||
{
|
||||
m_achievements_list_widget->addColumn( _("Goals"), 1 );
|
||||
m_achievements_list_widget->addColumn( _("Progress"), 1 );
|
||||
}
|
||||
} // beforeAddingWidget
|
||||
@ -109,8 +110,10 @@ void BaseOnlineProfileAchievements::init()
|
||||
if(a->getInfo()->isSecret() && !a->isAchieved())
|
||||
continue;
|
||||
ListWidget::ListCell title(translations->fribidize(a->getInfo()->getName()), -1, 2);
|
||||
ListWidget::ListCell goals(a->getGoalProgressAsString(), -1, 1);
|
||||
ListWidget::ListCell progress(a->getProgressAsString(), -1, 1);
|
||||
row.push_back(title);
|
||||
row.push_back(goals);
|
||||
row.push_back(progress);
|
||||
const std::string id = StringUtils::toString(a->getInfo()->getID());
|
||||
m_achievements_list_widget->addItem(id, row);
|
||||
|
Loading…
Reference in New Issue
Block a user