781 lines
28 KiB
C++
781 lines
28 KiB
C++
//
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
// Copyright (C) 2010-2015 SuperTuxKart-Team
|
|
//
|
|
// 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 "states_screens/feature_unlocked.hpp"
|
|
|
|
#include <SColor.h>
|
|
|
|
#include "audio/music_manager.hpp"
|
|
#include "challenges/challenge_data.hpp"
|
|
#include "challenges/unlock_manager.hpp"
|
|
#include "config/player_manager.hpp"
|
|
#include "config/stk_config.hpp"
|
|
#include "config/user_config.hpp"
|
|
#include "graphics/central_settings.hpp"
|
|
#include "graphics/sp/sp_base.hpp"
|
|
#include "graphics/sp/sp_mesh.hpp"
|
|
#include "graphics/sp/sp_mesh_buffer.hpp"
|
|
#include "graphics/sp/sp_mesh_node.hpp"
|
|
#include "graphics/sp/sp_texture_manager.hpp"
|
|
#include "guiengine/engine.hpp"
|
|
#include "guiengine/scalable_font.hpp"
|
|
#include "io/file_manager.hpp"
|
|
#include "karts/kart_model.hpp"
|
|
#include "karts/kart_properties.hpp"
|
|
#include "karts/kart_properties_manager.hpp"
|
|
#include "modes/cutscene_world.hpp"
|
|
#include "modes/overworld.hpp"
|
|
#include "modes/world.hpp"
|
|
#include "race/grand_prix_manager.hpp"
|
|
#include "states_screens/main_menu_screen.hpp"
|
|
#include "states_screens/state_manager.hpp"
|
|
#include "tracks/track.hpp"
|
|
#include "tracks/track_manager.hpp"
|
|
#include "utils/string_utils.hpp"
|
|
#include "utils/translation.hpp"
|
|
|
|
#include <IAnimatedMeshSceneNode.h>
|
|
#include <ICameraSceneNode.h>
|
|
#include <ILightSceneNode.h>
|
|
#include <IMeshSceneNode.h>
|
|
#include <ISceneManager.h>
|
|
|
|
#include <iostream>
|
|
|
|
#ifndef SERVER_ONLY
|
|
#include <ge_main.hpp>
|
|
#endif
|
|
|
|
using namespace irr::core;
|
|
using namespace irr::gui;
|
|
using namespace irr::video;
|
|
|
|
const float ANIM_TO = 7.0f;
|
|
const int GIFT_EXIT_FROM = (int)ANIM_TO;
|
|
const int GIFT_EXIT_TO = GIFT_EXIT_FROM + 7;
|
|
|
|
// ============================================================================
|
|
|
|
#if 0
|
|
#pragma mark FeatureUnlockedCutScene::UnlockedThing
|
|
#endif
|
|
|
|
FeatureUnlockedCutScene::UnlockedThing::UnlockedThing(const std::string &model,
|
|
const irr::core::stringw &msg)
|
|
{
|
|
m_unlocked_kart = NULL;
|
|
m_unlock_message = msg;
|
|
m_unlock_model = model;
|
|
m_curr_image = -1;
|
|
m_scale = 1.0f;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
FeatureUnlockedCutScene::UnlockedThing::UnlockedThing(const KartProperties* kart,
|
|
const irr::core::stringw &msg)
|
|
{
|
|
m_unlocked_kart = kart;
|
|
m_unlock_message = msg;
|
|
m_curr_image = -1;
|
|
m_scale = 1.0f;
|
|
} // UnlockedThing::UnlockedThing
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
FeatureUnlockedCutScene::UnlockedThing::UnlockedThing(irr::video::ITexture* pict,
|
|
float w, float h,
|
|
const irr::core::stringw &msg)
|
|
{
|
|
m_unlocked_kart = NULL;
|
|
#ifndef SERVER_ONLY
|
|
if (CVS->isGLSL())
|
|
{
|
|
m_sp_pictures.push_back(SP::SPTextureManager::get()
|
|
->getTexture(pict->getName().getPtr(), NULL, true,
|
|
""/*container_id*/));
|
|
}
|
|
else
|
|
{
|
|
m_pictures.push_back(pict);
|
|
}
|
|
#endif
|
|
m_w = w;
|
|
m_h = h;
|
|
m_unlock_message = msg;
|
|
m_curr_image = -1;
|
|
m_scale = 1.0f;
|
|
} // UnlockedThing::UnlockedThing
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
FeatureUnlockedCutScene::UnlockedThing
|
|
::UnlockedThing(std::vector<irr::video::ITexture*> picts,
|
|
float w, float h,
|
|
const irr::core::stringw &msg)
|
|
{
|
|
m_unlocked_kart = NULL;
|
|
#ifndef SERVER_ONLY
|
|
if (CVS->isGLSL())
|
|
{
|
|
for (auto* pict : picts)
|
|
{
|
|
m_sp_pictures.push_back(SP::SPTextureManager::get()
|
|
->getTexture(pict->getName().getPtr(), NULL, true,
|
|
""/*container_id*/));
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
m_pictures = picts;
|
|
}
|
|
m_pictures = picts;
|
|
m_w = w;
|
|
m_h = h;
|
|
m_unlock_message = msg;
|
|
m_curr_image = 0;
|
|
m_scale = 1.0f;
|
|
} // UnlockedThing::UnlockedThing
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
FeatureUnlockedCutScene::UnlockedThing::~UnlockedThing()
|
|
{
|
|
if (m_root_gift_node != NULL) irr_driver->removeNode(m_root_gift_node);
|
|
m_root_gift_node = NULL;
|
|
} // UnlockedThing::~UnlockedThing
|
|
|
|
// ============================================================================
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark FeatureUnlockedCutScene
|
|
#endif
|
|
|
|
FeatureUnlockedCutScene::FeatureUnlockedCutScene()
|
|
: CutsceneScreen("cutscene.stkgui")
|
|
{
|
|
m_key_angle = 0;
|
|
} // FeatureUnlockedCutScene
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::loadedFromFile()
|
|
{
|
|
} // loadedFromFile
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::onCutsceneEnd()
|
|
{
|
|
m_unlocked_stuff.clearAndDeleteAll();
|
|
#ifndef SERVER_ONLY
|
|
if (CVS->isGLSL())
|
|
{
|
|
SP::SPTextureManager::get()->removeUnusedTextures();
|
|
}
|
|
#endif
|
|
m_all_kart_models.clearAndDeleteAll();
|
|
|
|
// update point count and the list of locked/unlocked stuff
|
|
PlayerManager::getCurrentPlayer()->computeActive();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::
|
|
findWhatWasUnlocked(RaceManager::Difficulty difficulty,
|
|
std::vector<const ChallengeData*>& unlocked)
|
|
{
|
|
if (UserConfigParams::m_unlock_everything > 0)
|
|
return;
|
|
|
|
PlayerProfile *player = PlayerManager::getCurrentPlayer();
|
|
|
|
// The number of points is updated before this function is called
|
|
int points_before = player->getPointsBefore();
|
|
int points_now = player->getPoints();
|
|
|
|
std::vector<std::string> tracks;
|
|
std::vector<std::string> gps;
|
|
std::vector<std::string> karts;
|
|
|
|
player->computeActive();
|
|
unlock_manager->findWhatWasUnlocked(points_before, points_now, tracks, gps,
|
|
karts, unlocked);
|
|
|
|
for (unsigned int i = 0; i < tracks.size(); i++)
|
|
{
|
|
addUnlockedTrack(track_manager->getTrack(tracks[i]));
|
|
}
|
|
for (unsigned int i = 0; i < gps.size(); i++)
|
|
{
|
|
addUnlockedGP(grand_prix_manager->getGrandPrix(gps[i]));
|
|
}
|
|
for (unsigned int i = 0; i < karts.size(); i++)
|
|
{
|
|
addUnlockedKart(kart_properties_manager->getKart(karts[i]));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::addTrophy(RaceManager::Difficulty difficulty,
|
|
bool is_grandprix)
|
|
{
|
|
core::stringw msg;
|
|
|
|
int gp_factor = is_grandprix ? GP_FACTOR : 1;
|
|
RaceManager::Difficulty max_unlocked_difficulty = RaceManager::DIFFICULTY_BEST;
|
|
|
|
if (PlayerManager::getCurrentPlayer()->isLocked("difficulty_best"))
|
|
max_unlocked_difficulty = RaceManager::DIFFICULTY_HARD;
|
|
|
|
switch (difficulty)
|
|
{
|
|
case RaceManager::DIFFICULTY_EASY:
|
|
msg = _("You completed the easy challenge! "
|
|
"Points earned on this level: %i/%i",
|
|
CHALLENGE_POINTS[RaceManager::DIFFICULTY_EASY]*gp_factor,
|
|
CHALLENGE_POINTS[max_unlocked_difficulty]*gp_factor);
|
|
break;
|
|
case RaceManager::DIFFICULTY_MEDIUM:
|
|
msg = _("You completed the intermediate challenge! "
|
|
"Points earned on this level: %i/%i",
|
|
CHALLENGE_POINTS[RaceManager::DIFFICULTY_MEDIUM]*gp_factor,
|
|
CHALLENGE_POINTS[max_unlocked_difficulty]*gp_factor);
|
|
break;
|
|
case RaceManager::DIFFICULTY_HARD:
|
|
msg = _("You completed the difficult challenge! "
|
|
"Points earned on this level: %i/%i",
|
|
CHALLENGE_POINTS[RaceManager::DIFFICULTY_HARD]*gp_factor,
|
|
CHALLENGE_POINTS[max_unlocked_difficulty]*gp_factor);
|
|
break;
|
|
case RaceManager::DIFFICULTY_BEST:
|
|
msg = _("You completed the SuperTux challenge! "
|
|
"Points earned on this level: %i/%i",
|
|
CHALLENGE_POINTS[RaceManager::DIFFICULTY_BEST]*gp_factor,
|
|
CHALLENGE_POINTS[max_unlocked_difficulty]*gp_factor);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
std::string model;
|
|
switch (difficulty)
|
|
{
|
|
case RaceManager::DIFFICULTY_EASY:
|
|
model = file_manager->getAsset(FileManager::MODEL,"trophy_bronze.spm");
|
|
break;
|
|
case RaceManager::DIFFICULTY_MEDIUM:
|
|
model = file_manager->getAsset(FileManager::MODEL,"trophy_silver.spm");
|
|
break;
|
|
case RaceManager::DIFFICULTY_HARD:
|
|
model = file_manager->getAsset(FileManager::MODEL,"trophy_gold.spm");
|
|
break;
|
|
case RaceManager::DIFFICULTY_BEST:
|
|
model = file_manager->getAsset(FileManager::MODEL,"trophy_platinum.spm");
|
|
break;
|
|
default:
|
|
assert(false);
|
|
return;
|
|
}
|
|
|
|
|
|
m_unlocked_stuff.push_back( new UnlockedThing(model, msg) );
|
|
} // addTrophy
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::addUnlockedKart(const KartProperties* unlocked_kart)
|
|
{
|
|
if (unlocked_kart == NULL)
|
|
{
|
|
Log::error("FeatureUnlockedCutScene::addUnlockedKart",
|
|
"Unlocked kart does not exist");
|
|
return;
|
|
}
|
|
irr::core::stringw msg = _("You unlocked %s!", unlocked_kart->getName());
|
|
m_unlocked_stuff.push_back( new UnlockedThing(unlocked_kart, msg) );
|
|
} // addUnlockedKart
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::addUnlockedPicture(irr::video::ITexture* picture,
|
|
float w, float h,
|
|
const irr::core::stringw &msg)
|
|
{
|
|
if (picture == NULL)
|
|
{
|
|
Log::warn("FeatureUnlockedCutScene::addUnlockedPicture",
|
|
"Unlockable has no picture: %s",
|
|
core::stringc(msg.c_str()).c_str());
|
|
picture = irr_driver->getTexture(
|
|
file_manager->getAsset(FileManager::GUI_ICON,"main_help.png"));
|
|
|
|
}
|
|
|
|
m_unlocked_stuff.push_back( new UnlockedThing(picture, w, h, msg) );
|
|
} // addUnlockedPicture
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::addUnlockedPictures
|
|
(std::vector<irr::video::ITexture*> pictures,
|
|
float w, float h, irr::core::stringw msg)
|
|
{
|
|
assert(!pictures.empty());
|
|
|
|
m_unlocked_stuff.push_back( new UnlockedThing(pictures, w, h, msg) );
|
|
} // addUnlockedPictures
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::init()
|
|
{
|
|
m_global_time = 0.0f;
|
|
CutsceneWorld::setUseDuration(false);
|
|
|
|
const int unlockedStuffCount = m_unlocked_stuff.size();
|
|
|
|
if (unlockedStuffCount == 0)
|
|
Log::error("FeatureUnlockedCutScene::init",
|
|
"There is nothing in the unlock chest");
|
|
|
|
m_all_kart_models.clearAndDeleteAll();
|
|
for (int n=0; n<unlockedStuffCount; n++)
|
|
{
|
|
if (m_unlocked_stuff[n].m_unlock_model.size() > 0)
|
|
{
|
|
irr::scene::IMesh *mesh =
|
|
irr_driver->getMesh(m_unlocked_stuff[n].m_unlock_model);
|
|
m_unlocked_stuff[n].m_root_gift_node =
|
|
irr_driver->addMesh(mesh, "unlocked_model");
|
|
m_unlocked_stuff[n].m_scale = 0.7f;
|
|
}
|
|
else if (m_unlocked_stuff[n].m_unlocked_kart != NULL)
|
|
{
|
|
KartModel *kart_model =
|
|
m_unlocked_stuff[n].m_unlocked_kart->getKartModelCopy();
|
|
m_all_kart_models.push_back(kart_model);
|
|
m_unlocked_stuff[n].m_root_gift_node =
|
|
kart_model->attachModel(true, false);
|
|
m_unlocked_stuff[n].m_scale = 5.0f;
|
|
kart_model->setAnimation(KartModel::AF_DEFAULT);
|
|
// Set model current frame to "center"
|
|
kart_model->update(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
#ifdef DEBUG
|
|
m_unlocked_stuff[n].m_root_gift_node->setName("unlocked kart");
|
|
#endif
|
|
}
|
|
#ifndef SERVER_ONLY
|
|
else if (!m_unlocked_stuff[n].m_sp_pictures.empty())
|
|
{
|
|
scene::IMesh* mesh = irr_driver->createTexturedQuadMesh(NULL,
|
|
m_unlocked_stuff[n].m_w, m_unlocked_stuff[n].m_h);
|
|
m_unlocked_stuff[n].m_root_gift_node =
|
|
irr_driver->getSceneManager()->addEmptySceneNode();
|
|
SP::SPMesh* spm = SP::convertEVTStandard(mesh);
|
|
m_unlocked_stuff[n].m_side_1 = irr_driver->addMesh(spm,
|
|
"unlocked_picture", m_unlocked_stuff[n].m_root_gift_node);
|
|
spm->getSPMeshBuffer(0)->uploadGLMesh();
|
|
spm->getSPMeshBuffer(0)->getSPTextures()[0] =
|
|
m_unlocked_stuff[n].m_sp_pictures[0];
|
|
spm->getSPMeshBuffer(0)->reloadTextureCompare();
|
|
spm->drop();
|
|
|
|
mesh = irr_driver->createTexturedQuadMesh(NULL,
|
|
m_unlocked_stuff[n].m_w, m_unlocked_stuff[n].m_h);
|
|
spm = SP::convertEVTStandard(mesh);
|
|
m_unlocked_stuff[n].m_side_2 = irr_driver->addMesh(spm,
|
|
"unlocked_picture", m_unlocked_stuff[n].m_root_gift_node);
|
|
m_unlocked_stuff[n].m_side_2->setRotation
|
|
(core::vector3df(0.0f, 180.0f, 0.0f));
|
|
spm->getSPMeshBuffer(0)->uploadGLMesh();
|
|
spm->getSPMeshBuffer(0)->getSPTextures()[0] =
|
|
m_unlocked_stuff[n].m_sp_pictures[0];
|
|
spm->getSPMeshBuffer(0)->reloadTextureCompare();
|
|
spm->drop();
|
|
#ifdef DEBUG
|
|
m_unlocked_stuff[n].m_root_gift_node->setName("unlocked track picture");
|
|
#endif
|
|
}
|
|
#endif
|
|
else if (!m_unlocked_stuff[n].m_pictures.empty())
|
|
{
|
|
#ifndef SERVER_ONLY
|
|
bool vk = (GE::getDriver()->getDriverType() == video::EDT_VULKAN);
|
|
if (vk)
|
|
GE::getGEConfig()->m_convert_irrlicht_mesh = true;
|
|
#endif
|
|
|
|
video::SMaterial m;
|
|
//m.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
|
m.BackfaceCulling = true;
|
|
m.setTexture(0, m_unlocked_stuff[n].m_pictures[0]);
|
|
m.AmbientColor = video::SColor(255, 255, 255, 255);
|
|
m.DiffuseColor = video::SColor(255, 255, 255, 255);
|
|
m.EmissiveColor = video::SColor(255, 255, 255, 255);
|
|
m.SpecularColor = video::SColor(255, 255, 255, 255);
|
|
m.GouraudShading = false;
|
|
m.Shininess = 0;
|
|
|
|
m.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
|
|
m.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
|
|
scene::IMesh* mesh =
|
|
irr_driver->createTexturedQuadMesh(&m,
|
|
m_unlocked_stuff[n].m_w,
|
|
m_unlocked_stuff[n].m_h);
|
|
m_unlocked_stuff[n].m_root_gift_node =
|
|
irr_driver->getSceneManager()->addEmptySceneNode();
|
|
irr_driver->setAllMaterialFlags(mesh);
|
|
m_unlocked_stuff[n].m_side_1 =
|
|
irr_driver->addMesh(mesh, "unlocked_picture",
|
|
m_unlocked_stuff[n].m_root_gift_node);
|
|
mesh->drop();
|
|
|
|
mesh = irr_driver->createTexturedQuadMesh(&m,
|
|
m_unlocked_stuff[n].m_w,
|
|
m_unlocked_stuff[n].m_h);
|
|
irr_driver->setAllMaterialFlags(mesh);
|
|
m_unlocked_stuff[n].m_side_2 =
|
|
irr_driver->addMesh(mesh, "unlocked_picture",
|
|
m_unlocked_stuff[n].m_root_gift_node);
|
|
m_unlocked_stuff[n].m_side_2
|
|
->setRotation(core::vector3df(0.0f, 180.0f, 0.0f));
|
|
mesh->drop();
|
|
|
|
#ifndef SERVER_ONLY
|
|
if (vk)
|
|
GE::getGEConfig()->m_convert_irrlicht_mesh = false;
|
|
#endif
|
|
#ifdef DEBUG
|
|
m_unlocked_stuff[n].m_root_gift_node->setName("unlocked track picture");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
Log::error("FeatureUnlockedCutScene::init", "Malformed unlocked goody");
|
|
}
|
|
}
|
|
} // init
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::tearDown()
|
|
{
|
|
Screen::tearDown();
|
|
} // tearDown
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
//FIXME: doesn't go here...
|
|
template<typename T>
|
|
T keepInRange(T from, T to, T value)
|
|
{
|
|
if (value < from) return from;
|
|
if (value > to ) return to;
|
|
return value;
|
|
} // keepInRange
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::onUpdate(float dt)
|
|
{
|
|
m_global_time += dt;
|
|
const int unlockedStuffCount = m_unlocked_stuff.size();
|
|
|
|
// When the chest has opened but the items are not yet at their final position
|
|
if (m_global_time > GIFT_EXIT_FROM && m_global_time < GIFT_EXIT_TO)
|
|
{
|
|
float progress_factor = (m_global_time - GIFT_EXIT_FROM)
|
|
/ (GIFT_EXIT_TO - GIFT_EXIT_FROM);
|
|
float smoothed_progress_factor =
|
|
sinf((progress_factor - 0.5f)*M_PI)/2.0f + 0.5f;
|
|
|
|
for (int n=0; n<unlockedStuffCount; n++)
|
|
{
|
|
if (m_unlocked_stuff[n].m_root_gift_node == NULL) continue;
|
|
|
|
core::vector3df pos = m_unlocked_stuff[n].m_root_gift_node->getPosition();
|
|
pos.Y = sinf(smoothed_progress_factor*2.5f)*10.0f;
|
|
|
|
// when there are more than 1 unlocked items, make sure they each
|
|
// have their own path when they move
|
|
// and that they won't end offscreen in usual situations
|
|
|
|
// Put the trophy (item 0 in the unlocked stuff) in center
|
|
// For this, we exchange the position of the trophy with
|
|
// the item in the middle of the unlocked array.
|
|
int pos_value = (n == 0) ? unlockedStuffCount/2 :
|
|
(n == unlockedStuffCount/2) ? 0 : n;
|
|
float offset = (float) pos_value - unlockedStuffCount/2.0f + 0.5f;
|
|
offset *= (unlockedStuffCount <= 3) ? 1.4f :
|
|
(unlockedStuffCount <= 5) ? 1.2f : 1.0f;
|
|
pos.X += offset*dt;
|
|
|
|
pos.Z = smoothed_progress_factor * -4.0f;
|
|
|
|
m_unlocked_stuff[n].m_root_gift_node->setPosition(pos);
|
|
}
|
|
}
|
|
|
|
for (int n=0; n<unlockedStuffCount; n++)
|
|
{
|
|
if (m_unlocked_stuff[n].m_root_gift_node == NULL) continue;
|
|
|
|
irr::core::vector3df new_rot = m_unlocked_stuff[n].m_root_gift_node
|
|
->getRotation()
|
|
+ core::vector3df(0.0f, dt*25.0f, 0.0f);
|
|
m_unlocked_stuff[n].m_root_gift_node->setRotation(new_rot);
|
|
|
|
if (!m_unlocked_stuff[n].m_pictures.empty())
|
|
{
|
|
const int picture_count = (int)m_unlocked_stuff[n].m_pictures.size();
|
|
|
|
if (picture_count > 1)
|
|
{
|
|
const int previousTextureID = m_unlocked_stuff[n].m_curr_image;
|
|
const int textureID = int(m_global_time/1.2f) % picture_count;
|
|
|
|
if (textureID != previousTextureID)
|
|
{
|
|
#ifndef SERVER_ONLY
|
|
if (CVS->isGLSL())
|
|
{
|
|
SP::SPMesh* mesh = static_cast<SP::SPMeshNode*>
|
|
(m_unlocked_stuff[n].m_side_1)->getSPM();
|
|
|
|
assert(mesh->getMeshBufferCount() == 1);
|
|
SP::SPMeshBuffer* mb = mesh->getSPMeshBuffer(0);
|
|
mb->getSPTextures()[0] =
|
|
m_unlocked_stuff[n].m_sp_pictures[textureID];
|
|
mb->reloadTextureCompare();
|
|
|
|
mesh = static_cast<SP::SPMeshNode*>
|
|
(m_unlocked_stuff[n].m_side_2)->getSPM();
|
|
assert(mesh->getMeshBufferCount() == 1);
|
|
mb = mesh->getSPMeshBuffer(0);
|
|
mb->getSPTextures()[0] =
|
|
m_unlocked_stuff[n].m_sp_pictures[textureID];
|
|
mb->reloadTextureCompare();
|
|
|
|
m_unlocked_stuff[n].m_curr_image = textureID;
|
|
}
|
|
else
|
|
{
|
|
scene::IMesh* mesh =
|
|
static_cast<scene::IMeshSceneNode*>
|
|
(m_unlocked_stuff[n].m_side_1)->getMesh();
|
|
|
|
assert(mesh->getMeshBufferCount() == 1);
|
|
|
|
scene::IMeshBuffer* mb = mesh->getMeshBuffer(0);
|
|
|
|
SMaterial& m = mb->getMaterial();
|
|
m.setTexture(0, m_unlocked_stuff[n].m_pictures[textureID]);
|
|
|
|
// FIXME: this mesh is already associated with this
|
|
// node. I'm calling this to force irrLicht to refresh
|
|
// the display, now that Material has changed.
|
|
static_cast<scene::IMeshSceneNode*>
|
|
(m_unlocked_stuff[n].m_side_1)->setMesh(mesh);
|
|
|
|
m_unlocked_stuff[n].m_curr_image = textureID;
|
|
|
|
|
|
mesh = static_cast<scene::IMeshSceneNode*>
|
|
(m_unlocked_stuff[n].m_side_2)->getMesh();
|
|
assert(mesh->getMeshBufferCount() == 1);
|
|
mb = mesh->getMeshBuffer(0);
|
|
|
|
SMaterial& m2 = mb->getMaterial();
|
|
m2.setTexture(0, m_unlocked_stuff[n].m_pictures[textureID]);
|
|
|
|
// FIXME: this mesh is already associated with this
|
|
// node. I'm calling this to force irrLicht to refresh
|
|
// the display, now that Material has changed.
|
|
static_cast<scene::IMeshSceneNode*>
|
|
(m_unlocked_stuff[n].m_side_2)->setMesh(mesh);
|
|
|
|
m_unlocked_stuff[n].m_curr_image = textureID;
|
|
}
|
|
#endif
|
|
} // textureID != previousTextureID
|
|
} // if picture_count>1
|
|
} // if !m_unlocked_stuff[n].m_pictures.empty()
|
|
|
|
float scale = m_unlocked_stuff[n].m_scale;
|
|
if (m_global_time <= GIFT_EXIT_FROM)
|
|
scale *= 0.1f;
|
|
else if (m_global_time > GIFT_EXIT_FROM &&
|
|
m_global_time < GIFT_EXIT_TO)
|
|
{
|
|
scale *= ( (m_global_time - GIFT_EXIT_FROM)
|
|
/ (GIFT_EXIT_TO - GIFT_EXIT_FROM) );
|
|
}
|
|
m_unlocked_stuff[n].m_root_gift_node
|
|
->setScale(core::vector3df(scale, scale, scale));
|
|
} // for n<unlockedStuffCount
|
|
|
|
assert(m_unlocked_stuff.size() > 0);
|
|
|
|
const int w = irr_driver->getFrameSize().Width;
|
|
const int h = irr_driver->getFrameSize().Height;
|
|
const irr::video::SColor color(255, 255, 255, 255);
|
|
|
|
GUIEngine::getTitleFont()->draw(_("Challenge Completed"),
|
|
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, 0, 0, 0);
|
|
const int fontH = GUIEngine::getFontHeight();
|
|
const int MARGIN = 10;
|
|
|
|
int message_y = h - fontH*3 - MARGIN;
|
|
|
|
for (int n=unlockedStuffCount - 1; n>=0; n--)
|
|
{
|
|
GUIEngine::getFont()->draw(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);
|
|
}
|
|
}
|
|
} // onUpdate
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::addUnlockedTrack(const Track* track)
|
|
{
|
|
if (track == NULL)
|
|
{
|
|
Log::error("FeatureUnlockedCutScene::addUnlockedTrack",
|
|
"Unlocked track does not exist");
|
|
return;
|
|
}
|
|
|
|
const std::string sshot = track->getScreenshotFile();
|
|
core::stringw trackname = track->getName();
|
|
addUnlockedPicture( irr_driver->getTexture(sshot.c_str()), 4.0f, 3.0f,
|
|
_("You unlocked track %0", trackname));
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::addUnlockedGP(const GrandPrixData* gp)
|
|
{
|
|
std::vector<ITexture*> images;
|
|
core::stringw gpname;
|
|
if (gp == NULL)
|
|
{
|
|
Log::error("FeatureUnlockedCutScene::addUnlockedGP",
|
|
"Unlocked GP does not exist");
|
|
const std::string t_name =
|
|
file_manager->getAsset(FileManager::GUI_ICON, "main_help.png");
|
|
video::ITexture* WTF_image = irr_driver->getTexture(t_name);
|
|
images.push_back(WTF_image);
|
|
}
|
|
else
|
|
{
|
|
const std::vector<std::string> gptracks = gp->getTrackNames();
|
|
const int track_amount = (int)gptracks.size();
|
|
|
|
if (track_amount == 0)
|
|
{
|
|
Log::error("FeatureUnlockedCutScene::addUnlockedGP",
|
|
"Unlocked GP is empty");
|
|
video::ITexture* WTF_image =
|
|
irr_driver->getTexture( file_manager
|
|
->getAsset(FileManager::GUI_ICON,"main_help.png"));
|
|
images.push_back(WTF_image);
|
|
}
|
|
|
|
for (int t=0; t<track_amount; t++)
|
|
{
|
|
Track* track = track_manager->getTrack(gptracks[t]);
|
|
|
|
const std::string t_name =
|
|
track ? track->getScreenshotFile()
|
|
: file_manager->getAsset(FileManager::GUI_ICON, "main_help.png");
|
|
ITexture* tex = irr_driver->getTexture(t_name);
|
|
images.push_back(tex);
|
|
}
|
|
gpname = gp->getName();
|
|
}
|
|
|
|
addUnlockedPictures(images, 4.0f, 3.0f, _("You unlocked grand prix %0", gpname));
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool FeatureUnlockedCutScene::onEscapePressed()
|
|
{
|
|
continueButtonPressed();
|
|
return false; // continueButtonPressed already pop'ed the menu
|
|
} // onEscapePressed
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::continueButtonPressed()
|
|
{
|
|
if (m_global_time < GIFT_EXIT_TO)
|
|
{
|
|
// If animation was not over yet, the button is used to skip the animation
|
|
while (m_global_time < GIFT_EXIT_TO)
|
|
{
|
|
// simulate all the steps of the animation until we reach the end
|
|
onUpdate(0.4f);
|
|
World::getWorld()->updateWorld(stk_config->time2Ticks(0.4f));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
((CutsceneWorld*)World::getWorld())->abortCutscene();
|
|
}
|
|
|
|
} // continueButtonPressed
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void FeatureUnlockedCutScene::eventCallback(GUIEngine::Widget* widget,
|
|
const std::string& name,
|
|
const int playerID)
|
|
{
|
|
if (name == "continue")
|
|
{
|
|
continueButtonPressed();
|
|
}
|
|
} // eventCallback
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
MusicInformation* FeatureUnlockedCutScene::getInGameMenuMusic() const
|
|
{
|
|
MusicInformation* mi = stk_config->m_unlock_music;
|
|
return mi;
|
|
}
|