Some refactoring in he Achievement classes, code style cleanup.

This commit is contained in:
hiker 2014-02-21 22:15:36 +11:00
parent 8307e0d8a3
commit b214799a35
6 changed files with 259 additions and 140 deletions

View File

@ -32,28 +32,46 @@
#include <sstream>
#include <stdlib.h>
// ============================================================================
Achievement::Achievement(const AchievementInfo * info)
:m_achievement_info(info)
{
m_id = info->getID();
m_achieved = false;
}
} // Achievement
// ============================================================================
// ----------------------------------------------------------------------------
Achievement::~Achievement()
{
} // ~Achievement
}
// ----------------------------------------------------------------------------
/** Loads the value from an XML node.
* \param input*/
void Achievement::load(const XMLNode *node)
{
node->get("id", &m_id );
node->get("achieved", &m_achieved);
} // load
// ============================================================================
// ----------------------------------------------------------------------------
/** Saves the achievement status to a file.
* \param Output stream.
*/
void Achievement::save(UTFWriter &out)
{
out << L" <achievement id=\"" << m_id << L"\" "
<< L"achieved=\"" << m_achieved << "\"";
} // save
// ----------------------------------------------------------------------------
void Achievement::onRaceEnd()
{
if(m_achievement_info->needsResetAfterRace())
this->reset();
}
// ============================================================================
// ----------------------------------------------------------------------------
void Achievement::check()
{
if(m_achieved)
@ -72,106 +90,120 @@ void Achievement::check()
}
}
// ============================================================================
// ----------------------------------------------------------------------------
/** Constructor for a SingleAchievement.
*/
SingleAchievement::SingleAchievement(const AchievementInfo * info)
: Achievement(info)
{
m_progress = 0;
m_achieved = false;
}
} // SingleAchievement
// ============================================================================
void SingleAchievement::load(XMLNode * input)
// ----------------------------------------------------------------------------
/** Loads the state from an xml node.
* \param node The XML data.
*/
void SingleAchievement::load(const XMLNode *node)
{
std::string achieved("");
input->get("achieved", &achieved);
if(achieved == "true")
{
m_achieved = true;
return;
}
input->get("value", &m_progress);
}
// ============================================================================
Achievement::load(node);
if (!isAchieved())
node->get("progress", &m_progress);
} // load
// ----------------------------------------------------------------------------
/** Save the state to a file. The progress is only saved if the achievement
* has not been achieved yet.
* \param out The output file.
*/
void SingleAchievement::save(UTFWriter &out)
{
out << L" <achievement id=\"" << m_id << L"\" "
<< "achieved=\"" << m_achieved << "\"";
if(!m_achieved)
Achievement::save(out);
if (!m_achieved)
{
out << L" value=\"" << m_progress << L"\"";
out << L" progress=\"" << m_progress << L"\"";
}
out << L"/>\n";
} // save
// ============================================================================
// ----------------------------------------------------------------------------
/** Resets the challenge. Calls if necessary (i.e. if a challenge needs to
* be fulfilled in a single race).
*/
void SingleAchievement::reset()
{
m_progress = 0;
} // reset
// ============================================================================
// ----------------------------------------------------------------------------
/** Adds a value to this counter.
* \param increase Value to add.
*/
void SingleAchievement::increase(int increase)
{
m_progress += increase;
check();
}
} // increase
// ============================================================================
// ----------------------------------------------------------------------------
/** Returns a "k/n" string indicating how much of an achievement was achieved.
*/
irr::core::stringw SingleAchievement::getProgressAsString()
{
return StringUtils::toWString(m_progress) + "/" + StringUtils::toWString(((SingleAchievementInfo *) m_achievement_info)->getGoalValue());
}
// The info class returns the goal value
return StringUtils::toWString(m_progress) + "/"
+getInfo()->toString();
} // getProgressAsString
// ============================================================================
/** Constructor for a MapAchievement.
*/
MapAchievement::MapAchievement(const AchievementInfo * info)
: Achievement(info)
{
}
} // MapAchievement
// ============================================================================
void MapAchievement::load(XMLNode * input)
// ----------------------------------------------------------------------------
/** Loads the status from an XML node.
* \param node The XML data to load the status from.
*/
void MapAchievement::load(const XMLNode *node)
{
bool achieved = false;
input->get("achieved", &achieved);
if(achieved)
Achievement::load(node);
for (unsigned int i = 0; i < node->getNumNodes(); i++)
{
m_achieved = true;
return;
}
std::vector<XMLNode*> xml_entries;
input->getNodes("entry", xml_entries);
for (unsigned int n=0; n < xml_entries.size(); n++)
{
std::string key("");
xml_entries[n]->get("key", &key);
int value(0);
xml_entries[n]->get("value", &value);
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 status of this achievement to a file.
* \param out The file to write the state to.
*/
void MapAchievement::save(UTFWriter &out)
{
out << " <achievement id=\"" << m_id << "\" achieved=\""
<< StringUtils::toString(m_achieved) << "\">\n";
if(!m_achieved)
Achievement::save(out);
if (isAchieved())
{
std::map<std::string, int>::iterator i;
for ( i = m_progress_map.begin(); i != m_progress_map.end(); ++i )
{
out << " <entry key=\"" << i->first.c_str()
<< "\" value=\"" << StringUtils::toString(i->second)
<< "\"/>\n";
}
out << "/>\n";
return;
}
out << ">\n";
std::map<std::string, int>::iterator i;
for (i = m_progress_map.begin(); i != m_progress_map.end(); ++i)
{
out << " <" << i->first
<< " value=\"" << i->second << "\"/>\n";
}
out << " </achievement>\n";
} // save
// ============================================================================
// ----------------------------------------------------------------------------
int MapAchievement::getValue(const std::string & key)
{
@ -180,8 +212,7 @@ int MapAchievement::getValue(const std::string & key)
return 0;
}
// ============================================================================
// ----------------------------------------------------------------------------
void MapAchievement::reset()
{
std::map<std::string, int>::iterator iter;
@ -191,27 +222,27 @@ void MapAchievement::reset()
}
} // reset
// ============================================================================
// ----------------------------------------------------------------------------
void MapAchievement::increase(const std::string & key, int increase)
{
if ( m_progress_map.find(key) != m_progress_map.end())
if (m_progress_map.find(key) != m_progress_map.end())
{
m_progress_map[key] += increase;
check();
}
else
m_progress_map[key] = increase;
}
// ============================================================================
// ----------------------------------------------------------------------------
irr::core::stringw MapAchievement::getProgressAsString()
{
int progress(0);
int goal(0);
const std::map<std::string, int> goal_values = ((MapAchievementInfo *) m_achievement_info)->getGoalValues();
{
int progress = 0;
std::map<std::string, int>::const_iterator iter;
for ( iter = goal_values.begin(); iter != goal_values.end(); ++iter ) {
goal += iter->second;
progress += m_progress_map[iter->first];
for ( iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter)
{
progress += iter->second;
}
return StringUtils::toWString(progress) + "/" + StringUtils::toWString(goal);
return StringUtils::toWString(progress) + "/" + getInfo()->toString();
}

View File

@ -1,6 +1,7 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Glenn De Jonghe
// Copyright (C) 2013-2014 Glenn De Jonghe
// 2014 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@ -30,40 +31,61 @@ class XMLNode;
// ============================================================================
/**
* \brief
* \ingroup
*/
/** This is the base class for any achievement. It allows achievement status
* to be saved, and detects when an achievement is fulfilled.
* \ingroup achievements
*/
class AchievementInfo;
class Achievement
{
protected:
uint32_t m_id;
bool m_achieved;
const AchievementInfo * m_achievement_info;
void check ();
/** The id of this achievement. */
uint32_t m_id;
/** True if this achievement has been achieved. */
bool m_achieved;
/** A pointer to the corresponding AchievementInfo instance. */
const AchievementInfo *m_achievement_info;
void check();
public:
Achievement (const AchievementInfo * info);
virtual ~Achievement ();
uint32_t getID () const { return m_id; }
const AchievementInfo * getInfo () const { return m_achievement_info;}
virtual void load (XMLNode *input) = 0;
virtual void save (UTFWriter &out) = 0;
virtual void reset () = 0;
void onRaceEnd ();
void setAchieved () {m_achieved = true; };
virtual irr::core::stringw getProgressAsString () = 0;
enum AchievementType
{
AT_SINGLE,
AT_MAP
};
Achievement(const AchievementInfo * info);
virtual ~Achievement ();
virtual void load (const XMLNode *node) ;
virtual void save (UTFWriter &out) ;
virtual void reset () = 0;
virtual irr::core::stringw getProgressAsString() = 0;
void onRaceEnd();
// ------------------------------------------------------------------------
/** Returns the id of this achievement. */
uint32_t getID() const { return m_id; }
// ------------------------------------------------------------------------
/** Returns the AchievementInfo for this achievement. */
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; }
}; // class Achievement
// ============================================================================
/** This is a base class for an achievement that counts how often an event
* happened, and triggers the achievement to be fulfilled when a certain
* goal value is reached.
* \ingroup achievements
*/
class SingleAchievement : public Achievement
{
protected:
@ -73,7 +95,7 @@ public:
SingleAchievement (const AchievementInfo * info);
virtual ~SingleAchievement () {};
void load (XMLNode * input);
void load (const XMLNode *node);
int getValue () const { return m_progress; }
void save (UTFWriter &out);
void increase (int increase = 1);
@ -81,16 +103,23 @@ public:
virtual irr::core::stringw getProgressAsString ();
}; // class SingleAchievement
// ============================================================================
/** This achievement can keep track of a set of key-value pairs. Fulfillment is
* triggered when all values defined in the data/achievements.xml file have
* been reached.
* \ingroup achievements
*/
class MapAchievement : public Achievement
{
protected:
/** The map of key-value pairs. */
std::map<std::string, int> m_progress_map;
public:
MapAchievement (const AchievementInfo * info);
virtual ~MapAchievement () {};
void load (XMLNode * input);
void load (const XMLNode *node);
int getValue (const std::string & key);
void increase (const std::string & key, int increase = 1);
void save (UTFWriter &out);

View File

@ -25,27 +25,29 @@
#include <stdlib.h>
#include <assert.h>
// ============================================================================
AchievementInfo::AchievementInfo(const XMLNode * input)
{
input->get("id", &m_id);
input->get("title", &m_title);
input->get("description", &m_description);
std::string reset_after_race("");
input->get("reset_after_race", &reset_after_race);
m_reset_after_race = reset_after_race == "true";
}
input->get("id", &m_id );
input->get("title", &m_title );
input->get("description", &m_description );
input->get("reset_after_race", &m_reset_after_race);
} // AchievementInfo
// ============================================================================
SingleAchievementInfo::SingleAchievementInfo(const XMLNode * input)
: AchievementInfo(input)
{
input->get("goal", &m_goal_value);
}
} // SingleAchievementInfo
// ============================================================================
// ----------------------------------------------------------------------------
irr::core::stringw SingleAchievementInfo::toString() const
{
return StringUtils::toWString(m_goal_value);
} // toString
// ----------------------------------------------------------------------------
bool SingleAchievementInfo::checkCompletion(Achievement * achievement) const
{
SingleAchievement * single_achievement = (SingleAchievement *) achievement;
@ -71,13 +73,25 @@ MapAchievementInfo::MapAchievementInfo(const XMLNode * input)
if(m_goal_values.size() != xml_entries.size())
Log::error("MapAchievementInfo","Duplicate keys for the entries of a MapAchievement found.");
}
// ----------------------------------------------------------------------------
irr::core::stringw MapAchievementInfo::toString() const
{
int count = 0;
std::map<std::string, int>::const_iterator iter;
for (iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++)
{
count += iter->second;
}
return StringUtils::toWString(count);
} // toString
// ============================================================================
// ----------------------------------------------------------------------------
bool MapAchievementInfo::checkCompletion(Achievement * achievement) const
{
MapAchievement * map_achievement = (MapAchievement *) achievement;
std::map<std::string, int>::const_iterator iter;
for ( iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++ ) {
for ( iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++ )
{
if(map_achievement->getValue(iter->first) < iter->second)
return false;
}

View File

@ -21,65 +21,110 @@
#include "utils/types.hpp"
#include <irrString.h>
#include <string>
#include "io/xml_node.hpp"
#include "achievements/achievement.hpp"
#include <irrString.h>
#include <string>
// ============================================================================
class Achievement;
/**
* \brief
* \ingroup
/** 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.
* \ingroup achievements
*/
class AchievementInfo
{
protected:
uint32_t m_id;
/** The id of this Achievement. */
uint32_t m_id;
/** The title of this achievement. */
irr::core::stringw m_title;
/** The description of this achievement. */
irr::core::stringw m_description;
/** True if the achievement needs to be reset after each race. */
bool m_reset_after_race;
public:
AchievementInfo (const XMLNode * input);
virtual ~AchievementInfo () {};
uint32_t getID () const { return m_id; }
irr::core::stringw getDescription () const { return m_description; }
irr::core::stringw getTitle () const { return m_title; }
virtual Achievement::AchievementType getType () const = 0;
virtual bool checkCompletion (Achievement * achievement) const = 0;
bool needsResetAfterRace() const {return m_reset_after_race; }
virtual Achievement::AchievementType getType() const = 0;
virtual irr::core::stringw toString() const = 0;
virtual bool checkCompletion(Achievement * achievement) const = 0;
// ------------------------------------------------------------------------
/** Returns the id of this achievement. */
uint32_t getID() const { return m_id; }
// ------------------------------------------------------------------------
/** Returns the description of this achievement. */
irr::core::stringw getDescription() const { return m_description; }
// ------------------------------------------------------------------------
/** Returns the title of this achievement. */
irr::core::stringw getTitle() const { return m_title; }
// ------------------------------------------------------------------------
bool needsResetAfterRace() const { return m_reset_after_race; }
}; // class AchievementInfo
// ============================================================================
/** This class stores the information about an achievement that count a
* single value.
*/
class SingleAchievementInfo : public AchievementInfo
{
protected:
private:
/** Which value must be reached in order to achieve this achievement. */
int m_goal_value;
public:
SingleAchievementInfo (const XMLNode * input);
virtual ~SingleAchievementInfo () {};
int getGoalValue () const { return m_goal_value; }
virtual bool checkCompletion (Achievement * achievement) const;
virtual Achievement::AchievementType getType() const { return Achievement::AT_SINGLE; };
SingleAchievementInfo(const XMLNode * input);
virtual ~SingleAchievementInfo() {};
virtual irr::core::stringw toString() const;
virtual bool checkCompletion(Achievement * achievement) const;
// ------------------------------------------------------------------------
int getGoalValue() const { return m_goal_value; }
// ------------------------------------------------------------------------
virtual Achievement::AchievementType getType() const
{
return Achievement::AT_SINGLE;
} // getType
}; // class SingleAchievementInfo
// ============================================================================
/** This class stores a set of key-value pairs.
*/
class MapAchievementInfo : public AchievementInfo
{
protected:
/** The target values needed to be reached. */
std::map<std::string, int> m_goal_values;
public:
MapAchievementInfo (const XMLNode * input);
virtual ~MapAchievementInfo () {};
int getGoalValue (const std::string & key) { return m_goal_values[key];}
const std::map<std::string, int> & getGoalValues() const {return m_goal_values;}
virtual bool checkCompletion (Achievement * achievement) const;
virtual Achievement::AchievementType getType() const { return Achievement::AT_MAP; };
MapAchievementInfo(const XMLNode * input);
virtual ~MapAchievementInfo() {};
virtual bool checkCompletion(Achievement * achievement) const;
virtual irr::core::stringw toString() const;
// ------------------------------------------------------------------------
int getGoalValue(const std::string & key) { return m_goal_values[key]; }
// ------------------------------------------------------------------------
const std::map<std::string, int> & getGoalValues() const
{
return m_goal_values;
} // getGoalValues
// ------------------------------------------------------------------------
virtual Achievement::AchievementType getType() const
{
return Achievement::AT_MAP;
} // getType
}; // class MapAchievementInfo
#endif

View File

@ -94,14 +94,14 @@ void AchievementsStatus::deleteAchievements()
*/
void AchievementsStatus::save(UTFWriter &out)
{
out << L" <achievements online=\"" << m_online << L"\"> \n";
out << L" <achievements online=\"" << m_online << L"\"> \n";
std::map<uint32_t, Achievement*>::const_iterator i;
for(i = m_achievements.begin(); i != m_achievements.end(); i++)
{
if (i->second != NULL)
i->second->save(out);
}
out << L" </achievements>\n";
out << L" </achievements>\n";
} // save
// ----------------------------------------------------------------------------

View File

@ -271,7 +271,7 @@ void StoryModeStatus::grandPrixFinished()
*/
void StoryModeStatus::save(UTFWriter &out)
{
out << " <story-mode first-time=\"" << m_first_time << L"\">\n";
out << L" <story-mode first-time=\"" << m_first_time << L"\">\n";
std::map<std::string, ChallengeStatus*>::const_iterator i;
for(i = m_challenges_state.begin();
i != m_challenges_state.end(); i++)
@ -279,5 +279,5 @@ void StoryModeStatus::save(UTFWriter &out)
if (i->second != NULL)
i->second->save(out);
}
out << " </story-mode>\n";
out << L" </story-mode>\n";
} // save