Merged trunk with this branch. ATM the track screenshot does not work -
I am going to fix this next. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/reverse_mode@10862 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
commit
579715a8d8
@ -2,6 +2,7 @@
|
||||
# Always edit 'CMakeLists.in.txt' and not 'CMakeLists.txt', the latter is automatically generated
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.1)
|
||||
include (CheckCXXSourceCompiles)
|
||||
|
||||
project(SuperTuxKart)
|
||||
|
||||
@ -118,8 +119,24 @@ else()
|
||||
|
||||
if(HAVE_IRRLICHT)
|
||||
message("-- Irrlicht found (in ${HAVE_IRRLICHT}/irrlicht.h)")
|
||||
#include_directories(${IRRLICHT_DIR} ${IRRLICHT_DIR}/include /usr/include/irrlicht/ /usr/local/include/irrlicht/)
|
||||
include_directories(${HAVE_IRRLICHT})
|
||||
find_library(IRRLICHT_LIB /usr/lib /usr/local/lib ${IRRLICHT_DIR}/lib/Linux)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${HAVE_IRRLICHT})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${IRRLICHT_LIB})
|
||||
CHECK_CXX_SOURCE_COMPILES("#include <IrrCompileConfig.h>
|
||||
int main(int argc, char** argv) {
|
||||
#if IRRLICHT_VERSION_MAJOR > 1 || (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8)
|
||||
// ok
|
||||
#else
|
||||
#error Your irrlicht is too old
|
||||
#endif
|
||||
}" IRRLICHT_RECENT_ENOUGH)
|
||||
if(IRRLICHT_RECENT_ENOUGH)
|
||||
# OK
|
||||
else()
|
||||
message(FATAL_ERROR "\n -- This irrlicht is too old, please use irrlicht 1.8 (SVN)")
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "\n -- Irrlicht not found (can't locate irrlicht.h)\n Use -DIRRLICHT_DIR=/path/to/irrlicht")
|
||||
endif()
|
||||
@ -325,5 +342,3 @@ add_custom_target(GenerateDesktopFile
|
||||
COMMAND sed 's\#PREFIX\#${CMAKE_INSTALL_PREFIX}\#' ${CMAKE_CURRENT_SOURCE_DIR}/data/supertuxkart_desktop.template | sed 's\#VERSION\#${PROJECT_VERSION}\#' > ${CMAKE_CURRENT_SOURCE_DIR}/data/supertuxkart.desktop
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
ADD_DEPENDENCIES(supertuxkart GenerateDesktopFile)
|
||||
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -9,11 +9,11 @@
|
||||
</hard>
|
||||
<medium>
|
||||
<karts number="1"/>
|
||||
<requirements energy="10" time="105"/>
|
||||
<requirements energy="10" time="65"/>
|
||||
</medium>
|
||||
<easy>
|
||||
<karts number="1"/>
|
||||
<requirements energy="6" time="115"/>
|
||||
<requirements energy="6" time="80"/>
|
||||
</easy>
|
||||
</challenge>
|
||||
|
||||
|
@ -7,12 +7,12 @@
|
||||
y="0.001"
|
||||
z="-0.003" />
|
||||
|
||||
<material file="nitro-particle.png" />
|
||||
<material file="skid-particle1.png" />
|
||||
|
||||
<!-- Amount of particles emitted per second. The minimum rate
|
||||
is used to show that the skidding bonus is now available,
|
||||
the maximum is used when the skid bonus is applied to the kart -->
|
||||
<rate min="50"
|
||||
<rate min="200"
|
||||
max="600" />
|
||||
|
||||
<!-- Minimal and maximal lifetime of a particle, in milliseconds. -->
|
||||
|
@ -7,7 +7,7 @@
|
||||
y="0.001"
|
||||
z="-0.003" />
|
||||
|
||||
<material file="nitro-particle.png" />
|
||||
<material file="skid-particle2.png" />
|
||||
|
||||
<!-- Amount of particles emitted per second. The minimum rate
|
||||
is used to show that the skidding bonus is now available,
|
||||
|
@ -6,19 +6,31 @@
|
||||
|
||||
<spacer height="2%" width="1"/>
|
||||
|
||||
<icon-button id="novice" icon="gui/difficulty_easy.png"
|
||||
I18N="Difficulty" text="Novice" proportion="1"/>
|
||||
|
||||
<div width="100%" proportion="1" layout="horizontal-row">
|
||||
<icon-button id="novice" icon="gui/difficulty_easy.png"
|
||||
I18N="Difficulty" text="Novice" height="100%"/>
|
||||
<spacer width="5%" height="1"/>
|
||||
<label id="novice_label" proportion="1" height="100%"/>
|
||||
</div>
|
||||
|
||||
<spacer height="8%" width="1"/>
|
||||
|
||||
<icon-button id="intermediate" icon="gui/difficulty_medium.png"
|
||||
I18N="Difficulty" text="Intermediate" proportion="1"/>
|
||||
|
||||
<div width="100%" proportion="1" layout="horizontal-row">
|
||||
<icon-button id="intermediate" icon="gui/difficulty_medium.png"
|
||||
I18N="Difficulty" text="Intermediate" height="100%"/>
|
||||
<spacer width="5%" height="1"/>
|
||||
<label id="intermediate_label" proportion="1" height="100%"/>
|
||||
</div>
|
||||
|
||||
<spacer height="8%" width="1"/>
|
||||
|
||||
<icon-button id="expert" icon="gui/difficulty_hard.png"
|
||||
I18N="Difficulty" text="Expert" proportion="1"/>
|
||||
|
||||
<div width="100%" proportion="1" layout="horizontal-row">
|
||||
<icon-button id="expert" icon="gui/difficulty_hard.png"
|
||||
I18N="Difficulty" text="Expert" height="100%"/>
|
||||
<spacer width="5%" height="1"/>
|
||||
<label id="difficult_label" proportion="1" height="100%"/>
|
||||
</div>
|
||||
|
||||
<spacer height="8%" width="1"/>
|
||||
|
||||
</div>
|
||||
|
69
data/gui/track_info_dialog.stkgui
Normal file
69
data/gui/track_info_dialog.stkgui
Normal file
@ -0,0 +1,69 @@
|
||||
<stkgui>
|
||||
|
||||
<div x="5%" y="5%" width="90%" height="90%" layout="vertical-row">
|
||||
|
||||
<label id="name" width="100%" text_align="center"/>
|
||||
|
||||
<spacer width="1" height="5%"/>
|
||||
|
||||
<div width="95%" proportion="5" layout="horizontal-row">
|
||||
|
||||
<!-- Left pane -->
|
||||
<div proportion="1" height="100%" layout="vertical-row">
|
||||
<label id="highscores" width="100%" text_align="center" text="= Highscores ="/>
|
||||
|
||||
<spacer width="1" height="2%"/>
|
||||
|
||||
<div width="95%" height="fit" layout="horizontal-row">
|
||||
<icon id="iconscore1" icon="gui/random_kart.png" width="font" height="font"/>
|
||||
<spacer width="2%" height="1"/>
|
||||
<label id="highscore1" proportion="1" text="(Empty)"/>
|
||||
</div>
|
||||
|
||||
<spacer width="1" height="2%"/>
|
||||
|
||||
<div width="95%" height="fit" layout="horizontal-row">
|
||||
<icon id="iconscore2" icon="gui/random_kart.png" width="font" height="font"/>
|
||||
<spacer width="2%" height="1"/>
|
||||
<label id="highscore2" proportion="1" text="(Empty)"/>
|
||||
</div>
|
||||
|
||||
<spacer width="1" height="2%"/>
|
||||
|
||||
<div width="95%" height="fit" layout="horizontal-row">
|
||||
<icon id="iconscore3" icon="gui/random_kart.png" width="font" height="font"/>
|
||||
<spacer width="2%" height="1"/>
|
||||
<label id="highscore3" proportion="1" text="(Empty)"/>
|
||||
</div>
|
||||
|
||||
<spacer width="1" proportion="1"/>
|
||||
|
||||
<label id="author" width="100%" text_align="center" word_wrap="true"/>
|
||||
</div>
|
||||
|
||||
<!-- Right pane -->
|
||||
<div proportion="1" height="100%" layout="vertical-row">
|
||||
<placeholder proportion="1" height="100%" id="screenshot_div">
|
||||
</placeholder>
|
||||
<div width="75%" height="fit" layout="horizontal-row" >
|
||||
<spacer width="40" height="2" />
|
||||
<checkbox id="reverse"/>
|
||||
<spacer width="20" height="2" />
|
||||
<label height="100%" I18N="Drive the track reverse" text="Reverse"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<spacer width="1" height="5%"/>
|
||||
|
||||
<spinner id="lapcountspinner" width="50%" min="1" max="20" align="center" warp_around="true"
|
||||
I18N="In the track setup screen (number of laps choice, where %i is the number)" text="%i laps"/>
|
||||
|
||||
<spacer width="1" height="5%"/>
|
||||
|
||||
<button id="start" text="Start Race" align="center"/>
|
||||
|
||||
<spacer width="1" height="1%"/>
|
||||
</div>
|
||||
</stkgui>
|
BIN
data/models/bronze.png
Normal file
BIN
data/models/bronze.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
BIN
data/models/silver.png
Normal file
BIN
data/models/silver.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
data/models/trophy_bronze.b3d
Normal file
BIN
data/models/trophy_bronze.b3d
Normal file
Binary file not shown.
BIN
data/models/trophy_gold.b3d
Normal file
BIN
data/models/trophy_gold.b3d
Normal file
Binary file not shown.
BIN
data/models/trophy_silver.b3d
Normal file
BIN
data/models/trophy_silver.b3d
Normal file
Binary file not shown.
@ -312,7 +312,7 @@
|
||||
bevelling, and uses a simple box shape.
|
||||
As an example, a value of 1 for x and z will result in a
|
||||
sharp 'arrow' like shape. -->
|
||||
<collision impulse="150" impulse-time="0.1" side-impulse="600"
|
||||
<collision impulse="12000" impulse-time="0.1" side-impulse="600"
|
||||
restitution="1.0" bevel-factor="0.5 0.0 0.5" />
|
||||
|
||||
<!-- Kart-specific plunger and rubber band handling: max-length is
|
||||
|
@ -45,19 +45,50 @@ void Challenge::load(const XMLNode* challengesNode)
|
||||
m_data->getId().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// See if the challenge is solved (it's activated later from the
|
||||
// unlock_manager).
|
||||
bool finished=false;
|
||||
node->get("solved", &finished);
|
||||
const XMLNode* easy = node->getNode("easy");
|
||||
const XMLNode* medium = node->getNode("medium");
|
||||
const XMLNode* hard = node->getNode("hard");
|
||||
|
||||
m_state[0] = CH_INACTIVE;
|
||||
m_state[1] = CH_INACTIVE;
|
||||
m_state[2] = CH_INACTIVE;
|
||||
|
||||
if (easy != NULL)
|
||||
{
|
||||
bool finished = false;
|
||||
easy->get("solved", &finished);
|
||||
|
||||
m_state = finished ? CH_SOLVED : CH_INACTIVE;
|
||||
if (finished) m_state[0] = CH_SOLVED;
|
||||
}
|
||||
if (medium != NULL)
|
||||
{
|
||||
bool finished = false;
|
||||
medium->get("solved", &finished);
|
||||
|
||||
if (finished) m_state[1] = CH_SOLVED;
|
||||
}
|
||||
if (hard != NULL)
|
||||
{
|
||||
bool finished = false;
|
||||
hard->get("solved", &finished);
|
||||
|
||||
if (finished) m_state[2] = CH_SOLVED;
|
||||
}
|
||||
} // load
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
const wchar_t* boolstr(bool b)
|
||||
{
|
||||
return (b ? L"true" : L"false");
|
||||
}
|
||||
|
||||
void Challenge::save(XMLWriter& writer)
|
||||
{
|
||||
writer << L" <" << core::stringw(m_data->getId().c_str()) << L" solved=\""
|
||||
<< (isSolved() ? L"true" : L"false") << L"\"";
|
||||
writer << L" />\n";
|
||||
writer << L" <" << core::stringw(m_data->getId().c_str()) << L">\n"
|
||||
<< L" <easy solved=\"" << boolstr(isSolved(RaceManager::RD_EASY)) << L"\"/>\n"
|
||||
<< L" <medium solved=\"" << boolstr(isSolved(RaceManager::RD_MEDIUM)) << L"\"/>\n"
|
||||
<< L" <hard solved=\"" << boolstr(isSolved(RaceManager::RD_HARD)) << L"\"/>\n"
|
||||
<< L" </" << core::stringw(m_data->getId().c_str()) << L">\n";
|
||||
} // save
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <fstream>
|
||||
#include <irrString.h>
|
||||
|
||||
#include "race/race_manager.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
@ -46,26 +47,38 @@ class Challenge : public NoCopy
|
||||
private:
|
||||
enum {CH_INACTIVE, // challenge not yet possible
|
||||
CH_ACTIVE, // challenge possible, but not yet solved
|
||||
CH_SOLVED} m_state; // challenge was solved
|
||||
|
||||
CH_SOLVED} // challenge was solved
|
||||
m_state[RaceManager::DIFFICULTY_COUNT];
|
||||
|
||||
ChallengeData* m_data;
|
||||
|
||||
public:
|
||||
Challenge(ChallengeData* data) : m_state(CH_INACTIVE)
|
||||
{ m_data = data; }
|
||||
Challenge(ChallengeData* data)
|
||||
{
|
||||
m_data = data;
|
||||
m_state[RaceManager::RD_EASY] = CH_INACTIVE;
|
||||
m_state[RaceManager::RD_MEDIUM] = CH_INACTIVE;
|
||||
m_state[RaceManager::RD_HARD] = CH_INACTIVE;
|
||||
}
|
||||
virtual ~Challenge() {};
|
||||
void load(const XMLNode* config);
|
||||
void save(XMLWriter& writer);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
bool isSolved() const {return m_state==CH_SOLVED; }
|
||||
bool isSolved(RaceManager::Difficulty d) const {return m_state[d]==CH_SOLVED; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool isActive() const {return m_state==CH_ACTIVE; }
|
||||
bool isSolvedAtAnyDifficulty() const {return m_state[0]==CH_SOLVED ||
|
||||
m_state[1]==CH_SOLVED ||
|
||||
m_state[2]==CH_SOLVED; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setSolved() {m_state = CH_SOLVED; }
|
||||
bool isActive(RaceManager::Difficulty d) const {return m_state[d]==CH_ACTIVE; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setActive() {m_state = CH_ACTIVE; }
|
||||
void setSolved(RaceManager::Difficulty d) {m_state[d] = CH_SOLVED; }
|
||||
// ------------------------------------------------------------------------
|
||||
ChallengeData* getData() { return m_data; }
|
||||
void setActive(RaceManager::Difficulty d) {m_state[d] = CH_ACTIVE; }
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ChallengeData* getData() { return m_data; }
|
||||
const ChallengeData* getData() const { return m_data; }
|
||||
};
|
||||
#endif
|
||||
|
@ -356,12 +356,13 @@ bool ChallengeData::raceFinished()
|
||||
|
||||
int d = race_manager->getDifficulty();
|
||||
|
||||
Kart* kart = world->getPlayerKart(0);
|
||||
|
||||
if (track_name != m_track_id ) return false;
|
||||
if ((int)world->getNumKarts() < m_num_karts[d] ) return false;
|
||||
Kart* kart = world->getPlayerKart(0);
|
||||
if (m_energy[d] > 0 && kart->getEnergy() < m_energy[d] ) return false;
|
||||
if (m_position[d] > 0 && kart->getPosition() > m_position[d]) return false;
|
||||
|
||||
|
||||
// Follow the leader
|
||||
// -----------------
|
||||
if(m_minor==RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
|
@ -29,35 +29,6 @@ bool GameSlot::isLocked(const std::string& feature)
|
||||
{
|
||||
return m_locked_features.find(feature)!=m_locked_features.end();
|
||||
} // featureIsLocked
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const std::vector<const ChallengeData*> GameSlot::getUnlockedFeatures()
|
||||
{
|
||||
std::vector<const ChallengeData*> out;
|
||||
|
||||
std::map<std::string, Challenge*>::const_iterator i;
|
||||
for(i = m_challenges_state.begin();
|
||||
i != m_challenges_state.end(); i++)
|
||||
{
|
||||
if (i->second->isSolved()) out.push_back(i->second->getData());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
const std::vector<const ChallengeData*> GameSlot::getLockedChallenges()
|
||||
{
|
||||
std::vector<const ChallengeData*> out;
|
||||
|
||||
std::map<std::string, Challenge*>::const_iterator i;
|
||||
for(i = m_challenges_state.begin();
|
||||
i != m_challenges_state.end(); i++)
|
||||
{
|
||||
if (!i->second->isSolved()) out.push_back(i->second->getData());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void GameSlot::computeActive()
|
||||
@ -70,21 +41,53 @@ void GameSlot::computeActive()
|
||||
{
|
||||
// Changed challenge
|
||||
// -----------------
|
||||
if((i->second)->isSolved())
|
||||
if((i->second)->isSolvedAtAnyDifficulty())
|
||||
{
|
||||
// The constructor calls computeActive, which actually locks
|
||||
// all features, so unlock the solved ones (and don't try to
|
||||
// save the state, since we are currently reading it)
|
||||
|
||||
unlockFeature(i->second, /*save*/ false);
|
||||
if (i->second->isSolved(RaceManager::RD_EASY))
|
||||
{
|
||||
unlockFeature(i->second, RaceManager::RD_EASY, /*save*/ false);
|
||||
}
|
||||
if (i->second->isSolved(RaceManager::RD_MEDIUM))
|
||||
{
|
||||
unlockFeature(i->second, RaceManager::RD_MEDIUM, /*save*/ false);
|
||||
}
|
||||
if (i->second->isSolved(RaceManager::RD_HARD))
|
||||
{
|
||||
unlockFeature(i->second, RaceManager::RD_HARD, /*save*/ false);
|
||||
}
|
||||
m_points++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise lock the feature
|
||||
// --------------------------
|
||||
lockFeature(i->second);
|
||||
}
|
||||
|
||||
// Otherwise lock the feature
|
||||
// --------------------------
|
||||
lockFeature(i->second);
|
||||
i->second->setActive();
|
||||
if (i->second->isSolved(RaceManager::RD_HARD))
|
||||
{
|
||||
// challenge beaten at hardest, nothing more to do here
|
||||
continue;
|
||||
}
|
||||
else if (i->second->isSolved(RaceManager::RD_MEDIUM))
|
||||
{
|
||||
i->second->setActive(RaceManager::RD_HARD);
|
||||
}
|
||||
else if (i->second->isSolved(RaceManager::RD_EASY))
|
||||
{
|
||||
i->second->setActive(RaceManager::RD_HARD);
|
||||
i->second->setActive(RaceManager::RD_MEDIUM);
|
||||
}
|
||||
else
|
||||
{
|
||||
i->second->setActive(RaceManager::RD_HARD);
|
||||
i->second->setActive(RaceManager::RD_MEDIUM);
|
||||
i->second->setActive(RaceManager::RD_EASY);
|
||||
}
|
||||
} // for i
|
||||
clearUnlocked();
|
||||
} // computeActive
|
||||
@ -102,7 +105,7 @@ void GameSlot::lockFeature(Challenge *challenge)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GameSlot::unlockFeature(Challenge* c, bool do_save)
|
||||
void GameSlot::unlockFeature(Challenge* c, RaceManager::Difficulty d, bool do_save)
|
||||
{
|
||||
const unsigned int amount = (unsigned int)c->getData()->getFeatures().size();
|
||||
for(unsigned int n=0; n<amount; n++)
|
||||
@ -120,7 +123,7 @@ void GameSlot::unlockFeature(Challenge* c, bool do_save)
|
||||
|
||||
// Add to list of recently unlocked features
|
||||
m_unlocked_features.push_back(c->getData());
|
||||
c->setSolved(); // reset isActive flag
|
||||
c->setSolved(d); // reset isActive flag
|
||||
|
||||
// Save the new unlock information
|
||||
if(do_save) unlock_manager->save();
|
||||
@ -128,24 +131,6 @@ void GameSlot::unlockFeature(Challenge* c, bool do_save)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
std::vector<const ChallengeData*> GameSlot::getActiveChallenges()
|
||||
{
|
||||
computeActive();
|
||||
|
||||
std::vector<const ChallengeData*> out;
|
||||
|
||||
std::map<std::string, Challenge*>::const_iterator i;
|
||||
for(i = m_challenges_state.begin();
|
||||
i != m_challenges_state.end(); i++)
|
||||
{
|
||||
if (i->second->isActive()) out.push_back(i->second->getData());
|
||||
}
|
||||
|
||||
return out;
|
||||
} // getActiveChallenges
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** This is called when a race is finished. Call all active challenges
|
||||
*/
|
||||
void GameSlot::raceFinished()
|
||||
@ -156,9 +141,9 @@ void GameSlot::raceFinished()
|
||||
for(i = m_challenges_state.begin();
|
||||
i != m_challenges_state.end(); i++)
|
||||
{
|
||||
if(i->second->isActive() && i->second->getData()->raceFinished())
|
||||
if(i->second->isActive(race_manager->getDifficulty()) && i->second->getData()->raceFinished())
|
||||
{
|
||||
unlockFeature(i->second);
|
||||
unlockFeature(i->second, race_manager->getDifficulty());
|
||||
} // if isActive && challenge solved
|
||||
}
|
||||
//race_manager->setCoinTarget(0); //reset
|
||||
@ -172,10 +157,11 @@ void GameSlot::grandPrixFinished()
|
||||
for(i = m_challenges_state.begin();
|
||||
i != m_challenges_state.end(); i++)
|
||||
{
|
||||
if(i->second->isActive() && i->second->getData()->grandPrixFinished())
|
||||
if(i->second->isActive(race_manager->getDifficulty()) &&
|
||||
i->second->getData()->grandPrixFinished())
|
||||
{
|
||||
printf("===== A FEATURE WAS UNLOCKED BECAUSE YOU WON THE GP!! ==\n");
|
||||
unlockFeature(i->second);
|
||||
unlockFeature(i->second, race_manager->getDifficulty());
|
||||
}
|
||||
}
|
||||
race_manager->setCoinTarget(0);
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <vector>
|
||||
#include <irrString.h>
|
||||
|
||||
#include "race/race_manager.hpp"
|
||||
|
||||
class ChallengeData;
|
||||
class Challenge;
|
||||
class XMLWriter;
|
||||
@ -70,26 +72,17 @@ public:
|
||||
/** Returns the list of recently unlocked features (e.g. call at the end of a
|
||||
race to know if any features were unlocked) */
|
||||
const std::vector<const ChallengeData*>
|
||||
getRecentlyUnlockedFeatures() {return m_unlocked_features;}
|
||||
getRecentlyCompletedChallenges() {return m_unlocked_features;}
|
||||
|
||||
/** Clear the list of recently unlocked challenges */
|
||||
void clearUnlocked () {m_unlocked_features.clear(); }
|
||||
|
||||
|
||||
/** Returns a complete list of all solved challenges */
|
||||
const std::vector<const ChallengeData*> getUnlockedFeatures();
|
||||
|
||||
/** Returns the list of currently inaccessible (locked) challenges */
|
||||
const std::vector<const ChallengeData*> getLockedChallenges();
|
||||
|
||||
bool isLocked (const std::string& feature);
|
||||
|
||||
void lockFeature (Challenge *challenge);
|
||||
|
||||
void unlockFeature (Challenge* c, bool do_save=true);
|
||||
|
||||
std::vector<const ChallengeData*> getActiveChallenges();
|
||||
|
||||
void unlockFeature (Challenge* c, RaceManager::Difficulty d, bool do_save=true);
|
||||
|
||||
void raceFinished ();
|
||||
void grandPrixFinished ();
|
||||
|
||||
|
@ -63,6 +63,7 @@ void LODNode::render()
|
||||
void LODNode::OnRegisterSceneNode()
|
||||
{
|
||||
if (!isVisible()) return;
|
||||
if (m_nodes.size() == 0) return;
|
||||
|
||||
// TODO: optimize this, there is no need to check every frame
|
||||
scene::ICameraSceneNode* curr_cam = irr_driver->getSceneManager()->getActiveCamera();
|
||||
|
@ -92,7 +92,11 @@ public:
|
||||
void add(int level, scene::ISceneNode* node, bool reparent);
|
||||
|
||||
/** Get the highest level of detail node */
|
||||
scene::ISceneNode* getFirstNode() { assert(m_nodes.size() > 0); return m_nodes[0]; }
|
||||
scene::ISceneNode* getFirstNode()
|
||||
{
|
||||
if (m_nodes.size() > 0) return m_nodes[0];
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
std::vector<scene::ISceneNode*>& getAllNodes() { return m_nodes; }
|
||||
|
||||
|
@ -75,28 +75,34 @@ public:
|
||||
class WaterShaderProvider : public video::IShaderConstantSetCallBack
|
||||
{
|
||||
float m_dx_1, m_dy_1, m_dx_2, m_dy_2;
|
||||
float m_water_shader_speed_1;
|
||||
float m_water_shader_speed_2;
|
||||
|
||||
public:
|
||||
LEAK_CHECK()
|
||||
|
||||
|
||||
WaterShaderProvider()
|
||||
WaterShaderProvider(float water_shader_speed_1,
|
||||
float water_shader_speed_2)
|
||||
{
|
||||
m_dx_1 = 0.0f;
|
||||
m_dy_1 = 0.0f;
|
||||
m_dx_2 = 0.0f;
|
||||
m_dy_2 = 0.0f;
|
||||
|
||||
m_water_shader_speed_1 = water_shader_speed_1/100.0f;
|
||||
m_water_shader_speed_2 = water_shader_speed_2/100.0f;
|
||||
}
|
||||
|
||||
virtual void OnSetConstants(
|
||||
irr::video::IMaterialRendererServices *services,
|
||||
s32 userData)
|
||||
{
|
||||
m_dx_1 += GUIEngine::getLatestDt()/15.0f;
|
||||
m_dy_1 += GUIEngine::getLatestDt()/15.0f;
|
||||
m_dx_1 += GUIEngine::getLatestDt()*m_water_shader_speed_1;
|
||||
m_dy_1 += GUIEngine::getLatestDt()*m_water_shader_speed_1;
|
||||
|
||||
m_dx_2 += GUIEngine::getLatestDt()/25.0f;
|
||||
m_dy_2 -= GUIEngine::getLatestDt()/25.0f;
|
||||
m_dx_2 += GUIEngine::getLatestDt()*m_water_shader_speed_2;
|
||||
m_dy_2 -= GUIEngine::getLatestDt()*m_water_shader_speed_2;
|
||||
|
||||
if (m_dx_1 > 1.0f) m_dx_1 -= 1.0f;
|
||||
if (m_dy_1 > 1.0f) m_dy_1 -= 1.0f;
|
||||
@ -429,6 +435,11 @@ Material::Material(const XMLNode *node, int index)
|
||||
}
|
||||
|
||||
node->get("water-shader", &m_water_shader);
|
||||
if (m_water_shader)
|
||||
{
|
||||
node->get("water-shader-speed-1", &m_water_shader_speed_1);
|
||||
node->get("water-shader-speed-2", &m_water_shader_speed_2);
|
||||
}
|
||||
|
||||
// Terrain-specifc sound effect
|
||||
const unsigned int children_count = node->getNumNodes();
|
||||
@ -505,6 +516,8 @@ void Material::init(unsigned int index)
|
||||
m_add = false;
|
||||
m_disable_z_write = false;
|
||||
m_water_shader = false;
|
||||
m_water_shader_speed_1 = 6.6667f;
|
||||
m_water_shader_speed_2 = 4.0f;
|
||||
m_fog = true;
|
||||
m_max_speed_fraction = 1.0f;
|
||||
m_slowdown_time = 1.0f;
|
||||
@ -987,7 +1000,8 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m
|
||||
{
|
||||
if (m_shaders[WATER_SHADER] == NULL)
|
||||
{
|
||||
m_shaders[WATER_SHADER] = new WaterShaderProvider();
|
||||
m_shaders[WATER_SHADER] = new WaterShaderProvider(m_water_shader_speed_1,
|
||||
m_water_shader_speed_2);
|
||||
}
|
||||
|
||||
m->setTexture(1, irr_driver->getTexture(file_manager->getTextureFile("waternormals.jpg")));
|
||||
|
@ -107,7 +107,18 @@ private:
|
||||
bool m_zipper;
|
||||
/** If a kart is rescued when driving on this surface. */
|
||||
bool m_drive_reset;
|
||||
|
||||
/** If the water shader (simulating wave effects and reflexions) is enabled */
|
||||
bool m_water_shader;
|
||||
|
||||
/** Speed of the 'main' wave in the water shader. Only used if
|
||||
m_water_shader is true */
|
||||
float m_water_shader_speed_1;
|
||||
|
||||
/** Speed of the 'secondary' waves in the water shader. Only used if
|
||||
m_water_shader is true */
|
||||
float m_water_shader_speed_2;
|
||||
|
||||
/** If a kart is rescued when crashing into this surface. */
|
||||
CollisionReaction m_collision_reaction;
|
||||
|
||||
|
@ -248,6 +248,7 @@ void AbstractStateManager::resetAndGoToScreen(Screen* screen)
|
||||
if (m_game_mode != GAME) getCurrentScreen()->tearDown();
|
||||
m_menu_stack.clear();
|
||||
|
||||
if (!screen->isLoaded()) screen->loadFromFile();
|
||||
m_menu_stack.push_back(name);
|
||||
setGameState(MENU);
|
||||
|
||||
|
@ -372,6 +372,9 @@ namespace GUIEngine
|
||||
Another possible value is "fit", which will make a \<div\> fit to its
|
||||
contents.
|
||||
|
||||
Another possible value is "font", which will use the size of the font
|
||||
(useful to insert widgets inside text)
|
||||
|
||||
\n
|
||||
\subsection prop9 PROP_MAX_WIDTH, PROP_MAX_HEIGHT
|
||||
<em> Names in XML files: </em> \c "max_width", \c "max_height"
|
||||
@ -414,6 +417,10 @@ namespace GUIEngine
|
||||
is not what you're looking for; instead, add a stretching spacer before
|
||||
and after the widget(s) you want to center.
|
||||
|
||||
\note When applied to a label widget, this property will center the text
|
||||
widget within its parent. To align the text inside the label widget,
|
||||
see \ref prop4
|
||||
|
||||
\n
|
||||
\subsection prop13 PROP_PROPORTION
|
||||
<em> Name in XML files: </em> \c "proportion"
|
||||
|
@ -259,7 +259,8 @@ void LayoutManager::readCoords(Widget* self)
|
||||
// width
|
||||
{
|
||||
int abs_w = -1, percent_w = -1;
|
||||
if (convertToCoord(width, &abs_w, &percent_w ))
|
||||
if (width == "font") self->m_absolute_w = GUIEngine::getFontHeight();
|
||||
else if (convertToCoord(width, &abs_w, &percent_w ))
|
||||
{
|
||||
if (abs_w > -1) self->m_absolute_w = abs_w;
|
||||
else if (percent_w > -1) self->m_relative_w = (float)percent_w;
|
||||
@ -271,7 +272,8 @@ void LayoutManager::readCoords(Widget* self)
|
||||
// height
|
||||
{
|
||||
int abs_h = -1, percent_h = -1;
|
||||
if (convertToCoord(height, &abs_h, &percent_h ))
|
||||
if (height == "font") self->m_absolute_h = GUIEngine::getFontHeight();
|
||||
else if (convertToCoord(height, &abs_h, &percent_h ))
|
||||
{
|
||||
if (abs_h > -1) self->m_absolute_h = abs_h;
|
||||
else if (percent_h > -1) self->m_relative_h = (float)percent_h;
|
||||
|
@ -153,6 +153,8 @@ namespace GUIEngine
|
||||
*/
|
||||
int getMin() const { return m_min; }
|
||||
|
||||
void setMin(int n) { m_min = n; }
|
||||
|
||||
/** Override method from base class Widget */
|
||||
virtual void setActivated();
|
||||
|
||||
|
@ -292,14 +292,52 @@ void Attachment::hitBanana(Item *item, int new_attachment)
|
||||
} // hitBanana
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//** Moves a bomb from kart FROM to kart TO.
|
||||
void Attachment::moveBombFromTo(Kart *from, Kart *to)
|
||||
/** Updates the attachments in case of a kart-kart collision. This must only
|
||||
* be called for one of the karts in the collision, since it will update
|
||||
* the attachment for both karts.
|
||||
* \param other Pointer to the other kart hit.
|
||||
*/
|
||||
void Attachment::handleCollisionWithKart(Kart *other)
|
||||
{
|
||||
to->getAttachment()->set(ATTACH_BOMB,
|
||||
from->getAttachment()->getTimeLeft()+
|
||||
stk_config->m_bomb_time_increase, from);
|
||||
from->getAttachment()->clear();
|
||||
} // moveBombFromTo
|
||||
Attachment *attachment_other=other->getAttachment();
|
||||
|
||||
if(getType()==Attachment::ATTACH_BOMB)
|
||||
{
|
||||
// If both karts have a bomb, explode them immediately:
|
||||
if(attachment_other->getType()==Attachment::ATTACH_BOMB)
|
||||
{
|
||||
setTimeLeft(0.0f);
|
||||
attachment_other->setTimeLeft(0.0f);
|
||||
}
|
||||
else // only this kart has a bomb, move it to the other
|
||||
{
|
||||
if(getPreviousOwner()!=other)
|
||||
{
|
||||
// Don't move if this bomb was from other kart originally
|
||||
other->getAttachment()->set(ATTACH_BOMB,
|
||||
getTimeLeft()+
|
||||
stk_config->m_bomb_time_increase,
|
||||
m_kart);
|
||||
other->playCustomSFX(SFXManager::CUSTOM_ATTACH);
|
||||
clear();
|
||||
}
|
||||
}
|
||||
} // type==BOMB
|
||||
else if(attachment_other->getType()==Attachment::ATTACH_BOMB &&
|
||||
attachment_other->getPreviousOwner()!=m_kart)
|
||||
{
|
||||
set(ATTACH_BOMB, other->getAttachment()->getTimeLeft()+
|
||||
stk_config->m_bomb_time_increase, other);
|
||||
other->getAttachment()->clear();
|
||||
m_kart->playCustomSFX(SFXManager::CUSTOM_ATTACH);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_kart->playCustomSFX(SFXManager::CUSTOM_CRASH);
|
||||
other->playCustomSFX(SFXManager::CUSTOM_CRASH);
|
||||
}
|
||||
|
||||
} // handleCollisionWithKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Attachment::update(float dt)
|
||||
|
@ -99,9 +99,9 @@ public:
|
||||
void clear ();
|
||||
void hitBanana(Item *item, int new_attachment=-1);
|
||||
void update (float dt);
|
||||
void moveBombFromTo(Kart *from, Kart *to);
|
||||
|
||||
void handleCollisionWithKart(Kart *other);
|
||||
void set (AttachmentType type, float time, Kart *previous_kart=NULL);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the type of the attachment, but keeps the old time left value. */
|
||||
void set (AttachmentType type) { set(type, m_time_left); }
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "config/stk_config.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "items/projectile_manager.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "audio/sfx_base.hpp"
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/projectile_manager.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
|
@ -39,6 +39,7 @@
|
||||
# include "graphics/irr_driver.hpp"
|
||||
#endif
|
||||
#include "graphics/slip_stream.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
@ -264,6 +265,7 @@ void DefaultAIController::update(float dt)
|
||||
/*And obviously general kart stuff*/
|
||||
AIBaseController::update(dt);
|
||||
m_collided = false;
|
||||
m_controls->m_fire = false;
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -38,6 +38,7 @@
|
||||
#ifdef AI_DEBUG
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#endif
|
||||
#include "items/attachment.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "graphics/camera.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/item.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "race/history.hpp"
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "graphics/camera.hpp"
|
||||
#include "graphics/referee.hpp"
|
||||
#include "graphics/stars.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "modes/three_strikes_battle.hpp"
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "karts/kart_gfx.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "karts/controller/end_controller.hpp"
|
||||
#include "karts/kart_model.hpp"
|
||||
@ -69,7 +70,8 @@
|
||||
* \param is_first_kart Indicates whether this is the first *player* kart
|
||||
* \param init_transform The initial position and rotation for this kart.
|
||||
*/
|
||||
Kart::Kart (const std::string& ident, Track* track, int position, bool is_first_kart,
|
||||
Kart::Kart (const std::string& ident, unsigned int world_kart_id,
|
||||
Track* track, int position, bool is_first_kart,
|
||||
const btTransform& init_transform, RaceManager::KartType type)
|
||||
: TerrainInfo(1),
|
||||
Moveable(), EmergencyAnimation(this), MaxSpeed(this), m_powerup(this)
|
||||
@ -91,16 +93,15 @@ Kart::Kart (const std::string& ident, Track* track, int position, bool is_first_
|
||||
m_kart_model = m_kart_properties->getKartModelCopy();
|
||||
m_initial_position = position;
|
||||
m_race_position = position;
|
||||
m_world_kart_id = world_kart_id;
|
||||
m_collected_energy = 0;
|
||||
m_finished_race = false;
|
||||
m_wheel_toggle = 1;
|
||||
m_finish_time = 0.0f;
|
||||
m_bubblegum_time = 0.0f;
|
||||
m_invulnerable_time = 0.0f;
|
||||
m_squash_time = 0.0f;
|
||||
m_shadow_enabled = false;
|
||||
m_shadow = NULL;
|
||||
m_terrain_particles = NULL;
|
||||
m_collision_particles = NULL;
|
||||
m_slipstream = NULL;
|
||||
m_skidmarks = NULL;
|
||||
@ -430,7 +431,6 @@ Kart::~Kart()
|
||||
delete m_kart_gfx;
|
||||
if(m_terrain_sound) sfx_manager->deleteSFX(m_terrain_sound);
|
||||
if(m_previous_terrain_sound) sfx_manager->deleteSFX(m_previous_terrain_sound);
|
||||
if(m_terrain_particles) delete m_terrain_particles;
|
||||
if(m_collision_particles) delete m_collision_particles;
|
||||
if(m_slipstream) delete m_slipstream;
|
||||
if(m_rain) delete m_rain;
|
||||
@ -906,7 +906,6 @@ void Kart::update(float dt)
|
||||
//smoke drawing control point
|
||||
if (UserConfigParams::m_graphical_effects)
|
||||
{
|
||||
if (m_terrain_particles) m_terrain_particles->update(dt);
|
||||
if (m_rain)
|
||||
{
|
||||
m_rain->setPosition( getCamera()->getCameraSceneNode()->getPosition() );
|
||||
@ -1153,140 +1152,92 @@ void Kart::handleMaterialGFX()
|
||||
// on top of a surface (i.e. not falling), actually touching
|
||||
// something with the wheels, and the material has not the
|
||||
// below surface property set.
|
||||
if (material && isOnGround() && !material->isBelowSurface() && m_kart_mode != EA_RESCUE)
|
||||
if (material && isOnGround() && !material->isBelowSurface() &&
|
||||
m_kart_mode != EA_RESCUE && UserConfigParams::m_graphical_effects)
|
||||
{
|
||||
if (m_terrain_particles)
|
||||
|
||||
// Get the appropriate particle data depending on
|
||||
// wether the kart is skidding or driving.
|
||||
const ParticleKind* pk =
|
||||
material->getParticlesWhen(m_skidding > 1.0f
|
||||
? Material::EMIT_ON_SKID
|
||||
: Material::EMIT_ON_DRIVE);
|
||||
if(!pk)
|
||||
{
|
||||
Vec3 xyz;
|
||||
m_wheel_toggle = 1 - m_wheel_toggle;
|
||||
const btWheelInfo &wi =
|
||||
getVehicle()->getWheelInfo(2 + m_wheel_toggle);
|
||||
xyz = wi.m_raycastInfo.m_contactPointWS;
|
||||
|
||||
// FIXME: the X position is not yet always accurate.
|
||||
xyz += Vec3(0.06f * (m_wheel_toggle ? +1 : -1),
|
||||
0,
|
||||
0.06f);
|
||||
|
||||
// Get the appropriate particle data depending on
|
||||
// wether the kart is skidding or driving.
|
||||
const ParticleKind* pk =
|
||||
material->getParticlesWhen(m_skidding > 1.0f
|
||||
? Material::EMIT_ON_SKID
|
||||
: Material::EMIT_ON_DRIVE);
|
||||
if(!pk)
|
||||
{
|
||||
// Disable potentially running particle effects
|
||||
m_terrain_particles->setCreationRateAbsolute(0);
|
||||
return; // no particle effect, return
|
||||
}
|
||||
|
||||
// Now compute the particle creation rate:
|
||||
float rate = 0;
|
||||
const float speed = fabsf(getSpeed());
|
||||
|
||||
if (m_skidding > 1.0f)
|
||||
{
|
||||
rate = fabsf(m_controls.m_steer) > 0.8 ? m_skidding - 1 : 0;
|
||||
}
|
||||
else if (speed >= 0.5f)
|
||||
{
|
||||
rate = speed/m_kart_properties->getMaxSpeed();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_terrain_particles->setCreationRateAbsolute(0);
|
||||
return;
|
||||
}
|
||||
|
||||
float create = pk->getMinRate()*(1-rate) + pk->getMaxRate()*rate;
|
||||
m_terrain_particles->setParticleType(pk);
|
||||
|
||||
// when particle type changes, the emitter is re-created at (0,0,0) so we need to
|
||||
// set the position after setParticleType
|
||||
m_terrain_particles->setPosition(xyz);
|
||||
|
||||
m_terrain_particles->setCreationRateAbsolute(create);
|
||||
// Disable potentially running particle effects
|
||||
m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_TERRAIN, 0);
|
||||
return; // no particle effect, return
|
||||
}
|
||||
|
||||
m_kart_gfx->updateTerrain(pk);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Now the kart is either falling, or driving on a terrain which
|
||||
// has the 'below surface' flag set. Detect if there is a surface
|
||||
// on top of the kart.
|
||||
// --------------------------------------------------------------
|
||||
if (m_camera && m_camera->getMode() != Camera::CM_FINAL)
|
||||
{
|
||||
if (material && material->hasFallingEffect() && !m_flying)
|
||||
{
|
||||
m_camera->setMode(Camera::CM_FALLING);
|
||||
}
|
||||
else if (m_camera->getMode() != Camera::CM_NORMAL && m_camera->getMode() != Camera::CM_REVERSE)
|
||||
else if (m_camera->getMode() != Camera::CM_NORMAL &&
|
||||
m_camera->getMode() != Camera::CM_REVERSE)
|
||||
{
|
||||
m_camera->setMode(Camera::CM_NORMAL);
|
||||
}
|
||||
}
|
||||
} // camera != final camera
|
||||
|
||||
if (m_terrain_particles)
|
||||
{
|
||||
// Use the middle of the contact points of the two rear wheels
|
||||
// as the point from which to cast the ray upwards
|
||||
const btWheelInfo::RaycastInfo &ri2 =
|
||||
getVehicle()->getWheelInfo(2).m_raycastInfo;
|
||||
const btWheelInfo::RaycastInfo &ri3 =
|
||||
getVehicle()->getWheelInfo(3).m_raycastInfo;
|
||||
Vec3 from = (ri2.m_contactPointWS + ri3.m_contactPointWS)*0.5f;
|
||||
Vec3 xyz;
|
||||
const Material *surface_material;
|
||||
if(!getSurfaceInfo(from, &xyz, &surface_material))
|
||||
{
|
||||
m_terrain_particles->setCreationRateAbsolute(0);
|
||||
return;
|
||||
}
|
||||
const ParticleKind *pk =
|
||||
surface_material->getParticlesWhen(Material::EMIT_ON_DRIVE);
|
||||
if(pk && !m_flying && m_kart_mode != EA_RESCUE)
|
||||
{
|
||||
const float distance = xyz.distance2(from);
|
||||
m_terrain_particles->setParticleType(pk);
|
||||
m_terrain_particles->setPosition(xyz.toIrrVector());
|
||||
//const float speed = fabsf(getSpeed());
|
||||
//float rate = (speed>=0.5f) ? speed/m_kart_properties->getMaxSpeed()
|
||||
// : 0;
|
||||
if (!UserConfigParams::m_graphical_effects)
|
||||
return;
|
||||
|
||||
float create;
|
||||
if (distance < 2.0f)
|
||||
{
|
||||
create = (float)pk->getMaxRate();
|
||||
}
|
||||
else if (distance < 4.0f)
|
||||
{
|
||||
create = pk->getMinRate() + (pk->getMaxRate() - pk->getMinRate())*(distance - 2.0f)/2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
create = 0.0f;
|
||||
}
|
||||
m_terrain_particles->setCreationRateAbsolute(create);
|
||||
|
||||
|
||||
const std::string s = surface_material->getSFXName();
|
||||
if (s != "" && m_kart_mode != EA_RESCUE &&
|
||||
(m_terrain_sound == NULL || m_terrain_sound->getStatus() == SFXManager::SFX_STOPPED))
|
||||
{
|
||||
if (m_previous_terrain_sound) sfx_manager->deleteSFX(m_previous_terrain_sound);
|
||||
m_previous_terrain_sound = m_terrain_sound;
|
||||
if(m_previous_terrain_sound)
|
||||
m_previous_terrain_sound->setLoop(false);
|
||||
|
||||
m_terrain_sound = sfx_manager->createSoundSource(s);
|
||||
m_terrain_sound->play();
|
||||
m_terrain_sound->setLoop(false);
|
||||
}
|
||||
|
||||
// handleMaterialSFX(surface_material);
|
||||
}
|
||||
// Use the middle of the contact points of the two rear wheels
|
||||
// as the point from which to cast the ray upwards
|
||||
const btWheelInfo::RaycastInfo &ri2 =
|
||||
getVehicle()->getWheelInfo(2).m_raycastInfo;
|
||||
const btWheelInfo::RaycastInfo &ri3 =
|
||||
getVehicle()->getWheelInfo(3).m_raycastInfo;
|
||||
Vec3 from = (ri2.m_contactPointWS + ri3.m_contactPointWS)*0.5f;
|
||||
Vec3 xyz;
|
||||
const Material *surface_material;
|
||||
if(!getSurfaceInfo(from, &xyz, &surface_material))
|
||||
{
|
||||
m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_TERRAIN, 0);
|
||||
return;
|
||||
}
|
||||
const ParticleKind *pk =
|
||||
surface_material->getParticlesWhen(Material::EMIT_ON_DRIVE);
|
||||
|
||||
if(!pk || m_flying || m_kart_mode == EA_RESCUE)
|
||||
return;
|
||||
|
||||
// Now the kart is under a surface, and there is a surface effect
|
||||
// --------------------------------------------------------------
|
||||
m_kart_gfx->setParticleKind(KartGFX::KGFX_TERRAIN, pk);
|
||||
m_kart_gfx->setXYZ(KartGFX::KGFX_TERRAIN, xyz);
|
||||
|
||||
const float distance = xyz.distance2(from);
|
||||
float ratio;
|
||||
if (distance < 2.0f) ratio = 1.0f;
|
||||
else if (distance < 4.0f) ratio = (4.0f-distance)*0.5f;
|
||||
else ratio = -1.0f; // No more particles
|
||||
m_kart_gfx->setCreationRateRelative(KartGFX::KGFX_TERRAIN, ratio);
|
||||
|
||||
// Play special sound effects for this terrain
|
||||
// -------------------------------------------
|
||||
const std::string s = surface_material->getSFXName();
|
||||
if (s != "" && m_kart_mode != EA_RESCUE &&
|
||||
(m_terrain_sound == NULL || m_terrain_sound->getStatus() == SFXManager::SFX_STOPPED))
|
||||
{
|
||||
if (m_previous_terrain_sound) sfx_manager->deleteSFX(m_previous_terrain_sound);
|
||||
m_previous_terrain_sound = m_terrain_sound;
|
||||
if(m_previous_terrain_sound)
|
||||
m_previous_terrain_sound->setLoop(false);
|
||||
|
||||
m_terrain_sound = sfx_manager->createSoundSource(s);
|
||||
m_terrain_sound->play();
|
||||
m_terrain_sound->setLoop(false);
|
||||
}
|
||||
|
||||
} // handleMaterialGFX
|
||||
@ -1313,7 +1264,7 @@ void Kart::setCamera(Camera *camera)
|
||||
{
|
||||
m_rain->setCamera( camera->getCameraSceneNode() );
|
||||
}
|
||||
}
|
||||
} // setCamera
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sets zipper time, and apply one time additional speed boost. It can be
|
||||
@ -1406,44 +1357,64 @@ void Kart::setSlipstreamEffect(float f)
|
||||
} // setSlipstreamEffect
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Called when the kart crashes against the track (k=NULL) or another kart.
|
||||
* \param k Either a kart if a kart was hit, or NULL if the track was hit.
|
||||
* \param m
|
||||
/** Called when the kart crashes against another kart.
|
||||
* \param k The kart that was hit.
|
||||
* \param update_attachments If true the attachment of this kart and the
|
||||
* other kart hit will be updated (e.g. bombs will be moved)
|
||||
*/
|
||||
void Kart::crashed(Kart *k, const Material *m)
|
||||
void Kart::crashed(Kart *k, bool update_attachments)
|
||||
{
|
||||
if(update_attachments)
|
||||
{
|
||||
assert(k);
|
||||
getAttachment()->handleCollisionWithKart(k);
|
||||
}
|
||||
crashed();
|
||||
} // crashed(Kart, update_attachments
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Kart hits the track with a given material.
|
||||
* \param m Material hit, can be NULL if no specific material exists.
|
||||
*/
|
||||
void Kart::crashed(const Material *m)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// Simple debug output for people playing without sound.
|
||||
// This makes it easier to see if a kart hit the track (esp.
|
||||
// after a jump).
|
||||
// FIXME: This should be removed once the physics are fixed.
|
||||
if(!k && UserConfigParams::m_physics_debug)
|
||||
if(UserConfigParams::m_physics_debug)
|
||||
{
|
||||
// Add a counter to make it easier to see if a new line of
|
||||
// output was added.
|
||||
static int counter=0;
|
||||
printf("Kart %s hit track: %d.\n", getIdent().c_str(), counter++);
|
||||
printf("Kart %s hit track: %d material %s.\n",
|
||||
getIdent().c_str(), counter++,
|
||||
m->getTexFname().c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
m_controller->crashed();
|
||||
/** If a kart is crashing against the track, the collision is often
|
||||
* reported more than once, resulting in a machine gun effect, and too
|
||||
* long disabling of the engine. Therefore, this reaction is disabled
|
||||
* for 0.5 seconds after a crash.
|
||||
*/
|
||||
if(m && m->getCollisionReaction() != Material::NORMAL && !playingEmergencyAnimation())
|
||||
if(m && m->getCollisionReaction() != Material::NORMAL &&
|
||||
!playingEmergencyAnimation())
|
||||
{
|
||||
std::string particles = m->getCrashResetParticles();
|
||||
if (particles.size() > 0)
|
||||
{
|
||||
ParticleKind* kind = ParticleKindManager::get()->getParticles(particles);
|
||||
ParticleKind* kind =
|
||||
ParticleKindManager::get()->getParticles(particles);
|
||||
if (kind != NULL)
|
||||
{
|
||||
if (m_collision_particles == NULL)
|
||||
{
|
||||
Vec3 position(-getKartWidth()*0.35f, 0.06f, getKartLength()*0.5f);
|
||||
m_collision_particles = new ParticleEmitter(kind, position, getNode());
|
||||
Vec3 position(-getKartWidth()*0.35f, 0.06f,
|
||||
getKartLength()*0.5f);
|
||||
m_collision_particles =
|
||||
new ParticleEmitter(kind, position, getNode());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1465,14 +1436,24 @@ void Kart::crashed(Kart *k, const Material *m)
|
||||
{
|
||||
if (m_bounce_back_time <= 0.0f)
|
||||
{
|
||||
btVector3 push = m_vehicle->getRigidBody()->getLinearVelocity().normalized();
|
||||
push[1] = 0.1f;
|
||||
m_vehicle->getRigidBody()->applyCentralImpulse( -4000.0f*push );
|
||||
//m_vehicle->getRigidBody()->setLinearVelocity( -m_vehicle->getRigidBody()->getLinearVelocity() );
|
||||
m_bounce_back_time = 2.0f;
|
||||
btVector3 push = m_body->getLinearVelocity().normalized();
|
||||
push[1] = 0.1f;
|
||||
m_body->applyCentralImpulse( -4000.0f*push );
|
||||
m_bounce_back_time = 2.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crashed();
|
||||
} // crashed(Material)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Common code used when a kart or a material was hit.
|
||||
*/
|
||||
void Kart::crashed()
|
||||
{
|
||||
m_controller->crashed();
|
||||
|
||||
if(World::getWorld()->getTime()-m_time_last_crash < 0.5f) return;
|
||||
|
||||
m_time_last_crash = World::getWorld()->getTime();
|
||||
@ -2028,25 +2009,6 @@ void Kart::loadData(RaceManager::KartType type, bool is_first_kart,
|
||||
createPhysics();
|
||||
|
||||
// Attach Particle System
|
||||
|
||||
if (UserConfigParams::m_graphical_effects && !isWheeless())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Note: the smoke system is NOT child of the kart, since bullet
|
||||
// gives the position of the wheels on the ground in world coordinates.
|
||||
// So it's easier not to move the particle system with the kart, and set
|
||||
// the position directly from the wheel coordinates.
|
||||
Vec3 position(-getKartWidth()*0.35f, 0.06f, -getKartLength()*0.5f);
|
||||
m_terrain_particles = new ParticleEmitter(ParticleKindManager::get()->getParticles("smoke.xml"),
|
||||
position);
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
std::cerr << "[Kart::loadData] " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (type == RaceManager::KT_PLAYER && UserConfigParams::m_weather_effects &&
|
||||
track->getSkyParticles() != NULL)
|
||||
|
@ -28,7 +28,6 @@
|
||||
|
||||
#include "LinearMath/btTransform.h"
|
||||
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/powerup.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "karts/controller/kart_control.hpp"
|
||||
@ -42,6 +41,7 @@
|
||||
class btKart;
|
||||
class btUprightConstraint;
|
||||
|
||||
class Attachment;
|
||||
class Camera;
|
||||
class Item;
|
||||
class KartGFX;
|
||||
@ -114,9 +114,6 @@ private:
|
||||
* determine startup boost. */
|
||||
bool m_has_started;
|
||||
|
||||
/** For skidding smoke */
|
||||
int m_wheel_toggle;
|
||||
|
||||
/**<Maximum engine rpm's for the current gear*/
|
||||
float m_max_gear_rpm;
|
||||
|
||||
@ -154,9 +151,6 @@ private:
|
||||
* stuck to the kart, i.e. the shadow would be flying, too). */
|
||||
bool m_shadow_enabled;
|
||||
|
||||
/** Particle emitter used for terrain-specific effects (including but not limited too skidding). */
|
||||
ParticleEmitter *m_terrain_particles;
|
||||
|
||||
ParticleEmitter *m_sky_particles_emitter;
|
||||
|
||||
/** All particle effects. */
|
||||
@ -211,6 +205,7 @@ private:
|
||||
void updateEngineSFX();
|
||||
|
||||
float getVisualSkidOffset() const;
|
||||
void crashed();
|
||||
|
||||
protected:
|
||||
const KartProperties *m_kart_properties;
|
||||
@ -220,11 +215,10 @@ protected:
|
||||
KartModel* m_kart_model;
|
||||
|
||||
public:
|
||||
Kart(const std::string& ident, Track* track, int position, bool is_first_kart,
|
||||
Kart(const std::string& ident, unsigned int world_kart_id,
|
||||
Track* track, int position, bool is_first_kart,
|
||||
const btTransform& init_transform, RaceManager::KartType type);
|
||||
virtual ~Kart();
|
||||
unsigned int getWorldKartId() const { return m_world_kart_id; }
|
||||
void setWorldKartId(unsigned int n) { m_world_kart_id=n; }
|
||||
void loadData(RaceManager::KartType type, bool is_first_kart, Track* track,
|
||||
bool animatedModel);
|
||||
virtual void updateGraphics(float dt, const Vec3& off_xyz,
|
||||
@ -248,7 +242,8 @@ public:
|
||||
void handleZipper (const Material *m=NULL, bool play_sound=false);
|
||||
void setSquash (float time, float slowdown);
|
||||
|
||||
void crashed (Kart *k, const Material *m=NULL);
|
||||
void crashed (Kart *k, bool update_attachments);
|
||||
void crashed (const Material *m);
|
||||
|
||||
virtual void update (float dt);
|
||||
virtual void finishedRace (float time);
|
||||
@ -257,6 +252,9 @@ public:
|
||||
bool playCustomSFX (unsigned int type);
|
||||
void setController(Controller *controller);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the index of this kart in world. */
|
||||
unsigned int getWorldKartId() const { return m_world_kart_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns this kart's kart model. */
|
||||
KartModel* getKartModel() { return m_kart_model; }
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -22,45 +22,45 @@
|
||||
#include "io/file_manager.hpp"
|
||||
#include "graphics/particle_emitter.hpp"
|
||||
#include "graphics/particle_kind.hpp"
|
||||
#include "graphics/particle_kind_manager.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "physics/btKart.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
KartGFX::KartGFX(const Kart *kart) : m_current_skid(KGFX_SKID1)
|
||||
KartGFX::KartGFX(const Kart *kart)
|
||||
{
|
||||
if(!UserConfigParams::m_graphical_effects)
|
||||
{
|
||||
for(unsigned int i=0; i<KGFX_COUNT; i++)
|
||||
{
|
||||
m_all_emitters.push_back(NULL);
|
||||
m_all_particle_kinds.push_back(NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_kart = kart;
|
||||
|
||||
Vec3 position(0, kart->getKartHeight()*0.35f,
|
||||
-kart->getKartLength()*0.35f);
|
||||
Vec3 rear_center(0, kart->getKartHeight()*0.35f,
|
||||
-kart->getKartLength()*0.35f);
|
||||
|
||||
// Create all effects. Note that they must be created
|
||||
// in the order of KartGFXType.
|
||||
addEffect(KGFX_NITRO, "nitro.xml", position);
|
||||
addEffect(KGFX_ZIPPER, "zipper_fire.xml", position);
|
||||
addEffect(KGFX_SKID1, "skid1.xml", position);
|
||||
addEffect(KGFX_SKID2, "skid2.xml", position);
|
||||
addEffect(KGFX_NITRO, "nitro.xml", rear_center);
|
||||
addEffect(KGFX_ZIPPER, "zipper_fire.xml", rear_center);
|
||||
addEffect(KGFX_TERRAIN, "smoke.xml", Vec3(0,0,0));
|
||||
addEffect(KGFX_SKID1, "skid1.xml", rear_center);
|
||||
addEffect(KGFX_SKID2, "skid2.xml", rear_center);
|
||||
|
||||
} // KartGFX
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Destructor. Frees all particle effects and kinds.
|
||||
*/
|
||||
KartGFX::~KartGFX()
|
||||
{
|
||||
for(unsigned int i=0; i<KGFX_COUNT; i++)
|
||||
{
|
||||
if(m_all_emitters[i])
|
||||
delete m_all_emitters[i];
|
||||
if(m_all_particle_kinds[i])
|
||||
delete m_all_particle_kinds[i];
|
||||
} // for i < KGFX_COUNT
|
||||
|
||||
} // ~KartGFX
|
||||
@ -75,17 +75,23 @@ KartGFX::~KartGFX()
|
||||
void KartGFX::addEffect(KartGFXType type, const std::string &file_name,
|
||||
const Vec3 &position)
|
||||
{
|
||||
ParticleKind *kind = NULL;
|
||||
ParticleEmitter *emitter = NULL;
|
||||
const ParticleKind *kind = NULL;
|
||||
ParticleEmitter *emitter = NULL;
|
||||
try
|
||||
{
|
||||
kind = new ParticleKind(file_manager->getGfxFile(file_name));
|
||||
if(type==KGFX_SKID2)
|
||||
emitter = NULL; // skid2 is only used to store the emitter type
|
||||
|
||||
kind = ParticleKindManager::get()->getParticles(file_name);
|
||||
//kind = new ParticleKind(file_manager->getGfxFile(file_name));
|
||||
// Skid2 is only used to store the emitter type, and a wheeless
|
||||
// kart has no terrain effects.
|
||||
if(type==KGFX_SKID2 || (type==KGFX_TERRAIN && m_kart->isWheeless()) )
|
||||
emitter = NULL;
|
||||
else if(type==KGFX_TERRAIN)
|
||||
// Terrain is NOT a child of the kart, since bullet returns the
|
||||
// raycast info in world coordinates
|
||||
emitter = new ParticleEmitter(kind, position);
|
||||
else
|
||||
emitter = new ParticleEmitter(kind,
|
||||
position,
|
||||
m_kart->getNode());
|
||||
emitter = new ParticleEmitter(kind, position, m_kart->getNode());
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
@ -97,15 +103,20 @@ void KartGFX::addEffect(KartGFXType type, const std::string &file_name,
|
||||
kind = NULL;
|
||||
emitter = NULL;
|
||||
}
|
||||
assert(m_all_emitters.size()==type);
|
||||
assert((int)m_all_emitters.size()==type);
|
||||
m_all_emitters.push_back(emitter);
|
||||
assert(m_all_particle_kinds.size()==type);
|
||||
m_all_particle_kinds.push_back(kind);
|
||||
if(type==KGFX_SKID1)
|
||||
m_skid_kind1 = kind;
|
||||
else if (type==KGFX_SKID2)
|
||||
m_skid_kind2 = kind;
|
||||
} // addEffect
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Resets all particle emitters. Used at the (re)start of a race.
|
||||
*/
|
||||
void KartGFX::reset()
|
||||
{
|
||||
m_wheel_toggle = 1;
|
||||
for(unsigned int i=0; i<m_all_emitters.size(); i++)
|
||||
{
|
||||
if(m_all_emitters[i])
|
||||
@ -121,44 +132,40 @@ void KartGFX::reset()
|
||||
* \param type Must be either KGFX_SKID1 or KGFX_SKID2 - the particle type
|
||||
* to use corresponding to the bonus level.
|
||||
*/
|
||||
void KartGFX::setSkidLevel(unsigned int level)
|
||||
void KartGFX::setSkidLevel(const unsigned int level)
|
||||
{
|
||||
KartGFXType type = level==1 ? KGFX_SKID1 : KGFX_SKID2;
|
||||
assert(type == KGFX_SKID1 || type==KGFX_SKID2);
|
||||
m_current_skid = type;
|
||||
assert(level >= 1);
|
||||
assert(level <= 2);
|
||||
const ParticleKind *pk = level==1 ? m_skid_kind1 : m_skid_kind2;
|
||||
if(m_all_emitters[KGFX_SKID1])
|
||||
m_all_emitters[KGFX_SKID1]->setParticleType(
|
||||
m_all_particle_kinds[type]);
|
||||
m_all_emitters[KGFX_SKID1]->setParticleType(pk);
|
||||
} // setSkidLevel
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Updates all gfx.
|
||||
* \param dt Time step size.
|
||||
/** Sets a new particle type to be used. Note that the memory of this
|
||||
* kind must be managed by the caller.
|
||||
* \param type The emitter type for which to set the new particle type.
|
||||
* \param pk The particle kind to use.
|
||||
*/
|
||||
void KartGFX::update(float dt)
|
||||
void KartGFX::setParticleKind(const KartGFXType type, const ParticleKind *pk)
|
||||
{
|
||||
if(!UserConfigParams::m_graphical_effects) return;
|
||||
ParticleEmitter *pe = m_all_emitters[KGFX_TERRAIN];
|
||||
if(!pe) return;
|
||||
|
||||
for(unsigned int i=0; i<m_all_emitters.size(); i++)
|
||||
{
|
||||
if(m_all_emitters[i])
|
||||
m_all_emitters[i]->update(dt);
|
||||
}
|
||||
|
||||
} // update
|
||||
pe->setParticleType(pk);
|
||||
} // setParticleKind
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets the creation rate for the specified particle type relative to the
|
||||
* given minimum and maximum particle rate.
|
||||
* \param type The particle effect for which to set the
|
||||
* creation rate.
|
||||
* \param f The new relative creation rate.
|
||||
/** Defines the new position of the specified emitter.
|
||||
* \param type The emitter to set a new position for.
|
||||
* \param xyz The new position of the emitter.
|
||||
*/
|
||||
void KartGFX::setCreationRateRelative(KartGFXType type, float f)
|
||||
void KartGFX::setXYZ(const KartGFXType type, const Vec3 &xyz)
|
||||
{
|
||||
if(m_all_emitters[type])
|
||||
m_all_emitters[type]->setCreationRateRelative(f);
|
||||
} // setCreationRate
|
||||
ParticleEmitter *pe = m_all_emitters[KGFX_TERRAIN];
|
||||
if(!pe) return;
|
||||
pe->setPosition(xyz);
|
||||
} // setXYZ
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets the absolute creation rate for the specified particle type.
|
||||
@ -170,7 +177,26 @@ void KartGFX::setCreationRateAbsolute(KartGFXType type, float f)
|
||||
{
|
||||
if(m_all_emitters[type])
|
||||
m_all_emitters[type]->setCreationRateAbsolute(f);
|
||||
} // setCreationRate
|
||||
} // setCreationRateAbsolute
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets the creation rate for the specified particle type relative to the
|
||||
* given minimum and maximum particle rate. If a negative value is
|
||||
* specified, the creation rate will be set to 0 (absolute).
|
||||
* \param type The particle effect for which to set the
|
||||
* creation rate (<0 means no more particles).
|
||||
* \param f The new relative creation rate.
|
||||
*/
|
||||
void KartGFX::setCreationRateRelative(KartGFXType type, float f)
|
||||
{
|
||||
if(m_all_emitters[type])
|
||||
{
|
||||
if(f<0)
|
||||
m_all_emitters[type]->setCreationRateAbsolute(0);
|
||||
else
|
||||
m_all_emitters[type]->setCreationRateRelative(f);
|
||||
}
|
||||
} // setCreationRateRelative
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Resize the area from which the particles are emitted: the emitter box
|
||||
@ -185,4 +211,63 @@ void KartGFX::resizeBox(KartGFXType type, float speed, float dt)
|
||||
{
|
||||
if(m_all_emitters[type])
|
||||
m_all_emitters[type]->resizeBox(std::max(0.25f, speed*dt));
|
||||
} // resizeBox
|
||||
} // resizeBox
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** If necessary defines a new particle type for the terrain emitter. Then
|
||||
* adjusts the location of the terrain emitter to be in synch with the
|
||||
* current wheel position, and defines the emission rate depending on speed,
|
||||
* steering, and skidding.
|
||||
* \param pk Particle type to use.
|
||||
*/
|
||||
void KartGFX::updateTerrain(const ParticleKind *pk)
|
||||
{
|
||||
ParticleEmitter *pe = m_all_emitters[KGFX_TERRAIN];
|
||||
if(!pe) return;
|
||||
|
||||
pe->setParticleType(pk);
|
||||
|
||||
const btWheelInfo &wi = m_kart->getVehicle()
|
||||
->getWheelInfo(2+m_wheel_toggle);
|
||||
Vec3 xyz = wi.m_raycastInfo.m_contactPointWS;
|
||||
// FIXME: the X and Z position is not always accurate.
|
||||
xyz.setX(xyz.getX()+ 0.06f * (m_wheel_toggle ? +1 : -1));
|
||||
xyz.setZ(xyz.getZ()+0.06f);
|
||||
pe->setPosition(xyz);
|
||||
|
||||
// Now compute the particle creation rate:
|
||||
float rate = 0;
|
||||
const float speed = fabsf(m_kart->getSpeed());
|
||||
const float skidding = m_kart->getSkidding();
|
||||
if (skidding > 1.0f)
|
||||
rate = fabsf(m_kart->getControls().m_steer) > 0.8 ? skidding - 1 : 0;
|
||||
else if (speed >= 0.5f)
|
||||
rate = speed/m_kart->getKartProperties()->getMaxSpeed();
|
||||
else
|
||||
{
|
||||
pe->setCreationRateAbsolute(0);
|
||||
return;
|
||||
}
|
||||
// m_skidding can be > 2, and speed > maxSpeed (if powerups are used).
|
||||
if(rate>1.0f) rate = 1.0f;
|
||||
pe->setCreationRateRelative(rate);
|
||||
} // updateTerrain
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Updates all gfx.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void KartGFX::update(float dt)
|
||||
{
|
||||
if(!UserConfigParams::m_graphical_effects) return;
|
||||
|
||||
m_wheel_toggle = 1 - m_wheel_toggle;
|
||||
|
||||
for(unsigned int i=0; i<m_all_emitters.size(); i++)
|
||||
{
|
||||
if(m_all_emitters[i])
|
||||
m_all_emitters[i]->update(dt);
|
||||
}
|
||||
|
||||
} // update
|
||||
|
||||
|
@ -34,18 +34,25 @@ class KartGFX
|
||||
{
|
||||
public:
|
||||
/** All particle effects supported by this object.
|
||||
* Nitro, zipper, and skidding effects. KGFX_COUNT
|
||||
* Nitro, zipper, terrain, and skidding effects. Two different
|
||||
* skid types are supported, but only one emitter node will be
|
||||
* created. So KGFX_SKID1/2 store the two types, and KGFX_SKID
|
||||
* = KGFX_SKID1 stores the actual emitter node. KGFX_COUNT
|
||||
* is the number of entries and must therefore be last. */
|
||||
enum KartGFXType { KGFX_NITRO=0,
|
||||
KGFX_ZIPPER,
|
||||
KGFX_TERRAIN,
|
||||
KGFX_SKID,
|
||||
KGFX_SKID1=KGFX_SKID,
|
||||
KGFX_SKID2,
|
||||
KGFX_COUNT};
|
||||
|
||||
private:
|
||||
/** Vector of all particle kinde. */
|
||||
std::vector<ParticleKind*> m_all_particle_kinds;
|
||||
/** The particle kind for skidding bonus level 1. */
|
||||
const ParticleKind *m_skid_kind1;
|
||||
|
||||
/** The particle kind for skidding bonus level 2. */
|
||||
const ParticleKind *m_skid_kind2;
|
||||
|
||||
/** Vector of all particle emitters. */
|
||||
std::vector<ParticleEmitter*> m_all_emitters;
|
||||
@ -53,8 +60,8 @@ private:
|
||||
/** Pointer to the owner of this kart. */
|
||||
const Kart *m_kart;
|
||||
|
||||
/** Indicates the current skidding level, either skid1 or skid2. */
|
||||
KartGFXType m_current_skid;
|
||||
/** Used to alternate particle effects from the rear wheels. */
|
||||
int m_wheel_toggle;
|
||||
|
||||
void addEffect(KartGFXType type, const std::string &file_name,
|
||||
const Vec3 &position);
|
||||
@ -63,10 +70,13 @@ public:
|
||||
KartGFX(const Kart *kart);
|
||||
~KartGFX();
|
||||
void reset();
|
||||
void setSkidLevel(const unsigned int level);
|
||||
void setParticleKind(const KartGFXType type, const ParticleKind *pk);
|
||||
void setXYZ(const KartGFXType type, const Vec3 &xyz);
|
||||
void setCreationRateAbsolute(const KartGFXType type, float f);
|
||||
void setCreationRateRelative(const KartGFXType type, float f);
|
||||
void resizeBox(const KartGFXType type, float speed, float dt);
|
||||
void updateTerrain(const ParticleKind *pk);
|
||||
void update(float dt);
|
||||
void setCreationRateAbsolute(KartGFXType type, float f);
|
||||
void setCreationRateRelative(KartGFXType type, float f);
|
||||
void resizeBox(KartGFXType type, float speed, float dt);
|
||||
void setSkidLevel(unsigned int level);
|
||||
}; // KartWGFX
|
||||
#endif
|
||||
|
@ -20,11 +20,12 @@
|
||||
|
||||
#include "items/item.hpp"
|
||||
|
||||
KartWithStats::KartWithStats(const std::string& ident, Track* track,
|
||||
KartWithStats::KartWithStats(const std::string& ident,
|
||||
unsigned int world_kart_id, Track* track,
|
||||
int position, bool is_first_kart,
|
||||
const btTransform& init_transform,
|
||||
RaceManager::KartType type)
|
||||
: Kart(ident, track, position, is_first_kart,
|
||||
: Kart(ident, world_kart_id, track, position, is_first_kart,
|
||||
init_transform, type)
|
||||
{
|
||||
reset();
|
||||
|
@ -65,7 +65,8 @@ private:
|
||||
float m_skidding_time;
|
||||
|
||||
public:
|
||||
KartWithStats(const std::string& ident, Track* track,
|
||||
KartWithStats(const std::string& ident,
|
||||
unsigned int world_kart_id, Track* track,
|
||||
int position, bool is_first_kart,
|
||||
const btTransform& init_transform,
|
||||
RaceManager::KartType type);
|
||||
|
@ -874,7 +874,6 @@ int handleCmdLine(int argc, char **argv)
|
||||
|| !strcmp(argv[i], "-N") )
|
||||
{
|
||||
UserConfigParams::m_no_start_screen = true;
|
||||
unlock_manager->setCurrentSlot(UserConfigParams::m_all_players[0].getName());
|
||||
}
|
||||
else if ( !strcmp(argv[i], "--race-now")
|
||||
|| !strcmp(argv[i], "-R") )
|
||||
@ -965,6 +964,9 @@ int handleCmdLine(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
} // for i <argc
|
||||
if(UserConfigParams::m_no_start_screen)
|
||||
unlock_manager->setCurrentSlot(UserConfigParams::m_all_players[0]
|
||||
.getName() );
|
||||
if(ProfileWorld::isProfileMode())
|
||||
{
|
||||
UserConfigParams::m_sfx = false; // Disable sound effects
|
||||
|
@ -20,15 +20,57 @@
|
||||
#include "input/input.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "modes/overworld.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
#include "states_screens/dialogs/select_challenge.hpp"
|
||||
#include "states_screens/kart_selection.hpp"
|
||||
#include "states_screens/race_gui_overworld.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Function to simplify the start process */
|
||||
void OverWorld::enterOverWorld()
|
||||
{
|
||||
|
||||
race_manager->setNumLocalPlayers(1);
|
||||
race_manager->setMajorMode (RaceManager::MAJOR_MODE_SINGLE);
|
||||
race_manager->setMinorMode (RaceManager::MINOR_MODE_OVERWORLD);
|
||||
race_manager->setNumKarts( 1 );
|
||||
race_manager->setTrack( "overworld" );
|
||||
race_manager->setDifficulty(RaceManager::RD_HARD);
|
||||
|
||||
// Use keyboard 0 by default (FIXME: let player choose?)
|
||||
InputDevice* device = input_manager->getDeviceList()->getKeyboard(0);
|
||||
|
||||
// Create player and associate player with keyboard
|
||||
StateManager::get()->createActivePlayer(
|
||||
UserConfigParams::m_all_players.get(0), device );
|
||||
|
||||
if (kart_properties_manager->getKart(UserConfigParams::m_default_kart) == NULL)
|
||||
{
|
||||
fprintf(stderr, "[MainMenuScreen] WARNING: cannot find kart '%s', will revert to default\n",
|
||||
UserConfigParams::m_default_kart.c_str());
|
||||
UserConfigParams::m_default_kart.revertToDefaults();
|
||||
}
|
||||
race_manager->setLocalKartInfo(0, UserConfigParams::m_default_kart);
|
||||
|
||||
// ASSIGN should make sure that only input from assigned devices
|
||||
// is read.
|
||||
input_manager->getDeviceList()->setAssignMode(ASSIGN);
|
||||
input_manager->getDeviceList()
|
||||
->setSinglePlayer( StateManager::get()->getActivePlayer(0) );
|
||||
|
||||
StateManager::get()->enterGameState();
|
||||
network_manager->setupPlayerKartInfo();
|
||||
race_manager->startNew();
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
OverWorld::OverWorld() : LinearWorld()
|
||||
{
|
||||
m_return_to_garage = false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -56,11 +98,22 @@ void OverWorld::update(float dt)
|
||||
|
||||
const unsigned int kart_amount = m_karts.size();
|
||||
|
||||
// isn't cool, on the overworld nitro is free!
|
||||
// isn't it cool, on the overworld nitro is free!
|
||||
for(unsigned int n=0; n<kart_amount; n++)
|
||||
{
|
||||
m_karts[n]->setEnergy(100.0f);
|
||||
}
|
||||
|
||||
if (m_return_to_garage)
|
||||
{
|
||||
m_return_to_garage = false;
|
||||
delayedSelfDestruct();
|
||||
race_manager->exitRace(false);
|
||||
KartSelectionScreen* s = KartSelectionScreen::getInstance();
|
||||
s->setMultiplayer(false);
|
||||
s->setFromOverworld(true);
|
||||
StateManager::get()->resetAndGoToScreen(s);
|
||||
}
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -38,6 +38,8 @@ protected:
|
||||
/** Override from base class */
|
||||
virtual void createRaceGUI();
|
||||
|
||||
bool m_return_to_garage;
|
||||
|
||||
public:
|
||||
OverWorld();
|
||||
/** call just after instanciating. can't be moved to the contructor as child
|
||||
@ -46,6 +48,8 @@ public:
|
||||
virtual void init();
|
||||
virtual ~OverWorld();
|
||||
|
||||
static void enterOverWorld();
|
||||
|
||||
virtual void update(float delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@ -69,6 +73,8 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Override settings from base class */
|
||||
virtual bool useChecklineRequirements() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
void scheduleReturnToGarage() { m_return_to_garage = true; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -91,8 +91,12 @@ Kart *ProfileWorld::createKart(const std::string &kart_ident, int index,
|
||||
{
|
||||
btTransform init_pos = m_track->getStartTransform(index);
|
||||
|
||||
Kart *new_kart = new KartWithStats(kart_ident, m_track, index+1,
|
||||
false, init_pos,
|
||||
Kart *new_kart = new KartWithStats(kart_ident,
|
||||
/*world kart id*/ index,
|
||||
m_track,
|
||||
/*position*/ index+1,
|
||||
/*is_first_kart*/false,
|
||||
init_pos,
|
||||
RaceManager::KT_AI);
|
||||
|
||||
Controller *controller = loadAIController(new_kart);
|
||||
|
@ -89,6 +89,7 @@ World::World() : WorldStatus(), m_clear_color(255,100,101,140)
|
||||
m_clear_back_buffer = false;
|
||||
m_schedule_pause = false;
|
||||
m_schedule_unpause = false;
|
||||
m_self_destruct = false;
|
||||
|
||||
WorldStatus::setClockMode(CLOCK_CHRONO);
|
||||
} // World
|
||||
@ -144,7 +145,6 @@ void World::init()
|
||||
Kart* newkart = createKart(kart_ident, i, local_player_id,
|
||||
global_player_id);
|
||||
m_karts.push_back(newkart);
|
||||
newkart->setWorldKartId(m_karts.size()-1);
|
||||
m_track->adjustForFog(newkart->getNode());
|
||||
|
||||
} // for i
|
||||
@ -190,7 +190,7 @@ Kart *World::createKart(const std::string &kart_ident, int index,
|
||||
{
|
||||
int position = index+1;
|
||||
btTransform init_pos = m_track->getStartTransform(index);
|
||||
Kart *new_kart = new Kart(kart_ident, m_track, position,
|
||||
Kart *new_kart = new Kart(kart_ident, index,m_track, position,
|
||||
(local_player_id == 0), init_pos,
|
||||
race_manager->getKartType(index));
|
||||
Controller *controller = NULL;
|
||||
@ -590,6 +590,12 @@ void World::updateWorld(float dt)
|
||||
m_schedule_unpause = false;
|
||||
}
|
||||
|
||||
if (m_self_destruct)
|
||||
{
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't update world if a menu is shown or the race is over.
|
||||
if( m_phase == FINISH_PHASE ||
|
||||
m_phase == IN_GAME_MENU_PHASE )
|
||||
@ -600,7 +606,6 @@ void World::updateWorld(float dt)
|
||||
{
|
||||
enterRaceOverState();
|
||||
}
|
||||
|
||||
} // updateWorld
|
||||
|
||||
#define MEASURE_FPS 0
|
||||
@ -948,4 +953,13 @@ void World::unpause()
|
||||
}
|
||||
} // pause
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Call when the world needs to be deleted but you can't do it immediately
|
||||
* because you are e.g. within World::update()
|
||||
*/
|
||||
void World::delayedSelfDestruct()
|
||||
{
|
||||
m_self_destruct = true;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
@ -146,6 +146,11 @@ protected:
|
||||
|
||||
Phase m_scheduled_pause_phase;
|
||||
|
||||
/** Set when the world needs to be deleted but you can't do it immediately
|
||||
* because you are e.g. within World::update()
|
||||
*/
|
||||
bool m_self_destruct;
|
||||
|
||||
public:
|
||||
World();
|
||||
virtual ~World();
|
||||
@ -276,10 +281,12 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Override if you want to know when a kart presses fire */
|
||||
virtual void onFirePressed(Controller* who) {}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Whether to compute checkline requirements for each world on the
|
||||
* quadgraph. Override to change value. */
|
||||
virtual bool useChecklineRequirements() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
void delayedSelfDestruct();
|
||||
|
||||
}; // World
|
||||
|
||||
|
@ -23,10 +23,13 @@
|
||||
/** A network kart. On the server, it receives its control information (steering etc)
|
||||
from the network manager.
|
||||
*/
|
||||
NetworkKart::NetworkKart(const std::string &kart_name, Track* track, int position,
|
||||
NetworkKart::NetworkKart(const std::string &kart_name,
|
||||
unsigned int world_kart_id, Track* track,
|
||||
int position,
|
||||
const btTransform &init_transform, int global_player_id,
|
||||
RaceManager::KartType type)
|
||||
: Kart(kart_name, track, position, false, init_transform, type)
|
||||
: Kart(kart_name, world_kart_id, track, position,
|
||||
/*is_first_kart*/false, init_transform, type)
|
||||
{
|
||||
m_global_player_id = global_player_id;
|
||||
} // NetworkKart
|
||||
|
@ -28,7 +28,8 @@ class NetworkKart : public Kart
|
||||
private:
|
||||
int m_global_player_id; // to identify this kart to the network manager
|
||||
public:
|
||||
NetworkKart(const std::string& kart_name, Track* track, int position,
|
||||
NetworkKart(const std::string& kart_name, unsigned int world_kart_id,
|
||||
Track* track, int position,
|
||||
const btTransform& init_transform,
|
||||
int global_player_id, RaceManager::KartType type);
|
||||
void setControl(const KartControl& kc);
|
||||
|
@ -438,8 +438,11 @@ void btKart::updateVehicle( btScalar step )
|
||||
|
||||
if(m_time_additional_impulse>0)
|
||||
{
|
||||
m_time_additional_impulse -= step;
|
||||
m_chassisBody->applyCentralImpulse(m_additional_impulse);
|
||||
float dt = step > m_time_additional_impulse
|
||||
? m_time_additional_impulse
|
||||
: step;
|
||||
m_chassisBody->applyCentralImpulse(m_additional_impulse*dt);
|
||||
m_time_additional_impulse -= dt;
|
||||
}
|
||||
|
||||
if(m_time_additional_rotation>0)
|
||||
@ -461,7 +464,7 @@ void btKart::updateVehicle( btScalar step )
|
||||
// kart, or a strongly 'visual jolt' of the kart
|
||||
btTransform &iwt=m_chassisBody->getInterpolationWorldTransform();
|
||||
iwt.setRotation(iwt.getRotation()*add_rot);
|
||||
m_time_additional_rotation -= step;
|
||||
m_time_additional_rotation -= dt;
|
||||
}
|
||||
} // updateVehicle
|
||||
|
||||
@ -724,30 +727,33 @@ void btKart::updateFriction(btScalar timeStep)
|
||||
rollingFriction=0;
|
||||
}
|
||||
|
||||
//switch between active rolling (throttle), braking and non-active
|
||||
// rolling friction (no throttle/break)
|
||||
|
||||
m_wheelInfo[wheel].m_skidInfo= btScalar(1.);
|
||||
|
||||
btScalar maximp = wheelInfo.m_wheelsSuspensionForce
|
||||
* timeStep * wheelInfo.m_frictionSlip;
|
||||
btScalar maximpSide = maximp;
|
||||
btScalar maximpSquared = maximp * maximpSide;
|
||||
m_forwardImpulse[wheel] = rollingFriction;
|
||||
|
||||
btScalar x = (m_forwardImpulse[wheel] ) * fwdFactor;
|
||||
btScalar y = (m_sideImpulse[wheel] ) * sideFactor;
|
||||
|
||||
btScalar impulseSquared = (x*x + y*y);
|
||||
|
||||
if (impulseSquared > maximpSquared)
|
||||
if(m_time_additional_impulse>0)
|
||||
{
|
||||
sliding = true;
|
||||
btScalar factor = maximp / btSqrt(impulseSquared);
|
||||
m_wheelInfo[wheel].m_skidInfo *= factor;
|
||||
} // if impulseSquared > maximpSquared
|
||||
m_wheelInfo[wheel].m_skidInfo = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
btScalar maximp = wheelInfo.m_wheelsSuspensionForce
|
||||
* timeStep * wheelInfo.m_frictionSlip;
|
||||
btScalar maximpSide = maximp;
|
||||
btScalar maximpSquared = maximp * maximpSide;
|
||||
|
||||
btScalar x = (m_forwardImpulse[wheel] ) * fwdFactor;
|
||||
btScalar y = (m_sideImpulse[wheel] ) * sideFactor;
|
||||
|
||||
btScalar impulseSquared = (x*x + y*y);
|
||||
|
||||
if (impulseSquared > maximpSquared)
|
||||
{
|
||||
sliding = true;
|
||||
btScalar factor = maximp / btSqrt(impulseSquared);
|
||||
m_wheelInfo[wheel].m_skidInfo *= factor;
|
||||
} // if impulseSquared > maximpSquared
|
||||
} // else (!m_timed_impulse
|
||||
} // for (int wheel=0; wheel<getNumWheels(); wheel++)
|
||||
|
||||
} // for (int wheel=0; wheel<getNumWheels(); wheel++)
|
||||
|
||||
m_zipper_active = false;
|
||||
m_zipper_velocity = 0;
|
||||
@ -779,7 +785,7 @@ void btKart::updateFriction(btScalar timeStep)
|
||||
av.setY(m_skid_angular_velocity);
|
||||
m_chassisBody->setAngularVelocity(av);
|
||||
}
|
||||
else if (sliding && m_allow_sliding)
|
||||
else if (sliding && (m_allow_sliding || m_time_additional_impulse>0) )
|
||||
{
|
||||
for (int wheel = 0; wheel < getNumWheels(); wheel++)
|
||||
{
|
||||
|
@ -230,7 +230,7 @@ public:
|
||||
} // setTimedImpulse
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time an additional impulse is activated. */
|
||||
float getImpulseTime() const { return m_time_additional_impulse; }
|
||||
float getCentralImpulseTime() const { return m_time_additional_impulse; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets a rotation that is applied over a certain amount of time (to avoid
|
||||
* a too rapid changes in the kart).
|
||||
|
@ -221,6 +221,11 @@ bool Physics::projectKartDownwards(const Kart *k)
|
||||
Physics::CollisionSide Physics::getCollisionSide(const btRigidBody *body,
|
||||
const Vec3 &contact_point)
|
||||
{
|
||||
if(contact_point.getX()>0)
|
||||
return COL_RIGHT;
|
||||
else
|
||||
return COL_LEFT;
|
||||
|
||||
btVector3 aabb_min, aabb_max;
|
||||
static btTransform zero_trans(btQuaternion(0, 0, 0));
|
||||
body->getCollisionShape()->getAabb(zero_trans, aabb_min, aabb_max);
|
||||
@ -268,135 +273,118 @@ Physics::CollisionSide Physics::getCollisionSide(const btRigidBody *body,
|
||||
* server and if no networking is used, and from race_state on the client to
|
||||
* replay what happened on the server.
|
||||
* \param kart_a First kart involved in the collision.
|
||||
* \param contact_point_a Location of collision at first kart (in kart
|
||||
* coordinates).
|
||||
* \param kart_b Second kart involved in the collision.
|
||||
* \param contact_point_b Location of collision at second kart (in kart
|
||||
* coordinates).
|
||||
*/
|
||||
void Physics::KartKartCollision(Kart *kart_a, const Vec3 &contact_point_a,
|
||||
Kart *kart_b, const Vec3 &contact_point_b)
|
||||
{
|
||||
kart_a->crashed(kart_b); // will play crash sound for player karts
|
||||
kart_b->crashed(kart_a);
|
||||
Attachment *attachmentA=kart_a->getAttachment();
|
||||
Attachment *attachmentB=kart_b->getAttachment();
|
||||
// Only one kart needs to handle the attachments, it will
|
||||
// fix the attachments for the other kart.
|
||||
kart_a->crashed(kart_b, /*handle_attachments*/true);
|
||||
kart_b->crashed(kart_a, /*handle_attachments*/false);
|
||||
|
||||
if(attachmentA->getType()==Attachment::ATTACH_BOMB)
|
||||
Kart *left_kart, *right_kart;
|
||||
|
||||
// Determine which kart is pushed to the left, and which one to the
|
||||
// right. Ideally the sign of the X coordinate of the local conact point
|
||||
// could decide the direction (negative X --> was hit on left side, gets
|
||||
// push to right), but that can lead to both karts being pushed in the
|
||||
// same direction (front left of kart hits rear left).
|
||||
// So we just use a simple test (which does the right thing in ideal
|
||||
// crashes, but avoids pushing both karts in corner cases
|
||||
// - pun intended ;) ).
|
||||
if(contact_point_a.getX() < contact_point_b.getX())
|
||||
{
|
||||
// If both karts have a bomb, explode them immediately:
|
||||
if(attachmentB->getType()==Attachment::ATTACH_BOMB)
|
||||
{
|
||||
attachmentA->setTimeLeft(0.0f);
|
||||
attachmentB->setTimeLeft(0.0f);
|
||||
}
|
||||
else // only A has a bomb, move it to B (unless it was from B)
|
||||
{
|
||||
if(attachmentA->getPreviousOwner()!=kart_b)
|
||||
{
|
||||
attachmentA->moveBombFromTo(kart_a, kart_b);
|
||||
// Play appropriate SFX
|
||||
kart_b->playCustomSFX(SFXManager::CUSTOM_ATTACH);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(attachmentB->getType()==Attachment::ATTACH_BOMB &&
|
||||
attachmentB->getPreviousOwner()!=kart_a)
|
||||
{
|
||||
attachmentB->moveBombFromTo(kart_b, kart_a);
|
||||
kart_a->playCustomSFX(SFXManager::CUSTOM_ATTACH);
|
||||
left_kart = kart_a;
|
||||
right_kart = kart_b;
|
||||
}
|
||||
else
|
||||
{
|
||||
kart_a->playCustomSFX(SFXManager::CUSTOM_CRASH);
|
||||
kart_b->playCustomSFX(SFXManager::CUSTOM_CRASH);
|
||||
left_kart = kart_b;
|
||||
right_kart = kart_a;
|
||||
}
|
||||
|
||||
// If bouncing crashes is enabled, add an additional force to the
|
||||
// slower kart
|
||||
Kart *faster_kart, *slower_kart;
|
||||
Vec3 faster_cp, slower_cp;
|
||||
if(kart_a->getSpeed()>=kart_b->getSpeed())
|
||||
// Add a scaling factor depending on the mass (avoid div by zero)
|
||||
float f_right = right_kart->getKartProperties()->getMass() > 0
|
||||
? left_kart->getKartProperties()->getMass()
|
||||
/ right_kart->getKartProperties()->getMass()
|
||||
: 1.5f;
|
||||
// Add a scaling factor depending on speed (avoid div by 0)
|
||||
f_right *= right_kart->getSpeed() > 0
|
||||
? left_kart->getSpeed()
|
||||
/ right_kart->getSpeed()
|
||||
: 1.5f;
|
||||
// Cap f_right to [0.8,1.25], which results in f_left being
|
||||
// capped in the same interval
|
||||
if(f_right > 1.25f)
|
||||
f_right = 1.25f;
|
||||
else if(f_right< 0.8f)
|
||||
f_right = 0.8f;
|
||||
float f_left = f_right ==0 ? 1.5f : 1/f_right;
|
||||
|
||||
// Check if a kart is more 'actively' trying to push another kart
|
||||
// by checking its local sidewards velocity
|
||||
float vel_left = left_kart->getVelocityLC().getX();
|
||||
float vel_right = right_kart->getVelocityLC().getX();
|
||||
|
||||
// Use the difference in speed to determine which kart gets a
|
||||
// ramming bonus. Normally vel_right and vel_left will have
|
||||
// a different sign: right kart will be driving to the left,
|
||||
// and left kart to the right (both pushing at each other).
|
||||
// By using the sum we get the intended effect: if both karts
|
||||
// are pushing with the same speed, vel_diff is 0, if the right
|
||||
// kart is driving faster vel_diff will be < 0. If both velocities
|
||||
// have the same sign, one kart is trying to steer away from the
|
||||
// other, in which case it gets an even bigger push.
|
||||
float vel_diff = vel_right + vel_left;
|
||||
|
||||
// More driving towards left --> left kart gets bigger impulse
|
||||
if(vel_diff<0)
|
||||
{
|
||||
faster_kart = kart_a;
|
||||
faster_cp = contact_point_a;
|
||||
slower_kart = kart_b;
|
||||
slower_cp = contact_point_b;
|
||||
f_right *= vel_left == 0 ? 2.0f : (1.0f - vel_diff/fabsf(vel_left));
|
||||
if(f_right > 2.0f)
|
||||
f_right = 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
faster_kart = kart_b;
|
||||
faster_cp = contact_point_b;
|
||||
slower_kart = kart_a;
|
||||
slower_cp = contact_point_a;
|
||||
f_left *= vel_right == 0 ? 2.0f : (1.0f + vel_diff/fabsf(vel_right));
|
||||
if(f_left > 2.0f)
|
||||
f_left = 2.0f;
|
||||
}
|
||||
|
||||
CollisionSide faster_side = getCollisionSide(faster_kart->getBody(),
|
||||
faster_cp);
|
||||
CollisionSide slower_side = getCollisionSide(slower_kart->getBody(),
|
||||
slower_cp);
|
||||
// Increase the effect somewhat by squaring the factors
|
||||
f_left = f_left * f_left;
|
||||
f_right = f_right * f_right;
|
||||
|
||||
// This probably needs adjusting once we have different kart properties.
|
||||
// E.g. besides speed we might also want to take mass into account(?)
|
||||
if(faster_side==COL_FRONT)
|
||||
// First push one kart to the left (if there is not already
|
||||
// an impulse happening - one collision might cause more
|
||||
// than one impulse otherwise)
|
||||
if(right_kart->getVehicle()->getCentralImpulseTime()<=0)
|
||||
{
|
||||
// Special case: the faster kart hits a kart front on. In this case
|
||||
// the slower kart will be pushed out of the faster kart's way
|
||||
Vec3 dir = faster_kart->getVelocity();
|
||||
|
||||
// The direction in which the impulse will be applied depends on
|
||||
// which side of the faster kart was hitting it: if the hit is
|
||||
// on the right side of the faster kart, it will push the slower
|
||||
// kart to the right and vice versa. This is based on the
|
||||
// assumption that a hit to the right indicates that it's
|
||||
// shorter to push the slower kart to the right.
|
||||
Vec3 impulse;
|
||||
if(faster_cp.getX()>0)
|
||||
impulse = Vec3( dir.getZ(), 0, -dir.getX());
|
||||
else
|
||||
impulse = Vec3(-dir.getZ(), 0, dir.getX());
|
||||
impulse.normalize();
|
||||
impulse *= faster_kart->getKartProperties()->getCollisionImpulse();
|
||||
float t =
|
||||
faster_kart->getKartProperties()->getCollisionImpulseTime();
|
||||
if(t>0)
|
||||
slower_kart->getVehicle()->setTimedCentralImpulse(t, impulse);
|
||||
else
|
||||
slower_kart->getBody()->applyCentralImpulse(impulse);
|
||||
slower_kart->getBody()->setAngularVelocity(btVector3(0,0,0));
|
||||
// Apply some impulse to the slower kart as well?
|
||||
const KartProperties *kp = left_kart->getKartProperties();
|
||||
Vec3 impulse(-kp->getCollisionImpulse()*f_left, 0, 0);
|
||||
impulse = right_kart->getTrans().getBasis() * impulse;
|
||||
right_kart->getVehicle()
|
||||
->setTimedCentralImpulse(kp->getCollisionImpulseTime(),
|
||||
impulse);
|
||||
right_kart ->getBody()->setAngularVelocity(btVector3(0,0,0));
|
||||
}
|
||||
else
|
||||
|
||||
// Then push the other kart to the right (if there is no
|
||||
// impulse happening atm).
|
||||
if(left_kart->getVehicle()->getCentralImpulseTime()<=0)
|
||||
{
|
||||
// Non-frontal collision, push the two karts away from each other
|
||||
// First the faster kart
|
||||
Vec3 dir = faster_kart->getVelocity();
|
||||
Vec3 impulse;
|
||||
if(faster_cp.getX()>0)
|
||||
impulse = Vec3(-dir.getZ(), 0, dir.getX());
|
||||
else
|
||||
impulse = Vec3( dir.getZ(), 0, -dir.getX());
|
||||
impulse.normalize();
|
||||
impulse *= slower_kart->getKartProperties()->getCollisionImpulse();
|
||||
float t =
|
||||
faster_kart->getKartProperties()->getCollisionImpulseTime();
|
||||
if(t>0)
|
||||
faster_kart->getVehicle()->setTimedCentralImpulse(t, impulse);
|
||||
else
|
||||
faster_kart->getBody()->applyCentralImpulse(impulse);
|
||||
faster_kart->getBody()->setAngularVelocity(btVector3(0,0,0));
|
||||
|
||||
// Then the slower kart
|
||||
dir = slower_kart->getVelocity();
|
||||
if(slower_cp.getX()>0)
|
||||
impulse = Vec3(-dir.getZ(), 0, dir.getX());
|
||||
else
|
||||
impulse = Vec3( dir.getZ(), 0, -dir.getX());
|
||||
|
||||
impulse.normalize();
|
||||
impulse *= faster_kart->getKartProperties()->getCollisionImpulse();
|
||||
t = faster_kart->getKartProperties()->getCollisionImpulseTime();
|
||||
if(t>0)
|
||||
slower_kart->getVehicle()->setTimedCentralImpulse(t, impulse);
|
||||
else
|
||||
slower_kart->getBody()->applyCentralImpulse(impulse);
|
||||
slower_kart->getBody()->setAngularVelocity(btVector3(0,0,0));
|
||||
const KartProperties *kp = right_kart->getKartProperties();
|
||||
Vec3 impulse = Vec3(kp->getCollisionImpulse()*f_right, 0, 0);
|
||||
impulse = left_kart->getTrans().getBasis() * impulse;
|
||||
left_kart->getVehicle()
|
||||
->setTimedCentralImpulse(kp->getCollisionImpulseTime(),
|
||||
impulse);
|
||||
left_kart->getBody()->setAngularVelocity(btVector3(0,0,0));
|
||||
}
|
||||
|
||||
} // KartKartCollision
|
||||
@ -470,7 +458,7 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
|
||||
const Material *m
|
||||
= n>=0 ? upA->getPointerTriangleMesh()->getMaterial(n)
|
||||
: NULL;
|
||||
kart->crashed(NULL, m);
|
||||
kart->crashed(m);
|
||||
}
|
||||
}
|
||||
// 2) object a is a kart
|
||||
@ -485,7 +473,7 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
|
||||
const Material *m
|
||||
= n>=0 ? upB->getPointerTriangleMesh()->getMaterial(n)
|
||||
: NULL;
|
||||
kart->crashed(NULL, m); // Kart hit track
|
||||
kart->crashed(m); // Kart hit track
|
||||
}
|
||||
else if(upB->is(UserPointer::UP_FLYABLE))
|
||||
// 2.1 projectile hits kart
|
||||
|
@ -138,7 +138,7 @@ private:
|
||||
btCollisionDispatcher *m_dispatcher;
|
||||
btBroadphaseInterface *m_axis_sweep;
|
||||
btDefaultCollisionConfiguration *m_collision_conf;
|
||||
CollisionList m_all_collisions;
|
||||
CollisionList m_all_collisions;
|
||||
|
||||
public:
|
||||
Physics ();
|
||||
|
@ -490,7 +490,7 @@ void RaceManager::computeGPRanks()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void RaceManager::exitRace()
|
||||
void RaceManager::exitRace(bool delete_world)
|
||||
{
|
||||
// Only display the grand prix result screen if all tracks
|
||||
// were finished, and not when a race is aborted.
|
||||
@ -559,7 +559,8 @@ void RaceManager::exitRace()
|
||||
}
|
||||
}
|
||||
|
||||
World::deleteWorld();
|
||||
if (delete_world) World::deleteWorld();
|
||||
|
||||
m_track_number = 0;
|
||||
} // exitRace
|
||||
|
||||
|
@ -483,7 +483,7 @@ public:
|
||||
* \note In GP, displays the GP result screen first
|
||||
* \note Deletes the world.
|
||||
*/
|
||||
void exitRace();
|
||||
void exitRace(bool delete_world=true);
|
||||
|
||||
/**
|
||||
* \brief Higher-level method to start a GP without having to care about the exact startup sequence
|
||||
|
@ -309,7 +309,7 @@ RaceOverDialog::RaceOverDialog(const float percentWidth,
|
||||
}
|
||||
|
||||
// ---- Buttons at the bottom
|
||||
if (unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures().size() > 0)
|
||||
if (unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges().size() > 0)
|
||||
{
|
||||
const int label_y = m_area.getHeight() - (button_h + margin_between_buttons)*2;
|
||||
|
||||
@ -480,14 +480,14 @@ GUIEngine::EventPropagation RaceOverDialog::processEvent(const std::string& even
|
||||
else if (eventSource == "seeunlocked")
|
||||
{
|
||||
std::vector<const ChallengeData*> unlocked =
|
||||
unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures();
|
||||
unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges();
|
||||
unlock_manager->getCurrentSlot()->clearUnlocked();
|
||||
|
||||
FeatureUnlockedCutScene* scene =
|
||||
FeatureUnlockedCutScene::getInstance();
|
||||
|
||||
assert(unlocked.size() > 0);
|
||||
scene->addUnlockedThings(unlocked);
|
||||
scene->addTrophy(race_manager->getDifficulty());
|
||||
|
||||
ModalDialog::dismiss();
|
||||
|
||||
@ -505,7 +505,7 @@ GUIEngine::EventPropagation RaceOverDialog::processEvent(const std::string& even
|
||||
|
||||
void RaceOverDialog::escapePressed()
|
||||
{
|
||||
if (unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures().size() > 0)
|
||||
if (unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges().size() > 0)
|
||||
{
|
||||
std::string what = "seeunlocked";
|
||||
processEvent(what);
|
||||
|
@ -18,13 +18,47 @@
|
||||
#include "challenges/unlock_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/widgets/icon_button_widget.hpp"
|
||||
#include "guiengine/widgets/label_widget.hpp"
|
||||
#include "input/device_manager.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "states_screens/dialogs/select_challenge.hpp"
|
||||
|
||||
using namespace GUIEngine;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
core::stringw getLabel(RaceManager::Difficulty difficulty, const ChallengeData* c)
|
||||
{
|
||||
core::stringw label = _("Number of AI Karts : %i",
|
||||
c->getNumKarts(difficulty) - 1);
|
||||
|
||||
if (c->getPosition(difficulty) != -1)
|
||||
{
|
||||
label.append(L"\n");
|
||||
label.append( _("Required Rank : %i", c->getPosition(difficulty)) );
|
||||
}
|
||||
if (c->getTime(difficulty) > 0)
|
||||
{
|
||||
label.append(L"\n");
|
||||
label.append( _("Required Time : %i",
|
||||
StringUtils::timeToString(c->getTime(difficulty)).c_str()) );
|
||||
}
|
||||
if (c->getEnergy(difficulty) > 0)
|
||||
{
|
||||
label.append(L"\n");
|
||||
label.append( _("Required Nitro Points : %i", c->getEnergy(difficulty)) );
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
SelectChallengeDialog::SelectChallengeDialog(const float percentWidth,
|
||||
const float percentHeight,
|
||||
@ -35,14 +69,61 @@ SelectChallengeDialog::SelectChallengeDialog(const float percentWidth,
|
||||
m_challenge_id = challenge_id;
|
||||
World::getWorld()->schedulePause(WorldStatus::IN_GAME_MENU_PHASE);
|
||||
|
||||
// TODO: select the previously selected difficulty
|
||||
switch (UserConfigParams::m_difficulty)
|
||||
{
|
||||
case 0:
|
||||
getWidget("novice")->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
|
||||
break;
|
||||
case 1:
|
||||
getWidget("intermediate")->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
|
||||
break;
|
||||
case 2:
|
||||
getWidget("expert")->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
|
||||
break;
|
||||
}
|
||||
|
||||
const Challenge* c = unlock_manager->getCurrentSlot()->getChallenge(challenge_id);
|
||||
|
||||
if (c->isSolved(RaceManager::RD_EASY))
|
||||
{
|
||||
IconButtonWidget* btn = getWidget<IconButtonWidget>("novice");
|
||||
btn->setImage(file_manager->getTextureFile("cup_bronze.png").c_str(),
|
||||
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
|
||||
}
|
||||
|
||||
if (c->isSolved(RaceManager::RD_MEDIUM))
|
||||
{
|
||||
IconButtonWidget* btn = getWidget<IconButtonWidget>("intermediate");
|
||||
btn->setImage(file_manager->getTextureFile("cup_silver.png").c_str(),
|
||||
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
|
||||
}
|
||||
|
||||
if (c->isSolved(RaceManager::RD_HARD))
|
||||
{
|
||||
IconButtonWidget* btn = getWidget<IconButtonWidget>("expert");
|
||||
btn->setImage(file_manager->getTextureFile("cup_gold.png").c_str(),
|
||||
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
|
||||
}
|
||||
|
||||
|
||||
LabelWidget* novice_label = getWidget<LabelWidget>("novice_label");
|
||||
LabelWidget* medium_label = getWidget<LabelWidget>("intermediate_label");
|
||||
LabelWidget* expert_label = getWidget<LabelWidget>("difficult_label");
|
||||
|
||||
novice_label->setText( getLabel(RaceManager::RD_EASY, c->getData()), false );
|
||||
medium_label->setText( getLabel(RaceManager::RD_MEDIUM, c->getData()), false );
|
||||
expert_label->setText( getLabel(RaceManager::RD_HARD, c->getData()), false );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
SelectChallengeDialog::~SelectChallengeDialog()
|
||||
{
|
||||
World::getWorld()->scheduleUnpause();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
GUIEngine::EventPropagation SelectChallengeDialog::processEvent(const std::string& eventSourceParam)
|
||||
{
|
||||
std::string eventSource = eventSourceParam;
|
||||
@ -94,14 +175,17 @@ GUIEngine::EventPropagation SelectChallengeDialog::processEvent(const std::strin
|
||||
if (eventSource == "novice")
|
||||
{
|
||||
challenge->setRace(RaceManager::RD_EASY);
|
||||
UserConfigParams::m_difficulty = 0;
|
||||
}
|
||||
else if (eventSource == "intermediate")
|
||||
{
|
||||
challenge->setRace(RaceManager::RD_MEDIUM);
|
||||
UserConfigParams::m_difficulty = 1;
|
||||
}
|
||||
else if (eventSource == "expert")
|
||||
{
|
||||
challenge->setRace(RaceManager::RD_HARD);
|
||||
UserConfigParams::m_difficulty = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -119,3 +203,5 @@ GUIEngine::EventPropagation SelectChallengeDialog::processEvent(const std::strin
|
||||
return GUIEngine::EVENT_LET;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include "guiengine/screen.hpp"
|
||||
#include "guiengine/widgets/button_widget.hpp"
|
||||
#include "guiengine/widgets/icon_button_widget.hpp"
|
||||
#include "guiengine/widgets/label_widget.hpp"
|
||||
#include "guiengine/widgets/spinner_widget.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
@ -49,52 +51,32 @@ TrackInfoDialog::TrackInfoDialog(const std::string& ribbonItem, const std::strin
|
||||
const irr::core::stringw& trackName, ITexture* screenshot,
|
||||
const float w, const float h) : ModalDialog(w, h)
|
||||
{
|
||||
loadFromFile("track_info_dialog.stkgui");
|
||||
|
||||
const bool has_laps = race_manager->modeHasLaps();
|
||||
const bool has_highscores = race_manager->modeHasHighscores();
|
||||
|
||||
const int y1 = m_area.getHeight()/7;
|
||||
const int y2 = m_area.getHeight()*5/7;
|
||||
const int y3 = m_area.getHeight()*6/7;
|
||||
|
||||
m_track_ident = trackIdent;
|
||||
m_ribbon_item = ribbonItem;
|
||||
|
||||
// ---- Track title
|
||||
core::rect< s32 > area_top(0, 0, m_area.getWidth(), y1);
|
||||
IGUIStaticText* a = GUIEngine::getGUIEnv()->addStaticText( trackName.c_str(),
|
||||
area_top, false, true, // border, word warp
|
||||
m_irrlicht_window);
|
||||
a->setTabStop(false);
|
||||
|
||||
const int hscores_y_from = y1;
|
||||
const int hscores_y_to = y1 + (y2 - y1)*2/3;
|
||||
getWidget<LabelWidget>("name")->setText(trackName.c_str(), false);
|
||||
|
||||
// ---- Track credits
|
||||
Track* track = track_manager->getTrack(trackIdent);
|
||||
|
||||
core::rect< s32 > creator_info_area(0, hscores_y_to, m_area.getWidth()/2, y2);
|
||||
|
||||
//I18N: when showing who is the author of track '%s' (place %s where the name of the author should appear)
|
||||
stringw text = _("Track by %s", track->getDesigner().c_str());
|
||||
getWidget<LabelWidget>("author")->setText( _("Track by %s", track->getDesigner().c_str()), false );
|
||||
|
||||
IGUIStaticText* b = GUIEngine::getGUIEnv()->addStaticText( text.c_str(),
|
||||
creator_info_area, false , true , // border, word warp
|
||||
m_irrlicht_window);
|
||||
b->setTabStop(false);
|
||||
|
||||
|
||||
|
||||
// ---- Track screenshot
|
||||
Widget* screenshot_div = getWidget("screenshot_div");
|
||||
IconButtonWidget* screenshotWidget = new IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO,
|
||||
false /* tab stop */, false /* focusable */);
|
||||
// images are saved squared, but must be stretched to 4:
|
||||
screenshotWidget->setCustomAspectRatio(4.0f / 3.0f);
|
||||
core::rect< s32 > area_right(m_area.getWidth()/2, y1, m_area.getWidth(), y2-10);
|
||||
|
||||
screenshotWidget->m_x = area_right.UpperLeftCorner.X;
|
||||
screenshotWidget->m_y = area_right.UpperLeftCorner.Y;
|
||||
screenshotWidget->m_w = area_right.getWidth();
|
||||
screenshotWidget->m_h = area_right.getHeight();
|
||||
screenshotWidget->m_x = screenshot_div->m_x;
|
||||
screenshotWidget->m_y = screenshot_div->m_y;
|
||||
screenshotWidget->m_w = screenshot_div->m_w;
|
||||
screenshotWidget->m_h = screenshot_div->m_h;
|
||||
|
||||
// temporary icon, will replace it just after (but it will be shown if the given icon is not found)
|
||||
screenshotWidget->m_properties[PROP_ICON] = "gui/main_help.png";
|
||||
@ -107,73 +89,39 @@ TrackInfoDialog::TrackInfoDialog(const std::string& ribbonItem, const std::strin
|
||||
}
|
||||
m_widgets.push_back(screenshotWidget);
|
||||
|
||||
a->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
|
||||
b->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
|
||||
|
||||
|
||||
// ---- Lap count m_spinner
|
||||
if (has_laps)
|
||||
{
|
||||
m_spinner = new SpinnerWidget();
|
||||
m_spinner->m_x = m_area.getWidth()/2 - 200;
|
||||
m_spinner->m_y = y2;
|
||||
m_spinner->m_w = 400;
|
||||
m_spinner->m_h = y3 - y2 - 15;
|
||||
m_spinner->setParent(m_irrlicht_window);
|
||||
m_spinner = getWidget<SpinnerWidget>("lapcountspinner");
|
||||
|
||||
m_spinner->m_properties[PROP_ID] = "lapcountspinner";
|
||||
if (UserConfigParams::m_artist_debug_mode)
|
||||
{
|
||||
m_spinner->m_properties[PROP_MIN_VALUE] = "0";
|
||||
m_spinner->setMin(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spinner->m_properties[PROP_MIN_VALUE] = "1";
|
||||
}
|
||||
m_spinner->m_properties[PROP_MAX_VALUE] = "99";
|
||||
m_spinner->m_properties[PROP_WARP_AROUND] = "true";
|
||||
|
||||
//I18N: In the track setup screen (number of laps choice, where %i is the number)
|
||||
m_spinner->setText( _("%i laps") );
|
||||
|
||||
m_widgets.push_back(m_spinner);
|
||||
m_spinner->add();
|
||||
//m_spinner->setText( _("%i laps") );
|
||||
m_spinner->setValue( UserConfigParams::m_num_laps );
|
||||
m_spinner->getIrrlichtElement()->setTabStop(true);
|
||||
m_spinner->getIrrlichtElement()->setTabGroup(false);
|
||||
//m_spinner->getIrrlichtElement()->setTabStop(true);
|
||||
//m_spinner->getIrrlichtElement()->setTabGroup(false);
|
||||
|
||||
const int num_laps = m_spinner->getValue();
|
||||
race_manager->setNumLaps(num_laps);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spinner = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Reverse track
|
||||
const bool reverse_available = track->reverseAvailable();
|
||||
if (reverse_available)
|
||||
{
|
||||
m_checkbox = new CheckBoxWidget();
|
||||
m_checkbox->m_x = 0;
|
||||
m_checkbox->m_y = (y2+y3)/2;
|
||||
m_checkbox->m_w = 60;
|
||||
m_checkbox->m_h = 60;
|
||||
m_checkbox->setParent(m_irrlicht_window);
|
||||
m_checkbox->m_properties[PROP_ID] = "reversecheckbox";
|
||||
m_checkbox->m_properties[PROP_WARP_AROUND] = "true";
|
||||
//~ m_checkbox->setText( _("Reverse track") );
|
||||
m_widgets.push_back(m_checkbox);
|
||||
m_checkbox->add();
|
||||
m_checkbox = getWidget<CheckBoxWidget>("reverse");
|
||||
m_checkbox->setState(race_manager->getReverseTrack());
|
||||
m_checkbox->getIrrlichtElement()->setTabStop(true);
|
||||
m_checkbox->getIrrlichtElement()->setTabGroup(false);
|
||||
stringw text_reverse = _("Reverse");
|
||||
|
||||
IGUIStaticText* b = GUIEngine::getGUIEnv()->addStaticText(
|
||||
text_reverse.c_str(),
|
||||
core::rect< s32 >(m_checkbox->m_x+m_checkbox->m_w,
|
||||
m_checkbox->m_y+10, m_checkbox->m_x+200,
|
||||
m_checkbox->m_y+m_checkbox->m_h),
|
||||
false , true , // border, word warp
|
||||
m_irrlicht_window);
|
||||
b->setTabStop(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -181,33 +129,35 @@ TrackInfoDialog::TrackInfoDialog(const std::string& ribbonItem, const std::strin
|
||||
race_manager->setReverseTrack(false);
|
||||
}
|
||||
|
||||
// ---- Start button
|
||||
ButtonWidget* okBtn = new ButtonWidget();
|
||||
okBtn->m_properties[PROP_ID] = "start";
|
||||
okBtn->setText( _("Start Race") );
|
||||
okBtn->m_x = m_area.getWidth()/2 - 200;
|
||||
okBtn->m_y = y3;
|
||||
okBtn->m_w = 400;
|
||||
okBtn->m_h = m_area.getHeight() - y3 - 15;
|
||||
okBtn->setParent(m_irrlicht_window);
|
||||
m_widgets.push_back(okBtn);
|
||||
okBtn->add();
|
||||
okBtn->getIrrlichtElement()->setTabStop(true);
|
||||
okBtn->getIrrlichtElement()->setTabGroup(false);
|
||||
|
||||
// ---- High Scores
|
||||
if (has_highscores)
|
||||
{
|
||||
addHighScoreWidgets(hscores_y_from, hscores_y_to);
|
||||
const int num_laps = m_spinner->getValue();
|
||||
race_manager->setNumLaps(num_laps);
|
||||
m_kart_icons[0] = getWidget<IconButtonWidget>("iconscore1");
|
||||
m_kart_icons[1] = getWidget<IconButtonWidget>("iconscore2");
|
||||
m_kart_icons[2] = getWidget<IconButtonWidget>("iconscore3");
|
||||
|
||||
m_highscore_entries[0] = getWidget<LabelWidget>("highscore1");
|
||||
m_highscore_entries[1] = getWidget<LabelWidget>("highscore2");
|
||||
m_highscore_entries[2] = getWidget<LabelWidget>("highscore3");
|
||||
|
||||
updateHighScores();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
getWidget<IconButtonWidget>("iconscore1")->setVisible(false);
|
||||
getWidget<IconButtonWidget>("iconscore2")->setVisible(false);
|
||||
getWidget<IconButtonWidget>("iconscore3")->setVisible(false);
|
||||
|
||||
getWidget<LabelWidget>("highscores")->setVisible(false);
|
||||
getWidget<LabelWidget>("highscore1")->setVisible(false);
|
||||
getWidget<LabelWidget>("highscore2")->setVisible(false);
|
||||
getWidget<LabelWidget>("highscore3")->setVisible(false);
|
||||
}
|
||||
|
||||
getWidget<ButtonWidget>("start")->setFocusForPlayer( PLAYER_ID_GAME_MASTER );
|
||||
|
||||
okBtn->setFocusForPlayer( PLAYER_ID_GAME_MASTER );
|
||||
|
||||
}
|
||||
} // TrackInfoDialog
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -221,45 +171,7 @@ TrackInfoDialog::~TrackInfoDialog()
|
||||
((TracksScreen*)curr_screen)->setFocusOnTrack(m_ribbon_item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
void TrackInfoDialog::addHighScoreWidgets(const int hscores_y_from, const int hscores_y_to)
|
||||
{
|
||||
ITexture* texture = irr_driver->getTexture( (file_manager->getGUIDir() + "/random_kart.png").c_str() ) ;
|
||||
|
||||
core::rect< s32 > hiscores_title_area(5, hscores_y_from, m_area.getWidth()/2, hscores_y_from + 30);
|
||||
stringw text = _("= Highscores =");
|
||||
IGUIStaticText* hscores_header = GUIEngine::getGUIEnv()->addStaticText( text.c_str(), hiscores_title_area,
|
||||
false , true , // border, word warp
|
||||
m_irrlicht_window);
|
||||
hscores_header->setTextRestrainedInside(false);
|
||||
hscores_header->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
|
||||
|
||||
// fill highscore entries
|
||||
for (int n=0; n<HIGHSCORE_COUNT; n++)
|
||||
{
|
||||
const int from_y = hscores_y_from + (hscores_y_to - hscores_y_from)*(n+1)/(HIGHSCORE_COUNT+1);
|
||||
const int next_from_y = hscores_y_from + (hscores_y_to - hscores_y_from)*(n+2)/(HIGHSCORE_COUNT+1);
|
||||
|
||||
const int gap = 3;
|
||||
const int icon_size = next_from_y - from_y - gap*2;
|
||||
|
||||
core::rect< s32 > icon_area(5, from_y + gap, 5 + icon_size, from_y + icon_size);
|
||||
|
||||
m_kart_icons[n] = GUIEngine::getGUIEnv()->addImage( icon_area, m_irrlicht_window );
|
||||
m_kart_icons[n]->setImage(texture);
|
||||
m_kart_icons[n]->setScaleImage(true);
|
||||
m_kart_icons[n]->setTabStop(false);
|
||||
m_kart_icons[n]->setUseAlphaChannel(true);
|
||||
|
||||
core::rect< s32 > entry_area(icon_size + 10, from_y, m_area.getWidth()/2, next_from_y);
|
||||
m_highscore_entries[n] = GUIEngine::getGUIEnv()->addStaticText( L"", entry_area,
|
||||
false , true , // border, word warp
|
||||
m_irrlicht_window);
|
||||
}
|
||||
}
|
||||
} // ~TrackInfoDialog
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -305,7 +217,6 @@ void TrackInfoDialog::updateHighScores()
|
||||
{
|
||||
//I18N: for empty highscores entries
|
||||
line = _("(Empty)");
|
||||
line += "\n";
|
||||
|
||||
ITexture* no_kart_texture = irr_driver->getTexture(
|
||||
(file_manager->getGUIDir() + "/random_kart.png").c_str() ) ;
|
||||
@ -313,23 +224,27 @@ void TrackInfoDialog::updateHighScores()
|
||||
|
||||
}
|
||||
|
||||
m_highscore_entries[n]->setText( line.c_str() );
|
||||
m_highscore_entries[n]->setText( line.c_str(), false );
|
||||
|
||||
}
|
||||
}
|
||||
} // updateHighScores
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
void TrackInfoDialog::onEnterPressedInternal()
|
||||
{
|
||||
ModalDialog::dismiss();
|
||||
|
||||
// Create a copy of member variables we still need, since they will
|
||||
// not be accessible after dismiss:
|
||||
const int num_laps = (m_spinner == NULL ? -1 : m_spinner->getValue());
|
||||
const bool reverse_track = m_checkbox == NULL ? false
|
||||
: m_checkbox->getState();
|
||||
race_manager->setReverseTrack(reverse_track);
|
||||
race_manager->startSingleRace(m_track_ident, num_laps);
|
||||
}
|
||||
printf("Reverse: %d\n", reverse_track);
|
||||
std::string track_ident = m_track_ident;
|
||||
ModalDialog::dismiss();
|
||||
race_manager->startSingleRace(track_ident, num_laps);
|
||||
} // onEnterPressedInternal
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -337,12 +252,7 @@ GUIEngine::EventPropagation TrackInfoDialog::processEvent(const std::string& eve
|
||||
{
|
||||
if (eventSource == "start" )
|
||||
{
|
||||
// Create a copy of member variables we still need, since they will
|
||||
// not be accessible after dismiss:
|
||||
const int num_laps = (m_spinner == NULL ? -1 : m_spinner->getValue());
|
||||
std::string track_ident = m_track_ident;
|
||||
ModalDialog::dismiss();
|
||||
race_manager->startSingleRace(track_ident, num_laps);
|
||||
onEnterPressedInternal();
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
}
|
||||
else if (eventSource == "reversecheckbox")
|
||||
@ -359,6 +269,6 @@ GUIEngine::EventPropagation TrackInfoDialog::processEvent(const std::string& eve
|
||||
}
|
||||
|
||||
return GUIEngine::EVENT_LET;
|
||||
}
|
||||
} // processEvent
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
@ -20,12 +20,16 @@
|
||||
#define HEADER_TRACKINFO_DIALOG_HPP
|
||||
|
||||
#include "guiengine/modaldialog.hpp"
|
||||
#include "guiengine/widgets/spinner_widget.hpp"
|
||||
#include "guiengine/widgets/check_box_widget.hpp"
|
||||
|
||||
static const int HIGHSCORE_COUNT = 3;
|
||||
|
||||
namespace irr { namespace gui { class IGUIImage; class IGUIStaticText; } }
|
||||
namespace GUIEngine
|
||||
{
|
||||
class SpinnerWidget;
|
||||
class IconButtonWidget;
|
||||
class LabelWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Dialog that shows the information about a given track
|
||||
@ -40,10 +44,9 @@ class TrackInfoDialog : public GUIEngine::ModalDialog
|
||||
// irrlicht labels (more complicated uses require the use of our widget set)
|
||||
GUIEngine::SpinnerWidget* m_spinner;
|
||||
GUIEngine::CheckBoxWidget* m_checkbox;
|
||||
irr::gui::IGUIImage* m_kart_icons[HIGHSCORE_COUNT];
|
||||
irr::gui::IGUIStaticText* m_highscore_entries[HIGHSCORE_COUNT];
|
||||
GUIEngine::IconButtonWidget* m_kart_icons[HIGHSCORE_COUNT];
|
||||
GUIEngine::LabelWidget* m_highscore_entries[HIGHSCORE_COUNT];
|
||||
|
||||
void addHighScoreWidgets(const int hscores_y_from, const int hscores_y_to);
|
||||
void updateHighScores();
|
||||
|
||||
public:
|
||||
|
@ -54,6 +54,18 @@ DEFINE_SCREEN_SINGLETON( FeatureUnlockedCutScene );
|
||||
#pragma mark FeatureUnlockedCutScene::UnlockedThing
|
||||
#endif
|
||||
|
||||
FeatureUnlockedCutScene::UnlockedThing::UnlockedThing(std::string model,
|
||||
irr::core::stringw msg)
|
||||
{
|
||||
m_unlocked_kart = NULL;
|
||||
m_unlock_message = msg;
|
||||
m_unlock_model = model;
|
||||
m_curr_image = -1;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
FeatureUnlockedCutScene::UnlockedThing::UnlockedThing(KartProperties* kart,
|
||||
irr::core::stringw msg)
|
||||
{
|
||||
@ -125,6 +137,48 @@ void FeatureUnlockedCutScene::loadedFromFile()
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void FeatureUnlockedCutScene::addTrophy(RaceManager::Difficulty difficulty)
|
||||
{
|
||||
core::stringw msg;
|
||||
switch (difficulty)
|
||||
{
|
||||
case RaceManager::RD_EASY:
|
||||
msg = _("You completed the easy challenge!");
|
||||
break;
|
||||
case RaceManager::RD_MEDIUM:
|
||||
msg = _("You completed the intermediate challenge!");
|
||||
break;
|
||||
case RaceManager::RD_HARD:
|
||||
msg = _("You completed the difficult challenge!");
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
std::string model;
|
||||
switch (difficulty)
|
||||
{
|
||||
case RaceManager::RD_EASY:
|
||||
model = file_manager->getModelFile("trophy_bronze.b3d");
|
||||
break;
|
||||
case RaceManager::RD_MEDIUM:
|
||||
model = file_manager->getModelFile("trophy_silver.b3d");
|
||||
break;
|
||||
case RaceManager::RD_HARD:
|
||||
model = file_manager->getModelFile("trophy_gold.b3d");
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_unlocked_stuff.push_back( new UnlockedThing(model, msg) );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// unused for now, maybe will be useful later?
|
||||
/*
|
||||
void FeatureUnlockedCutScene::addUnlockedKart(KartProperties* unlocked_kart,
|
||||
irr::core::stringw msg)
|
||||
{
|
||||
@ -159,7 +213,7 @@ void FeatureUnlockedCutScene::addUnlockedPictures(std::vector<irr::video::ITextu
|
||||
|
||||
m_unlocked_stuff.push_back( new UnlockedThing(pictures, w, h, msg) );
|
||||
} // addUnlockedPictures
|
||||
|
||||
*/
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const float CAMERA_INITIAL_X = 0.0f;
|
||||
@ -232,7 +286,11 @@ void FeatureUnlockedCutScene::init()
|
||||
m_all_kart_models.clearAndDeleteAll();
|
||||
for (int n=0; n<unlockedStuffCount; n++)
|
||||
{
|
||||
if (m_unlocked_stuff[n].m_unlocked_kart != NULL)
|
||||
if (m_unlocked_stuff[n].m_unlock_model.size() > 0)
|
||||
{
|
||||
m_unlocked_stuff[n].m_root_gift_node = irr_driver->addMesh( irr_driver->getMesh(m_unlocked_stuff[n].m_unlock_model) );
|
||||
}
|
||||
else if (m_unlocked_stuff[n].m_unlocked_kart != NULL)
|
||||
{
|
||||
KartModel *kart_model =
|
||||
m_unlocked_stuff[n].m_unlocked_kart->getKartModelCopy();
|
||||
@ -499,6 +557,8 @@ void FeatureUnlockedCutScene::onUpdate(float dt,
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// unused for now... maybe this could could useful later?
|
||||
/*
|
||||
void FeatureUnlockedCutScene::addUnlockedThings(const std::vector<const ChallengeData*> unlocked)
|
||||
{
|
||||
for (unsigned int n=0; n<unlocked.size(); n++)
|
||||
@ -613,6 +673,7 @@ void FeatureUnlockedCutScene::addUnlockedThings(const std::vector<const Challeng
|
||||
} // next feature
|
||||
} // next challenge
|
||||
} // addUnlockedThings
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "guiengine/screen.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
|
||||
namespace irr {
|
||||
@ -47,6 +48,8 @@ class FeatureUnlockedCutScene : public GUIEngine::Screen, public GUIEngine::Scre
|
||||
/** Will be non-null if this unlocked thing is a kart */
|
||||
KartProperties* m_unlocked_kart;
|
||||
|
||||
std::string m_unlock_model;
|
||||
|
||||
/** Will be non-empty if this unlocked thing is one or many pictures */
|
||||
std::vector<irr::video::ITexture*> m_pictures;
|
||||
/** Will be set if this unlocked thing is a picture */
|
||||
@ -59,6 +62,8 @@ class FeatureUnlockedCutScene : public GUIEngine::Screen, public GUIEngine::Scre
|
||||
|
||||
irr::core::stringw m_unlock_message;
|
||||
|
||||
UnlockedThing(std::string model, irr::core::stringw msg);
|
||||
|
||||
UnlockedThing(KartProperties* kart, irr::core::stringw msg);
|
||||
|
||||
/**
|
||||
@ -136,21 +141,28 @@ public:
|
||||
|
||||
/** Call before showing up the screen to make a kart come out of the chest.
|
||||
'addUnlockedThings' will invoke this, so you generally don't need to call this directly. */
|
||||
void addUnlockedKart(KartProperties* unlocked_kart, irr::core::stringw msg);
|
||||
// unused for now, maybe will be useful later?
|
||||
//void addUnlockedKart(KartProperties* unlocked_kart, irr::core::stringw msg);
|
||||
|
||||
/** Call before showing up the screen to make a picture come out of the chest
|
||||
'addUnlockedThings' will invoke this, so you generally don't need to call this directly. */
|
||||
void addUnlockedPicture(irr::video::ITexture* picture, float w, float h, irr::core::stringw msg);
|
||||
// unused for now, maybe will be useful later?
|
||||
//void addUnlockedPicture(irr::video::ITexture* picture, float w, float h, irr::core::stringw msg);
|
||||
|
||||
/** Call before showing up the screen to make a picture slideshow come out of the chest
|
||||
'addUnlockedThings' will invoke this, so you generally don't need to call this directly. */
|
||||
void addUnlockedPictures(std::vector<irr::video::ITexture*> pictures,
|
||||
float w, float h, irr::core::stringw msg);
|
||||
// unused for now, maybe will be useful later?
|
||||
//void addUnlockedPictures(std::vector<irr::video::ITexture*> pictures,
|
||||
// float w, float h, irr::core::stringw msg);
|
||||
|
||||
/** Call before showing up the screen to make whatever the passed challenges unlocked
|
||||
* come out of the chest */
|
||||
// unused for now... maybe this could could useful later?
|
||||
/*
|
||||
void addUnlockedThings(const std::vector<const ChallengeData*> unlocked);
|
||||
*/
|
||||
|
||||
void addTrophy(RaceManager::Difficulty difficulty);
|
||||
|
||||
/** override from base class to handle escape press */
|
||||
virtual bool onEscapePressed();
|
||||
|
@ -271,17 +271,17 @@ void GrandPrixLose::eventCallback(GUIEngine::Widget* widget,
|
||||
// un-set the GP mode so that after unlocking, it doesn't try to continue the GP
|
||||
race_manager->setMajorMode (RaceManager::MAJOR_MODE_SINGLE);
|
||||
|
||||
if (unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures().size() > 0)
|
||||
if (unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges().size() > 0)
|
||||
{
|
||||
std::vector<const ChallengeData*> unlocked =
|
||||
unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures();
|
||||
unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges();
|
||||
unlock_manager->getCurrentSlot()->clearUnlocked();
|
||||
|
||||
FeatureUnlockedCutScene* scene =
|
||||
FeatureUnlockedCutScene::getInstance();
|
||||
|
||||
assert(unlocked.size() > 0);
|
||||
scene->addUnlockedThings(unlocked);
|
||||
scene->addTrophy(race_manager->getDifficulty());
|
||||
|
||||
StateManager::get()->replaceTopMostScreen(scene);
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ void GrandPrixWin::loadedFromFile()
|
||||
void GrandPrixWin::init()
|
||||
{
|
||||
Screen::init();
|
||||
if (unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures().size() > 0)
|
||||
if (unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges().size() > 0)
|
||||
{
|
||||
const core::dimension2d<u32>& frame_size = GUIEngine::getDriver()->getCurrentRenderTargetSize();
|
||||
|
||||
@ -393,17 +393,17 @@ void GrandPrixWin::eventCallback(GUIEngine::Widget* widget,
|
||||
// un-set the GP mode so that after unlocking, it doesn't try to continue the GP
|
||||
race_manager->setMajorMode (RaceManager::MAJOR_MODE_SINGLE);
|
||||
|
||||
if (unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures().size() > 0)
|
||||
if (unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges().size() > 0)
|
||||
{
|
||||
std::vector<const ChallengeData*> unlocked =
|
||||
unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures();
|
||||
unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges();
|
||||
unlock_manager->getCurrentSlot()->clearUnlocked();
|
||||
|
||||
FeatureUnlockedCutScene* scene =
|
||||
FeatureUnlockedCutScene::getInstance();
|
||||
|
||||
assert(unlocked.size() > 0);
|
||||
scene->addUnlockedThings(unlocked);
|
||||
scene->addTrophy(race_manager->getDifficulty());
|
||||
|
||||
StateManager::get()->replaceTopMostScreen(scene);
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "items/item_manager.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "modes/overworld.hpp"
|
||||
#include "states_screens/race_setup_screen.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
@ -1597,8 +1598,16 @@ void KartSelectionScreen::eventCallback(Widget* widget,
|
||||
playerConfirm(playerID);
|
||||
}
|
||||
else if (name == "back")
|
||||
{
|
||||
StateManager::get()->escapePressed();
|
||||
{
|
||||
if (m_from_overworld)
|
||||
{
|
||||
m_from_overworld = false; // valid once
|
||||
OverWorld::enterOverWorld();
|
||||
}
|
||||
else
|
||||
{
|
||||
StateManager::get()->escapePressed();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1625,6 +1634,22 @@ void KartSelectionScreen::setMultiplayer(bool multiplayer)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool KartSelectionScreen::onEscapePressed()
|
||||
{
|
||||
if (m_from_overworld)
|
||||
{
|
||||
m_from_overworld = false; // valid once
|
||||
OverWorld::enterOverWorld();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if 0
|
||||
#pragma mark -
|
||||
#pragma mark KartSelectionScreen (private)
|
||||
@ -1747,7 +1772,16 @@ void KartSelectionScreen::allPlayersDone()
|
||||
input_manager->getDeviceList()->setSinglePlayer( NULL );
|
||||
}
|
||||
|
||||
StateManager::get()->pushScreen( RaceSetupScreen::getInstance() );
|
||||
// ---- Go to next screen or return to overworld
|
||||
if (m_from_overworld)
|
||||
{
|
||||
m_from_overworld = false; // valid once
|
||||
OverWorld::enterOverWorld();
|
||||
}
|
||||
else
|
||||
{
|
||||
StateManager::get()->pushScreen( RaceSetupScreen::getInstance() );
|
||||
}
|
||||
} // allPlayersDone
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -51,6 +51,9 @@ class KartSelectionScreen : public GUIEngine::Screen,
|
||||
|
||||
bool m_multiplayer;
|
||||
|
||||
/** Whether this screen is being visited from overworld or not */
|
||||
bool m_from_overworld;
|
||||
|
||||
KartSelectionScreen();
|
||||
|
||||
/** Stores whether any player confirmed their choice; then, some things
|
||||
@ -93,6 +96,9 @@ public:
|
||||
|
||||
void setMultiplayer(bool multiplayer);
|
||||
|
||||
/** \brief Set whether this screen is being visited from overworld or not */
|
||||
void setFromOverworld(bool from_overworld) { m_from_overworld = from_overworld; }
|
||||
|
||||
/** \brief Called when a player hits 'fire'/'select' on his device to
|
||||
* join the game */
|
||||
bool playerJoin(InputDevice* device, bool firstPlayer);
|
||||
@ -122,4 +128,8 @@ public:
|
||||
/** \brief implement optional callback from parent
|
||||
* class GUIEngine::Screen */
|
||||
virtual void unloaded();
|
||||
|
||||
/** \brief implement optional callback from parent
|
||||
* class GUIEngine::Screen */
|
||||
virtual bool onEscapePressed();
|
||||
};
|
||||
|
@ -256,6 +256,7 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name,
|
||||
{
|
||||
KartSelectionScreen* s = KartSelectionScreen::getInstance();
|
||||
s->setMultiplayer(false);
|
||||
s->setFromOverworld(false);
|
||||
StateManager::get()->pushScreen( s );
|
||||
}
|
||||
else if (selection == "multiplayer")
|
||||
@ -283,35 +284,7 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name,
|
||||
}
|
||||
else if (selection == "story")
|
||||
{
|
||||
/*
|
||||
StateManager::get()->pushScreen(ChallengesScreen::getInstance());
|
||||
*/
|
||||
|
||||
race_manager->setNumLocalPlayers(1);
|
||||
race_manager->setMajorMode (RaceManager::MAJOR_MODE_SINGLE);
|
||||
race_manager->setMinorMode (RaceManager::MINOR_MODE_OVERWORLD);
|
||||
race_manager->setNumKarts( 1 );
|
||||
race_manager->setTrack( "overworld" );
|
||||
race_manager->setDifficulty(RaceManager::RD_HARD);
|
||||
|
||||
// Use keyboard 0 by default (FIXME: let player choose?)
|
||||
InputDevice* device = input_manager->getDeviceList()->getKeyboard(0);
|
||||
|
||||
// Create player and associate player with keyboard
|
||||
StateManager::get()->createActivePlayer(
|
||||
UserConfigParams::m_all_players.get(0), device );
|
||||
|
||||
race_manager->setLocalKartInfo(0, "tux");
|
||||
|
||||
// ASSIGN should make sure that only input from assigned devices
|
||||
// is read.
|
||||
input_manager->getDeviceList()->setAssignMode(ASSIGN);
|
||||
input_manager->getDeviceList()
|
||||
->setSinglePlayer( StateManager::get()->getActivePlayer(0) );
|
||||
|
||||
StateManager::get()->enterGameState();
|
||||
network_manager->setupPlayerKartInfo();
|
||||
race_manager->startNew();
|
||||
OverWorld::enterOverWorld();
|
||||
}
|
||||
else if (selection == "tutorial")
|
||||
{
|
||||
|
@ -51,7 +51,9 @@ using namespace irr;
|
||||
|
||||
const int LOCKED = 0;
|
||||
const int OPEN = 1;
|
||||
const int COMPLETED = 2;
|
||||
const int COMPLETED_EASY = 2;
|
||||
const int COMPLETED_MEDIUM = 3;
|
||||
const int COMPLETED_HARD = 4;
|
||||
|
||||
/** The constructor is called before anything is attached to the scene node.
|
||||
* So rendering to a texture can be done here. But world is not yet fully
|
||||
@ -60,8 +62,10 @@ const int COMPLETED = 2;
|
||||
RaceGUIOverworld::RaceGUIOverworld()
|
||||
{
|
||||
m_enabled = true;
|
||||
m_trophy = irr_driver->getTexture( file_manager->getTextureFile("cup_gold.png") );
|
||||
|
||||
m_trophy1 = irr_driver->getTexture( file_manager->getTextureFile("cup_bronze.png") );
|
||||
m_trophy2 = irr_driver->getTexture( file_manager->getTextureFile("cup_silver.png") );
|
||||
m_trophy3 = irr_driver->getTexture( file_manager->getTextureFile("cup_gold.png") );
|
||||
|
||||
const float scaling = irr_driver->getFrameSize().Height / 420.0f;
|
||||
// Marker texture has to be power-of-two for (old) OpenGL compliance
|
||||
m_marker_rendered_size = 2 << ((int) ceil(1.0 + log(32.0 * scaling)));
|
||||
@ -101,18 +105,14 @@ RaceGUIOverworld::RaceGUIOverworld()
|
||||
gui::ScalableFont* font = GUIEngine::getFont();
|
||||
m_trophy_points_width = font->getDimension(L"100").Width;
|
||||
|
||||
const std::vector<const ChallengeData*>& v = unlock_manager->getCurrentSlot()->getLockedChallenges();
|
||||
for (unsigned int n=0; n<v.size(); n++)
|
||||
{
|
||||
m_locked_challenges.insert(v[n]);
|
||||
}
|
||||
|
||||
m_lock = irr_driver->getTexture( file_manager->getTextureFile("gui_lock.png") );
|
||||
m_open_challenge = irr_driver->getTexture( file_manager->getGUIDir() + "challenge.png" );
|
||||
|
||||
m_icons[0] = m_lock;
|
||||
m_icons[1] = m_open_challenge;
|
||||
m_icons[2] = m_trophy;
|
||||
m_icons[2] = m_trophy1;
|
||||
m_icons[3] = m_trophy2;
|
||||
m_icons[4] = m_trophy3;
|
||||
} // RaceGUIOverworld
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -217,9 +217,9 @@ void RaceGUIOverworld::drawTrophyPoints()
|
||||
const int size = UserConfigParams::m_width/20;
|
||||
core::rect<s32> dest(pos.UpperLeftCorner.X - size - 5, pos.UpperLeftCorner.Y,
|
||||
pos.UpperLeftCorner.X - 5, pos.UpperLeftCorner.Y + size);
|
||||
core::rect<s32> source(core::position2di(0, 0), m_trophy->getSize());
|
||||
core::rect<s32> source(core::position2di(0, 0), m_trophy3->getSize());
|
||||
|
||||
irr_driver->getVideoDriver()->draw2DImage(m_trophy, dest, source, NULL,
|
||||
irr_driver->getVideoDriver()->draw2DImage(m_trophy3, dest, source, NULL,
|
||||
NULL, true /* alpha */);
|
||||
|
||||
pos.LowerRightCorner.Y = dest.LowerRightCorner.Y;
|
||||
@ -321,8 +321,10 @@ void RaceGUIOverworld::drawGlobalMiniMap()
|
||||
int state = (challenges[n].m_force_field.m_is_locked ? LOCKED : OPEN);
|
||||
|
||||
const Challenge* c = unlock_manager->getCurrentSlot()->getChallenge(challenges[n].m_challenge_id);
|
||||
if (c->isSolved()) state = COMPLETED;
|
||||
|
||||
if (c->isSolved(RaceManager::RD_HARD)) state = COMPLETED_HARD;
|
||||
else if (c->isSolved(RaceManager::RD_MEDIUM)) state = COMPLETED_MEDIUM;
|
||||
else if (c->isSolved(RaceManager::RD_EASY)) state = COMPLETED_EASY;
|
||||
|
||||
const core::rect<s32> source(core::position2d<s32>(0,0),
|
||||
m_icons[state]->getOriginalSize());
|
||||
|
||||
|
@ -61,11 +61,13 @@ private:
|
||||
/** The mini map of the track. */
|
||||
video::ITexture *m_mini_map;
|
||||
|
||||
video::ITexture *m_trophy;
|
||||
video::ITexture *m_trophy1;
|
||||
video::ITexture *m_trophy2;
|
||||
video::ITexture *m_trophy3;
|
||||
video::ITexture *m_lock;
|
||||
video::ITexture *m_open_challenge;
|
||||
|
||||
video::ITexture* m_icons[3];
|
||||
video::ITexture* m_icons[5];
|
||||
|
||||
/** The size of a single marker on the screen for AI karts,
|
||||
* need not be a power of 2. */
|
||||
@ -95,8 +97,6 @@ private:
|
||||
|
||||
int m_trophy_points_width;
|
||||
|
||||
std::set<const ChallengeData*> m_locked_challenges;
|
||||
|
||||
/* Display informat for one player on the screen. */
|
||||
void drawEnergyMeter (int x, int y, const Kart *kart,
|
||||
const core::recti &viewport,
|
||||
|
@ -90,7 +90,7 @@ void RaceResultGUI::enableAllButtons()
|
||||
|
||||
// If something was unlocked
|
||||
// -------------------------
|
||||
int n = unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures().size();
|
||||
int n = unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges().size();
|
||||
if(n>0)
|
||||
{
|
||||
top->setText(n==1 ? _("See unlocked feature")
|
||||
@ -137,7 +137,7 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
|
||||
// If something was unlocked, the 'continue' button was
|
||||
// actually used to display "Show unlocked feature(s)" text.
|
||||
// ---------------------------------------------------------
|
||||
int n = unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures().size();
|
||||
int n = unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges().size();
|
||||
if(n>0)
|
||||
{
|
||||
if(name=="top")
|
||||
@ -148,11 +148,11 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
|
||||
}
|
||||
|
||||
std::vector<const ChallengeData*> unlocked =
|
||||
unlock_manager->getCurrentSlot()->getRecentlyUnlockedFeatures();
|
||||
unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges();
|
||||
unlock_manager->getCurrentSlot()->clearUnlocked();
|
||||
FeatureUnlockedCutScene* scene =
|
||||
FeatureUnlockedCutScene::getInstance();
|
||||
scene->addUnlockedThings(unlocked);
|
||||
scene->addTrophy(race_manager->getDifficulty());
|
||||
StateManager::get()->popMenu();
|
||||
StateManager::get()->pushScreen(scene);
|
||||
World::deleteWorld();
|
||||
|
@ -190,6 +190,14 @@ void Track::cleanup()
|
||||
}
|
||||
m_all_cached_meshes.clear();
|
||||
|
||||
// Now free meshes that are not associated to any scene node.
|
||||
for (unsigned int i=0; i<m_detached_cached_meshes.size(); i++)
|
||||
{
|
||||
irr_driver->dropAllTextures(m_detached_cached_meshes[i]);
|
||||
irr_driver->removeMeshFromCache(m_detached_cached_meshes[i]);
|
||||
}
|
||||
m_detached_cached_meshes.clear();
|
||||
|
||||
QuadGraph::destroy();
|
||||
|
||||
if(m_mini_map)
|
||||
@ -459,6 +467,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node)
|
||||
if (node->getType() == scene::ESNT_LOD_NODE)
|
||||
{
|
||||
node = ((LODNode*)node)->getFirstNode();
|
||||
if (node == NULL)
|
||||
{
|
||||
fprintf(stderr, "[Track] WARNING: this track contains an empty LOD group : '%s'\n",
|
||||
((LODNode*)node)->getGroupName().c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const core::vector3df &pos = node->getPosition();
|
||||
@ -810,7 +824,7 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
std::string challenge;
|
||||
n->get("challenge", &challenge);
|
||||
|
||||
lodLoader.check(n);
|
||||
bool is_lod = lodLoader.check(n);
|
||||
|
||||
if (tangent)
|
||||
{
|
||||
@ -818,6 +832,13 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
|
||||
scene::IMesh* original_mesh = irr_driver->getMesh(full_path);
|
||||
|
||||
if (std::find(m_detached_cached_meshes.begin(),
|
||||
m_detached_cached_meshes.end(),
|
||||
original_mesh) == m_detached_cached_meshes.end())
|
||||
{
|
||||
m_detached_cached_meshes.push_back(original_mesh);
|
||||
}
|
||||
|
||||
// create a node out of this mesh just for bullet; delete it after, normal maps are special
|
||||
// and require tangent meshes
|
||||
scene_node = irr_driver->addMesh(original_mesh);
|
||||
@ -828,10 +849,12 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
|
||||
convertTrackToBullet(scene_node);
|
||||
scene_node->remove();
|
||||
|
||||
irr_driver->grabAllTextures(original_mesh);
|
||||
|
||||
scene::IMesh* mesh = manip->createMeshWithTangents(original_mesh);
|
||||
mesh->grab();
|
||||
irr_driver->grabAllTextures(mesh);
|
||||
|
||||
m_all_cached_meshes.push_back(mesh);
|
||||
scene_node = irr_driver->addMesh(mesh);
|
||||
scene_node->setPosition(xyz);
|
||||
@ -846,7 +869,7 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
handleAnimatedTextures(scene_node, *n);
|
||||
m_all_nodes.push_back( scene_node );
|
||||
}
|
||||
else if (lodLoader.check(n))
|
||||
else if (is_lod)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
@ -136,6 +136,12 @@ private:
|
||||
* that those meshes are being cached by irrlicht, and need to be freed. */
|
||||
std::vector<scene::IMesh*> m_all_cached_meshes;
|
||||
|
||||
/**
|
||||
* m_all_cached_meshes assumes meshes are attached to a scene node.
|
||||
* This one assumes the mesh is NOT connected to any node.
|
||||
*/
|
||||
std::vector<scene::IMesh*> m_detached_cached_meshes;
|
||||
|
||||
/** A list of all textures loaded by the track, so that they can
|
||||
* be removed from the cache at cleanup time. */
|
||||
std::vector<video::ITexture*> m_all_cached_textures;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "io/file_manager.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "modes/overworld.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
@ -44,6 +45,8 @@ TrackObject::TrackObject(const XMLNode &xml_node)
|
||||
m_enabled = true;
|
||||
m_is_looped = false;
|
||||
m_sound = NULL;
|
||||
m_mesh = NULL;
|
||||
m_node = NULL;
|
||||
|
||||
xml_node.get("xyz", &m_init_xyz );
|
||||
xml_node.get("hpr", &m_init_hpr );
|
||||
@ -57,12 +60,12 @@ TrackObject::TrackObject(const XMLNode &xml_node)
|
||||
|
||||
xml_node.get("lod_group", &m_lod_group);
|
||||
|
||||
/** For sound effects */
|
||||
bool trigger_when_near = false;
|
||||
|
||||
/** For sound effects */
|
||||
float trigger_distance = 1.0f;
|
||||
std::string type;
|
||||
xml_node.get("type", &type );
|
||||
|
||||
bool trigger_when_near = false;
|
||||
float trigger_distance = 1.0f;
|
||||
|
||||
// FIXME: at this time sound emitters are just disabled in multiplayer
|
||||
// otherwise the sounds would be constantly heard
|
||||
if (sound.size() > 0 && race_manager->getNumLocalPlayers() == 1)
|
||||
@ -105,14 +108,27 @@ TrackObject::TrackObject(const XMLNode &xml_node)
|
||||
"[TrackObject] Sound emitter object could not be created\n");
|
||||
}
|
||||
}
|
||||
else if (type == "action-trigger")
|
||||
{
|
||||
trigger_when_near = true;
|
||||
|
||||
xml_node.get("distance", &trigger_distance);
|
||||
|
||||
xml_node.get("action", &m_action);
|
||||
|
||||
if (m_action.size() == 0)
|
||||
{
|
||||
fprintf(stderr, "[TrackObject] WARNING: action-trigger has no action defined\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Some animated objects (billboards, sound emitters)
|
||||
// Some animated objects (billboards, sound emitters, action triggers)
|
||||
// don't use this scene node
|
||||
if (model_name == "")
|
||||
{
|
||||
m_node = NULL;
|
||||
m_mesh = NULL;
|
||||
|
||||
|
||||
if (trigger_when_near)
|
||||
{
|
||||
item_manager->newItem(m_init_xyz, trigger_distance, this);
|
||||
@ -122,6 +138,7 @@ TrackObject::TrackObject(const XMLNode &xml_node)
|
||||
{
|
||||
std::string full_path =
|
||||
World::getWorld()->getTrack()->getTrackFile(model_name);
|
||||
|
||||
if(file_manager->fileExists(full_path))
|
||||
{
|
||||
m_mesh = irr_driver->getAnimatedMesh(full_path);
|
||||
@ -132,13 +149,11 @@ TrackObject::TrackObject(const XMLNode &xml_node)
|
||||
// in STK's model directory.
|
||||
full_path = file_manager->getModelFile(model_name);
|
||||
m_mesh = irr_driver->getAnimatedMesh(full_path);
|
||||
|
||||
if(!m_mesh)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Warning: '%s' in '%s' not found and is ignored.\n",
|
||||
xml_node.getName().c_str(), model_name.c_str());
|
||||
return;
|
||||
} // if(!m_mesh)
|
||||
throw std::runtime_error("Model '" + model_name + "' cannot be found");
|
||||
}
|
||||
}
|
||||
|
||||
m_mesh->grab();
|
||||
@ -295,4 +310,16 @@ void TrackObject::onTriggerItemApproached(Item* who)
|
||||
{
|
||||
m_sound->play();
|
||||
}
|
||||
else if (m_action.size() > 0)
|
||||
{
|
||||
if (m_action == "garage")
|
||||
{
|
||||
dynamic_cast<OverWorld*>(World::getWorld())->scheduleReturnToGarage();
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "[TrackObject] WARNING: unknown action <%s>\n",
|
||||
m_action.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,9 @@ protected:
|
||||
/** LOD group this object is part of, if it is LOD */
|
||||
std::string m_lod_group;
|
||||
|
||||
/** For action trigger objects */
|
||||
std::string m_action;
|
||||
|
||||
public:
|
||||
TrackObject(const XMLNode &xml_node);
|
||||
TrackObject(const core::vector3df& pos, const core::vector3df& hpr,
|
||||
|
@ -47,46 +47,58 @@ TrackObjectManager::~TrackObjectManager()
|
||||
*/
|
||||
void TrackObjectManager::add(const XMLNode &xml_node)
|
||||
{
|
||||
std::string groupname;
|
||||
xml_node.get("lod_group", &groupname);
|
||||
bool is_lod = !groupname.empty();
|
||||
|
||||
std::string type;
|
||||
xml_node.get("type", &type);
|
||||
if(type=="movable")
|
||||
try
|
||||
{
|
||||
if (is_lod)
|
||||
std::string groupname;
|
||||
xml_node.get("lod_group", &groupname);
|
||||
bool is_lod = !groupname.empty();
|
||||
|
||||
std::string type;
|
||||
xml_node.get("type", &type);
|
||||
if(type=="movable")
|
||||
{
|
||||
m_lod_objects[groupname].push_back(new PhysicalObject(xml_node));
|
||||
if (is_lod)
|
||||
{
|
||||
m_lod_objects[groupname].push_back(new PhysicalObject(xml_node));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_all_objects.push_back(new PhysicalObject(xml_node));
|
||||
}
|
||||
}
|
||||
else if(type=="animation")
|
||||
{
|
||||
if (is_lod)
|
||||
{
|
||||
m_lod_objects[groupname].push_back(new ThreeDAnimation(xml_node));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_all_objects.push_back(new ThreeDAnimation(xml_node));
|
||||
}
|
||||
}
|
||||
else if(type=="billboard")
|
||||
{
|
||||
m_all_objects.push_back(new BillboardAnimation(xml_node));
|
||||
}
|
||||
else if(type=="sfx-emitter")
|
||||
{
|
||||
m_all_objects.push_back(new TrackObject(xml_node));
|
||||
}
|
||||
else if(type=="action-trigger")
|
||||
{
|
||||
m_all_objects.push_back(new TrackObject(xml_node));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_all_objects.push_back(new PhysicalObject(xml_node));
|
||||
fprintf(stderr, "Unknown track object: '%s' - ignored.\n",
|
||||
type.c_str());
|
||||
}
|
||||
}
|
||||
else if(type=="animation")
|
||||
catch (std::exception& e)
|
||||
{
|
||||
if (is_lod)
|
||||
{
|
||||
m_lod_objects[groupname].push_back(new ThreeDAnimation(xml_node));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_all_objects.push_back(new ThreeDAnimation(xml_node));
|
||||
}
|
||||
}
|
||||
else if(type=="billboard")
|
||||
{
|
||||
m_all_objects.push_back(new BillboardAnimation(xml_node));
|
||||
}
|
||||
else if(type=="sfx-emitter")
|
||||
{
|
||||
m_all_objects.push_back(new TrackObject(xml_node));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Unknown track object: '%s' - ignored.\n",
|
||||
type.c_str());
|
||||
fprintf(stderr, "[TrackObjectManager] WARNING: Could not load track object. Reason : %s\n",
|
||||
e.what());
|
||||
}
|
||||
} // add
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user