/** * @brief Get the primary weapon of the client. * @return the primary weapon of the client */ weapon_t G_GetPrimaryWeaponForClient(gclient_t *client) { int i; bg_playerclass_t *classInfo; if (client->sess.sessionTeam != TEAM_ALLIES && client->sess.sessionTeam != TEAM_AXIS) { return WP_NONE; } if (client->sess.skill[SK_HEAVY_WEAPONS] < 4) { if (COM_BitCheck(client->ps.weapons, WP_THOMPSON)) { return WP_THOMPSON; } if (COM_BitCheck(client->ps.weapons, WP_MP40)) { return WP_MP40; } } classInfo = &bg_allies_playerclasses[client->sess.playerType]; for (i = 0; i < MAX_WEAPS_PER_CLASS; i++) { if (classInfo->classWeapons[i] == WP_MP40 || classInfo->classWeapons[i] == WP_THOMPSON) { continue; } if (COM_BitCheck(client->ps.weapons, classInfo->classWeapons[i])) { return classInfo->classWeapons[i]; } } classInfo = &bg_axis_playerclasses[client->sess.playerType]; for (i = 0; i < MAX_WEAPS_PER_CLASS; i++) { if (classInfo->classWeapons[i] == WP_MP40 || classInfo->classWeapons[i] == WP_THOMPSON) { continue; } if (COM_BitCheck(client->ps.weapons, classInfo->classWeapons[i])) { return classInfo->classWeapons[i]; } } return WP_NONE; }
/** * @brief Auto action when touching an item. * * PICKUP_ACTIVATE (0), he will pick up items only when using +activate * PICKUP_TOUCH (1), he will pickup items when touched * PICKUP_FORCE (2), he will pickup the next item when touched (and reset to PICKUP_ACTIVATE when done) */ void Touch_Item_Auto(gentity_t *ent, gentity_t *other, trace_t *trace) { if (other->client->pers.autoActivate == PICKUP_ACTIVATE) { return; } if (!ent->active && ent->item->giType == IT_WEAPON) { if (ent->item->giTag != WP_AMMO) { if (!COM_BitCheck(other->client->ps.weapons, ent->item->giTag)) { return; // force activate only } } } ent->active = qtrue; Touch_Item(ent, other, trace); if (other->client->pers.autoActivate == PICKUP_FORCE) // autoactivate probably forced by the "Cmd_Activate_f()" function { other->client->pers.autoActivate = PICKUP_ACTIVATE; // so reset it. } }
weapon_t G_GetPrimaryWeaponForClient( gclient_t *client ) { int i; bg_playerclass_t *classInfo; if( client->sess.sessionTeam != TEAM_ALLIES && client->sess.sessionTeam != TEAM_AXIS ) { return WP_NONE; } if( client->sess.skill[SK_HEAVY_WEAPONS] < 4 || client->sess.playerType != PC_SOLDIER) { if( COM_BitCheck( client->ps.weapons, WP_THOMPSON ) ) return WP_THOMPSON; if( COM_BitCheck( client->ps.weapons, WP_MP40 ) ) return WP_MP40; } classInfo = &bg_allies_playerclasses[client->sess.playerType]; // pheno: unlock weapons for allied team BG_UnlockWeapons(classInfo, client->sess.playerType, client->sess.sessionTeam); for( i = 0; i < MAX_WEAPS_PER_CLASS; i++) { if( classInfo->classWeapons[i] == WP_MP40 || classInfo->classWeapons[i] == WP_THOMPSON ) continue; if( COM_BitCheck( client->ps.weapons, classInfo->classWeapons[i] ) ) { return classInfo->classWeapons[i]; } } classInfo = &bg_axis_playerclasses[client->sess.playerType]; // pheno: unlock weapons for axis team BG_UnlockWeapons(classInfo, client->sess.playerType, client->sess.sessionTeam); for( i = 0; i < MAX_WEAPS_PER_CLASS; i++) { if( classInfo->classWeapons[i] == WP_MP40 || classInfo->classWeapons[i] == WP_THOMPSON ) continue; if( COM_BitCheck( client->ps.weapons, classInfo->classWeapons[i] ) ) { return classInfo->classWeapons[i]; } } return WP_NONE; }
/** * @brief Parses fireteam servercommand */ void CG_ParseFireteams() { int i, j; char *s; const char *p; int clnts[2]; for (i = 0; i < MAX_CLIENTS; i++) { cgs.clientinfo[i].fireteamData = NULL; } for (i = 0; i < MAX_FIRETEAMS; i++) { char hexbuffer[11] = "0x00000000"; p = CG_ConfigString(CS_FIRETEAMS + i); j = atoi(Info_ValueForKey(p, "id")); if (j == -1) { cg.fireTeams[i].inuse = qfalse; continue; } else { cg.fireTeams[i].inuse = qtrue; cg.fireTeams[i].ident = j; } s = Info_ValueForKey(p, "l"); cg.fireTeams[i].leader = atoi(s); s = Info_ValueForKey(p, "p"); cg.fireTeams[i].priv = (qboolean)atoi(s); s = Info_ValueForKey(p, "c"); Q_strncpyz(hexbuffer + 2, s, 9); sscanf(hexbuffer, "%x", &clnts[1]); Q_strncpyz(hexbuffer + 2, s + 8, 9); sscanf(hexbuffer, "%x", &clnts[0]); for (j = 0; j < cgs.maxclients; j++) { if (COM_BitCheck(clnts, j)) { cg.fireTeams[i].joinOrder[j] = qtrue; cgs.clientinfo[j].fireteamData = &cg.fireTeams[i]; //CG_Printf("%s\n", cgs.clientinfo[j].name); } else { cg.fireTeams[i].joinOrder[j] = qfalse; } } } CG_SortClientFireteam(); }
char *AIFunc_StimSoldierAttack1Start( cast_state_t *cs ) { gentity_t *ent; //static vec3_t mins={-96,-96,0}, maxs={96,96,72}; vec3_t pos, dir; trace_t tr; // cs->weaponFireTimes[cs->bs->weaponnum] = level.time; ent = &g_entities[cs->entityNum]; // // face them AICast_AimAtEnemy( cs ); // first, check if this is a good place to start the flying attack AngleVectors( cs->bs->ideal_viewangles, dir, NULL, NULL ); VectorMA( cs->bs->origin, 300, dir, pos ); pos[2] += 128; trap_Trace( &tr, cs->bs->origin, cs->bs->cur_ps.mins, cs->bs->cur_ps.maxs, pos, cs->entityNum, MASK_PLAYERSOLID ); if ( tr.startsolid || tr.allsolid ) { return NULL; // not a good place } // check we can attack them from there // select our special weapon (rocket launcher or tesla) if ( COM_BitCheck( cs->bs->cur_ps.weapons, WP_ROCKET_LAUNCHER ) ) { cs->bs->weaponnum = WP_ROCKET_LAUNCHER; } else if ( COM_BitCheck( cs->bs->cur_ps.weapons, WP_TESLA ) ) { cs->bs->weaponnum = WP_TESLA; } else { // no weapon? G_Error( "stim soldier tried special jump attack without a tesla or rocket launcher\n" ); } if ( !AICast_CheckAttackAtPos( cs->entityNum, cs->bs->enemy, pos, qfalse, qfalse ) ) { AICast_ChooseWeapon( cs, qfalse ); return NULL; } // play the animation ent->client->ps.legsAnim = ( ( ent->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | STIMSOLDIER_FLYJUMP_ANIM; ent->client->ps.legsTimer = STIMSOLDIER_FLYJUMP_DELAY; // stay down until attack is finished // cs->aiFlags &= ~AIFL_LAND_ANIM_PLAYED; // play the buildup sound // TODO // cs->aifunc = AIFunc_StimSoldierAttack1; return "AIFunc_StimSoldierAttack1"; }
// Nico, check if ew can follow a given client qboolean G_AllowFollow(gentity_t *ent, gentity_t *other) { // Nico, only referee can spec in cup mode if (g_cupMode.integer != 0 && ent->client->sess.referee != RL_REFEREE) { return qfalse; } return !other->client->sess.specLocked || COM_BitCheck(other->client->sess.specInvitedClients, ent - g_entities) || ent->client->sess.referee == RL_REFEREE; }
/** * @brief G_GetSecondaryWeaponForClient * @param[in] client * @param primary - unused * @return * * @note Unused */ weapon_t G_GetSecondaryWeaponForClient(gclient_t *client, weapon_t primary) { weapon_t secondary = WP_NONE; // early out if not on a team if (client->sess.sessionTeam != TEAM_ALLIES && client->sess.sessionTeam != TEAM_AXIS) { return WP_NONE; } // Record our secondary weapon (usually a pistol sidearm) // Colts if (COM_BitCheck(client->ps.weapons, WP_AKIMBO_SILENCEDCOLT)) { secondary = WP_AKIMBO_SILENCEDCOLT; } else if (COM_BitCheck(client->ps.weapons, WP_AKIMBO_COLT)) { secondary = WP_AKIMBO_COLT; } else if (COM_BitCheck(client->ps.weapons, WP_SILENCED_COLT)) { secondary = WP_SILENCED_COLT; } else if (COM_BitCheck(client->ps.weapons, WP_COLT)) { secondary = WP_COLT; } // Lugers else if (COM_BitCheck(client->ps.weapons, WP_AKIMBO_SILENCEDLUGER)) { secondary = WP_AKIMBO_SILENCEDLUGER; } else if (COM_BitCheck(client->ps.weapons, WP_AKIMBO_LUGER)) { secondary = WP_AKIMBO_LUGER; } else if (COM_BitCheck(client->ps.weapons, WP_SILENCER)) { secondary = WP_SILENCER; } else if (COM_BitCheck(client->ps.weapons, WP_LUGER)) { secondary = WP_LUGER; } return secondary; }
/* ================= 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 } } }
qboolean G_CanPickupWeapon( weapon_t weapon, gentity_t* ent ) { // tjw: don't let players pick up a weapon they are // already holding. if(COM_BitCheck(ent->client->ps.weapons, weapon)) return qfalse; if( ent->client->sess.sessionTeam == TEAM_AXIS ) { if( weapon == WP_THOMPSON ) { weapon = WP_MP40; } else if( weapon == WP_CARBINE ) { weapon = WP_KAR98; } else if( weapon == WP_GARAND ) { weapon = WP_K43; } } else if( ent->client->sess.sessionTeam == TEAM_ALLIES ) { if( weapon == WP_MP40 ) { weapon = WP_THOMPSON; } else if( weapon == WP_KAR98 ) { weapon = WP_CARBINE; } else if( weapon == WP_K43 ) { weapon = WP_GARAND; } } if( g_unlockDropWeapons.integer ) { return qtrue; } // tjw: check heavy weapon restrictions if(G_IsWeaponDisabled(ent, weapon, ent->client->sess.sessionTeam, qtrue)) { return qfalse; } return BG_WeaponIsPrimaryForClassAndTeam( ent->client->sess.playerType, ent->client->sess.sessionTeam, weapon ); }
/* ============== Touch_Item if other->client->pers.autoActivate == PICKUP_ACTIVATE (0), he will pick up items only when using +activate if other->client->pers.autoActivate == PICKUP_TOUCH (1), he will pickup items when touched if other->client->pers.autoActivate == PICKUP_FORCE (2), he will pickup the next item when touched (and reset to PICKUP_ACTIVATE when done) ============== */ void Touch_Item_Auto( gentity_t *ent, gentity_t *other, trace_t *trace ) { if( other->client->pers.autoActivate == PICKUP_ACTIVATE ) return; if( !ent->active && ent->item->giType == IT_WEAPON ) { if( ent->item->giTag != WP_AMMO && ent->item->giTag != WP_BINOCULARS ) { if ( G_GetPrimaryWeaponForClient(other->client) || (!BG_WeaponIsPrimaryForClassAndTeam( other->client->sess.playerType, TEAM_ALLIES, ent->item->giTag ) && !BG_WeaponIsPrimaryForClassAndTeam( other->client->sess.playerType, TEAM_AXIS, ent->item->giTag ) ) ) { if( !COM_BitCheck( other->client->ps.weapons, ent->item->giTag ) ) { return; // force activate only } } } } ent->active = qtrue; Touch_Item( ent, other, trace ); if( other->client->pers.autoActivate == PICKUP_FORCE ) // autoactivate probably forced by the "Cmd_Activate_f()" function other->client->pers.autoActivate = PICKUP_ACTIVATE; // so reset it. }
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; }
// ************** PLAYERS // // Show client info void G_players_cmd(gentity_t *ent, unsigned int dwCommand, qboolean fValue) { int i, idnum, max_rate, cnt=0, tteam; int user_rate, user_snaps, bots = 0; gclient_t *cl; gentity_t *cl_ent; char n2[MAX_NETNAME], ready[16], ref[16], ign[16], rate[256]; char *s, *tc, *coach, userinfo[MAX_INFO_STRING]; if(g_gamestate.integer == GS_PLAYING) { if(ent) { CP("print \"\n^3 ID^1 : ^3Player Nudge Rate MaxPkts Snaps\n\""); CP( "print \"^1-----------------------------------------------------------^7\n\""); } else { G_Printf(" ID : Player Nudge Rate MaxPkts Snaps\n"); G_Printf("-----------------------------------------------------------\n"); } } else { if(ent) { CP("print \"\n^3Status^1 : ^3ID^1 : ^3Player Nudge Rate MaxPkts Snaps\n\""); CP( "print \"^1---------------------------------------------------------------------^7\n\""); } else { G_Printf("Status : ID : Player Nudge Rate MaxPkts Snaps\n"); G_Printf("---------------------------------------------------------------------\n"); } } max_rate = trap_Cvar_VariableIntegerValue("sv_maxrate"); for(i=0; i<level.numConnectedClients; i++) { idnum = level.sortedClients[i];//level.sortedNames[i]; cl = &level.clients[idnum]; cl_ent = g_entities + idnum; SanitizeString(cl->pers.netname, n2, qtrue); n2[26] = 0; ref[0] = 0; ign[0] = 0; ready[0] = 0; // Rate info if(cl_ent->r.svFlags & SVF_BOT) { strcpy(rate, va("%s%s%s%s", "[BOT]", " -----", " --", " --")); bots++; } else if(cl->pers.connected == CON_CONNECTING) { strcpy(rate, va("%s", "^3>>> CONNECTING <<<")); } else { trap_GetUserinfo( idnum, userinfo, sizeof(userinfo)); s = Info_ValueForKey( userinfo, "rate" ); user_rate = (max_rate > 0 && atoi(s) > max_rate) ? max_rate : atoi(s); s = Info_ValueForKey( userinfo, "snaps" ); user_snaps = atoi(s); strcpy(rate, va("%5d%6d%9d%7d", cl->pers.clientTimeNudge, user_rate, cl->pers.clientMaxPackets, user_snaps)); } if(g_gamestate.integer != GS_PLAYING) { // Dens: bots aren't counted, but specs are since changeset 1469 if((g_entities[idnum].r.svFlags & SVF_BOT) || cl->pers.connected == CON_CONNECTING) strcpy(ready, ((ent) ? "^5--------^1 :" : "-------- :")); else if(cl->pers.ready) strcpy(ready, ((ent) ? "^3(READY)^1 :" : "(READY) :")); else strcpy(ready, ((ent) ? "NOTREADY^1 :" : "NOTREADY :")); } if(cl->sess.referee) strcpy(ref, "REF "); // pheno: mark ignored clients if ( COM_BitCheck(ent->client->sess.ignoreClients, idnum) ) { strcpy(ign, (( ent ) ? "^8I" : "I")); } if(cl->sess.coach_team) { tteam = cl->sess.coach_team; coach = (ent) ? "^3C" : "C"; } else { tteam = cl->sess.sessionTeam; coach = " "; } tc = (ent) ? "^7 " : " "; if(g_gametype.integer >= GT_WOLF) { if(tteam == TEAM_AXIS) tc = (ent) ? "^1X^7" : "X"; if(tteam == TEAM_ALLIES) tc = (ent) ? "^4L^7" : "L"; } if(ent) CP(va("print \"%s%s%2d%s^1:%s %-26s^7%s ^3%s%s\n\"", ready, tc, idnum, coach, ((ref[0])?"^3":"^7"), n2, rate, ref, ign)); else G_Printf("%s%s%2d%s: %-26s%s %s%s\n", ready, tc, idnum, coach, n2, rate, ref, ign); cnt++; } if(ent) CP(va("print \"\n^3%2d^7 total players (^3%2d^7 humans, ^3%2d^7 bots)\n\n\"", cnt, cnt - bots, bots)); else G_Printf("\n%2d total players (%2d humans, %2d bots\n\n", cnt, cnt - bots, bots); // Team speclock info if(g_gametype.integer >= GT_WOLF) { for(i=TEAM_AXIS; i<=TEAM_ALLIES; i++) { if(teamInfo[i].spec_lock) { if(ent) CP(va("print \"** %s team is speclocked.\n\"", aTeams[i])); else G_Printf("** %s team is speclocked.\n", aTeams[i]); } } } }
// Parses fireteam servercommand void CG_ParseFireteams() { int i, j; char *s; const char *p; int clnts[2]; qboolean onFireteam2; qboolean isLeader2; // qboolean onFireteam = CG_IsOnFireteam( cg.clientNum ) ? qtrue : qfalse; // qboolean isLeader = CG_IsFireTeamLeader( cg.clientNum ) ? qtrue : qfalse; for (i = 0; i < MAX_CLIENTS; i++) { cgs.clientinfo[i].fireteamData = NULL; } for (i = 0; i < MAX_FIRETEAMS; i++) { char hexbuffer[11] = "0x00000000"; p = CG_ConfigString(CS_FIRETEAMS + i); /* s = Info_ValueForKey(p, "n"); if(!s || !*s) { cg.fireTeams[i].inuse = qfalse; continue; } else { cg.fireTeams[i].inuse = qtrue; }*/ // Q_strncpyz(cg.fireTeams[i].name, s, 32); // CG_Printf("Fireteam: %s\n", cg.fireTeams[i].name); j = atoi(Info_ValueForKey(p, "id")); if (j == -1) { cg.fireTeams[i].inuse = qfalse; continue; } else { cg.fireTeams[i].inuse = qtrue; cg.fireTeams[i].ident = j; } s = Info_ValueForKey(p, "l"); cg.fireTeams[i].leader = atoi(s); s = Info_ValueForKey(p, "c"); Q_strncpyz(hexbuffer + 2, s, 9); sscanf(hexbuffer, "%x", &clnts[1]); Q_strncpyz(hexbuffer + 2, s + 8, 9); sscanf(hexbuffer, "%x", &clnts[0]); for (j = 0; j < MAX_CLIENTS; j++) { if (COM_BitCheck(clnts, j)) { cg.fireTeams[i].joinOrder[j] = qtrue; cgs.clientinfo[j].fireteamData = &cg.fireTeams[i]; // CG_Printf("%s\n", cgs.clientinfo[j].name); } else { cg.fireTeams[i].joinOrder[j] = qfalse; } } } CG_SortClientFireteam(); onFireteam2 = CG_IsOnFireteam(cg.clientNum) ? qtrue : qfalse; isLeader2 = CG_IsFireTeamLeader(cg.clientNum) ? qtrue : qfalse; }
/** * @brief G_ResetXP * @param[in,out] ent */ void G_ResetXP(gentity_t *ent) { int i = 0; int ammo[MAX_WEAPONS], ammoclip[MAX_WEAPONS]; int oldWeapon; //, newWeapon; if (!ent || !ent->client) { return; } #ifdef FEATURE_RATING if (!g_skillRating.integer) #endif { ent->client->sess.rank = 0; } for (i = 0; i < SK_NUM_SKILLS; i++) { ent->client->sess.skillpoints[i] = 0.0f; ent->client->sess.skill[i] = 0; } G_CalcRank(ent->client); ent->client->ps.stats[STAT_XP] = 0; ent->client->ps.persistant[PERS_SCORE] = 0; // zero out all weapons and grab the default weapons for a player of this XP level. // backup.. Com_Memcpy(ammo, ent->client->ps.ammo, sizeof(ammo)); Com_Memcpy(ammoclip, ent->client->ps.ammoclip, sizeof(ammoclip)); oldWeapon = ent->client->ps.weapon; // Check weapon validity, maybe dump some weapons for this (now) unskilled player.. // It also sets the (possibly new) amounts of ammo for weapons. SetWolfSpawnWeapons(ent->client); // restore.. //newWeapon = ent->client->ps.weapon; for (i = WP_NONE; i < WP_NUM_WEAPONS; ++i) //i<MAX_WEAPONS { // only restore ammo for valid weapons.. // ..they might have lost some weapons because of skill changes. // Also restore to the old amount of ammo, because.. // ..SetWolfSpawnWeapons sets amount of ammo for a fresh spawning player, // which is usually more than the player currently has left. if (COM_BitCheck(ent->client->ps.weapons, i)) { if (ammo[i] < ent->client->ps.ammo[i]) { ent->client->ps.ammo[i] = ammo[i]; } if (ammoclip[i] < ent->client->ps.ammoclip[i]) { ent->client->ps.ammoclip[i] = ammoclip[i]; } } else { ent->client->ps.ammo[i] = 0; ent->client->ps.ammoclip[i] = 0; } } // check if the old weapon is still valid. // If so, restore to the last used weapon.. if (COM_BitCheck(ent->client->ps.weapons, oldWeapon)) { ent->client->ps.weapon = oldWeapon; } ClientUserinfoChanged(ent - g_entities); }
/* ============== ClientThink This will be called once for each client frame, which will usually be a couple times for each server frame on fast clients. If "g_synchronousClients 1" is set, this will be called exactly once for each server frame, which makes for smooth demo recording. ============== */ void ClientThink_real( gentity_t *ent ) { gclient_t *client; pmove_t pm; // vec3_t oldOrigin; int oldEventSequence; int msec; usercmd_t *ucmd; int monsterslick = 0; // JPW NERVE int i; vec3_t muzzlebounce; gitem_t *item; gentity_t *ent2; vec3_t velocity, org, offset; vec3_t angles,mins,maxs; int weapon; trace_t tr; // jpw // Rafael wolfkick //int validkick; //static int wolfkicktimer = 0; client = ent->client; // don't think if the client is not yet connected (and thus not yet spawned in) if ( client->pers.connected != CON_CONNECTED ) { return; } if ( client->cameraPortal ) { G_SetOrigin( client->cameraPortal, client->ps.origin ); trap_LinkEntity( client->cameraPortal ); VectorCopy( client->cameraOrigin, client->cameraPortal->s.origin2 ); } // mark the time, so the connection sprite can be removed ucmd = &ent->client->pers.cmd; ent->client->ps.identifyClient = ucmd->identClient; // NERVE - SMF // JPW NERVE -- update counter for capture & hold display if ( g_gametype.integer == GT_WOLF_CPH ) { client->ps.stats[STAT_CAPTUREHOLD_RED] = level.capturetimes[TEAM_RED]; client->ps.stats[STAT_CAPTUREHOLD_BLUE] = level.capturetimes[TEAM_BLUE]; } // jpw // sanity check the command time to prevent speedup cheating if ( ucmd->serverTime > level.time + 200 ) { ucmd->serverTime = level.time + 200; // G_Printf("serverTime <<<<<\n" ); } if ( ucmd->serverTime < level.time - 1000 ) { ucmd->serverTime = level.time - 1000; // G_Printf("serverTime >>>>>\n" ); } msec = ucmd->serverTime - client->ps.commandTime; // following others may result in bad times, but we still want // to check for follow toggles if ( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) { return; /* // Ridah, fixes savegame timing issue if (msec < -100) { client->ps.commandTime = ucmd->serverTime - 100; msec = 100; } else { return; } */ // done. } if ( msec > 200 ) { msec = 200; } if ( pmove_msec.integer < 8 ) { trap_Cvar_Set( "pmove_msec", "8" ); } else if ( pmove_msec.integer > 33 ) { trap_Cvar_Set( "pmove_msec", "33" ); } if ( pmove_fixed.integer || client->pers.pmoveFixed ) { ucmd->serverTime = ( ( ucmd->serverTime + pmove_msec.integer - 1 ) / pmove_msec.integer ) * pmove_msec.integer; //if (ucmd->serverTime - client->ps.commandTime <= 0) // return; } // // check for exiting intermission // if ( level.intermissiontime ) { ClientIntermissionThink( client ); return; } // spectators don't do much // DHM - Nerve :: In limbo use SpectatorThink if ( client->sess.sessionTeam == TEAM_SPECTATOR || client->ps.pm_flags & PMF_LIMBO ) { if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) { return; } SpectatorThink( ent, ucmd ); return; } // JPW NERVE do some time-based muzzle flip -- this never gets touched in single player (see g_weapon.c) // #define RIFLE_SHAKE_TIME 150 // JPW NERVE this one goes with the commented out old damped "realistic" behavior below #define RIFLE_SHAKE_TIME 300 // per Id request, longer recoil time if ( client->sniperRifleFiredTime ) { if ( level.time - client->sniperRifleFiredTime > RIFLE_SHAKE_TIME ) { client->sniperRifleFiredTime = 0; } else { VectorCopy( client->ps.viewangles,muzzlebounce ); // JPW per Id request, longer recoil time muzzlebounce[PITCH] -= 2 * cos( 2.5 * ( level.time - client->sniperRifleFiredTime ) / RIFLE_SHAKE_TIME ); muzzlebounce[YAW] += 0.5*client->sniperRifleMuzzleYaw*cos( 1.0 - ( level.time - client->sniperRifleFiredTime ) * 3 / RIFLE_SHAKE_TIME ); muzzlebounce[PITCH] -= 0.25 * random() * ( 1.0f - ( level.time - client->sniperRifleFiredTime ) / RIFLE_SHAKE_TIME ); muzzlebounce[YAW] += 0.5 * crandom() * ( 1.0f - ( level.time - client->sniperRifleFiredTime ) / RIFLE_SHAKE_TIME ); SetClientViewAngle( ent,muzzlebounce ); } } if ( client->ps.stats[STAT_PLAYER_CLASS] == PC_MEDIC ) { if ( level.time > client->ps.powerups[PW_REGEN] + 5000 ) { client->ps.powerups[PW_REGEN] = level.time; } } // also update weapon recharge time // JPW drop button drops secondary weapon so new one can be picked up // TTimo explicit braces to avoid ambiguous 'else' if ( g_gametype.integer != GT_SINGLE_PLAYER ) { if ( ucmd->wbuttons & WBUTTON_DROP ) { if ( !client->dropWeaponTime ) { client->dropWeaponTime = 1; // just latch it for now if ( ( client->ps.stats[STAT_PLAYER_CLASS] == PC_SOLDIER ) || ( client->ps.stats[STAT_PLAYER_CLASS] == PC_LT ) ) { for ( i = 0; i < MAX_WEAPS_IN_BANK_MP; i++ ) { weapon = weapBanksMultiPlayer[3][i]; if ( COM_BitCheck( client->ps.weapons,weapon ) ) { 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; 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_MAUSER ) { COM_BitClear( client->ps.weapons,WP_SNIPERRIFLE ); } // Clear out empty weapon, change to next best weapon G_AddEvent( ent, EV_NOAMMO, 0 ); i = MAX_WEAPS_IN_BANK_MP; // show_bug.cgi?id=568 if ( client->ps.weapon == weapon ) { client->ps.weapon = 0; } ent2->count = client->ps.ammoclip[BG_FindClipForWeapon( weapon )]; ent2->item->quantity = client->ps.ammoclip[BG_FindClipForWeapon( weapon )]; client->ps.ammoclip[BG_FindClipForWeapon( weapon )] = 0; } } } } } else { client->dropWeaponTime = 0; } } // jpw // check for inactivity timer, but never drop the local client of a non-dedicated server if ( !ClientInactivityTimer( client ) ) { return; } if ( reloading || client->cameraPortal ) { ucmd->buttons = 0; ucmd->forwardmove = 0; ucmd->rightmove = 0; ucmd->upmove = 0; ucmd->wbuttons = 0; ucmd->wolfkick = 0; if ( client->cameraPortal ) { client->ps.pm_type = PM_FREEZE; } } else if ( client->noclip ) { client->ps.pm_type = PM_NOCLIP; } else if ( client->ps.stats[STAT_HEALTH] <= 0 ) { client->ps.pm_type = PM_DEAD; } else { client->ps.pm_type = PM_NORMAL; } // set parachute anim condition flag BG_UpdateConditionValue( ent->s.number, ANIM_COND_PARACHUTE, ( ent->flags & FL_PARACHUTE ) != 0, qfalse ); // all playing clients are assumed to be in combat mode if ( !client->ps.aiChar ) { client->ps.aiState = AISTATE_COMBAT; } client->ps.gravity = g_gravity.value; // set speed client->ps.speed = g_speed.value; if ( client->ps.powerups[PW_HASTE] ) { client->ps.speed *= 1.3; } // set up for pmove oldEventSequence = client->ps.eventSequence; client->currentAimSpreadScale = (float)client->ps.aimSpreadScale / 255.0; memset( &pm, 0, sizeof( pm ) ); pm.ps = &client->ps; pm.pmext = &client->pmext; pm.cmd = *ucmd; pm.oldcmd = client->pers.oldcmd; if ( pm.ps->pm_type == PM_DEAD ) { pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; // DHM-Nerve added:: EF_DEAD is checked for in Pmove functions, but wasn't being set // until after Pmove pm.ps->eFlags |= EF_DEAD; // dhm-Nerve end } else { pm.tracemask = MASK_PLAYERSOLID; } // MrE: always use capsule for AI and player //pm.trace = trap_TraceCapsule;//trap_Trace; //DHM - Nerve :: We've gone back to using normal bbox traces pm.trace = trap_Trace; pm.pointcontents = trap_PointContents; pm.debugLevel = g_debugMove.integer; pm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0; pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed; pm.pmove_msec = pmove_msec.integer; pm.noWeapClips = ( g_dmflags.integer & DF_NO_WEAPRELOAD ) > 0; if ( ent->aiCharacter && AICast_NoReload( ent->s.number ) ) { pm.noWeapClips = qtrue; // ensure AI characters don't use clips if they're not supposed to. } // Ridah // if (ent->r.svFlags & SVF_NOFOOTSTEPS) // pm.noFootsteps = qtrue; VectorCopy( client->ps.origin, client->oldOrigin ); // NERVE - SMF pm.gametype = g_gametype.integer; pm.ltChargeTime = g_LTChargeTime.integer; pm.soldierChargeTime = g_soldierChargeTime.integer; pm.engineerChargeTime = g_engineerChargeTime.integer; pm.medicChargeTime = g_medicChargeTime.integer; // -NERVE - SMF monsterslick = Pmove( &pm ); if ( monsterslick && !( ent->flags & FL_NO_MONSTERSLICK ) ) { //vec3_t dir; //vec3_t kvel; //vec3_t forward; // TTimo gcc: might be used unitialized in this function float angle = 0.0f; qboolean bogus = qfalse; // NE if ( ( monsterslick & SURF_MONSLICK_N ) && ( monsterslick & SURF_MONSLICK_E ) ) { angle = 45; } // NW else if ( ( monsterslick & SURF_MONSLICK_N ) && ( monsterslick & SURF_MONSLICK_W ) ) { angle = 135; } // N else if ( monsterslick & SURF_MONSLICK_N ) { angle = 90; } // SE else if ( ( monsterslick & SURF_MONSLICK_S ) && ( monsterslick & SURF_MONSLICK_E ) ) { angle = 315; } // SW else if ( ( monsterslick & SURF_MONSLICK_S ) && ( monsterslick & SURF_MONSLICK_W ) ) { angle = 225; } // S else if ( monsterslick & SURF_MONSLICK_S ) { angle = 270; } // E else if ( monsterslick & SURF_MONSLICK_E ) { angle = 0; } // W else if ( monsterslick & SURF_MONSLICK_W ) { angle = 180; } else { bogus = qtrue; } } // server cursor hints if ( ent->lastHintCheckTime < level.time ) { G_CheckForCursorHints( ent ); ent->lastHintCheckTime = level.time + FRAMETIME; } // DHM - Nerve :: Set animMovetype to 1 if ducking if ( ent->client->ps.pm_flags & PMF_DUCKED ) { ent->s.animMovetype = 1; } else { ent->s.animMovetype = 0; } // save results of pmove if ( ent->client->ps.eventSequence != oldEventSequence ) { ent->eventTime = level.time; ent->r.eventTime = level.time; } // Ridah, fixes jittery zombie movement if ( g_smoothClients.integer ) { BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue ); } else { BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue ); } if ( !( ent->client->ps.eFlags & EF_FIRING ) ) { client->fireHeld = qfalse; // for grapple } // // // use the precise origin for linking // VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); // // // use the snapped origin for linking so it matches client predicted versions VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin ); VectorCopy( pm.mins, ent->r.mins ); VectorCopy( pm.maxs, ent->r.maxs ); ent->waterlevel = pm.waterlevel; ent->watertype = pm.watertype; // execute client events ClientEvents( ent, oldEventSequence ); // link entity now, after any personal teleporters have been used trap_LinkEntity( ent ); if ( !ent->client->noclip ) { G_TouchTriggers( ent ); } // NOTE: now copy the exact origin over otherwise clients can be snapped into solid VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); // store the client's current position for antilag traces G_StoreClientPosition( ent ); // touch other objects ClientImpacts( ent, &pm ); // save results of triggers and client events if ( ent->client->ps.eventSequence != oldEventSequence ) { ent->eventTime = level.time; } // swap and latch button actions client->oldbuttons = client->buttons; client->buttons = ucmd->buttons; client->latched_buttons = client->buttons & ~client->oldbuttons; // client->latched_buttons |= client->buttons & ~client->oldbuttons; // FIXME:? (SA) MP method (causes problems for us. activate 'sticks') //----(SA) added client->oldwbuttons = client->wbuttons; client->wbuttons = ucmd->wbuttons; client->latched_wbuttons = client->wbuttons & ~client->oldwbuttons; // client->latched_wbuttons |= client->wbuttons & ~client->oldwbuttons; // FIXME:? (SA) MP method // Rafael - Activate // Ridah, made it a latched event (occurs on keydown only) if ( client->latched_buttons & BUTTON_ACTIVATE ) { Cmd_Activate_f( ent ); } if ( ent->flags & FL_NOFATIGUE ) { ent->client->ps.sprintTime = 20000; } // check for respawning if ( client->ps.stats[STAT_HEALTH] <= 0 ) { // DHM - Nerve if ( g_gametype.integer >= GT_WOLF ) { WolfFindMedic( ent ); } // dhm - end // wait for the attack button to be pressed if ( level.time > client->respawnTime ) { // forcerespawn is to prevent users from waiting out powerups if ( ( g_gametype.integer != GT_SINGLE_PLAYER ) && ( g_forcerespawn.integer > 0 ) && ( ( level.time - client->respawnTime ) > g_forcerespawn.integer * 1000 ) && ( !( ent->client->ps.pm_flags & PMF_LIMBO ) ) ) { // JPW NERVE // JPW NERVE if ( g_gametype.integer >= GT_WOLF ) { limbo( ent, qtrue ); } else { respawn( ent ); } // jpw return; } // DHM - Nerve :: Single player game respawns immediately as before, // but in multiplayer, require button press before respawn if ( g_gametype.integer == GT_SINGLE_PLAYER ) { respawn( ent ); } // NERVE - SMF - we want to only respawn on jump button now else if ( ( ucmd->upmove > 0 ) && ( !( ent->client->ps.pm_flags & PMF_LIMBO ) ) ) { // JPW NERVE // JPW NERVE if ( g_gametype.integer >= GT_WOLF ) { limbo( ent, qtrue ); } else { respawn( ent ); } // jpw } // dhm - Nerve :: end // NERVE - SMF - we want to immediately go to limbo mode if gibbed else if ( client->ps.stats[STAT_HEALTH] <= GIB_HEALTH && !( ent->client->ps.pm_flags & PMF_LIMBO ) ) { if ( g_gametype.integer >= GT_WOLF ) { limbo( ent, qfalse ); } else { respawn( ent ); } } // -NERVE - SMF } return; } // perform once-a-second actions ClientTimerActions( ent, msec ); }
void CG_DrawMortarMarker(int px, int py, int pw, int ph, qboolean draw, mapScissor_t *scissor, int expand) { if (cg.lastFiredWeapon == WP_MORTAR_SET && cg.mortarImpactTime >= 0) { if (cg.snap->ps.weapon != WP_MORTAR_SET) { cg.mortarImpactTime = 0; } else { vec4_t colour = { 1.f, 1.f, 1.f, 1.f }; vec3_t point; if (scissor) { point[0] = ((cg.mortarImpactPos[0] - cg.mapcoordsMins[0]) * cg.mapcoordsScale[0]) * pw * scissor->zoomFactor; point[1] = ((cg.mortarImpactPos[1] - cg.mapcoordsMins[1]) * cg.mapcoordsScale[1]) * ph * scissor->zoomFactor; } else { point[0] = px + (((cg.mortarImpactPos[0] - cg.mapcoordsMins[0]) * cg.mapcoordsScale[0]) * pw); point[1] = py + (((cg.mortarImpactPos[1] - cg.mapcoordsMins[1]) * cg.mapcoordsScale[1]) * ph); } // don't return if the marker is culled, just don't draw it. if (!(scissor && CG_ScissorPointIsCulled(point, scissor))) { if (scissor) { point[0] += px - scissor->tl[0]; point[1] += py - scissor->tl[1]; } if (cg.mortarImpactOutOfMap) { if (!scissor) { // near the edge of the map, fit into it if (point[0] + 8.f > (px + pw)) { point[0] -= 8.f; } else if (point[0] - 8.f < px) { point[0] += 8.f; } if (point[1] + 8.f > (py + ph)) { point[1] -= 8.f; } else if (point[1] - 8.f < py) { point[1] += 8.f; } } colour[3] = .5f; } trap_R_SetColor(colour); CG_DrawRotatedPic(point[0] - 8.f, point[1] - 8.f, 16, 16, cgs.media.ccMortarHit, .5f - (cg.mortarFireAngles[YAW] /*- 180.f */ + 45.f) / 360.f); trap_R_SetColor(NULL); } } } if (COM_BitCheck(cg.snap->ps.weapons, WP_MORTAR_SET)) { vec4_t colour = { 1.f, 1.f, 1.f, 1.f }; vec3_t point; int i, fadeTime; for (i = 0; i < MAX_CLIENTS; i++) { fadeTime = cg.time - (cg.artilleryRequestTime[i] + 25000); if (fadeTime < 5000) { if (fadeTime > 0) { colour[3] = 1.f - (fadeTime / 5000.f); } if (scissor) { point[0] = ((cg.artilleryRequestPos[i][0] - cg.mapcoordsMins[0]) * cg.mapcoordsScale[0]) * pw * scissor->zoomFactor; point[1] = ((cg.artilleryRequestPos[i][1] - cg.mapcoordsMins[1]) * cg.mapcoordsScale[1]) * ph * scissor->zoomFactor; } else { point[0] = px + (((cg.artilleryRequestPos[i][0] - cg.mapcoordsMins[0]) * cg.mapcoordsScale[0]) * pw); point[1] = py + (((cg.artilleryRequestPos[i][1] - cg.mapcoordsMins[1]) * cg.mapcoordsScale[1]) * ph); } // don't return if the marker is culled, just skip // it (so we draw the rest, if any) if (scissor && CG_ScissorPointIsCulled(point, scissor)) { continue; } if (scissor) { point[0] += px - scissor->tl[0]; point[1] += py - scissor->tl[1]; } trap_R_SetColor(colour); CG_DrawPic(point[0] - 8.f, point[1] - 8.f, 16, 16, cgs.media.ccMortarTarget); trap_R_SetColor(NULL); } } } }
/** * @brief Pick a weapon up. * @param[in,out] ent * @param[in,out] other * @return */ int Pickup_Weapon(gentity_t *ent, gentity_t *other) { int quantity; qboolean alreadyHave = qfalse; // magic ammo for any two-handed weapon if (ent->item->giWeapon == WP_AMMO) { AddMagicAmmo(other, ent->count); if (ent->parent && ent->parent->client) { other->client->pers.lastammo_client = ent->parent->s.clientNum; } // if field ops isn't giving ammo to self or the enemy, give him some props if (ent->parent && (ent->parent->client != other->client)) { if (ent->parent && ent->parent->client && other->client->sess.sessionTeam == ent->parent->client->sess.sessionTeam) { 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->giWeapon); // prevents drop/pickup weapon "quick reload" exploit if (alreadyHave) { Add_Ammo(other, ent->item->giWeapon, quantity, qfalse); // secondary weapon ammo if (ent->delay != 0.f) { Add_Ammo(other, GetWeaponTableData(ent->item->giWeapon)->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 (GetWeaponTableData(other->client->ps.weapon)->isSetWeapon) { return 0; } // see if we can pick it up if (G_CanPickupWeapon(ent->item->giWeapon, other)) { weapon_t primaryWeapon; if (other->client->sess.playerType == PC_SOLDIER && other->client->sess.skill[SK_HEAVY_WEAPONS] >= 4) { primaryWeapon = G_GetPrimaryWeaponForClientSoldier(ent->item->giWeapon, 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->giWeapon); // fixup mauser/sniper issues if (GetWeaponTableData(ent->item->giWeapon)->weapAlts != WP_NONE) { weapon_t weapAlts = GetWeaponTableData(ent->item->giWeapon)->weapAlts; if (GetWeaponTableData(weapAlts)->isRiflenade || GetWeaponTableData(weapAlts)->isScoped || GetWeaponTableData(weapAlts)->isSetWeapon) { COM_BitSet(other->client->ps.weapons, weapAlts); } } other->client->ps.ammoclip[GetWeaponTableData(ent->item->giWeapon)->clipIndex] = 0; other->client->ps.ammo[GetWeaponTableData(ent->item->giWeapon)->ammoIndex] = 0; if (GetWeaponTableData(ent->item->giWeapon)->isMortar) { other->client->ps.ammo[GetWeaponTableData(ent->item->giWeapon)->clipIndex] = quantity; // secondary weapon ammo if (ent->delay != 0.f) { Add_Ammo(other, GetWeaponTableData(ent->item->giWeapon)->weapAlts, ent->delay, qfalse); } } else { other->client->ps.ammoclip[GetWeaponTableData(ent->item->giWeapon)->clipIndex] = quantity; // secondary weapon ammo if (ent->delay != 0.f) { other->client->ps.ammo[GetWeaponTableData(ent->item->giWeapon)->weapAlts] = ent->delay; } } } } else { return 0; } } #ifdef FEATURE_OMNIBOT Bot_Event_AddWeapon(other->client->ps.clientNum, Bot_WeaponGameToBot(ent->item->giWeapon)); #endif return RESPAWN_NEVER; }
static int PM_Weapon_CheckForRechamber(int time) { return 0; #define int_ptr_val(x) (*(int*)((int)x)) pmove_t *xm = *(pmove_t**)(int)pm; #define ps_off(type, off) (*(type*)((int)xm->ps + off)) int *weaponstate = (int*)((int)xm->ps + 180); int *weapons = *(int**)((int)xm->ps + 796); int weapon = *(int*)((int)xm->ps + 176); int *weaponTime = (int*)((int)xm->ps + 44); int *weaponDelay = (int*)((int)xm->ps + 48); int v2 = *(int*)((int)pml + 132); if(!int_ptr_val(v2 + 712)) return 0; if(!COM_BitCheck(weapons, weapon)) return 0; if(*weaponstate == WEAPON_RECHAMBERING) { if(time) { COM_BitClear(weapons, weapon); PM_AddEvent(EV_EJECT_BRASS); if(*weaponTime) return 1; } } if(!*weaponTime || ((*weaponstate - WEAPON_FIRING) > WEAPON_RAISING && *weaponstate != WEAPON_MELEE_WINDUP && *weaponstate != WEAPON_MELEE_RELAX && !*weaponDelay)) { if(*weaponstate == WEAPON_RECHAMBERING) { if(xm->cmd.wbuttons) { int *v9 = (int*)((int)xm->ps + 980); if(*v9 & 0xFFFFFDFF) { if(xm->ps->pm_type <= 5) { int v6 = *v9 & 0x200; BYTE1(v6) ^= 2; *v9 = v6; } } } *weaponstate = WEAPON_READY; return 0; } } if(*weaponstate == WEAPON_READY) { if(xm->ps->pm_type > 5 || !xm->cmd.wbuttons) goto label_27; /* v8 = 0.75 < *(float *)(v2 + 184); v9 = 0; v10 = 0.75 == *(float *)(v2 + 184); if ( (HIBYTE(v7) & 0x45) == 1 ) { if ( *(_DWORD *)(v2 + 4) > 5 || !*(_BYTE *)(xm + 10) ) goto LABEL_27; v11 = *(_DWORD *)(v2 + 980) & 0x200; BYTE1(v11) ^= 2u; LOBYTE(v11) = 7; } else { if ( *(_DWORD *)(v2 + 4) > 5 || !*(_BYTE *)(xm + 10) ) goto LABEL_27; v11 = *(_DWORD *)(v2 + 980) & 0x200; BYTE1(v11) ^= 2u; LOBYTE(v11) = 4; } *(_DWORD *)(v2 + 980) = v11; */ //set cool stuff for keys? //ps_off(int,980) = label_27: *weaponstate = WEAPON_RECHAMBERING; *weaponTime = int_ptr_val(v2 + 472); int v13 = int_ptr_val(v2 + 476); /* if(v13 && v13 < *weaponTime) *weaponDelay = v13; else *weaponDelay = 1;*/ PM_AddEvent(EV_RECHAMBER_WEAPON); } return 0; #undef int_ptr_val }
/** * @brief Get the primary weapon of the client. * @return the primary weapon of the soldier client */ weapon_t G_GetPrimaryWeaponForClientSoldier(weapon_t weapon, gclient_t *client) { int i; bg_playerclass_t *classInfo; if (client->sess.sessionTeam != TEAM_ALLIES && client->sess.sessionTeam != TEAM_AXIS) { return WP_NONE; } if (COM_BitCheck(client->ps.weapons, WP_PANZERFAUST) || COM_BitCheck(client->ps.weapons, WP_BAZOOKA) || COM_BitCheck(client->ps.weapons, WP_FLAMETHROWER) || COM_BitCheck(client->ps.weapons, WP_MOBILE_MG42) || COM_BitCheck(client->ps.weapons, WP_MOBILE_BROWNING) || COM_BitCheck(client->ps.weapons, WP_MORTAR) || COM_BitCheck(client->ps.weapons, WP_MORTAR2)) { // if weapons are SMS & HW, return SMS if picking up SMS if (COM_BitCheck(client->ps.weapons, WP_MP40) && weapon == WP_THOMPSON) { return WP_MP40; } else if (COM_BitCheck(client->ps.weapons, WP_THOMPSON) && weapon == WP_MP40) { return WP_THOMPSON; } else { // if weapons are SMS & HW, return HW if picking up HW classInfo = &bg_allies_playerclasses[client->sess.playerType]; for (i = 0; i < MAX_WEAPS_PER_CLASS; i++) { if (classInfo->classWeapons[i] == WP_MP40 || classInfo->classWeapons[i] == WP_THOMPSON) { continue; } if (COM_BitCheck(client->ps.weapons, classInfo->classWeapons[i])) { return classInfo->classWeapons[i]; } } classInfo = &bg_axis_playerclasses[client->sess.playerType]; for (i = 0; i < MAX_WEAPS_PER_CLASS; i++) { if (classInfo->classWeapons[i] == WP_MP40 || classInfo->classWeapons[i] == WP_THOMPSON) { continue; } if (COM_BitCheck(client->ps.weapons, classInfo->classWeapons[i])) { return classInfo->classWeapons[i]; } } } } else { // if weapons are SMS and pistols, return SMS if picking up SMS or HW if (COM_BitCheck(client->ps.weapons, WP_THOMPSON)) { return WP_THOMPSON; } if (COM_BitCheck(client->ps.weapons, WP_MP40)) { return WP_MP40; } } return WP_NONE; }
/** * @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; }
/* ============ AICast_Think entry point for all cast AI ============ */ void AICast_Think( int client, float thinktime ) { gentity_t *ent; cast_state_t *cs; int i; int animIndex; animation_t *anim; // if (saveGamePending || (strlen( g_missionStats.string ) > 2 )) { // return; // } // // get the cast ready for processing // cs = AICast_GetCastState( client ); ent = &g_entities[client]; // // make sure we are using the right AAS data for this entity (one's that don't get set will default to the player's AAS data) trap_AAS_SetCurrentWorld( cs->aasWorldIndex ); // // make sure we have a valid navigation system // if ( !trap_AAS_Initialized() ) { return; } // trap_EA_ResetInput( client, NULL ); cs->aiFlags &= ~AIFL_VIEWLOCKED; //cs->bs->weaponnum = ent->client->ps.weapon; // // turn off flags that are set each frame if needed ent->client->ps.eFlags &= ~( EF_NOSWINGANGLES | EF_MONSTER_EFFECT | EF_MONSTER_EFFECT2 | EF_MONSTER_EFFECT3 ); // conditional flags if ( ent->aiCharacter == AICHAR_ZOMBIE ) { if ( COM_BitCheck( ent->client->ps.weapons, WP_MONSTER_ATTACK1 ) ) { cs->aiFlags |= AIFL_NO_FLAME_DAMAGE; SET_FLAMING_ZOMBIE( ent->s, 1 ); } else { SET_FLAMING_ZOMBIE( ent->s, 0 ); } } // // if we're dead, do special stuff only if ( ent->health <= 0 || cs->revivingTime || cs->rebirthTime ) { // if ( cs->revivingTime && cs->revivingTime < level.time ) { // start us thinking again ent->client->ps.pm_type = PM_NORMAL; cs->revivingTime = 0; } // if ( cs->rebirthTime && cs->rebirthTime < level.time ) { vec3_t mins, maxs; int touch[10], numTouch; float oldmaxZ; oldmaxZ = ent->r.maxs[2]; // make sure the area is clear AIChar_SetBBox( ent, cs ); VectorAdd( ent->r.currentOrigin, ent->r.mins, mins ); VectorAdd( ent->r.currentOrigin, ent->r.maxs, maxs ); trap_UnlinkEntity( ent ); numTouch = trap_EntitiesInBox( mins, maxs, touch, 10 ); if ( numTouch ) { for ( i = 0; i < numTouch; i++ ) { //if (!g_entities[touch[i]].client || g_entities[touch[i]].r.contents == CONTENTS_BODY) if ( g_entities[touch[i]].r.contents & MASK_PLAYERSOLID ) { break; } } if ( i == numTouch ) { numTouch = 0; } } if ( numTouch == 0 ) { // ok to spawn // give them health when they start reviving, so we won't gib after // just a couple shots while reviving ent->health = ent->client->ps.stats[STAT_HEALTH] = ent->client->ps.stats[STAT_MAX_HEALTH] = ( ( cs->attributes[STARTING_HEALTH] - 50 ) > 30 ? ( cs->attributes[STARTING_HEALTH] - 50 ) : 30 ); ent->r.contents = CONTENTS_BODY; ent->clipmask = MASK_PLAYERSOLID; ent->takedamage = qtrue; ent->waterlevel = 0; ent->watertype = 0; ent->flags = 0; ent->die = AICast_Die; ent->client->ps.eFlags &= ~EF_DEAD; ent->s.eFlags &= ~EF_DEAD; cs->rebirthTime = 0; cs->deathTime = 0; // play the revive animation cs->revivingTime = level.time + BG_AnimScriptEvent( &ent->client->ps, ANIM_ET_REVIVE, qfalse, qtrue );; } else { // can't spawn yet, so set bbox back, and wait ent->r.maxs[2] = oldmaxZ; ent->client->ps.maxs[2] = ent->r.maxs[2]; } trap_LinkEntity( ent ); } // ZOMBIE should set effect flag if really dead if ( cs->aiCharacter == AICHAR_ZOMBIE && !ent->r.contents ) { ent->client->ps.eFlags |= EF_MONSTER_EFFECT2; } // if ( ent->health > GIB_HEALTH && cs->deathTime && cs->deathTime < ( level.time - 3000 ) ) { /* // been dead for long enough, set our animation to the end frame switch ( ent->s.legsAnim & ~ANIM_TOGGLEBIT ) { case BOTH_DEATH1: case BOTH_DEAD1: anim = BOTH_DEAD1; break; case BOTH_DEATH2: case BOTH_DEAD2: anim = BOTH_DEAD2; break; case BOTH_DEATH3: case BOTH_DEAD3: anim = BOTH_DEAD3; break; default: G_Error( "%s has unknown death animation\n", ent->classname); } ent->client->ps.torsoAnim = ( ( ent->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; ent->client->ps.legsAnim = ( ( ent->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; */ cs->deathTime = 0; ent->r.svFlags &= ~SVF_BROADCAST; } // // no more thinking required return; } // // set some anim conditions if ( cs->secondDeadTime ) { BG_UpdateConditionValue( cs->entityNum, ANIM_COND_SECONDLIFE, qtrue, qfalse ); } else { BG_UpdateConditionValue( cs->entityNum, ANIM_COND_SECONDLIFE, qfalse, qfalse ); } // set health value if ( ent->health <= 0.25 * cs->attributes[STARTING_HEALTH] ) { BG_UpdateConditionValue( cs->entityNum, ANIM_COND_HEALTH_LEVEL, 3, qfalse ); } else if ( ent->health <= 0.5 * cs->attributes[STARTING_HEALTH] ) { BG_UpdateConditionValue( cs->entityNum, ANIM_COND_HEALTH_LEVEL, 2, qfalse ); } else { BG_UpdateConditionValue( cs->entityNum, ANIM_COND_HEALTH_LEVEL, 1, qfalse ); } // cs->speedScale = 1.0; // reset each frame, set if required cs->actionFlags = 0; // FIXME: move this to a Cast AI movement init function! //retrieve the current client state BotAI_GetClientState( client, &( cs->bs->cur_ps ) ); // // setup movement speeds for the given state // walking animIndex = BG_GetAnimScriptAnimation( cs->entityNum, ent->client->ps.aiState, ANIM_MT_WALK ); if ( animIndex >= 0 ) { anim = BG_GetAnimationForIndex( cs->entityNum, animIndex ); cs->attributes[WALKING_SPEED] = anim->moveSpeed; } // crouching animIndex = BG_GetAnimScriptAnimation( cs->entityNum, ent->client->ps.aiState, ANIM_MT_WALKCR ); if ( animIndex >= 0 ) { anim = BG_GetAnimationForIndex( cs->entityNum, animIndex ); cs->attributes[CROUCHING_SPEED] = anim->moveSpeed; } // running animIndex = BG_GetAnimScriptAnimation( cs->entityNum, ent->client->ps.aiState, ANIM_MT_RUN ); if ( animIndex >= 0 ) { anim = BG_GetAnimationForIndex( cs->entityNum, animIndex ); cs->attributes[RUNNING_SPEED] = anim->moveSpeed; } // update crouch speed scale ent->client->ps.crouchSpeedScale = cs->attributes[CROUCHING_SPEED] / cs->attributes[RUNNING_SPEED]; // // only enable headlook if we want to this frame ent->client->ps.eFlags &= ~EF_HEADLOOK; if ( cs->bs->enemy >= 0 ) { ent->client->ps.eFlags &= ~EF_STAND_IDLE2; // never use alt idle if fighting } // // check for dead leader if ( cs->leaderNum >= 0 && g_entities[cs->leaderNum].health <= 0 ) { cs->leaderNum = -1; } // #if 0 // HACK for village2, if they are stuck, find a good position (there is a friendly guy placed inside a table) { trace_t tr; vec3_t org; trap_Trace( &tr, cs->bs->cur_ps.origin, cs->bs->cur_ps.mins, cs->bs->cur_ps.maxs, cs->bs->cur_ps.origin, cs->entityNum, CONTENTS_SOLID ); while ( tr.startsolid ) { VectorCopy( cs->bs->cur_ps.origin, org ); org[0] += 96 * crandom(); org[1] += 96 * crandom(); org[2] += 16 * crandom(); trap_Trace( &tr, org, cs->bs->cur_ps.mins, cs->bs->cur_ps.maxs, org, cs->entityNum, CONTENTS_SOLID ); G_SetOrigin( &g_entities[cs->entityNum], org ); VectorCopy( org, g_entities[cs->entityNum].client->ps.origin ); } } #endif //add the delta angles to the cast's current view angles for ( i = 0; i < 3; i++ ) { cs->bs->viewangles[i] = AngleMod( cs->bs->viewangles[i] + SHORT2ANGLE( cs->bs->cur_ps.delta_angles[i] ) ); } // //increase the local time of the cast cs->bs->ltime += thinktime; // cs->bs->thinktime = thinktime; //origin of the cast VectorCopy( cs->bs->cur_ps.origin, cs->bs->origin ); //eye coordinates of the cast VectorCopy( cs->bs->cur_ps.origin, cs->bs->eye ); cs->bs->eye[2] += cs->bs->cur_ps.viewheight; //get the area the cast is in cs->bs->areanum = BotPointAreaNum( cs->bs->origin ); // clear flags each frame cs->bs->flags = 0; // // check enemy health if ( cs->bs->enemy >= 0 && g_entities[cs->bs->enemy].health <= 0 ) { cs->bs->enemy = -1; } // // if the previous movetype was temporary, set it back if ( cs->movestateType == MSTYPE_TEMPORARY ) { cs->movestate = MS_DEFAULT; cs->movestateType = MSTYPE_NONE; } // crouching? if ( ( cs->bs->attackcrouch_time > trap_AAS_Time() ) && ( ( cs->lastAttackCrouch > level.time - 500 ) || ( cs->thinkFuncChangeTime < level.time - 1000 ) ) ) { // if we are not moving, and we are firing, always stand, unless we are allowed to crouch + fire if ( VectorLength( cs->bs->cur_ps.velocity ) || ( cs->lastWeaponFired < level.time - 2000 ) || ( cs->aiFlags & AIFL_ATTACK_CROUCH ) ) { cs->lastAttackCrouch = level.time; trap_EA_Crouch( cs->bs->client ); } } // //if (cs->bs->enemy >= 0) { //update the attack inventory values AICast_UpdateBattleInventory( cs, cs->bs->enemy ); //} // // if we don't have ammo for the current weapon, get rid of it if ( !( COM_BitCheck( cs->bs->cur_ps.weapons, cs->bs->weaponnum ) ) || !AICast_GotEnoughAmmoForWeapon( cs, cs->bs->weaponnum ) ) { // select a weapon AICast_ChooseWeapon( cs, qfalse ); // if still no ammo, select a blank weapon //if (!AICast_GotEnoughAmmoForWeapon( cs, cs->bs->weaponnum )) { // cs->bs->weaponnum = WP_NONE; //} } // // in query mode, we do special handling (pause scripting, check for transition to alert/combat, etc) if ( cs->aiState == AISTATE_QUERY ) { AICast_QueryThink( cs ); } else if ( cs->pauseTime < level.time ) { // do the thinking AICast_ProcessAIFunctions( cs, thinktime ); // // make sure the correct weapon is selected trap_EA_SelectWeapon( cs->bs->client, cs->bs->weaponnum ); // // process current script if it exists cs->castScriptStatusCurrent = cs->castScriptStatus; AICast_ScriptRun( cs, qfalse ); } // // set special movestate if necessary if ( cs->movestateType != MSTYPE_NONE ) { switch ( cs->movestate ) { case MS_WALK: cs->actionFlags |= CASTACTION_WALK; break; case MS_CROUCH: trap_EA_Crouch( cs->entityNum ); break; default: break; // TTimo gcc: MS_DEFAULT MS_RUN not handled in switch } } // //subtract the delta angles for ( i = 0; i < 3; i++ ) { cs->bs->viewangles[i] = AngleMod( cs->bs->viewangles[i] - SHORT2ANGLE( cs->bs->cur_ps.delta_angles[i] ) ); } }
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; }
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; } } } }