/* This file is part of the TDE games library Copyright (C) 2001 Martin Heni (martin@heni-online.de) Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* $Id$ */ #ifndef __KGAMEIO_H__ #define __KGAMEIO_H__ #include #include #include class KPlayer; class KGame; class TDEProcess; /** * \short Base class for IO devices for games * * This is the master class for * creating IO game devices. You cannot use it directly. * Either take one of the classes derived from it or * you have to create your own IO class derived from it (more probably). * * The idea behind this class is to provide a common interface * for input devices into your game. By programming a KGameIO * device you need not distinguish the actual IO in the game * anymore. All work is done by the IO's. This allows very * easy reuse in other games as well. * A further advantage of using the IO's is that you can exchange * the control of a player at runtime. E.g. you switch a player * to be controlled by the computer or vice versa. * * To achieve this you have to make all of your player inputs through a * KGameIO. You will usually call KGameIO::sendInput to do so. * * @author Martin Heni */ class KDE_EXPORT KGameIO : public TQObject { TQ_OBJECT public: /** * Constructs a KGameIO object */ KGameIO(); KGameIO(KPlayer*); virtual ~KGameIO(); /** * Gives debug output of the game status */ void Debug(); /** * Identifies the KGameIO via the rtti function */ enum IOMode {GenericIO=1,KeyIO=2,MouseIO=4,ProcessIO=8,ComputerIO=16}; /** * Run time idendification. Predefined values are from IOMode * You MUST overwrite this in derived classes! * * @return rtti value */ virtual int rtti() const = 0; // Computer, network, local, ... /** * This function returns the player who owns this IO * * @return the player this IO device is plugged into */ KPlayer *player() const {return mPlayer;} /** * Equivalent to player()->game() * @return the @ref KGame object of this player **/ KGame* game() const; /** * Sets the player to which this IO belongs to. This * is done automatically when adding a device to a * player * * @param p the player */ void setPlayer(KPlayer *p) {mPlayer=p;} /** * Init this device by setting the player and e.g. sending an * init message to the device. This initialisation message is * very useful for computer players as you can transmit the * game status to them and only update this status in the setTurn * commands. * * Called by @ref KPlayer::addGameIO only! */ virtual void initIO(KPlayer *p); /** * Notifies the IO device that the player's setTurn had been called * Called by KPlayer * * This emits @ref signalPrepareTurn and sends the turn if the send * parameter is set to true. * * @param b turn is true/false */ virtual void notifyTurn(bool b); /** * Send an input message using @ref KPlayer::forwardInput **/ bool sendInput(TQDataStream& stream, bool transmit = true, TQ_UINT32 sender = 0); signals: /** * Signal generated when @ref KPlayer::myTurn changes. This can either be * when you get the turn status or when you lose it. * * The datastream has to be filled with a move. If you set (or leave) the * send parameter to FALSE then nothing happens: the datastream will be * ignored. If you set it to TRUE @ref sendInput is used to * send the move. * * Often you want to ignore this signal (leave send=FALSE) and send the * message later. This is usually the case for a human player as he probably * doesn't react immediately. But you can still use this e.g. to notify the * player about the turn change. * * Example: * \code * void GameWindow::slotPrepareTurn(TQDataStream &stream,bool b,KGameIO *input,bool * ) * { * KPlayer *player=input->player(); * if (!player->myTurn()) return ; * if (!b) return ; // only do something on setTurn(true) * stream << 1 << 2 << 3; // Some data for the process * } * \endcode * * @param io the KGameIO object itself * @param stream the stream into which the move will be written * @param turn the argument of setTurn * @param send set this to true to send the generated move using @ref * sendInput **/ void signalPrepareTurn(TQDataStream & stream, bool turn, KGameIO *io, bool * send); private: KPlayer *mPlayer; }; /** * The KGameKeyIO class. It is used to process keyboard input * from a widget and create moves for the player it belongs to. * @author Martin Heni */ class KDE_EXPORT KGameKeyIO : public KGameIO { TQ_OBJECT public: /** * Create a keyboard input devices. All keyboards * inputs of the given widgets are passed through a signal * handler signalKeyEvent and can be used to generate * a valid move for the player. * Note the widget you pass to the constructor must be * the main window of your application, e.g. view->parentWidget() * as QT does not forward your keyevents otherwise. This means * that this might be a different widget comapred to the one you * use for mouse inputs! * Example: * \code * KGameKeyIO *input; * input=new KGameKeyIO(myWidget); * connect(input,TQ_SIGNAL(signalKeyEvent(KGameIO *,TQDataStream &,TQKeyEvent *,bool *)), * this,TQ_SLOT(slotKeyInput(KGameIO *,TQDataStream &,TQKeyEvent *,bool *))); * \endcode * * @param parent The parents widget whose keyboard events * should be grabbed */ KGameKeyIO(TQWidget *parent); virtual ~KGameKeyIO(); /** * The idendification of the IO * * @return KeyIO */ virtual int rtti() const; signals: /** * Signal handler for keyboard events. This function is called * on every keyboard event. If appropriate it can generate a * move for the player the device belongs to. If this is done * and the event is eaten eatevent needs to be set to true. * What move you generate (i.e. what you write to the stream) * is totally up to you as it will not be evaluated but forwared * to the player's/game's input move function * Example: * \code * KPlayer *player=input->player(); // Get the player * TQ_INT32 key=e->key(); * stream << key; * eatevent=true; * \endcode * * @param io the IO device we belong to * @param stream the stream where we write our move into * @param m The TQKeyEvent we can evaluate * @param eatevent set this to true if we processed the event */ void signalKeyEvent(KGameIO *io,TQDataStream &stream,TQKeyEvent *m,bool *eatevent); protected: /** * Internal method to process the events */ bool eventFilter( TQObject *o, TQEvent *e ); }; /** * The KGameMouseIO class. It is used to process mouse input * from a widget and create moves for the player it belongs to. * @author Martin Heni */ class KDE_EXPORT KGameMouseIO : public KGameIO { TQ_OBJECT public: /** * Creates a mouse IO device. It captures all mouse * event of the given widget and forwards them to the * signal handler signalMouseEvent. * Example: * \code * KGameMouseIO *input; * input=new KGameMouseIO(mView); * connect(input,TQ_SIGNAL(signalMouseEvent(KGameIO *,TQDataStream &,TQMouseEvent *,bool *)), * this,TQ_SLOT(slotMouseInput(KGameIO *,TQDataStream &,TQMouseEvent *,bool *))); * \endcode * * @param parent The widget whose events should be captured * @param trackmouse enables mouse tracking (gives mouse move events) */ KGameMouseIO(TQWidget *parent,bool trackmouse=false); virtual ~KGameMouseIO(); /** * Manually activate or deactivate mouse tracking * * @param b true = tracking on */ void setMouseTracking(bool b); /** * The idendification of the IO * * @return MouseIO */ virtual int rtti() const; signals: /** * Signal handler for mouse events. This function is called * on every mouse event. If appropriate it can generate a * move for the player the device belongs to. If this is done * and the event is eaten eatevent needs to be set to true. * @see signalKeyEvent * Example: * \code * KPlayer *player=input->player(); // Get the player * TQ_INT32 button=e->button(); * stream << button; * eatevent=true; * \endcode * * @param io the IO device we belong to * @param stream the stream where we write our move into * @param m The TQMouseEvent we can evaluate * @param eatevent set this to true if we processed the event */ void signalMouseEvent(KGameIO *io,TQDataStream &stream,TQMouseEvent *m,bool *eatevent); protected: /** * Internal event filter */ bool eventFilter( TQObject *o, TQEvent *e ); }; /** * The KGameProcessIO class. It is used to create a computer player * via a separate process and communicate transparetly with it. * Its counterpart is the @ref KGameProcess class which needs * to be used by the computer player. See its documentation * for the definition of the computer player. * @author Martin Heni */ class KDE_EXPORT KGameProcessIO : public KGameIO { TQ_OBJECT public: /** * Creates a computer player via a separate process. The process * name is given as fully qualified filename. * Example: * \code * KGameProcessIO *input; * input=new KGameProcessIO(executable_file); * connect(input,TQ_SIGNAL(signalPrepareTurn(TQDataStream &,bool,KGameIO *,bool *)), * this,TQ_SLOT(slotPrepareTurn(TQDataStream &,bool,KGameIO *,bool *))); * connect(input,TQ_SIGNAL(signalProcessQuery(TQDataStream &,KGameProcessIO *)), * this,TQ_SLOT(slotProcessQuery(TQDataStream &,KGameProcessIO *))); * \endcode * * @param name the filename of the process to start */ KGameProcessIO(const TQString& name); /** * Deletes the process input devices */ virtual ~KGameProcessIO(); /** * The idendification of the IO * * @return ProcessIO */ int rtti() const; /** * Send a message to the process. This is analogous to the sendMessage * commands of KGame. It will result in a signal of the computer player * on which you can react in the process player. * * @param stream - the actual data * @param msgid - the id of the message * @param receiver - not used * @param sender - who send the message */ void sendMessage(TQDataStream &stream,int msgid, TQ_UINT32 receiver, TQ_UINT32 sender); /** * Send a system message to the process. This is analogous to the sendMessage * commands of KGame. It will result in a signal of the computer player * on which you can react in the process player. * * @param stream - the actual data * @param msgid - the id of the message * @param receiver - not used * @param sender - who send the message */ void sendSystemMessage(TQDataStream &stream, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender); /** * Init this device by setting the player and e.g. sending an * init message to the device. Calling this function will emit * the IOAdded signal on which you can react and initilise the * computer player. * This function is called automatically when adding the IO to * a player. */ void initIO(KPlayer *p); /** * Notifies the IO device that the player's setTurn had been called * Called by KPlayer. You can react on the @ref signalPrepareTurn to * prepare a message for the process, i.e. either update it on * the changes made to the game since the last turn or the initIO * has been called or transmit your gamestatus now. * * @param turn is true/false */ virtual void notifyTurn(bool turn); protected: /** * Internal ~ombined function for all message handling **/ void sendAllMessages(TQDataStream &stream,int msgid, TQ_UINT32 receiver, TQ_UINT32 sender, bool usermsg); protected slots: /** * Internal message handler to receive data from the process */ void receivedMessage(const TQByteArray& receiveBuffer); signals: /** * A computer query message is received. This is a 'dummy' * message sent by the process if it needs to communicate * with us. It is not forwarded over the network. * Reacting to this message allows you to 'answer' questions * of the process, e.g. sending addition data which the process * needs to calculate a move. * * Example: * \code * void GameWindow::slotProcessQuery(TQDataStream &stream,KGameProcessIO *reply) * { * int no; * stream >> no; // We assume the process sends us an integer question numner * if (no==1) // but YOU have to do this in the process player * { * TQByteArray buffer; * TQDataStream out(buffer,IO_WriteOnly); * reply->sendSystemMessage(out,4242,0,0); // lets reply something... * } * } * \endcode */ void signalProcessQuery(TQDataStream &stream,KGameProcessIO *me); /** * Signal generated when the computer player is added. * You can use this to communicated with the process and * e.g. send initialisation information to the process. * * @param game the KGameIO object itself * @param stream the stream into which the move will be written * @param p the player itself * @param send set this to false if no move should be generated */ void signalIOAdded(KGameIO *game,TQDataStream &stream,KPlayer *p,bool *send); protected: private: class KGameProcessIOPrivate; KGameProcessIOPrivate* d; }; /** * \brief KGameIO variant for real-time games * * The KGameComputerIO class. It is used to create a LOCAL computer player * and communicate transparently with it. * Question: Is this needed or is it overwritten anyway for a real game? * * You most probably don't want to use this if you want to design a turn based * game/player. You'll rather use @ref KGameIO directly, i.e. subclass it * yourself. You just need to use @ref KGameIO::signalPrepareTurn and/or @ref * KGameIO::notifyTurn there. * * This is rather meant to be of use in real time games. * * @author */ class KDE_EXPORT KGameComputerIO : public KGameIO { TQ_OBJECT public: /** * Creates a LOCAL computer player * */ KGameComputerIO(); KGameComputerIO(KPlayer* player); ~KGameComputerIO(); int rtti() const; /** * The number of advance calls until the player (or rather: the IO) * does something (default: 1). **/ void setReactionPeriod(int advanceCalls); int reactionPeriod() const; /** * Start a TQTimer which calls advance every @p ms milli seconds. **/ void setAdvancePeriod(int ms); void stopAdvancePeriod(); /** * Ignore calls number of advance calls. if calls is -1 then all * following advance calls are ignored until unpause is called. * * This simply prevents the internal advance counter to be increased. * * You may want to use this to emulate a "thinking" computer player. Note * that this means if you increase the advance period (see * setAdvancePeriod), i.e. if you change the speed of your game, your * computer player thinks "faster". * @param calls Number of advance calls to be ignored **/ void pause(int calls = -1); /** * Equivalent to pause(0). Immediately continue to increase the internal * advance counter. **/ void unpause(); public slots: /** * Works kind of similar to TQCanvas::advance. Increase the internal * advance counter. If @p reactionPeriod is reached the counter is set back to * 0 and @ref signalReaction is emitted. This is when the player is meant * to do something (move its units or so). * * This is very useful if you use TQCanvas as you can use this in your * TQCanvas::advance call. The advantage is that if you change the speed * of the game (i.e. change TQCanvas::setAdvancePeriod) the computer * player gets slower as well. * * If you don't use TQCanvas you can use setAdvancePeriod to get * the same result. Alternatively you can just use a TQTimer. * **/ virtual void advance(); signals: /** * This signal is emitted when your computer player is meant to do * something, or better is meant to be allowed to do something. **/ void signalReaction(); protected: /** * Default implementation simply emits signalReaction **/ virtual void reaction(); private: void init(); private: class KGameComputerIOPrivate; KGameComputerIOPrivate* d; }; #endif