// xkan, 10/26/2002 // extracted from Fill_Clip: add the specified ammount of ammo into the clip // returns whether ammo was added to the clip int AddToClip( playerState_t *ps,// which player int weapon, // weapon to add ammo for int ammomove, // ammount to add. 0 means fill the clip if possible int outOfReserve) // is the amount to be added out of reserve { int inclip, maxclip; int ammoweap = BG_FindAmmoForWeapon(weapon); if(weapon < WP_LUGER || weapon >= WP_NUM_WEAPONS) return qfalse; inclip = ps->ammoclip[BG_FindClipForWeapon(weapon)]; maxclip = GetAmmoTableData(weapon)->maxclip; if (!ammomove) // amount to add to the clip not specified ammomove = maxclip - inclip; // max amount that can be moved into the clip else if (ammomove > maxclip - inclip) ammomove = maxclip - inclip; if (outOfReserve) { // cap move amount if it's more than you've got in reserve if(ammomove > ps->ammo[ammoweap]) ammomove = ps->ammo[ammoweap]; } if(ammomove) { if (outOfReserve) ps->ammo[ammoweap] -= ammomove; ps->ammoclip[BG_FindClipForWeapon(weapon)] += ammomove; return qtrue; } return qfalse; }
/* ============== Fill_Clip push reserve ammo into available space in the clip ============== */ void Fill_Clip( playerState_t *ps, int weapon ) { int inclip, maxclip, ammomove; int ammoweap = BG_FindAmmoForWeapon( weapon ); if ( weapon < WP_LUGER || weapon >= WP_NUM_WEAPONS ) { return; } if ( g_dmflags.integer & DF_NO_WEAPRELOAD ) { return; } inclip = ps->ammoclip[BG_FindClipForWeapon( weapon )]; maxclip = ammoTable[weapon].maxclip; ammomove = maxclip - inclip; // max amount that can be moved into the clip // cap move amount if it's more than you've got in reserve if ( ammomove > ps->ammo[ammoweap] ) { ammomove = ps->ammo[ammoweap]; } if ( ammomove ) { ps->ammo[ammoweap] -= ammomove; ps->ammoclip[BG_FindClipForWeapon( weapon )] += ammomove; } }
/** * @brief Add ammo. * @return whether any ammo was added */ int Add_Ammo(gentity_t *ent, int weapon, int count, qboolean fillClip) { int ammoweap = BG_FindAmmoForWeapon(weapon); int maxammo = BG_MaxAmmoForWeapon(ammoweap, ent->client->sess.skill); int originalCount = ent->client->ps.ammo[ammoweap]; // FIXME: do a switch if (ammoweap == WP_GRENADE_LAUNCHER) // make sure if he picks up a grenade that he get's the "launcher" too { COM_BitSet(ent->client->ps.weapons, WP_GRENADE_LAUNCHER); fillClip = qtrue; // grenades always filter into the "clip" } else if (ammoweap == WP_GRENADE_PINEAPPLE) { COM_BitSet(ent->client->ps.weapons, WP_GRENADE_PINEAPPLE); fillClip = qtrue; // grenades always filter into the "clip" } else if (ammoweap == WP_DYNAMITE) { COM_BitSet(ent->client->ps.weapons, WP_DYNAMITE); fillClip = qtrue; } else if (ammoweap == WP_SATCHEL_DET) { COM_BitSet(ent->client->ps.weapons, WP_SATCHEL_DET); fillClip = qtrue; } if (fillClip) { Fill_Clip(&ent->client->ps, weapon); } if (ammoweap == WP_PANZERFAUST || ammoweap == WP_BAZOOKA || ammoweap == WP_FLAMETHROWER) { ent->client->ps.ammoclip[ammoweap] += count; if (ent->client->ps.ammoclip[ammoweap] > maxammo) { ent->client->ps.ammoclip[ammoweap] = maxammo; // - ent->client->ps.ammoclip[BG_FindClipForWeapon(weapon)]; } } else { ent->client->ps.ammo[ammoweap] += count; if (ent->client->ps.ammo[ammoweap] > maxammo) { ent->client->ps.ammo[ammoweap] = maxammo; // - ent->client->ps.ammoclip[BG_FindClipForWeapon(weapon)]; } } if (count >= 999) // 'really, give /all/' { ent->client->ps.ammo[ammoweap] = count; } return (ent->client->ps.ammo[ammoweap] > originalCount); }
qboolean AddWeaponToPlayer(gclient_t *client, weapon_t weapon, int ammo, int ammoclip, qboolean setcurrent) { COM_BitSet(client->ps.weapons, weapon); client->ps.ammoclip[BG_FindClipForWeapon(weapon)] = ammoclip; client->ps.ammo[BG_FindAmmoForWeapon(weapon)] = ammo; if (setcurrent) { client->ps.weapon = weapon; } return qtrue; }
/* =============== trigger_ammo_touch =============== */ void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { int ammo, clips, maxClips, maxAmmo; if( !other->client ) return; if( other->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS ) return; if( self->timestamp > level.time ) return; if( other->client->ps.weaponstate != WEAPON_READY ) return; if( BG_FindUsesEnergyForWeapon( other->client->ps.weapon ) && self->spawnflags & 2 ) return; if( !BG_FindUsesEnergyForWeapon( other->client->ps.weapon ) && self->spawnflags & 4 ) return; if( self->spawnflags & 1 ) self->timestamp = level.time + 1000; else self->timestamp = level.time + FRAMETIME; BG_FindAmmoForWeapon( other->client->ps.weapon, &maxAmmo, &maxClips ); BG_UnpackAmmoArray( other->client->ps.weapon, other->client->ps.ammo, other->client->ps.powerups, &ammo, &clips ); if( ( ammo + self->damage ) > maxAmmo ) { if( clips < maxClips ) { clips++; ammo = 1; } else ammo = maxAmmo; } else ammo += self->damage; BG_PackAmmoArray( other->client->ps.weapon, other->client->ps.ammo, other->client->ps.powerups, ammo, clips ); }
// TAT 11/6/2002 // Local func to actual do skill upgrade, used by both MP skill system, and SP scripted skill system static void G_UpgradeSkill( gentity_t *ent, skillType_t skill ) { int i, cnt = 0; // See if this is the first time we've reached this skill level for( i = 0; i < SK_NUM_SKILLS; i++ ) { if( i == skill ) continue; if( ent->client->sess.skill[skill] <= ent->client->sess.skill[i] ) break; } G_DebugAddSkillLevel( ent, skill ); if( i == SK_NUM_SKILLS ) { // increase rank ent->client->sess.rank++; } if( ent->client->sess.rank >=4 ) { // Gordon: count the number of maxed out skills for( i = 0; i < SK_NUM_SKILLS; i++ ) { if( ent->client->sess.skill[ i ] >= 4 ) { cnt++; } } ent->client->sess.rank = cnt + 3; if( ent->client->sess.rank > 10 ) { ent->client->sess.rank = 10; } } ClientUserinfoChanged( ent-g_entities ); // Give em rightaway if( skill == SK_BATTLE_SENSE && ent->client->sess.skill[skill] == 1 ) { if( AddWeaponToPlayer( ent->client, WP_BINOCULARS, 1, 0, qfalse ) ) { ent->client->ps.stats[STAT_KEYS] |= ( 1 << INV_BINOCS ); } } else if( skill == SK_FIRST_AID && ent->client->sess.playerType == PC_MEDIC && ent->client->sess.skill[skill] == 4 ) { AddWeaponToPlayer( ent->client, WP_MEDIC_ADRENALINE, ent->client->ps.ammo[BG_FindAmmoForWeapon(WP_MEDIC_ADRENALINE)], ent->client->ps.ammoclip[BG_FindClipForWeapon(WP_MEDIC_ADRENALINE)], qfalse ); } }
/* ================= TossClientItems Toss the weapon and powerups for the killed player ================= */ void TossClientItems( gentity_t *self ) { gitem_t *item; int weapon; gentity_t *drop = 0; // drop the weapon if not a gauntlet or machinegun weapon = self->s.weapon; // make a special check to see if they are changing to a new // weapon that isn't the mg or gauntlet. Without this, a client // can pick up a weapon, be killed, and not drop the weapon because // their weapon change hasn't completed yet and they are still holding the MG. // (SA) always drop what you were switching to if ( 1 ) { if ( self->client->ps.weaponstate == WEAPON_DROPPING ) { weapon = self->client->pers.cmd.weapon; } if ( !( COM_BitCheck( self->client->ps.weapons, weapon ) ) ) { weapon = WP_NONE; } } // JPW NERVE don't drop these weapon types if ( ( weapon == WP_FLAMETHROWER ) || ( weapon == WP_GARAND ) || ( weapon == WP_MAUSER ) || ( weapon == WP_VENOM ) ) { weapon = WP_NONE; } // jpw if ( weapon > WP_NONE && weapon < WP_MONSTER_ATTACK1 && self->client->ps.ammo[ BG_FindAmmoForWeapon( weapon_t (weapon) )] ) { // find the item type for this weapon item = BG_FindItemForWeapon( weapon_t (weapon) ); // spawn the item // Rafael if ( !( self->client->ps.persistant[PERS_HWEAPON_USE] ) ) { drop = Drop_Item( self, item, 0, qfalse ); // JPW NERVE -- fix ammo counts drop->count = self->client->ps.ammoclip[BG_FindClipForWeapon( weapon_t (weapon) )]; drop->item->quantity = self->client->ps.ammoclip[BG_FindClipForWeapon( weapon_t (weapon) )]; // jpw } } }
/* ================= G_GiveClientMaxAmmo ================= */ void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo ) { int i; int maxAmmo, maxClips; qboolean weaponType, restoredAmmo = qfalse; for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) { if( buyingEnergyAmmo ) weaponType = BG_FindUsesEnergyForWeapon( i ); else weaponType = !BG_FindUsesEnergyForWeapon( i ); if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) && weaponType && !BG_FindInfinteAmmoForWeapon( i ) && !BG_WeaponIsFull( i, ent->client->ps.stats, ent->client->ps.ammo, ent->client->ps.powerups ) ) { BG_FindAmmoForWeapon( i, &maxAmmo, &maxClips ); if(ent->client->pers.trippleammo == 1) { maxAmmo*=3; } if( buyingEnergyAmmo ) { G_AddEvent( ent, EV_RPTUSE_SOUND, 0 ); if( BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) ) maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); } BG_PackAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups, maxAmmo, maxClips ); restoredAmmo = qtrue; } } if( restoredAmmo ) G_ForceWeaponChange( ent, ent->client->ps.weapon ); }
//----(SA) modified void Add_Ammo( gentity_t *ent, int weapon, int count, qboolean fillClip ) { int ammoweap = BG_FindAmmoForWeapon( weapon ); int totalcount; ent->client->ps.ammo[ammoweap] += count; if ( ammoweap == WP_GRENADE_LAUNCHER ) { // make sure if he picks up a grenade that he get's the "launcher" too COM_BitSet( ent->client->ps.weapons, WP_GRENADE_LAUNCHER ); fillClip = qtrue; // grenades always filter into the "clip" } else if ( ammoweap == WP_GRENADE_PINEAPPLE ) { COM_BitSet( ent->client->ps.weapons, WP_GRENADE_PINEAPPLE ); fillClip = qtrue; // grenades always filter into the "clip" } else if ( ammoweap == WP_DYNAMITE || ammoweap == WP_DYNAMITE2 ) { COM_BitSet( ent->client->ps.weapons, WP_DYNAMITE ); fillClip = qtrue; } if ( fillClip ) { Fill_Clip( &ent->client->ps, weapon ); } // cap to max ammo if ( g_dmflags.integer & DF_NO_WEAPRELOAD ) { // no clips totalcount = ent->client->ps.ammo[ammoweap]; if ( totalcount > ammoTable[ammoweap].maxammo ) { ent->client->ps.ammo[ammoweap] = ammoTable[ammoweap].maxammo; } } else { // using clips totalcount = ent->client->ps.ammo[ammoweap] + ent->client->ps.ammoclip[BG_FindClipForWeapon( weapon )]; if ( totalcount > ammoTable[ammoweap].maxammo ) { ent->client->ps.ammo[ammoweap] = ammoTable[ammoweap].maxammo - ent->client->ps.ammoclip[BG_FindClipForWeapon( weapon )]; } } if ( count >= 999 ) { // 'really, give /all/' ent->client->ps.ammo[ammoweap] = count; } // JPW NERVE }
/** * @brief Add the specified ammount of ammo into the clip. * @param ps which player * @param weapon to add ammo for * @param ammomove amount to add. 0 means fill the clip if possible * @param outOfReserve amount to be added out of reserve * @return qboolean whether ammo was added to the clip. */ int AddToClip(playerState_t *ps, int weapon, int ammomove, int outOfReserve) { int inclip, maxclip; int ammoweap = BG_FindAmmoForWeapon(weapon); if (weapon < WP_LUGER || weapon >= WP_NUM_WEAPONS) { return qfalse; } inclip = ps->ammoclip[BG_FindClipForWeapon(weapon)]; maxclip = GetAmmoTableData(weapon)->maxclip; if (!ammomove) // amount to add to the clip not specified { ammomove = maxclip - inclip; // max amount that can be moved into the clip } else if (ammomove > maxclip - inclip) { ammomove = maxclip - inclip; } if (outOfReserve) { // cap move amount if it's more than you've got in reserve if (ammomove > ps->ammo[ammoweap]) { ammomove = ps->ammo[ammoweap]; } } if (ammomove) { if (outOfReserve) { ps->ammo[ammoweap] -= ammomove; } ps->ammoclip[BG_FindClipForWeapon(weapon)] += ammomove; return qtrue; } return qfalse; }
int Pickup_Weapon( gentity_t *ent, gentity_t *other ) { int quantity; qboolean alreadyHave = qfalse; // JPW NERVE -- magic ammo for any two-handed weapon if( ent->item->giTag == WP_AMMO ) { AddMagicAmmo( other, ent->count ); // tjw: added for g_shortcuts if(ent->parent && ent->parent->client) other->client->pers.lastammo_client = ent->parent->s.clientNum; // if LT isn't giving ammo to self or another LT or the enemy, give him some props if( other->client->ps.stats[STAT_PLAYER_CLASS] != PC_FIELDOPS ) { if ( ent->parent && ent->parent->client && other->client->sess.sessionTeam == ent->parent->client->sess.sessionTeam ) { if (!(ent->parent->client->PCSpecialPickedUpCount % LT_SPECIAL_PICKUP_MOD)) { AddScore(ent->parent, WOLF_AMMO_UP); if(ent->parent && ent->parent->client) { G_LogPrintf("Ammo_Pack: %d %d\n", ent->parent - g_entities, other - g_entities); // OSP } } ent->parent->client->PCSpecialPickedUpCount++; // forty - #474 - don't give xp if we're picking up our own ammo packs. if(other != ent->parent) { G_AddSkillPoints( ent->parent, SK_SIGNALS, 1.f ); G_DebugAddSkillPoints( ent->parent, SK_SIGNALS, 1.f, "ammo pack picked up" ); } //omni-bot event if ( ent->parent ) Bot_Event_RecievedAmmo(other-g_entities, ent->parent); // extracted code originally here into AddMagicAmmo -xkan, 9/18/2002 // add 1 clip of magic ammo for any two-handed weapon } return RESPAWN_SP; } } if( ent->item->giTag == WP_BINOCULARS && (g_weapons.integer & WPF_DROP_BINOCS) ) { COM_BitSet( other->client->ps.weapons, WP_BINOCULARS ); other->client->ps.ammo[BG_FindAmmoForWeapon(WP_BINOCULARS)] = 1; other->client->ps.stats[STAT_KEYS] |= ( 1 << INV_BINOCS ); other->client->sess.numBinocs++; } quantity = ent->count; // check if player already had the weapon alreadyHave = COM_BitCheck( other->client->ps.weapons, ent->item->giTag ); // JPW NERVE prevents drop/pickup weapon "quick reload" exploit if( alreadyHave ) { Add_Ammo( other, ent->item->giTag, quantity, qfalse ); // Gordon: secondary weapon ammo if( ent->delay ) { Add_Ammo( other, weapAlts[ ent->item->giTag ], ent->delay, qfalse ); } } else { if( level.time - other->client->dropWeaponTime < 1000 ) { return 0; } if( other->client->ps.weapon == WP_MORTAR_SET || other->client->ps.weapon == WP_MOBILE_MG42_SET ) { return 0; } // See if we can pick it up if( G_CanPickupWeapon( ent->item->giTag, other ) ) { weapon_t primaryWeapon = G_GetPrimaryWeaponForClient( other->client ); // rain - added parens around ambiguous && if( 1 || // Terifire, for dropweapon (other->client->sess.playerType == PC_SOLDIER && other->client->sess.skill[SK_HEAVY_WEAPONS] >= 4) ) { // gabriel: If a lvl 4 soldier is picking un a mp40/thompson, // don't allow the soldier to have both an mp40 and a thompson if ((ent->item->giTag == WP_MP40) && COM_BitCheck( other->client->ps.weapons, WP_THOMPSON)) { G_DropWeapon( other, WP_THOMPSON); } else if ((ent->item->giTag == WP_THOMPSON) && COM_BitCheck( other->client->ps.weapons, WP_MP40)) { G_DropWeapon( other, WP_MP40); } else if( primaryWeapon ) { // Otherwise, function normally // drop our primary weapon G_DropWeapon( other, primaryWeapon ); } // now pickup the other one other->client->dropWeaponTime = level.time; // add the weapon COM_BitSet( other->client->ps.weapons, ent->item->giTag ); // DHM - Fixup mauser/sniper issues if( ent->item->giTag == WP_FG42 ) { COM_BitSet( other->client->ps.weapons, WP_FG42SCOPE); } else if(ent->item->giTag == WP_GARAND) { COM_BitSet( other->client->ps.weapons, WP_GARAND_SCOPE); } else if( ent->item->giTag == WP_K43 ) { COM_BitSet( other->client->ps.weapons, WP_K43_SCOPE ); } else if( ent->item->giTag == WP_MORTAR ) { COM_BitSet( other->client->ps.weapons, WP_MORTAR_SET ); } else if( ent->item->giTag == WP_MOBILE_MG42 ) { COM_BitSet( other->client->ps.weapons, WP_MOBILE_MG42_SET ); } else if( ent->item->giTag == WP_CARBINE ) { COM_BitSet( other->client->ps.weapons, WP_M7 ); } else if( ent->item->giTag == WP_KAR98 ) { COM_BitSet( other->client->ps.weapons, WP_GPG40 ); } other->client->ps.ammoclip[BG_FindClipForWeapon(ent->item->giTag)] = 0; other->client->ps.ammo[BG_FindAmmoForWeapon(ent->item->giTag)] = 0; if( ent->item->giTag == WP_MORTAR ) { other->client->ps.ammo[BG_FindClipForWeapon(ent->item->giTag)] = quantity; // Gordon: secondary weapon ammo if( ent->delay ) { Add_Ammo( other, weapAlts[ ent->item->giTag ], ent->delay, qfalse ); } /* quad: maybe make a g_weapons flag for this? } else if ((ent->item->giTag == WP_THOMPSON || ent->item->giTag == WP_MP40)) { // TODO: ???? (quad) // redeye - NQ style weapon switching with full ammo // note: I wrote this code before source of NQ was available, so this is less // good than NQ's implementation but still better than original ETPub int weap = BG_FindClipForWeapon(ent->item->giTag); int ammoweap = BG_FindAmmoForWeapon(ent->item->giTag); int max_ammo_per_clip = GetAmmoTableData(ammoweap)->maxclip; int ammo_in_clips = quantity - max_ammo_per_clip; if (quantity <= max_ammo_per_clip) { other->client->ps.ammoclip[weap] = quantity; other->client->ps.ammo[weap] = 0; } else { other->client->ps.ammoclip[weap] = max_ammo_per_clip; other->client->ps.ammo[weap] = ammo_in_clips; } */ } else { other->client->ps.ammoclip[BG_FindClipForWeapon(ent->item->giTag)] = quantity; // Gordon: secondary weapon ammo if( ent->delay ) { other->client->ps.ammo[ weapAlts[ ent->item->giTag ] ] = ent->delay; } } } } else { return 0; } } // TAT 1/6/2003 - If we are a bot, call the pickup function #ifndef NO_BOT_SUPPORT if( other->r.svFlags & SVF_BOT ) BotPickupWeapon( other->s.number, ent->item->giTag, alreadyHave ); #endif Bot_Event_AddWeapon(other->client->ps.clientNum, Bot_WeaponGameToBot(ent->item->giTag)); return -1; }
/* ============== CG_CheckAmmo If the ammo has gone low enough to generate the warning, play a sound ============== */ void CG_CheckAmmo( void ) { int i; int total; int weapons[MAX_WEAPONS / ( sizeof( int ) * 8 )]; // see about how many seconds of ammo we have remaining memcpy( weapons, cg.snap->ps.weapons, sizeof( weapons ) ); if ( !weapons[0] && !weapons[1] ) { // (SA) we start out with no weapons, so don't make a click on startup return; } total = 0; // first weap now WP_LUGER for ( i = WP_FIRST ; i < WP_NUM_WEAPONS ; i++ ) { if ( !( weapons[0] & ( 1 << i ) ) ) { continue; } switch ( i ) { case WP_PANZERFAUST: case WP_GRENADE_LAUNCHER: case WP_GRENADE_PINEAPPLE: case WP_LUGER: case WP_COLT: case WP_AKIMBO: case WP_SILENCER: case WP_FG42: case WP_FG42SCOPE: case WP_MP40: case WP_THOMPSON: case WP_STEN: case WP_VENOM: case WP_TESLA: case WP_MAUSER: case WP_GARAND: default: total += cg.snap->ps.ammo[BG_FindAmmoForWeapon( i )] * 1000; // break; // default: // total += cg.snap->ps.ammo[BG_FindAmmoForWeapon(i)] * 200; // break; } if ( total >= 5000 ) { cg.lowAmmoWarning = 0; return; } } if ( !cg.lowAmmoWarning ) { // play a sound on this transition trap_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND ); } if ( total == 0 ) { cg.lowAmmoWarning = 2; } else { cg.lowAmmoWarning = 1; } }
/* =========== ClientSpawn Called every time a client is placed fresh in the world: after the first ClientBegin, and after each respawn Initializes all non-persistant parts of playerState ============ */ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles ) { int index; vec3_t spawn_origin, spawn_angles; gclient_t *client; int i; clientPersistant_t saved; clientSession_t savedSess; int persistant[ MAX_PERSISTANT ]; gentity_t *spawnPoint = NULL; int flags; int savedPing; int teamLocal; int eventSequence; char userinfo[ MAX_INFO_STRING ]; vec3_t up = { 0.0f, 0.0f, 1.0f }; int maxAmmo, maxClips; weapon_t weapon; index = ent - g_entities; client = ent->client; teamLocal = client->pers.teamSelection; //TA: only start client if chosen a class and joined a team if( client->pers.classSelection == PCL_NONE && teamLocal == PTE_NONE ) { client->sess.sessionTeam = TEAM_SPECTATOR; client->sess.spectatorState = SPECTATOR_FREE; } else if( client->pers.classSelection == PCL_NONE ) { client->sess.sessionTeam = TEAM_SPECTATOR; client->sess.spectatorState = SPECTATOR_LOCKED; } //if client is dead and following teammate, stop following before spawning if(ent->client->sess.spectatorClient!=-1) { ent->client->sess.spectatorClient = -1; ent->client->sess.spectatorState = SPECTATOR_FREE; } if( origin != NULL ) VectorCopy( origin, spawn_origin ); if( angles != NULL ) VectorCopy( angles, spawn_angles ); // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if( client->sess.sessionTeam == TEAM_SPECTATOR ) { if( teamLocal == PTE_NONE ) spawnPoint = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles ); else if( teamLocal == PTE_ALIENS ) spawnPoint = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles ); else if( teamLocal == PTE_HUMANS ) spawnPoint = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles ); } else { if( spawn == NULL ) { G_Error( "ClientSpawn: spawn is NULL\n" ); return; } spawnPoint = spawn; if( ent != spawn ) { //start spawn animation on spawnPoint G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue ); if( spawnPoint->biteam == PTE_ALIENS ) spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME; else if( spawnPoint->biteam == PTE_HUMANS ) spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME; } } client->pers.teamState.state = TEAM_ACTIVE; // toggle the teleport bit so the client knows to not lerp flags = ent->client->ps.eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED ); flags ^= EF_TELEPORT_BIT; G_UnlaggedClear( ent ); // clear everything but the persistant data saved = client->pers; savedSess = client->sess; savedPing = client->ps.ping; for( i = 0; i < MAX_PERSISTANT; i++ ) persistant[ i ] = client->ps.persistant[ i ]; eventSequence = client->ps.eventSequence; memset( client, 0, sizeof( *client ) ); client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; client->lastkilled_client = -1; for( i = 0; i < MAX_PERSISTANT; i++ ) client->ps.persistant[ i ] = persistant[ i ]; client->ps.eventSequence = eventSequence; // increment the spawncount so the client will detect the respawn client->ps.persistant[ PERS_SPAWN_COUNT ]++; client->ps.persistant[ PERS_TEAM ] = client->sess.sessionTeam; // restore really persistant things client->ps.persistant[ PERS_SCORE ] = client->pers.score; client->ps.persistant[ PERS_CREDIT ] = client->pers.credit; client->airOutTime = level.time + 12000; trap_GetUserinfo( index, userinfo, sizeof( userinfo ) ); client->ps.eFlags = flags; //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection ); ent->s.groundEntityNum = ENTITYNUM_NONE; ent->client = &level.clients[ index ]; ent->takedamage = qtrue; ent->inuse = qtrue; ent->classname = "player"; ent->r.contents = CONTENTS_BODY; ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags = 0; //TA: calculate each client's acceleration ent->evaluateAcceleration = qtrue; client->ps.stats[ STAT_WEAPONS ] = 0; client->ps.stats[ STAT_WEAPONS2 ] = 0; client->ps.stats[ STAT_SLOTS ] = 0; client->ps.eFlags = flags; client->ps.clientNum = index; BG_FindBBoxForClass( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL ); if( client->sess.sessionTeam != TEAM_SPECTATOR ) client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] = BG_FindHealthForClass( ent->client->pers.classSelection ); else client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] = 100; // clear entity values if( ent->client->pers.classSelection == PCL_HUMAN ) { BG_AddWeaponToInventory( WP_BLASTER, client->ps.stats ); BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats ); weapon = client->pers.humanItemSelection; } else if( client->sess.sessionTeam != TEAM_SPECTATOR ) weapon = BG_FindStartWeaponForClass( ent->client->pers.classSelection ); else weapon = WP_NONE; BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips ); BG_AddWeaponToInventory( weapon, client->ps.stats ); BG_PackAmmoArray( weapon, client->ps.ammo, client->ps.powerups, maxAmmo, maxClips ); ent->client->ps.stats[ STAT_PCLASS ] = ent->client->pers.classSelection; ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.teamSelection; ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE; ent->client->ps.stats[ STAT_STATE ] = 0; VectorSet( ent->client->ps.grapplePoint, 0.0f, 0.0f, 1.0f ); // health will count down towards max_health ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25; //if evolving scale health if( ent == spawn ) { ent->health *= ent->client->pers.evolveHealthFraction; client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction; } //clear the credits array for( i = 0; i < MAX_CLIENTS; i++ ) ent->credits[ i ] = 0; client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA; G_SetOrigin( ent, spawn_origin ); VectorCopy( spawn_origin, client->ps.origin ); #define UP_VEL 150.0f #define F_VEL 50.0f //give aliens some spawn velocity if( client->sess.sessionTeam != TEAM_SPECTATOR && client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) { if( ent == spawn ) { //evolution particle system G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) ); } else { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); if( spawnPoint->s.origin2[ 2 ] > 0.0f ) { vec3_t forward, dir; AngleVectors( spawn_angles, forward, NULL, NULL ); VectorScale( forward, F_VEL, forward ); VectorAdd( spawnPoint->s.origin2, forward, dir ); VectorNormalize( dir ); VectorScale( dir, UP_VEL, client->ps.velocity ); } G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 ); } } else if( client->sess.sessionTeam != TEAM_SPECTATOR && client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); } // the respawned flag will be cleared after the attack and jump keys come up client->ps.pm_flags |= PMF_RESPAWNED; trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); G_SetClientViewAngle( ent, spawn_angles ); if( !( client->sess.sessionTeam == TEAM_SPECTATOR ) ) { /*G_KillBox( ent );*/ //blame this if a newly spawned client gets stuck in another trap_LinkEntity( ent ); // force the base weapon up client->ps.weapon = WP_NONE; client->ps.weaponstate = WEAPON_READY; } // don't allow full run speed for a bit client->ps.pm_flags |= PMF_TIME_KNOCKBACK; client->ps.pm_time = 100; client->respawnTime = level.time; client->lastKillTime = level.time; client->inactivityTime = level.time + g_inactivity.integer * 1000; client->latched_buttons = 0; // set default animations client->ps.torsoAnim = TORSO_STAND; client->ps.legsAnim = LEGS_IDLE; if( level.intermissiontime ) MoveClientToIntermission( ent ); else { // fire the targets of the spawn point if( !spawn ) G_UseTargets( spawnPoint, ent ); // select the highest weapon number available, after any // spawn given items have fired client->ps.weapon = 1; for( i = WP_NUM_WEAPONS - 1; i > 0 ; i-- ) { if( BG_InventoryContainsWeapon( i, client->ps.stats ) ) { client->ps.weapon = i; break; } } } // run a client frame to drop exactly to the floor, // initialize animations and other things client->ps.commandTime = level.time - 100; ent->client->pers.cmd.serverTime = level.time; ClientThink( ent-g_entities ); // positively link the client, even if the command times are weird if( client->sess.sessionTeam != TEAM_SPECTATOR ) { BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); trap_LinkEntity( ent ); } //TA: must do this here so the number of active clients is calculated CalculateRanks( ); // run the presend to set anything else ClientEndFrame( ent ); // clear entity state values BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); }
int Pickup_Weapon( gentity_t *ent, gentity_t *other ) { int quantity; qboolean alreadyHave = qfalse; // JPW NERVE -- magic ammo for any two-handed weapon if( ent->item->giTag == WP_AMMO ) { AddMagicAmmo( other, ent->count ); // if LT isn't giving ammo to self or another LT or the enemy, give him some props if( other->client->ps.stats[STAT_PLAYER_CLASS] != PC_FIELDOPS ) { if ( ent->parent && ent->parent->client && other->client->sess.sessionTeam == ent->parent->client->sess.sessionTeam ) { if (!(ent->parent->client->PCSpecialPickedUpCount % LT_SPECIAL_PICKUP_MOD)) { AddScore(ent->parent, WOLF_AMMO_UP); if(ent->parent && ent->parent->client) { G_LogPrintf("Ammo_Pack: %d %d\n", ent->parent - g_entities, other - g_entities); // OSP } } ent->parent->client->PCSpecialPickedUpCount++; G_AddSkillPoints( ent->parent, SK_SIGNALS, 1.f ); G_DebugAddSkillPoints( ent->parent, SK_SIGNALS, 1.f, "ammo pack picked up" ); // extracted code originally here into AddMagicAmmo -xkan, 9/18/2002 // add 1 clip of magic ammo for any two-handed weapon } return RESPAWN_SP; } } quantity = ent->count; // check if player already had the weapon alreadyHave = COM_BitCheck( other->client->ps.weapons, ent->item->giTag ); // JPW NERVE prevents drop/pickup weapon "quick reload" exploit if( alreadyHave ) { Add_Ammo( other, ent->item->giTag, quantity, qfalse ); // Gordon: secondary weapon ammo if( ent->delay ) { Add_Ammo( other, weapAlts[ ent->item->giTag ], ent->delay, qfalse ); } } else { if( level.time - other->client->dropWeaponTime < 1000 ) { return 0; } if( other->client->ps.weapon == WP_MORTAR_SET || other->client->ps.weapon == WP_MOBILE_MG42_SET ) { return 0; } // See if we can pick it up if( G_CanPickupWeapon( ent->item->giTag, other ) ) { weapon_t primaryWeapon = G_GetPrimaryWeaponForClient( other->client ); if( primaryWeapon || other->client->sess.playerType == PC_SOLDIER && other->client->sess.skill[SK_HEAVY_WEAPONS] >= 4 ) { if( primaryWeapon ) { // drop our primary weapon G_DropWeapon( other, primaryWeapon ); } // now pickup the other one other->client->dropWeaponTime = level.time; // add the weapon COM_BitSet( other->client->ps.weapons, ent->item->giTag ); // DHM - Fixup mauser/sniper issues if( ent->item->giTag == WP_FG42 ) { COM_BitSet( other->client->ps.weapons, WP_FG42SCOPE); } else if(ent->item->giTag == WP_GARAND) { COM_BitSet( other->client->ps.weapons, WP_GARAND_SCOPE); } else if( ent->item->giTag == WP_K43 ) { COM_BitSet( other->client->ps.weapons, WP_K43_SCOPE ); } else if( ent->item->giTag == WP_MORTAR ) { COM_BitSet( other->client->ps.weapons, WP_MORTAR_SET ); } else if( ent->item->giTag == WP_MOBILE_MG42 ) { COM_BitSet( other->client->ps.weapons, WP_MOBILE_MG42_SET ); } else if( ent->item->giTag == WP_CARBINE ) { COM_BitSet( other->client->ps.weapons, WP_M7 ); } else if( ent->item->giTag == WP_KAR98 ) { COM_BitSet( other->client->ps.weapons, WP_GPG40 ); } other->client->ps.ammoclip[BG_FindClipForWeapon(ent->item->giTag)] = 0; other->client->ps.ammo[BG_FindAmmoForWeapon(ent->item->giTag)] = 0; if( ent->item->giTag == WP_MORTAR ) { other->client->ps.ammo[BG_FindClipForWeapon(ent->item->giTag)] = quantity; // Gordon: secondary weapon ammo if( ent->delay ) { Add_Ammo( other, weapAlts[ ent->item->giTag ], ent->delay, qfalse ); } } else { other->client->ps.ammoclip[BG_FindClipForWeapon(ent->item->giTag)] = quantity; // Gordon: secondary weapon ammo if( ent->delay ) { other->client->ps.ammo[ weapAlts[ ent->item->giTag ] ] = ent->delay; } } } } else { return 0; } } return -1; }
void G_DropWeapon( gentity_t *ent, weapon_t weapon ) { vec3_t angles, velocity, org, offset, mins, maxs; gclient_t *client = ent->client; gentity_t *ent2; gitem_t *item; trace_t tr; item = BG_FindItemForWeapon( weapon ); VectorCopy( client->ps.viewangles, angles ); // clamp pitch if ( angles[PITCH] < -30 ) angles[PITCH] = -30; else if ( angles[PITCH] > 30 ) angles[PITCH] = 30; AngleVectors( angles, velocity, NULL, NULL ); VectorScale( velocity, 64, offset ); offset[2] += client->ps.viewheight / 2.f; VectorScale( velocity, 75, velocity ); velocity[2] += 50 + random() * 35; VectorAdd( client->ps.origin, offset, org ); VectorSet( mins, -ITEM_RADIUS, -ITEM_RADIUS, 0 ); VectorSet( maxs, ITEM_RADIUS, ITEM_RADIUS, 2*ITEM_RADIUS ); trap_Trace( &tr, client->ps.origin, mins, maxs, org, ent->s.number, MASK_SOLID ); VectorCopy( tr.endpos, org ); ent2 = LaunchItem( item, org, velocity, client->ps.clientNum ); COM_BitClear( client->ps.weapons, weapon ); if( weapon == WP_KAR98 ) { COM_BitClear( client->ps.weapons, WP_GPG40 ); } else if ( weapon == WP_CARBINE ) { COM_BitClear( client->ps.weapons, WP_M7 ); } else if ( weapon == WP_FG42 ) { COM_BitClear( client->ps.weapons, WP_FG42SCOPE ); } else if( weapon == WP_K43 ) { COM_BitClear( client->ps.weapons, WP_K43_SCOPE ); } else if( weapon == WP_GARAND ) { COM_BitClear( client->ps.weapons, WP_GARAND_SCOPE ); } else if( weapon == WP_MORTAR ) { COM_BitClear( client->ps.weapons, WP_MORTAR_SET ); } else if( weapon == WP_MOBILE_MG42 ) { COM_BitClear( client->ps.weapons, WP_MOBILE_MG42_SET ); } // Clear out empty weapon, change to next best weapon G_AddEvent( ent, EV_WEAPONSWITCHED, 0 ); if( weapon == client->ps.weapon ) client->ps.weapon = 0; if( weapon == WP_MORTAR ) { ent2->count = client->ps.ammo[BG_FindAmmoForWeapon(weapon)] + client->ps.ammoclip[BG_FindClipForWeapon(weapon)]; } else { ent2->count = client->ps.ammoclip[BG_FindClipForWeapon(weapon)]; } if( weapon == WP_KAR98 || weapon == WP_CARBINE ) { ent2->delay = client->ps.ammo[BG_FindAmmoForWeapon(weapAlts[weapon])] + client->ps.ammoclip[BG_FindClipForWeapon(weapAlts[weapon])]; } else { ent2->delay = 0; } // ent2->item->quantity = client->ps.ammoclip[BG_FindClipForWeapon(weapon)]; // Gordon: um, modifying an item is not a good idea client->ps.ammoclip[BG_FindClipForWeapon(weapon)] = 0; }
/* ================== ClientTimerActions Actions that happen once a second ================== */ void ClientTimerActions( gentity_t *ent, int msec ) { gclient_t *client; usercmd_t *ucmd; int aForward, aRight; ucmd = &ent->client->pers.cmd; aForward = abs( ucmd->forwardmove ); aRight = abs( ucmd->rightmove ); client = ent->client; client->time100 += msec; client->time1000 += msec; client->time10000 += msec; while ( client->time100 >= 100 ) { client->time100 -= 100; //if not trying to run then not trying to sprint if( aForward <= 64 ) client->ps.stats[ STAT_STATE ] &= ~SS_SPEEDBOOST; if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) ) client->ps.stats[ STAT_STATE ] &= ~SS_SPEEDBOOST; if( ( client->ps.stats[ STAT_STATE ] & SS_SPEEDBOOST ) && ucmd->upmove >= 0 ) { //subtract stamina if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, client->ps.stats ) ) client->ps.stats[ STAT_STAMINA ] -= STAMINA_LARMOUR_TAKE; else client->ps.stats[ STAT_STAMINA ] -= STAMINA_SPRINT_TAKE; if( client->ps.stats[ STAT_STAMINA ] < -MAX_STAMINA ) client->ps.stats[ STAT_STAMINA ] = -MAX_STAMINA; } if( ( aForward <= 64 && aForward > 5 ) || ( aRight <= 64 && aRight > 5 ) ) { //restore stamina client->ps.stats[ STAT_STAMINA ] += STAMINA_WALK_RESTORE; if( client->ps.stats[ STAT_STAMINA ] > MAX_STAMINA ) client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA; } else if( aForward <= 5 && aRight <= 5 ) { //restore stamina faster client->ps.stats[ STAT_STAMINA ] += STAMINA_STOP_RESTORE; if( client->ps.stats[ STAT_STAMINA ] > MAX_STAMINA ) client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA; } //client is charging up for a pounce if( client->ps.weapon == WP_ALEVEL3 || client->ps.weapon == WP_ALEVEL3_UPG ) { int pounceSpeed = 0; if( client->ps.weapon == WP_ALEVEL3 ) pounceSpeed = LEVEL3_POUNCE_SPEED; else if( client->ps.weapon == WP_ALEVEL3_UPG ) pounceSpeed = LEVEL3_POUNCE_UPG_SPEED; if( client->ps.stats[ STAT_MISC ] < pounceSpeed && ucmd->buttons & BUTTON_ATTACK2 ) client->ps.stats[ STAT_MISC ] += ( 100.0f / (float)LEVEL3_POUNCE_CHARGE_TIME ) * pounceSpeed; if( !( ucmd->buttons & BUTTON_ATTACK2 ) ) { if( client->ps.stats[ STAT_MISC ] > 0 ) { client->allowedToPounce = qtrue; client->pouncePayload = client->ps.stats[ STAT_MISC ]; } client->ps.stats[ STAT_MISC ] = 0; } if( client->ps.stats[ STAT_MISC ] > pounceSpeed ) client->ps.stats[ STAT_MISC ] = pounceSpeed; } //client is charging up for a... charge if( client->ps.weapon == WP_ALEVEL4 ) { if( client->ps.stats[ STAT_MISC ] < LEVEL4_CHARGE_TIME && ucmd->buttons & BUTTON_ATTACK2 && !client->charging ) { client->charging = qfalse; //should already be off, just making sure client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING; if( ucmd->forwardmove > 0 ) { //trigger charge sound...is quite annoying //if( client->ps.stats[ STAT_MISC ] <= 0 ) // G_AddEvent( ent, EV_LEV4_CHARGE_PREPARE, 0 ); client->ps.stats[ STAT_MISC ] += (int)( 100 * (float)LEVEL4_CHARGE_CHARGE_RATIO ); if( client->ps.stats[ STAT_MISC ] > LEVEL4_CHARGE_TIME ) client->ps.stats[ STAT_MISC ] = LEVEL4_CHARGE_TIME; } else client->ps.stats[ STAT_MISC ] = 0; } if( !( ucmd->buttons & BUTTON_ATTACK2 ) || client->charging || client->ps.stats[ STAT_MISC ] == LEVEL4_CHARGE_TIME ) { if( client->ps.stats[ STAT_MISC ] > LEVEL4_MIN_CHARGE_TIME ) { client->ps.stats[ STAT_MISC ] -= 100; if( client->charging == qfalse ) G_AddEvent( ent, EV_LEV4_CHARGE_START, 0 ); client->charging = qtrue; client->ps.stats[ STAT_STATE ] |= SS_CHARGING; //if the charger has stopped moving take a chunk of charge away if( VectorLength( client->ps.velocity ) < 64.0f || aRight ) client->ps.stats[ STAT_MISC ] = client->ps.stats[ STAT_MISC ] / 2; //can't charge backwards if( ucmd->forwardmove < 0 ) client->ps.stats[ STAT_MISC ] = 0; } else client->ps.stats[ STAT_MISC ] = 0; if( client->ps.stats[ STAT_MISC ] <= 0 ) { client->ps.stats[ STAT_MISC ] = 0; client->charging = qfalse; client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING; } } } //client is charging up an lcannon if( client->ps.weapon == WP_LUCIFER_CANNON ) { int ammo; BG_UnpackAmmoArray( WP_LUCIFER_CANNON, client->ps.ammo, client->ps.powerups, &ammo, NULL ); if( client->ps.stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE && ucmd->buttons & BUTTON_ATTACK ) client->ps.stats[ STAT_MISC ] += ( 100.0f / LCANNON_CHARGE_TIME ) * LCANNON_TOTAL_CHARGE; if( client->ps.stats[ STAT_MISC ] > LCANNON_TOTAL_CHARGE ) client->ps.stats[ STAT_MISC ] = LCANNON_TOTAL_CHARGE; if( client->ps.stats[ STAT_MISC ] > ( ammo * LCANNON_TOTAL_CHARGE ) / 10 ) client->ps.stats[ STAT_MISC ] = ammo * LCANNON_TOTAL_CHARGE / 10; } switch( client->ps.weapon ) { case WP_ABUILD: case WP_ABUILD2: case WP_HBUILD: case WP_HBUILD2: //set validity bit on buildable if( ( client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) > BA_NONE ) { int dist = BG_FindBuildDistForClass( ent->client->ps.stats[ STAT_PCLASS ] ); vec3_t dummy; if( G_itemFits( ent, (buildable_t)(client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT), dist, dummy ) == IBE_NONE ) client->ps.stats[ STAT_BUILDABLE ] |= SB_VALID_TOGGLEBIT; else client->ps.stats[ STAT_BUILDABLE ] &= ~SB_VALID_TOGGLEBIT; } //update build timer if( client->ps.stats[ STAT_MISC ] > 0 ) client->ps.stats[ STAT_MISC ] -= 100; if( client->ps.stats[ STAT_MISC ] < 0 ) client->ps.stats[ STAT_MISC ] = 0; break; default: break; } if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE ) { int remainingStartupTime = MEDKIT_STARTUP_TIME - ( level.time - client->lastMedKitTime ); if( remainingStartupTime < 0 ) { if( ent->health < ent->client->ps.stats[ STAT_MAX_HEALTH ] && ent->client->medKitHealthToRestore && ent->client->ps.pm_type != PM_DEAD ) { ent->client->medKitHealthToRestore--; ent->health++; } else ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE; } else { if( ent->health < ent->client->ps.stats[ STAT_MAX_HEALTH ] && ent->client->medKitHealthToRestore && ent->client->ps.pm_type != PM_DEAD ) { //partial increase if( level.time > client->medKitIncrementTime ) { ent->client->medKitHealthToRestore--; ent->health++; client->medKitIncrementTime = level.time + ( remainingStartupTime / MEDKIT_STARTUP_SPEED ); } } else ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE; } } } while( client->time1000 >= 1000 ) { client->time1000 -= 1000; //client is poison clouded if( client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED ) G_Damage( ent, client->lastPoisonCloudedClient, client->lastPoisonCloudedClient, NULL, NULL, LEVEL1_PCLOUD_DMG, 0, MOD_LEVEL1_PCLOUD ); //client is poisoned if( client->ps.stats[ STAT_STATE ] & SS_POISONED ) { int i; int seconds = ( ( level.time - client->lastPoisonTime ) / 1000 ) + 1; int damage = ALIEN_POISON_DMG, damage2 = 0; for( i = 0; i < seconds; i++ ) { if( i == seconds - 1 ) damage2 = damage; damage *= ALIEN_POISON_DIVIDER; } damage = damage2 - damage; G_Damage( ent, client->lastPoisonClient, client->lastPoisonClient, NULL, NULL, damage, 0, MOD_POISON ); } //replenish alien health if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) { int entityList[ MAX_GENTITIES ]; vec3_t range = { LEVEL4_REGEN_RANGE, LEVEL4_REGEN_RANGE, LEVEL4_REGEN_RANGE }; vec3_t mins, maxs; int i, num; gentity_t *boostEntity; float modifier = 1.0f; VectorAdd( client->ps.origin, range, maxs ); VectorSubtract( client->ps.origin, range, mins ); num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); for( i = 0; i < num; i++ ) { boostEntity = &g_entities[ entityList[ i ] ]; if( boostEntity->client && boostEntity->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS && boostEntity->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL4 ) { modifier = LEVEL4_REGEN_MOD; break; } else if( boostEntity->s.eType == ET_BUILDABLE && boostEntity->s.modelindex == BA_A_BOOSTER && boostEntity->spawned ) { modifier = BOOSTER_REGEN_MOD; break; } } if( ent->health > 0 && ent->health < client->ps.stats[ STAT_MAX_HEALTH ] && ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time ) ent->health += BG_FindRegenRateForClass( client->ps.stats[ STAT_PCLASS ] ) * modifier; if( ent->health > client->ps.stats[ STAT_MAX_HEALTH ] ) ent->health = client->ps.stats[ STAT_MAX_HEALTH ]; } } while( client->time10000 >= 10000 ) { client->time10000 -= 10000; if( client->ps.weapon == WP_ALEVEL3_UPG ) { int ammo, maxAmmo; BG_FindAmmoForWeapon( WP_ALEVEL3_UPG, &maxAmmo, NULL ); BG_UnpackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, &ammo, NULL ); if( ammo < maxAmmo ) { ammo++; BG_PackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, ammo, 0 ); } } } }
// Set up snapshot merge based on this portal qboolean G_smvRunCamera(gentity_t *ent) { int id = ent->TargetFlag; int chargeTime, sprintTime, hintTime, weapHeat; playerState_t *tps, *ps; // Opt out if not a real MV portal if (ent->tagParent == NULL || ent->tagParent->client == NULL) { return qfalse; } if ((ps = &ent->tagParent->client->ps) == NULL) { return qfalse; } // If viewing client is no longer connected, delete this camera if (ent->tagParent->client->pers.connected != CON_CONNECTED) { G_FreeEntity(ent); return qtrue; } // Also remove if the target player is no longer in the game playing if (ent->target_ent->client->pers.connected != CON_CONNECTED || ent->target_ent->client->sess.sessionTeam == TEAM_SPECTATOR) { G_smvLocateEntityInMVList(ent->tagParent, ent->target_ent - g_entities, qtrue); return qtrue; } // Seems that depending on player's state, we pull from either r.currentOrigin, or s.origin // if(!spec) then use: r.currentOrigin // if(spec) then use: s.origin // // This is true for both the portal origin and its target (origin2) // VectorCopy(ent->tagParent->s.origin, ent->s.origin); G_SetOrigin(ent, ent->s.origin); VectorCopy(ent->target_ent->r.currentOrigin, ent->s.origin2); trap_LinkEntity(ent); // Only allow client ids 0 to (MAX_MVCLIENTS-1) to be updated with extra info if (id >= MAX_MVCLIENTS) { return qtrue; } tps = &ent->target_ent->client->ps; if (tps->stats[STAT_PLAYER_CLASS] == PC_ENGINEER) { chargeTime = g_engineerChargeTime.value; } else if (tps->stats[STAT_PLAYER_CLASS] == PC_MEDIC) { chargeTime = g_medicChargeTime.value; } else if (tps->stats[STAT_PLAYER_CLASS] == PC_FIELDOPS) { chargeTime = g_fieldopsChargeTime.value; } else if (tps->stats[STAT_PLAYER_CLASS] == PC_COVERTOPS) { chargeTime = g_covertopsChargeTime.value; } else { chargeTime = g_soldierChargeTime.value; } chargeTime = (level.time - tps->classWeaponTime >= (int)chargeTime) ? 0 : (1 + floor(15.0f * (float)(level.time - tps->classWeaponTime) / chargeTime)); sprintTime = (ent->target_ent->client->pmext.sprintTime >= 20000) ? 0.0f : (1 + floor(7.0f * (float)ent->target_ent->client->pmext.sprintTime / 20000.0f)); weapHeat = floor((float)tps->curWeapHeat * 15.0f / 255.0f); hintTime = (tps->serverCursorHint != HINT_BUILD && (tps->serverCursorHintVal >= 255 || tps->serverCursorHintVal == 0)) ? 0 : (1 + floor(15.0f * (float)tps->serverCursorHintVal / 255.0f)); // (Remaining bits) // ammo : 0 // ammo-1 : 0 // ammiclip : 0 // ammoclip-1: 16 id = MAX_WEAPONS - 1 - (id * 2); if (tps->pm_flags & PMF_LIMBO) { ps->ammo[id] = 0; ps->ammo[id - 1] = 0; ps->ammoclip[id - 1] = 0; } else { ps->ammo[id] = (((ent->target_ent->health > 0) ? ent->target_ent->health : 0) & 0xFF); // Meds up to 140 :( ps->ammo[id] |= (hintTime & 0x0F) << 8; // 4 bits for work on current item (dynamite, weapon repair, etc.) ps->ammo[id] |= (weapHeat & 0x0F) << 12; // 4 bits for weapon heat info ps->ammo[id - 1] = tps->ammo[BG_FindAmmoForWeapon(tps->weapon)] & 0x3FF; // 11 bits needed to cover 1500 Venom ammo ps->ammo[id - 1] |= (BG_simpleWeaponState(tps->weaponstate) & 0x03) << 11; // 2 bits for current weapon state ps->ammo[id - 1] |= ((tps->persistant[PERS_HWEAPON_USE]) ? 1 : 0) << 13; // 1 bit for mg42 use ps->ammo[id - 1] |= (BG_simpleHintsCollapse(tps->serverCursorHint, hintTime) & 0x03) << 14; // 2 bits for cursor hints // G_Printf("tps->hint: %d, dr: %d, collapse: %d\n", tps->serverCursorHint, HINT_DOOR_ROTATING, G_simpleHintsCollapse(tps->serverCursorHint, hintTime)); ps->ammoclip[id - 1] = tps->ammoclip[BG_FindClipForWeapon(tps->weapon)] & 0x1FF; // 9 bits to cover 500 Venom ammo clip ps->ammoclip[id - 1] |= (chargeTime & 0x0F) << 9; // 4 bits for weapon charge time ps->ammoclip[id - 1] |= (sprintTime & 0x07) << 13; // 3 bits for fatigue } return qtrue; }
/** * @brief Drop weapon. */ void G_DropWeapon(gentity_t *ent, weapon_t weapon) { vec3_t angles, velocity, org, offset, mins, maxs; gclient_t *client = ent->client; gentity_t *ent2; gitem_t *item; trace_t tr; if (!IS_VALID_WEAPON(weapon)) { return; } item = BG_FindItemForWeapon(weapon); VectorCopy(client->ps.viewangles, angles); // clamp pitch if (angles[PITCH] < -30) { angles[PITCH] = -30; } else if (angles[PITCH] > 30) { angles[PITCH] = 30; } AngleVectors(angles, velocity, NULL, NULL); VectorScale(velocity, 64, offset); offset[2] += client->ps.viewheight / 2.f; VectorScale(velocity, 75, velocity); velocity[2] += 50 + random() * 35; VectorAdd(client->ps.origin, offset, org); VectorSet(mins, -ITEM_RADIUS, -ITEM_RADIUS, 0); VectorSet(maxs, ITEM_RADIUS, ITEM_RADIUS, 2 * ITEM_RADIUS); trap_Trace(&tr, client->ps.origin, mins, maxs, org, ent->s.number, MASK_SOLID); VectorCopy(tr.endpos, org); ent2 = LaunchItem(item, org, velocity, client->ps.clientNum); COM_BitClear(client->ps.weapons, weapon); switch (weapon) { case WP_KAR98: COM_BitClear(client->ps.weapons, WP_GPG40); break; case WP_CARBINE: COM_BitClear(client->ps.weapons, WP_M7); break; case WP_FG42: COM_BitClear(client->ps.weapons, WP_FG42SCOPE); break; case WP_K43: COM_BitClear(client->ps.weapons, WP_K43_SCOPE); break; case WP_GARAND: COM_BitClear(client->ps.weapons, WP_GARAND_SCOPE); break; case WP_MORTAR: COM_BitClear(client->ps.weapons, WP_MORTAR_SET); break; case WP_MORTAR2: COM_BitClear(client->ps.weapons, WP_MORTAR2_SET); break; case WP_MOBILE_MG42: COM_BitClear(client->ps.weapons, WP_MOBILE_MG42_SET); break; case WP_MOBILE_BROWNING: COM_BitClear(client->ps.weapons, WP_MOBILE_BROWNING_SET); break; default: break; } // Clear out empty weapon, change to next best weapon G_AddEvent(ent, EV_WEAPONSWITCHED, 0); if (weapon == client->ps.weapon) { client->ps.weapon = 0; } if (IS_MORTAR_WEAPON_SET(weapon)) { ent2->count = client->ps.ammo[BG_FindAmmoForWeapon(weapon)] + client->ps.ammoclip[BG_FindClipForWeapon(weapon)]; } else { ent2->count = client->ps.ammoclip[BG_FindClipForWeapon(weapon)]; } if (weapon == WP_KAR98 || weapon == WP_CARBINE) { ent2->delay = client->ps.ammo[BG_FindAmmoForWeapon(weaponTable[weapon].weapAlts)]; } else { ent2->delay = 0; } // ent2->item->quantity = client->ps.ammoclip[BG_FindClipForWeapon(weapon)]; // um, modifying an item is not a good idea client->ps.ammoclip[BG_FindClipForWeapon(weapon)] = 0; #ifdef FEATURE_OMNIBOT Bot_Event_RemoveWeapon(client->ps.clientNum, Bot_WeaponGameToBot(weapon)); #endif }
static int CG_PlayerAmmoValue(int *ammo, int *clips, int *akimboammo) { centity_t *cent; playerState_t *ps; int weap; qboolean skipammo = qfalse; *ammo = *clips = *akimboammo = -1; if (cg.snap->ps.clientNum == cg.clientNum) { cent = &cg.predictedPlayerEntity; } else { cent = &cg_entities[cg.snap->ps.clientNum]; } ps = &cg.snap->ps; weap = cent->currentState.weapon; if (!weap) { return weap; } switch (weap) // some weapons don't draw ammo count text { case WP_AMMO: case WP_MEDKIT: case WP_KNIFE: case WP_PLIERS: case WP_SMOKE_MARKER: case WP_DYNAMITE: case WP_SATCHEL: case WP_SATCHEL_DET: case WP_SMOKE_BOMB: case WP_BINOCULARS: return weap; case WP_LANDMINE: case WP_MEDIC_SYRINGE: case WP_MEDIC_ADRENALINE: case WP_GRENADE_LAUNCHER: case WP_GRENADE_PINEAPPLE: case WP_FLAMETHROWER: case WP_MORTAR: case WP_MORTAR_SET: case WP_PANZERFAUST: skipammo = qtrue; break; default: break; } if (cg.snap->ps.eFlags & EF_MG42_ACTIVE || cg.snap->ps.eFlags & EF_MOUNTEDTANK) { return WP_MOBILE_MG42; } // total ammo in clips *clips = cg.snap->ps.ammo[BG_FindAmmoForWeapon(weap)]; // current clip *ammo = ps->ammoclip[BG_FindClipForWeapon(weap)]; if (BG_IsAkimboWeapon(weap)) { *akimboammo = ps->ammoclip[BG_FindClipForWeapon(BG_AkimboSidearm(weap))]; } else { *akimboammo = -1; } if (weap == WP_LANDMINE) { if (!cgs.gameManager) { *ammo = 0; } else { if (cgs.clientinfo[ps->clientNum].team == TEAM_AXIS) { *ammo = cgs.gameManager->currentState.otherEntityNum; } else { *ammo = cgs.gameManager->currentState.otherEntityNum2; } } } else if (weap == WP_MORTAR || weap == WP_MORTAR_SET || weap == WP_PANZERFAUST) { *ammo += *clips; } if (skipammo) { *clips = -1; } return weap; }
/** * @brief Pick a weapon up. */ int Pickup_Weapon(gentity_t *ent, gentity_t *other) { int quantity; qboolean alreadyHave = qfalse; // magic ammo for any two-handed weapon if (ent->item->giTag == WP_AMMO) { AddMagicAmmo(other, ent->count); if (ent->parent && ent->parent->client) { other->client->pers.lastammo_client = ent->parent->s.clientNum; } // if LT isn't giving ammo to self or another LT or the enemy, give him some props if (other->client->ps.stats[STAT_PLAYER_CLASS] != PC_FIELDOPS) { if (ent->parent && ent->parent->client && other->client->sess.sessionTeam == ent->parent->client->sess.sessionTeam) { if (!(ent->parent->client->PCSpecialPickedUpCount % LT_SPECIAL_PICKUP_MOD)) { AddScore(ent->parent, WOLF_AMMO_UP); if (ent->parent && ent->parent->client) { G_LogPrintf("Ammo_Pack: %d %d\n", (int)(ent->parent - g_entities), (int)(other - g_entities)); } } ent->parent->client->PCSpecialPickedUpCount++; G_AddSkillPoints(ent->parent, SK_SIGNALS, 1.f); G_DebugAddSkillPoints(ent->parent, SK_SIGNALS, 1.f, "ammo pack picked up"); #ifdef FEATURE_OMNIBOT //omni-bot event if (ent->parent) { Bot_Event_RecievedAmmo(other - g_entities, ent->parent); } #endif // extracted code originally here into AddMagicAmmo // add 1 clip of magic ammo for any two-handed weapon } return RESPAWN_NEVER; } } quantity = ent->count; // check if player already had the weapon alreadyHave = COM_BitCheck(other->client->ps.weapons, ent->item->giTag); // prevents drop/pickup weapon "quick reload" exploit if (alreadyHave) { Add_Ammo(other, ent->item->giTag, quantity, qfalse); // secondary weapon ammo if (ent->delay) { Add_Ammo(other, weaponTable[ent->item->giTag].weapAlts, ent->delay, qfalse); } } else { if (level.time - other->client->dropWeaponTime < 1000) { return 0; } // don't pick up when MG or mortar is set if (IS_MORTAR_WEAPON_SET(other->client->ps.weapon) || IS_MG_WEAPON_SET(other->client->ps.weapon)) { return 0; } // see if we can pick it up if (G_CanPickupWeapon(ent->item->giTag, other)) { weapon_t primaryWeapon; if (other->client->sess.playerType == PC_SOLDIER && other->client->sess.skill[SK_HEAVY_WEAPONS] >= 4) { primaryWeapon = G_GetPrimaryWeaponForClientSoldier(ent->item->giTag, other->client); } else { primaryWeapon = G_GetPrimaryWeaponForClient(other->client); } // added parens around ambiguous && if (primaryWeapon) { // drop our primary weapon G_DropWeapon(other, primaryWeapon); // now pickup the other one other->client->dropWeaponTime = level.time; // add the weapon COM_BitSet(other->client->ps.weapons, ent->item->giTag); // fixup mauser/sniper issues switch (ent->item->giTag) { case WP_FG42: COM_BitSet(other->client->ps.weapons, WP_FG42SCOPE); break; case WP_GARAND: COM_BitSet(other->client->ps.weapons, WP_GARAND_SCOPE); break; case WP_K43: COM_BitSet(other->client->ps.weapons, WP_K43_SCOPE); break; case WP_MORTAR: COM_BitSet(other->client->ps.weapons, WP_MORTAR_SET); break; case WP_MORTAR2: COM_BitSet(other->client->ps.weapons, WP_MORTAR2_SET); break; case WP_MOBILE_MG42: COM_BitSet(other->client->ps.weapons, WP_MOBILE_MG42_SET); break; case WP_MOBILE_BROWNING: COM_BitSet(other->client->ps.weapons, WP_MOBILE_BROWNING_SET); break; case WP_CARBINE: COM_BitSet(other->client->ps.weapons, WP_M7); break; case WP_KAR98: COM_BitSet(other->client->ps.weapons, WP_GPG40); break; default: break; } other->client->ps.ammoclip[BG_FindClipForWeapon(ent->item->giTag)] = 0; other->client->ps.ammo[BG_FindAmmoForWeapon(ent->item->giTag)] = 0; if (ent->item->giTag == WP_MORTAR || ent->item->giTag == WP_MORTAR2) { other->client->ps.ammo[BG_FindClipForWeapon(ent->item->giTag)] = quantity; // secondary weapon ammo if (ent->delay) { Add_Ammo(other, weaponTable[ent->item->giTag].weapAlts, ent->delay, qfalse); } } else { other->client->ps.ammoclip[BG_FindClipForWeapon(ent->item->giTag)] = quantity; // secondary weapon ammo if (ent->delay) { other->client->ps.ammo[weaponTable[ent->item->giTag].weapAlts] = ent->delay; } } } } else { return 0; } } #ifdef FEATURE_OMNIBOT Bot_Event_AddWeapon(other->client->ps.clientNum, Bot_WeaponGameToBot(ent->item->giTag)); #endif return RESPAWN_NEVER; }
int Pickup_Weapon( gentity_t *ent, gentity_t *other ) { int quantity; qboolean alreadyHave = qfalse; int i,weapon; // JPW NERVE // JPW NERVE -- magic ammo for any two-handed weapon if ( ent->item->giTag == WP_AMMO ) { // if LT isn't giving ammo to self or another LT or the enemy, give him some props if ( other->client->ps.stats[STAT_PLAYER_CLASS] != PC_LT ) { if ( ent->parent ) { if ( other->client->sess.sessionTeam == ent->parent->client->sess.sessionTeam ) { if ( ent->parent->client ) { if ( !( ent->parent->client->PCSpecialPickedUpCount % LT_SPECIAL_PICKUP_MOD ) ) { AddScore( ent->parent, WOLF_AMMO_UP ); } ent->parent->client->PCSpecialPickedUpCount++; } } } } // everybody likes grenades -- abuse weapon var as grenade type and i as max # grenades class can carry switch ( other->client->ps.stats[STAT_PLAYER_CLASS] ) { case PC_LT: // redundant but added for completeness/flexibility case PC_MEDIC: i = 1; break; case PC_SOLDIER: i = 4; break; case PC_ENGINEER: i = 8; break; default: i = 1; break; } if ( other->client->sess.sessionTeam == TEAM_RED ) { weapon = WP_GRENADE_LAUNCHER; } else { weapon = WP_GRENADE_PINEAPPLE; } if ( other->client->ps.ammoclip[BG_FindClipForWeapon( weapon )] < i ) { other->client->ps.ammoclip[BG_FindClipForWeapon( weapon )]++; } COM_BitSet( other->client->ps.weapons,weapon ); // TTimo - add 8 pistol bullets if ( other->client->sess.sessionTeam == TEAM_RED ) { weapon = WP_LUGER; } else { weapon = WP_COLT; } // G_Printf("filling magazine for weapon %d colt/luger (%d rounds)\n", weapon, ammoTable[weapon].maxclip); other->client->ps.ammo[BG_FindAmmoForWeapon( weapon )] += ammoTable[weapon].maxclip; if ( other->client->ps.ammo[BG_FindAmmoForWeapon( weapon )] > ammoTable[weapon].maxclip * 4 ) { other->client->ps.ammo[BG_FindAmmoForWeapon( weapon )] = ammoTable[weapon].maxclip * 4; } // and some two-handed ammo for ( i = 0; i < MAX_WEAPS_IN_BANK_MP; i++ ) { weapon = weapBanksMultiPlayer[3][i]; if ( COM_BitCheck( other->client->ps.weapons, weapon ) ) { // G_Printf("filling magazine for weapon %d (%d rounds)\n",weapon,ammoTable[weapon].maxclip); if ( weapon == WP_FLAMETHROWER ) { // FT doesn't use magazines so refill tank other->client->ps.ammoclip[BG_FindAmmoForWeapon( WP_FLAMETHROWER )] = ammoTable[weapon].maxclip; } else { other->client->ps.ammo[BG_FindAmmoForWeapon( weapon )] += ammoTable[weapon].maxclip; if ( other->client->ps.ammo[BG_FindAmmoForWeapon( weapon )] > ammoTable[weapon].maxclip * 3 ) { other->client->ps.ammo[BG_FindAmmoForWeapon( weapon )] = ammoTable[weapon].maxclip * 3; } } return RESPAWN_SP; } } return RESPAWN_SP; } // jpw if ( ent->count < 0 ) { quantity = 0; // None for you, sir! } else { if ( ent->count ) { quantity = ent->count; } else { //----(SA) modified // JPW NERVE did this so ammocounts work right on dropped weapons if ( g_gametype.integer != GT_SINGLE_PLAYER ) { quantity = ent->item->quantity; } else { // jpw quantity = ( random() * ( ent->item->quantity - 1 ) ) + 1; // giving 1-<item default count> } } } // check if player already had the weapon alreadyHave = COM_BitCheck( other->client->ps.weapons, ent->item->giTag ); // add the weapon COM_BitSet( other->client->ps.weapons, ent->item->giTag ); // DHM - Fixup mauser/sniper issues if ( ent->item->giTag == WP_MAUSER ) { COM_BitSet( other->client->ps.weapons, WP_SNIPERRIFLE ); } if ( ent->item->giTag == WP_SNIPERRIFLE ) { COM_BitSet( other->client->ps.weapons, WP_MAUSER ); } //----(SA) added // snooper == automatic garand mod if ( ent->item->giTag == WP_SNOOPERSCOPE ) { COM_BitSet( other->client->ps.weapons, WP_GARAND ); } // fg42scope == automatic fg42 mod else if ( ent->item->giTag == WP_FG42SCOPE ) { COM_BitSet( other->client->ps.weapons, WP_FG42 ); } else if ( ent->item->giTag == WP_GARAND ) { COM_BitSet( other->client->ps.weapons, WP_SNOOPERSCOPE ); } //----(SA) end // JPW NERVE prevents drop/pickup weapon "quick reload" exploit if ( alreadyHave ) { Add_Ammo( other, ent->item->giTag, quantity, !alreadyHave ); } else { other->client->ps.ammoclip[BG_FindClipForWeapon( ent->item->giTag )] = quantity; } // jpw // single player has no respawns (SA) if ( g_gametype.integer == GT_SINGLE_PLAYER ) { return RESPAWN_SP; } if ( g_gametype.integer == GT_TEAM ) { return g_weaponTeamRespawn.integer; } return g_weaponRespawn.integer; }
/* ================= TossClientItems Toss the weapon and powerups for the killed player ================= */ void TossClientItems( gentity_t *self ) { gitem_t *item; vec3_t forward; int weapon; float angle; int i; gentity_t *drop = 0; // drop the weapon if not a gauntlet or machinegun weapon = self->s.weapon; switch ( self->aiCharacter ) { case AICHAR_ZOMBIE: case AICHAR_WARZOMBIE: case AICHAR_LOPER: return; //----(SA) removed DK's special case default: break; } AngleVectors( self->r.currentAngles, forward, NULL, NULL ); G_ThrowChair( self, forward, qtrue ); // drop chair if you're holding one //----(SA) added // make a special check to see if they are changing to a new // weapon that isn't the mg or gauntlet. Without this, a client // can pick up a weapon, be killed, and not drop the weapon because // their weapon change hasn't completed yet and they are still holding the MG. // (SA) always drop what you were switching to if ( 1 ) { // if ( weapon == WP_MACHINEGUN || weapon == WP_GRAPPLING_HOOK ) { if ( self->client->ps.weaponstate == WEAPON_DROPPING || self->client->ps.weaponstate == WEAPON_DROPPING_TORELOAD ) { weapon = self->client->pers.cmd.weapon; } if ( !( COM_BitCheck( self->client->ps.weapons, weapon ) ) ) { weapon = WP_NONE; } } //----(SA) added if ( weapon == WP_SNOOPERSCOPE ) { weapon = WP_GARAND; } if ( weapon == WP_FG42SCOPE ) { weapon = WP_FG42; } if ( weapon == WP_AKIMBO ) { //----(SA) added weapon = WP_COLT; } //----(SA) end if ( weapon > WP_NONE && weapon < WP_MONSTER_ATTACK1 && self->client->ps.ammo[ BG_FindAmmoForWeapon( weapon )] ) { // find the item type for this weapon item = BG_FindItemForWeapon( weapon ); // spawn the item // Rafael if ( !( self->client->ps.persistant[PERS_HWEAPON_USE] ) ) { drop = Drop_Item( self, item, 0, qfalse ); } } if ( g_gametype.integer == GT_SINGLE_PLAYER ) { // dropped items stay forever in SP if ( drop ) { drop->nextthink = 0; } } if ( g_gametype.integer != GT_TEAM ) { // drop all the powerups if not in teamplay angle = 45; for ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) { if ( self->client->ps.powerups[ i ] > level.time ) { item = BG_FindItemForPowerup( i ); if ( !item ) { continue; } drop = Drop_Item( self, item, angle, qfalse ); // decide how many seconds it has left drop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000; if ( drop->count < 1 ) { drop->count = 1; } drop->nextthink = 0; // stay forever angle += 45; } } } }