2019-03-13 19:20:07 +00:00
/*
2020-06-04 21:01:28 +00:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2019-03-13 19:20:07 +00:00
Copyright ( C ) 1997 - 2001 Id Software , Inc .
Copyright ( C ) 2000 - 2002 Mr . Hyde and Mad Dog
2020-06-04 21:01:28 +00:00
This file is part of Lazarus Quake 2 Mod source code .
2019-03-13 19:20:07 +00:00
2020-06-04 21:01:28 +00:00
Lazarus Quake 2 Mod source code 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 .
2019-03-13 19:20:07 +00:00
2020-06-04 21:01:28 +00:00
Lazarus Quake 2 Mod source code 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 .
2019-03-13 19:20:07 +00:00
You should have received a copy of the GNU General Public License
2020-06-04 21:01:28 +00:00
along with Lazarus Quake 2 Mod source code ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2019-03-13 19:20:07 +00:00
*/
# include "g_local.h"
# include "m_player.h"
# define MUD1BASE 0.20
# define MUD1AMP 0.08
# define MUD3 0.08
void ClientUserinfoChanged ( edict_t * ent , char * userinfo ) ;
void SP_misc_teleporter_dest ( edict_t * ent ) ;
//
// Gross, ugly, disgustuing hack section
//
// this function is an ugly as hell hack to fix some map flaws
//
// the coop spawn spots on some maps are SNAFU. There are coop spots
// with the wrong targetname as well as spots with no name at all
//
// we use carnal knowledge of the maps to fix the coop spot targetnames to match
// that of the nearest named single player spot
/*static*/ void SP_FixCoopSpots ( edict_t * self )
{
edict_t * spot ;
vec3_t d ;
spot = NULL ;
2020-08-05 01:33:39 +00:00
while ( 1 )
2019-03-13 19:20:07 +00:00
{
spot = G_Find ( spot , FOFS ( classname ) , " info_player_start " ) ;
if ( ! spot )
return ;
if ( ! spot - > targetname )
continue ;
VectorSubtract ( self - > s . origin , spot - > s . origin , d ) ;
if ( VectorLength ( d ) < 384 )
{
if ( ( ! self - > targetname ) | | Q_stricmp ( self - > targetname , spot - > targetname ) ! = 0 )
{
// gi.dprintf("FixCoopSpots changed %s at %s targetname from %s to %s\n", self->classname, vtos(self->s.origin), self->targetname, spot->targetname);
self - > targetname = spot - > targetname ;
}
return ;
}
}
}
// now if that one wasn't ugly enough for you then try this one on for size
// some maps don't have any coop spots at all, so we need to create them
// where they should have been
/*static*/ void SP_CreateCoopSpots ( edict_t * self )
{
edict_t * spot ;
if ( Q_stricmp ( level . mapname , " security " ) = = 0 )
{
spot = G_Spawn ( ) ;
spot - > classname = " info_player_coop " ;
spot - > s . origin [ 0 ] = 188 - 64 ;
spot - > s . origin [ 1 ] = - 164 ;
spot - > s . origin [ 2 ] = 80 ;
spot - > targetname = " jail3 " ;
spot - > s . angles [ 1 ] = 90 ;
spot = G_Spawn ( ) ;
spot - > classname = " info_player_coop " ;
spot - > s . origin [ 0 ] = 188 + 64 ;
spot - > s . origin [ 1 ] = - 164 ;
spot - > s . origin [ 2 ] = 80 ;
spot - > targetname = " jail3 " ;
spot - > s . angles [ 1 ] = 90 ;
spot = G_Spawn ( ) ;
spot - > classname = " info_player_coop " ;
spot - > s . origin [ 0 ] = 188 + 128 ;
spot - > s . origin [ 1 ] = - 164 ;
spot - > s . origin [ 2 ] = 80 ;
spot - > targetname = " jail3 " ;
spot - > s . angles [ 1 ] = 90 ;
return ;
}
}
/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
The normal starting point for a level .
*/
void SP_info_player_start ( edict_t * self )
{
2020-10-27 06:00:05 +00:00
self - > class_id = ENTITY_INFO_PLAYER_START ;
2019-03-13 19:20:07 +00:00
if ( ! coop - > value )
return ;
if ( Q_stricmp ( level . mapname , " security " ) = = 0 )
{
// invoke one of our gross, ugly, disgusting hacks
self - > think = SP_CreateCoopSpots ;
self - > nextthink = level . time + FRAMETIME ;
}
}
/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32)
potential spawning position for deathmatch games
*/
void SP_info_player_deathmatch ( edict_t * self )
{
if ( ! deathmatch - > value )
{
G_FreeEdict ( self ) ;
return ;
}
SP_misc_teleporter_dest ( self ) ;
2020-10-27 06:00:05 +00:00
self - > class_id = ENTITY_INFO_PLAYER_DEATHMATCH ;
2019-03-13 19:20:07 +00:00
}
/*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 32)
potential spawning position for coop games
*/
void SP_info_player_coop ( edict_t * self )
{
if ( ! coop - > value )
{
G_FreeEdict ( self ) ;
return ;
}
2020-10-27 06:00:05 +00:00
self - > class_id = ENTITY_INFO_PLAYER_COOP ;
2020-08-05 01:33:39 +00:00
if ( ( Q_stricmp ( level . mapname , " jail2 " ) = = 0 ) | |
2019-03-13 19:20:07 +00:00
( Q_stricmp ( level . mapname , " jail4 " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " mine1 " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " mine2 " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " mine3 " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " mine4 " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " lab " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " boss1 " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " fact3 " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " biggun " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " space " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " command " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " power2 " ) = = 0 ) | |
( Q_stricmp ( level . mapname , " strike " ) = = 0 ) )
{
// invoke one of our gross, ugly, disgusting hacks
self - > think = SP_FixCoopSpots ;
self - > nextthink = level . time + FRAMETIME ;
}
}
/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32) LETTERBOX
The deathmatch intermission point will be at one of these
Use ' angles ' instead of ' angle ' , so you can set pitch or roll as well as yaw . ' pitch yaw roll '
*/
2020-10-27 06:00:05 +00:00
void SP_info_player_intermission ( edict_t * self ) //was void
2019-03-13 19:20:07 +00:00
{
2020-10-27 06:00:05 +00:00
self - > class_id = ENTITY_INFO_PLAYER_INTERMISSION ;
2019-03-13 19:20:07 +00:00
}
//=======================================================================
void player_pain ( edict_t * self , edict_t * other , float kick , int damage )
{
// player pain is handled at the end of the frame in P_DamageFeedback
}
qboolean IsFemale ( edict_t * ent )
{
char * info ;
if ( ! ent - > client )
return false ;
info = Info_ValueForKey ( ent - > client - > pers . userinfo , " gender " ) ;
if ( info [ 0 ] = = ' f ' | | info [ 0 ] = = ' F ' )
return true ;
if ( strstr ( info , " crakhor " ) ) // Knightmare added
return true ;
return false ;
}
qboolean IsNeutral ( edict_t * ent )
{
char * info ;
if ( ! ent - > client )
return false ;
info = Info_ValueForKey ( ent - > client - > pers . userinfo , " gender " ) ;
if ( strstr ( info , " crakhor " ) ) // Knightmare added
return false ;
if ( info [ 0 ] ! = ' f ' & & info [ 0 ] ! = ' F ' & & info [ 0 ] ! = ' m ' & & info [ 0 ] ! = ' M ' )
return true ;
return false ;
}
void ClientObituary ( edict_t * self , edict_t * inflictor , edict_t * attacker )
{
int mod ;
char * message ;
char * message2 ;
qboolean ff ;
if ( coop - > value & & attacker - > client )
meansOfDeath | = MOD_FRIENDLY_FIRE ;
if ( deathmatch - > value | | coop - > value | | ! deathmatch - > value )
{
ff = meansOfDeath & MOD_FRIENDLY_FIRE ;
mod = meansOfDeath & ~ MOD_FRIENDLY_FIRE ;
message = NULL ;
message2 = " " ;
switch ( mod )
{
case MOD_SUICIDE :
message = " suicides " ;
break ;
case MOD_FALLING :
message = " cratered " ;
break ;
case MOD_CRUSH :
message = " was squished " ;
break ;
case MOD_WATER :
message = " sank like a rock " ;
break ;
case MOD_SLIME :
message = " melted " ;
break ;
case MOD_LAVA :
message = " does a back flip into the lava " ;
break ;
case MOD_EXPLOSIVE :
case MOD_BARREL :
message = " blew up " ;
break ;
case MOD_EXIT :
message = " found a way out " ;
break ;
case MOD_TARGET_LASER :
message = " saw the light " ;
break ;
case MOD_TARGET_BLASTER :
message = " got blasted " ;
break ;
case MOD_BOMB :
case MOD_SPLASH :
case MOD_TRIGGER_HURT :
case MOD_VEHICLE :
message = " was in the wrong place " ;
break ;
}
if ( attacker = = self )
{
switch ( mod )
{
case MOD_HELD_GRENADE :
message = " tried to put the pin back in " ;
break ;
case MOD_HG_SPLASH :
case MOD_G_SPLASH :
if ( IsNeutral ( self ) )
message = " tripped on its own grenade " ;
else if ( IsFemale ( self ) )
message = " tripped on her own grenade " ;
else
message = " tripped on his own grenade " ;
break ;
case MOD_R_SPLASH :
if ( IsNeutral ( self ) )
message = " blew itself up " ;
else if ( IsFemale ( self ) )
message = " blew herself up " ;
else
message = " blew himself up " ;
break ;
case MOD_BFG_BLAST :
message = " should have used a smaller gun " ;
break ;
default :
if ( IsNeutral ( self ) )
message = " killed itself " ;
else if ( IsFemale ( self ) )
message = " killed herself " ;
else
message = " killed himself " ;
break ;
}
}
if ( message )
{
safe_bprintf ( PRINT_MEDIUM , " %s %s. \n " , self - > client - > pers . netname , message ) ;
if ( deathmatch - > value )
self - > client - > resp . score - - ;
self - > enemy = NULL ;
return ;
}
self - > enemy = attacker ;
if ( attacker & & attacker - > client )
{
switch ( mod )
{
case MOD_BLASTER :
message = " was blasted by " ;
break ;
case MOD_SHOTGUN :
message = " was gunned down by " ;
break ;
case MOD_SSHOTGUN :
message = " was blown away by " ;
message2 = " 's super shotgun " ;
break ;
case MOD_MACHINEGUN :
message = " was machinegunned by " ;
break ;
case MOD_CHAINGUN :
message = " was cut in half by " ;
message2 = " 's chaingun " ;
break ;
case MOD_GRENADE :
message = " was popped by " ;
message2 = " 's grenade " ;
break ;
case MOD_G_SPLASH :
message = " was shredded by " ;
message2 = " 's shrapnel " ;
break ;
case MOD_ROCKET :
message = " ate " ;
message2 = " 's rocket " ;
break ;
case MOD_R_SPLASH :
message = " almost dodged " ;
message2 = " 's rocket " ;
break ;
case MOD_HYPERBLASTER :
message = " was melted by " ;
message2 = " 's hyperblaster " ;
break ;
case MOD_RAILGUN :
message = " was railed by " ;
break ;
case MOD_BFG_LASER :
message = " saw the pretty lights from " ;
message2 = " 's BFG " ;
break ;
case MOD_BFG_BLAST :
message = " was disintegrated by " ;
message2 = " 's BFG blast " ;
break ;
case MOD_BFG_EFFECT :
message = " couldn't hide from " ;
message2 = " 's BFG " ;
break ;
case MOD_HANDGRENADE :
message = " caught " ;
message2 = " 's handgrenade " ;
break ;
case MOD_HG_SPLASH :
message = " didn't see " ;
message2 = " 's handgrenade " ;
break ;
case MOD_HELD_GRENADE :
message = " feels " ;
message2 = " 's pain " ;
break ;
case MOD_TELEFRAG :
message = " tried to invade " ;
message2 = " 's personal space " ;
break ;
//ZOID
case MOD_GRAPPLE :
message = " was caught by " ;
message2 = " 's grapple " ;
break ;
//ZOID
case MOD_VEHICLE :
message = " was splattered by " ;
message2 = " 's vehicle " ;
break ;
case MOD_KICK :
message = " was booted by " ;
message2 = " 's foot " ;
break ;
}
if ( message )
{
safe_bprintf ( PRINT_MEDIUM , " %s %s %s%s \n " , self - > client - > pers . netname , message , attacker - > client - > pers . netname , message2 ) ;
if ( deathmatch - > value )
{
if ( ff )
attacker - > client - > resp . score - - ;
else
attacker - > client - > resp . score + + ;
}
return ;
}
}
2020-08-05 01:33:39 +00:00
// Knightmare- Single-player obits
2019-03-13 19:20:07 +00:00
if ( attacker - > svflags & SVF_MONSTER )
{ // Light Guard
if ( ! strcmp ( attacker - > classname , " monster_soldier_light " ) )
message = " was blasted by a " ;
// Shotgun Guard
else if ( ! strcmp ( attacker - > classname , " monster_soldier " ) )
message = " was gunned down by a " ;
// Machinegun Guard
else if ( ! strcmp ( attacker - > classname , " monster_soldier_ss " ) )
message = " was machinegunned by a " ;
// Enforcer
else if ( ! strcmp ( attacker - > classname , " monster_infantry " ) )
{
if ( mod = = MOD_HIT )
message = " was bludgened by an " ;
else
message = " was pumped full of lead by an " ;
}
// Gunner
else if ( ! strcmp ( attacker - > classname , " monster_gunner " ) )
{
if ( mod = = MOD_GRENADE )
{
message = " was popped by a " ;
message2 = " 's grenade " ;
}
else if ( mod = = MOD_G_SPLASH )
{
message = " was shredded by a " ;
message2 = " 's shrapnel " ;
}
else
message = " was machinegunned by a " ;
}
// Berserker
else if ( ! strcmp ( attacker - > classname , " monster_berserk " ) )
message = " was smashed by a " ;
// Gladiator
else if ( ! strcmp ( attacker - > classname , " monster_gladiator " ) )
{
if ( mod = = MOD_RAILGUN )
message = " was railed by a " ;
else
{
message = " was mangled by a " ;
message2 = " 's claw " ;
}
}
// Medic
else if ( ! strcmp ( attacker - > classname , " monster_medic " ) )
message = " was blasted by a " ;
// Icarus
else if ( ! strcmp ( attacker - > classname , " monster_hover " ) )
message = " was blasted by an " ;
// Iron Maiden
else if ( ! strcmp ( attacker - > classname , " monster_chick " ) )
{
if ( mod = = MOD_ROCKET )
{
message = " ate an " ;
message2 = " 's rocket " ;
}
else if ( mod = = MOD_R_SPLASH )
{
message = " almost dodged an " ;
message2 = " 's rocket " ;
}
else if ( mod = = MOD_HIT )
message = " was bitch-slapped by an " ;
}
// Parasite
else if ( ! strcmp ( attacker - > classname , " monster_parasite " ) )
message = " was exsanguiated by a " ;
// Brain
else if ( ! strcmp ( attacker - > classname , " monster_brain " ) )
{
message = " was torn up by a " ;
message2 = " 's tentacles " ;
}
// Flyer
else if ( ! strcmp ( attacker - > classname , " monster_flyer " ) )
{
if ( mod = = MOD_BLASTER )
message = " was blasted by a " ;
else if ( mod = = MOD_HIT )
{
message = " was cut up by a " ;
message2 = " 's sharp wings " ;
}
}
// Technician
else if ( ! strcmp ( attacker - > classname , " monster_floater " ) )
{
if ( mod = = MOD_BLASTER )
message = " was blasted by a " ;
else if ( mod = = MOD_HIT )
{
message = " was gouged to death by a " ;
message2 = " 's utility claw " ;
}
}
// Tank/Tank Commander
else if ( ! strcmp ( attacker - > classname , " monster_tank " )
| | ! strcmp ( attacker - > classname , " monster_tank_commander " ) )
{
if ( mod = = MOD_BLASTER )
message = " was blasted by a " ;
else if ( mod = = MOD_ROCKET )
{
message = " ate a " ;
message2 = " 's rocket " ;
}
else if ( mod = = MOD_R_SPLASH )
{
message = " almost dodged a " ;
message2 = " 's rocket " ;
}
else
message = " was pumped full of lead by a " ;
}
// Supertank
else if ( ! strcmp ( attacker - > classname , " monster_supertank " ) )
{
if ( mod = = MOD_ROCKET )
{
message = " ate a " ;
message2 = " 's rocket " ;
}
else if ( mod = = MOD_R_SPLASH )
{
message = " almost dodged a " ;
message2 = " 's rocket " ;
}
else
message = " was chaingunned by a " ;
}
// Hornet
else if ( ! strcmp ( attacker - > classname , " monster_boss2 " ) )
{
if ( mod = = MOD_ROCKET )
{
message = " ate a " ;
message2 = " 's rocket " ;
}
else if ( mod = = MOD_R_SPLASH )
{
message = " almost dodged a " ;
message2 = " 's rockets " ;
}
else
message = " was chaingunned by a " ;
}
// Jorg
else if ( ! strcmp ( attacker - > classname , " monster_jorg " ) )
{
if ( mod = = MOD_BFG_LASER )
{
message = " saw the pretty lights from the " ;
message2 = " 's BFG " ;
}
else if ( mod = = MOD_BFG_BLAST )
{
message = " was disintegrated by the " ;
message2 = " 's BFG blast " ;
}
else if ( mod = = MOD_BFG_EFFECT )
{
message = " couldn't hide from the " ;
message2 = " 's BFG " ;
}
else
{
message = " was shredded by the " ;
message2 = " 's chain-cannons " ;
}
}
// Makron
else if ( ! strcmp ( attacker - > classname , " monster_makron " ) )
{
if ( mod = = MOD_BLASTER )
{
message = " was melted by the " ;
message2 = " 's hyperblaster " ;
}
else if ( mod = = MOD_RAILGUN )
message = " was railed by the " ;
else if ( mod = = MOD_BFG_LASER )
{
message = " saw the pretty lights from the " ;
message2 = " 's BFG " ;
}
else if ( mod = = MOD_BFG_BLAST )
{
message = " was disintegrated by the " ;
message2 = " 's BFG blast " ;
}
else if ( mod = = MOD_BFG_EFFECT )
{
message = " couldn't hide from the " ;
message2 = " 's BFG " ;
}
}
// Barracuda Shark
else if ( ! strcmp ( attacker - > classname , " monster_flipper " ) )
message = " was chewed up by a " ;
// Mutant
else if ( ! strcmp ( attacker - > classname , " monster_mutant " ) )
message = " was clawed by a " ;
}
if ( message )
{
safe_bprintf ( PRINT_MEDIUM , " %s %s %s%s \n " , self - > client - > pers . netname , message , attacker - > common_name , message2 ) ;
if ( coop - > value )
self - > client - > resp . score - - ;
self - > enemy = NULL ;
return ;
}
2020-08-05 01:33:39 +00:00
// end Knightmare
2019-03-13 19:20:07 +00:00
}
safe_bprintf ( PRINT_MEDIUM , " %s died. \n " , self - > client - > pers . netname ) ;
if ( deathmatch - > value )
self - > client - > resp . score - - ;
}
void Touch_Item ( edict_t * ent , edict_t * other , cplane_t * plane , csurface_t * surf ) ;
void TossClientWeapon ( edict_t * self )
{
gitem_t * item ;
edict_t * drop ;
qboolean quad ;
float spread ;
if ( ! deathmatch - > value )
return ;
item = self - > client - > pers . weapon ;
if ( ! self - > client - > pers . inventory [ self - > client - > ammo_index ] )
item = NULL ;
if ( item & & ( strcmp ( item - > pickup_name , " Blaster " ) = = 0 ) )
item = NULL ;
if ( item & & ( strcmp ( item - > pickup_name , " Grapple " ) = = 0 ) )
item = NULL ;
if ( item & & ( strcmp ( item - > pickup_name , " No Weapon " ) = = 0 ) )
item = NULL ;
// Knightmare- don't drop homing rocket launcher (null model error), drop rocket launcher instead
if ( item & & ( strcmp ( item - > pickup_name , " Homing Rocket Launcher " ) = = 0 ) )
item = FindItem ( " Rocket Launcher " ) ;
if ( ! ( ( int ) ( dmflags - > value ) & DF_QUAD_DROP ) )
quad = false ;
else
quad = ( self - > client - > quad_framenum > ( level . framenum + 10 ) ) ;
if ( item & & quad )
spread = 22.5 ;
else
spread = 0.0 ;
if ( item )
{
self - > client - > v_angle [ YAW ] - = spread ;
drop = Drop_Item ( self , item ) ;
self - > client - > v_angle [ YAW ] + = spread ;
drop - > spawnflags = DROPPED_PLAYER_ITEM ;
}
if ( quad )
{
self - > client - > v_angle [ YAW ] + = spread ;
drop = Drop_Item ( self , FindItemByClassname ( " item_quad " ) ) ;
self - > client - > v_angle [ YAW ] - = spread ;
drop - > spawnflags | = DROPPED_PLAYER_ITEM ;
drop - > touch = Touch_Item ;
drop - > nextthink = level . time + ( self - > client - > quad_framenum - level . framenum ) * FRAMETIME ;
drop - > think = G_FreeEdict ;
}
}
/*
= = = = = = = = = = = = = = = = = =
LookAtKiller
= = = = = = = = = = = = = = = = = =
*/
void LookAtKiller ( edict_t * self , edict_t * inflictor , edict_t * attacker )
{
vec3_t dir ;
if ( attacker & & attacker ! = world & & attacker ! = self )
{
VectorSubtract ( attacker - > s . origin , self - > s . origin , dir ) ;
}
else if ( inflictor & & inflictor ! = world & & inflictor ! = self )
{
VectorSubtract ( inflictor - > s . origin , self - > s . origin , dir ) ;
}
else
{
self - > client - > killer_yaw = self - > s . angles [ YAW ] ;
return ;
}
if ( dir [ 0 ] )
self - > client - > killer_yaw = 180 / M_PI * atan2 ( dir [ 1 ] , dir [ 0 ] ) ;
else {
self - > client - > killer_yaw = 0 ;
if ( dir [ 1 ] > 0 )
self - > client - > killer_yaw = 90 ;
else if ( dir [ 1 ] < 0 )
self - > client - > killer_yaw = - 90 ;
}
if ( self - > client - > killer_yaw < 0 )
self - > client - > killer_yaw + = 360 ;
}
/*
= = = = = = = = = = = = = = = = = =
player_die
= = = = = = = = = = = = = = = = = =
*/
void player_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point )
{
int n ;
// tpp
if ( self - > client - > chasetoggle )
{
ChasecamRemove ( self , OPTION_OFF ) ;
self - > client - > pers . chasetoggle = 1 ;
}
else
self - > client - > pers . chasetoggle = 0 ;
// end tpp
self - > client - > pers . spawn_landmark = false ; // paranoia check
self - > client - > pers . spawn_levelchange = false ;
SetLazarusCrosshair ( self ) ; //backup crosshair
self - > client - > zooming = 0 ;
self - > client - > zoomed = false ;
SetSensitivities ( self , true ) ;
if ( self - > client - > spycam )
camera_off ( self ) ;
if ( self - > turret )
turret_disengage ( self - > turret ) ;
if ( self - > client - > textdisplay )
Text_Close ( self ) ;
VectorClear ( self - > avelocity ) ;
self - > takedamage = DAMAGE_YES ;
self - > movetype = MOVETYPE_TOSS ;
self - > s . modelindex2 = 0 ; // remove linked weapon model
//ZOID
self - > s . modelindex3 = 0 ; // remove linked ctf flag
//ZOID
self - > s . angles [ 0 ] = 0 ;
self - > s . angles [ 2 ] = 0 ;
self - > s . sound = 0 ;
self - > client - > weapon_sound = 0 ;
self - > maxs [ 2 ] = - 8 ;
// self->solid = SOLID_NOT;
self - > svflags | = SVF_DEADMONSTER ;
if ( ! self - > deadflag )
{
self - > client - > respawn_time = level . time + 1.0 ;
LookAtKiller ( self , inflictor , attacker ) ;
self - > client - > ps . pmove . pm_type = PM_DEAD ;
ClientObituary ( self , inflictor , attacker ) ;
//ZOID
if ( ctf - > value )
{
// if at start and same team, clear
if ( meansOfDeath = = MOD_TELEFRAG & &
self - > client - > resp . ctf_state < 2 & &
self - > client - > resp . ctf_team = = attacker - > client - > resp . ctf_team ) {
attacker - > client - > resp . score - - ;
self - > client - > resp . ctf_state = 0 ;
}
CTFFragBonuses ( self , inflictor , attacker ) ;
}
//ZOID
TossClientWeapon ( self ) ;
//ZOID
if ( ctf - > value )
{
CTFPlayerResetGrapple ( self ) ;
CTFDeadDropFlag ( self ) ;
}
CTFDeadDropTech ( self ) ;
//ZOID
// Knightmare added- drop ammogen backpack
if ( ! OnSameTeam ( self , attacker ) )
CTFApplyAmmogen ( attacker , self ) ;
if ( deathmatch - > value )
Cmd_Help_f ( self ) ; // show scores
// clear inventory
// this is kind of ugly, but it's how we want to handle keys in coop
for ( n = 0 ; n < game . num_items ; n + + )
{
if ( coop - > value & & itemlist [ n ] . flags & IT_KEY )
self - > client - > resp . coop_respawn . inventory [ n ] = self - > client - > pers . inventory [ n ] ;
self - > client - > pers . inventory [ n ] = 0 ;
}
}
// remove powerups
self - > client - > quad_framenum = 0 ;
self - > client - > invincible_framenum = 0 ;
self - > client - > breather_framenum = 0 ;
self - > client - > enviro_framenum = 0 ;
self - > flags & = ~ ( FL_POWER_SHIELD | FL_POWER_SCREEN ) ;
self - > client - > flashlight = false ;
// turn off alt-fire mode if on
self - > client - > pers . fire_mode = 0 ;
//self->client->nNewLatch &= ~BUTTON_ATTACK2;
//if (self->health < self->gib_health)
if ( self - > health < player_gib_health - > value )
{ // gib
int num_giblets = 4 ;
//if (deathmatch->value && (self->health < (self->gib_health*2)))
if ( deathmatch - > value & & ( self - > health < ( player_gib_health - > value * 2 ) ) )
num_giblets = 8 ;
gi . sound ( self , CHAN_BODY , gi . soundindex ( " misc/udeath.wav " ) , 1 , ATTN_NORM , 0 ) ;
for ( n = 0 ; n < num_giblets ; n + + )
ThrowGib ( self , " models/objects/gibs/sm_meat/tris.md2 " , damage , GIB_ORGANIC ) ;
if ( mega_gibs - > value )
{
ThrowGib ( self , " models/objects/gibs/arm/tris.md2 " , damage , GIB_ORGANIC ) ;
ThrowGib ( self , " models/objects/gibs/arm/tris.md2 " , damage , GIB_ORGANIC ) ;
ThrowGib ( self , " models/objects/gibs/leg/tris.md2 " , damage , GIB_ORGANIC ) ;
ThrowGib ( self , " models/objects/gibs/leg/tris.md2 " , damage , GIB_ORGANIC ) ;
ThrowGib ( self , " models/objects/gibs/bone/tris.md2 " , damage , GIB_ORGANIC ) ;
ThrowGib ( self , " models/objects/gibs/bone2/tris.md2 " , damage , GIB_ORGANIC ) ;
}
ThrowClientHead ( self , damage ) ;
//ZOID
self - > client - > anim_priority = ANIM_DEATH ;
self - > client - > anim_end = 0 ;
//ZOID
self - > takedamage = DAMAGE_NO ;
}
else
{ // normal death
if ( ! self - > deadflag )
{
static int i ;
i = ( i + 1 ) % 3 ;
// start a death animation
self - > client - > anim_priority = ANIM_DEATH ;
if ( self - > client - > ps . pmove . pm_flags & PMF_DUCKED )
{
self - > s . frame = FRAME_crdeath1 - 1 ;
self - > client - > anim_end = FRAME_crdeath5 ;
}
else switch ( i )
{
case 0 :
self - > s . frame = FRAME_death101 - 1 ;
self - > client - > anim_end = FRAME_death106 ;
break ;
case 1 :
self - > s . frame = FRAME_death201 - 1 ;
self - > client - > anim_end = FRAME_death206 ;
break ;
case 2 :
self - > s . frame = FRAME_death301 - 1 ;
self - > client - > anim_end = FRAME_death308 ;
break ;
}
gi . sound ( self , CHAN_VOICE , gi . soundindex ( va ( " *death%i.wav " , ( rand ( ) % 4 ) + 1 ) ) , 1 , ATTN_NORM , 0 ) ;
}
}
# ifdef JETPACK_MOD
if ( self - > client - > jetpack )
{
Jet_BecomeExplosion ( self , damage ) ;
/*stop jetting when dead*/
self - > client - > jetpack_framenum = 0 ;
self - > client - > jetpack = false ;
// DWH: force player to gib
//self->health = self->gib_health-1;
self - > health = player_gib_health - > value - 1 ;
}
# endif
self - > deadflag = DEAD_DEAD ;
gi . linkentity ( self ) ;
}
//=======================================================================
void SwitchToBestStartWeapon ( gclient_t * client )
{
if ( ! client )
return ;
if ( client - > pers . inventory [ slugs_index ]
& & client - > pers . inventory [ ITEM_INDEX ( FindItem ( " railgun " ) ) ] )
{
client - > pers . weapon = FindItem ( " railgun " ) ;
return ;
}
if ( client - > pers . inventory [ cells_index ]
& & client - > pers . inventory [ ITEM_INDEX ( FindItem ( " hyperblaster " ) ) ] )
{
client - > pers . weapon = FindItem ( " hyperblaster " ) ;
return ;
}
if ( client - > pers . inventory [ bullets_index ]
& & client - > pers . inventory [ ITEM_INDEX ( FindItem ( " chaingun " ) ) ] )
{
client - > pers . weapon = FindItem ( " chaingun " ) ;
return ;
}
if ( client - > pers . inventory [ bullets_index ]
& & client - > pers . inventory [ ITEM_INDEX ( FindItem ( " machinegun " ) ) ] )
{
client - > pers . weapon = FindItem ( " machinegun " ) ;
return ;
}
if ( client - > pers . inventory [ shells_index ] > 1
& & client - > pers . inventory [ ITEM_INDEX ( FindItem ( " super shotgun " ) ) ] )
{
client - > pers . weapon = FindItem ( " super shotgun " ) ;
return ;
}
if ( client - > pers . inventory [ shells_index ]
& & client - > pers . inventory [ ITEM_INDEX ( FindItem ( " shotgun " ) ) ] )
{
client - > pers . weapon = FindItem ( " shotgun " ) ;
return ;
}
// DWH: Dude may not HAVE a blaster
//ent->client->newweapon = FindItem ("blaster");
if ( client - > pers . inventory [ ITEM_INDEX ( FindItem ( " blaster " ) ) ] )
client - > pers . weapon = FindItem ( " blaster " ) ;
else
client - > pers . weapon = FindItem ( " No Weapon " ) ;
}
void SelectStartWeapon ( gclient_t * client , int style )
{
gitem_t * item ;
int n ;
// Lazarus: We allow choice of weapons (or no weapon) at startup
// If style is non-zero, first clear player inventory of all
// weapons and ammo that might have been passed over through
// target_changelevel or acquired when previously called by
// InitClientPersistant
if ( style )
{
for ( n = 0 ; n < MAX_ITEMS ; n + + )
{
if ( itemlist [ n ] . flags & IT_WEAPON )
client - > pers . inventory [ n ] = 0 ;
}
client - > pers . inventory [ shells_index ] = 0 ;
client - > pers . inventory [ bullets_index ] = 0 ;
client - > pers . inventory [ grenades_index ] = 0 ;
client - > pers . inventory [ rockets_index ] = 0 ;
client - > pers . inventory [ cells_index ] = 0 ;
client - > pers . inventory [ slugs_index ] = 0 ;
client - > pers . inventory [ homing_index ] = 0 ;
}
switch ( style )
{
case - 1 :
item = FindItem ( " No Weapon " ) ;
break ;
case - 2 :
case 2 :
item = FindItem ( " Shotgun " ) ;
break ;
case - 3 :
case 3 :
item = FindItem ( " Super Shotgun " ) ;
break ;
case - 4 :
case 4 :
item = FindItem ( " Machinegun " ) ;
break ;
case - 5 :
case 5 :
item = FindItem ( " Chaingun " ) ;
break ;
case - 6 :
case 6 :
item = FindItem ( " Grenade Launcher " ) ;
break ;
case - 7 :
case 7 :
item = FindItem ( " Rocket Launcher " ) ;
break ;
case - 8 :
case 8 :
item = FindItem ( " HyperBlaster " ) ;
break ;
case - 9 :
case 9 :
item = FindItem ( " Railgun " ) ;
break ;
case - 10 :
case 10 :
item = FindItem ( " BFG10K " ) ;
break ;
default :
item = FindItem ( " Blaster " ) ;
break ;
}
client - > pers . selected_item = ITEM_INDEX ( item ) ;
client - > pers . inventory [ client - > pers . selected_item ] = 1 ;
client - > pers . weapon = item ;
//ZOID
if ( ctf - > value )
{
client - > pers . lastweapon = item ;
item = FindItem ( " Grapple " ) ;
client - > pers . inventory [ ITEM_INDEX ( item ) ] = 1 ;
}
//ZOID
// Lazarus: If default weapon is NOT "No Weapon", then give player
// a blaster
if ( style > 1 )
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Blaster " ) ) ] = 1 ;
// Knightmare- player always has null weapon to allow holstering
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " No Weapon " ) ) ] = 1 ;
// and give him standard ammo
if ( item - > ammo )
{
gitem_t * ammo ;
ammo = FindItem ( item - > ammo ) ;
if ( deathmatch - > value & & ( ( int ) dmflags - > value & DF_INFINITE_AMMO ) )
client - > pers . inventory [ ITEM_INDEX ( ammo ) ] + = 1000 ;
else
client - > pers . inventory [ ITEM_INDEX ( ammo ) ] + = ammo - > quantity ;
}
// Knightmare- DM start values
if ( deathmatch - > value )
{
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Shells " ) ) ] = sk_dm_start_shells - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Bullets " ) ) ] = sk_dm_start_bullets - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Rockets " ) ) ] = sk_dm_start_rockets - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Homing Rockets " ) ) ] = sk_dm_start_homing - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Grenades " ) ) ] = sk_dm_start_grenades - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Cells " ) ) ] = sk_dm_start_cells - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Slugs " ) ) ] = sk_dm_start_slugs - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Shotgun " ) ) ] = sk_dm_start_shotgun - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Super Shotgun " ) ) ] = sk_dm_start_sshotgun - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Machinegun " ) ) ] = sk_dm_start_machinegun - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Chaingun " ) ) ] = sk_dm_start_chaingun - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Grenade Launcher " ) ) ] = sk_dm_start_grenadelauncher - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Rocket Launcher " ) ) ] = sk_dm_start_rocketlauncher - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Homing Rocket Launcher " ) ) ] = sk_dm_start_rocketlauncher - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " HyperBlaster " ) ) ] = sk_dm_start_hyperblaster - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " Railgun " ) ) ] = sk_dm_start_railgun - > value ;
client - > pers . inventory [ ITEM_INDEX ( FindItem ( " BFG10K " ) ) ] = sk_dm_start_bfg - > value ;
SwitchToBestStartWeapon ( client ) ;
}
}
/*
= = = = = = = = = = = = = =
InitClientPersistant
This is only called when the game first initializes in single player ,
but is called after each death and level change in deathmatch
= = = = = = = = = = = = = =
*/
void InitClientPersistant ( gclient_t * client , int style )
{
memset ( & client - > pers , 0 , sizeof ( client - > pers ) ) ;
client - > homing_rocket = NULL ;
SelectStartWeapon ( client , style ) ;
client - > pers . health = 100 ;
if ( deathmatch - > value )
client - > pers . max_health = sk_max_health_dm - > value ;
else
client - > pers . max_health = sk_max_health - > value ;
client - > pers . max_bullets = sk_max_bullets - > value ;
client - > pers . max_shells = sk_max_shells - > value ;
client - > pers . max_rockets = sk_max_rockets - > value ;
client - > pers . max_grenades = sk_max_grenades - > value ;
client - > pers . max_cells = sk_max_cells - > value ;
client - > pers . max_slugs = sk_max_slugs - > value ;
client - > pers . max_fuel = sk_max_fuel - > value ;
client - > pers . max_homing_rockets = sk_max_rockets - > value ;
client - > pers . fire_mode = 0 ; // Lazarus alternate fire mode
client - > pers . connected = true ;
// tpp
//Default chasecam to tpp setting
client - > pers . chasetoggle = tpp - > value ;
// end tpp
// Lazarus
client - > zooming = 0 ;
client - > zoomed = false ;
client - > spycam = NULL ;
client - > pers . spawn_landmark = false ;
client - > pers . spawn_levelchange = false ;
}
void InitClientResp ( gclient_t * client )
{
//ZOID
int ctf_team = client - > resp . ctf_team ;
qboolean id_state = client - > resp . id_state ;
//ZOID
memset ( & client - > resp , 0 , sizeof ( client - > resp ) ) ;
//ZOID
client - > resp . ctf_team = ctf_team ;
client - > resp . id_state = id_state ;
//ZOID
client - > resp . enterframe = level . framenum ;
client - > resp . coop_respawn = client - > pers ;
//ZOID
if ( ctf - > value & & client - > resp . ctf_team < CTF_TEAM1 )
CTFAssignTeam ( client ) ;
//ZOID
}
/*
= = = = = = = = = = = = = = = = = =
SaveClientData
Some information that should be persistant , like health ,
is still stored in the edict structure , so it needs to
be mirrored out to the client structure before all the
edicts are wiped .
= = = = = = = = = = = = = = = = = =
*/
void SaveClientData ( void )
{
int i ;
edict_t * ent ;
for ( i = 0 ; i < game . maxclients ; i + + )
{
ent = & g_edicts [ 1 + i ] ;
if ( ! ent - > inuse )
continue ;
// tpp
game . clients [ i ] . pers . chasetoggle = ent - > client - > pers . chasetoggle ;
// end tpp
game . clients [ i ] . pers . newweapon = ent - > client - > newweapon ;
game . clients [ i ] . pers . health = ent - > health ;
game . clients [ i ] . pers . max_health = ent - > max_health ;
game . clients [ i ] . pers . savedFlags = ( ent - > flags & ( FL_GODMODE | FL_NOTARGET | FL_POWER_SHIELD | FL_POWER_SCREEN ) ) ;
if ( coop - > value )
game . clients [ i ] . pers . score = ent - > client - > resp . score ;
}
}
void FetchClientEntData ( edict_t * ent )
{
ent - > health = ent - > client - > pers . health ;
ent - > gib_health = player_gib_health - > value ; // was -40
ent - > max_health = ent - > client - > pers . max_health ;
ent - > flags | = ent - > client - > pers . savedFlags ;
if ( coop - > value )
ent - > client - > resp . score = ent - > client - > pers . score ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
SelectSpawnPoint
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
PlayersRangeFromSpot
Returns the distance to the nearest player from the given spot
= = = = = = = = = = = = = = = =
*/
float PlayersRangeFromSpot ( edict_t * spot )
{
edict_t * player ;
float bestplayerdistance ;
vec3_t v ;
int n ;
float playerdistance ;
bestplayerdistance = 9999999 ;
for ( n = 1 ; n < = maxclients - > value ; n + + )
{
player = & g_edicts [ n ] ;
if ( ! player - > inuse )
continue ;
if ( player - > health < = 0 )
continue ;
VectorSubtract ( spot - > s . origin , player - > s . origin , v ) ;
playerdistance = VectorLength ( v ) ;
if ( playerdistance < bestplayerdistance )
bestplayerdistance = playerdistance ;
}
return bestplayerdistance ;
}
/*
= = = = = = = = = = = = = = = =
SelectRandomDeathmatchSpawnPoint
go to a random point , but NOT the two points closest
to other players
= = = = = = = = = = = = = = = =
*/
edict_t * SelectRandomDeathmatchSpawnPoint ( void )
{
edict_t * spot , * spot1 , * spot2 ;
int count = 0 ;
int selection ;
float range , range1 , range2 ;
spot = NULL ;
range1 = range2 = 99999 ;
spot1 = spot2 = NULL ;
while ( ( spot = G_Find ( spot , FOFS ( classname ) , " info_player_deathmatch " ) ) ! = NULL )
{
count + + ;
range = PlayersRangeFromSpot ( spot ) ;
if ( range < range1 )
{
range1 = range ;
spot1 = spot ;
}
else if ( range < range2 )
{
range2 = range ;
spot2 = spot ;
}
}
if ( ! count )
return NULL ;
if ( count < = 2 )
{
spot1 = spot2 = NULL ;
}
// Lazarus: This is wrong. If there is no spot1 or spot2, all spots should
// be valid.
// else
// count -= 2;
else
{
2020-08-05 01:33:39 +00:00
if ( spot1 ) count - - ;
if ( spot2 ) count - - ;
2019-03-13 19:20:07 +00:00
}
selection = rand ( ) % count ;
spot = NULL ;
do
{
spot = G_Find ( spot , FOFS ( classname ) , " info_player_deathmatch " ) ;
if ( spot = = spot1 | | spot = = spot2 )
selection + + ;
2020-08-05 01:33:39 +00:00
} while ( selection - - ) ;
2019-03-13 19:20:07 +00:00
return spot ;
}
/*
= = = = = = = = = = = = = = = =
SelectFarthestDeathmatchSpawnPoint
= = = = = = = = = = = = = = = =
*/
edict_t * SelectFarthestDeathmatchSpawnPoint ( void )
{
edict_t * bestspot ;
float bestdistance , bestplayerdistance ;
edict_t * spot ;
spot = NULL ;
bestspot = NULL ;
bestdistance = 0 ;
while ( ( spot = G_Find ( spot , FOFS ( classname ) , " info_player_deathmatch " ) ) ! = NULL )
{
bestplayerdistance = PlayersRangeFromSpot ( spot ) ;
if ( bestplayerdistance > bestdistance )
{
bestspot = spot ;
bestdistance = bestplayerdistance ;
}
}
if ( bestspot )
{
return bestspot ;
}
// if there is a player just spawned on each and every start spot
// we have no choice to turn one into a telefrag meltdown
spot = G_Find ( NULL , FOFS ( classname ) , " info_player_deathmatch " ) ;
return spot ;
}
edict_t * SelectDeathmatchSpawnPoint ( void )
{
if ( ( int ) ( dmflags - > value ) & DF_SPAWN_FARTHEST )
return SelectFarthestDeathmatchSpawnPoint ( ) ;
else
return SelectRandomDeathmatchSpawnPoint ( ) ;
}
edict_t * SelectCoopSpawnPoint ( edict_t * ent )
{
int index ;
edict_t * spot = NULL ;
char * target ;
index = ent - > client - game . clients ;
// player 0 starts in normal player spawn point
if ( ! index )
return NULL ;
spot = NULL ;
// assume there are four coop spots at each spawnpoint
while ( 1 )
{
spot = G_Find ( spot , FOFS ( classname ) , " info_player_coop " ) ;
if ( ! spot )
return NULL ; // we didn't have enough...
target = spot - > targetname ;
if ( ! target )
target = " " ;
if ( Q_stricmp ( game . spawnpoint , target ) = = 0 )
{ // this is a coop spawn point for one of the clients here
index - - ;
if ( ! index )
return spot ; // this is it
}
}
return spot ;
}
/*
= = = = = = = = = = =
SelectSpawnPoint
Chooses a player start , deathmatch start , coop start , etc
= = = = = = = = = = = =
*/
void SelectSpawnPoint ( edict_t * ent , vec3_t origin , vec3_t angles , int * style , int * health )
{
edict_t * spot = NULL ;
if ( deathmatch - > value ) {
//ZOID
if ( ctf - > value )
spot = SelectCTFSpawnPoint ( ent ) ;
else
//ZOID
spot = SelectDeathmatchSpawnPoint ( ) ;
}
else if ( coop - > value )
spot = SelectCoopSpawnPoint ( ent ) ;
// find a single player start spot
if ( ! spot )
{
while ( ( spot = G_Find ( spot , FOFS ( classname ) , " info_player_start " ) ) ! = NULL )
{
if ( ! game . spawnpoint [ 0 ] & & ! spot - > targetname )
break ;
if ( ! game . spawnpoint [ 0 ] | | ! spot - > targetname )
continue ;
if ( Q_stricmp ( game . spawnpoint , spot - > targetname ) = = 0 )
break ;
}
if ( ! spot )
{
if ( ! game . spawnpoint [ 0 ] )
{ // there wasn't a spawnpoint without a target, so use any
spot = G_Find ( spot , FOFS ( classname ) , " info_player_start " ) ;
}
if ( ! spot )
gi . error ( " Couldn't find spawn point %s \n " , game . spawnpoint ) ;
}
}
2019-03-27 01:47:47 +00:00
if ( style )
* style = spot - > style ;
if ( health )
* health = spot - > health ;
2019-03-13 19:20:07 +00:00
VectorCopy ( spot - > s . origin , origin ) ;
origin [ 2 ] + = 9 ;
VectorCopy ( spot - > s . angles , angles ) ;
2020-08-05 01:33:39 +00:00
if ( ! deathmatch - > value & & ! coop - > value ) {
2019-03-13 19:20:07 +00:00
spot - > count - - ;
2020-08-05 01:33:39 +00:00
if ( ! spot - > count ) {
2019-03-13 19:20:07 +00:00
spot - > think = G_FreeEdict ;
spot - > nextthink = level . time + 1 ;
}
}
}
//======================================================================
void InitBodyQue ( void )
{
// DWH: bodyque isn't used in SP, so why reserve space for it?
if ( deathmatch - > value | | coop - > value )
{
int i ;
edict_t * ent ;
level . body_que = 0 ;
for ( i = 0 ; i < BODY_QUEUE_SIZE ; i + + )
{
ent = G_Spawn ( ) ;
ent - > classname = " bodyque " ;
}
}
}
void body_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point )
{
int n ;
//if (self->health < self->gib_health)
if ( self - > health < player_gib_health - > value )
{
int num_giblets = 4 ;
//if (deathmatch->value && (self->health < (self->gib_health*2)))
if ( deathmatch - > value & & ( self - > health < ( player_gib_health - > value * 2 ) ) )
num_giblets = 8 ;
gi . sound ( self , CHAN_BODY , gi . soundindex ( " misc/udeath.wav " ) , 1 , ATTN_NORM , 0 ) ;
for ( n = 0 ; n < num_giblets ; n + + )
ThrowGib ( self , " models/objects/gibs/sm_meat/tris.md2 " , damage , GIB_ORGANIC ) ;
if ( mega_gibs - > value )
{
ThrowGib ( self , " models/objects/gibs/arm/tris.md2 " , damage , GIB_ORGANIC ) ;
ThrowGib ( self , " models/objects/gibs/arm/tris.md2 " , damage , GIB_ORGANIC ) ;
ThrowGib ( self , " models/objects/gibs/leg/tris.md2 " , damage , GIB_ORGANIC ) ;
ThrowGib ( self , " models/objects/gibs/leg/tris.md2 " , damage , GIB_ORGANIC ) ;
ThrowGib ( self , " models/objects/gibs/bone/tris.md2 " , damage , GIB_ORGANIC ) ;
ThrowGib ( self , " models/objects/gibs/bone2/tris.md2 " , damage , GIB_ORGANIC ) ;
}
self - > s . origin [ 2 ] - = 48 ;
ThrowClientHead ( self , damage ) ;
self - > takedamage = DAMAGE_NO ;
}
}
void CopyToBodyQue ( edict_t * ent )
{
edict_t * body ;
// grab a body que and cycle to the next one
body = & g_edicts [ ( int ) maxclients - > value + level . body_que + 1 ] ;
level . body_que = ( level . body_que + 1 ) % BODY_QUEUE_SIZE ;
// FIXME: send an effect on the removed body
gi . unlinkentity ( ent ) ;
gi . unlinkentity ( body ) ;
body - > s = ent - > s ;
body - > s . number = body - g_edicts ;
body - > svflags = ent - > svflags ;
VectorCopy ( ent - > mins , body - > mins ) ;
VectorCopy ( ent - > maxs , body - > maxs ) ;
VectorCopy ( ent - > absmin , body - > absmin ) ;
VectorCopy ( ent - > absmax , body - > absmax ) ;
VectorCopy ( ent - > size , body - > size ) ;
body - > solid = ent - > solid ;
body - > clipmask = ent - > clipmask ;
body - > owner = ent - > owner ;
body - > movetype = ent - > movetype ;
body - > die = body_die ;
body - > takedamage = DAMAGE_YES ;
gi . linkentity ( body ) ;
}
void respawn ( edict_t * self )
{
// tpp
if ( self - > crosshair )
G_FreeEdict ( self - > crosshair ) ;
self - > crosshair = NULL ;
if ( self - > client - > oldplayer )
G_FreeEdict ( self - > client - > oldplayer ) ;
self - > client - > oldplayer = NULL ;
if ( self - > client - > chasecam )
G_FreeEdict ( self - > client - > chasecam ) ;
self - > client - > chasecam = NULL ;
// end tpp
if ( deathmatch - > value | | coop - > value )
{
// ACEBOT_ADD special respawning code
if ( self - > is_bot )
{
ACESP_Respawn ( self ) ;
return ;
}
// ACEBOT_END
// spectator's don't leave bodies
if ( self - > movetype ! = MOVETYPE_NOCLIP )
CopyToBodyQue ( self ) ;
self - > svflags & = ~ SVF_NOCLIENT ;
PutClientInServer ( self ) ;
// add a teleportation effect
self - > s . event = EV_PLAYER_TELEPORT ;
// hold in place briefly
self - > client - > ps . pmove . pm_flags = PMF_TIME_TELEPORT ;
self - > client - > ps . pmove . pm_time = 14 ;
self - > client - > respawn_time = level . time ;
return ;
}
// restart the entire server
gi . AddCommandString ( " menu_loadgame \n " ) ;
}
/*
* only called when pers . spectator changes
* note that resp . spectator should be the opposite of pers . spectator here
*/
void spectator_respawn ( edict_t * ent )
{
int i , numspec ;
// if the user wants to become a spectator, make sure he doesn't
// exceed max_spectators
2020-04-20 07:17:27 +00:00
if ( ent - > client - > pers . spectator )
{
2019-03-13 19:20:07 +00:00
char * value = Info_ValueForKey ( ent - > client - > pers . userinfo , " spectator " ) ;
if ( * spectator_password - > string & &
strcmp ( spectator_password - > string , " none " ) & &
strcmp ( spectator_password - > string , value ) ) {
safe_cprintf ( ent , PRINT_HIGH , " Spectator password incorrect. \n " ) ;
ent - > client - > pers . spectator = false ;
gi . WriteByte ( svc_stufftext ) ;
gi . WriteString ( " spectator 0 \n " ) ;
gi . unicast ( ent , true ) ;
return ;
}
// count spectators
for ( i = 1 , numspec = 0 ; i < = maxclients - > value ; i + + )
if ( g_edicts [ i ] . inuse & & g_edicts [ i ] . client - > pers . spectator )
numspec + + ;
2020-04-20 07:17:27 +00:00
if ( numspec > = maxspectators - > value )
{
2019-03-13 19:20:07 +00:00
safe_cprintf ( ent , PRINT_HIGH , " Server spectator limit is full. " ) ;
ent - > client - > pers . spectator = false ;
// reset his spectator var
gi . WriteByte ( svc_stufftext ) ;
gi . WriteString ( " spectator 0 \n " ) ;
gi . unicast ( ent , true ) ;
return ;
}
2020-04-20 07:17:27 +00:00
}
else
{
2019-03-13 19:20:07 +00:00
// he was a spectator and wants to join the game
// he must have the right password
char * value = Info_ValueForKey ( ent - > client - > pers . userinfo , " password " ) ;
if ( * password - > string & & strcmp ( password - > string , " none " ) & &
2020-04-20 07:17:27 +00:00
strcmp ( password - > string , value ) )
{
2019-03-13 19:20:07 +00:00
safe_cprintf ( ent , PRINT_HIGH , " Password incorrect. \n " ) ;
ent - > client - > pers . spectator = true ;
gi . WriteByte ( svc_stufftext ) ;
gi . WriteString ( " spectator 1 \n " ) ;
gi . unicast ( ent , true ) ;
return ;
}
}
// clear client on respawn
ent - > client - > resp . score = ent - > client - > pers . score = 0 ;
ent - > svflags & = ~ SVF_NOCLIENT ;
PutClientInServer ( ent ) ;
// add a teleportation effect
2020-04-20 07:17:27 +00:00
if ( ! ent - > client - > pers . spectator )
{
2019-03-13 19:20:07 +00:00
// send effect
gi . WriteByte ( svc_muzzleflash ) ;
gi . WriteShort ( ent - g_edicts ) ;
gi . WriteByte ( MZ_LOGIN ) ;
gi . multicast ( ent - > s . origin , MULTICAST_PVS ) ;
// hold in place briefly
ent - > client - > ps . pmove . pm_flags = PMF_TIME_TELEPORT ;
ent - > client - > ps . pmove . pm_time = 14 ;
}
ent - > client - > respawn_time = level . time ;
if ( ent - > client - > pers . spectator )
safe_bprintf ( PRINT_HIGH , " %s has moved to the sidelines \n " , ent - > client - > pers . netname ) ;
else
safe_bprintf ( PRINT_HIGH , " %s joined the game \n " , ent - > client - > pers . netname ) ;
}
//==============================================================
/*
= = = = = = = = = = =
PutClientInServer
Called when a player connects to a server or respawns in
a deathmatch .
= = = = = = = = = = = =
*/
void PutClientInServer ( edict_t * ent )
{
extern int nostatus ;
vec3_t mins = { - 16 , - 16 , - 24 } ;
vec3_t maxs = { 16 , 16 , 32 } ;
int index ;
vec3_t spawn_origin , spawn_angles , spawn_viewangles ;
gclient_t * client ;
int i ;
// tpp
int chasetoggle ;
gitem_t * newweapon ;
char userinfo [ MAX_INFO_STRING ] ;
// end tpp
qboolean spawn_landmark ;
qboolean spawn_levelchange ;
int spawn_gunframe ;
int spawn_modelframe ;
int spawn_anim_end ;
int spawn_pm_flags ;
int spawn_style ;
int spawn_health ;
client_persistant_t saved ;
client_respawn_t resp ;
// find a spawn point
// do it before setting health back up, so farthest
// ranging doesn't count this client
SelectSpawnPoint ( ent , spawn_origin , spawn_angles , & spawn_style , & spawn_health ) ;
index = ent - g_edicts - 1 ;
client = ent - > client ;
// tpp
chasetoggle = client - > pers . chasetoggle ;
// end tpp
newweapon = client - > pers . newweapon ;
spawn_landmark = client - > pers . spawn_landmark ;
spawn_levelchange = client - > pers . spawn_levelchange ;
spawn_gunframe = client - > pers . spawn_gunframe ;
spawn_modelframe = client - > pers . spawn_modelframe ;
spawn_anim_end = client - > pers . spawn_anim_end ;
client - > pers . spawn_landmark = false ;
client - > pers . spawn_levelchange = false ;
if ( spawn_landmark )
{
spawn_origin [ 2 ] - = 9 ;
VectorAdd ( spawn_origin , client - > pers . spawn_offset , spawn_origin ) ;
VectorCopy ( client - > pers . spawn_angles , spawn_angles ) ;
VectorCopy ( client - > pers . spawn_viewangles , spawn_viewangles ) ;
VectorCopy ( client - > pers . spawn_velocity , ent - > velocity ) ;
spawn_pm_flags = client - > pers . spawn_pm_flags ;
}
// deathmatch wipes most client data every spawn
if ( deathmatch - > value )
{
char userinfo [ MAX_INFO_STRING ] ;
resp = client - > resp ;
memcpy ( userinfo , client - > pers . userinfo , sizeof ( userinfo ) ) ;
InitClientPersistant ( client , spawn_style ) ;
ClientUserinfoChanged ( ent , userinfo ) ;
}
else if ( coop - > value )
{
2020-08-05 01:33:39 +00:00
// int n;
2019-03-13 19:20:07 +00:00
char userinfo [ MAX_INFO_STRING ] ;
resp = client - > resp ;
memcpy ( userinfo , client - > pers . userinfo , sizeof ( userinfo ) ) ;
resp . coop_respawn . game_helpchanged = client - > pers . game_helpchanged ;
resp . coop_respawn . helpchanged = client - > pers . helpchanged ;
client - > pers = resp . coop_respawn ;
ClientUserinfoChanged ( ent , userinfo ) ;
if ( resp . score > client - > pers . score )
client - > pers . score = resp . score ;
}
else
{
memset ( & resp , 0 , sizeof ( resp ) ) ;
}
// tpp
// A bug in Q2 that you couldn't see without thirdpp
memcpy ( userinfo , client - > pers . userinfo , sizeof ( userinfo ) ) ;
ClientUserinfoChanged ( ent , userinfo ) ;
// end tpp
// clear everything but the persistant data
saved = client - > pers ;
memset ( client , 0 , sizeof ( * client ) ) ;
client - > pers = saved ;
if ( client - > pers . health < = 0 )
InitClientPersistant ( client , spawn_style ) ;
else if ( spawn_style )
SelectStartWeapon ( client , spawn_style ) ;
client - > resp = resp ;
// tpp
client - > pers . chasetoggle = chasetoggle ;
// end tpp
client - > pers . newweapon = newweapon ;
// copy some data from the client to the entity
FetchClientEntData ( ent ) ;
// Lazarus: Starting health < max. Presumably player was hurt in a crash
2020-08-05 01:33:39 +00:00
if ( ( spawn_health > 0 ) & & ! deathmatch - > value & & ! coop - > value )
2019-03-13 19:20:07 +00:00
ent - > health = min ( ent - > health , spawn_health ) ;
// clear entity values
ent - > groundentity = NULL ;
ent - > client = & game . clients [ index ] ;
ent - > takedamage = DAMAGE_AIM ;
ent - > movetype = MOVETYPE_WALK ;
ent - > viewheight = 22 ;
ent - > inuse = true ;
ent - > classname = " player " ;
ent - > mass = 200 ;
ent - > solid = SOLID_BBOX ;
ent - > deadflag = DEAD_NO ;
ent - > air_finished = level . time + 12 ;
ent - > clipmask = MASK_PLAYERSOLID ;
ent - > model = " players/male/tris.md2 " ;
ent - > pain = player_pain ;
ent - > die = player_die ;
ent - > waterlevel = 0 ;
ent - > watertype = 0 ;
ent - > flags & = ~ FL_NO_KNOCKBACK ;
ent - > svflags & = ~ SVF_DEADMONSTER ;
// tpp
ent - > svflags & = ~ SVF_NOCLIENT ;
// turn on prediction
ent - > client - > ps . pmove . pm_flags & = ~ PMF_NO_PREDICTION ;
// end tpp
ent - > client - > spycam = NULL ;
ent - > client - > camplayer = NULL ;
// ACEBOT_ADD
ent - > is_bot = false ;
ent - > last_node = - 1 ;
ent - > is_jumping = false ;
// ACEBOT_END
VectorCopy ( mins , ent - > mins ) ;
VectorCopy ( maxs , ent - > maxs ) ;
2020-08-05 01:33:39 +00:00
if ( ! spawn_landmark )
2019-03-13 19:20:07 +00:00
VectorClear ( ent - > velocity ) ;
// clear playerstate values
memset ( & ent - > client - > ps , 0 , sizeof ( client - > ps ) ) ;
2020-08-05 01:33:39 +00:00
if ( spawn_landmark )
2019-03-13 19:20:07 +00:00
client - > ps . pmove . pm_flags = spawn_pm_flags ;
client - > ps . pmove . origin [ 0 ] = spawn_origin [ 0 ] * 8 ;
client - > ps . pmove . origin [ 1 ] = spawn_origin [ 1 ] * 8 ;
client - > ps . pmove . origin [ 2 ] = spawn_origin [ 2 ] * 8 ;
if ( deathmatch - > value & & ( ( int ) dmflags - > value & DF_FIXED_FOV ) )
{
client - > ps . fov = 90 ;
}
else
{
client - > ps . fov = atoi ( Info_ValueForKey ( client - > pers . userinfo , " fov " ) ) ;
if ( client - > ps . fov < 1 )
client - > ps . fov = 90 ;
else if ( client - > ps . fov > 160 )
client - > ps . fov = 160 ;
}
// DWH
client - > original_fov = client - > ps . fov ;
// end DWH
client - > ps . gunindex = gi . modelindex ( client - > pers . weapon - > view_model ) ;
// Server-side speed control stuff
# ifdef KMQUAKE2_ENGINE_MOD
client - > ps . maxspeed = player_max_speed - > value ;
client - > ps . duckspeed = player_crouch_speed - > value ;
client - > ps . accel = player_accel - > value ;
client - > ps . stopspeed = player_stopspeed - > value ;
# endif
// clear entity state values
ent - > s . effects = 0 ;
ent - > s . modelindex = MAX_MODELS - 1 ; // will use the skin specified model
2020-08-05 01:33:39 +00:00
if ( ITEM_INDEX ( client - > pers . weapon ) = = noweapon_index )
2019-03-13 19:20:07 +00:00
ent - > s . modelindex2 = 0 ;
else
ent - > s . modelindex2 = MAX_MODELS - 1 ; // custom gun model
// sknum is player num and weapon number
// weapon number will be added in changeweapon
ent - > s . skinnum = ent - g_edicts - 1 ;
ent - > s . frame = 0 ;
VectorCopy ( spawn_origin , ent - > s . origin ) ;
ent - > s . origin [ 2 ] + = 1 ; // make sure off ground
VectorCopy ( ent - > s . origin , ent - > s . old_origin ) ;
// set the delta angle
for ( i = 0 ; i < 3 ; i + + )
{
client - > ps . pmove . delta_angles [ i ] = ANGLE2SHORT ( spawn_angles [ i ] - client - > resp . cmd_angles [ i ] ) ;
}
ent - > s . angles [ PITCH ] = ent - > s . angles [ ROLL ] = 0 ;
ent - > s . angles [ YAW ] = spawn_angles [ YAW ] ;
2020-08-05 01:33:39 +00:00
if ( spawn_landmark )
2019-03-13 19:20:07 +00:00
{
VectorCopy ( spawn_viewangles , client - > ps . viewangles ) ;
2020-08-05 01:33:39 +00:00
// client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
2019-03-13 19:20:07 +00:00
}
else
2020-08-05 01:33:39 +00:00
VectorCopy ( ent - > s . angles , client - > ps . viewangles ) ;
2019-03-13 19:20:07 +00:00
VectorCopy ( client - > ps . viewangles , client - > v_angle ) ;
// spawn a spectator
2020-04-20 07:17:27 +00:00
if ( client - > pers . spectator )
{
2019-03-13 19:20:07 +00:00
client - > chase_target = NULL ;
client - > resp . spectator = true ;
ent - > movetype = MOVETYPE_NOCLIP ;
ent - > solid = SOLID_NOT ;
ent - > svflags | = SVF_NOCLIENT ;
ent - > client - > ps . gunindex = 0 ;
gi . linkentity ( ent ) ;
return ;
2020-04-20 07:17:27 +00:00
}
else
2019-03-13 19:20:07 +00:00
client - > resp . spectator = false ;
// DWH:
client - > flashlight = false ;
client - > secs_per_frame = 0.025 ; // assumed 40 fps until we know better
client - > fps_time_start = level . time ;
if ( ! KillBox ( ent ) )
{ // could't spawn in?
}
//ZOID
if ( ctf - > value & & CTFStartClient ( ent ) )
return ;
//ZOID
gi . linkentity ( ent ) ;
// tpp
client - > chasetoggle = 0 ;
// If chasetoggle set then turn on (delayed start of 5 frames - 0.5s)
2020-08-05 01:33:39 +00:00
if ( client - > pers . chasetoggle )
2019-03-13 19:20:07 +00:00
client - > delayedstart = 5 ;
// end tpp
if ( spawn_levelchange & & ! client - > pers . chasetoggle & & ! client - > pers . newweapon )
{
// we already had a weapon when the level changed... no need to bring it up
int i ;
client - > pers . lastweapon = client - > pers . weapon ;
client - > newweapon = NULL ;
client - > machinegun_shots = 0 ;
i = ( ( client - > pers . weapon - > weapmodel & 0xff ) < < 8 ) ;
ent - > s . skinnum = ( ent - g_edicts - 1 ) | i ;
if ( client - > pers . weapon - > ammo )
client - > ammo_index = ITEM_INDEX ( FindItem ( client - > pers . weapon - > ammo ) ) ;
else
client - > ammo_index = 0 ;
client - > weaponstate = WEAPON_READY ;
client - > ps . gunframe = 0 ;
client - > ps . gunindex = gi . modelindex ( client - > pers . weapon - > view_model ) ;
client - > ps . gunframe = spawn_gunframe ;
ent - > s . frame = spawn_modelframe ;
client - > anim_end = spawn_anim_end ;
}
else
{
// force the current weapon up
client - > newweapon = client - > pers . weapon ;
ChangeWeapon ( ent ) ;
}
// Paril's fix for this getting reset after map changes
if ( ! ent - > client - > pers . connected )
ent - > client - > pers . connected = true ;
}
/*
= = = = = = = = = = = = = = = = = = = = =
ClientBeginDeathmatch
A client has just connected to the server in
deathmatch mode , so clear everything out before starting them .
= = = = = = = = = = = = = = = = = = = = =
*/
void ClientBeginDeathmatch ( edict_t * ent )
{
// ACEBOT_ADD
//static char current_map[55];
// ACEBOT_END
G_InitEdict ( ent ) ;
InitClientResp ( ent - > client ) ;
// ACEBOT_ADD
ACEIT_PlayerAdded ( ent ) ;
// ACEBOT_END
// locate ent at a spawn point
PutClientInServer ( ent ) ;
if ( level . intermissiontime )
{
MoveClientToIntermission ( ent ) ;
}
else
{
// send effect
gi . WriteByte ( svc_muzzleflash ) ;
gi . WriteShort ( ent - g_edicts ) ;
gi . WriteByte ( MZ_LOGIN ) ;
gi . multicast ( ent - > s . origin , MULTICAST_PVS ) ;
}
safe_bprintf ( PRINT_HIGH , " %s entered the game \n " , ent - > client - > pers . netname ) ;
// ACEBOT_ADD
safe_centerprintf ( ent , " \n ====================================== \n ACE Bot II Mod \n \n 'sv addbot' to add a new bot. \n 'sv removebot <name>' to remove bot. \n 'sv dmpause' to pause the game. \n 'sv savenodes' to save level path data. \n ====================================== \n \n " ) ;
// Knightmare- moved this to g_spawn.c for bot support in dedicated servers
// If the map changes on us, init and reload the nodes
2020-08-05 01:33:39 +00:00
/*if (strcmp(level.mapname,current_map))
2019-03-13 19:20:07 +00:00
{
ACEND_InitNodes ( ) ;
ACEND_LoadNodes ( ) ;
//ACESP_LoadBots(); // Knightmare- removed this
ACESP_LoadBotInfo ( ) ; // Knightmare- load bot info file
// strncpy(current_map, level.mapname);
Q_strncpyz ( current_map , level . mapname , sizeof ( current_map ) ) ;
} */
// ACEBOT_END
// make sure all view stuff is valid
ClientEndServerFrame ( ent ) ;
}
/*
= = = = = = = = = = =
ClientBegin
called when a client has finished connecting , and is ready
to be placed into the game . This will happen every level load .
= = = = = = = = = = = =
*/
void ClientBegin ( edict_t * ent )
{
int i ;
ent - > client = game . clients + ( ent - g_edicts - 1 ) ;
// Lazarus: Set the alias for our alternate attack
2020-08-05 01:33:39 +00:00
// stuffcmd(ent, "alias +attack2 attack2_on; alias -attack2 attack2_off\n");
2019-03-13 19:20:07 +00:00
if ( deathmatch - > value )
{
ClientBeginDeathmatch ( ent ) ;
return ;
}
2020-04-07 06:02:54 +00:00
Fog_Off ( ent ) ;
2020-04-20 07:17:27 +00:00
// Fog (ent);
2019-03-13 19:20:07 +00:00
stuffcmd ( ent , " alias +zoomin zoomin;alias -zoomin zoominstop \n " ) ;
stuffcmd ( ent , " alias +zoomout zoomout;alias -zoomout zoomoutstop \n " ) ;
stuffcmd ( ent , " alias +zoom zoomon;alias -zoom zoomoff \n " ) ;
// if there is already a body waiting for us (a loadgame), just
// take it, otherwise spawn one from scratch
if ( ent - > inuse = = true )
{
// the client has cleared the client side viewangles upon
// connecting to the server, which is different than the
// state when the game is saved, so we need to compensate
// with deltaangles
for ( i = 0 ; i < 3 ; i + + )
ent - > client - > ps . pmove . delta_angles [ i ] = ANGLE2SHORT ( ent - > client - > ps . viewangles [ i ] ) ;
}
else
{
// a spawn point will completely reinitialize the entity
// except for the persistant data that was initialized at
// ClientConnect() time
G_InitEdict ( ent ) ;
ent - > classname = " player " ;
InitClientResp ( ent - > client ) ;
PutClientInServer ( ent ) ;
}
if ( level . intermissiontime )
{
MoveClientToIntermission ( ent ) ;
}
else
{
// send effect if in a multiplayer game
if ( game . maxclients > 1 )
{
gi . WriteByte ( svc_muzzleflash ) ;
gi . WriteShort ( ent - g_edicts ) ;
gi . WriteByte ( MZ_LOGIN ) ;
gi . multicast ( ent - > s . origin , MULTICAST_PVS ) ;
safe_bprintf ( PRINT_HIGH , " %s entered the game \n " , ent - > client - > pers . netname ) ;
}
}
// DWH
SetLazarusCrosshair ( ent ) ; //backup crosshair
SetSensitivities ( ent , true ) ;
if ( game . maxclients = = 1 )
{
// For SP games, check for monsters who were mad at player
// in previous level and have changed levels with the player
edict_t * monster ;
2020-08-05 01:33:39 +00:00
for ( i = 2 ; i < globals . num_edicts ; i + + )
2019-03-13 19:20:07 +00:00
{
monster = & g_edicts [ i ] ;
2020-08-05 01:33:39 +00:00
if ( ! monster - > inuse )
2019-03-13 19:20:07 +00:00
continue ;
2020-08-05 01:33:39 +00:00
if ( ! ( monster - > svflags & SVF_MONSTER ) )
2019-03-13 19:20:07 +00:00
continue ;
2020-08-05 01:33:39 +00:00
if ( monster - > health < = 0 )
2019-03-13 19:20:07 +00:00
continue ;
2020-08-05 01:33:39 +00:00
if ( monster - > monsterinfo . aiflags & AI_RESPAWN_FINDPLAYER )
2019-03-13 19:20:07 +00:00
{
monster - > monsterinfo . aiflags & = ~ AI_RESPAWN_FINDPLAYER ;
2020-08-05 01:33:39 +00:00
if ( ! monster - > enemy )
2019-03-13 19:20:07 +00:00
{
monster - > enemy = ent ;
FoundTarget ( monster ) ;
}
}
}
}
// make sure all view stuff is valid
ClientEndServerFrame ( ent ) ;
}
/*
= = = = = = = = = = =
ClientUserInfoChanged
called whenever the player updates a userinfo variable .
The game can override any of the settings in place
( forcing skins or names , etc ) before copying it off .
= = = = = = = = = = = =
*/
void ClientUserinfoChanged ( edict_t * ent , char * userinfo )
{
char * s ;
int playernum ;
// check for malformed or illegal info strings
if ( ! Info_Validate ( userinfo ) )
{
2020-04-20 07:17:27 +00:00
// strncpy (userinfo, "\\name\\badinfo\\skin\\male/grunt");
2019-03-29 01:37:34 +00:00
Q_strncpyz ( userinfo , " \\ name \\ badinfo \\ skin \\ male/grunt " , MAX_INFO_STRING ) ; // userinfo is always length of MAX_INFO_STRING
2019-03-13 19:20:07 +00:00
}
// set name
s = Info_ValueForKey ( userinfo , " name " ) ;
strncpy ( ent - > client - > pers . netname , s , sizeof ( ent - > client - > pers . netname ) - 1 ) ;
// set spectator
s = Info_ValueForKey ( userinfo , " spectator " ) ;
// spectators are only supported in deathmatch
if ( deathmatch - > value & & * s & & strcmp ( s , " 0 " ) )
ent - > client - > pers . spectator = true ;
else
ent - > client - > pers . spectator = false ;
// set skin
s = Info_ValueForKey ( userinfo , " skin " ) ;
playernum = ent - g_edicts - 1 ;
// combine name and skin into a configstring
//ZOID
if ( ctf - > value )
CTFAssignSkin ( ent , s ) ;
else
//ZOID
gi . configstring ( CS_PLAYERSKINS + playernum , va ( " %s \\ %s " , ent - > client - > pers . netname , s ) ) ;
//ZOID
// set player name field (used in id_state view)
gi . configstring ( CS_GENERAL + playernum , ent - > client - > pers . netname ) ;
//ZOID
// fov
if ( deathmatch - > value & & ( ( int ) dmflags - > value & DF_FIXED_FOV ) )
{
ent - > client - > ps . fov = 90 ;
ent - > client - > original_fov = ent - > client - > ps . fov ;
}
else
{
float new_fov ;
new_fov = atoi ( Info_ValueForKey ( userinfo , " fov " ) ) ;
if ( new_fov < 1 )
new_fov = 90 ;
else if ( new_fov > 160 )
new_fov = 160 ;
2020-08-05 01:33:39 +00:00
if ( new_fov ! = ent - > client - > original_fov ) {
2019-03-13 19:20:07 +00:00
ent - > client - > ps . fov = new_fov ;
ent - > client - > original_fov = new_fov ;
}
}
// handedness
s = Info_ValueForKey ( userinfo , " hand " ) ;
if ( strlen ( s ) )
ent - > client - > pers . hand = atoi ( s ) ;
// save off the userinfo in case we want to check something later
strncpy ( ent - > client - > pers . userinfo , userinfo , sizeof ( ent - > client - > pers . userinfo ) - 1 ) ;
}
/*
= = = = = = = = = = =
ClientConnect
Called when a player begins connecting to the server .
The game can refuse entrance to a client by returning false .
If the client is allowed , the connection process will continue
and eventually get to ClientBegin ( )
Changing levels will NOT cause this to be called again , but
loadgames will .
= = = = = = = = = = = =
*/
qboolean ClientConnect ( edict_t * ent , char * userinfo )
{
char * value ;
// check to see if they are on the banned IP list
value = Info_ValueForKey ( userinfo , " ip " ) ;
if ( SV_FilterPacket ( value ) ) {
Info_SetValueForKey ( userinfo , " rejmsg " , " Banned. " ) ;
return false ;
}
// check for a spectator
value = Info_ValueForKey ( userinfo , " spectator " ) ;
if ( deathmatch - > value & & * value & & strcmp ( value , " 0 " ) ) {
int i , numspec ;
if ( * spectator_password - > string & &
strcmp ( spectator_password - > string , " none " ) & &
strcmp ( spectator_password - > string , value ) ) {
Info_SetValueForKey ( userinfo , " rejmsg " , " Spectator password required or incorrect. " ) ;
return false ;
}
// count spectators
for ( i = numspec = 0 ; i < maxclients - > value ; i + + )
if ( g_edicts [ i + 1 ] . inuse & & g_edicts [ i + 1 ] . client - > pers . spectator )
numspec + + ;
if ( numspec > = maxspectators - > value ) {
Info_SetValueForKey ( userinfo , " rejmsg " , " Server spectator limit is full. " ) ;
return false ;
}
} else {
// check for a password
value = Info_ValueForKey ( userinfo , " password " ) ;
if ( * password - > string & & strcmp ( password - > string , " none " ) & &
strcmp ( password - > string , value ) ) {
Info_SetValueForKey ( userinfo , " rejmsg " , " Password required or incorrect. " ) ;
return false ;
}
}
// they can connect
ent - > client = game . clients + ( ent - g_edicts - 1 ) ;
// if there is already a body waiting for us (a loadgame), just
// take it, otherwise spawn one from scratch
if ( ent - > inuse = = false )
{
// clear the respawning variables
//ZOID -- force team join
if ( ctf - > value )
{
ent - > client - > resp . ctf_team = - 1 ;
ent - > client - > resp . id_state = true ;
}
//ZOID
InitClientResp ( ent - > client ) ;
if ( ! game . autosaved | | ! ent - > client - > pers . weapon )
InitClientPersistant ( ent - > client , world - > style ) ;
}
ClientUserinfoChanged ( ent , userinfo ) ;
if ( game . maxclients > 1 )
gi . dprintf ( " %s connected \n " , ent - > client - > pers . netname ) ;
ent - > svflags = 0 ; // make sure we start with known default
ent - > client - > pers . connected = true ;
return true ;
}
/*
= = = = = = = = = = =
ClientDisconnect
Called when a player drops from the server .
Will not be called between levels .
= = = = = = = = = = = =
*/
void ClientDisconnect ( edict_t * ent )
{
int playernum ;
if ( ! ent - > client )
return ;
// tpp
2020-08-05 01:33:39 +00:00
if ( ent - > client - > chasetoggle )
2019-03-13 19:20:07 +00:00
ChasecamRemove ( ent , OPTION_OFF ) ;
// end tpp
// DWH
SetLazarusCrosshair ( ent ) ; //backup crosshair
ent - > client - > zooming = 0 ;
ent - > client - > zoomed = false ;
SetSensitivities ( ent , true ) ;
// end DWH
if ( ent - > client - > textdisplay )
Text_Close ( ent ) ;
safe_bprintf ( PRINT_HIGH , " %s disconnected \n " , ent - > client - > pers . netname ) ;
// ACEBOT_ADD
ACEIT_PlayerRemoved ( ent ) ;
// ACEBOT_END
//ZOID
CTFDeadDropFlag ( ent ) ;
CTFDeadDropTech ( ent ) ;
//ZOID
// send effect
gi . WriteByte ( svc_muzzleflash ) ;
gi . WriteShort ( ent - g_edicts ) ;
gi . WriteByte ( MZ_LOGOUT ) ;
gi . multicast ( ent - > s . origin , MULTICAST_PVS ) ;
gi . unlinkentity ( ent ) ;
ent - > s . modelindex = 0 ;
ent - > solid = SOLID_NOT ;
ent - > inuse = false ;
ent - > classname = " disconnected " ;
ent - > client - > pers . connected = false ;
2020-08-05 01:33:39 +00:00
if ( ent - > client - > spycam )
2019-03-13 19:20:07 +00:00
camera_off ( ent ) ;
playernum = ent - g_edicts - 1 ;
gi . configstring ( CS_PLAYERSKINS + playernum , " " ) ;
}
//==============================================================
edict_t * pm_passent ;
// pmove doesn't need to know about passent and contentmask
trace_t PM_trace ( vec3_t start , vec3_t mins , vec3_t maxs , vec3_t end )
{
if ( pm_passent - > health > 0 )
return gi . trace ( start , mins , maxs , end , pm_passent , MASK_PLAYERSOLID ) ;
else
return gi . trace ( start , mins , maxs , end , pm_passent , MASK_DEADSOLID ) ;
}
unsigned CheckBlock ( void * b , int c )
{
int v , i ;
v = 0 ;
for ( i = 0 ; i < c ; i + + )
v + = ( ( byte * ) b ) [ i ] ;
return v ;
}
void PrintPmove ( pmove_t * pm )
{
unsigned c1 , c2 ;
c1 = CheckBlock ( & pm - > s , sizeof ( pm - > s ) ) ;
c2 = CheckBlock ( & pm - > cmd , sizeof ( pm - > cmd ) ) ;
Com_Printf ( " sv %3i:%i %i \n " , pm - > cmd . impulse , c1 , c2 ) ;
}
// DWH
//==========================================================================
// DWH: PM_CmdScale was ripped from Q3 source
//==========================================================================
float PM_CmdScale ( usercmd_t * cmd ) {
int max ;
float total ;
float scale ;
max = abs ( cmd - > forwardmove ) ;
if ( abs ( cmd - > sidemove ) > max ) {
max = abs ( cmd - > sidemove ) ;
}
if ( abs ( cmd - > upmove ) > max ) {
max = abs ( cmd - > upmove ) ;
}
if ( ! max ) {
return 0 ;
}
total = sqrt ( cmd - > forwardmove * cmd - > forwardmove
+ cmd - > sidemove * cmd - > sidemove + cmd - > upmove * cmd - > upmove ) ;
scale = max / total ;
return scale ;
}
void RemovePush ( edict_t * ent )
{
ent - > client - > push - > s . sound = 0 ;
ent - > client - > push - > activator = NULL ;
ent - > client - > push = NULL ;
ent - > client - > ps . pmove . pm_flags & = ~ PMF_NO_PREDICTION ;
// If tpp is NOT always on, and auto-switch for func_pushables IS on,
// and we're currently in third-person view, switch it off
// Knightmare- don't autoswitch if client-side chasecam is on
# ifdef KMQUAKE2_ENGINE_MOD
if ( ! tpp - > value & & tpp_auto - > value & & ( ! cl_thirdperson - > value | | deathmatch - > value | | coop - > value ) & & ent - > client - > chasetoggle )
# else
2020-08-05 01:33:39 +00:00
if ( ! tpp - > value & & tpp_auto - > value & & ent - > client - > chasetoggle )
2019-03-13 19:20:07 +00:00
# endif
Cmd_Chasecam_Toggle ( ent ) ;
}
void ClientPushPushable ( edict_t * ent )
{
edict_t * box = ent - > client - > push ;
vec_t dist ;
vec3_t new_origin , v , vbox ;
VectorAdd ( box - > absmax , box - > absmin , vbox ) ;
VectorScale ( vbox , 0.5 , vbox ) ;
if ( point_infront ( ent , vbox ) )
{
VectorSubtract ( ent - > s . origin , box - > offset , new_origin ) ;
VectorSubtract ( new_origin , box - > s . origin , v ) ;
v [ 2 ] = 0 ;
dist = VectorLength ( v ) ;
2020-08-05 01:33:39 +00:00
if ( dist > 8 )
2019-03-13 19:20:07 +00:00
{
// func_pushable got hung up somehow. Break off contact
RemovePush ( ent ) ;
}
2020-08-05 01:33:39 +00:00
else if ( dist > 0 )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( ! box - > speaker )
2019-03-13 19:20:07 +00:00
box - > s . sound = box - > noise_index ;
box_walkmove ( box , vectoyaw ( v ) , dist ) ;
}
else
box - > s . sound = 0 ;
}
else
RemovePush ( ent ) ;
}
void ClientSpycam ( edict_t * ent )
{
gclient_t * client = ent - > client ;
edict_t * camera = ent - > client - > spycam ;
pmove_t pm ;
qboolean is_actor ;
trace_t tr ;
vec3_t forward , left , up ;
vec3_t dir , start ;
float dist ;
int i ;
memset ( & pm , 0 , sizeof ( pm ) ) ;
2020-08-05 01:33:39 +00:00
if ( client - > ucmd . sidemove & & level . time > ent - > last_move_time + 1 )
2019-03-13 19:20:07 +00:00
{
camera - > flags & = ~ FL_ROBOT ;
2020-08-05 01:33:39 +00:00
if ( camera - > viewer = = ent )
2019-03-13 19:20:07 +00:00
camera - > viewer = NULL ;
2020-08-05 01:33:39 +00:00
if ( client - > ucmd . sidemove > 0 )
2019-03-13 19:20:07 +00:00
camera = G_FindNextCamera ( camera , client - > monitor ) ;
else
camera = G_FindPrevCamera ( camera , client - > monitor ) ;
2020-08-05 01:33:39 +00:00
if ( camera )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( ! camera - > viewer )
2019-03-13 19:20:07 +00:00
camera - > viewer = ent ;
client - > spycam = camera ;
VectorAdd ( camera - > s . origin , camera - > move_origin , ent - > s . origin ) ;
2020-08-05 01:33:39 +00:00
if ( camera - > viewmessage )
2019-03-13 19:20:07 +00:00
safe_centerprintf ( ent , camera - > viewmessage ) ;
ent - > last_move_time = level . time ;
}
else
camera = client - > spycam ;
2020-08-05 01:33:39 +00:00
if ( camera - > monsterinfo . aiflags & AI_ACTOR )
2019-03-13 19:20:07 +00:00
{
camera - > flags | = FL_ROBOT ;
2020-08-05 01:33:39 +00:00
if ( camera - > monsterinfo . aiflags & AI_FOLLOW_LEADER )
2019-03-13 19:20:07 +00:00
{
camera - > monsterinfo . aiflags & = ~ AI_FOLLOW_LEADER ;
camera - > monsterinfo . old_leader = NULL ;
camera - > monsterinfo . leader = NULL ;
camera - > movetarget = camera - > goalentity = NULL ;
camera - > monsterinfo . stand ( camera ) ;
}
}
}
2020-08-05 01:33:39 +00:00
if ( ( camera - > svflags & SVF_MONSTER ) & & ( camera - > monsterinfo . aiflags & AI_ACTOR ) )
2019-03-13 19:20:07 +00:00
is_actor = true ;
else
is_actor = false ;
2020-08-05 01:33:39 +00:00
if ( camera - > enemy & & ( camera - > enemy - > deadflag | | ! camera - > enemy - > inuse ) )
2019-03-13 19:20:07 +00:00
camera - > enemy = NULL ;
AngleVectors ( camera - > s . angles , forward , left , up ) ;
2020-08-05 01:33:39 +00:00
if ( is_actor & & ! camera - > enemy )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( ( abs ( client - > ucmd . forwardmove ) > 199 ) & & ( camera - > groundentity ) )
2019-03-13 19:20:07 +00:00
{
// walk/run
edict_t * thing ;
vec3_t end ;
float dist ;
thing = camera - > vehicle ;
VectorMA ( camera - > s . origin , WORLD_SIZE , forward , end ) ; // was 8192
tr = gi . trace ( camera - > s . origin , camera - > mins , camera - > maxs , end , camera , MASK_SOLID ) ;
2020-08-05 01:33:39 +00:00
if ( client - > ucmd . forwardmove < 0 )
2019-03-13 19:20:07 +00:00
{
trace_t back ;
VectorMA ( camera - > s . origin , - WORLD_SIZE , forward , end ) ; // was -8192
back = gi . trace ( camera - > s . origin , camera - > mins , camera - > maxs , end , camera , MASK_SOLID ) ;
VectorSubtract ( back . endpos , camera - > s . origin , end ) ;
dist = VectorLength ( end ) ;
VectorCopy ( tr . endpos , end ) ;
}
else
{
VectorSubtract ( tr . endpos , camera - > s . origin , end ) ;
dist = VectorLength ( end ) - 8 ;
VectorMA ( camera - > s . origin , dist , forward , end ) ;
}
2020-08-05 01:33:39 +00:00
if ( dist > 8 )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( ! thing | | ! thing - > inuse | | Q_stricmp ( thing - > classname , " thing " ) )
2019-03-13 19:20:07 +00:00
thing = camera - > vehicle = SpawnThing ( ) ;
thing - > touch_debounce_time = level . time + 5.0 ;
thing - > target_ent = camera ;
VectorCopy ( end , thing - > s . origin ) ;
ED_CallSpawn ( thing ) ;
camera - > monsterinfo . aiflags | = AI_CHASE_THING ;
camera - > monsterinfo . aiflags & = ~ ( AI_CHICKEN | AI_STAND_GROUND ) ;
camera - > monsterinfo . pausetime = 0 ;
camera - > movetarget = camera - > goalentity = thing ;
camera - > monsterinfo . old_leader = NULL ;
camera - > monsterinfo . leader = thing ;
VectorSubtract ( thing - > s . origin , camera - > s . origin , dir ) ;
camera - > ideal_yaw = vectoyaw ( dir ) ;
2020-08-05 01:33:39 +00:00
if ( client - > ucmd . forwardmove > 300 )
2019-03-13 19:20:07 +00:00
actor_run ( camera ) ;
2020-08-05 01:33:39 +00:00
else if ( client - > ucmd . forwardmove > 199 )
2019-03-13 19:20:07 +00:00
actor_walk ( camera ) ;
2020-08-05 01:33:39 +00:00
else if ( client - > ucmd . forwardmove < - 300 )
2019-03-13 19:20:07 +00:00
actor_run_back ( camera ) ;
else
actor_walk_back ( camera ) ;
}
2020-08-05 01:33:39 +00:00
else if ( thing )
2019-03-13 19:20:07 +00:00
{
camera - > monsterinfo . aiflags & = ~ AI_CHASE_THING ;
camera - > movetarget = camera - > goalentity = NULL ;
G_FreeEdict ( thing ) ;
camera - > vehicle = NULL ;
actor_stand ( camera ) ;
}
}
2020-08-05 01:33:39 +00:00
if ( ( client - > ucmd . forwardmove = = 0 ) & & ( camera - > groundentity ) )
2019-03-13 19:20:07 +00:00
{
// stop
edict_t * thing = camera - > vehicle ;
2020-08-05 01:33:39 +00:00
if ( thing )
2019-03-13 19:20:07 +00:00
{
camera - > monsterinfo . aiflags & = ~ AI_CHASE_THING ;
camera - > movetarget = camera - > goalentity = NULL ;
G_FreeEdict ( thing ) ;
camera - > vehicle = NULL ;
actor_stand ( camera ) ;
}
}
2020-08-05 01:33:39 +00:00
if ( client - > ucmd . upmove )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( ( client - > ucmd . upmove > 0 ) & & camera - > groundentity & & ! camera - > waterlevel )
2019-03-13 19:20:07 +00:00
{
// jump
2020-08-05 01:33:39 +00:00
if ( client - > ucmd . forwardmove > 300 )
2019-03-13 19:20:07 +00:00
VectorScale ( forward , 400 , camera - > velocity ) ;
2020-08-05 01:33:39 +00:00
else if ( client - > ucmd . forwardmove > 199 )
2019-03-13 19:20:07 +00:00
VectorScale ( forward , 200 , camera - > velocity ) ;
2020-08-05 01:33:39 +00:00
else if ( client - > ucmd . forwardmove < - 300 )
2019-03-13 19:20:07 +00:00
VectorScale ( forward , - 400 , camera - > velocity ) ;
2020-08-05 01:33:39 +00:00
else if ( client - > ucmd . forwardmove < - 199 )
2019-03-13 19:20:07 +00:00
VectorScale ( forward , - 200 , camera - > velocity ) ;
camera - > velocity [ 2 ] = 250 ;
camera - > monsterinfo . savemove = camera - > monsterinfo . currentmove ;
actor_jump ( camera ) ;
camera - > groundentity = NULL ;
}
2020-08-05 01:33:39 +00:00
else if ( ( client - > ucmd . upmove < 0 ) & & ( camera - > groundentity ) & & ! ( camera - > monsterinfo . aiflags & AI_CROUCH ) )
2019-03-13 19:20:07 +00:00
{
// crouch
2020-08-05 01:33:39 +00:00
if ( ( camera - > monsterinfo . currentmove = = & actor_move_walk ) | |
2019-03-13 19:20:07 +00:00
( camera - > monsterinfo . currentmove = = & actor_move_run ) | |
( camera - > monsterinfo . currentmove = = & actor_move_run_bad ) )
{
camera - > monsterinfo . currentmove = & actor_move_crouchwalk ;
camera - > maxs [ 2 ] - = 28 ;
camera - > viewheight - = 28 ;
camera - > move_origin [ 2 ] - = 28 ;
camera - > monsterinfo . aiflags | = AI_CROUCH ;
}
2020-08-05 01:33:39 +00:00
else if ( ( camera - > monsterinfo . currentmove = = & actor_move_walk_back ) | |
2019-03-13 19:20:07 +00:00
( camera - > monsterinfo . currentmove = = & actor_move_run_back ) )
{
camera - > monsterinfo . currentmove = & actor_move_crouchwalk_back ;
camera - > maxs [ 2 ] - = 28 ;
camera - > viewheight - = 28 ;
camera - > move_origin [ 2 ] - = 28 ;
camera - > monsterinfo . aiflags | = AI_CROUCH ;
}
else if ( camera - > monsterinfo . currentmove = = & actor_move_stand )
{
camera - > monsterinfo . currentmove = & actor_move_crouch ;
camera - > maxs [ 2 ] - = 28 ;
camera - > viewheight - = 28 ;
camera - > move_origin [ 2 ] - = 28 ;
camera - > monsterinfo . aiflags | = AI_CROUCH ;
}
}
}
2020-08-05 01:33:39 +00:00
if ( ( client - > ucmd . upmove > = 0 ) & & ( camera - > monsterinfo . aiflags & AI_CROUCH ) )
2019-03-13 19:20:07 +00:00
{
// come out of crouch
camera - > maxs [ 2 ] + = 28 ;
camera - > viewheight + = 28 ;
camera - > move_origin [ 2 ] + = 28 ;
camera - > monsterinfo . aiflags & = ~ AI_CROUCH ;
2020-08-05 01:33:39 +00:00
if ( camera - > monsterinfo . currentmove = = & actor_move_crouchwalk )
2019-03-13 19:20:07 +00:00
actor_walk ( camera ) ;
2020-08-05 01:33:39 +00:00
else if ( camera - > monsterinfo . currentmove = = & actor_move_crouchwalk_back )
2019-03-13 19:20:07 +00:00
actor_walk_back ( camera ) ;
2020-08-05 01:33:39 +00:00
else if ( camera - > monsterinfo . currentmove = = & actor_move_crouch )
2019-03-13 19:20:07 +00:00
actor_stand ( camera ) ;
}
}
client - > ps . pmove . pm_type = PM_FREEZE ;
2020-08-05 01:33:39 +00:00
if ( camera - > viewer = = ent ) {
if ( ( client - > old_owner_angles [ 0 ] ! = client - > ucmd . angles [ 0 ] ) | |
2019-03-13 19:20:07 +00:00
( client - > old_owner_angles [ 1 ] ! = client - > ucmd . angles [ 1 ] ) )
{
// Give game a bit of time to catch up after player
// causes ucmd pitch angle to roll over... otherwise
// we'll hit on the above test even though player
// hasn't hit +lookup/+lookdown
float delta ;
delta = level . time - camera - > touch_debounce_time ;
2020-08-05 01:33:39 +00:00
if ( delta < 0 | | delta > 1.0 )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( is_actor )
2019-03-13 19:20:07 +00:00
{
float diff ;
diff = SHORT2ANGLE ( client - > ucmd . angles [ 1 ] - client - > old_owner_angles [ 1 ] ) ;
2020-08-05 01:33:39 +00:00
if ( diff < - 180 )
2019-03-13 19:20:07 +00:00
diff + = 360 ;
2020-08-05 01:33:39 +00:00
if ( diff > 180 )
2019-03-13 19:20:07 +00:00
diff - = 360 ;
camera - > ideal_yaw + = diff ;
2020-08-05 01:33:39 +00:00
if ( ( abs ( diff ) > 100 ) & & camera - > vehicle )
2019-03-13 19:20:07 +00:00
{
vec3_t angles ;
vec3_t end , f ;
VectorSet ( angles , 0 , camera - > ideal_yaw , 0 ) ;
AngleVectors ( angles , f , NULL , NULL ) ;
VectorMA ( camera - > s . origin , WORLD_SIZE , f , end ) ; // was 8192
tr = gi . trace ( camera - > s . origin , camera - > mins , camera - > maxs , end , camera , MASK_SOLID ) ;
VectorCopy ( tr . endpos , camera - > vehicle - > s . origin ) ;
camera - > vehicle - > touch_debounce_time = level . time + 5.0 ;
gi . linkentity ( camera - > vehicle ) ;
}
ai_turn ( camera , 0. ) ;
diff = SHORT2ANGLE ( client - > ucmd . angles [ 0 ] - client - > old_owner_angles [ 0 ] ) ;
2020-08-05 01:33:39 +00:00
if ( diff < - 180 )
2019-03-13 19:20:07 +00:00
diff + = 360 ;
2020-08-05 01:33:39 +00:00
if ( diff > 180 )
2019-03-13 19:20:07 +00:00
diff - = 360 ;
camera - > move_angles [ 0 ] + = diff ;
client - > old_owner_angles [ 0 ] = client - > ucmd . angles [ 0 ] ;
client - > old_owner_angles [ 1 ] = client - > ucmd . angles [ 1 ] ;
}
}
}
if ( client - > ucmd . buttons & BUTTON_ATTACK & & camera - > sounds > = 0 ) {
if ( level . time > = camera - > monsterinfo . attack_finished ) {
client - > latched_buttons & = ~ BUTTON_ATTACK ;
2020-08-05 01:33:39 +00:00
if ( ! Q_stricmp ( camera - > classname , " turret_breach " ) )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( camera - > sounds = = 5 | | camera - > sounds = = 6 )
2019-03-13 19:20:07 +00:00
camera - > monsterinfo . attack_finished = level . time ;
else
camera - > monsterinfo . attack_finished = level . time + 1.0 ;
2020-08-05 01:33:39 +00:00
turret_breach_fire ( camera ) ;
2019-03-13 19:20:07 +00:00
}
2020-08-05 01:33:39 +00:00
else if ( is_actor )
2019-03-13 19:20:07 +00:00
{
int weapon = camera - > actor_weapon [ camera - > actor_current_weapon ] ;
2020-08-05 01:33:39 +00:00
if ( ! camera - > enemy )
2019-03-13 19:20:07 +00:00
{
edict_t * target ;
target = LookingAt ( ent , 0 , NULL , NULL ) ;
2020-08-05 01:33:39 +00:00
if ( target & & target - > takedamage & & ( target ! = client - > camplayer ) )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( camera - > vehicle )
2019-03-13 19:20:07 +00:00
{
// Currently following "thing" - turn that off
camera - > monsterinfo . aiflags & = ~ AI_CHASE_THING ;
camera - > movetarget = camera - > goalentity = NULL ;
G_FreeEdict ( camera - > vehicle ) ;
camera - > vehicle = NULL ;
}
camera - > enemy = target ;
actor_fire ( camera ) ;
camera - > enemy = NULL ;
2020-08-05 01:33:39 +00:00
if ( camera - > monsterinfo . aiflags & AI_HOLD_FRAME )
2019-03-13 19:20:07 +00:00
camera - > monsterinfo . attack_finished = level . time + FRAMETIME ;
else
camera - > monsterinfo . attack_finished = level . time + 1.0 ;
}
}
}
}
}
2020-08-05 01:33:39 +00:00
if ( client - > zoomed ) {
2019-03-13 19:20:07 +00:00
camera - > touch_debounce_time =
max ( camera - > touch_debounce_time , level . time + 1.0 ) ;
}
}
VectorMA ( camera - > s . origin , camera - > move_origin [ 0 ] , forward , start ) ;
VectorMA ( start , - camera - > move_origin [ 1 ] , left , start ) ;
VectorMA ( start , camera - > move_origin [ 2 ] , up , start ) ;
tr = gi . trace ( camera - > s . origin , NULL , NULL , start , camera , MASK_SOLID ) ;
2020-08-05 01:33:39 +00:00
if ( tr . fraction < 1.0 )
2019-03-13 19:20:07 +00:00
{
VectorSubtract ( tr . endpos , camera - > s . origin , dir ) ;
dist = VectorNormalize ( dir ) - 2 ;
2020-08-05 01:33:39 +00:00
if ( dist < 0 ) dist = 0. ;
2019-03-13 19:20:07 +00:00
VectorMA ( camera - > s . origin , dist , dir , start ) ;
}
VectorCopy ( start , ent - > s . origin ) ;
VectorCopy ( camera - > velocity , ent - > velocity ) ;
client - > resp . cmd_angles [ 0 ] = SHORT2ANGLE ( client - > ucmd . angles [ 0 ] ) ;
client - > resp . cmd_angles [ 1 ] = SHORT2ANGLE ( client - > ucmd . angles [ 1 ] ) ;
client - > resp . cmd_angles [ 2 ] = SHORT2ANGLE ( client - > ucmd . angles [ 2 ] ) ;
memset ( & pm , 0 , sizeof ( pm ) ) ;
pm . s = client - > ps . pmove ;
for ( i = 0 ; i < 3 ; i + + ) {
pm . s . origin [ i ] = ent - > s . origin [ i ] * 8 ;
client - > ps . pmove . delta_angles [ i ] =
ANGLE2SHORT ( client - > ps . viewangles [ i ] - client - > resp . cmd_angles [ i ] ) ;
}
if ( memcmp ( & client - > old_pmove , & pm . s , sizeof ( pm . s ) ) )
pm . snapinitial = true ;
pm . cmd = client - > ucmd ;
pm . trace = PM_trace ; // adds default parms
pm . pointcontents = gi . pointcontents ;
gi . Pmove ( & pm ) ;
gi . linkentity ( ent ) ;
// client->old_owner_angles[0] = client->ucmd.angles[0];
// client->old_owner_angles[1] = client->ucmd.angles[1];
G_TouchTriggers ( ent ) ; // we'll only allow touching trigger_look with "Cam Owner" SF
}
/*
= = = = = = = = = = = = = =
ClientThink
This will be called once for each client frame , which will
usually be a couple times for each server frame .
= = = = = = = = = = = = = =
*/
void ClientThink ( edict_t * ent , usercmd_t * ucmd )
{
gclient_t * client ;
edict_t * other ;
edict_t * ground ;
pmove_t pm ;
vec_t t ;
//vec3_t view;
vec3_t oldorigin , oldvelocity ;
int i , j ;
float ground_speed ;
// short save_forwardmove;
// Knightmare- dm pause
if ( paused & & deathmatch - > value )
{
safe_centerprintf ( ent , " PAUSED \n \n (type \" sv dmpause \" to resume) " ) ;
ent - > client - > ps . pmove . pm_flags | = PMF_NO_PREDICTION ;
return ;
}
level . current_entity = ent ;
client = ent - > client ;
// Lazarus: Copy latest usercmd stuff for use in other routines
client - > ucmd = * ucmd ;
VectorCopy ( ent - > s . origin , oldorigin ) ;
VectorCopy ( ent - > velocity , oldvelocity ) ;
ground = ent - > groundentity ;
2020-08-05 01:33:39 +00:00
if ( ground & & ( ground - > movetype = = MOVETYPE_PUSH ) & & ( ground ! = world ) & & ground - > turn_rider )
2019-03-13 19:20:07 +00:00
ground_speed = VectorLength ( ground - > velocity ) ;
else
ground_speed = 0 ;
2020-08-05 01:33:39 +00:00
if ( ( ent - > in_mud ) | |
2019-03-13 19:20:07 +00:00
( ent - > client - > push ) | |
( ent - > vehicle ) | |
( ent - > client - > chasetoggle ) | |
( ent - > turret ) | |
( ent - > client - > spycam ) | |
( ground_speed > 0 ) )
ent - > client - > ps . pmove . pm_flags | = PMF_NO_PREDICTION ;
else
ent - > client - > ps . pmove . pm_flags & = ~ PMF_NO_PREDICTION ;
// Server-side speed control stuff
# ifdef KMQUAKE2_ENGINE_MOD
client - > ps . maxspeed = player_max_speed - > value ;
client - > ps . duckspeed = player_crouch_speed - > value ;
client - > ps . accel = player_accel - > value ;
client - > ps . stopspeed = player_stopspeed - > value ;
# endif
2020-08-05 01:33:39 +00:00
if ( client - > startframe = = 0 )
2019-03-13 19:20:07 +00:00
client - > startframe = level . framenum ;
client - > fps_frames + + ;
2020-08-05 01:33:39 +00:00
if ( client - > fps_frames > = 100 ) {
2019-03-13 19:20:07 +00:00
client - > secs_per_frame = ( level . time - client - > fps_time_start ) / 100 ;
client - > fps_frames = 0 ;
client - > fps_time_start = level . time ;
client - > frame_zoomrate = zoomrate - > value * client - > secs_per_frame ;
}
2020-08-05 01:33:39 +00:00
// VectorCopy(ent->s.origin,view);
// view[2] += ent->viewheight;
2019-03-13 19:20:07 +00:00
Fog ( ent ) ; //view);
// MUD - get mud level
if ( level . mud_puddles )
{
edict_t * mud ;
ent - > in_mud = 0 ;
2020-08-05 01:33:39 +00:00
for ( i = game . maxclients + 1 ; i < globals . num_edicts & & ! ent - > in_mud ; i + + )
2019-03-13 19:20:07 +00:00
{
mud = & g_edicts [ i ] ;
2020-08-05 01:33:39 +00:00
if ( ! mud - > inuse ) continue ;
if ( ! ( mud - > svflags & SVF_MUD ) ) continue ;
if ( ent - > absmin [ 0 ] > mud - > absmax [ 0 ] ) continue ;
if ( ent - > absmin [ 1 ] > mud - > absmax [ 1 ] ) continue ;
if ( ent - > absmin [ 2 ] > mud - > absmax [ 2 ] ) continue ;
if ( ent - > absmax [ 0 ] < mud - > absmin [ 0 ] ) continue ;
if ( ent - > absmax [ 1 ] < mud - > absmin [ 1 ] ) continue ;
if ( ent - > absmax [ 2 ] < mud - > absmin [ 2 ] ) continue ;
2019-03-13 19:20:07 +00:00
ent - > in_mud = 1 ;
2020-08-05 01:33:39 +00:00
if ( ent - > s . origin [ 2 ] < mud - > absmax [ 2 ] )
2019-03-13 19:20:07 +00:00
ent - > in_mud = 2 ;
2020-08-05 01:33:39 +00:00
if ( ent - > s . origin [ 2 ] + ent - > viewheight < mud - > absmax [ 2 ] )
2019-03-13 19:20:07 +00:00
ent - > in_mud = 3 ;
}
}
// USE - special actions taken when +use is pressed
if ( ! client - > use & & ( ucmd - > buttons & BUTTON_USE ) )
{
// use key was NOT pressed, but now is
client - > use = 1 ;
if ( client - > spycam )
camera_off ( ent ) ;
else
{
edict_t * viewing ;
vec3_t intersect ;
float range ;
viewing = LookingAt ( ent , 0 , intersect , & range ) ;
2020-08-05 01:33:39 +00:00
if ( viewing & & viewing - > classname )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( ! Q_stricmp ( viewing - > classname , " crane_control " ) & & range < = 100 )
2019-03-13 19:20:07 +00:00
crane_control_action ( viewing , ent , intersect ) ;
2020-08-05 01:33:39 +00:00
if ( ! Q_stricmp ( viewing - > classname , " target_lock_digit " ) & & range < = 100 )
2019-03-13 19:20:07 +00:00
lock_digit_increment ( viewing , ent ) ;
2020-08-05 01:33:39 +00:00
if ( ! Q_stricmp ( viewing - > classname , " func_trainbutton " ) & & ( viewing - > spawnflags & 1 ) & & range < = 64 )
2019-03-13 19:20:07 +00:00
trainbutton_use ( viewing , ent , ent ) ;
// Knightmare- different range for chasecam
2020-08-05 01:33:39 +00:00
if ( ! Q_stricmp ( viewing - > classname , " func_monitor " ) & & ( ( range < = 100 ) | | ( client - > chasetoggle & & range < = client - > zoom + 160.00 ) ) )
2019-03-13 19:20:07 +00:00
{
use_camera ( viewing , ent , ent ) ;
2020-08-05 01:33:39 +00:00
if ( client - > spycam & & client - > spycam - > viewer = = ent )
2019-03-13 19:20:07 +00:00
{
client - > old_owner_angles [ 0 ] = ucmd - > angles [ 0 ] ;
client - > old_owner_angles [ 1 ] = ucmd - > angles [ 1 ] ;
}
}
2020-08-05 01:33:39 +00:00
if ( viewing - > monsterinfo . aiflags & AI_ACTOR )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( viewing - > monsterinfo . aiflags & AI_FOLLOW_LEADER )
2019-03-13 19:20:07 +00:00
{
viewing - > monsterinfo . aiflags & = ~ AI_FOLLOW_LEADER ;
viewing - > monsterinfo . old_leader = NULL ;
viewing - > monsterinfo . leader = NULL ;
viewing - > movetarget = viewing - > goalentity = NULL ;
viewing - > monsterinfo . stand ( viewing ) ;
}
else
{
vec3_t dir ;
viewing - > monsterinfo . aiflags | = AI_FOLLOW_LEADER ;
viewing - > monsterinfo . leader = ent ;
VectorSubtract ( ent - > s . origin , viewing - > s . origin , dir ) ;
viewing - > ideal_yaw = vectoyaw ( dir ) ;
2020-08-05 01:33:39 +00:00
if ( fabs ( viewing - > s . angles [ YAW ] - viewing - > ideal_yaw ) < 90 )
2019-03-13 19:20:07 +00:00
actor_salute ( viewing ) ;
}
}
}
}
}
2020-08-05 01:33:39 +00:00
if ( ucmd - > buttons & BUTTON_USE )
2019-03-13 19:20:07 +00:00
client - > use = 1 ;
else
client - > use = 0 ;
if ( client - > push )
{
// currently pushing or pulling a func_pushable
2020-08-05 01:33:39 +00:00
if ( ! client - > use )
2019-03-13 19:20:07 +00:00
{
// whoops - released USE key
RemovePush ( ent ) ;
}
2020-08-05 01:33:39 +00:00
else if ( ( ! ent - > groundentity ) & & ( ent - > waterlevel = = 0 | | client - > push - > waterlevel = = 0 ) )
2019-03-13 19:20:07 +00:00
{
// oops, we fall down
RemovePush ( ent ) ;
}
else
{
// Scale client velocity by mass of func_pushable
t = VectorLength ( ent - > velocity ) ;
2020-08-05 01:33:39 +00:00
if ( t > client - > maxvelocity )
2019-03-13 19:20:07 +00:00
VectorScale ( ent - > velocity , client - > maxvelocity / t , ent - > velocity ) ;
client - > ps . pmove . pm_flags | = PMF_NO_PREDICTION ;
t = 200. / client - > push - > mass ;
ucmd - > forwardmove * = t ;
ucmd - > sidemove * = t ;
}
}
2020-08-05 01:33:39 +00:00
if ( ent - > turret & & ucmd - > upmove > 10 )
2019-03-13 19:20:07 +00:00
turret_disengage ( ent - > turret ) ;
// INTERMISSION
if ( level . intermissiontime )
{
// tpp
if ( client - > chasetoggle )
ChasecamRemove ( ent , OPTION_OFF ) ;
// end tpp
// Lazarus spycam
if ( client - > spycam )
camera_off ( ent ) ;
client - > ps . pmove . pm_type = PM_FREEZE ;
// can exit intermission after five seconds
if ( level . time > level . intermissiontime + 5.0
& & ( ucmd - > buttons & BUTTON_ANY ) )
level . exitintermission = true ;
return ;
}
if ( ent - > target_ent & & ! Q_stricmp ( ent - > target_ent - > classname , " target_monitor " ) )
{
edict_t * monitor = ent - > target_ent ;
2020-08-05 01:33:39 +00:00
if ( monitor - > target_ent & & monitor - > target_ent - > inuse )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( monitor - > spawnflags & 2 )
2019-03-13 19:20:07 +00:00
VectorCopy ( monitor - > target_ent - > s . angles , client - > ps . viewangles ) ;
else
{
vec3_t dir ;
VectorSubtract ( monitor - > target_ent - > s . origin , monitor - > s . origin , dir ) ;
vectoangles ( dir , client - > ps . viewangles ) ;
}
}
else
VectorCopy ( monitor - > s . angles , client - > ps . viewangles ) ;
VectorCopy ( monitor - > s . origin , ent - > s . origin ) ;
client - > ps . pmove . pm_type = PM_FREEZE ;
return ;
}
// THIRDPERSON VIEW in/out
// if NOT pushing something AND in third person AND use key is pressed,
// move viewpoint in/out
if ( client - > chasetoggle & & ! client - > push )
{
// Knigthtmare- and if not about to push something or infront of func_monitor
edict_t * viewing ;
vec3_t intersect ;
float range ;
viewing = LookingAt ( ent , 0 , intersect , & range ) ;
if ( ! ( viewing & & viewing - > classname
& & ( Q_stricmp ( viewing - > classname , " func_monitor " ) | | Q_stricmp ( viewing - > classname , " func_pushable " ) )
& & range < = 100 ) )
{
if ( ( ucmd - > buttons & BUTTON_USE ) & & ( ! deathmatch - > value ) )
{
client - > use = 1 ;
if ( ( ucmd - > forwardmove < 0 ) & & ( client - > zoom < 100 ) )
client - > zoom + + ;
else if ( ( ucmd - > forwardmove > 0 ) & & ( client - > zoom > - 40 ) )
client - > zoom - - ;
ucmd - > forwardmove = 0 ;
ucmd - > sidemove = 0 ;
}
else if ( client - > use )
{
//client->zoom = 0;
if ( client - > oldplayer )
{
// set angles
for ( i = 0 ; i < 3 ; i + + )
{
ent - > client - > ps . pmove . delta_angles [ i ] = ANGLE2SHORT ( ent - > client - > oldplayer - > s . angles [ i ] - ent - > client - > resp . cmd_angles [ i ] ) ;
}
}
client - > use = 0 ;
}
}
}
// ZOOM
if ( client - > zooming ) {
client - > pers . hand = 2 ;
2020-08-05 01:33:39 +00:00
if ( client - > zooming > 0 ) {
if ( client - > ps . fov > 5 ) {
2019-03-13 19:20:07 +00:00
client - > ps . fov - = client - > frame_zoomrate ;
2020-08-05 01:33:39 +00:00
if ( client - > ps . fov < 5 )
2019-03-13 19:20:07 +00:00
client - > ps . fov = 5 ;
} else {
client - > ps . fov = 5 ;
}
client - > zoomed = true ;
} else {
2020-08-05 01:33:39 +00:00
if ( client - > ps . fov < client - > original_fov ) {
2019-03-13 19:20:07 +00:00
client - > ps . fov + = client - > frame_zoomrate ;
2020-08-05 01:33:39 +00:00
if ( client - > ps . fov > client - > original_fov ) {
2019-03-13 19:20:07 +00:00
client - > ps . fov = client - > original_fov ;
client - > zoomed = false ;
} else
client - > zoomed = true ;
} else {
client - > ps . fov = client - > original_fov ;
client - > zoomed = false ;
}
}
}
// SPYCAM
if ( client - > spycam ) {
ClientSpycam ( ent ) ;
return ; // no movement while in cam
} // END SPYCAM
pm_passent = ent ;
// Lazarus: developer item movement
2020-08-05 01:33:39 +00:00
if ( client - > use & & client - > shift_dir )
2019-03-13 19:20:07 +00:00
ShiftItem ( ent , client - > shift_dir ) ;
if ( client - > chase_target ) {
client - > resp . cmd_angles [ 0 ] = SHORT2ANGLE ( ucmd - > angles [ 0 ] ) ;
client - > resp . cmd_angles [ 1 ] = SHORT2ANGLE ( ucmd - > angles [ 1 ] ) ;
client - > resp . cmd_angles [ 2 ] = SHORT2ANGLE ( ucmd - > angles [ 2 ] ) ;
} else {
// set up for pmove
memset ( & pm , 0 , sizeof ( pm ) ) ;
if ( ent - > movetype = = MOVETYPE_NOCLIP )
client - > ps . pmove . pm_type = PM_SPECTATOR ;
else if ( ent - > s . modelindex ! = MAX_MODELS - 1 )
client - > ps . pmove . pm_type = PM_GIB ;
else if ( ent - > deadflag )
client - > ps . pmove . pm_type = PM_DEAD ;
else
client - > ps . pmove . pm_type = PM_NORMAL ;
2020-08-05 01:33:39 +00:00
if ( level . time > ent - > gravity_debounce_time )
2019-03-13 19:20:07 +00:00
client - > ps . pmove . gravity = sv_gravity - > value ;
else
client - > ps . pmove . gravity = 0 ;
# ifdef JETPACK_MOD
if ( client - > jetpack )
{
2020-08-05 01:33:39 +00:00
if ( ( ucmd - > upmove ! = 0 ) | | ( ucmd - > forwardmove ! = 0 ) | | ( ucmd - > sidemove ! = 0 ) )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( ucmd - > upmove > 0 | | ! ent - > groundentity )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( ! client - > jetpack_thrusting )
2019-03-13 19:20:07 +00:00
{
gi . sound ( ent , CHAN_AUTO , gi . soundindex ( " jetpack/rev.wav " ) , 1 , ATTN_NORM , 0 ) ;
client - > jetpack_start_thrust = level . framenum ;
}
client - > jetpack_thrusting = true ;
}
else
client - > jetpack_thrusting = false ;
}
else
client - > jetpack_thrusting = false ;
2020-08-05 01:33:39 +00:00
if ( client - > jetpack_framenum + client - > pers . inventory [ fuel_index ] > level . framenum )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( jetpack_weenie - > value )
2019-03-13 19:20:07 +00:00
{
Jet_ApplyJet ( ent , ucmd ) ;
2020-08-05 01:33:39 +00:00
if ( client - > jetpack_framenum < level . framenum )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( ! client - > jetpack_infinite )
2019-03-13 19:20:07 +00:00
client - > pers . inventory [ fuel_index ] - = 10 ;
client - > jetpack_framenum = level . framenum + 10 ;
}
}
else
{
2020-08-05 01:33:39 +00:00
if ( client - > jetpack_thrusting )
2019-03-13 19:20:07 +00:00
Jet_ApplyJet ( ent , ucmd ) ;
2020-08-05 01:33:39 +00:00
if ( client - > jetpack_framenum < = level . framenum )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( client - > jetpack_thrusting )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( ! client - > jetpack_infinite )
2019-03-13 19:20:07 +00:00
client - > pers . inventory [ fuel_index ] - = 11 ;
client - > jetpack_framenum = level . framenum + 10 ;
}
else
{
2020-08-05 01:33:39 +00:00
if ( ! client - > jetpack_infinite )
2019-03-13 19:20:07 +00:00
client - > pers . inventory [ fuel_index ] - - ;
client - > jetpack_framenum = level . framenum + 10 ;
}
}
2020-08-05 01:33:39 +00:00
if ( ucmd - > upmove = = 0 )
2019-03-13 19:20:07 +00:00
{
// accelerate to 75% gravity in 2 seconds
float gravity ;
float g_max = 0.75 * sv_gravity - > value ;
gravity = g_max * ( level . framenum - client - > jetpack_last_thrust ) / 20 ;
2020-08-05 01:33:39 +00:00
if ( gravity > g_max ) gravity = g_max ;
2019-03-13 19:20:07 +00:00
client - > ps . pmove . gravity = ( short ) gravity ;
}
else
client - > jetpack_last_thrust = level . framenum ;
}
}
else
{
client - > jetpack = false ;
ent - > s . frame = FRAME_jump2 ; // reset from stand to avoid goofiness
}
}
# endif // #ifdef JETPACK_MOD
pm . s = client - > ps . pmove ;
for ( i = 0 ; i < 3 ; i + + )
{
pm . s . origin [ i ] = ent - > s . origin [ i ] * 8 ;
2020-04-20 07:17:27 +00:00
// FIXME: make sure this short doesn't overflow
2019-03-13 19:20:07 +00:00
pm . s . velocity [ i ] = ent - > velocity [ i ] * 8 ;
}
if ( memcmp ( & client - > old_pmove , & pm . s , sizeof ( pm . s ) ) )
{
pm . snapinitial = true ;
// gi.dprintf ("pmove changed!\n");
}
pm . cmd = * ucmd ;
pm . trace = PM_trace ; // adds default parms
pm . pointcontents = gi . pointcontents ;
2020-08-05 01:33:39 +00:00
if ( ent - > vehicle )
2019-03-13 19:20:07 +00:00
pm . s . pm_flags | = PMF_ON_GROUND ;
// perform a pmove
gi . Pmove ( & pm ) ;
// save results of pmove
client - > ps . pmove = pm . s ;
client - > old_pmove = pm . s ;
for ( i = 0 ; i < 3 ; i + + )
{
ent - > s . origin [ i ] = pm . s . origin [ i ] * 0.125 ;
ent - > velocity [ i ] = pm . s . velocity [ i ] * 0.125 ;
}
VectorCopy ( pm . mins , ent - > mins ) ;
VectorCopy ( pm . maxs , ent - > maxs ) ;
client - > resp . cmd_angles [ 0 ] = SHORT2ANGLE ( ucmd - > angles [ 0 ] ) ;
client - > resp . cmd_angles [ 1 ] = SHORT2ANGLE ( ucmd - > angles [ 1 ] ) ;
client - > resp . cmd_angles [ 2 ] = SHORT2ANGLE ( ucmd - > angles [ 2 ] ) ;
# ifdef JETPACK_MOD
if ( client - > jetpack & & jetpack_weenie - > value )
{
2020-08-05 01:33:39 +00:00
if ( pm . groundentity ) // are we on ground
2019-03-13 19:20:07 +00:00
if ( Jet_AvoidGround ( ent ) ) // then lift us if possible
pm . groundentity = NULL ; // now we are no longer on ground
}
# endif
// MUD - "correct" Pmove physics
if ( pm . waterlevel & & ent - > in_mud )
{
vec3_t point ;
vec3_t end ;
vec3_t deltapos , deltavel ;
float frac ;
pm . watertype | = CONTENTS_MUD ;
ent - > in_mud = pm . waterlevel ;
VectorSubtract ( ent - > s . origin , oldorigin , deltapos ) ;
VectorSubtract ( ent - > velocity , oldvelocity , deltavel ) ;
if ( pm . waterlevel = = 1 )
{
frac = MUD1BASE + MUD1AMP * sin ( ( float ) ( level . framenum % 10 ) / 10. * 2 * M_PI ) ;
ent - > s . origin [ 0 ] = oldorigin [ 0 ] + frac * deltapos [ 0 ] ;
ent - > s . origin [ 1 ] = oldorigin [ 1 ] + frac * deltapos [ 1 ] ;
ent - > s . origin [ 2 ] = oldorigin [ 2 ] + 0.75 * deltapos [ 2 ] ;
ent - > velocity [ 0 ] = oldvelocity [ 0 ] + frac * deltavel [ 0 ] ;
ent - > velocity [ 1 ] = oldvelocity [ 1 ] + frac * deltavel [ 1 ] ;
ent - > velocity [ 2 ] = oldvelocity [ 2 ] + 0.75 * deltavel [ 2 ] ;
}
else if ( pm . waterlevel = = 2 )
{
trace_t tr ;
float dist ;
VectorCopy ( oldorigin , point ) ;
point [ 2 ] + = ent - > maxs [ 2 ] ;
end [ 0 ] = point [ 0 ] ; end [ 1 ] = point [ 1 ] ; end [ 2 ] = oldorigin [ 2 ] + ent - > mins [ 2 ] ;
tr = gi . trace ( point , NULL , NULL , end , ent , CONTENTS_WATER ) ;
dist = point [ 2 ] - tr . endpos [ 2 ] ;
// frac = waterlevel 1 frac at dist=32 or more,
// = waterlevel 3 frac at dist=10 or less
2020-08-05 01:33:39 +00:00
if ( dist < = 10 )
2019-03-13 19:20:07 +00:00
frac = MUD3 ;
else
frac = MUD3 + ( dist - 10 ) / 22. * ( MUD1BASE - MUD3 ) ;
ent - > s . origin [ 0 ] = oldorigin [ 0 ] + frac * deltapos [ 0 ] ;
ent - > s . origin [ 1 ] = oldorigin [ 1 ] + frac * deltapos [ 1 ] ;
ent - > s . origin [ 2 ] = oldorigin [ 2 ] + frac * deltapos [ 2 ] ;
ent - > velocity [ 0 ] = oldvelocity [ 0 ] + frac * deltavel [ 0 ] ;
ent - > velocity [ 1 ] = oldvelocity [ 1 ] + frac * deltavel [ 1 ] ;
ent - > velocity [ 2 ] = oldvelocity [ 2 ] + frac * deltavel [ 2 ] ;
if ( ! ent - > groundentity )
{
// Player can't possibly move up
ent - > s . origin [ 2 ] = min ( oldorigin [ 2 ] , ent - > s . origin [ 2 ] ) ;
ent - > velocity [ 2 ] = min ( oldvelocity [ 2 ] , ent - > velocity [ 2 ] ) ;
ent - > velocity [ 2 ] = min ( - 10 , ent - > velocity [ 2 ] ) ;
}
}
else
{
ent - > s . origin [ 0 ] = oldorigin [ 0 ] + MUD3 * deltapos [ 0 ] ;
ent - > s . origin [ 1 ] = oldorigin [ 1 ] + MUD3 * deltapos [ 1 ] ;
ent - > velocity [ 0 ] = oldvelocity [ 0 ] + MUD3 * deltavel [ 0 ] ;
ent - > velocity [ 1 ] = oldvelocity [ 1 ] + MUD3 * deltavel [ 1 ] ;
if ( ent - > groundentity )
{
ent - > s . origin [ 2 ] = oldorigin [ 2 ] + MUD3 * deltapos [ 2 ] ;
ent - > velocity [ 2 ] = oldvelocity [ 2 ] + MUD3 * deltavel [ 2 ] ;
}
else
{
ent - > s . origin [ 2 ] = min ( oldorigin [ 2 ] , ent - > s . origin [ 2 ] ) ;
ent - > velocity [ 2 ] = min ( oldvelocity [ 2 ] , 0 ) ;
}
}
}
else
ent - > in_mud = 0 ;
// end MUD
if ( ent - > groundentity & & ! pm . groundentity & & ( pm . cmd . upmove > = 10 ) & & ( pm . waterlevel = = 0 ) & & ! client - > jetpack )
{ // Knightmare- allow disabling of STUPID grunting when jumping
if ( ( deathmatch - > value | | player_jump_sounds - > value ) & & ! ent - > vehicle )
{
gi . sound ( ent , CHAN_VOICE , gi . soundindex ( " *jump1.wav " ) , 1 , ATTN_NORM , 0 ) ;
PlayerNoise ( ent , ent - > s . origin , PNOISE_SELF ) ;
}
// Paril's vehicle targeting
if ( ent - > vehicle )
G_UseTargets ( ent - > vehicle , ent ) ;
// Lazarus: temporarily match velocities with entity we just
// jumped from
VectorAdd ( ent - > groundentity - > velocity , ent - > velocity , ent - > velocity ) ;
}
if ( ent - > groundentity & & ! pm . groundentity & & ( pm . cmd . upmove > = 10 ) & & ( pm . waterlevel = = 0 ) )
ent - > client - > jumping = 1 ;
if ( ent - > deadflag ! = DEAD_FROZEN )
ent - > viewheight = pm . viewheight ;
ent - > waterlevel = pm . waterlevel ;
ent - > watertype = pm . watertype ;
ent - > groundentity = pm . groundentity ;
if ( pm . groundentity )
ent - > groundentity_linkcount = pm . groundentity - > linkcount ;
// Lazarus - lie about ground when driving a vehicle.
// Pmove apparently doesn't think the ground
// can be "owned"
if ( ent - > vehicle & & ! ent - > groundentity )
{
ent - > groundentity = ent - > vehicle ;
ent - > groundentity_linkcount = ent - > vehicle - > linkcount ;
}
if ( ent - > deadflag )
{
if ( ent - > deadflag ! = DEAD_FROZEN )
{
client - > ps . viewangles [ ROLL ] = 40 ;
client - > ps . viewangles [ PITCH ] = - 15 ;
client - > ps . viewangles [ YAW ] = client - > killer_yaw ;
}
}
else
{
VectorCopy ( pm . viewangles , client - > v_angle ) ;
VectorCopy ( pm . viewangles , client - > ps . viewangles ) ;
}
# ifdef JETPACK_MOD
if ( client - > jetpack & & ! ( ucmd - > buttons & BUTTONS_ATTACK ) )
ent - > s . frame = FRAME_stand20 ;
# endif
//ZOID
if ( client - > ctf_grapple )
CTFGrapplePull ( client - > ctf_grapple ) ;
//ZOID
gi . linkentity ( ent ) ;
if ( ent - > movetype ! = MOVETYPE_NOCLIP )
G_TouchTriggers ( ent ) ;
2020-08-05 01:33:39 +00:00
if ( ( world - > effects & FX_WORLDSPAWN_JUMPKICK ) & & ( ent - > client - > jumping ) & & ( ent - > solid ! = SOLID_NOT ) )
2019-03-13 19:20:07 +00:00
kick_attack ( ent ) ;
// touch other objects
// Lazarus: but NOT if game is frozen
2020-08-05 01:33:39 +00:00
if ( ! level . freeze )
2019-03-13 19:20:07 +00:00
{
for ( i = 0 ; i < pm . numtouch ; i + + )
{
other = pm . touchents [ i ] ;
for ( j = 0 ; j < i ; j + + )
if ( pm . touchents [ j ] = = other )
break ;
if ( j ! = i )
continue ; // duplicated
if ( ! other - > touch )
continue ;
other - > touch ( other , ent , NULL , NULL ) ;
}
}
}
client - > oldbuttons = client - > buttons ;
client - > buttons = ucmd - > buttons ;
client - > latched_buttons | = client - > buttons & ~ client - > oldbuttons ;
// save light level the player is standing on for
// monster sighting AI
ent - > light_level = ucmd - > lightlevel ;
// CDawg - add here!
if ( ucmd - > forwardmove < - 1 )
ent - > client - > backpedaling = true ;
else
ent - > client - > backpedaling = false ;
// CDawg end here!
// fire weapon from final position if needed
if ( client - > latched_buttons & BUTTONS_ATTACK
//ZOID
& & ! ( ctf - > value & & ent - > movetype = = MOVETYPE_NOCLIP ) )
//ZOID
{
if ( client - > resp . spectator ) {
client - > latched_buttons = 0 ;
if ( client - > chase_target ) {
client - > chase_target = NULL ;
client - > ps . pmove . pm_flags & = ~ PMF_NO_PREDICTION ;
} else
GetChaseTarget ( ent ) ;
} else if ( ! client - > weapon_thunk ) {
client - > weapon_thunk = true ;
Think_Weapon ( ent ) ;
}
}
// ACEBOT_ADD
if ( ! ent - > is_bot & & ! ent - > deadflag & & ! ent - > client - > resp . spectator )
ACEND_PathMap ( ent ) ;
// ACEBOT_END
if ( client - > resp . spectator ) {
if ( ucmd - > upmove > = 10 ) {
if ( ! ( client - > ps . pmove . pm_flags & PMF_JUMP_HELD ) ) {
client - > ps . pmove . pm_flags | = PMF_JUMP_HELD ;
if ( client - > chase_target )
ChaseNext ( ent ) ;
else
GetChaseTarget ( ent ) ;
}
} else
client - > ps . pmove . pm_flags & = ~ PMF_JUMP_HELD ;
}
//ZOID
//regen tech
CTFApplyRegeneration ( ent ) ;
//ZOID
// update chase cam if being followed
for ( i = 1 ; i < = maxclients - > value ; i + + ) {
other = g_edicts + i ;
if ( other - > inuse & & other - > client - > chase_target = = ent )
UpdateChaseCam ( other ) ;
}
2020-08-05 01:33:39 +00:00
if ( client - > push ! = NULL )
2019-03-13 19:20:07 +00:00
{
2020-08-05 01:33:39 +00:00
if ( client - > use & &
2019-03-13 19:20:07 +00:00
( ( ucmd - > forwardmove ! = 0 ) | | ( ucmd - > sidemove ! = 0 ) ) )
ClientPushPushable ( ent ) ;
else
client - > push - > s . sound = 0 ;
}
}
/*
= = = = = = = = = = = = = =
ClientBeginServerFrame
This will be called once for each server frame , before running
any other entities in the world .
= = = = = = = = = = = = = =
*/
void ClientBeginServerFrame ( edict_t * ent )
{
gclient_t * client ;
int buttonMask ;
if ( level . intermissiontime )
return ;
client = ent - > client ;
// DWH
2020-08-05 01:33:39 +00:00
if ( client - > spycam )
2019-03-13 19:20:07 +00:00
client = client - > camplayer - > client ;
// tpp
if ( client - > delayedstart > 0 )
client - > delayedstart - - ;
if ( client - > delayedstart = = 1 )
ChasecamStart ( ent ) ;
// end tpp
if ( deathmatch - > value & &
client - > pers . spectator ! = client - > resp . spectator & &
( level . time - client - > respawn_time ) > = 5 ) {
spectator_respawn ( ent ) ;
return ;
}
// run weapon animations if it hasn't been done by a ucmd_t
if ( ! client - > weapon_thunk & & ! client - > resp . spectator
//ZOID
& & ! ( ctf - > value & & ent - > movetype = = MOVETYPE_NOCLIP ) )
//ZOID
Think_Weapon ( ent ) ;
else
client - > weapon_thunk = false ;
if ( ent - > deadflag )
{
// wait for any button just going down
if ( level . time > client - > respawn_time )
{
// tpp
if ( ent - > crosshair )
G_FreeEdict ( ent - > crosshair ) ;
ent - > crosshair = NULL ;
if ( ent - > client - > oldplayer )
G_FreeEdict ( ent - > client - > oldplayer ) ;
ent - > client - > oldplayer = NULL ;
if ( ent - > client - > chasecam )
G_FreeEdict ( ent - > client - > chasecam ) ;
ent - > client - > chasecam = NULL ;
// end tpp
// in deathmatch, only wait for attack button
if ( deathmatch - > value )
buttonMask = BUTTONS_ATTACK ;
else
buttonMask = - 1 ;
if ( ( client - > latched_buttons & buttonMask ) | |
( deathmatch - > value & & ( ( int ) dmflags - > value & DF_FORCE_RESPAWN ) ) )
{
respawn ( ent ) ;
client - > latched_buttons = 0 ;
}
}
return ;
}
// add player trail so monsters can follow
// DWH: Don't add player trail for players in camera
if ( ! deathmatch - > value & & ! client - > spycam )
if ( ! visible ( ent , PlayerTrail_LastSpot ( ) ) )
PlayerTrail_Add ( ent - > s . old_origin ) ;
client - > latched_buttons = 0 ;
}