game-source/klik/act/act_player.qc
Ragnvald Maartmann-Moe IV 1cb1b902f9 Beware. klik of death.
2004-02-09 04:25:00 +00:00

768 lines
16 KiB
C++

#include "common.qh"
#include "damage.qh"
#include "mdl.qh"
#include "client.qh"
#include "server.qh"
#include "misc.qh"
#include "items.qh"
#include "weapon.qh"
#include "equip.qh"
#include "act.qh"
#include "act_player.qh"
#include "override.qh"
void ()
act_player_init =
{
precache_sound ("player/plyrjmp8.wav");
precache_sound ("player/h2ojump.wav");
precache_sound ("player/land.wav");
precache_sound ("player/land2.wav");
precache_sound ("player/inh2o.wav");
precache_sound ("player/slimbrn2.wav");
precache_sound ("player/inlava.wav");
precache_sound ("misc/water1.wav");
precache_sound ("misc/water2.wav");
precache_sound ("player/drown1.wav");
precache_sound ("player/drown2.wav");
precache_sound ("player/lburn1.wav");
precache_sound ("player/lburn2.wav");
precache_sound ("player/gasp1.wav");
precache_sound ("player/gasp2.wav");
precache_sound ("misc/outwater.wav");
precache_sound ("player/pain1.wav");
precache_sound ("player/pain2.wav");
precache_sound ("player/pain3.wav");
precache_sound ("player/pain4.wav");
precache_sound ("player/pain5.wav");
precache_sound ("player/pain6.wav");
precache_sound ("player/death1.wav");
precache_sound ("player/death2.wav");
precache_sound ("player/death3.wav");
precache_sound ("player/death4.wav");
precache_sound ("player/death5.wav");
precache_sound ("player/gib.wav");
precache_sound ("player/udeath.wav");
precache_sound ("player/h2odeath.wav");
precache_model ("progs/backpack.mdl");
precache_sound ("weapons/lock4.wav");
precache_sound ("items/itembk2.wav");
};
// ========================================================================
void (float scl)
player_throw_ammo =
{
local entity player;
player = self;
self = spawn ("BACKPACK");
if (scl > 1) {
/* FIXME: This is actually a hack to avoid powerups */
#define qg(eid) \
if (equip_query (player, eid)) \
equip_grant (self, eid) \
qg (EQUIPID_SUPER_SHOTGUN);
qg (EQUIPID_NAILGUN);
qg (EQUIPID_SUPER_NAILGUN);
qg (EQUIPID_GRENADE_LAUNCHER);
qg (EQUIPID_ROCKET_LAUNCHER);
qg (EQUIPID_LIGHTNING_GUN);
#undef qg
player.itemfield_1 = 0;
player.itemfield_2 = 0;
player.itemfield_3 = 0;
player.itemfield_4 = 0;
scl = 1;
}
self.ammo_shells = player.ammo_shells * scl;
player.ammo_shells -= self.ammo_shells;
self.ammo_nails = player.ammo_nails * scl;
player.ammo_nails -= self.ammo_nails;
self.ammo_rockets = player.ammo_rockets * scl;
player.ammo_rockets -= self.ammo_rockets;
self.ammo_cells = player.ammo_cells * scl;
player.ammo_cells -= self.ammo_cells;
if (!self.ammo_shells && !self.ammo_nails && !self.ammo_rockets
&& !self.ammo_cells && !self.itemfield_1 && !self.itemfield_2
&& !self.itemfield_3 && !self.itemfield_4) {
remove (self);
self = player;
return;
}
self.origin = center (player);
self.movetype = MOVETYPE_TOSS;
self.velocity_x = crandom () * 100;
self.velocity_y = crandom () * 100;
self.velocity_z = 200;
self.mins = '-16 -16 0';
self.maxs = '16 16 56';
self.model = "progs/backpack.mdl";
self.noise2 = "weapons/lock4.wav";
self.noise7 = "items/itembk2.wav";
self.wait = -1;
self.think = SUB_remove;
self.nextthink = time + 20 + random () *20;
item_generic ();
self = player;
};
void ()
player_die =
{
local float r;
if (self.health > CONFIG_GIB_HEALTH) {
if (self.waterlevel >= 3) {
self.noise = "player/h2odeath.wav";
} else {
r = random () * 5;
if (r < 1)
self.noise = "player/death1.wav";
else if (r < 2)
self.noise = "player/death2.wav";
else if (r < 3)
self.noise = "player/death3.wav";
else if (r < 4)
self.noise = "player/death4.wav";
else
self.noise = "player/death5.wav";
}
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NONE);
player_throw_ammo (2);
mdl_bodyque_and_func (MDL_FUNC_DIE, floor (random () * 5));
} else {
r = random () * 2;
if (r < 1)
self.noise = "player/gib.wav";
else
self.noise = "player/udeath.wav";
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NONE);
mdl_bodyque_and_func (MDL_FUNC_GIB, 0);
}
makevectors (self.angles); /* Not v_angle! */
self.velocity = (v_forward * -200) + (v_up * 100);
if (self.v_angle_x < 75 && self.v_angle_x > -75) {
self.angles = self.v_angle;
self.angles_x += 20;
self.fixangle = TRUE;
}
/* FIXME: Hack. */
setorigin (self, vieworigin (self));
RemoveClientFromGame ();
};
// ========================================================================
float (float d)
_player_takedamage_core =
{
self.health -= d;
self.dmg_take += d;
if (floor (self.health) <= 0) {
deathmsg_display ();
player_die ();
} else {
deathmsg_nodisplay ();
self.mdl_func (MDL_FUNC_PAIN, d);
}
return TRUE;
};
float (float d)
player_takedamage =
{
local float taked, r;
damage_push (d);
taked = damage_armor (d);
self.dmg_save += (d - taked);
if (taked <= 0)
return FALSE;
if (self.pain_finished < time) {
if ((self.mdl_mod & MDL_MOD_SWIM_IN) && self.air_finished < (time + random () * 9)) {
r = random () * 2;
if (r < 1)
self.noise = "player/drown2.wav";
else
self.noise = "player/drown1.wav";
} else {
r = random () * 5;
if (r < 1)
self.noise = "player/pain1.wav";
else if (r < 2)
self.noise = "player/pain2.wav";
else if (r < 3)
self.noise = "player/pain3.wav";
else if (r < 4)
self.noise = "player/pain4.wav";
else if (r < 5)
self.noise = "player/pain5.wav";
else
self.noise = "player/pain6.wav";
}
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.pain_finished = time + 1;
}
return _player_takedamage_core (taked);
};
// ========================================================================
float (float d)
_player_takedamage_drown =
{
local float r;
if (d <= 0)
return FALSE;
if (self.pain_finished < time) {
r = random () * 2;
if (r < 1)
self.noise = self.noise3;
else
self.noise = self.noise4;
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.pain_finished = time + 1;
}
return _player_takedamage_core (d);
};
float (float d)
_player_takedamage_melt =
{
local float taked, r;
taked = damage_armor (d);
self.dmg_save += d - taked;
if (taked <= 0)
return FALSE;
if (self.pain_finished < time) {
r = random () * 2;
if (r < 1)
self.noise = self.noise3;
else
self.noise = self.noise4;
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.pain_finished = time + 1;
}
return _player_takedamage_core (taked);
};
float (float d, float (float d) damg_func, void () deathmessage)
_player_damage_custom =
{
local float ret;
override_set_th_takedamage (self, damg_func);
ret = damage (self, self, world, d, deathmessage);
override_set_th_takedamage (self, player_takedamage);
return ret;
};
// ========================================================================
void ()
_deathmsg_player_liquid =
{
local string def_nname;
local float r;
def_nname = name (self);
switch (self.watertype) {
case CONTENT_WATER:
r = random () * 2;
if (r < 1)
bprint (PRINT_DEATH, def_nname, " sleeps with the fishes.\n");
else
bprint (PRINT_DEATH, def_nname, " hunts for air.\n");
break;
case CONTENT_SLIME:
r = random () * 2;
if (r < 1)
bprint (PRINT_DEATH, def_nname, " can't exist on slime alone.\n");
else
bprint (PRINT_DEATH, def_nname, " floats in slime.\n");
break;
case CONTENT_LAVA:
r = random () * 3;
if (r < 1)
bprint (PRINT_DEATH, def_nname, " swam in a volcano.\n");
else if (r < 2)
bprint (PRINT_DEATH, def_nname, " turned into hot slag.\n");
else
bprint (PRINT_DEATH, def_nname, " parties with Chthon.\n");
break;
default:
bprint (PRINT_DEATH, def_nname, " gulps it down.\n");
break;
}
};
void ()
_deathmsg_player_fall =
{
local string def_name;
local float r;
def_name = name (self);
r = random () * 3;
if (r < 1)
bprint (PRINT_DEATH, def_name, " landed head-first.\n");
else if (r < 2)
bprint (PRINT_DEATH, def_name, " cratered.\n");
else
bprint (PRINT_DEATH, def_name,
" took a nose dive into the ground.\n");
};
// ========================================================================
/* This is so stupid. */
float ()
_player_jump =
{
if (!self.button2) {
self.flags |= FL_JUMPRELEASED;
return FALSE;
}
if (!(self.flags & FL_ONGROUND))
return FALSE;
if (!(self.flags & FL_JUMPRELEASED))
return FALSE;
self.mdl_func (MDL_FUNC_JUMP, 0);
self.flags &= ~FL_JUMPRELEASED;
self.button2 = 0;
return TRUE;
};
void ()
_player_water_jump =
{
if (self.waterlevel <= 1) {
if (_player_jump())
sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
return;
}
if (self.waterlevel <= 2) {
if (_player_jump ())
sound (self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM);
}
/* Yeah. The engine is a piece of crap. */
if (self.button2) {
if (self.flags & FL_ONGROUND) {
self.flags &= ~FL_ONGROUND;
self.origin_z++;
}
}
};
/* This is called every frame... */
void ()
player_prethink =
{
/* Gasp for air if we weren't swimming..
/* Checking here rather than later, with mdl_mod is a HACK */
/* It avoids the gasp when the player hasn't communicated
with the server in a while (it happens..) */
if (self.waterlevel < 3) {
if (self.mdl_mod & MDL_MOD_SWIM_IN) {
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;
}
/* Let the MDL (and us) know we're swimming */
self.mdl_mod &= ~MDL_MOD_SWIM;
if (self.waterlevel >= 3)
self.mdl_mod |= MDL_MOD_SWIM_IN;
else if (self.waterlevel >= 1)
self.mdl_mod |= MDL_MOD_SWIM_OVER;
/* Handle environmental damage */
if (self.watertype == CONTENT_SLIME) {
self.noise3 = "player/lburn1.wav";
self.noise4 = "player/lburn2.wav";
_player_damage_custom (4 * self.waterlevel * frametime,
_player_takedamage_melt,
_deathmsg_player_liquid);
} else if (self.watertype == CONTENT_LAVA) {
self.noise3 = "player/lburn1.wav";
self.noise4 = "player/lburn2.wav";
_player_damage_custom (50 * self.waterlevel * frametime,
_player_takedamage_melt,
_deathmsg_player_liquid);
}
/* Try to breathe :) */
if (self.air_finished < time) {
local float damg;
damg = (time - self.air_finished) * 0.2;
if (damg > 1.5)
damg = 1.5;
self.noise3 = "player/drown1.wav";
self.noise4 = "player/drown2.wav";
_player_damage_custom (damg, _player_takedamage_drown,
_deathmsg_player_liquid);
}
/* Enter/exit water, swim sound */
if (!self.waterlevel) {
if (self.flags & FL_INWATER) {
sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
self.flags &= ~FL_INWATER;
}
if (_player_jump())
sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
} else {
if (!(self.flags & FL_INWATER)) {
if (self.watertype == CONTENT_WATER)
self.noise = "player/inh2o.wav";
else if (self.watertype == CONTENT_SLIME)
self.noise = "player/slimbrn2.wav";
else if (self.watertype == CONTENT_LAVA)
self.noise = "player/inlava.wav";
sound (self, CHAN_BODY, self.noise, 1, ATTN_NORM);
self.flags = (self.flags & ~FL_JUMPRELEASED) | FL_INWATER;
self.water_finished = 0;
}
if (self.mdl_mod&MDL_MOD_SWIM) {
local float increment, mxspeed;
increment = vlen (self.origin - self.pos1);
mxspeed = calc_max_speed (self);
if (increment > mxspeed)
increment = mxspeed;
self.water_finished += increment;
if (self.water_finished >= mxspeed) {
self.water_finished = 0;
if (random () < 0.5)
self.noise = "misc/water1.wav";
else
self.noise = "misc/water2.wav";
sound (self, CHAN_BODY, self.noise, 1, ATTN_NORM);
}
}
_player_water_jump ();
}
self.pos1 = self.origin;
#if DEBUG
debug_impulse ();
#endif
weapon_player_impulse ();
};
/* This is not called every frame */
void ()
player_think =
{ // The player does not think.
};
/* FIXME: We should check to see if we actually collided.
I don't know how to at the moment... */
void ()
player_velocity_damage =
{
local vector vel, dir;
local float v1, v2;
vel = self.movedir;
self.movedir = self.velocity;
/* Did we just teleport? */
if (self.teleport_time)
return;
/* Did we slow down a lot? */
v1 = vlen (vel);
v2 = vlen (self.velocity);
if (v2 >= v1)
return;
vel = vel - self.velocity;
vel_z = vel_z * 2;
v1 = vlen (vel);
/* Find the largest magnitude dir */
vel_x = fabs (vel_x);
vel_y = fabs (vel_y);
vel_z = fabs (vel_z);
dir = '0 0 1';
if (vel_y > (vel * dir))
dir = '0 1 0';
if (vel_x > (vel * dir))
dir = '1 0 0';
/* Play sounds, apply damage */
if (v1 > CONFIG_LAND_SOUND) {
if (dir_z && (self.watertype == CONTENT_WATER)) {
self.noise = "player/h2ojump.wav";
} else if (v1 > CONFIG_LAND_HURT) {
self.noise = "player/land2.wav";
self.pain_finished = time + 1;
damage (self, self, world, 5, _deathmsg_player_fall);
} else {
self.noise = "player/land.wav";
}
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
}
};
/* This is also called every frame... */
void ()
player_postthink =
{
player_velocity_damage ();
self.items &= ~(IT_ARMOR1|IT_ARMOR2|IT_ARMOR3);
if (self.armortype >= 0.8)
self.items |= IT_ARMOR3;
else if (self.armortype >= 0.6)
self.items |= IT_ARMOR2;
else if (self.armortype >= 0.3)
self.items |= IT_ARMOR1;
update_weapon_flags ();
weapon_set_ammo ();
};
// ========================================================================
void (float nitem, string str1, string str2)
_item_xprint_strs =
{
if (!is_cl (self))
return;
if (!str1)
return;
if (nitem == 1) {
stuffcmd (self, "bf\n");
xprint_start (self, PRINT_LOW);
xprint_str ("You get ");
} else if (nitem > 1)
xprint_str (", ");
xprint_str (str1);
if (str2)
xprint_str (str2);
};
void (float nitem, string str1, string str2)
_item_xprint_strs_last =
{
if (!is_cl(self))
return;
if (!str1)
return;
if (nitem == 1) {
stuffcmd (self, "bf\n");
xprint_start (self, PRINT_LOW);
xprint_str ("You get ");
}
if (nitem == 2)
xprint_str (" and ");
else if (nitem > 2)
xprint_str (", and ");
xprint_str (str1);
if (str2)
xprint_str (str2);
xprint_str ("\n");
};
float nitem;
string str1, str2;
void (.float fld, float max, string sing, string plur)
_player_takefield =
{
local float new, diff;
new = increase_bound (self.fld, other.fld, max);
if (new > 999)
new = 999;
if (new > self.fld) {
diff = floor (new) - floor (self.fld);
if (!diff)
diff = new - self.fld;
_item_xprint_strs (nitem, str1, str2);
str1 = ftos (diff);
if (diff == 1)
str2 = sing;
else
str2 = plur;
nitem++;
self.fld = new;
}
};
float ()
player_takeitem =
{
local float eid;
nitem = 0;
str1 = NIL;
str2 = NIL;
while ((eid = equip_iter (other)) != -1) {
if (equip_query (self, eid))
continue;
equip_grant (self, eid);
_item_xprint_strs (nitem, str1, str2);
str1 = "the ";
str2 = equip_id_to_string (eid);
nitem++;
}
_player_takefield (ammo_shells, self.max_ammo_shells, " shell", " shells");
_player_takefield (ammo_nails, self.max_ammo_nails, " nail", " nails");
_player_takefield (ammo_rockets, self.max_ammo_rockets, " rocket",
" rockets");
_player_takefield (ammo_cells, self.max_ammo_cells, " cell", " cells");
if (other.armorvalue <= self.max_armor) {
if ((other.armorvalue * other.armortype)
> (self.armorvalue * self.armortype)) {
self.armorvalue = other.armorvalue;
self.armortype = other.armortype;
_item_xprint_strs (nitem, str1, str2);
str2 = NIL;
if (self.armortype >= 0.8)
str1 = "strong armor";
else if (self.armortype >= 0.6)
str1 = "medium armor";
else if (self.armortype >= 0.3)
str1 = "light armor";
else
str1 = "really crappy armor";
nitem++;
}
}
_player_takefield (health, self.max_health, " health", " health");
_item_xprint_strs_last (nitem, str1, str2);
if (nitem)
return TRUE;
return FALSE;
};
// ===================================================================== //
void ()
act_setup_player ={
act_setup ();
self.movedir = '0 0 0';
self.solid = SOLID_SLIDEBOX;
self.takedamage = DAMAGE_AIM;
self.movetype = MOVETYPE_WALK;
self.deadflag = DEAD_NO;
self.gravity = 1;
self.maxspeed = sv_maxspeed;
self.mass = 1000;
self.air_finished = time + 12;
self.pain_finished = 0;
self.water_finished = 0;
override_set_th_takeitem (self, player_takeitem);
override_set_th_takedamage (self, player_takedamage);
override_set_prethink (self, player_prethink);
override_set_actthink (self, player_think);
override_set_postthink (self, player_postthink);
};