CLIENT/SERVER: Misc. Weapon Spread improvements

Adds proper gun recoil to FTE, as well as moves spread calculation to be
relative to crosshairs. CSQC's crosshair values are now accurate to
World at War as well. Weapons are also much more precise ADS, so the Kar
is more viable. Shotguns also no longer reduce spread when ADS, in
parity with World at War :^)
This commit is contained in:
Steam Deck User 2023-03-02 22:06:26 -05:00
parent b097c6535c
commit 12a2633738
8 changed files with 553 additions and 340 deletions

View file

@ -229,4 +229,6 @@ int platform_is_web;
float GPActive[32];
string build_datetime;
#define VERSION_STRING "v1.0"
#define VERSION_STRING "v1.0"
vector gun_kick;

View file

@ -1159,14 +1159,14 @@ void() Draw_Crosshair =
if (cur_spread >= CrossHairMaxSpread(getstatf(STAT_ACTIVEWEAPON), getstatf(STAT_PLAYERSTANCE))) {
cur_spread = CrossHairMaxSpread(getstatf(STAT_ACTIVEWEAPON), getstatf(STAT_PLAYERSTANCE));
} else {
cur_spread += (frametime*80);
cur_spread += (frametime*160);
}
} else {
croshhairmoving = 0;
if (cur_spread > 0)
cur_spread -= (frametime*80);
cur_spread -= (frametime*160);
else
cur_spread = 0;
@ -1234,13 +1234,13 @@ void() Draw_Crosshair =
crosshair_offset_step += (crosshair_offset - crosshair_offset_step) * 0.5;
// Creds to heartologic for some actually good crosshair position stuff.
vector crossSize = [1, 8];
vector crossSize = [1, 5];
vector screenSize = [g_width, g_height];
drawfill(screenSize / 2 - [crossSize.x * 0.5, +crossSize.y * 2 + crosshair_offset_step], crossSize, crosshair_color, crosshair_opacity, 0); // top
drawfill(screenSize / 2 - [crossSize.x * 0.5, -crossSize.y * 1 - crosshair_offset_step], crossSize, crosshair_color, crosshair_opacity, 0); // bottom
drawfill(screenSize / 2 - [+crossSize.y * 2 + crosshair_offset_step, crossSize.x * 0.5], [crossSize.y, crossSize.x], crosshair_color, crosshair_opacity, 0); // right
drawfill(screenSize / 2 - [-crossSize.y * 1 - crosshair_offset_step, crossSize.x * 0.5], [crossSize.y, crossSize.x], crosshair_color, crosshair_opacity, 0); // left
drawfill(screenSize / 2 - [crossSize.x, +crossSize.y * 2 + crosshair_offset_step], crossSize, crosshair_color, crosshair_opacity, 0); // top
drawfill(screenSize / 2 - [crossSize.x, -crossSize.y * 1 - crosshair_offset_step], crossSize, crosshair_color, crosshair_opacity, 0); // bottom
drawfill(screenSize / 2 - [+crossSize.y * 2 + crosshair_offset_step, crossSize.x], [crossSize.y, crossSize.x], crosshair_color, crosshair_opacity, 0); // right
drawfill(screenSize / 2 - [-crossSize.y * 1 - crosshair_offset_step, crossSize.x], [crossSize.y, crossSize.x], crosshair_color, crosshair_opacity, 0); // left
}
else if (getstatf(STAT_WEAPONZOOM) != 1 && getstatf(STAT_WEAPONZOOM) != 2) {
vector screenSize2 = [g_width, g_height];

View file

@ -454,6 +454,39 @@ noref void(float isnew) CSQC_Ent_Update =
addentity(self);
}
float(__inout vector v) VectorNormalize =
{
float length = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
if (length)
{
float ilength = 1 / length;
v[0] *= ilength;
v[1] *= ilength;
v[2] *= ilength;
}
return length;
}
void() DropRecoilKick =
{
float len;
if (crosshair_spread_time > time)
return;
len = VectorNormalize(gun_kick);
len = len - frametime*5;
if (len < 0)
len = 0;
gun_kick[0] *= len;
gun_kick[1] *= len;
gun_kick[2] *= len;
}
// CALLED EVERY CLIENT RENDER FRAME
float pap_flash_alternate;
noref void(float width, float height, float menushown) CSQC_UpdateView =
@ -591,6 +624,14 @@ noref void(float width, float height, float menushown) CSQC_UpdateView =
deltalisten("models/weapons/pistol/pistol.iqm", add_outline, 0);*/
//deltalisten("models/humanoid_simplerig.iqm", add_outline, 0);
DropRecoilKick();
camang[0] += gun_kick[0];
camang[1] += gun_kick[1];
camang[2] += gun_kick[2];
setviewprop(VF_ANGLES, camang);
//does what you think it does
renderscene();
@ -773,6 +814,8 @@ noref void() CSQC_Input_Frame =
{
input_movevalues *= 0.5;
}
input_angles = getproperty(VF_ANGLES);
}
float() tracerthink =
@ -908,6 +951,14 @@ noref void() CSQC_Parse_Event =
splat.predraw = alphafade;
}
break;
case EVENT_WEAPONRECOIL:
local vector rec;
rec_x = readcoord()/5;
rec_y = readcoord()/5;
rec_z = readcoord()/5;
gun_kick += rec;
break;
case EVENT_EXPLOSION:
local vector org;
org_x = readcoord();

View file

@ -222,6 +222,25 @@ void(entity who, float broadcast_time, float type, string str) BroadcastMessageT
#endif // FTE
}
// FIXME: basically a copy of CL_SendWeaponFire but for FTE
void(entity who, float weapon) SendWeaponRecoil =
{
#ifdef FTE
vector Wep_Recoil;
Wep_Recoil = GetWeaponRecoil(weapon);
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WEAPONRECOIL);
WriteCoord (MSG_MULTICAST, Wep_Recoil_x);
WriteCoord (MSG_MULTICAST, Wep_Recoil_y);
WriteCoord (MSG_MULTICAST, Wep_Recoil_z);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
#endif // FTE
}
void(float broadcast_time, float type, string str) BroadcastMessage =
{
#ifdef FTE

View file

@ -0,0 +1,327 @@
/*
server/player/last_stand.qc
Functionality pertaining to Player's Last Stand mode and the act
of getting out of it.
Copyright (C) 2021-2023 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
float() PollPlayersAlive;
void() EndGameSetup;
void() SpectatorSpawn;
#define LAST_STAND_DURATION_SEC 100 // Seconds in Last Stand.
// when dead and other players exist and are alive, throw user into spectate mode
void(entity deceased) Player_BecomeSpectator =
{
if (!deceased.downed)
return;
/*if (self.beingrevived)
{
self.think = startspectate;
self.nextthink = time + 0.1;
return;
}*/
deceased.downedloop = 0;
deceased.beingrevived = false;
deceased.model = "";
setmodel(deceased, deceased.model);
deceased.health = 100;
deceased.weaponmodel = "";
deceased.weapon2model = "";
deceased.weapon = 0;
deceased.downed = 0;
deceased.frame = 0;
UpdateVmodel(deceased.weaponmodel, GetWepSkin(deceased.weapon));
UpdateV2model(deceased.weapon2model, GetWepSkin(deceased.weapon));
entity tempe;
tempe = self;
self = deceased;
SwitchWeapon(self.weapon);
SpectatorSpawn();
self = tempe;
}
void() ReviveTracker_Update =
{
// Add to the die timer..
self.ltime += 0.1;
// Bleed Out Timer
if (self.ltime >= LAST_STAND_DURATION_SEC) {
// Get rid of the Revive Icon from HUDs and make them a spectator.
DisableReviveIcon(self.owner.electro_targeted);
Player_BecomeSpectator(self.owner);
// Prevent any leakage
remove(self);
} else {
self.nextthink = time + 0.1;
}
}
void(entity deceased) SpawnReviveTracker =
{
entity revive_tracker = spawn();
revive_tracker.owner = deceased;
revive_tracker.think = ReviveTracker_Update;
revive_tracker.nextthink = time + 0.1;
}
void() Player_ReviveTrigger =
{
if (other.classname != "player" || (self.beingrevived == true && self.firer != other))
return;
// perform a trace to make sure they're always facing the revivee
vector source;
makevectors(self.angles);
source = other.origin - '0 0 12';
traceline(source, source + v_forward*50, 0, other);
other.active_door = trace_ent;
centerprint(other, other.active_door.classname);
if (self.beingrevived == false && other.active_door == self)
useprint(other, 13, 0, 0);
}
void() Player_EnterLastStand =
{
// 'Pro Gamer Move' achievement.
if (rounds <= 1 && self.currentmag == 0 &&
self.currentmag2 == 0 && self.currentammo == 0 &&
self.secondarymag == 0 && self.secondarymag2 == 0 &&
self.secondaryammo == 0) {
GiveAchievement(9, self);
}
// Play Last Stand Animation
PAnim_GetDown1();
// Force the player to prone.
if (self.stance == 2) self.new_ofs_z = self.view_ofs_z - 42;
if (self.stance == 1) self.new_ofs_z = self.view_ofs_z - 24;
self.stance = 0;
// Get Rid of Mule Kick Weapon (FIXME -- this just obliterates the third slot)
self.thirdweapon = 0;
// Calculate the loss in points, take away points from downed Player.
float point_difference;
point_difference = self.points;
point_difference -= 10*rint((self.points*0.95)/10);
addmoney(self, point_difference * -1, false);
self.requirespower = point_difference;
// Broadcast that the player has downed.
BroadcastMessage(time + 3, 2, self.netname);
// Different hitbox for Last Stand
setsize(self, '-16 -16 -32', '16 16 40');
// Reset state
self.velocity = self.zoom = 0;
self.downed = true;
self.dive_delay = 0;
self.movetype = MOVETYPE_WALK;
// Determine if we should End the Game.
float players_still_alive = PollPlayersAlive();
if ((coop && !players_still_alive) || (!coop && !(self.perks & P_REVIVE))) {
EndGameSetup();
return;
} else {
self.health = 19;
}
// Initiate Self-Revive on Solo
if ((self.perks & P_REVIVE) && !coop) {
self.progress_bar = 10 + time;
self.progress_bar_time = 10;
self.progress_bar_percent = 1;
}
// Take away weapons and Perks
self.perks = 0;
SetPerk(self, self.perks);
self.weaponbk = self.weapon;
self.currentammobk = self.currentammo;
self.currentmagbk = self.currentmag;
self.currentmagbk2 = self.currentmag2;
if(Util_PlayerHasWeapon(self, W_BIATCH, false) ||
Util_PlayerHasWeapon(self, W_RAY, true) ||
Util_PlayerHasWeapon(self, W_357, true)) {
float weapon_slot;
float total_ammo;
total_ammo = 0;
weapon_slot = Util_PlayerHasWeapon(self, W_RAY, true);
if (weapon_slot == 0) weapon_slot = Util_PlayerHasWeapon(self, W_BIATCH, false);
if (weapon_slot == 0) weapon_slot = Util_PlayerHasWeapon(self, W_357, true);
switch(weapon_slot) {
case 1:
total_ammo = self.currentmag + self.currentmag2 + self.currentammo;
break;
case 2:
total_ammo = self.secondarymag + self.secondarymag2 + self.secondaryammo;
self.weapon = self.secondaryweapon;
break;
}
// If it's greater than the mag size, we can fill the magazine.
if (total_ammo > getWeaponMag(self.weapon)) {
self.currentmag = getWeaponMag(self.weapon);
// subtract it from the total ammo
total_ammo -= self.currentmag;
} else {
self.currentmag = total_ammo;
total_ammo = 0;
}
// Check for dual wield mag too
if (IsDualWeapon(self.weapon)) {
if (total_ammo > getWeaponMag(self.weapon)) {
self.currentmag2 = getWeaponMag(self.weapon);
// subtract it from the total ammo
total_ammo -= self.currentmag2;
} else {
self.currentmag2 = total_ammo;
total_ammo = 0;
}
}
// Ray Gun has a special case where we DON'T fill its reserve
if (self.weapon != W_RAY && self.weapon != W_PORTER) {
// Now see if the reserve ammo is more than max downed capacity
if (total_ammo > getWeaponMag(self.weapon)*2) {
self.currentammo = getWeaponMag(self.weapon)*2;
} else {
// It's not so just fill it
self.currentammo = total_ammo;
}
} else {
self.currentammo = 0;
}
} else {
if (!coop) {
self.weapon = W_BIATCH;
self.currentammo = 12;
self.currentmag = self.currentmag2 = 6;
} else {
self.weapon = W_COLT;
self.currentmag = 8;
self.currentammo = 16;
}
}
// Play Switch Animation
self.weaponmodel = GetWeaponModel(self.weapon, 0);
SwitchWeapon(self.weapon);
float startframe = GetFrame(self.weapon,TAKE_OUT_START);
float endframe = GetFrame(self.weapon,TAKE_OUT_END);
Set_W_Frame (startframe, endframe, 0, 0, 0, SUB_Null, self.weaponmodel, false, S_BOTH);
// Spawn Revive Sprite and Revive Tracker in Co-Op
if (coop) {
EnableReviveIcon(revive_index, self.origin + VEC_VIEW_OFS);
SpawnReviveTracker(self);
self.touch = Player_ReviveTrigger;
self.electro_targeted = revive_index;
revive_index++;
}
//self.think = rec_downed;
//self.nextthink = time + 0.1;
}
void() Player_LeaveLastStand =
{
local string modelname;
float startframe;
float endframe;
playgetup(); // animation
self.new_ofs_z = self.view_ofs_z + 42;
self.stance = 2;
self.health = 100;
self.downedloop = 0; // used for death timing vs endgame
self.downed = 0;
self.classname = "player";
// Revert Hitbox
setsize(self, '-16 -16 -32', '16 16 40');
// Take away the ammo that was fired while in last stand.
if (self.weapon != W_COLT) {
if (self.weapon == self.weaponbk) {
self.currentammobk -= self.teslacount;
// Take from the mag if the reserve is empty now
if (self.currentammobk < 0)
self.currentmagbk += self.currentammobk;
self.currentammobk = 0;
} else if (self.weapon == self.secondaryweapon) {
self.secondaryammo -= self.teslacount;
// Take from the mag if the reserve is empty now
if (self.secondaryammo < 0)
self.secondarymag += self.secondaryammo;
self.secondaryammo = 0;
}
}
self.teslacount = 0;
if (!coop) {
addmoney(self, self.requirespower, false);
}
if (self.weaponbk)
{
self.weapon = self.weaponbk;
self.currentammo = self.currentammobk;
self.currentmag = self.currentmagbk;
self.currentmag2 = self.currentmagbk2;
}
modelname = GetWeaponModel(self.weapon, 0);
self.weaponmodel = modelname;
SwitchWeapon(self.weapon);
self.weapon2model = GetWeapon2Model(self.weapon);
self.movetype = MOVETYPE_WALK;
startframe = GetFrame(self.weapon,TAKE_OUT_START);
endframe = GetFrame(self.weapon,TAKE_OUT_END);
Set_W_Frame (startframe, endframe, 0, 0, 0, SUB_Null, modelname, false, S_BOTH);
};

View file

@ -1398,7 +1398,7 @@ void(float side) W_Fire =
string modelname = "";
string soundname;
float spread;
float sprdstance = 0;
float is_moving;
float delay;
//Update the basic vectors
@ -1440,41 +1440,22 @@ void(float side) W_Fire =
if (self.perks & P_DOUBLE)
shotcount *= 2;
switch(self.stance) {
case 2:
sprdstance = 0;
break;
case 1:
sprdstance = 2;
break;
case 0:
sprdstance = 4;
break;
default:
sprdstance = 0;
break;
}
if (self.velocity)
is_moving = true;
else
is_moving = false;
spread = (1.5*GetWeaponSpread(self.weapon))-sprdstance;
spread = GetWeaponSpread(self.weapon, is_moving, self.stance);
if (self.perks & P_DEAD) {
spread *= 0.65;
}
if (self.zoom == 1) {
if (self.weapon == W_TRENCH ||
self.weapon == W_DB ||
self.weapon == W_SAWNOFF ||
self.weapon == W_GUT ||
self.weapon == W_BORE) {
spread = spread * 0.75;
} else {
spread = spread * 0.1;
}
if (self.zoom == 1 && W_SpreadAffectedByADS(self.weapon)) {
spread *= 0.02;
} else if (self.zoom == 2) {
spread = spread * 0.05;
} else if (self.velocity || !(self.flags & FL_ONGROUND))
spread *= 2;
}
if (self.downed)
playdownfire();
@ -1575,12 +1556,7 @@ void(float side) W_Fire =
if (self.perks & P_DEAD)
return;
vector Wep_Recoil;
Wep_Recoil = GetWeaponRecoil(self.weapon)*0.5;
self.punchangle_x = Wep_Recoil_x;
self.punchangle_y = Wep_Recoil_y;
self.punchangle_z = Wep_Recoil_z;
SendWeaponRecoil(self, self.weapon);
#endif // FTE

View file

@ -53,6 +53,7 @@ const float EVENT_ACHIEVEMENTPROGRESS = 36;
const float EVENT_REVIVEON = 37;
const float EVENT_REVIVEOFF = 38;
const float EVENT_REVIVECHANGE = 39;
const float EVENT_WEAPONRECOIL = 40;
// Define our FTE platform
#ifndef STANDARD

View file

@ -999,112 +999,6 @@ float(float wep, float penetration_times) getWeaponPenetration =
}
}
float(float wep) GetWeaponSpread =
{
switch (wep)
{
case W_COLT:
return 7.5;
case W_BIATCH:
return 7.5;
case W_KAR:
return 25;
case W_ARMAGEDDON:
return 25;
case W_THOMPSON:
return 5;
case W_GIBS:
return 5;
case W_RAY:
return 5;
case W_PORTER:
return 5;
case W_KAR_SCOPE:
return 25;
case W_HEADCRACKER:
return 25;
case W_BAR:
return 5;
case W_WIDOW:
return 5;
case W_M1A1:
return 5;
case W_WIDDER:
return 5;
case W_M2:
return 0;
case W_FIW:
return 0;
case W_TYPE:
return 5;
case W_SAMURAI:
return 5;
case W_SAWNOFF:
return 15;
case W_SNUFF:
return 15;
case W_PPSH:
return 5;
case W_REAPER:
return 5;
case W_DB:
return 12.5;
case W_BORE:
return 12.5;
case W_FG:
return 5;
case W_IMPELLER:
return 5;
case W_TRENCH:
return 12.5;
case W_GUT:
return 12.5;
case W_MG:
return 10;
case W_BARRACUDA:
return 10;
case W_GEWEHR:
return 5;
case W_COMPRESSOR:
return 5;
case W_BROWNING:
return 10;
case W_ACCELERATOR:
return 10;
case W_357:
return 5;
case W_KILLU:
return 5;
case W_M1:
return 5;
case W_M1000:
return 5;
case W_MP40:
return 5;
case W_AFTERBURNER:
return 5;
case W_MP5K:
return 5;
case W_KOLLIDER:
return 5;
case W_PTRS:
return 15;
case W_PENETRATOR:
return 15;
case W_STG:
return 5;
case W_SPATZ:
return 5;
case W_TESLA:
return 5;
case W_M14:
return 5;
}
return 0;
}
float(float wep, float delaytype) getWeaponDelay =
{
@ -3572,249 +3466,205 @@ float(float wep) getWeaponRecoilReturn =
float(float weapon, float stance) CrossHairWeapon =
{
float sprd;
sprd = 0;
float crosshair_spread = 0;
switch(weapon)
{
case W_COLT:
case W_BIATCH:
sprd = 15;
break;
case W_KAR:
case W_ARMAGEDDON:
sprd = 50;
break;
case W_THOMPSON:
case W_GIBS:
sprd = 10;
break;
case W_357:
case W_KILLU:
sprd = 10;
break;
case W_BAR:
case W_WIDOW:
sprd = 10;
break;
case W_BROWNING:
case W_ACCELERATOR:
sprd = 20;
break;
case W_DB:
case W_BORE:
sprd = 25;
break;
case W_FG:
case W_IMPELLER:
sprd = 10;
break;
case W_GEWEHR:
case W_COMPRESSOR:
sprd = 10;
break;
case W_KAR_SCOPE:
case W_HEADCRACKER:
sprd = 50;
break;
case W_M1:
case W_M1000:
sprd = 10;
break;
case W_M1A1:
case W_WIDDER:
sprd = 10;
break;
case W_MP40:
case W_AFTERBURNER:
sprd = 10;
break;
case W_MP5K:
case W_KOLLIDER:
sprd = 10;
break;
case W_MG:
case W_BARRACUDA:
sprd = 20;
break;
case W_PANZER:
case W_LONGINUS:
sprd = 0;
break;
case W_PPSH:
case W_REAPER:
sprd = 10;
crosshair_spread = 22;
break;
case W_PTRS:
case W_PENETRATOR:
sprd = 50;
case W_KAR_SCOPE:
case W_HEADCRACKER:
case W_KAR:
case W_ARMAGEDDON:
crosshair_spread = 65;
break;
case W_MP40:
case W_AFTERBURNER:
case W_STG:
case W_SPATZ:
case W_THOMPSON:
case W_GIBS:
case W_BAR:
case W_WIDOW:
case W_PPSH:
case W_REAPER:
case W_RAY:
case W_PORTER:
sprd = 10;
case W_TYPE:
case W_SAMURAI:
case W_FG:
case W_IMPELLER:
case W_MP5K:
case W_KOLLIDER:
crosshair_spread = 10;
break;
case W_BROWNING:
case W_ACCELERATOR:
case W_MG:
case W_BARRACUDA:
crosshair_spread = 30;
break;
case W_SAWNOFF:
case W_SNUFF:
sprd = 30;
break;
case W_STG:
case W_SPATZ:
sprd = 10;
crosshair_spread = 50;
break;
case W_TRENCH:
case W_GUT:
sprd = 25;
case W_DB:
case W_BORE:
crosshair_spread = 35;
break;
case W_TYPE:
case W_SAMURAI:
sprd = 10;
case W_GEWEHR:
case W_COMPRESSOR:
case W_M1:
case W_M1000:
case W_M1A1:
case W_WIDDER:
crosshair_spread = 5;
break;
case W_PANZER:
case W_LONGINUS:
case W_TESLA:
sprd = 0;
crosshair_spread = 0;
break;
default:
sprd = 0;
crosshair_spread = 0;
break;
}
if (sprd == 0)
return 0;
else {
switch(stance) {
// early out
if (crosshair_spread == 0)
return crosshair_spread;
// pretty sure CoD doesn't compute this, but we're cooler than CoD
switch(stance) {
case 2:
return sprd;
return crosshair_spread;
case 1:
return sprd - 2;
return crosshair_spread * 0.90;
case 0:
return sprd - 4;
return crosshair_spread * 0.85;
default: return 0;
}
}
return crosshair_spread;
}
float(float weapon, float stance) CrossHairMaxSpread =
{
float sprd;
sprd = 0;
float crosshair_spread = 0;
switch(weapon)
{
case W_COLT:
case W_BIATCH:
sprd = 30;
break;
case W_KAR:
case W_ARMAGEDDON:
sprd = 75;
break;
case W_THOMPSON:
case W_GIBS:
sprd = 25;
break;
case W_357:
case W_KILLU:
sprd = 20;
break;
case W_BAR:
case W_WIDOW:
sprd = 35;
break;
case W_BROWNING:
case W_ACCELERATOR:
sprd = 50;
break;
case W_DB:
case W_BORE:
sprd = 25;
break;
case W_FG:
case W_IMPELLER:
sprd = 40;
break;
case W_GEWEHR:
case W_COMPRESSOR:
sprd = 35;
break;
case W_KAR_SCOPE:
case W_HEADCRACKER:
sprd = 75;
break;
case W_M1:
case W_M1000:
sprd = 35;
break;
case W_M1A1:
case W_WIDDER:
sprd = 35;
break;
case W_STG:
case W_SPATZ:
case W_MP40:
case W_AFTERBURNER:
sprd = 25;
break;
case W_THOMPSON:
case W_GIBS:
case W_BAR:
case W_WIDOW:
case W_357:
case W_KILLU:
case W_BROWNING:
case W_ACCELERATOR:
case W_FG:
case W_IMPELLER:
case W_MP5K:
case W_KOLLIDER:
sprd = 25;
break;
case W_MG:
case W_BARRACUDA:
sprd = 50;
break;
case W_PANZER:
case W_LONGINUS:
sprd = 0;
break;
case W_PPSH:
case W_REAPER:
sprd = 25;
case W_RAY:
case W_PORTER:
case W_TYPE:
case W_SAMURAI:
crosshair_spread = 48;
break;
case W_PTRS:
case W_PENETRATOR:
sprd = 75;
break;
case W_RAY:
case W_PORTER:
sprd = 20;
case W_KAR_SCOPE:
case W_HEADCRACKER:
case W_KAR:
case W_ARMAGEDDON:
crosshair_spread = 75;
break;
case W_SAWNOFF:
case W_SNUFF:
sprd = 30;
break;
case W_STG:
case W_SPATZ:
sprd = 35;
crosshair_spread = 50;
break;
case W_DB:
case W_BORE:
case W_TRENCH:
case W_GUT:
sprd = 25;
break;
case W_TYPE:
case W_SAMURAI:
sprd = 25;
case W_GEWEHR:
case W_COMPRESSOR:
case W_M1:
case W_M1000:
case W_M1A1:
case W_WIDDER:
crosshair_spread = 35;
break;
case W_PANZER:
case W_LONGINUS:
case W_TESLA:
sprd = 0;
crosshair_spread = 0;
break;
default:
sprd = 0;
crosshair_spread = 0;
break;
}
if (sprd == 0)
return 0;
else {
switch(stance) {
// early out
if (crosshair_spread == 0)
return crosshair_spread;
// pretty sure CoD doesn't compute this, but we're cooler than CoD
switch(stance) {
case 2:
return sprd;
return crosshair_spread;
case 1:
return sprd - 2;
return crosshair_spread * 0.90;
case 0:
return sprd - 4;
default:
return 0;
}
return crosshair_spread * 0.85;
default: return 0;
}
return crosshair_spread;
}
float(float wep) W_SpreadAffectedByADS =
{
switch (wep) {
case W_SAWNOFF:
case W_SNUFF:
case W_DB:
case W_BORE:
case W_TRENCH:
case W_GUT:
return false;
default:
return true;
}
}
float(float wep, float is_moving, float stance) GetWeaponSpread =
{
float magic_number = 1.15;
if (!is_moving) {
return (CrossHairWeapon(wep, stance));
} else {
return (CrossHairMaxSpread(wep, stance)/2) * magic_number;
}
}
@ -4013,26 +3863,13 @@ vector(float wep) GetWeaponRecoil =
r = random();
temp1 = change_1 + change_2;
temp2 = change_1 + change_2 + change_3;
#ifdef FTE
if (r < change_1)
final_kick_y = kick_change_x*0.25;
final_kick_y = kick_change_x*0.4;
else if (r < temp1)
final_kick_x = kick_change_y*-1*.25;
final_kick_x = kick_change_y*-0.4;
else if (r < temp2)
final_kick_y = kick_change_z*-1*0.25;
#else
if (r < change_1)
final_kick_y = kick_change_x;
else if (r < temp1)
final_kick_x = kick_change_y*-1;
else if (r < temp2)
final_kick_y = kick_change_z*-1;
#endif // FTE
final_kick_y = kick_change_z*-0.4;
final_kick_y = final_kick_y + guaranteed_x;
final_kick_x = final_kick_x - guaranteed_y;