Reimplement Gold Driver and Unstoppable by gathering data in general counters. Also fix #3487

This commit is contained in:
Alayan 2018-10-02 01:14:23 +02:00 committed by auriamg
parent 41ea4b1997
commit 70eb11de4f
6 changed files with 180 additions and 45 deletions

View File

@ -45,7 +45,6 @@
<standard goal="1"/>
<std_timetrial goal="1"/>
<follow_leader goal="1"/>
<opponents goal="3"/>
</achievement>
<achievement id="7" check-type="all-at-least" reset-type="race"
name="Powerup Love" description="Use 10 or more powerups in a race.">

View File

@ -41,6 +41,10 @@ AchievementsStatus::AchievementsStatus()
{
m_valid = true;
m_online = true;
for (unsigned int i=0; i<ACHIEVE_DATA_NUM; i++)
{
m_variables[i].counter = 0;
}
} // AchievementsStatus
// ----------------------------------------------------------------------------
@ -78,6 +82,29 @@ void AchievementsStatus::load(const XMLNode * input)
achievement->load(xml_achievements[i]);
} // for i in xml_achievements
// Load achievement data
int data_version = -1;
const XMLNode *n = input->getNode("data");
if (n!=NULL)
n->get("version", &data_version);
if (data_version == DATA_VERSION)
{
std::vector<XMLNode*> xml_achievement_data;
input->getNodes("var", xml_achievement_data);
for (unsigned int i = 0; i < xml_achievement_data.size(); i++)
{
if (i>=ACHIEVE_DATA_NUM)
{
Log::warn("AchievementsStatus",
"Found more saved achievement data "
"than there should be. Discarding.");
continue;
}
xml_achievement_data[i]->get("counter",&m_variables[i].counter);
}
}
// If there is nothing valid to load ; we keep the init values
} // load
// ----------------------------------------------------------------------------
@ -101,6 +128,11 @@ void AchievementsStatus::save(UTFWriter &out)
if (i->second != NULL)
i->second->save(out);
}
out << " <data version=\"1\"/>\n";
for(int i=0;i<ACHIEVE_DATA_NUM;i++)
{
out << " <var counter=\"" << m_variables[i].counter << "\"/>\n";
}
out << " </achievements>\n";
} // save
@ -157,6 +189,65 @@ void AchievementsStatus::sync(const std::vector<uint32_t> & achieved_ids)
}
} // sync
/* This function checks over achievements to update their goals
FIXME It is currently hard-coded to specific achievements,
until it can entirely supersedes the previous system and
removes its complications. */
void AchievementsStatus::updateAchievementsProgress(unsigned int achieve_data_id)
{
Achievement *gold_driver = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER);
Achievement *unstoppable = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_UNSTOPPABLE);
if (!unstoppable->isAchieved())
{
unstoppable->reset();
unstoppable->increase("wins", "wins", m_variables[ACHIEVE_CONS_WON_RACES].counter);
}
if (!gold_driver->isAchieved())
{
gold_driver->reset();
gold_driver->increase("standard", "standard", m_variables[ACHIEVE_WON_NORMAL_RACES].counter);
gold_driver->increase("std_timetrial", "std_timetrial", m_variables[ACHIEVE_WON_TT_RACES].counter);
gold_driver->increase("follow_leader", "follow_leader", m_variables[ACHIEVE_WON_FTL_RACES].counter);
}
}
// ----------------------------------------------------------------------------
void AchievementsStatus::increaseDataVar(unsigned int achieve_data_id, int increase)
{
if (achieve_data_id<ACHIEVE_DATA_NUM)
{
m_variables[achieve_data_id].counter += increase;
updateAchievementsProgress(achieve_data_id);
if (m_variables[achieve_data_id].counter > 10000000)
m_variables[achieve_data_id].counter = 10000000;
}
#ifdef DEBUG
else
{
Log::error("Achievements", "Achievement data id %i don't match any variable.",
achieve_data_id);
}
#endif
} // increaseDataVar
// ----------------------------------------------------------------------------
void AchievementsStatus::resetDataVar(unsigned int achieve_data_id)
{
if (achieve_data_id<ACHIEVE_DATA_NUM)
{
m_variables[achieve_data_id].counter = 0;
}
#ifdef DEBUG
else
{
Log::error("Achievements", "Achievement data id %i don't match any variable.",
achieve_data_id);
}
#endif
} // resetDataVar
// ----------------------------------------------------------------------------
void AchievementsStatus::onRaceEnd()
{

View File

@ -40,10 +40,44 @@ class XMLNode;
*/
class AchievementsStatus
{
public :
enum { // Won races values share the following properties :
// 1. Only races with at least 3 AI count unless otherwise specified.
ACHIEVE_WON_RACES = 0, // Normal, time-trial and FTL
ACHIEVE_WON_NORMAL_RACES = 1, // Normal race only
ACHIEVE_WON_TT_RACES = 2, // Time-trial race only
ACHIEVE_WON_FTL_RACES = 3, // Follow-the-leader race only
// Consecutive won race values :
// 1. Ignore races with not enough AIs for incrementation
// 2. Reset the counter in case of loss against any number of AIs
ACHIEVE_CONS_WON_RACES = 4,
// Won races in (at least) hard requires at least 5 AI opponents
ACHIEVE_CONS_WON_RACES_HARD = 5,
ACHIEVE_DATA_NUM = 6
};
private:
std::map<uint32_t, Achievement *> m_achievements;
bool m_online;
bool m_valid;
// Variables used to track achievements progress,
// one variable may be used by several achievements.
// TODO
// Currently this only uses an int counter.
// Evaluate if additional data keeping (max achived ?) can be useful,
// and either expand the struct or remove it.
struct AchievementVariable
{
int counter;
};
const int DATA_VERSION = 1;
// The tracked values are defined at compile time
AchievementVariable m_variables[ACHIEVE_DATA_NUM];
bool m_online;
bool m_valid;
class SyncAchievementsRequest : public Online::XMLRequest {
virtual void callback ();
@ -59,6 +93,9 @@ public :
void save(UTFWriter &out);
void add(Achievement *achievement);
void sync(const std::vector<uint32_t> & achieved_ids);
void updateAchievementsProgress(unsigned int achieve_data_id);
void increaseDataVar(unsigned int achieve_data_id, int increase);
void resetDataVar(unsigned int achieve_data_id);
void onRaceEnd();
void onLapEnd();
// ------------------------------------------------------------------------

View File

@ -165,6 +165,30 @@ public:
a->increase(key, goal_key.empty() ? key : goal_key, increase);
} // increaseAchievement
// ------------------------------------------------------------------------
/** A handy shortcut to increase points for an achievement data of the
* current player.
* \param achievement_data_id The achievement data id
* \param increase How much to increase the current value.
*/
static void increaseAchievement(unsigned int achievement_data_id,
int increase = 1)
{
getCurrentAchievementsStatus()
->increaseDataVar(achievement_data_id, increase);
} // increaseAchievement
// ------------------------------------------------------------------------
/** Reset an achievement data for current player.
* \param achievement_data_id The achievement data id
*/
static void resetAchievementData(unsigned int achievement_data_id)
{
getCurrentAchievementsStatus()
->resetDataVar(achievement_data_id);
} // resetAchievementData
// ------------------------------------------------------------------------
}; // PlayerManager
#endif

View File

@ -624,61 +624,43 @@ void World::terminateRace()
"laps", race_manager->getNumLaps());
}
Achievement *achiev = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER);
if (achiev)
// Increment won races counts
if (race_manager->isLinearRaceMode())
{
std::string mode_name = getIdent(); // Get the race mode name
int winner_position = 1;
unsigned int opponents = achiev->getInfo()->getGoalValue("opponents"); // Get the required opponents number
if (mode_name == IDENT_FTL)
{
winner_position = 2;
opponents++;
}
for(unsigned int i = 0; i < kart_amount; i++)
{
// Retrieve the current player
if (m_karts[i]->getController()->canGetAchievements())
{
int winner_position = 1;
if (race_manager->isFollowMode()) winner_position = 2;//TODO : check this always work
// Check if the player has won
if (m_karts[i]->getPosition() == winner_position && kart_amount > opponents )
if (m_karts[i]->getPosition() == winner_position && race_manager->getNumberOfAIKarts() >= 3)
{
// Update the achievement
mode_name = StringUtils::toLowerCase(mode_name);
if (achiev->getValue("opponents") <= 0)
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER,
"opponents", opponents);
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER,
mode_name, 1);
}
}
} // for i < kart_amount
} // if (achiev)
PlayerManager::increaseAchievement(AchievementsStatus::ACHIEVE_WON_RACES,1);
PlayerManager::increaseAchievement(AchievementsStatus::ACHIEVE_CONS_WON_RACES,1);
if (race_manager->isTimeTrialMode())
PlayerManager::increaseAchievement(AchievementsStatus::ACHIEVE_WON_TT_RACES,1);
else if (race_manager->isFollowMode())
PlayerManager::increaseAchievement(AchievementsStatus::ACHIEVE_WON_FTL_RACES,1);
else // normal race
PlayerManager::increaseAchievement(AchievementsStatus::ACHIEVE_WON_NORMAL_RACES,1);
Achievement *win = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_UNSTOPPABLE);
//if achivement has been unlocked
if (win->getValue("wins") < 5 )
{
for(unsigned int i = 0; i < kart_amount; i++)
{
// Retrieve the current player
if (m_karts[i]->getController()->canGetAchievements())
{
// Check if the player has won
if (m_karts[i]->getPosition() == 1 )
{
// Increase number of consecutive wins
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_UNSTOPPABLE,
"wins", 1);
if (race_manager->getNumberOfAIKarts() >= 5 &&
(race_manager->getDifficulty() == RaceManager::DIFFICULTY_HARD ||
race_manager->getDifficulty() == RaceManager::DIFFICULTY_BEST))
PlayerManager::increaseAchievement(AchievementsStatus::ACHIEVE_CONS_WON_RACES_HARD,1);
}
else
// Race lost, reset the consecutive wins counters
else if (m_karts[i]->getPosition() > winner_position)
{
//Set number of consecutive wins to 0
win->reset();
PlayerManager::resetAchievementData(AchievementsStatus::ACHIEVE_CONS_WON_RACES);
PlayerManager::resetAchievementData(AchievementsStatus::ACHIEVE_CONS_WON_RACES_HARD);
}
}
}
}
} // for i<kart_amount
} // if isLinearRaceMode
PlayerManager::getCurrentPlayer()->raceFinished();
if (m_race_gui) m_race_gui->clearAllMessages();

View File

@ -514,6 +514,8 @@ public:
* AI karts. */
unsigned int getNumberOfKarts() const {return m_num_karts; }
// ------------------------------------------------------------------------
unsigned int getNumberOfAIKarts() const {return m_ai_kart_list.size(); }
// ------------------------------------------------------------------------
unsigned int getNumNonGhostKarts() const { return m_num_karts - m_num_ghost_karts; }
// ------------------------------------------------------------------------
MajorRaceModeType getMajorMode() const { return m_major_mode; }