1) Added network kart type.

2) Modified menu handling for clients (i.e. skip game mode select etc).
3) Added more (currently mostly empty) network functions.
4) Added missing network manager from previous commit.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@2222 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2008-09-07 13:25:58 +00:00
parent 2f2197308d
commit 78f8c60934
15 changed files with 2235 additions and 1871 deletions

View File

@ -37,7 +37,9 @@
#else
# define CONFIGDIR ".supertuxkart"
#endif
#include "plib/ul.h"
// ul.h includes windows.h, so this define is necessary
#define _WINSOCKAPI_
#include <plib/ul.h>
#include "file_manager.hpp"
#include "world.hpp"
#include "btBulletDynamicsCommon.h"

View File

@ -17,7 +17,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <cstdlib>
//#include <cstdlib>
#ifdef __APPLE__
# include <OpenGL/gl.h>

View File

@ -31,6 +31,8 @@
#include "material.hpp"
#include "unlock_manager.hpp"
#include "translation.hpp"
#include "network_manager.hpp"
#if defined(WIN32) && !defined(__CYGWIN__)
# define snprintf _snprintf
#endif
@ -389,10 +391,16 @@ void CharSel::select()
}
}
if (race_manager->getMajorMode() == RaceManager::RM_GRAND_PRIX)
menu_manager->pushMenu(MENUID_GRANDPRIXSELECT);
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
{
}
else
menu_manager->pushMenu(MENUID_TRACKSEL);
{
if (race_manager->getMajorMode() == RaceManager::RM_GRAND_PRIX)
menu_manager->pushMenu(MENUID_GRANDPRIXSELECT);
else
menu_manager->pushMenu(MENUID_TRACKSEL);
}
} // select
//----------------------------------------------------------------------------

View File

@ -26,6 +26,7 @@
#include "translation.hpp"
#include "user_config.hpp"
#include "unlock_manager.hpp"
#include "network_manager.hpp"
enum WidgetTokens
{
@ -48,7 +49,8 @@ MainMenu::MainMenu()
widget_manager->addTextButtonWgt( WTOK_MULTI, WIDTH, 7, _("Multiplayer") );
std::vector<const Challenge*> all_challenges=unlock_manager->getActiveChallenges();
if(all_challenges.size()>0)
// Only allow challenges if not networking for now!
if(all_challenges.size()>0 && network_manager->getMode()==NetworkManager::NW_NONE)
{
widget_manager->addTextButtonWgt( WTOK_CHALLENGES, WIDTH, 7, _("Challenges") );
}
@ -88,7 +90,16 @@ void MainMenu::select()
{
case WTOK_SINGLE:
race_manager->setNumPlayers(1);
menu_manager->pushMenu(MENUID_GAMEMODE);
// The clients do not do any mode selection, they go immediately
// to the character selection screen.
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
{
menu_manager->pushMenu(MENUID_CHARSEL_P1);
}
else
{
menu_manager->pushMenu(MENUID_GAMEMODE);
}
break;
case WTOK_MULTI:
menu_manager->pushMenu(MENUID_NUMPLAYERS);

View File

@ -22,6 +22,7 @@
#include "widget_manager.hpp"
#include "menu_manager.hpp"
#include "translation.hpp"
#include "network_manager.hpp"
enum WidgetTokens
{
@ -63,7 +64,10 @@ void NumPlayers::select()
case WTOK_PLAYER_3:
case WTOK_PLAYER_4:
race_manager->setNumPlayers(widget_manager->getSelectedWgt());
menu_manager->pushMenu(MENUID_GAMEMODE);
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
menu_manager->pushMenu(MENUID_CHARSEL_P1);
else
menu_manager->pushMenu(MENUID_GAMEMODE);
break;
case WTOK_QUIT:
menu_manager->popMenu();

View File

@ -23,6 +23,8 @@
#include "material_manager.hpp"
#include "unlock_manager.hpp"
#include "translation.hpp"
#include "network_manager.hpp"
#if defined(WIN32) && !defined(__CYGWIN__)
# define snprintf _snprintf
#endif
@ -53,6 +55,16 @@ enum WidgetTokens
RaceOptions::RaceOptions()
{
// First update the server's race_manager with the number of players
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
{
network_manager->sendKartsInformationToServer();
}
else if(network_manager->getMode()==NetworkManager::NW_SERVER)
{
network_manager->waitForKartsInformation();
}
m_difficulty=race_manager->getDifficulty();
// FIXME: no medium AI atm
if(m_difficulty==RaceManager::RD_MEDIUM) m_difficulty=RaceManager::RD_HARD;
@ -269,6 +281,14 @@ void RaceOptions::select()
}
menu_manager->pushMenu(MENUID_START_RACE_FEEDBACK);
if(network_manager->getMode()==NetworkManager::NW_SERVER)
{
network_manager->sendRaceInformationToClients();
}
else if(network_manager->getMode()==NetworkManager::NW_CLIENT)
{
network_manager->waitForRaceInformation();
}
break;
case WTOK_QUIT:
menu_manager->popMenu();

View File

@ -20,6 +20,8 @@
#ifndef HEADER_HERRING_H
#define HEADER_HERRING_H
// num_players triggers 'already defined' messages without the WINSOCKAPI define. Don't ask me :(
#define _WINSOCKAPI_
#include <plib/sg.h>
#include "coord.hpp"
@ -27,7 +29,7 @@ class Kart;
class ssgTransform;
class ssgEntity;
// HE_RED ust be the first, HE_SILVER the last entry. See HerringManager
// HE_RED must be the first, HE_SILVER the last entry. See HerringManager
enum herringType { HE_RED, HE_GREEN, HE_GOLD, HE_SILVER };
// -----------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@
# ifdef __CYGWIN__
# include <unistd.h>
# endif
# define _WINSOCKAPI_
# include <windows.h>
# ifdef _MSC_VER
# include <io.h>
@ -125,7 +126,6 @@ void cmdLineHelp (char* invocation)
int handleCmdLine(int argc, char **argv)
{
int n;
char s[80];
for(int i=1; i<argc; i++)
{
if(argv[i][0] != '-') continue;
@ -172,11 +172,6 @@ int handleCmdLine(int argc, char **argv)
{
network_manager->setPort(n);
}
else if( sscanf(argv[i], "--client=%s", s) )
{
network_manager->setMode(NetworkManager::NW_CLIENT);
network_manager->setServerIP(s);
}
else if( sscanf(argv[i], "--numclients=%d", &n) )
{
network_manager->setNumClients(n);
@ -534,12 +529,10 @@ int main(int argc, char *argv[] )
exit(-3);
}
if(!network_manager->initialiseConnections())
{
fprintf(stderr, "Problems initialising network connections, aborting.\n");
exit(-4);
}
exit(0);
if(!network_manager->initialiseConnections())
{
fprintf(stderr, "Problems initialising network connections, aborting.\n");
}
// Not replaying
// =============

231
src/network_manager.cpp Normal file
View File

@ -0,0 +1,231 @@
// $Id: network_manager.hpp 2128 2008-06-13 00:53:52Z cosmosninja $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2008 Joerg Henrichs, Stephen Leak
//
// 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 "network_manager.hpp"
#include "stk_config.hpp"
NetworkManager* network_manager = 0;
NetworkManager::NetworkManager()
{
m_mode = NW_NONE;
m_state = NS_SYNCHRONISING;
m_port = 12345;
m_server_address = "172.31.41.53";
m_num_clients = 0;
#ifdef HAVE_ENET
if (enet_initialize () != 0)
{
fprintf (stderr, "An error occurred while initializing ENet.\n");
exit(-1);
}
#endif
} // NetworkManager
// -----------------------------------------------------------------------------
bool NetworkManager::initialiseConnections()
{
switch(m_mode)
{
case NW_NONE: return true;
case NW_CLIENT: return initClient();
case NW_SERVER: return initServer();
}
return true;
} // NetworkManager
// -----------------------------------------------------------------------------
NetworkManager::~NetworkManager()
{
#ifdef HAVE_ENET
if(m_mode==NW_SERVER || m_mode==NW_CLIENT) enet_host_destroy(m_host);
enet_deinitialize();
#endif
} // ~NetworkManager
// -----------------------------------------------------------------------------
bool NetworkManager::initServer()
{
#ifdef HAVE_ENET
fprintf(stderr, "Initialising server, listening on %d\n", m_port);
ENetAddress address;
address.host = ENET_HOST_ANY;
address.port = m_port;
m_host = enet_host_create (& address /* the address to bind the server host to */,
stk_config->m_max_karts /* number of connections */,
0 /* incoming bandwidth */,
0 /* outgoing bandwidth */ );
if (m_host == NULL)
{
fprintf (stderr,
"An error occurred while trying to create an ENet server host.\n"
"Progressing in non-network mode\n");
m_mode = NW_NONE;
return false;
}
fprintf(stderr, "Server initialised, waiting for connections ...\n");
return true;
#endif
} // initServer
// -----------------------------------------------------------------------------
bool NetworkManager::initClient()
{
fprintf(stderr, "Initialising client\n");
#ifdef HAVE_ENET
m_host = enet_host_create (NULL /* create a client host */,
1 /* only allow 1 outgoing connection */,
0 /* downstream bandwidth unlimited */,
0 /* upstream bandwidth unlimited */ );
if (m_host == NULL)
{
fprintf (stderr,
"An error occurred while trying to create an ENet client host.\n");
return false;
}
ENetAddress address;
ENetEvent event;
ENetPeer *peer;
enet_address_set_host (& address, m_server_address.c_str());
address.port = m_port;
/* Initiate the connection, allocating the two channels 0 and 1. */
peer = enet_host_connect (m_host, &address, 2);
if (peer == NULL)
{
fprintf (stderr,
"No available peers for initiating an ENet connection.\n");
return false;
}
/* Wait up to 5 seconds for the connection attempt to succeed. */
if (enet_host_service (m_host, & event, 5000) > 0 &&
event.type == ENET_EVENT_TYPE_CONNECT)
{
fprintf(stderr, "Connection to %s:%d succeeded.",
m_server_address.c_str(), m_port);
enet_host_service(m_host, &event, 1000);
}
else
{
/* Either the 5 seconds are up or a disconnect event was */
/* received. Reset the peer in the event the 5 seconds */
/* had run out without any significant event. */
enet_peer_reset (peer);
fprintf(stderr, "Connection to '%s:%d' failed.",
m_server_address.c_str(), m_port);
}
return true;
#endif
} // initServer
// ----------------------------------------------------------------------------
void NetworkManager::handleNewConnection(ENetEvent *event)
{
if(m_state!=NS_SYNCHRONISING)
{
// We don't accept connections atm
return;
}
m_num_clients++;
fprintf (stderr, "A new client connected from %x:%u. Connected: %d.\n",
event->peer -> address.host,
event->peer -> address.port, m_num_clients);
} // handleNewConnection
// ----------------------------------------------------------------------------
void NetworkManager::handleDisconnection(ENetEvent *event)
{
if(m_state!=NS_SYNCHRONISING)
{
fprintf(stderr, "Disconnect while in race - close your eyes and hope for the best.\n");
return;
}
fprintf(stderr, "%x:%d disconected.\n", event->peer->address.host,
event->peer->address.port );
m_num_clients--;
} // handleDisconnection
// ----------------------------------------------------------------------------
void NetworkManager::handleNewMessage(ENetEvent *event)
{
if(m_state==NS_SYNCHRONISING)
{
fprintf(stderr, "Received a receive event while waiting for client - ignored.\n");
return;
}
} // handleNewMessage
// ----------------------------------------------------------------------------
void NetworkManager::update(float dt)
{
ENetEvent event;
int result = enet_host_service (m_host, &event, 1);
if(result==0) return;
if(result<0)
{
fprintf(stderr, "Error while receiving messages -> ignored.\n");
return;
}
switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT: handleNewConnection(&event); break;
case ENET_EVENT_TYPE_RECEIVE: handleNewMessage(&event); break;
case ENET_EVENT_TYPE_DISCONNECT: handleDisconnection(&event); break;
case ENET_EVENT_TYPE_NONE: break;
}
} // update
// ----------------------------------------------------------------------------
/** Send race_manager->getNumPlayers(), the kart and the name of each
player to the server.
*/
void NetworkManager::sendKartsInformationToServer()
{
} // sendKartsInformationToServer
// ----------------------------------------------------------------------------
/** Receive and store the information from sendKartsInformation()
*/
void NetworkManager::waitForKartsInformation()
{
} // waitForKartsInformation
// ----------------------------------------------------------------------------
/** Sends the information from the race_manager to all clients.
*/
void NetworkManager::sendRaceInformationToClients()
{
} // sendRaceInformationToClients
// ----------------------------------------------------------------------------
/** Receives and sets the race_manager information.
*/
void NetworkManager::waitForRaceInformation()
{
} // waitForRaceInformation
// ----------------------------------------------------------------------------

76
src/network_manager.hpp Normal file
View File

@ -0,0 +1,76 @@
// $Id: network_manager.hpp 2128 2008-06-13 00:53:52Z cosmosninja $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2008 Joerg Henrichs, Stephen Leak
//
// 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 HEADER_NETWORK_MANAGER_H
#define HEADER_NETWORK_MANAGER_H
#include <string>
#ifdef HAVE_ENET
# include "enet/enet.h"
#endif
class NetworkManager
{
public:
// The mode the network manager is operating in
enum NetworkMode {NW_SERVER, NW_CLIENT, NW_NONE};
// The current state.
enum NetworkState {NS_SYNCHRONISING, NS_RACING};
private:
NetworkMode m_mode;
NetworkState m_state;
int m_port;
std::string m_server_address;
int m_num_clients;
#ifdef HAVE_ENET
ENetHost *m_host;
#endif
bool initServer();
bool initClient();
void handleNewConnection(ENetEvent *event);
void handleNewMessage (ENetEvent *event);
void handleDisconnection(ENetEvent *event);
public:
NetworkManager();
~NetworkManager();
void setMode(NetworkMode m) {m_mode = m; }
NetworkMode getMode() const {return m_mode; }
void setState(NetworkState s) {m_state = s; }
NetworkState getState() const {return m_state; }
void setNumClients(int n) {m_num_clients = n; }
int getNumClients() const {return m_num_clients;}
void setPort(int p) {m_port=p; }
void setServerIP(const std::string &s) {m_server_address=s; }
bool initialiseConnections();
void update(float dt);
void sendKartsInformationToServer();
void waitForKartsInformation();
void sendRaceInformationToClients();
void waitForRaceInformation();
};
extern NetworkManager *network_manager;
#endif

View File

@ -161,13 +161,13 @@ void PlayerKart::update(float dt)
m_penalty_time=1.0;
// A warning gets displayed in RaceGUI
}
else
else
{
// The call to update is necessary here (even though the kart
// The call to update is necessary here (even though the kart
// shouldn't actually change) to update m_transform. Otherwise
// the camera gets the wrong position.
Kart::update(dt);
}
// the camera gets the wrong position.
Kart::update(dt);
}
return;
}

View File

@ -1,274 +1,276 @@
// $Id$
//
// 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 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 <iostream>
#include "track_manager.hpp"
#include "game_manager.hpp"
#include "kart_properties_manager.hpp"
#include "race_manager.hpp"
#include "unlock_manager.hpp"
#include "gui/menu_manager.hpp"
#include "world.hpp"
#include "scene.hpp"
#include "user_config.hpp"
#include "stk_config.hpp"
RaceManager* race_manager= NULL;
RaceManager::RaceManager()
{
m_num_karts = user_config->m_karts;
m_difficulty = RD_HARD;
m_major_mode = RM_SINGLE;
m_minor_mode = RM_QUICK_RACE;
m_track_number = 0;
m_active_race = false;
m_score_for_position = stk_config->m_scores;
m_coin_target = 0;
setTrack("race");
setPlayerKart(0, "tuxkart");
} // RaceManager
//-----------------------------------------------------------------------------
RaceManager::~RaceManager()
{
} // ~RaceManager
//-----------------------------------------------------------------------------
void RaceManager::reset()
{
m_num_finished_karts = 0;
m_num_finished_players = 0;
} // reset
//-----------------------------------------------------------------------------
void RaceManager::setPlayerKart(unsigned int player, const std::string& kart)
{
if (player >= 0 && player < 4)
{
if (player >= getNumPlayers())
setNumPlayers(player+1);
m_player_karts[player] = kart;
}
else
{
fprintf(stderr, "Warning: player '%d' does not exists.\n", player);
}
} // setPlayerKart
//-----------------------------------------------------------------------------
void RaceManager::setNumPlayers(int num)
{
m_player_karts.resize(num);
for(PlayerKarts::iterator i = m_player_karts.begin(); i != m_player_karts.end(); ++i)
{
if (i->empty())
{
*i = "tuxkart";
}
}
} // setNumPlayers
//-----------------------------------------------------------------------------
void RaceManager::setDifficulty(Difficulty diff)
{
if(diff==RD_SKIDDING)
{
m_difficulty = RD_HARD;
user_config->m_skidding = true;
}
else
{
m_difficulty = diff;
user_config->m_skidding = false;
}
} // setDifficulty
//-----------------------------------------------------------------------------
void RaceManager::setTrack(const std::string& track)
{
m_tracks.clear();
m_tracks.push_back(track);
} // setTrack
//-----------------------------------------------------------------------------
void RaceManager::startNew()
{
if(m_major_mode==RM_GRAND_PRIX) // GP: get tracks and laps from grand prix
{
m_tracks = m_grand_prix.getTracks();
m_num_laps = m_grand_prix.getLaps();
}
assert(m_player_karts.size() > 0);
// command line parameters: negative numbers=all karts
if(m_num_karts < 0 ) m_num_karts = stk_config->m_max_karts;
if((size_t)m_num_karts < m_player_karts.size())
m_num_karts = (int)m_player_karts.size();
// Create the list of all kart names to use
// ========================================
std::vector<std::string> kart_names;
kart_names.resize(m_num_karts);
for(unsigned int i = 0; i < m_player_karts.size(); i++)
{
/*Players position is behind the AI in the first race*/
kart_names[m_num_karts-1 - i] = m_player_karts[m_player_karts.size() - 1 - i];
}
kart_properties_manager->fillWithRandomKarts(kart_names);
// Create the kart status data structure to keep track of scores, times, ...
// ==========================================================================
const int num_ai_karts = m_num_karts - (int)m_player_karts.size();
m_kart_status.clear();
for(int i=0; i<m_num_karts; i++)
{
// AI karts have -1 as player
bool is_player = i>=num_ai_karts; // players start at the back
m_kart_status.push_back(KartStatus(kart_names[i], i,
is_player ? i-num_ai_karts : -1 ) );
} // for i<m_num_karts
// Then start the race with the first track
// ========================================
m_track_number = 0;
startNextRace();
} // startNew
//-----------------------------------------------------------------------------
void RaceManager::startNextRace()
{
m_num_finished_karts = 0;
m_num_finished_players = 0;
// if subsequent race, sort kart status structure
// ==============================================
if (m_track_number > 0)
{
// In follow the leader mode do not change the first kart,
// since it's always the leader.
int offset = (m_minor_mode==RM_FOLLOW_LEADER) ? 1 : 0;
std::sort(m_kart_status.begin()+offset, m_kart_status.end());
//reverse kart order if flagged in stk_config
if (stk_config->m_grid_order)
{
std::reverse(m_kart_status.begin()+offset, m_kart_status.end());
}
} // not first race
// the constructor assigns this object to the global
// variable world. Admittedly a bit ugly, but simplifies
// handling of objects which get created in the constructor
// and need world to be defined.
new World();
m_active_race = true;
} // startNextRace
//-----------------------------------------------------------------------------
void RaceManager::next()
{
m_num_finished_karts = 0;
m_num_finished_players = 0;
m_track_number++;
if(m_track_number<(int)m_tracks.size())
{
scene->clear();
startNextRace();
}
else
{
exit_race();
}
} // next
//-----------------------------------------------------------------------------
void RaceManager::exit_race()
{
// Only display the grand prix result screen if all tracks
// were finished, and not when a race is aborted.
if(m_major_mode==RM_GRAND_PRIX && m_track_number==(int)m_tracks.size())
{
unlock_manager->grandPrixFinished();
menu_manager->switchToGrandPrixEnding();
}
else
{
menu_manager->switchToMainMenu();
}
scene->clear();
delete world;
world = 0;
m_track_number = 0;
m_active_race = false;
} // exit_Race
//-----------------------------------------------------------------------------
// Kart kart has finished the race at the specified time (which can be different
// from world->getClock() in case of setting extrapolated arrival times).
void RaceManager::RaceFinished(const Kart *kart, float time)
{
unsigned i;
for(i=0; i<m_kart_status.size(); i++)
{
if(kart->getIdent()==m_kart_status[i].m_ident) break;
} // for i
if(i>=m_kart_status.size())
{
fprintf(stderr, "Kart '%s' not found. Ignored.\n",kart->getName().c_str());
return;
}
// In follow the leader mode, kart 0 does not get any points,
// so the position of each kart is actually one better --> decrease pos
int pos = kart->getPosition();
if(m_minor_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[i].m_score += m_score_for_position[pos-1];
m_kart_status[i].m_last_score = m_score_for_position[pos-1];
m_kart_status[i].m_overall_time += time;
m_kart_status[i].m_last_time = time;
m_num_finished_karts ++;
if(kart->isPlayerKart()) m_num_finished_players++;
} // raceFinished
//-----------------------------------------------------------------------------
void RaceManager::rerunRace()
{
// Subtract last score from all karts:
for(int i=0; i<m_num_karts; i++)
{
m_kart_status[i].m_score -= m_kart_status[i].m_last_score;
m_kart_status[i].m_overall_time -= m_kart_status[i].m_last_time;
}
world->restartRace();
} // rerunRace
/* EOF */
// $Id$
//
// 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 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 <iostream>
#include "track_manager.hpp"
#include "game_manager.hpp"
#include "kart_properties_manager.hpp"
#include "race_manager.hpp"
#include "unlock_manager.hpp"
#include "gui/menu_manager.hpp"
#include "world.hpp"
#include "scene.hpp"
#include "user_config.hpp"
#include "stk_config.hpp"
RaceManager* race_manager= NULL;
RaceManager::RaceManager()
{
m_num_karts = user_config->m_karts;
m_difficulty = RD_HARD;
m_major_mode = RM_SINGLE;
m_minor_mode = RM_QUICK_RACE;
m_track_number = 0;
m_active_race = false;
m_score_for_position = stk_config->m_scores;
m_coin_target = 0;
setTrack("race");
setPlayerKart(0, "tuxkart");
} // RaceManager
//-----------------------------------------------------------------------------
RaceManager::~RaceManager()
{
} // ~RaceManager
//-----------------------------------------------------------------------------
void RaceManager::reset()
{
m_num_finished_karts = 0;
m_num_finished_players = 0;
} // reset
//-----------------------------------------------------------------------------
void RaceManager::setPlayerKart(unsigned int player, const std::string& kart)
{
if (player >= 0 && player < 4)
{
if (player >= getNumPlayers())
setNumPlayers(player+1);
m_player_karts[player] = kart;
}
else
{
fprintf(stderr, "Warning: player '%d' does not exists.\n", player);
}
} // setPlayerKart
//-----------------------------------------------------------------------------
void RaceManager::setNumPlayers(int num)
{
m_player_karts.resize(num);
for(PlayerKarts::iterator i = m_player_karts.begin(); i != m_player_karts.end(); ++i)
{
if (i->empty())
{
*i = "tuxkart";
}
}
} // setNumPlayers
//-----------------------------------------------------------------------------
void RaceManager::setDifficulty(Difficulty diff)
{
if(diff==RD_SKIDDING)
{
m_difficulty = RD_HARD;
user_config->m_skidding = true;
}
else
{
m_difficulty = diff;
user_config->m_skidding = false;
}
} // setDifficulty
//-----------------------------------------------------------------------------
void RaceManager::setTrack(const std::string& track)
{
m_tracks.clear();
m_tracks.push_back(track);
} // setTrack
//-----------------------------------------------------------------------------
void RaceManager::startNew()
{
if(m_major_mode==RM_GRAND_PRIX) // GP: get tracks and laps from grand prix
{
m_tracks = m_grand_prix.getTracks();
m_num_laps = m_grand_prix.getLaps();
}
assert(m_player_karts.size() > 0);
// command line parameters: negative numbers=all karts
if(m_num_karts < 0 ) m_num_karts = stk_config->m_max_karts;
if((size_t)m_num_karts < m_player_karts.size())
m_num_karts = (int)m_player_karts.size();
// Create the list of all kart names to use
// ========================================
std::vector<std::string> kart_names;
kart_names.resize(m_num_karts);
for(unsigned int i = 0; i < m_player_karts.size(); i++)
{
/*Players position is behind the AI in the first race*/
kart_names[m_num_karts-1 - i] = m_player_karts[m_player_karts.size() - 1 - i];
}
kart_properties_manager->fillWithRandomKarts(kart_names);
// Create the kart status data structure to keep track of scores, times, ...
// ==========================================================================
const int num_ai_karts = m_num_karts - (int)m_player_karts.size();
m_kart_status.clear();
for(int i=0; i<m_num_karts; i++)
{
// AI karts have -1 as player
bool is_player = i>=num_ai_karts; // players start at the back
m_kart_status.push_back(KartStatus(kart_names[i], i,
is_player ? i-num_ai_karts : -1,
is_player ? KT_PLAYER: KT_AI
) );
} // for i<m_num_karts
// Then start the race with the first track
// ========================================
m_track_number = 0;
startNextRace();
} // startNew
//-----------------------------------------------------------------------------
void RaceManager::startNextRace()
{
m_num_finished_karts = 0;
m_num_finished_players = 0;
// if subsequent race, sort kart status structure
// ==============================================
if (m_track_number > 0)
{
// In follow the leader mode do not change the first kart,
// since it's always the leader.
int offset = (m_minor_mode==RM_FOLLOW_LEADER) ? 1 : 0;
std::sort(m_kart_status.begin()+offset, m_kart_status.end());
//reverse kart order if flagged in stk_config
if (stk_config->m_grid_order)
{
std::reverse(m_kart_status.begin()+offset, m_kart_status.end());
}
} // not first race
// the constructor assigns this object to the global
// variable world. Admittedly a bit ugly, but simplifies
// handling of objects which get created in the constructor
// and need world to be defined.
new World();
m_active_race = true;
} // startNextRace
//-----------------------------------------------------------------------------
void RaceManager::next()
{
m_num_finished_karts = 0;
m_num_finished_players = 0;
m_track_number++;
if(m_track_number<(int)m_tracks.size())
{
scene->clear();
startNextRace();
}
else
{
exit_race();
}
} // next
//-----------------------------------------------------------------------------
void RaceManager::exit_race()
{
// Only display the grand prix result screen if all tracks
// were finished, and not when a race is aborted.
if(m_major_mode==RM_GRAND_PRIX && m_track_number==(int)m_tracks.size())
{
unlock_manager->grandPrixFinished();
menu_manager->switchToGrandPrixEnding();
}
else
{
menu_manager->switchToMainMenu();
}
scene->clear();
delete world;
world = 0;
m_track_number = 0;
m_active_race = false;
} // exit_Race
//-----------------------------------------------------------------------------
// Kart kart has finished the race at the specified time (which can be different
// from world->getClock() in case of setting extrapolated arrival times).
void RaceManager::RaceFinished(const Kart *kart, float time)
{
unsigned i;
for(i=0; i<m_kart_status.size(); i++)
{
if(kart->getIdent()==m_kart_status[i].m_ident) break;
} // for i
if(i>=m_kart_status.size())
{
fprintf(stderr, "Kart '%s' not found. Ignored.\n",kart->getName().c_str());
return;
}
// In follow the leader mode, kart 0 does not get any points,
// so the position of each kart is actually one better --> decrease pos
int pos = kart->getPosition();
if(m_minor_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[i].m_score += m_score_for_position[pos-1];
m_kart_status[i].m_last_score = m_score_for_position[pos-1];
m_kart_status[i].m_overall_time += time;
m_kart_status[i].m_last_time = time;
m_num_finished_karts ++;
if(kart->isPlayerKart()) m_num_finished_players++;
} // raceFinished
//-----------------------------------------------------------------------------
void RaceManager::rerunRace()
{
// Subtract last score from all karts:
for(int i=0; i<m_num_karts; i++)
{
m_kart_status[i].m_score -= m_kart_status[i].m_last_score;
m_kart_status[i].m_overall_time -= m_kart_status[i].m_last_time;
}
world->restartRace();
} // rerunRace
/* EOF */

View File

@ -22,8 +22,8 @@
#include <vector>
#include <algorithm>
#include <string>
#include "grand_prix_data.hpp"
/** The race manager has two functions:
@ -49,7 +49,7 @@ public:
enum RaceModeType { RM_GRAND_PRIX, RM_SINGLE, // The two current major modes
RM_QUICK_RACE, RM_TIME_TRIAL, RM_FOLLOW_LEADER };
enum Difficulty { RD_EASY, RD_MEDIUM, RD_HARD, RD_SKIDDING };
enum KartType { KT_PLAYER, KT_NETWORK_PLAYER, KT_AI, KT_LEADER, KT_GHOST };
private:
struct KartStatus
{
@ -59,13 +59,15 @@ private:
double m_overall_time; // sum of times of all races
double m_last_time; // needed for restart
int m_prev_finish_pos; // previous finished position
KartType m_kart_type; // Kart type: AI, player, network player etc.
int m_player_id; // player controling the kart, for AI: -1
KartStatus(const std::string& ident, const int& prev_finish_pos,
const int& player_id) :
const int& player_id, KartType kt) :
m_ident(ident), m_score(0), m_last_score(0),
m_overall_time(0.0f), m_last_time(0.0f),
m_prev_finish_pos(prev_finish_pos), m_player_id(player_id)
m_prev_finish_pos(prev_finish_pos), m_kart_type(kt),
m_player_id(player_id)
{}
}; // KartStatus
@ -139,7 +141,7 @@ public:
int allPlayerFinished() const {return
m_num_finished_players==m_player_karts.size(); }
int raceIsActive() const { return m_active_race; }
bool isPlayer(int kart) const {return m_kart_status[kart].m_player_id>-1; }
KartType getKartType(int kart) const {return m_kart_status[kart].m_kart_type; }
void setMirror() {/*FIXME*/}
void setReverse(){/*FIXME*/}

View File

@ -117,16 +117,21 @@ World::World()
}
else
{
if (race_manager->isPlayer(i))
switch(race_manager->getKartType(i))
{
case RaceManager::KT_PLAYER:
newkart = new PlayerKart(kart_name, position,
&(user_config->m_player[player_id]),
init_pos, player_id);
m_player_karts[player_id] = (PlayerKart*)newkart;
}
else
{
break;
case RaceManager::KT_NETWORK_PLAYER:
break;
case RaceManager::KT_AI:
newkart = loadRobot(kart_name, position, init_pos);
break;
case RaceManager::KT_GHOST:
break;
}
} // if !user_config->m_profile
if(user_config->m_replay_history)