tutorial developing progress commit
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@7087 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
5a74502c29
commit
2e5689134c
@ -2,21 +2,18 @@
|
||||
|
||||
<div x="5%" y="2%" width="90%" height="96%" layout="vertical-row" >
|
||||
|
||||
<header I18N="Title for challenges screen" text="Tutorial : Selection Room" text_align="center" width="100%" />
|
||||
|
||||
<box id="animated_area" width="100%" proportion="1" layout="vertical-row">
|
||||
|
||||
<ribbon_grid id="tutorial" proportion="3" width="100%"
|
||||
label_location="bottom" align="center" child_width="128" child_height="128" />
|
||||
<header I18N="Title for tutorials screen" text="Tutorial : Selection Room" text_align="center" width="100%" />
|
||||
|
||||
<spacer proportion="1" width="100%"/>
|
||||
|
||||
<list id="tutorials" proportion="5" width="75%" align="center"/>
|
||||
|
||||
<spacer proportion="1" width="100%"/>
|
||||
|
||||
</box>
|
||||
|
||||
<spacer width="100%" height="45"/>
|
||||
|
||||
</div>
|
||||
|
||||
<button id="back" x="20" y="-40" height="35" align="left" text="Back to main menu"/>
|
||||
<button id="play" x="-200" y="-40" height="35" align="right" text="Play all"/>
|
||||
|
||||
</stkgui>
|
@ -15,10 +15,13 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
#include "states_screens/tutorial_screen.hpp"
|
||||
|
||||
#include "challenges/unlock_manager.hpp"
|
||||
#include "guiengine/widgets/list_widget.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
|
||||
#include "tutorial/tutorial_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/widgets/dynamic_ribbon_widget.hpp"
|
||||
@ -65,46 +68,62 @@ void TutorialScreen::onUpdate(float elapsed_time, irr::video::IVideoDriver*)
|
||||
void TutorialScreen::init()
|
||||
{
|
||||
Screen::init();
|
||||
DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("tutorial");
|
||||
assert( w != NULL );
|
||||
|
||||
ListWidget* tutorials_list = this->getWidget<ListWidget>("tutorials");
|
||||
assert( tutorials_list != NULL );
|
||||
|
||||
// FIXME different icons for each tutorial option & add then to
|
||||
video::ITexture* tutorial_icon = irr_driver->getTexture( file_manager->getGUIDir() + "/keyboard.png" );
|
||||
|
||||
m_icon_bank = new irr::gui::STKModifiedSpriteBank( GUIEngine::getGUIEnv() );
|
||||
m_icon_bank->addTextureAsSprite(tutorial_icon);
|
||||
|
||||
// scale icons depending on screen resolution. the numbers below are a bit arbitrary
|
||||
const int screen_width = irr_driver->getFrameSize().Width;
|
||||
const float scale = 0.3f + 0.2f*std::max(0, screen_width - 640)/564.0f;
|
||||
m_icon_bank->setScale(scale);
|
||||
|
||||
// Add the icons to our list
|
||||
tutorials_list->setIcons(m_icon_bank);
|
||||
// Re-build track list everytime (accounts for locking changes, etc.)
|
||||
w->clearItems();
|
||||
//tutorials_list->clearItems();
|
||||
|
||||
const std::vector<const Challenge*>& activeChallenges = unlock_manager->getActiveChallenges();
|
||||
const std::vector<const Challenge*>& solvedChallenges = unlock_manager->getUnlockedFeatures();
|
||||
const std::vector<const Challenge*>& lockedChallenges = unlock_manager->getLockedChallenges();
|
||||
/* const std::vector<const Challenge*>& activeTutorials = tutorial_manager->getActiveChallenges();
|
||||
const std::vector<const Challenge*>& solvedTutorials = tutorial_manager->getUnlockedFeatures();
|
||||
const std::vector<const Challenge*>& lockedTutorials = tutorial_manager->getLockedChallenges();
|
||||
|
||||
const int activeChallengeAmount = activeChallenges.size();
|
||||
const int solvedChallengeAmount = solvedChallenges.size();
|
||||
const int lockedChallengeAmount = lockedChallenges.size();
|
||||
const int activeTutorialAmount = activeTutorials.size();
|
||||
const int solvedTutorialAmount = solvedTutorials.size();
|
||||
const int lockedTutorialAmount = lockedTutorials.size();
|
||||
*/
|
||||
|
||||
for (int n=0; n<activeChallengeAmount; n++)
|
||||
// FIXME Hard coded tutorial options
|
||||
tutorials_list->addItem(BASIC_DRIVING, " Basic Driving" , 0);
|
||||
tutorials_list->addItem(SHARP_TURN, " Sharp Turn" , 0);
|
||||
tutorials_list->addItem(NITRO, " Nitro" , 0 );
|
||||
tutorials_list->addItem(COLLECTIBLE_WEAPONS, " Collectible Weapons" , 0);
|
||||
tutorials_list->addItem(SHOOTING_BACKWARDS, " Shooting Backwards" , 0);
|
||||
|
||||
/* for (int i=0;i<5;i++)
|
||||
{
|
||||
w->addItem(activeChallenges[n]->getName() + L"\n" + activeChallenges[n]->getChallengeDescription(),
|
||||
activeChallenges[n]->getId(), "/gui/tutorial.png");
|
||||
}
|
||||
for (int n=0; n<solvedChallengeAmount; n++)
|
||||
{
|
||||
// TODO : add bronze/silver/gold difficulties to challenges
|
||||
w->addItem(solvedChallenges[n]->getName() + L"\n" + solvedChallenges[n]->getChallengeDescription(),
|
||||
solvedChallenges[n]->getId(), "/textures/cup_gold.png");
|
||||
}
|
||||
for (int n=0; n<lockedChallengeAmount; n++)
|
||||
{
|
||||
w->addItem( _("Locked : solve active tutorial to gain access to more!"), "locked",
|
||||
"/gui/tutorial.png", LOCKED_BADGE);
|
||||
//KeyboardConfig *config = input_manager->getDeviceList()->getKeyboardConfig(i);
|
||||
|
||||
std::ostringstream kbname;
|
||||
kbname << "keyboard" << i;
|
||||
const std::string internal_name = kbname.str();
|
||||
|
||||
//FIXME: I18N: since irrLicht's list widget has the nasty tendency to put the
|
||||
// icons very close to the text, I'm adding spaces to compensate...
|
||||
|
||||
}
|
||||
// tutorials_list->updateItemDisplay();
|
||||
|
||||
|
||||
w->updateItemDisplay();
|
||||
|
||||
if (w->getItems().empty())
|
||||
/* if (tutorials_list->getItems().empty())
|
||||
{
|
||||
fprintf(stderr, "Error, no tutorial!\n");
|
||||
return;
|
||||
}
|
||||
w->setSelection(0 /* whatever is first */, PLAYER_ID_GAME_MASTER, true /* focus it */);
|
||||
}*/
|
||||
//tutorials_list->setSelection(0 /* whatever is first */, PLAYER_ID_GAME_MASTER, true /* focus it */);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
@ -115,15 +134,104 @@ void TutorialScreen::eventCallback(GUIEngine::Widget* widget, const std::string&
|
||||
{
|
||||
StateManager::get()->escapePressed();
|
||||
}
|
||||
else if (name == "tutorial")
|
||||
else if (name == "tutorials")
|
||||
{
|
||||
DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("tutorial");
|
||||
ListWidget* tutorials = this->getWidget<ListWidget>("tutorials");
|
||||
const std::string& selection = tutorials->getSelectionInternalName();
|
||||
if (selection == BASIC_DRIVING)
|
||||
{
|
||||
//FIXME: simplify and centralize race start sequence!!
|
||||
|
||||
// Verify the kart in the config exists
|
||||
if (kart_properties_manager->getKart(UserConfigParams::m_default_kart) == NULL)
|
||||
{
|
||||
UserConfigParams::m_default_kart.revertToDefaults();
|
||||
}
|
||||
|
||||
// Use latest used device
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
|
||||
// Create player and associate player with device (FIXME: ask for player ident)
|
||||
StateManager::get()->createActivePlayer( UserConfigParams::m_all_players.get(0), device );
|
||||
|
||||
// Set up race manager appropriately
|
||||
race_manager->setNumLocalPlayers(1);
|
||||
race_manager->setLocalKartInfo(0, UserConfigParams::m_default_kart);
|
||||
|
||||
// ASSIGN should make sure that only input from assigned devices is read.
|
||||
input_manager->getDeviceList()->setAssignMode(ASSIGN);
|
||||
|
||||
// Go straight to the race
|
||||
StateManager::get()->enterGameState();
|
||||
|
||||
// Initialise global data - necessary even in local games to avoid
|
||||
// many if tests in other places (e.g. if network_game call
|
||||
// network_manager else call race_manager).
|
||||
network_manager->initCharacterDataStructures();
|
||||
|
||||
// Launch tutorial
|
||||
//tutorial_manager->getTutorial(selection)->setRace();
|
||||
|
||||
// FIXME this code have to be in Tutorial class (and loaded from file xD)
|
||||
RaceManager::MajorRaceModeType m_major;
|
||||
RaceManager::MinorRaceModeType m_minor;
|
||||
RaceManager::Difficulty m_difficulty;
|
||||
|
||||
m_minor = RaceManager::MINOR_MODE_NORMAL_RACE;
|
||||
m_major = RaceManager::MAJOR_MODE_SINGLE;
|
||||
m_difficulty = RaceManager::RD_EASY;
|
||||
|
||||
race_manager->setMinorMode(m_minor);
|
||||
race_manager->setMajorMode(m_major);
|
||||
race_manager->setTrack((std::string)"canyon");
|
||||
|
||||
race_manager->setDifficulty(m_difficulty);
|
||||
race_manager->setNumLaps(1);
|
||||
race_manager->setNumKarts(1);
|
||||
race_manager->setNumPlayers(1);
|
||||
race_manager->setNumLocalPlayers(1);
|
||||
|
||||
//race_manager->setCoinTarget(m_energy);
|
||||
|
||||
// Sets up kart info, including random list of kart for AI
|
||||
network_manager->setupPlayerKartInfo();
|
||||
race_manager->startNew();
|
||||
}
|
||||
else if (name == SHARP_TURN)
|
||||
{
|
||||
}
|
||||
else if (name == NITRO)
|
||||
{
|
||||
}
|
||||
else if (name == COLLECTIBLE_WEAPONS)
|
||||
{
|
||||
}
|
||||
else if (name == SHOOTING_BACKWARDS)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
/*int i = -1, read = 0;
|
||||
read = sscanf( selection.c_str(), "gamepad%i", &i );
|
||||
if (read == 1 && i != -1)
|
||||
{
|
||||
OptionsScreenInput2::getInstance()->setDevice( input_manager->getDeviceList()->getGamepadConfig(i) );
|
||||
StateManager::get()->replaceTopMostScreen(OptionsScreenInput2::getInstance());
|
||||
//updateInputButtons( input_manager->getDeviceList()->getGamepadConfig(i) );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Cannot read internal gamepad input device ID : " << selection.c_str() << std::endl;
|
||||
}*/
|
||||
|
||||
|
||||
/* DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("tutorial");
|
||||
assert( w != NULL );
|
||||
|
||||
// only player 0 can start a challenge (i.e. we have no multiplayer tutorial)
|
||||
std::string selection = w->getSelectionIDString( PLAYER_ID_GAME_MASTER );
|
||||
|
||||
if (selection == "locked")
|
||||
/*if (selection == "locked")
|
||||
{
|
||||
unlock_manager->playLockSound();
|
||||
}
|
||||
@ -164,9 +272,9 @@ void TutorialScreen::eventCallback(GUIEngine::Widget* widget, const std::string&
|
||||
// Sets up kart info, including random list of kart for AI
|
||||
network_manager->setupPlayerKartInfo();
|
||||
race_manager->startNew();
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -21,13 +21,26 @@
|
||||
#include "irrlicht.h"
|
||||
#include "guiengine/screen.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
#include "guiengine/CGUISpriteBank.h"
|
||||
|
||||
using namespace irr::core;
|
||||
|
||||
const std::string BASIC_DRIVING = "bd";
|
||||
const std::string SHARP_TURN = "st";
|
||||
const std::string NITRO = "nt";
|
||||
const std::string COLLECTIBLE_WEAPONS = "cw";
|
||||
const std::string SHOOTING_BACKWARDS = "sb";
|
||||
|
||||
class TutorialScreen : public GUIEngine::Screen, public GUIEngine::ScreenSingleton<TutorialScreen>
|
||||
{
|
||||
{
|
||||
|
||||
|
||||
friend class GUIEngine::ScreenSingleton<TutorialScreen>;
|
||||
TutorialScreen();
|
||||
|
||||
irr::gui::STKModifiedSpriteBank* m_icon_bank;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
|
@ -27,12 +27,12 @@
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <irrlicht.h>
|
||||
|
||||
// SuperTuxKart includes
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
|
||||
using namespace std; // To avoid using std:: all the time
|
||||
|
||||
using namespace irr::core;
|
||||
class XMLNode;
|
||||
|
||||
enum REWARD_TYPE
|
||||
@ -42,14 +42,14 @@ enum REWARD_TYPE
|
||||
UNLOCK_KART,
|
||||
UNLOCK_DIFFICULTY};
|
||||
|
||||
struct UnlockableFeature
|
||||
/*struct UnlockableFeature
|
||||
{
|
||||
string name; // internal name
|
||||
irr::core::stringw user_name; // not all types of feature have one
|
||||
stringw user_name; // not all types of feature have one
|
||||
REWARD_TYPE type;
|
||||
|
||||
const irr::core::stringw getUnlockedMessage() const;
|
||||
};
|
||||
const stringw getUnlockedMessage() const;
|
||||
};*/
|
||||
|
||||
|
||||
/**
|
||||
@ -59,61 +59,62 @@ struct UnlockableFeature
|
||||
class Tutorial : public NoCopy
|
||||
{
|
||||
private:
|
||||
enum {CH_INACTIVE, // challenge not yet possible
|
||||
// TBR ????
|
||||
enum {CH_INACTIVE, // tutorial not yet possible
|
||||
CH_ACTIVE, // challenge possible, but not yet solved
|
||||
CH_SOLVED} m_state; // challenge was solved
|
||||
|
||||
string m_Id; // short, internal name for this tutorial
|
||||
irr::core::stringw m_Name; // name used in menu for this tutorial
|
||||
irr::core::stringw m_challenge_description; // Message the user gets when the feature is not yet unlocked
|
||||
vector<UnlockableFeature> m_feature; // Features to unlock
|
||||
vector<string> m_prerequisites; // what needs to be done before accessing this tutorial
|
||||
std::string m_Id; // short, internal name for this tutorial
|
||||
irr::core::stringw m_Name; // name used in menu for this tutorial
|
||||
irr::core::stringw m_challenge_description; // Message the user gets when the feature is not yet unlocked
|
||||
// vector<UnlockableFeature> m_feature; // Features to unlock
|
||||
// vector<string> m_prerequisites; // what needs to be done before accessing this tutorial
|
||||
|
||||
public:
|
||||
// Constructors + Destructor
|
||||
Tutorial(const string &id, const string &name);
|
||||
Tutorial(const std::string &id, const std::string &name);
|
||||
Tutorial() {m_Id=""; m_Name="";m_state=CH_INACTIVE;}
|
||||
virtual ~Tutorial() {};
|
||||
|
||||
const string &getId() const { return m_Id; }
|
||||
const irr::core::stringw &getName() const { return m_Name; }
|
||||
void setName(const irr::core::stringw & s) { m_Name = s; }
|
||||
void setId(const string& s) { m_Id = s; }
|
||||
void addUnlockTrackReward(const string &track_name);
|
||||
void addUnlockModeReward(const string &internal_mode_name,
|
||||
const std::string &getId() const { return m_Id;}
|
||||
irr::core::stringw getName() const { return m_Name;}
|
||||
void setName(const irr::core::stringw & s) { m_Name = s;}
|
||||
void setId(const std::string& s) { m_Id = s;}
|
||||
void addUnlockTrackReward(const std::string &track_name);
|
||||
void addUnlockModeReward(const std::string &internal_mode_name,
|
||||
const irr::core::stringw &user_mode_name);
|
||||
void addUnlockGPReward(const string &gp_name);
|
||||
void addUnlockDifficultyReward(const string &internal_name,
|
||||
/* void addUnlockGPReward(const std::string &gp_name);
|
||||
void addUnlockDifficultyReward(const std::string &internal_name,
|
||||
const irr::core::stringw &user_name);
|
||||
void addUnlockKartReward(const string &internal_name,
|
||||
void addUnlockKartReward(const std::string &internal_name,
|
||||
const irr::core::stringw &user_name);
|
||||
|
||||
const vector<UnlockableFeature>&
|
||||
/*const vector<UnlockableFeature>&
|
||||
getFeatures() const { return m_feature; }
|
||||
void setChallengeDescription(const irr::core::stringw& d)
|
||||
{m_challenge_description=d; }
|
||||
const irr::core::stringw&
|
||||
getChallengeDescription() const {return m_challenge_description; }
|
||||
void addDependency(const string id) {m_prerequisites.push_back(id); }
|
||||
void addDependency(const std::string id) {m_prerequisites.push_back(id); }
|
||||
bool isSolved() const {return m_state==CH_SOLVED; }
|
||||
bool isActive() const {return m_state==CH_ACTIVE; }
|
||||
void setSolved() {m_state = CH_SOLVED; }
|
||||
void setActive() {m_state = CH_ACTIVE; }
|
||||
const vector<string>&
|
||||
const vector<std::string>&
|
||||
getPrerequisites() const {return m_prerequisites; }
|
||||
void load(const XMLNode* config);
|
||||
void save(ofstream& writer);
|
||||
|
||||
// These functions are meant for customisation, e.g. load/save
|
||||
// additional state information specific to the challenge
|
||||
virtual void loadAdditionalInfo(const XMLNode* config) {};
|
||||
virtual void saveAdditionalInfo(ofstream& writer) {};
|
||||
// additional state information specific to the tutorial
|
||||
virtual void loadAdditionalInfo(const XMLNode* config) {};
|
||||
virtual void saveAdditionalInfo(ofstream& writer) {};
|
||||
|
||||
// These functions are called when a race/gp is finished. It allows
|
||||
// the challenge to unlock features (when returning true), otherwise
|
||||
// the feature remains locked.
|
||||
virtual bool raceFinished() {return false;} // end of a race
|
||||
virtual bool grandPrixFinished() {return false;} // end of a GP
|
||||
//virtual bool grandPrixFinished() {return false;} // end of a GP
|
||||
|
||||
/** sets the right parameters in RaceManager to try this tutorial */
|
||||
virtual void setRace() const = 0;
|
||||
|
@ -1,11 +1,406 @@
|
||||
#include "tutorial_manager.hpp"
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2010 Alejandro Santiago
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "tutorial/tutorial_manager.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "audio/sfx_base.hpp"
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
TutorialManager* tutorial_manager=0;
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
TutorialManager::TutorialManager()
|
||||
{
|
||||
//ctor
|
||||
}
|
||||
// The global variable 'tutorial_manager' is needed in the tutorials,
|
||||
// but it's not set yet - so we define it here (and it gets re-assign
|
||||
// in main).
|
||||
tutorial_manager=this;
|
||||
|
||||
m_locked_sound = sfx_manager->createSoundSource("locked");
|
||||
|
||||
// FIXME : Read tutorials from .../data
|
||||
// -----------------------------
|
||||
//std::set<std::string> result;
|
||||
//file_manager->listFiles(result, "data");
|
||||
//for(std::set<std::string>::iterator i = result.begin();
|
||||
// i != result.end() ; i++)
|
||||
//{
|
||||
// if (StringUtils::hasSuffix(*i, ".challenge"))
|
||||
// addChallenge(file_manager->getDataFile(*i));
|
||||
//} // for i
|
||||
|
||||
//// Read tutorials from .../data/tracks/*
|
||||
//// --------------------------------------
|
||||
//const std::vector<std::string> *all_track_dirs = track_manager->getAllTrackDirs();
|
||||
//for(std::vector<std::string>::const_iterator dir=all_track_dirs->begin();
|
||||
// dir!=all_track_dirs->end(); dir++)
|
||||
//{
|
||||
// std::set<std::string> all_files;
|
||||
// file_manager->listFiles(all_files, *dir, /*is_full_path*/ true);
|
||||
// for(std::set<std::string>::iterator file=all_files.begin();
|
||||
// file!=all_files.end(); file++)
|
||||
// {
|
||||
// if(!StringUtils::hasSuffix(*file,".challenge")) continue;
|
||||
// std::string filename=*dir+"/"+*file;
|
||||
// FILE *f=fopen(filename.c_str(), "r");
|
||||
// if(f)
|
||||
// {
|
||||
// fclose(f);
|
||||
// ChallengeData* newChallenge = NULL;
|
||||
// try
|
||||
// {
|
||||
// newChallenge = new ChallengeData(filename);
|
||||
// }
|
||||
// catch (std::runtime_error& ex)
|
||||
// {
|
||||
// std::cerr << "\n/!\\ An error occurred while loading challenge file '" << filename << "' : "
|
||||
// << ex.what() << " : challenge will be ignored.\n\n";
|
||||
// continue;
|
||||
// }
|
||||
// addChallenge(newChallenge);
|
||||
|
||||
// } // if file
|
||||
// } // for file in files
|
||||
//} // for dir in all_track_dirs
|
||||
|
||||
//// Load challenges from .../data/karts (FIXME: the code below is just copied and pasted from above xD)
|
||||
//// -----------------------------------
|
||||
//const std::vector<std::string> *all_kart_dirs =
|
||||
// kart_properties_manager->getAllKartDirs();
|
||||
|
||||
//// Find out which characters are available and load them
|
||||
//for(std::vector<std::string>::const_iterator dir = all_kart_dirs->begin();
|
||||
// dir != all_kart_dirs->end(); dir++)
|
||||
//{
|
||||
// std::set<std::string> all_files;
|
||||
// file_manager->listFiles(all_files, *dir, /*is_full_path*/ true);
|
||||
// for(std::set<std::string>::iterator file=all_files.begin();
|
||||
// file!=all_files.end(); file++)
|
||||
// {
|
||||
// if(!StringUtils::hasSuffix(*file,".challenge")) continue;
|
||||
// std::string filename=*dir+"/"+*file;
|
||||
// FILE *f=fopen(filename.c_str(), "r");
|
||||
// if(f)
|
||||
// {
|
||||
// fclose(f);
|
||||
//
|
||||
// ChallengeData* newChallenge = NULL;
|
||||
// try
|
||||
// {
|
||||
// newChallenge = new ChallengeData(filename);
|
||||
// }
|
||||
// catch (std::runtime_error& ex)
|
||||
// {
|
||||
// std::cerr << "\n/!\\ An error occurred while loading challenge file '" << filename << "' : "
|
||||
// << ex.what() << " : challenge will be ignored.\n\n";
|
||||
// continue;
|
||||
// }
|
||||
// addChallenge(newChallenge);
|
||||
// } // if file
|
||||
// } // for file in files
|
||||
//} // for dir in all_karts_dirs
|
||||
|
||||
//// Challenges from .../data/grandprix
|
||||
//// ----------------------------------
|
||||
//file_manager->listFiles(result, "data/grandprix");
|
||||
//for(std::set<std::string>::iterator i = result.begin();
|
||||
// i != result.end() ; i++)
|
||||
//{
|
||||
// if (StringUtils::hasSuffix(*i, ".challenge"))
|
||||
// addChallenge(file_manager->getDataFile("grandprix/"+*i));
|
||||
//} // for i
|
||||
|
||||
//// Hard coded challenges can be added here.
|
||||
|
||||
//computeActive(); //FIXME: 'load' calls 'computeActive', not sure this call here is needed
|
||||
load();
|
||||
|
||||
} // UnlockManager
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
** Saves the challenge status.
|
||||
*/
|
||||
TutorialManager::~TutorialManager()
|
||||
{
|
||||
//dtor
|
||||
//save();
|
||||
|
||||
// sfx_manager is destroyed before UnlockManager is, so SFX will be already deleted
|
||||
// sfx_manager->deleteSFX(m_locked_sound);
|
||||
} // ~UnlockManager
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void TutorialManager::addTutorial(Tutorial * m_tutorial)
|
||||
{
|
||||
m_all_tutorials[m_tutorial->getId()]=m_tutorial;
|
||||
} // addTutorial
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void TutorialManager::addTutorial(const std::string& filename)
|
||||
{
|
||||
/* ChallengeData* newChallenge = NULL;
|
||||
try
|
||||
{
|
||||
newChallenge = new ChallengeData(filename);
|
||||
newChallenge->check();
|
||||
}
|
||||
catch (std::runtime_error& ex)
|
||||
{
|
||||
std::cerr << "\n/!\\ An error occurred while loading challenge file '" << filename << "' : "
|
||||
<< ex.what() << " : challenge will be ignored.\n\n";
|
||||
if (newChallenge != NULL) delete newChallenge;
|
||||
return;
|
||||
}
|
||||
addChallenge(newChallenge);*/
|
||||
|
||||
} // addChallenge
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
std::vector<const Tutorial*> TutorialManager::getActiveTutorials()
|
||||
{
|
||||
computeActive();
|
||||
std::vector<const Tutorial*> all_active;
|
||||
//for(AllChallengesType::iterator i =m_all_challenges.begin();
|
||||
// i!=m_all_challenges.end(); i++)
|
||||
//{
|
||||
// if(i->second->isActive()) all_active.push_back(i->second);
|
||||
//}
|
||||
return all_active;
|
||||
} // getActiveChallenges
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const Tutorial* TutorialManager::getTutorial(const std::string& id)
|
||||
{
|
||||
if(m_all_tutorials.find(id)==m_all_tutorials.end()) return NULL;
|
||||
return m_all_tutorials[id];
|
||||
} // getTutorial
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
** This is called from user_config when reading the config file
|
||||
*/
|
||||
void TutorialManager::load()
|
||||
{
|
||||
const std::string filename=file_manager->getChallengeFile("challenges.xml");
|
||||
XMLNode* root = file_manager->createXMLTree(filename);
|
||||
if(!root || root->getName() != "challenges")
|
||||
{
|
||||
std::cerr << "Challenge file '" << filename << "' will be created."
|
||||
<< std::endl;
|
||||
save();
|
||||
|
||||
if (root) delete root;
|
||||
return;
|
||||
}
|
||||
|
||||
for(AllTutorialsType::iterator i = m_all_tutorials.begin();
|
||||
i!= m_all_tutorials.end(); i++)
|
||||
{
|
||||
// i->second->load(root);
|
||||
}
|
||||
computeActive();
|
||||
|
||||
delete root;
|
||||
} // load
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void TutorialManager::save()
|
||||
{
|
||||
//std::ofstream challenge_file;
|
||||
//std::string filename = file_manager->getChallengeFile("challenges.xml");
|
||||
//challenge_file.open(filename.c_str());
|
||||
|
||||
//if(!challenge_file.is_open())
|
||||
//{
|
||||
// std::cerr << "Failed to open " << filename << " for writing, challenges won't be saved\n";
|
||||
// return;
|
||||
//}
|
||||
|
||||
//challenge_file << "<?xml version=\"1.0\"?>\n";
|
||||
//challenge_file << "<challenges>\n";
|
||||
//
|
||||
//for(AllChallengesType::iterator i = m_all_challenges.begin();
|
||||
// i!= m_all_challenges.end(); i++)
|
||||
//{
|
||||
// i->second->save(challenge_file);
|
||||
//}
|
||||
//
|
||||
//challenge_file << "</challenges>\n\n";
|
||||
//challenge_file.close();
|
||||
} // save
|
||||
|
||||
void TutorialManager::playLockSound() const
|
||||
{
|
||||
m_locked_sound->play();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void TutorialManager::computeActive()
|
||||
{
|
||||
// for(AllChallengesType::iterator i =m_all_challenges.begin();
|
||||
// i!=m_all_challenges.end(); i++)
|
||||
// {
|
||||
// // Changed challenge
|
||||
// // -----------------
|
||||
// if((i->second)->isSolved())
|
||||
// {
|
||||
// // The constructor calls computeActive, which actually locks
|
||||
// // all features, so unlock the solved ones (and don't try to
|
||||
// // save the state, since we are currently reading it)
|
||||
//
|
||||
// unlockFeature(i->second, /*save*/ false);
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// // Otherwise lock the feature, and check if the challenge is active
|
||||
// // ----------------------------------------------------------------
|
||||
// lockFeature(i->second);
|
||||
// std::vector<std::string> pre_req=(i->second)->getPrerequisites();
|
||||
// bool allSolved=true;
|
||||
// for(std::vector<std::string>::iterator pre =pre_req.begin();
|
||||
// pre!=pre_req.end(); pre++)
|
||||
// {
|
||||
// const Challenge*p = getChallenge(*pre);
|
||||
// if(!p)
|
||||
// {
|
||||
// fprintf(stderr,"Challenge prerequisite '%s' of '%s' not found - ignored\n",
|
||||
// pre->c_str(), i->first.c_str());
|
||||
// //continue;
|
||||
// allSolved=false;
|
||||
// break;
|
||||
// }
|
||||
// else if(!p->isSolved())
|
||||
// {
|
||||
// allSolved=false;
|
||||
// break;
|
||||
// }
|
||||
// } // for all pre in pre_req
|
||||
// if(allSolved)
|
||||
// {
|
||||
// i->second->setActive();
|
||||
// } // if solved
|
||||
// } // for i
|
||||
// clearUnlocked();
|
||||
//
|
||||
} // computeActive
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
** This is called when a race is finished. Call all active challenges
|
||||
*/
|
||||
//void TutorialManager::raceFinished()
|
||||
//{
|
||||
// //for(AllChallengesType::iterator i =m_all_challenges.begin();
|
||||
// // i!=m_all_challenges.end(); i++)
|
||||
// //{
|
||||
// // if(i->second->isActive() && i->second->raceFinished())
|
||||
// // {
|
||||
// // unlockFeature(i->second);
|
||||
// // } // if isActive && challenge solved
|
||||
// //}
|
||||
// //race_manager->setCoinTarget(0); //reset
|
||||
//} // raceFinished
|
||||
|
||||
////-----------------------------------------------------------------------------
|
||||
//void UnlockManager::grandPrixFinished()
|
||||
//{
|
||||
// for(AllChallengesType::iterator i =m_all_challenges.begin();
|
||||
// i!=m_all_challenges.end(); i++)
|
||||
// {
|
||||
// if(i->second->isActive() && i->second->grandPrixFinished())
|
||||
// {
|
||||
// std::cout << "===== A FEATURE WAS UNLOCKED BECAUSE YOU WON THE GP!! ==\n";
|
||||
// unlockFeature(i->second);
|
||||
// }
|
||||
// }
|
||||
// race_manager->setCoinTarget(0);
|
||||
//} // grandPrixFinished
|
||||
|
||||
////-----------------------------------------------------------------------------
|
||||
//void UnlockManager::lockFeature(Challenge* challenge)
|
||||
//{
|
||||
// const unsigned int amount = (unsigned int)challenge->getFeatures().size();
|
||||
// for(unsigned int n=0; n<amount; n++)
|
||||
// m_locked_features[challenge->getFeatures()[n].name]=true;
|
||||
//} // lockFeature
|
||||
//
|
||||
////-----------------------------------------------------------------------------
|
||||
|
||||
//void UnlockManager::unlockFeature(Challenge* c, bool do_save)
|
||||
//{
|
||||
// const unsigned int amount = (unsigned int)c->getFeatures().size();
|
||||
// for(unsigned int n=0; n<amount; n++)
|
||||
// {
|
||||
// std::string feature = c->getFeatures()[n].name;
|
||||
// std::map<std::string,bool>::iterator p=m_locked_features.find(feature);
|
||||
// if(p==m_locked_features.end())
|
||||
// {
|
||||
// //fprintf(stderr,"Unlocking feature '%s' failed: feature is not locked.\n",
|
||||
// // (feature).c_str());
|
||||
// return;
|
||||
// }
|
||||
// m_locked_features.erase(p);
|
||||
// }
|
||||
//
|
||||
// // Add to list of recently unlocked features
|
||||
// m_unlocked_features.push_back(c);
|
||||
// c->setSolved(); // reset isActive flag
|
||||
//
|
||||
// // Save the new unlock information
|
||||
// if(do_save) save();
|
||||
//} // unlockFeature
|
||||
//
|
||||
////-----------------------------------------------------------------------------
|
||||
//bool UnlockManager::isLocked(const std::string& feature)
|
||||
//{
|
||||
// return m_locked_features.find(feature)!=m_locked_features.end();
|
||||
//} // featureIsLocked
|
||||
////-----------------------------------------------------------------------------
|
||||
//const std::vector<const Challenge*> UnlockManager::getUnlockedFeatures()
|
||||
//{
|
||||
// std::vector<const Challenge*> out;
|
||||
//
|
||||
// for(AllChallengesType::const_iterator i =m_all_challenges.begin();
|
||||
// i!=m_all_challenges.end(); i++)
|
||||
// {
|
||||
// if (i->second->isSolved()) out.push_back(i->second);
|
||||
// }
|
||||
//
|
||||
// return out;
|
||||
//}
|
||||
////-----------------------------------------------------------------------------
|
||||
//const std::vector<const Challenge*> UnlockManager::getLockedChallenges()
|
||||
//{
|
||||
// std::vector<const Challenge*> out;
|
||||
//
|
||||
// for(AllChallengesType::const_iterator i =m_all_challenges.begin();
|
||||
// i!=m_all_challenges.end(); i++)
|
||||
// {
|
||||
// if (!i->second->isSolved() && !i->second->isActive()) out.push_back(i->second);
|
||||
// }
|
||||
//
|
||||
// return out;
|
||||
//}
|
@ -28,7 +28,6 @@
|
||||
class XMLNode;
|
||||
class SFXBase;
|
||||
|
||||
using namespace std;
|
||||
/**
|
||||
* \brief main class to handle the tutorials list
|
||||
* \ingroup tutorial
|
||||
@ -36,11 +35,13 @@ using namespace std;
|
||||
class TutorialManager : public NoCopy
|
||||
{
|
||||
private:
|
||||
SFXBase *m_locked_sound;
|
||||
typedef map<string, Tutorial*> AllChallengesType;
|
||||
AllChallengesType m_all_tutorial;
|
||||
map<string, bool> m_locked_tutorials;
|
||||
vector<const Tutorial*> m_unlocked_tutorials;
|
||||
typedef std::map<std::string, Tutorial*> AllTutorialsType;
|
||||
|
||||
SFXBase *m_locked_sound;
|
||||
AllTutorialsType m_all_tutorials;
|
||||
std::map<std::string, bool> m_locked_tutorials;
|
||||
std::vector<const Tutorial*> m_unlocked_tutorials;
|
||||
|
||||
void computeActive ();
|
||||
void load ();
|
||||
|
||||
@ -49,8 +50,8 @@ private:
|
||||
public:
|
||||
TutorialManager ();
|
||||
~TutorialManager ();
|
||||
void addTutorial (Tutorial *t);
|
||||
void addTutorial (const string& filename);
|
||||
void addTutorial (Tutorial * m_tutorial);
|
||||
void addTutorial (const std::string& filename);
|
||||
void save ();
|
||||
vector<const Tutorial*> getActiveTutorials();
|
||||
|
||||
@ -67,12 +68,12 @@ public:
|
||||
/** Returns the list of currently inaccessible (locked) challenges */
|
||||
const vector<const Tutorial*> getLockedTutorials();
|
||||
|
||||
const Tutorial *getTutorial (const string& id);
|
||||
const Tutorial *getTutorial (const std::string& id);
|
||||
|
||||
void raceFinished ();
|
||||
/*void raceFinished ();
|
||||
void grandPrixFinished ();
|
||||
void lockFeature (Tutorial* tutorial);
|
||||
bool isLocked (const string& feature);
|
||||
bool isLocked (const string& feature);*/
|
||||
|
||||
/** Eye- (or rather ear-) candy. Play a sound when user tries to access a locked area */
|
||||
void playLockSound() const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user