/* =============== GLimp_EndFrame Responsible for doing a swapbuffers =============== */ void GLimp_EndFrame( void ) { // don't flip if drawing to front buffer if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 ) { SDL_GL_SwapWindow( window ); } /*if( r_minimize && r_minimize->integer ) { extern qboolean fullscreen_minimized; extern void IN_DeactivateMouse( void ); SDL_Surface *s = SDL_GetWindowSurface( window );//SDL_GetVideoSurface( ); qboolean fullscreen = qfalse; qboolean minimized = qfalse; fullscreen = ( s && ( s->flags & SDL_WINDOW_FULLSCREEN ) ); #ifdef MACOS_X // this is a bit crap, but the mac SDL_WM_IconifyWindow does not work // on fullscreen windows, nor does the SDL_WM_ToggleFullscreen work if( !fullscreen ) { if( SDL_WM_IconifyWindow( ) ) IN_DeactivateMouse(); Cvar_Set( "r_minimize", "0" ); } else if( r_fullscreen->integer ) { Cvar_Set( "r_fullscreen", "0" ); fullscreen_minimized = qtrue; } #else minimized = ( SDL_WM_IconifyWindow( ) != 0 ); if( fullscreen && minimized ) fullscreen_minimized = qtrue; // this shouldn't be necessary, but seems to prevent X11 mouse problems if( minimized ) IN_DeactivateMouse(); Cvar_Set( "r_minimize", "0" ); #endif // MACOS_X }*/ /* if( r_fullscreen->modified ) { qboolean fullscreen; qboolean needToToggle = qtrue; qboolean sdlToggled = qfalse; SDL_Surface *s = SDL_GetWindowSurface( window ); if( s ) { // Find out the current state fullscreen = !!( s->flags & SDL_WINDOW_FULLSCREEN ); if( r_fullscreen->integer && Cvar_VariableIntegerValue( "in_nograb" ) ) { ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n"); ri.Cvar_Set( "r_fullscreen", "0" ); r_fullscreen->modified = qfalse; } // Is the state we want different from the current state? needToToggle = !!r_fullscreen->integer != fullscreen; if( needToToggle ) { if( r_fullscreen->integer ) { sdlToggled = SDL_SetWindowFullscreen( window, SDL_WINDOW_FULLSCREEN ); } else { sdlToggled = SDL_SetWindowFullscreen( window, 0 ); } if( sdlToggled == 0 ) { sdlToggled = 1; } } } if( needToToggle ) { // SDL_WM_ToggleFullScreen didn't work, so do it the slow way if( !sdlToggled ) Cbuf_AddText( "vid_restart" ); IN_Restart( ); } r_fullscreen->modified = qfalse; }*/ }
static void WP_FireConcussionAlt( gentity_t *ent ) {//a rail-gun-like beam int damage = weaponData[WP_CONCUSSION].altDamage, skip, traces = DISRUPTOR_ALT_TRACES; //int velocity = weaponData[WP_CONCUSSION].altVelocity; qboolean render_impact = qtrue; vec3_t start, end; vec3_t muzzle2, spot, dir; trace_t tr; gentity_t *traceEnt, *tent; float dist, shotDist, shotRange = 8192; qboolean hitDodged = qfalse; if (ent->s.number >= MAX_CLIENTS) { vec3_t angles; vectoangles(forwardVec, angles); angles[PITCH] += ( Q_flrand(-1.0f, 1.0f) * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f angles[YAW] += ( Q_flrand(-1.0f, 1.0f) * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f AngleVectors(angles, forwardVec, vrightVec, up); } //Shove us backwards for half a second VectorMA( ent->client->ps.velocity, -200, forwardVec, ent->client->ps.velocity ); ent->client->ps.groundEntityNum = ENTITYNUM_NONE; if ( (ent->client->ps.pm_flags&PMF_DUCKED) ) {//hunkered down ent->client->ps.pm_time = 100; } else { ent->client->ps.pm_time = 250; } ent->client->ps.pm_flags |= PMF_TIME_KNOCKBACK|PMF_TIME_NOFRICTION; //FIXME: only if on ground? So no "rocket jump"? Or: (see next FIXME) //FIXME: instead, set a forced ucmd backmove instead of this sliding VectorCopy( muzzle, muzzle2 ); // making a backup copy // The trace start will originate at the eye so we can ensure that it hits the crosshair. if ( ent->NPC ) { switch ( g_spskill->integer ) { case 0: damage = CONC_ALT_NPC_DAMAGE_EASY; break; case 1: damage = CONC_ALT_NPC_DAMAGE_MEDIUM; break; case 2: default: damage = CONC_ALT_NPC_DAMAGE_HARD; break; } damage *= weaponData[WP_CONCUSSION].npcAltDmgMult; } VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin ); skip = ent->s.number; // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // damage *= 2; // } //Make it a little easier to hit guys at long range vec3_t shot_mins, shot_maxs; VectorSet( shot_mins, -1, -1, -1 ); VectorSet( shot_maxs, 1, 1, 1 ); for ( int i = 0; i < traces; i++ ) { VectorMA( start, shotRange, forwardVec, end ); //NOTE: if you want to be able to hit guys in emplaced guns, use "G2_COLLIDE, 10" instead of "G2_RETURNONHIT, 0" //alternately, if you end up hitting an emplaced_gun that has a sitter, just redo this one trace with the "G2_COLLIDE, 10" to see if we it the sitter //gi.trace( &tr, start, NULL, NULL, end, skip, MASK_SHOT, G2_COLLIDE, 10 );//G2_RETURNONHIT, 0 ); gi.trace( &tr, start, shot_mins, shot_maxs, end, skip, MASK_SHOT, G2_COLLIDE, 10 );//G2_RETURNONHIT, 0 ); if ( tr.surfaceFlags & SURF_NOIMPACT ) { render_impact = qfalse; } if ( tr.entityNum == ent->s.number ) { // should never happen, but basically we don't want to consider a hit to ourselves? // Get ready for an attempt to trace through another person VectorCopy( tr.endpos, muzzle2 ); VectorCopy( tr.endpos, start ); skip = tr.entityNum; #ifdef _DEBUG gi.Printf( "BAD! Concussion gun shot somehow traced back and hit the owner!\n" ); #endif continue; } // always render a shot beam, doing this the old way because I don't much feel like overriding the effect. //NOTE: let's just draw one beam at the end //tent = G_TempEntity( tr.endpos, EV_CONC_ALT_SHOT ); //tent->svFlags |= SVF_BROADCAST; //VectorCopy( muzzle2, tent->s.origin2 ); if ( tr.fraction >= 1.0f ) { // draw the beam but don't do anything else break; } traceEnt = &g_entities[tr.entityNum]; if ( traceEnt //&& traceEnt->NPC && (traceEnt->s.weapon == WP_SABER || (traceEnt->client && (traceEnt->client->NPC_class == CLASS_BOBAFETT || traceEnt->client->NPC_class == CLASS_MANDA || traceEnt->client->NPC_class == CLASS_COMMANDO||traceEnt->client->NPC_class == CLASS_REBORN)))) {//FIXME: need a more reliable way to know we hit a jedi? hitDodged = Jedi_DodgeEvasion( traceEnt, ent, &tr, HL_NONE ); //acts like we didn't even hit him } if ( !hitDodged ) { if ( render_impact ) { if (( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage ) || !Q_stricmp( traceEnt->classname, "misc_model_breakable" ) || traceEnt->s.eType == ET_MOVER ) { // Create a simple impact type mark that doesn't last long in the world G_PlayEffect( G_EffectIndex( "concussion/alt_hit" ), tr.endpos, tr.plane.normal ); if ( traceEnt->client && LogAccuracyHit( traceEnt, ent )) {//NOTE: hitting multiple ents can still get you over 100% accuracy ent->client->ps.persistant[PERS_ACCURACY_HITS]++; } int hitLoc = G_GetHitLocFromTrace( &tr, MOD_CONC_ALT ); qboolean noKnockBack = (qboolean)((traceEnt->flags&FL_NO_KNOCKBACK) != 0);//will be set if they die, I want to know if it was on *before* they died if ( traceEnt && traceEnt->client && traceEnt->client->NPC_class == CLASS_GALAKMECH ) {//hehe G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, 10, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_CONC_ALT, hitLoc ); break; } G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, damage, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_CONC_ALT, hitLoc ); //do knockback and knockdown manually if ( traceEnt->client ) {//only if we hit a client vec3_t pushDir; VectorCopy( forwardVec, pushDir ); if ( pushDir[2] < 0.2f ) { pushDir[2] = 0.2f; }//hmm, re-normalize? nah... //if ( traceEnt->NPC || Q_irand(0,g_spskill->integer+1) ) { if ( !noKnockBack ) {//knock-backable G_Throw( traceEnt, pushDir, 200 ); if ( traceEnt->client->NPC_class == CLASS_ROCKETTROOPER ) { traceEnt->client->ps.pm_time = Q_irand( 1500, 3000 ); } } if ( traceEnt->health > 0 ) {//alive if ( G_HasKnockdownAnims( traceEnt ) ) {//knock-downable G_Knockdown( traceEnt, ent, pushDir, 400, qtrue ); } } } } if ( traceEnt->s.eType == ET_MOVER ) {//stop the traces on any mover break; } } else { // we only make this mark on things that can't break or move tent = G_TempEntity( tr.endpos, EV_CONC_ALT_MISS ); tent->svFlags |= SVF_BROADCAST; VectorCopy( tr.plane.normal, tent->pos1 ); break; // hit solid, but doesn't take damage, so stop the shot...we _could_ allow it to shoot through walls, might be cool? } } else // not rendering impact, must be a skybox or other similar thing? { break; // don't try anymore traces } } // Get ready for an attempt to trace through another person VectorCopy( tr.endpos, muzzle2 ); VectorCopy( tr.endpos, start ); skip = tr.entityNum; hitDodged = qfalse; } //just draw one beam all the way to the end tent = G_TempEntity( tr.endpos, EV_CONC_ALT_SHOT ); tent->svFlags |= SVF_BROADCAST; VectorCopy( muzzle, tent->s.origin2 ); // now go along the trail and make sight events VectorSubtract( tr.endpos, muzzle, dir ); shotDist = VectorNormalize( dir ); //FIXME: if shoot *really* close to someone, the alert could be way out of their FOV for ( dist = 0; dist < shotDist; dist += 64 ) { //FIXME: on a really long shot, this could make a LOT of alerts in one frame... VectorMA( muzzle, dist, dir, spot ); AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 ); //FIXME: creates *way* too many effects, make it one effect somehow? G_PlayEffect( G_EffectIndex( "concussion/alt_ring" ), spot, forwardVec ); } //FIXME: spawn a temp ent that continuously spawns sight alerts here? And 1 sound alert to draw their attention? VectorMA( start, shotDist-4, forwardVec, spot ); AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 ); G_PlayEffect( G_EffectIndex( "concussion/altmuzzle_flash" ), muzzle, forwardVec ); }
static race_t TranslateRaceName( const char *name ) { if ( !Q_stricmp( name, "human" ) ) { return RACE_HUMAN; } if ( !Q_stricmp( name, "borg" ) ) { return RACE_BORG; } if ( !Q_stricmp( name, "parasite" ) ) { return RACE_PARASITE; } if ( !Q_stricmp( name, "klingon" ) ) { return RACE_KLINGON; } if ( !Q_stricmp( name, "malon" ) ) { return RACE_MALON; } if ( !Q_stricmp( name, "hirogen" ) ) { return RACE_HIROGEN; } if ( !Q_stricmp( name, "stasis" ) ) { return RACE_STASIS; } if ( !Q_stricmp( name, "species8472" ) ) { return RACE_8472; } if ( !Q_stricmp( name, "dreadnought" ) ) { return RACE_BOT; } if ( !Q_stricmp( name, "harvester" ) || !Q_stricmp( name, "biohulk" ) ) { return RACE_HARVESTER; } if ( !Q_stricmp( name, "reaver" ) ) { return RACE_REAVER; } if ( !Q_stricmp( name, "avatar" ) ) { return RACE_AVATAR; } if ( !Q_stricmp( name, "vulcan" ) ) { return RACE_VULCAN; } if ( !Q_stricmp( name, "betazoid" ) ) { return RACE_BETAZOID; } if ( !Q_stricmp( name, "bolian" ) ) { return RACE_BOLIAN; } if ( !Q_stricmp( name, "talaxian" ) ) { return RACE_TALAXIAN; } if ( !Q_stricmp( name, "bajoran" ) ) { return RACE_BAJORAN; } if ( !Q_stricmp( name, "hologram" ) ) { return RACE_HOLOGRAM; } return RACE_NONE; }
/* ================== SV_Map_f Restart the server on a different map ================== */ static void SV_Map_f( void ) { char *cmd; char *map; qboolean killBots, cheat; char expanded[MAX_QPATH]; char mapname[MAX_QPATH]; map = Cmd_Argv(1); if ( !map ) { return; } // make sure the level exists before trying to change, so that // a typo at the server console won't end the game Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map); if ( FS_ReadFile (expanded, NULL) == -1 ) { Com_Printf ("Can't find map %s\n", expanded); return; } // force latched values to get set Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH ); cmd = Cmd_Argv(0); if ( Q_stricmpn( cmd, "sp", 2 ) == 0 ) { Cvar_SetValue( "g_gametype", GT_SINGLE_PLAYER ); Cvar_SetValue( "g_doWarmup", 0 ); // may not set sv_maxclients directly, always set latched Cvar_SetLatched( "sv_maxclients", "8" ); cmd += 2; cheat = qfalse; killBots = qtrue; } else { if ( !Q_stricmp( cmd, "devmap" ) || !Q_stricmp( cmd, "spdevmap" ) ) { cheat = qtrue; killBots = qtrue; } else { cheat = qfalse; killBots = qfalse; } if( sv_gametype->integer == GT_SINGLE_PLAYER ) { Cvar_SetValue( "g_gametype", GT_FFA ); } } // save the map name here cause on a map restart we reload the q3config.cfg // and thus nuke the arguments of the map command Q_strncpyz(mapname, map, sizeof(mapname)); // start up the map SV_SpawnServer( mapname, killBots ); // set the cheat value // if the level was started with "map <levelname>", then // cheats will not be allowed. If started with "devmap <levelname>" // then cheats will be allowed if ( cheat ) { Cvar_Set( "sv_cheats", "1" ); } else { Cvar_Set( "sv_cheats", "0" ); } }
//G_MissileImpact now returns qfalse if and only if the player physically dodged the damage. //this allows G_RunMissile to properly handle he qboolean G_MissileImpact( gentity_t *ent, trace_t *trace ) { //void G_MissileImpact( gentity_t *ent, trace_t *trace ) { //[/DodgeSys] gentity_t *other; qboolean isKnockedSaber = qfalse; //[DodgeSys] int missileDmg; //[/DodgeSys] other = &g_entities[trace->entityNum]; // check for bounce //[WeaponSys] //allow thermals to bounce off players and such. if ( (!other->takedamage || ent->s.weapon == WP_THERMAL) && //if ( !other->takedamage && //[/WeaponSys] (ent->bounceCount > 0 || ent->bounceCount == -5) && ( ent->flags & ( FL_BOUNCE | FL_BOUNCE_HALF ) ) ) { G_BounceMissile( ent, trace ); G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 ); //[DodgeSys] return qtrue; //return; //[/DodgeSys] } else if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF)) { //this is a knocked-away saber if (ent->bounceCount > 0 || ent->bounceCount == -5) { G_BounceMissile( ent, trace ); G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 ); //[DodgeSys] return qtrue; //return; //[/DodgeSys] } isKnockedSaber = qtrue; } // I would glom onto the FL_BOUNCE code section above, but don't feel like risking breaking something else if (/* (!other->takedamage && (ent->bounceCount > 0 || ent->bounceCount == -5) && ( ent->flags&(FL_BOUNCE_SHRAPNEL) ) ) ||*/ ((trace->surfaceFlags&SURF_FORCEFIELD)&&!ent->splashDamage&&!ent->splashRadius&&(ent->bounceCount > 0 || ent->bounceCount == -5)) ) { G_BounceMissile( ent, trace ); if ( ent->bounceCount < 1 ) { ent->flags &= ~FL_BOUNCE_SHRAPNEL; } //[DodgeSys] return qtrue; //return; //[/DodgeSys] } if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber) { //hit this person's saber, so.. gentity_t *otherOwner = &g_entities[other->r.ownerNum]; if (otherOwner->takedamage && otherOwner->client && otherOwner->client->ps.duelInProgress && otherOwner->client->ps.duelIndex != ent->r.ownerNum) { goto killProj; } } else if (!isKnockedSaber) { if (other->takedamage && other->client && other->client->ps.duelInProgress && other->client->ps.duelIndex != ent->r.ownerNum) { goto killProj; } } if (other->flags & FL_DMG_BY_HEAVY_WEAP_ONLY) { if (ent->methodOfDeath != MOD_REPEATER_ALT && ent->methodOfDeath != MOD_ROCKET && ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH && ent->methodOfDeath != MOD_ROCKET_HOMING && ent->methodOfDeath != MOD_THERMAL && ent->methodOfDeath != MOD_THERMAL_SPLASH && ent->methodOfDeath != MOD_TRIP_MINE_SPLASH && ent->methodOfDeath != MOD_TIMED_MINE_SPLASH && ent->methodOfDeath != MOD_DET_PACK_SPLASH && ent->methodOfDeath != MOD_VEHICLE && ent->methodOfDeath != MOD_CONC && ent->methodOfDeath != MOD_CONC_ALT && ent->methodOfDeath != MOD_SABER && //[Asteroids] ent->methodOfDeath != MOD_TURBLAST && ent->methodOfDeath != MOD_TARGET_LASER) //[/Asteroids] { vec3_t fwd; if (trace) { VectorCopy(trace->plane.normal, fwd); } else { //oh well AngleVectors(other->r.currentAngles, fwd, NULL, NULL); } G_DeflectMissile(other, ent, fwd); G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd); //[DodgeSys] return qtrue; //return; //[/DodgeSys] } } //ROP VEHICLE_IMP START if((other->s.NPC_class == CLASS_VEHICLE && other->m_pVehicle && !other->m_pVehicle->m_pVehicleInfo->AllWeaponsDoDamageToShields && other->client->ps.stats[STAT_ARMOR] > 0) || other->flags & FL_SHIELDED) { if (ent->s.weapon != WP_ROCKET_LAUNCHER && ent->s.weapon != WP_THERMAL && ent->s.weapon != WP_GRENADE && ent->s.weapon != WP_DET_PACK && ent->s.weapon != WP_DEMP2 && ent->s.weapon != WP_EMPLACED_GUN && ent->s.weapon != WP_TURRET && ent->methodOfDeath != MOD_REPEATER_ALT && ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH && ent->methodOfDeath != MOD_TURBLAST && ent->methodOfDeath != MOD_VEHICLE && ent->methodOfDeath != MOD_CONC && ent->methodOfDeath != MOD_CONC_ALT && !(ent->dflags&DAMAGE_HEAVY_WEAP_CLASS) ) { vec3_t fwd; if (other->client) { AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL); } else { AngleVectors(other->r.currentAngles, fwd, NULL, NULL); } G_DeflectMissile(other, ent, fwd); G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd); //[DodgeSys] return qtrue; //return; //[/DodgeSys] } } //ROP VEHICLE_IMP END //[BoltBlockSys] if (OJP_SaberCanBlock(other, ent, qfalse, trace->endpos, -1, -1)) //[/BoltBlockSys] { //only block one projectile per 200ms (to prevent giant swarms of projectiles being blocked) //[BoltBlockSys] //racc - missile hit the actual player and it's a type of missile that you can deflect/ref with the saber. //racc - play projectile block animation other->client->ps.weaponTime = 0; WP_SaberBlockNonRandom(other, ent->r.currentOrigin, qtrue); OJP_HandleBoltBlock(ent, other, trace); //[DodgeSys] return qtrue; //return; //[/DodgeSys] //[/BoltBlockSys] } else if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber) { //hit this person's saber, so.. gentity_t *otherOwner = &g_entities[other->r.ownerNum]; if (otherOwner->takedamage && otherOwner->client && ent->s.weapon != WP_TUSKEN_RIFLE && ent->s.weapon != WP_ROCKET_LAUNCHER && ent->s.weapon != WP_THERMAL && ent->s.weapon != WP_GRENADE && ent->s.weapon != WP_DET_PACK && //[BoltBlockSys] //ent->s.weapon != WP_DEMP2 && //[BoltBlockSys] ent->methodOfDeath != MOD_REPEATER_ALT && ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH && ent->methodOfDeath != MOD_CONC && ent->methodOfDeath != MOD_CONC_ALT /*&& otherOwner->client->ps.saberBlockTime < level.time*/) { //for now still deflect even if saberBlockTime >= level.time because it hit the actual saber //in this case, deflect it even if we can't actually block it because it hit our saber //WP_SaberCanBlock(otherOwner, ent->r.currentOrigin, 0, 0, qtrue, 0); if ((otherOwner->client && !BG_SaberInAttack(otherOwner->client->ps.saberMove)) || (otherOwner->client && (pm->cmd.buttons & BUTTON_FORCEPOWER || pm->cmd.buttons & BUTTON_FORCEGRIP || pm->cmd.buttons & BUTTON_FORCE_LIGHTNING) )) { //racc - play projectile block animation even in . otherOwner->client->ps.weaponTime = 0; WP_SaberBlockNonRandom(otherOwner, ent->r.currentOrigin, qtrue); } //[BoltBlockSys] OJP_HandleBoltBlock(ent, otherOwner, trace); //[/BoltBlockSys] //[DodgeSys] return qtrue; //return; //[/DodgeSys] } } // check for sticking //[SaberThrowSys] if ( !other->takedamage && ( ent->s.eFlags & EF_MISSILE_STICK ) && ent->s.weapon != WP_SABER) //if ( !other->takedamage && ( ent->s.eFlags & EF_MISSILE_STICK ) ) //[/SaberThrowSys] { laserTrapStick( ent, trace->endpos, trace->plane.normal ); G_AddEvent( ent, EV_MISSILE_STICK, 0 ); //[DodgeSys] return qtrue; //return; //[/DodgeSys] } // impact damage if (other->takedamage && !isKnockedSaber) { //[DodgeSys] //make players be able to dodge projectiles. missileDmg = ent->damage; if(G_DoDodge(other, &g_entities[ent->r.ownerNum], trace->endpos, -1, &missileDmg, ent->methodOfDeath)) { //player dodged the damage, have missile continue moving. if(ent->s.weapon == WP_ROCKET_LAUNCHER) ent->genericValue1 = 0; return qfalse; } //[/DodgeSys] // FIXME: wrong damage direction? //[DodgeSys] if ( missileDmg ) { //if ( ent->damage ) { //[/DodgeSys] vec3_t velocity; qboolean didDmg = qfalse; BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity ); if ( VectorLength( velocity ) == 0 ) { velocity[2] = 1; // stepped on a grenade } if (ent->s.weapon == WP_BOWCASTER || ent->s.weapon == WP_FLECHETTE || ent->s.weapon == WP_ROCKET_LAUNCHER) { if (ent->s.weapon == WP_FLECHETTE && (ent->s.eFlags & EF_ALT_FIRING)) { ent->think(ent); } else { G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity, //[DodgeSys] ent->r.currentOrigin, missileDmg, //[/DodgeSys] DAMAGE_HALF_ABSORB, ent->methodOfDeath); didDmg = qtrue; } } else { gentity_t *owner = &g_entities[ent->r.ownerNum]; float distance = VectorDistance(owner->r.currentOrigin,other->r.currentOrigin); if(distance <= 100.0f) { G_Damage (other, ent, owner, velocity, //[DodgeSys] ent->r.currentOrigin, missileDmg * 2, //[/DodgeSys] 0, ent->methodOfDeath); } else if (distance <= 300.0f) { G_Damage (other, ent, owner, velocity, //[DodgeSys] ent->r.currentOrigin, missileDmg * 1.5, //[/DodgeSys] 0, ent->methodOfDeath); } else { G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity, //[DodgeSys] ent->r.currentOrigin, missileDmg, //[/DodgeSys] 0, ent->methodOfDeath); } didDmg = qtrue; } if (didDmg && other && other->client) { //What I'm wondering is why this isn't in the NPC pain funcs. But this is what SP does, so whatever. class_t npc_class = other->client->NPC_class; // If we are a robot and we aren't currently doing the full body electricity... if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE || npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 || npc_class == CLASS_REMOTE || npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || //npc_class == CLASS_PROTOCOL ||//no protocol, looks odd npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY ) { // special droid only behaviors if ( other->client->ps.electrifyTime < level.time + 100 ) { // ... do the effect for a split second for some more feedback other->client->ps.electrifyTime = level.time + 450; } //FIXME: throw some sparks off droids,too } } } if ( ent->s.weapon == WP_DEMP2 ) { //a hit with demp2 decloaks people, disables ships if ( other && other->client && other->client->NPC_class == CLASS_VEHICLE ) { //hit a vehicle if ( other->m_pVehicle //valid vehicle ent && other->m_pVehicle->m_pVehicleInfo//valid stats && (other->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER//always affect speeders ||(other->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER && ent->classname && Q_stricmp("vehicle_proj", ent->classname ) == 0) )//only vehicle ion weapons affect a fighter in this manner && !FighterIsLanded( other->m_pVehicle , &other->client->ps )//not landed && !(other->spawnflags&2) )//and not suspended { //vehicles hit by "ion cannons" lose control if ( other->client->ps.electrifyTime > level.time ) { //add onto it //FIXME: extern the length of the "out of control" time? other->client->ps.electrifyTime += Q_irand(200,500); if ( other->client->ps.electrifyTime > level.time + 4000 ) { //cap it other->client->ps.electrifyTime = level.time + 4000; } } else { //start it //FIXME: extern the length of the "out of control" time? other->client->ps.electrifyTime = level.time + Q_irand(200,500); } } } else if ( other && other->client && other->client->ps.powerups[PW_CLOAKED] ) { Jedi_Decloak( other ); if ( ent->methodOfDeath == MOD_DEMP2_ALT ) { //direct hit with alt disables cloak forever //permanently disable the saboteur's cloak other->client->cloakToggleTime = Q3_INFINITE; } else { //temp disable other->client->cloakToggleTime = level.time + Q_irand( 3000, 10000 ); } } } } killProj: // is it cheaper in bandwidth to just remove this ent and create a new // one, rather than changing the missile into the explosion? if ( other->takedamage && other->client && !isKnockedSaber ) { G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) ); ent->s.otherEntityNum = other->s.number; } else if( trace->surfaceFlags & SURF_METALSTEPS ) { G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) ); } else if (ent->s.weapon != G2_MODEL_PART && !isKnockedSaber) { G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) ); } if (!isKnockedSaber) { ent->freeAfterEvent = qtrue; // change over to a normal entity right at the point of impact ent->s.eType = ET_GENERAL; } SnapVectorTowards( trace->endpos, ent->s.pos.trBase ); // save net bandwidth G_SetOrigin( ent, trace->endpos ); ent->takedamage = qfalse; // splash damage (doesn't apply to person directly hit) if ( ent->splashDamage ) { G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, other, ent, ent->splashMethodOfDeath ); } if (ent->s.weapon == G2_MODEL_PART) { ent->freeAfterEvent = qfalse; //it will free itself } trap_LinkEntity( ent ); //[DodgeSys] return qtrue; //[/DodgeSys] }
/* ============ Cmd_CompleteArgument ============ */ void Cmd_CompleteArgument( const char *command, char *args, int argNum ) { for ( cmd_function_t *cmd=cmd_functions; cmd; cmd=cmd->next ) { if ( !Q_stricmp( command, cmd->name ) && cmd->complete ) cmd->complete( args, argNum ); } }
static void Svcmd_Kick_f( void ) { gclient_t *cl; int i; int timeout = -1; char sTimeout[MAX_TOKEN_CHARS]; char name[MAX_TOKEN_CHARS]; // make sure server is running if ( !G_Is_SV_Running() ) { G_Printf( "Server is not running.\n" ); return; } if ( trap_Argc() < 2 || trap_Argc() > 3 ) { G_Printf ("Usage: kick <player name> [timeout]\n"); return; } if( trap_Argc() == 3 ) { trap_Argv( 2, sTimeout, sizeof( sTimeout ) ); timeout = atoi( sTimeout ); } else { timeout = 300; } trap_Argv(1, name, sizeof(name)); cl = G_GetPlayerByName( name );//ClientForString( name ); if ( !cl ) { if ( !Q_stricmp(name, "all") ) { for (i = 0, cl = level.clients; i < level.numConnectedClients; i++, cl++) { // dont kick localclients ... if ( cl->pers.localClient ) { continue; } if ( timeout != -1 ) { char *ip; char userinfo[MAX_INFO_STRING]; trap_GetUserinfo( cl - level.clients, userinfo, sizeof( userinfo ) ); ip = Info_ValueForKey (userinfo, "ip"); // use engine banning system, mods may choose to use their own banlist if (USE_ENGINE_BANLIST) { // kick but dont ban bots, they arent that lame if ( (g_entities[cl - level.clients].r.svFlags & SVF_BOT) ) { timeout = 0; } trap_DropClient(cl - level.clients, "player kicked", timeout); } else { trap_DropClient(cl - level.clients, "player kicked", 0); // kick but dont ban bots, they arent that lame if ( !(g_entities[cl - level.clients].r.svFlags & SVF_BOT) ) AddIPBan( ip ); } } else { trap_DropClient(cl - level.clients, "player kicked", 0); } } } else if ( !Q_stricmp(name, "allbots") ) { for (i = 0, cl = level.clients; i < level.numConnectedClients; i++, cl++) { if ( !(g_entities[cl - level.clients].r.svFlags & SVF_BOT) ) { continue; } // kick but dont ban bots, they arent that lame trap_DropClient(cl - level.clients, "player kicked", 0); } } return; } else { // dont kick localclients ... if ( cl->pers.localClient ) { G_Printf("Cannot kick host player\n"); return; } if ( timeout != -1 ) { char *ip; char userinfo[MAX_INFO_STRING]; trap_GetUserinfo( cl - level.clients, userinfo, sizeof( userinfo ) ); ip = Info_ValueForKey (userinfo, "ip"); // use engine banning system, mods may choose to use their own banlist if (USE_ENGINE_BANLIST) { // kick but dont ban bots, they arent that lame if ( (g_entities[cl - level.clients].r.svFlags & SVF_BOT) ) { timeout = 0; } trap_DropClient(cl - level.clients, "player kicked", timeout); } else { trap_DropClient(cl - level.clients, "player kicked", 0); // kick but dont ban bots, they arent that lame if ( !(g_entities[cl - level.clients].r.svFlags & SVF_BOT) ) AddIPBan( ip ); } } else { trap_DropClient(cl - level.clients, "player kicked", 0); } } }
/* * Give items to a client */ void Cmd_Give_f(edict_t *ent) { char *name; gitem_t *it; int index; int i; qboolean give_all; edict_t *it_ent; if (!ent) { return; } if ((deathmatch->value || coop->value) && !sv_cheats->value) { gi.cprintf( ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n"); return; } name = gi.args(); if (Q_stricmp(name, "all") == 0) { give_all = true; } else { give_all = false; } if (give_all || (Q_stricmp(gi.argv(1), "health") == 0)) { if (gi.argc() == 3) { ent->health = (int)strtol(gi.argv(2), (char **)NULL, 10); } else { ent->health = ent->max_health; } if (!give_all) { return; } } if (give_all || (Q_stricmp(name, "weapons") == 0)) { for (i = 0; i < game.num_items; i++) { it = itemlist + i; if (!it->pickup) { continue; } if (!(it->flags & IT_WEAPON)) { continue; } ent->client->pers.inventory[i] += 1; } if (!give_all) { return; } } if (give_all || (Q_stricmp(name, "ammo") == 0)) { for (i = 0; i < game.num_items; i++) { it = itemlist + i; if (!it->pickup) { continue; } if (!(it->flags & IT_AMMO)) { continue; } Add_Ammo(ent, it, 1000); } if (!give_all) { return; } } if (give_all || (Q_stricmp(name, "armor") == 0)) { gitem_armor_t *info; it = FindItem("Jacket Armor"); ent->client->pers.inventory[ITEM_INDEX(it)] = 0; it = FindItem("Combat Armor"); ent->client->pers.inventory[ITEM_INDEX(it)] = 0; it = FindItem("Body Armor"); info = (gitem_armor_t *)it->info; ent->client->pers.inventory[ITEM_INDEX(it)] = info->max_count; if (!give_all) { return; } } if (give_all || (Q_stricmp(name, "Power Shield") == 0)) { it = FindItem("Power Shield"); it_ent = G_Spawn(); it_ent->classname = it->classname; SpawnItem(it_ent, it); Touch_Item(it_ent, ent, NULL, NULL); if (it_ent->inuse) { G_FreeEdict(it_ent); } if (!give_all) { return; } } if (give_all) { for (i = 0; i < game.num_items; i++) { it = itemlist + i; if (!it->pickup) { continue; } if (it->flags & (IT_ARMOR | IT_WEAPON | IT_AMMO)) { continue; } ent->client->pers.inventory[i] = 1; } return; } it = FindItem(name); if (!it) { name = gi.argv(1); it = FindItem(name); if (!it) { gi.cprintf(ent, PRINT_HIGH, "unknown item\n"); return; } } if (!it->pickup) { gi.cprintf(ent, PRINT_HIGH, "non-pickup item\n"); return; } index = ITEM_INDEX(it); if (it->flags & IT_AMMO) { if (gi.argc() == 3) { ent->client->pers.inventory[index] = (int)strtol(gi.argv(2), (char **)NULL, 10); } else { ent->client->pers.inventory[index] += it->quantity; } } else { it_ent = G_Spawn(); it_ent->classname = it->classname; SpawnItem(it_ent, it); Touch_Item(it_ent, ent, NULL, NULL); if (it_ent->inuse) { G_FreeEdict(it_ent); } } }
// finds all trigger_multiples linked to asw_objective_escape entities void CASW_Spawn_Manager::FindEscapeTriggers() { m_EscapeTriggers.Purge(); // go through all escape objectives CBaseEntity* pEntity = NULL; while ( (pEntity = gEntList.FindEntityByClassname( pEntity, "asw_objective_escape" )) != NULL ) { CASW_Objective_Escape* pObjective = dynamic_cast<CASW_Objective_Escape*>(pEntity); if ( !pObjective ) continue; const char *pszEscapeTargetName = STRING( pObjective->GetEntityName() ); CBaseEntity* pOtherEntity = NULL; while ( (pOtherEntity = gEntList.FindEntityByClassname( pOtherEntity, "trigger_multiple" )) != NULL ) { CTriggerMultiple *pTrigger = dynamic_cast<CTriggerMultiple*>( pOtherEntity ); if ( !pTrigger ) continue; bool bAdded = false; CBaseEntityOutput *pOutput = pTrigger->FindNamedOutput( "OnTrigger" ); if ( pOutput ) { CEventAction *pAction = pOutput->GetFirstAction(); while ( pAction ) { if ( !Q_stricmp( STRING( pAction->m_iTarget ), pszEscapeTargetName ) ) { bAdded = true; m_EscapeTriggers.AddToTail( pTrigger ); break; } pAction = pAction->m_pNext; } } if ( !bAdded ) { pOutput = pTrigger->FindNamedOutput( "OnStartTouch" ); if ( pOutput ) { CEventAction *pAction = pOutput->GetFirstAction(); while ( pAction ) { if ( !Q_stricmp( STRING( pAction->m_iTarget ), pszEscapeTargetName ) ) { bAdded = true; m_EscapeTriggers.AddToTail( pTrigger ); break; } pAction = pAction->m_pNext; } } } } } Msg("Spawn manager found %d escape triggers\n", m_EscapeTriggers.Count() ); }
/* ================= ConsoleCommand ================= */ qboolean ConsoleCommand( void ) { char cmd[MAX_TOKEN_CHARS]; trap_Argv( 0, cmd, sizeof( cmd ) ); #ifdef SAVEGAME_SUPPORT if (Q_stricmp (cmd, "savegame") == 0) { if( g_gametype.integer != GT_SINGLE_PLAYER ) return qtrue; // don't allow a manual savegame command while we are waiting for the game to start/exit if (g_reloading.integer) return qtrue; if (saveGamePending) return qtrue; trap_Argv( 1, cmd, sizeof( cmd ) ); if (strlen(cmd) > 0) { // strip the extension if provided if (strrchr(cmd, '.')) { cmd[strrchr(cmd,'.')-cmd] = '\0'; } if ( !Q_stricmp( cmd, "current") ) { // beginning of map Com_Printf("sorry, '%s' is a reserved savegame name. please use another name.\n", cmd); return qtrue; } if (G_SaveGame( cmd )) trap_SendServerCommand(-1, "cp \"Game Saved\n\""); // deletedgame else G_Printf( "Unable to save game.\n" ); } else { // need a name G_Printf( "syntax: savegame <name>\n" ); } return qtrue; } #endif // SAVEGAME_SUPPORT if ( Q_stricmp (cmd, "entitylist") == 0 ) { Svcmd_EntityList_f(); return qtrue; } if ( Q_stricmp (cmd, "forceteam") == 0 ) { Svcmd_ForceTeam_f(); return qtrue; } if (Q_stricmp (cmd, "game_memory") == 0) { Svcmd_GameMem_f(); return qtrue; } /*if (Q_stricmp (cmd, "addbot") == 0) { Svcmd_AddBot_f(); return qtrue; } if (Q_stricmp (cmd, "removebot") == 0) { Svcmd_AddBot_f(); return qtrue; }*/ if (Q_stricmp (cmd, "addip") == 0) { Svcmd_AddIP_f(); return qtrue; } if (Q_stricmp (cmd, "removeip") == 0) { Svcmd_RemoveIP_f(); return qtrue; } if (Q_stricmp (cmd, "listip") == 0) { trap_SendConsoleCommand( EXEC_INSERT, "g_banIPs\n" ); return qtrue; } if (Q_stricmp (cmd, "listmaxlivesip") == 0) { PrintMaxLivesGUID(); return qtrue; } if (Q_stricmp (cmd, "reset_match") == 0) { Svcmd_ResetMatch_f(qtrue, qtrue); return qtrue; } if (Q_stricmp (cmd, "swap_teams") == 0) { Svcmd_SwapTeams_f(); return qtrue; } if (Q_stricmp (cmd, "shuffle_teams") == 0) { Svcmd_ShuffleTeams_f(); return qtrue; } // -NERVE - SMF if (Q_stricmp (cmd, "makeReferee") == 0) { G_MakeReferee(); return qtrue; } if (Q_stricmp (cmd, "removeReferee") == 0) { G_RemoveReferee(); return qtrue; } /*if (Q_stricmp (cmd, "mute") == 0) { G_MuteClient(); return qtrue; } if (Q_stricmp (cmd, "unmute") == 0) { G_UnMuteClient(); return qtrue; }*/ if (Q_stricmp (cmd, "ban") == 0) { G_PlayerBan(); return qtrue; } if( Q_stricmp( cmd, "campaign" ) == 0 ) { Svcmd_Campaign_f(); return qtrue; } if( Q_stricmp( cmd, "listcampaigns" ) == 0 ) { Svcmd_ListCampaigns_f(); return qtrue; } // fretn - moved from engine if (!Q_stricmp(cmd, "kick")) { Svcmd_Kick_f(); return qtrue; } if (!Q_stricmp(cmd, "clientkick")) { Svcmd_KickNum_f(); return qtrue; } if (!Q_stricmp(cmd, "noVoteLimit")) { Svcmd_noVoteLimit(); return qtrue; } if (!Q_stricmp(cmd, "cp")) { AP(va("cp \"%s\n\"", ConcatArgs(1))); return qtrue; } if (!Q_stricmp(cmd, "qsay")) { AP(va("chat \"%s\"", ConcatArgs(1))); G_LogPrintf("qsay: \"%s\n\"", ConcatArgs(1)); return qtrue; } if (!Q_stricmp(cmd, "bp")) { AP(va("bp \"%s\"", ConcatArgs(1))); G_LogPrintf("banner: \"%s\n\"", ConcatArgs(1)); return qtrue; } if (!Q_stricmp(cmd, "cpm")) { AP(va("cpm \"%s\n\"", ConcatArgs(1))); return qtrue; } if (!Q_stricmp(cmd, "freespec")) { gclient_t *cl; char num[MAX_TOKEN_CHARS]; int clientnum; trap_Argv(1, num, sizeof(num)); clientnum = atoi(num); cl = G_GetPlayerByNum( clientnum ); if ( !cl ) { return; } cl->sess.freeSpec = qtrue; return qtrue; } if (!Q_stricmp(cmd, "pcmd")) { gclient_t *cl; char name[MAX_TOKEN_CHARS]; int clientNum; trap_Argv(1, name, sizeof(name)); clientNum = atoi(name); cl = G_GetPlayerByNum( clientNum ); if ( !cl ) { return; } trap_SendServerCommand(cl - level.clients, va("pcmd %s", ConcatArgs(2))); return qtrue; } if (!Q_stricmp(cmd, "blockmap")) { char map[MAX_STRING_TOKENS]; char blocklist[MAX_CVAR_VALUE_STRING]; trap_Argv(1, map, sizeof(map)); if (strlen(tjg_blockedMaps.string) + strlen(map) > sizeof(tjg_blockedMaps.string)) { AP("print \"tjg_blockedMaps is full.\n\""); } else { Com_sprintf(blocklist, sizeof(blocklist), "%s %s", tjg_blockedMaps.string, map); trap_Cvar_Set("tjg_blockedMaps", va("%s", blocklist)); } return qtrue; } if (!tjg_recordMode.integer) { if (!Q_stricmp(cmd, "forcecvar")) { char cvar_name[MAX_TOKEN_CHARS]; char cvar_val[MAX_TOKEN_CHARS]; trap_Argv(1, cvar_name, sizeof(cvar_name)); trap_Argv(2, cvar_val, sizeof(cvar_val)); trap_Cvar_Set(cvar_name, va("%d", atoi(cvar_val))); AP(va("print \"Forced %s to %s.\n\"", cvar_name, va("%d", atoi(cvar_val)) ) ); return qtrue; } } if( g_dedicated.integer ) { if( !Q_stricmp (cmd, "say")) { trap_SendServerCommand( -1, va("cpm \"server: %s\n\"", ConcatArgs(1) ) ); return qtrue; } // OSP - console also gets ref commands if(!level.fLocalHost && Q_stricmp(cmd, "ref") == 0) { // CHRUKER: b005 - G_refCommandCheck expects the next argument (warn, pause, lock etc). trap_Argv(1, cmd, sizeof(cmd)); if(!G_refCommandCheck(NULL, cmd)) { G_refHelp_cmd(NULL); } return(qtrue); } // everything else will also be printed as a say command // trap_SendServerCommand( -1, va("cpm \"server: %s\n\"", ConcatArgs(0) ) ); // prints to the console instead now return qfalse; } return qfalse; }
qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC ) { char *token; char *value; char *p; int n; float f; char *patch; char sound[MAX_QPATH]; clientInfo_t *ci = &NPC->client->clientInfo; renderInfo_t *ri = &NPC->client->renderInfo; gNPCstats_t *stats = &NPC->NPC->stats; if ( !NPCName || !NPCName[0]) { NPCName = "Player"; } Q_strncpyz( ci->name, NPCName, sizeof( ci->name ) ); // fill in defaults stats->aggression = 3; stats->aim = 3; stats->earshot = 1024; stats->evasion = 3; stats->hfov = 75; stats->intelligence = 3; stats->move = 3; stats->reactions = 3; stats->vfov = 45; stats->vigilance = 0.1f; stats->visrange = 1024; stats->moveType = MT_RUNJUMP; stats->yawSpeed = 90; stats->walkSpeed = 90; stats->runSpeed = 300; stats->acceleration = 15;//Increase/descrease speed this much per frame (20fps) ri->scaleXYZ[0] = ri->scaleXYZ[1] = ri->scaleXYZ[2] = 100; //Set defaults //FIXME: should probably put default torso and head models, but what about enemies //that don't have any- like Stasis? Q_strncpyz( ri->headModelName, DEFAULT_HEADMODEL, sizeof(ri->headModelName), qtrue); Q_strncpyz( ri->torsoModelName, DEFAULT_TORSOMODEL, sizeof(ri->torsoModelName), qtrue); Q_strncpyz( ri->legsModelName, DEFAULT_LEGSMODEL, sizeof(ri->legsModelName), qtrue); //FIXME: should we have one for weapon too? /* ri->headYawRangeLeft = 50; ri->headYawRangeRight = 50; ri->headPitchRangeUp = 40; ri->headPitchRangeDown = 50; ri->torsoYawRangeLeft = 60; ri->torsoYawRangeRight = 60; ri->torsoPitchRangeUp = 30; ri->torsoPitchRangeDown = 70; */ ri->headYawRangeLeft = 80; ri->headYawRangeRight = 80; ri->headPitchRangeUp = 45; ri->headPitchRangeDown = 45; ri->torsoYawRangeLeft = 90; ri->torsoYawRangeRight = 90; ri->torsoPitchRangeUp = 30; ri->torsoPitchRangeDown = 50; /* NPC->NPC->allWeaponOrder[0] = WP_COMPRESSION_RIFLE; NPC->NPC->allWeaponOrder[1] = WP_PHASER; NPC->NPC->allWeaponOrder[2] = WP_IMOD; NPC->NPC->allWeaponOrder[3] = WP_SCAVENGER_RIFLE; NPC->NPC->allWeaponOrder[4] = WP_TRICORDER; NPC->NPC->allWeaponOrder[6] = WP_NONE; NPC->NPC->allWeaponOrder[6] = WP_NONE; NPC->NPC->allWeaponOrder[7] = WP_NONE; */ VectorCopy(playerMins, NPC->mins); VectorCopy(playerMaxs, NPC->maxs); NPC->client->crouchheight = CROUCH_MAXS_2; NPC->client->standheight = DEFAULT_MAXS_2; //ci->customBasicSoundDir = "munro"; if ( !Q_stricmp( "random", NPCName ) ) {//Randomly assemble a starfleet guy NPC_BuildRandom( NPC ); } else { p = NPCParms; COM_BeginParseSession(); // look for the right NPC while ( p ) { token = COM_ParseExt( &p, qtrue ); if ( token[0] == 0 ) { return qfalse; } if ( !Q_stricmp( token, NPCName ) ) { break; } SkipBracedSection( &p ); } if ( !p ) { return qfalse; } if ( G_ParseLiteral( &p, "{" ) ) { return qfalse; } // parse the NPC info block while ( 1 ) { token = COM_ParseExt( &p, qtrue ); if ( !token[0] ) { gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", NPCName ); return qfalse; } if ( !Q_stricmp( token, "}" ) ) { break; } //===MODEL PROPERTIES=========================================================== // headmodel if ( !Q_stricmp( token, "headmodel" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if(!Q_stricmp("none", value)) { ri->headModelName[0] = NULL; //Zero the head clamp range so the torso & legs don't lag behind ri->headYawRangeLeft = ri->headYawRangeRight = ri->headPitchRangeUp = ri->headPitchRangeDown = 0; } else { Q_strncpyz( ri->headModelName, value, sizeof(ri->headModelName), qtrue); } continue; } // torsomodel if ( !Q_stricmp( token, "torsomodel" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if(!Q_stricmp("none", value)) { ri->torsoModelName[0] = NULL; //Zero the torso clamp range so the legs don't lag behind ri->torsoYawRangeLeft = ri->torsoYawRangeRight = ri->torsoPitchRangeUp = ri->torsoPitchRangeDown = 0; } else { Q_strncpyz( ri->torsoModelName, value, sizeof(ri->torsoModelName), qtrue); } continue; } // legsmodel if ( !Q_stricmp( token, "legsmodel" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } Q_strncpyz( ri->legsModelName, value, sizeof(ri->legsModelName), qtrue); //Need to do this here to get the right index G_ParseAnimFileSet( value, &ci->animFileIndex, qfalse ); continue; } //headYawRangeLeft if ( !Q_stricmp( token, "headYawRangeLeft" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->headYawRangeLeft = n; continue; } //headYawRangeRight if ( !Q_stricmp( token, "headYawRangeRight" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->headYawRangeRight = n; continue; } //headPitchRangeUp if ( !Q_stricmp( token, "headPitchRangeUp" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->headPitchRangeUp = n; continue; } //headPitchRangeDown if ( !Q_stricmp( token, "headPitchRangeDown" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->headPitchRangeDown = n; continue; } //torsoYawRangeLeft if ( !Q_stricmp( token, "torsoYawRangeLeft" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->torsoYawRangeLeft = n; continue; } //torsoYawRangeRight if ( !Q_stricmp( token, "torsoYawRangeRight" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->torsoYawRangeRight = n; continue; } //torsoPitchRangeUp if ( !Q_stricmp( token, "torsoPitchRangeUp" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->torsoPitchRangeUp = n; continue; } //torsoPitchRangeDown if ( !Q_stricmp( token, "torsoPitchRangeDown" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->torsoPitchRangeDown = n; continue; } // Uniform XYZ scale if ( !Q_stricmp( token, "scale" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->scaleXYZ[0] = ri->scaleXYZ[1] = ri->scaleXYZ[2] = n; continue; } //X scale if ( !Q_stricmp( token, "scaleX" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->scaleXYZ[0] = n; continue; } //Y scale if ( !Q_stricmp( token, "scaleY" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->scaleXYZ[1] = n; continue; } //Z scale if ( !Q_stricmp( token, "scaleZ" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } ri->scaleXYZ[2] = n; continue; } if ( !Q_stricmp( token, "boltOn" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } G_AddBoltOn( NPC, value ); continue; } //===AI STATS===================================================================== // aggression if ( !Q_stricmp( token, "aggression" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 1 || n > 5 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->aggression = n; continue; } // aim if ( !Q_stricmp( token, "aim" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 1 || n > 5 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->aim = n; continue; } // earshot if ( !Q_stricmp( token, "earshot" ) ) { if ( G_ParseFloat( &p, &f ) ) { SkipRestOfLine( &p ); continue; } if ( f < 0.0f ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->earshot = f; continue; } // evasion if ( !Q_stricmp( token, "evasion" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 1 || n > 5 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->evasion = n; continue; } // hfov if ( !Q_stricmp( token, "hfov" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 30 || n > 180 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->hfov = n;// / 2; //FIXME: Why was this being done?! continue; } // intelligence if ( !Q_stricmp( token, "intelligence" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 1 || n > 5 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->intelligence = n; continue; } // move if ( !Q_stricmp( token, "move" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 1 || n > 5 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->move = n; continue; } // reactions if ( !Q_stricmp( token, "reactions" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 1 || n > 5 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->reactions = n; continue; } // shootDistance if ( !Q_stricmp( token, "shootDistance" ) ) { if ( G_ParseFloat( &p, &f ) ) { SkipRestOfLine( &p ); continue; } if ( f < 0.0f ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->shootDistance = f; continue; } // vfov if ( !Q_stricmp( token, "vfov" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 30 || n > 180 ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->vfov = n / 2; continue; } // vigilance if ( !Q_stricmp( token, "vigilance" ) ) { if ( G_ParseFloat( &p, &f ) ) { SkipRestOfLine( &p ); continue; } if ( f < 0.0f ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->vigilance = f; continue; } // visrange if ( !Q_stricmp( token, "visrange" ) ) { if ( G_ParseFloat( &p, &f ) ) { SkipRestOfLine( &p ); continue; } if ( f < 0.0f ) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->visrange = f; continue; } // race if ( !Q_stricmp( token, "race" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } NPC->client->race = TranslateRaceName(value); continue; } // rank if ( !Q_stricmp( token, "rank" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } NPC->NPC->rank = TranslateRankName(value); continue; } // fullName if ( !Q_stricmp( token, "fullName" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } NPC->fullName = G_NewString(value); continue; } // playerTeam if ( !Q_stricmp( token, "playerTeam" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } NPC->client->playerTeam = TranslateTeamName(value); continue; } // enemyTeam if ( !Q_stricmp( token, "enemyTeam" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } NPC->client->enemyTeam = TranslateTeamName(value); continue; } //===MOVEMENT STATS============================================================ if ( !Q_stricmp( token, "width" ) ) { if ( G_ParseInt( &p, &n ) ) { continue; } NPC->mins[0] = NPC->mins[1] = -n; NPC->maxs[0] = NPC->maxs[1] = n; continue; } if ( !Q_stricmp( token, "height" ) ) { if ( G_ParseInt( &p, &n ) ) { continue; } NPC->mins[2] = DEFAULT_MINS_2;//Cannot change NPC->maxs[2] = NPC->client->standheight = n + DEFAULT_MINS_2; continue; } if ( !Q_stricmp( token, "crouchheight" ) ) { if ( G_ParseInt( &p, &n ) ) { continue; } NPC->client->crouchheight = n + DEFAULT_MINS_2; continue; } if ( !Q_stricmp( token, "movetype" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } stats->moveType = (movetype_t)MoveTypeNameToEnum(value); continue; } // yawSpeed if ( !Q_stricmp( token, "yawSpeed" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n <= 0) { gi.Printf( "bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->yawSpeed = ((float)(n)); continue; } // walkSpeed if ( !Q_stricmp( token, "walkSpeed" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->walkSpeed = n; continue; } //runSpeed if ( !Q_stricmp( token, "runSpeed" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->runSpeed = n; continue; } //acceleration if ( !Q_stricmp( token, "acceleration" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } stats->acceleration = n; continue; } //===MISC=============================================================================== // default behavior if ( !Q_stricmp( token, "behavior" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < BS_DEFAULT || n >= NUM_BSTATES ) { gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName ); continue; } NPC->NPC->defaultBehavior = (bState_t)(n); continue; } // snd if ( !Q_stricmp( token, "snd" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if ( !(NPC->svFlags&SVF_NO_BASIC_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); patch = strstr( sound, "/" ); if ( patch ) { *patch = 0; } ci->customBasicSoundDir = G_NewString( sound ); } continue; } // sndcombat if ( !Q_stricmp( token, "sndcombat" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if ( !(NPC->svFlags&SVF_NO_COMBAT_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); patch = strstr( sound, "/" ); if ( patch ) { *patch = 0; } ci->customCombatSoundDir = G_NewString( sound ); } continue; } // sndextra if ( !Q_stricmp( token, "sndextra" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if ( !(NPC->svFlags&SVF_NO_EXTRA_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); patch = strstr( sound, "/" ); if ( patch ) { *patch = 0; } ci->customExtraSoundDir = G_NewString( sound ); } continue; } // sndscav if ( !Q_stricmp( token, "sndscav" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if ( !(NPC->svFlags&SVF_NO_SCAV_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); patch = strstr( sound, "/" ); if ( patch ) { *patch = 0; } ci->customScavSoundDir = G_NewString( sound ); } continue; } gi.Printf( "WARNING: unknown keyword '%s' while parsing '%s'\n", token, NPCName ); SkipRestOfLine( &p ); } } ci->infoValid = qfalse; if( NPCsPrecached ) {//Spawning in after initial precache, our models are precached, we just need to set our clientInfo CG_RegisterClientModels( NPC->s.number ); CG_RegisterNPCCustomSounds( ci ); CG_RegisterNPCEffects( NPC->client->playerTeam ); } return qtrue; }
/* void NPC_Precache ( char *NPCName ) Precaches NPC skins, tgas and md3s. */ void NPC_Precache ( gentity_t *spawner ) { clientInfo_t ci={0}; renderInfo_t ri={0}; team_t playerTeam = TEAM_FREE; char *token; char *value; char *p; char *patch; char sound[MAX_QPATH]; if ( !Q_stricmp( "random", spawner->NPC_type ) ) {//sorry, can't precache a random just yet return; } p = NPCParms; COM_BeginParseSession(); // look for the right NPC while ( p ) { token = COM_ParseExt( &p, qtrue ); if ( token[0] == 0 ) return; if ( !Q_stricmp( token, spawner->NPC_type ) ) { break; } SkipBracedSection( &p ); } if ( !p ) { return; } if ( G_ParseLiteral( &p, "{" ) ) { return; } // parse the NPC info block while ( 1 ) { token = COM_ParseExt( &p, qtrue ); if ( !token[0] ) { gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", spawner->NPC_type ); return; } if ( !Q_stricmp( token, "}" ) ) { break; } // headmodel if ( !Q_stricmp( token, "headmodel" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if(!Q_stricmp("none", value)) { } else { Q_strncpyz( ri.headModelName, value, sizeof(ri.headModelName), qtrue); } continue; } // torsomodel if ( !Q_stricmp( token, "torsomodel" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if(!Q_stricmp("none", value)) { } else { Q_strncpyz( ri.torsoModelName, value, sizeof(ri.torsoModelName), qtrue); } continue; } // legsmodel if ( !Q_stricmp( token, "legsmodel" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } Q_strncpyz( ri.legsModelName, value, sizeof(ri.legsModelName), qtrue); continue; } // playerTeam if ( !Q_stricmp( token, "playerTeam" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } playerTeam = TranslateTeamName(value); continue; } // snd if ( !Q_stricmp( token, "snd" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if ( !(spawner->svFlags&SVF_NO_BASIC_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); patch = strstr( sound, "/" ); if ( patch ) { *patch = 0; } ci.customBasicSoundDir = G_NewString( sound ); } continue; } // sndcombat if ( !Q_stricmp( token, "sndcombat" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if ( !(spawner->svFlags&SVF_NO_COMBAT_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); patch = strstr( sound, "/" ); if ( patch ) { *patch = 0; } ci.customCombatSoundDir = G_NewString( sound ); } continue; } // sndextra if ( !Q_stricmp( token, "sndextra" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if ( !(spawner->svFlags&SVF_NO_EXTRA_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); patch = strstr( sound, "/" ); if ( patch ) { *patch = 0; } ci.customExtraSoundDir = G_NewString( sound ); } continue; } // sndscav if ( !Q_stricmp( token, "sndscav" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } if ( !(spawner->svFlags&SVF_NO_SCAV_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); patch = strstr( sound, "/" ); if ( patch ) { *patch = 0; } ci.customScavSoundDir = G_NewString( sound ); } continue; } } CG_RegisterClientRenderInfo( &ci, &ri ); CG_RegisterNPCCustomSounds( &ci ); CG_RegisterNPCEffects( playerTeam ); //FIXME: precache the beam-in/exit sound and effect if not silentspawn //FIXME: Look for a "sounds" directory and precache death, pain, alert sounds }
void NPC_PrecacheAnimationCFG( const char *NPC_type ) { char *token; char *value; char *p; int junk; if ( !Q_stricmp( "random", NPC_type ) ) {//sorry, can't precache a random just yet return; } p = NPCParms; COM_BeginParseSession(); // look for the right NPC while ( p ) { token = COM_ParseExt( &p, qtrue ); if ( token[0] == 0 ) return; if ( !Q_stricmp( token, NPC_type ) ) { break; } SkipBracedSection( &p ); } if ( !p ) { return; } if ( G_ParseLiteral( &p, "{" ) ) { return; } // parse the NPC info block while ( 1 ) { token = COM_ParseExt( &p, qtrue ); if ( !token[0] ) { gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", NPC_type ); return; } if ( !Q_stricmp( token, "}" ) ) { break; } // legsmodel if ( !Q_stricmp( token, "legsmodel" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } G_ParseAnimFileSet( value, &junk, qfalse ); return; } } }
int NET_Socket ( char *net_interface, int port, netsrc_t type, int family ) { char Buf[BUFSIZ], *Host, *Service; int newsocket, Error; struct sockaddr_storage ss; struct addrinfo hints, *res, *ai; qboolean _true = true; int i = 1; struct ipv6_mreq mreq; cvar_t *mcast; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; hints.ai_flags = AI_PASSIVE; if (!net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost")) { Host = (family == AF_INET6) ? "::" : "0.0.0.0"; } else { Host = net_interface; } if (port == PORT_ANY) { Service = NULL; } else { sprintf(Buf, "%5d", port); Service = Buf; } if ((Error = getaddrinfo(Host, Service, &hints, &res))) { return 0; } for (ai = res; ai != NULL; ai = ai->ai_next) { if ((newsocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) { Com_Printf("NET_Socket: socket: %s\n", strerror(errno)); continue; } /* make it non-blocking */ if (ioctl(newsocket, FIONBIO, (char *)&_true) == -1) { Com_Printf("NET_Socket: ioctl FIONBIO: %s\n", strerror(errno)); continue; } if (family == AF_INET) { /* make it broadcast capable */ if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1) { Com_Printf("ERROR: NET_Socket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString()); return 0; } } /* make it reusable */ if (setsockopt(newsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i)) == -1) { Com_Printf("ERROR: NET_Socket: setsockopt SO_REUSEADDR:%s\n", NET_ErrorString()); return 0; } if (bind(newsocket, ai->ai_addr, ai->ai_addrlen) < 0) { Com_Printf("NET_Socket: bind: %s\n", strerror(errno)); } else { memcpy(&ss, ai->ai_addr, ai->ai_addrlen); break; } } if (res != NULL) { freeaddrinfo(res); } if (ai == NULL) { return 0; } switch (ss.ss_family) { case AF_INET: break; case AF_INET6: /* Multicast outgoing interface is specified for client and server (+set multicast <ifname>) */ mcast = Cvar_Get("multicast", "NULL", CVAR_NOSET); multicast_interface = (strcmp(mcast->string, "NULL") ? mcast->string : NULL); if (multicast_interface != NULL) { /* multicast_interface is a global variable. Also used in NET_SendPacket() */ if ((mreq.ipv6mr_interface = if_nametoindex(multicast_interface)) == 0) { Com_Printf("NET_Socket: invalid interface: %s\n", multicast_interface); } if (setsockopt(newsocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &mreq.ipv6mr_interface, sizeof(mreq.ipv6mr_interface)) < 0) { Com_Printf("NET_Socket: IPV6_MULTICAST_IF: %s\n", strerror(errno)); } /* Join multicast group ONLY if server */ if (type == NS_SERVER) { if (inet_pton(AF_INET6, QUAKE2MCAST, &mreq.ipv6mr_multiaddr.s6_addr) != 1) { Com_Printf("NET_Socket: inet_pton: %s\n", strerror(errno)); } if (setsockopt(newsocket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { Com_Printf("NET_Socket: IPV6_JOIN_GROUP: %s\n", strerror(errno)); } } } break; } return newsocket; }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. ================ */ void SV_SpawnServer( char *server, ForceReload_e eForceReload, qboolean bAllowScreenDissolve ) { int i; int checksum; // The following fixes for potential issues only work on Xbox #ifdef _XBOX extern qboolean stop_icarus; stop_icarus = qfalse; //Broken scripts may leave the player locked. I think that's always bad. extern qboolean player_locked; player_locked = qfalse; //If you quit while in Matrix Mode, this never gets cleared! extern qboolean MatrixMode; MatrixMode = qfalse; // Temporary code to turn on HDR effect for specific maps only if (!Q_stricmp(server, "t3_rift")) { Cvar_Set( "r_hdreffect", "1" ); } else { Cvar_Set( "r_hdreffect", "0" ); } #endif RE_RegisterMedia_LevelLoadBegin( server, eForceReload, bAllowScreenDissolve ); Cvar_SetValue( "cl_paused", 0 ); Cvar_Set( "timescale", "1" );//jic we were skipping // shut down the existing game if it is running SV_ShutdownGameProgs(qtrue); Com_Printf ("------ Server Initialization ------\n%s\n", com_version->string); Com_Printf ("Server: %s\n",server); #ifdef _XBOX // disable vsync during load for speed qglDisable(GL_VSYNC); #endif // don't let sound stutter and dump all stuff on the hunk CL_MapLoading(); if (!CM_SameMap(server)) { //rww - only clear if not loading the same map CM_ClearMap(); } #ifndef _XBOX else if (CM_HasTerrain()) { //always clear when going between maps with terrain CM_ClearMap(); } #endif // Miniheap never changes sizes, so I just put it really early in mem. G2VertSpaceServer->ResetHeap(); #ifdef _XBOX // Deletes all textures R_DeleteTextures(); #endif Hunk_Clear(); // Moved up from below to help reduce fragmentation if (svs.snapshotEntities) { Z_Free(svs.snapshotEntities); svs.snapshotEntities = NULL; } // wipe the entire per-level structure // Also moved up, trying to do all freeing before new allocs for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { if ( sv.configstrings[i] ) { Z_Free( sv.configstrings[i] ); sv.configstrings[i] = NULL; } } #ifdef _XBOX SV_ClearLastLevel(); #endif // Collect all the small allocations done by the cvar system // This frees, then allocates. Make it the last thing before other // allocations begin! Cvar_Defrag(); /* This is useful for debugging memory fragmentation. Please don't remove it. */ #ifdef _XBOX // We've over-freed the info array above, this puts it back into a working state Ghoul2InfoArray_Reset(); extern void Z_DumpMemMap_f(void); extern void Z_Details_f(void); extern void Z_TagPointers(memtag_t); Z_DumpMemMap_f(); // Z_TagPointers(TAG_ALL); Z_Details_f(); #endif // init client structures and svs.numSnapshotEntities // This is moved down quite a bit, but should be safe. And keeps // svs.clients right at the beginning of memory if ( !Cvar_VariableIntegerValue("sv_running") ) { SV_Startup(); } // clear out those shaders, images and Models R_InitImages(); R_InitShaders(); R_ModelInit(); // allocate the snapshot entities svs.snapshotEntities = (entityState_t *) Z_Malloc (sizeof(entityState_t)*svs.numSnapshotEntities, TAG_CLIENTS, qtrue ); Music_SetLevelName(server); // toggle the server bit so clients can detect that a // server has changed //!@ svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", va("map %s", server) ); memset (&sv, 0, sizeof(sv)); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } sv.time = 1000; G2API_SetTime(sv.time,G2T_SV_TIME); #ifdef _XBOX CL_StartHunkUsers(); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); RE_LoadWorldMap(va("maps/%s.bsp", server)); #else CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum, qfalse ); #endif // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { ge->RunFrame( sv.time ); sv.time += 100; G2API_SetTime(sv.time,G2T_SV_TIME); } ge->ConnectNavs(sv_mapname->string, sv_mapChecksum->integer); // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<1 ; i++) { // clear all time counters, because we have reset sv.time svs.clients[i].lastPacketTime = 0; svs.clients[i].lastConnectTime = 0; svs.clients[i].nextSnapshotTime = 0; // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; // connect the client again denied = ge->ClientConnect( i, qfalse, eNO/*qfalse*/ ); // firstTime = qfalse, qbFromSavedGame if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { svs.clients[i].state = CS_CONNECTED; // when we get the next packet from a connected client, // the new gamestate will be sent } } } // run another frame to allow things to look at all connected clients ge->RunFrame( sv.time ); sv.time += 100; G2API_SetTime(sv.time,G2T_SV_TIME); // save systeminfo and serverinfo strings SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info svs.nextHeartbeatTime = -9999999; Hunk_SetMark(); Z_Validate(); Z_Validate(); Z_Validate(); Com_Printf ("-----------------------------------\n"); }
void ClientCommand(edict_t *ent) { char *cmd; if (!ent) { return; } if (!ent->client) { return; /* not fully in game yet */ } cmd = gi.argv(0); if (Q_stricmp(cmd, "players") == 0) { Cmd_Players_f(ent); return; } if (Q_stricmp(cmd, "say") == 0) { Cmd_Say_f(ent, false, false); return; } if (Q_stricmp(cmd, "say_team") == 0) { Cmd_Say_f(ent, true, false); return; } if (Q_stricmp(cmd, "score") == 0) { Cmd_Score_f(ent); return; } if (Q_stricmp(cmd, "help") == 0) { Cmd_Help_f(ent); return; } if (level.intermissiontime) { return; } if (Q_stricmp(cmd, "use") == 0) { Cmd_Use_f(ent); } else if (Q_stricmp(cmd, "drop") == 0) { Cmd_Drop_f(ent); } else if (Q_stricmp(cmd, "give") == 0) { Cmd_Give_f(ent); } else if (Q_stricmp(cmd, "god") == 0) { Cmd_God_f(ent); } else if (Q_stricmp(cmd, "notarget") == 0) { Cmd_Notarget_f(ent); } else if (Q_stricmp(cmd, "noclip") == 0) { Cmd_Noclip_f(ent); } else if (Q_stricmp(cmd, "inven") == 0) { Cmd_Inven_f(ent); } else if (Q_stricmp(cmd, "invnext") == 0) { SelectNextItem(ent, -1); } else if (Q_stricmp(cmd, "invprev") == 0) { SelectPrevItem(ent, -1); } else if (Q_stricmp(cmd, "invnextw") == 0) { SelectNextItem(ent, IT_WEAPON); } else if (Q_stricmp(cmd, "invprevw") == 0) { SelectPrevItem(ent, IT_WEAPON); } else if (Q_stricmp(cmd, "invnextp") == 0) { SelectNextItem(ent, IT_POWERUP); } else if (Q_stricmp(cmd, "invprevp") == 0) { SelectPrevItem(ent, IT_POWERUP); } else if (Q_stricmp(cmd, "invuse") == 0) { Cmd_InvUse_f(ent); } else if (Q_stricmp(cmd, "invdrop") == 0) { Cmd_InvDrop_f(ent); } else if (Q_stricmp(cmd, "weapprev") == 0) { Cmd_WeapPrev_f(ent); } else if (Q_stricmp(cmd, "weapnext") == 0) { Cmd_WeapNext_f(ent); } else if (Q_stricmp(cmd, "weaplast") == 0) { Cmd_WeapLast_f(ent); } else if (Q_stricmp(cmd, "kill") == 0) { Cmd_Kill_f(ent); } else if (Q_stricmp(cmd, "putaway") == 0) { Cmd_PutAway_f(ent); } else if (Q_stricmp(cmd, "wave") == 0) { Cmd_Wave_f(ent); } else if (Q_stricmp(cmd, "playerlist") == 0) { Cmd_PlayerList_f(ent); } else /* anything that doesn't match a command will be a chat */ { Cmd_Say_f(ent, false, true); } }
//----------------------------------------------------- static qboolean VEH_TurretFindEnemies( Vehicle_t *pVeh, gentity_t *parent, turretStats_t *turretStats, int turretNum, int curMuzzle ) //----------------------------------------------------- { qboolean found = qfalse; int i, count; float bestDist = turretStats->fAIRange * turretStats->fAIRange; float enemyDist; vec3_t enemyDir, org, org2; qboolean foundClient = qfalse; gentity_t *entity_list[MAX_GENTITIES], *target, *bestTarget = NULL; WP_CalcVehMuzzle( parent, curMuzzle ); VectorCopy( pVeh->m_vMuzzlePos[curMuzzle], org2 ); count = G_RadiusList( org2, turretStats->fAIRange, parent, qtrue, entity_list ); for ( i = 0; i < count; i++ ) { trace_t tr; target = entity_list[i]; if ( target == parent || !target->takedamage || target->health <= 0 || ( target->flags & FL_NOTARGET )) { continue; } if ( !target->client ) {// only attack clients if ( !(target->flags&FL_BBRUSH)//not a breakable brush || !target->takedamage//is a bbrush, but invincible || (target->NPC_targetname&&parent->targetname&&Q_stricmp(target->NPC_targetname,parent->targetname)!=0) )//not in invicible bbrush, but can only be broken by an NPC that is not me { if ( target->s.weapon == WP_TURRET && target->classname && Q_strncmp( "misc_turret", target->classname, 11 ) == 0 ) {//these guys we want to shoot at } else { continue; } } //else: we will shoot at bbrushes! } else if ( target->client->sess.sessionTeam == TEAM_SPECTATOR ) { continue; } if ( target == ((gentity_t*)pVeh->m_pPilot) || target->r.ownerNum == parent->s.number ) {//don't get angry at my pilot or passengers? continue; } if ( parent->client && parent->client->sess.sessionTeam ) { if ( target->client ) { if ( target->client->sess.sessionTeam == parent->client->sess.sessionTeam ) { // A bot/client/NPC we don't want to shoot continue; } } else if ( target->teamnodmg == parent->client->sess.sessionTeam ) {//some other entity that's allied with us continue; } } if ( !trap_InPVS( org2, target->r.currentOrigin )) { continue; } VectorCopy( target->r.currentOrigin, org ); trap_Trace( &tr, org2, NULL, NULL, org, parent->s.number, MASK_SHOT ); if ( tr.entityNum == target->s.number || (!tr.allsolid && !tr.startsolid && tr.fraction == 1.0 ) ) { // Only acquire if have a clear shot, Is it in range and closer than our best? VectorSubtract( target->r.currentOrigin, org2, enemyDir ); enemyDist = VectorLengthSquared( enemyDir ); if ( enemyDist < bestDist || (target->client && !foundClient))// all things equal, keep current { bestTarget = target; bestDist = enemyDist; found = qtrue; if ( target->client ) {//prefer clients over non-clients foundClient = qtrue; } } } } if ( found ) { pVeh->turretStatus[turretNum].enemyEntNum = bestTarget->s.number; } return found; }
void _MapExitLevel (char *NextMap) { votelist_t *votemap = NULL; //Igor[Rock] BEGIN FILE *votefile; char buf[MAX_STR_LEN]; //Igor[Rock] END if (_iCheckMapVotes ()) { votemap = MapWithMostVotes (NULL); Q_strncpyz (NextMap, votemap->mapname, MAX_QPATH); gi.bprintf (PRINT_HIGH, "Next map was voted on and is %s.\n", NextMap); } //clear stats for (votemap = map_votes; votemap != NULL; votemap = votemap->next) { //Igor[Rock] BEGIN if (votemap->num_votes) { votemap->num_allvotes += votemap->num_votes; num_allvotes += votemap->num_votes; } if (Q_stricmp (level.mapname, votemap->mapname) == 0) { if (map_num_clients > 1) { if (votemap->num_allvotes < (map_num_clients / 2)) { num_allvotes -= votemap->num_allvotes; votemap->num_allvotes = 0; } else { num_allvotes -= (map_num_clients / 2); votemap->num_allvotes -= (map_num_clients / 2); } } else { if (votemap->num_allvotes) { num_allvotes--; votemap->num_allvotes--; } } } //Igor[Rock] END votemap->num_votes = 0; } //Igor[Rock] BEGIN // Save the actual votes to a file votefile = fopen (maplistpath, "w"); if (votefile != NULL) { sprintf (buf, "%d\n", num_allvotes); fputs (buf, votefile); for (votemap = map_votes; votemap != NULL; votemap = votemap->next) { sprintf (buf, "%s,%d\n", votemap->mapname, votemap->num_allvotes); fputs (buf, votefile); } fclose (votefile); } //Igor[Rock] END map_num_votes = 0; map_num_clients = 0; map_need_to_check_votes = true; }
/* ================== SV_WriteDownloadToClient Check to see if the client wants a file, open it if needed and start pumping the client Fill up msg with data ================== */ void SV_WriteDownloadToClient(client_t *cl, msg_t *msg) { int curindex; int rate; int blockspersnap; int unreferenced = 1; char errorMessage[1024]; char pakbuf[MAX_QPATH], *pakptr; int numRefPaks; if (!*cl->downloadName) return; // Nothing being downloaded if(!cl->download) { qboolean idPack = qfalse; qboolean missionPack = qfalse; // Chop off filename extension. Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName); pakptr = strrchr(pakbuf, '.'); if(pakptr) { *pakptr = '\0'; // Check for pk3 filename extension if(!Q_stricmp(pakptr + 1, "pk3")) { const char *referencedPaks = FS_ReferencedPakNames(); // Check whether the file appears in the list of referenced // paks to prevent downloading of arbitrary files. Cmd_TokenizeStringIgnoreQuotes(referencedPaks); numRefPaks = Cmd_Argc(); for(curindex = 0; curindex < numRefPaks; curindex++) { if(!FS_FilenameCompare(Cmd_Argv(curindex), pakbuf)) { unreferenced = 0; // now that we know the file is referenced, // check whether it's legal to download it. missionPack = FS_idPak(pakbuf, "missionpack"); idPack = missionPack; idPack = (qboolean)(idPack || FS_idPak(pakbuf, BASEGAME)); break; } } } } cl->download = 0; // We open the file here if ( !sv_allowDownload->integer || idPack || unreferenced || ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) { // cannot auto-download file if(unreferenced) { Com_Printf("clientDownload: %d : \"%s\" is not referenced and cannot be downloaded.\n", (int) (cl - svs.clients), cl->downloadName); Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" is not referenced and cannot be downloaded.", cl->downloadName); } else if (idPack) { Com_Printf("clientDownload: %d : \"%s\" cannot download id pk3 files\n", (int) (cl - svs.clients), cl->downloadName); if(missionPack) { Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload Team Arena file \"%s\"\n" "The Team Arena mission pack can be found in your local game store.", cl->downloadName); } else { Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName); } } else if ( !sv_allowDownload->integer ) { Com_Printf("clientDownload: %d : \"%s\" download disabled\n", (int) (cl - svs.clients), cl->downloadName); if (sv_pure->integer) { Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" "You will need to get this file elsewhere before you " "can connect to this pure server.\n", cl->downloadName); } else { Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" "The server you are connecting to is not a pure server, " "set autodownload to No in your settings and you might be " "able to join the game anyway.\n", cl->downloadName); } } else { // NOTE TTimo this is NOT supposed to happen unless bug in our filesystem scheme? // if the pk3 is referenced, it must have been found somewhere in the filesystem Com_Printf("clientDownload: %d : \"%s\" file not found on server\n", (int) (cl - svs.clients), cl->downloadName); Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" not found on server for autodownloading.\n", cl->downloadName); } MSG_WriteByte( msg, svc_download ); MSG_WriteShort( msg, 0 ); // client is expecting block zero MSG_WriteLong( msg, -1 ); // illegal file size MSG_WriteString( msg, errorMessage ); *cl->downloadName = 0; if(cl->download) FS_FCloseFile(cl->download); return; } Com_Printf( "clientDownload: %d : beginning \"%s\"\n", (int) (cl - svs.clients), cl->downloadName ); // Init cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0; cl->downloadCount = 0; cl->downloadEOF = qfalse; } // Perform any reads that we need to while (cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW && cl->downloadSize != cl->downloadCount) { curindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW); if (!cl->downloadBlocks[curindex]) cl->downloadBlocks[curindex] = (unsigned char *)Z_Malloc( MAX_DOWNLOAD_BLKSIZE, TAG_DOWNLOAD, qtrue ); cl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download ); if (cl->downloadBlockSize[curindex] < 0) { // EOF right now cl->downloadCount = cl->downloadSize; break; } cl->downloadCount += cl->downloadBlockSize[curindex]; // Load in next block cl->downloadCurrentBlock++; } // Check to see if we have eof condition and add the EOF block if (cl->downloadCount == cl->downloadSize && !cl->downloadEOF && cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW) { cl->downloadBlockSize[cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW] = 0; cl->downloadCurrentBlock++; cl->downloadEOF = qtrue; // We have added the EOF block } // Loop up to window size times based on how many blocks we can fit in the // client snapMsec and rate // based on the rate, how many bytes can we fit in the snapMsec time of the client // normal rate / snapshotMsec calculation rate = cl->rate; if ( sv_maxRate->integer ) { if ( sv_maxRate->integer < 1000 ) { Cvar_Set( "sv_MaxRate", "1000" ); } if ( sv_maxRate->integer < rate ) { rate = sv_maxRate->integer; } } if (!rate) { blockspersnap = 1; } else { blockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) / MAX_DOWNLOAD_BLKSIZE; } if (blockspersnap < 0) blockspersnap = 1; while (blockspersnap--) { // Write out the next section of the file, if we have already reached our window, // automatically start retransmitting if (cl->downloadClientBlock == cl->downloadCurrentBlock) return; // Nothing to transmit if (cl->downloadXmitBlock == cl->downloadCurrentBlock) { // We have transmitted the complete window, should we start resending? if (svs.time - cl->downloadSendTime > MAX_DOWNLOAD_BLKSIZE * 1000 / rate) cl->downloadXmitBlock = cl->downloadClientBlock; else return; } // Send current block curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW); MSG_WriteByte( msg, svc_download ); MSG_WriteShort( msg, cl->downloadXmitBlock ); // block zero is special, contains file size if ( cl->downloadXmitBlock == 0 ) MSG_WriteLong( msg, cl->downloadSize ); MSG_WriteShort( msg, cl->downloadBlockSize[curindex] ); // Write the block if ( cl->downloadBlockSize[curindex] ) { MSG_WriteData( msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex] ); } Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock ); // Move on to the next block // It will get sent with next snap shot. The rate will keep us in line. cl->downloadXmitBlock++; cl->downloadSendTime = svs.time; } }
static void Z_TagDebug_f(void) { TagBlockLabels_t AllTagBlockLabels_Local; qboolean bSnapShotTestActive = qfalse; memtag_t eTag = TAG_ALL; const char *psTAGName = Cmd_Argv(1); if (psTAGName[0]) { // check optional arg... // if (!Q_stricmp(psTAGName,"#snap")) { bSnapShotTestActive = qtrue; AllTagBlockLabels_Local = AllTagBlockLabels; // horrible great STL copy psTAGName = Cmd_Argv(2); } if (psTAGName[0]) { // skip over "tag_" if user supplied it... // if (!Q_stricmpn(psTAGName,"TAG_",4)) { psTAGName += 4; } // see if the user specified a valid tag... // for (int i=0; i<TAG_COUNT; i++) { if (!Q_stricmp(psTAGName,psTagStrings[i])) { eTag = (memtag_t) i; break; } } } } else { Com_Printf("Usage: 'zone_tagdebug [#snap] <tag>', e.g. TAG_GHOUL2, TAG_ALL (careful!)\n"); return; } Com_Printf("Dumping debug data for tag \"%s\"...%s\n\n",psTagStrings[eTag], bSnapShotTestActive?"( since snapshot only )":""); Com_Printf("%8s"," "); // to compensate for code further down: Com_Printf("(%5d) ",iBlocksListed); if (eTag == TAG_ALL) { Com_Printf("%20s ","Zone Tag"); } Com_Printf("%9s\n","Bytes"); Com_Printf("%8s"," "); if (eTag == TAG_ALL) { Com_Printf("%20s ","--------"); } Com_Printf("%9s\n","-----"); if (bSnapShotTestActive) { // dec ref counts in last snapshot for all current blocks (which will make new stuff go negative) // zoneHeader_t *pMemory = TheZone.Header.pNext; while (pMemory) { if (pMemory->eTag == eTag || eTag == TAG_ALL) { AllTagBlockLabels_Local[psTagStrings[pMemory->eTag]][pMemory->sOptionalLabel]--; } pMemory = pMemory->pNext; } } // now dump them out... // int iBlocksListed = 0; int iTotalSize = 0; zoneHeader_t *pMemory = TheZone.Header.pNext; while (pMemory) { if ( (pMemory->eTag == eTag || eTag == TAG_ALL) && (!bSnapShotTestActive || (pMemory->iSnapshotNumber == giZoneSnaphotNum && AllTagBlockLabels_Local[psTagStrings[pMemory->eTag]][pMemory->sOptionalLabel] <0) ) ) { float fSize = (float)(pMemory->iSize) / 1024.0f / 1024.0f; int iSize = fSize; int iRemainder = 100.0f * (fSize - floor(fSize)); Com_Printf("(%5d) ",iBlocksListed); if (eTag == TAG_ALL) { Com_Printf("%20s",psTagStrings[pMemory->eTag]); } Com_Printf(" %9d (%2d.%02dMB) File: \"%s\", Line: %d\n", pMemory->iSize, iSize,iRemainder, pMemory->sSrcFileBaseName, pMemory->iSrcFileLineNum ); if (pMemory->sOptionalLabel[0]) { Com_Printf("( Label: \"%s\" )\n",pMemory->sOptionalLabel); } iBlocksListed++; iTotalSize += pMemory->iSize; if (bSnapShotTestActive) { // bump ref count so we only 1 warning per new string, not for every one sharing that label... // AllTagBlockLabels_Local[psTagStrings[pMemory->eTag]][pMemory->sOptionalLabel]++; } } pMemory = pMemory->pNext; } Com_Printf("( %d blocks listed, %d bytes (%.2fMB) total )\n",iBlocksListed, iTotalSize, (float)iTotalSize / 1024.0f / 1024.0f); }
void SP_info_player_coop(edict_t *self){ if(!coop->value){ G_FreeEdict(self); return; } if((Q_stricmp(level.mapname, "jail2") == 0) || (Q_stricmp(level.mapname, "jail4") == 0) || (Q_stricmp(level.mapname, "mine1") == 0) || (Q_stricmp(level.mapname, "mine2") == 0) || (Q_stricmp(level.mapname, "mine3") == 0) || (Q_stricmp(level.mapname, "mine4") == 0) || (Q_stricmp(level.mapname, "lab") == 0) || (Q_stricmp(level.mapname, "boss1") == 0) || (Q_stricmp(level.mapname, "fact3") == 0) || (Q_stricmp(level.mapname, "biggun") == 0) || (Q_stricmp(level.mapname, "space") == 0) || (Q_stricmp(level.mapname, "command") == 0) || (Q_stricmp(level.mapname, "power2") == 0) || (Q_stricmp(level.mapname, "strike") == 0)){ // invoke one of our gross, ugly, disgusting hacks self->think = SP_FixCoopSpots; self->nextthink = level.time + FRAMETIME; } }
/* ============ Cmd_SetCommandCompletionFunc ============ */ void Cmd_SetCommandCompletionFunc( const char *command, completionFunc_t complete ) { for ( cmd_function_t *cmd=cmd_functions; cmd; cmd=cmd->next ) { if ( !Q_stricmp( command, cmd->name ) ) cmd->complete = complete; } }
void CG_DrawFireTeamOverlay( rectDef_t* rect ) { int x = rect->x; int y = rect->y + 1; // +1, jitter it into place in 1024 :) int boxWidth = 204; int bestWidth = -1; char *locStr[MAX_FIRETEAM_MEMBERS]; vec2_t loc; float h; clientInfo_t* ci = NULL; char buffer[64]; fireteamData_t* f = NULL; int i; vec4_t clr1 = { .16f, .2f, .17f, .8f }; vec4_t clr2 = { 0.f, 0.f, 0.f, .2f }; vec4_t clr3 = { 0.25f, 0.f, 0.f, 153/255.f }; vec4_t tclr = { 0.6f, 0.6f, 0.6f, 1.0f }; vec4_t bgColor = { 0.0f, 0.0f, 0.0f, 0.6f }; // window vec4_t borderColor = { 0.5f, 0.5f, 0.5f, 0.5f }; // window centity_t* cent; bgColor[3] = cg_fireteamAlpha.value; if(cg.hudEditor.showHudEditor) { //draw a fake fireteam box... CG_DrawFakeFireTeamOverlay(rect); return; } else if(!(f = CG_IsOnFireteam( cg.clientNum ))) { return; } h = 12 + 2 + 2; for(i = 0; i < MAX_FIRETEAM_MEMBERS; i++) { int locwidth; vec3_t origin; ci = CG_SortedFireTeamPlayerForPosition( i ); if(!ci) { break; } h += FT_BAR_HEIGHT + FT_BAR_YSPACING; loc[0] = ci->location[0]; loc[1] = ci->location[1]; if(cg_locations.integer > 0) { qboolean locValid = qtrue; cent = &cg_entities[ci->clientNum]; // Dens: use lerpOrigin for now origin[0] = cent->lerpOrigin[0]; origin[1] = cent->lerpOrigin[1]; origin[2] = cent->lerpOrigin[2]; locStr[i] = va( "^3%s", CG_GetLocationMsg(origin)); if (!Q_stricmp( locStr[i], "^3Unknown")){ locStr[i] = va( "^3(%s)", BG_GetLocationString( loc )); locValid = qfalse; } if(cg_locations.integer > 1 && locValid) Q_strcat( locStr[i], 64, va(" ^3(%s)", BG_GetLocationString( loc )) ); } else { locStr[i] = va( "^3(%s)", BG_GetLocationString( loc )); } if( !locStr[i][1] || !*locStr[i] ) locStr[i] = " "; locwidth = CG_Text_Width_Ext( locStr[i], 0.2f, 0, &cgs.media.font3 ); if(locwidth > bestWidth) bestWidth = locwidth; } boxWidth += bestWidth; CG_DrawRect( x, y, boxWidth, h, 1, borderColor); CG_FillRect( x + 1, y + 1, boxWidth - 2, h - 2, bgColor); x += 2; y += 2; CG_FillRect( x, y, boxWidth - 4, 12, clr1 ); Com_sprintf( buffer, 64, "Fireteam: %s", bg_fireteamNames[f->ident] ); //sprintf( buffer, "Fireteam: %s", bg_fireteamNames[f->ident] ); Q_strupr( buffer ); CG_Text_Paint_Ext( x + 3, y + FT_BAR_HEIGHT, .19f, .19f, tclr, buffer, 0, 0, 0, &cgs.media.font1 ); x += 2; //y += 2; for(i = 0; i < MAX_FIRETEAM_MEMBERS; i++) { y += FT_BAR_HEIGHT + FT_BAR_YSPACING; x = rect->x + 2; ci = CG_SortedFireTeamPlayerForPosition( i ); if(!ci) { break;; } if( ci->selected ) { CG_FillRect( x, y + FT_BAR_YSPACING, boxWidth - 4, FT_BAR_HEIGHT, clr3 ); } else { CG_FillRect( x, y + FT_BAR_YSPACING, boxWidth - 4, FT_BAR_HEIGHT, clr2 ); } x += 4; //draw class if(cg_drawClassIcons.integer & CLASSICON_FIRETEAM){ trap_R_SetColor( colorWhite ); CG_DrawPic(x-2, y+2, FT_BAR_HEIGHT, FT_BAR_HEIGHT, cgs.media.skillPics[BG_ClassSkillForClass( ci->cls )]); trap_R_SetColor( NULL ); }else{ CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, colorWhite, BG_ClassLetterForNumber( ci->cls ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 ); } x += 10; // quad: draw latched class // pheno: not with an old server, that doesn't send the latched class if( ci->cls != ci->latchClass && cgs.etpub > ETPUB_VERSION( 0, 8, 1 ) ) { //draw separator CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, colorYellow, ">", 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 ); x += 10; //draw class if(cg_drawClassIcons.integer & CLASSICON_FIRETEAM) { trap_R_SetColor( colorYellow ); CG_DrawPic(x - 2, y + 2, FT_BAR_HEIGHT, FT_BAR_HEIGHT, cgs.media.skillPics[BG_ClassSkillForClass(ci->latchClass)]); trap_R_SetColor(NULL); } else { CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, colorYellow, BG_ClassLetterForNumber( ci->latchClass ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 ); } x += 10; } else x += 20; CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, ci->team == TEAM_AXIS ? miniRankNames_Axis[ci->rank] : miniRankNames_Allies[ci->rank], 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 ); x += 22; CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, ci->name, 0, 17, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 ); x += 90; /* CG_DrawPic(x + 2, y + 2, FT_BAR_HEIGHT - 4, FT_BAR_HEIGHT - 4, cgs.media.movementAutonomyIcons[0]); x += FT_BAR_HEIGHT; CG_DrawPic(x + 2, y + 2, FT_BAR_HEIGHT - 4, FT_BAR_HEIGHT - 4, cgs.media.weaponAutonomyIcons[0]); x += FT_BAR_HEIGHT; x += 4;*/ /* if( isLeader ) { CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, va("%i", i+4), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 ); }*/ x += 20; if( ci->health > 80 ) { CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, va("%i", ci->health < 0 ? 0 : ci->health ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 ); } else if( ci->health > 0 ) { CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT, .2f, .2f, colorYellow, va("%i", ci->health < 0 ? 0 : ci->health ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 ); } else { CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT, .2f, .2f, colorRed, va("0%s", ci->health < 0 ? "" : "*" ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 ); } x += 30; CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, locStr[i], 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 ); } }