1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
|
#ifndef MP_INTERFACE_H
#define MP_INTERFACE_H
#include <tqwidget.h>
#include <tqvaluelist.h>
#include <tqptrlist.h>
#include "mp_board.h"
#include "mp_option.h"
class TQHBoxLayout;
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 TQWidget
{
Q_OBJECT
TQ_OBJECT
public:
/** Constructor which takes a MPGameInfo struct as parameter.
*/
MPInterface(const MPGameInfo &gameInfo,
uint nbActions, const ActionData *data,
TQWidget *tqparent = 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<Data> boards;
uint nbLocalHumans;
TQHBoxLayout *hbl;
bool _server, disconnected;
KeyData *_keyData;
TQMemArray<KeyCollection *> _keyCol;
void createServerGame(const TQPtrList<RemoteHostData> &);
void createClientGame(const RemoteHostData &);
void createLocalGame(const ConnectionData &);
void specialLocalGame(uint nbHumans, uint nbComputers);
void clear();
void initKeys(uint nbHumans);
};
#endif // MP_INTERFACE_H
|