Added preliminary easter-egg mode. It still needs a icon (battle mode

used atm), and a better easter egg model (atm bunny from snow mountain,
... whith turns out has lost the black nose). One track has easter eggs
added (math class).


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@12281 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2012-12-17 00:33:47 +00:00
parent 8202eb8f9e
commit 29be45b198
28 changed files with 500 additions and 114 deletions

BIN
data/gui/mode_easter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -9,5 +9,7 @@
handled as one, so list it here --> handled as one, so list it here -->
<bubblegum model="bubblegum.b3d" lowmodel="bubblegum-low.b3d" /> <bubblegum model="bubblegum.b3d" lowmodel="bubblegum-low.b3d" />
<bubblegum-nolok model="bubblegum-nolok.b3d" lowmodel="bubblegum-nolok-low.b3d"/> <bubblegum-nolok model="bubblegum-nolok.b3d" lowmodel="bubblegum-nolok-low.b3d"/>
<!-- <easter-egg model="easter_egg.b3d" /> -->
<easter-egg model="easter_egg.b3d" />
</items> </items>

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
data/models/easter_egg.b3d Normal file

Binary file not shown.

View File

@ -110,8 +110,9 @@
<powerup collect-mode="new"/> <powerup collect-mode="new"/>
<!-- time: How long a switch is being effective. <!-- time: How long a switch is being effective.
items for each item list the index of the item it is switched with. items for each item list the index of the item it is switched with.
Order: giftbox, banana, big-nitro, small-nitro, bubble-gum, trigger, nolok-bubble-gum --> Order: giftbox, banana, big-nitro, small-nitro, bubble-gum, trigger,
<switch time="5" items="1 0 4 4 2 5 2"/> nolok-bubble-gum, easter egg -->
<switch time="5" items="1 0 4 4 2 5 2 7"/>
<!-- How often bubble gum get driven over before it disappears. --> <!-- How often bubble gum get driven over before it disappears. -->
<bubble-gum disappear-counter="1"/> <bubble-gum disappear-counter="1"/>

View File

@ -121,6 +121,7 @@ src/main.cpp
src/main_loop.cpp src/main_loop.cpp
src/modes/cutscene_world.cpp src/modes/cutscene_world.cpp
src/modes/demo_world.cpp src/modes/demo_world.cpp
src/modes/easter_egg_hunt.cpp
src/modes/follow_the_leader.cpp src/modes/follow_the_leader.cpp
src/modes/game_tutorial.cpp src/modes/game_tutorial.cpp
src/modes/linear_world.cpp src/modes/linear_world.cpp
@ -367,6 +368,7 @@ src/karts/skidding_properties.hpp
src/main_loop.hpp src/main_loop.hpp
src/modes/cutscene_world.hpp src/modes/cutscene_world.hpp
src/modes/demo_world.hpp src/modes/demo_world.hpp
src/modes/easter_egg_hunt.hpp
src/modes/follow_the_leader.hpp src/modes/follow_the_leader.hpp
src/modes/game_tutorial.hpp src/modes/game_tutorial.hpp
src/modes/linear_world.hpp src/modes/linear_world.hpp

View File

@ -700,6 +700,10 @@
RelativePath="..\..\modes\demo_world.cpp" RelativePath="..\..\modes\demo_world.cpp"
> >
</File> </File>
<File
RelativePath="..\..\modes\easter_egg_hunt.cpp"
>
</File>
<File <File
RelativePath="..\..\modes\follow_the_leader.cpp" RelativePath="..\..\modes\follow_the_leader.cpp"
> >
@ -1886,6 +1890,10 @@
RelativePath="..\..\modes\demo_world.hpp" RelativePath="..\..\modes\demo_world.hpp"
> >
</File> </File>
<File
RelativePath="..\..\modes\easter_egg_hunt.hpp"
>
</File>
<File <File
RelativePath="..\..\modes\follow_the_leader.hpp" RelativePath="..\..\modes\follow_the_leader.hpp"
> >

View File

@ -24,6 +24,7 @@
#include "graphics/irr_driver.hpp" #include "graphics/irr_driver.hpp"
#include "graphics/lod_node.hpp" #include "graphics/lod_node.hpp"
#include "karts/abstract_kart.hpp" #include "karts/abstract_kart.hpp"
#include "modes/easter_egg_hunt.hpp"
#include "modes/three_strikes_battle.hpp" #include "modes/three_strikes_battle.hpp"
#include "modes/world.hpp" #include "modes/world.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
@ -109,10 +110,17 @@ void Item::initItem(ItemType type, const Vec3 &xyz)
m_deactive_time = 0; m_deactive_time = 0;
m_time_till_return = 0.0f; // not strictly necessary, see isCollected() m_time_till_return = 0.0f; // not strictly necessary, see isCollected()
m_emitter = NULL; m_emitter = NULL;
m_rotate = (type!=ITEM_BUBBLEGUM) && (type!=ITEM_TRIGGER); m_rotate = (type!=ITEM_BUBBLEGUM) && (type!=ITEM_TRIGGER) &&
m_disappear_counter = m_type==ITEM_BUBBLEGUM (type!=ITEM_EASTER_EGG);
? stk_config->m_bubble_gum_counter switch(m_type)
: -1 ; {
case ITEM_BUBBLEGUM:
m_disappear_counter = stk_config->m_bubble_gum_counter; break;
case ITEM_EASTER_EGG:
m_disappear_counter = -1; break;
default:
m_disappear_counter = -1;
}
// Now determine in which quad this item is, and its distance // Now determine in which quad this item is, and its distance
// from the center within this quad. // from the center within this quad.
m_graph_node = QuadGraph::UNKNOWN_SECTOR; m_graph_node = QuadGraph::UNKNOWN_SECTOR;
@ -236,9 +244,15 @@ void Item::reset()
m_collected = false; m_collected = false;
m_time_till_return = 0.0f; m_time_till_return = 0.0f;
m_deactive_time = 0.0f; m_deactive_time = 0.0f;
m_disappear_counter = m_type==ITEM_BUBBLEGUM switch(m_type)
? stk_config->m_bubble_gum_counter {
: -1 ; case ITEM_BUBBLEGUM:
m_disappear_counter = stk_config->m_bubble_gum_counter; break;
case ITEM_EASTER_EGG:
m_disappear_counter = -1; break;
default:
m_disappear_counter = -1;
}
if(m_original_type!=ITEM_NONE) if(m_original_type!=ITEM_NONE)
{ {
setType(m_original_type); setType(m_original_type);
@ -319,7 +333,18 @@ void Item::collected(const AbstractKart *kart, float t)
{ {
m_collected = true; m_collected = true;
m_event_handler = kart; m_event_handler = kart;
if(m_type==ITEM_BUBBLEGUM && m_disappear_counter>0) if(m_type==ITEM_EASTER_EGG)
{
m_time_till_return=99999;
EasterEggHunt *world = dynamic_cast<EasterEggHunt*>(World::getWorld());
assert(world);
world->collectedEasterEgg(kart);
if (m_node != NULL)
{
m_node->setVisible(false);
}
}
else if(m_type==ITEM_BUBBLEGUM && m_disappear_counter>0)
{ {
m_disappear_counter --; m_disappear_counter --;
// Deactivates the item for a certain amount of time. It is used to // Deactivates the item for a certain amount of time. It is used to

View File

@ -74,6 +74,8 @@ public:
ITEM_BUBBLEGUM, ITEM_BUBBLEGUM,
ITEM_BUBBLEGUM_NOLOK, ITEM_BUBBLEGUM_NOLOK,
/** For easter egg mode only. */
ITEM_EASTER_EGG,
/** An invisible item that can be used to trigger some behavior when /** An invisible item that can be used to trigger some behavior when
* approaching a point * approaching a point
*/ */

View File

@ -77,8 +77,8 @@ void ItemManager::loadDefaultItemMeshes()
item_names[Item::ITEM_NITRO_BIG ] = "nitro-big"; item_names[Item::ITEM_NITRO_BIG ] = "nitro-big";
item_names[Item::ITEM_NITRO_SMALL] = "nitro-small"; item_names[Item::ITEM_NITRO_SMALL] = "nitro-small";
item_names[Item::ITEM_TRIGGER ] = "trigger"; item_names[Item::ITEM_TRIGGER ] = "trigger";
item_names[Item::ITEM_BUBBLEGUM_NOLOK] = "bubblegum-nolok"; item_names[Item::ITEM_BUBBLEGUM_NOLOK] = "bubblegum-nolok";
item_names[Item::ITEM_EASTER_EGG ] = "easter-egg";
const std::string file_name = file_manager->getDataFile("items.xml"); const std::string file_name = file_manager->getDataFile("items.xml");
const XMLNode *root = file_manager->createXMLTree(file_name); const XMLNode *root = file_manager->createXMLTree(file_name);

View File

@ -85,7 +85,7 @@ void ProjectileManager::update(float dt)
he = next; he = next;
} }
// Update this hit effect. If it can be removed, remove it. // Update this hit effect. If it can be removed, remove it.
if((*he)->updateAndDelete(dt)) else if((*he)->updateAndDelete(dt))
{ {
delete *he; delete *he;
HitEffects::iterator next = m_active_hit_effects.erase(he); HitEffects::iterator next = m_active_hit_effects.erase(he);

View File

@ -27,13 +27,7 @@ float AIProperties::UNDEFINED = -99.9f;
*/ */
AIProperties::AIProperties(RaceManager::Difficulty difficulty) AIProperties::AIProperties(RaceManager::Difficulty difficulty)
{ {
switch(difficulty) m_ident = race_manager->getDifficultyAsString(difficulty);
{
case RaceManager::DIFFICULTY_EASY: m_ident="easy"; break;
case RaceManager::DIFFICULTY_MEDIUM: m_ident="medium"; break;
case RaceManager::DIFFICULTY_HARD: m_ident="hard"; break;
default: m_ident=""; break;
}
m_max_item_angle = UNDEFINED; m_max_item_angle = UNDEFINED;
m_max_item_angle_high_speed = UNDEFINED; m_max_item_angle_high_speed = UNDEFINED;

View File

@ -69,6 +69,9 @@ void Moveable::updateGraphics(float dt, const Vec3& offset_xyz,
Vec3 xyz=getXYZ()+offset_xyz; Vec3 xyz=getXYZ()+offset_xyz;
m_node->setPosition(xyz.toIrrVector()); m_node->setPosition(xyz.toIrrVector());
btQuaternion r_all = getRotation()*rotation; btQuaternion r_all = getRotation()*rotation;
if(btFuzzyZero(r_all.getX()) && btFuzzyZero(r_all.getY()-0.70710677f) &&
btFuzzyZero(r_all.getZ()) && btFuzzyZero(r_all.getW()-0.70710677f) )
r_all.setX(0.000001f);
Vec3 hpr; Vec3 hpr;
hpr.setHPR(r_all); hpr.setHPR(r_all);
m_node->setRotation(hpr.toIrrHPR()); m_node->setRotation(hpr.toIrrHPR());

View File

@ -0,0 +1,203 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2012 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "modes/easter_egg_hunt.hpp"
#include "io/file_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "tracks/track.hpp"
//-----------------------------------------------------------------------------
/** Constructor. Sets up the clock mode etc.
*/
EasterEggHunt::EasterEggHunt() : WorldWithRank()
{
WorldStatus::setClockMode(CLOCK_CHRONO);
m_use_highscores = false;
m_eggs_found = 0;
} // EasterEggHunt
//-----------------------------------------------------------------------------
/** Initialises the easer egg hunt.
*/
void EasterEggHunt::init()
{
WorldWithRank::init();
m_display_rank = false;
// check for possible problems if AI karts were incorrectly added
if(getNumKarts() > race_manager->getNumPlayers())
{
fprintf(stderr, "No AI exists for this game mode\n");
exit(1);
}
const unsigned int kart_amount = m_karts.size();
m_eggs_collected.resize(m_karts.size(), 0);
} // EasterEggHunt
//-----------------------------------------------------------------------------
/** Destructor. Clears all internal data structures, and removes the tire mesh
* from the mesh cache.
*/
EasterEggHunt::~EasterEggHunt()
{
} // ~EasterEggHunt
//-----------------------------------------------------------------------------
/** Check if a file easter_eggs.xml exists in the track directory, and if so
* loads that file and makes the easter egg mode available for this track.
*/
void EasterEggHunt::readData(const std::string &filename)
{
XMLNode *easter = file_manager->createXMLTree(filename);
if(!easter)
return;
if(easter->getName()!="EasterEggHunt")
{
printf("Can't load easter egg file '%s' - no EasterEggHunt element.",
filename);
delete easter;
return;
}
const XMLNode *data = NULL;
std::string difficulty_name;
RaceManager::Difficulty diff = race_manager->getDifficulty();
for(unsigned int i=0; i<RaceManager::DIFFICULTY_COUNT; i++)
{
difficulty_name = race_manager->getDifficultyAsString(diff);
data = easter->getNode(difficulty_name);
if(data) break;
diff = (RaceManager::Difficulty)(diff+1);
if(diff==RaceManager::DIFFICULTY_LAST)
diff = RaceManager::DIFFICULTY_FIRST;
}
if(!data)
{
delete easter;
return;
}
m_time_limit = 9999;
data->get("time-limit", &m_time_limit);
m_number_of_eggs = 0;
for(unsigned int i=0; i<data->getNumNodes(); i++)
{
const XMLNode *egg = data->getNode(i);
if(egg->getName()!="easter-egg")
{
printf("Unknown node '%s' in easter egg level '%s' - ignored.\n",
egg->getName().c_str(), difficulty_name.c_str());
continue;
}
World::getTrack()->itemCommand(egg);
m_number_of_eggs++;
} // for i <num_nodes
delete easter;
WorldStatus::setClockMode(CLOCK_CHRONO, m_time_limit);
} // readEasterEggInfo
//-----------------------------------------------------------------------------
/** Returns the internal identifier for this race.
*/
const std::string& EasterEggHunt::getIdent() const
{
return IDENT_EASTER;
} // getIdent
//-----------------------------------------------------------------------------
/** Called when a kart has collected an egg.
* \param kart The kart that collected an egg.
*/
void EasterEggHunt::collectedEasterEgg(const AbstractKart *kart)
{
m_eggs_collected[kart->getWorldKartId()]++;
m_eggs_found++;
} // collectedEasterEgg
//-----------------------------------------------------------------------------
/** Update the world and the track.
* \param dt Time step size.
*/
void EasterEggHunt::update(float dt)
{
WorldWithRank::update(dt);
WorldWithRank::updateTrack(dt);
} // update
//-----------------------------------------------------------------------------
/** The hunt is over once all eggs are found.
*/
bool EasterEggHunt::isRaceOver()
{
if(m_eggs_found == m_number_of_eggs)
return true;
if(m_time<0)
return true;
return false;
} // isRaceOver
//-----------------------------------------------------------------------------
/** Called then a battle is restarted.
*/
void EasterEggHunt::restartRace()
{
WorldWithRank::restartRace();
for(unsigned int i=0; i<m_eggs_collected.size(); i++)
m_eggs_collected[i] = 0;
m_eggs_found = 0;
} // restartRace
//-----------------------------------------------------------------------------
/** Returns the data to display in the race gui.
*/
void EasterEggHunt::getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info)
{
const unsigned int kart_amount = getNumKarts();
for(unsigned int i = 0; i < kart_amount ; i++)
{
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
std::ostringstream o;
//I18n: number of collected eggs / overall number of eggs
rank_info.m_text = StringUtils::insertValues(_("Eggs: %d / %d"),
m_eggs_collected[i],
m_number_of_eggs);
rank_info.m_color = video::SColor(255, 255, 255, 255);
}
} // getKartDisplayInfo
//-----------------------------------------------------------------------------
/** Moves a kart to its rescue position.
* \param kart The kart that was rescued.
*/
void EasterEggHunt::moveKartAfterRescue(AbstractKart* kart)
{
int start_position = kart->getInitialPosition();
btTransform start_pos = getTrack()->getStartTransform(start_position-1);
kart->getBody()->setCenterOfMassTransform(start_pos);
} // moveKartAfterRescue

74
src/modes/easter_egg_hunt.hpp Executable file
View File

@ -0,0 +1,74 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2012 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef EASTER_EGG_HUNT_HPP
#define EASTER_EGG_HUNT_HPP
#include "modes/world_with_rank.hpp"
#include "states_screens/race_gui_base.hpp"
#include <string>
#include <vector>
class AbstractKart;
/**
* \brief An implementation of World to provide an easter egg hunt like mode
* \ingroup modes
*/
class EasterEggHunt: public WorldWithRank
{
private:
/** Keeps track of how many eggs each kart has found. */
std::vector<int> m_eggs_collected;
/** A time limit for the hunt. */
float m_time_limit;
/** Overall number of easter eggs. */
int m_number_of_eggs;
/** Number of eggs found so far. */
int m_eggs_found;
public:
EasterEggHunt();
virtual ~EasterEggHunt();
virtual void init();
virtual bool isRaceOver();
// overriding World methods
virtual void restartRace();
virtual bool raceHasLaps(){ return false; }
virtual void moveKartAfterRescue(AbstractKart* kart);
virtual const std::string& getIdent() const;
virtual void update(float dt);
virtual void getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info);
void updateKartRanks();
void collectedEasterEgg(const AbstractKart *kart);
void readData(const std::string &filename);
}; // EasterEggHunt
#endif

View File

@ -422,9 +422,7 @@ void LinearWorld::getKartsDisplayInfo(
AbstractKart* kart = m_karts[i]; AbstractKart* kart = m_karts[i];
// reset color // reset color
rank_info.r = 1.0; rank_info.m_color = video::SColor(255, 255, 255, 255);
rank_info.g = 1.0;
rank_info.b = 1.0;
rank_info.lap = -1; rank_info.lap = -1;
if(kart->isEliminated()) continue; if(kart->isEliminated()) continue;
@ -486,12 +484,15 @@ void LinearWorld::getKartsDisplayInfo(
if(kart_info.m_race_lap>=numLaps) if(kart_info.m_race_lap>=numLaps)
{ // kart is finished, display in green { // kart is finished, display in green
rank_info.g = rank_info.b = 0; rank_info.m_color.setGreen(0);
rank_info.m_color.setBlue(0);
} }
else if(kart_info.m_race_lap>=0 && numLaps>1) else if(kart_info.m_race_lap>=0 && numLaps>1)
{ {
rank_info.g = rank_info.b = int col = (int)(255*(1.0f-(float)kart_info.m_race_lap
1.0f-(float)kart_info.m_race_lap/((float)numLaps-1.0f); /((float)numLaps-1.0f) ));
rank_info.m_color.setBlue(col);
rank_info.m_color.setGreen(col);
} }
} // next kart } // next kart
@ -561,22 +562,15 @@ void LinearWorld::moveKartAfterRescue(AbstractKart* kart)
info.getSector()->rescue(); info.getSector()->rescue();
int sector = info.getSector()->getCurrentGraphNode(); int sector = info.getSector()->getCurrentGraphNode();
kart->setXYZ( QuadGraph::get()
->getQuadOfNode(sector).getCenter());
btQuaternion heading(btVector3(0.0f, 1.0f, 0.0f),
m_track->getAngle(sector) );
kart->setRotation(heading);
// A certain epsilon is added here to the Z coordinate, in case // A certain epsilon is added here to the Z coordinate, in case
// that the drivelines are somewhat under the track. Otherwise, the // that the drivelines are somewhat under the track. Otherwise, the
// kart might be placed a little bit under the track, triggering // kart might be placed a little bit under the track, triggering
// a rescue, ... (experimentally found value) // a rescue, ... (experimentally found value)
float epsilon = 0.5f * kart->getKartHeight(); float epsilon = 0.5f * kart->getKartHeight();
const Vec3 &xyz = QuadGraph::get()->getQuadOfNode(sector).getCenter();
btTransform pos; btTransform pos;
pos.setOrigin(kart->getXYZ()+btVector3(0, kart->getKartHeight() + epsilon, pos.setOrigin(xyz+btVector3(0, kart->getKartHeight() + epsilon,0));
0));
pos.setRotation(btQuaternion(btVector3(0.0f, 1.0f, 0.0f), pos.setRotation(btQuaternion(btVector3(0.0f, 1.0f, 0.0f),
m_track->getAngle(sector))); m_track->getAngle(sector)));

View File

@ -438,24 +438,16 @@ void ThreeStrikesBattle::getKartsDisplayInfo(
switch(m_kart_info[i].m_lives) switch(m_kart_info[i].m_lives)
{ {
case 3: case 3:
rank_info.r = 0.0; rank_info.m_color = video::SColor(255, 0, 255, 0);
rank_info.g = 1.0;
rank_info.b = 0.0;
break; break;
case 2: case 2:
rank_info.r = 1.0; rank_info.m_color = video::SColor(255, 255, 229, 0);
rank_info.g = 0.9f;
rank_info.b = 0.0;
break; break;
case 1: case 1:
rank_info.r = 1.0; rank_info.m_color = video::SColor(255, 255, 0, 0);
rank_info.g = 0.0;
rank_info.b = 0.0;
break; break;
case 0: case 0:
rank_info.r = 0.5; rank_info.m_color = video::SColor(128, 128, 128, 0);
rank_info.g = 0.5;
rank_info.b = 0.5;
break; break;
} }

View File

@ -138,7 +138,7 @@ void World::init()
// Load the track models - this must be done before the karts so that the // Load the track models - this must be done before the karts so that the
// karts can be positioned properly on (and not in) the tracks. // karts can be positioned properly on (and not in) the tracks.
m_track->loadTrackModel(this, race_manager->getReverseTrack()); m_track->loadTrackModel(race_manager->getReverseTrack());
for(unsigned int i=0; i<num_karts; i++) for(unsigned int i=0; i<num_karts; i++)
{ {

View File

@ -32,6 +32,7 @@
#include "karts/kart_properties_manager.hpp" #include "karts/kart_properties_manager.hpp"
#include "modes/cutscene_world.hpp" #include "modes/cutscene_world.hpp"
#include "modes/demo_world.hpp" #include "modes/demo_world.hpp"
#include "modes/easter_egg_hunt.hpp"
#include "modes/follow_the_leader.hpp" #include "modes/follow_the_leader.hpp"
#include "modes/overworld.hpp" #include "modes/overworld.hpp"
#include "modes/profile_world.hpp" #include "modes/profile_world.hpp"
@ -394,6 +395,8 @@ void RaceManager::startNextRace()
World::setWorld(new OverWorld()); World::setWorld(new OverWorld());
else if(m_minor_mode==MINOR_MODE_CUTSCENE) else if(m_minor_mode==MINOR_MODE_CUTSCENE)
World::setWorld(new CutsceneWorld()); World::setWorld(new CutsceneWorld());
else if(m_minor_mode==MINOR_MODE_EASTER_EGG)
World::setWorld(new EasterEggHunt());
else else
{ {
fprintf(stderr,"Could not create given race mode\n"); fprintf(stderr,"Could not create given race mode\n");

View File

@ -42,6 +42,7 @@ static const std::string IDENT_STD ("STANDARD" );
static const std::string IDENT_TTRIAL ("STD_TIMETRIAL" ); static const std::string IDENT_TTRIAL ("STD_TIMETRIAL" );
static const std::string IDENT_FTL ("FOLLOW_LEADER" ); static const std::string IDENT_FTL ("FOLLOW_LEADER" );
static const std::string IDENT_STRIKES ("BATTLE_3_STRIKES"); static const std::string IDENT_STRIKES ("BATTLE_3_STRIKES");
static const std::string IDENT_EASTER ("EASTER_EGG_HUNT");
static const std::string IDENT_OVERWORLD("OVERWORLD" ); static const std::string IDENT_OVERWORLD("OVERWORLD" );
static const std::string IDENT_CUSTSCENE("CUTSCENE" ); static const std::string IDENT_CUSTSCENE("CUTSCENE" );
@ -94,6 +95,7 @@ public:
// issues // issues
#define LINEAR_RACE(ID, COUNT_LAPSES) (1000+ID+100*COUNT_LAPSES) #define LINEAR_RACE(ID, COUNT_LAPSES) (1000+ID+100*COUNT_LAPSES)
#define BATTLE_ARENA(ID) (2000+ID) #define BATTLE_ARENA(ID) (2000+ID)
#define EASTER_EGG(ID) (3000+ID)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Minor variants to the major types of race. /** Minor variants to the major types of race.
@ -108,7 +110,9 @@ public:
MINOR_MODE_OVERWORLD = LINEAR_RACE(3, false), MINOR_MODE_OVERWORLD = LINEAR_RACE(3, false),
MINOR_MODE_3_STRIKES = BATTLE_ARENA(0), MINOR_MODE_3_STRIKES = BATTLE_ARENA(0),
MINOR_MODE_CUTSCENE = BATTLE_ARENA(1) MINOR_MODE_CUTSCENE = BATTLE_ARENA(1),
MINOR_MODE_EASTER_EGG = EASTER_EGG(0)
}; };
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -132,6 +136,7 @@ public:
case MINOR_MODE_TIME_TRIAL: return IDENT_TTRIAL; case MINOR_MODE_TIME_TRIAL: return IDENT_TTRIAL;
case MINOR_MODE_FOLLOW_LEADER: return IDENT_FTL; case MINOR_MODE_FOLLOW_LEADER: return IDENT_FTL;
case MINOR_MODE_3_STRIKES: return IDENT_STRIKES; case MINOR_MODE_3_STRIKES: return IDENT_STRIKES;
case MINOR_MODE_EASTER_EGG: return IDENT_EASTER;
default: assert(false); default: assert(false);
return IDENT_STD; // stop compiler warning return IDENT_STD; // stop compiler warning
} }
@ -149,6 +154,7 @@ public:
case MINOR_MODE_TIME_TRIAL: return "/gui/mode_tt.png"; case MINOR_MODE_TIME_TRIAL: return "/gui/mode_tt.png";
case MINOR_MODE_FOLLOW_LEADER: return "/gui/mode_ftl.png"; case MINOR_MODE_FOLLOW_LEADER: return "/gui/mode_ftl.png";
case MINOR_MODE_3_STRIKES: return "/gui/mode_3strikes.png"; case MINOR_MODE_3_STRIKES: return "/gui/mode_3strikes.png";
case MINOR_MODE_EASTER_EGG: return "/gui/mode_easter.png";
default: assert(false); return NULL; default: assert(false); return NULL;
} }
} // getIconOf } // getIconOf
@ -169,6 +175,7 @@ public:
case MINOR_MODE_FOLLOW_LEADER: return _("Follow the Leader"); case MINOR_MODE_FOLLOW_LEADER: return _("Follow the Leader");
//I18N: Game mode //I18N: Game mode
case MINOR_MODE_3_STRIKES: return _("3 Strikes Battle"); case MINOR_MODE_3_STRIKES: return _("3 Strikes Battle");
case MINOR_MODE_EASTER_EGG: return _("Easter Egg Hunt");
default: assert(false); return NULL; default: assert(false); return NULL;
} }
} }
@ -182,6 +189,7 @@ public:
case MINOR_MODE_TIME_TRIAL: return true; case MINOR_MODE_TIME_TRIAL: return true;
case MINOR_MODE_FOLLOW_LEADER: return true; case MINOR_MODE_FOLLOW_LEADER: return true;
case MINOR_MODE_3_STRIKES: return false; case MINOR_MODE_3_STRIKES: return false;
case MINOR_MODE_EASTER_EGG: return false;
default: assert(false); return NULL; default: assert(false); return NULL;
} }
} }
@ -199,6 +207,7 @@ public:
else if (name==IDENT_TTRIAL ) return MINOR_MODE_TIME_TRIAL; else if (name==IDENT_TTRIAL ) return MINOR_MODE_TIME_TRIAL;
else if (name==IDENT_FTL ) return MINOR_MODE_FOLLOW_LEADER; else if (name==IDENT_FTL ) return MINOR_MODE_FOLLOW_LEADER;
else if (name==IDENT_STRIKES) return MINOR_MODE_3_STRIKES; else if (name==IDENT_STRIKES) return MINOR_MODE_3_STRIKES;
else if (name==IDENT_EASTER ) return MINOR_MODE_EASTER_EGG;
assert(0); assert(0);
return MINOR_MODE_NONE; return MINOR_MODE_NONE;
@ -209,8 +218,10 @@ public:
/** Game difficulty. */ /** Game difficulty. */
enum Difficulty { DIFFICULTY_EASY, enum Difficulty { DIFFICULTY_EASY,
DIFFICULTY_FIRST = DIFFICULTY_EASY,
DIFFICULTY_MEDIUM, DIFFICULTY_MEDIUM,
DIFFICULTY_HARD, DIFFICULTY_HARD,
DIFFICULTY_LAST = DIFFICULTY_HARD,
DIFFICULTY_COUNT}; DIFFICULTY_COUNT};
/** Different kart types: A local player, a player connected via network, /** Different kart types: A local player, a player connected via network,
@ -467,8 +478,21 @@ public:
/** \return whether the track should be reversed */ /** \return whether the track should be reversed */
bool getReverseTrack() const { return m_reverse_track[m_track_number]; } bool getReverseTrack() const { return m_reverse_track[m_track_number]; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the difficulty. */
Difficulty getDifficulty() const { return m_difficulty; } Difficulty getDifficulty() const { return m_difficulty; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the specified difficulty as a string. */
std::string getDifficultyAsString(Difficulty diff) const
{
switch(diff)
{
case RaceManager::DIFFICULTY_EASY: return "easy"; break;
case RaceManager::DIFFICULTY_MEDIUM: return "medium"; break;
case RaceManager::DIFFICULTY_HARD: return "hard"; break;
}
return "";
} // getDifficultyAsString
// ------------------------------------------------------------------------
const std::string& getTrackName() const { return m_tracks[m_track_number];} const std::string& getTrackName() const { return m_tracks[m_track_number];}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
const GrandPrixData *getGrandPrix() const { return &m_grand_prix; } const GrandPrixData *getGrandPrix() const { return &m_grand_prix; }

View File

@ -72,7 +72,7 @@ RacePausedDialog::~RacePausedDialog()
void RacePausedDialog::loadedFromFile() void RacePausedDialog::loadedFromFile()
{ {
// disable the "restart" button in GPs // disable the "restart" button in GPs
if (race_manager->getMajorMode() != RaceManager::MAJOR_MODE_SINGLE) if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
{ {
GUIEngine::RibbonWidget* choice_ribbon = GUIEngine::RibbonWidget* choice_ribbon =
getWidget<GUIEngine::RibbonWidget>("choiceribbon"); getWidget<GUIEngine::RibbonWidget>("choiceribbon");

View File

@ -807,7 +807,8 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
int lap = info.lap; int lap = info.lap;
// In battle mode there is no distance along track etc. // In battle mode there is no distance along track etc.
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES) if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES ||
race_manager->getMinorMode()==RaceManager::MINOR_MODE_EASTER_EGG)
{ {
x = x_base; x = x_base;
y = previous_y+ICON_PLAYER_WIDTH+2; y = previous_y+ICON_PLAYER_WIDTH+2;
@ -870,15 +871,12 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
if (m_kart_display_infos[kart_id].m_text.size() > 0) if (m_kart_display_infos[kart_id].m_text.size() > 0)
{ {
video::SColor color = video::SColor(255,
(int)(255*info.r),
(int)(255*info.g),
(int)(255*info.b) );
core::rect<s32> pos(x+ICON_PLAYER_WIDTH, y+5, core::rect<s32> pos(x+ICON_PLAYER_WIDTH, y+5,
x+ICON_PLAYER_WIDTH, y+5); x+ICON_PLAYER_WIDTH, y+5);
core::stringw s=info.m_text.c_str(); core::stringw s=info.m_text.c_str();
font->draw(s.c_str(), pos, color, false, false, NULL, true /* ignore RTL */); font->draw(s.c_str(), pos, info.m_color, false, false, NULL,
true /* ignore RTL */);
} }
if (info.special_title.size() > 0) if (info.special_title.size() > 0)
@ -887,7 +885,8 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
core::rect<s32> pos(x+ICON_PLAYER_WIDTH, y+5, core::rect<s32> pos(x+ICON_PLAYER_WIDTH, y+5,
x+ICON_PLAYER_WIDTH, y+5); x+ICON_PLAYER_WIDTH, y+5);
core::stringw s(info.special_title.c_str()); core::stringw s(info.special_title.c_str());
font->draw(s.c_str(), pos, color, false, false, NULL, true /* ignore RTL */); font->draw(s.c_str(), pos, info.m_color, false, false, NULL,
true /* ignore RTL */);
} }
// draw icon // draw icon

View File

@ -53,16 +53,16 @@ public:
*/ */
struct KartIconDisplayInfo struct KartIconDisplayInfo
{ {
/** text to display next to icon, if any */ /** Text to display next to icon, if any. */
core::stringw m_text; core::stringw m_text;
/** text color, if any text */ /** Text color, if any text. */
float r, g, b; video::SColor m_color;
/** if this kart has a special title, e.g. "leader" in follow-the-leader */ /** If this kart has a special title, e.g. "leader" in follow-the-leader. */
core::stringw special_title; core::stringw special_title;
/** Current lap of this kart, or -1 if irrelevant */ /** Current lap of this kart, or -1 if irrelevant. */
int lap; int lap;
}; // KartIconDisplayInfo }; // KartIconDisplayInfo

View File

@ -33,6 +33,7 @@ const int CONFIG_CODE_NORMAL = 0;
const int CONFIG_CODE_TIMETRIAL = 1; const int CONFIG_CODE_TIMETRIAL = 1;
const int CONFIG_CODE_FTL = 2; const int CONFIG_CODE_FTL = 2;
const int CONFIG_CODE_3STRIKES = 3; const int CONFIG_CODE_3STRIKES = 3;
const int CONFIG_CODE_EASTER = 4;
using namespace GUIEngine; using namespace GUIEngine;
DEFINE_SCREEN_SINGLETON( RaceSetupScreen ); DEFINE_SCREEN_SINGLETON( RaceSetupScreen );
@ -53,19 +54,19 @@ public:
// game mode changed!! // game mode changed!!
m_parent->onGameModeChanged(); m_parent->onGameModeChanged();
} }
}; }; // GameModeRibbonListener
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
RaceSetupScreen::RaceSetupScreen() : Screen("racesetup.stkgui") RaceSetupScreen::RaceSetupScreen() : Screen("racesetup.stkgui")
{ {
} } // RaceSetupScreen
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void RaceSetupScreen::loadedFromFile() void RaceSetupScreen::loadedFromFile()
{ {
} } // loadedFromFile
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -127,6 +128,13 @@ void RaceSetupScreen::eventCallback(Widget* widget, const std::string& name, con
race_manager->setNumKarts( race_manager->getNumLocalPlayers() ); // no AI karts; race_manager->setNumKarts( race_manager->getNumLocalPlayers() ); // no AI karts;
StateManager::get()->pushScreen( ArenasScreen::getInstance() ); StateManager::get()->pushScreen( ArenasScreen::getInstance() );
} }
else if (selectedMode == IDENT_EASTER)
{
race_manager->setMinorMode(RaceManager::MINOR_MODE_EASTER_EGG);
UserConfigParams::m_game_mode = CONFIG_CODE_EASTER;
race_manager->setNumKarts( race_manager->getNumLocalPlayers() ); // no AI karts;
StateManager::get()->pushScreen( TracksScreen::getInstance() );
}
else if (selectedMode == "locked") else if (selectedMode == "locked")
{ {
unlock_manager->playLockSound(); unlock_manager->playLockSound();
@ -142,7 +150,7 @@ void RaceSetupScreen::eventCallback(Widget* widget, const std::string& name, con
{ {
StateManager::get()->escapePressed(); StateManager::get()->escapePressed();
} }
} } // eventCallback
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -167,7 +175,7 @@ void RaceSetupScreen::onGameModeChanged()
{ {
kartamount->setActivated(); kartamount->setActivated();
} }
} } // onGameModeChanged
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -228,7 +236,15 @@ void RaceSetupScreen::init()
name4 += _("Hit others with weapons until they lose all their lives. (Only in multiplayer games)"); name4 += _("Hit others with weapons until they lose all their lives. (Only in multiplayer games)");
w2->addItem( name4, IDENT_STRIKES, RaceManager::getIconOf(RaceManager::MINOR_MODE_3_STRIKES)); w2->addItem( name4, IDENT_STRIKES, RaceManager::getIconOf(RaceManager::MINOR_MODE_3_STRIKES));
} }
{
irr::core::stringw name1 = irr::core::stringw(
RaceManager::getNameOf(RaceManager::MINOR_MODE_EASTER_EGG)) + L"\n";
//FIXME: avoid duplicating descriptions from the help menu!
name1 += _("Find all Easter Eggs");
w2->addItem( name1, IDENT_EASTER,
RaceManager::getIconOf(RaceManager::MINOR_MODE_EASTER_EGG));
}
w2->updateItemDisplay(); w2->updateItemDisplay();
@ -247,10 +263,13 @@ void RaceSetupScreen::init()
case CONFIG_CODE_3STRIKES : case CONFIG_CODE_3STRIKES :
w2->setSelection(IDENT_STRIKES, PLAYER_ID_GAME_MASTER, true); w2->setSelection(IDENT_STRIKES, PLAYER_ID_GAME_MASTER, true);
break; break;
case CONFIG_CODE_EASTER :
w2->setSelection(IDENT_EASTER, PLAYER_ID_GAME_MASTER, true);
break;
} }
m_mode_listener = new GameModeRibbonListener(this); m_mode_listener = new GameModeRibbonListener(this);
w2->registerHoverListener(m_mode_listener); w2->registerHoverListener(m_mode_listener);
} } // init
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -286,6 +286,9 @@ void TracksScreen::buildTrackList()
for (int n=0; n<trackAmount; n++) for (int n=0; n<trackAmount; n++)
{ {
Track* curr = track_manager->getTrack( n ); Track* curr = track_manager->getTrack( n );
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_EASTER_EGG
&& !curr->hasEasterEggs())
continue;
if (curr->isArena()) continue; if (curr->isArena()) continue;
if (curr->isInternal()) continue; if (curr->isInternal()) continue;
@ -313,6 +316,9 @@ void TracksScreen::buildTrackList()
for (int n=0; n<trackAmount; n++) for (int n=0; n<trackAmount; n++)
{ {
Track* curr = track_manager->getTrack( curr_group[n] ); Track* curr = track_manager->getTrack( curr_group[n] );
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_EASTER_EGG
&& !curr->hasEasterEggs())
continue;
if (curr->isArena()) continue; if (curr->isArena()) continue;
if (curr->isInternal()) continue; if (curr->isInternal()) continue;

View File

@ -60,8 +60,12 @@ void CheckLap::reset(const Track &track)
bool CheckLap::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, int indx) bool CheckLap::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, int indx)
{ {
float track_length = World::getWorld()->getTrack()->getTrackLength(); float track_length = World::getWorld()->getTrack()->getTrackLength();
float current_distance = LinearWorld *lin_world = dynamic_cast<LinearWorld*>(World::getWorld());
((LinearWorld*)World::getWorld())->getDistanceDownTrackForKart(indx); // Can happen if a non-lap based race mode is used with a scene file that
// has check defined.
if(!lin_world)
return false;
float current_distance = lin_world->getDistanceDownTrackForKart(indx);
bool result =(m_previous_distance[indx]>0.95f*track_length && bool result =(m_previous_distance[indx]>0.95f*track_length &&
current_distance<7.0f); current_distance<7.0f);
if(UserConfigParams::m_check_debug && result) if(UserConfigParams::m_check_debug && result)

View File

@ -47,6 +47,7 @@ using namespace irr;
#include "items/item.hpp" #include "items/item.hpp"
#include "items/item_manager.hpp" #include "items/item_manager.hpp"
#include "modes/linear_world.hpp" #include "modes/linear_world.hpp"
#include "modes/easter_egg_hunt.hpp"
#include "modes/world.hpp" #include "modes/world.hpp"
#include "physics/physical_object.hpp" #include "physics/physical_object.hpp"
#include "physics/physics.hpp" #include "physics/physics.hpp"
@ -92,6 +93,7 @@ Track::Track(const std::string &filename)
m_enable_push_back = true; m_enable_push_back = true;
m_reverse_available = false; m_reverse_available = false;
m_is_arena = false; m_is_arena = false;
m_has_easter_eggs = false;
m_is_cutscene = false; m_is_cutscene = false;
m_camera_far = 1000.0f; m_camera_far = 1000.0f;
m_mini_map = NULL; m_mini_map = NULL;
@ -354,6 +356,9 @@ void Track::loadTrackInfo()
m_screenshot = m_root+"/"+m_screenshot; m_screenshot = m_root+"/"+m_screenshot;
delete root; delete root;
std::string dir = StringUtils::getPath(m_filename);
std::string easter_name = dir+"/easter_eggs.xml";
m_has_easter_eggs = file_manager->fileExists(easter_name);
} // loadTrackInfo } // loadTrackInfo
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1238,9 +1243,7 @@ void Track::createWater(const XMLNode &node)
* \param mode_id Which of the modes of a track to use. This determines which * \param mode_id Which of the modes of a track to use. This determines which
* scene, quad, and graph file to load. * scene, quad, and graph file to load.
*/ */
void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
void Track::loadTrackModel(World* parent, bool reverse_track,
unsigned int mode_id )
{ {
if(!m_reverse_available) if(!m_reverse_available)
{ {
@ -1390,7 +1393,8 @@ void Track::loadTrackModel(World* parent, bool reverse_track,
createWater(*node); createWater(*node);
} }
else if(name=="banana" || name=="item" || else if(name=="banana" || name=="item" ||
name=="small-nitro" || name=="big-nitro") name=="small-nitro" || name=="big-nitro" ||
name=="easter-egg" )
{ {
// will be handled later // will be handled later
} }
@ -1420,6 +1424,8 @@ void Track::loadTrackModel(World* parent, bool reverse_track,
} }
else if(name=="checks") else if(name=="checks")
{ {
// Easter egg hunts don't have laps.
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_EASTER_EGG)
CheckManager::get()->load(*node); CheckManager::get()->load(*node);
} }
else if (name=="particle-emitter") else if (name=="particle-emitter")
@ -1573,8 +1579,8 @@ void Track::loadTrackModel(World* parent, bool reverse_track,
} }
else if(m_sky_type==SKY_COLOR) else if(m_sky_type==SKY_COLOR)
{ {
parent->setClearBackBuffer(true); World::getWorld()->setClearBackBuffer(true);
parent->setClearbackBufferColor(m_sky_color); World::getWorld()->setClearbackBufferColor(m_sky_color);
} }
@ -1609,25 +1615,12 @@ void Track::loadTrackModel(World* parent, bool reverse_track,
for(unsigned int i=0; i<root->getNumNodes(); i++) for(unsigned int i=0; i<root->getNumNodes(); i++)
{ {
const XMLNode *node = root->getNode(i); const XMLNode *node = root->getNode(i);
const std::string name = node->getName(); const std::string &name = node->getName();
if (name=="banana" || name=="item" || if (name=="banana" || name=="item" ||
name=="small-nitro" || name=="big-nitro") name=="small-nitro" || name=="big-nitro" ||
name=="easter-egg" )
{ {
Item::ItemType type; itemCommand(node);
if (name=="banana" ) type = Item::ITEM_BANANA;
else if(name=="item" ) type = Item::ITEM_BONUS_BOX;
else if(name=="small-nitro") type = Item::ITEM_NITRO_SMALL;
else type = Item::ITEM_NITRO_BIG;
Vec3 xyz;
// Set some kind of default in case Z is not defined in the file
// (with the new track exporter it always is defined anyway).
// Z is the height from which the item is dropped on the track.
xyz.setY(1000);
node->getXYZ(&xyz);
bool drop=true;
node->get("drop", &drop);
// Height is needed if bit 2 (for z) is not set
itemCommand(xyz, type, drop);
} }
} // for i<root->getNumNodes() } // for i<root->getNumNodes()
@ -1645,7 +1638,8 @@ void Track::loadTrackModel(World* parent, bool reverse_track,
{ {
printf("WARNING: no check lines found in track '%s'.\n", printf("WARNING: no check lines found in track '%s'.\n",
m_ident.c_str()); m_ident.c_str());
printf("Lap counting will not work, and start positions might be incorrect.\n"); printf("Lap counting will not work, and start positions might be "
"incorrect.\n");
} }
if(UserConfigParams::logMemory()) if(UserConfigParams::logMemory())
@ -1654,10 +1648,18 @@ void Track::loadTrackModel(World* parent, bool reverse_track,
irr_driver->getSceneManager()->getMeshCache()->getMeshCount(), irr_driver->getSceneManager()->getMeshCache()->getMeshCount(),
irr_driver->getVideoDriver()->getTextureCount()); irr_driver->getVideoDriver()->getTextureCount());
if (World::getWorld()->useChecklineRequirements()) World *world = World::getWorld();
if (world->useChecklineRequirements())
{ {
QuadGraph::get()->computeChecklineRequirements(); QuadGraph::get()->computeChecklineRequirements();
} }
EasterEggHunt *easter_world = dynamic_cast<EasterEggHunt*>(world);
if(easter_world)
{
std::string dir = StringUtils::getPath(m_filename);
easter_world->readData(dir+"/easter_eggs.xml");
}
} // loadTrackModel } // loadTrackModel
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1804,14 +1806,38 @@ void Track::handleSky(const XMLNode &xml_node, const std::string &filename)
* \param drop True if the item Z position should be determined based on * \param drop True if the item Z position should be determined based on
* the track topology. * the track topology.
*/ */
void Track::itemCommand(const Vec3 &xyz, Item::ItemType type, void Track::itemCommand(const XMLNode *node)
bool drop)
{ {
const std::string &name = node->getName();
Item::ItemType type;
if (name=="banana" ) type = Item::ITEM_BANANA;
else if(name=="item" ) type = Item::ITEM_BONUS_BOX;
else if(name=="small-nitro") type = Item::ITEM_NITRO_SMALL;
else if(name=="easter-egg" ) type = Item::ITEM_EASTER_EGG;
else type = Item::ITEM_NITRO_BIG;
Vec3 xyz;
// Set some kind of default in case Y is not defined in the file
// (with the new track exporter it always is defined anyway).
// Y is the height from which the item is dropped on the track.
xyz.setY(1000);
node->getXYZ(&xyz);
bool drop=true;
node->get("drop", &drop);
// Some modes (e.g. time trial) don't have any bonus boxes // Some modes (e.g. time trial) don't have any bonus boxes
if(type==Item::ITEM_BONUS_BOX && if(type==Item::ITEM_BONUS_BOX &&
!World::getWorld()->haveBonusBoxes()) !World::getWorld()->haveBonusBoxes())
return; return;
// Only do easter eggs in easter egg mode.
if(type==Item::ITEM_EASTER_EGG &&
!(race_manager->getMinorMode()==RaceManager::MINOR_MODE_EASTER_EGG))
{
printf("Found easter egg in non-easter-egg mode - ignored.\n");
return;
}
Vec3 loc(xyz); Vec3 loc(xyz);
// if only 2d coordinates are given, let the item fall from very high // if only 2d coordinates are given, let the item fall from very high
if(drop) if(drop)

View File

@ -228,6 +228,9 @@ private:
/** True if this track is an arena. */ /** True if this track is an arena. */
bool m_is_arena; bool m_is_arena;
/** True if this track has easter eggs. */
bool m_has_easter_eggs;
bool m_is_cutscene; bool m_is_cutscene;
/** The version of this track. A certain STK version will only support /** The version of this track. A certain STK version will only support
@ -358,8 +361,6 @@ private:
std::vector<BezierCurve*> m_all_curves; std::vector<BezierCurve*> m_all_curves;
void loadTrackInfo(); void loadTrackInfo();
void itemCommand(const Vec3 &xyz, Item::ItemType item_type,
bool drop);
void loadQuadGraph(unsigned int mode_id, const bool reverse); void loadQuadGraph(unsigned int mode_id, const bool reverse);
void convertTrackToBullet(scene::ISceneNode *node); void convertTrackToBullet(scene::ISceneNode *node);
bool loadMainTrack(const XMLNode &node); bool loadMainTrack(const XMLNode &node);
@ -386,7 +387,9 @@ public:
void update(float dt); void update(float dt);
void reset(); void reset();
void adjustForFog(scene::ISceneNode *node); void adjustForFog(scene::ISceneNode *node);
void adjustForFog(scene::IMesh* mesh, scene::ISceneNode* parent_scene_node); void adjustForFog(scene::IMesh* mesh,
scene::ISceneNode* parent_scene_node);
void itemCommand(const XMLNode *node);
const core::vector3df& getSunRotation(); const core::vector3df& getSunRotation();
/** Sets the current ambient color for a kart with index k. */ /** Sets the current ambient color for a kart with index k. */
void setAmbientColor(const video::SColor &color, void setAmbientColor(const video::SColor &color,
@ -394,6 +397,8 @@ public:
void handleExplosion(const Vec3 &pos, void handleExplosion(const Vec3 &pos,
const PhysicalObject *mp, const PhysicalObject *mp,
bool secondary_hits=true) const; bool secondary_hits=true) const;
void loadTrackModel (bool reverse_track = false,
unsigned int mode_id=0);
std::vector< std::vector<float> > std::vector< std::vector<float> >
buildHeightMap(); buildHeightMap();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -402,11 +407,11 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
const core::dimension2du& getMiniMapSize() const { return m_mini_map_size; } const core::dimension2du& getMiniMapSize() const { return m_mini_map_size; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns true if this track has an arena mode. */
bool isArena() const { return m_is_arena; } bool isArena() const { return m_is_arena; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void loadTrackModel (World* parent, /** Returns true if this track has easter eggs. */
bool reverse_track = false, bool hasEasterEggs() const { return m_has_easter_eggs; }
unsigned int mode_id=0);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void addMusic (MusicInformation* mi) void addMusic (MusicInformation* mi)
{m_music.push_back(mi); } {m_music.push_back(mi); }