/* server/player.qc Various stuff done for the player, including per-frame functions like PlayerPreThink and PlayerPostThink, also client specific stuff like PutClientInServer etc. Copyright (C) 2021-2024 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 */ void(entity e) Light_None; void() Spawns_Init; void() SUB_UseTargets; void() rec_downed; #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;} #define forward 0 #define backward 1 #define left 2 #define right 3 #define all_move -1 float(float dir) checkMovement = { switch(dir) { case forward: if (self.movement_x > 0) return 1; break; case backward: if (self.movement_x < 0) return 1; break; case right: if (self.movement_y > 0) return 1; break; case left: if (self.movement_y < 0) return 1; break; case all_move: if (self.movement_x || self.movement_y) 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; } } 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 override = 0; #endif // FTE if(self.button2 || override) { if (self.downed) return; if (self.stance == PLAYER_STANCE_STAND) { // 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); } } else self.flags = self.flags | FL_JUMPRELEASED; } 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; if (self.sprinting) { #ifdef FTE // 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 } else if (!self.sprinting && !self.zoom) { #ifdef FTE if (checkMovement(-1)) self.punchangle_x = 0.25*sin(time*15); #endif // FTE } else if (self.zoom != 3) { self.maxspeed *= 0.5; } // Speed Penalty if (self.speed_penalty_time > time) { self.maxspeed *= self.speed_penalty; } else { self.speed_penalty = 1; } switch(self.stance) { case 1: self.maxspeed *= 0.65; break; case 0: self.maxspeed *= 0.25; break; } #ifdef FTE if (checkMovement(backward)) { self.maxspeed *= 0.7; } else if (checkMovement(left) || checkMovement(right)) { self.maxspeed *= 0.8; } #endif // FTE if (!self.isBuying) self.maxspeed *= GetWeaponWalkSpeed(self.perks, self.weapon); } if(self.isspec != 0 && !self.downed) { if(self.button0 && self.fire_delay < time) { 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; } 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 { WeaponCore_ClientLogic(); } 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. 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) { self.cooldown = true; } if (self.cooldown && self.weapons[weapon_slot].weapon_magazine > 20) self.cooldown = false; if (self.weapons[weapon_slot].weapon_magazine < getWeaponMag(self.weapons[weapon_slot].weapon_id)) { self.weapons[weapon_slot].weapon_magazine += 1; } self.ltime = time + 0.1; } }; float player_trace_time; void() PlayerPostThink = { #ifdef FTE // Network everything self.SendFlags = 1; // Obtain menu state from CSQC via infokeys. self.is_in_menu = stof(infokey(self, "in_menu")); if (self.is_in_menu != 1) if (infokey(self, "chat") == "1") self.is_in_menu = 2; #endif // FTE if(self.isspec) return; //landsound if((self.oldvelocity_z < -212) && (self.flags & FL_ONGROUND)) { sound(self, CHAN_BODY, "sounds/player/land.wav", 0.6, 1.75); 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; } } #ifdef FTE //footsteps if((vlen(self.velocity) > 20) &&(( time - self.lastsound_time > 0.4) || (time - self.lastsound_time > 0.3 && self.sprinting)) && (self.flags & FL_ONGROUND)) { float movelen = vlen(input_movevalues); if(movelen > 300) { local float ran = random(); if(ran > 0.8) sound(self, CHAN_BODY, "sounds/player/footstep1.wav", 0.6, 2.5); else if(ran > 0.6) sound(self, CHAN_BODY, "sounds/player/footstep2.wav", 0.6, 2.5); else if(ran > 0.4) sound(self, CHAN_BODY, "sounds/player/footstep3.wav", 0.6, 2.5); else if(ran > 0.2) sound(self, CHAN_BODY, "sounds/player/footstep4.wav", 0.6, 2.5); else sound(self, CHAN_BODY, "sounds/player/footstep5.wav", 0.6, 2.5); self.lastsound_time = time; } } #endif // FTE // Health Regeneration 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; } } 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 if (!self.velocity || self.stance != 2) { W_SprintStop(); } #else if (!self.velocity || !checkMovement(0) || self.stance != 2) { //moto (FIXME) -- move me! W_SprintStop(); } #endif // FTE 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; #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 // use .head here to avoid expanding ent struct self.head = trace_ent; // 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; } }; void() ClientKill = {}; //called when a client connects to the server void() ClientConnect = { 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; }; void() PlayerSpawn = { entity spawnpoint = world; local_client = self; self.isspec = FALSE; self.classname = "player"; self.solid = SOLID_BBOX; self.flags = FL_CLIENT; self.onfire = false; self.fire_timeout = 0; // We can only collide with zombies (and not their limbs) #ifdef FTE self.dimension_hit = HITBOX_DIM_ZOMBIES; #endif // FTE setmodel(self, "models/player.mdl"); self.movetype = MOVETYPE_WALK; self.max_health = self.health = PLAYER_START_HEALTH; entity who = find(world,classname,"player"); while(who != self && !self.playernum) { if(who) { player_count++; break; } } if (!self.playernum) { self.playernum = player_count + 1; if (self.playernum == 1) pl1 = self; } // Assign them a spawn location. Player_PickSpawnPoint(); 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); } 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); self.stamina = 3; self.reviving = 0; self.perks = G_PERKS; UpdatePlayerCount(player_count); #ifdef FTE self.viewzoom = 1; self.SendEntity = Player_SendEntity; 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 self.Weapon_Name = GetWeaponName(self.weapon); self.Flash_Offset = GetWeaponFlash_Offset(self.weapon); self.Flash_Size = GetWeaponFlash_Size(self.weapon); self.ADS_Offset = GetWeaponADSOfs(self.weapon); #endif // FTE if (G_STARTROUND != 1) { rounds = G_STARTROUND - 1; } // Make sure players joining after game start are still allowed // to see their name. if (time >= 5 && self.name != "") nzp_setplayername(self, self.name); }; void() SpectatorSpawn = { local entity spawnpoint; spawnpoint = find(world, classname, "info_player_1_spawn"); self.isspec = TRUE; self.health = 420; self.classname = "spectator"; self.solid = SOLID_CORPSE; setmodel(self, "models/sprites/null.spr"); self.movetype = MOVETYPE_FLY; self.origin = spawnpoint.origin + [0,0,1]; self.fixangle = TRUE; setsize(self, PLAYER_MINS_STANDING, PLAYER_MAXS_STANDING); self.view_ofs = '0 0 22'; self.aiment = world; }; //called when a client loads a map float spawns_initialized; void() PutClientInServer = { // Init Spawn Points if (!spawns_initialized) { Spawns_Init(); spawns_initialized = true; } 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 else SpectatorSpawn(); #endif // FTE GameRestart_ResetPerkaColas(); }; //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; self.is_in_menu = 0; #endif // FTE }; void() SetNewParms = { }; void() SetChangeParms = { }; #ifdef FTE void() SV_RunClientCommand = { runstandardplayerphysics(self); } #endif // FTE