diff --git a/src/config/player_profile.cpp b/src/config/player_profile.cpp index c934ee6d7..fb1bcd269 100644 --- a/src/config/player_profile.cpp +++ b/src/config/player_profile.cpp @@ -99,6 +99,8 @@ PlayerProfile::PlayerProfile(const XMLNode* node) //------------------------------------------------------------------------------ PlayerProfile::~PlayerProfile() { + delete m_story_mode_status; + delete m_achievements_status; #ifdef DEBUG m_magic_number = 0xDEADBEEF; #endif diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index efc52b545..a986707d1 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -370,6 +370,9 @@ void RibbonWidget::add() m_element->setTabOrder(id); m_element->setTabGroup(false); updateSelection(); + + if (!m_is_visible) + setVisible(false); } // add // ---------------------------------------------------------------------------- diff --git a/src/main_loop.cpp b/src/main_loop.cpp index 6c6459755..ff0a2964d 100644 --- a/src/main_loop.cpp +++ b/src/main_loop.cpp @@ -184,7 +184,7 @@ void MainLoop::run() if (STKHost::get()->requestedShutdown()) STKHost::get()->shutdown(); else - ProtocolManager::getInstance()->update(); + ProtocolManager::getInstance()->update(dt); } PROFILER_POP_CPU_MARKER(); @@ -196,7 +196,7 @@ void MainLoop::run() { PROFILER_PUSH_CPU_MARKER("Protocol manager update", 0x7F, 0x00, 0x7F); if(NetworkConfig::get()->isNetworking()) - ProtocolManager::getInstance()->update(); + ProtocolManager::getInstance()->update(dt); PROFILER_POP_CPU_MARKER(); PROFILER_PUSH_CPU_MARKER("Database polling update", 0x00, 0x7F, 0x7F); diff --git a/src/network/protocol.cpp b/src/network/protocol.cpp index 209cead08..1aaff34d6 100644 --- a/src/network/protocol.cpp +++ b/src/network/protocol.cpp @@ -107,6 +107,21 @@ void Protocol::requestTerminate() ProtocolManager::getInstance()->requestTerminate(this); } // requestTerminate +// ---------------------------------------------------------------------------- +/** Finds a protocol with the given type and requests it to be terminated. + * If no such protocol exist, log an error message. + * \param type The protocol type to delete. + */ +void Protocol::findAndTerminateProtocol(ProtocolType type) +{ + Protocol* protocol = ProtocolManager::getInstance()->getProtocol(type); + if (protocol) + protocol->requestTerminate(); + else + Log::error("ClientLobbyRoomProtocol", + "No protocol %d registered.", type); +} // findAndTerminateProtocol + // ---------------------------------------------------------------------------- /** Sends a message to all peers, inserting the peer's token into the message. * The message is composed of a 1-byte message (usually the message type) diff --git a/src/network/protocol.hpp b/src/network/protocol.hpp index c7570b04a..12d3412fa 100644 --- a/src/network/protocol.hpp +++ b/src/network/protocol.hpp @@ -121,7 +121,7 @@ public: /** \brief Called by the protocol listener, synchronously with the main * loop. Must be re-defined.*/ - virtual void update() = 0; + virtual void update(float dt) = 0; /** \brief Called by the protocol listener as often as possible. * Must be re-defined. */ @@ -138,6 +138,7 @@ public: void requestPause(); void requestUnpause(); void requestTerminate(); + void findAndTerminateProtocol(ProtocolType type); // ------------------------------------------------------------------------ /** \brief Called when the protocol is paused (by an other entity or by diff --git a/src/network/protocol_manager.cpp b/src/network/protocol_manager.cpp index 0310a6496..e1b3a676c 100644 --- a/src/network/protocol_manager.cpp +++ b/src/network/protocol_manager.cpp @@ -315,13 +315,13 @@ bool ProtocolManager::sendEvent(Event* event) /** \brief Updates the manager. * * This function processes the events queue, notifies the concerned - * protocols that they have events to process. Then ask all protocols - * to update themselves. Finally processes stored requests about + * protocols that they have events to process. Then asks all protocols + * to update themselves. Finally it processes stored requests about * starting, stoping, pausing etc... protocols. - * This function is called by the main loop. + * This function is called by the main thread (i.e. from main_loop). * This function IS FPS-dependant. */ -void ProtocolManager::update() +void ProtocolManager::update(float dt) { // before updating, notify protocols that they have received events m_events_to_process.lock(); @@ -346,7 +346,7 @@ void ProtocolManager::update() for (unsigned int i = 0; i < m_protocols.getData().size(); i++) { if (m_protocols.getData()[i]->getState() == PROTOCOL_STATE_RUNNING) - m_protocols.getData()[i]->update(); + m_protocols.getData()[i]->update(dt); } m_protocols.unlock(); } // update @@ -357,7 +357,7 @@ void ProtocolManager::update() * protocols that they have events to process. Then ask all protocols * to update themselves. Finally processes stored requests about * starting, stoping, pausing etc... protocols. - * This function is called in a thread. + * This function is called in a separate thread running in this instance. * This function IS NOT FPS-dependant. */ void ProtocolManager::asynchronousUpdate() diff --git a/src/network/protocol_manager.hpp b/src/network/protocol_manager.hpp index f0b96b414..82d722edf 100644 --- a/src/network/protocol_manager.hpp +++ b/src/network/protocol_manager.hpp @@ -144,7 +144,7 @@ public: virtual void requestPause(Protocol* protocol); virtual void requestUnpause(Protocol* protocol); virtual void requestTerminate(Protocol* protocol); - virtual void update(); + virtual void update(float dt); virtual Protocol* getProtocol(uint32_t id); virtual Protocol* getProtocol(ProtocolType type); }; // class ProtocolManager diff --git a/src/network/protocols/client_lobby_room_protocol.cpp b/src/network/protocols/client_lobby_room_protocol.cpp index f332eeb1e..d8d06e406 100644 --- a/src/network/protocols/client_lobby_room_protocol.cpp +++ b/src/network/protocols/client_lobby_room_protocol.cpp @@ -31,6 +31,7 @@ #include "online/online_profile.hpp" #include "states_screens/networking_lobby.hpp" #include "states_screens/network_kart_selection.hpp" +#include "states_screens/race_result_gui.hpp" #include "states_screens/state_manager.hpp" #include "utils/log.hpp" @@ -174,7 +175,8 @@ void ClientLobbyRoomProtocol::voteLaps(uint8_t player_id, uint8_t laps, } // voteLaps //----------------------------------------------------------------------------- - +/** Called when a client selects to exit a server. + */ void ClientLobbyRoomProtocol::leave() { m_server->disconnect(); @@ -183,30 +185,40 @@ void ClientLobbyRoomProtocol::leave() ServersManager::get()->unsetJoinedServer(); } // leave +//----------------------------------------------------------------------------- +/** Called from the gui when a client clicked on 'continue' on the race result + * screen. It notifies the server that this client has exited the screen and + * is back at the lobby. + */ +void ClientLobbyRoomProtocol::doneWithResults() +{ + NetworkString *done = getNetworkString(1); + done->addUInt8(LE_RACE_FINISHED_ACK); + sendToServer(done, /*reliable*/true); + delete done; +} // doneWithResults + //----------------------------------------------------------------------------- bool ClientLobbyRoomProtocol::notifyEvent(Event* event) { assert(m_setup); // assert that the setup exists - if (event->getType() == EVENT_TYPE_MESSAGE) + + NetworkString &data = event->data(); + assert(data.size()); // assert that data isn't empty + uint8_t message_type = data.getUInt8(); + Log::info("ClientLobbyRoomProtocol", "Synchronous message of type %d", + message_type); + switch(message_type) { - NetworkString &data = event->data(); - assert(data.size()); // assert that data isn't empty - uint8_t message_type = data.getUInt8(); - if (message_type != LE_KART_SELECTION_UPDATE && - message_type != LE_RACE_FINISHED ) - return false; // don't treat the event - - Log::info("ClientLobbyRoomProtocol", "Synchronous message of type %d", - message_type); - if (message_type == LE_KART_SELECTION_UPDATE) // kart selection update - kartSelectionUpdate(event); - else if (message_type == LE_RACE_FINISHED) // end of race - raceFinished(event); - - return true; - } - return false; + case LE_KART_SELECTION_UPDATE: kartSelectionUpdate(event); break; + case LE_RACE_FINISHED: raceFinished(event); break; + case LE_EXIT_RESULT: exitResultScreen(event); break; + default: + return false; + break; + } // switch + return true; } // notifyEvent //----------------------------------------------------------------------------- @@ -257,7 +269,7 @@ bool ClientLobbyRoomProtocol::notifyEventAsynchronous(Event* event) //----------------------------------------------------------------------------- -void ClientLobbyRoomProtocol::update() +void ClientLobbyRoomProtocol::update(float dt) { switch (m_state) { @@ -302,15 +314,7 @@ void ClientLobbyRoomProtocol::update() case SELECTING_KARTS: break; case PLAYING: - { - // race is now over, kill race protocols and return to connected state - if (RaceEventManager::getInstance()->isRaceOver()) - { - Log::info("ClientLobbyRoomProtocol", "Game finished."); - m_state = RACE_FINISHED; - } - } - break; + break; case RACE_FINISHED: break; case DONE: @@ -663,7 +667,15 @@ void ClientLobbyRoomProtocol::raceFinished(Event* event) } // raceFinished //----------------------------------------------------------------------------- +/** Called when the server informs the clients to exit the race result screen. + * It exits the race, and goes back to the lobby. + */ +void ClientLobbyRoomProtocol::exitResultScreen(Event *event) +{ + RaceResultGUI::getInstance()->backToLobby(); +} // exitResultScreen +//----------------------------------------------------------------------------- /*! \brief Called when a player votes for a major race mode. * \param event : Event providing the information. * diff --git a/src/network/protocols/client_lobby_room_protocol.hpp b/src/network/protocols/client_lobby_room_protocol.hpp index 1b4e18908..1e0547473 100644 --- a/src/network/protocols/client_lobby_room_protocol.hpp +++ b/src/network/protocols/client_lobby_room_protocol.hpp @@ -3,67 +3,74 @@ #include "network/protocols/lobby_room_protocol.hpp" #include "network/transport_address.hpp" +#include "utils/cpp2011.hpp" class STKPeer; class ClientLobbyRoomProtocol : public LobbyRoomProtocol { - public: - ClientLobbyRoomProtocol(const TransportAddress& server_address); - virtual ~ClientLobbyRoomProtocol(); +private: + void newPlayer(Event* event); + void disconnectedPlayer(Event* event); + void connectionAccepted(Event* event); //!< Callback function on connection acceptation + void connectionRefused(Event* event); //!< Callback function on connection refusal + void kartSelectionRefused(Event* event); + void kartSelectionUpdate(Event* event); + void startGame(Event* event); + void startSelection(Event* event); + void raceFinished(Event* event); + void exitResultScreen(Event *event); + // race votes + void playerMajorVote(Event* event); + void playerRaceCountVote(Event* event); + void playerMinorVote(Event* event); + void playerTrackVote(Event* event); + void playerReversedVote(Event* event); + void playerLapsVote(Event* event); - void requestKartSelection(uint8_t player_id, - const std::string &kart_name); - void voteMajor(uint8_t player_id, uint32_t major); - void voteRaceCount(uint8_t player_id, uint8_t count); - void voteMinor(uint8_t player_id, uint32_t minor); - void voteTrack(uint8_t player_id, const std::string &track, - uint8_t track_nb = 0); - void voteReversed(uint8_t player_id, bool reversed, uint8_t track_nb = 0); - void voteLaps(uint8_t player_id, uint8_t laps, uint8_t track_nb = 0); - void leave(); + TransportAddress m_server_address; - virtual bool notifyEvent(Event* event); - virtual bool notifyEventAsynchronous(Event* event); - virtual void setup(); - virtual void update(); - virtual void asynchronousUpdate() {} + STKPeer* m_server; - protected: - void newPlayer(Event* event); - void disconnectedPlayer(Event* event); - void connectionAccepted(Event* event); //!< Callback function on connection acceptation - void connectionRefused(Event* event); //!< Callback function on connection refusal - void kartSelectionRefused(Event* event); - void kartSelectionUpdate(Event* event); - void startGame(Event* event); - void startSelection(Event* event); - void raceFinished(Event* event); - // race votes - void playerMajorVote(Event* event); - void playerRaceCountVote(Event* event); - void playerMinorVote(Event* event); - void playerTrackVote(Event* event); - void playerReversedVote(Event* event); - void playerLapsVote(Event* event); + enum STATE + { + NONE, + LINKED, + REQUESTING_CONNECTION, + CONNECTED, // means in the lobby room + KART_SELECTION, // Start kart selection, then go to next state + SELECTING_KARTS, // in the network kart selection screen + PLAYING, // racing + RACE_FINISHED, // race result shown + DONE, + EXITING + }; - TransportAddress m_server_address; - STKPeer* m_server; + /** The state of the finite state machine. */ + STATE m_state; + +public: + ClientLobbyRoomProtocol(const TransportAddress& server_address); + virtual ~ClientLobbyRoomProtocol(); + + void requestKartSelection(uint8_t player_id, + const std::string &kart_name); + void voteMajor(uint8_t player_id, uint32_t major); + void voteRaceCount(uint8_t player_id, uint8_t count); + void voteMinor(uint8_t player_id, uint32_t minor); + void voteTrack(uint8_t player_id, const std::string &track, + uint8_t track_nb = 0); + void voteReversed(uint8_t player_id, bool reversed, uint8_t track_nb = 0); + void voteLaps(uint8_t player_id, uint8_t laps, uint8_t track_nb = 0); + void doneWithResults(); + void leave(); + + virtual bool notifyEvent(Event* event) OVERRIDE; + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; + virtual void setup() OVERRIDE; + virtual void update(float dt) OVERRIDE; + virtual void asynchronousUpdate() OVERRIDE {} - enum STATE - { - NONE, - LINKED, - REQUESTING_CONNECTION, - CONNECTED, // means in the lobby room - KART_SELECTION, - SELECTING_KARTS, // in the network kart selection screen - PLAYING, - RACE_FINISHED, - DONE, - EXITING - }; - STATE m_state; }; #endif // CLIENT_LOBBY_ROOM_PROTOCOL_HPP diff --git a/src/network/protocols/connect_to_peer.hpp b/src/network/protocols/connect_to_peer.hpp index 054c6ea62..b83080b48 100644 --- a/src/network/protocols/connect_to_peer.hpp +++ b/src/network/protocols/connect_to_peer.hpp @@ -56,7 +56,7 @@ public: virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; virtual void setup() OVERRIDE; - virtual void update() OVERRIDE {} + virtual void update(float dt) OVERRIDE {} virtual void asynchronousUpdate() OVERRIDE; virtual void callback(Protocol *protocol) OVERRIDE; }; // class ConnectToPeer diff --git a/src/network/protocols/connect_to_server.hpp b/src/network/protocols/connect_to_server.hpp index 0fb020ac0..e69a8e370 100644 --- a/src/network/protocols/connect_to_server.hpp +++ b/src/network/protocols/connect_to_server.hpp @@ -63,7 +63,7 @@ public: virtual void setup() OVERRIDE; virtual void asynchronousUpdate() OVERRIDE; virtual void callback(Protocol *protocol) OVERRIDE; - virtual void update() OVERRIDE {} + virtual void update(float dt) OVERRIDE {} void setServerAddress(const TransportAddress &address); }; // class ConnectToServer diff --git a/src/network/protocols/controller_events_protocol.cpp b/src/network/protocols/controller_events_protocol.cpp index 66a88188e..f0e986b83 100644 --- a/src/network/protocols/controller_events_protocol.cpp +++ b/src/network/protocols/controller_events_protocol.cpp @@ -95,12 +95,6 @@ bool ControllerEventsProtocol::notifyEventAsynchronous(Event* event) return true; } // notifyEventAsynchronous -//----------------------------------------------------------------------------- - -void ControllerEventsProtocol::update() -{ -} // update - //----------------------------------------------------------------------------- /** Called from the local kart controller when an action (like steering, * acceleration, ...) was triggered. It compresses the current kart control diff --git a/src/network/protocols/controller_events_protocol.hpp b/src/network/protocols/controller_events_protocol.hpp index efa08c1a3..f357c3c46 100644 --- a/src/network/protocols/controller_events_protocol.hpp +++ b/src/network/protocols/controller_events_protocol.hpp @@ -22,6 +22,7 @@ #include "network/protocol.hpp" #include "input/input.hpp" +#include "utils/cpp2011.hpp" class Controller; class STKPeer; @@ -33,10 +34,10 @@ public: ControllerEventsProtocol(); virtual ~ControllerEventsProtocol(); - virtual bool notifyEventAsynchronous(Event* event); - virtual void update(); - virtual void setup() {}; - virtual void asynchronousUpdate() {} + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; + virtual void update(float dt) OVERRIDE {}; + virtual void setup() OVERRIDE {}; + virtual void asynchronousUpdate() OVERRIDE {} void controllerAction(Controller* controller, PlayerAction action, int value); diff --git a/src/network/protocols/game_events_protocol.cpp b/src/network/protocols/game_events_protocol.cpp index f100bf0e7..1bf40db47 100644 --- a/src/network/protocols/game_events_protocol.cpp +++ b/src/network/protocols/game_events_protocol.cpp @@ -63,16 +63,6 @@ bool GameEventsProtocol::notifyEvent(Event* event) return true; } // notifyEvent -// ---------------------------------------------------------------------------- -void GameEventsProtocol::setup() -{ -} // setup - -// ---------------------------------------------------------------------------- -void GameEventsProtocol::update() -{ -} // update - // ---------------------------------------------------------------------------- /** Called on the server when an item is collected. */ diff --git a/src/network/protocols/game_events_protocol.hpp b/src/network/protocols/game_events_protocol.hpp index 7389b93aa..eed98bc78 100644 --- a/src/network/protocols/game_events_protocol.hpp +++ b/src/network/protocols/game_events_protocol.hpp @@ -2,6 +2,7 @@ #define GAME_EVENTS_PROTOCOL_HPP #include "network/protocol.hpp" +#include "utils/cpp2011.hpp" class AbstractKart; class Item; @@ -18,17 +19,19 @@ public: GameEventsProtocol(); virtual ~GameEventsProtocol(); - virtual bool notifyEvent(Event* event); - virtual void setup(); - virtual void update(); + virtual bool notifyEvent(Event* event) OVERRIDE; void collectedItem(Item* item, AbstractKart* kart); void collectedItem(const NetworkString &ns); void kartFinishedRace(AbstractKart *kart, float time); void kartFinishedRace(const NetworkString &ns); + virtual void setup() OVERRIDE {}; + virtual void update(float dt) OVERRIDE {}; + virtual void asynchronousUpdate() OVERRIDE{} // ------------------------------------------------------------------------ - virtual void asynchronousUpdate() {} - // ------------------------------------------------------------------------ - virtual bool notifyEventAsynchronous(Event* event) { return false; } + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE + { + return false; + } // notifyEventAsynchronous }; // class GameEventsProtocol diff --git a/src/network/protocols/get_peer_address.hpp b/src/network/protocols/get_peer_address.hpp index dbeb84f93..094639953 100644 --- a/src/network/protocols/get_peer_address.hpp +++ b/src/network/protocols/get_peer_address.hpp @@ -21,6 +21,7 @@ #include "network/protocol.hpp" #include "network/transport_address.hpp" +#include "utils/cpp2011.hpp" namespace Online { class XMLRequest; } @@ -37,19 +38,19 @@ public: GetPeerAddress(uint32_t peer_id, CallbackObject* callback_object); virtual ~GetPeerAddress(); - virtual void setup(); - virtual void asynchronousUpdate(); + virtual void setup() OVERRIDE; + virtual void asynchronousUpdate() OVERRIDE; void setPeerID(uint32_t m_peer_id); // ------------------------------------------------------------------------ /** Returns the address found. */ const TransportAddress &getAddress() const { return m_address; } // ------------------------------------------------------------------------ - virtual void update() {} + virtual void update(float dt) OVERRIDE {} // ------------------------------------------------------------------------ - virtual bool notifyEvent(Event* event) { return true; } + virtual bool notifyEvent(Event* event) OVERRIDE { return true; } // ------------------------------------------------------------------------ - virtual bool notifyEventAsynchronous(Event* event) { return true; } + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE { return true; } }; // class GetPeerAddress diff --git a/src/network/protocols/get_public_address.hpp b/src/network/protocols/get_public_address.hpp index 61aa9c4f4..783597d04 100644 --- a/src/network/protocols/get_public_address.hpp +++ b/src/network/protocols/get_public_address.hpp @@ -20,6 +20,7 @@ #define GET_PUBLIC_ADDRESS_HPP #include "network/protocol.hpp" +#include "utils/cpp2011.hpp" #include @@ -27,34 +28,39 @@ class Network; class GetPublicAddress : public Protocol { - public: - GetPublicAddress(CallbackObject *callback = NULL); - virtual ~GetPublicAddress() {} +private: + void createStunRequest(); + std::string parseStunResponse(); - virtual bool notifyEvent(Event* event) { return true; } - virtual bool notifyEventAsynchronous(Event* event) { return true; } - virtual void setup() { m_state = NOTHING_DONE; } - virtual void update() {} - virtual void asynchronousUpdate(); + // Constants + static const uint32_t m_stun_magic_cookie; + static const int m_stun_server_port = 3478; - private: - void createStunRequest(); - std::string parseStunResponse(); + enum State + { + NOTHING_DONE, + STUN_REQUEST_SENT, + EXITING + } m_state; - // Constants - static const uint32_t m_stun_magic_cookie; - static const int m_stun_server_port = 3478; + uint8_t m_stun_tansaction_id[12]; + uint32_t m_stun_server_ip; + Network* m_transaction_host; - enum State - { - NOTHING_DONE, - STUN_REQUEST_SENT, - EXITING - } m_state; +public: + GetPublicAddress(CallbackObject *callback = NULL); + virtual ~GetPublicAddress() {} - uint8_t m_stun_tansaction_id[12]; - uint32_t m_stun_server_ip; - Network* m_transaction_host; -}; + virtual void asynchronousUpdate() OVERRIDE; + // ------------------------------------------------------------------------ + virtual void update(float dt) OVERRIDE {} + // ------------------------------------------------------------------------ + virtual bool notifyEvent(Event* event) OVERRIDE { return true; } + // ------------------------------------------------------------------------ + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE { return true; } + // ------------------------------------------------------------------------ + virtual void setup() { m_state = NOTHING_DONE; } + +}; // class GetPublicAddress #endif // GET_PUBLIC_ADDRESS_HPP diff --git a/src/network/protocols/hide_public_address.hpp b/src/network/protocols/hide_public_address.hpp index f2279390c..858833bea 100644 --- a/src/network/protocols/hide_public_address.hpp +++ b/src/network/protocols/hide_public_address.hpp @@ -20,6 +20,7 @@ #define HIDE_PUBLIC_ADDRESS_HPP #include "network/protocol.hpp" +#include "utils/cpp2011.hpp" #include @@ -27,26 +28,29 @@ namespace Online { class XMLRequest; } class HidePublicAddress : public Protocol { - public: - HidePublicAddress(); - virtual ~HidePublicAddress(); +private: + Online::XMLRequest* m_request; + enum STATE + { + NONE, + REQUEST_PENDING, + DONE, + EXITING + }; + STATE m_state; - virtual bool notifyEvent(Event* event) { return true; } - virtual bool notifyEventAsynchronous(Event* event) { return true; } - virtual void setup(); - virtual void update() {} - virtual void asynchronousUpdate(); +public: + HidePublicAddress(); + virtual ~HidePublicAddress(); - protected: - Online::XMLRequest* m_request; - enum STATE - { - NONE, - REQUEST_PENDING, - DONE, - EXITING - }; - STATE m_state; -}; + virtual void asynchronousUpdate() OVERRIDE; + virtual void setup() OVERRIDE; + // ------------------------------------------------------------------------ + virtual bool notifyEvent(Event* event) OVERRIDE { return true; } + // ------------------------------------------------------------------------ + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE { return true; } + // ------------------------------------------------------------------------ + virtual void update(float dt) OVERRIDE {} +}; // class HidePublicAddress #endif // HIDE_PUBLIC_ADDRESS_HPP diff --git a/src/network/protocols/kart_update_protocol.cpp b/src/network/protocols/kart_update_protocol.cpp index a6f41ad91..6c2f70b6e 100644 --- a/src/network/protocols/kart_update_protocol.cpp +++ b/src/network/protocols/kart_update_protocol.cpp @@ -67,7 +67,7 @@ bool KartUpdateProtocol::notifyEvent(Event* event) * or more updates before this client handles them, only the last one will * actually be handled (i.e. outdated kart position updates are discarded). */ -void KartUpdateProtocol::update() +void KartUpdateProtocol::update(float dt) { if (!World::getWorld()) return; diff --git a/src/network/protocols/kart_update_protocol.hpp b/src/network/protocols/kart_update_protocol.hpp index f5eb27201..be5e144f4 100644 --- a/src/network/protocols/kart_update_protocol.hpp +++ b/src/network/protocols/kart_update_protocol.hpp @@ -2,7 +2,9 @@ #define KART_UPDATE_PROTOCOL_HPP #include "network/protocol.hpp" +#include "utils/cpp2011.hpp" #include "utils/vec3.hpp" + #include "LinearMath/btQuaternion.h" #include @@ -27,10 +29,10 @@ public: KartUpdateProtocol(); virtual ~KartUpdateProtocol(); - virtual bool notifyEvent(Event* event); - virtual void setup(); - virtual void update(); - virtual void asynchronousUpdate() {}; + virtual bool notifyEvent(Event* event) OVERRIDE; + virtual void setup() OVERRIDE; + virtual void update(float dt) OVERRIDE; + virtual void asynchronousUpdate() OVERRIDE {}; }; // KartUpdateProtocol diff --git a/src/network/protocols/lobby_room_protocol.hpp b/src/network/protocols/lobby_room_protocol.hpp index bdd073030..9fa9185e3 100644 --- a/src/network/protocols/lobby_room_protocol.hpp +++ b/src/network/protocols/lobby_room_protocol.hpp @@ -36,24 +36,26 @@ public: /** Lists all lobby events (LE). */ enum { - LE_CONNECTION_REQUESTED = 1, - LE_REQUEST_BEGIN, - LE_NEW_PLAYER_CONNECTED, - LE_KART_SELECTION, - LE_PLAYER_DISCONNECTED, - LE_KART_SELECTION_UPDATE, - LE_START_RACE, - LE_START_SELECTION, - LE_RACE_FINISHED, - LE_CONNECTION_REFUSED, - LE_CONNECTION_ACCEPTED, - LE_KART_SELECTION_REFUSED, - LE_VOTE_MAJOR, - LE_VOTE_RACE_COUNT, - LE_VOTE_MINOR, - LE_VOTE_TRACK, - LE_VOTE_REVERSE, - LE_VOTE_LAPS, + LE_CONNECTION_REQUESTED = 1, // a connection to the server + LE_CONNECTION_REFUSED, // Connection to server refused + LE_CONNECTION_ACCEPTED, // Connection to server accepted + LE_KART_SELECTION_UPDATE, // inform client about kart selected + LE_REQUEST_BEGIN, // begin of kart selection + LE_KART_SELECTION_REFUSED, // Client not auth. to start selection + LE_NEW_PLAYER_CONNECTED, // inform client about new player + LE_KART_SELECTION, // Player selected kart + LE_PLAYER_DISCONNECTED, // Client disconnected + LE_START_RACE, // start race + LE_START_SELECTION, // inform client to start selection + LE_RACE_FINISHED, // race has finished, display result + LE_RACE_FINISHED_ACK, // client went back to lobby + LE_EXIT_RESULT, // Force clients to exit race result screen + LE_VOTE_MAJOR, // vote of major race mode + LE_VOTE_MINOR, // vote for minor race mode + LE_VOTE_RACE_COUNT, // vote for number of tracks + LE_VOTE_TRACK, // vote for a track + LE_VOTE_REVERSE, // vote if race in reverse + LE_VOTE_LAPS, // vote number of laps }; protected: @@ -71,7 +73,7 @@ public: virtual ~LobbyRoomProtocol() {} // ------------------------------------------------------------------------ virtual void setup() = 0; - virtual void update() = 0; + virtual void update(float dt) = 0; }; // class LobbyRoomProtocol #endif // LOBBY_ROOM_PROTOCOL_HPP diff --git a/src/network/protocols/ping_protocol.hpp b/src/network/protocols/ping_protocol.hpp index def641311..fdb66adf2 100644 --- a/src/network/protocols/ping_protocol.hpp +++ b/src/network/protocols/ping_protocol.hpp @@ -3,6 +3,7 @@ #include "network/protocol.hpp" #include "network/transport_address.hpp" +#include "utils/cpp2011.hpp" class PingProtocol : public Protocol { @@ -16,16 +17,19 @@ private: /** Time of last ping. */ double m_last_ping_time; public: - PingProtocol(const TransportAddress& ping_dst, - double delay_between_pings); - virtual ~PingProtocol(); + PingProtocol(const TransportAddress& ping_dst, + double delay_between_pings); + virtual ~PingProtocol(); - virtual bool notifyEvent(Event* event) { return true; } - virtual bool notifyEventAsynchronous(Event* event) { return true; } - virtual void setup(); - virtual void update() {} - virtual void asynchronousUpdate(); + virtual void asynchronousUpdate() OVERRIDE; + virtual void setup() OVERRIDE; + // ------------------------------------------------------------------------ + virtual bool notifyEvent(Event* event) OVERRIDE { return true; } + // ------------------------------------------------------------------------ + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE { return true; } + // ------------------------------------------------------------------------ + virtual void update(float dt) OVERRIDE {} }; #endif // PING_PROTOCOL_HPP diff --git a/src/network/protocols/request_connection.hpp b/src/network/protocols/request_connection.hpp index 2184efefd..de70737e0 100644 --- a/src/network/protocols/request_connection.hpp +++ b/src/network/protocols/request_connection.hpp @@ -38,12 +38,14 @@ public: RequestConnection(uint32_t server_id); virtual ~RequestConnection(); - - virtual bool notifyEvent(Event* event) { return true; } - virtual bool notifyEventAsynchronous(Event* event) { return true; } - virtual void setup(); - virtual void update() {} - virtual void asynchronousUpdate(); + virtual void setup() OVERRIDE; + virtual void asynchronousUpdate() OVERRIDE; + // ------------------------------------------------------------------------ + virtual bool notifyEvent(Event* event) OVERRIDE { return true; } + // ------------------------------------------------------------------------ + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE { return true; } + // ------------------------------------------------------------------------ + virtual void update(float dt) OVERRIDE {} }; // RequestConnection diff --git a/src/network/protocols/server_lobby_room_protocol.cpp b/src/network/protocols/server_lobby_room_protocol.cpp index b4c6bab81..42039815b 100644 --- a/src/network/protocols/server_lobby_room_protocol.cpp +++ b/src/network/protocols/server_lobby_room_protocol.cpp @@ -33,6 +33,7 @@ #include "network/stk_peer.hpp" #include "online/online_profile.hpp" #include "online/request_manager.hpp" +#include "states_screens/race_result_gui.hpp" #include "utils/log.hpp" #include "utils/random_generator.hpp" #include "utils/time.hpp" @@ -67,7 +68,6 @@ void ServerLobbyRoomProtocol::setup() m_state = NetworkConfig::get()->isLAN() ? ACCEPTING_CLIENTS : NONE; m_selection_enabled = false; - m_in_race = false; m_current_protocol = NULL; Log::info("ServerLobbyRoomProtocol", "Starting the protocol."); } // setup @@ -96,6 +96,7 @@ bool ServerLobbyRoomProtocol::notifyEventAsynchronous(Event* event) case LE_VOTE_TRACK: playerTrackVote(event); break; case LE_VOTE_REVERSE: playerReversedVote(event); break; case LE_VOTE_LAPS: playerLapsVote(event); break; + case LE_RACE_FINISHED_ACK: playerFinishedResult(event); break; } // switch } // if (event->getType() == EVENT_TYPE_MESSAGE) @@ -111,7 +112,7 @@ bool ServerLobbyRoomProtocol::notifyEventAsynchronous(Event* event) * is known, register the server and its address with the stk server so that * client can find it. */ -void ServerLobbyRoomProtocol::update() +void ServerLobbyRoomProtocol::update(float dt) { switch (m_state) { @@ -142,16 +143,38 @@ void ServerLobbyRoomProtocol::update() // Only poll the STK server if this is a WAN server. if(NetworkConfig::get()->isWAN()) checkIncomingConnectionRequests(); - if (m_in_race && World::getWorld() && + break; + } + case SELECTING: + break; // Nothing to do, this is event based + case RACING: + if (World::getWorld() && RaceEventManager::getInstance()->isRunning()) { checkRaceFinished(); } - break; - } - case SELECTING_KARTS: - break; // Nothing to do, this is event based + case RESULT_DISPLAY: + if(StkTime::getRealTime() > m_timeout) + { + // Send a notification to all clients to exit + // the race result screen + NetworkString *exit_result_screen = getNetworkString(1); + exit_result_screen->setSynchronous(true); + exit_result_screen->addUInt8(LE_EXIT_RESULT); + sendMessageToPeersChangingToken(exit_result_screen, + /*reliable*/true); + delete exit_result_screen; + m_state = ACCEPTING_CLIENTS; + RaceResultGUI::getInstance()->backToLobby(); + // notify the network world that it is stopped + RaceEventManager::getInstance()->stop(); + // stop race protocols + findAndTerminateProtocol(PROTOCOL_CONTROLLER_EVENTS); + findAndTerminateProtocol(PROTOCOL_KART_UPDATE); + findAndTerminateProtocol(PROTOCOL_GAME_EVENTS); + } + break; case DONE: m_state = EXITING; requestTerminate(); @@ -227,7 +250,7 @@ void ServerLobbyRoomProtocol::startGame() delete ns; Protocol *p = new StartGameProtocol(m_setup); p->requestStart(); - m_in_race = true; + m_state = RACING; } // startGame //----------------------------------------------------------------------------- @@ -252,7 +275,7 @@ void ServerLobbyRoomProtocol::startSelection(const Event *event) m_selection_enabled = true; - m_state = SELECTING_KARTS; + m_state = SELECTING; } // startSelection //----------------------------------------------------------------------------- @@ -304,79 +327,55 @@ void ServerLobbyRoomProtocol::checkIncomingConnectionRequests() } // checkIncomingConnectionRequests //----------------------------------------------------------------------------- - -void ServerLobbyRoomProtocol::checkRaceFinished() +/** Checks if the race is finished, and if so informs the clients and switches + * to state RESULT_DISPLAY, during which the race result gui is shown and all + * clients can click on 'continue'. + */ + void ServerLobbyRoomProtocol::checkRaceFinished() { assert(RaceEventManager::getInstance()->isRunning()); assert(World::getWorld()); - // if race is over, give the final score to everybody - if (RaceEventManager::getInstance()->isRaceOver()) + if(!RaceEventManager::getInstance()->isRaceOver()) return; + + m_player_ready_counter = 0; + // Set the delay before the server forces all clients to exit the race + // result screen and go back to the lobby + m_timeout = (float)(StkTime::getRealTime()+15.0f); + m_state = RESULT_DISPLAY; + + // calculate karts ranks : + int num_karts = race_manager->getNumberOfKarts(); + std::vector karts_results; + std::vector karts_times; + for (int j = 0; j < num_karts; j++) { - // calculate karts ranks : - int num_players = race_manager->getNumberOfKarts(); - std::vector karts_results; - std::vector karts_times; - for (int j = 0; j < num_players; j++) + float kart_time = race_manager->getKartRaceTime(j); + for (unsigned int i = 0; i < karts_times.size(); i++) { - float kart_time = race_manager->getKartRaceTime(j); - for (unsigned int i = 0; i < karts_times.size(); i++) + if (kart_time < karts_times[i]) { - if (kart_time < karts_times[i]) - { - karts_times.insert(karts_times.begin()+i, kart_time); - karts_results.insert(karts_results.begin()+i, j); - break; - } + karts_times.insert(karts_times.begin() + i, kart_time); + karts_results.insert(karts_results.begin() + i, j); + break; } } - - const std::vector &peers = STKHost::get()->getPeers(); - - NetworkString *total = getNetworkString(1+karts_results.size()); - total->setSynchronous(true); - total->addUInt8(LE_RACE_FINISHED); - for (unsigned int i = 0; i < karts_results.size(); i++) - { - total->addUInt8(karts_results[i]); // kart pos = i+1 - Log::info("ServerLobbyRoomProtocol", "Kart %d finished #%d", - karts_results[i], i + 1); - } - sendMessageToPeersChangingToken(total, /*reliable*/ true); - delete total; - Log::info("ServerLobbyRoomProtocol", "End of game message sent"); - m_in_race = false; - - // stop race protocols - Protocol* protocol = ProtocolManager::getInstance() - ->getProtocol(PROTOCOL_CONTROLLER_EVENTS); - if (protocol) - protocol->requestTerminate(); - else - Log::error("ClientLobbyRoomProtocol", - "No controller events protocol registered."); - - protocol = ProtocolManager::getInstance() - ->getProtocol(PROTOCOL_KART_UPDATE); - if (protocol) - protocol->requestTerminate(); - else - Log::error("ClientLobbyRoomProtocol", - "No kart update protocol registered."); - - protocol = ProtocolManager::getInstance() - ->getProtocol(PROTOCOL_GAME_EVENTS); - if (protocol) - protocol->requestTerminate(); - else - Log::error("ClientLobbyRoomProtocol", - "No game events protocol registered."); - - // notify the network world that it is stopped - RaceEventManager::getInstance()->stop(); - // exit the race now - race_manager->exitRace(); - race_manager->setAIKartOverride(""); } + + const std::vector &peers = STKHost::get()->getPeers(); + + NetworkString *total = getNetworkString(1 + karts_results.size()); + total->setSynchronous(true); + total->addUInt8(LE_RACE_FINISHED); + for (unsigned int i = 0; i < karts_results.size(); i++) + { + total->addUInt8(karts_results[i]); // kart pos = i+1 + Log::info("ServerLobbyRoomProtocol", "Kart %d finished #%d", + karts_results[i], i + 1); + } + sendMessageToPeersChangingToken(total, /*reliable*/ true); + delete total; + Log::info("ServerLobbyRoomProtocol", "End of game message sent"); + } // checkRaceFinished //----------------------------------------------------------------------------- @@ -522,7 +521,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) */ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) { - if(m_state!=SELECTING_KARTS) + if(m_state!=SELECTING) { Log::warn("Server", "Received kart selection while in state %d.", m_state); @@ -751,3 +750,19 @@ void ServerLobbyRoomProtocol::playerLapsVote(Event* event) } // playerLapsVote //----------------------------------------------------------------------------- +/** Called when a client clicks on 'ok' on the race result screen. + * If all players have clicked on 'ok', go back to the lobby. + */ +void ServerLobbyRoomProtocol::playerFinishedResult(Event *event) +{ + m_player_ready_counter++; + if(m_player_ready_counter == STKHost::get()->getPeerCount()) + { + // We can't trigger the world/race exit here, since this is called + // from the protocol manager thread. So instead we force the timeout + // to get triggered (which is done from the main thread): + m_timeout = 0; + } +} // playerFinishedResult + +//----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby_room_protocol.hpp b/src/network/protocols/server_lobby_room_protocol.hpp index 35fcb1554..4a4cb697f 100644 --- a/src/network/protocols/server_lobby_room_protocol.hpp +++ b/src/network/protocols/server_lobby_room_protocol.hpp @@ -13,10 +13,12 @@ private: enum { NONE, - GETTING_PUBLIC_ADDRESS, - ACCEPTING_CLIENTS, - SELECTING_KARTS, - DONE, + GETTING_PUBLIC_ADDRESS, // Waiting to receive its public ip address + ACCEPTING_CLIENTS, // In lobby, accepting clients + SELECTING, // kart, track, ... selection started + RACING, // racing + RESULT_DISPLAY, // Show result screen + DONE, // shutting down server EXITING } m_state; @@ -25,7 +27,12 @@ private: Protocol *m_current_protocol; bool m_selection_enabled; - bool m_in_race; + + /** Counts how many players are ready to go on. */ + int m_player_ready_counter; + + /** Timeout counter for showing the result screen. */ + float m_timeout; // connection management void clientDisconnected(Event* event); @@ -39,6 +46,7 @@ private: void playerTrackVote(Event* event); void playerReversedVote(Event* event); void playerLapsVote(Event* event); + void playerFinishedResult(Event *event); void registerServer(); public: @@ -47,7 +55,7 @@ public: virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; virtual void setup() OVERRIDE; - virtual void update() OVERRIDE; + virtual void update(float dt) OVERRIDE; virtual void asynchronousUpdate() OVERRIDE {}; void startGame(); diff --git a/src/network/protocols/start_game_protocol.cpp b/src/network/protocols/start_game_protocol.cpp index 223c6f301..e913b1d10 100644 --- a/src/network/protocols/start_game_protocol.cpp +++ b/src/network/protocols/start_game_protocol.cpp @@ -170,7 +170,7 @@ void StartGameProtocol::startRace() } // startRace // ---------------------------------------------------------------------------- -void StartGameProtocol::update() +void StartGameProtocol::update(float dt) { switch(m_state) { diff --git a/src/network/protocols/start_game_protocol.hpp b/src/network/protocols/start_game_protocol.hpp index e3bbe0147..c300a5bbf 100644 --- a/src/network/protocols/start_game_protocol.hpp +++ b/src/network/protocols/start_game_protocol.hpp @@ -2,6 +2,8 @@ #define START_GAME_PROTOCOL_HPP #include "network/protocol.hpp" +#include "utils/cpp2011.hpp" + #include class GameSetup; @@ -39,10 +41,10 @@ public: virtual ~StartGameProtocol(); virtual bool notifyEventAsynchronous(Event* event); - virtual void setup(); - virtual void update(); + virtual void setup() OVERRIDE; + virtual void update(float dt) OVERRIDE; void ready(); - virtual void asynchronousUpdate() {} + virtual void asynchronousUpdate() OVERRIDE {} }; // class StartGameProtocol diff --git a/src/network/protocols/stop_server.hpp b/src/network/protocols/stop_server.hpp index feba521b1..6ec1c814e 100644 --- a/src/network/protocols/stop_server.hpp +++ b/src/network/protocols/stop_server.hpp @@ -2,6 +2,7 @@ #define STOP_SERVER_HPP #include "network/protocol.hpp" +#include "utils/cpp2011.hpp" namespace Online { class XMLRequest; } @@ -10,25 +11,26 @@ namespace Online { class XMLRequest; } class StopServer : public Protocol { - public: - StopServer(); - virtual ~StopServer(); +private: + Online::XMLRequest* m_request; + enum STATE + { + NONE, + REQUEST_PENDING, + DONE, + EXITING + }; + STATE m_state; +public: + StopServer(); + virtual ~StopServer(); - virtual bool notifyEventAsynchronous(Event* event); - virtual void setup(); - virtual void update() {} - virtual void asynchronousUpdate(); + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; + virtual void setup() OVERRIDE; + virtual void asynchronousUpdate() OVERRIDE; + // -------------------------------------------------------------------- + virtual void update(float dt) OVERRIDE {} - protected: - Online::XMLRequest* m_request; - enum STATE - { - NONE, - REQUEST_PENDING, - DONE, - EXITING - }; - STATE m_state; }; #endif // STOP_SERVER_HPP diff --git a/src/network/protocols/synchronization_protocol.hpp b/src/network/protocols/synchronization_protocol.hpp index 1bc1abfae..4190f2b95 100644 --- a/src/network/protocols/synchronization_protocol.hpp +++ b/src/network/protocols/synchronization_protocol.hpp @@ -2,6 +2,8 @@ #define SYNCHRONIZATION_PROTOCOL_HPP #include "network/protocol.hpp" +#include "utils/cpp2011.hpp" + #include #include @@ -28,12 +30,13 @@ public: SynchronizationProtocol(); virtual ~SynchronizationProtocol(); - virtual bool notifyEventAsynchronous(Event* event); - virtual void setup(); - virtual void update() {} - virtual void asynchronousUpdate(); + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; + virtual void setup() OVERRIDE; + virtual void asynchronousUpdate() OVERRIDE; void startCountdown(int ms_countdown); + // ------------------------------------------------------------------------ + virtual void update(float dt) OVERRIDE {} // ------------------------------------------------------------------------ int getCountdown() { return (int)(m_countdown*1000.0); } diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index cad666134..c3b01d29d 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -305,8 +305,8 @@ void STKHost::init() // Optional: start the network console m_network_console = new NetworkConsole(); m_network_console->run(); - -} // STKHost + +} // STKHost // ---------------------------------------------------------------------------- /** Destructor. Stops the listening thread, closes the packet log file and diff --git a/src/states_screens/create_server_screen.cpp b/src/states_screens/create_server_screen.cpp index 625d18ccf..ef85f887b 100644 --- a/src/states_screens/create_server_screen.cpp +++ b/src/states_screens/create_server_screen.cpp @@ -148,7 +148,7 @@ void CreateServerScreen::onUpdate(float delta) // Otherwise wait till we get an answer from the server: // ----------------------------------------------------- - if(!STKHost::get()->isRegistered()) + if(!STKHost::get()->isRegistered() && !NetworkConfig::get()->isLAN()) { m_info_widget->setDefaultColor(); m_info_widget->setText(StringUtils::loadingDots(_("Creating server")), diff --git a/src/states_screens/networking_lobby.cpp b/src/states_screens/networking_lobby.cpp index 2d59d7dea..596a027e9 100644 --- a/src/states_screens/networking_lobby.cpp +++ b/src/states_screens/networking_lobby.cpp @@ -125,7 +125,8 @@ void NetworkingLobby::init() m_server_game_mode->setText(mode, false); } - m_start_button->setVisible(STKHost::get()->isAuthorisedToControl()); + if(!NetworkConfig::get()->isServer()) + m_start_button->setVisible(STKHost::get()->isAuthorisedToControl()); // For now create the active player and bind it to the right // input device. @@ -138,8 +139,11 @@ void NetworkingLobby::init() void NetworkingLobby::onUpdate(float delta) { // FIXME Network looby should be closed when stkhost is shut down - m_start_button->setVisible(STKHost::existHost() && - STKHost::get()->isAuthorisedToControl()); + if(NetworkConfig::get()->isClient()) + { + m_start_button->setVisible(STKHost::existHost() && + STKHost::get()->isAuthorisedToControl()); + } } // onUpdate // ---------------------------------------------------------------------------- diff --git a/src/states_screens/online_profile_base.cpp b/src/states_screens/online_profile_base.cpp index ffd5f4176..208123750 100644 --- a/src/states_screens/online_profile_base.cpp +++ b/src/states_screens/online_profile_base.cpp @@ -81,6 +81,15 @@ void OnlineProfileBase::loadedFromFile() void OnlineProfileBase::beforeAddingWidget() { m_visiting_profile = ProfileManager::get()->getVisitingProfile(); +} // beforeAddingWidget + +// ----------------------------------------------------------------------------- +/** Called when entering this menu (before widgets are added). + */ +void OnlineProfileBase::init() +{ + Screen::init(); + if (m_profile_tabs) { if (!m_visiting_profile || !m_visiting_profile->isCurrentUser()) @@ -95,14 +104,6 @@ void OnlineProfileBase::beforeAddingWidget() m_profile_tabs->setVisible(false); } } // if m_profile_tabhs -} // beforeAddingWidget - -// ----------------------------------------------------------------------------- -/** Called when entering this menu (before widgets are added). - */ -void OnlineProfileBase::init() -{ - Screen::init(); if (m_profile_tabs) { diff --git a/src/states_screens/online_profile_servers.cpp b/src/states_screens/online_profile_servers.cpp index 61235f1b0..f3c404815 100644 --- a/src/states_screens/online_profile_servers.cpp +++ b/src/states_screens/online_profile_servers.cpp @@ -137,6 +137,11 @@ void OnlineProfileServers::doQuickPlay() // select first one const Server *server = ServersManager::get()->getQuickPlay(); + if(!server) + { + Log::error("OnlineProfileServers", "Can not find quick play server."); + return; + } // do a join request XMLRequest *join_request = new RequestConnection::ServerJoinRequest(); diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index c751e3335..49db63595 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -42,6 +42,8 @@ #include "modes/overworld.hpp" #include "modes/soccer_world.hpp" #include "modes/world_with_rank.hpp" +#include "network/protocol_manager.hpp" +#include "network/protocols/client_lobby_room_protocol.hpp" #include "race/highscores.hpp" #include "scriptengine/property_animator.hpp" #include "states_screens/feature_unlocked.hpp" @@ -56,12 +58,12 @@ #include "utils/string_utils.hpp" #include -DEFINE_SCREEN_SINGLETON( RaceResultGUI ); +DEFINE_SCREEN_SINGLETON(RaceResultGUI); /** Constructor, initialises internal data structures. */ RaceResultGUI::RaceResultGUI() : Screen("race_result.stkgui", - /*pause race*/ false) + /*pause race*/ false) { } // RaceResultGUI @@ -76,7 +78,7 @@ void RaceResultGUI::init() determineTableLayout(); m_animation_state = RR_INIT; - m_timer = 0; + m_timer = 0; getWidget("top")->setVisible(false); getWidget("middle")->setVisible(false); @@ -114,7 +116,7 @@ void RaceResultGUI::init() GUIEngine::Widget* result_table = getWidget("result-table"); assert(result_table != NULL); m_sshot_height = (int)(UserConfigParams::m_height*0.1275); - m_max_tracks = std::max (1, ((result_table->m_h - getFontHeight () * 5) / + m_max_tracks = std::max(1, ((result_table->m_h - getFontHeight() * 5) / (m_sshot_height + SSHOT_SEPARATION))); //Show at least one // Calculate screenshot scrolling parameters @@ -154,11 +156,11 @@ void RaceResultGUI::tearDown() */ void RaceResultGUI::enableAllButtons() { - GUIEngine::Widget *top = getWidget("top"); + GUIEngine::Widget *top = getWidget("top"); GUIEngine::Widget *middle = getWidget("middle"); GUIEngine::Widget *bottom = getWidget("bottom"); - if (race_manager->getMajorMode()==RaceManager::MAJOR_MODE_GRAND_PRIX) + if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) { enableGPProgress(); } @@ -168,12 +170,12 @@ void RaceResultGUI::enableAllButtons() { Log::info("This work was networked", "This is a network world."); top->setVisible(false); - middle->setText( _("Continue.") ); + middle->setText(_("Continue.")); middle->setVisible(true); middle->setFocusForPlayer(PLAYER_ID_GAME_MASTER); - bottom->setText( _("Quit the server.") ); + bottom->setText(_("Quit the server.")); bottom->setVisible(true); - if (race_manager->getMajorMode()==RaceManager::MAJOR_MODE_GRAND_PRIX) + if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) { middle->setVisible(false); // you have to wait the server to start again bottom->setFocusForPlayer(PLAYER_ID_GAME_MASTER); @@ -185,23 +187,23 @@ void RaceResultGUI::enableAllButtons() // If something was unlocked // ------------------------- int n = (int)PlayerManager::getCurrentPlayer()->getRecentlyCompletedChallenges().size(); - if(n>0) + if (n > 0) { - top->setText(n==1 ? _("You completed a challenge!") - : _("You completed challenges!")); + top->setText(n == 1 ? _("You completed a challenge!") + : _("You completed challenges!")); top->setVisible(true); top->setFocusForPlayer(PLAYER_ID_GAME_MASTER); } - else if (race_manager->getMajorMode()==RaceManager::MAJOR_MODE_GRAND_PRIX) + else if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) { // In case of a GP: // ---------------- top->setVisible(false); - middle->setText( _("Continue") ); + middle->setText(_("Continue")); middle->setVisible(true); - bottom->setText( _("Abort Grand Prix") ); + bottom->setText(_("Abort Grand Prix")); bottom->setVisible(true); middle->setFocusForPlayer(PLAYER_ID_GAME_MASTER); @@ -211,19 +213,19 @@ void RaceResultGUI::enableAllButtons() // Normal race // ----------- - middle->setText( _("Restart") ); + middle->setText(_("Restart")); middle->setVisible(true); if (race_manager->raceWasStartedFromOverworld()) { top->setVisible(false); - bottom->setText( _("Back to challenge selection") ); + bottom->setText(_("Back to challenge selection")); } else { - top->setText( _("Setup New Race") ); + top->setText(_("Setup New Race")); top->setVisible(true); - bottom->setText( _("Back to the menu") ); + bottom->setText(_("Back to the menu")); } bottom->setVisible(true); @@ -233,7 +235,7 @@ void RaceResultGUI::enableAllButtons() //----------------------------------------------------------------------------- void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, - const std::string& name, const int playerID) + const std::string& name, const int playerID) { int n_tracks = race_manager->getGrandPrix().getNumberOfTracks(); if (name == "up_button" && n_tracks > m_max_tracks && m_start_track > 0) @@ -254,10 +256,10 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, // actually used to display "Show unlocked feature(s)" text. // --------------------------------------------------------- int n = (int)PlayerManager::getCurrentPlayer() - ->getRecentlyCompletedChallenges().size(); - if(n>0) + ->getRecentlyCompletedChallenges().size(); + if (n>0) { - if(name=="top") + if (name == "top") { if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) { @@ -291,7 +293,7 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, CutsceneWorld::setUseDuration(true); StateManager::get()->enterGameState(); race_manager->setMinorMode(RaceManager::MINOR_MODE_CUTSCENE); - race_manager->setNumKarts( 0 ); + race_manager->setNumKarts(0); race_manager->setNumPlayers(0); race_manager->startSingleRace("endcutscene", 999, false); @@ -327,7 +329,7 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, return; } Log::fatal("RaceResultGUI", "Incorrect event '%s' when things are unlocked.", - name.c_str()); + name.c_str()); } // If we're playing online : @@ -336,14 +338,14 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, StateManager::get()->popMenu(); if (name == "middle") // Continue button (return to server lobby) { - race_manager->exitRace(); - race_manager->setAIKartOverride(""); - Screen* newStack[] = {MainMenuScreen::getInstance(), - OnlineProfileServers::getInstance(), - ServerSelection::getInstance(), - NetworkingLobby::getInstance(), - NULL}; - StateManager::get()->resetAndSetStack( newStack ); + // Signal to the server that this client is back in the lobby now. + Protocol* protocol = + ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM); + ClientLobbyRoomProtocol* clrp = + static_cast(protocol); + if(clrp) + clrp->doneWithResults(); + backToLobby(); } if (name == "bottom") // Quit server (return to main menu) { @@ -367,18 +369,18 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, else if (name == "bottom") // Abort { new MessageDialog(_("Do you really want to abort the Grand Prix?"), - MessageDialog::MESSAGE_DIALOG_CONFIRM, this, false); + MessageDialog::MESSAGE_DIALOG_CONFIRM, this, false); } else if (!getWidget(name.c_str())->isVisible()) Log::fatal("RaceResultGUI", "Incorrect event '%s' when things are unlocked.", - name.c_str()); + name.c_str()); return; } // This is a normal race, nothing was unlocked // ------------------------------------------- StateManager::get()->popMenu(); - if(name=="top") // Setup new race + if (name == "top") // Setup new race { race_manager->exitRace(); race_manager->setAIKartOverride(""); @@ -386,16 +388,16 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, // automatically called when the screen is left. Note that the // NetworkKartSelectionScreen::getInstance()->tearDown(); caused #1347 KartSelectionScreen::getRunningInstance()->tearDown(); - Screen* newStack[] = {MainMenuScreen::getInstance(), + Screen* newStack[] = { MainMenuScreen::getInstance(), RaceSetupScreen::getInstance(), - NULL}; - StateManager::get()->resetAndSetStack( newStack ); + NULL }; + StateManager::get()->resetAndSetStack(newStack); } - else if (name=="middle") // Restart + else if (name == "middle") // Restart { race_manager->rerunRace(); } - else if (name=="bottom") // Back to main + else if (name == "bottom") // Back to main { race_manager->exitRace(); race_manager->setAIKartOverride(""); @@ -413,1020 +415,1035 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, } else Log::fatal("RaceResultGUI", "Incorrect event '%s' for normal race.", - name.c_str()); + name.c_str()); return; } // eventCallback //----------------------------------------------------------------------------- - -void RaceResultGUI::onConfirm() +/** Sets up the giu to go back to the lobby. Can only be called in case of a + * networked game. + */ +void RaceResultGUI::backToLobby() { - //race_manager->saveGP(); // Save the aborted GP - GUIEngine::ModalDialog::dismiss(); - cleanupGPProgress(); - StateManager::get()->popMenu(); race_manager->exitRace(); race_manager->setAIKartOverride(""); - StateManager::get()->resetAndGoToScreen( - MainMenuScreen::getInstance()); + Screen* newStack[] = { MainMenuScreen::getInstance(), + OnlineProfileServers::getInstance(), + ServerSelection::getInstance(), + NetworkingLobby::getInstance(), + NULL }; + StateManager::get()->resetAndSetStack(newStack); +} // backToLobby - if (race_manager->raceWasStartedFromOverworld()) +//----------------------------------------------------------------------------- + void RaceResultGUI::onConfirm() { - OverWorld::enterOverWorld(); - } -} + //race_manager->saveGP(); // Save the aborted GP + GUIEngine::ModalDialog::dismiss(); + cleanupGPProgress(); + StateManager::get()->popMenu(); + race_manager->exitRace(); + race_manager->setAIKartOverride(""); + StateManager::get()->resetAndGoToScreen( + MainMenuScreen::getInstance()); -//----------------------------------------------------------------------------- -/** This determines the layout, i.e. the size of all columns, font size etc. - */ -void RaceResultGUI::determineTableLayout() -{ - GUIEngine::Widget *table_area = getWidget("result-table"); - - m_font = GUIEngine::getFont(); - assert(m_font); - m_was_monospace = m_font->getMonospaceDigits(); - m_font->setMonospaceDigits(true); - WorldWithRank *rank_world = (WorldWithRank*)World::getWorld(); - - unsigned int first_position = 1; - if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER) - first_position = 2; - - // Use only the karts that are supposed to be displayed (and - // ignore e.g. the leader in a FTL race). - unsigned int num_karts =race_manager->getNumberOfKarts()-first_position+1; - - // In FTL races the leader kart is not displayed - m_all_row_infos.resize(num_karts); - - - // Determine the kart to display in the right order, - // and the maximum width for the kart name column - // ------------------------------------------------- - m_width_kart_name = 0; - float max_finish_time = 0; - - for(unsigned int position=first_position; - position<=race_manager->getNumberOfKarts(); position++) - { - const AbstractKart *kart = rank_world->getKartAtPosition(position); - - // Save a pointer to the current row_info entry - RowInfo *ri = &(m_all_row_infos[position-first_position]); - ri->m_is_player_kart = kart->getController()->isLocalPlayerController(); - - // Identify Human player, if so display real name other than kart name - const int rm_id = kart->getWorldKartId() - - (race_manager->getNumberOfKarts() - race_manager->getNumPlayers()); - - if (rm_id >= 0) - ri->m_kart_name = race_manager->getKartInfo(rm_id).getPlayerName(); - else - ri->m_kart_name = translations->fribidize(kart->getName()); - - video::ITexture *icon = - kart->getKartProperties()->getIconMaterial()->getTexture(); - ri->m_kart_icon = icon; - - // FTL karts will get a time assigned, they are not shown as eliminated - if (kart->isEliminated() && - race_manager->getMinorMode()!=RaceManager::MINOR_MODE_FOLLOW_LEADER) + if (race_manager->raceWasStartedFromOverworld()) { - ri->m_finish_time_string = core::stringw(_("Eliminated")); - } - else - { - const float time = kart->getFinishTime(); - if(time > max_finish_time) max_finish_time = time; - std::string time_string = StringUtils::timeToString(time); - ri->m_finish_time_string = time_string.c_str(); - } - - core::dimension2du rect = - m_font->getDimension(ri->m_kart_name.c_str()); - if(rect.Width > m_width_kart_name) - m_width_kart_name = rect.Width; - } // for position - - std::string max_time = StringUtils::timeToString(max_finish_time); - core::stringw string_max_time(max_time.c_str()); - core::dimension2du r = m_font->getDimension(string_max_time.c_str()); - m_width_finish_time = r.Width; - - // Top pixel where to display text - m_top = table_area->m_y; - - // Height of the result display - unsigned int height = table_area->m_h; - - // Setup different timing information for the different phases - // ----------------------------------------------------------- - // How much time between consecutive rows - m_time_between_rows = 0.1f; - - // How long it takes for one line to scroll from right to left - m_time_single_scroll = 0.2f; - - // Time to rotate the entries to the proper GP position. - m_time_rotation = 1.0f; - - // The time the first phase is being displayed: add the start time - // of the last kart to the duration of the scroll plus some time - // of rest before the next phase starts - m_time_overall_scroll = (num_karts-1)*m_time_between_rows - + m_time_single_scroll + 2.0f; - - // The time to increase the number of points. - m_time_for_points = 1.0f; - - // Determine text height - r = m_font->getDimension(L"Y"); - m_distance_between_rows = (int)(1.5f*r.Height); - - // If there are too many karts, reduce size between rows - if(m_distance_between_rows * num_karts > height) - m_distance_between_rows = height / num_karts; - - m_width_icon = table_area->m_h / 18; - - m_width_column_space = 10; - - // Determine width of new points column - - m_font->setMonospaceDigits(true); - core::dimension2du r_new_p = m_font->getDimension(L"+99"); - - m_width_new_points = r_new_p.Width; - - // Determine width of overall points column - core::dimension2du r_all_p = m_font->getDimension(L"999"); - m_font->setMonospaceDigits(false); - - m_width_all_points = r_all_p.Width; - - m_table_width = m_width_icon + m_width_column_space - + m_width_kart_name; - - if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_FOLLOW_LEADER) - m_table_width += m_width_finish_time + m_width_column_space; - - // Only in GP mode are the points displayed. - if (race_manager->getMajorMode()==RaceManager::MAJOR_MODE_GRAND_PRIX) - m_table_width += m_width_new_points + m_width_all_points - + 2 * m_width_column_space; - - m_leftmost_column = table_area->m_x; -} // determineTableLayout - -//----------------------------------------------------------------------------- -/** This function is called when one of the player presses 'fire'. The next - * phase of the animation will be displayed. E.g. - * in a GP: pressing fire while/after showing the latest race result will - * start the animation for the current GP result - * in a normal race: when pressing fire while an animation is played, - * start the menu showing 'rerun, new race, back to main' etc. - */ -void RaceResultGUI::nextPhase() -{ - // This will trigger the next phase in the next render call. - m_timer = 9999; -} // nextPhase - -//----------------------------------------------------------------------------- -/** If escape is pressed, don't do the default option (close the screen), but - * advance to the next animation phase. - */ -bool RaceResultGUI::onEscapePressed() -{ - nextPhase(); - return false; // indicates 'do not close' -} // onEscapePressed - -//----------------------------------------------------------------------------- -/** This is called before an event is sent to a widget. Since in this case - * no widget is active, the event would be lost, so we act on fire events - * here and trigger the next phase. - */ -GUIEngine::EventPropagation RaceResultGUI::filterActions(PlayerAction action, - int deviceID, - const unsigned int value, - Input::InputType type, - int playerId) -{ - if(action!=PA_FIRE) return GUIEngine::EVENT_LET; - - // If the buttons are already visible, let the event go through since - // it will be triggering eventCallback where this is handles. - - if(m_animation_state == RR_WAIT_TILL_END) return GUIEngine::EVENT_LET; - - nextPhase(); - return GUIEngine::EVENT_BLOCK; -} // filterActions - -//----------------------------------------------------------------------------- -/** Called once a frame, this now triggers the rendering of the actual - * race result gui. - */ -void RaceResultGUI::onUpdate(float dt) -{ - renderGlobal(dt); - - // When the finish sound has been played, start the race over music. - if(m_finish_sound && m_finish_sound->getStatus() != SFXBase::SFX_PLAYING) - { - try - { - // This call is done once each frame, but startMusic() is cheap - // if the music is already playing. - music_manager->startMusic(m_race_over_music); - } - catch (std::exception& e) - { - Log::error("RaceResultGUI", "Exception caught when " - "trying to load music: %s", e.what()); + OverWorld::enterOverWorld(); } } -} // onUpdate -//----------------------------------------------------------------------------- -/** Render all global parts of the race gui, i.e. things that are only - * displayed once even in splitscreen. - * \param dt Timestep sized. - */ -void RaceResultGUI::renderGlobal(float dt) -{ - bool isSoccerWorld = race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER; - - m_timer += dt; - assert(World::getWorld()->getPhase()==WorldStatus::RESULT_DISPLAY_PHASE); - unsigned int num_karts = (unsigned int)m_all_row_infos.size(); - - // First: Update the finite state machine - // ====================================== - switch(m_animation_state) + //----------------------------------------------------------------------------- + /** This determines the layout, i.e. the size of all columns, font size etc. + */ + void RaceResultGUI::determineTableLayout() { - case RR_INIT: - for(unsigned int i=0; im_start_at = m_time_between_rows * i; - ri->m_x_pos = (float)UserConfigParams::m_width; - ri->m_y_pos = (float)(m_top+i*m_distance_between_rows); - } - m_animation_state = RR_RACE_RESULT; - break; - case RR_RACE_RESULT: - if(m_timer > m_time_overall_scroll) - { - // Make sure that all lines are aligned to the left - // (in case that the animation was skipped). - for(unsigned int i=0; im_x_pos = (float)m_leftmost_column; - } - if(race_manager->getMajorMode() != - RaceManager::MAJOR_MODE_GRAND_PRIX) - { - m_animation_state = RR_WAIT_TILL_END; - enableAllButtons(); - break; - } + GUIEngine::Widget *table_area = getWidget("result-table"); - determineGPLayout(); - m_animation_state = RR_OLD_GP_RESULTS; - m_timer = 0; - } - break; - case RR_OLD_GP_RESULTS: - if(m_timer > m_time_overall_scroll) + m_font = GUIEngine::getFont(); + assert(m_font); + m_was_monospace = m_font->getMonospaceDigits(); + m_font->setMonospaceDigits(true); + WorldWithRank *rank_world = (WorldWithRank*)World::getWorld(); + + unsigned int first_position = 1; + if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER) + first_position = 2; + + // Use only the karts that are supposed to be displayed (and + // ignore e.g. the leader in a FTL race). + unsigned int num_karts = race_manager->getNumberOfKarts() - first_position + 1; + + // In FTL races the leader kart is not displayed + m_all_row_infos.resize(num_karts); + + + // Determine the kart to display in the right order, + // and the maximum width for the kart name column + // ------------------------------------------------- + m_width_kart_name = 0; + float max_finish_time = 0; + + for (unsigned int position = first_position; + position <= race_manager->getNumberOfKarts(); position++) { - m_animation_state = RR_INCREASE_POINTS; - m_timer = 0; - for(unsigned int i=0; im_x_pos = (float)m_leftmost_column; - } - } - break; - case RR_INCREASE_POINTS: - // Have one second delay before the resorting starts. - if(m_timer > 1+m_time_for_points) - { - m_animation_state = RR_RESORT_TABLE; - if(m_gp_position_was_changed) - m_timer = 0; + const AbstractKart *kart = rank_world->getKartAtPosition(position); + + // Save a pointer to the current row_info entry + RowInfo *ri = &(m_all_row_infos[position - first_position]); + ri->m_is_player_kart = kart->getController()->isLocalPlayerController(); + + // Identify Human player, if so display real name other than kart name + const int rm_id = kart->getWorldKartId() - + (race_manager->getNumberOfKarts() - race_manager->getNumPlayers()); + + if (rm_id >= 0) + ri->m_kart_name = race_manager->getKartInfo(rm_id).getPlayerName(); else - // This causes the phase to go to RESORT_TABLE once, and then - // immediately wait till end. This has the advantage that any - // phase change settings will be processed properly. - m_timer = m_time_rotation+1; - // Make the new row permanent; necessary in case - // that the animation is skipped. - for(unsigned int i=0; im_kart_name = translations->fribidize(kart->getName()); + + video::ITexture *icon = + kart->getKartProperties()->getIconMaterial()->getTexture(); + ri->m_kart_icon = icon; + + // FTL karts will get a time assigned, they are not shown as eliminated + if (kart->isEliminated() && + race_manager->getMinorMode() != RaceManager::MINOR_MODE_FOLLOW_LEADER) { - RowInfo *ri = &(m_all_row_infos[i]); - ri->m_new_points = 0; - ri->m_current_displayed_points = - (float)ri->m_new_overall_points; + ri->m_finish_time_string = core::stringw(_("Eliminated")); + } + else + { + const float time = kart->getFinishTime(); + if (time > max_finish_time) max_finish_time = time; + std::string time_string = StringUtils::timeToString(time); + ri->m_finish_time_string = time_string.c_str(); } - } - break; - case RR_RESORT_TABLE: - if(m_timer > m_time_rotation) + core::dimension2du rect = + m_font->getDimension(ri->m_kart_name.c_str()); + if (rect.Width > m_width_kart_name) + m_width_kart_name = rect.Width; + } // for position + + std::string max_time = StringUtils::timeToString(max_finish_time); + core::stringw string_max_time(max_time.c_str()); + core::dimension2du r = m_font->getDimension(string_max_time.c_str()); + m_width_finish_time = r.Width; + + // Top pixel where to display text + m_top = table_area->m_y; + + // Height of the result display + unsigned int height = table_area->m_h; + + // Setup different timing information for the different phases + // ----------------------------------------------------------- + // How much time between consecutive rows + m_time_between_rows = 0.1f; + + // How long it takes for one line to scroll from right to left + m_time_single_scroll = 0.2f; + + // Time to rotate the entries to the proper GP position. + m_time_rotation = 1.0f; + + // The time the first phase is being displayed: add the start time + // of the last kart to the duration of the scroll plus some time + // of rest before the next phase starts + m_time_overall_scroll = (num_karts - 1)*m_time_between_rows + + m_time_single_scroll + 2.0f; + + // The time to increase the number of points. + m_time_for_points = 1.0f; + + // Determine text height + r = m_font->getDimension(L"Y"); + m_distance_between_rows = (int)(1.5f*r.Height); + + // If there are too many karts, reduce size between rows + if (m_distance_between_rows * num_karts > height) + m_distance_between_rows = height / num_karts; + + m_width_icon = table_area->m_h / 18; + + m_width_column_space = 10; + + // Determine width of new points column + + m_font->setMonospaceDigits(true); + core::dimension2du r_new_p = m_font->getDimension(L"+99"); + + m_width_new_points = r_new_p.Width; + + // Determine width of overall points column + core::dimension2du r_all_p = m_font->getDimension(L"999"); + m_font->setMonospaceDigits(false); + + m_width_all_points = r_all_p.Width; + + m_table_width = m_width_icon + m_width_column_space + + m_width_kart_name; + + if (race_manager->getMinorMode() != RaceManager::MINOR_MODE_FOLLOW_LEADER) + m_table_width += m_width_finish_time + m_width_column_space; + + // Only in GP mode are the points displayed. + if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) + m_table_width += m_width_new_points + m_width_all_points + + 2 * m_width_column_space; + + m_leftmost_column = table_area->m_x; + } // determineTableLayout + + //----------------------------------------------------------------------------- + /** This function is called when one of the player presses 'fire'. The next + * phase of the animation will be displayed. E.g. + * in a GP: pressing fire while/after showing the latest race result will + * start the animation for the current GP result + * in a normal race: when pressing fire while an animation is played, + * start the menu showing 'rerun, new race, back to main' etc. + */ + void RaceResultGUI::nextPhase() + { + // This will trigger the next phase in the next render call. + m_timer = 9999; + } // nextPhase + + //----------------------------------------------------------------------------- + /** If escape is pressed, don't do the default option (close the screen), but + * advance to the next animation phase. + */ + bool RaceResultGUI::onEscapePressed() + { + nextPhase(); + return false; // indicates 'do not close' + } // onEscapePressed + + //----------------------------------------------------------------------------- + /** This is called before an event is sent to a widget. Since in this case + * no widget is active, the event would be lost, so we act on fire events + * here and trigger the next phase. + */ + GUIEngine::EventPropagation RaceResultGUI::filterActions(PlayerAction action, + int deviceID, + const unsigned int value, + Input::InputType type, + int playerId) + { + if (action != PA_FIRE) return GUIEngine::EVENT_LET; + + // If the buttons are already visible, let the event go through since + // it will be triggering eventCallback where this is handles. + + if (m_animation_state == RR_WAIT_TILL_END) return GUIEngine::EVENT_LET; + + nextPhase(); + return GUIEngine::EVENT_BLOCK; + } // filterActions + + //----------------------------------------------------------------------------- + /** Called once a frame, this now triggers the rendering of the actual + * race result gui. + */ + void RaceResultGUI::onUpdate(float dt) + { + renderGlobal(dt); + + // When the finish sound has been played, start the race over music. + if (m_finish_sound && m_finish_sound->getStatus() != SFXBase::SFX_PLAYING) { - m_animation_state = RR_WAIT_TILL_END; - // Make the new row permanent. - for(unsigned int i=0; istartMusic(m_race_over_music); + } + catch (std::exception& e) + { + Log::error("RaceResultGUI", "Exception caught when " + "trying to load music: %s", e.what()); + } + } + } // onUpdate + + //----------------------------------------------------------------------------- + /** Render all global parts of the race gui, i.e. things that are only + * displayed once even in splitscreen. + * \param dt Timestep sized. + */ + void RaceResultGUI::renderGlobal(float dt) + { + bool isSoccerWorld = race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER; + + m_timer += dt; + assert(World::getWorld()->getPhase() == WorldStatus::RESULT_DISPLAY_PHASE); + unsigned int num_karts = (unsigned int)m_all_row_infos.size(); + + // First: Update the finite state machine + // ====================================== + switch (m_animation_state) + { + case RR_INIT: + for (unsigned int i = 0; i < num_karts; i++) { RowInfo *ri = &(m_all_row_infos[i]); - ri->m_y_pos = ri->m_centre_point - ri->m_radius; + ri->m_start_at = m_time_between_rows * i; + ri->m_x_pos = (float)UserConfigParams::m_width; + ri->m_y_pos = (float)(m_top + i*m_distance_between_rows); } - enableAllButtons(); - } - break; - case RR_WAIT_TILL_END: - if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) - displayGPProgress(); - if(m_timer - m_time_rotation > 1.0f && - dynamic_cast(World::getWorld()) ) - { - race_manager->exitRace(); - StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance()); - } - break; - } // switch - - // Second phase: update X and Y positions for the various animations - // ================================================================= - float v = 0.9f*UserConfigParams::m_width/m_time_single_scroll; - if(!isSoccerWorld) - { - for(unsigned int i=0; im_x_pos; - float y = ri->m_y_pos; - switch(m_animation_state) + m_animation_state = RR_RACE_RESULT; + break; + case RR_RACE_RESULT: + if (m_timer > m_time_overall_scroll) { - // Both states use the same scrolling: - case RR_INIT: break; // Remove compiler warning - case RR_RACE_RESULT: - case RR_OLD_GP_RESULTS: - if(m_timer > ri->m_start_at) - { // if active - ri->m_x_pos -= dt*v; - if(ri->m_x_posm_x_pos = (float)m_leftmost_column; - x = ri->m_x_pos; - } - break; - case RR_INCREASE_POINTS: - { - WorldWithRank *wwr = dynamic_cast(World::getWorld()); - assert(wwr); - int most_points; - if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER) - most_points = wwr->getScoreForPosition(2); - else - most_points = wwr->getScoreForPosition(1); - ri->m_current_displayed_points += - dt*most_points / m_time_for_points; - if (ri->m_current_displayed_points > ri->m_new_overall_points) + // Make sure that all lines are aligned to the left + // (in case that the animation was skipped). + for (unsigned int i = 0; i < num_karts; i++) { + RowInfo *ri = &(m_all_row_infos[i]); + ri->m_x_pos = (float)m_leftmost_column; + } + if (race_manager->getMajorMode() != + RaceManager::MAJOR_MODE_GRAND_PRIX) + { + m_animation_state = RR_WAIT_TILL_END; + enableAllButtons(); + break; + } + + determineGPLayout(); + m_animation_state = RR_OLD_GP_RESULTS; + m_timer = 0; + } + break; + case RR_OLD_GP_RESULTS: + if (m_timer > m_time_overall_scroll) + { + m_animation_state = RR_INCREASE_POINTS; + m_timer = 0; + for (unsigned int i = 0; i < num_karts; i++) + { + RowInfo *ri = &(m_all_row_infos[i]); + ri->m_x_pos = (float)m_leftmost_column; + } + } + break; + case RR_INCREASE_POINTS: + // Have one second delay before the resorting starts. + if (m_timer > 1 + m_time_for_points) + { + m_animation_state = RR_RESORT_TABLE; + if (m_gp_position_was_changed) + m_timer = 0; + else + // This causes the phase to go to RESORT_TABLE once, and then + // immediately wait till end. This has the advantage that any + // phase change settings will be processed properly. + m_timer = m_time_rotation + 1; + // Make the new row permanent; necessary in case + // that the animation is skipped. + for (unsigned int i = 0; i < num_karts; i++) + { + RowInfo *ri = &(m_all_row_infos[i]); + ri->m_new_points = 0; ri->m_current_displayed_points = (float)ri->m_new_overall_points; } - ri->m_new_points -= - dt*most_points / m_time_for_points; - if (ri->m_new_points < 0) - ri->m_new_points = 0; - break; + } - case RR_RESORT_TABLE: - x = ri->m_x_pos - - ri->m_radius*sin(m_timer/m_time_rotation*M_PI); - y = ri->m_centre_point - + ri->m_radius*cos(m_timer/m_time_rotation*M_PI); - break; - case RR_WAIT_TILL_END: - break; - } // switch - displayOneEntry((unsigned int)x, (unsigned int)y, i, true); - } // for i - } - else - displaySoccerResults(); + break; + case RR_RESORT_TABLE: + if (m_timer > m_time_rotation) + { + m_animation_state = RR_WAIT_TILL_END; + // Make the new row permanent. + for (unsigned int i = 0; i < num_karts; i++) + { + RowInfo *ri = &(m_all_row_infos[i]); + ri->m_y_pos = ri->m_centre_point - ri->m_radius; + } + enableAllButtons(); + } + break; + case RR_WAIT_TILL_END: + if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) + displayGPProgress(); + if (m_timer - m_time_rotation > 1.0f && + dynamic_cast(World::getWorld())) + { + race_manager->exitRace(); + StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance()); + } + break; + } // switch - // Display highscores - if (race_manager->getMajorMode() != RaceManager::MAJOR_MODE_GRAND_PRIX || - m_animation_state == RR_RACE_RESULT) - { - displayHighScores(); - } -} // renderGlobal - -//----------------------------------------------------------------------------- -/** Determine the layout and fields for the GP table based on the previous - * GP results. - */ -void RaceResultGUI::determineGPLayout() -{ - unsigned int num_karts = race_manager->getNumberOfKarts(); - std::vector old_rank(num_karts, 0); - for(unsigned int kart_id=0; kart_idgetKartGPRank(kart_id); - // In case of FTL mode: ignore the leader - if(rank<0) continue; - old_rank[kart_id] = rank; - const AbstractKart *kart = World::getWorld()->getKart(kart_id); - RowInfo *ri = &(m_all_row_infos[rank]); - ri->m_kart_icon = - kart->getKartProperties()->getIconMaterial()->getTexture(); - - const int rm_id = kart_id - - (race_manager->getNumberOfKarts() - race_manager->getNumPlayers()); - - if (rm_id >= 0) - ri->m_kart_name = race_manager->getKartInfo(rm_id).getPlayerName(); - else - ri->m_kart_name = translations->fribidize(kart->getName()); - - ri->m_is_player_kart = kart->getController()->isLocalPlayerController(); - - // In FTL karts do have a time, which is shown even when the kart - // is eliminated - if (kart->isEliminated() && - race_manager->getMinorMode()!=RaceManager::MINOR_MODE_FOLLOW_LEADER) + // Second phase: update X and Y positions for the various animations + // ================================================================= + float v = 0.9f*UserConfigParams::m_width / m_time_single_scroll; + if (!isSoccerWorld) { - ri->m_finish_time_string = core::stringw(_("Eliminated")); + for (unsigned int i = 0; i < m_all_row_infos.size(); i++) + { + RowInfo *ri = &(m_all_row_infos[i]); + float x = ri->m_x_pos; + float y = ri->m_y_pos; + switch (m_animation_state) + { + // Both states use the same scrolling: + case RR_INIT: break; // Remove compiler warning + case RR_RACE_RESULT: + case RR_OLD_GP_RESULTS: + if (m_timer > ri->m_start_at) + { // if active + ri->m_x_pos -= dt*v; + if (ri->m_x_pos < m_leftmost_column) + ri->m_x_pos = (float)m_leftmost_column; + x = ri->m_x_pos; + } + break; + case RR_INCREASE_POINTS: + { + WorldWithRank *wwr = dynamic_cast(World::getWorld()); + assert(wwr); + int most_points; + if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER) + most_points = wwr->getScoreForPosition(2); + else + most_points = wwr->getScoreForPosition(1); + ri->m_current_displayed_points += + dt*most_points / m_time_for_points; + if (ri->m_current_displayed_points > ri->m_new_overall_points) + { + ri->m_current_displayed_points = + (float)ri->m_new_overall_points; + } + ri->m_new_points -= + dt*most_points / m_time_for_points; + if (ri->m_new_points < 0) + ri->m_new_points = 0; + break; + } + case RR_RESORT_TABLE: + x = ri->m_x_pos + - ri->m_radius*sin(m_timer / m_time_rotation*M_PI); + y = ri->m_centre_point + + ri->m_radius*cos(m_timer / m_time_rotation*M_PI); + break; + case RR_WAIT_TILL_END: + break; + } // switch + displayOneEntry((unsigned int)x, (unsigned int)y, i, true); + } // for i } else + displaySoccerResults(); + + // Display highscores + if (race_manager->getMajorMode() != RaceManager::MAJOR_MODE_GRAND_PRIX || + m_animation_state == RR_RACE_RESULT) { - float time = race_manager->getOverallTime(kart_id); - ri->m_finish_time_string - = StringUtils::timeToString(time).c_str(); + displayHighScores(); } - ri->m_start_at = m_time_between_rows * rank; - ri->m_x_pos = (float)UserConfigParams::m_width; - ri->m_y_pos = (float)(m_top+rank*m_distance_between_rows); - int p = race_manager->getKartPrevScore(kart_id); - ri->m_current_displayed_points = (float)p; - if (kart->isEliminated() && - race_manager->getMinorMode()!=RaceManager::MINOR_MODE_FOLLOW_LEADER) + } // renderGlobal + + //----------------------------------------------------------------------------- + /** Determine the layout and fields for the GP table based on the previous + * GP results. + */ + void RaceResultGUI::determineGPLayout() + { + unsigned int num_karts = race_manager->getNumberOfKarts(); + std::vector old_rank(num_karts, 0); + for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++) { - ri->m_new_points = 0; + int rank = race_manager->getKartGPRank(kart_id); + // In case of FTL mode: ignore the leader + if (rank < 0) continue; + old_rank[kart_id] = rank; + const AbstractKart *kart = World::getWorld()->getKart(kart_id); + RowInfo *ri = &(m_all_row_infos[rank]); + ri->m_kart_icon = + kart->getKartProperties()->getIconMaterial()->getTexture(); + + const int rm_id = kart_id - + (race_manager->getNumberOfKarts() - race_manager->getNumPlayers()); + + if (rm_id >= 0) + ri->m_kart_name = race_manager->getKartInfo(rm_id).getPlayerName(); + else + ri->m_kart_name = translations->fribidize(kart->getName()); + + ri->m_is_player_kart = kart->getController()->isLocalPlayerController(); + + // In FTL karts do have a time, which is shown even when the kart + // is eliminated + if (kart->isEliminated() && + race_manager->getMinorMode() != RaceManager::MINOR_MODE_FOLLOW_LEADER) + { + ri->m_finish_time_string = core::stringw(_("Eliminated")); + } + else + { + float time = race_manager->getOverallTime(kart_id); + ri->m_finish_time_string + = StringUtils::timeToString(time).c_str(); + } + ri->m_start_at = m_time_between_rows * rank; + ri->m_x_pos = (float)UserConfigParams::m_width; + ri->m_y_pos = (float)(m_top + rank*m_distance_between_rows); + int p = race_manager->getKartPrevScore(kart_id); + ri->m_current_displayed_points = (float)p; + if (kart->isEliminated() && + race_manager->getMinorMode() != RaceManager::MINOR_MODE_FOLLOW_LEADER) + { + ri->m_new_points = 0; + } + else + { + WorldWithRank *wwr = dynamic_cast(World::getWorld()); + assert(wwr); + ri->m_new_points = + (float)wwr->getScoreForPosition(kart->getPosition()); + } } - else + + // Now update the GP ranks, and determine the new position + // ------------------------------------------------------- + race_manager->computeGPRanks(); + m_gp_position_was_changed = false; + for (unsigned int i = 0; i < num_karts; i++) { - WorldWithRank *wwr = dynamic_cast(World::getWorld()); - assert(wwr); - ri->m_new_points = - (float)wwr->getScoreForPosition(kart->getPosition()); - } - } + int j = old_rank[i]; + int gp_position = race_manager->getKartGPRank(i); + m_gp_position_was_changed |= j != gp_position; + RowInfo *ri = &(m_all_row_infos[j]); + ri->m_radius = (j - gp_position)*(int)m_distance_between_rows*0.5f; + ri->m_centre_point = m_top + (gp_position + j)*m_distance_between_rows*0.5f; + int p = race_manager->getKartScore(i); + ri->m_new_overall_points = p; + } // i < num_karts + } // determineGPLayout - // Now update the GP ranks, and determine the new position - // ------------------------------------------------------- - race_manager->computeGPRanks(); - m_gp_position_was_changed = false; - for(unsigned int i=0; igetKartGPRank(i); - m_gp_position_was_changed |= j!=gp_position; - RowInfo *ri = &(m_all_row_infos[j]); - ri->m_radius = (j-gp_position)*(int)m_distance_between_rows*0.5f; - ri->m_centre_point= m_top+(gp_position+j)*m_distance_between_rows*0.5f; - int p = race_manager->getKartScore(i); - ri->m_new_overall_points = p; - } // i < num_karts -} // determineGPLayout + RowInfo *ri = &(m_all_row_infos[n]); + video::SColor color = ri->m_is_player_kart + ? video::SColor(255, 255, 0, 0) + : video::SColor(255, 255, 255, 255); -//----------------------------------------------------------------------------- -/** Displays the race results for a single kart. - * \param n Index of the kart to be displayed. - * \param display_points True if GP points should be displayed, too - */ -void RaceResultGUI::displayOneEntry(unsigned int x, unsigned int y, - unsigned int n, bool display_points) -{ - RowInfo *ri = &(m_all_row_infos[n]); - video::SColor color = ri->m_is_player_kart - ? video::SColor(255,255,0, 0 ) - : video::SColor(255,255,255,255); + unsigned int current_x = x; - unsigned int current_x = x; - - // First draw the icon - // ------------------- - if(ri->m_kart_icon) - { - core::recti source_rect(core::vector2di(0,0), - ri->m_kart_icon->getSize()); - core::recti dest_rect(current_x, y, - current_x+m_width_icon, y+m_width_icon); - draw2DImage(ri->m_kart_icon, dest_rect, - source_rect, NULL, NULL, - true); - } - - current_x += m_width_icon + m_width_column_space; - - // Draw the name - // ------------- - - core::recti pos_name(current_x, y, - UserConfigParams::m_width, y+m_distance_between_rows); - m_font->draw(ri->m_kart_name, pos_name, color, false, false, NULL, - true /* ignoreRTL */); - current_x += m_width_kart_name + m_width_column_space; - - - core::recti dest_rect = core::recti(current_x, y, current_x + 100, y + 10); - m_font->draw(ri->m_finish_time_string, dest_rect, color, false, false, - NULL, true /* ignoreRTL */); - current_x += m_width_finish_time + m_width_column_space; - - // Only display points in GP mode and when the GP results are displayed. - // ===================================================================== - if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX && - m_animation_state != RR_RACE_RESULT) - { - // Draw the new points + // First draw the icon // ------------------- - if(ri->m_new_points > 0) + if (ri->m_kart_icon) { - core::recti dest_rect = core::recti(current_x, y, - current_x+100, y+10); - core::stringw point_string = core::stringw("+") - + core::stringw((int)ri->m_new_points); - // With mono-space digits space has the same width as each digit, - // so we can simply fill up the string with spaces to get the - // right aligned. - while(point_string.size()<3) - point_string = core::stringw(" ")+point_string; - m_font->draw(point_string, dest_rect, color, false, false, NULL, - true /* ignoreRTL */); + core::recti source_rect(core::vector2di(0, 0), + ri->m_kart_icon->getSize()); + core::recti dest_rect(current_x, y, + current_x + m_width_icon, y + m_width_icon); + draw2DImage(ri->m_kart_icon, dest_rect, + source_rect, NULL, NULL, + true); } - current_x += m_width_new_points + m_width_column_space; - // Draw the old_points plus increase value - // --------------------------------------- - core::recti dest_rect = core::recti(current_x, y, current_x+100, y+10); - core::stringw point_inc_string = - core::stringw((int)(ri->m_current_displayed_points)); - while(point_inc_string.size()<3) - point_inc_string = core::stringw(" ")+point_inc_string; - m_font->draw(point_inc_string, dest_rect, color, false, false, NULL, - true /* ignoreRTL */); - } -} // displayOneEntry + current_x += m_width_icon + m_width_column_space; -//----------------------------------------------------------------------------- -void RaceResultGUI::displaySoccerResults() -{ + // Draw the name + // ------------- - //Draw win text - core::stringw result_text; - static video::SColor color = video::SColor(255, 255, 255, 255); - gui::IGUIFont* font = GUIEngine::getTitleFont(); - int current_x = UserConfigParams::m_width/2; - RowInfo *ri = &(m_all_row_infos[0]); - int current_y = (int)ri->m_y_pos; - SoccerWorld* sw = (SoccerWorld*)World::getWorld(); - const int red_score = sw->getScore(SOCCER_TEAM_RED); - const int blue_score = sw->getScore(SOCCER_TEAM_BLUE); + core::recti pos_name(current_x, y, + UserConfigParams::m_width, y + m_distance_between_rows); + m_font->draw(ri->m_kart_name, pos_name, color, false, false, NULL, + true /* ignoreRTL */); + current_x += m_width_kart_name + m_width_column_space; - GUIEngine::Widget *table_area = getWidget("result-table"); - int height = table_area->m_h + table_area->m_y; - if(red_score > blue_score) + core::recti dest_rect = core::recti(current_x, y, current_x + 100, y + 10); + m_font->draw(ri->m_finish_time_string, dest_rect, color, false, false, + NULL, true /* ignoreRTL */); + current_x += m_width_finish_time + m_width_column_space; + + // Only display points in GP mode and when the GP results are displayed. + // ===================================================================== + if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX && + m_animation_state != RR_RACE_RESULT) + { + // Draw the new points + // ------------------- + if (ri->m_new_points > 0) + { + core::recti dest_rect = core::recti(current_x, y, + current_x + 100, y + 10); + core::stringw point_string = core::stringw("+") + + core::stringw((int)ri->m_new_points); + // With mono-space digits space has the same width as each digit, + // so we can simply fill up the string with spaces to get the + // right aligned. + while (point_string.size() < 3) + point_string = core::stringw(" ") + point_string; + m_font->draw(point_string, dest_rect, color, false, false, NULL, + true /* ignoreRTL */); + } + current_x += m_width_new_points + m_width_column_space; + + // Draw the old_points plus increase value + // --------------------------------------- + core::recti dest_rect = core::recti(current_x, y, current_x + 100, y + 10); + core::stringw point_inc_string = + core::stringw((int)(ri->m_current_displayed_points)); + while (point_inc_string.size() < 3) + point_inc_string = core::stringw(" ") + point_inc_string; + m_font->draw(point_inc_string, dest_rect, color, false, false, NULL, + true /* ignoreRTL */); + } + } // displayOneEntry + + //----------------------------------------------------------------------------- + void RaceResultGUI::displaySoccerResults() { - result_text = _("Red Team Wins"); - } - else if(blue_score > red_score) - { - result_text = _("Blue Team Wins"); - } - else - { - //Cannot really happen now. Only in time limited matches. - result_text = _("It's a draw"); - } - core::rect pos(current_x, current_y, current_x, current_y); - font->draw(result_text.c_str(), pos, color, true, true); - core::dimension2du rect = m_font->getDimension(result_text.c_str()); + //Draw win text + core::stringw result_text; + static video::SColor color = video::SColor(255, 255, 255, 255); + gui::IGUIFont* font = GUIEngine::getTitleFont(); + int current_x = UserConfigParams::m_width / 2; + RowInfo *ri = &(m_all_row_infos[0]); + int current_y = (int)ri->m_y_pos; + SoccerWorld* sw = (SoccerWorld*)World::getWorld(); + const int red_score = sw->getScore(SOCCER_TEAM_RED); + const int blue_score = sw->getScore(SOCCER_TEAM_BLUE); - //Draw team scores: - current_y += rect.Height; - current_x /= 2; - irr::video::ITexture* red_icon = irr_driver->getTexture(FileManager::GUI, - "soccer_ball_red.png"); - irr::video::ITexture* blue_icon = irr_driver->getTexture(FileManager::GUI, - "soccer_ball_blue.png"); + GUIEngine::Widget *table_area = getWidget("result-table"); + int height = table_area->m_h + table_area->m_y; - core::recti source_rect(core::vector2di(0,0), red_icon->getSize()); - core::recti dest_rect(current_x, current_y, current_x+red_icon->getSize().Width/2, - current_y+red_icon->getSize().Height/2); - draw2DImage(red_icon, dest_rect,source_rect, - NULL,NULL, true); - current_x += UserConfigParams::m_width/2 - red_icon->getSize().Width/2; - dest_rect = core::recti(current_x, current_y, current_x+red_icon->getSize().Width/2, - current_y+red_icon->getSize().Height/2); - draw2DImage(blue_icon,dest_rect,source_rect, - NULL, NULL, true); - - result_text = StringUtils::toWString(blue_score); - rect = m_font->getDimension(result_text.c_str()); - current_x += red_icon->getSize().Width/4; - current_y += red_icon->getSize().Height/2 + rect.Height/4; - pos = core::rect(current_x, current_y, current_x, current_y); - color = video::SColor(255,255,255,255); - font->draw(result_text.c_str(), pos, color, true, false); - - current_x -= UserConfigParams::m_width/2 - red_icon->getSize().Width/2; - result_text = StringUtils::toWString(red_score); - pos = core::rect(current_x,current_y,current_x,current_y); - font->draw(result_text.c_str(), pos, color, true, false); - - int center_x = UserConfigParams::m_width/2; - pos = core::rect(center_x, current_y, center_x, current_y); - font->draw("-", pos, color, true, false); - - //Draw goal scorers: - //The red scorers: - current_y += rect.Height/2 + rect.Height/4; - font = GUIEngine::getSmallFont(); - std::vector scorers = sw->getScorers(SOCCER_TEAM_RED); - std::vector score_times = sw->getScoreTimes(SOCCER_TEAM_RED); - irr::video::ITexture* scorer_icon; - - int prev_y = current_y; - for(unsigned int i=0; igetNumberOfKarts() - race_manager->getNumPlayers()); - - if (rm_id >= 0) - result_text = race_manager->getKartInfo(rm_id).getPlayerName(); + if (red_score > blue_score) + { + result_text = _("Red Team Wins"); + } + else if (blue_score > red_score) + { + result_text = _("Blue Team Wins"); + } else - result_text = sw->getKart(kart_id)-> + { + //Cannot really happen now. Only in time limited matches. + result_text = _("It's a draw"); + } + core::rect pos(current_x, current_y, current_x, current_y); + font->draw(result_text.c_str(), pos, color, true, true); + + core::dimension2du rect = m_font->getDimension(result_text.c_str()); + + //Draw team scores: + current_y += rect.Height; + current_x /= 2; + irr::video::ITexture* red_icon = irr_driver->getTexture(FileManager::GUI, + "soccer_ball_red.png"); + irr::video::ITexture* blue_icon = irr_driver->getTexture(FileManager::GUI, + "soccer_ball_blue.png"); + + core::recti source_rect(core::vector2di(0, 0), red_icon->getSize()); + core::recti dest_rect(current_x, current_y, current_x + red_icon->getSize().Width / 2, + current_y + red_icon->getSize().Height / 2); + draw2DImage(red_icon, dest_rect, source_rect, + NULL, NULL, true); + current_x += UserConfigParams::m_width / 2 - red_icon->getSize().Width / 2; + dest_rect = core::recti(current_x, current_y, current_x + red_icon->getSize().Width / 2, + current_y + red_icon->getSize().Height / 2); + draw2DImage(blue_icon, dest_rect, source_rect, + NULL, NULL, true); + + result_text = StringUtils::toWString(blue_score); + rect = m_font->getDimension(result_text.c_str()); + current_x += red_icon->getSize().Width / 4; + current_y += red_icon->getSize().Height / 2 + rect.Height / 4; + pos = core::rect(current_x, current_y, current_x, current_y); + color = video::SColor(255, 255, 255, 255); + font->draw(result_text.c_str(), pos, color, true, false); + + current_x -= UserConfigParams::m_width / 2 - red_icon->getSize().Width / 2; + result_text = StringUtils::toWString(red_score); + pos = core::rect(current_x, current_y, current_x, current_y); + font->draw(result_text.c_str(), pos, color, true, false); + + int center_x = UserConfigParams::m_width / 2; + pos = core::rect(center_x, current_y, center_x, current_y); + font->draw("-", pos, color, true, false); + + //Draw goal scorers: + //The red scorers: + current_y += rect.Height / 2 + rect.Height / 4; + font = GUIEngine::getSmallFont(); + std::vector scorers = sw->getScorers(SOCCER_TEAM_RED); + std::vector score_times = sw->getScoreTimes(SOCCER_TEAM_RED); + irr::video::ITexture* scorer_icon; + + int prev_y = current_y; + for (unsigned int i = 0; i < scorers.size(); i++) + { + const bool own_goal = !(scorers.at(i).m_correct_goal); + + const int kart_id = scorers.at(i).m_id; + const int rm_id = kart_id - + (race_manager->getNumberOfKarts() - race_manager->getNumPlayers()); + + if (rm_id >= 0) + result_text = race_manager->getKartInfo(rm_id).getPlayerName(); + else + result_text = sw->getKart(kart_id)-> getKartProperties()->getName(); - if (own_goal) - { - result_text.append(" "); - result_text.append( _("(Own Goal)") ); + if (own_goal) + { + result_text.append(" "); + result_text.append(_("(Own Goal)")); + } + + result_text.append(" "); + result_text.append(StringUtils::timeToString(score_times.at(i)).c_str()); + rect = m_font->getDimension(result_text.c_str()); + + if (height - prev_y < ((short)scorers.size() + 1)*(short)rect.Height) + current_y += (height - prev_y) / ((short)scorers.size() + 1); + else + current_y += rect.Height; + + if (current_y > height) break; + + pos = core::rect(current_x, current_y, current_x, current_y); + font->draw(result_text, pos, (own_goal ? + video::SColor(255, 255, 0, 0) : color), true, false); + scorer_icon = sw->getKart(scorers.at(i).m_id) + ->getKartProperties()->getIconMaterial()->getTexture(); + source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize()); + irr::u32 offset_x = GUIEngine::getFont()->getDimension(result_text.c_str()).Width / 2; + dest_rect = core::recti(current_x - offset_x - 30, current_y, current_x - offset_x, current_y + 30); + draw2DImage(scorer_icon, dest_rect, source_rect, + NULL, NULL, true); } - result_text.append(" "); - result_text.append(StringUtils::timeToString(score_times.at(i)).c_str()); - rect = m_font->getDimension(result_text.c_str()); + //The blue scorers: + current_y = prev_y; + current_x += UserConfigParams::m_width / 2 - red_icon->getSize().Width / 2; + scorers = sw->getScorers(SOCCER_TEAM_BLUE); + score_times = sw->getScoreTimes(SOCCER_TEAM_BLUE); + for (unsigned int i = 0; i < scorers.size(); i++) + { + const bool own_goal = !(scorers.at(i).m_correct_goal); - if(height-prev_y < ((short)scorers.size()+1)*(short)rect.Height) - current_y += (height-prev_y)/((short)scorers.size()+1); - else - current_y += rect.Height; + const int kart_id = scorers.at(i).m_id; + const int rm_id = kart_id - + (race_manager->getNumberOfKarts() - race_manager->getNumPlayers()); - if(current_y > height) break; - - pos = core::rect(current_x,current_y,current_x,current_y); - font->draw(result_text, pos, (own_goal ? - video::SColor(255, 255, 0, 0) : color), true, false); - scorer_icon = sw->getKart(scorers.at(i).m_id) - ->getKartProperties()->getIconMaterial()->getTexture(); - source_rect = core::recti(core::vector2di(0,0), scorer_icon->getSize()); - irr::u32 offset_x = GUIEngine::getFont()->getDimension(result_text.c_str()).Width/2; - dest_rect = core::recti(current_x-offset_x-30, current_y, current_x-offset_x, current_y+ 30); - draw2DImage(scorer_icon, dest_rect, source_rect, - NULL, NULL, true); - } - - //The blue scorers: - current_y = prev_y; - current_x += UserConfigParams::m_width/2 - red_icon->getSize().Width/2; - scorers = sw->getScorers(SOCCER_TEAM_BLUE); - score_times = sw->getScoreTimes(SOCCER_TEAM_BLUE); - for(unsigned int i=0; igetNumberOfKarts() - race_manager->getNumPlayers()); - - if (rm_id >= 0) - result_text = race_manager->getKartInfo(rm_id).getPlayerName(); - else - result_text = sw->getKart(kart_id)-> + if (rm_id >= 0) + result_text = race_manager->getKartInfo(rm_id).getPlayerName(); + else + result_text = sw->getKart(kart_id)-> getKartProperties()->getName(); - if (own_goal) - { - result_text.append(" "); - result_text.append( _("(Own Goal)") ); + if (own_goal) + { + result_text.append(" "); + result_text.append(_("(Own Goal)")); + } + + result_text.append(" "); + result_text.append(StringUtils::timeToString(score_times.at(i)).c_str()); + rect = m_font->getDimension(result_text.c_str()); + + if (height - prev_y < ((short)scorers.size() + 1)*(short)rect.Height) + current_y += (height - prev_y) / ((short)scorers.size() + 1); + else + current_y += rect.Height; + + if (current_y > height) break; + + pos = core::rect(current_x, current_y, current_x, current_y); + font->draw(result_text, pos, (own_goal ? + video::SColor(255, 255, 0, 0) : color), true, false); + scorer_icon = sw->getKart(scorers.at(i).m_id)-> + getKartProperties()->getIconMaterial()->getTexture(); + source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize()); + irr::u32 offset_x = GUIEngine::getFont()->getDimension(result_text.c_str()).Width / 2; + + dest_rect = core::recti(current_x - offset_x - 30, current_y, current_x - offset_x, current_y + 30); + draw2DImage(scorer_icon, dest_rect, source_rect, + NULL, NULL, true); } - - result_text.append(" "); - result_text.append(StringUtils::timeToString(score_times.at(i)).c_str()); - rect = m_font->getDimension(result_text.c_str()); - - if(height-prev_y < ((short)scorers.size()+1)*(short)rect.Height) - current_y += (height-prev_y)/((short)scorers.size()+1); - else - current_y += rect.Height; - - if(current_y > height) break; - - pos = core::rect(current_x,current_y,current_x,current_y); - font->draw(result_text,pos, (own_goal ? - video::SColor(255, 255, 0, 0) : color), true, false); - scorer_icon = sw->getKart(scorers.at(i).m_id)-> - getKartProperties()->getIconMaterial()->getTexture(); - source_rect = core::recti(core::vector2di(0,0), scorer_icon->getSize()); - irr::u32 offset_x = GUIEngine::getFont()->getDimension(result_text.c_str()).Width/2; - - dest_rect = core::recti(current_x-offset_x-30, current_y, current_x-offset_x, current_y+ 30); - draw2DImage(scorer_icon, dest_rect, source_rect, - NULL, NULL, true); } -} -//----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- -void RaceResultGUI::clearHighscores() -{ - m_highscore_rank = 0; -} // clearHighscores - -//----------------------------------------------------------------------------- - -void RaceResultGUI::setHighscore(int rank) -{ - m_highscore_rank = rank; -} // setHighscore - -// ---------------------------------------------------------------------------- -void RaceResultGUI::enableGPProgress() -{ - if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) + void RaceResultGUI::clearHighscores() { + m_highscore_rank = 0; + } // clearHighscores + + //----------------------------------------------------------------------------- + + void RaceResultGUI::setHighscore(int rank) + { + m_highscore_rank = rank; + } // setHighscore + + // ---------------------------------------------------------------------------- + void RaceResultGUI::enableGPProgress() + { + if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) + { + GUIEngine::Widget* result_table = getWidget("result-table"); + assert(result_table != NULL); + + int currentTrack = race_manager->getTrackNumber(); + int font_height = getFontHeight(); + int w = (int)(UserConfigParams::m_width*0.17); + int x = (int)(result_table->m_x + result_table->m_w - w - 15); + int y = (m_top + font_height + 5); + + //Current progress + GUIEngine::LabelWidget* status_label = new GUIEngine::LabelWidget(); + status_label->m_properties[GUIEngine::PROP_ID] = "status_label"; + status_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "center"; + status_label->m_x = x; + status_label->m_y = y; + status_label->m_w = w; + status_label->m_h = font_height; + status_label->add(); + status_label->setText(_("Track %i/%i", currentTrack + 1, + race_manager->getGrandPrix().getNumberOfTracks()), true); + addGPProgressWidget(status_label); + y = (status_label->m_y + status_label->m_h + 5); + + //Scroll up button + GUIEngine::IconButtonWidget* up_button = new GUIEngine::IconButtonWidget( + GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, + false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + up_button->m_properties[GUIEngine::PROP_ID] = "up_button"; + up_button->m_x = x; + up_button->m_y = y; + up_button->m_w = w; + up_button->m_h = font_height; + up_button->add(); + up_button->setImage(file_manager->getAsset(FileManager::GUI, "scroll_up.png")); + addGPProgressWidget(up_button); + y = (up_button->m_y + up_button->m_h + SSHOT_SEPARATION); + + //Track screenshots and labels + int n_sshot = 1; + for (int i = m_start_track; i < m_end_track; i++) + { + //Screenshot + GUIEngine::IconButtonWidget* screenshot_widget = + new GUIEngine::IconButtonWidget( + GUIEngine::IconButtonWidget:: + SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, + false, false, + GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + screenshot_widget->setCustomAspectRatio(4.0f / 3.0f); + screenshot_widget->m_x = x; + screenshot_widget->m_y = y; + screenshot_widget->m_w = w; + screenshot_widget->m_h = m_sshot_height; + screenshot_widget->m_properties[GUIEngine::PROP_ID] = + ("sshot_" + StringUtils::toString(n_sshot)); + screenshot_widget->add(); + addGPProgressWidget(screenshot_widget); + + //Label + GUIEngine::LabelWidget* sshot_label = new GUIEngine::LabelWidget(); + sshot_label->m_properties[GUIEngine::PROP_ID] = + ("sshot_label_" + StringUtils::toString(n_sshot)); + sshot_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "left"; + sshot_label->m_x = (x + w + 5); + sshot_label->m_y = (y + (m_sshot_height / 2) - (font_height / 2)); + sshot_label->m_w = (w / 2); + sshot_label->m_h = font_height; + sshot_label->add(); + addGPProgressWidget(sshot_label); + + y += (m_sshot_height + SSHOT_SEPARATION); + n_sshot++; + } // for + displayScreenShots(); + + //Scroll down button + GUIEngine::IconButtonWidget* down_button = new GUIEngine::IconButtonWidget( + GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, + false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + down_button->m_properties[GUIEngine::PROP_ID] = "down_button"; + down_button->m_x = x; + down_button->m_y = y; + down_button->m_w = w; + down_button->m_h = font_height; + down_button->add(); + down_button->setImage(file_manager->getAsset(FileManager::GUI, "scroll_down.png")); + addGPProgressWidget(down_button); + + } // if MAJOR_MODE_GRAND_PRIX) + + } // enableGPProgress + + // ---------------------------------------------------------------------------- + void RaceResultGUI::addGPProgressWidget(GUIEngine::Widget* widget) + { + m_widgets.push_back(widget); + m_gp_progress_widgets.push_back(widget); + } + + // ---------------------------------------------------------------------------- + void RaceResultGUI::displayGPProgress() + { + core::stringw msg = _("Grand Prix progress:"); + GUIEngine::Widget* result_table = getWidget("result-table"); assert(result_table != NULL); - int currentTrack = race_manager->getTrackNumber(); - int font_height = getFontHeight (); - int w = (int)(UserConfigParams::m_width*0.17); - int x = (int)(result_table->m_x + result_table->m_w - w - 15); - int y = (m_top + font_height + 5); + video::SColor color = video::SColor(255, 255, 0, 0); + core::recti dest_rect( + result_table->m_x + result_table->m_w - m_font->getDimension(msg.c_str()).Width - 5, + m_top, 0, 0); - //Current progress - GUIEngine::LabelWidget* status_label = new GUIEngine::LabelWidget(); - status_label->m_properties[GUIEngine::PROP_ID] = "status_label"; - status_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "center"; - status_label->m_x = x; - status_label->m_y = y; - status_label->m_w = w; - status_label->m_h = font_height; - status_label->add(); - status_label->setText(_("Track %i/%i", currentTrack + 1, - race_manager->getGrandPrix().getNumberOfTracks()), true); - addGPProgressWidget(status_label); - y = (status_label->m_y + status_label->m_h + 5); + m_font->draw(msg, dest_rect, color, false, false, NULL, true); + } // displayGPProgress - //Scroll up button - GUIEngine::IconButtonWidget* up_button = new GUIEngine::IconButtonWidget( - GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, - false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); - up_button->m_properties[GUIEngine::PROP_ID] = "up_button"; - up_button->m_x = x; - up_button->m_y = y; - up_button->m_w = w; - up_button->m_h = font_height; - up_button->add(); - up_button->setImage(file_manager->getAsset(FileManager::GUI,"scroll_up.png")); - addGPProgressWidget(up_button); - y = (up_button->m_y + up_button->m_h + SSHOT_SEPARATION); - - //Track screenshots and labels - int n_sshot = 1; - for(int i=m_start_track; isetCustomAspectRatio(4.0f / 3.0f); - screenshot_widget->m_x = x; - screenshot_widget->m_y = y; - screenshot_widget->m_w = w; - screenshot_widget->m_h = m_sshot_height; - screenshot_widget->m_properties[GUIEngine::PROP_ID] = - ("sshot_" + StringUtils::toString(n_sshot)); - screenshot_widget->add(); - addGPProgressWidget(screenshot_widget); - - //Label - GUIEngine::LabelWidget* sshot_label = new GUIEngine::LabelWidget(); - sshot_label->m_properties[GUIEngine::PROP_ID] = - ("sshot_label_" + StringUtils::toString(n_sshot)); - sshot_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "left"; - sshot_label->m_x = (x + w + 5); - sshot_label->m_y = (y + (m_sshot_height / 2) - (font_height / 2)); - sshot_label->m_w = (w / 2); - sshot_label->m_h = font_height; - sshot_label->add(); - addGPProgressWidget(sshot_label); - - y += (m_sshot_height + SSHOT_SEPARATION); - n_sshot++; - } // for - displayScreenShots(); - - //Scroll down button - GUIEngine::IconButtonWidget* down_button = new GUIEngine::IconButtonWidget( - GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, - false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); - down_button->m_properties[GUIEngine::PROP_ID] = "down_button"; - down_button->m_x = x; - down_button->m_y = y; - down_button->m_w = w; - down_button->m_h = font_height; - down_button->add(); - down_button->setImage(file_manager->getAsset(FileManager::GUI,"scroll_down.png")); - addGPProgressWidget(down_button); - - } // if MAJOR_MODE_GRAND_PRIX) - -} // enableGPProgress - -// ---------------------------------------------------------------------------- -void RaceResultGUI::addGPProgressWidget(GUIEngine::Widget* widget) -{ - m_widgets.push_back(widget); - m_gp_progress_widgets.push_back(widget); -} - -// ---------------------------------------------------------------------------- -void RaceResultGUI::displayGPProgress() -{ - core::stringw msg = _("Grand Prix progress:"); - - GUIEngine::Widget* result_table = getWidget("result-table"); - assert(result_table != NULL); - - video::SColor color = video::SColor(255,255,0,0); - core::recti dest_rect( - result_table->m_x + result_table->m_w - m_font->getDimension(msg.c_str()).Width - 5, - m_top, 0, 0); - - m_font->draw(msg, dest_rect, color, false, false, NULL, true); -} // displayGPProgress - -// ---------------------------------------------------------------------------- -void RaceResultGUI::cleanupGPProgress() -{ - for (size_t i = 0; i < m_gp_progress_widgets.size(); i++) - m_widgets.remove(m_gp_progress_widgets.get(i)); - m_gp_progress_widgets.clearAndDeleteAll(); -} // cleanupGPProgress - -// ---------------------------------------------------------------------------- -void RaceResultGUI::displayHighScores() -{ - // This happens in demo world - if(!World::getWorld()) - return; - - Highscores* scores = World::getWorld()->getHighscores(); - // In some case for exemple FTL they will be no highscores - if (scores != NULL) + // ---------------------------------------------------------------------------- + void RaceResultGUI::cleanupGPProgress() { - video::SColor white_color = video::SColor(255,255,255,255); + for (size_t i = 0; i < m_gp_progress_widgets.size(); i++) + m_widgets.remove(m_gp_progress_widgets.get(i)); + m_gp_progress_widgets.clearAndDeleteAll(); + } // cleanupGPProgress - int x = (int)(UserConfigParams::m_width*0.65f); - int y = m_top; + // ---------------------------------------------------------------------------- + void RaceResultGUI::displayHighScores() + { + // This happens in demo world + if (!World::getWorld()) + return; - // First draw title - GUIEngine::getFont()->draw(_("Highscores"), - core::recti(x, y, 0, 0), - white_color, - false, false, NULL, true /* ignoreRTL */); - - std::string kart_name; - irr::core::stringw player_name; - - // prevent excessive long name - unsigned int max_characters = 15; - unsigned int max_width = (UserConfigParams::m_width / 2 - 200) / 10; - if (max_width < 15) - max_characters = max_width; - - float time; - for (int i = 0; i < scores->getNumberEntries(); i++) + Highscores* scores = World::getWorld()->getHighscores(); + // In some case for exemple FTL they will be no highscores + if (scores != NULL) { - scores->getEntry(i,kart_name,player_name, &time); - if (player_name.size() > max_characters) + video::SColor white_color = video::SColor(255, 255, 255, 255); + + int x = (int)(UserConfigParams::m_width*0.65f); + int y = m_top; + + // First draw title + GUIEngine::getFont()->draw(_("Highscores"), + core::recti(x, y, 0, 0), + white_color, + false, false, NULL, true /* ignoreRTL */); + + std::string kart_name; + irr::core::stringw player_name; + + // prevent excessive long name + unsigned int max_characters = 15; + unsigned int max_width = (UserConfigParams::m_width / 2 - 200) / 10; + if (max_width < 15) + max_characters = max_width; + + float time; + for (int i = 0; i < scores->getNumberEntries(); i++) { - int begin = (int(m_timer/0.4f)) % ( player_name.size() - max_characters ); - player_name = player_name.subString(begin,max_characters,false); - } - - video::SColor text_color = white_color; - if (m_highscore_rank-1 == i) - { - text_color = video::SColor(255,255,0, 0 ); - } - - int current_x = x; - int current_y = y + (int) ((i + 1) * m_distance_between_rows * 1.5f); - - const KartProperties* prop = kart_properties_manager->getKart(kart_name); - if (prop != NULL) - { - const std::string &icon_path = prop->getAbsoluteIconFile(); - video::ITexture* kart_icon_texture = irr_driver->getTexture( icon_path ); - - if (kart_icon_texture != NULL) + scores->getEntry(i, kart_name, player_name, &time); + if (player_name.size() > max_characters) { - core::recti source_rect(core::vector2di(0,0), - kart_icon_texture->getSize()); - - core::recti dest_rect(current_x, current_y, - current_x+m_width_icon, current_y+m_width_icon); - - draw2DImage( - kart_icon_texture, dest_rect, - source_rect, NULL, NULL, - true); - - current_x += m_width_icon + m_width_column_space; + int begin = (int(m_timer / 0.4f)) % (player_name.size() - max_characters); + player_name = player_name.subString(begin, max_characters, false); } + + video::SColor text_color = white_color; + if (m_highscore_rank - 1 == i) + { + text_color = video::SColor(255, 255, 0, 0); + } + + int current_x = x; + int current_y = y + (int)((i + 1) * m_distance_between_rows * 1.5f); + + const KartProperties* prop = kart_properties_manager->getKart(kart_name); + if (prop != NULL) + { + const std::string &icon_path = prop->getAbsoluteIconFile(); + video::ITexture* kart_icon_texture = irr_driver->getTexture(icon_path); + + if (kart_icon_texture != NULL) + { + core::recti source_rect(core::vector2di(0, 0), + kart_icon_texture->getSize()); + + core::recti dest_rect(current_x, current_y, + current_x + m_width_icon, current_y + m_width_icon); + + draw2DImage( + kart_icon_texture, dest_rect, + source_rect, NULL, NULL, + true); + + current_x += m_width_icon + m_width_column_space; + } + } + + // draw the player name + GUIEngine::getSmallFont()->draw(player_name.c_str(), + core::recti(current_x, current_y, current_x + 150, current_y + 10), + text_color, + false, false, NULL, true /* ignoreRTL */); + + current_x = (int)(UserConfigParams::m_width * 0.85f); + + // Finally draw the time + std::string time_string = StringUtils::timeToString(time); + GUIEngine::getSmallFont()->draw(time_string.c_str(), + core::recti(current_x, current_y, current_x + 100, current_y + 10), + text_color, + false, false, NULL, true /* ignoreRTL */); } - - // draw the player name - GUIEngine::getSmallFont()->draw(player_name.c_str(), - core::recti(current_x, current_y, current_x+150, current_y+10), - text_color, - false, false, NULL, true /* ignoreRTL */); - - current_x = (int) (UserConfigParams::m_width * 0.85f); - - // Finally draw the time - std::string time_string = StringUtils::timeToString(time); - GUIEngine::getSmallFont()->draw(time_string.c_str(), - core::recti(current_x, current_y, current_x+100, current_y+10), - text_color, - false, false, NULL, true /* ignoreRTL */); } } -} -// ---------------------------------------------------------------------------- -void RaceResultGUI::displayScreenShots() -{ - const std::vector tracks = - race_manager->getGrandPrix().getTrackNames(); - int currentTrack = race_manager->getTrackNumber(); - - int n_sshot = 1; - for(int i = m_start_track; i < m_end_track; i++) + // ---------------------------------------------------------------------------- + void RaceResultGUI::displayScreenShots() { - Track* track = track_manager->getTrack(tracks[i]); - GUIEngine::IconButtonWidget* sshot = getWidget( - ("sshot_" + StringUtils::toString(n_sshot)).c_str()); - GUIEngine::LabelWidget* label = getWidget( - ("sshot_label_" + StringUtils::toString(n_sshot)).c_str()); - assert(track != NULL && sshot != NULL && label != NULL); + const std::vector tracks = + race_manager->getGrandPrix().getTrackNames(); + int currentTrack = race_manager->getTrackNumber(); - sshot->setImage(track->getScreenshotFile()); - if (i <= currentTrack) - sshot->setBadge(GUIEngine::OK_BADGE); - else - sshot->resetAllBadges(); + int n_sshot = 1; + for (int i = m_start_track; i < m_end_track; i++) + { + Track* track = track_manager->getTrack(tracks[i]); + GUIEngine::IconButtonWidget* sshot = getWidget( + ("sshot_" + StringUtils::toString(n_sshot)).c_str()); + GUIEngine::LabelWidget* label = getWidget( + ("sshot_label_" + StringUtils::toString(n_sshot)).c_str()); + assert(track != NULL && sshot != NULL && label != NULL); - label->setText(StringUtils::toWString(i + 1), true); + sshot->setImage(track->getScreenshotFile()); + if (i <= currentTrack) + sshot->setBadge(GUIEngine::OK_BADGE); + else + sshot->resetAllBadges(); - n_sshot++; + label->setText(StringUtils::toWString(i + 1), true); + + n_sshot++; + } } -} -// ---------------------------------------------------------------------------- -int RaceResultGUI::getFontHeight () const -{ - assert(m_font != NULL); - return m_font->getDimension(L"A").Height; //Could be any capital letter -} + // ---------------------------------------------------------------------------- + int RaceResultGUI::getFontHeight() const + { + assert(m_font != NULL); + return m_font->getDimension(L"A").Height; //Could be any capital letter + } diff --git a/src/states_screens/race_result_gui.hpp b/src/states_screens/race_result_gui.hpp index cef78b92e..b261620d6 100644 --- a/src/states_screens/race_result_gui.hpp +++ b/src/states_screens/race_result_gui.hpp @@ -213,6 +213,7 @@ public: Input::InputType type, int playerId) OVERRIDE; void eventCallback(GUIEngine::Widget* widget, const std::string& name, const int playerID) OVERRIDE; + void backToLobby(); friend class GUIEngine::ScreenSingleton;