LICENSE: The Artistic License 2.0

/*
 * qstat.h
 * by Steve Jankowski
 * steve@qstat.org
 * http://www.qstat.org
 *
 * Copyright 1996,1997,1998,1999,2000,2001,2002 by Steve Jankowski
 */



{
    /* BFRIS */
    BFRIS_SERVER,		/* id */
    "BFS",			/* type_prefix */
    "bfs",			/* type_string */
    "-bfs",			/* type_option */
    "BFRIS",			/* game_name */
    0,				/* master */
    BFRIS_DEFAULT_PORT,		/* default_port */
    0,				/* port_offset */
    TF_TCP_CONNECT,		/* flags */
    "Rules",			/* game_rule */
    "BFRIS",			/* template_var */
    NULL,			/* status_packet */
    0,				/* status_len */
    NULL,			/* player_packet */
    0,				/* player_len */
    NULL,			/* rule_packet */
    0,				/* rule_len */
    NULL,			/* master_packet */
    0,				/* master_len */
    NULL,			/* master_protocol */
    NULL,			/* master_query */
    display_bfris_player_info,	/* display_player_func */
    display_server_rules,	/* display_rule_func */
    raw_display_bfris_player_info,/* display_raw_player_func */
    raw_display_server_rules,	/* display_raw_rule_func */
    xml_display_bfris_player_info,	/* display_xml_player_func */
    xml_display_server_rules,	/* display_xml_rule_func */
    send_bfris_request_packet,	/* status_query_func */
    NULL,			/* rule_query_func */
    NULL,			/* player_query_func */
    deal_with_bfris_packet,	/* packet_func */
},




/* postions of map name, player name (in player substring), zero-based */
#define BFRIS_MAP_POS 18
#define BFRIS_PNAME_POS 11
query_status_t deal_with_bfris_packet(struct qserver *server, char *rawpkt, int pktlen)
{
	int i, player_data_pos, nplayers;
	SavedData *sdata;
	unsigned char *saved_data;
	int saved_data_size;

	debug( 2, "deal_with_bfris_packet %p, %d", server, pktlen );

	server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);

	/* add to the data previously saved */
	sdata = &server->saved_data;
	if (!sdata->data)
	{
		sdata->data = (char*)malloc(pktlen);
	}
	else
	{
		sdata->data = (char*)realloc(sdata->data, sdata->datalen + pktlen);
	}

	memcpy(sdata->data + sdata->datalen, rawpkt, pktlen);
	sdata->datalen += pktlen;

	saved_data = (unsigned char*)sdata->data;
	saved_data_size = sdata->datalen;

	/* after we get the server portion of the data, server->game != NULL */
	if (!server->game)
	{

		/* server data goes up to map name */
		if (sdata->datalen <= BFRIS_MAP_POS)
		{
			return INPROGRESS;
		}

		/* see if map name is complete */
		player_data_pos = 0;
		for (i = BFRIS_MAP_POS; i < saved_data_size; i++)
		{
			if (saved_data[i] == '\0')
			{
				player_data_pos = i + 1;
				/* data must extend beyond map name */
				if (saved_data_size <= player_data_pos)
				{
					return INPROGRESS;
				}
				break;
			}
		}

		/* did we find beginning of player data? */
		if (!player_data_pos)
		{
			return INPROGRESS;
		}

		/* now we can go ahead and fill in server data */
		server->map_name = strdup((char*)saved_data + BFRIS_MAP_POS);
		server->max_players = saved_data[12];
		server->protocol_version = saved_data[11];

		/* save game type */
		switch (saved_data[13] &15)
		{
			case 0:
				server->game = "FFA";
				break;
			case 5:
				server->game = "Rover";
				break;
			case 6:
				server->game = "Occupation";
				break;
			case 7:
				server->game = "SPAAL";
				break;
			case 8:
				server->game = "CTF";
				break;
			default:
				server->game = "unknown";
				break;
		}
		server->flags |= FLAG_DO_NOT_FREE_GAME;
		add_rule(server, server->type->game_rule, server->game, NO_FLAGS);

		if (get_server_rules)
		{
			char buf[24];

			/* server revision */
			sprintf(buf, "%d", (unsigned int)saved_data[11]);
			add_rule(server, "Revision", buf, NO_FLAGS);

			/* latency */
			sprintf(buf, "%d", (unsigned int)saved_data[10]);
			add_rule(server, "Latency", buf, NO_FLAGS);

			/* player allocation */
			add_rule(server, "Allocation", saved_data[13] &16 ? "Automatic" : "Manual", NO_FLAGS);

		}

	}

	/* If we got this far, we know the data saved goes at least to the start of
	the player information, and that the server data is taken care of.
	 */

	/* start of player data */
	player_data_pos = BFRIS_MAP_POS + strlen((char*)saved_data + BFRIS_MAP_POS) + 1;

	/* ensure all player data have arrived */
	nplayers = 0;
	while (saved_data[player_data_pos] != '\0')
	{

		player_data_pos += BFRIS_PNAME_POS;

		/* does player data extend to player name? */
		if (saved_data_size <= player_data_pos + 1)
		{
			return INPROGRESS;
		}

		/* does player data extend to end of player name? */
		for (i = 0; player_data_pos + i < saved_data_size; i++)
		{

			if (saved_data_size == player_data_pos + i + 1)
			{
				return INPROGRESS;
			}

			if (saved_data[player_data_pos + i] == '\0')
			{
				player_data_pos += i + 1;
				nplayers++;
				break;
			}
		}
	}
	/* all player data are complete */

	server->num_players = nplayers;

	if (get_player_info)
	{

		/* start of player data */
		player_data_pos = BFRIS_MAP_POS + strlen((char*)saved_data + BFRIS_MAP_POS) + 1;

		for (i = 0; i < nplayers; i++)
		{
			struct player *player;
			player = add_player(server, saved_data[player_data_pos]);

			player->ship = saved_data[player_data_pos + 1];
			player->ping = saved_data[player_data_pos + 2];
			player->frags = saved_data[player_data_pos + 3];
			player->team = saved_data[player_data_pos + 4];
			switch (player->team)
			{
				case 0:
					player->team_name = "silver";
					break;
				case 1:
					player->team_name = "red";
					break;
				case 2:
					player->team_name = "blue";
					break;
				case 3:
					player->team_name = "green";
					break;
				case 4:
					player->team_name = "purple";
					break;
				case 5:
					player->team_name = "yellow";
					break;
				case 6:
					player->team_name = "cyan";
					break;
				default:
					player->team_name = "unknown";
					break;
			}
			player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM;
			player->room = saved_data[player_data_pos + 5];

			/* score is little-endian integer */
			player->score = saved_data[player_data_pos + 7] +
				(saved_data[player_data_pos + 8] << 8) +
				(saved_data[player_data_pos + 9] << 16) +
				(saved_data[player_data_pos + 10] << 24);

			/* for archs with > 4-byte int */
			if (player->score &0x80000000)
			{
				player->score = - (~(player->score)) - 1;
			}


			player_data_pos += BFRIS_PNAME_POS;
			player->name = strdup((char*)saved_data + player_data_pos);

			player_data_pos += strlen(player->name) + 1;
		}

	}

	server->server_name = BFRIS_SERVER_NAME;

	return DONE_FORCE;
}


