Пример #1
0
/*
==============
ClientThink

This will be called once for each client frame, which will
usually be a couple times for each server frame on fast clients.

If "g_synchronousClients 1" is set, this will be called exactly
once for each server frame, which makes for smooth demo recording.
==============
*/
void ClientThink_real(gentity_t *ent) {
	int       msec, oldEventSequence;
	pmove_t   pm;
	usercmd_t *ucmd;
	gclient_t *client = ent->client;

	// don't think if the client is not yet connected (and thus not yet spawned in)
	if (client->pers.connected != CON_CONNECTED) {
		return;
	}

	if (ent->s.eFlags & EF_MOUNTEDTANK) {
		client->pmext.centerangles[YAW]   = ent->tagParent->r.currentAngles[YAW];
		client->pmext.centerangles[PITCH] = ent->tagParent->r.currentAngles[PITCH];
	}

	// mark the time, so the connection sprite can be removed
	ucmd = &ent->client->pers.cmd;

	ent->client->ps.identifyClient = ucmd->identClient;     // NERVE - SMF

	// sanity check the command time to prevent speedup cheating
	if (ucmd->serverTime > level.time + 200) {
		ucmd->serverTime = level.time + 200;
	}
	if (ucmd->serverTime < level.time - 1000) {
		ucmd->serverTime = level.time - 1000;
	}

	msec = ucmd->serverTime - client->ps.commandTime;
	// following others may result in bad times, but we still want
	// to check for follow toggles
	if (msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW) {
		return;
	}
	if (msec > 200) {
		msec = 200;
	}

	// Nico, pmove_fixed
	if (client->pers.pmoveFixed) {
		ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer - 1) / pmove_msec.integer) * pmove_msec.integer;
	}

	if (client->wantsscore) {
		G_SendScore(ent);
		client->wantsscore = qfalse;
	}

	// check for inactivity timer, but never drop the local client of a non-dedicated server
	// OSP - moved here to allow for spec inactivity checks as well
	if (!ClientInactivityTimer(client)) {
		return;
	}

	if (!(ucmd->flags & 0x01) || ucmd->forwardmove || ucmd->rightmove || ucmd->upmove || ucmd->wbuttons || ucmd->doubleTap) {
		ent->r.svFlags &= ~(SVF_SELF_PORTAL_EXCLUSIVE | SVF_SELF_PORTAL);
	}

	// spectators don't do much
	// DHM - Nerve :: In limbo use SpectatorThink
	if (client->sess.sessionTeam == TEAM_SPECTATOR || client->ps.pm_flags & PMF_LIMBO) {
		SpectatorThink(ent, ucmd);
		return;
	}

	if (client->ps.eFlags & EF_VIEWING_CAMERA) {
		ucmd->buttons     = 0;
		ucmd->forwardmove = 0;
		ucmd->rightmove   = 0;
		ucmd->upmove      = 0;
		ucmd->wbuttons    = 0;
		ucmd->doubleTap   = 0;

		// freeze player
		client->ps.pm_type = PM_FREEZE;
	} else if (client->noclip) {
		client->ps.pm_type = PM_NOCLIP;
	} else if (client->ps.stats[STAT_HEALTH] <= 0) {
		client->ps.pm_type = PM_DEAD;
	} else {
		client->ps.pm_type = PM_NORMAL;
	}

	client->ps.aiState = AISTATE_COMBAT;
	client->ps.gravity = DEFAULT_GRAVITY;
	client->ps.speed   = DEFAULT_SPEED;

	if (client->speedScale) {                // Goalitem speed scale
		client->ps.speed *= (client->speedScale * 0.01);
	}

	// set up for pmove
	oldEventSequence = client->ps.eventSequence;

	client->currentAimSpreadScale = (float)client->ps.aimSpreadScale / 255.0;

	memset(&pm, 0, sizeof (pm));

	pm.ps        = &client->ps;
	pm.pmext     = &client->pmext;
	pm.character = client->pers.character;
	pm.cmd       = *ucmd;
	pm.oldcmd    = client->pers.oldcmd;
	// MrE: always use capsule for AI and player
	pm.trace = trap_TraceCapsule;

	// Nico, ghost players
	pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
	if (pm.ps->pm_type == PM_DEAD) {
		pm.ps->eFlags |= EF_DEAD;
	} else if (pm.ps->pm_type == PM_SPECTATOR) {
		pm.trace = trap_TraceCapsuleNoEnts;
	}
	// Nico, end of ghost players

	//DHM - Nerve :: We've gone back to using normal bbox traces
	pm.pointcontents = trap_PointContents;
	pm.debugLevel    = g_debugMove.integer;
	pm.noFootsteps   = qfalse;

	// Nico, pmove_fixed
	// pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;
	pm.pmove_fixed = client->pers.pmoveFixed;
	pm.pmove_msec  = pmove_msec.integer;

	// Nico, game physics
	pm.physics = physics.integer;

	pm.isTimerun        = isTimerun.integer;
	pm.timerunActive    = client->sess.timerunActive;
	pm.timerunStartTime = client->sess.timerunStartTime + 500;

	// Nico, store logins status in pmove
	if (client->sess.logged) {
		pm.isLogged = 1;
	} else {
		pm.isLogged = 0;
	}

	pm.noWeapClips = qfalse;

	VectorCopy(client->ps.origin, client->oldOrigin);

	// NERVE - SMF
	pm.ltChargeTime       = level.lieutenantChargeTime[client->sess.sessionTeam - 1];
	pm.soldierChargeTime  = level.soldierChargeTime[client->sess.sessionTeam - 1];
	pm.engineerChargeTime = level.engineerChargeTime[client->sess.sessionTeam - 1];
	pm.medicChargeTime    = level.medicChargeTime[client->sess.sessionTeam - 1];
	// -NERVE - SMF

	client->pmext.airleft = ent->client->airOutTime - level.time;

	pm.covertopsChargeTime = level.covertopsChargeTime[client->sess.sessionTeam - 1];

	// Gordon: bit hacky, stop the slight lag from client -> server even on locahost, switching back to the weapon you were holding
	//			and then back to what weapon you should have, became VERY noticible for the kar98/carbine + gpg40, esp now i've added the
	//			animation locking
	if (level.time - client->pers.lastSpawnTime < 1000) {
		pm.cmd.weapon = client->ps.weapon;
	}

	Pmove(&pm);

	// Gordon: thx to bani for this
	// ikkyo - fix leaning players bug
	VectorCopy(client->ps.velocity, ent->s.pos.trDelta);
	SnapVector(ent->s.pos.trDelta);
	// end

	// server cursor hints
	if (ent->lastHintCheckTime < level.time) {
		G_CheckForCursorHints(ent);

		ent->lastHintCheckTime = level.time + FRAMETIME;
	}

	// DHM - Nerve :: Set animMovetype to 1 if ducking
	if (ent->client->ps.pm_flags & PMF_DUCKED) {
		ent->s.animMovetype = 1;
	} else {
		ent->s.animMovetype = 0;
	}

	// save results of pmove
	if (ent->client->ps.eventSequence != oldEventSequence) {
		ent->eventTime   = level.time;
		ent->r.eventTime = level.time;
	}

	// Ridah, fixes jittery zombie movement
	if (g_smoothClients.integer) {
		BG_PlayerStateToEntityStateExtraPolate(&ent->client->ps, &ent->s, level.time, qfalse);
	} else {
		BG_PlayerStateToEntityState(&ent->client->ps, &ent->s, qfalse);
	}

	if (!(ent->client->ps.eFlags & EF_FIRING)) {
		client->fireHeld = qfalse;      // for grapple
	}

//	// use the snapped origin for linking so it matches client predicted versions
	VectorCopy(ent->s.pos.trBase, ent->r.currentOrigin);

	VectorCopy(pm.mins, ent->r.mins);
	VectorCopy(pm.maxs, ent->r.maxs);

	ent->waterlevel = pm.waterlevel;
	ent->watertype  = pm.watertype;

	// execute client events
	ClientEvents(ent, oldEventSequence);

	// link entity now, after any personal teleporters have been used
	trap_LinkEntity(ent);
	if (!ent->client->noclip) {
		G_TouchTriggers(ent);
	}

	// NOTE: now copy the exact origin over otherwise clients can be snapped into solid
	VectorCopy(ent->client->ps.origin, ent->r.currentOrigin);

	// touch other objects
	ClientImpacts(ent, &pm);

	// save results of triggers and client events
	if (ent->client->ps.eventSequence != oldEventSequence) {
		ent->eventTime = level.time;
	}

	// swap and latch button actions
	client->oldbuttons      = client->buttons;
	client->buttons         = ucmd->buttons;
	client->latched_buttons = client->buttons & ~client->oldbuttons;

	//----(SA)	added
	client->oldwbuttons      = client->wbuttons;
	client->wbuttons         = ucmd->wbuttons;
	client->latched_wbuttons = client->wbuttons & ~client->oldwbuttons;

	// Rafael - Activate
	// Ridah, made it a latched event (occurs on keydown only)
	if (client->latched_buttons & BUTTON_ACTIVATE) {
		Cmd_Activate_f(ent);
	}

	if (g_entities[ent->client->ps.identifyClient].team != ent->team ||
	    !g_entities[ent->client->ps.identifyClient].client) {
		ent->client->ps.identifyClient = -1;
	}

	// check for respawning
	if (client->ps.stats[STAT_HEALTH] <= 0) {
		// Nico, forcing respawn
		limbo(ent);

		return;
	}

	// perform once-a-second actions
	ClientTimerActions(ent, msec);

	// Nico, check ping
	if (client->sess.timerunActive && client->ps.ping > MAX_PLAYER_PING) {
		CP(va("cpm \"%s^w: ^1too high ping detected, timerun stopped\n\"", GAME_VERSION_COLORED));
		// Nico, notify the client and its spectators the timerun has stopped
		notify_timerun_stop(ent, 0);
		client->sess.timerunActive = qfalse;
	}

	// Nico, pmove_fixed
	if (!client->pers.pmoveFixed) {
		CP(va("cpm \"%s^w: ^1you were removed from teams because you can not use pmove_fixed 0\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "pmoveon");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, check rate
	if (client->pers.rate < MIN_PLAYER_RATE_VALUE || client->pers.rate > MAX_PLAYER_RATE_VALUE) {
		CP(va("cpm \"%s^w: ^1you were removed from teams because you must use %d <= rate <= %d\n\"", GAME_VERSION_COLORED, MIN_PLAYER_RATE_VALUE, MAX_PLAYER_RATE_VALUE));
		trap_SendServerCommand(ent - g_entities, "resetRate");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, check snaps (unsigned int)
	if (client->pers.snaps > MAX_PLAYER_SNAPS_VALUE) {
		CP(va("cpm \"%s^w: ^1you were removed from teams because you must use %d <= snaps <= %d\n\"", GAME_VERSION_COLORED, MIN_PLAYER_SNAPS_VALUE, MAX_PLAYER_SNAPS_VALUE));
		trap_SendServerCommand(ent - g_entities, "resetSnaps");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, check timenudge
	if (client->pers.clientTimeNudge != FORCED_PLAYER_TIMENUDGE_VALUE) {
		CP(va("cpm \"%s^w: ^1you were removed from teams because you must use cl_timenudge %d\n\"", GAME_VERSION_COLORED, FORCED_PLAYER_TIMENUDGE_VALUE));
		trap_SendServerCommand(ent - g_entities, "resetTimeNudge");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, check maxpackets
	if (client->pers.clientMaxPackets < MIN_PLAYER_MAX_PACKETS_VALUE || client->pers.clientMaxPackets > MAX_PLAYER_MAX_PACKETS_VALUE) {
		CP(va("cpm \"%s^w: ^1you were removed from teams because you must use %d <= cl_maxpackets <= %d\n\"", GAME_VERSION_COLORED, MIN_PLAYER_MAX_PACKETS_VALUE, MAX_PLAYER_MAX_PACKETS_VALUE));
		trap_SendServerCommand(ent - g_entities, "resetMaxPackets");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, check max FPS
	if (client->pers.maxFPS < MIN_PLAYER_FPS_VALUE || client->pers.maxFPS > MAX_PLAYER_FPS_VALUE) {
		CP(va("cpm \"%s^w: ^1you were removed from teams because you must use %d <= com_maxfps <= %d\n\"", GAME_VERSION_COLORED, MIN_PLAYER_FPS_VALUE, MAX_PLAYER_FPS_VALUE));
		trap_SendServerCommand(ent - g_entities, "resetMaxFPS");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, force auto demo record in cup mode
	if (g_cupMode.integer != 0 && client->pers.autoDemo == 0) {
		CP(va("cpm \"%s^w: ^1you were removed from teams because you must use cg_autoDemo 1\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "autoDemoOn");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, force hide me in cup mode
	if (g_cupMode.integer != 0 && client->pers.hideme == 0) {
		CP(va("cpm \"%s^w: ^1you were removed from teams because you must use cg_hideMe 1\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "hideMeOn");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, force CGaz 0 in cup mode
	if (g_cupMode.integer != 0 && client->pers.cgaz != 0) {
		CP(va("cpm \"%s^w: ^1you were removed from teams because you must use cg_drawCGaz 0\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "CGazOff");
		SetTeam(ent, "s", -1, -1, qfalse);
	}
}
Пример #2
0
/* QUAKED target_stopTimer (1 0 0) (-8 -8 -8) (8 8 8)
 * timer stop
 *
 * "name"				timerun name
 * "minCheckpoints"		minimal passed checkpoints to activate this stoptimer
 */
void target_stoptimer_use(gentity_t *self, gentity_t *other, gentity_t *activator) {
	int       time;
	gclient_t *client = activator->client;
	int       timerunNum;

	// Nico, silent GCC
	(void)other;

	if (!client->sess.timerunActive) {
		return;
	}

	// don't stop the time if this isn't a corresponding stoptimer
	if (Q_stricmp(self->timerunName, client->sess.currentTimerun)) {
		return;
	}

	timerunNum = client->sess.currentTimerunNum;

	// required number of checkpoints passed?
	if (client->sess.timerunCheckpointsPassed < self->count) {
		CPx(activator - g_entities, va("cpm \"^d%s^f:^1 Minimum checkpoints not passed (%d/%d)\n\"", client->sess.currentTimerun, client->sess.timerunCheckpointsPassed, self->count));
		notify_timerun_stop(activator, 0);
		client->sess.timerunActive = qfalse;

		return;
	}

	time = client->sess.timerunLastTime[timerunNum] = client->ps.commandTime - client->sess.timerunStartTime;

	if (!client->sess.timerunBestTime[timerunNum] || time < client->sess.timerunBestTime[timerunNum]) {
		// best personal for this session
		if (client->sess.logged) {
			client->sess.timerunBestTime[timerunNum] = time;

			// Nico, update best speed of run
			client->sess.timerunBestSpeed[timerunNum] = client->sess.maxSpeed;

			// Nico, set score so that xfire can see it (only if cup mode is DISABLED)
			if (g_cupMode.integer != 1) {
				client->ps.persistant[PERS_SCORE] = client->sess.timerunLastTime[timerunNum];
			}
		}

		// CP are updated here if API is not used or if CP were note loaded
		if (!g_useAPI.integer || client->sess.timerunCheckpointWereLoaded[timerunNum] == 0) {
			memcpy(client->sess.timerunBestCheckpointTimes[timerunNum], client->sess.timerunCheckpointTimes, sizeof (client->sess.timerunCheckpointTimes));
		}
	}

	// Nico, stop speed
	client->sess.stopSpeed = (int)sqrt(client->ps.velocity[0] * client->ps.velocity[0] + client->ps.velocity[1] * client->ps.velocity[1]);

	// Nico, send record if needed
	if (g_useAPI.integer && client->sess.logged) {
		Cmd_SendRecord_f(activator, client->sess.currentTimerun, client->pers.authToken,
		                 time, client->sess.startSpeed, client->sess.stopSpeed, client->sess.maxSpeed,
		                 client->ps.identifyClientHealth, // Nico, this is used as a jumps counter
		                 client->pers.ip, client->pers.maxFPS,
		                 client->pers.clientTimeNudge, client->pers.rate, client->pers.clientMaxPackets, client->pers.snaps,
		                 g_strictSaveLoad.integer, g_disableDrowning.integer, g_holdDoorsOpen.integer, g_enableMapEntities.integer);
	} else {
		// Nico, API is not used and/or client is not logged,
		// we cannnot know if his last time his SB/PB or something
		// else. So we keep his last demo.
		saveDemo(activator);
	}

	// Nico, notify the client and its spectators the timerun has stopped
	notify_timerun_stop(activator, client->sess.timerunLastTime[timerunNum]);

	client->sess.timerunActive = qfalse;
}
Пример #3
0
/*
===========
ClientSpawn

Called every time a client is placed fresh in the world:
after the first ClientBegin, and after each respawn
Initializes all non-persistant parts of playerState
============
*/
void ClientSpawn(gentity_t *ent) {
	int                index;
	vec3_t             spawn_origin, spawn_angles;
	gclient_t          *client;
	int                i;
	clientPersistant_t saved;
	clientSession_t    savedSess;
	int                persistant[MAX_PERSISTANT];
	gentity_t          *spawnPoint;
	int                flags;
	int                savedPing;
	int                savedTeam;
	qboolean           update = qfalse;
	save_position_t    *pos   = NULL;

	index  = ent - g_entities;
	client = ent->client;

	G_UpdateSpawnCounts();

	client->pers.lastSpawnTime = level.time;

	if (client->sess.sessionTeam != TEAM_AXIS && client->sess.sessionTeam != TEAM_ALLIES) {
		spawnPoint = SelectSpectatorSpawnPoint(spawn_origin, spawn_angles);
	} else {
		spawnPoint = SelectPlayerSpawnPoint(client->sess.sessionTeam, spawn_origin, spawn_angles, client->sess.spawnObjectiveIndex);
	}

	client->pers.teamState.state = TEAM_ACTIVE;

	// toggle the teleport bit so the client knows to not lerp
	flags  = ent->client->ps.eFlags & EF_TELEPORT_BIT;
	flags ^= EF_TELEPORT_BIT;
	flags |= (client->ps.eFlags & EF_VOTED);
	// clear everything but the persistant data

	ent->s.eFlags &= ~EF_MOUNTEDTANK;

	// Nico, notify timerun_stop
	notify_timerun_stop(ent, 0);
	ent->client->sess.timerunActive = qfalse;

	saved     = client->pers;
	savedSess = client->sess;
	savedPing = client->ps.ping;
	savedTeam = client->ps.teamNum;

	for (i = 0 ; i < MAX_PERSISTANT ; i++) {
		persistant[i] = client->ps.persistant[i];
	}

	memset(client, 0, sizeof (*client));

	client->pers       = saved;
	client->sess       = savedSess;
	client->ps.ping    = savedPing;
	client->ps.teamNum = savedTeam;

	for (i = 0 ; i < MAX_PERSISTANT ; i++) {
		client->ps.persistant[i] = persistant[i];
	}

	// increment the spawncount so the client will detect the respawn

	client->ps.persistant[PERS_SPAWN_COUNT]++;

	client->ps.persistant[PERS_TEAM]        = client->sess.sessionTeam;
	client->ps.persistant[PERS_HWEAPON_USE] = 0;

	client->airOutTime = level.time + 12000;

	// clear entity values
	client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
	client->ps.eFlags                 = flags;

	ent->s.groundEntityNum = ENTITYNUM_NONE;
	ent->client            = &level.clients[index];
	ent->takedamage        = qtrue;
	ent->inuse             = qtrue;
	ent->classname = "player";
	ent->r.contents = CONTENTS_BODY;
	ent->clipmask = MASK_PLAYERSOLID;

	// DHM - Nerve :: Init to -1 on first spawn;
	ent->props_frame_state = -1;

	ent->die        = player_die;
	ent->waterlevel = 0;
	ent->watertype  = 0;
	ent->flags      = 0;

	VectorCopy(playerMins, ent->r.mins);
	VectorCopy(playerMaxs, ent->r.maxs);

	// Ridah, setup the bounding boxes and viewheights for prediction
	VectorCopy(ent->r.mins, client->ps.mins);
	VectorCopy(ent->r.maxs, client->ps.maxs);

	client->ps.crouchViewHeight = CROUCH_VIEWHEIGHT;
	client->ps.standViewHeight  = DEFAULT_VIEWHEIGHT;
	client->ps.deadViewHeight   = DEAD_VIEWHEIGHT;

	client->ps.crouchMaxZ = client->ps.maxs[2] - (client->ps.standViewHeight - client->ps.crouchViewHeight);

	client->ps.runSpeedScale    = 0.8;
	client->ps.sprintSpeedScale = 1.1;
	client->ps.crouchSpeedScale = 0.25;
	client->ps.weaponstate      = WEAPON_READY;

	// Rafael

	client->ps.friction = 1.0;
	// done.

	// TTimo
	// retrieve from the persistant storage (we use this in pmoveExt_t beause we need it in bg_*)
	client->pmext.bAutoReload = client->pers.bAutoReloadAux;
	// done

	client->ps.clientNum = index;

	trap_GetUsercmd(client - level.clients, &ent->client->pers.cmd);    // NERVE - SMF - moved this up here

	if (client->sess.playerType != client->sess.latchPlayerType) {
		update = qtrue;
	}

	client->sess.playerType = client->sess.latchPlayerType;

	if (client->sess.playerWeapon != client->sess.latchPlayerWeapon) {
		client->sess.playerWeapon = client->sess.latchPlayerWeapon;
		update                    = qtrue;
	}

	client->sess.playerWeapon2 = client->sess.latchPlayerWeapon2;

	if (update) {
		ClientUserinfoChanged(index);
	}

	G_UpdateCharacter(client);

	SetWolfSpawnWeapons(client);

	client->pers.maxHealth = 125;
	client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;

	client->pers.cmd.weapon = ent->client->ps.weapon;
// dhm - end

	ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH];

	G_SetOrigin(ent, spawn_origin);
	VectorCopy(spawn_origin, client->ps.origin);

	// the respawned flag will be cleared after the attack and jump keys come up
	client->ps.pm_flags |= PMF_RESPAWNED;

	SetClientViewAngle(ent, spawn_angles);

	if (ent->client->sess.sessionTeam != TEAM_SPECTATOR) {
		trap_LinkEntity(ent);
	}

	client->inactivityTime   = level.time + g_inactivity.integer * 1000;
	client->latched_buttons  = 0;
	client->latched_wbuttons = 0;   //----(SA)	added

	// fire the targets of the spawn point
	G_UseTargets(spawnPoint, ent);

	// run a client frame to drop exactly to the floor,
	// initialize animations and other things
	client->ps.commandTime           = level.time - 100;
	ent->client->pers.cmd.serverTime = level.time;
	ClientThink(ent - g_entities);

	// positively link the client, even if the command times are weird
	if (ent->client->sess.sessionTeam != TEAM_SPECTATOR) {
		BG_PlayerStateToEntityState(&client->ps, &ent->s, qtrue);
		VectorCopy(ent->client->ps.origin, ent->r.currentOrigin);
		trap_LinkEntity(ent);
	}

	// run the presend to set anything else
	ClientEndFrame(ent);

	// set idle animation on weapon
	ent->client->ps.weapAnim = ((ent->client->ps.weapAnim & ANIM_TOGGLEBIT) ^ ANIM_TOGGLEBIT) | PM_IdleAnimForWeapon(ent->client->ps.weapon);

	// clear entity state values
	BG_PlayerStateToEntityState(&client->ps, &ent->s, qtrue);

	// show_bug.cgi?id=569
	G_ResetMarkers(ent);

	// RF, start the scripting system
	if (client->sess.sessionTeam != TEAM_SPECTATOR) {

		// RF, call entity scripting event
		G_Script_ScriptEvent(ent, "playerstart", "");
	}

	// Nico, autoload position
	if (ent->client->pers.autoLoad && !ent->client->sess.lastDieWasASelfkill && (ent->client->sess.sessionTeam == TEAM_AXIS || ent->client->sess.sessionTeam == TEAM_ALLIES)) {
		if (ent->client->sess.sessionTeam == TEAM_ALLIES) {
			pos = ent->client->sess.alliesSaves;
		} else {
			pos = ent->client->sess.axisSaves;
		}

		if (pos->valid) {
			VectorCopy(pos->origin, ent->client->ps.origin);

			// Nico, load angles if cg_loadViewAngles = 1
			if (ent->client->pers.loadViewAngles) {
				SetClientViewAngle(ent, pos->vangles);
			}

			// Nico, load saved weapon if cg_loadWeapon = 1
			if (ent->client->pers.loadWeapon) {
				ent->client->ps.weapon = pos->weapon;
			}

			VectorClear(ent->client->ps.velocity);

			if (ent->client->ps.stats[STAT_HEALTH] < 100 && ent->client->ps.stats[STAT_HEALTH] > 0) {
				ent->health = 100;
			}
		}
	}
}