1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2010-2015 SuperTuxKart-Team
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License
7 //  as published by the Free Software Foundation; either version 3
8 //  of the License, or (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 #include "states_screens/feature_unlocked.hpp"
20 
21 #include <SColor.h>
22 
23 #include "audio/music_manager.hpp"
24 #include "challenges/challenge_data.hpp"
25 #include "challenges/unlock_manager.hpp"
26 #include "config/player_manager.hpp"
27 #include "config/user_config.hpp"
28 #include "graphics/central_settings.hpp"
29 #include "graphics/sp/sp_base.hpp"
30 #include "graphics/sp/sp_mesh.hpp"
31 #include "graphics/sp/sp_mesh_buffer.hpp"
32 #include "graphics/sp/sp_mesh_node.hpp"
33 #include "graphics/sp/sp_texture_manager.hpp"
34 #include "guiengine/engine.hpp"
35 #include "guiengine/scalable_font.hpp"
36 #include "io/file_manager.hpp"
37 #include "karts/kart_model.hpp"
38 #include "karts/kart_properties.hpp"
39 #include "karts/kart_properties_manager.hpp"
40 #include "modes/cutscene_world.hpp"
41 #include "modes/overworld.hpp"
42 #include "modes/world.hpp"
43 #include "race/grand_prix_manager.hpp"
44 #include "states_screens/main_menu_screen.hpp"
45 #include "states_screens/state_manager.hpp"
46 #include "tracks/track.hpp"
47 #include "tracks/track_manager.hpp"
48 #include "utils/string_utils.hpp"
49 #include "utils/translation.hpp"
50 
51 #include <IAnimatedMeshSceneNode.h>
52 #include <ICameraSceneNode.h>
53 #include <ILightSceneNode.h>
54 #include <IMeshSceneNode.h>
55 #include <ISceneManager.h>
56 
57 #include <iostream>
58 
59 using namespace irr::core;
60 using namespace irr::gui;
61 using namespace irr::video;
62 
63 const float ANIM_TO = 7.0f;
64 const int GIFT_EXIT_FROM = (int)ANIM_TO;
65 const int GIFT_EXIT_TO = GIFT_EXIT_FROM + 7;
66 
67 // ============================================================================
68 
69 #if 0
70 #pragma mark FeatureUnlockedCutScene::UnlockedThing
71 #endif
72 
UnlockedThing(const std::string & model,const irr::core::stringw & msg)73 FeatureUnlockedCutScene::UnlockedThing::UnlockedThing(const std::string &model,
74                                                       const irr::core::stringw &msg)
75 {
76     m_unlocked_kart      = NULL;
77     m_unlock_message     = msg;
78     m_unlock_model       = model;
79     m_curr_image         = -1;
80     m_scale              = 1.0f;
81 }
82 
83 // ----------------------------------------------------------------------------
84 
85 
UnlockedThing(const KartProperties * kart,const irr::core::stringw & msg)86 FeatureUnlockedCutScene::UnlockedThing::UnlockedThing(const KartProperties* kart,
87                                                       const irr::core::stringw &msg)
88 {
89     m_unlocked_kart      = kart;
90     m_unlock_message     = msg;
91     m_curr_image         = -1;
92     m_scale              = 1.0f;
93 }   // UnlockedThing::UnlockedThing
94 
95 // ----------------------------------------------------------------------------
96 
UnlockedThing(irr::video::ITexture * pict,float w,float h,const irr::core::stringw & msg)97 FeatureUnlockedCutScene::UnlockedThing::UnlockedThing(irr::video::ITexture* pict,
98                                                       float w, float h,
99                                                       const irr::core::stringw &msg)
100 {
101     m_unlocked_kart = NULL;
102 #ifndef SERVER_ONLY
103     if (CVS->isGLSL())
104     {
105         m_sp_pictures.push_back(SP::SPTextureManager::get()
106             ->getTexture(pict->getName().getPtr(), NULL, true,
107             ""/*container_id*/));
108     }
109     else
110     {
111         m_pictures.push_back(pict);
112     }
113 #endif
114     m_w = w;
115     m_h = h;
116     m_unlock_message = msg;
117     m_curr_image = -1;
118     m_scale = 1.0f;
119 }   // UnlockedThing::UnlockedThing
120 
121 // ----------------------------------------------------------------------------
122 
123 FeatureUnlockedCutScene::UnlockedThing
UnlockedThing(std::vector<irr::video::ITexture * > picts,float w,float h,const irr::core::stringw & msg)124                         ::UnlockedThing(std::vector<irr::video::ITexture*> picts,
125                                         float w, float h,
126                                         const irr::core::stringw &msg)
127 {
128     m_unlocked_kart = NULL;
129 #ifndef SERVER_ONLY
130     if (CVS->isGLSL())
131     {
132         for (auto* pict : picts)
133         {
134             m_sp_pictures.push_back(SP::SPTextureManager::get()
135                 ->getTexture(pict->getName().getPtr(), NULL, true,
136                 ""/*container_id*/));
137         }
138     }
139     else
140 #endif
141     {
142         m_pictures = picts;
143     }
144     m_pictures = picts;
145     m_w = w;
146     m_h = h;
147     m_unlock_message = msg;
148     m_curr_image = 0;
149     m_scale = 1.0f;
150 }   // UnlockedThing::UnlockedThing
151 
152 // ----------------------------------------------------------------------------
153 
~UnlockedThing()154 FeatureUnlockedCutScene::UnlockedThing::~UnlockedThing()
155 {
156     if (m_root_gift_node != NULL) irr_driver->removeNode(m_root_gift_node);
157     m_root_gift_node = NULL;
158 }   // UnlockedThing::~UnlockedThing
159 
160 // ============================================================================
161 
162 #if 0
163 #pragma mark -
164 #pragma mark FeatureUnlockedCutScene
165 #endif
166 
FeatureUnlockedCutScene()167 FeatureUnlockedCutScene::FeatureUnlockedCutScene()
168             : CutsceneScreen("cutscene.stkgui")
169 {
170     m_key_angle = 0;
171 }  // FeatureUnlockedCutScene
172 
173 // ----------------------------------------------------------------------------
174 
loadedFromFile()175 void FeatureUnlockedCutScene::loadedFromFile()
176 {
177 }   // loadedFromFile
178 
179 // ----------------------------------------------------------------------------
180 
onCutsceneEnd()181 void FeatureUnlockedCutScene::onCutsceneEnd()
182 {
183     m_unlocked_stuff.clearAndDeleteAll();
184 #ifndef SERVER_ONLY
185     if (CVS->isGLSL())
186     {
187         SP::SPTextureManager::get()->removeUnusedTextures();
188     }
189 #endif
190     m_all_kart_models.clearAndDeleteAll();
191 
192     // update point count and the list of locked/unlocked stuff
193     PlayerManager::getCurrentPlayer()->computeActive();
194 }
195 
196 // ----------------------------------------------------------------------------
197 
198 void FeatureUnlockedCutScene::
findWhatWasUnlocked(RaceManager::Difficulty difficulty,std::vector<const ChallengeData * > & unlocked)199                findWhatWasUnlocked(RaceManager::Difficulty difficulty,
200                                    std::vector<const ChallengeData*>& unlocked)
201 {
202     if (UserConfigParams::m_unlock_everything > 0)
203         return;
204 
205     PlayerProfile *player = PlayerManager::getCurrentPlayer();
206 
207     // The number of points is updated before this function is called
208     int points_before = player->getPointsBefore();
209     int points_now = player->getPoints();
210 
211     std::vector<std::string> tracks;
212     std::vector<std::string> gps;
213     std::vector<std::string> karts;
214 
215     player->computeActive();
216     unlock_manager->findWhatWasUnlocked(points_before, points_now, tracks, gps,
217                                         karts, unlocked);
218 
219     for (unsigned int i = 0; i < tracks.size(); i++)
220     {
221         addUnlockedTrack(track_manager->getTrack(tracks[i]));
222     }
223     for (unsigned int i = 0; i < gps.size(); i++)
224     {
225         addUnlockedGP(grand_prix_manager->getGrandPrix(gps[i]));
226     }
227     for (unsigned int i = 0; i < karts.size(); i++)
228     {
229         addUnlockedKart(kart_properties_manager->getKart(karts[i]));
230     }
231 }
232 
233 // ----------------------------------------------------------------------------
234 
addTrophy(RaceManager::Difficulty difficulty,bool is_grandprix)235 void FeatureUnlockedCutScene::addTrophy(RaceManager::Difficulty difficulty,
236                                         bool is_grandprix)
237 {
238     core::stringw msg;
239 
240     int gp_factor = is_grandprix ? GP_FACTOR : 1;
241     RaceManager::Difficulty max_unlocked_difficulty = RaceManager::DIFFICULTY_BEST;
242 
243     if (PlayerManager::getCurrentPlayer()->isLocked("difficulty_best"))
244         max_unlocked_difficulty = RaceManager::DIFFICULTY_HARD;
245 
246     switch (difficulty)
247     {
248         case RaceManager::DIFFICULTY_EASY:
249             msg = _("You completed the easy challenge! "
250                     "Points earned on this level: %i/%i",
251                     CHALLENGE_POINTS[RaceManager::DIFFICULTY_EASY]*gp_factor,
252                     CHALLENGE_POINTS[max_unlocked_difficulty]*gp_factor);
253             break;
254         case RaceManager::DIFFICULTY_MEDIUM:
255             msg = _("You completed the intermediate challenge! "
256                     "Points earned on this level: %i/%i",
257                     CHALLENGE_POINTS[RaceManager::DIFFICULTY_MEDIUM]*gp_factor,
258                     CHALLENGE_POINTS[max_unlocked_difficulty]*gp_factor);
259             break;
260         case RaceManager::DIFFICULTY_HARD:
261             msg = _("You completed the difficult challenge! "
262                     "Points earned on this level: %i/%i",
263                     CHALLENGE_POINTS[RaceManager::DIFFICULTY_HARD]*gp_factor,
264                     CHALLENGE_POINTS[max_unlocked_difficulty]*gp_factor);
265             break;
266         case RaceManager::DIFFICULTY_BEST:
267             msg = _("You completed the SuperTux challenge! "
268                     "Points earned on this level: %i/%i",
269                     CHALLENGE_POINTS[RaceManager::DIFFICULTY_BEST]*gp_factor,
270                 CHALLENGE_POINTS[max_unlocked_difficulty]*gp_factor);
271             break;
272         default:
273             assert(false);
274     }
275 
276     std::string model;
277     switch (difficulty)
278     {
279         case RaceManager::DIFFICULTY_EASY:
280             model = file_manager->getAsset(FileManager::MODEL,"trophy_bronze.spm");
281             break;
282         case RaceManager::DIFFICULTY_MEDIUM:
283             model = file_manager->getAsset(FileManager::MODEL,"trophy_silver.spm");
284             break;
285         case RaceManager::DIFFICULTY_HARD:
286             model = file_manager->getAsset(FileManager::MODEL,"trophy_gold.spm");
287             break;
288         case RaceManager::DIFFICULTY_BEST:
289             model = file_manager->getAsset(FileManager::MODEL,"trophy_platinum.spm");
290             break;
291         default:
292             assert(false);
293             return;
294     }
295 
296 
297     m_unlocked_stuff.push_back( new UnlockedThing(model, msg) );
298 }   // addTrophy
299 
300 // ----------------------------------------------------------------------------
301 
addUnlockedKart(const KartProperties * unlocked_kart)302 void FeatureUnlockedCutScene::addUnlockedKart(const KartProperties* unlocked_kart)
303 {
304     if (unlocked_kart == NULL)
305     {
306         Log::error("FeatureUnlockedCutScene::addUnlockedKart",
307                    "Unlocked kart does not exist");
308         return;
309     }
310     irr::core::stringw msg = _("You unlocked %s!", unlocked_kart->getName());
311     m_unlocked_stuff.push_back( new UnlockedThing(unlocked_kart, msg) );
312 }  // addUnlockedKart
313 
314 // ----------------------------------------------------------------------------
315 
addUnlockedPicture(irr::video::ITexture * picture,float w,float h,const irr::core::stringw & msg)316 void FeatureUnlockedCutScene::addUnlockedPicture(irr::video::ITexture* picture,
317                                                  float w, float h,
318                                                  const irr::core::stringw &msg)
319 {
320     if (picture == NULL)
321     {
322         Log::warn("FeatureUnlockedCutScene::addUnlockedPicture",
323                   "Unlockable has no picture: %s",
324                   core::stringc(msg.c_str()).c_str());
325         picture = irr_driver->getTexture(
326                      file_manager->getAsset(FileManager::GUI_ICON,"main_help.png"));
327 
328     }
329 
330     m_unlocked_stuff.push_back( new UnlockedThing(picture, w, h, msg) );
331 }   // addUnlockedPicture
332 
333 // ----------------------------------------------------------------------------
334 
addUnlockedPictures(std::vector<irr::video::ITexture * > pictures,float w,float h,irr::core::stringw msg)335 void FeatureUnlockedCutScene::addUnlockedPictures
336                               (std::vector<irr::video::ITexture*> pictures,
337                                float w, float h, irr::core::stringw msg)
338 {
339     assert(!pictures.empty());
340 
341     m_unlocked_stuff.push_back( new UnlockedThing(pictures, w, h, msg) );
342 }   // addUnlockedPictures
343 
344 // ----------------------------------------------------------------------------
345 
init()346 void FeatureUnlockedCutScene::init()
347 {
348     m_global_time = 0.0f;
349     CutsceneWorld::setUseDuration(false);
350 
351     const int unlockedStuffCount = m_unlocked_stuff.size();
352 
353     if (unlockedStuffCount == 0)
354         Log::error("FeatureUnlockedCutScene::init",
355                    "There is nothing in the unlock chest");
356 
357     m_all_kart_models.clearAndDeleteAll();
358     for (int n=0; n<unlockedStuffCount; n++)
359     {
360         if (m_unlocked_stuff[n].m_unlock_model.size() > 0)
361         {
362             irr::scene::IMesh *mesh =
363                 irr_driver->getMesh(m_unlocked_stuff[n].m_unlock_model);
364             m_unlocked_stuff[n].m_root_gift_node =
365                 irr_driver->addMesh(mesh, "unlocked_model");
366             m_unlocked_stuff[n].m_scale = 0.7f;
367         }
368         else if (m_unlocked_stuff[n].m_unlocked_kart != NULL)
369         {
370             KartModel *kart_model =
371                 m_unlocked_stuff[n].m_unlocked_kart->getKartModelCopy();
372             m_all_kart_models.push_back(kart_model);
373             m_unlocked_stuff[n].m_root_gift_node =
374                 kart_model->attachModel(true, false);
375             m_unlocked_stuff[n].m_scale = 5.0f;
376             kart_model->setAnimation(KartModel::AF_DEFAULT);
377             // Set model current frame to "center"
378             kart_model->update(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
379 
380 #ifdef DEBUG
381             m_unlocked_stuff[n].m_root_gift_node->setName("unlocked kart");
382 #endif
383         }
384 #ifndef SERVER_ONLY
385         else if (!m_unlocked_stuff[n].m_sp_pictures.empty())
386         {
387             scene::IMesh* mesh = irr_driver->createTexturedQuadMesh(NULL,
388                 m_unlocked_stuff[n].m_w, m_unlocked_stuff[n].m_h);
389             m_unlocked_stuff[n].m_root_gift_node =
390                 irr_driver->getSceneManager()->addEmptySceneNode();
391             SP::SPMesh* spm = SP::convertEVTStandard(mesh);
392             m_unlocked_stuff[n].m_side_1 = irr_driver->addMesh(spm,
393                 "unlocked_picture", m_unlocked_stuff[n].m_root_gift_node);
394             spm->getSPMeshBuffer(0)->uploadGLMesh();
395             spm->getSPMeshBuffer(0)->getSPTextures()[0] =
396                 m_unlocked_stuff[n].m_sp_pictures[0];
397             spm->getSPMeshBuffer(0)->reloadTextureCompare();
398             spm->drop();
399 
400             mesh = irr_driver->createTexturedQuadMesh(NULL,
401                 m_unlocked_stuff[n].m_w, m_unlocked_stuff[n].m_h);
402             spm = SP::convertEVTStandard(mesh);
403             m_unlocked_stuff[n].m_side_2 = irr_driver->addMesh(spm,
404                 "unlocked_picture",  m_unlocked_stuff[n].m_root_gift_node);
405             m_unlocked_stuff[n].m_side_2->setRotation
406                 (core::vector3df(0.0f, 180.0f, 0.0f));
407             spm->getSPMeshBuffer(0)->uploadGLMesh();
408             spm->getSPMeshBuffer(0)->getSPTextures()[0] =
409                 m_unlocked_stuff[n].m_sp_pictures[0];
410             spm->getSPMeshBuffer(0)->reloadTextureCompare();
411             spm->drop();
412 #ifdef DEBUG
413             m_unlocked_stuff[n].m_root_gift_node->setName("unlocked track picture");
414 #endif
415         }
416 #endif
417         else if (!m_unlocked_stuff[n].m_pictures.empty())
418         {
419             video::SMaterial m;
420             //m.MaterialType    = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
421             m.BackfaceCulling = true;
422             m.setTexture(0, m_unlocked_stuff[n].m_pictures[0]);
423             m.AmbientColor  = video::SColor(255, 255, 255, 255);
424             m.DiffuseColor  = video::SColor(255, 255, 255, 255);
425             m.EmissiveColor = video::SColor(255, 255, 255, 255);
426             m.SpecularColor = video::SColor(255, 255, 255, 255);
427             m.GouraudShading = false;
428             m.Shininess      = 0;
429 
430             m.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
431             m.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
432             scene::IMesh* mesh =
433                 irr_driver->createTexturedQuadMesh(&m,
434                                                    m_unlocked_stuff[n].m_w,
435                                                    m_unlocked_stuff[n].m_h);
436             m_unlocked_stuff[n].m_root_gift_node =
437                 irr_driver->getSceneManager()->addEmptySceneNode();
438             irr_driver->setAllMaterialFlags(mesh);
439             m_unlocked_stuff[n].m_side_1 =
440                 irr_driver->addMesh(mesh, "unlocked_picture",
441                                     m_unlocked_stuff[n].m_root_gift_node);
442             mesh->drop();
443 
444             mesh = irr_driver->createTexturedQuadMesh(&m,
445                 m_unlocked_stuff[n].m_w,
446                 m_unlocked_stuff[n].m_h);
447             irr_driver->setAllMaterialFlags(mesh);
448             m_unlocked_stuff[n].m_side_2 =
449                 irr_driver->addMesh(mesh, "unlocked_picture",
450                                     m_unlocked_stuff[n].m_root_gift_node);
451             m_unlocked_stuff[n].m_side_2
452                 ->setRotation(core::vector3df(0.0f, 180.0f, 0.0f));
453             mesh->drop();
454 #ifdef DEBUG
455             m_unlocked_stuff[n].m_root_gift_node->setName("unlocked track picture");
456 #endif
457         }
458         else
459         {
460             Log::error("FeatureUnlockedCutScene::init", "Malformed unlocked goody");
461         }
462     }
463 }   // init
464 
465 // ----------------------------------------------------------------------------
466 
tearDown()467 void FeatureUnlockedCutScene::tearDown()
468 {
469     Screen::tearDown();
470 }   // tearDown
471 
472 // ----------------------------------------------------------------------------
473 
474 //FIXME: doesn't go here...
475 template<typename T>
keepInRange(T from,T to,T value)476 T keepInRange(T from, T to, T value)
477 {
478     if (value < from) return from;
479     if (value > to  ) return to;
480     return value;
481 }   // keepInRange
482 
483 // ----------------------------------------------------------------------------
484 
onUpdate(float dt)485 void FeatureUnlockedCutScene::onUpdate(float dt)
486 {
487     m_global_time += dt;
488     const int unlockedStuffCount = m_unlocked_stuff.size();
489 
490     // When the chest has opened but the items are not yet at their final position
491     if (m_global_time > GIFT_EXIT_FROM && m_global_time < GIFT_EXIT_TO)
492     {
493         float progress_factor = (m_global_time - GIFT_EXIT_FROM)
494                               / (GIFT_EXIT_TO - GIFT_EXIT_FROM);
495         float smoothed_progress_factor =
496                                 sinf((progress_factor - 0.5f)*M_PI)/2.0f + 0.5f;
497 
498         for (int n=0; n<unlockedStuffCount; n++)
499         {
500             if (m_unlocked_stuff[n].m_root_gift_node == NULL) continue;
501 
502             core::vector3df pos = m_unlocked_stuff[n].m_root_gift_node->getPosition();
503             pos.Y = sinf(smoothed_progress_factor*2.5f)*10.0f;
504 
505             // when there are more than 1 unlocked items, make sure they each
506             // have their own path when they move
507             // and that they won't end offscreen in usual situations
508 
509             // Put the trophy (item 0 in the unlocked stuff) in center
510             // For this, we exchange the position of the trophy with
511             // the item in the middle of the unlocked array.
512             int pos_value = (n == 0) ? unlockedStuffCount/2 :
513                             (n == unlockedStuffCount/2) ? 0 : n;
514             float offset = (float) pos_value - unlockedStuffCount/2.0f + 0.5f;
515             offset *= (unlockedStuffCount <= 3) ? 1.4f :
516                       (unlockedStuffCount <= 5) ? 1.2f : 1.0f;
517             pos.X += offset*dt;
518 
519             pos.Z = smoothed_progress_factor * -4.0f;
520 
521             m_unlocked_stuff[n].m_root_gift_node->setPosition(pos);
522         }
523     }
524 
525     for (int n=0; n<unlockedStuffCount; n++)
526     {
527         if (m_unlocked_stuff[n].m_root_gift_node == NULL) continue;
528 
529         irr::core::vector3df new_rot = m_unlocked_stuff[n].m_root_gift_node
530                                                           ->getRotation()
531                                      + core::vector3df(0.0f, dt*25.0f, 0.0f);
532         m_unlocked_stuff[n].m_root_gift_node->setRotation(new_rot);
533 
534         if (!m_unlocked_stuff[n].m_pictures.empty())
535         {
536             const int picture_count = (int)m_unlocked_stuff[n].m_pictures.size();
537 
538             if (picture_count > 1)
539             {
540                 const int previousTextureID = m_unlocked_stuff[n].m_curr_image;
541                 const int textureID = int(m_global_time/1.2f) % picture_count;
542 
543                 if (textureID != previousTextureID)
544                 {
545 #ifndef SERVER_ONLY
546                     if (CVS->isGLSL())
547                     {
548                         SP::SPMesh* mesh = static_cast<SP::SPMeshNode*>
549                                            (m_unlocked_stuff[n].m_side_1)->getSPM();
550 
551                         assert(mesh->getMeshBufferCount() == 1);
552                         SP::SPMeshBuffer* mb = mesh->getSPMeshBuffer(0);
553                         mb->getSPTextures()[0] =
554                             m_unlocked_stuff[n].m_sp_pictures[textureID];
555                         mb->reloadTextureCompare();
556 
557                         mesh = static_cast<SP::SPMeshNode*>
558                                     (m_unlocked_stuff[n].m_side_2)->getSPM();
559                         assert(mesh->getMeshBufferCount() == 1);
560                         mb = mesh->getSPMeshBuffer(0);
561                         mb->getSPTextures()[0] =
562                             m_unlocked_stuff[n].m_sp_pictures[textureID];
563                         mb->reloadTextureCompare();
564 
565                         m_unlocked_stuff[n].m_curr_image = textureID;
566                     }
567                     else
568                     {
569                         scene::IMesh* mesh =
570                             static_cast<scene::IMeshSceneNode*>
571                                        (m_unlocked_stuff[n].m_side_1)->getMesh();
572 
573                         assert(mesh->getMeshBufferCount() == 1);
574 
575                         scene::IMeshBuffer* mb = mesh->getMeshBuffer(0);
576 
577                         SMaterial& m = mb->getMaterial();
578                         m.setTexture(0, m_unlocked_stuff[n].m_pictures[textureID]);
579 
580                         // FIXME: this mesh is already associated with this
581                         // node. I'm calling this to force irrLicht to refresh
582                         // the display, now that Material has changed.
583                         static_cast<scene::IMeshSceneNode*>
584                                  (m_unlocked_stuff[n].m_side_1)->setMesh(mesh);
585 
586                         m_unlocked_stuff[n].m_curr_image = textureID;
587 
588 
589                         mesh = static_cast<scene::IMeshSceneNode*>
590                                     (m_unlocked_stuff[n].m_side_2)->getMesh();
591                         assert(mesh->getMeshBufferCount() == 1);
592                         mb = mesh->getMeshBuffer(0);
593 
594                         SMaterial& m2 = mb->getMaterial();
595                         m2.setTexture(0, m_unlocked_stuff[n].m_pictures[textureID]);
596 
597                         // FIXME: this mesh is already associated with this
598                         // node. I'm calling this to force irrLicht to refresh
599                         // the display, now that Material has changed.
600                         static_cast<scene::IMeshSceneNode*>
601                             (m_unlocked_stuff[n].m_side_2)->setMesh(mesh);
602 
603                         m_unlocked_stuff[n].m_curr_image = textureID;
604                     }
605 #endif
606                 }   // textureID != previousTextureID
607             }   // if picture_count>1
608         }   // if !m_unlocked_stuff[n].m_pictures.empty()
609 
610         float scale = m_unlocked_stuff[n].m_scale;
611         if (m_global_time <= GIFT_EXIT_FROM)
612             scale *= 0.1f;
613         else if (m_global_time > GIFT_EXIT_FROM &&
614                  m_global_time < GIFT_EXIT_TO)
615         {
616             scale *= (  (m_global_time - GIFT_EXIT_FROM)
617                        / (GIFT_EXIT_TO - GIFT_EXIT_FROM) );
618         }
619         m_unlocked_stuff[n].m_root_gift_node
620                             ->setScale(core::vector3df(scale, scale, scale));
621     }   // for n<unlockedStuffCount
622 
623     assert(m_unlocked_stuff.size() > 0);
624 
625     static const int w = irr_driver->getFrameSize().Width;
626     static const int h = irr_driver->getFrameSize().Height;
627     const irr::video::SColor color(255, 255, 255, 255);
628 
629     GUIEngine::getTitleFont()->draw(_("Challenge Completed"),
630                                     core::rect< s32 >( 0, 0, w, h/10 ),
631                                     color,
632                                     true/* center h */, true /* center v */ );
633 
634     if (m_global_time > GIFT_EXIT_TO)
635     {
636         const irr::video::SColor color2(255, 0, 0, 0);
637         const int fontH = GUIEngine::getFontHeight();
638         const int MARGIN = 10;
639 
640         int message_y = h - fontH*3 - MARGIN;
641 
642         for (int n=unlockedStuffCount - 1; n>=0; n--)
643         {
644             GUIEngine::getFont()->draw(m_unlocked_stuff[n].m_unlock_message,
645                                        core::rect< s32 >( 0, message_y, w,
646                                                              message_y + fontH ),
647                                        color2,
648                                        true /* center h */, true /* center v */ );
649             message_y -= (fontH + MARGIN);
650         }
651     }
652 }   // onUpdate
653 
654 // ----------------------------------------------------------------------------
655 
addUnlockedTrack(const Track * track)656 void FeatureUnlockedCutScene::addUnlockedTrack(const Track* track)
657 {
658     if (track == NULL)
659     {
660         Log::error("FeatureUnlockedCutScene::addUnlockedTrack",
661                    "Unlocked track does not exist");
662         return;
663     }
664 
665     const std::string sshot = track->getScreenshotFile();
666     core::stringw trackname = track->getName();
667     addUnlockedPicture( irr_driver->getTexture(sshot.c_str()), 4.0f, 3.0f,
668         _("You unlocked track %0", trackname));
669 }
670 
671 // ----------------------------------------------------------------------------
672 
addUnlockedGP(const GrandPrixData * gp)673 void FeatureUnlockedCutScene::addUnlockedGP(const GrandPrixData* gp)
674 {
675     std::vector<ITexture*> images;
676     core::stringw gpname;
677     if (gp == NULL)
678     {
679         Log::error("FeatureUnlockedCutScene::addUnlockedGP",
680                    "Unlocked GP does not exist");
681         const std::string t_name =
682             file_manager->getAsset(FileManager::GUI_ICON, "main_help.png");
683         video::ITexture* WTF_image = irr_driver->getTexture(t_name);
684         images.push_back(WTF_image);
685     }
686     else
687     {
688         const std::vector<std::string> gptracks = gp->getTrackNames();
689         const int track_amount = (int)gptracks.size();
690 
691         if (track_amount == 0)
692         {
693             Log::error("FeatureUnlockedCutScene::addUnlockedGP",
694                        "Unlocked GP is empty");
695             video::ITexture* WTF_image =
696                 irr_driver->getTexture( file_manager
697                                         ->getAsset(FileManager::GUI_ICON,"main_help.png"));
698             images.push_back(WTF_image);
699         }
700 
701         for (int t=0; t<track_amount; t++)
702         {
703             Track* track = track_manager->getTrack(gptracks[t]);
704 
705             const std::string t_name =
706                 track ? track->getScreenshotFile()
707                       : file_manager->getAsset(FileManager::GUI_ICON, "main_help.png");
708             ITexture* tex = irr_driver->getTexture(t_name);
709             images.push_back(tex);
710         }
711         gpname = gp->getName();
712     }
713 
714     addUnlockedPictures(images, 4.0f, 3.0f, _("You unlocked grand prix %0", gpname));
715 }
716 
717 // ----------------------------------------------------------------------------
718 
onEscapePressed()719 bool FeatureUnlockedCutScene::onEscapePressed()
720 {
721     continueButtonPressed();
722     return false; // continueButtonPressed already pop'ed the menu
723 }   // onEscapePressed
724 
725 // ----------------------------------------------------------------------------
726 
continueButtonPressed()727 void FeatureUnlockedCutScene::continueButtonPressed()
728 {
729     if (m_global_time < GIFT_EXIT_TO)
730     {
731         // If animation was not over yet, the button is used to skip the animation
732         while (m_global_time < GIFT_EXIT_TO)
733         {
734             // simulate all the steps of the animation until we reach the end
735             onUpdate(0.4f);
736             World::getWorld()->updateWorld(stk_config->time2Ticks(0.4f));
737         }
738     }
739     else
740     {
741         ((CutsceneWorld*)World::getWorld())->abortCutscene();
742     }
743 
744 }   // continueButtonPressed
745 
746 // ----------------------------------------------------------------------------
747 
eventCallback(GUIEngine::Widget * widget,const std::string & name,const int playerID)748 void FeatureUnlockedCutScene::eventCallback(GUIEngine::Widget* widget,
749                                             const std::string& name,
750                                             const int playerID)
751 {
752     if (name == "continue")
753     {
754         continueButtonPressed();
755     }
756 }   // eventCallback
757 
758 // ----------------------------------------------------------------------------
759 
getInGameMenuMusic() const760 MusicInformation* FeatureUnlockedCutScene::getInGameMenuMusic() const
761 {
762     MusicInformation* mi = music_manager->getMusicInformation("win_theme.music");
763     return mi;
764 }
765