initial commit, lordsawar source, slightly modified
[lordsawar] / src / game-client.cpp
1 // Copyright (C) 2008 Ole Laursen
2 //
3 //  This program is free software; you can redistribute it and/or modify
4 //  it under the terms of the GNU General Public License as published by
5 //  the Free Software Foundation; either version 3 of the License, or
6 //  (at your option) any later version.
7 //
8 //  This program is distributed in the hope that it will be useful,
9 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //  GNU Library General Public License for more details.
12 //
13 //  You should have received a copy of the GNU General Public License
14 //  along with this program; if not, write to the Free Software
15 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
16 //  02110-1301, USA.
17
18 #include <iostream>
19 #include <fstream>
20
21 #include "game-client.h"
22
23 #include "network-connection.h"
24 #include "File.h"
25 #include "action.h"
26 #include "network-action.h"
27 #include "network-history.h"
28 #include "playerlist.h"
29 #include "network_player.h"
30 #include "xmlhelper.h"
31   
32 #include "real_player.h" 
33 #include "network_player.h" 
34
35
36 GameClient * GameClient::s_instance = 0;
37
38
39 GameClient* GameClient::getInstance()
40 {
41     if (s_instance == 0)
42         s_instance = new GameClient();
43
44     return s_instance;
45 }
46
47 void GameClient::deleteInstance()
48 {
49     if (s_instance)
50         delete s_instance;
51
52     s_instance = 0;
53 }
54
55 GameClient::GameClient()
56 {
57   d_connected = false;
58   player_id = -1;
59 }
60
61 GameClient::~GameClient()
62 {
63   if (network_connection.get() != NULL)
64     network_connection->send(MESSAGE_TYPE_PARTICIPANT_DISCONNECT, d_nickname);
65 }
66
67 void GameClient::start(std::string host, guint32 port, std::string nick)
68 {
69   d_host = host;
70   d_port = port;
71   player_id = -1;
72   setNickname(nick);
73   network_connection.reset(new NetworkConnection());
74   network_connection->connected.connect(
75     sigc::mem_fun(this, &GameClient::onConnected));
76   network_connection->connection_lost.connect(
77     sigc::mem_fun(this, &GameClient::onConnectionLost));
78   network_connection->got_message.connect(
79     sigc::mem_fun(this, &GameClient::onGotMessage));
80   network_connection->connectToHost(host, port);
81 }
82
83 void GameClient::onConnected() 
84 {
85   std::cerr << "connected" << std::endl;
86   d_connected = true;
87
88   network_connection->send(MESSAGE_TYPE_PING, "");
89
90   client_connected.emit();
91 }
92
93 void GameClient::onConnectionLost()
94 {
95   std::cerr << "connection lost" << std::endl;
96   if (d_connected)
97     client_disconnected.emit();
98   else
99     client_could_not_connect.emit();
100 }
101
102 void GameClient::sat_down(Player *player, std::string nickname)
103 {
104   if (!player)
105     return;
106   if (player->getType() == Player::NETWORKED)
107     dynamic_cast<NetworkPlayer*>(player)->setConnected(true);
108   player_sits.emit(player, nickname);
109 }
110
111 void GameClient::stood_up(Player *player, std::string nickname)
112 {
113   if (!player)
114     return;
115   if (player->getType() == Player::HUMAN)
116     {
117       //this covers the "boot", or forcibly-stand case.
118       NetworkPlayer *new_p = new NetworkPlayer(*player);
119       Playerlist::getInstance()->swap(player, new_p);
120       delete player;
121       new_p->setConnected(false);
122     }
123   else if (player->getType() == Player::NETWORKED)
124     dynamic_cast<NetworkPlayer*>(player)->setConnected(false);
125   player_stands.emit(player, nickname);
126 }
127
128 void GameClient::onGotMessage(MessageType type, std::string payload)
129 {
130   std::cerr << "got message of type " << type << std::endl;
131   switch (type) {
132   case MESSAGE_TYPE_PING:
133     network_connection->send(MESSAGE_TYPE_PONG, "PONGOGOGO");
134     break;
135
136   case MESSAGE_TYPE_PONG:
137     network_connection->send(MESSAGE_TYPE_PARTICIPANT_CONNECT, d_nickname);
138     break;
139
140   case MESSAGE_TYPE_SENDING_ACTIONS:
141     gotActions(payload);
142     break;
143
144   case MESSAGE_TYPE_SENDING_MAP:
145     gotScenario(payload);
146     break;
147
148   case MESSAGE_TYPE_PARTICIPANT_CONNECTED:
149     remote_participant_joins.emit(payload);
150     break;
151   case MESSAGE_TYPE_PARTICIPANT_DISCONNECTED:
152     remote_participant_departs.emit(payload);
153     break;
154
155   case MESSAGE_TYPE_REQUEST_SEAT_MANIFEST:
156   case MESSAGE_TYPE_P1_SIT:
157   case MESSAGE_TYPE_P2_SIT:
158   case MESSAGE_TYPE_P3_SIT:
159   case MESSAGE_TYPE_P4_SIT:
160   case MESSAGE_TYPE_P5_SIT:
161   case MESSAGE_TYPE_P6_SIT:
162   case MESSAGE_TYPE_P7_SIT:
163   case MESSAGE_TYPE_P8_SIT:
164   case MESSAGE_TYPE_P1_STAND:
165   case MESSAGE_TYPE_P2_STAND:
166   case MESSAGE_TYPE_P3_STAND:
167   case MESSAGE_TYPE_P4_STAND:
168   case MESSAGE_TYPE_P5_STAND:
169   case MESSAGE_TYPE_P6_STAND:
170   case MESSAGE_TYPE_P7_STAND:
171   case MESSAGE_TYPE_P8_STAND:
172   case MESSAGE_TYPE_PARTICIPANT_CONNECT:
173   case MESSAGE_TYPE_PARTICIPANT_DISCONNECT:
174   case MESSAGE_TYPE_CHAT:
175   case MESSAGE_TYPE_ROUND_OVER:
176     //FIXME: faulty server.
177     break;
178
179   case MESSAGE_TYPE_CHATTED:
180     gotChatMessage("", payload);
181     break;
182     //this is the client realizing that some other player joined the server
183   case MESSAGE_TYPE_P1_SAT_DOWN:
184     sat_down(Playerlist::getInstance()->getPlayer(0), payload);
185     break;
186   case MESSAGE_TYPE_P2_SAT_DOWN:
187     sat_down(Playerlist::getInstance()->getPlayer(1), payload);
188     break;
189   case MESSAGE_TYPE_P3_SAT_DOWN:
190     sat_down(Playerlist::getInstance()->getPlayer(2), payload);
191     break;
192   case MESSAGE_TYPE_P4_SAT_DOWN:
193     sat_down(Playerlist::getInstance()->getPlayer(3), payload);
194     break;
195   case MESSAGE_TYPE_P5_SAT_DOWN:
196     sat_down(Playerlist::getInstance()->getPlayer(4), payload);
197     break;
198   case MESSAGE_TYPE_P6_SAT_DOWN:
199     sat_down(Playerlist::getInstance()->getPlayer(5), payload);
200     break;
201   case MESSAGE_TYPE_P7_SAT_DOWN:
202     sat_down(Playerlist::getInstance()->getPlayer(6), payload);
203     break;
204   case MESSAGE_TYPE_P8_SAT_DOWN:
205     sat_down(Playerlist::getInstance()->getPlayer(7), payload);
206     break;
207   case MESSAGE_TYPE_P1_STOOD_UP:
208     stood_up(Playerlist::getInstance()->getPlayer(0), payload);
209     break;
210   case MESSAGE_TYPE_P2_STOOD_UP:
211     stood_up(Playerlist::getInstance()->getPlayer(1), payload);
212     break;
213   case MESSAGE_TYPE_P3_STOOD_UP:
214     stood_up(Playerlist::getInstance()->getPlayer(2), payload);
215     break;
216   case MESSAGE_TYPE_P4_STOOD_UP:
217     stood_up(Playerlist::getInstance()->getPlayer(3), payload);
218     break;
219   case MESSAGE_TYPE_P5_STOOD_UP:
220     stood_up(Playerlist::getInstance()->getPlayer(4), payload);
221     break;
222   case MESSAGE_TYPE_P6_STOOD_UP:
223     stood_up(Playerlist::getInstance()->getPlayer(5), payload);
224     break;
225   case MESSAGE_TYPE_P7_STOOD_UP:
226     stood_up(Playerlist::getInstance()->getPlayer(6), payload);
227     break;
228   case MESSAGE_TYPE_P8_STOOD_UP:
229     stood_up(Playerlist::getInstance()->getPlayer(7), payload);
230     break;
231
232   case MESSAGE_TYPE_SENDING_HISTORY:
233     gotHistories(payload);
234     break;
235   
236   case MESSAGE_TYPE_SERVER_DISCONNECT:
237     client_disconnected.emit();
238     break;
239
240   case MESSAGE_TYPE_TURN_ORDER:
241     gotTurnOrder (payload);
242     break;
243
244   case MESSAGE_TYPE_KILL_PLAYER:
245     gotKillPlayer(Playerlist::getInstance()->getPlayer(atoi(payload.c_str())));
246     break;
247
248   case MESSAGE_TYPE_ROUND_START:
249     round_begins.emit();
250     break;
251   }
252 }
253
254 void GameClient::gotKillPlayer(Player *player)
255 {
256   player->kill();
257 }  
258
259 void GameClient::onHistoryDone(NetworkHistory *history)
260 {
261   std::string desc = history->toString();
262   std::cerr << "Game Client got " << desc <<"\n";
263
264   if (history->getHistory()->getType() == History::PLAYER_VANQUISHED)
265     local_player_died(history->getOwner());
266
267   histories.push_back(history);
268   sendHistories();
269   clearNetworkHistorylist(histories);
270 }
271
272 void GameClient::onActionDone(NetworkAction *action)
273 {
274   std::string desc = action->toString();
275   std::cerr << "Game Client got " << desc <<"\n";
276
277   if (action->getAction()->getType() == Action::END_TURN)
278     local_player_moved(action->getOwner());
279   if (action->getAction()->getType() == Action::INIT_TURN)
280     local_player_starts_move(action->getOwner());
281
282   actions.push_back(action);
283   sendActions();
284   clearNetworkActionlist(actions);
285
286 }
287 void GameClient::sendActions()
288 {
289   std::ostringstream os;
290   XML_Helper helper(&os);
291
292   helper.begin("1");
293   helper.openTag("actions");
294
295   for (std::list<NetworkAction *>::iterator i = actions.begin(),
296        end = actions.end(); i != end; ++i)
297     {
298       (*i)->save(&helper);
299     }
300
301   helper.closeTag();
302
303   std::cerr << "sending actions" << std::endl;
304   network_connection->send(MESSAGE_TYPE_SENDING_ACTIONS, os.str());
305 }
306
307 void GameClient::sendHistories()
308 {
309   std::ostringstream os;
310   XML_Helper helper(&os);
311
312   helper.begin("1");
313   helper.openTag("histories");
314
315   for (std::list<NetworkHistory *>::iterator i = histories.begin(),
316        end = histories.end(); i != end; ++i)
317     (**i).save(&helper);
318
319   helper.closeTag();
320
321   network_connection->send(MESSAGE_TYPE_SENDING_HISTORY, os.str());
322 }
323
324 void GameClient::sit_down (Player *player)
325 {
326   if (!player)
327     return;
328   MessageType type;
329   switch (player->getId())
330     {
331     case 0: type = MESSAGE_TYPE_P1_SIT; break;
332     case 1: type = MESSAGE_TYPE_P2_SIT; break;
333     case 2: type = MESSAGE_TYPE_P3_SIT; break;
334     case 3: type = MESSAGE_TYPE_P4_SIT; break;
335     case 4: type = MESSAGE_TYPE_P5_SIT; break;
336     case 5: type = MESSAGE_TYPE_P6_SIT; break;
337     case 6: type = MESSAGE_TYPE_P7_SIT; break;
338     case 7: type = MESSAGE_TYPE_P8_SIT; break;
339     default:
340             return;
341     }
342   RealPlayer *new_p = new RealPlayer (*player);
343   Playerlist::getInstance()->swap(player, new_p);
344   stopListeningForLocalEvents(player);
345   listenForLocalEvents(new_p);
346   delete player;
347   network_connection->send(type, d_nickname);
348 }
349
350 void GameClient::stand_up (Player *player)
351 {
352   if (!player)
353     return;
354   MessageType type;
355   switch (player->getId())
356     {
357     case 0: type = MESSAGE_TYPE_P1_STAND; break;
358     case 1: type = MESSAGE_TYPE_P2_STAND; break;
359     case 2: type = MESSAGE_TYPE_P3_STAND; break;
360     case 3: type = MESSAGE_TYPE_P4_STAND; break;
361     case 4: type = MESSAGE_TYPE_P5_STAND; break;
362     case 5: type = MESSAGE_TYPE_P6_STAND; break;
363     case 6: type = MESSAGE_TYPE_P7_STAND; break;
364     case 7: type = MESSAGE_TYPE_P8_STAND; break;
365     default:
366             return;
367     }
368   //now turning a human player into a network player
369   NetworkPlayer *new_p = new NetworkPlayer(*player);
370   Playerlist::getInstance()->swap(player, new_p);
371   stopListeningForLocalEvents(new_p);
372   delete player;
373   new_p->setConnected(false);
374   network_connection->send(type, d_nickname);
375 }
376
377 void GameClient::chat(std::string message)
378 {
379   network_connection->send(MESSAGE_TYPE_CHAT, d_nickname + ":" + message);
380 }
381   
382 void GameClient::request_seat_manifest()
383 {
384   network_connection->send(MESSAGE_TYPE_REQUEST_SEAT_MANIFEST, "");
385 }
386     
387 void GameClient::gotTurnOrder (std::string payload)
388 {
389   std::list<guint32> player_ids;
390   std::stringstream players;
391   players.str(payload);
392
393   int ival;
394   while (players.eof() == false)
395     {
396       ival = -1;
397       players >> ival;
398       if (ival != -1)
399         player_ids.push_back(ival);
400     }
401   Playerlist::getInstance()->reorder(player_ids);
402   playerlist_reorder_received.emit();
403 }
404
405 void GameClient::sendRoundOver()
406 {
407   network_connection->send(MESSAGE_TYPE_ROUND_OVER, "");
408 }