Example #1
0
/**
 * @sa gi.AddEvent
 * @param[in] mask The player bitmask to send the events to. Use @c PM_ALL to send to every connected player.
 */
static void SV_AddEvent (unsigned int mask, int eType, int entnum)
{
	pending_event_t *p = &sv->pendingEvent;
	const int rawType = eType &~ EVENT_INSTANTLY;

	if (rawType >= EV_NUM_EVENTS || rawType < 0)
		Com_Error(ERR_DROP, "SV_AddEvent: invalid event %i", rawType);

	const char *eventName = eventNames[rawType].name;
	Com_DPrintf(DEBUG_EVENTSYS, "Event type: %s (%i - %i) (mask %s) (entnum: %i)\n", eventName,
			rawType, eType, Com_UnsignedIntToBinary(mask), entnum);

	/* finish the last event */
	if (p->pending)
		SV_EndEvents();

	/* start the new event */
	p->pending = true;
	p->playerMask = mask;
	p->type = eType;
	p->entnum = entnum;
	p->buf = new dbuffer();

	/* write header */
	NET_WriteByte(p->buf, svc_event);
	NET_WriteByte(p->buf, eType);
	if (entnum != -1)
		NET_WriteShort(p->buf, entnum);
}
Example #2
0
/**
 * @brief Responds with teaminfo such as free team num
 * @sa CL_ParseTeamInfoMessage
 */
static void SVC_TeamInfo (struct net_stream *s)
{
	client_t *cl;
	dbuffer msg;
	char infoGlobal[MAX_INFO_STRING] = "";

	NET_WriteByte(&msg, clc_oob);
	NET_WriteRawString(&msg, "teaminfo\n");

	Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_teamplay", Cvar_GetString("sv_teamplay"));
	Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxteams", Cvar_GetString("sv_maxteams"));
	Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxplayersperteam", Cvar_GetString("sv_maxplayersperteam"));
	NET_WriteString(&msg, infoGlobal);

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL) {
		if (cl->state >= cs_connected) {
			char infoPlayer[MAX_INFO_STRING] = "";
			/* show players that already have a team with their teamnum */
			int teamId = svs.ge->ClientGetTeamNum(cl->player);
			if (!teamId)
				teamId = TEAM_NO_ACTIVE;
			Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_team", teamId);
			Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_ready", svs.ge->ClientIsReady(cl->player));
			Info_SetValueForKey(infoPlayer, sizeof(infoPlayer), "cl_name", cl->name);
			NET_WriteString(&msg, infoPlayer);
		}
	}

	NET_WriteByte(&msg, 0);

	NET_WriteMsg(s, msg);
}
Example #3
0
/**
 * @brief
 * @note Called after precache was sent from the server
 * @sa SV_Configstrings_f
 * @sa CL_Precache_f
 */
void CL_RequestNextDownload (void)
{
	if (cls.state != ca_connected) {
		Com_Printf("CL_RequestNextDownload: Not connected (%i)\n", cls.state);
		return;
	}

	/* Use the map data from the server */
	cl.mapTiles = SV_GetMapTiles();
	cl.mapData = SV_GetMapData();

	/* as a multiplayer client we have to load the map here and
	 * check the compatibility with the server */
	if (!Com_ServerState() && !CL_CanMultiplayerStart())
		return;

	CL_ViewLoadMedia();

	dbuffer msg(7);
	/* send begin */
	/* this will activate the render process (see client state ca_active) */
	NET_WriteByte(&msg, clc_stringcmd);
	/* see CL_StartGame */
	NET_WriteString(&msg, NET_STATE_BEGIN "\n");
	NET_WriteMsg(cls.netStream, msg);

	cls.waitingForStart = CL_Milliseconds();

	S_MumbleLink();
}
Example #4
0
/**
 * @brief Called during startup of mission to send team info
 */
void GAME_SpawnSoldiers (void)
{
	const cgame_export_t *list = GAME_GetCurrentType();
	qboolean spawnStatus;

	/* this callback is responsible to set up the cl.chrList */
	if (list && list->Spawn)
		spawnStatus = list->Spawn();
	else
		spawnStatus = GAME_Spawn();

	if (spawnStatus && cl.chrList.num > 0) {
		struct dbuffer *msg;

		/* send team info */
		msg = new_dbuffer();
		GAME_SendCurrentTeamSpawningInfo(msg, &cl.chrList);
		NET_WriteMsg(cls.netStream, msg);

		msg = new_dbuffer();
		NET_WriteByte(msg, clc_stringcmd);
		NET_WriteString(msg, "spawn\n");
		NET_WriteMsg(cls.netStream, msg);

		GAME_InitializeBattlescape(&cl.chrList);
	}
}
Example #5
0
/**
 * @brief Responds with all the info that the server browser can see
 * @sa SV_StatusString
 */
static void SVC_Status (struct net_stream* s)
{
    if (SVC_RateLimitAddress(*s)) {
        Com_DPrintf(DEBUG_SERVER, "SVC_Status: rate limit from %s exceeded, dropping request\n", NET_StreamToString(s));
        return;
    }

    /* Allow getstatus to be DoSed relatively easily, but prevent excess outbound bandwidth usage when being flooded inbound */
    if (SVC_RateLimit(&outboundLeakyBucket, 10, 100)) {
        Com_DPrintf(DEBUG_SERVER, "SVC_Status: rate limit exceeded, dropping request\n");
        return;
    }

    dbuffer msg;
    NET_WriteByte(&msg, svc_oob);
    NET_WriteRawString(&msg, SV_CMD_PRINT "\n");
    char info[MAX_INFO_STRING];
    NET_WriteRawString(&msg, Cvar_Serverinfo(info, sizeof(info)));
    NET_WriteRawString(&msg, "\n");

    client_t* cl = nullptr;
    while ((cl = SV_GetNextClient(cl)) != nullptr) {
        if (cl->state <= cs_free)
            continue;

        char player[1024];
        Com_sprintf(player, sizeof(player), "%i \"%s\"\n", svs.ge->ClientGetTeamNum(*cl->player), cl->name);
        NET_WriteRawString(&msg, player);
    }

    NET_WriteMsg(s, msg);
}
Example #6
0
/**
 * @brief Called when the player is totally leaving the server, either willingly
 * or unwillingly. This is NOT called if the entire server is quitting
 * or crashing.
 */
void SV_DropClient (client_t * drop, const char *message)
{
	/* add the disconnect */
	dbuffer msg(2 + strlen(message));
	NET_WriteByte(&msg, svc_disconnect);
	NET_WriteString(&msg, message);
	NET_WriteMsg(drop->stream, msg);
	SV_BroadcastPrintf(PRINT_CHAT, "%s was dropped from the server - reason: %s\n", drop->name, message);

	if (drop->state == cs_spawned || drop->state == cs_spawning) {
		/* call the prog function for removing a client */
		/* this will remove the body, among other things */
		const ScopedMutex scopedMutex(svs.serverMutex);
		svs.ge->ClientDisconnect(drop->player);
	}

	NET_StreamFinished(drop->stream);
	drop->stream = NULL;

	drop->player->inuse = false;
	SV_SetClientState(drop, cs_free);
	drop->name[0] = 0;

	if (svs.abandon) {
		int count = 0;
		client_t *cl = NULL;
		while ((cl = SV_GetNextClient(cl)) != NULL)
			if (cl->state >= cs_connected)
				count++;
		if (count == 0)
			svs.killserver = true;
	}
}
Example #7
0
/**
 * @brief Search the index in the config strings relative to a given start
 * @param name The value of the config string to search the index for
 * @param start The relative start point for the search
 * @param max The max. searched entries in the config string before giving up
 * @param create if @c true the value will get written into the config strings (appended)
 * @return @c 0 if not found
 */
static unsigned int SV_FindIndex (const char *name, int start, int max, qboolean create)
{
	int i;

	if (!name || !name[0])
		return 0;

	for (i = 1; i < max && SV_GetConfigString(start + i)[0] != '\0'; i++) {
		const char *configString = SV_GetConfigString(start + i);
		if (Q_streq(configString, name))
			return i;
	}

	if (!create)
		return 0;

	if (i == max)
		Com_Error(ERR_DROP, "*Index: overflow '%s' start: %i, max: %i", name, start, max);

	SV_SetConfigString(start + i, name);

	if (Com_ServerState() != ss_loading) {	/* send the update to everyone */
		struct dbuffer *msg = new_dbuffer();
		NET_WriteByte(msg, svc_configstring);
		NET_WriteShort(msg, start + i);
		NET_WriteString(msg, name);
		SV_Multicast(~0, msg);
	}

	return i;
}
Example #8
0
/**
 * @brief Sets the @c cls.state to @c ca_disconnected and informs the server
 * @sa CL_Drop
 * @note Goes from a connected state to disconnected state
 * Sends a disconnect message to the server
 * This is also called on @c Com_Error, so it shouldn't cause any errors
 */
void CL_Disconnect (void)
{
	if (cls.state < ca_connecting)
		return;

	Com_Printf("Disconnecting...\n");

	/* send a disconnect message to the server */
	if (!Com_ServerState()) {
		dbuffer msg;
		NET_WriteByte(&msg, clc_stringcmd);
		NET_WriteString(&msg, NET_STATE_DISCONNECT "\n");
		NET_WriteMsg(cls.netStream, msg);
		/* make sure, that this is send */
		NET_Wait(0);
	}

	NET_StreamFinished(cls.netStream);
	cls.netStream = nullptr;

	CL_ClearState();

	S_Stop();

	R_ShutdownModels(false);
	R_FreeWorldImages();

	CL_SetClientState(ca_disconnected);
	CL_ClearBattlescapeEvents();
	GAME_EndBattlescape();
}
Example #9
0
/**
 * @brief Stores a team-list (chr-list) info to buffer (which might be a network buffer, too).
 * @sa G_ClientTeamInfo
 * @sa MP_SaveTeamMultiplayerInfo
 * @note Called in CL_Precache_f to send the team info to server
 */
static void GAME_SendCurrentTeamSpawningInfo (struct dbuffer * buf, chrList_t *team)
{
	int i;

	/* header */
	NET_WriteByte(buf, clc_teaminfo);
	NET_WriteByte(buf, team->num);

	Com_DPrintf(DEBUG_CLIENT, "GAME_SendCurrentTeamSpawningInfo: Upload information about %i soldiers to server\n", team->num);
	for (i = 0; i < team->num; i++) {
		character_t *chr = team->chr[i];

		GAME_NetSendCharacter(buf, chr);

		CL_NetSendInventory(buf, &chr->i);
	}
}
Example #10
0
/**
 * @brief Sends text across to be displayed if the level passes
 */
void SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...)
{
	if (level > cl->messagelevel)
		return;

	dbuffer msg;
	NET_WriteByte(&msg, svc_print);
	NET_WriteByte(&msg, level);

	va_list argptr;
	va_start(argptr, fmt);
	char str[MAX_SVC_PRINT];
	NET_VPrintf(&msg, fmt, argptr, str, sizeof(str));
	va_end(argptr);

	NET_WriteMsg(cl->stream, msg);
}
Example #11
0
/**
 * @brief Use this if the value might change and you need the position in the buffer
 * @note If someone aborts or adds an event, this pointer is of course no longer valid
 */
static byte* SV_WriteDummyByte (byte c)
{
	pending_event_t *p = &sv->pendingEvent;
	byte *pos = (byte*) p->buf->end;
	NET_WriteByte(p->buf, c);
	assert(pos != NULL);
	return pos;
}
Example #12
0
/**
 * @note EV_ACTOR_SHOOT is using WriteDir for writing the normal, but ReadByte
 * for reading it - keep that in mind when you change something here
 */
void NET_WriteDir (dbuffer* buf, const vec3_t dir)
{
    if (!dir) {
        NET_WriteByte(buf, 0);
        return;
    }

    float bestd = 0.0f;
    int best = 0;
    const size_t bytedirsLength = lengthof(bytedirs);
    for (int i = 0; i < bytedirsLength; i++) {
        const float d = DotProduct(dir, bytedirs[i]);
        if (d > bestd) {
            bestd = d;
            best = i;
        }
    }
    NET_WriteByte(buf, best);
}
Example #13
0
static void testDBufferNetHandling (void)
{
	dbuffer buf;
	NET_WriteByte(&buf, 'b');
	CU_ASSERT_EQUAL(1, buf.length());
	NET_WriteShort(&buf, 128);
	CU_ASSERT_EQUAL(3, buf.length());
	NET_WriteLong(&buf, 128);
	CU_ASSERT_EQUAL(7, buf.length());
}
Example #14
0
/**
 * @sa gi.AddEvent
 * @param[in] mask The player bitmask to send the events to. Use @c PM_ALL to send to every connected player.
 */
static void SV_AddEvent (unsigned int mask, int eType)
{
	pending_event_t *p = &sv->pendingEvent;
	Com_DPrintf(DEBUG_EVENTSYS, "Event type: %i (mask %i)\n", eType, mask);

	/* finish the last event */
	if (p->pending)
		SV_EndEvents();

	/* start the new event */
	p->pending = qtrue;
	p->playerMask = mask;
	p->type = eType;
	p->buf = new_dbuffer();

	/* write header */
	NET_WriteByte(p->buf, svc_event);
	NET_WriteByte(p->buf, eType);
}
Example #15
0
/**
 * @brief Sends text across to be displayed if the level passes
 */
void SV_ClientPrintf (client_t * cl, int level, const char *fmt, ...)
{
	va_list argptr;
	struct dbuffer *msg;
	char str[1024];

	if (level > cl->messagelevel)
		return;

	msg = new_dbuffer();
	NET_WriteByte(msg, svc_print);
	NET_WriteByte(msg, level);

	va_start(argptr, fmt);
	NET_VPrintf(msg, fmt, argptr, str, sizeof(str));
	va_end(argptr);

	NET_WriteMsg(cl->stream, msg);
}
Example #16
0
static void testEvents (void)
{
	const event_t events[] = {EV_RESET, EV_START, EV_ENDROUND, EV_ENDROUNDANNOUNCE};
	for (int i = 0; i < lengthof(events); i++) {
		dbuffer buf;
		NET_WriteByte(&buf, events[i]);
		CL_ParseEvent(&buf);
	}
	CU_ASSERT_EQUAL(CL_ClearBattlescapeEvents(), lengthof(events));
}
Example #17
0
/**
 * @brief Sends text to all active clients
 */
void SV_BroadcastPrintf (int level, const char *fmt, ...)
{
	va_list argptr;
	struct dbuffer *msg;
	client_t *cl;
	char str[1024];

	msg = new_dbuffer();
	NET_WriteByte(msg, svc_print);
	NET_WriteByte(msg, level);

	va_start(argptr, fmt);
	NET_VPrintf(msg, fmt, argptr, str, sizeof(str));
	va_end(argptr);

	/* echo to console */
	if (sv_dedicated->integer) {
		char copy[1024];
		int i;
		const int length = sizeof(copy) - 1;

		va_start(argptr, fmt);
		Q_vsnprintf(copy, sizeof(copy), fmt, argptr);
		va_end(argptr);

		/* mask off high bits */
		for (i = 0; i < length && copy[i]; i++)
			copy[i] = copy[i] & 127;
		copy[i] = '\0';
		Com_Printf("%s", copy);
	}

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL) {
		if (level > cl->messagelevel)
			continue;
		if (cl->state < cs_connected)
			continue;
		NET_WriteConstMsg(cl->stream, msg);
	}

	free_dbuffer(msg);
}
Example #18
0
/**
 * @brief Responds with teaminfo such as free team num
 * @sa CL_ParseTeamInfoMessage
 */
static void SVC_TeamInfo (struct net_stream* s)
{
    if (SVC_RateLimitAddress(*s)) {
        Com_DPrintf(DEBUG_SERVER, "SVC_TeamInfo: rate limit from %s exceeded, dropping request\n", NET_StreamToString(s));
        return;
    }

    /* Allow getinfo to be DoSed relatively easily, but prevent excess outbound bandwidth usage when being flooded inbound */
    if (SVC_RateLimit(&outboundLeakyBucket)) {
        Com_DPrintf(DEBUG_SERVER, "SVC_TeamInfo: rate limit exceeded, dropping request\n");
        return;
    }

    char infoGlobal[MAX_INFO_STRING] = "";
    Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_teamplay", Cvar_GetString("sv_teamplay"));
    Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxteams", Cvar_GetString("sv_maxteams"));
    Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxplayersperteam", Cvar_GetString("sv_maxplayersperteam"));

    dbuffer msg;
    NET_WriteByte(&msg, svc_oob);
    NET_WriteRawString(&msg, "teaminfo\n");
    NET_WriteString(&msg, infoGlobal);

    client_t* cl = nullptr;
    while ((cl = SV_GetNextClient(cl)) != nullptr) {
        if (cl->state < cs_connected)
            continue;
        char infoPlayer[MAX_INFO_STRING] = "";
        /* show players that already have a team with their teamnum */
        int teamId = svs.ge->ClientGetTeamNum(*cl->player);
        if (!teamId)
            teamId = TEAM_NO_ACTIVE;
        Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_team", teamId);
        Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_ready", svs.ge->ClientIsReady(cl->player));
        Info_SetValueForKey(infoPlayer, sizeof(infoPlayer), "cl_name", cl->name);
        NET_WriteString(&msg, infoPlayer);
    }

    NET_WriteByte(&msg, 0);

    NET_WriteMsg(s, msg);
}
Example #19
0
static void testDBufferNetHandling (void)
{
	dbuffer* buf = new_dbuffer();
	NET_WriteByte(buf, 'b');
	CU_ASSERT_EQUAL(1, dbuffer_len(buf));
	NET_WriteShort(buf, 128);
	CU_ASSERT_EQUAL(3, dbuffer_len(buf));
	NET_WriteLong(buf, 128);
	CU_ASSERT_EQUAL(7, dbuffer_len(buf));
	free_dbuffer(buf);
}
Example #20
0
/**
 * @brief Writes to buffer according to format; version without syntactic sugar
 * for variable arguments, to call it from other functions with variable arguments
 * @note short and char are promoted to int when passed to variadic functions!
 */
void NET_vWriteFormat (dbuffer* buf, const char* format, va_list ap)
{
    while (*format) {
        const char typeID = *format++;

        switch (typeID) {
        case 'c':
            NET_WriteChar(buf, va_arg(ap, int));
            break;
        case 'b':
            NET_WriteByte(buf, va_arg(ap, int));
            break;
        case 's':
            NET_WriteShort(buf, va_arg(ap, int));
            break;
        case 'l':
            NET_WriteLong(buf, va_arg(ap, int));
            break;
        case 'p':
            NET_WritePos(buf, va_arg(ap, float*));
            break;
        case 'g':
            NET_WriteGPos(buf, va_arg(ap, byte*));
            break;
        case 'd':
            NET_WriteDir(buf, va_arg(ap, float*));
            break;
        case 'a':
            /* NOTE: float is promoted to double through ... */
            NET_WriteAngle(buf, va_arg(ap, double));
            break;
        case '!':
            break;
        case '&':
            NET_WriteString(buf, va_arg(ap, char*));
            break;
        case '*': {
            const int n = va_arg(ap, int);
            const byte* p = va_arg(ap, byte*);
            NET_WriteShort(buf, n);
            for (int i = 0; i < n; i++)
                NET_WriteByte(buf, *p++);
            break;
        }
        default:
            Com_Error(ERR_DROP, "WriteFormat: Unknown type!");
        }
    }
    /* Too many arguments for the given format; too few cause crash above */
#ifdef PARANOID
    if (!ap)
        Com_Error(ERR_DROP, "WriteFormat: Too many arguments!");
#endif
}
Example #21
0
/**
 * @sa gi.EndEvents
 */
static void SV_EndEvents (void)
{
	pending_event_t *p = &sv->pendingEvent;

	if (!p->pending)
		return;

	NET_WriteByte(p->buf, EV_NULL);
	SV_Multicast(p->playerMask, p->buf);
	p->pending = qfalse;
	/* freed in SV_Multicast */
	p->buf = NULL;
}
Example #22
0
/**
 * @brief Used by SV_Shutdown to send a final message to all
 * connected clients before the server goes down.
 * @sa SV_Shutdown
 */
static void SV_FinalMessage (const char *message, bool reconnect)
{
	client_t *cl;
	dbuffer msg(2 + strlen(message));

	if (reconnect)
		NET_WriteByte(&msg, svc_reconnect);
	else
		NET_WriteByte(&msg, svc_disconnect);
	NET_WriteString(&msg, message);

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL)
		if (cl->state >= cs_connected) {
			NET_WriteConstMsg(cl->stream, msg);
			NET_StreamFinished(cl->stream);
			cl->stream = NULL;
		}

	/* make sure, that this is send */
	NET_Wait(0);
}
Example #23
0
/**
 * @sa gi.EndEvents
 */
static void SV_EndEvents (void)
{
	pending_event_t *p = &sv->pendingEvent;

	if (!p->pending)
		return;

	NET_WriteByte(p->buf, EV_NULL);
	SV_Multicast(p->playerMask, *p->buf);
	p->pending = false;
	delete p->buf;
	p->buf = NULL;
}
Example #24
0
/**
 * @sa SV_BroadcastCommand
 */
void SV_ClientCommand (client_t *client, const char *fmt, ...)
{
	va_list ap;
	char str[MAX_SVC_STUFFTEXT];
	dbuffer msg;

	NET_WriteByte(&msg, svc_stufftext);

	va_start(ap, fmt);
	NET_VPrintf(&msg, fmt, ap, str, sizeof(str));
	va_end(ap);

	NET_WriteMsg(client->stream, msg);
}
Example #25
0
/**
 * @sa SV_BroadcastCommand
 */
void SV_ClientCommand (client_t *client, const char *fmt, ...)
{
	va_list ap;
	char str[1024];
	struct dbuffer *msg = new_dbuffer();

	NET_WriteByte(msg, svc_stufftext);

	va_start(ap, fmt);
	NET_VPrintf(msg, fmt, ap, str, sizeof(str));
	va_end(ap);

	NET_WriteMsg(client->stream, msg);
}
Example #26
0
/**
 * @brief Send the userinfo to the server (and to all other clients)
 * when they changed (CVAR_USERINFO)
 * @sa CL_Connect
 */
static void CL_SendChangedUserinfos (void)
{
	/* send a userinfo update if needed */
	if (cls.state < ca_connected)
		return;
	if (!Com_IsUserinfoModified())
		return;
	char info[MAX_INFO_STRING];
	const char* userInfo = Cvar_Userinfo(info, sizeof(info));
	dbuffer msg(strlen(userInfo) + 2);
	NET_WriteByte(&msg, clc_userinfo);
	NET_WriteString(&msg, userInfo);
	NET_WriteMsg(cls.netStream, msg);
	Com_SetUserinfoModified(false);
}
Example #27
0
static void CL_ForwardToServer_f (void)
{
	if (cls.state != ca_connected && cls.state != ca_active) {
		Com_Printf("Can't \"%s\", not connected\n", Cmd_Argv(0));
		return;
	}

	/* don't forward the first argument */
	if (Cmd_Argc() > 1) {
		const int len = strlen(Cmd_Args()) + 1;
		dbuffer msg(len + 1);
		NET_WriteByte(&msg, clc_stringcmd);
		msg.add(Cmd_Args(), len);
		NET_WriteMsg(cls.netStream, msg);
	}
}
Example #28
0
/**
 * @brief Finishes the current turn of the player in battlescape and starts the turn for the next team.
 */
static void CL_NextRound_f (void)
{
	/* can't end round if we are not in battlescape */
	if (!CL_BattlescapeRunning())
		return;

	/* can't end round if we're not active */
	if (!cls.isOurRound()) {
		HUD_DisplayMessage(_("It is not your turn!"));
		return;
	}

	/* send endround */
	dbuffer msg;
	NET_WriteByte(&msg, clc_endround);
	NET_WriteMsg(cls.netStream, msg);
}
Example #29
0
/**
 * @brief Finishes the current round of the player in battlescape and starts the round for the next team.
 */
static void CL_NextRound_f (void)
{
	struct dbuffer *msg;
	/* can't end round if we are not in battlescape */
	if (!CL_BattlescapeRunning())
		return;

	/* can't end round if we're not active */
	if (cls.team != cl.actTeam) {
		HUD_DisplayMessage(_("This isn't your round"));
		return;
	}

	/* send endround */
	msg = new_dbuffer();
	NET_WriteByte(msg, clc_endround);
	NET_WriteMsg(cls.netStream, msg);
}
Example #30
0
/**
 * @brief Send the character information to the server that is needed to spawn the soldiers of the player.
 * @param[out] buf The net channel buffer to write the character data into.
 * @param[in] chr The character to get the data from.
 */
static void GAME_NetSendCharacter (struct dbuffer * buf, const character_t *chr)
{
	int j;

	if (!chr)
		Com_Error(ERR_DROP, "No character given");
	if (chr->fieldSize != ACTOR_SIZE_2x2 && chr->fieldSize != ACTOR_SIZE_NORMAL)
		Com_Error(ERR_DROP, "Invalid character size given for character '%s': %i",
				chr->name, chr->fieldSize);
	if (chr->teamDef == NULL)
		Com_Error(ERR_DROP, "Character with no teamdef set (%s)", chr->name);

	NET_WriteByte(buf, chr->fieldSize);
	NET_WriteShort(buf, chr->ucn);
	NET_WriteString(buf, chr->name);

	/* model */
	NET_WriteString(buf, chr->path);
	NET_WriteString(buf, chr->body);
	NET_WriteString(buf, chr->head);
	NET_WriteByte(buf, chr->skin);

	NET_WriteShort(buf, chr->HP);
	NET_WriteShort(buf, chr->maxHP);
	NET_WriteByte(buf, chr->teamDef->idx);
	NET_WriteByte(buf, chr->gender);
	NET_WriteByte(buf, chr->STUN);
	NET_WriteByte(buf, chr->morale);

	for (j = 0; j < SKILL_NUM_TYPES + 1; j++)
		NET_WriteLong(buf, chr->score.experience[j]);
	for (j = 0; j < SKILL_NUM_TYPES; j++)
		NET_WriteByte(buf, chr->score.skills[j]);
	for (j = 0; j < SKILL_NUM_TYPES + 1; j++)
		NET_WriteByte(buf, chr->score.initialSkills[j]);
	for (j = 0; j < KILLED_NUM_TYPES; j++)
		NET_WriteShort(buf, chr->score.kills[j]);
	for (j = 0; j < KILLED_NUM_TYPES; j++)
		NET_WriteShort(buf, chr->score.stuns[j]);
	NET_WriteShort(buf, chr->score.assignedMissions);
}