400 lines
18 KiB
C++

//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2004-2015 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_WORLD_HPP
#define HEADER_WORLD_HPP
/**
* \defgroup modes
* Contains the logic for the various game modes (race, follow the leader,
* battle, etc.)
*/
#include <limits>
#include <map>
#include <memory>
#include <vector>
#include <stdexcept>
#include "graphics/weather.hpp"
#include "modes/world_status.hpp"
#include "race/highscores.hpp"
#include "states_screens/race_gui_base.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/random_generator.hpp"
#include "LinearMath/btTransform.h"
class AbstractKart;
class BareNetworkString;
class btRigidBody;
class Controller;
class ItemState;
class PhysicalObject;
class STKPeer;
namespace Scripting
{
class ScriptEngine;
}
namespace irr
{
namespace scene { class ISceneNode; }
}
class AbortWorldUpdateException : public std::runtime_error
{
public:
AbortWorldUpdateException() : std::runtime_error("race abort") { };
};
/**
* \brief base class for all game modes
* This class is responsible for running the actual race. A world is created
* by the race manager on the start of each race (so a new world is created
* for each race of a Grand Prix). It creates the
* physics, loads the track, creates all karts, and initialises the race
* specific managers (ItemManager, ProjectilManager, highscores, ...).
* It uses the information from the race manager to get information like
* what and how many karts, track to load etc. This class does not really
* know about Grand Prixs, a GP is created
* It maintains the race clock, and updates all karts, herings etc. during
* the race.
* Special game modes (e.g. follow the leader) are currently integrated in
* this world, see e.g. updateRaceStatus where the world clock behaviour
* is handled differently to create the count down.
* \ingroup modes
*/
class World : public WorldStatus
{
public:
typedef std::vector<std::shared_ptr<AbstractKart> > KartList;
private:
/** A pointer to the global world object for a race. */
static World *m_world;
// ------------------------------------------------------------------------
void setAITeam();
// ------------------------------------------------------------------------
std::shared_ptr<AbstractKart> createKartWithTeam
(const std::string &kart_ident, int index, int local_player_id,
int global_player_id, RaceManager::KartType type,
PerPlayerDifficulty difficulty);
protected:
#ifdef DEBUG
unsigned int m_magic_number;
#endif
/* Team related variables. */
int m_red_ai;
int m_blue_ai;
std::map<int, KartTeam> m_kart_team_map;
std::map<int, unsigned int> m_kart_position_map;
/** The list of all karts. */
KartList m_karts;
RandomGenerator m_random;
AbstractKart* m_fastest_kart;
/** Number of eliminated karts. */
int m_eliminated_karts;
/** Number of eliminated players. */
int m_eliminated_players;
/** OVerall number of players. */
int m_num_players;
bool m_faster_music_active; // true if faster music was activated
bool m_stop_music_when_dialog_open;
bool m_unfair_team;
/** Whether highscores should be used for this kind of race.
* True by default, change to false in a child class to disable.
*/
bool m_use_highscores;
void updateHighscores (int* best_highscore_rank);
void resetAllKarts ();
Controller*
loadAIController (AbstractKart *kart);
virtual std::shared_ptr<AbstractKart> createKart
(const std::string &kart_ident, int index, int local_player_id,
int global_player_id, RaceManager::KartType type,
PerPlayerDifficulty difficulty);
/** Pointer to the race GUI. The race GUI is handled by world. */
RaceGUIBase *m_race_gui;
/** The actual race gui needs to be saved when the race result gui is
displayed since it is still needed in case of a restart, and it
can't simply be created again (since it assumes that it can render
to texture without having any scene nodes, but in case of a restart
there are scene nodes). */
RaceGUIBase *m_saved_race_gui;
/** Pausing/unpausing are not done immediately, but at next udpdate. The
* use of this is when switching between screens : if we leave a screen
* that paused the game, only to go to another screen that pauses back
* the game, this mechanism prevents the game from moving on between
* the switch. */
bool m_schedule_pause;
/** Pausing/unpausing are not done immediately, but at next udpdate. The
* use of this is when switching between screens : if we leave a screen
* that paused the game, only to go to another screen that pauses back
* the game, this mechanism prevents the game from moving on between the
* switch. */
bool m_schedule_unpause;
bool m_schedule_exit_race;
bool m_schedule_tutorial;
Phase m_scheduled_pause_phase;
/** Set when the world needs to be deleted but you can't do it immediately
* because you are e.g. within World::update()
*/
bool m_self_destruct;
/** Set when the world is online and counts network players. */
bool m_is_network_world;
virtual void onGo() OVERRIDE;
/** Returns true if the race is over. Must be defined by all modes. */
virtual bool isRaceOver() = 0;
virtual void update(int ticks) OVERRIDE;
virtual void createRaceGUI();
void updateTrack(int ticks);
// ------------------------------------------------------------------------
/** Used for AI karts that are still racing when all player kart finished.
* Generally it should estimate the arrival time for those karts, but as
* a default (useful for battle mode and ftl races) we just use the
* current time for this (since this is a good value for karts still
* around at the end of a race, and other criteria (number of lives,
* race position) will be used to determine the final order.
*/
virtual float estimateFinishTimeForKart(AbstractKart* kart)
{return getTime(); }
void updateAchievementDataEndRace();
void updateAchievementModeCounters(bool start);
public:
World();
virtual ~World();
// Static functions to access world:
// =================================
// ------------------------------------------------------------------------
/** Returns a pointer to the (singleton) world object. */
static World* getWorld() { return m_world; }
// ------------------------------------------------------------------------
/** Delete the )singleton) world object, if it exists, and sets the
* singleton pointer to NULL. It's harmless to call this if the world
* has been deleted already. */
static void deleteWorld() { delete m_world; m_world = NULL; }
// ------------------------------------------------------------------------
/** Sets the pointer to the world object. This is only used by
* the race_manager.*/
static void setWorld(World *world) {m_world = world; }
// ------------------------------------------------------------------------
// Pure virtual functions
// ======================
/** Each game mode should have a unique identifier. Override
* this method in child classes to provide it. */
virtual const std::string& getIdent() const = 0;
// ------------------------------------------------------------------------
/** Returns the number of rescue positions on a given track and game
* mode. */
virtual unsigned int getNumberOfRescuePositions() const;
// ------------------------------------------------------------------------
/** Determines the rescue position index of the specified kart. */
virtual unsigned int getRescuePositionIndex(AbstractKart *kart) = 0;
// ------------------------------------------------------------------------
/** Returns the bullet transformation for the specified rescue index. */
virtual btTransform getRescueTransform(unsigned int index) const;
// ------------------------------------------------------------------------
virtual void moveKartAfterRescue(AbstractKart* kart);
// ------------------------------------------------------------------------
/** Called when it is needed to know whether this kind of race involves
* counting laps. */
virtual bool raceHasLaps() = 0;
// ------------------------------------------------------------------------
/** Returns the number of laps for a given kart. Only valid when
* raceHasLaps() - otherwise STK will abort. */
virtual int getFinishedLapsOfKart(unsigned int kart_index) const
{
assert(false); return -1; // remove compiler warning
} // getFinishedLapsOfKart
// ------------------------------------------------------------------------
/** Called by the code that draws the list of karts on the race GUI
* to know what needs to be drawn in the current mode. */
virtual void getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info)= 0;
// ------------------------------------------------------------------------
// Virtual functions
// =================
virtual void init();
virtual void updateGraphics(float dt);
virtual void terminateRace() OVERRIDE;
virtual void reset(bool restart=false) OVERRIDE;
virtual void pause(Phase phase) OVERRIDE;
virtual void unpause() OVERRIDE;
virtual void getDefaultCollectibles(int *collectible_type,
int *amount );
// ------------------------------------------------------------------------
/** Receives notification if an item is collected. Used for easter eggs. */
virtual void collectedItem(const AbstractKart *kart,
const ItemState *item ) {}
// ------------------------------------------------------------------------
virtual void endRaceEarly() { return; }
// ------------------------------------------------------------------------
/** Called to determine whether this race mode uses bonus boxes. */
virtual bool haveBonusBoxes() { return true; }
// ------------------------------------------------------------------------
/** Returns if this mode should use fast music (if available). */
virtual bool useFastMusicNearEnd() const { return true; }
// ------------------------------------------------------------------------
/** If you want to do something to karts or their graphics at the start
* of the race, override this. */
virtual void kartAdded(AbstractKart* kart, scene::ISceneNode* node) {}
// ------------------------------------------------------------------------
/** Called whenever a kart starts a new lap. Meaningless (and won't be
* called) in non-laped races.
*/
virtual void newLap(unsigned int kart_index) {}
// ------------------------------------------------------------------------
/** Called when a kart was hit by a projectile. */
virtual bool kartHit(int kart_id, int hitter = -1) { return false; }
// ------------------------------------------------------------------------
virtual void onMouseClick(int x, int y) {};
// Other functions
// ===============
Highscores *getHighscores() const;
void schedulePause(Phase phase);
void scheduleUnpause();
void scheduleExitRace() { m_schedule_exit_race = true; }
void scheduleTutorial();
void updateWorld(int ticks);
void handleExplosion(const Vec3 &xyz, AbstractKart *kart_hit,
PhysicalObject *object);
AbstractKart* getPlayerKart(unsigned int player) const;
AbstractKart* getLocalPlayerKart(unsigned int n) const;
virtual const btTransform &getStartTransform(int index);
void moveKartTo(AbstractKart* kart, const btTransform &t);
// ------------------------------------------------------------------------
/** Returns a pointer to the race gui. */
RaceGUIBase *getRaceGUI() const { return m_race_gui;}
// ------------------------------------------------------------------------
/** Returns the number of karts in the race. */
unsigned int getNumKarts() const { return (unsigned int) m_karts.size(); }
// ------------------------------------------------------------------------
/** Returns the kart with a given world id. */
AbstractKart *getKart(int kartId) const {
assert(kartId >= 0 && kartId < int(m_karts.size()));
return m_karts[kartId].get(); }
// ------------------------------------------------------------------------
/** Returns all karts. */
const KartList & getKarts() const { return m_karts; }
// ------------------------------------------------------------------------
/** Returns the number of currently active (i.e.non-elikminated) karts. */
unsigned int getCurrentNumKarts() const { return (int)m_karts.size() -
m_eliminated_karts; }
// ------------------------------------------------------------------------
/** Returns the number of currently active (i.e. non-eliminated) players.*/
unsigned int getCurrentNumPlayers() const { return m_num_players -
m_eliminated_players;}
// ------------------------------------------------------------------------
void resetElimination()
{
m_eliminated_karts = 0;
m_eliminated_players = 0;
}
// ------------------------------------------------------------------------
virtual void addReservedKart(int kart_id)
{
if (m_eliminated_karts > 0)
m_eliminated_karts--;
}
// ------------------------------------------------------------------------
virtual void saveCompleteState(BareNetworkString* bns, STKPeer* peer) {}
// ------------------------------------------------------------------------
virtual void restoreCompleteState(const BareNetworkString& buffer) {}
// ------------------------------------------------------------------------
/** The code that draws the timer should call this first to know
* whether the game mode wants a timer drawn. */
virtual bool shouldDrawTimer() const
{ return isActiveRacePhase() && getClockMode() != CLOCK_NONE; }
// ------------------------------------------------------------------------
/** \return whether this world can generate/have highscores */
bool useHighScores() const { return m_use_highscores; }
// ------------------------------------------------------------------------
/** Override if you want to know when a kart presses fire */
virtual void onFirePressed(Controller* who) {}
// ------------------------------------------------------------------------
/** Whether to compute checkline requirements for each world on the
* quadgraph. Override to change value. */
virtual bool useChecklineRequirements() const { return false; }
// ------------------------------------------------------------------------
virtual void escapePressed();
// ------------------------------------------------------------------------
virtual void loadCustomModels() {}
// ------------------------------------------------------------------------
void eliminateKart(int kart_number, bool notify_of_elimination = true);
// ------------------------------------------------------------------------
void setUnfairTeam(bool val) { m_unfair_team = val; }
// ------------------------------------------------------------------------
virtual bool hasTeam() const { return false; }
// ------------------------------------------------------------------------
/** Get the team of kart in world (including AIs) */
KartTeam getKartTeam(unsigned int kart_id) const;
// ------------------------------------------------------------------------
int getTeamNum(KartTeam team) const;
// ------------------------------------------------------------------------
/** Set the network mode (true if networked) */
void setNetworkWorld(bool is_networked) { m_is_network_world = is_networked; }
// ------------------------------------------------------------------------
bool isNetworkWorld() const { return m_is_network_world; }
// ------------------------------------------------------------------------
/** Set the team arrow on karts if necessary*/
void initTeamArrows(AbstractKart* k);
// ------------------------------------------------------------------------
/** Used by server to get the current started game progress in either or
* both remaining time or progress in percent. uint32_t max for either or
* both if not available. */
virtual std::pair<uint32_t, uint32_t> getGameStartedProgress() const
{
return std::make_pair(std::numeric_limits<uint32_t>::max(),
std::numeric_limits<uint32_t>::max());
}
// ------------------------------------------------------------------------
virtual bool isGoalPhase() const { return false; }
}; // World
#endif
/* EOF */