djcev.com

//

Git Repos / fte_dogmode / qc / monsters / playerclient.qc

Last update to this file was on 2024-04-12 at 18:56.

Show playerclient.qc

//==============================================================================
// client / player
//==============================================================================

//======================================================================
// constants
//======================================================================

const float PLAYER_HEALTH = 100; // id1 100

const vector PLAYER_HEAD_MINS = '-9.67 -12.38 -2.1';
const vector PLAYER_HEAD_MAXS = '11.49 50.7 30';

//======================================================================
// globals
//======================================================================

float modelindex_eyes;
float modelindex_player;

//======================================================================
// fields
//======================================================================

.float axhitme;
.float fly_sound;
.float jump_flag; // player jump flag
.float reset_items; // dumptruck_ds
.float swim_flag; // player swimming sound flag

.float air_finished; // when time > air_finished, drown
.float attack_finished;
.float pain_finished;
.float invincible_finished;
.float invisible_finished;
.float super_damage_finished;
.float radsuit_finished;

.float damage_time;
.float invincible_time, invincible_sound;
.float invisible_time, invisible_sound;
.float super_time, super_sound;
.float rad_time;
.float megahealth_rottime; // dumptruck_ds

.float step_time; // CEV

// set to time+0.2 whenever a client fires a weapon or takes damage.
// Used to alert monsters that otherwise would let the player go
.float show_hostile;

.string deathtype; // keeps track of how the player died

#ifdef SSQC
// DP_INPUTBUTTONS (in qw we set 1 to equal 3 to match zquake/fuhquake/mvdsv)
.float button3;
.float button4;
.float button5;
.float button6;
.float button7;
.float button8;
#endif

//======================================================================
// forward declarations
//======================================================================

// player
void() player_impulse_cheat; // impulse commands
void() player_impulse_quadcheat;
void() player_impulse_serverflags;
void() player_impulse_changeweapon;
void() player_impulse_cycleweapon;
void() player_impulse_cycleweaponreverse;
void() player_impulse;
void() player_superdamage_sound;
void() player_set_current_ammo; // ammo, weapon firing, attacks
float() player_best_weapon;
float() player_check_no_ammo;
void() player_fire_axe;
void() player_fire_shotgun;
void() player_fire_supershotgun;
void(float offset) player_fire_spikes;
void() player_fire_superspikes;
void() player_fire_grenade;
void() player_fire_rocket;
void() player_fire_lightning;
void() player_attack;
void() player_set_suicide_frame; // pain, damage, death
void() player_pain_sound;
void() player_death_sound;
void() player_dead;
void() player_footsteps; // thinking & animation frames
void() player_stand;
void() player_axstand;
void(void() axthink) player_run;
void(void() runthink) player_axrun;
void() pl_axstnd1; void() pl_axstnd2; void() pl_axstnd3; void() pl_axstnd4;
void() pl_axstnd5; void() pl_axstnd6; void() pl_axstnd7; void() pl_axstnd8;
void() pl_axstnd9; void() pl_axstnd10; void() pl_axstnd11; void() pl_axstnd12;
void() pl_stand1; void() pl_stand2; void() pl_stand3; void() pl_stand4;
void() pl_stand5;
void() pl_run1; void() pl_run2; void() pl_run3; void() pl_run4;
void() pl_run5; void() pl_run6;
void() pl_shot1; void() pl_shot2; void() pl_shot3; void() pl_shot4;
void() pl_shot5; void() pl_shot6;
void() pl_axe1; void() pl_axe2; void() pl_axe3; void() pl_axe4;
void() pl_axeb1; void() pl_axeb2; void() pl_axeb3; void() pl_axeb4;
void() pl_axec1; void() pl_axec2; void() pl_axec3; void() pl_axec4;
void() pl_axed1; void() pl_axed2; void() pl_axed3; void() pl_axed4;
void() pl_nail1; void() pl_nail2;
void() pl_light1; void() pl_light2;
void() pl_rocket1; void() pl_rocket2; void() pl_rocket3;
void() pl_rocket4; void() pl_rocket5; void() pl_rocket6;
void() pl_pain1; void() pl_pain2; void() pl_pain3;
void() pl_pain4; void() pl_pain5; void() pl_pain6;
void() pl_axpain1; void() pl_axpain2; void() pl_axpain3;
void() pl_axpain4; void() pl_axpain5; void() pl_axpain6;
void() pl_diea1; void() pl_diea2; void() pl_diea3; void() pl_diea4;
void() pl_diea5; void() pl_diea6; void() pl_diea7; void() pl_diea8;
void() pl_diea9; void() pl_diea10; void() pl_diea11;
void() pl_dieb1; void() pl_dieb2; void() pl_dieb3; void() pl_dieb4;
void() pl_dieb5; void() pl_dieb6; void() pl_dieb7; void() pl_dieb8;
void() pl_dieb9;
void() pl_diec1; void() pl_diec2; void() pl_diec3; void() pl_diec4;
void() pl_diec5; void() pl_diec6; void() pl_diec7; void() pl_diec8;
void() pl_diec9; void() pl_diec10; void() pl_diec11; void() pl_diec12;
void() pl_diec13; void() pl_diec14; void() pl_diec15;
void() pl_died1; void() pl_died2; void() pl_died3; void() pl_died4;
void() pl_died5; void() pl_died6; void() pl_died7; void() pl_died8;
void() pl_died9;
void() pl_diee1; void() pl_diee2; void() pl_diee3; void() pl_diee4;
void() pl_diee5; void() pl_diee6; void() pl_diee7; void() pl_diee8;
void() pl_diee9;
void() player_death_think;
void() player_prethink_watermove;
void() player_prethink_waterjump;
void() player_prethink_jump;
void() player_prethink;
void() player_postthink_powerups;
void() player_postthink;
float(entity to, float fl) player_sendentity; // object interaction
void(entity attacker, float damage) player_pain;
void(vector dir) player_destroy_gib;
void(vector dir) player_destroy;
void() player_touch;
entity() player_init_selectspawnpoint; // initialization
void() player_init_level_parms;
void() player_respawn;
void(entity e) player_init;
strip void() player;

// gib_head_player
void(entity act, vector dir, float dmg) throw_gib_head_player;
void(entity e) gib_head_player_init;
void() gib_head_player;

// player_dead_axe
void() player_dead_axe;

// player_dead_face_down
void() player_dead_face_down;

// player_dead_on_side
void() player_dead_on_side;

//======================================================================
// frame macros
//======================================================================

$cd id1/models/player_4
$origin 0 -6 24
$base base
$skin skin

$frame axrun1 axrun2 axrun3 axrun4 axrun5 axrun6

$frame rockrun1 rockrun2 rockrun3 rockrun4 rockrun5 rockrun6

$frame stand1 stand2 stand3 stand4 stand5

$frame axstnd1 axstnd2 axstnd3 axstnd4 axstnd5 axstnd6
$frame axstnd7 axstnd8 axstnd9 axstnd10 axstnd11 axstnd12

$frame axpain1 axpain2 axpain3 axpain4 axpain5 axpain6

$frame pain1 pain2 pain3 pain4 pain5 pain6

$frame axdeth1 axdeth2 axdeth3 axdeth4 axdeth5 axdeth6
$frame axdeth7 axdeth8 axdeth9

$frame deatha1 deatha2 deatha3 deatha4 deatha5 deatha6 deatha7 deatha8
$frame deatha9 deatha10 deatha11
$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8
$frame deathb9
$frame deathc1 deathc2 deathc3 deathc4 deathc5 deathc6 deathc7 deathc8
$frame deathc9 deathc10 deathc11 deathc12 deathc13 deathc14 deathc15
$frame deathd1 deathd2 deathd3 deathd4 deathd5 deathd6 deathd7
$frame deathd8 deathd9
$frame deathe1 deathe2 deathe3 deathe4 deathe5 deathe6 deathe7
$frame deathe8 deathe9

$frame nailatt1 nailatt2

$frame light1 light2

$frame rockatt1 rockatt2 rockatt3 rockatt4 rockatt5 rockatt6

$frame shotatt1 shotatt2 shotatt3 shotatt4 shotatt5 shotatt6

$frame axatt1 axatt2 axatt3 axatt4 axatt5 axatt6
$frame axattb1 axattb2 axattb3 axattb4 axattb5 axattb6
$frame axattc1 axattc2 axattc3 axattc4 axattc5 axattc6
$frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6

//------------------------------------------------------------------------------

//----------------------------------------------------------------------
// Player Class: spawn functions, animation, client handling, etc. -- CEV
//----------------------------------------------------------------------
// class player: entity
// {
//==============================================================
// Client Input Handling
//==============================================================

//--------------------------------------------------------------
// CheatCommand
//--------------------------------------------------------------
void() player_impulse_cheat =
{
// 1998-07-29 Cheats coop fix by Maddes start
// if (deathmatch || coop)
if (deathmatch)
// 1998-07-29 Cheats coop fix by Maddes end
return;

self.ammo_cells = 200;
self.ammo_nails = 200;
self.ammo_rockets = 100;
self.ammo_shells = 100;
self.items = self.items | IT_AXE | IT_SHOTGUN |
IT_SUPER_SHOTGUN | IT_NAILGUN | IT_SUPER_NAILGUN |
IT_GRENADE_LAUNCHER | IT_ROCKET_LAUNCHER | IT_LIGHTNING;

// support for item_key_custom -- iw
base_item_key_giveallkeys (self);

self.weapon = IT_ROCKET_LAUNCHER;
self.impulse = 0;
player_set_current_ammo ();
};

//--------------------------------------------------------------
void() player_impulse_quadcheat =
{
// 1998-07-29 Cheats coop fix by Maddes start
// if (deathmatch || coop)
if (deathmatch)
// 1998-07-29 Cheats coop fix by Maddes end
return;

self.super_time = 1;
self.super_damage_finished = time + 30;
self.items = self.items | IT_QUAD;
dprint ("player::quad_cheat: quad damage\n");
};

//--------------------------------------------------------------
// ServerflagsCommand -- Just for development
//--------------------------------------------------------------
void() player_impulse_serverflags =
{
// 1998-07-29 Cheats coop fix by Maddes start
if (deathmatch)
return;
// 1998-07-29 Cheats coop fix by Maddes end

serverflags = serverflags * 2 + 1;
};

//--------------------------------------------------------------
// ChangeWeaponCommand -- was W_ChangeWeapon
//--------------------------------------------------------------
void() player_impulse_changeweapon =
{
local float it, haveammo, fl;

// assign fl to silence a warning -- CEV
fl = IT_AXE;
it = self.items;
haveammo = TRUE;

switch (self.impulse)
{
case 1:
fl = IT_AXE;
break;
case 2:
fl = IT_SHOTGUN;
if (self.ammo_shells < 1)
haveammo = FALSE;
break;
case 3:
fl = IT_SUPER_SHOTGUN;
if (self.ammo_shells < 2)
haveammo = FALSE;
break;
case 4:
fl = IT_NAILGUN;
if (self.ammo_nails < 1)
haveammo = FALSE;
break;
case 5:
fl = IT_SUPER_NAILGUN;
if (self.ammo_nails < 2)
haveammo = FALSE;
break;
case 6:
fl = IT_GRENADE_LAUNCHER;
if (self.ammo_rockets < 1)
haveammo = FALSE;
break;
case 7:
fl = IT_ROCKET_LAUNCHER;
if (self.ammo_rockets < 1)
haveammo = FALSE;
break;
case 8:
fl = IT_LIGHTNING;
if (self.ammo_cells < 1)
haveammo = FALSE;
break;
default:
dprint (sprintf("player::change_weapon: WARNING"
" bad impulse: %f\n", self.impulse));
return;
}

self.impulse = 0;

if (!(self.items & fl))
{
// don't have the weapon or the ammo
sprint (self, "no weapon.\n");
return;
}

if (haveammo == FALSE)
{
// don't have the ammo
sprint (self, "not enough ammo.\n");
return;
}

// set weapon, set ammo
self.weapon = fl;
player_set_current_ammo ();
};

//--------------------------------------------------------------
// CycleWeaponCommand -- Go to the next weapon with ammo
//--------------------------------------------------------------
void() player_impulse_cycleweapon =
{
local float haveammo;

self.impulse = 0;

while (1)
{
haveammo = TRUE;

if (self.weapon == IT_LIGHTNING)
{
self.weapon = IT_AXE;
}
else if (self.weapon == IT_AXE)
{
self.weapon = IT_SHOTGUN;
if (self.ammo_shells < 1)
haveammo = FALSE;
}
else if (self.weapon == IT_SHOTGUN)
{
self.weapon = IT_SUPER_SHOTGUN;
if (self.ammo_shells < 2)
haveammo = FALSE;
}
else if (self.weapon == IT_SUPER_SHOTGUN)
{
self.weapon = IT_NAILGUN;
if (self.ammo_nails < 1)
haveammo = FALSE;
}
else if (self.weapon == IT_NAILGUN)
{
self.weapon = IT_SUPER_NAILGUN;
if (self.ammo_nails < 2)
haveammo = FALSE;
}
else if (self.weapon == IT_SUPER_NAILGUN)
{
self.weapon = IT_GRENADE_LAUNCHER;
if (self.ammo_rockets < 1)
haveammo = FALSE;
}
else if (self.weapon == IT_GRENADE_LAUNCHER)
{
self.weapon = IT_ROCKET_LAUNCHER;
if (self.ammo_rockets < 1)
haveammo = FALSE;
}
else if (self.weapon == IT_ROCKET_LAUNCHER)
{
self.weapon = IT_LIGHTNING;
if (self.ammo_cells < 1)
haveammo = FALSE;
}

if ((self.items & self.weapon) && haveammo == TRUE)
{
player_set_current_ammo ();
return;
}
}
};

//--------------------------------------------------------------
// CycleWeaponReverseCommand -- Go to the prev weapon with ammo
//--------------------------------------------------------------
void() player_impulse_cycleweaponreverse =
{
local float haveammo;

self.impulse = 0;

while (1)
{
haveammo = TRUE;

if (self.weapon == IT_LIGHTNING)
{
self.weapon = IT_ROCKET_LAUNCHER;
if (self.ammo_rockets < 1)
haveammo = FALSE;
}
else if (self.weapon == IT_ROCKET_LAUNCHER)
{
self.weapon = IT_GRENADE_LAUNCHER;
if (self.ammo_rockets < 1)
haveammo = FALSE;
}
else if (self.weapon == IT_GRENADE_LAUNCHER)
{
self.weapon = IT_SUPER_NAILGUN;
if (self.ammo_nails < 2)
haveammo = FALSE;
}
else if (self.weapon == IT_SUPER_NAILGUN)
{
self.weapon = IT_NAILGUN;
if (self.ammo_nails < 1)
haveammo = FALSE;
}
else if (self.weapon == IT_NAILGUN)
{
self.weapon = IT_SUPER_SHOTGUN;
if (self.ammo_shells < 2)
haveammo = FALSE;
}
else if (self.weapon == IT_SUPER_SHOTGUN)
{
self.weapon = IT_SHOTGUN;
if (self.ammo_shells < 1)
haveammo = FALSE;
}
else if (self.weapon == IT_SHOTGUN)
{
self.weapon = IT_AXE;
}
else if (self.weapon == IT_AXE)
{
self.weapon = IT_LIGHTNING;
if (self.ammo_cells < 1)
haveammo = FALSE;
}

if ((self.items & self.weapon) && haveammo == TRUE)
{
player_set_current_ammo ();
return;
}
}
};

//--------------------------------------------------------------
// ImpulseCommands
//--------------------------------------------------------------
void() player_impulse =
{
switch (self.impulse)
{
case 1..8:
player_impulse_changeweapon ();
return;
case 9:
player_impulse_cheat ();
break;
case 10:
player_impulse_cycleweapon ();
break;
case 11:
player_impulse_serverflags ();
break;
case 12:
player_impulse_cycleweaponreverse ();
break;
case 100:
// dumptruck_ds version inspired by Copper
sprint (self, version);
break;
case 255:
player_impulse_quadcheat ();
break;
default:
dprint (sprintf("player_impulse: "
"unknown impulse %g\n", self.impulse));
break;
}

self.impulse = 0;
};

//==============================================================
// Client & Player Sounds
//==============================================================

//--------------------------------------------------------------
// SuperDamageSound -- Plays sound if needed
//--------------------------------------------------------------
void() player_superdamage_sound =
{
if (self.super_damage_finished > time &&
self.super_sound < time)
{
self.super_sound = time + 1;
sound (self, CHAN_AUTO, "items/damage3.wav",
1, ATTN_NORM);
}
};

//==============================================================
// Ammo Handling, Weapon Switching, Attack
//==============================================================

//--------------------------------------------------------------
// player_set_current_ammo -- was W_SetCurrentAmmo in weapons.qc
//--------------------------------------------------------------
void() player_set_current_ammo =
{
// get out of any weapon firing states
pl_run1 ();

self.items = self.items - (self.items & (IT_SHELLS | IT_NAILS |
IT_ROCKETS | IT_CELLS));

if (self.weapon == IT_AXE)
{
self.currentammo = 0;
self.weaponmodel = "progs/v_axe.mdl";
self.weaponframe = 0;
}
else if (self.weapon == IT_SHOTGUN)
{
self.currentammo = self.ammo_shells;
self.weaponmodel = "progs/v_shot.mdl";
self.weaponframe = 0;
self.items = self.items | IT_SHELLS;
}
else if (self.weapon == IT_SUPER_SHOTGUN)
{
self.currentammo = self.ammo_shells;
self.weaponmodel = "progs/v_shot2.mdl";
self.weaponframe = 0;
self.items = self.items | IT_SHELLS;
}
else if (self.weapon == IT_NAILGUN)
{
self.currentammo = self.ammo_nails;
self.weaponmodel = "progs/v_nail.mdl";
self.weaponframe = 0;
self.items = self.items | IT_NAILS;
}
else if (self.weapon == IT_SUPER_NAILGUN)
{
self.currentammo = self.ammo_nails;
self.weaponmodel = "progs/v_nail2.mdl";
self.weaponframe = 0;
self.items = self.items | IT_NAILS;
}
else if (self.weapon == IT_GRENADE_LAUNCHER)
{
self.currentammo = self.ammo_rockets;
self.weaponmodel = "progs/v_rock.mdl";
self.weaponframe = 0;
self.items = self.items | IT_ROCKETS;
}
else if (self.weapon == IT_ROCKET_LAUNCHER)
{
self.currentammo = self.ammo_rockets;
self.weaponmodel = "progs/v_rock2.mdl";
self.weaponframe = 0;
self.items = self.items | IT_ROCKETS;
}
else if (self.weapon == IT_LIGHTNING)
{
self.currentammo = self.ammo_cells;
self.weaponmodel = "progs/v_light.mdl";
self.weaponframe = 0;
self.items = self.items | IT_CELLS;
}
else
{
self.currentammo = 0;
self.weaponmodel = "";
self.weaponframe = 0;
}
};

//--------------------------------------------------------------
// best_weapon -- was W_BestWeapon in weapons.qc
//--------------------------------------------------------------
float() player_best_weapon =
{
if (self.waterlevel <= WATERLEVEL_FEET &&
self.ammo_cells >= 1 && (self.items & IT_LIGHTNING))
{
return IT_LIGHTNING;
}

if (self.ammo_nails >= 2 && (self.items & IT_SUPER_NAILGUN))
return IT_SUPER_NAILGUN;

if (self.ammo_shells >= 2 && (self.items & IT_SUPER_SHOTGUN))
return IT_SUPER_SHOTGUN;

if (self.ammo_nails >= 1 && (self.items & IT_NAILGUN))
return IT_NAILGUN;

if (self.ammo_shells >= 1 && (self.items & IT_SHOTGUN))
return IT_SHOTGUN;

return IT_AXE;
};

//--------------------------------------------------------------
float() player_check_no_ammo =
{
if (self.currentammo > 0)
return TRUE;

if (self.weapon == IT_AXE)
return TRUE;

self.weapon = player_best_weapon ();
player_set_current_ammo ();

// drop the weapon down
return FALSE;
};

//--------------------------------------------------------------
// Weapon 1: W_FireAxe
//--------------------------------------------------------------
void() player_fire_axe =
{
local vector source;
local vector org;

makevectors (self.v_angle);
source = self.origin + '0 0 16';
traceline (source, source + v_forward * 64, FALSE, self);
if (trace_fraction == 1.0)
return;
org = trace_endpos - v_forward * 4;

if (trace_ent.takedamage)
{
trace_ent.axhitme = 1;
spawn_blood (org, '0 0 0', 20);
t_damage2 (trace_ent, self, self, 20);
}
else
{
// hit wall
sound (self, CHAN_WEAPON, "player/axhit2.wav",
1, ATTN_NORM);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_GUNSHOT);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
}
};

//--------------------------------------------------------------
// Weapon 2: W_FireShotgun
//--------------------------------------------------------------
void() player_fire_shotgun =
{
local vector org, dir, vdir;
local float vspeed;

sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);

self.punchangle_x = -2;

self.currentammo = self.ammo_shells = self.ammo_shells - 1;
// dir = aim (self, 100000);
makevectors (self.v_angle);

org = self.origin + (v_forward * 10) + (v_right * 0) +
(v_up * 8);
dir = normalize (v_forward * BULLET_SPEED);

// 5 bullets instead of 6 -- CEV
for (float i = 0; i < 5; i++)
{
vspeed = crandom () * 10 + BULLET_SPEED;
vdir = dir + crandom() * 0.04 * v_right +
crandom() * 0.04 * v_up;
/*
vdir = dir +
((((i / 10.0) - 0.3) * 0.12) * v_right) +
((((i / 10.0) - 0.3) * 0.12) * v_up);
*/
vdir *= min (vspeed, world_maxvelocity);

spawn_projectile_bullet (self, org, vdir);
}
};

//--------------------------------------------------------------
// Weapon 3: W_FireSuperShotgun
//--------------------------------------------------------------
void() player_fire_supershotgun =
{
local vector org, dir, vdir;
local float vspeed;

if (self.currentammo == 1)
{
player_fire_shotgun ();
return;
}

sound (self, CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);

self.punchangle_x = -4;

self.currentammo = self.ammo_shells = self.ammo_shells - 2;
// dir = aim (self, 100000);
makevectors (self.v_angle);

org = self.origin + (v_forward * 10) + (v_right * 0) +
(v_up * 8);
dir = normalize (v_forward * BULLET_SPEED);

// 12 bullets instead of 14 -- CEV
for (float i = 0; i < 12; i++)
{
vspeed = crandom () * 10 + BULLET_SPEED;
vdir = dir + (crandom() * 0.14) * v_right +
(crandom() * 0.08) * v_up;
vdir *= min (vspeed, world_maxvelocity);

spawn_projectile_bullet (self, org, vdir);
}
};

//--------------------------------------------------------------
// Weapon 4: W_FireSpikes
//--------------------------------------------------------------
void(float offset) player_fire_spikes =
{
local vector dir;

makevectors (self.v_angle);

if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
{
player_fire_superspikes ();
return;
}

if (self.ammo_nails < 1)
{
self.weapon = player_best_weapon ();
player_set_current_ammo ();
return;
}

sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
self.attack_finished = time + 0.2;
self.currentammo = self.ammo_nails = self.ammo_nails - 1;

dir = aim (self, SPIKE_SPEED);
// dir = normalize (dir);
// SetSpeed
dir *= min (SPIKE_SPEED, world_maxvelocity);

// seven Nailgun position fix - thanks to Greenwood
// -- dumptruck_ds
spawn_projectile_spike (self,
self.origin + self.view_ofs + v_up * -8 +
v_right * (offset * 0.5),
dir, SPIKE_NORMAL_DAMAGE);

self.punchangle_x = -2;
};

//--------------------------------------------------------------
// Weapon 5: W_FireSuperSpikes
//--------------------------------------------------------------
void() player_fire_superspikes =
{
local vector dir;

sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
self.attack_finished = time + 0.2;
self.currentammo = self.ammo_nails = self.ammo_nails - 2;

dir = aim (self, SPIKE_SPEED);
// dir = normalize (dir);
// SetSpeed
dir *= min (SPIKE_SPEED, world_maxvelocity);

// seven Nailgun position fix - thanks to Greenwood
// -- dumptruck_ds
spawn_projectile_spike (self, self.origin + '0 0 16',
dir, SPIKE_SUPER_DAMAGE);

self.punchangle_x = -2;
};

//--------------------------------------------------------------
// Weapon 6: W_FireGrenade
//--------------------------------------------------------------
void() player_fire_grenade =
{
local vector missile_velocity = '0 0 0';

self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;

sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);

self.punchangle_x = -2;

// set missile speed
makevectors (self.v_angle);

if (self.v_angle_x)
{
missile_velocity = v_forward * GRENADE_SPEED +
v_up * 200 + crandom() * v_right * 10 +
crandom() * v_up * 10;
}
else
{
missile_velocity = aim (self, 10000);
missile_velocity = missile_velocity * GRENADE_SPEED;
missile_velocity_z = 200;
}

spawn_projectile_grenade (self, self.origin, missile_velocity);
};

//--------------------------------------------------------------
// Weapon 7: W_FireRocket
//--------------------------------------------------------------
void() player_fire_rocket =
{
local vector missile_velocity = '0 0 0';

self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;

sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);

self.punchangle_x = -2;

// set missile speed
makevectors (self.v_angle);
missile_velocity = aim (self, 1000);
missile_velocity *= ROCKET_SPEED;

spawn_projectile_rocket (self,
self.origin + v_forward * 8 + '0 0 16',
missile_velocity);
};

//--------------------------------------------------------------
// Weapon 8: W_FireLightning
//--------------------------------------------------------------
void() player_fire_lightning =
{
if (self.ammo_cells < 1)
{
self.weapon = player_best_weapon ();
player_set_current_ammo ();
return;
}

// explode if under water
if (self.waterlevel > WATERLEVEL_FEET)
{
local float cells = self.ammo_cells;
self.ammo_cells = 0;
player_set_current_ammo ();
t_radiusdamage2 (self, self, 35 * cells, world);
return;
}

if (self.t_width < time)
{
sound (self, CHAN_WEAPON, "weapons/lhit.wav",
1, ATTN_NORM);
self.t_width = time + 0.6;
}
self.punchangle_x = -2;

self.currentammo = self.ammo_cells = self.ammo_cells - 1;

// TODO CEV
// local vector org = self.origin;
local vector org = self.origin + '0 0 16';
makevectors (self.v_angle);

traceline (org, org + v_forward * 600, TRUE, self);

WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, self);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
WriteCoord (MSG_BROADCAST, trace_endpos_x);
WriteCoord (MSG_BROADCAST, trace_endpos_y);
WriteCoord (MSG_BROADCAST, trace_endpos_z);

fire_lightning (self.origin, trace_endpos + v_forward * 4,
self, 30);
};

//--------------------------------------------------------------
// PlayerAttack -- An attack impulse can be triggered now
//--------------------------------------------------------------
void() player_attack =
{
local float r;

if (player_check_no_ammo() == FALSE)
return;

// calculate forward angle for velocity
makevectors (self.v_angle);
// wake monsters up
self.show_hostile = time + 1;

if (self.weapon == IT_AXE)
{
sound (self, CHAN_WEAPON, "weapons/ax1.wav",
1, ATTN_NORM);
r = random ();
if (r < 0.25)
pl_axe1 ();
else if (r < 0.5)
pl_axeb1 ();
else if (r < 0.75)
pl_axec1 ();
else
pl_axed1 ();
self.attack_finished = time + 0.5;
}
else if (self.weapon == IT_SHOTGUN)
{
pl_shot1 ();
player_fire_shotgun ();
self.attack_finished = time + 0.5;
}
else if (self.weapon == IT_SUPER_SHOTGUN)
{
pl_shot1 ();
player_fire_supershotgun ();
self.attack_finished = time + 0.7;
}
else if (self.weapon == IT_NAILGUN)
{
pl_nail1 ();
}
else if (self.weapon == IT_SUPER_NAILGUN)
{
pl_nail1 ();
}
else if (self.weapon == IT_GRENADE_LAUNCHER)
{
pl_rocket1 ();
player_fire_grenade ();
self.attack_finished = time + 0.6;
}
else if (self.weapon == IT_ROCKET_LAUNCHER)
{
pl_rocket1 ();
player_fire_rocket ();
self.attack_finished = time + 0.8;
}
else if (self.weapon == IT_LIGHTNING)
{
pl_light1 ();
self.attack_finished = time + 0.1;
sound (self, CHAN_AUTO, "weapons/lstart.wav",
1, ATTN_NORM);
}
};

//==============================================================
// Pain and Death
//==============================================================

//--------------------------------------------------------------
void() player_set_suicide_frame =
{
// used by klill command and disconnect command
if (self.model != "progs/player.mdl")
// allready gibbed
return;
self.frame = $deatha11;
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_TOSS;
self.deadflag = DEAD_DEAD;
self.nextthink = -1;
};

//--------------------------------------------------------------
// PainSound
//--------------------------------------------------------------
void() player_pain_sound =
{
local float rs;

if (self.health < 0)
return;

if (damage_attacker.classname == "teledeath")
{
sound (self, CHAN_VOICE, "player/teledth1.wav",
1, ATTN_NONE);
return;
}

// water pain sounds
if (self.watertype == CONTENT_WATER &&
self.waterlevel == WATERLEVEL_EYES)
{
// PlayerDeathBubbles
spawn_air_bubbles (self, self.origin, 1);
if (random() > 0.5)
sound (self, CHAN_VOICE, "player/drown1.wav",
1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "player/drown2.wav",
1, ATTN_NORM);
return;
}

// slime pain sounds
if (self.watertype == CONTENT_SLIME)
{
// FIX ME put in some steam here
// 1998-08-10 Player gulps bubbles when hurt in slime
// by Maddes start
if (self.waterlevel == WATERLEVEL_EYES)
// PlayerDeathBubbles
spawn_air_bubbles (self, self.origin, 1);
// 1998-08-10 Player gulps bubbles when hurt in slime
// by Maddes end
if (random() > 0.5)
sound (self, CHAN_VOICE, "player/lburn1.wav",
1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "player/lburn2.wav",
1, ATTN_NORM);
return;
}

if (self.watertype == CONTENT_LAVA)
{
if (random() > 0.5)
sound (self, CHAN_VOICE, "player/lburn1.wav",
1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "player/lburn2.wav",
1, ATTN_NORM);
return;
}

if (self.pain_finished > time)
{
self.axhitme = 0;
return;
}

// don't make multiple pain sounds right after each other
self.pain_finished = time + 0.5;

// ax pain sound
if (self.axhitme == 1)
{
self.axhitme = 0;
sound (self, CHAN_VOICE, "player/axhit1.wav",
1, ATTN_NORM);
return;
}

rs = rint ((random() * 5) + 1);

self.noise = "";
if (rs == 1)
self.noise = "player/pain1.wav";
else if (rs == 2)
self.noise = "player/pain2.wav";
else if (rs == 3)
self.noise = "player/pain3.wav";
else if (rs == 4)
self.noise = "player/pain4.wav";
else if (rs == 5)
self.noise = "player/pain5.wav";
else
self.noise = "player/pain6.wav";

sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
return;
};

//--------------------------------------------------------------
// PlayerDeathSound
//--------------------------------------------------------------
void() player_death_sound =
{
local float rs;

// water death sounds
if (self.waterlevel == WATERLEVEL_EYES)
{
// PlayerDeathBubbles
spawn_air_bubbles (self, self.origin, 20);
sound (self, CHAN_VOICE, "player/h2odeath.wav",
1, ATTN_NONE);
return;
}

rs = rint ((random() * 4) + 1);
if (rs == 1)
self.noise = "player/death1.wav";
else if (rs == 2)
self.noise = "player/death2.wav";
else if (rs == 3)
self.noise = "player/death3.wav";
else if (rs == 4)
self.noise = "player/death4.wav";
else if (rs == 5)
self.noise = "player/death5.wav";

sound (self, CHAN_VOICE, self.noise, 1, ATTN_NONE);
return;
};

//--------------------------------------------------------------
// PlayerDead -- the player is dead, hold them there
//--------------------------------------------------------------
void() player_dead =
{
self.nextthink = -1;
// allow respawn after a certain time
self.deadflag = DEAD_DEAD;
};

//==============================================================
// Player Think Functions
//==============================================================

//--------------------------------------------------------------
void() player_footsteps =
{
// not moving, no steps
if (self.velocity_x == 0 || self.velocity_y == 0)
return;

// no steps when submerged at the waist or greater
if (self.waterlevel >= WATERLEVEL_WAIST)
return;

if (self.pmove_flags & PMF_AIRSTEPPED)
{
// the heavy foot
self.pmove_flags &= ~PMF_AIRSTEPPED;
sound (self, CHAN_FEET, "steps/foot6.wav",
0.9, ATTN_FEET);
}
else if (self.waterlevel > WATERLEVEL_NONE)
{
dprint ("player_footsteps: water\n");
}
else
{
local float vol;

if (self.speed > PM_RUNSPEED * 0.9)
{
vol = 0.2 + (random() * 0.5);
}
else if (self.speed > PM_WALKSPEED * 0.9 &&
(self.frame == $rockrun2 ||
self.frame == $axrun2))
{
vol = 0.1 + (random() * 0.3);
}
else
{
// no footsteps below PM_WALKSPEED * 0.9
return;
}

local string newstep = "";

if (self.cnt == 0 || self.cnt > 6)
self.cnt = rint (1 + random() * 5);

switch (self.cnt)
{
case 1:
newstep = "steps/foot1.wav";
break;
case 2:
newstep = "steps/foot2.wav";
break;
case 3:
newstep = "steps/foot3.wav";
break;
case 4:
newstep = "steps/foot4.wav";
break;
case 5:
newstep = "steps/foot5.wav";
break;
case 6:
newstep = "steps/foot7.wav";
break;
}

self.cnt++;
sound (self, CHAN_FEET, newstep, vol, ATTN_FEET);
}
// dprint (sprintf("player_footsteps: step time diff %g\n",
// time - self.step_time));
self.step_time = time;
};

//--------------------------------------------------------------
void() player_stand =
{
self.weaponframe = 0;

if (self.velocity_x || self.velocity_y)
{
if (self.weapon == IT_AXE)
pl_axrun1 ();
else
pl_run1 ();
}
else if (self.weapon == IT_AXE)
{
pl_axstnd1 ();
}
};

//--------------------------------------------------------------
void() player_axstand =
{
self.weaponframe = 0;

if (self.velocity_x || self.velocity_y)
{
if (self.weapon == IT_AXE)
pl_axrun1 ();
else
pl_run1 ();
return;
}
else if (self.weapon != IT_AXE)
{
pl_stand1 ();
}
};

//--------------------------------------------------------------
void(void() axthink) player_run =
{
// dprint (sprintf("player_run: frame %g\n", self.frame));

if (self.velocity_x == 0 && self.velocity_y == 0)
pl_stand1 ();
else if (self.weapon == IT_AXE)
axthink ();
};

//--------------------------------------------------------------
void(void() runthink) player_axrun =
{
// dprint (sprintf("player_axrun: frame %g\n", self.frame));

if (self.velocity_x == 0 && self.velocity_y == 0)
pl_stand1 ();
else if (self.weapon != IT_AXE)
runthink ();
};

//--------------------------------------------------------------
// Player Axe Stand function
//--------------------------------------------------------------
void() pl_axstnd1 = [$axstnd1, pl_axstnd2] { player_axstand (); };
void() pl_axstnd2 = [$axstnd2, pl_axstnd3] { player_axstand (); };
void() pl_axstnd3 = [$axstnd3, pl_axstnd4] { player_axstand (); };
void() pl_axstnd4 = [$axstnd4, pl_axstnd5] { player_axstand (); };
void() pl_axstnd5 = [$axstnd5, pl_axstnd6] { player_axstand (); };
void() pl_axstnd6 = [$axstnd6, pl_axstnd7] { player_axstand (); };
void() pl_axstnd7 = [$axstnd7, pl_axstnd8] { player_axstand (); };
void() pl_axstnd8 = [$axstnd8, pl_axstnd9] { player_axstand (); };
void() pl_axstnd9 = [$axstnd9, pl_axstnd10] { player_axstand (); };
void() pl_axstnd10 = [$axstnd10, pl_axstnd11] { player_axstand (); };
void() pl_axstnd11 = [$axstnd11, pl_axstnd12] { player_axstand (); };
void() pl_axstnd12 = [$axstnd12, pl_axstnd1] { player_axstand (); };

//--------------------------------------------------------------
// Player Stand function
//--------------------------------------------------------------
void() pl_stand1 = [$stand1, pl_stand2] { player_stand (); };
void() pl_stand2 = [$stand2, pl_stand3] { player_stand (); };
void() pl_stand3 = [$stand3, pl_stand4] { player_stand (); };
void() pl_stand4 = [$stand4, pl_stand5] { player_stand (); };
void() pl_stand5 = [$stand5, pl_stand1] { player_stand (); };

//--------------------------------------------------------------
// Player Axe Run function
//--------------------------------------------------------------
void() pl_axrun1 = [$axrun1, pl_axrun2]
{
self.weaponframe = 0;
player_axrun (pl_run1);
};
void() pl_axrun2 = [$axrun2, pl_axrun3]
{
// left foot down
player_axrun (pl_run2);
if (self.flags & FL_ONGROUND)
player_footsteps ();
};
void() pl_axrun3 = [$axrun3, pl_axrun4] { player_axrun (pl_run3); };
void() pl_axrun4 = [$axrun4, pl_axrun5] { player_axrun (pl_run4); };
void() pl_axrun5 = [$axrun5, pl_axrun6]
{
// right foot down
player_axrun (pl_run5);
if (self.flags & FL_ONGROUND)
player_footsteps ();
};
void() pl_axrun6 = [$axrun6, pl_axrun1] { player_axrun (pl_run6); };

//--------------------------------------------------------------
// Player Run function
//--------------------------------------------------------------
void() pl_run1 = [$rockrun1, pl_run2]
{
self.weaponframe = 0;
player_run (pl_axrun1);
};
void() pl_run2 = [$rockrun2, pl_run3]
{
// left foot down
player_run (pl_axrun2);
if (self.flags & FL_ONGROUND)
player_footsteps ();
};
void() pl_run3 = [$rockrun3, pl_run4] { player_run (pl_axrun3); };
void() pl_run4 = [$rockrun4, pl_run5] { player_run (pl_axrun4); };
void() pl_run5 = [$rockrun5, pl_run6]
{
// right foot down
player_run (pl_axrun5);
if (self.flags & FL_ONGROUND)
player_footsteps ();
};
void() pl_run6 = [$rockrun6, pl_run1] { player_run (pl_axrun6); };

//--------------------------------------------------------------
// Player Projectile Attack
//--------------------------------------------------------------
void() pl_shot1 = [$shotatt1, pl_shot2]
{
self.weaponframe = 1;
self.effects = self.effects | EF_MUZZLEFLASH;
};
void() pl_shot2 = [$shotatt2, pl_shot3] { self.weaponframe = 2; };
void() pl_shot3 = [$shotatt3, pl_shot4] { self.weaponframe = 3; };
void() pl_shot4 = [$shotatt4, pl_shot5] { self.weaponframe = 4; };
void() pl_shot5 = [$shotatt5, pl_shot6] { self.weaponframe = 5; };
void() pl_shot6 = [$shotatt6, pl_run1] { self.weaponframe = 6; };

//--------------------------------------------------------------
// Player Axe Attack A
//--------------------------------------------------------------
void() pl_axe1 = [$axatt1, pl_axe2] { self.weaponframe = 1; };
void() pl_axe2 = [$axatt2, pl_axe3] { self.weaponframe = 2; };
void() pl_axe3 = [$axatt3, pl_axe4]
{
self.weaponframe = 3;
player_fire_axe ();
};
void() pl_axe4 = [$axatt4, pl_run1] { self.weaponframe = 4; };

//--------------------------------------------------------------
// Player Axe Attack B
//--------------------------------------------------------------
void() pl_axeb1 = [$axattb1, pl_axeb2] { self.weaponframe = 5; };
void() pl_axeb2 = [$axattb2, pl_axeb3] { self.weaponframe = 6; };
void() pl_axeb3 = [$axattb3, pl_axeb4]
{
self.weaponframe = 7;
player_fire_axe ();
};
void() pl_axeb4 = [$axattb4, pl_run1] { self.weaponframe = 8; };

//--------------------------------------------------------------
// Player Axe Attack C
//--------------------------------------------------------------
void() pl_axec1 = [$axattc1, pl_axec2] { self.weaponframe = 1; };
void() pl_axec2 = [$axattc2, pl_axec3] { self.weaponframe = 2; };
void() pl_axec3 = [$axattc3, pl_axec4]
{
self.weaponframe = 3;
player_fire_axe ();
};
void() pl_axec4 = [$axattc4, pl_run1] { self.weaponframe = 4; };

//--------------------------------------------------------------
// Player Axe Attack D
//--------------------------------------------------------------
void() pl_axed1 = [$axattd1, pl_axed2] { self.weaponframe = 5; };
void() pl_axed2 = [$axattd2, pl_axed3] { self.weaponframe = 6; };
void() pl_axed3 = [$axattd3, pl_axed4]
{
self.weaponframe = 7;
player_fire_axe ();
};
void() pl_axed4 = [$axattd4, pl_run1] { self.weaponframe = 8; };

//--------------------------------------------------------------
// Player Nail Attack
//--------------------------------------------------------------
void() pl_nail1 = [$nailatt1, pl_nail2]
{
self.effects = self.effects | EF_MUZZLEFLASH;

if (!self.button0)
{
pl_run1 ();
return;
}

self.weaponframe = self.weaponframe + 1;
if (self.weaponframe == 9)
self.weaponframe = 1;
player_superdamage_sound ();
player_fire_spikes (4);
self.attack_finished = time + 0.2;
};
void() pl_nail2 = [$nailatt2, pl_nail1]
{
self.effects = self.effects | EF_MUZZLEFLASH;

if (!self.button0)
{
pl_run1 ();
return;
}

self.weaponframe = self.weaponframe + 1;
if (self.weaponframe == 9)
self.weaponframe = 1;
player_superdamage_sound ();
player_fire_spikes (-4);
self.attack_finished = time + 0.2;
};

//--------------------------------------------------------------
// Player LG Attack
//--------------------------------------------------------------
void() pl_light1 = [$light1, pl_light2]
{
self.effects = self.effects | EF_MUZZLEFLASH;

if (!self.button0)
{
pl_run1 ();
return;
}

self.weaponframe = self.weaponframe + 1;
if (self.weaponframe == 5)
self.weaponframe = 1;
player_superdamage_sound ();
player_fire_lightning ();
self.attack_finished = time + 0.2;
};
void() pl_light2 = [$light2, pl_light1]
{
self.effects = self.effects | EF_MUZZLEFLASH;

if (!self.button0)
{
pl_run1 ();
return;
}

self.weaponframe = self.weaponframe + 1;
if (self.weaponframe == 5)
self.weaponframe = 1;
player_superdamage_sound ();
player_fire_lightning ();
self.attack_finished = time + 0.2;
};

//--------------------------------------------------------------
// Player Rocket Attack
//--------------------------------------------------------------
void() pl_rocket1 = [$rockatt1, pl_rocket2]
{
self.weaponframe = 1;
self.effects = self.effects | EF_MUZZLEFLASH;
};
void() pl_rocket2 = [$rockatt2, pl_rocket3] { self.weaponframe = 2; };
void() pl_rocket3 = [$rockatt3, pl_rocket4] { self.weaponframe = 3; };
void() pl_rocket4 = [$rockatt4, pl_rocket5] { self.weaponframe = 4; };
void() pl_rocket5 = [$rockatt5, pl_rocket6] { self.weaponframe = 5; };
void() pl_rocket6 = [$rockatt6, pl_run1] { self.weaponframe = 6; };

//--------------------------------------------------------------
// Player Pain state A
//--------------------------------------------------------------
void() pl_pain1 = [$pain1, pl_pain2]
{
player_pain_sound ();
self.weaponframe = 0;
};
void() pl_pain2 = [$pain2, pl_pain3] { };
void() pl_pain3 = [$pain3, pl_pain4] { };
void() pl_pain4 = [$pain4, pl_pain5] { };
void() pl_pain5 = [$pain5, pl_pain6] { };
void() pl_pain6 = [$pain6, pl_run1] { };

//--------------------------------------------------------------
// Player Axe Pain state A
//--------------------------------------------------------------
void() pl_axpain1 = [$axpain1, pl_axpain2]
{
player_pain_sound ();
self.weaponframe = 0;
};
void() pl_axpain2 = [$axpain2, pl_axpain3] {};
void() pl_axpain3 = [$axpain3, pl_axpain4] {};
void() pl_axpain4 = [$axpain4, pl_axpain5] {};
void() pl_axpain5 = [$axpain5, pl_axpain6] {};
void() pl_axpain6 = [$axpain6, pl_run1] {};

//--------------------------------------------------------------
// Player Death state A
//--------------------------------------------------------------
void() pl_diea1 = [$deatha1, pl_diea2] {};
void() pl_diea2 = [$deatha2, pl_diea3] {};
void() pl_diea3 = [$deatha3, pl_diea4] {};
void() pl_diea4 = [$deatha4, pl_diea5] {};
void() pl_diea5 = [$deatha5, pl_diea6] {};
void() pl_diea6 = [$deatha6, pl_diea7] {};
void() pl_diea7 = [$deatha7, pl_diea8] {};
void() pl_diea8 = [$deatha8, pl_diea9] {};
void() pl_diea9 = [$deatha9, pl_diea10] {};
void() pl_diea10 = [$deatha10, pl_diea11] {};
void() pl_diea11 = [$deatha11, pl_diea11] { player_dead (); };

//--------------------------------------------------------------
// Player Death state B
//--------------------------------------------------------------
void() pl_dieb1 = [$deathb1, pl_dieb2] {};
void() pl_dieb2 = [$deathb2, pl_dieb3] {};
void() pl_dieb3 = [$deathb3, pl_dieb4] {};
void() pl_dieb4 = [$deathb4, pl_dieb5] {};
void() pl_dieb5 = [$deathb5, pl_dieb6] {};
void() pl_dieb6 = [$deathb6, pl_dieb7] {};
void() pl_dieb7 = [$deathb7, pl_dieb8] {};
void() pl_dieb8 = [$deathb8, pl_dieb9] {};
void() pl_dieb9 = [$deathb9, pl_dieb9] { player_dead (); };

//--------------------------------------------------------------
// Player Death state C
//--------------------------------------------------------------
void() pl_diec1 = [$deathc1, pl_diec2] {};
void() pl_diec2 = [$deathc2, pl_diec3] {};
void() pl_diec3 = [$deathc3, pl_diec4] {};
void() pl_diec4 = [$deathc4, pl_diec5] {};
void() pl_diec5 = [$deathc5, pl_diec6] {};
void() pl_diec6 = [$deathc6, pl_diec7] {};
void() pl_diec7 = [$deathc7, pl_diec8] {};
void() pl_diec8 = [$deathc8, pl_diec9] {};
void() pl_diec9 = [$deathc9, pl_diec10] {};
void() pl_diec10 = [$deathc10, pl_diec11] {};
void() pl_diec11 = [$deathc11, pl_diec12] {};
void() pl_diec12 = [$deathc12, pl_diec13] {};
void() pl_diec13 = [$deathc13, pl_diec14] {};
void() pl_diec14 = [$deathc14, pl_diec15] {};
void() pl_diec15 = [$deathc15, pl_diec15] { player_dead (); };

//--------------------------------------------------------------
// Player Death state D
//--------------------------------------------------------------
void() pl_died1 = [$deathd1, pl_died2] {};
void() pl_died2 = [$deathd2, pl_died3] {};
void() pl_died3 = [$deathd3, pl_died4] {};
void() pl_died4 = [$deathd4, pl_died5] {};
void() pl_died5 = [$deathd5, pl_died6] {};
void() pl_died6 = [$deathd6, pl_died7] {};
void() pl_died7 = [$deathd7, pl_died8] {};
void() pl_died8 = [$deathd8, pl_died9] {};
void() pl_died9 = [$deathd9, pl_died9] { player_dead (); };

//--------------------------------------------------------------
// Player Death state E
//--------------------------------------------------------------
void() pl_diee1 = [$deathe1, pl_diee2] {};
void() pl_diee2 = [$deathe2, pl_diee3] {};
void() pl_diee3 = [$deathe3, pl_diee4] {};
void() pl_diee4 = [$deathe4, pl_diee5] {};
void() pl_diee5 = [$deathe5, pl_diee6] {};
void() pl_diee6 = [$deathe6, pl_diee7] {};
void() pl_diee7 = [$deathe7, pl_diee8] {};
void() pl_diee8 = [$deathe8, pl_diee9] {};
void() pl_diee9 = [$deathe9, pl_diee9] { player_dead (); };

//--------------------------------------------------------------
// Player Axe Death state A
//--------------------------------------------------------------
void() pl_die_ax1 = [$axdeth1, pl_die_ax2] {};
void() pl_die_ax2 = [$axdeth2, pl_die_ax3] {};
void() pl_die_ax3 = [$axdeth3, pl_die_ax4] {};
void() pl_die_ax4 = [$axdeth4, pl_die_ax5] {};
void() pl_die_ax5 = [$axdeth5, pl_die_ax6] {};
void() pl_die_ax6 = [$axdeth6, pl_die_ax7] {};
void() pl_die_ax7 = [$axdeth7, pl_die_ax8] {};
void() pl_die_ax8 = [$axdeth8, pl_die_ax9] {};
void() pl_die_ax9 = [$axdeth9, pl_die_ax9] { player_dead (); };

//--------------------------------------------------------------
// PlayerDeathThink -- called from prethink when dead
//--------------------------------------------------------------
void() player_death_think =
{
local float forward;

if ((self.flags & FL_ONGROUND))
{
forward = vlen (self.velocity);
forward = forward - 20;
if (forward <= 0)
self.velocity = '0 0 0';
else
self.velocity = forward *
normalize (self.velocity);
}

// wait for all buttons released
if (self.deadflag == DEAD_DEAD)
{
if (self.button2 || self.button1 || self.button0)
return;
self.deadflag = DEAD_RESPAWNABLE;
return;
}

// wait for any button down
if (!self.button2 && !self.button1 && !self.button0)
return;

self.button0 = 0;
self.button1 = 0;
self.button2 = 0;
player_respawn ();
};

//--------------------------------------------------------------
// WaterMove
//--------------------------------------------------------------
void() player_prethink_watermove =
{
if (self.movetype == MOVETYPE_NOCLIP)
{
self.air_finished = time + 120;
return;
}

if (self.health < 0)
return;

if (self.waterlevel != 3)
{
if (self.air_finished < time)
sound (self, CHAN_VOICE, "player/gasp2.wav",
1, ATTN_NORM);
else if (self.air_finished < time + 9)
sound (self, CHAN_VOICE, "player/gasp1.wav",
1, ATTN_NORM);
self.air_finished = time + 12;
self.dmg = 2;
}
else if (self.air_finished < time)
{
// drown!
if (self.pain_finished < time)
{
self.dmg = self.dmg + 2;
if (self.dmg > 15)
self.dmg = 10;
self.deathtype = "drowning";
t_damage2 (self, world, world, self.dmg);
self.deathtype = "";
self.pain_finished = time + 1;
}
}

if (!self.waterlevel)
{
if (self.flags & FL_INWATER)
{
// play leave water sound
sound (self, CHAN_BODY, "misc/outwater.wav",
1, ATTN_NORM);
self.flags = self.flags - FL_INWATER;
}
return;
}

if (self.watertype == CONTENT_LAVA)
{
// do damage
if (self.damage_time < time)
{
if (self.radsuit_finished > time)
self.damage_time = time + 1;
else
self.damage_time = time + 0.2;

self.deathtype = "lava";
t_damage2 (self, world, world,
10 * self.waterlevel);
self.deathtype = "";
}
}
else if (self.watertype == CONTENT_SLIME)
{
// do damage
if (self.damage_time < time &&
self.radsuit_finished < time)
{
self.damage_time = time + 1;
self.deathtype = "slime";
t_damage2 (self, world, world,
4 * self.waterlevel);
self.deathtype = "";
}
}

if (!(self.flags & FL_INWATER))
{
// player enter water sound
if (self.watertype == CONTENT_LAVA)
sound (self, CHAN_BODY, "player/inlava.wav",
1, ATTN_NORM);
if (self.watertype == CONTENT_WATER)
sound (self, CHAN_BODY, "player/inh2o.wav",
1, ATTN_NORM);
if (self.watertype == CONTENT_SLIME)
sound (self, CHAN_BODY, "player/slimbrn2.wav",
1, ATTN_NORM);

self.flags = self.flags + FL_INWATER;
self.damage_time = 0;
}
};

//--------------------------------------------------------------
// CheckWaterJump -- the legacy standard id1 (?) waterjump
//--------------------------------------------------------------
void() player_prethink_waterjump =
{
// from Copper -- dumptruck_ds
if (self.movetype == MOVETYPE_NOCLIP)
return;

local vector start, end;

// check for a jump-out-of-water
makevectors (self.angles);
start = self.origin;
start_z = start_z + 8;
v_forward_z = 0;
normalize (v_forward);
end = start + v_forward * 24;
traceline (start, end, TRUE, self);
if (trace_fraction < 1)
{
// solid at waist
start_z = start_z + self.maxs_z - 8;
end = start + v_forward * 24;
self.movedir = trace_plane_normal * -50;
traceline (start, end, TRUE, self);
if (trace_fraction == 1)
{
// open at eye level
self.flags = self.flags | FL_WATERJUMP;
self.velocity_z = 225;
self.flags -= self.flags & FL_JUMPRELEASED;
// safety net
self.teleport_time = time + 2;
return;
}
}
};

//--------------------------------------------------------------
// PlayerJump -- standard legacy id1 jump logic
//--------------------------------------------------------------
void() player_prethink_jump =
{
if (self.flags & FL_WATERJUMP)
return;

if (self.waterlevel >= 2)
{
if (self.watertype == CONTENT_WATER)
self.velocity_z = 100;
else if (self.watertype == CONTENT_SLIME)
self.velocity_z = 80;
else
self.velocity_z = 50;

// play swiming sound
if (self.swim_flag < time)
{
self.swim_flag = time + 1;
if (random() < 0.5)
sound (self, CHAN_BODY,
"misc/water1.wav",
1, ATTN_NORM);
else
sound (self, CHAN_BODY,
"misc/water2.wav",
1, ATTN_NORM);
}
return;
}

// refactoring from Copper -- dumptruck_ds
if (self.movetype != MOVETYPE_NOCLIP)
{
if (!(self.flags & FL_ONGROUND))
return;
// don't pogo stick
if ( !(self.flags & FL_JUMPRELEASED) )
return;
// player jumping sound (h00rt)
sound (self, CHAN_BODY, "player/plyrjmp8.wav",
1, ATTN_NORM);
}

self.flags = self.flags - (self.flags & FL_JUMPRELEASED);

// don't stairwalk
self.flags = self.flags - FL_ONGROUND;

self.button2 = 0;
self.velocity_z = self.velocity_z + 270;
};

//--------------------------------------------------------------
// Called by PlayerPreThink in entrypoints.qc -- CEV
//--------------------------------------------------------------
void() player_prethink =
{
local float do_ladder_physics = FALSE;

if (self.button4)
dprint ("player_prethink: button4!\n");

// note that this code block is here, before the tests
// which check whether the player is dead, so that the
// player's gravity will be correctly updated even if
// they e.g. fell off a ladder because they died -- iw
if (world_standardphysics)
{
if (self.pmove_flags & PMF_ONLADDER)
{
do_ladder_physics = TRUE;
// not zero, because zero means "default"
self.gravity = 0.0000001;
self.pmove_flags &= ~PMF_ONLADDER;
}
else
{
do_ladder_physics = FALSE;
self.gravity = self.wantedgravity;
}

// from copper -- dumptruck_ds
if (self.movetype == MOVETYPE_NOCLIP)
self.flags |= FL_FLY;
}
else
{
self.gravity = self.wantedgravity;
}

/*
dprint (sprintf("player::prethink: getlight %v\n",
getlight (self.origin)));
*/

// for referencing horizontal velocity later -- CEV
self.speed = vlen ([self.velocity_x, self.velocity_y, 0]);

// If just spawned in, try to recover previous fog values
// from own client entity, if any
if (clean_up_client_stuff)
fog_set_from_ent (self, self);

// WaterMove - needs to run even if doing nonstandard physics
player_prethink_watermove ();

if (world_standardphysics)
{
// run legacy CheckWaterJump if we're doing
// standard physics -- CEV
if (self.waterlevel == 2)
player_prethink_waterjump ();

// johnfitz ladder conditions, added from
// Rubicon2 -- dumptruck_ds
if (do_ladder_physics)
{
if (self.button2)
{
// PlayerClimb -- johnfitz
self.velocity = '0 0 160';
/*
// no ladder footsteps for now
if (time > self.ladder_step_finished)
{
// TODO CEV oof
r = random();
if (r > 0.66)
sound (self, CHAN_BODY,
"ladder/metal1.wav",
0.5, ATTN_NORM);
else if (r > 0.33)
sound (self, CHAN_BODY,
"ladder/metal2.wav",
0.5, ATTN_NORM);
else
sound (self, CHAN_BODY,
"ladder/metal3.wav",
0.5, ATTN_NORM);
self.ladder_step_finished =
time + 0.3;
}
*/
}
else
{
self.flags |= FL_JUMPRELEASED;
self.velocity = 0.9 * self.velocity;
self.velocity_z = 0;
}
}
else
{
if (self.button2)
player_prethink_jump ();
else
self.flags |= FL_JUMPRELEASED;
}
}

if (self.deadflag >= DEAD_DEAD)
{
// dead, so run the death think -- CEV
player_death_think ();
return;
}

if (self.deadflag == DEAD_DYING)
// dying, so do nothing
return;

// teleporters can force a non-moving pause time
if (time < self.pausetime)
self.velocity = '0 0 0';

if (time > self.attack_finished && self.currentammo == 0
&& self.weapon != IT_AXE)
{
self.weapon = player_best_weapon ();
player_set_current_ammo ();
}
};

//--------------------------------------------------------------
// CheckPowerups -- Check for turning off powerups
//--------------------------------------------------------------
void() player_postthink_powerups =
{
if (self.health <= 0)
return;

// invisibility
if (self.invisible_finished)
{
// sound and screen flash when items starts to run out
if (self.invisible_sound < time)
{
sound (self, CHAN_AUTO, "items/inv3.wav",
0.5, ATTN_IDLE);
self.invisible_sound = time +
((random() * 3) + 1);
}

if (self.invisible_finished < time + 3)
{
if (self.invisible_time == 1)
{
sprint (self, "Ring of Shadows magic is"
" fading\n");
stuffcmd (self, "bf\n");
sound (self, CHAN_AUTO,"items/inv2.wav",
1, ATTN_NORM);
self.invisible_time = time + 1;
}

if (self.invisible_time < time)
{
self.invisible_time = time + 1;
stuffcmd (self, "bf\n");
}
}

if (self.invisible_finished < time)
{
// just stopped
self.items = self.items - IT_INVISIBILITY;
self.invisible_finished = 0;
self.invisible_time = 0;
}

// use the eyes
self.frame = 0;
self.modelindex = modelindex_eyes;
}
else
{
// don't use the eyes
self.modelindex = modelindex_player;
}

// invincibility
if (self.invincible_finished)
{
// sound and screen flash when items starts to run out
if (self.invincible_finished < time + 3)
{
if (self.invincible_time == 1)
{
sprint (self, "Protection is almost "
"burned out\n");
stuffcmd (self, "bf\n");
sound (self, CHAN_AUTO,
"items/protect2.wav",
1, ATTN_NORM);
self.invincible_time = time + 1;
}

if (self.invincible_time < time)
{
self.invincible_time = time + 1;
stuffcmd (self, "bf\n");
}
}

if (self.invincible_finished < time)
{
// just stopped
self.items = self.items - IT_INVULNERABILITY;
self.invincible_time = 0;
self.invincible_finished = 0;
}
if (self.invincible_finished > time)
self.effects = self.effects | EF_DIMLIGHT;
else
self.effects -= self.effects & EF_DIMLIGHT;
}

// super damage
if (self.super_damage_finished)
{
// sound and screen flash when items starts to run out
if (self.super_damage_finished < time + 3)
{
if (self.super_time == 1)
{
sprint (self, "Quad Damage is wearing "
"off\n");
stuffcmd (self, "bf\n");
sound (self, CHAN_AUTO,
"items/damage2.wav",
1, ATTN_NORM);
self.super_time = time + 1;
}

if (self.super_time < time)
{
self.super_time = time + 1;
stuffcmd (self, "bf\n");
}
}

if (self.super_damage_finished < time)
{
// just stopped
self.items = self.items - IT_QUAD;
self.super_damage_finished = 0;
self.super_time = 0;
}
if (self.super_damage_finished > time)
self.effects = self.effects | EF_DIMLIGHT;
else
self.effects -= self.effects & EF_DIMLIGHT;
}

// suit
if (self.radsuit_finished)
{
// don't drown
self.air_finished = time + 12;

// sound and screen flash when items starts to run out
if (self.radsuit_finished < time + 3)
{
if (self.rad_time == 1)
{
sprint (self, "Air supply in Biosuit "
"expiring\n");
stuffcmd (self, "bf\n");
sound (self, CHAN_AUTO,
"items/suit2.wav",
1, ATTN_NORM);
self.rad_time = time + 1;
}

if (self.rad_time < time)
{
self.rad_time = time + 1;
stuffcmd (self, "bf\n");
}
}

if (self.radsuit_finished < time)
{
// just stopped
self.items = self.items - IT_SUIT;
self.rad_time = 0;
self.radsuit_finished = 0;
}
}
};

//--------------------------------------------------------------
// Called by PlayerPostThink in entrypoints.qc -- CEV
//--------------------------------------------------------------
void() player_postthink =
{
if (self.view_ofs == '0 0 0')
// intermission or finale
return;

if (self.pmove_flags & PMF_AIRSTEPPED)
if (self.step_time <= time - 0.4)
self.pmove_flags &= ~PMF_AIRSTEPPED;

// full send -- CEV
self.SendFlags = 0xffffff;

if (self.deadflag)
return;

// next block was in W_WeaponFrame -- CEV
if (time >= self.attack_finished)
{
if (self.impulse)
player_impulse ();

if (self.button0)
{
player_superdamage_sound ();
player_attack ();
}
}

// check to see if player landed and play landing sound
if ((self.jump_flag < -300) && (self.flags & FL_ONGROUND) &&
(self.health > 0))
{
if (self.watertype == CONTENT_WATER)
sound (self, CHAN_BODY, "player/h2ojump.wav",
1, ATTN_NORM);
else if (self.jump_flag < -650)
{
self.deathtype = "falling";
t_damage2 (self, world, world, 5);
self.deathtype = "";
sound (self, CHAN_VOICE, "player/land2.wav",
1, ATTN_NORM);
}
else
sound (self, CHAN_VOICE, "player/land.wav",
1, ATTN_NORM);

self.jump_flag = 0;
}

if (!(self.flags & FL_ONGROUND))
self.jump_flag = self.velocity_z;

// dumptruck_ds -- self replaces item_megahealth_rot in items.qc
if (self.health > self.max_health)
{
if (self.megahealth_rottime < time)
{
self.megahealth_rottime = time + 1;
self.health = self.health - 1;
}
else if (self.health <= 100)
{
// thanks ydrol!!!
self.items = self.items -
(self.items & IT_SUPERHEALTH);
}
}

player_postthink_powerups ();

// from Copper -- dumptruck_ds
if (world_standardphysics && self.movetype != MOVETYPE_NOCLIP)
self.flags &= ~FL_FLY;
};

//==============================================================
// Interaction
//==============================================================

//--------------------------------------------------------------
// SendEntity -- transmit updates from server to client -- CEV
//--------------------------------------------------------------
float(entity to, float fl) player_sendentity =
{
WriteByte (MSG_ENTITY, CT_PLAYER);
WriteByte (MSG_ENTITY, self.frame);
WriteCoord (MSG_ENTITY, self.origin_x);
WriteCoord (MSG_ENTITY, self.origin_y);
WriteCoord (MSG_ENTITY, self.origin_z);
WriteShort (MSG_ENTITY, self.angles_x * 32767 / 360);
WriteShort (MSG_ENTITY, self.angles_y * 32767 / 360);
WriteShort (MSG_ENTITY, self.angles_z * 32767 / 360);
WriteShort (MSG_ENTITY, self.velocity_x);
WriteShort (MSG_ENTITY, self.velocity_y);
WriteShort (MSG_ENTITY, self.velocity_z);
WriteFloat (MSG_ENTITY, self.effects);
WriteFloat (MSG_ENTITY, self.flags);
WriteFloat (MSG_ENTITY, self.pmove_flags);
WriteFloat (MSG_ENTITY, self.doublejump_timer);
return TRUE;
};

//--------------------------------------------------------------
// player_pain
//--------------------------------------------------------------
void(entity attacker, float damage) player_pain =
{
if (self.weaponframe)
return;

if (self.invisible_finished > time)
// eyes don't have pain frames
return;

if (self.weapon == IT_AXE)
pl_axpain1 ();
else
pl_pain1 ();
};

//--------------------------------------------------------------
// gib_player
//--------------------------------------------------------------
void(vector dir) player_destroy_gib =
{
throw_gib_head_player (self, dir, self.health);
throw_gib_1 (self, dir, self.health);
throw_gib_2 (self, dir, self.health);
throw_gib_3 (self, dir, self.health);

self.deadflag = DEAD_DEAD;

if (damage_attacker.classname == "teledeath")
sound (self, CHAN_VOICE, "player/teledth1.wav",
1, ATTN_NONE);
else if (damage_attacker.classname == "teledeath2")
sound (self, CHAN_VOICE, "player/teledth1.wav",
1, ATTN_NONE);
else
if (random() < 0.5)
sound (self, CHAN_VOICE, "player/gib.wav",
1, ATTN_NONE);
else
sound (self, CHAN_VOICE, "player/udeath.wav",
1, ATTN_NONE);
};

//--------------------------------------------------------------
// PlayerDie
//--------------------------------------------------------------
void(vector dir) player_destroy =
{
local float i;

// 1998-07-23 Palette shift when player dies with quad/pentagram
// fix by Maddes start
// self.items = self.items - (self.items & IT_INVISIBILITY);
self.items = self.items - (self.items &
(IT_INVISIBILITY | IT_INVULNERABILITY |
IT_SUIT | IT_QUAD));
// 1998-07-23 Palette shift when player dies with quad/pentagram
// fix by Maddes end

// don't die as eyes
// self.invisible_finished = 0;
self.invincible_finished = 0;
self.super_damage_finished = 0;
self.radsuit_finished = 0;

// 1998-07-23 Glowing corpse of players which had quad/pentagram
// until respawn fix by Maddes
self.effects = 0;

// don't use eyes
self.modelindex = modelindex_player;

if (deathmatch || coop)
item_backpack_drop (self);

self.weaponmodel = "";
self.view_ofs = '0 0 -8';
self.deadflag = DEAD_DYING;
self.solid = SOLID_NOT;
self.flags = self.flags - (self.flags & FL_ONGROUND);
self.movetype = MOVETYPE_TOSS;

if (self.velocity_z < 10)
self.velocity_z = self.velocity_z + random() * 300;

if (self.health < -40)
{
player_destroy_gib (dir);
return;
}

player_death_sound ();

self.angles_x = 0;
self.angles_z = 0;

if (self.weapon == IT_AXE)
{
pl_die_ax1 ();
return;
}

i = cvar ("temp1");
if (!i)
i = 1 + floor (random() * 6);

if (i == 1)
pl_diea1 ();
else if (i == 2)
pl_dieb1 ();
else if (i == 3)
pl_diec1 ();
else if (i == 4)
pl_died1 ();
else
pl_diee1 ();
};

//--------------------------------------------------------------
// by: Philip Martin aka: Kryten
// When on top of monsters or players you slide. This is a QuakeC
// problem. The function below fixes that problem.
// based on code given to Kryten by: Michael Turitzin (MaNiAc)
//--------------------------------------------------------------
void() player_touch =
{
// 1998-09-16 Sliding/not-jumping on monsters/boxes/players
// fix by Maddes/Kryten start

// can cause problems for monsters on top of a player,
// so only players
if (other.classtype != CT_PLAYER)
return;
if (other.health <= 0)
return;

if ((!(other.flags & FL_ONGROUND)) &&
((other.absmin_z >= self.absmax_z - 2)))
{
other.flags = other.flags + FL_ONGROUND;
}

// you can add other stuff like pushable players/monsters here

// 1998-09-16 Sliding/not-jumping on monsters/boxes/players
// fix by Maddes/Kryten end
};

//==============================================================
// Initialization
//==============================================================

//--------------------------------------------------------------
// SelectSpawnPoint -- Returns the entity to spawn at
//--------------------------------------------------------------
entity() player_init_selectspawnpoint =
{
local entity spot, thing;
local float pcount;

// testinfo_player_start is only found in regioned levels
spot = findfloat (world, classtype, CT_INFO_TESTPLAYERSTART);
if (spot)
return spot;

// choose a info_player_deathmatch point
if (coop)
{
lastspawn = findfloat (lastspawn, classtype,
CT_INFO_PLAYER_COOP);
if (lastspawn == world)
lastspawn = findfloat (lastspawn, classtype,
CT_INFO_PLAYER_START);
if (lastspawn != world)
return lastspawn;
}
else if (deathmatch)
{
spot = lastspawn;
// TODO CEV this loops infinitely if no
// info_player_deathmatch
while (1)
{
spot = findfloat (spot, classtype,
CT_INFO_PLAYER_DEATHMATCH);
if (spot != world)
{
if (spot == lastspawn)
return lastspawn;
pcount = 0;
thing = findradius (spot.origin, 32);
while (thing)
{
if (thing.classtype==CT_PLAYER)
pcount = pcount + 1;
thing = thing.chain;
}
if (pcount == 0)
{
lastspawn = spot;
return spot;
}
}
}
}

if (serverflags)
{
// return with a rune to start
spot = findfloat (world, classtype,
CT_INFO_PLAYER_START2);
if (spot)
return spot;
}

spot = findfloat (world, classtype, CT_INFO_PLAYER_START);
if (!spot)
error ("player_init_selectspawnpoint: "
"no info_player_start on level");

return spot;
};

//--------------------------------------------------------------
void() player_init_level_parms =
{
// Reset the player's inventory if they returned to the
// start map with a rune, or if the mapper set the
// "reset_items" field of worldspawn to a non-zero value.
// (The old "reset_items" check, which this replaces,
// had a comment from dumptruck_ds thanking Spike.) -- iw
if ((serverflags != 0 && world.model == "maps/start.bsp") ||
world.reset_items != 0)
{
SetNewParms ();
}

self.items = parm1;
self.health = parm2;
self.armorvalue = parm3;
self.ammo_shells = parm4;
self.ammo_nails = parm5;
self.ammo_rockets = parm6;
self.ammo_cells = parm7;
self.weapon = parm8;
self.armortype = parm9 * 0.01;
};

//--------------------------------------------------------------
// respawn -- called by ClientKill and DeadThink
//--------------------------------------------------------------
void() player_respawn =
{
if (coop)
{
// make a copy of the dead body for appearances sake
CopyToBodyQue (self);
// get the spawn parms as they were at level start
setspawnparms (self);
// respawn
player_init (self);
}
else if (deathmatch)
{
// make a copy of the dead body for appearances sake
CopyToBodyQue (self);
// set default spawn parms
SetNewParms ();
// respawn
player_init (self);
}
else
{
// restart the entire server
localcmd ("restart\n");
}
};

//--------------------------------------------------------------
// most of this was previously in PutClientInServer -- CEV
//--------------------------------------------------------------
void(entity e) player_init =
{
local entity spot;

spot = player_init_selectspawnpoint ();

e.classname = "player";
e.classtype = CT_PLAYER;
e.health = PLAYER_HEALTH;
e.takedamage = DAMAGE_AIM;
e.solid = SOLID_SLIDEBOX;
// e.solid = SOLID_BBOX;
e.movetype = MOVETYPE_WALK;
e.show_hostile = 0;
e.max_health = 100;
e.flags = FL_CLIENT;
e.air_finished = time + 12;
// initial water damage
e.dmg = 2;
e.super_damage_finished = 0;
e.radsuit_finished = 0;
e.invisible_finished = 0;
e.invincible_finished = 0;
e.effects = 0;
e.invincible_time = 0;
e.deathtype = "";
e.gravity = 0;
e.wantedgravity = 0;
// support for item_key_custom -- iw
e.customkeys = 0;

// Setup cutscene stuff. Legacy code from Zerstorer.
// -- dumptruck_ds
e.script_count = 2;
e.script_delay = 1;
e.script_time = 0;

player_init_level_parms ();
player_set_current_ammo ();

e.attack_finished = time;
e.pain = player_pain;
e.destroy = player_destroy;
e.touch = player_touch;
e.SendEntity = player_sendentity;
e.deadflag = DEAD_NO;
// pausetime is set by teleporters to keep the player
// from moving for a while
e.pausetime = 0;

e.origin = spot.origin + '0 0 1';
e.angles = spot.angles;
// turn this way immediately
e.fixangle = TRUE;

// fog control.
// Looks if there's any fog values set at the current
// spawn point. If not, looks for those in worldspawn instead
if (spot.fog_density)
fog_save (e, spot.fog_density, spot.fog_color);
else if (world.fog_density)
fog_save (e, world.fog_density, world.fog_color);

if (spot.skyfog_density)
skyfog_save (e, spot.skyfog_density);
else if (world.skyfog_density)
skyfog_save (e, world.skyfog_density);

// decreased on subsequent frames, used to start some
// fog-related stuff
clean_up_client_stuff = 2;

// oh, this is a hack!
setmodel (e, "progs/eyes.mdl");
modelindex_eyes = e.modelindex;

// Drake -- dumptruck_ds
setmodel (e, "progs/s_null.spr");
// Drake -- dumptruck_ds
// setmodel (e, "progs/null_256.spr");
mindex_inviso = e.modelindex;

setmodel (e, "progs/player.mdl");
modelindex_player = e.modelindex;

setsize (e, VEC_HULL_MIN, VEC_HULL_MAX);

e.view_ofs = '0 0 22';
// Mod - Xian (May.20.97)
// Bug where player would have velocity from their last kill
e.velocity = '0 0 0';
// 1998-07-21 Player moves after respawn fix by Xian

e.SendFlags = 0xffffff;

// pl_stand1 needs 'self' to be 'e' -- CEV
if (self == e)
pl_stand1 ();
else
sub_runvoidas (e, pl_stand1);

if (deathmatch || coop)
{
makevectors (e.angles);
spawn_tfog (e.origin + v_forward * 20);
}

spawn_tdeath (e.origin, e);
};

//--------------------------------------------------------------
strip void() player =
{
player_init (self);
};
// };

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Scenic Dead Monster Patch stuff here from DeadStuff mod -- dumptruck_ds
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

/*QUAKED gib_head_player (0 0.5 0.8) (-16 -16 0) (16 16 56) SOLID X X X X X X X NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER X NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{
model ("progs/h_player.mdl");
}*/
//----------------------------------------------------------------------
// class gib_head_player: base_gib_head
// {
//--------------------------------------------------------------
// ThrowHead
//--------------------------------------------------------------
void(entity act, vector dir, float dmg) throw_gib_head_player =
{
base_gib_head_throw (act, dir, dmg, gib_head_player_init);
};

//--------------------------------------------------------------
void(entity e) gib_head_player_init =
{
// don't reset class if passed a client entity -- CEV
if (!(e.flags & FL_CLIENT))
{
e.classname = "gib_head_player";
e.classtype = CT_GORE_HEAD_PLAYER;
}

// gib_init interprets spawnflags and will set .solid -- CEV
base_gib_head_init (e);

if (e.mdl_head != "")
{
precache_model (e.mdl_head);
setmodel (e, e.mdl_head);
}
else
{
precache_model ("progs/h_player.mdl");
setmodel (e, "progs/h_player.mdl");
if (e.solid == SOLID_BBOX)
setsize (e, PLAYER_HEAD_MINS, PLAYER_HEAD_MAXS);
else if (e.solid == SOLID_TRIGGER)
setsize (e, '-16 -16 0', '16 16 56');
}

e.frame = 0;
};

//--------------------------------------------------------------
void() gib_head_player =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

gib_head_player_init (self);
};
// };

/*QUAKED player_dead_axe (0 0.5 0.8) (-16 -16 -24) (16 16 32) SOLID X X X X X X X NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER X NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{
model ({"path":"progs/player.mdl","frame":49});
}
*/
void() player_dead_axe =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

precache_model ("progs/player.mdl");
setmodel (self, "progs/player.mdl");
self.frame = $axdeth9;

if (self.spawnflags & 1)
{
self.solid = SOLID_BBOX;
setsize (self,'-38.72 -5.83 -50.45','28.73 33.85 30');
}
else
{
self.solid = SOLID_NOT;
}
};

/*QUAKED player_dead_face_down (0 0.5 0.8) (-16 -16 -24) (16 16 32) SOLID X X X X X X X NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER X NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{
model ({"path":"progs/player.mdl","frame":84});
}
*/
void() player_dead_face_down =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

precache_model ("progs/player.mdl");
setmodel (self, "progs/player.mdl");
self.frame = $deathc14;

if (self.spawnflags & 1)
{
self.solid = SOLID_BBOX;
setsize (self,'-50.28 -23.55 -49.85','30.66 14.49 30');
}
else
{
self.solid = SOLID_NOT;
}
};

/*QUAKED player_dead_on_side (0 0.5 0.8) (-16 -16 -24) (16 16 32) SOLID X X X X X X X NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER X NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{
model ({"path":"progs/player.mdl","frame":102});
}
*/
void() player_dead_on_side =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

precache_model ("progs/player.mdl");
setmodel (self, "progs/player.mdl");
self.frame = $deathe9;

if (self.spawnflags & 1)
{
self.solid = SOLID_BBOX;
setsize (self,'-38.72 -5.83 -50.45','28.73 33.85 30');
}
else
{
self.solid = SOLID_NOT;
}
};

//======================================================================
// END Scenic Dead Monster Patch stuff here from DeadStuff mod -- dumptruck_ds
//======================================================================

Return to the top of this page or return to the overview of this repo.

Log playerclient.qc

Date Commit Message Author + -
2024-04-12 Moveable gibs, heads, some bugfixes cev +110 -111
2024-04-08 Registered monsters, projectile bugfixes cev +5  
2024-04-05 Player footsteps, shareware monsters, misc? cev +209 -37
2024-03-24 2nd pass refactor, rework QC class structure cev +1051 -994
2024-02-27 Bullet projectile, pmove changes, misc cev +52 -7
2024-02-18 Client/player, projectiles, entrypoints refactor cev +2571  

Return to the top of this page or return to the overview of this repo.