quakec/source/server/player.qc

1020 lines
30 KiB
C++
Raw Normal View History

2022-02-08 18:42:28 +00:00
/*
server/player.qc
2022-02-08 18:42:28 +00:00
Various stuff done for the player, including per-frame functions
like PlayerPreThink and PlayerPostThink, also client specific
stuff like PutClientInServer etc.
2024-01-07 23:24:48 +00:00
Copyright (C) 2021-2024 NZ:P Team
2022-02-08 18:42:28 +00:00
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
*/
void(entity e) Light_None;
void() Spawns_Init;
void() SUB_UseTargets;
void() rec_downed;
2022-02-08 18:42:28 +00:00
#define PLAYER_START_HEALTH 100
#define PLAYER_CROUCH_DIFFERENCE_HL 25
#define PLAYER_PRONE_DIFFERENCE_HL 23
#define PLAYER_CROUCH_DIFFERENCE_QK 15
#define PLAYER_PRONE_DIFFERENCE_QK 13
#define PLAYER_ANIM_WALK 1
#define PLAYER_ANIM_SPRINT 2
//
// Player 3rd Person Animations
//
// Walking
void() PAnim_Walk =[ 1, PAnim_Walk1 ] {self.frame = 0; self.tp_anim_time = time + 0.5;}
void() PAnim_Walk1 =[ 2, PAnim_Walk2 ] {self.frame = 1;}
void() PAnim_Walk2 =[ 3, PAnim_Walk3 ] {self.frame = 2;}
void() PAnim_Walk3 =[ 4, PAnim_Walk4 ] {self.frame = 3;}
void() PAnim_Walk4 =[ 5, PAnim_Walk5 ] {self.frame = 4;}
void() PAnim_Walk5 =[ 6, PAnim_Walk6 ] {self.frame = 5;}
void() PAnim_Walk6 =[ 7, PAnim_Walk7 ] {self.frame = 6;}
void() PAnim_Walk7 =[ 8, PAnim_Walk8 ] {self.frame = 7;}
void() PAnim_Walk8 =[ 9, SUB_Null ] {self.frame = 8;}
// Sprinting
void() PAnim_Sprint =[ 1, PAnim_Sprint1 ] {self.frame = 25; self.tp_anim_time = time + 0.65;}
void() PAnim_Sprint1 =[ 2, PAnim_Sprint2 ] {self.frame = 26;}
void() PAnim_Sprint2 =[ 3, PAnim_Sprint3 ] {self.frame = 27;}
void() PAnim_Sprint3 =[ 4, PAnim_Sprint4 ] {self.frame = 28;}
void() PAnim_Sprint4 =[ 5, PAnim_Sprint5 ] {self.frame = 29;}
void() PAnim_Sprint5 =[ 6, PAnim_Sprint6 ] {self.frame = 30;}
void() PAnim_Sprint6 =[ 7, SUB_Null ] {self.frame = 31;}
// Reloading
void() PAnim_Reload =[ 1, PAnim_Reload1 ] {self.frame = 11; self.tp_anim_time = time + 1;}
void() PAnim_Reload1 =[ 2, PAnim_Reload2 ] {self.frame = 12;}
void() PAnim_Reload2 =[ 3, PAnim_Reload3 ] {self.frame = 13;}
void() PAnim_Reload3 =[ 4, PAnim_Reload4 ] {self.frame = 14;}
void() PAnim_Reload4 =[ 5, PAnim_Reload5 ] {self.frame = 15;}
void() PAnim_Reload5 =[ 6, PAnim_Reload6 ] {self.frame = 16;}
void() PAnim_Reload6 =[ 7, PAnim_Reload7 ] {self.frame = 17;}
void() PAnim_Reload7 =[ 8, PAnim_Reload8 ] {self.frame = 18;}
void() PAnim_Reload8 =[ 9, PAnim_Reload9 ] {self.frame = 19;}
void() PAnim_Reload9 =[ 10, PAnim_Reload10 ] {self.frame = 20;}
void() PAnim_Reload10 =[ 11, PAnim_Reload11 ] {self.frame = 21;}
void() PAnim_Reload11 =[ 12, PAnim_Reload12 ] {self.frame = 22;}
void() PAnim_Reload12 =[ 13, PAnim_Reload13 ] {self.frame = 23;}
void() PAnim_Reload13 =[ 14, SUB_Null ] {self.frame = 24;}
// Firing
void() PAnim_Fire =[ 1, PAnim_Fire1 ] {self.frame = 9; self.tp_anim_time = time + 0.25;}
void() PAnim_Fire1 =[ 2, SUB_Null ] {self.frame = 10;}
// Melee
void() PAnim_Melee =[ 1, PAnim_Melee1 ] {self.frame = 49; self.tp_anim_time = time + 0.65;}
void() PAnim_Melee1 =[ 2, PAnim_Melee2 ] {self.frame = 50;}
void() PAnim_Melee2 =[ 3, PAnim_Melee3 ] {self.frame = 51;}
void() PAnim_Melee3 =[ 4, PAnim_Melee4 ] {self.frame = 52;}
void() PAnim_Melee4 =[ 5, PAnim_Melee5 ] {self.frame = 53;}
void() PAnim_Melee5 =[ 6, PAnim_Melee6 ] {self.frame = 54;}
void() PAnim_Melee6 =[ 7, SUB_Null ] {self.frame = 55;}
// Weapon Swap
void() PAnim_Swap =[ 1, PAnim_Swap1 ] {self.frame = 56; self.tp_anim_time = time + 1;}
void() PAnim_Swap1 =[ 2, PAnim_Swap2 ] {self.frame = 57;}
void() PAnim_Swap2 =[ 3, PAnim_Swap3 ] {self.frame = 58;}
void() PAnim_Swap3 =[ 4, PAnim_Swap4 ] {self.frame = 59;}
void() PAnim_Swap4 =[ 5, PAnim_Swap5 ] {self.frame = 60;}
void() PAnim_Swap5 =[ 6, PAnim_Swap6 ] {self.frame = 61;}
void() PAnim_Swap6 =[ 7, PAnim_Swap7 ] {self.frame = 62;}
void() PAnim_Swap7 =[ 8, PAnim_Swap8 ] {self.frame = 63;}
void() PAnim_Swap8 =[ 9, SUB_Null ] {self.frame = 64;}
// Enter Dolphin Dive
void() PAnim_EnterDive =[ 1, PAnim_EnterDive1 ] {self.frame = 203; self.tp_anim_time = time + 5;}
void() PAnim_EnterDive1 =[ 2, PAnim_EnterDive2 ] {self.frame = 204;}
void() PAnim_EnterDive2 =[ 3, PAnim_EnterDive3 ] {self.frame = 205;}
void() PAnim_EnterDive3 =[ 4, PAnim_EnterDive4 ] {self.frame = 206;}
void() PAnim_EnterDive4 =[ 5, SUB_Null ] {self.frame = 207;}
// Flop from Dive
void() PAnim_Flop =[ 1, PAnim_Flop1 ] {self.frame = 208; self.tp_anim_time = time + 1;}
void() PAnim_Flop1 =[ 2, PAnim_Flop2 ] {self.frame = 209;}
void() PAnim_Flop2 =[ 3, PAnim_Flop3 ] {self.frame = 210;}
void() PAnim_Flop3 =[ 4, SUB_Null ] {self.frame = 211;}
// Enter Stand
void() PAnim_Stand =[ 1, PAnim_Stand1 ] {self.frame = 114; self.tp_anim_time = time + 1;}
void() PAnim_Stand1 =[ 2, PAnim_Stand2 ] {self.frame = 113;}
void() PAnim_Stand2 =[ 3, SUB_Null ] {self.frame = 0;}
// Enter Crouch
void() PAnim_Crouch =[ 1, PAnim_Crouch1 ] {self.frame = 113; self.tp_anim_time = time + 0.5;}
void() PAnim_Crouch1 =[ 2, PAnim_Crouch2 ] {self.frame = 114;}
void() PAnim_Crouch2 =[ 3, SUB_Null ] {self.frame = 115;}
// Walking, while Crouch
void() PAnim_CrouchWalk =[ 1, PAnim_CrouchWalk1 ] {self.frame = 116; self.tp_anim_time = time + 0.5;}
void() PAnim_CrouchWalk1=[ 2, PAnim_CrouchWalk2 ] {self.frame = 117;}
void() PAnim_CrouchWalk2=[ 3, PAnim_CrouchWalk3 ] {self.frame = 118;}
void() PAnim_CrouchWalk3=[ 4, PAnim_CrouchWalk4 ] {self.frame = 119;}
void() PAnim_CrouchWalk4=[ 5, PAnim_CrouchWalk5 ] {self.frame = 120;}
void() PAnim_CrouchWalk5=[ 6, PAnim_CrouchWalk6 ] {self.frame = 121;}
void() PAnim_CrouchWalk6=[ 7, PAnim_CrouchWalk7 ] {self.frame = 122;}
void() PAnim_CrouchWalk7=[ 8, PAnim_CrouchWalk8 ] {self.frame = 123;}
void() PAnim_CrouchWalk8=[ 9, SUB_Null ] {self.frame = 124;}
// Reloading, while Crouch
void() PAnim_CrReload =[ 1, PAnim_CrReload1 ] {self.frame = 128; self.tp_anim_time = time + 1;}
void() PAnim_CrReload1 =[ 2, PAnim_CrReload2 ] {self.frame = 129;}
void() PAnim_CrReload2 =[ 3, PAnim_CrReload3 ] {self.frame = 130;}
void() PAnim_CrReload3 =[ 4, PAnim_CrReload4 ] {self.frame = 131;}
void() PAnim_CrReload4 =[ 5, PAnim_CrReload5 ] {self.frame = 132;}
void() PAnim_CrReload5 =[ 6, PAnim_CrReload6 ] {self.frame = 133;}
void() PAnim_CrReload6 =[ 7, PAnim_CrReload7 ] {self.frame = 134;}
void() PAnim_CrReload7 =[ 8, PAnim_CrReload8 ] {self.frame = 135;}
void() PAnim_CrReload8 =[ 9, PAnim_CrReload9 ] {self.frame = 136;}
void() PAnim_CrReload9 =[ 10, SUB_Null ] {self.frame = 115;}
// Firing, while Crouch
void() PAnim_CrouchFire =[ 1, PAnim_CrouchFire1 ] {self.frame = 126; self.tp_anim_time = time + 0.25;}
void() PAnim_CrouchFire1=[ 2, SUB_Null ] {self.frame = 127;}
// Enter Prone
void() PAnim_Prone =[ 1, PAnim_Prone1 ] {self.frame = 154; self.tp_anim_time = time + 1.5;}
void() PAnim_Prone1 =[ 2, PAnim_Prone2 ] {self.frame = 155;}
void() PAnim_Prone2 =[ 3, PAnim_Prone3 ] {self.frame = 156;}
void() PAnim_Prone3 =[ 4, PAnim_Prone4 ] {self.frame = 157;}
void() PAnim_Prone4 =[ 5, PAnim_Prone5 ] {self.frame = 158;}
void() PAnim_Prone5 =[ 6, PAnim_Prone6 ] {self.frame = 159;}
void() PAnim_Prone6 =[ 7, PAnim_Prone7 ] {self.frame = 160;}
void() PAnim_Prone7 =[ 8, PAnim_Prone8 ] {self.frame = 161;}
void() PAnim_Prone8 =[ 9, SUB_Null ] {self.frame = 162;}
// Walking, while Prone
void() PAnim_ProneWalk =[ 1, PAnim_ProneWalk1 ] {self.frame = 162; self.tp_anim_time = time + 1.5;}
void() PAnim_ProneWalk1 =[ 2, PAnim_ProneWalk2 ] {self.frame = 163;}
void() PAnim_ProneWalk2 =[ 3, PAnim_ProneWalk3 ] {self.frame = 164;}
void() PAnim_ProneWalk3 =[ 4, PAnim_ProneWalk4 ] {self.frame = 165;}
void() PAnim_ProneWalk4 =[ 5, PAnim_ProneWalk5 ] {self.frame = 166;}
void() PAnim_ProneWalk5 =[ 6, PAnim_ProneWalk6 ] {self.frame = 167;}
void() PAnim_ProneWalk6 =[ 7, PAnim_ProneWalk7 ] {self.frame = 168;}
void() PAnim_ProneWalk7 =[ 8, PAnim_ProneWalk8 ] {self.frame = 169;}
void() PAnim_ProneWalk8 =[ 9, PAnim_ProneWalk9 ] {self.frame = 170;}
void() PAnim_ProneWalk9 =[ 10, PAnim_ProneWalk10 ] {self.frame = 171;}
void() PAnim_ProneWalk10=[ 11, PAnim_ProneWalk11 ] {self.frame = 172;}
void() PAnim_ProneWalk11=[ 12, PAnim_ProneWalk12 ] {self.frame = 173;}
void() PAnim_ProneWalk12=[ 13, SUB_Null ] {self.frame = 174;}
// Reloading, while Prone
void() PAnim_PrReload =[ 1, PAnim_PrReload1 ] {self.frame = 176; self.tp_anim_time = time + 1;}
void() PAnim_PrReload1 =[ 2, PAnim_PrReload2 ] {self.frame = 177;}
void() PAnim_PrReload2 =[ 3, PAnim_PrReload3 ] {self.frame = 178;}
void() PAnim_PrReload3 =[ 4, PAnim_PrReload4 ] {self.frame = 179;}
void() PAnim_PrReload4 =[ 5, PAnim_PrReload5 ] {self.frame = 180;}
void() PAnim_PrReload5 =[ 6, PAnim_PrReload6 ] {self.frame = 181;}
void() PAnim_PrReload6 =[ 7, SUB_Null ] {self.frame = 162;}
// Enter Crouch, from Prone
void() PAnim_UpCrouch =[ 1, PAnim_UpCrouch1 ] {self.frame = 161; self.tp_anim_time = time + 1;}
void() PAnim_UpCrouch1 =[ 2, PAnim_UpCrouch2 ] {self.frame = 160;}
void() PAnim_UpCrouch2 =[ 3, PAnim_UpCrouch3 ] {self.frame = 159;}
void() PAnim_UpCrouch3 =[ 4, PAnim_UpCrouch4 ] {self.frame = 158;}
void() PAnim_UpCrouch4 =[ 5, PAnim_UpCrouch5 ] {self.frame = 157;}
void() PAnim_UpCrouch5 =[ 6, PAnim_UpCrouch6 ] {self.frame = 156;}
void() PAnim_UpCrouch6 =[ 7, PAnim_UpCrouch7 ] {self.frame = 155;}
void() PAnim_UpCrouch7 =[ 8, PAnim_UpCrouch8 ] {self.frame = 154;}
void() PAnim_UpCrouch8 =[ 9, SUB_Null ] {self.frame = 115;}
// Enter Last Stand
void() PAnim_GetDown =[ 1, PAnim_GetDown1 ] {self.frame = 32; self.tp_anim_time = time + 1;};
void() PAnim_GetDown1 =[ 2, PAnim_GetDown2 ] {self.frame = 33;};
void() PAnim_GetDown2 =[ 3, PAnim_GetDown3 ] {self.frame = 34;};
void() PAnim_GetDown3 =[ 4, PAnim_GetDown4 ] {self.frame = 35;};
void() PAnim_GetDown4 =[ 5, PAnim_GetDown5 ] {self.frame = 36;};
void() PAnim_GetDown5 =[ 6, SUB_Null ] {self.frame = 37; rec_downed();};
// Firing, while in Last Stand
void() PAnim_LastFire =[ 1, PAnim_LastFire1 ] {self.frame = 36; self.tp_anim_time = time + 0.25;}
void() PAnim_LastFire1 =[ 2, SUB_Null ] {self.frame = 37;}
// Leave Last Stand
void() PAnim_GetUp =[ 1, PAnim_GetUp1 ] {self.frame = 39; self.tp_anim_time = time + 1;}
void() PAnim_GetUp1 =[ 2, PAnim_GetUp2 ] {self.frame = 40;}
void() PAnim_GetUp2 =[ 3, PAnim_GetUp3 ] {self.frame = 41;}
void() PAnim_GetUp3 =[ 4, PAnim_GetUp4 ] {self.frame = 42;}
void() PAnim_GetUp4 =[ 5, PAnim_GetUp5 ] {self.frame = 43;}
void() PAnim_GetUp5 =[ 6, PAnim_GetUp6 ] {self.frame = 44;}
void() PAnim_GetUp6 =[ 7, PAnim_GetUp7 ] {self.frame = 45;}
void() PAnim_GetUp7 =[ 8, PAnim_GetUp8 ] {self.frame = 46;}
void() PAnim_GetUp8 =[ 9, PAnim_GetUp9 ] {self.frame = 47;}
void() PAnim_GetUp9 =[ 10, SUB_Null ] {self.frame = 48;}
2022-02-08 18:42:28 +00:00
#define forward 0
#define backward 1
#define left 2
#define right 3
#define all_move -1
2022-09-03 00:19:25 +00:00
2022-02-08 18:42:28 +00:00
float(float dir) checkMovement =
{
2022-02-08 18:42:28 +00:00
switch(dir) {
case forward:
if (self.movement_x > 0)
2022-02-08 18:42:28 +00:00
return 1;
break;
case backward:
if (self.movement_x < 0)
2022-02-08 18:42:28 +00:00
return 1;
break;
case right:
if (self.movement_y > 0)
2022-02-08 18:42:28 +00:00
return 1;
break;
case left:
if (self.movement_y < 0)
2022-02-08 18:42:28 +00:00
return 1;
break;
case all_move:
if (self.movement_x || self.movement_y)
2022-02-08 18:42:28 +00:00
return 1;
break;
default:
return 0;
}
}
//
// Player_CanStandHere
// Performs a tracebox and will return true
// if the player can stance in their current
// space.
//
float(entity who) Player_CanStandHere =
{
// There shouldn't be any real reason we'd care about this since beta maps don't support
// stance changing impacting the bbox, but still, consistency..
if (map_compatibility_mode == MAP_COMPAT_BETA)
tracebox(who.origin, PLAYER_MINS_QUAKE, PLAYER_MAXS_QUAKE, who.origin, true, who);
else
tracebox(who.origin, PLAYER_MINS_STANDING, PLAYER_MAXS_STANDING, who.origin, true, who);
return !trace_startsolid;
}
//
// Player_SetStance(who, preferred_stance, play_animation)
// Lowers the camera height as needed, registers
// preferred stance, plays animation, and sets
// bounding box (if applicable).
//
void(entity who, float preferred_stance, float play_animation) Player_SetStance =
{
// Don't bother if we're already the desired stance, or if it wasn't valid
if (who.stance == preferred_stance || preferred_stance < 0 || preferred_stance > 2)
return;
// First check -- if we want to stand, only crouch if there
// is no space for it.
if (preferred_stance == PLAYER_STANCE_STAND && !Player_CanStandHere(who))
preferred_stance = PLAYER_STANCE_CROUCH;
// Set the bounding box
if (map_compatibility_mode != MAP_COMPAT_BETA) {
if (preferred_stance != PLAYER_STANCE_STAND)
setsize(self, PLAYER_MINS_CROUCHING, PLAYER_MAXS_CROUCHING);
else
setsize(self, PLAYER_MINS_STANDING, PLAYER_MAXS_STANDING);
}
// NZ:P Beta should change the stances by a different amount,
// to avoid looking like you're in the ground..
float height_diff_crouch, height_diff_prone;
if (map_compatibility_mode == MAP_COMPAT_BETA) {
height_diff_crouch = PLAYER_CROUCH_DIFFERENCE_QK;
height_diff_prone = PLAYER_PRONE_DIFFERENCE_QK;
} else {
height_diff_crouch = PLAYER_CROUCH_DIFFERENCE_HL;
height_diff_prone = PLAYER_PRONE_DIFFERENCE_HL;
}
// Prone while standing? Lower to crouch + prone height.
if (who.stance == PLAYER_STANCE_STAND && preferred_stance == PLAYER_STANCE_PRONE)
who.new_ofs_z = who.view_ofs_z - (height_diff_crouch + height_diff_prone);
// Prone while crouching? Lower to prone height.
else if (who.stance == PLAYER_STANCE_CROUCH && preferred_stance == PLAYER_STANCE_PRONE)
who.new_ofs_z = who.view_ofs_z - height_diff_prone;
// Crouch while proning? Raise to crouch height/take away prone difference.
else if (who.stance == PLAYER_STANCE_PRONE && preferred_stance == PLAYER_STANCE_CROUCH)
who.new_ofs_z = who.view_ofs_z + height_diff_prone;
// Crouch while standing? Lower to crouch height.
else if (who.stance == PLAYER_STANCE_STAND && preferred_stance == PLAYER_STANCE_CROUCH)
who.new_ofs_z = who.view_ofs_z - height_diff_crouch;
// Stand while crouching? Raise to stand height/take away crouch difference.
else if (who.stance == PLAYER_STANCE_CROUCH && preferred_stance == PLAYER_STANCE_STAND)
who.new_ofs_z = who.view_ofs_z + height_diff_crouch;
// Stand while proning? Raise to stand height/take away crouch + prone difference.
else if (who.stance == PLAYER_STANCE_PRONE && preferred_stance == PLAYER_STANCE_STAND)
who.new_ofs_z = who.view_ofs_z + (height_diff_crouch + height_diff_prone);
// Set the stance value
who.stance = preferred_stance;
// Animation playback
if (play_animation == true) {
entity tempe = self;
self = who;
switch(who.stance) {
case PLAYER_STANCE_STAND: PAnim_Stand(); break;
case PLAYER_STANCE_CROUCH: PAnim_Crouch(); break;
case PLAYER_STANCE_PRONE: PAnim_Prone(); break;
default: break;
}
self = tempe;
}
}
2022-02-08 18:42:28 +00:00
void() PlayerJump =
{
if (!(self.flags & FL_ONGROUND)
|| !(self.flags & FL_JUMPRELEASED)
|| self.downed
|| self.dive ) {
return;
}
self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
if (self.button2)
self.button2 = 0;
self.oldz = self.origin_z;
self.velocity_z = 230;
}
void(float override) JumpCheck =
{
#ifndef FTE
2022-02-08 18:42:28 +00:00
override = 0;
#endif // FTE
2022-02-08 18:42:28 +00:00
if(self.button2 || override) {
if (self.downed)
return;
if (self.stance == PLAYER_STANCE_STAND) {
2022-02-08 18:42:28 +00:00
// naievil -- stop sprinting if we jump, which is a real mechanic from the game that we never implemented
if (self.sprinting) {
W_SprintStop();
}
PlayerJump();
} else if (self.view_ofs_z == self.new_ofs_z && (self.flags & FL_ONGROUND)) {
Player_SetStance(self, PLAYER_STANCE_STAND, true);
2022-02-08 18:42:28 +00:00
}
} else
self.flags = self.flags | FL_JUMPRELEASED;
}
2022-09-03 00:19:25 +00:00
2022-02-08 18:42:28 +00:00
void() PlayerPreThink =
{
if (self.downed) {
self.maxspeed = 30;
} else {
// Walk slower to account for NZ:P Beta Scaling.
if (map_compatibility_mode == MAP_COMPAT_BETA)
self.maxspeed = 150;
else
self.maxspeed = 190;
2022-02-08 18:42:28 +00:00
if (self.sprinting) {
#ifdef FTE
2022-02-08 18:42:28 +00:00
// viewbob when running
self.punchangle_y = 0.6*sin(time*10);
#endif // FTE
//playrun1();
self.maxspeed *= 1.5; // down from 1.66x, to match WaW
2022-02-08 18:42:28 +00:00
} else if (!self.sprinting && !self.zoom) {
#ifdef FTE
2022-02-08 18:42:28 +00:00
if (checkMovement(-1))
self.punchangle_x = 0.25*sin(time*15);
#endif // FTE
2022-02-08 18:42:28 +00:00
} else if (self.zoom != 3) {
self.maxspeed *= 0.5;
2022-04-06 01:46:24 +00:00
}
// Speed Penalty
if (self.speed_penalty_time > time)
{
self.maxspeed *= self.speed_penalty;
} else {
self.speed_penalty = 1;
2022-02-08 18:42:28 +00:00
}
switch(self.stance) {
case 1:
self.maxspeed *= 0.65;
2022-02-08 18:42:28 +00:00
break;
case 0:
self.maxspeed *= 0.25;
break;
}
#ifdef FTE
2022-02-08 18:42:28 +00:00
if (checkMovement(backward)) {
self.maxspeed *= 0.7;
} else if (checkMovement(left) || checkMovement(right)) {
self.maxspeed *= 0.8;
}
#endif // FTE
2022-02-08 18:42:28 +00:00
if (!self.isBuying)
self.maxspeed *= GetWeaponWalkSpeed(self.perks, self.weapon);
2022-02-08 18:42:28 +00:00
}
if(self.isspec != 0 && !self.downed)
{
if(self.button0 && self.fire_delay < time)
2022-02-08 18:42:28 +00:00
{
self.aiment = find(self.aiment, classname, "player");
if(self.aiment != world)
{
sprint(self, PRINT_HIGH, "Now spectating ");
sprint(self, PRINT_HIGH, self.aiment.netname);
sprint(self, PRINT_HIGH, "\n");
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
}
else
{
sprint(self, PRINT_HIGH, "Freefly spectate\n");
self.movetype = MOVETYPE_FLY;
}
self.fire_delay = time + 0.25;
2022-02-08 18:42:28 +00:00
}
if(self.aiment != world)
{
self.origin = self.aiment.origin;
self.angles = self.aiment.v_angle;
self.velocity = self.aiment.velocity;
self.fixangle = TRUE;
}
return;
}
if (cvar("waypoint_mode")) {
Waypoint_Logic();
} else {
2024-01-09 22:45:23 +00:00
WeaponCore_ClientLogic();
2022-02-08 18:42:28 +00:00
}
JumpCheck(0);
// Fire effect
if (self.onfire) {
Effect_Fire(self.origin);
if (self.fire_timeout < time)
self.onfire = false;
}
// Flamethrower-based weapon cooldown/refuel process.
2022-02-08 18:42:28 +00:00
if (self.ltime < time) {
float weapon_slot = Weapon_PlayerHasWeaponWithFiretype(self, FIRETYPE_FLAME);
if (weapon_slot == 0)
return;
weapon_slot--;
if (self.weapons[weapon_slot].weapon_magazine == 0 && !self.cooldown) {
2022-02-08 18:42:28 +00:00
self.cooldown = true;
}
if (self.cooldown && self.weapons[weapon_slot].weapon_magazine > 20)
2022-02-08 18:42:28 +00:00
self.cooldown = false;
if (self.weapons[weapon_slot].weapon_magazine < getWeaponMag(self.weapons[weapon_slot].weapon_id)) {
self.weapons[weapon_slot].weapon_magazine += 1;
2023-10-17 12:54:27 +00:00
}
2022-02-08 18:42:28 +00:00
self.ltime = time + 0.1;
}
};
float player_trace_time;
2022-02-08 18:42:28 +00:00
void() PlayerPostThink =
{
#ifdef FTE
// Network everything
self.SendFlags = 1;
#endif // FTE
2022-02-08 18:42:28 +00:00
if(self.isspec)
return;
#ifndef FTE
if (time < 5 && self.name != "")
nzp_setplayername(self, self.name);
#endif // FTE
2022-02-08 18:42:28 +00:00
//landsound
if((self.oldvelocity_z < -212) && (self.flags & FL_ONGROUND))
2022-02-08 18:42:28 +00:00
{
2023-11-16 00:34:01 +00:00
sound(self, CHAN_BODY, "sounds/player/land.wav", 0.6, 1.75);
2022-02-08 18:42:28 +00:00
self.lastsound_time = time - 0.15;
}
// Walking Animations
if (self.tp_anim_time < time && self.reload_delay < time && self.reload_delay2 < time
&& self.fire_delay < time && self.fire_delay2 < time && self.knife_delay < time) {
if (vlen(self.velocity) > 20) {
if (self.sprinting) {
PAnim_Sprint();
self.tp_anim_type = PLAYER_ANIM_SPRINT;
} else {
self.tp_anim_type = PLAYER_ANIM_WALK;
switch(self.stance) {
case 2: PAnim_Walk(); break;
case 1: PAnim_CrouchWalk(); break;
case 0: PAnim_ProneWalk(); break;
}
}
} else {
// Stand still so Crouch Walk isn't stuck in place
switch(self.stance) {
case 2: self.frame = 0; break;
case 1: self.frame = 115; break;
case 0: self.frame = 162; break;
}
// If we're downed force set the last stand idle frame as well
// so the player doesn't look like they're just prone.
if (self.downed)
self.frame = 37;
}
}
2022-02-08 18:42:28 +00:00
#ifdef FTE
2022-02-08 18:42:28 +00:00
//footsteps
if((vlen(self.velocity) > 20) &&(( time - self.lastsound_time > 0.4) || (time - self.lastsound_time > 0.3 && self.sprinting)) && (self.flags & FL_ONGROUND))
2022-02-08 18:42:28 +00:00
{
float movelen = vlen(input_movevalues);
2022-02-08 18:42:28 +00:00
if(movelen > 300)
{
2022-02-08 18:42:28 +00:00
local float ran = random();
if(ran > 0.8)
2023-11-16 00:34:01 +00:00
sound(self, CHAN_BODY, "sounds/player/footstep1.wav", 0.6, 2.5);
2022-02-08 18:42:28 +00:00
else if(ran > 0.6)
2023-11-16 00:34:01 +00:00
sound(self, CHAN_BODY, "sounds/player/footstep2.wav", 0.6, 2.5);
2022-02-08 18:42:28 +00:00
else if(ran > 0.4)
2023-11-16 00:34:01 +00:00
sound(self, CHAN_BODY, "sounds/player/footstep3.wav", 0.6, 2.5);
2022-02-08 18:42:28 +00:00
else if(ran > 0.2)
2023-11-16 00:34:01 +00:00
sound(self, CHAN_BODY, "sounds/player/footstep4.wav", 0.6, 2.5);
2022-02-08 18:42:28 +00:00
else
2023-11-16 00:34:01 +00:00
sound(self, CHAN_BODY, "sounds/player/footstep5.wav", 0.6, 2.5);
2022-02-08 18:42:28 +00:00
self.lastsound_time = time;
}
}
#endif // FTE
2022-02-08 18:42:28 +00:00
// Health Regeneration
2022-02-08 18:42:28 +00:00
if (self.health_delay < time && self.health != self.max_health && !self.downed)
{
// If we weren't super low on health, regen is instant.
if (self.health_was_very_low == true) {
self.health += 120 * frametime;
} else {
// Was 100% instant, but this delays it by only a few
// frames so the graphic doesn't just vanish when healed.
self.health += 300 * frametime;
}
// Make sure we mark that we weren't just super hurt anymore.
if (self.max_health <= self.health) {
self.health = self.max_health;
self.health_was_very_low = false;
}
2022-02-08 18:42:28 +00:00
}
if (self.progress_bar) {
if (self.progress_bar < time) {
if (self.downed)
GetUp();
if (self.reviving)
self.revived = 1;
self.progress_bar = 0;
self.progress_bar_time = 0;
self.progress_bar_percent = 0;
} else {
float remaining = self.progress_bar - time;
self.progress_bar_percent = invertfloat((remaining / self.progress_bar_time));
}
}
if (self.sprinting) {
self.sprint_timer = self.sprint_duration + (time - self.sprint_start_time);
#ifndef FTE
2022-02-08 18:42:28 +00:00
if (!self.velocity || self.stance != 2) {
W_SprintStop();
}
#else
2022-02-08 18:42:28 +00:00
if (!self.velocity || !checkMovement(0) || self.stance != 2) { //moto (FIXME) -- move me!
W_SprintStop();
}
#endif // FTE
2022-02-08 18:42:28 +00:00
if (self.perks & P_STAMIN) {
if (self.sprint_timer > sprint_max_time * 2) {
W_SprintStop();
}
}
else
{
if (self.sprint_timer > sprint_max_time) {
W_SprintStop();
}
}
} else if (self.sprint_duration > 0.0) {
self.sprint_rest_time = (time - self.sprint_stop_time);
}
self.oldvelocity = self.velocity;
// Perform a traceline to keep track of entities directly
// in front of the player.
// Also don't do it every frame because that's really tough
// on perf.
if (player_trace_time < time) {
vector source;
makevectors (self.v_angle);
source = self.origin + self.view_ofs;
2022-02-08 18:42:28 +00:00
#ifdef FTE
self.dimension_hit = HITBOX_DIM_LIMBS | HITBOX_DIM_ZOMBIES;
#endif // FTE
traceline (source, source + v_forward*800*1.2, 0, self);
#ifdef FTE
self.dimension_hit = HITBOX_DIM_ZOMBIES;
#endif // FTE
2022-02-08 18:42:28 +00:00
// use .head here to avoid expanding ent struct
self.head = trace_ent;
2022-02-08 18:42:28 +00:00
// check whether we're looking at an entity separately to communicate
// with the client more reasonably
if (trace_ent.classname == "ai_zombie" || trace_ent.classname == "ai_zombie_head"
|| trace_ent.classname == "ai_zombie_rarm" ||trace_ent.classname == "ai_zombie_larm"
|| trace_ent.classname == "ai_dog")
self.facingenemy = true;
else
self.facingenemy = false;
// 1/4 of a second is enough of a delay to not kill the effect.
player_trace_time = time + 0.25;
}
2022-02-08 18:42:28 +00:00
};
void() ClientKill = {};
//called when a client connects to the server
void() ClientConnect =
2023-02-07 07:32:14 +00:00
{
2022-02-08 18:42:28 +00:00
if(cvar("developer") || player_count > 1) {
bprint(PRINT_HIGH, self.netname); //print player name
bprint(PRINT_HIGH, " connected.\n");
}
};
//
// Player_PickSpawnPoint()
// Picks a valid spawn point for the
// newly spawning player, as well as
// assigns any spawn-specific fields
// (e.g., starting weapon).
//
void() Player_PickSpawnPoint =
{
entity spawn_point = world;
float found_viable_spawn = false;
// Assign a location
while(!found_viable_spawn) {
float index = random();
// assign one of the spawnpoints
if (index < 0.25)
spawn_point = find(world, classname, SPAWN_1_CLASS);
else if (index < 0.50)
spawn_point = find(world, classname, SPAWN_2_CLASS);
else if (index < 0.75)
spawn_point = find(world, classname, SPAWN_3_CLASS);
else
spawn_point = find(world, classname, SPAWN_4_CLASS);
float found_player_here = false;
entity ents_in_spawn_range = findradius(spawn_point.origin, 32);
// check if there's a player in the way
while(ents_in_spawn_range != world) {
if (ents_in_spawn_range.classname == "player")
found_player_here = true;
ents_in_spawn_range = ents_in_spawn_range.chain;
}
// no player in the way, this spawn is good.
if (found_player_here == false)
found_viable_spawn = true;
}
// Give them their name
self.name = spawn_point.name;
// Set their location
self.origin = spawn_point.origin + '0 0 1';
self.angles = spawn_point.angles;
// Assign their starting weapon
Weapon_AssignWeapon(0, spawn_point.weapon, spawn_point.currentmag, spawn_point.currentammo);
// Activate anything the Spawn was targeting
entity tempe = self;
self = spawn_point;
SUB_UseTargets();
self = tempe;
};
2022-02-08 18:42:28 +00:00
void() PlayerSpawn =
{
entity spawnpoint = world;
2022-02-08 18:42:28 +00:00
local_client = self;
2023-01-13 16:42:27 +00:00
2022-02-08 18:42:28 +00:00
self.isspec = FALSE;
self.classname = "player";
self.solid = SOLID_BBOX;
self.onfire = false;
self.fire_timeout = 0;
2023-01-15 18:10:25 +00:00
// We can only collide with zombies (and not their limbs)
#ifdef FTE
2023-01-15 18:10:25 +00:00
self.dimension_hit = HITBOX_DIM_ZOMBIES;
#endif // FTE
2022-02-08 18:42:28 +00:00
setmodel(self, "models/player.mdl");
self.movetype = MOVETYPE_WALK;
self.max_health = self.health = PLAYER_START_HEALTH;
2022-02-08 18:42:28 +00:00
entity who = find(world,classname,"player");
while(who != self && !self.playernum)
{
if(who)
{
player_count++;
break;
}
}
2023-01-13 16:42:27 +00:00
if (!self.playernum) {
self.playernum = player_count + 1;
if (self.playernum == 1)
pl1 = self;
2022-02-08 18:42:28 +00:00
}
2023-01-13 16:42:27 +00:00
// Assign them a spawn location.
Player_PickSpawnPoint();
2022-02-08 18:42:28 +00:00
self.fixangle = true;
// NZ:P Beta used Quake BSP 29, so set bounding box accordingly.
if (map_compatibility_mode == MAP_COMPAT_BETA) {
self.view_ofs = VIEW_OFS_QK;
setsize(self, PLAYER_MINS_QUAKE, PLAYER_MAXS_QUAKE);
} else {
self.view_ofs = VIEW_OFS_HL;
setsize(self, PLAYER_MINS_STANDING, PLAYER_MAXS_STANDING);
}
2022-02-08 18:42:28 +00:00
self.stance = 2;
self.new_ofs_z = self.view_ofs_z;
self.oldz = self.origin_z;
self.grenades = self.grenades | 1; // add frag grenades to player inventory
if (rounds)
self.primary_grenades = 2;
else
self.primary_grenades = 0; // start off without grenades
self.pri_grenade_state = 0; // defines that frag grenades are for player first, not betty
self.secondary_grenades = -1; // shows that we both don't have betties AND shouldn't draw the image onscreen
if (!self.points)
addmoney(self, G_STARTPOINTS, 0);
self.weaponmodel = GetWeaponModel(self.weapon, 0);// Give weapon model
self.weapon2model = GetWeapon2Model(self.weapon);
SwitchWeapon(self.weapon);
self.stamina = 3;
self.reviving = 0;
self.perks = G_PERKS;
SetPerk(self, self.perks);
if (rounds < 1 && player_count == 0) {
sound(self, CHAN_AUTO, "sounds/rounds/splash.wav", 1, ATTN_NONE);
sound(self, CHAN_ITEM, "sounds/rounds/nround.wav", 0.75, ATTN_NONE);
2022-02-08 18:42:28 +00:00
}
PromptLevelChange(self.nextthink + 3, 1, self);
UpdatePlayerCount(player_count);
#ifdef FTE
2022-02-08 18:42:28 +00:00
UpdateV2model("", 0);
stuffcmd(self, "cl_gunx 8;cl_guny 16;cl_gunz 25\n");
SetRound(self, G_STARTROUND);
self.viewzoom = 1;
self.SendEntity = Player_SendEntity;
2022-02-08 18:42:28 +00:00
self.weapon_animduration = getWeaponDelay(self.weapon, FIRE);
if (G_WORLDTEXT)
WorldText(world.chaptertitle, world.location, world.date, world.person, self);
ReportMapMode(map_compatibility_mode, self);
#else
2022-02-08 18:42:28 +00:00
self.Weapon_Name = GetWeaponName(self.weapon);
self.Flash_Offset = GetWeaponFlash_Offset(self.weapon);
self.Flash_Size = GetWeaponFlash_Size(self.weapon);
self.ADS_Offset = GetWeaponADSOfs_PSP(self.weapon);
#endif // FTE
2022-02-08 18:42:28 +00:00
if (G_STARTROUND != 1) {
rounds = G_STARTROUND - 1;
}
};
void() SpectatorSpawn =
{
local entity spawnpoint;
spawnpoint = find(world, classname, "info_player_1_spawn");
2022-02-08 18:42:28 +00:00
self.isspec = TRUE;
self.health = 420;
2022-02-08 18:42:28 +00:00
self.classname = "spectator";
self.solid = SOLID_CORPSE;
setmodel(self, "models/sprites/null.spr");
2022-02-08 18:42:28 +00:00
self.movetype = MOVETYPE_FLY;
self.origin = spawnpoint.origin + [0,0,1];
self.fixangle = TRUE;
setsize(self, PLAYER_MINS_STANDING, PLAYER_MAXS_STANDING);
2022-02-08 18:42:28 +00:00
self.view_ofs = '0 0 22';
self.aiment = world;
};
//called when a client loads a map
float spawns_initialized;
2022-02-08 18:42:28 +00:00
void() PutClientInServer =
{
// Init Spawn Points
if (!spawns_initialized) {
Spawns_Init();
spawns_initialized = true;
}
2022-02-08 18:42:28 +00:00
if(cvar("developer") || player_count > 1) {
bprint(PRINT_HIGH, self.netname);
bprint(PRINT_HIGH, " has joined the game.\n");
}
if (spawn_time > time || !rounds)
PlayerSpawn();
#ifdef FTE
2022-02-08 18:42:28 +00:00
else
SpectatorSpawn();
#endif // FTE
GameRestart_ResetPerkaColas();
2022-02-08 18:42:28 +00:00
};
//called when client disconnects from the server
void() ClientDisconnect =
{
bprint(PRINT_HIGH, self.netname);
bprint(PRINT_HIGH, " has left the game.\n");
player_count--;
UpdatePlayerCount(player_count);
self.classname = "disconnected";
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_BOUNCE;
self.nextthink = -1;
setmodel(self, "models/sprites/null.spr");
GameRestart_ResetPerkaColas();
if (self.downed) {
DisableReviveIcon(self.electro_targeted);
revive_index--;
}
#ifdef FTE
// Network everything
self.SendFlags = 1;
#endif // FTE
2022-02-08 18:42:28 +00:00
};
void() SetNewParms =
{
};
void() SetChangeParms =
{
};
#ifdef FTE
2022-02-08 18:42:28 +00:00
void() SV_RunClientCommand =
{
runstandardplayerphysics(self);
}
#endif // FTE