diff --git a/src/challenges/challenge.cpp b/src/challenges/challenge.cpp index 676db7b42..a17553692 100644 --- a/src/challenges/challenge.cpp +++ b/src/challenges/challenge.cpp @@ -31,6 +31,44 @@ #include "utils/translation.hpp" #include "utils/string_utils.hpp" +const irr::core::stringw UnlockableFeature::getUnlockedMessage() const +{ + switch (type) + { + case UNLOCK_TRACK: + { // {} avoids compiler warning + Track* track = track_manager->getTrack( name ); + return StringUtils::insertValues(_("New track '%s' now available"), + track->getName().c_str() ); + break; + } + case UNLOCK_MODE: + { + return StringUtils::insertValues(_("New game mode '%s' now available"), + user_name.c_str()); + } + case UNLOCK_GP: + { + const irr::core::stringw& gp_user_name = grand_prix_manager->getGrandPrix(name)->getName(); + return StringUtils::insertValues(_("New Grand Prix '%s' now available"), + gp_user_name.c_str()); + } + case UNLOCK_DIFFICULTY: + { + return StringUtils::insertValues(_("New difficulty\n'%s' now available"), + user_name.c_str()); + } + case UNLOCK_KART: + { + const KartProperties *kp=kart_properties_manager->getKart( name ); + return StringUtils::insertValues( _("New kart\n'%s' now available"), + kp->getName().c_str()); + } + default: + assert(false); + return L""; + } // switch +} //----------------------------------------------------------------------------- void Challenge::addUnlockTrackReward(const std::string &track_name) @@ -85,61 +123,6 @@ void Challenge::addUnlockKartReward(const std::string &internal_name, m_feature.push_back(feature); } -//----------------------------------------------------------------------------- -const irr::core::stringw Challenge::getUnlockedMessage() const -{ - irr::core::stringw unlocked_message; - - const unsigned int amount = (unsigned int)m_feature.size(); - for(unsigned int n=0; n0) unlocked_message+='\n'; - - irr::core::stringw message; - - // write message depending on feature type - switch(m_feature[n].type) - { - case UNLOCK_TRACK: - { // {} avoids compiler warning - Track* track = track_manager->getTrack( m_feature[n].name ); - message = StringUtils::insertValues( - _("New track '%s'\nnow available"), - track->getName().c_str() ); - break; - } - case UNLOCK_MODE: - message = StringUtils::insertValues( - _("New game mode\n'%s'\nnow available"), - m_feature[n].user_name.c_str()); - break; - case UNLOCK_GP: - { - const irr::core::stringw& gp_user_name = grand_prix_manager->getGrandPrix(m_feature[n].name)->getName(); - message = StringUtils::insertValues( - _("New Grand Prix '%s'\nnow available"), - gp_user_name.c_str()); - break; - } - case UNLOCK_DIFFICULTY: - message = StringUtils::insertValues( - _("New difficulty\n'%s'\nnow available"), - m_feature[n].user_name.c_str()); - break; - case UNLOCK_KART: - const KartProperties *kp=kart_properties_manager->getKart(m_feature[n].name ); - message = StringUtils::insertValues( - _("New kart\n'%s'\nnow available"), - kp->getName().c_str()); - break; - } // switch - unlocked_message += message; - } // for n - - return unlocked_message; -} - //----------------------------------------------------------------------------- /** Loads the state for a challenge object (esp. m_state), and calls the * virtual function loadAdditionalInfo for additional information diff --git a/src/challenges/challenge.hpp b/src/challenges/challenge.hpp index 26094628f..9e7b3c000 100644 --- a/src/challenges/challenge.hpp +++ b/src/challenges/challenge.hpp @@ -39,6 +39,8 @@ struct UnlockableFeature std::string name; // internal name irr::core::stringw user_name; // not all types of feature have one REWARD_TYPE type; + + const irr::core::stringw getUnlockedMessage() const; }; // A base class for all challenges @@ -70,7 +72,6 @@ public: void addUnlockKartReward(const std::string &internal_name, const irr::core::stringw &user_name); - const irr::core::stringw getUnlockedMessage() const; const std::vector& getFeatures() const { return m_feature; } void setChallengeDescription(const irr::core::stringw& d) diff --git a/src/challenges/challenge_data.cpp b/src/challenges/challenge_data.cpp index 224ba47c2..9dd46b8a7 100644 --- a/src/challenges/challenge_data.cpp +++ b/src/challenges/challenge_data.cpp @@ -227,7 +227,7 @@ void ChallengeData::getUnlocks(const XMLNode *root, const std:: string type, if (prop == NULL) { std::cerr << "Challenge refers to kart " << attrib << - ", which is unknown. Ignoring challenge.\n"; + ", which is unknown. Ignoring reward.\n"; break; } irr::core::stringw user_name = prop->getName(); diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 70aef339b..aef505c02 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -524,23 +524,26 @@ scene::IMesh *IrrDriver::createTexturedQuadMesh(const video::SMaterial *material { scene::SMeshBuffer *buffer = new scene::SMeshBuffer(); + const float w_2 = (float)w/2.0f; + const float h_2 = (float)h/2.0f; + video::S3DVertex v1; - v1.Pos = core::vector3df(0,0,0); + v1.Pos = core::vector3df(-w_2,-h_2,0); v1.Normal = core::vector3df(1/sqrt(2.0f), 1/sqrt(2.0f), 0); // I hope normals are ok... v1.TCoords = core::vector2d(0,1); video::S3DVertex v2; - v2.Pos = core::vector3df((float)w,0,0); + v2.Pos = core::vector3df(w_2,-h_2,0); v2.Normal = core::vector3df(1/sqrt(2.0f), 1/sqrt(2.0f), 0); v2.TCoords = core::vector2d(1,1); video::S3DVertex v3; - v3.Pos = core::vector3df((float)w,(float)h,0); + v3.Pos = core::vector3df(w_2,h_2,0); v3.Normal = core::vector3df(1/sqrt(2.0f), 1/sqrt(2.0f), 0); v3.TCoords = core::vector2d(1,0); video::S3DVertex v4; - v4.Pos = core::vector3df(0,(float)h,0); + v4.Pos = core::vector3df(-w_2,h_2,0); v4.Normal = core::vector3df(1/sqrt(2.0f), 1/sqrt(2.0f), 0); v4.TCoords = core::vector2d(0,0); diff --git a/src/states_screens/dialogs/race_over_dialog.cpp b/src/states_screens/dialogs/race_over_dialog.cpp index ed33a827a..22b273a0c 100644 --- a/src/states_screens/dialogs/race_over_dialog.cpp +++ b/src/states_screens/dialogs/race_over_dialog.cpp @@ -376,34 +376,73 @@ GUIEngine::EventPropagation RaceOverDialog::processEvent(const std::string& even unlock_manager->clearUnlocked(); FeatureUnlockedCutScene* scene = FeatureUnlockedCutScene::getInstance(); + + /* + scene->addUnlockedKart( const_cast(kart_properties_manager->getKart("gnu")), + _("Unlocked gnu kart") ); + scene->addUnlockedPicture( + irr_driver->getTexture(track_manager->getTrack("beach")->getScreenshotFile().c_str()), + _("Unlocked beach track")); + scene->addUnlockedPicture( + irr_driver->getTexture(track_manager->getTrack("lighthouse")->getScreenshotFile().c_str()), + _("Unlocked lighthouse track")); + //scene->addUnlockedPicture( irr_driver->getTexture(track_manager->getTrack("canyon")->getScreenshotFile().c_str()) ); + */ + + assert(unlocked.size() > 0); for (unsigned int n=0; n& unlockedFeatures = unlocked[n]->getFeatures(); + assert(unlockedFeatures.size() > 0); + + for (unsigned int i=0; igetTrack(unlockedFeatures[i].name); + assert(track != NULL); + const std::string sshot = track->getScreenshotFile(); + scene->addUnlockedPicture( irr_driver->getTexture(sshot.c_str()), + unlockedFeatures[i].getUnlockedMessage() ); + break; + } + case UNLOCK_GP: + { + //TODO + break; + } + case UNLOCK_MODE: + { + //TODO + break; + } + case UNLOCK_KART: + { + const KartProperties* kart = kart_properties_manager->getKart(unlockedFeatures[i].name); + assert(kart != NULL); + + // the passed kart will not be modified, that's why I allow myself to use const_cast + scene->addUnlockedKart( const_cast(kart), + unlockedFeatures[i].getUnlockedMessage() ); + break; + } + case UNLOCK_DIFFICULTY: + { + //TODO + break; + } + default: + { + assert(false); + } + } + + } // next feature + } // next challenge - //FIXME: update the feature unlocked scene to be able to handle when many features are unlocked - if (unlocked_kart) - { - // the passed kart will not be modified, that's why I allow myself to use const_cast - scene->setUnlockedKart( const_cast(kart_properties_manager->getKart("gnu")) ); - } - else if (unlocked_track) - { - scene->setUnlockedPicture( irr_driver->getTexture(track_manager->getTrack("beach")->getScreenshotFile().c_str()) ); - } - else if (unlocked_game_mode) - { - //TODO! - assert(false); - } - else - { - assert(false); - } - } - ModalDialog::dismiss(); // clear the race (FIXME: is this the right way to go?) diff --git a/src/states_screens/feature_unlocked.cpp b/src/states_screens/feature_unlocked.cpp index 763662f30..260c3ae77 100644 --- a/src/states_screens/feature_unlocked.cpp +++ b/src/states_screens/feature_unlocked.cpp @@ -23,27 +23,23 @@ FeatureUnlockedCutScene::FeatureUnlockedCutScene() : Screen("feature_unlocked.st setNeeds3D(true); throttleFPS = false; - m_unlocked_kart = NULL; - m_unlocked_thing_picture = NULL; } // ------------------------------------------------------------------------------------- -void FeatureUnlockedCutScene::setUnlockedKart(KartProperties* unlocked_kart) +void FeatureUnlockedCutScene::addUnlockedKart(KartProperties* unlocked_kart, irr::core::stringw msg) { assert(unlocked_kart != NULL); - m_unlocked_kart = unlocked_kart; - m_unlocked_thing_picture = NULL; + m_unlocked_stuff.push_back( new UnlockedThing(unlocked_kart, msg) ); } // ------------------------------------------------------------------------------------- -void FeatureUnlockedCutScene::setUnlockedPicture(irr::video::ITexture* picture) +void FeatureUnlockedCutScene::addUnlockedPicture(irr::video::ITexture* picture, irr::core::stringw msg) { assert(picture != NULL); - m_unlocked_kart = NULL; - m_unlocked_thing_picture = picture; + m_unlocked_stuff.push_back( new UnlockedThing(picture, msg) ); } // ------------------------------------------------------------------------------------- @@ -85,47 +81,54 @@ void FeatureUnlockedCutScene::init() m_light->getLightData().DiffuseColor = irr::video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); m_light->getLightData().SpecularColor = irr::video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); - if (m_unlocked_kart != NULL) + const int unlockedStuffCount = m_unlocked_stuff.size(); + + if (unlockedStuffCount == 0) std::cerr << "There is nothing in the unlock chest!!!\n"; + + for (int n=0; ngetKartModel(); - - scene::ISceneNode* kart_node = irr_driver->getSceneManager()->addMeshSceneNode(kartModel->getModel()); - - for (int n=0; n<4; n++) + if (m_unlocked_stuff[n].m_unlocked_kart != NULL) { - scene::ISceneNode* wheel = irr_driver->getSceneManager()->addMeshSceneNode(kartModel->getWheelModel(n), kart_node); - wheel->setPosition( kartModel->getWheelGraphicsPosition(n).toIrrVector() ); - wheel->updateAbsolutePosition(); + KartModel* kartModel = m_unlocked_stuff[n].m_unlocked_kart->getKartModel(); + + scene::ISceneNode* kart_node = irr_driver->getSceneManager()->addMeshSceneNode(kartModel->getModel()); + + for (int w=0; w<4; w++) + { + scene::ISceneNode* wheel = irr_driver->getSceneManager()->addMeshSceneNode(kartModel->getWheelModel(w), kart_node); + wheel->setPosition( kartModel->getWheelGraphicsPosition(w).toIrrVector() ); + wheel->updateAbsolutePosition(); + } + + m_unlocked_stuff[n].m_root_gift_node = kart_node; } - - m_root_gift_node = kart_node; - } - else if (m_unlocked_thing_picture != NULL) - { - video::SMaterial m; - m.BackfaceCulling = false; - m.setTexture(0, m_unlocked_thing_picture); - m.AmbientColor = SColor(255,255,255,255); - m.DiffuseColor = SColor(255,255,255,255); - m.SpecularColor = SColor(0,0,0,0); - m.GouraudShading = false; - m.Shininess = 0; - //m.setFlag(video::EMF_TEXTURE_WRAP, false); - -#if (IRRLICHT_VERSION_MAJOR == 1) && (IRRLICHT_VERSION_MINOR >= 7) - m.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE; - m.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; -#else - m.TextureLayer[0].TextureWrap = video::ETC_CLAMP_TO_EDGE; -#endif + else if (m_unlocked_stuff[n].m_picture != NULL) + { + video::SMaterial m; + m.BackfaceCulling = false; + m.setTexture(0, m_unlocked_stuff[n].m_picture); + m.AmbientColor = SColor(255,255,255,255); + m.DiffuseColor = SColor(255,255,255,255); + m.SpecularColor = SColor(0,0,0,0); + m.GouraudShading = false; + m.Shininess = 0; + //m.setFlag(video::EMF_TEXTURE_WRAP, false); + + #if (IRRLICHT_VERSION_MAJOR == 1) && (IRRLICHT_VERSION_MINOR >= 7) + m.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE; + m.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + #else + m.TextureLayer[0].TextureWrap = video::ETC_CLAMP_TO_EDGE; + #endif - scene::IMesh* mesh = irr_driver->createTexturedQuadMesh(&m, 1.0, 0.75); - m_root_gift_node = irr_driver->addMesh(mesh); + scene::IMesh* mesh = irr_driver->createTexturedQuadMesh(&m, 1.0, 0.75); + m_unlocked_stuff[n].m_root_gift_node = irr_driver->addMesh(mesh); - } - else - { - std::cerr << "There is nothing in the chest!!!\n"; + } + else + { + std::cerr << "Malformed unlocked goody!!!\n"; + } } } @@ -149,11 +152,7 @@ void FeatureUnlockedCutScene::tearDown() irr_driver->removeNode(m_light); m_light = NULL; - if (m_root_gift_node != NULL) - { - irr_driver->removeNode(m_root_gift_node); - m_root_gift_node = NULL; - } + m_unlocked_stuff.clearAndDeleteAll(); } // ------------------------------------------------------------------------------------- @@ -197,24 +196,43 @@ void FeatureUnlockedCutScene::onUpdate(float dt, irr::video::IVideoDriver* drive const int GIFT_EXIT_FROM = (int)ANIM_TO; const int GIFT_EXIT_TO = GIFT_EXIT_FROM + 12; - if (m_global_time > GIFT_EXIT_FROM && m_global_time < GIFT_EXIT_TO && m_root_gift_node != NULL) - { - core::vector3df pos = m_root_gift_node->getPosition(); - pos.Y = sin( (float)((m_global_time - GIFT_EXIT_FROM)*M_PI*1.2/GIFT_EXIT_TO) )*30.0f; - pos.X += 2*dt; - pos.Z += 5*dt; + const int unlockedStuffCount = m_unlocked_stuff.size(); - m_root_gift_node->setPosition(pos); - - core::vector3df scale = m_root_gift_node->getScale(); - scale.X += 2*dt; - scale.Y += 2*dt; - scale.Z += 2*dt; - m_root_gift_node->setScale(scale); - + if (m_global_time > GIFT_EXIT_FROM && m_global_time < GIFT_EXIT_TO) + { + + for (int n=0; ngetPosition(); + pos.Y = sin( (float)((m_global_time - GIFT_EXIT_FROM)*M_PI*1.2/GIFT_EXIT_TO) )*30.0f; + + // when there are more than 1 unlocked items, make sure they each have their own path when they move + if (unlockedStuffCount > 1) + { + if (n % 2 == 0) pos.X -= 2.2f*dt*float( int((n + 1)/2) ); + else pos.X += 2.2f*dt*float( int((n + 1)/2) ); + //std::cout << "Object " << n << " moving by " << (n % 2 == 0 ? -4.0f : 4.0f)*float( n/2 + 1 ) << std::endl; + } + else + { + pos.X += 2*dt; + } + + pos.Z += 5*dt; + + m_unlocked_stuff[n].m_root_gift_node->setPosition(pos); + + core::vector3df scale = m_unlocked_stuff[n].m_root_gift_node->getScale(); + scale.X += 2*dt; + scale.Y += 2*dt; + scale.Z += 2*dt; + m_unlocked_stuff[n].m_root_gift_node->setScale(scale); + } core::vector3df campos = m_camera->getPosition(); - campos.X += 5*dt; + campos.X += 2*dt; campos.Z += 5*dt; m_camera->setPosition(campos); @@ -226,9 +244,11 @@ void FeatureUnlockedCutScene::onUpdate(float dt, irr::video::IVideoDriver* drive sin((1.0f-m_key_angle)*M_PI/8 + M_PI/4)*70.0f) ); } - if (m_root_gift_node != NULL) + assert(m_unlocked_stuff.size() > 0); + if (m_unlocked_stuff[0].m_root_gift_node != NULL) { - m_camera->setTarget( m_root_gift_node->getPosition() + core::vector3df(0.0f, 10.0f, 0.0f) ); + m_camera->setTarget( m_unlocked_stuff[0].m_root_gift_node->getPosition() + + core::vector3df(0.0f, 10.0f, 0.0f) ); m_camera->updateAbsolutePosition(); } else @@ -241,12 +261,28 @@ void FeatureUnlockedCutScene::onUpdate(float dt, irr::video::IVideoDriver* drive static const int h = irr_driver->getFrameSize().Height; const irr::video::SColor color(255, 255, 255, 255); - static int test_y = 0; - GUIEngine::getTitleFont()->draw(_("Feature Unlocked"), - core::rect< s32 >( 0, test_y, w, h/10 ), + core::rect< s32 >( 0, 0, w, h/10 ), color, true/* center h */, true /* center v */ ); + + if (m_global_time > GIFT_EXIT_TO) + { + const irr::video::SColor color2(255, 255, 126, 21); + const int fontH = GUIEngine::getFontHeight(); + const int MARGIN = 10; + + int message_y = h - fontH*3 - MARGIN; + + for (int n=0; ndraw(m_unlocked_stuff[n].m_unlock_message, + core::rect< s32 >( 0, message_y, w, message_y + fontH ), + color2, + true /* center h */, true /* center v */ ); + message_y -= (fontH + MARGIN); + } + } } // ------------------------------------------------------------------------------------- diff --git a/src/states_screens/feature_unlocked.hpp b/src/states_screens/feature_unlocked.hpp index 255755df4..7a6e60cd7 100644 --- a/src/states_screens/feature_unlocked.hpp +++ b/src/states_screens/feature_unlocked.hpp @@ -2,6 +2,7 @@ #define HEADER_FEATURE_UNLOCKED_HPP #include "guiengine/screen.hpp" +#include "utils/ptr_vector.hpp" namespace irr { namespace scene { class ISceneNode; class ICameraSceneNode; class ILightSceneNode; } } class KartProperties; @@ -13,12 +14,37 @@ class FeatureUnlockedCutScene : public GUIEngine::Screen, public GUIEngine::Scre FeatureUnlockedCutScene(); - /** Whichever of these is non-null decides whhat comes out of the chest */ - KartProperties* m_unlocked_kart; - irr::video::ITexture* m_unlocked_thing_picture; + /** Whichever of these is non-null decides what comes out of the chest */ + struct UnlockedThing + { + KartProperties* m_unlocked_kart; + irr::video::ITexture* m_picture; + + /** Contains whatever is in the chest */ + scene::ISceneNode* m_root_gift_node; + + irr::core::stringw m_unlock_message; + + UnlockedThing(KartProperties* kart, irr::core::stringw msg) + { + m_unlocked_kart = kart; + m_picture = NULL; + m_unlock_message = msg; + } + UnlockedThing(irr::video::ITexture* pict, irr::core::stringw msg) + { + m_unlocked_kart = NULL; + m_picture = pict; + m_unlock_message = msg; + } + ~UnlockedThing() + { + if (m_root_gift_node != NULL) irr_driver->removeNode(m_root_gift_node); + m_root_gift_node = NULL; + } + }; + ptr_vector m_unlocked_stuff; - /** Contains whatever is in the chest */ - scene::ISceneNode* m_root_gift_node; /** sky angle, 0-360 */ float m_sky_angle; @@ -51,10 +77,10 @@ public: void eventCallback(GUIEngine::Widget* widget, const std::string& name, const int playerID); /** Call before showing up the screen to make a kart come out of the chest */ - void setUnlockedKart(KartProperties* unlocked_kart); + void addUnlockedKart(KartProperties* unlocked_kart, irr::core::stringw msg); /** Call before showing up the screen to make a picture come out of the chest */ - void setUnlockedPicture(irr::video::ITexture* picture); + void addUnlockedPicture(irr::video::ITexture* picture, irr::core::stringw msg); /** override from base class to handle escape press */ virtual bool onEscapePressed();