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