You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/libtdegames/kgame/kgameio.h

572 lines
18 KiB

/*
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 <tqstring.h>
#include <tqobject.h>
#include <kdemacros.h>
class KPlayer;
class KGame;
class KProcess;
/**
* \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 <martin@heni-online.de>
*/
class KDE_EXPORT KGameIO : public TQObject
{
Q_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 <martin@heni-online.de>
*/
class KDE_EXPORT KGameKeyIO : public KGameIO
{
Q_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,TQT_SIGNAL(signalKeyEvent(KGameIO *,TQDataStream &,TQKeyEvent *,bool *)),
* this,TQT_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 <martin@heni-online.de>
*/
class KDE_EXPORT KGameMouseIO : public KGameIO
{
Q_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,TQT_SIGNAL(signalMouseEvent(KGameIO *,TQDataStream &,TQMouseEvent *,bool *)),
* this,TQT_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 <martin@heni-online.de>
*/
class KDE_EXPORT KGameProcessIO : public KGameIO
{
Q_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,TQT_SIGNAL(signalPrepareTurn(TQDataStream &,bool,KGameIO *,bool *)),
* this,TQT_SLOT(slotPrepareTurn(TQDataStream &,bool,KGameIO *,bool *)));
* connect(input,TQT_SIGNAL(signalProcessQuery(TQDataStream &,KGameProcessIO *)),
* this,TQT_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 <b_mann@gmx.de>
*/
class KDE_EXPORT KGameComputerIO : public KGameIO
{
Q_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