1 /* Pioneers - Implementation of the excellent Settlers of Catan board game.
2  *   Go buy a copy.
3  *
4  * Copyright (C) 1999 Dave Cole
5  * Copyright (C) 2003-2007 Bas Wijnen <shevek@fmf.nl>
6  * Copyright (C) 2005-2010 Roland Clobus <rclobus@rclobus.nl>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 #include "config.h"
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include "server.h"
28 #include "network.h"
29 #include "random.h"
30 
31 /* Local function prototypes */
32 static gboolean mode_check_version(Player * player, gint event);
33 static gboolean mode_check_status(Player * player, gint event);
34 static gboolean mode_bad_version(Player * player, gint event);
35 static gboolean mode_global(Player * player, gint event);
36 static gboolean mode_unhandled(Player * player, gint event);
37 static void player_setup(Player * player, gint playernum,
38 			 const gchar * name, gboolean force_spectator);
39 static Player *player_by_name(Game * game, char *name);
40 
41 #define tournament_minute 1000 * 60
42 #define time_to_wait_for_players 30 * 60 * 1000
43 
44 /** Is the game a tournament game?
45  *  @param game The game
46  *  @return TRUE if this game is a tournament game
47 */
is_tournament_game(const Game * game)48 static gboolean is_tournament_game(const Game * game)
49 {
50 	return game->params->tournament_time > 0;
51 }
52 
53 /** Find a free number for a connecting player.
54  * The number has not been used before.
55  *  @param game The game
56  *  @param force_spectator The connecting player must be a spectator
57  */
next_free_player_num(Game * game,gboolean force_spectator)58 static gint next_free_player_num(Game * game, gboolean force_spectator)
59 {
60 	gint idx;
61 
62 	if (!force_spectator) {
63 		GList *list;
64 		gboolean player_taken[MAX_PLAYERS];
65 		guint available = game->params->num_players;
66 
67 		memset(player_taken, 0, sizeof(player_taken));
68 		playerlist_inc_use_count(game);
69 		for (list = game->player_list;
70 		     list != NULL; list = g_list_next(list)) {
71 			Player *player = list->data;
72 			if (player->num >= 0
73 			    && !player_is_spectator(game, player->num)) {
74 				player_taken[player->num] = TRUE;
75 				--available;
76 			}
77 		}
78 		playerlist_dec_use_count(game);
79 		if (available > 0) {
80 			guint skip;
81 			if (game->random_order) {
82 				skip = random_guint(available);
83 			} else {
84 				skip = 0;
85 			}
86 			idx = 0;
87 			++skip;
88 			while (player_taken[idx] || --skip != 0)
89 				++idx;
90 			return idx;
91 		}
92 	}
93 
94 	/* No players available/wanted, look for a spectator number */
95 	idx = (gint) game->params->num_players;
96 	while (player_by_num(game, idx) != NULL)
97 		++idx;
98 	return idx;
99 }
100 
mode_global(Player * player,gint event)101 static gboolean mode_global(Player * player, gint event)
102 {
103 	StateMachine *sm = player->sm;
104 	Game *game = player->game;
105 	gchar *text;
106 
107 	switch (event) {
108 	case SM_FREE:
109 		if (player->name != NULL)
110 			g_free(player->name);
111 		if (player->style != NULL)
112 			g_free(player->style);
113 		if (player->location != NULL)
114 			g_free(player->location);
115 		if (player->devel != NULL)
116 			deck_free(player->devel, NULL);
117 		if (player->num >= 0
118 		    && !player_is_spectator(game, player->num)
119 		    && !player->disconnected) {
120 			game->num_players--;
121 			meta_report_num_players(game->num_players);
122 		}
123 		g_list_free(player->build_list);
124 		g_list_free(player->special_points);
125 		g_free(player);
126 		return TRUE;
127 	case SM_NET_CLOSE:
128 		player_remove(player);
129 		if (player->num >= 0) {
130 			player_broadcast(player, PB_OTHERS, FIRST_VERSION,
131 					 LATEST_VERSION, "has quit\n");
132 			player_archive(player);
133 		} else {
134 			player_free(player);
135 		}
136 		driver->player_change(game);
137 		return TRUE;
138 	case SM_RECV:
139 		if (sm_recv(sm, "chat %S", &text)) {
140 			if (strlen(text) > MAX_CHAT)
141 				player_send(player, FIRST_VERSION,
142 					    LATEST_VERSION, "ERR %s\n",
143 					    _("chat too long"));
144 			else
145 				player_broadcast(player, PB_ALL,
146 						 FIRST_VERSION,
147 						 LATEST_VERSION,
148 						 "chat %s\n", text);
149 			g_free(text);
150 			return TRUE;
151 		}
152 		if (sm_recv(sm, "name %S", &text)) {
153 			if (text[0] == '\0')
154 				player_send(player, FIRST_VERSION,
155 					    LATEST_VERSION,
156 					    "ERR invalid-name\n");
157 			else if (strlen(text) > MAX_NAME_LENGTH)
158 				player_send(player, FIRST_VERSION,
159 					    LATEST_VERSION, "ERR %s\n",
160 					    _("name too long"));
161 			else
162 				player_set_name(player, text);
163 			g_free(text);
164 			return TRUE;
165 		}
166 		if (sm_recv(sm, "style %S", &text)) {
167 			if (player->style)
168 				g_free(player->style);
169 			player->style = text;
170 			player_broadcast(player, PB_ALL, V0_11,
171 					 LATEST_VERSION, "style %s\n",
172 					 text);
173 			return TRUE;
174 		}
175 		break;
176 	default:
177 		break;
178 	}
179 	return FALSE;
180 }
181 
mode_unhandled(Player * player,gint event)182 static gboolean mode_unhandled(Player * player, gint event)
183 {
184 	StateMachine *sm = player->sm;
185 	gchar *text;
186 
187 	switch (event) {
188 	case SM_RECV:
189 		if (sm_recv(sm, "extension %S", &text)) {
190 			player_send(player, FIRST_VERSION, LATEST_VERSION,
191 				    "NOTE %s\n",
192 				    N_("ignoring unknown extension"));
193 			log_message(MSG_INFO,
194 				    "ignoring unknown extension from %s: %s\n",
195 				    player->name, text);
196 			g_free(text);
197 			return TRUE;
198 		}
199 		break;
200 	default:
201 		break;
202 	}
203 	return FALSE;
204 }
205 
206 /* Called to start the game (if it hasn't been yet). Add computer
207  * players to fill any empty spots
208  *
209  */
tournament_start_cb(gpointer data)210 static gboolean tournament_start_cb(gpointer data)
211 {
212 	guint i;
213 	Game *game = (Game *) data;
214 	GList *player;
215 	gboolean human_player_present;
216 
217 	g_source_remove(game->tournament_timer);
218 	game->tournament_timer = 0;
219 
220 	/* if game already started */
221 	if (game->num_players == game->params->num_players)
222 		return FALSE;
223 
224 	if (game->num_players == 0) {
225 		player_broadcast(player_none(game), PB_SILENT,
226 				 FIRST_VERSION, LATEST_VERSION,
227 				 "NOTE %s\n",
228 				 N_
229 				 ("The last player left, the "
230 				  "tournament timer is reset."));
231 		game->tournament_countdown = game->params->tournament_time;
232 		return FALSE;
233 	}
234 
235 	/* remove all disconnected players */
236 	playerlist_inc_use_count(game);
237 	for (player = game->player_list; player != NULL;
238 	     player = g_list_next(player)) {
239 		Player *p = player->data;
240 		if (p->disconnected && !sm_get_use_cache(p->sm)) {
241 			player_free(p);
242 		}
243 	}
244 	playerlist_dec_use_count(game);
245 
246 	/* if no human players are present, quit */
247 	playerlist_inc_use_count(game);
248 	human_player_present = FALSE;
249 	for (player = game->player_list;
250 	     player != NULL && !human_player_present;
251 	     player = g_list_next(player)) {
252 		Player *p = player->data;
253 		if (!player_is_spectator(game, p->num)
254 		    && determine_player_type(p->style) == PLAYER_HUMAN) {
255 			human_player_present = TRUE;
256 		}
257 	}
258 	playerlist_dec_use_count(game);
259 	if (!human_player_present) {
260 		player_broadcast(player_none(game), PB_SILENT,
261 				 FIRST_VERSION, LATEST_VERSION,
262 				 "NOTE %s\n",
263 				 N_("No human players present. Bye."));
264 		request_server_stop(game);
265 		return FALSE;
266 	}
267 
268 	player_broadcast(player_none(game), PB_SILENT, FIRST_VERSION,
269 			 LATEST_VERSION, "NOTE %s\n",
270 			 N_("Game starts, adding computer players."));
271 
272 	/* add computer players to start game */
273 	for (i = game->num_players; i < game->params->num_players; i++) {
274 		add_computer_player(game, TRUE);
275 	}
276 
277 	return FALSE;
278 }
279 
280 /*
281  * Keep players notified about when the tournament game is going to start
282  *
283  */
talk_about_tournament_cb(gpointer data)284 static gboolean talk_about_tournament_cb(gpointer data)
285 {
286 	Game *game = (Game *) data;
287 	const gchar *message;
288 
289 	/* if game already started */
290 	if (game->num_players == game->params->num_players)
291 		return FALSE;
292 
293 	if (game->num_players == 0) {
294 		if (game->tournament_timer != 0) {
295 			player_broadcast(player_none(game), PB_SILENT,
296 					 FIRST_VERSION, LATEST_VERSION,
297 					 "NOTE %s\n",
298 					 N_
299 					 ("The last player left, the "
300 					  "tournament timer is reset."));
301 			game->tournament_countdown =
302 			    game->params->tournament_time;
303 			g_source_remove(game->tournament_timer);
304 			game->tournament_timer = 0;
305 		}
306 		return FALSE;
307 	}
308 
309 	/* ngettext can not be used here,
310 	 * because the string must be sent untranslated */
311 	message = game->tournament_countdown != 1 ?
312 	    N_("The game starts in %s minutes.") :
313 	    N_("The game starts in %s minute.");
314 
315 	player_broadcast(player_none(game), PB_SILENT, FIRST_VERSION,
316 			 LATEST_VERSION, "NOTE1 %d|%s\n",
317 			 game->tournament_countdown, message);
318 	game->tournament_countdown--;
319 
320 	if (game->tournament_countdown > 0)
321 		g_timeout_add(tournament_minute,
322 			      &talk_about_tournament_cb, game);
323 
324 	return FALSE;
325 }
326 
327 /** Generate a name for a computer player.
328  * The name will be unique for the game.
329 */
generate_name_for_computer_player(Game * game)330 static gchar *generate_name_for_computer_player(Game * game)
331 {
332 	gchar *filename;
333 	FILE *stream;
334 	gchar *line;
335 	gchar *name = NULL;
336 	int num = 1;
337 
338 	filename =
339 	    g_build_filename(get_pioneers_dir(), "computer_names", NULL);
340 	stream = fopen(filename, "r");
341 	if (!stream) {
342 		g_warning("Unable to open %s", filename);
343 		/* Default name for the AI when the computer_names file
344 		 * is not found or empty.
345 		 */
346 	} else {
347 		while (read_line_from_file(&line, stream)) {
348 			if (player_by_name(game, line) == NULL) {
349 				if (g_random_int_range(0, num) == 0) {
350 					if (name)
351 						g_free(name);
352 					name = g_strdup(line);
353 				}
354 				num++;
355 			}
356 		}
357 		fclose(stream);
358 		if (num == 1) {
359 			g_warning("Empty file or all names taken: %s",
360 				  filename);
361 		}
362 	}
363 	g_free(filename);
364 
365 	if (name == NULL) {
366 		gint counter = 2;
367 
368 		/* Default name for the AI when the computer_names file
369 		 * is not found or empty.
370 		 */
371 		name = g_strdup(_("Computer Player"));
372 
373 		while (player_by_name(game, name) != NULL) {
374 			g_free(name);
375 			name =
376 			    g_strdup_printf("%s (%d)",
377 					    _("Computer Player"),
378 					    counter++);
379 		}
380 	}
381 
382 	return name;
383 }
384 
385 /** Add a new computer player (disconnected)
386  */
player_new_computer_player(Game * game)387 gchar *player_new_computer_player(Game * game)
388 {
389 	Player *player;
390 	gchar *name;
391 
392 	/* Reserve the name, so the names of the computer players will
393 	   be unique */
394 	name = generate_name_for_computer_player(game);
395 	player = player_new(game, name);
396 	player->disconnected = TRUE;
397 	sm_goto(player->sm, (StateFunc) mode_idle);
398 	return name;
399 }
400 
401 /** Allocate a new Player struct.
402  *  The StateMachine is not initialized.
403  *   */
player_new(Game * game,const gchar * name)404 Player *player_new(Game * game, const gchar * name)
405 {
406 	Player *player;
407 	StateMachine *sm;
408 
409 	player = g_malloc0(sizeof(*player));
410 	sm = player->sm = sm_new(player);
411 
412 	sm_global_set(sm, (StateFunc) mode_global);
413 	sm_unhandled_set(sm, (StateFunc) mode_unhandled);
414 
415 	player->game = game;
416 	player->location = g_strdup("not connected");
417 	player->devel = deck_new();
418 	game->player_list = g_list_append(game->player_list, player);
419 	player->num = -1;
420 	player->chapel_played = 0;
421 	player->univ_played = 0;
422 	player->gov_played = 0;
423 	player->libr_played = 0;
424 	player->market_played = 0;
425 	player->islands_discovered = 0;
426 	player->disconnected = FALSE;
427 	player->name = g_strdup(name);
428 	player->style = NULL;
429 	player->special_points = NULL;
430 	player->special_points_next_id = 0;
431 
432 	driver->player_change(game);
433 
434 	return player;
435 }
436 
player_new_connection(Game * game,Session * ses)437 Player *player_new_connection(Game * game, Session * ses)
438 {
439 	gchar name[100];
440 	size_t i;
441 	Player *player;
442 	StateMachine *sm;
443 	GError *error;
444 	gchar *location;
445 	gchar *port;
446 
447 	error = NULL;
448 	if (!net_get_peer_name(ses, &location, &port, &error)) {
449 		/* %s = error message */
450 		log_message(MSG_ERROR,
451 			    _("Unable to determine the "
452 			      "hostname of the player: %s"),
453 			    error->message);
454 		g_error_free(error);
455 	}
456 
457 	/* give player a name, some functions need it */
458 	strcpy(name, "connecting");
459 	for (i = strlen(name); i < G_N_ELEMENTS(name) - 1; ++i) {
460 		if (player_by_name(game, name) == NULL)
461 			break;
462 		name[i] = '_';
463 		name[i + 1] = 0;
464 	}
465 	if (i == G_N_ELEMENTS(name) - 1) {
466 		/* there are too many pending connections */
467 		net_write(ses, "ERR Too many connections\n");
468 		g_free(location);
469 		g_free(port);
470 		return NULL;
471 	}
472 
473 	if (game->is_game_over) {
474 		/* The game is over, don't accept new players */
475 		/* Message to send to the client when the game is already over
476 		 * when a connection is made. */
477 		net_printf(ses, "NOTE %s\n", N_("Sorry, game is over."));
478 		log_message(MSG_INFO,
479 			    _("Player from %s is refused: game is over\n"),
480 			    location);
481 		g_free(location);
482 		g_free(port);
483 		return NULL;
484 	}
485 
486 	player = player_new(game, name);
487 	sm = player->sm;
488 	sm_set_session(sm, ses);
489 	net_set_check_connection_alive(ses, 30);
490 	g_free(player->location);
491 	player->location = g_strdup(location);
492 
493 	/* Cache messages of the game in progress until all initial
494 	 * messages have been sent
495 	 */
496 	sm_set_use_cache(sm, TRUE);
497 
498 	sm_goto(sm, (StateFunc) mode_check_version);
499 
500 	driver->player_change(game);
501 	return player;
502 }
503 
504 /* set the player name.  Most of the time, player_set_name is called instead,
505  * which calls this function with public set to TRUE.  Only player_setup calls
506  * this with public == FALSE, because it doesn't want the broadcast. */
player_set_name_real(Player * player,gchar * name,gboolean public)507 static void player_set_name_real(Player * player, gchar * name,
508 				 gboolean public)
509 {
510 	Game *game = player->game;
511 	Player *player_temp;
512 
513 	g_assert(name[0] != 0);
514 
515 	if (((player_temp = player_by_name(game, name)) != NULL) &&
516 	    (player_temp != player)) {
517 		/* make it a note, not an error, so nothing bad happens
518 		 * (on error the AI would disconnect) */
519 		player_send(player, FIRST_VERSION, LATEST_VERSION,
520 			    "NOTE %s\n",
521 			    N_(""
522 			       "Name not changed: new name is already in use"));
523 		return;
524 	}
525 
526 	if (player->name != name) {
527 		g_free(player->name);
528 		player->name = g_strdup(name);
529 	}
530 
531 	if (public)
532 		player_broadcast(player, PB_ALL, FIRST_VERSION,
533 				 LATEST_VERSION, "is %s\n", player->name);
534 
535 	driver->player_renamed(player);
536 	driver->player_change(game);
537 }
538 
player_setup(Player * player,gint playernum,const gchar * name,gboolean force_spectator)539 static void player_setup(Player * player, gint playernum,
540 			 const gchar * name, gboolean force_spectator)
541 {
542 	gchar nm[MAX_NAME_LENGTH + 1];
543 	Game *game = player->game;
544 	StateMachine *sm = player->sm;
545 	Player *other;
546 
547 	player->num = playernum;
548 	if (player->num < 0) {
549 		player->num = next_free_player_num(game, force_spectator);
550 	}
551 
552 	if (!player_is_spectator(game, player->num)) {
553 		game->num_players++;
554 		meta_report_num_players(game->num_players);
555 	}
556 
557 	player->num_roads = 0;
558 	player->num_bridges = 0;
559 	player->num_ships = 0;
560 	player->num_settlements = 0;
561 	player->num_cities = 0;
562 
563 	/* give the player her new name */
564 	if (name == NULL) {
565 		if (player_is_spectator(game, player->num)) {
566 			gint num = 1;
567 			do {
568 				sprintf(nm, _("Spectator %d"), num++);
569 			} while (player_by_name(game, nm) != NULL);
570 		} else {
571 			sprintf(nm, _("Player %d"), player->num);
572 		}
573 	} else {
574 		strncpy(nm, name, G_N_ELEMENTS(nm));
575 		nm[G_N_ELEMENTS(nm) - 1] = '\0';
576 	}
577 
578 	/* if the new name exists, try padding it with underscores */
579 	other = player_by_name(game, nm);
580 	if (other != player && other != NULL) {
581 		size_t i;
582 		/* add underscores until the name is unique */
583 		for (i = strlen(nm); i < G_N_ELEMENTS(nm) - 1; ++i) {
584 			if (player_by_name(game, nm) == NULL)
585 				break;
586 			nm[i] = '_';
587 			nm[i + 1] = 0;
588 		}
589 		/* Adding underscores was not enough to make the name unique.
590 		 * While staying within the maximum name length,
591 		 * create numbers at the end of the name.
592 		 * Repeat until an unique name has been found.
593 		 */
594 		while (player_by_name(game, nm)) {
595 			gint digit = 10;
596 			i = G_N_ELEMENTS(nm) - 1;
597 			while (digit == 10 && i > 0) {
598 				/* Digit will be: 0..10 */
599 				--i;
600 				digit = g_ascii_digit_value(nm[i]) + 1;
601 				nm[i] = (gchar) ('0' + digit % 10);
602 			}
603 		}
604 	}
605 	/* copy the (possibly new) name to dynamic memory */
606 	/* don't broadcast the name.  This is done by mode_pre_game, after
607 	 * telling the user how many players are in the game.
608 	 * That should keep things easier for the client. */
609 	player_set_name_real(player, nm, FALSE);
610 
611 	/* add the info in the output device */
612 	driver->player_added(player);
613 	driver->player_change(game);
614 	if (playernum < 0)
615 		sm_goto(sm, (StateFunc) mode_pre_game);
616 }
617 
player_free(Player * player)618 void player_free(Player * player)
619 {
620 	Game *game = player->game;
621 
622 	if (game->player_list_use_count > 0) {
623 		game->dead_players =
624 		    g_list_append(game->dead_players, player);
625 		player->disconnected = TRUE;
626 		return;
627 	}
628 
629 	game->player_list = g_list_remove(game->player_list, player);
630 	driver->player_change(game);
631 
632 	sm_free(player->sm);
633 }
634 
timed_out(gpointer data)635 static gboolean timed_out(gpointer data)
636 {
637 	Game *game = data;
638 	log_message(MSG_INFO,
639 		    _(""
640 		      "Was hanging around for too long without players... bye.\n"));
641 	player_broadcast(player_none(game), PB_SILENT,
642 			 FIRST_VERSION, LATEST_VERSION,
643 			 "NOTE %s\n",
644 			 N_("No human players present. Bye."));
645 	request_server_stop(game);
646 	return FALSE;
647 }
648 
player_archive(Player * player)649 void player_archive(Player * player)
650 {
651 	StateFunc state;
652 	Game *game = player->game;
653 	gboolean human_player_present;
654 	GList *pl;
655 
656 	/* If this was a spectator, forget about him */
657 	if (player_is_spectator(game, player->num)) {
658 		player_free(player);
659 		return;
660 	}
661 	/* If this game can't be started, forget old players */
662 	if (params_game_is_unstartable(game->params)) {
663 		player_free(player);
664 		return;
665 	}
666 
667 	/* Mark the player as disconnected */
668 	player->disconnected = TRUE;
669 
670 	/* If the player was in the middle of a trade, pop the state
671 	   machine and inform others as necessary */
672 	state = sm_current(player->sm);
673 	if (state == (StateFunc) mode_domestic_quote_rejected) {
674 		/* No special actions needed */
675 	} else if (state == (StateFunc) mode_domestic_quote) {
676 		/* Retract all quotes */
677 		for (;;) {
678 			QuoteInfo *quote;
679 			quote = quotelist_find_domestic(game->quotes,
680 							player->num, -1);
681 			if (quote == NULL)
682 				break;
683 			quotelist_delete(game->quotes, quote);
684 			player_broadcast(player, PB_RESPOND, FIRST_VERSION,
685 					 LATEST_VERSION,
686 					 "domestic-quote delete %d\n",
687 					 quote->var.d.quote_num);
688 		}
689 	} else if (state == (StateFunc) mode_domestic_initiate) {
690 		/* End the trade */
691 		trade_finish_domestic(player);
692 	}
693 
694 	/* If the player was robbing something, auto-undo to robber
695 	 * placement.  */
696 	if (state == (StateFunc) mode_select_robbed
697 	    || state == (StateFunc) mode_select_pirated)
698 		robber_undo(player);
699 
700 	/* Inform the metaserver */
701 	game->num_players--;
702 	meta_report_num_players(game->num_players);
703 
704 	/* if no human players are present, start timer */
705 	playerlist_inc_use_count(game);
706 	human_player_present = FALSE;
707 	for (pl = game->player_list;
708 	     pl != NULL && !human_player_present; pl = g_list_next(pl)) {
709 		Player *p = pl->data;
710 		if (!player_is_spectator(game, p->num)
711 		    && !p->disconnected
712 		    && determine_player_type(p->style) == PLAYER_HUMAN) {
713 			human_player_present = TRUE;
714 		}
715 	}
716 	playerlist_dec_use_count(game);
717 	if (!human_player_present && game->no_humans_timer == 0
718 	    && is_tournament_game(game)) {
719 		game->no_humans_timer =
720 		    g_timeout_add(time_to_wait_for_players, timed_out,
721 				  game);
722 		player_broadcast(player_none(game), PB_SILENT,
723 				 FIRST_VERSION, LATEST_VERSION,
724 				 "NOTE %s\n",
725 				 N_
726 				 ("The last human player left. Waiting for the return of a player."));
727 	}
728 }
729 
730 /* Try to revive the player
731    newp: Player* attempt to revive this player
732    name: The player wants to have this name, if possible
733 */
player_revive(Player * newp,char * name)734 void player_revive(Player * newp, char *name)
735 {
736 	Game *game = newp->game;
737 	GList *current = NULL;
738 	Player *p = NULL;
739 	gboolean reviving_player_in_setup;
740 	gchar *safe_name;
741 
742 	if (game->no_humans_timer != 0) {
743 		g_source_remove(game->no_humans_timer);
744 		game->no_humans_timer = 0;
745 		player_broadcast(player_none(game), PB_SILENT,
746 				 FIRST_VERSION, LATEST_VERSION,
747 				 "NOTE %s\n", N_("Resuming the game."));
748 	}
749 
750 	/* first see if a player with the given name exists */
751 	if (name) {
752 		playerlist_inc_use_count(game);
753 		for (current = game->player_list; current != NULL;
754 		     current = g_list_next(current)) {
755 			p = current->data;
756 			if (!strcmp(name, p->name))
757 				if (p->disconnected
758 				    && !sm_get_use_cache(p->sm)
759 				    && p != newp)
760 					break;
761 		}
762 		playerlist_dec_use_count(game);
763 	}
764 	/* if not, try to find an unused player number */
765 	if (current == NULL) {
766 		gint num;
767 
768 		num = next_free_player_num(game, FALSE);
769 		if (num < (gint) game->params->num_players) {
770 			player_setup(newp, -1, name, FALSE);
771 			return;
772 		}
773 	}
774 	/* if not, try to take over another disconnected player */
775 	if (current == NULL) {
776 		playerlist_inc_use_count(game);
777 		for (current = game->player_list; current != NULL;
778 		     current = g_list_next(current)) {
779 			p = current->data;
780 			if (p->disconnected && !sm_get_use_cache(p->sm)
781 			    && p != newp)
782 				break;
783 		}
784 		playerlist_dec_use_count(game);
785 	}
786 	/* if still no player is found, do a normal setup */
787 	if (current == NULL) {
788 		player_setup(newp, -1, name, FALSE);
789 		return;
790 	}
791 
792 	/* Reviving the player that is currently in the setup phase */
793 	reviving_player_in_setup =
794 	    (game->setup_player && game->setup_player->data == p);
795 
796 	/* remove the disconnected player from the player list, it's memory will be freed at the end of this routine */
797 	game->player_list = g_list_remove(game->player_list, p);
798 
799 	/* initialize the player */
800 	player_setup(newp, p->num, name, FALSE);
801 
802 	/* mark the player as a reconnect */
803 	newp->disconnected = TRUE;
804 
805 	/* Don't use the old player's name */
806 
807 	/* copy over all the data from p */
808 	g_assert(newp->build_list == NULL);
809 	newp->build_list = p->build_list;
810 	p->build_list = NULL;	/* prevent deletion */
811 
812 	memcpy(newp->prev_assets, p->prev_assets,
813 	       sizeof(newp->prev_assets));
814 	memcpy(newp->assets, p->assets, sizeof(newp->assets));
815 	newp->gold = p->gold;
816 	/* take over the development deck */
817 	deck_free(newp->devel, NULL);
818 	newp->devel = p->devel;
819 	p->devel = NULL;
820 
821 	g_assert(newp->special_points == NULL);
822 	newp->special_points = p->special_points;
823 	p->special_points = NULL;	/* prevent deletion */
824 
825 	newp->discard_num = p->discard_num;
826 	newp->num_roads = p->num_roads;
827 	newp->num_bridges = p->num_bridges;
828 	newp->num_ships = p->num_ships;
829 	newp->num_settlements = p->num_settlements;
830 	newp->num_cities = p->num_cities;
831 	newp->num_soldiers = p->num_soldiers;
832 	newp->develop_points = p->develop_points;
833 	newp->chapel_played = p->chapel_played;
834 	newp->univ_played = p->univ_played;
835 	newp->gov_played = p->gov_played;
836 	newp->libr_played = p->libr_played;
837 	newp->market_played = p->market_played;
838 	/* Not copied: sm, game, location, num, client_version */
839 
840 	sm_copy_stack(newp->sm, p->sm);
841 	if (sm_current(newp->sm) != (StateFunc) mode_pre_game)
842 		sm_push(newp->sm, (StateFunc) mode_pre_game);
843 	else
844 		sm_goto(newp->sm, (StateFunc) mode_pre_game);
845 
846 	/* Copy longest road and largest army */
847 	if (game->longest_road == p)
848 		game->longest_road = newp;
849 	if (game->largest_army == p)
850 		game->largest_army = newp;
851 
852 	if (reviving_player_in_setup) {
853 		/* Restore the pointer */
854 		game->setup_player = game->player_list;
855 		while (game->setup_player
856 		       && game->setup_player->data != newp) {
857 			game->setup_player =
858 			    g_list_next(game->setup_player);
859 		}
860 		g_assert(game->setup_player != NULL);
861 	}
862 	p->num = -1;		/* prevent the number of players
863 				   from getting decremented */
864 
865 	player_free(p);
866 
867 	/* Make sure the name in the broadcast doesn't contain the separator */
868 	safe_name = g_strdup(newp->name);
869 	g_strdelimit(safe_name, "|", '_');
870 	player_broadcast(newp, PB_SILENT, FIRST_VERSION, LATEST_VERSION,
871 			 "NOTE1 %s|%s\n", safe_name,
872 			 /* %s is the name of the reconnecting player */
873 			 N_("%s has reconnected."));
874 	g_free(safe_name);
875 	return;
876 }
877 
mode_spectator(Player * player,gint event)878 gboolean mode_spectator(Player * player, gint event)
879 {
880 	gint num;
881 	Game *game = player->game;
882 	StateMachine *sm = player->sm;
883 	Player *other;
884 
885 	sm_state_name(sm, "mode_spectator");
886 	if (event != SM_RECV)
887 		return FALSE;
888 	/* first see if this is a valid event for this mode */
889 	if (sm_recv(sm, "play")) {
890 		/* try to be the first available player */
891 		num = next_free_player_num(game, FALSE);
892 		if (num >= (gint) game->params->num_players) {
893 			player_send(player, FIRST_VERSION, LATEST_VERSION,
894 				    "ERR game-full");
895 			return TRUE;
896 		}
897 	} else if (sm_recv(sm, "play %d", &num)) {
898 		/* try to be the specified player number */
899 		if (num >= (gint) game->params->num_players
900 		    || num < 0
901 		    || !player_by_num(game, num)->disconnected) {
902 			player_send(player, FIRST_VERSION, LATEST_VERSION,
903 				    "ERR invalid-player");
904 			return TRUE;
905 		}
906 	} else
907 		/* input was not what we expected,
908 		 * see if mode_unhandled likes it */
909 		return FALSE;
910 
911 	other = player_by_num(game, num);
912 	if (other == NULL) {
913 		player_send(player, FIRST_VERSION, LATEST_VERSION, "Ok\n");
914 		player_broadcast(player, PB_ALL, FIRST_VERSION,
915 				 LATEST_VERSION, "was spectator %d\n",
916 				 player->num);
917 		sm_set_use_cache(player->sm, TRUE);
918 		player_setup(player, -1, player->name, FALSE);
919 		sm_goto(sm, (StateFunc) mode_pre_game);
920 		return TRUE;
921 	}
922 	sm_set_use_cache(player->sm, TRUE);
923 	player_revive(player, player->name);
924 	return TRUE;
925 }
926 
mode_bad_version(Player * player,gint event)927 static gboolean mode_bad_version(Player * player, gint event)
928 {
929 	StateMachine *sm = player->sm;
930 
931 	sm_state_name(sm, "mode_bad_version");
932 	switch (event) {
933 	case SM_ENTER:
934 		player_send_uncached(player, FIRST_VERSION, LATEST_VERSION,
935 				     "ERR sorry, version conflict\n");
936 		player_free(player);
937 		break;
938 	}
939 	return FALSE;
940 }
941 
mode_check_version(Player * player,gint event)942 static gboolean mode_check_version(Player * player, gint event)
943 {
944 	StateMachine *sm = player->sm;
945 	gchar *version;
946 
947 	sm_state_name(sm, "mode_check_version");
948 	switch (event) {
949 	case SM_ENTER:
950 		player_send_uncached(player, UNKNOWN_VERSION,
951 				     UNKNOWN_VERSION, "version report\n");
952 		break;
953 
954 	case SM_RECV:
955 		if (sm_recv(sm, "version %S", &version)) {
956 			ClientVersionType cvt =
957 			    client_version_type_from_string(version);
958 			player->version = cvt;
959 			if (can_client_connect_to_server
960 			    (cvt, LATEST_VERSION)) {
961 				sm_goto(sm, (StateFunc) mode_check_status);
962 			} else {
963 				gchar *mismatch =
964 				    g_strdup_printf("%s <-> %s",
965 						    client_version_type_to_string
966 						    (LATEST_VERSION),
967 						    version);
968 				/* Make sure the argument does not contain the separator */
969 				g_strdelimit(mismatch, "|", '_');
970 				player_send_uncached(player, cvt, cvt,
971 						     "NOTE1 %s|%s\n",
972 						     mismatch,
973 						     N_(""
974 							"Version mismatch: %s"));
975 				g_free(mismatch);
976 				sm_goto(sm, (StateFunc) mode_bad_version);
977 			}
978 			g_free(version);
979 			return TRUE;
980 		}
981 		break;
982 	default:
983 		break;
984 	}
985 	return FALSE;
986 }
987 
start_tournament_mode(Player * player)988 static void start_tournament_mode(Player * player)
989 {
990 	Game *game = player->game;
991 
992 	if (is_tournament_game(game)) {
993 		/* if first player in and this is a tournament start the timer */
994 		if (game->num_players == 1) {
995 			game->tournament_countdown =
996 			    game->params->tournament_time;
997 			game->tournament_timer =
998 			    g_timeout_add(game->tournament_countdown *
999 					  tournament_minute + 500,
1000 					  &tournament_start_cb, game);
1001 			g_timeout_add(1000, &talk_about_tournament_cb,
1002 				      game);
1003 		} else {
1004 			if (game->tournament_timer != 0
1005 			    && game->num_players !=
1006 			    game->params->num_players) {
1007 				player_send(player, FIRST_VERSION,
1008 					    LATEST_VERSION, "NOTE %s\n",
1009 					    N_
1010 					    ("This game will start soon."));
1011 			}
1012 		}
1013 	}
1014 }
1015 
mode_check_status(Player * player,gint event)1016 static gboolean mode_check_status(Player * player, gint event)
1017 {
1018 	StateMachine *sm = player->sm;
1019 	gchar *playername;
1020 
1021 	sm_state_name(sm, "mode_check_status");
1022 	switch (event) {
1023 	case SM_ENTER:
1024 		player_send_uncached(player, FIRST_VERSION, LATEST_VERSION,
1025 				     "status report\n");
1026 		break;
1027 
1028 	case SM_RECV:
1029 		if (sm_recv(sm, "status newplayer")) {
1030 			player_setup(player, -1, NULL, FALSE);
1031 			start_tournament_mode(player);
1032 			return TRUE;
1033 		}
1034 		if (sm_recv(sm, "status reconnect %S", &playername)) {
1035 			/* if possible, try to revive the player */
1036 			player_revive(player, playername);
1037 			g_free(playername);
1038 			start_tournament_mode(player);
1039 			return TRUE;
1040 		}
1041 		if (sm_recv(sm, "status newviewer")) {
1042 			player_setup(player, -1, NULL, TRUE);
1043 			return TRUE;
1044 		}
1045 		if (sm_recv(sm, "status viewer %S", &playername)) {
1046 			player_setup(player, -1, playername, TRUE);
1047 			g_free(playername);
1048 			return TRUE;
1049 		}
1050 		break;
1051 	default:
1052 		break;
1053 	}
1054 	return FALSE;
1055 }
1056 
1057 /* Returns a GList* to player 0 */
player_first_real(Game * game)1058 GList *player_first_real(Game * game)
1059 {
1060 	GList *list;
1061 	/* search for player 0 */
1062 	playerlist_inc_use_count(game);
1063 	for (list = game->player_list;
1064 	     list != NULL; list = g_list_next(list)) {
1065 		Player *player = list->data;
1066 		if (player->num == 0)
1067 			break;
1068 	}
1069 	playerlist_dec_use_count(game);
1070 	return list;
1071 }
1072 
1073 /* Returns a GList * to a player with a number one higher than last */
player_next_real(GList * last)1074 GList *player_next_real(GList * last)
1075 {
1076 	Player *player;
1077 	Game *game;
1078 	guint numplayers;
1079 	gint nextnum;
1080 	GList *list;
1081 
1082 	if (!last)
1083 		return NULL;
1084 
1085 	player = last->data;
1086 	game = player->game;
1087 	numplayers = game->params->num_players;
1088 	nextnum = player->num + 1;
1089 
1090 	if (nextnum >= (gint) numplayers)
1091 		return NULL;
1092 
1093 	playerlist_inc_use_count(game);
1094 	for (list = game->player_list; list != NULL;
1095 	     list = g_list_next(list)) {
1096 		Player *scan = list->data;
1097 		if (scan->num == nextnum)
1098 			break;
1099 	}
1100 	playerlist_dec_use_count(game);
1101 	return list;
1102 }
1103 
player_by_name(Game * game,char * name)1104 static Player *player_by_name(Game * game, char *name)
1105 {
1106 	GList *list;
1107 
1108 	playerlist_inc_use_count(game);
1109 	for (list = game->player_list;
1110 	     list != NULL; list = g_list_next(list)) {
1111 		Player *player = list->data;
1112 
1113 		if (player->name != NULL
1114 		    && strcmp(player->name, name) == 0) {
1115 			playerlist_dec_use_count(game);
1116 			return player;
1117 		}
1118 	}
1119 	playerlist_dec_use_count(game);
1120 
1121 	return NULL;
1122 }
1123 
player_by_num(Game * game,gint num)1124 Player *player_by_num(Game * game, gint num)
1125 {
1126 	GList *list;
1127 
1128 	playerlist_inc_use_count(game);
1129 	for (list = game->player_list;
1130 	     list != NULL; list = g_list_next(list)) {
1131 		Player *player = list->data;
1132 
1133 		if (player->num == num) {
1134 			playerlist_dec_use_count(game);
1135 			return player;
1136 		}
1137 	}
1138 	playerlist_dec_use_count(game);
1139 
1140 	return NULL;
1141 }
1142 
player_is_spectator(Game * game,gint player_num)1143 gboolean player_is_spectator(Game * game, gint player_num)
1144 {
1145 	return (gint) game->params->num_players <= player_num;
1146 }
1147 
1148 /* Returns a player that's not part of the game.
1149  */
player_none(Game * game)1150 Player *player_none(Game * game)
1151 {
1152 	static Player player;
1153 
1154 	player.game = game;
1155 	player.num = -1;
1156 	player.disconnected = TRUE;
1157 	return &player;
1158 }
1159 
1160 /** Broadcast a message to all players and spectators - prepend "player %d " to
1161  * all players except the one generating the message.
1162  * Also prepend 'extension' when this message is a protocol extension.
1163  *
1164  *  send to  PB_SILENT PB_RESPOND PB_ALL PB_OTHERS
1165  *  player      -           -       +        **
1166  *  other       -           +       +        +
1167  * ** = don't send to the player
1168  * +  = prepend 'player %d' to the message
1169  * -  = don't alter the message
1170  */
player_broadcast_internal(Player * player,BroadcastType type,const gchar * message,gboolean is_extension,ClientVersionType first_supported_version,ClientVersionType last_supported_version)1171 static void player_broadcast_internal(Player * player, BroadcastType type,
1172 				      const gchar * message,
1173 				      gboolean is_extension,
1174 				      ClientVersionType
1175 				      first_supported_version,
1176 				      ClientVersionType
1177 				      last_supported_version)
1178 {
1179 	Game *game = player->game;
1180 	GList *list;
1181 
1182 	playerlist_inc_use_count(game);
1183 	for (list = game->player_list; list != NULL;
1184 	     list = g_list_next(list)) {
1185 		Player *scan = list->data;
1186 		if ((scan->disconnected && !sm_get_use_cache(scan->sm))
1187 		    || scan->num < 0
1188 		    || scan->version < first_supported_version
1189 		    || scan->version > last_supported_version)
1190 			continue;
1191 		if (type == PB_SILENT
1192 		    || (scan == player && type == PB_RESPOND)) {
1193 			if (is_extension) {
1194 				player_send(scan, first_supported_version,
1195 					    last_supported_version,
1196 					    "extension %s", message);
1197 			} else {
1198 				player_send(scan, first_supported_version,
1199 					    last_supported_version, "%s",
1200 					    message);
1201 			}
1202 		} else if (scan != player || type == PB_ALL) {
1203 			if (is_extension) {
1204 				player_send(scan, first_supported_version,
1205 					    last_supported_version,
1206 					    "extension player %d %s",
1207 					    player->num, message);
1208 			} else {
1209 				player_send(scan, first_supported_version,
1210 					    last_supported_version,
1211 					    "player %d %s", player->num,
1212 					    message);
1213 			}
1214 
1215 		}
1216 	}
1217 	playerlist_dec_use_count(game);
1218 }
1219 
1220 /** As player_broadcast, but will add the 'extension' keyword */
player_broadcast_extension(Player * player,BroadcastType type,ClientVersionType first_supported_version,ClientVersionType last_supported_version,const char * fmt,...)1221 void player_broadcast_extension(Player * player, BroadcastType type,
1222 				ClientVersionType first_supported_version,
1223 				ClientVersionType last_supported_version,
1224 				const char *fmt, ...)
1225 {
1226 	gchar *buff;
1227 	va_list ap;
1228 
1229 	va_start(ap, fmt);
1230 	buff = game_vprintf(fmt, ap);
1231 	va_end(ap);
1232 
1233 	player_broadcast_internal(player, type, buff, TRUE,
1234 				  first_supported_version,
1235 				  last_supported_version);
1236 	g_free(buff);
1237 }
1238 
1239 /** Broadcast a message to all players and spectators */
player_broadcast(Player * player,BroadcastType type,ClientVersionType first_supported_version,ClientVersionType last_supported_version,const char * fmt,...)1240 void player_broadcast(Player * player, BroadcastType type,
1241 		      ClientVersionType first_supported_version,
1242 		      ClientVersionType last_supported_version,
1243 		      const char *fmt, ...)
1244 {
1245 	gchar *buff;
1246 	va_list ap;
1247 
1248 	va_start(ap, fmt);
1249 	buff = game_vprintf(fmt, ap);
1250 	va_end(ap);
1251 
1252 	player_broadcast_internal(player, type, buff, FALSE,
1253 				  first_supported_version,
1254 				  last_supported_version);
1255 	g_free(buff);
1256 }
1257 
1258 /** Send a message to one player */
player_send(Player * player,ClientVersionType first_supported_version,ClientVersionType last_supported_version,const char * fmt,...)1259 void player_send(Player * player,
1260 		 ClientVersionType first_supported_version,
1261 		 ClientVersionType last_supported_version, const char *fmt,
1262 		 ...)
1263 {
1264 	gchar *buff;
1265 	va_list ap;
1266 
1267 	if (player->version < first_supported_version
1268 	    || player->version > last_supported_version)
1269 		return;
1270 
1271 	va_start(ap, fmt);
1272 	buff = game_vprintf(fmt, ap);
1273 	va_end(ap);
1274 
1275 	sm_write(player->sm, buff);
1276 	g_free(buff);
1277 }
1278 
1279 /** Send a message to one player, even when caching is turned on */
player_send_uncached(Player * player,ClientVersionType first_supported_version,ClientVersionType last_supported_version,const char * fmt,...)1280 void player_send_uncached(Player * player,
1281 			  ClientVersionType first_supported_version,
1282 			  ClientVersionType last_supported_version,
1283 			  const char *fmt, ...)
1284 {
1285 	gchar *buff;
1286 	va_list ap;
1287 
1288 	if (player->version < first_supported_version
1289 	    || player->version > last_supported_version)
1290 		return;
1291 
1292 	va_start(ap, fmt);
1293 	buff = game_vprintf(fmt, ap);
1294 	va_end(ap);
1295 
1296 	sm_write_uncached(player->sm, buff);
1297 	g_free(buff);
1298 }
1299 
player_set_name(Player * player,gchar * name)1300 void player_set_name(Player * player, gchar * name)
1301 {
1302 	player_set_name_real(player, name, TRUE);
1303 }
1304 
player_remove(Player * player)1305 void player_remove(Player * player)
1306 {
1307 	driver->player_removed(player);
1308 }
1309 
list_from_player(Player * player)1310 GList *list_from_player(Player * player)
1311 {
1312 	GList *list;
1313 	for (list = player_first_real(player->game); list != NULL;
1314 	     list = player_next_real(list))
1315 		if (list->data == player)
1316 			break;
1317 	g_assert(list != NULL);
1318 	return list;
1319 }
1320 
next_player_loop(GList * current,Player * first)1321 GList *next_player_loop(GList * current, Player * first)
1322 {
1323 	current = player_next_real(current);
1324 	if (current == NULL)
1325 		current = player_first_real(first->game);
1326 	if (current->data == first)
1327 		return NULL;
1328 	return current;
1329 }
1330 
playerlist_inc_use_count(Game * game)1331 void playerlist_inc_use_count(Game * game)
1332 {
1333 	game->player_list_use_count++;
1334 }
1335 
playerlist_dec_use_count(Game * game)1336 void playerlist_dec_use_count(Game * game)
1337 {
1338 	game->player_list_use_count--;
1339 	if (game->player_list_use_count == 0) {
1340 		GList *current;
1341 		GList *all_dead_players;
1342 		current = game->dead_players;
1343 		all_dead_players = game->dead_players;	/* Remember this for g_list_free */
1344 		game->dead_players = NULL;	/* Clear the list */
1345 		for (; current != NULL; current = g_list_next(current)) {
1346 			Player *p = current->data;
1347 			player_free(p);
1348 		}
1349 		g_list_free(all_dead_players);
1350 	}
1351 }
1352