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
 */

 
/* for some reason Descent3 uses a different request for pxo/non-pxo games. blah. */
unsigned char descent3_pxoinfoquery[] = {
    0x01, /* "internal descent3 routing" */
    0x29, /* request server info? (pxo listed servers) */
    0x0b, 0x00, /* packet length (- routing byte) */
    0x1b, 0x2f, 0xf4, 0x41, 0x09, 0x00, 0x00, 0x00 /* unknown */
};
unsigned char descent3_tcpipinfoquery[] = {
    0x01, /* "internal descent3 routing" */
    0x1e, /* request server info? (tcpip only servers) */
    0x0b, 0x00, /* packet length (- routing byte) */
    0x1b, 0x2f, 0xf4, 0x41, 0x09, 0x00, 0x00, 0x00 /* unknown */
};
/* http://ml.warpcore.org/d3dl/200101/msg00001.html
 * http://ml.warpcore.org/d3dl/200101/msg00004.html */
unsigned char descent3_playerquery[] = {
    0x01, /* "internal descent3 routing" */
    0x72, /* MP_REQUEST_PLAYERLIST   */
    0x03, 0x00 /* packet length (- routing byte) */
};

 


{
    /* DESCENT3 PROTOCOL */
    DESCENT3_SERVER,		/* id */
    "D3S",			/* type_prefix */
    "d3s",			/* type_string */
    "-d3s",			/* type_option */
    "Descent3",			/* game_name */
    0,				/* master */
    DESCENT3_DEFAULT_PORT,	/* default_port */
    0,				/* port_offset */
    0,				/* flags */
    "gametype",			/* game_rule */
    "DESCENT3",			/* template_var */
    (char*) &descent3_tcpipinfoquery,	/* status_packet */
    sizeof( descent3_tcpipinfoquery),	/* status_len */
    (char*) &descent3_playerquery,	/* player_packet */
    sizeof( descent3_playerquery),	/* player_len */
    NULL,			/* rule_packet */
    0,				/* rule_len */
    NULL,			/* master_packet */
    0,				/* master_len */
    NULL,			/* master_protocol */
    NULL,			/* master_query */
    display_descent3_player_info,	/* display_player_func */
    display_server_rules,	/* display_rule_func */
    raw_display_descent3_player_info,	/* display_raw_player_func */
    raw_display_server_rules,	/* display_raw_rule_func */
    xml_display_descent3_player_info,	/* display_xml_player_func */
    xml_display_server_rules,	/* display_xml_rule_func */
    send_gps_request_packet,	/* status_query_func */
    NULL,			/* rule_query_func */
    NULL,			/* player_query_func */
    deal_with_descent3_packet,	/* packet_func */
},
{
    /* DESCENT3 PROTOCOL */
    DESCENT3_PXO_SERVER,	/* id */
    "D3P",			/* type_prefix */
    "d3p",			/* type_string */
    "-d3p",			/* type_option */
    "Descent3 PXO protocol",	/* game_name */
    0,				/* master */
    DESCENT3_DEFAULT_PORT,	/* default_port */
    0,				/* port_offset */
    0,				/* flags */
    "gametype",			/* game_rule */
    "DESCENT3",			/* template_var */
    (char*) &descent3_pxoinfoquery,	/* status_packet */
    sizeof( descent3_pxoinfoquery),	/* status_len */
    (char*) &descent3_playerquery,	/* player_packet */
    sizeof( descent3_playerquery),	/* player_len */
    NULL,			/* rule_packet */
    0,				/* rule_len */
    NULL,			/* master_packet */
    0,				/* master_len */
    NULL,			/* master_protocol */
    NULL,			/* master_query */
    display_descent3_player_info,	/* display_player_func */
    display_server_rules,	/* display_rule_func */
    raw_display_descent3_player_info,	/* display_raw_player_func */
    raw_display_server_rules,	/* display_raw_rule_func */
    xml_display_descent3_player_info,	/* display_xml_player_func */
    xml_display_server_rules,	/* display_xml_rule_func */
    send_gps_request_packet,	/* status_query_func */
    NULL,			/* rule_query_func */
    NULL,			/* player_query_func */
    deal_with_descent3_packet,	/* packet_func */
},




query_status_t deal_with_descent3_packet(struct qserver *server, char *rawpkt, int pktlen)
{
	char *pkt;
	char buf[24];

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

	if (server->server_name == NULL)
	{
		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
	}

	if (pktlen < 4)
	{
		fprintf(stderr, "short descent3 packet\n");
		print_packet(server, rawpkt, pktlen);
		return PKT_ERROR;
	}

	/* 'info' response */
	if (rawpkt[1] == 0x1f)
	{
		if (server->server_name != NULL)
		{
			return PKT_ERROR;
		}


		pkt = &rawpkt[0x15];
		server->server_name = strdup(pkt);
		pkt += strlen(pkt) + 2;
		server->map_name = strdup(pkt); /* mission name (blah.mn3) */
		pkt += strlen(pkt) + 2;
		add_rule(server, "level_name", pkt, NO_FLAGS);
		pkt += strlen(pkt) + 2;
		add_rule(server, "gametype", pkt, NO_FLAGS);
		pkt += strlen(pkt) + 1;

		sprintf(buf, "%hu", swap_short_from_little(pkt));
		add_rule(server, "level_num", buf, NO_FLAGS);
		pkt += 2;
		server->num_players = swap_short_from_little(pkt);
		pkt += 2;
		server->max_players = swap_short_from_little(pkt);
		pkt += 2;

		/* unknown/undecoded fields.. stuff like permissible, banned items/ships, etc */
		add_uchar_rule(server, "u0", pkt[0]);
		add_uchar_rule(server, "u1", pkt[1]);
		add_uchar_rule(server, "u2", pkt[2]);
		add_uchar_rule(server, "u3", pkt[3]);
		add_uchar_rule(server, "u4", pkt[4]);
		add_uchar_rule(server, "u5", pkt[5]);
		add_uchar_rule(server, "u6", pkt[6]);
		add_uchar_rule(server, "u7", pkt[7]);
		add_uchar_rule(server, "u8", pkt[8]);

		add_uchar_rule(server, "randpowerup", (unsigned char)!(pkt[4] &1)); /*
		randomize powerup spawn */
		add_uchar_rule(server, "acccollisions", (unsigned char)((pkt[5] &4) > 0));
		/* accurate collision detection */
		add_uchar_rule(server, "brightships", (unsigned char)((pkt[5] &16) > 0));
		/* bright player ships */
		add_uchar_rule(server, "mouselook", (unsigned char)((pkt[6] &1) > 0)); /*
		mouselook enabled */
		sprintf(buf, "%s%s", (pkt[4] &16) ? "PP" : "CS", (pkt[6] &1) ? "-ML" : "");
		add_rule(server, "servertype", buf, NO_FLAGS);

		sprintf(buf, "%hhu", pkt[9]);
		add_rule(server, "difficulty", buf, NO_FLAGS);

		/* unknown/undecoded fields after known flags removed */
		add_uchar_rule(server, "x4", (unsigned char)(pkt[4] &~(1+16)));
		add_uchar_rule(server, "x5", (unsigned char)(pkt[5] &~(4+16)));
		add_uchar_rule(server, "x6", (unsigned char)(pkt[6] &~1));

		if (get_player_info && server->num_players)
		{
			server->next_player_info = 0;
			send_player_request_packet(server);
			return INPROGRESS;
		}

	}
	/* MP_PLAYERLIST_DATA */
	else if (rawpkt[1] == 0x73)
	{
		struct player *player;
		struct player **last_player = &server->players;

		if (server->players != NULL)
		{
			return PKT_ERROR;
		}

		pkt = &rawpkt[0x4];
		while (*pkt)
		{
			player = (struct player*)calloc(1, sizeof(struct player));
			player->name = strdup(pkt);
			pkt += strlen(pkt) + 1;
			*last_player = player;
			last_player = &player->next;
		}
		server->next_player_info = NO_PLAYER_INFO;
	}
	else
	{
		fprintf(stderr, "unknown d3 packet\n");
		print_packet(server, rawpkt, pktlen);
	}

	return DONE_FORCE;
}

