Added first beta version of 'follow the leader' mode.

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@1683 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2008-04-15 13:57:18 +00:00
parent 0867675fb9
commit 68dae90d15
31 changed files with 859 additions and 210 deletions

View File

@ -21,6 +21,7 @@
(parachute-done-fraction 0.7 ) ;; fraction of speed when lost will detach parachute
(bomb-time 30.0 ) ;; time till a bomb explodes
(bomb-time-increase -5.0 ) ;; time added to timer when bomb is passed on
(leader-intervals 30 20 10) ;; Time till a kart is removed in follow leader mode
(anvil-time 2.0 ) ;; time an anvil is active
(zipper-time 3.0 ) ;; time a zipper is active
(zipper-force 800.0 ) ;; additional zipper force

View File

@ -38,6 +38,7 @@ supertuxkart_SOURCES = main.cpp \
music_ogg.cpp music_ogg.hpp \
music_information.cpp music_information.hpp \
sfx_openal.cpp sfx_openal.hpp \
smoke.cpp smoke.hpp \
input.hpp \
isect.cpp isect.hpp \
track.cpp track.hpp \
@ -95,6 +96,7 @@ supertuxkart_SOURCES = main.cpp \
challenges/all_tracks.cpp challenges/all_tracks.hpp \
challenges/energy_math_class.cpp challenges/energy_math_class.hpp\
challenges/win_gotm_cup.cpp challenges/win_gotm_cup.hpp \
challenges/race_track_time.cpp challenges/race_track_time.hpp\
lisp/lisp.cpp lisp/lisp.hpp \
lisp/lexer.cpp lisp/lexer.hpp \
lisp/parser.cpp lisp/parser.hpp \
@ -118,6 +120,7 @@ supertuxkart_SOURCES = main.cpp \
gui/game_mode.cpp gui/game_mode.hpp \
gui/difficulty.cpp gui/difficulty.hpp \
gui/char_sel.cpp gui/char_sel.hpp \
gui/leader_result.cpp gui/leader_result.hpp \
gui/main_menu.cpp gui/main_menu.hpp \
gui/help_page_one.cpp gui/help_page_one.hpp \
gui/help_page_two.cpp gui/help_page_two.hpp \

View File

@ -83,9 +83,11 @@ void Camera::setScreenPosition ( int numPlayers, int pos )
Camera::Camera(int numPlayers, int which)
: m_reverse(false)
{
m_which_kart = which; // Just for now
m_mode = CM_NORMAL;
m_context = new ssgContext ;
m_mode = CM_NORMAL;
m_context = new ssgContext ;
m_which_kart = which;
if(m_which_kart >= int(race_manager->getNumKarts()) || m_which_kart < 0 )
m_which_kart =0;
// FIXME: clipping should be configurable for slower machines
const Track* track = world->getTrack();
@ -101,7 +103,10 @@ Camera::Camera(int numPlayers, int which)
//-----------------------------------------------------------------------------
void Camera::setMode(Mode mode)
{
m_mode = mode;
m_mode = mode;
m_LastPitch = 0.0f;
if(m_mode==CM_LEADER_MODE)
setReverseHeading(true);
} // setMode
//-----------------------------------------------------------------------------
@ -122,32 +127,44 @@ void Camera::reset()
//-----------------------------------------------------------------------------
void Camera::update (float dt)
{
// Update the camera
if ( m_which_kart >= int(world->getNumKarts()) || m_which_kart < 0 ) m_which_kart = 0 ;
sgCoord kartcoord;
const Kart *kart=world->getPlayerKart(m_which_kart);
sgCopyCoord(&kartcoord, world->getPlayerKart(m_which_kart)->getCoord());
// Use the terrain pitch to avoid the camera following a wheelie the kart is doing
kartcoord.hpr[1]=RAD_TO_DEGREE( kart->getTerrainPitch(DEGREE_TO_RAD(kartcoord.hpr[0])) );
kartcoord.hpr[2] = 0;
// Only adjust the pitch if it's not the first frame (which is indicated by having
// dt=0). Otherwise the camera will change pitch during ready-set-go.
if(dt>0)
const Kart *kart;
// Update the camera
if(m_mode==CM_LEADER_MODE)
{
// If the terrain pitch is 'significantly' different from the camera angle,
// start adjusting the camera. This helps with steep declines, where
// otherwise the track is not visible anymore.
if(fabsf(kartcoord.hpr[1]-m_LastPitch)>1.0f) {
kartcoord.hpr[1] = m_LastPitch + (kartcoord.hpr[1]-m_LastPitch)*2.0f*dt;
}
else
{
kartcoord.hpr[1]=m_LastPitch;
}
kart=world->getKart(0);
sgCopyCoord(&kartcoord, kart->getCoord());
// This gives a camera slightly above the kart, facing downwards
// But this works only when the karts are within a certain distance
// otherwise only the track is seen :(
// kartcoord.xyz[2]+=3.0f; // raise camera
kartcoord.hpr[1]+=17; // face downwards
}
m_LastPitch = kartcoord.hpr[1];
else
{
kart=world->getPlayerKart(m_which_kart);
sgCopyCoord(&kartcoord, kart->getCoord());
// Use the terrain pitch to avoid the camera following a wheelie the kart is doing
kartcoord.hpr[1]=RAD_TO_DEGREE( kart->getTerrainPitch(DEGREE_TO_RAD(kartcoord.hpr[0])) );
kartcoord.hpr[2] = 0;
// Only adjust the pitch if it's not the first frame (which is indicated by having
// dt=0). Otherwise the camera will change pitch during ready-set-go.
if(dt>0)
{
// If the terrain pitch is 'significantly' different from the camera angle,
// start adjusting the camera. This helps with steep declines, where
// otherwise the track is not visible anymore.
if(fabsf(kartcoord.hpr[1]-m_LastPitch)>1.0f) {
kartcoord.hpr[1] = m_LastPitch + (kartcoord.hpr[1]-m_LastPitch)*2.0f*dt;
}
else
{
kartcoord.hpr[1]=m_LastPitch;
}
} // dt>0.0
m_LastPitch = kartcoord.hpr[1];
} // m_mode!=CM_LEADER_MODE
if (m_mode == CM_SIMPLE_REPLAY)
kartcoord.hpr[0] = 0;
@ -180,7 +197,7 @@ void Camera::update (float dt)
}
else if (m_mode == CM_NO_FAKE_DRIFT)
{
const float STEER_OFFSET = world->getPlayerKart(m_which_kart)->getSteerAngle()*-10.0f;
const float STEER_OFFSET = kart->getSteerAngle()*-10.0f;
sgMat4 cam_rot;
sgMat4 tmp;

View File

@ -36,9 +36,9 @@ public:
CM_SIMPLE_REPLAY
};
protected:
ssgContext *m_context ;
ssgContext *m_context ;
int m_which_kart ;
int m_which_kart;
Mode m_mode;
float m_last_steer_offset;
float m_x, m_y, m_w, m_h ;

View File

@ -0,0 +1,41 @@
// $Id: race_track_time.cpp 1259 2007-09-24 12:28:19Z hiker $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2008 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 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be ruseful,
// 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 <algorithm>
#include "challenges/race_track_time.hpp"
#include "world.hpp"
RaceTrackTime::RaceTrackTime() : Challenge("racetracktime", "Finish Race track in 1:15")
{
setChallengeDescription("Finish 3 laps in the Race track\nwith 3 AI karts\nin under 1:15 minutes.");
setFeatureDescription("New game mode\n'Follow Leader'\nnow available");
setFeature("followleader");
} // RaceTrackTime
//-----------------------------------------------------------------------------
bool RaceTrackTime::raceFinished()
{
std::string track_name = world->getTrack()->getIdent();
if(track_name!="race" ) return false; // wrong track
Kart* kart=world->getPlayerKart(0);
if(kart->getFinishTime()>75) return false; // too slow
if(kart->getLap()!=3 ) return false; // wrong number of laps
return true;
} // raceFinished
//-----------------------------------------------------------------------------

View File

@ -0,0 +1,35 @@
// $Id: race_track_time.hpp 1259 2007-09-24 12:28:19Z hiker $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2008 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 2
// 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 HEADER_RACE_TRACK_TIME_H
#define HEADER_RACE_TRACK_TIME_H
#include <string>
#include <vector>
#include "challenges/challenge.hpp"
class RaceTrackTime : public Challenge
{
public:
RaceTrackTime();
virtual bool raceFinished();
}; // RaceTrackTime
#endif

View File

@ -39,10 +39,10 @@ bool WinGOTMCup::grandPrixFinished()
race_manager->getNumKarts() < 4 ||
race_manager->getNumPlayers() > 1) return false;
// Check if the player was number one:
for(int i=0; i<(int)world->getNumKarts(); i++)
for(int i=0; i<(int)race_manager->getNumKarts(); i++)
{
const Kart* k=world->getKart(i);
if(k->isPlayerKart()) return k->getPosition()==1;
if(k->isPlayerKart() && !k->isEliminated()) return k->getPosition()==1;
}
return false;
} // raceFinished

View File

@ -74,17 +74,17 @@ void Collectable::use()
case COLLECT_ANVIL:
//Attach an anvil(twice as good as the one given
//by the bananas) to the kart in the 1st position.
for(unsigned int i = 0 ; i < world->getNumKarts(); ++i)
for(unsigned int i = 0 ; i < race_manager->getNumKarts(); ++i)
{
if(world->getKart(i) == m_owner) continue;
if(world->getKart(i)->getPosition() == 1)
Kart *kart=world->getKart(i);
if(kart->isEliminated()) continue;
if(kart == m_owner) continue;
if(kart->getPosition() == 1)
{
world->getKart(i)->
attach(ATTACH_ANVIL, stk_config->m_anvil_time);
world->getKart(i)->adjustSpeedWeight(stk_config->m_anvil_speed_factor*0.5f);
kart->attach(ATTACH_ANVIL, stk_config->m_anvil_time);
kart->adjustSpeedWeight(stk_config->m_anvil_speed_factor*0.5f);
if(world->getKart(i)->isPlayerKart())
if(kart->isPlayerKart())
sound_manager->playSfx(SOUND_USE_ANVIL);
break;
}
@ -98,16 +98,15 @@ void Collectable::use()
//Attach a parachutte(that last as twice as the
//one from the bananas) to all the karts that
//are in front of this one.
for(unsigned int i = 0 ; i < world->getNumKarts(); ++i)
for(unsigned int i = 0 ; i < race_manager->getNumKarts(); ++i)
{
if(world->getKart(i) == m_owner) continue;
if(m_owner->getPosition() > world->
getKart(i)->getPosition())
Kart *kart=world->getKart(i);
if(kart->isEliminated() || kart== m_owner) continue;
if(m_owner->getPosition() > kart->getPosition())
{
world->getKart(i)->attach(
ATTACH_PARACHUTE, stk_config->m_parachute_time_other);
kart->attach(ATTACH_PARACHUTE, stk_config->m_parachute_time_other);
if(world->getKart(i)->isPlayerKart())
if(kart->isPlayerKart())
player_affected = true;
}
@ -137,18 +136,18 @@ void Collectable::hitRedHerring(int n)
if(m_owner->getPosition() != 1 && m_type == COLLECT_NOTHING)
{
const int SPECIAL_PROB = (int)(15.0 / ((float)world->getNumKarts() /
const int SPECIAL_PROB = (int)(15.0 / ((float)world->getCurrentNumKarts() /
(float)m_owner->getPosition()));
const int RAND_NUM = rand()%100;
if(RAND_NUM <= SPECIAL_PROB)
{
//If the driver in the first position has finished, give the driver
//the parachute.
for(unsigned int i=0; i < world->getNumKarts(); ++i)
for(unsigned int i=0; i < race_manager->getNumKarts(); ++i)
{
if(world->getKart(i) == m_owner) continue;
if(world->getKart(i)->getPosition() == 1 && world->getKart(i)->
raceIsFinished())
Kart *kart = world->getKart(i);
if(kart->isEliminated() || kart == m_owner) continue;
if(kart->getPosition() == 1 && kart->raceIsFinished())
{
m_type = COLLECT_PARACHUTE;
m_number = 1;

View File

@ -150,10 +150,10 @@ void Flyable::getClosestKart(const Kart **minKart, float *minDist, btVector3 *mi
{
btTransform tProjectile=getTrans();
*minDist = 99999.9f;
for(unsigned int i=0 ; i<world->getNumKarts(); i++ )
for(unsigned int i=0 ; i<race_manager->getNumKarts(); i++ )
{
Kart *kart = world -> getKart(i);
if(kart == m_owner) continue;
if(kart->isEliminated() || kart == m_owner) continue;
btTransform t=kart->getTrans();
btVector3 delta = t.getOrigin()-tProjectile.getOrigin();
@ -224,9 +224,9 @@ void Flyable::explode(Kart *kart_hit, MovingPhysics* moving_physics)
world->getPhysics()->removeBody(getBody());
m_exploded=true;
for ( unsigned int i = 0 ; i < world->getNumKarts() ; i++ )
for ( unsigned int i = 0 ; i < race_manager->getNumKarts() ; i++ )
{
Kart *kart = world -> getKart(i);
Kart *kart = world->getKart(i);
// handle the actual explosion. Set a flag it if was a direct hit.
kart->handleExplosion(m_curr_pos.xyz, kart==kart_hit);
}

View File

@ -31,6 +31,7 @@ enum WidgetTokens
WTOK_GP,
WTOK_QUICKRACE,
WTOK_TIMETRIAL,
WTOK_FOLLOW_LEADER,
WTOK_EMPTY,
WTOK_BACK
};
@ -68,7 +69,16 @@ GameMode::GameMode()
widget_manager->addWgt(WTOK_TIMETRIAL, 50, 7);
widget_manager->setWgtText( WTOK_TIMETRIAL, _("Time Trial"));
}
widget_manager->addWgt(WTOK_FOLLOW_LEADER, 50, 7);
if(unlock_manager->isLocked("followleader"))
{
widget_manager->setWgtText( WTOK_FOLLOW_LEADER, "???");
widget_manager->deactivateWgt(WTOK_FOLLOW_LEADER);
}
else
{
widget_manager->setWgtText( WTOK_FOLLOW_LEADER, _("Follow the Leader"));
}
widget_manager->addWgt(WTOK_EMPTY, 50, 7);
widget_manager->hideWgtRect( WTOK_EMPTY );
widget_manager->hideWgtText( WTOK_EMPTY );
@ -101,6 +111,10 @@ void GameMode::select()
race_manager->setRaceMode(RaceManager::RM_QUICK_RACE);
menu_manager->pushMenu(MENUID_DIFFICULTY);
break;
case WTOK_FOLLOW_LEADER:
race_manager->setRaceMode(RaceManager::RM_FOLLOW_LEADER);
menu_manager->pushMenu(MENUID_DIFFICULTY);
break;
case WTOK_TIMETRIAL:
race_manager->setRaceMode(RaceManager::RM_TIME_TRIAL);
menu_manager->pushMenu(MENUID_CHARSEL_P1); //difficulty makes no sense here

240
src/gui/leader_result.cpp Normal file
View File

@ -0,0 +1,240 @@
// $Id: grand_prix_ending.cpp 1681 2008-04-09 13:52:48Z hikerstk $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2008 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 2
// 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 <sstream>
#include <string>
#include <SDL/SDL.h>
#include "leader_result.hpp"
#include "loader.hpp"
#include "sound_manager.hpp"
#include "kart_properties_manager.hpp"
#include "unlock_manager.hpp"
#include "widget_manager.hpp"
#include "race_manager.hpp"
#include "game_manager.hpp"
#include "user_config.hpp"
#include "menu_manager.hpp"
#include "kart_properties.hpp"
#include "translation.hpp"
#include "kart.hpp"
#include "world.hpp"
#include "scene.hpp"
#if defined(WIN32) && !defined(__CYGWIN__)
# define snprintf _snprintf
#endif
enum WidgetTokens
{
WTOK_TITLE,
WTOK_QUIT,
WTOK_FIRSTKART
};
LeaderResult::LeaderResult()
: m_kart(0)
{
// for some strange reasons plib calls makeCurrent() in ssgContext
// constructor, so we have to save the old one here and restore it
ssgContext* oldContext = ssgGetCurrentContext();
m_context = new ssgContext;
oldContext->makeCurrent();
const unsigned int MAX_STR_LEN = 60;
const unsigned int NUM_KARTS = race_manager->getNumKarts();
int *scores = new int[NUM_KARTS];
int *position = new int[NUM_KARTS];
double *race_time = new double[NUM_KARTS];
// Ignore kart 0, since it was the leader
for( unsigned int kart_id = 1; kart_id < NUM_KARTS; ++kart_id )
{
position[kart_id] = kart_id;
scores[kart_id] = race_manager->getKartScore(kart_id);
race_time[kart_id] = race_manager->getOverallTime(kart_id);
}
//Bubblesort
bool sorted;
do
{
sorted = true;
for( unsigned int i = 1; i < NUM_KARTS - 1; ++i )
{
if( scores[i] < scores[i+1] || (scores[i] == scores[i+1]
&& race_time[i] > race_time[i+1]))
{
int tmp_score[2];
double tmp_time;
tmp_score[0] = position[i];
tmp_score[1] = scores[i];
tmp_time = race_time[i];
position[i] = position[i+1];
scores[i] = scores[i+1];
race_time[i] = race_time[i+1];
position[i+1] = tmp_score[0];
scores[i+1] = tmp_score[1];
race_time[i+1] = tmp_time;
sorted = false;
}
}
} while(!sorted);
static char output[MAX_MESSAGE_LENGTH];
snprintf(output, sizeof(output),
_("The winner is %s!"),race_manager->getKartName(position[1]).c_str());
widget_manager->addWgt( WTOK_TITLE, 60, 10);
widget_manager->showWgtRect(WTOK_TITLE);
widget_manager->showWgtText(WTOK_TITLE);
widget_manager->setWgtText(WTOK_TITLE, output);
widget_manager->setWgtTextSize(WTOK_TITLE, WGT_FNT_LRG);
widget_manager->breakLine();
m_score = new char[MAX_STR_LEN*NUM_KARTS];
for(unsigned int i=1; i < NUM_KARTS; ++i)
{
char sTime[20];
TimeToString(race_time[i], sTime);
sprintf((char*)(m_score + MAX_STR_LEN * i), "%d. %s %d %s",
i + 1, race_manager->getKartName(position[i]).c_str(), scores[i], sTime );
widget_manager->addWgt(WTOK_FIRSTKART + i, 40, 5);
widget_manager->showWgtRect(WTOK_FIRSTKART + i);
widget_manager->showWgtText(WTOK_FIRSTKART + i);
widget_manager->setWgtText(WTOK_FIRSTKART + i,
(char*)(m_score + MAX_STR_LEN * i));
widget_manager->setWgtTextSize(WTOK_FIRSTKART + i, WGT_FNT_SML);
widget_manager->breakLine();
}
const std::string KART_NAME = race_manager->getKartName(position[1]);
const KartProperties* WINNING_KART = kart_properties_manager->getKart(KART_NAME);
delete []scores;
delete []position;
delete []race_time;
widget_manager->addWgt(WTOK_QUIT, 50, 7);
widget_manager->activateWgt(WTOK_QUIT);
widget_manager->showWgtRect(WTOK_QUIT);
widget_manager->showWgtText(WTOK_QUIT);
if(unlock_manager->getUnlockedFeatures().size()>0)
{
widget_manager->setWgtText(WTOK_QUIT, _("Continue"));
}
else
{
widget_manager->setWgtText(WTOK_QUIT, _("Back to the main menu"));
}
widget_manager->layout(WGT_AREA_TOP);
m_kart = new ssgTransform;
m_kart->ref();
ssgEntity* kartentity = WINNING_KART->getModel();
m_kart->addKid(kartentity);
sound_manager->playSfx(SOUND_WINNER);
m_clock = 0;
//FIXME: this is taken from RaceMode::exit_race,
//this should be organized better.
scene->clear();
delete world;
world = 0;
race_manager->m_active_race = false;
}
//-----------------------------------------------------------------------------
LeaderResult::~LeaderResult()
{
widget_manager->reset();
ssgDeRefDelete(m_kart);
delete m_context;
delete[] m_score;
//The next line prevents textures like the background of the main menu from
//going white after finishing the grandprix
// FIXME: I think this is not necessary anymore after the
// texture bug fix (r733) - but I can't currently test this.
loader->shared_textures.removeAll();
}
//-----------------------------------------------------------------------------
void LeaderResult::update(float dt)
{
m_clock += dt * 40.0f;
glClearColor (0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ssgContext* oldContext = ssgGetCurrentContext();
m_context -> makeCurrent();
// FIXME: A bit hackish...
glViewport ( 0, 0, 800, 320);
m_context -> setFOV ( 45.0f, 45.0f * 320.0f/800.0f ) ;
m_context -> setNearFar ( 0.05f, 1000.0f ) ;
sgCoord cam_pos;
sgSetCoord(&cam_pos, 0, 0, 0, 0, 0, 0);
m_context -> setCamera ( &cam_pos ) ;
glEnable (GL_DEPTH_TEST);
sgCoord trans;
sgSetCoord(&trans, 0, 3, -.4f, m_clock, 0, 0);
m_kart->setTransform (&trans) ;
//glShadeModel(GL_SMOOTH);
ssgCullAndDraw ( m_kart ) ;
glViewport ( 0, 0, user_config->m_width, user_config->m_height ) ;
glDisable (GL_DEPTH_TEST);
oldContext->makeCurrent();
BaseGUI::update(dt);
}
//-----------------------------------------------------------------------------
void LeaderResult::select()
{
// If a new feature was unlocked, display the new feature first
// before returning to the main menu
if(unlock_manager->getUnlockedFeatures().size()>0)
{
// This removes this menu from the stack, and adds the main menu.
// Then we push the new feature menu on top, so that it will be
// displayed next, and on return the main menu is shown.
menu_manager->switchToMainMenu();
menu_manager->pushMenu(MENUID_UNLOCKED_FEATURE);
return;
}
menu_manager->switchToMainMenu();
}

47
src/gui/leader_result.hpp Executable file
View File

@ -0,0 +1,47 @@
// $Id: grand_prix_ending.hpp 1023 2007-04-29 22:23:46Z coz $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2008 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 2
// 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 HEADER_LEADER_RESULT_H
#define HEADER_LEADER_RESULT_H
#include "base_gui.hpp"
class ssgBranch;
class ssgTransform;
class ssgContext;
class LeaderResult: public BaseGUI
{
private:
ssgContext* m_context;
ssgTransform* m_kart;
int m_current_kart;
int m_kart_name_label;
char* m_score;
float m_clock;
public:
LeaderResult();
~LeaderResult();
void update(float dt);
void select();
};
#endif

View File

@ -54,6 +54,7 @@
#include "widget_manager.hpp"
#include "challenges_menu.hpp"
#include "feature_unlocked.hpp"
#include "leader_result.hpp"
using namespace std;
@ -187,6 +188,9 @@ void MenuManager::update()
case MENUID_RACERESULT:
m_current_menu= new RaceResultsGUI();
break;
case MENUID_LEADERRESULT:
m_current_menu= new LeaderResult();
break;
case MENUID_GRANDPRIXEND:
m_current_menu= new GrandPrixEnd();
break;

View File

@ -36,6 +36,7 @@ enum MenuManagerIDs
MENUID_DIFFICULTY,
MENUID_GAMEMODE,
MENUID_RACERESULT,
MENUID_LEADERRESULT,
MENUID_GRANDPRIXEND,
MENUID_RACEMENU,
MENUID_TRACKSEL,

View File

@ -167,21 +167,21 @@ RaceGUI::handle(GameAction ga, int value)
switch (ga)
{
case GA_DEBUG_ADD_SPARK:
if (world->getNumPlayers() ==1 )
if (race_manager->getNumPlayers() ==1 )
{
Kart* kart = world->getPlayerKart(0);
kart->setCollectable(COLLECT_SPARK, 10000);
}
break;
case GA_DEBUG_ADD_MISSILE:
if (world->getNumPlayers() ==1 )
if (race_manager->getNumPlayers() ==1 )
{
Kart* kart = world->getPlayerKart(0);
kart->setCollectable(COLLECT_MISSILE, 10000);
}
break;
case GA_DEBUG_ADD_HOMING:
if (world->getNumPlayers() ==1 )
if (race_manager->getNumPlayers() ==1 )
{
Kart* kart = world->getPlayerKart(0);
kart->setCollectable(COLLECT_HOMING, 10000);
@ -289,11 +289,12 @@ void RaceGUI::drawMap ()
glBegin ( GL_QUADS ) ;
for ( unsigned int i = 0 ; i < world->getNumKarts() ; i++ )
for ( unsigned int i = 0 ; i < race_manager->getNumKarts() ; i++ )
{
sgCoord *c ;
Kart* kart = world->getKart(i);
if(kart->isEliminated()) continue; // don't draw eliminated kart
glColor3fv ( *kart->getColor());
c = kart->getCoord () ;
@ -336,9 +337,10 @@ void RaceGUI::drawPlayerIcons ()
// Find the best time for the lap. We can't simply use
// the time of the kart at position 1, since the kart
// might have been overtaken by now
for(unsigned int i = 0; i < world->getNumKarts() ; i++)
for(unsigned int i = 0; i < race_manager->getNumKarts() ; i++)
{
Kart* kart = world->getKart(i);
if(kart->isEliminated()) continue;
float lap_time = kart->getTimeAtLap();
int laps = kart->getLap();
@ -355,9 +357,10 @@ void RaceGUI::drawPlayerIcons ()
} // for i<getNumKarts
int bFirst = 1;
for(unsigned int i = 0; i < world->getNumKarts() ; i++)
for(unsigned int i = 0; i < race_manager->getNumKarts() ; i++)
{
Kart* kart = world->getKart(i);
if(kart->isEliminated()) continue;
int position = kart->getPosition();
int lap = kart->getLap();
@ -395,8 +398,9 @@ void RaceGUI::drawPlayerIcons ()
str[0]='+'; str[1]=0;
TimeToString(timeBehind, str+1);
}
font_race->PrintShadow(str, 30, ICON_PLAYER_WIDHT+x, y+5,
red, green, blue);
if(race_manager->raceHasLaps())
font_race->PrintShadow(str, 30, ICON_PLAYER_WIDHT+x, y+5,
red, green, blue);
}
glEnable(GL_CULL_FACE);
@ -746,7 +750,7 @@ void RaceGUI::drawLap(Kart* kart, int offset_x, int offset_y,
float ratio_x, float ratio_y )
{
// Don't display laps in follow the leader mode
if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER) return;
if(!race_manager->raceHasLaps()) return;
float maxRatio = std::max(ratio_x, ratio_y);
char str[256];
@ -909,7 +913,7 @@ void RaceGUI::drawStatusText(const float dt)
}
if(world->isStartPhase())
{
for(unsigned int i=0; i<world->getNumPlayers(); i++)
for(unsigned int i=0; i<race_manager->getNumPlayers(); i++)
{
if(world->getPlayerKart(i)->earlyStartPenalty())
{
@ -922,14 +926,14 @@ void RaceGUI::drawStatusText(const float dt)
float split_screen_ratio_x, split_screen_ratio_y;
split_screen_ratio_x = split_screen_ratio_y = 1.0;
if(world->getNumPlayers() >= 2)
if(race_manager->getNumPlayers() >= 2)
split_screen_ratio_y = 0.5;
if(world->getNumPlayers() >= 3)
if(race_manager->getNumPlayers() >= 3)
split_screen_ratio_x = 0.5;
if ( world->isRacePhase() )
{
const int numPlayers = world->getNumPlayers();
const int numPlayers = race_manager->getNumPlayers();
for(int pla = 0; pla < numPlayers; pla++)
{

View File

@ -74,7 +74,7 @@ RaceResultsGUI::RaceResultsGUI()
const unsigned int MAX_STR_LEN = 60;
const unsigned int NUM_KARTS = world->getNumKarts();
const unsigned int NUM_KARTS = race_manager->getNumKarts();
int* order = new int [NUM_KARTS];
m_score = new char[NUM_KARTS * MAX_STR_LEN];
@ -82,7 +82,7 @@ RaceResultsGUI::RaceResultsGUI()
for(unsigned int i=0; i < NUM_KARTS; i++)
{
Kart *k = world->getKart(i);
Kart *k = world->getKart(i); // Display even for eliminated karts!
order[k->getPosition()-1] = i;
const std::string& s = k->getName();
unsigned int l = (unsigned int)s.size();

View File

@ -853,6 +853,10 @@
RelativePath="../../../src\skid_mark.cpp"
>
</File>
<File
RelativePath="..\..\smoke.cpp"
>
</File>
<File
RelativePath="../../../src\sound_manager.cpp"
>
@ -992,6 +996,10 @@
RelativePath="..\..\gui\help_page_two.cpp"
>
</File>
<File
RelativePath="..\..\gui\leader_result.cpp"
>
</File>
<File
RelativePath="../../../src\gui\main_menu.cpp"
>
@ -1080,6 +1088,10 @@
RelativePath="..\..\challenges\energy_math_class.cpp"
>
</File>
<File
RelativePath="..\..\challenges\race_track_time.cpp"
>
</File>
<File
RelativePath="..\..\challenges\win_gotm_cup.cpp"
>
@ -1315,6 +1327,10 @@
RelativePath="../../../src\skid_mark.hpp"
>
</File>
<File
RelativePath="..\..\smoke.hpp"
>
</File>
<File
RelativePath="../../../src\sound_manager.hpp"
>
@ -1454,6 +1470,10 @@
RelativePath="..\..\gui\help_page_two.hpp"
>
</File>
<File
RelativePath="..\..\gui\leader_result.hpp"
>
</File>
<File
RelativePath="../../../src\gui\main_menu.hpp"
>
@ -1542,6 +1562,10 @@
RelativePath="..\..\challenges\energy_math_class.hpp"
>
</File>
<File
RelativePath="..\..\challenges\race_track_time.hpp"
>
</File>
<File
RelativePath="..\..\challenges\win_gotm_cup.hpp"
>

View File

@ -20,6 +20,7 @@
#include <math.h>
#include <iostream>
#include <plib/ssg.h>
#include "bullet/Demos/OpenGL/GL_ShapeDrawer.h"
#include "loader.hpp"
#include "herring_manager.hpp"
@ -38,87 +39,12 @@
#include "gui/menu_manager.hpp"
#include "gui/race_gui.hpp"
#include "translation.hpp"
#include "bullet/Demos/OpenGL/GL_ShapeDrawer.h"
#include "smoke.hpp"
#if defined(WIN32) && !defined(__CYGWIN__)
# define snprintf _snprintf
#endif
KartParticleSystem::KartParticleSystem(Kart* kart_,
int num, float _create_rate, int _ttf,
float sz, float bsphere_size)
: ParticleSystem (num, _create_rate, _ttf, sz, bsphere_size),
m_kart(kart_)
{
getBSphere () -> setCenter ( 0, 0, 0 ) ;
getBSphere () -> setRadius ( 1000.0f ) ;
dirtyBSphere();
} // KartParticleSystem
//-----------------------------------------------------------------------------
void KartParticleSystem::update ( float t )
{
#if 0
std::cout << "BSphere: r:" << getBSphere()->radius
<< " (" << getBSphere()->center[0]
<< ", " << getBSphere()->center[1]
<< ", " << getBSphere()->center[2]
<< ")"
<< std::endl;
#endif
getBSphere () -> setRadius ( 1000.0f ) ;
ParticleSystem::update(t);
} // update
//-----------------------------------------------------------------------------
void KartParticleSystem::particle_create(int, Particle *p)
{
sgSetVec4 ( p -> m_col, 1, 1, 1, 1 ) ; /* initially white */
sgSetVec3 ( p -> m_pos, 0, 0, 0 ) ; /* start off on the ground */
sgSetVec3 ( p -> m_vel, 0, 0, 0 ) ;
sgSetVec3 ( p -> m_acc, 0, 0, 2.0f ) ; /* Gravity */
p -> m_size = .5f;
p -> m_time_to_live = 0.5 ; /* Droplets evaporate after 5 seconds */
const sgCoord* POS = m_kart->getCoord();
const btVector3 VEL = m_kart->getVelocity();
const float X_DIRECTION = sgCos (POS->hpr[0] - 90.0f); // Point at the rear
const float Y_DIRECTION = sgSin (POS->hpr[0] - 90.0f); // Point at the rear
sgCopyVec3 (p->m_pos, POS->xyz);
p->m_pos[0] += X_DIRECTION * 0.7f;
p->m_pos[1] += Y_DIRECTION * 0.7f;
const float ABS_VEL = sqrt((VEL.getX() * VEL.getX()) + (VEL.getY() * VEL.getY()));
p->m_vel[0] = X_DIRECTION * -ABS_VEL/2;
p->m_vel[1] = Y_DIRECTION * -ABS_VEL/2;
p->m_vel[0] += sgCos ((float)(rand()%180));
p->m_vel[1] += sgSin ((float)(rand()%180));
p->m_vel[2] += sgSin ((float)(rand()%100));
getBSphere () -> setCenter ( POS->xyz[0], POS->xyz[1], POS->xyz[2] ) ;
} // particle_create
//-----------------------------------------------------------------------------
void KartParticleSystem::particle_update (float delta, int,
Particle * particle)
{
particle->m_size += delta*2.0f;
particle->m_col[3] -= delta * 2.0f;
particle->m_pos[0] += particle->m_vel[0] * delta;
particle->m_pos[1] += particle->m_vel[1] * delta;
particle->m_pos[2] += particle->m_vel[2] * delta;
} // particle_update
//-----------------------------------------------------------------------------
void KartParticleSystem::particle_delete (int , Particle* )
{} // particle_delete
//=============================================================================
Kart::Kart (const std::string& kart_name, int position_ ,
sgCoord init_pos)
: TerrainInfo(1),
@ -134,6 +60,7 @@ Kart::Kart (const std::string& kart_name, int position_ ,
m_kart_properties = kart_properties_manager->getKart(kart_name);
m_grid_position = position_ ;
m_num_herrings_gobbled = 0;
m_eliminated = false;
m_finished_race = false;
m_finish_time = 0.0f;
m_prev_accel = 0.0f;
@ -325,6 +252,17 @@ Kart::~Kart()
}
} // ~Kart
//-----------------------------------------------------------------------------
void Kart::eliminate()
{
m_eliminated = true;
world->getPhysics()->removeKart(this);
// make the kart invisible by placing it way under the track
sgVec3 hell; hell[0]=0.0f; hell[1]=0.0f; hell[2] = -10000.0f;
getModelTransform()->setTransform(hell);
} // eliminate
//-----------------------------------------------------------------------------
/** Returns true if the kart is 'resting'
*
@ -352,6 +290,10 @@ void Kart::adjustSpeedWeight(float f)
//-----------------------------------------------------------------------------
void Kart::reset()
{
if(m_eliminated)
{
world->getPhysics()->addKart(this, m_vehicle);
}
Moveable::reset();
m_attachment.clear();
@ -363,6 +305,7 @@ void Kart::reset()
m_shortcut_sector = Track::UNKNOWN_SECTOR;
m_race_position = 9;
m_finished_race = false;
m_eliminated = false;
m_finish_time = 0.0f;
m_zipper_time_left = 0.0f;
m_num_herrings_gobbled = 0;
@ -460,7 +403,8 @@ void Kart::doLapCounting ()
time_per_lap=world->getTime()-m_lap_start_time;
}
if(time_per_lap < world->getFastestLapTime() )
if(time_per_lap < world->getFastestLapTime() &&
race_manager->raceHasLaps())
{
world->setFastestLap(this, time_per_lap);
RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
@ -490,6 +434,13 @@ void Kart::doLapCounting ()
// Prevent cheating by setting time to a negative number, indicating
// that the line wasn't crossed properly.
m_lap_start_time = -1.0f;
} else
{ // Switch to fast music in case of follow the leader when only 3 karts are left
if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER &&
world->getCurrentNumKarts()==3)
{
sound_manager->switchToFastMusic();
}
}
} // doLapCounting
@ -1118,7 +1069,7 @@ void Kart::loadData()
// Attach Particle System
//JH sgCoord pipe_pos = {{0, 0, .3}, {0, 0, 0}} ;
m_smoke_system = new KartParticleSystem(this, 50, 100.0f, true, 0.35f, 1000);
m_smoke_system = new Smoke(this, 50, 100.0f, true, 0.35f, 1000);
m_smoke_system -> init(5);
//JH m_smoke_system -> setState (getMaterial ("smoke.png")-> getState() );
//m_smoke_system -> setState ( m_smokepuff ) ;

View File

@ -25,7 +25,6 @@
#include "btBulletDynamicsCommon.h"
#include "moveable.hpp"
#include "particle_system.hpp"
#include "kart_properties.hpp"
#include "attachment.hpp"
#include "collectable.hpp"
@ -46,24 +45,9 @@ struct KartControl
};
class SkidMark;
class Kart;
class Herring;
class Smoke;
class KartParticleSystem : public ParticleSystem
{
private:
Kart* m_kart;
public:
KartParticleSystem (Kart* kart, int num, float _create_rate,
int _turn_to_face, float sz, float bsphere_size);
virtual void update (float t );
virtual void particle_create(int index, Particle* p );
virtual void particle_update(float deltaTime, int index, Particle *p );
virtual void particle_delete(int index, Particle* p );
};
// =============================================================================
class Kart : public TerrainInfo, public Moveable
{
protected:
@ -105,7 +89,7 @@ private:
int m_num_herrings_gobbled;
ssgSimpleState* m_smokepuff;
// don't delete the following 2 vars (they're kids in the hirarchy)
KartParticleSystem* m_smoke_system;
Smoke *m_smoke_system;
ssgTransform* m_exhaust_pipe;
float m_wheel_rotation;
@ -124,6 +108,7 @@ private:
float m_speed;
bool m_rescue;
bool m_eliminated;
protected:
float m_rescue_pitch, m_rescue_roll;
@ -217,6 +202,8 @@ public:
float handleWheelie (float dt);
float getActualWheelForce();
bool isOnGround () const;
bool isEliminated () const {return m_eliminated;}
void eliminate ();
bool isRescue () const {return m_rescue;}
void resetBrakes ();
void adjustSpeedWeight(float f);

View File

@ -219,6 +219,7 @@ void PlayerKart::reset()
m_controls.jump = false;
m_penalty_time = 0;
m_time_last_crash_sound = -10.0f;
m_camera->setMode(Camera::CM_NORMAL); // can be changed if camera was eliminated
m_camera->setReverseHeading(false);
Kart::reset();
} // reset

View File

@ -204,11 +204,23 @@ void RaceManager::exit_race()
//-----------------------------------------------------------------------------
void RaceManager::addKartResult(int kart, int pos, float time)
{
// In follow the leader mode, kart 0 does not get any points,
// so the position of each kart is actually one better --> decrease pos
if(m_race_mode==RM_FOLLOW_LEADER)
{
pos--;
// If the position is negative (i.e. follow leader and kart on
// position 0) set the score of this kart to the lowest possible
// score, since the kart is ahead of the leader
if(pos<=0) pos=stk_config->m_max_karts;
}
m_kart_status[kart].m_score += m_score_for_position[pos-1];
m_kart_status[kart].m_last_score = m_score_for_position[pos-1];
m_kart_status[kart].m_overall_time += time;
m_kart_status[kart].m_last_time = time;
} // addKartResult
//-----------------------------------------------------------------------------
void RaceManager::restartRace()
{

View File

@ -87,6 +87,12 @@ private:
unsigned int m_num_finished_players;
void startNextRace(); // start a next race
friend bool operator< (const KartStatus& left, const KartStatus& right)
{
return (left.m_score < right.m_score);
}
public:
bool m_active_race; //True if there is a race
@ -119,10 +125,12 @@ public:
{ return m_kart_status[kart].m_ident;}
const std::string& getHerringStyle() const
{ return m_cup.getHerringStyle(); }
int getKartScore(int kart) const { return m_kart_status[kart].m_score;}
int getPositionScore(int p) const { return m_score_for_position[p-1];}
double getOverallTime(int kart) const {return m_kart_status[kart].m_overall_time;}
int getKartScore(int krt) const { return m_kart_status[krt].m_score;}
int getPositionScore(int p) const { return m_score_for_position[p-1]; }
double getOverallTime(int kart) const { return m_kart_status[kart].m_overall_time;}
bool isEliminated(int kart) const { return m_kart_status[kart].m_is_eliminated;}
bool raceHasLaps() const { return m_race_mode!=RM_FOLLOW_LEADER;}
void eliminate(int kart) { m_kart_status[kart].m_is_eliminated=true;}
void addFinishedKarts(int num) { m_num_finished_karts += num; }
void PlayerFinishes() { m_num_finished_players++; }
int allPlayerFinished() const {return m_num_finished_players==m_player_karts.size();}
@ -136,13 +144,6 @@ public:
void next(); // start the next race or go back to the start screen
void restartRace(); // restart same race again
void exit_race(); // exit a race (and don't start the next one)
friend bool operator< (const KartStatus& left, const KartStatus& right)
{
return (left.m_score < right.m_score);
}
};
extern RaceManager *race_manager;

View File

@ -556,7 +556,7 @@ void DefaultRobot::check_crashes( const int STEPS, sgVec3 const pos )
m_crashes.clear();
const size_t NUM_KARTS = world->getNumKarts();
const size_t NUM_KARTS = race_manager->getNumKarts();
//Protection against having vel_normal with nan values
const btVector3 &VEL = getVelocity();
@ -581,7 +581,8 @@ void DefaultRobot::check_crashes( const int STEPS, sgVec3 const pos )
{
for( unsigned int j = 0; j < NUM_KARTS; ++j )
{
if(world->getKart(j) == this) continue;
const Kart* kart=world->getKart(j);
if(kart==this||kart->isEliminated()) continue; // ignore eliminated karts
kart_distance = sgDistanceVec2( step_coord,
world->getKart(j)->getCoord()->xyz );

View File

@ -135,7 +135,7 @@ void Scene::draw(float dt)
for (Cameras::iterator i = m_cameras.begin(); i != m_cameras.end(); ++i)
{
(*i)->update(dt);
(*i) -> apply () ;
(*i)->apply ();
if(!user_config->m_bullet_debug)
{
@ -179,15 +179,16 @@ void Scene::draw(float dt)
glFrustum(-f, f, -f, f, 1.0, 1000.0);
btVector3 pos;
sgCoord *c = world->getKart(world->getNumKarts()-1)->getCoord();
sgCoord *c = world->getKart(race_manager->getNumKarts()-1)->getCoord();
gluLookAt(c->xyz[0], c->xyz[1]-5.f, c->xyz[2]+4,
c->xyz[0], c->xyz[1], c->xyz[2],
0.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
for (World::Karts::size_type i = 0 ; i < world->getNumKarts(); ++i)
for (World::Karts::size_type i = 0 ; i < race_manager->getNumKarts(); ++i)
{
world->getKart((int)i)->draw();
Kart *kart=world->getKart((int)i);
if(!kart->isEliminated()) kart->draw();
}
world->getPhysics()->draw();
} // bullet_debug

98
src/smoke.cpp Executable file
View File

@ -0,0 +1,98 @@
// $Id: dust_cloud.cpp 1681 2008-04-09 13:52:48Z hikerstk $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2006 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// 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 "smoke.hpp"
#include "kart.hpp"
Smoke::Smoke(Kart* kart_,
int num, float _create_rate, int _ttf,
float sz, float bsphere_size)
: ParticleSystem (num, _create_rate, _ttf, sz, bsphere_size),
m_kart(kart_)
{
getBSphere () -> setCenter ( 0, 0, 0 ) ;
getBSphere () -> setRadius ( 1000.0f ) ;
dirtyBSphere();
} // KartParticleSystem
//-----------------------------------------------------------------------------
void Smoke::update ( float t )
{
#if 0
std::cout << "BSphere: r:" << getBSphere()->radius
<< " (" << getBSphere()->center[0]
<< ", " << getBSphere()->center[1]
<< ", " << getBSphere()->center[2]
<< ")"
<< std::endl;
#endif
getBSphere () -> setRadius ( 1000.0f ) ;
ParticleSystem::update(t);
} // update
//-----------------------------------------------------------------------------
void Smoke::particle_create(int, Particle *p)
{
sgSetVec4 ( p -> m_col, 1, 1, 1, 1 ) ; /* initially white */
sgSetVec3 ( p -> m_pos, 0, 0, 0 ) ; /* start off on the ground */
sgSetVec3 ( p -> m_vel, 0, 0, 0 ) ;
sgSetVec3 ( p -> m_acc, 0, 0, 2.0f ) ; /* Gravity */
p -> m_size = .5f;
p -> m_time_to_live = 0.5 ; /* Droplets evaporate after 5 seconds */
const sgCoord* POS = m_kart->getCoord();
const btVector3 VEL = m_kart->getVelocity();
const float X_DIRECTION = sgCos (POS->hpr[0] - 90.0f); // Point at the rear
const float Y_DIRECTION = sgSin (POS->hpr[0] - 90.0f); // Point at the rear
sgCopyVec3 (p->m_pos, POS->xyz);
p->m_pos[0] += X_DIRECTION * 0.7f;
p->m_pos[1] += Y_DIRECTION * 0.7f;
const float ABS_VEL = sqrt((VEL.getX() * VEL.getX()) + (VEL.getY() * VEL.getY()));
p->m_vel[0] = X_DIRECTION * -ABS_VEL/2;
p->m_vel[1] = Y_DIRECTION * -ABS_VEL/2;
p->m_vel[0] += sgCos ((float)(rand()%180));
p->m_vel[1] += sgSin ((float)(rand()%180));
p->m_vel[2] += sgSin ((float)(rand()%100));
getBSphere () -> setCenter ( POS->xyz[0], POS->xyz[1], POS->xyz[2] ) ;
} // particle_create
//-----------------------------------------------------------------------------
void Smoke::particle_update (float delta, int,
Particle * particle)
{
particle->m_size += delta*2.0f;
particle->m_col[3] -= delta * 2.0f;
particle->m_pos[0] += particle->m_vel[0] * delta;
particle->m_pos[1] += particle->m_vel[1] * delta;
particle->m_pos[2] += particle->m_vel[2] * delta;
} // particle_update
//-----------------------------------------------------------------------------
void Smoke::particle_delete (int , Particle* )
{} // particle_delete

41
src/smoke.hpp Executable file
View File

@ -0,0 +1,41 @@
// $Id: dust_cloud.hpp 1681 2008-04-09 13:52:48Z hikerstk $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2006 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// 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 HEADER_SMOKE_H
#define HEADER_SMOKE_H
#include <plib/sg.h>
#include "particle_system.hpp"
class Kart;
class Smoke : public ParticleSystem
{
private:
Kart* m_kart;
public:
Smoke(Kart* kart, int num, float _create_rate,
int _turn_to_face, float sz, float bsphere_size);
virtual void update (float t );
virtual void particle_create(int index, Particle* p );
virtual void particle_update(float deltaTime, int index, Particle *p );
virtual void particle_delete(int index, Particle* p );
};
#endif

View File

@ -62,6 +62,11 @@ void STKConfig::load(const std::string filename)
fprintf(stderr,"Not or not enough scores defined in stk_config");
exit(-1);
}
if(m_leader_intervals.size()==0)
{
fprintf(stderr,"No follow leader interval(s) defined in stk_config");
exit(-1);
}
CHECK_NEG(m_max_karts, "max-karts" );
CHECK_NEG(m_grid_order, "grid-order" );
@ -148,6 +153,7 @@ void STKConfig::init_defaults()
m_grid_order = -100;
m_title_music = NULL;
m_scores.clear();
m_leader_intervals.clear();
} // init_defaults
//-----------------------------------------------------------------------------
@ -166,6 +172,7 @@ void STKConfig::getAllData(const lisp::Lisp* lisp)
lisp->get("jump-impulse", m_jump_impulse );
lisp->get("bomb-time", m_bomb_time );
lisp->get("bomb-time-increase", m_bomb_time_increase );
lisp->getVector("leader-intervals", m_leader_intervals );
lisp->get("anvil-time", m_anvil_time );
lisp->get("zipper-time", m_zipper_time );
lisp->get("zipper-force", m_zipper_force );

View File

@ -46,6 +46,8 @@ public:
float m_explosion_impulse_objects;// impulse of explosion on moving objects, e.g. road cones, ...
int m_max_karts; // maximum number of karts
int m_grid_order; // whether grand prix grid is in point or reverse point order
std::vector<float>
m_leader_intervals; // interval in follow the leader till last kart is reomved
std::vector<int> m_scores; // scores depending on position
MusicInformation* m_title_music; // filename of the title music to play

View File

@ -22,6 +22,7 @@
#include "challenges/all_tracks.hpp"
#include "challenges/energy_math_class.hpp"
#include "challenges/win_gotm_cup.hpp"
#include "challenges/race_track_time.hpp"
#include "user_config.hpp"
UnlockManager* unlock_manager=0;
@ -39,6 +40,7 @@ UnlockManager::UnlockManager()
c=new AllTracks(); m_all_challenges[c->getId()]=c;
c=new EnergyMathClass(); m_all_challenges[c->getId()]=c;
c=new WinGOTMCup(); m_all_challenges[c->getId()]=c;
c=new RaceTrackTime(); m_all_challenges[c->getId()]=c;
computeActive();
} // UnlockManager

View File

@ -49,7 +49,6 @@
# include "replay_player.hpp"
#endif
#if defined(WIN32) && !defined(__CYGWIN__)
# define snprintf _snprintf
#endif
@ -62,14 +61,15 @@ World::World()
#endif
{
delete world;
world = this;
m_phase = SETUP_PHASE;
m_track = NULL;
m_clock = 0.0f;
m_fastest_lap = 9999999.9f;
m_fastest_kart = 0;
world = this;
m_phase = SETUP_PHASE;
m_track = NULL;
m_clock = 0.0f;
m_fastest_lap = 9999999.9f;
m_fastest_kart = 0;
m_eliminated_karts = 0;
m_eliminated_players = 0;
m_leader_intervals = stk_config->m_leader_intervals;
// Grab the track file
try
@ -251,6 +251,11 @@ void World::update(float dt)
if( getPhase() == FINISH_PHASE )
{
if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER)
{
menu_manager->pushMenu(MENUID_LEADERRESULT);
return;
}
// Add times to highscore list. First compute the order of karts,
// so that the timing of the fastest kart is added first (otherwise
// someone might get into the highscore list, only to be kicked out
@ -290,9 +295,10 @@ void World::update(float dt)
}
if(!user_config->m_replay_history) history->StoreDelta(dt);
m_physics->update(dt);
for ( Karts::size_type i = 0 ; i < m_kart.size(); ++i)
for (int i = 0 ; i <(int) m_kart.size(); ++i)
{
m_kart[i]->update(dt) ;
// Update all karts that are not eliminated
if(!race_manager->isEliminated(i)) m_kart[i]->update(dt) ;
}
projectile_manager->update(dt);
@ -300,8 +306,9 @@ void World::update(float dt)
for ( Karts::size_type i = 0 ; i < m_kart.size(); ++i)
{
if(!m_kart[i]) continue; // ignore eliminated kart
if(!m_kart[i]->raceIsFinished()) updateRacePosition((int)i);
m_kart[i]->addMessages();
if(m_kart[i]->isPlayerKart()) m_kart[i]->addMessages(); // add 'wrong direction'
}
/* Routine stuff we do even when paused */
@ -412,7 +419,10 @@ void World::updateRaceStatus(float dt)
case SET_PHASE : if(m_clock>2.0)
{
m_phase=GO_PHASE;
m_clock=0.0f;
if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER)
m_clock=m_leader_intervals[0];
else
m_clock=0.0f;
sound_manager->playSfx(SOUND_START);
// Reset the brakes now that the prestart
// phase is over (braking prevents the karts
@ -427,9 +437,57 @@ void World::updateRaceStatus(float dt)
#endif
}
break;
case GO_PHASE : if(m_clock>1.0) m_phase=RACE_PHASE; break;
case GO_PHASE : if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER)
{
// Switch to race if more than 1 second has past
if(m_clock<m_leader_intervals[0]-1.0f)
m_phase=RACE_PHASE;
}
else
{
if(m_clock>1.0) // how long to display the 'go' message
m_phase=RACE_PHASE;
}
break;
default : break;
} // switch
if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER)
{
// Count 'normal' till race phase has started, then count backwards
if(m_phase==RACE_PHASE || m_phase==GO_PHASE)
m_clock -=dt;
else
m_clock +=dt;
if(m_clock<0.0f)
{
if(m_leader_intervals.size()>1)
m_leader_intervals.erase(m_leader_intervals.begin());
m_clock=m_leader_intervals[0];
int kart_number;
for (kart_number=0; kart_number<(int)m_kart.size(); kart_number++)
{
if(m_kart[kart_number]->isEliminated()) continue;
if(m_kart[kart_number]->getPosition()==getCurrentNumKarts())
break;
}
assert(kart_number!=m_kart.size());
removeKart(kart_number);
// The follow the leader race is over if there isonly one kart left,
// or if all players have gone
if(getCurrentNumKarts()==2 ||getCurrentNumPlayers()==0)
{
// Add the results for the remaining kart
for(int i=1; i<(int)race_manager->getNumKarts(); i++)
if(!m_kart[i]->isEliminated())
race_manager->addKartResult(i, m_kart[i]->getPosition(),
m_clock);
m_phase=FINISH_PHASE;
return;
}
} // m_clock<0
return;
} // if is follow leader mode
// Now handling of normal race
// ===========================
@ -442,6 +500,7 @@ void World::updateRaceStatus(float dt)
int new_finished_karts = 0;
for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
{
if(m_kart[i]->isEliminated()) continue;
// FIXME: this part should be done as part of Kart::update
if ((m_kart[i]->getLap () >= race_manager->getNumLaps()) && !m_kart[i]->raceIsFinished())
{
@ -521,6 +580,53 @@ void World::updateRaceStatus(float dt)
if(m_phase==FINISH_PHASE) unlock_manager->raceFinished();
} // updateRaceStatus
//-----------------------------------------------------------------------------
/** Called in follow-leader-mode to remove the last kart
*/
void World::removeKart(int kart_number)
{
Kart *kart = m_kart[kart_number];
// Display a message about the eliminated kart in the race gui
RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
if(m)
{
for (std::vector<PlayerKart*>::iterator i = m_player_karts.begin();
i != m_player_karts.end(); i++ )
{
if(*i==kart)
{
m->addMessage(_("You have been\neliminated!"), *i, 2.0f, 60);
}
else
{
char s[MAX_MESSAGE_LENGTH];
snprintf(s, MAX_MESSAGE_LENGTH,_("'%s' has\nbeen eliminated."),
kart->getName().c_str());
m->addMessage( s, *i, 2.0f, 60);
}
} // for i in kart
} // if raceMenu exist
if(kart->isPlayerKart())
{
// Change the camera so that it will be attached to the leader
// and facing backwards.
Camera* camera=((PlayerKart*)kart)->getCamera();
camera->setMode(Camera::CM_LEADER_MODE);
m_eliminated_players++;
}
// The kart can't be eliminated, since otherwise a race can't be restarted.
// So it's only marked to be eliminated (and ignored in all loops). Important:
// world->getCurrentNumKarts() returns the number of still racing karts. This
// value can not be used for loops over all karts, use race_manager->getNumKarts()
// instead!
race_manager->addKartResult(kart_number, kart->getPosition(), m_clock);
race_manager->eliminate(kart_number);
kart->eliminate();
m_eliminated_karts++;
} // removeKart
//-----------------------------------------------------------------------------
void World::updateRacePosition ( int k )
{
@ -530,7 +636,8 @@ void World::updateRacePosition ( int k )
for ( Karts::size_type j = 0 ; j < m_kart.size() ; ++j )
{
if ( int(j) == k ) continue ;
if(int(j) == k) continue;
if(!m_kart[j]) continue; // eliminated karts
// Count karts ahead of the current kart, i.e. kart that are already
// finished (the current kart k has not yet finished!!), have done more
@ -542,10 +649,9 @@ void World::updateRacePosition ( int k )
p++ ;
}
m_kart [ k ] -> setPosition ( p ) ;
m_kart[k]->setPosition(p);
} // updateRacePosition
//-----------------------------------------------------------------------------
void World::loadTrack()
{
@ -588,8 +694,11 @@ void World::loadTrack()
//-----------------------------------------------------------------------------
void World::restartRace()
{
m_clock = 0.0f;
m_phase = SETUP_PHASE;
m_clock = 0.0f;
m_phase = SETUP_PHASE;
m_eliminated_karts = 0;
m_eliminated_players = 0;
m_leader_intervals = stk_config->m_leader_intervals;
for ( Karts::iterator i = m_kart.begin(); i != m_kart.end() ; ++i )
{

View File

@ -90,8 +90,10 @@ public:
kartId < int(m_kart.size()));
return m_kart[kartId];
}
unsigned int getNumKarts() const {return (int)m_kart.size(); }
unsigned int getNumPlayers() const {return (unsigned int)m_player_karts.size();}
unsigned int getCurrentNumKarts() const { return (int)m_kart.size()-
m_eliminated_karts; }
unsigned int getCurrentNumPlayers() const { return (int)m_player_karts.size()-
m_eliminated_players; }
/** Returns the phase of the game */
Phase getPhase() const { return m_phase; }
@ -116,11 +118,15 @@ private:
Highscores* m_highscores;
Phase m_phase;
float m_clock;
void updateRacePosition( int k );
void loadTrack();
void updateRaceStatus(float dt);
void resetAllKarts();
int m_eliminated_karts; // number of eliminated karts
int m_eliminated_players; // number of eliminated players
std::vector<float>
m_leader_intervals; // time till elimination in follow leader
void updateRacePosition( int k );
void loadTrack();
void updateRaceStatus(float dt);
void resetAllKarts();
void removeKart(int kart_number);
Kart* loadRobot(const std::string& kart_name, int position,
sgCoord init_pos);