int Pickup_PersistantPowerup( gentity_t *ent, gentity_t *other ) { float handicap; int max; other->player->ps.stats[STAT_PERSISTANT_POWERUP] = BG_ItemNumForItem( ent->item ); other->player->persistantPowerup = ent; handicap = PlayerHandicap( other->player ); switch( ent->item->giTag ) { case PW_GUARD: max = (int)(2 * handicap); other->health = max; other->player->ps.stats[STAT_HEALTH] = max; other->player->ps.stats[STAT_MAX_HEALTH] = max; other->player->ps.stats[STAT_ARMOR] = max; other->player->pers.maxHealth = max; break; case PW_SCOUT: other->player->pers.maxHealth = handicap; other->player->ps.stats[STAT_ARMOR] = 0; break; case PW_AMMOREGEN: other->player->pers.maxHealth = handicap; memset(other->player->ammoTimes, 0, sizeof(other->player->ammoTimes)); break; case PW_DOUBLER: default: other->player->pers.maxHealth = handicap; break; } return -1; }
/* =========== PlayerUserinfoChanged Called from PlayerConnect when the player first connects and directly by the server system when the player updates a userinfo variable. The game can override any of the settings and call trap_SetUserinfo if desired. ============ */ void PlayerUserinfoChanged( int playerNum ) { gentity_t *ent; int teamTask, teamLeader; char *s; char model[MAX_QPATH]; char headModel[MAX_QPATH]; char oldname[MAX_STRING_CHARS]; gplayer_t *player; char c1[MAX_INFO_STRING]; char c2[MAX_INFO_STRING]; char userinfo[MAX_INFO_STRING]; ent = g_entities + playerNum; player = ent->player; trap_GetUserinfo( playerNum, userinfo, sizeof( userinfo ) ); // check for malformed or illegal info strings if ( !Info_Validate(userinfo) ) { strcpy (userinfo, "\\name\\badinfo"); // don't keep those players and userinfo trap_DropPlayer(playerNum, "Invalid userinfo"); } // check the item prediction s = Info_ValueForKey( userinfo, "cg_predictItems" ); if ( !atoi( s ) ) { player->pers.predictItemPickup = qfalse; } else { player->pers.predictItemPickup = qtrue; } // check the anti lag s = Info_ValueForKey( userinfo, "cg_antiLag" ); player->pers.antiLag = atoi( s ); // set name Q_strncpyz ( oldname, player->pers.netname, sizeof( oldname ) ); s = Info_ValueForKey (userinfo, "name"); PlayerCleanName( s, player->pers.netname, sizeof(player->pers.netname) ); if ( player->sess.sessionTeam == TEAM_SPECTATOR ) { if ( player->sess.spectatorState == SPECTATOR_SCOREBOARD ) { Q_strncpyz( player->pers.netname, "scoreboard", sizeof(player->pers.netname) ); } } if ( player->pers.connected == CON_CONNECTED ) { if ( strcmp( oldname, player->pers.netname ) ) { trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname, player->pers.netname) ); } } // set max health #ifdef MISSIONPACK if (player->ps.powerups[PW_GUARD]) { player->pers.maxHealth = 200; } else { player->pers.maxHealth = PlayerHandicap( player ); } #else player->pers.maxHealth = PlayerHandicap( player ); #endif player->ps.stats[STAT_MAX_HEALTH] = player->pers.maxHealth; // set model if( g_gametype.integer >= GT_TEAM ) { Q_strncpyz( model, Info_ValueForKey (userinfo, "team_model"), sizeof( model ) ); Q_strncpyz( headModel, Info_ValueForKey (userinfo, "team_headmodel"), sizeof( headModel ) ); } else { Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) ); Q_strncpyz( headModel, Info_ValueForKey (userinfo, "headmodel"), sizeof( headModel ) ); } #ifdef MISSIONPACK if (g_gametype.integer >= GT_TEAM) { player->pers.teamInfo = qtrue; } else { s = Info_ValueForKey( userinfo, "teamoverlay" ); if ( ! *s || atoi( s ) != 0 ) { player->pers.teamInfo = qtrue; } else { player->pers.teamInfo = qfalse; } } #else // teamInfo s = Info_ValueForKey( userinfo, "teamoverlay" ); if ( ! *s || atoi( s ) != 0 ) { player->pers.teamInfo = qtrue; } else { player->pers.teamInfo = qfalse; } #endif /* s = Info_ValueForKey( userinfo, "cg_pmove_fixed" ); if ( !*s || atoi( s ) == 0 ) { player->pers.pmoveFixed = qfalse; } else { player->pers.pmoveFixed = qtrue; } */ // team task (0 = none, 1 = offence, 2 = defence) teamTask = atoi(Info_ValueForKey(userinfo, "teamtask")); // team Leader (1 = leader, 0 is normal player) teamLeader = player->sess.teamLeader; // colors strcpy(c1, Info_ValueForKey( userinfo, "color1" )); strcpy(c2, Info_ValueForKey( userinfo, "color2" )); // send over a subset of the userinfo keys so other clients can // print scoreboards, display models, and play custom sounds if (ent->r.svFlags & SVF_BOT) { s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d", player->pers.netname, player->sess.sessionTeam, model, headModel, c1, c2, player->pers.maxHealth, player->sess.wins, player->sess.losses, Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader ); } else { s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d", player->pers.netname, player->sess.sessionTeam, model, headModel, c1, c2, player->pers.maxHealth, player->sess.wins, player->sess.losses, teamTask, teamLeader); } trap_SetConfigstring( CS_PLAYERS+playerNum, s ); // this is not the userinfo, more like the configstring actually G_LogPrintf( "PlayerUserinfoChanged: %i %s\n", playerNum, s ); }
/* =========== PlayerSpawn Called every time a player is placed fresh in the world: after the first PlayerBegin, and after each respawn Initializes all non-persistant parts of playerState ============ */ void PlayerSpawn(gentity_t *ent) { int index; vec3_t spawn_origin, spawn_angles; gplayer_t *player; int i; playerPersistant_t saved; playerSession_t savedSess; int persistant[MAX_PERSISTANT]; gentity_t *spawnPoint; gentity_t *tent; int flags; int savedPing; // char *savedAreaBits; int accuracy_hits, accuracy_shots; int eventSequence; int startWeapon, startAmmo; index = ent - g_entities; player = ent->player; VectorClear(spawn_origin); // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this player if ( player->sess.sessionTeam == TEAM_SPECTATOR ) { spawnPoint = SelectSpectatorSpawnPoint ( spawn_origin, spawn_angles); } else if (g_gametype.integer >= GT_CTF ) { // all base oriented team games use the CTF spawn points spawnPoint = SelectCTFSpawnPoint ( player->sess.sessionTeam, player->pers.teamState.state, spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT)); } else { // the first spawn should be at a good looking spot if ( player->pers.initialSpawn && player->pers.localClient ) { spawnPoint = SelectInitialSpawnPoint(spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT)); } else { // don't spawn near existing origin if possible spawnPoint = SelectSpawnPoint ( player->ps.origin, spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT)); } } player->pers.teamState.state = TEAM_ACTIVE; // always clear the kamikaze flag ent->s.eFlags &= ~EF_KAMIKAZE; // toggle the teleport bit so the client knows to not lerp // and never clear the voted flag flags = ent->player->ps.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED); flags ^= EF_TELEPORT_BIT; // clear everything but the persistant data saved = player->pers; savedSess = player->sess; savedPing = player->ps.ping; // savedAreaBits = player->areabits; accuracy_hits = player->accuracy_hits; accuracy_shots = player->accuracy_shots; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { persistant[i] = player->ps.persistant[i]; } eventSequence = player->ps.eventSequence; Com_Memset (player, 0, sizeof(*player)); player->pers = saved; player->sess = savedSess; player->ps.ping = savedPing; // player->areabits = savedAreaBits; player->accuracy_hits = accuracy_hits; player->accuracy_shots = accuracy_shots; player->lastkilled_player = -1; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { player->ps.persistant[i] = persistant[i]; } player->ps.eventSequence = eventSequence; // increment the spawncount so the client will detect the respawn player->ps.persistant[PERS_SPAWN_COUNT]++; player->ps.persistant[PERS_TEAM] = player->sess.sessionTeam; player->airOutTime = level.time + 12000; // set max health player->pers.maxHealth = PlayerHandicap( player ); // clear entity values player->ps.stats[STAT_MAX_HEALTH] = player->pers.maxHealth; player->ps.eFlags = flags; player->ps.contents = CONTENTS_BODY; player->ps.collisionType = ( g_playerCapsule.integer == 1 ) ? CT_CAPSULE : CT_AABB; ent->s.groundEntityNum = ENTITYNUM_NONE; ent->player = &level.players[index]; ent->takedamage = qtrue; ent->inuse = qtrue; ent->classname = "player"; ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags = 0; ent->player->headless = qfalse; VectorCopy (playerMins, player->ps.mins); VectorCopy (playerMaxs, player->ps.maxs); player->ps.playerNum = index; if ( g_instaGib.integer == 1 ) { startWeapon = WP_RAILGUN; startAmmo = 50; } else if ( g_instaGib.integer == 2 ) { startWeapon = WP_ROCKET_LAUNCHER; startAmmo = 50; } else { startWeapon = WP_MACHINEGUN; startAmmo = 100; } player->ps.stats[STAT_WEAPONS] = ( 1 << startWeapon ); player->ps.ammo[startWeapon] = startAmmo; player->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET ); player->ps.ammo[WP_GAUNTLET] = -1; player->ps.ammo[WP_GRAPPLING_HOOK] = -1; // health will count down towards max_health ent->health = player->ps.stats[STAT_HEALTH] = player->ps.stats[STAT_MAX_HEALTH] = MAX_HEALTH; G_SetOrigin( ent, spawn_origin ); VectorCopy( spawn_origin, player->ps.origin ); // the respawned flag will be cleared after the attack and jump keys come up player->ps.pm_flags |= PMF_RESPAWNED; trap_GetUsercmd( player - level.players, &ent->player->pers.cmd ); SetPlayerViewAngle( ent, spawn_angles ); // don't allow full run speed for a bit player->ps.pm_flags |= PMF_TIME_KNOCKBACK; player->ps.pm_time = 100; player->respawnTime = level.time; player->inactivityTime = level.time + g_inactivity.integer * 1000; player->latched_buttons = 0; // set default animations player->ps.torsoAnim = TORSO_STAND; player->ps.legsAnim = LEGS_IDLE; if (!level.intermissiontime) { if (ent->player->sess.sessionTeam != TEAM_SPECTATOR) { G_KillBox(ent); // force the base weapon up player->ps.weapon = startWeapon; player->ps.weaponstate = WEAPON_READY; // fire the targets of the spawn point G_UseTargets(spawnPoint, ent); // select the highest weapon number available, after any spawn given items have fired player->ps.weapon = 1; for (i = WP_NUM_WEAPONS - 1 ; i > 0 ; i--) { if (player->ps.stats[STAT_WEAPONS] & (1 << i)) { player->ps.weapon = i; break; } } // positively link the player, even if the command times are weird VectorCopy(ent->player->ps.origin, ent->r.currentOrigin); tent = G_TempEntity(ent->player->ps.origin, EV_PLAYER_TELEPORT_IN); tent->s.playerNum = ent->s.playerNum; trap_LinkEntity (ent); } } else { // move players to intermission MovePlayerToIntermission(ent); } // run a player frame to drop exactly to the floor, // initialize animations and other things player->ps.commandTime = level.time - 100; ent->player->pers.cmd.serverTime = level.time; PlayerThink( ent-g_entities ); // run the presend to set anything else, follow spectators wait // until all players have been reconnected after map_restart if ( ent->player->sess.spectatorState != SPECTATOR_FOLLOW ) { PlayerEndFrame( ent ); } // clear entity state values BG_PlayerStateToEntityState( &player->ps, &ent->s, qtrue ); // we don't want players being backward-reconciled to the place they died G_ResetHistory( ent ); }