#ifndef MP_INTERFACE_H #define MP_INTERFACE_H #include #include #include #include "mp_board.h" #include "mp_option.h" class QHBoxLayout; class Local; class ConnectionData; class RemoteHostData; class KeyData; class KeyCollection; class KKeyDialog; class KAction; struct ActionData { const char *label, *name; const char *slot, *slotRelease; // if slotRelease!=0 // : use keyPress/ReleaseEvent mecanism }; /** * This structure contains information about the game * configuration. */ typedef struct { /** The game version id used for identification (e.g. "4"). * You should change this id when the game is made incompatible * with previous version. (changes in data for example). */ const char *gameId; /** Maximum number of local players. */ uint maxNbLocalPlayers; /** Interval (in msec.) between data exchange. */ uint interval; /** If there are built-in artificial intelligences that can play. */ bool AIAllowed; /** Slot for player/AI additional configuration. These must be SLOTs which * take an "int" as parameter. It must open a setting * dialog for the corresponding local player/computer and save the * new settings in the config file. It should probably create a group * with the given number in its name. * If such a pointer is set to 0 : it means there is no perticular * setting. */ const char *humanSettingSlot, *AISettingSlot; } MPGameInfo; /** * The MPInterface class is useful for multiplayers game * management. Each game is represented by a class you have inherited * from the @ref MPBoard class. * * Multiplayers games can take place with several (humans or eventually * AIs) players on the same computer (they use the same keyboard and have * each a @ref MPBoard widget on the screen) or/and network players. * * This class is intended to do all the hard work of sending/receiving data * between the players and to send the keyboard events to the right * @ref MPBoard. So multiplayers game should be completely transparent * from your point of view. * * Note : The data exchange is done in background with a timer calling at given * intervals the read/write methods. Obviously this kind of things can be done * easily with threads but I have no experience with thread programming * and not all people have thread libraries and a thread-safe system. */ class MPInterface : public QWidget { Q_OBJECT public: /** Constructor which takes a MPGameInfo struct as parameter. */ MPInterface(const MPGameInfo &gameInfo, uint nbActions, const ActionData *data, TQWidget *parent = 0, const char *name = 0); virtual ~MPInterface(); public slots: /** Create a single player game for a human being. * Call @ref stop if a game is already created. */ void singleHuman() { specialLocalGame(1, 0); } /** Create a local game opposing two human beings. * Call @ref stop if a game is already created. */ void humanVsHuman() { specialLocalGame(2, 0); } /** Create a local game opposing a human with an AI. * Call @ref stop if a game is already created. */ void humanVsComputer() { specialLocalGame(1, 1); } /** Open a dialog to create a multiplayer game. * Call @ref stop if a game is already created. */ void dialog(); public: virtual void addKeys(KKeyDialog &); void saveKeys(); /** Called when a new game is created. At this point * the number of players is known. */ virtual void init() {} /** Called just before a new game is created (called by * singleHuman, humanVsHuman, humanVsComputer and dialog). */ virtual void stop() {} /** Called when the start button of the netmeeting is pressed. */ virtual void start() {} /** * Set keys configuration for the given number of human players. * The size of the array is the number of defined actions. */ void setDefaultKeycodes(uint nbHumans, uint human, const int *keycodes); /** * @return the total number of players. * (If called from client : return the number of local boards). */ uint nbPlayers() const; /** * @return true if the interface is the server. */ bool server() const { return _server; } /** @return the player name. Do not call from client ! */ TQString playerName(uint i) const; /** * Create a new @ref MPBoard. * * @param i is the game index that goes from 0 to the number of * local players : it can be used to retrieve configuration settings. */ virtual MPBoard *newBoard(uint i) = 0; /** * This method must read data from each client with method * @ref readingStream, do the needed treatement * (for instance which players has lost, which data to be resent, ...) and * then write the useful data to each client with method * @ref writingStream. * * NB: this method is also called for single player games but * you probably only want to check for game over condition (it depends * on game implementation that you really return data to the board). */ virtual void treatData() = 0; /** @return the reading stream for board #i. * Do not call from client ! */ TQDataStream &readingStream(uint i) const; /** @return the writing stream for board #i. */ TQDataStream &writingStream(uint i) const; /** * Read data sent from server to clients "MultiplayersInterface" * (this data is not addressed to boards). * These are meta data that are not directly used in game. * It can be used to display "game over" infos for all * local games. * NB: the use of this method is optional. */ virtual void dataFromServer(TQDataStream &) {} /** Used by the server to write meta data to clients. * NB: the use of this method is optional. * Do not call from client ! */ TQDataStream &dataToClientsStream() const; /** Write immediately data to clients and local boards. * It is unlike the normal exchange which is driven * by the timer of the server. Be aware of possible * interactions. */ void immediateWrite(); /** * This method should be overload if an option widget is used in the * the "netmeeting" dialog). By default a * null pointer is returned and so no option widget is shown. * The option widget must be inherited from the @ref MPOptionWidget class. */ virtual MPOptionWidget *newOptionWidget() const { return 0; } /** Called when a network error occurred or when a host gets disconnected. * The default implementation displays a message and calls singleHumans() * ie it stops the current game. By overloading this method, it is * possible to continue the game at this point with the remaining players. */ virtual void hostDisconnected(uint i, const TQString &msg); protected: void paintEvent(TQPaintEvent *); void keyPressEvent(TQKeyEvent *); void keyReleaseEvent(TQKeyEvent *); private slots: void enableKeys(bool enable); void singleHumanSlot(); public: class Data { public: Data() {} MPBoard *ptr; int humanIndex; TQString name; }; private: Local *internal; const MPGameInfo gameInfo; TQValueList boards; uint nbLocalHumans; TQHBoxLayout *hbl; bool _server, disconnected; KeyData *_keyData; TQMemArray _keyCol; void createServerGame(const TQPtrList &); void createClientGame(const RemoteHostData &); void createLocalGame(const ConnectionData &); void specialLocalGame(uint nbHumans, uint nbComputers); void clear(); void initKeys(uint nbHumans); }; #endif // MP_INTERFACE_H