Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Just kind of shoving the QuakeWorld QuakeC source in here.

  • Loading branch information...
commit bf4ac424ce754894ac8f1dae6a3981954bc9852d 1 parent 0023db3
@tbradshaw tbradshaw authored
View
166 qw-qc/buttons.qc
@@ -0,0 +1,166 @@
+/*
+ buttons.qc
+
+ button and multiple button
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to:
+
+ Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330
+ Boston, MA 02111-1307, USA
+
+*/
+
+void() button_wait;
+void() button_return;
+
+void() button_wait =
+{
+ self.state = STATE_TOP;
+ self.nextthink = self.ltime + self.wait;
+ self.think = button_return;
+ activator = self.enemy;
+ SUB_UseTargets();
+ self.frame = 1; // use alternate textures
+};
+
+void() button_done =
+{
+ self.state = STATE_BOTTOM;
+};
+
+void() button_return =
+{
+ self.state = STATE_DOWN;
+ SUB_CalcMove (self.pos1, self.speed, button_done);
+ self.frame = 0; // use normal textures
+ if (self.health)
+ self.takedamage = DAMAGE_YES; // can be shot again
+};
+
+
+void() button_blocked =
+{ // do nothing, just don't ome all the way back out
+};
+
+
+void() button_fire =
+{
+ if (self.state == STATE_UP || self.state == STATE_TOP)
+ return;
+
+ sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
+
+ self.state = STATE_UP;
+ SUB_CalcMove (self.pos2, self.speed, button_wait);
+};
+
+
+void() button_use =
+{
+ self.enemy = activator;
+ button_fire ();
+};
+
+void() button_touch =
+{
+ if (other.classname != "player")
+ return;
+ self.enemy = other;
+ button_fire ();
+};
+
+void() button_killed =
+{
+ self.enemy = damage_attacker;
+ self.health = self.max_health;
+ self.takedamage = DAMAGE_NO; // wil be reset upon return
+ button_fire ();
+};
+
+
+/*QUAKED func_button (0 .5 .8) ?
+When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
+
+"angle" determines the opening direction
+"target" all entities with a matching targetname will be used
+"speed" override the default 40 speed
+"wait" override the default 1 second wait (-1 = never return)
+"lip" override the default 4 pixel lip remaining at end of move
+"health" if set, the button must be killed instead of touched
+"sounds"
+0) steam metal
+1) wooden clunk
+2) metallic click
+3) in-out
+*/
+void() func_button =
+{
+local float gtemp, ftemp;
+
+ if (self.sounds == 0)
+ {
+ precache_sound ("buttons/airbut1.wav");
+ self.noise = "buttons/airbut1.wav";
+ }
+ if (self.sounds == 1)
+ {
+ precache_sound ("buttons/switch21.wav");
+ self.noise = "buttons/switch21.wav";
+ }
+ if (self.sounds == 2)
+ {
+ precache_sound ("buttons/switch02.wav");
+ self.noise = "buttons/switch02.wav";
+ }
+ if (self.sounds == 3)
+ {
+ precache_sound ("buttons/switch04.wav");
+ self.noise = "buttons/switch04.wav";
+ }
+
+ SetMovedir ();
+
+ self.movetype = MOVETYPE_PUSH;
+ self.solid = SOLID_BSP;
+ setmodel (self, self.model);
+
+ self.blocked = button_blocked;
+ self.use = button_use;
+
+ if (self.health)
+ {
+ self.max_health = self.health;
+ self.th_die = button_killed;
+ self.takedamage = DAMAGE_YES;
+ }
+ else
+ self.touch = button_touch;
+
+ if (!self.speed)
+ self.speed = 40;
+ if (!self.wait)
+ self.wait = 1;
+ if (!self.lip)
+ self.lip = 4;
+
+ self.state = STATE_BOTTOM;
+
+ self.pos1 = self.origin;
+ self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
+};
+
View
1,524 qw-qc/client.qc
@@ -0,0 +1,1524 @@
+/*
+ client.qc
+
+ client functions
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to:
+
+ Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330
+ Boston, MA 02111-1307, USA
+
+*/
+
+// prototypes
+void () W_WeaponFrame;
+void() W_SetCurrentAmmo;
+void() player_pain;
+void() player_stand1;
+void (vector org) spawn_tfog;
+void (vector org, entity death_owner) spawn_tdeath;
+
+float modelindex_eyes, modelindex_player;
+
+/*
+=============================================================================
+
+ LEVEL CHANGING / INTERMISSION
+
+=============================================================================
+*/
+
+string nextmap;
+
+float intermission_running;
+float intermission_exittime;
+
+/*QUAKED info_intermission (1 0.5 0.5) (-16 -16 -16) (16 16 16)
+This is the camera point for the intermission.
+Use mangle instead of angle, so you can set pitch or roll as well as yaw. 'pitch roll yaw'
+*/
+void() info_intermission =
+{
+ self.angles = self.mangle; // so C can get at it
+};
+
+
+
+void() SetChangeParms =
+{
+ if (self.health <= 0)
+ {
+ SetNewParms ();
+ return;
+ }
+
+// remove items
+ self.items = self.items - (self.items &
+ (IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY | IT_SUIT | IT_QUAD) );
+
+// cap super health
+ if (self.health > 100)
+ self.health = 100;
+ if (self.health < 50)
+ self.health = 50;
+ parm1 = self.items;
+ parm2 = self.health;
+ parm3 = self.armorvalue;
+ if (self.ammo_shells < 25)
+ parm4 = 25;
+ else
+ parm4 = self.ammo_shells;
+ parm5 = self.ammo_nails;
+ parm6 = self.ammo_rockets;
+ parm7 = self.ammo_cells;
+ parm8 = self.weapon;
+ parm9 = self.armortype * 100;
+};
+
+void() SetNewParms =
+{
+ parm1 = IT_SHOTGUN | IT_AXE;
+ parm2 = 100;
+ parm3 = 0;
+ parm4 = 25;
+ parm5 = 0;
+ parm6 = 0;
+ parm7 = 0;
+ parm8 = 1;
+ parm9 = 0;
+};
+
+void() DecodeLevelParms =
+{
+ if (serverflags)
+ {
+ if (world.model == "maps/start.bsp")
+ SetNewParms (); // take away all stuff on starting new episode
+ }
+
+ 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;
+};
+
+/*
+============
+FindIntermission
+
+Returns the entity to view from
+============
+*/
+entity() FindIntermission =
+{
+ local entity spot;
+ local float cyc;
+
+// look for info_intermission first
+ spot = find (world, classname, "info_intermission");
+ if (spot)
+ { // pick a random one
+ cyc = random() * 4;
+ while (cyc > 1)
+ {
+ spot = find (spot, classname, "info_intermission");
+ if (!spot)
+ spot = find (spot, classname, "info_intermission");
+ cyc = cyc - 1;
+ }
+ return spot;
+ }
+
+// then look for the start position
+ spot = find (world, classname, "info_player_start");
+ if (spot)
+ return spot;
+
+ objerror ("FindIntermission: no spot");
+};
+
+
+void() GotoNextMap =
+{
+ local string newmap;
+
+//ZOID: 12-13-96, samelevel is overloaded, only 1 works for same level
+
+ if (cvar("samelevel") == 1) // if samelevel is set, stay on same level
+ changelevel (mapname);
+ else {
+ // configurable map lists, see if the current map exists as a
+ // serverinfo/localinfo var
+ newmap = infokey(world, mapname);
+ if (newmap != "")
+ changelevel (newmap);
+ else
+ changelevel (nextmap);
+ }
+};
+
+
+
+/*
+============
+IntermissionThink
+
+When the player presses attack or jump, change to the next level
+============
+*/
+void() IntermissionThink =
+{
+ if (time < intermission_exittime)
+ return;
+
+ if (!self.button0 && !self.button1 && !self.button2)
+ return;
+
+ GotoNextMap ();
+};
+
+/*
+============
+execute_changelevel
+
+The global "nextmap" has been set previously.
+Take the players to the intermission spot
+============
+*/
+void() execute_changelevel =
+{
+ local entity pos;
+
+ intermission_running = 1;
+
+// enforce a wait time before allowing changelevel
+ intermission_exittime = time + 5;
+
+ pos = FindIntermission ();
+
+// play intermission music
+ WriteByte (MSG_ALL, SVC_CDTRACK);
+ WriteByte (MSG_ALL, 3);
+
+ WriteByte (MSG_ALL, SVC_INTERMISSION);
+ WriteCoord (MSG_ALL, pos.origin_x);
+ WriteCoord (MSG_ALL, pos.origin_y);
+ WriteCoord (MSG_ALL, pos.origin_z);
+ WriteAngle (MSG_ALL, pos.mangle_x);
+ WriteAngle (MSG_ALL, pos.mangle_y);
+ WriteAngle (MSG_ALL, pos.mangle_z);
+
+ other = find (world, classname, "player");
+ while (other != world)
+ {
+ other.takedamage = DAMAGE_NO;
+ other.solid = SOLID_NOT;
+ other.movetype = MOVETYPE_NONE;
+ other.modelindex = 0;
+ other = find (other, classname, "player");
+ }
+
+};
+
+
+void() changelevel_touch =
+{
+ local entity pos;
+
+ if (other.classname != "player")
+ return;
+
+// if "noexit" is set, blow up the player trying to leave
+//ZOID, 12-13-96, noexit isn't supported in QW. Overload samelevel
+// if ((cvar("noexit") == 1) || ((cvar("noexit") == 2) && (mapname != "start")))
+ if ((cvar("samelevel") == 2) || ((cvar("samelevel") == 3) && (mapname != "start")))
+ {
+ T_Damage (other, self, self, 50000);
+ return;
+ }
+
+ bprint (PRINT_HIGH, other.netname);
+ bprint (PRINT_HIGH," exited the level\n");
+
+ nextmap = self.map;
+
+ SUB_UseTargets ();
+
+ self.touch = SUB_Null;
+
+// we can't move people right now, because touch functions are called
+// in the middle of C movement code, so set a think time to do it
+ self.think = execute_changelevel;
+ self.nextthink = time + 0.1;
+};
+
+/*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION
+When the player touches this, he gets sent to the map listed in the "map" variable. Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display stats.
+*/
+void() trigger_changelevel =
+{
+ if (!self.map)
+ objerror ("chagnelevel trigger doesn't have map");
+
+ InitTrigger ();
+ self.touch = changelevel_touch;
+};
+
+
+/*
+=============================================================================
+
+ PLAYER GAME EDGE FUNCTIONS
+
+=============================================================================
+*/
+
+void() set_suicide_frame;
+
+// called by ClientKill and DeadThink
+void() respawn =
+{
+ // make a copy of the dead body for appearances sake
+ CopyToBodyQue (self);
+ // set default spawn parms
+ SetNewParms ();
+ // respawn
+ PutClientInServer ();
+};
+
+
+/*
+============
+ClientKill
+
+Player entered the suicide command
+============
+*/
+void() ClientKill =
+{
+ bprint (PRINT_MEDIUM, self.netname);
+ bprint (PRINT_MEDIUM, " suicides\n");
+ set_suicide_frame ();
+ self.modelindex = modelindex_player;
+ logfrag (self, self);
+ self.frags = self.frags - 2; // extra penalty
+ respawn ();
+};
+
+float(vector v) CheckSpawnPoint =
+{
+ return FALSE;
+};
+
+/*
+============
+SelectSpawnPoint
+
+Returns the entity to spawn at
+============
+*/
+entity() SelectSpawnPoint =
+{
+ local entity spot, newspot, thing;
+ local float numspots, totalspots;
+ local float rnum, pcount;
+ local float rs;
+ local entity spots;
+
+ numspots = 0;
+ totalspots = 0;
+
+// testinfo_player_start is only found in regioned levels
+ spot = find (world, classname, "testplayerstart");
+ if (spot)
+ return spot;
+
+// choose a info_player_deathmatch point
+
+// ok, find all spots that don't have players nearby
+
+ spots = world;
+ spot = find (world, classname, "info_player_deathmatch");
+ while (spot)
+ {
+ totalspots = totalspots + 1;
+
+ thing=findradius(spot.origin, 84);
+ pcount=0;
+ while (thing)
+ {
+ if (thing.classname == "player")
+ pcount=pcount + 1;
+ thing=thing.chain;
+ }
+ if (pcount == 0) {
+ spot.goalentity = spots;
+ spots = spot;
+ numspots = numspots + 1;
+ }
+
+ // Get the next spot in the chain
+ spot = find (spot, classname, "info_player_deathmatch");
+ }
+ totalspots=totalspots - 1;
+ if (!numspots) {
+ // ack, they are all full, just pick one at random
+// bprint (PRINT_HIGH, "Ackk! All spots are full. Selecting random spawn spot\n");
+ totalspots = rint((random() * totalspots));
+ spot = find (world, classname, "info_player_deathmatch");
+ while (totalspots > 0) {
+ totalspots = totalspots - 1;
+ spot = find (spot, classname, "info_player_deathmatch");
+ }
+ return spot;
+ }
+
+// We now have the number of spots available on the map in numspots
+
+ // Generate a random number between 1 and numspots
+
+ numspots = numspots - 1;
+
+ numspots = rint((random() * numspots ) );
+
+ spot = spots;
+ while (numspots > 0) {
+ spot = spot.goalentity;
+ numspots = numspots - 1;
+ }
+ return spot;
+
+};
+void() DecodeLevelParms;
+void() PlayerDie;
+
+/*
+===========
+ValidateUser
+
+
+============
+*/
+float(entity e) ValidateUser =
+{
+/*
+ local string s;
+ local string userclan;
+ local float rank, rankmin, rankmax;
+
+//
+// if the server has set "clan1" and "clan2", then it
+// is a clan match that will allow only those two clans in
+//
+ s = serverinfo("clan1");
+ if (s)
+ {
+ userclan = masterinfo(e,"clan");
+ if (s == userclan)
+ return true;
+ s = serverinfo("clan2");
+ if (s == userclan)
+ return true;
+ return false;
+ }
+
+//
+// if the server has set "rankmin" and/or "rankmax" then
+// the users rank must be between those two values
+//
+ s = masterinfo (e, "rank");
+ rank = stof (s);
+
+ s = serverinfo("rankmin");
+ if (s)
+ {
+ rankmin = stof (s);
+ if (rank < rankmin)
+ return false;
+ }
+ s = serverinfo("rankmax");
+ if (s)
+ {
+ rankmax = stof (s);
+ if (rankmax < rank)
+ return false;
+ }
+
+ return true;
+*/
+};
+
+
+/*
+===========
+PutClientInServer
+
+called each time a player enters a new level
+============
+*/
+void() PutClientInServer =
+{
+ local entity spot;
+ local string s;
+
+ self.classname = "player";
+ self.health = 100;
+ self.takedamage = DAMAGE_AIM;
+ self.solid = SOLID_SLIDEBOX;
+ self.movetype = MOVETYPE_WALK;
+ self.show_hostile = 0;
+ self.max_health = 100;
+ self.flags = FL_CLIENT;
+ self.air_finished = time + 12;
+ self.dmg = 2; // initial water damage
+ self.super_damage_finished = 0;
+ self.radsuit_finished = 0;
+ self.invisible_finished = 0;
+ self.invincible_finished = 0;
+ self.effects = 0;
+ self.invincible_time = 0;
+
+ DecodeLevelParms ();
+
+ W_SetCurrentAmmo ();
+
+ self.attack_finished = time;
+ self.th_pain = player_pain;
+ self.th_die = PlayerDie;
+
+ self.deadflag = DEAD_NO;
+// paustime is set by teleporters to keep the player from moving a while
+ self.pausetime = 0;
+
+ spot = SelectSpawnPoint ();
+
+ self.origin = spot.origin + '0 0 1';
+ self.angles = spot.angles;
+ self.fixangle = TRUE; // turn this way immediately
+
+// oh, this is a hack!
+ setmodel (self, "progs/eyes.mdl");
+ modelindex_eyes = self.modelindex;
+
+ setmodel (self, "progs/player.mdl");
+ modelindex_player = self.modelindex;
+
+ setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
+
+ self.view_ofs = '0 0 22';
+
+// Mod - Xian (May.20.97)
+// Bug where player would have velocity from their last kill
+
+ self.velocity = '0 0 0';
+
+ player_stand1 ();
+
+ makevectors(self.angles);
+ spawn_tfog (self.origin + v_forward*20);
+
+ spawn_tdeath (self.origin, self);
+
+ // Set Rocket Jump Modifiers
+ if (stof(infokey(world, "rj")) != 0)
+ {
+ rj = stof(infokey(world, "rj"));
+ }
+
+ if (deathmatch == 4)
+ {
+ self.ammo_shells = 0;
+ if (stof(infokey(world, "axe")) == 0)
+ {
+ self.ammo_nails = 255;
+ self.ammo_shells = 255;
+ self.ammo_rockets = 255;
+ self.ammo_cells = 255;
+ self.items = self.items | IT_NAILGUN;
+ self.items = self.items | IT_SUPER_NAILGUN;
+ self.items = self.items | IT_SUPER_SHOTGUN;
+ self.items = self.items | IT_ROCKET_LAUNCHER;
+// self.items = self.items | IT_GRENADE_LAUNCHER;
+ self.items = self.items | IT_LIGHTNING;
+ }
+ self.items = self.items - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR3;
+ self.armorvalue = 200;
+ self.armortype = 0.8;
+ self.health = 250;
+ self.items = self.items | IT_INVULNERABILITY;
+ self.invincible_time = 1;
+ self.invincible_finished = time + 3;
+ }
+
+ if (deathmatch == 5)
+ {
+ self.ammo_nails = 80;
+ self.ammo_shells = 30;
+ self.ammo_rockets = 10;
+ self.ammo_cells = 30;
+ self.items = self.items | IT_NAILGUN;
+ self.items = self.items | IT_SUPER_NAILGUN;
+ self.items = self.items | IT_SUPER_SHOTGUN;
+ self.items = self.items | IT_ROCKET_LAUNCHER;
+ self.items = self.items | IT_GRENADE_LAUNCHER;
+ self.items = self.items | IT_LIGHTNING;
+ self.items = self.items - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR3;
+ self.armorvalue = 200;
+ self.armortype = 0.8;
+ self.health = 200;
+ self.items = self.items | IT_INVULNERABILITY;
+ self.invincible_time = 1;
+ self.invincible_finished = time + 3;
+ }
+
+
+};
+
+
+/*
+=============================================================================
+
+ QUAKED FUNCTIONS
+
+=============================================================================
+*/
+
+
+/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 24)
+The normal starting point for a level.
+*/
+void() info_player_start =
+{
+};
+
+
+/*QUAKED info_player_start2 (1 0 0) (-16 -16 -24) (16 16 24)
+Only used on start map for the return point from an episode.
+*/
+void() info_player_start2 =
+{
+};
+
+/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 24)
+potential spawning position for deathmatch games
+*/
+void() info_player_deathmatch =
+{
+};
+
+/*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 24)
+potential spawning position for coop games
+*/
+void() info_player_coop =
+{
+};
+
+/*
+===============================================================================
+
+RULES
+
+===============================================================================
+*/
+
+/*
+go to the next level for deathmatch
+*/
+void() NextLevel =
+{
+ local entity o;
+ local string newmap;
+
+ if (nextmap != "")
+ return; // already done
+
+ if (mapname == "start")
+ {
+ if (!cvar("registered"))
+ {
+ mapname = "e1m1";
+ }
+ else if (!(serverflags & 1))
+ {
+ mapname = "e1m1";
+ serverflags = serverflags | 1;
+ }
+ else if (!(serverflags & 2))
+ {
+ mapname = "e2m1";
+ serverflags = serverflags | 2;
+ }
+ else if (!(serverflags & 4))
+ {
+ mapname = "e3m1";
+ serverflags = serverflags | 4;
+ }
+ else if (!(serverflags & 8))
+ {
+ mapname = "e4m1";
+ serverflags = serverflags - 7;
+ }
+
+ o = spawn();
+ o.map = mapname;
+ }
+ else
+ {
+ // find a trigger changelevel
+ o = find(world, classname, "trigger_changelevel");
+ if (!o || mapname == "start")
+ { // go back to same map if no trigger_changelevel
+ o = spawn();
+ o.map = mapname;
+ }
+ }
+
+ nextmap = o.map;
+
+ if (o.nextthink < time)
+ {
+ o.think = execute_changelevel;
+ o.nextthink = time + 0.1;
+ }
+};
+
+/*
+============
+CheckRules
+
+Exit deathmatch games upon conditions
+============
+*/
+void() CheckRules =
+{
+ if (timelimit && time >= timelimit)
+ NextLevel ();
+
+ if (fraglimit && self.frags >= fraglimit)
+ NextLevel ();
+};
+
+//============================================================================
+
+void() PlayerDeathThink =
+{
+ local entity old_self;
+ 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;
+ respawn();
+};
+
+
+void() PlayerJump =
+{
+ local vector start, end;
+
+ if (self.flags & FL_WATERJUMP)
+ return;
+
+ if (self.waterlevel >= 2)
+ {
+// 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;
+ }
+
+ if (!(self.flags & FL_ONGROUND))
+ return;
+
+ if ( !(self.flags & FL_JUMPRELEASED) )
+ return; // don't pogo stick
+
+ self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
+ self.button2 = 0;
+
+// player jumping sound
+ sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
+};
+
+
+/*
+===========
+WaterMove
+
+============
+*/
+.float dmgtime;
+
+void() WaterMove =
+{
+//dprint (ftos(self.waterlevel));
+ if (self.movetype == MOVETYPE_NOCLIP)
+ 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;
+ T_Damage (self, world, world, self.dmg);
+ 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.dmgtime < time)
+ {
+ if (self.radsuit_finished > time)
+ self.dmgtime = time + 1;
+ else
+ self.dmgtime = time + 0.2;
+
+ T_Damage (self, world, world, 10*self.waterlevel);
+ }
+ }
+ else if (self.watertype == CONTENT_SLIME)
+ { // do damage
+ if (self.dmgtime < time && self.radsuit_finished < time)
+ {
+ self.dmgtime = time + 1;
+ T_Damage (self, world, world, 4*self.waterlevel);
+ }
+ }
+
+ 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.dmgtime = 0;
+ }
+};
+
+void() CheckWaterJump =
+{
+ 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 - (self.flags & FL_JUMPRELEASED);
+ self.teleport_time = time + 2; // safety net
+ return;
+ }
+ }
+};
+
+/*
+================
+PlayerPreThink
+
+Called every frame before physics are run
+================
+*/
+void() PlayerPreThink =
+{
+ local float mspeed, aspeed;
+ local float r;
+
+ if (intermission_running)
+ {
+ IntermissionThink (); // otherwise a button could be missed between
+ return; // the think tics
+ }
+
+ if (self.view_ofs == '0 0 0')
+ return; // intermission or finale
+
+ makevectors (self.v_angle); // is this still used
+
+ self.deathtype = "";
+
+ CheckRules ();
+ WaterMove ();
+/*
+ if (self.waterlevel == 2)
+ CheckWaterJump ();
+*/
+
+ if (self.deadflag >= DEAD_DEAD)
+ {
+ PlayerDeathThink ();
+ return;
+ }
+
+ if (self.deadflag == DEAD_DYING)
+ return; // dying, so do nothing
+
+ if (self.button2)
+ {
+ PlayerJump ();
+ }
+ else
+ self.flags = self.flags | FL_JUMPRELEASED;
+
+// 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 = W_BestWeapon ();
+ W_SetCurrentAmmo ();
+ }
+};
+
+/*
+================
+CheckPowerups
+
+Check for turning off powerups
+================
+*/
+void() CheckPowerups =
+{
+ 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, PRINT_HIGH, "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
+ self.modelindex = modelindex_player; // don't use eyes
+
+// 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, PRINT_HIGH, "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;
+ self.effects = self.effects | EF_RED;
+ }
+ else
+ {
+ self.effects = self.effects - (self.effects & EF_DIMLIGHT);
+ self.effects = self.effects - (self.effects & EF_RED);
+ }
+ }
+
+// 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)
+ {
+ if (deathmatch == 4)
+ sprint (self, PRINT_HIGH, "OctaPower is wearing off\n");
+ else
+ sprint (self, PRINT_HIGH, "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;
+ if (deathmatch == 4)
+ {
+ self.ammo_cells = 255;
+ self.armorvalue = 1;
+ self.armortype = 0.8;
+ self.health = 100;
+ }
+ self.super_damage_finished = 0;
+ self.super_time = 0;
+ }
+ if (self.super_damage_finished > time)
+ {
+ self.effects = self.effects | EF_DIMLIGHT;
+ self.effects = self.effects | EF_BLUE;
+ }
+ else
+ {
+ self.effects = self.effects - (self.effects & EF_DIMLIGHT);
+ self.effects = self.effects - (self.effects & EF_BLUE);
+ }
+ }
+
+// suit
+ if (self.radsuit_finished)
+ {
+ self.air_finished = time + 12; // don't drown
+
+// sound and screen flash when items starts to run out
+ if (self.radsuit_finished < time + 3)
+ {
+ if (self.rad_time == 1)
+ {
+ sprint (self, PRINT_HIGH, "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;
+ }
+ }
+
+};
+
+
+/*
+================
+PlayerPostThink
+
+Called every frame after physics are run
+================
+*/
+void() PlayerPostThink =
+{
+ local float mspeed, aspeed;
+ local float r;
+
+//dprint ("post think\n");
+ if (self.view_ofs == '0 0 0')
+ return; // intermission or finale
+ if (self.deadflag)
+ return;
+
+// check to see if player landed and play landing sound
+ if ((self.jump_flag < -300) && (self.flags & FL_ONGROUND) )
+ {
+ 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_Damage (self, world, world, 5);
+ sound (self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM);
+ }
+ else
+ sound (self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM);
+ }
+
+ self.jump_flag = self.velocity_z;
+
+ CheckPowerups ();
+
+ W_WeaponFrame ();
+
+};
+
+
+/*
+===========
+ClientConnect
+
+called when a player connects to a server
+============
+*/
+void() ClientConnect =
+{
+ bprint (PRINT_HIGH, self.netname);
+ bprint (PRINT_HIGH, " entered the game\n");
+
+// a client connecting during an intermission can cause problems
+ if (intermission_running)
+ GotoNextMap ();
+};
+
+
+/*
+===========
+ClientDisconnect
+
+called when a player disconnects from a server
+============
+*/
+void() ClientDisconnect =
+{
+ // let everyone else know
+ bprint (PRINT_HIGH, self.netname);
+ bprint (PRINT_HIGH, " left the game with ");
+ bprint (PRINT_HIGH, ftos(self.frags));
+ bprint (PRINT_HIGH, " frags\n");
+ sound (self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE);
+ set_suicide_frame ();
+};
+
+/*
+===========
+ClientObituary
+
+called when a player dies
+============
+*/
+
+void(entity targ, entity attacker) ClientObituary =
+{
+ local float rnum;
+ local string deathstring, deathstring2;
+ local string s;
+ local string attackerteam, targteam;
+
+ rnum = random();
+ //ZOID 12-13-96: self.team doesn't work in QW. Use keys
+ attackerteam = infokey(attacker, "team");
+ targteam = infokey(targ, "team");
+
+ if (targ.classname == "player")
+ {
+
+ if (deathmatch > 3)
+ {
+ if (targ.deathtype == "selfwater")
+ {
+ bprint (PRINT_MEDIUM, targ.netname);
+ bprint (PRINT_MEDIUM," electrocutes himself.\n ");
+ targ.frags = targ.frags - 1;
+ return;
+ }
+ }
+
+ if (attacker.classname == "teledeath")
+ {
+ bprint (PRINT_MEDIUM,targ.netname);
+ bprint (PRINT_MEDIUM," was telefragged by ");
+ bprint (PRINT_MEDIUM,attacker.owner.netname);
+ bprint (PRINT_MEDIUM,"\n");
+ logfrag (attacker.owner, targ);
+
+ attacker.owner.frags = attacker.owner.frags + 1;
+ return;
+ }
+
+ if (attacker.classname == "teledeath2")
+ {
+ bprint (PRINT_MEDIUM,"Satan's power deflects ");
+ bprint (PRINT_MEDIUM,targ.netname);
+ bprint (PRINT_MEDIUM,"'s telefrag\n");
+
+ targ.frags = targ.frags - 1;
+ logfrag (targ, targ);
+ return;
+ }
+
+ // double 666 telefrag (can happen often in deathmatch 4)
+ if (attacker.classname == "teledeath3")
+ {
+ bprint (PRINT_MEDIUM,targ.netname);
+ bprint (PRINT_MEDIUM," was telefragged by ");
+ bprint (PRINT_MEDIUM,attacker.owner.netname);
+ bprint (PRINT_MEDIUM, "'s Satan's power\n");
+ targ.frags = targ.frags - 1;
+ logfrag (targ, targ);
+ return;
+ }
+
+
+ if (targ.deathtype == "squish")
+ {
+ if (teamplay && targteam == attackerteam && attackerteam != "" && targ != attacker)
+ {
+ logfrag (attacker, attacker);
+ attacker.frags = attacker.frags - 1;
+ bprint (PRINT_MEDIUM,attacker.netname);
+ bprint (PRINT_MEDIUM," squished a teammate\n");
+ return;
+ }
+ else if (attacker.classname == "player" && attacker != targ)
+ {
+ bprint (PRINT_MEDIUM, attacker.netname);
+ bprint (PRINT_MEDIUM," squishes ");
+ bprint (PRINT_MEDIUM,targ.netname);
+ bprint (PRINT_MEDIUM,"\n");
+ logfrag (attacker, targ);
+ attacker.frags = attacker.frags + 1;
+ return;
+ }
+ else
+ {
+ logfrag (targ, targ);
+ targ.frags = targ.frags - 1; // killed self
+ bprint (PRINT_MEDIUM,targ.netname);
+ bprint (PRINT_MEDIUM," was squished\n");
+ return;
+ }
+ }
+
+ if (attacker.classname == "player")
+ {
+ if (targ == attacker)
+ {
+ // killed self
+ logfrag (attacker, attacker);
+ attacker.frags = attacker.frags - 1;
+ bprint (PRINT_MEDIUM,targ.netname);
+ if (targ.deathtype == "grenade")
+ bprint (PRINT_MEDIUM," tries to put the pin back in\n");
+ else if (targ.deathtype == "rocket")
+ bprint (PRINT_MEDIUM," becomes bored with life\n");
+ else if (targ.weapon == 64 && targ.waterlevel > 1)
+ {
+ if (targ.watertype == CONTENT_SLIME)
+ bprint (PRINT_MEDIUM," discharges into the slime\n");
+ else if (targ.watertype == CONTENT_LAVA)
+ bprint (PRINT_MEDIUM," discharges into the lava\n");
+ else
+ bprint (PRINT_MEDIUM," discharges into the water.\n");
+ }
+ else
+ bprint (PRINT_MEDIUM," becomes bored with life\n");
+ return;
+ }
+ else if ( (teamplay == 2) && (targteam == attackerteam) &&
+ (attackerteam != "") )
+ {
+ if (rnum < 0.25)
+ deathstring = " mows down a teammate\n";
+ else if (rnum < 0.50)
+ deathstring = " checks his glasses\n";
+ else if (rnum < 0.75)
+ deathstring = " gets a frag for the other team\n";
+ else
+ deathstring = " loses another friend\n";
+ bprint (PRINT_MEDIUM, attacker.netname);
+ bprint (PRINT_MEDIUM, deathstring);
+ attacker.frags = attacker.frags - 1;
+ //ZOID 12-13-96: killing a teammate logs as suicide
+ logfrag (attacker, attacker);
+ return;
+ }
+ else
+ {
+ logfrag (attacker, targ);
+ attacker.frags = attacker.frags + 1;
+
+ rnum = attacker.weapon;
+ if (targ.deathtype == "nail")
+ {
+ deathstring = " was nailed by ";
+ deathstring2 = "\n";
+ }
+ else if (targ.deathtype == "supernail")
+ {
+ deathstring = " was punctured by ";
+ deathstring2 = "\n";
+ }
+ else if (targ.deathtype == "grenade")
+ {
+ deathstring = " eats ";
+ deathstring2 = "'s pineapple\n";
+ if (targ.health < -40)
+ {
+ deathstring = " was gibbed by ";
+ deathstring2 = "'s grenade\n";
+ }
+ }
+ else if (targ.deathtype == "rocket")
+ {
+ if (attacker.super_damage_finished > 0 && targ.health < -40)
+ {
+ rnum = random();
+ if (rnum < 0.3)
+ deathstring = " was brutalized by ";
+ else if (rnum < 0.6)
+ deathstring = " was smeared by ";
+ else
+ {
+ bprint (PRINT_MEDIUM, attacker.netname);
+ bprint (PRINT_MEDIUM, " rips ");
+ bprint (PRINT_MEDIUM, targ.netname);
+ bprint (PRINT_MEDIUM, " a new one\n");
+ return;
+ }
+ deathstring2 = "'s quad rocket\n";
+ }
+ else
+ {
+ deathstring = " rides ";
+ deathstring2 = "'s rocket\n";
+ if (targ.health < -40)
+ {
+ deathstring = " was gibbed by ";
+ deathstring2 = "'s rocket\n" ;
+ }
+ }
+ }
+ else if (rnum == IT_AXE)
+ {
+ deathstring = " was ax-murdered by ";
+ deathstring2 = "\n";
+ }
+ else if (rnum == IT_SHOTGUN)
+ {
+ deathstring = " chewed on ";
+ deathstring2 = "'s boomstick\n";
+ }
+ else if (rnum == IT_SUPER_SHOTGUN)
+ {
+ deathstring = " ate 2 loads of ";
+ deathstring2 = "'s buckshot\n";
+ }
+ else if (rnum == IT_LIGHTNING)
+ {
+ deathstring = " accepts ";
+ if (attacker.waterlevel > 1)
+ deathstring2 = "'s discharge\n";
+ else
+ deathstring2 = "'s shaft\n";
+ }
+ bprint (PRINT_MEDIUM,targ.netname);
+ bprint (PRINT_MEDIUM,deathstring);
+ bprint (PRINT_MEDIUM,attacker.netname);
+ bprint (PRINT_MEDIUM,deathstring2);
+ }
+ return;
+ }
+ else
+ {
+ logfrag (targ, targ);
+ targ.frags = targ.frags - 1; // killed self
+ rnum = targ.watertype;
+
+ bprint (PRINT_MEDIUM,targ.netname);
+ if (rnum == -3)
+ {
+ if (random() < 0.5)
+ bprint (PRINT_MEDIUM," sleeps with the fishes\n");
+ else
+ bprint (PRINT_MEDIUM," sucks it down\n");
+ return;
+ }
+ else if (rnum == -4)
+ {
+ if (random() < 0.5)
+ bprint (PRINT_MEDIUM," gulped a load of slime\n");
+ else
+ bprint (PRINT_MEDIUM," can't exist on slime alone\n");
+ return;
+ }
+ else if (rnum == -5)
+ {
+ if (targ.health < -15)
+ {
+ bprint (PRINT_MEDIUM," burst into flames\n");
+ return;
+ }
+ if (random() < 0.5)
+ bprint (PRINT_MEDIUM," turned into hot slag\n");
+ else
+ bprint (PRINT_MEDIUM," visits the Volcano God\n");
+ return;
+ }
+
+ if (attacker.classname == "explo_box")
+ {
+ bprint (PRINT_MEDIUM," blew up\n");
+ return;
+ }
+ if (targ.deathtype == "falling")
+ {
+ bprint (PRINT_MEDIUM," fell to his death\n");
+ return;
+ }
+ if (targ.deathtype == "nail" || targ.deathtype == "supernail")
+ {
+ bprint (PRINT_MEDIUM," was spiked\n");
+ return;
+ }
+ if (targ.deathtype == "laser")
+ {
+ bprint (PRINT_MEDIUM," was zapped\n");
+ return;
+ }
+ if (attacker.classname == "fireball")
+ {
+ bprint (PRINT_MEDIUM," ate a lavaball\n");
+ return;
+ }
+ if (attacker.classname == "trigger_changelevel")
+ {
+ bprint (PRINT_MEDIUM," tried to leave\n");
+ return;
+ }
+
+ bprint (PRINT_MEDIUM," died\n");
+ }
+ }
+};
View
350 qw-qc/combat.qc
@@ -0,0 +1,350 @@
+/*
+ combat.qc
+
+ damage, obit, etc related functions
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to:
+
+ Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330
+ Boston, MA 02111-1307, USA
+
+*/
+
+void() T_MissileTouch;
+void() info_player_start;
+void(entity targ, entity attacker) ClientObituary;
+void(entity inflictor, entity attacker, float damage, entity ignore, string dtype) T_RadiusDamage;
+
+/*SERVER
+void() monster_death_use;
+*/
+
+//============================================================================
+
+/*
+============
+CanDamage
+
+Returns true if the inflictor can directly damage the target. Used for
+explosions and melee attacks.
+============
+*/
+float(entity targ, entity inflictor) CanDamage =
+{
+// bmodels need special checking because their origin is 0,0,0
+ if (targ.movetype == MOVETYPE_PUSH)
+ {
+ traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self);
+ if (trace_fraction == 1)
+ return TRUE;
+ if (trace_ent == targ)
+ return TRUE;
+ return FALSE;
+ }
+
+ traceline(inflictor.origin, targ.origin, TRUE, self);
+ if (trace_fraction == 1)
+ return TRUE;
+ traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self);
+ if (trace_fraction == 1)
+ return TRUE;
+ traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self);
+ if (trace_fraction == 1)
+ return TRUE;
+ traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self);
+ if (trace_fraction == 1)
+ return TRUE;
+ traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self);
+ if (trace_fraction == 1)
+ return TRUE;
+
+ return FALSE;
+};
+
+
+/*
+============
+Killed
+============
+*/
+void(entity targ, entity attacker) Killed =
+{
+ local entity oself;
+
+ oself = self;
+ self = targ;
+
+ if (self.health < -99)
+ self.health = -99; // don't let sbar look bad if a player
+
+ if (self.movetype == MOVETYPE_PUSH || self.movetype == MOVETYPE_NONE)
+ { // doors, triggers, etc
+ self.th_die ();
+ self = oself;
+ return;
+ }
+
+ self.enemy = attacker;
+
+// bump the monster counter
+ if (self.flags & FL_MONSTER)
+ {
+ killed_monsters = killed_monsters + 1;
+ WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
+ }
+
+ ClientObituary(self, attacker);
+
+ self.takedamage = DAMAGE_NO;
+ self.touch = SUB_Null;
+ self.effects = 0;
+
+/*SERVER
+ monster_death_use();
+*/
+ self.th_die ();
+
+ self = oself;
+};
+
+
+/*
+============
+T_Damage
+
+The damage is coming from inflictor, but get mad at attacker
+This should be the only function that ever reduces health.
+============
+*/
+void(entity targ, entity inflictor, entity attacker, float damage) T_Damage=
+{
+ local vector dir;
+ local entity oldself;
+ local float save;
+ local float take;
+ local string s;
+ local string attackerteam, targteam;
+
+
+ if (!targ.takedamage)
+ return;
+
+// used by buttons and triggers to set activator for target firing
+ damage_attacker = attacker;
+
+
+// check for quad damage powerup on the attacker
+ if (attacker.super_damage_finished > time && inflictor.classname != "door")
+ if (deathmatch == 4)
+ damage = damage * 8;
+ else
+ damage = damage * 4;
+
+// save damage based on the target's armor level
+
+ save = ceil(targ.armortype*damage);
+ if (save >= targ.armorvalue)
+ {
+ save = targ.armorvalue;
+ targ.armortype = 0; // lost all armor
+ targ.items = targ.items - (targ.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3));
+ }
+
+ targ.armorvalue = targ.armorvalue - save;
+ take = ceil(damage-save);
+
+// add to the damage total for clients, which will be sent as a single
+// message at the end of the frame
+// FIXME: remove after combining shotgun blasts?
+ if (targ.flags & FL_CLIENT)
+ {
+ targ.dmg_take = targ.dmg_take + take;
+ targ.dmg_save = targ.dmg_save + save;
+ targ.dmg_inflictor = inflictor;
+ }
+
+ damage_inflictor = inflictor;
+
+
+// figure momentum add
+ if ( (inflictor != world) && (targ.movetype == MOVETYPE_WALK) )
+ {
+ dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5;
+ dir = normalize(dir);
+ // Set kickback for smaller weapons
+//Zoid -- use normal NQ kickback
+// // Read: only if it's not yourself doing the damage
+// if ( (damage < 60) & ((attacker.classname == "player") & (targ.classname == "player")) & ( attacker.netname != targ.netname))
+// targ.velocity = targ.velocity + dir * damage * 11;
+// else
+ // Otherwise, these rules apply to rockets and grenades
+ // for blast velocity
+ targ.velocity = targ.velocity + dir * damage * 8;
+
+ // Rocket Jump modifiers
+ if ( (rj > 1) & ((attacker.classname == "player") & (targ.classname == "player")) & ( attacker.netname == targ.netname))
+ targ.velocity = targ.velocity + dir * damage * rj;
+
+ }
+
+
+
+// check for godmode or invincibility
+ if (targ.flags & FL_GODMODE)
+ return;
+ if (targ.invincible_finished >= time)
+ {
+ if (self.invincible_sound < time)
+ {
+ sound (targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
+ self.invincible_sound = time + 2;
+ }
+ return;
+ }
+
+// team play damage avoidance
+//ZOID 12-13-96: self.team doesn't work in QW. Use keys
+ attackerteam = infokey(attacker, "team");
+ targteam = infokey(targ, "team");
+
+ if ((teamplay == 1) && (targteam == attackerteam) &&
+ (attacker.classname == "player") && (attackerteam != "") &&
+ inflictor.classname !="door")
+ return;
+
+ if ((teamplay == 3) && (targteam == attackerteam) &&
+ (attacker.classname == "player") && (attackerteam != "") &&
+ (targ != attacker)&& inflictor.classname !="door")
+ return;
+
+// do the damage
+ targ.health = targ.health - take;
+
+ if (targ.health <= 0)
+ {
+ Killed (targ, attacker);
+ return;
+ }
+
+// react to the damage
+ oldself = self;
+ self = targ;
+
+/*SERVER
+ if ( (self.flags & FL_MONSTER) && attacker != world)
+ {
+ // get mad unless of the same class (except for soldiers)
+ if (self != attacker && attacker != self.enemy)
+ {
+ if ( (self.classname != attacker.classname)
+ || (self.classname == "monster_army" ) )
+ {
+ if (self.enemy.classname == "player")
+ self.oldenemy = self.enemy;
+ self.enemy = attacker;
+ FoundTarget ();
+ }
+ }
+ }
+*/
+ if (self.th_pain)
+ {
+ self.th_pain (attacker, take);
+ }
+
+ self = oldself;
+};
+
+/*
+============
+T_RadiusDamage
+============
+*/
+void(entity inflictor, entity attacker, float damage, entity ignore, string dtype) T_RadiusDamage =
+{
+ local float points;
+ local entity head;
+ local vector org;
+
+ head = findradius(inflictor.origin, damage+40);
+
+ while (head)
+ {
+ //bprint (PRINT_HIGH, head.classname);
+ //bprint (PRINT_HIGH, " | ");
+ //bprint (PRINT_HIGH, head.netname);
+ //bprint (PRINT_HIGH, "\n");
+
+ if (head != ignore)
+ {
+ if (head.takedamage)
+ {
+ org = head.origin + (head.mins + head.maxs)*0.5;
+ points = 0.5*vlen (inflictor.origin - org);
+ if (points < 0)
+ points = 0;
+ points = damage - points;
+
+ if (head == attacker)
+ points = points * 0.5;
+ if (points > 0)
+ {
+ if (CanDamage (head, inflictor))
+ {
+ head.deathtype = dtype;
+ T_Damage (head, inflictor, attacker, points);
+ }
+ }
+ }
+ }
+ head = head.chain;
+ }
+};
+
+/*
+============
+T_BeamDamage
+============
+*/
+void(entity attacker, float damage) T_BeamDamage =
+{
+ local float points;
+ local entity head;
+
+ head = findradius(attacker.origin, damage+40);
+
+ while (head)
+ {
+ if (head.takedamage)
+ {
+ points = 0.5*vlen (attacker.origin - head.origin);
+ if (points < 0)
+ points = 0;
+ points = damage - points;
+ if (head == attacker)
+ points = points * 0.5;
+ if (points > 0)
+ {
+ if (CanDamage (head, attacker))
+ T_Damage (head, attacker, attacker, points);
+ }
+ }
+ head = head.chain;
+ }
+};
+
View
754 qw-qc/defs.qc
@@ -0,0 +1,754 @@
+/*
+ defs.qc
+
+ global definitions
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to:
+
+ Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330
+ Boston, MA 02111-1307, USA
+
+*/
+
+/*
+==============================================================================
+
+ SOURCE FOR GLOBALVARS_T C STRUCTURE
+
+==============================================================================
+*/
+
+//
+// system globals
+//
+entity self;
+entity other;
+entity world;
+float time;
+float frametime;
+
+entity newmis; // if this is set, the entity that just
+ // run created a new missile that should
+ // be simulated immediately
+
+
+float force_retouch; // force all entities to touch triggers
+ // next frame. this is needed because
+ // non-moving things don't normally scan
+ // for triggers, and when a trigger is
+ // created (like a teleport trigger), it
+ // needs to catch everything.
+ // decremented each frame, so set to 2
+ // to guarantee everything is touched
+string mapname;
+
+float serverflags; // propagated from level to level, used to
+ // keep track of completed episodes
+
+float total_secrets;
+float total_monsters;
+
+float found_secrets; // number of secrets found
+float killed_monsters; // number of monsters killed
+
+
+// spawnparms are used to encode information about clients across server
+// level changes
+float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16;
+
+//
+// global variables set by built in functions
+//
+vector v_forward, v_up, v_right; // set by makevectors()
+
+// set by traceline / tracebox
+float trace_allsolid;
+float trace_startsolid;
+float trace_fraction;
+vector trace_endpos;
+vector trace_plane_normal;
+float trace_plane_dist;
+entity trace_ent;
+float trace_inopen;
+float trace_inwater;
+
+entity msg_entity; // destination of single entity writes
+
+//
+// required prog functions
+//
+void() main; // only for testing
+
+void() StartFrame;
+
+void() PlayerPreThink;
+void() PlayerPostThink;
+
+void() ClientKill;
+void() ClientConnect;
+void() PutClientInServer; // call after setting the parm1... parms
+void() ClientDisconnect;
+
+void() SetNewParms; // called when a client first connects to
+ // a server. sets parms so they can be
+ // saved off for restarts
+
+void() SetChangeParms; // call to set parms for self so they can
+ // be saved for a level transition
+
+
+//================================================
+void end_sys_globals; // flag for structure dumping
+//================================================
+
+/*
+==============================================================================
+
+ SOURCE FOR ENTVARS_T C STRUCTURE
+
+==============================================================================
+*/
+
+//
+// system fields (*** = do not set in prog code, maintained by C code)
+//
+.float modelindex; // *** model index in the precached list
+.vector absmin, absmax; // *** origin + mins / maxs
+
+.float ltime; // local time for entity
+.float lastruntime; // *** to allow entities to run out of sequence
+
+.float movetype;
+.float solid;
+
+.vector origin; // ***
+.vector oldorigin; // ***
+.vector velocity;
+.vector angles;
+.vector avelocity;
+
+.string classname; // spawn function
+.string model;
+.float frame;
+.float skin;
+.float effects;
+
+.vector mins, maxs; // bounding box extents reletive to origin
+.vector size; // maxs - mins
+
+.void() touch;
+.void() use;
+.void() think;
+.void() blocked; // for doors or plats, called when can't push other
+
+.float nextthink;
+.entity groundentity;
+
+
+
+// stats
+.float health;
+.float frags;
+.float weapon; // one of the IT_SHOTGUN, etc flags
+.string weaponmodel;
+.float weaponframe;
+.float currentammo;
+.float ammo_shells, ammo_nails, ammo_rockets, ammo_cells;
+
+.float items; // bit flags
+
+.float takedamage;
+.entity chain;
+.float deadflag;
+
+.vector view_ofs; // add to origin to get eye point
+
+
+.float button0; // fire
+.float button1; // use
+.float button2; // jump
+
+.float impulse; // weapon changes
+
+.float fixangle;
+.vector v_angle; // view / targeting angle for players
+
+.string netname;
+
+.entity enemy;
+
+.float flags;
+
+.float colormap;
+.float team;
+
+.float max_health; // players maximum health is stored here
+
+.float teleport_time; // don't back up
+
+.float armortype; // save this fraction of incoming damage
+.float armorvalue;
+
+.float waterlevel; // 0 = not in, 1 = feet, 2 = wast, 3 = eyes
+.float watertype; // a contents value
+
+.float ideal_yaw;
+.float yaw_speed;
+
+.entity aiment;
+
+.entity goalentity; // a movetarget or an enemy
+
+.float spawnflags;
+
+.string target;
+.string targetname;
+
+// damage is accumulated through a frame. and sent as one single
+// message, so the super shotgun doesn't generate huge messages
+.float dmg_take;
+.float dmg_save;
+.entity dmg_inflictor;
+
+.entity owner; // who launched a missile
+.vector movedir; // mostly for doors, but also used for waterjump
+
+.string message; // trigger messages
+
+.float sounds; // either a cd track number or sound number
+
+.string noise, noise1, noise2, noise3; // contains names of wavs to play
+
+//================================================
+void end_sys_fields; // flag for structure dumping
+//================================================
+
+/*
+==============================================================================
+
+ VARS NOT REFERENCED BY C CODE
+
+==============================================================================
+*/
+
+
+//
+// constants
+//
+
+float FALSE = 0;
+float TRUE = 1;
+
+// edict.flags
+float FL_FLY = 1;
+float FL_SWIM = 2;
+float FL_CLIENT = 8; // set for all client edicts
+float FL_INWATER = 16; // for enter / leave water splash
+float FL_MONSTER = 32;
+float FL_GODMODE = 64; // player cheat
+float FL_NOTARGET = 128; // player cheat
+float FL_ITEM = 256; // extra wide size for bonus items
+float FL_ONGROUND = 512; // standing on something
+float FL_PARTIALGROUND = 1024; // not all corners are valid
+float FL_WATERJUMP = 2048; // player jumping out of water
+float FL_JUMPRELEASED = 4096; // for jump debouncing
+
+// edict.movetype values
+float MOVETYPE_NONE = 0; // never moves
+//float MOVETYPE_ANGLENOCLIP = 1;
+//float MOVETYPE_ANGLECLIP = 2;
+float MOVETYPE_WALK = 3; // players only
+float MOVETYPE_STEP = 4; // discrete, not real time unless fall
+float MOVETYPE_FLY = 5;
+float MOVETYPE_TOSS = 6; // gravity
+float MOVETYPE_PUSH = 7; // no clip to world, push and crush
+float MOVETYPE_NOCLIP = 8;
+float MOVETYPE_FLYMISSILE = 9; // fly with extra size against monsters
+float MOVETYPE_BOUNCE = 10;
+float MOVETYPE_BOUNCEMISSILE = 11; // bounce with extra size
+
+// edict.solid values
+float SOLID_NOT = 0; // no interaction with other objects
+float SOLID_TRIGGER = 1; // touch on edge, but not blocking
+float SOLID_BBOX = 2; // touch on edge, block
+float SOLID_SLIDEBOX = 3; // touch on edge, but not an onground
+float SOLID_BSP = 4; // bsp clip, touch on edge, block
+
+// range values
+float RANGE_MELEE = 0;
+float RANGE_NEAR = 1;
+float RANGE_MID = 2;
+float RANGE_FAR = 3;
+
+// deadflag values
+
+float DEAD_NO = 0;
+float DEAD_DYING = 1;
+float DEAD_DEAD = 2;
+float DEAD_RESPAWNABLE = 3;
+
+// takedamage values
+
+float DAMAGE_NO = 0;
+float DAMAGE_YES = 1;
+float DAMAGE_AIM = 2;
+
+// items
+float IT_AXE = 4096;
+float IT_SHOTGUN = 1;
+float IT_SUPER_SHOTGUN = 2;
+float IT_NAILGUN = 4;
+float IT_SUPER_NAILGUN = 8;
+float IT_GRENADE_LAUNCHER = 16;
+float IT_ROCKET_LAUNCHER = 32;
+float IT_LIGHTNING = 64;
+float IT_EXTRA_WEAPON = 128;
+
+float IT_SHELLS = 256;
+float IT_NAILS = 512;
+float IT_ROCKETS = 1024;
+float IT_CELLS = 2048;
+
+float IT_ARMOR1 = 8192;
+float IT_ARMOR2 = 16384;
+float IT_ARMOR3 = 32768;
+float IT_SUPERHEALTH = 65536;
+
+float IT_KEY1 = 131072;
+float IT_KEY2 = 262144;
+
+float IT_INVISIBILITY = 524288;
+float IT_INVULNERABILITY = 1048576;
+float IT_SUIT = 2097152;
+float IT_QUAD = 4194304;
+
+// point content values
+
+float CONTENT_EMPTY = -1;
+float CONTENT_SOLID = -2;
+float CONTENT_WATER = -3;
+float CONTENT_SLIME = -4;
+float CONTENT_LAVA = -5;
+float CONTENT_SKY = -6;
+
+float STATE_TOP = 0;
+float STATE_BOTTOM = 1;
+float STATE_UP = 2;
+float STATE_DOWN = 3;
+
+vector VEC_ORIGIN = '0 0 0';
+vector VEC_HULL_MIN = '-16 -16 -24';
+vector VEC_HULL_MAX = '16 16 32';
+
+vector VEC_HULL2_MIN = '-32 -32 -24';
+vector VEC_HULL2_MAX = '32 32 64';
+
+// protocol bytes
+float SVC_TEMPENTITY = 23;
+float SVC_KILLEDMONSTER = 27;
+float SVC_FOUNDSECRET = 28;
+float SVC_INTERMISSION = 30;
+float SVC_FINALE = 31;
+float SVC_CDTRACK = 32;
+float SVC_SELLSCREEN = 33;
+float SVC_SMALLKICK = 34;
+float SVC_BIGKICK = 35;
+float SVC_MUZZLEFLASH = 39;
+
+
+float TE_SPIKE = 0;
+float TE_SUPERSPIKE = 1;
+float TE_GUNSHOT = 2;
+float TE_EXPLOSION = 3;
+float TE_TAREXPLOSION = 4;
+float TE_LIGHTNING1 = 5;
+float TE_LIGHTNING2 = 6;
+float TE_WIZSPIKE = 7;
+float TE_KNIGHTSPIKE = 8;
+float TE_LIGHTNING3 = 9;
+float TE_LAVASPLASH = 10;
+float TE_TELEPORT = 11;
+float TE_BLOOD = 12;
+float TE_LIGHTNINGBLOOD = 13;
+
+// sound channels
+// channel 0 never willingly overrides
+// other channels (1-7) allways override a playing sound on that channel
+float CHAN_AUTO = 0;
+float CHAN_WEAPON = 1;
+float CHAN_VOICE = 2;
+float CHAN_ITEM = 3;
+float CHAN_BODY = 4;
+float CHAN_NO_PHS_ADD = 8; // ie: CHAN_BODY+CHAN_NO_PHS_ADD
+
+float ATTN_NONE = 0;
+float ATTN_NORM = 1;
+float ATTN_IDLE = 2;
+float ATTN_STATIC = 3;
+
+// update types
+
+float UPDATE_GENERAL = 0;
+float UPDATE_STATIC = 1;
+float UPDATE_BINARY = 2;
+float UPDATE_TEMP = 3;
+
+// entity effects
+
+//float EF_BRIGHTFIELD = 1;
+//float EF_MUZZLEFLASH = 2;
+float EF_BRIGHTLIGHT = 4;
+float EF_DIMLIGHT = 8;
+float EF_FLAG1 = 16;
+float EF_FLAG2 = 32;
+// GLQuakeWorld Stuff
+float EF_BLUE = 64; // Blue Globe effect for Quad
+float EF_RED = 128; // Red Globe effect for Pentagram
+// messages
+float MSG_BROADCAST = 0; // unreliable to all
+float MSG_ONE = 1; // reliable to one (msg_entity)
+float MSG_ALL = 2; // reliable to all
+float MSG_INIT = 3; // write to the init string
+float MSG_MULTICAST = 4; // for multicast() call
+
+// message levels
+float PRINT_LOW = 0; // pickup messages
+float PRINT_MEDIUM = 1; // death messages
+float PRINT_HIGH = 2; // critical messages
+float PRINT_CHAT = 3; // also goes to chat console
+
+// multicast sets
+float MULTICAST_ALL = 0; // every client
+float MULTICAST_PHS = 1; // within hearing
+float MULTICAST_PVS = 2; // within sight
+float MULTICAST_ALL_R = 3; // every client, reliable
+float MULTICAST_PHS_R = 4; // within hearing, reliable
+float MULTICAST_PVS_R = 5; // within sight, reliable
+
+
+
+
+//================================================
+
+//
+// globals
+//
+float movedist;
+
+string string_null; // null string, nothing should be held here
+float empty_float;
+
+entity activator; // the entity that activated a trigger or brush
+
+entity damage_attacker; // set by T_Damage
+entity damage_inflictor;
+float framecount;
+
+//
+// cvars checked each frame
+//
+float teamplay;
+float timelimit;
+float fraglimit;
+float deathmatch;
+float rj = 1;
+
+//================================================
+
+//
+// world fields (FIXME: make globals)
+//
+.string wad;
+.string map;
+.float worldtype; // 0=medieval 1=metal 2=base
+
+//================================================
+
+.string killtarget;
+
+//
+// quakeed fields
+//
+.float light_lev; // not used by game, but parsed by light util
+.float style;
+
+
+//
+// monster ai
+//
+.void() th_stand;
+.void() th_walk;
+.void() th_run;
+.void() th_missile;
+.void() th_melee;
+.void(entity attacker, float damage) th_pain;
+.void() th_die;
+
+.entity oldenemy; // mad at this player before taking damage
+
+.float speed;
+
+.float lefty;
+
+.float search_time;
+.float attack_state;
+
+float AS_STRAIGHT = 1;
+float AS_SLIDING = 2;
+float AS_MELEE = 3;
+float AS_MISSILE = 4;
+
+//
+// player only fields
+//
+.float voided;
+.float walkframe;
+
+// Zoid Additions
+.float maxspeed; // Used to set Maxspeed on a player
+.float gravity; // Gravity Multiplier (0 to 1.0)
+
+
+
+.float attack_finished;
+.float pain_finished;
+
+.float invincible_finished;
+.float invisible_finished;
+.float super_damage_finished;
+.float radsuit_finished;
+
+.float invincible_time, invincible_sound;
+.float invisible_time, invisible_sound;
+.float super_time, super_sound;
+.float rad_time;
+.float fly_sound;
+
+.float axhitme;
+
+.float show_hostile; // 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 jump_flag; // player jump flag
+.float swim_flag; // player swimming sound flag
+.float air_finished; // when time > air_finished, start drowning
+.float bubble_count; // keeps track of the number of bubbles
+.string deathtype; // keeps track of how the player died
+
+//
+// object stuff
+//
+.string mdl;
+.vector mangle; // angle at start
+
+.vector oldorigin; // only used by secret door
+
+.float t_length, t_width;
+
+
+//
+// doors, etc
+//
+.vector dest, dest1, dest2;
+.float wait; // time from firing to restarting
+.float delay; // time from activation to firing
+.entity trigger_field; // door's trigger entity
+.string noise4;
+
+//
+// monsters
+//
+.float pausetime;
+.entity movetarget;
+
+
+//
+// doors
+//
+.float aflag;
+.float dmg; // damage done by door when hit
+
+//
+// misc
+//
+.float cnt; // misc flag
+
+//
+// subs
+//
+.void() think1;
+.vector finaldest, finalangle;
+
+//
+// triggers
+//
+.float count; // for counting triggers
+
+
+//
+// plats / doors / buttons
+//
+.float lip;
+.float state;
+.vector pos1, pos2; // top and bottom positions
+.float height;
+
+//
+// sounds
+//
+.float waitmin, waitmax;
+.float distance;
+.float volume;
+
+
+
+
+//===========================================================================
+
+
+//
+// builtin functions
+//
+
+void(vector ang) makevectors = #1; // sets v_forward, etc globals
+void(entity e, vector o) setorigin = #2;
+void(entity e, string m) setmodel = #3; // set movetype and solid first
+void(entity e, vector min, vector max) setsize = #4;
+// #5 was removed
+void() break = #6;
+float() random = #7; // returns 0 - 1
+void(entity e, float chan, string samp, float vol, float atten) sound = #8;
+vector(vector v) normalize = #9;
+void(string e) error = #10;
+void(string e) objerror = #11;
+float(vector v) vlen = #12;
+float(vector v) vectoyaw = #13;
+entity() spawn = #14;
+void(entity e) remove = #15;
+
+// sets trace_* globals
+// nomonsters can be:
+// An entity will also be ignored for testing if forent == test,
+// forent->owner == test, or test->owner == forent
+// a forent of world is ignored
+void(vector v1, vector v2, float nomonsters, entity forent) traceline = #16;
+
+entity() checkclient = #17; // returns a client to look for
+entity(entity start, .string fld, string match) find = #18;
+string(string s) precache_sound = #19;
+string(string s) precache_model = #20;
+void(entity client, string s)stuffcmd = #21;
+entity(vector org, float rad) findradius = #22;
+void(float level, string s) bprint = #23;
+void(entity client, float level, string s) sprint = #24;
+void(string s) dprint = #25;
+string(float f) ftos = #26;
+string(vector v) vtos = #27;
+void() coredump = #28; // prints all edicts
+void() traceon = #29; // turns statment trace on
+void() traceoff = #30;
+void(entity e) eprint = #31; // prints an entire edict
+float(float yaw, float dist) walkmove = #32; // returns TRUE or FALSE
+// #33 was removed
+float(float yaw, float dist) droptofloor= #34; // TRUE if landed on floor
+void(float style, string value) lightstyle = #35;
+float(float v) rint = #36; // round to nearest int
+float(float v) floor = #37; // largest integer <= v
+float(float v) ceil = #38; // smallest integer >= v
+// #39 was removed
+float(entity e) checkbottom = #40; // true if self is on ground
+float(vector v) pointcontents = #41; // returns a CONTENT_*
+// #42 was removed
+float(float f) fabs = #43;
+vector(entity e, float speed) aim = #44; // returns the shooting vector
+float(string s) cvar = #45; // return cvar.value
+void(string s) localcmd = #46; // put string into local que
+entity(entity e) nextent = #47; // for looping through all ents
+// #48 was removed
+void() ChangeYaw = #49; // turn towards self.ideal_yaw
+ // at self.yaw_speed
+// #50 was removed
+vector(vector v) vectoangles = #51;
+
+//
+// direct client message generation
+//
+void(float to, float f) WriteByte = #52;
+void(float to, float f) WriteChar = #53;
+void(float to, float f) WriteShort = #54;
+void(float to, float f) WriteLong = #55;
+void(float to, float f) WriteCoord = #56;
+void(float to, float f) WriteAngle = #57;
+void(float to, string s) WriteString = #58;
+void(float to, entity s) WriteEntity = #59;
+
+// several removed
+
+void(float step) movetogoal = #67;
+
+string(string s) precache_file = #68; // no effect except for -copy
+void(entity e) makestatic = #69;
+void(string s) changelevel = #70;
+
+//#71 was removed
+
+void(string var, string val) cvar_set = #72; // sets cvar.value
+
+void(entity client, string s) centerprint = #73; // sprint, but in middle
+
+void(vector pos, string samp, float vol, float atten) ambientsound = #74;
+
+string(string s) precache_model2 = #75; // registered version only
+string(string s) precache_sound2 = #76; // registered version only
+string(string s) precache_file2 = #77; // registered version only
+
+void(entity e) setspawnparms = #78; // set parm1... to the
+ // values at level start
+ // for coop respawn
+void(entity killer, entity killee) logfrag = #79; // add to stats
+
+string(entity e, string key) infokey = #80; // get a key value (world = serverinfo)
+float(string s) stof = #81; // convert string to float
+void(vector where, float set) multicast = #82; // sends the temp message to a set
+ // of clients, possibly in PVS or PHS
+
+//============================================================================
+
+//
+// subs.qc
+//
+void(vector tdest, float tspeed, void() func) SUB_CalcMove;
+void(entity ent, vector tdest, float tspeed, void() func) SUB_CalcMoveEnt;
+void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove;
+void() SUB_CalcMoveDone;
+void() SUB_CalcAngleMoveDone;
+void() SUB_Null;
+void() SUB_UseTargets;
+void() SUB_Remove;
+
+//
+// combat.qc
+//
+void(entity targ, entity inflictor, entity attacker, float damage) T_Damage;
+
+
+float (entity e, float healamount, float ignore) T_Heal; // health function
+
+float(entity targ, entity inflictor) CanDamage;
+
+
View
809 qw-qc/doors.qc
@@ -0,0 +1,809 @@
+/*
+ doors.qc
+
+ door functions
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to:
+
+ Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330
+ Boston, MA 02111-1307, USA
+
+*/
+
+float DOOR_START_OPEN = 1;
+float DOOR_DONT_LINK = 4;
+float DOOR_GOLD_KEY = 8;
+float DOOR_SILVER_KEY = 16;
+float DOOR_TOGGLE = 32;
+
+/*
+
+Doors are similar to buttons, but can spawn a fat trigger field around them
+to open without a touch, and they link together to form simultanious