Back Last changes: 1998-09-01 Contact Maddes

QuakeC Fixes

QuakeC categories: Infos & Hints Fixes Workarounds Enhancements
(discontinued, check out URQP source for more information)

Index

New-line problems
Some lines in the second half of "Items.qc" are missing a new-line or carriage-return character, so they are more than one code line in a text line. Just look for them and correct them, this will help you to read these lines.

Spelling error
There's a spelling error in "Client.qc" at the begin of the "trigger_changelevel" function, it should be called "changelevel".

Fish count fix
Fishes are counted twice, once in "swimmonster_start_go()" and once in "swimmonster_start()". These functions are located at the end of "Monster.qc", just comment out "total_monsters = total_monsters + 1;" in "swimmonster_start_go()" to make it work like in the other functions.

New episode fix
When a player gets back to the start map without having a rune he keeps all his weapons and ammo.
Removing the weapons on the start map depends on "serverflags" (rune-flags) instead of "deathmatch". Just change "DecodeLevelParms()" in "Client.qc" to recognize SinglePlayer/Coop instead of the runes.

"Client.qc"
void() DecodeLevelParms =
{
// 1998-01-21 Episode fix by Maddes  start
	if (!deathmatch)
//	if (serverflags)
// 1998-01-21 Episode fix by Maddes  end
	{
		if (world.model == "maps/start.bsp")
			SetNewParms ();		// take away all stuff on starting new episode
	}
...
};

Thunderbolt fix
The waterlevel is not recognized in "RankForWeapon()" of "Items.qc", so you have to put it in. Quake will then never switch to the thunderbolt underwater again when in Deathmatch.
Additional comment:
Why did id not return a rank of 99 instead of 7 to make the code expandable without changes?

"Items.qc"

float(float w) RankForWeapon =
{
	if (self.waterlevel <= 1 && w == IT_LIGHTNING)		// 1997-12-23 Thunderbolt fix by Maddes  recognize waterlevel
		return 1;
	if (w == IT_ROCKET_LAUNCHER)
		return 2;
...
	if (w == IT_NAILGUN)
		return 6;
	return 7;
};
To avoid switching to the thunderbolt in SinglePlayer and Coop, you have to eleminate the if clause in "weapon_touch()" and "BackpackTouch()".
Additional comment:
I think id had a correct or other weapon selection, but forget to put it in, otherwise I don't know why "best" is defined and filled. Or maybe just a rest of an old code, which could be deleted?
"Items.qc"

void() weapon_touch =
{
...
// change to the weapon
	old = other.items;
	other.items = other.items | new;
	
	stemp = self;
	self = other;

// 1997-12-23 Thunderbolt fix by Maddes  start
/* don't separate between SinglePlayer/Coop and Deathmatch
	if (!deathmatch)
		self.weapon = new;
	else
*/
// 1997-12-23 Thunderbolt fix by Maddes  end
		Deathmatch_Weapon (old, new);

	W_SetCurrentAmmo();

	self = stemp;

	if (leave)
		return;
...
};

void() BackpackTouch =
{
...	
// change to the weapon
// 1997-12-23 Thunderbolt fix by Maddes  start
/* don't separate between SinglePlayer/Coop and Deathmatch
	if (!deathmatch)
		self.weapon = new;
	else
*/
// 1997-12-23 Thunderbolt fix by Maddes  end
		Deathmatch_Weapon (old, new);

	W_SetCurrentAmmo ();
};

"NoExit" SinglePlayer/Coop fix
Although the "NoExit" console variable was created for deathmatch purposes, it's also recognized in SinglePlayer and Coop games, which permits exiting a level.
All you have to do is to check for deathmatch in the handling of "NoExit" in the "changelevel_touch()" function of "Client.qc".

"Client.qc"

void() changelevel_touch =
{
	local entity	pos;

	if (other.classname != "player")
		return;

// 1998-07-08 Noexit singleplayer/coop fix by Maddes  start
	if (deathmatch)
	{
// 1998-07-08 Noexit singleplayer/coop fix by Maddes  end
	if ((cvar("noexit") == 1) || ((cvar("noexit") == 2) && (mapname != "start")))
	{
		T_Damage (other, self, self, 50000);
		return;
	}
	}	// 1998-07-08 Noexit singleplayer/coop fix by Maddes
...
};

Respawn velocity fix by Xian
This prevents the player from keeping his previous velocity when he respawns. Taken from the QuakeWorld v2.21 source, fixed by Xian.

"Client.qc"
void() PutClientInServer =
{
...
	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';	// 1998-07-21 Player moves after respawn fix by Xian

	player_stand1 ();
...
};

Classname trigger_hurt entity fix by Robert Field
There is a bug in the handling of classname trigger_hurt entities in "triggers.qc".

"Defs.qc"

// 1998-07-03 hurt_touch fix by Robert Field  start
//
// triggers.qc
//
.float hurt_together_time;
.float hurt_nextthink;
// 1998-07-03 hurt_touch fix by Robert Field  end
If you read the code then an classname trigger_hurt entity should hurt players every second. This doesn't happen due to the "hurt_on()" function use of SOLID_TRIGGER is not 'enough' to relink the trigger into the world (restoring self.model and then executing InitTrigger relinks correctly but only one player is hurt (the first on the client entity order list)).
See the rocket launcher area of map end for an example.
The "hurt_on()" function is no longer needed.
"Triggers.qc"

// 1998-07-03 hurt_touch fix by Robert Field  start
/*
void() hurt_on =
{
	self.solid = SOLID_TRIGGER;
	self.nextthink = -1;
};
*/
// 1998-07-03 hurt_touch fix by Robert Field  end

void() hurt_touch =
{
	if (other.takedamage)
	{
// 1998-07-03 hurt_touch fix by Robert Field  start
//		self.solid = SOLID_NOT;
		if (time != self.hurt_together_time)
			if (time < self.hurt_nextthink)
				return;
// 1998-07-03 hurt_touch fix by Robert Field  end
		T_Damage (other, self, self, self.dmg);
// 1998-07-03 hurt_touch fix by Robert Field  start
//		self.think = hurt_on;
//		self.nextthink = time + 1;
		self.hurt_together_time = time;
		self.hurt_nextthink = time + 1;
// 1998-07-03 hurt_touch fix by Robert Field  end
	}

	return;
};

Respawning where player died fix by Robert Field
This prevents the player from respawning where he died, when all respawning spots are occupied.

"Client.qc"
void() PutClientInServer =
{
...
// paustime is set by teleporters to keep the player from moving a while
	self.pausetime = 0;
	
//	spot = SelectSpawnPoint ();

	self.origin = self.oldorigin = spot.origin + '0 0 1';	// 1998-07-21 Respawning where player died fix by Robert Field
	self.angles = spot.angles;
	self.fixangle = TRUE;		// turn this way immediately
...
};

Wrong obituary messages fix by Zoid
When a player is killed through a not-immediately-hit weapon or better projectile (rocket, grenade, spike, etc) and the attacker changes his weapon before the impact, the wrong obituary message is displayed, e.g. axemurder instead of rocket gib. To avoid this you have to make use of ".deathtype" for those weapons and projectiles.
The following code is taken from the QW 2.21 source.

First you have to expand the "T_RadiusDamage" with a new parameter, which contains the deathtype for the victims of the splash damage.

"Combat.qc"
void() tdeath_touch =
// 1998-07-24 Wrong obituary messages fix by Zoid  added parameter dtype
void(entity inflictor, entity attacker, float damage, entity ignore, string dtype) T_RadiusDamage =
{
	...
	head = findradius(inflictor.origin, damage+40);
	
	while (head)
	{
		if (head != ignore)
		{
			if (head.takedamage)
			{
			...
				if (points > 0)
				{
					if (CanDamage (head, inflictor))
					{
						head.deathtype = dtype;	// 1998-07-24 Wrong obituary messages fix by Zoid
					....
					}
				}
			}
		}
		head = head.chain;
	}
...
};
Then you have to do define a deathtype for all those weapons and projectiles. This has to be done for direct impact and splash damage. Don't forget the laser bolts, plats and doors for traps. The doors need an additional handling for traps (double-sided doors) to determine who triggered them. Finally all other uses of "T_RadiusDamage" for damage caused by monsters has to be adpated with setting the deathtype to nothing.
"Weapons.qc"
void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
void () player_run;
void(entity bomb, entity attacker, float rad, entity ignore, string dtype) T_RadiusDamage;	// 1998-07-24 Wrong obituary messages fix by Zoid
...
void() T_MissileTouch =
{
...
	damg = 100 + random()*20;
	
	if (other.health)
	{
		other.deathtype = "rocket";	// 1998-07-24 Wrong obituary messages fix by Zoid
		if (other.classname == "monster_shambler")
			damg = damg * 0.5;	// mostly immune
		T_Damage (other, self, self.owner, damg );
	}

	// don't do radius damage to the other, because all the damage
	// was done in the impact
	T_RadiusDamage (self, self.owner, 120, other, "rocket");	// 1998-07-24 Wrong obituary messages fix by Zoid
...
};
...
void() W_FireLightning =
{
...
// explode if under water
	if (self.waterlevel > 1)
	{
		cells = self.ammo_cells;
		self.ammo_cells = 0;
		W_SetCurrentAmmo ();
		T_RadiusDamage (self, self, 35*cells, world, "");	// 1998-07-24 Wrong obituary messages fix by Zoid
		return;
	}
...
};

void() GrenadeExplode =
{
	T_RadiusDamage (self, self.owner, 120, world, "grenade");	// 1998-07-24 Wrong obituary messages fix by Zoid
...
};
...
void() spike_touch =
{
...
// hit something that bleeds
	if (other.takedamage)
	{
		spawn_touchblood (9);
		other.deathtype = "nail";	// 1998-07-24 Wrong obituary messages fix by Zoid
		T_Damage (other, self, self.owner, 9);
	}
...
};

void() superspike_touch =
{
...
// hit something that bleeds
	if (other.takedamage)
	{
		spawn_touchblood (18);
		other.deathtype = "supernail";	// 1998-07-24 Wrong obituary messages fix by Zoid
		T_Damage (other, self, self.owner, 18);
	}
...
};

"Doors.qc"
void() door_blocked =
{
// 1998-07-24 Wrong obituary messages fix by Zoid  start
	other.deathtype = "squish";
//	T_Damage (other, self, self, self.dmg);
	T_Damage (other, self, self.goalentity, self.dmg);
// 1998-07-24 Wrong obituary messages fix by Zoid  end
...
};
...
void() door_fire =
{
...
// trigger all paired doors
	starte = self;
	do
	{
		self.goalentity = activator;	// 1998-07-24 Wrong obituary messages fix by Zoid  Who fired us
		door_go_up ();
		self = self.enemy;
	} while ( (self != starte) && (self != world) );
	self = oself;
};
...
void () secret_blocked =
{
	if (time < self.attack_finished)
		return;
	self.attack_finished = time + 0.5;
	other.deathtype = "squish";	// 1998-07-24 Wrong obituary messages fix by Zoid
	T_Damage (other, self, self, self.dmg);
};

"Plats.qc"
void() plat_crush =
{
//dprint ("plat_crush\n");

	other.deathtype = "squish";	// 1998-07-24 Wrong obituary messages fix by Zoid
	T_Damage (other, self, self, 1);
...
};
...
void() train_blocked =
{
	if (time < self.attack_finished)
		return;
	self.attack_finished = time + 0.5;
	other.deathtype = "squish";	// 1998-07-24 Wrong obituary messages fix by Zoid
	T_Damage (other, self, self, self.dmg);
};

"Enforcer.qc"
void() Laser_Touch =
{
...
	if (other.health)
	{
		SpawnBlood (org, self.velocity*0.2, 15);
		other.deathtype = "laser";	// 1998-07-24 Wrong obituary messages fix by Zoid
		T_Damage (other, self, self.owner, 15);
	}
...
};

"Misc.qc"
void() barrel_explode =
{
	self.takedamage = DAMAGE_NO;
	self.classname = "explo_box";
	// did say self.owner
	T_RadiusDamage (self, self, 160, world, "");	// 1998-07-24 Wrong obituary messages fix by Zoid
	sound (self, CHAN_VOICE, "weapons/r_exp3.wav", 1, ATTN_NORM);
	particle (self.origin, '0 0 0', 75, 255);

	self.origin_z = self.origin_z + 32;
	BecomeExplosion ();
};

"Ogre.qc"
void() OgreGrenadeExplode =
{
	T_RadiusDamage (self, self.owner, 40, world, "");	// 1998-07-24 Wrong obituary messages fix by Zoid
...
};

"Shalrath.qc"
void() ShalMissileTouch =
{
	if (other == self.owner)
		return;		// don't explode on owner

	if (other.classname == "monster_zombie")
		T_Damage (other, self, self, 110);	
	T_RadiusDamage (self, self.owner, 40, world, "");	// 1998-07-24 Wrong obituary messages fix by Zoid
	sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
...
};

"Tarbaby.qc"
void()	tbaby_die2	=[	$exp,		tbaby_run1	]
{
	T_RadiusDamage (self, self, 120, world, "");	// 1998-07-24 Wrong obituary messages fix by Zoid
...
};
At last you should initialize every player's deathtype every frame and recognize it on their death.
"Client.qc"
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 = "";	// 1998-07-24 Wrong obituary messages fix by Zoid
...
};
...
void() PlayerPostThink =
{
...
// 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";	// 1998-07-24 Wrong obituary messages fix by Zoid
			T_Damage (self, world, world, 5); 
			sound (self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM);
//			self.deathtype = "falling";	// 1998-07-24 Wrong obituary messages fix by Zoid
		}
	...
	}
...
};
...
void(entity targ, entity attacker) ClientObituary =
{
...
// 1998-07-24 Wrong obituary messages fix by Zoid  start
		if (targ.deathtype == "squish")
		{
			if (teamplay && targ.team == attacker.team && targ != attacker)
			{
				attacker.frags = attacker.frags - 1; 
				bprint (attacker.netname);
				bprint (" squished a teammate\n");
				return;
			}
			else if (attacker.classname == "player" && targ != attacker)
			{
				bprint (attacker.netname);
				bprint (" squishes ");
				bprint (targ.netname);
				bprint ("\n");
				attacker.frags = attacker.frags + 1;
				return;
			}
			else
			{
				targ.frags = targ.frags - 1;            // killed self
				bprint (targ.netname);
				bprint (" was squished\n");
				return;
			}
			return;
		}
// 1998-07-24 Wrong obituary messages fix by Zoid  end

		if (attacker.classname == "player")
		{
			if (targ == attacker)
			{
				// killed self
				attacker.frags = attacker.frags - 1;
				bprint (targ.netname);

// 1998-07-24 Wrong obituary messages fix by Zoid  start
				if (targ.deathtype == "grenade")
				{
					bprint (" tries to put the pin back in\n");
					return;
				}
				else if (targ.deathtype == "rocket")
				{
					// 1998-07-24 enhanced obituary messages by Maddes  start
					if (targ.health < -40)
						bprint (" explodes with his own rocket\n");
					else
						bprint (" dies through his own rocket\n");
					// 1998-07-24 enhanced obituary messages by Maddes  end
					return;
				}
				else
// 1998-07-24 Wrong obituary messages fix by Zoid  end
				if (targ.weapon == IT_LIGHTNING && targ.waterlevel > 1)
				{
// 1998-07-24 Wrong obituary messages fix by Zoid  start
					if (targ.watertype == CONTENT_SLIME)
						bprint (" discharges into the slime\n");
					else if (targ.watertype == CONTENT_LAVA)
						bprint (" discharges into the lava\n");
					else
// 1998-07-24 Wrong obituary messages fix by Zoid  end
						bprint (" discharges into the water.\n");
					return;
				}
// 1998-07-24 Wrong obituary messages fix by Zoid  start
//				if (targ.weapon == IT_GRENADE_LAUNCHER)
//					bprint (" tries to put the pin back in\n");
//				else
// 1998-07-24 Wrong obituary messages fix by Zoid  end
					bprint (" becomes bored with life\n");
				return;
			}
			else if ( (teamplay == 2) && (targ.team > 0)&&(targ.team == attacker.team) )
			{
			...
			}
			else
			{
				attacker.frags = attacker.frags + 1;

				rnum = attacker.weapon;
// 1998-07-24 Wrong obituary messages fix by Zoid  start
				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 (attacker.netname);
							bprint (" rips ");
							bprint (targ.netname);
							bprint (" 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
// 1998-07-24 Wrong obituary messages fix by Zoid  end
				if (rnum == IT_AXE)
				{
					deathstring = " was ax-murdered by ";
					deathstring2 = "\n";
				}
				else	// 1998-07-24 Wrong obituary messages fix by Zoid
				if (rnum == IT_SHOTGUN)
				{
					deathstring = " chewed on ";
					deathstring2 = "'s boomstick\n";
				}
				else	// 1998-07-24 Wrong obituary messages fix by Zoid
				if (rnum == IT_SUPER_SHOTGUN)
				{
					deathstring = " ate 2 loads of ";
					deathstring2 = "'s buckshot\n";
				}
// 1998-07-24 Wrong obituary messages fix by Zoid  start
//				if (rnum == IT_NAILGUN)
//				{
//					deathstring = " was nailed by ";
//					deathstring2 = "\n";
//				}
//				if (rnum == IT_SUPER_NAILGUN)
//				{
//					deathstring = " was punctured by ";
//					deathstring2 = "\n";
//				}
//				if (rnum == IT_GRENADE_LAUNCHER)
//				{
//					deathstring = " eats ";
//					deathstring2 = "'s pineapple\n";
//					if (targ.health < -40)
//					{
//						deathstring = " was gibbed by ";
//						deathstring2 = "'s grenade\n";
//					}
//				}
//				if (rnum == IT_ROCKET_LAUNCHER)
//				{
//					deathstring = " rides ";
//					deathstring2 = "'s rocket\n";
//					if (targ.health < -40)
//					{
//						deathstring = " was gibbed by ";
//						deathstring2 = "'s rocket\n";
//					}
//				}
				else
// 1998-07-24 Wrong obituary messages fix by Zoid  end
				if (rnum == IT_LIGHTNING)
				{
					deathstring = " accepts ";
					if (attacker.waterlevel > 1)
						deathstring2 = "'s discharge\n";
					else
						deathstring2 = "'s shaft\n";
				}
				bprint (targ.netname);
				bprint (deathstring);
				bprint (attacker.netname);
				bprint (deathstring2);
			}
			return;
		}
		else
		{
			targ.frags = targ.frags - 1;
			bprint (targ.netname);

			// killed by a monster?
			if (attacker.flags & FL_MONSTER)
			{
			...
			}

			// tricks and traps
			if (attacker.classname == "explo_box")
			{
				bprint (" blew up\n");
				return;
			}
// 1998-07-24 Wrong obituary messages fix by Zoid  start
			if (targ.deathtype == "falling")
			{
				bprint (" fell to his death\n");
				return;
			}
/*
			if (attacker.solid == SOLID_BSP && attacker != world)
			{	
				bprint (" was squished\n");
				return;
			}
			if (attacker.classname == "trap_shooter" || attacker.classname == "trap_spikeshooter")
			{
				bprint (" was spiked\n");
				return;
			}
*/
			if (targ.deathtype == "nail" || targ.deathtype == "supernail")
			{
				bprint (" was spiked\n");
				return;
			}
			if (targ.deathtype == "laser")
			{
				bprint (" was zapped\n");
				return;
			}
// 1998-07-24 Wrong obituary messages fix by Zoid  end
			if (attacker.classname == "fireball")
			{
				bprint (" ate a lavaball\n");
				return;
			}
			if (attacker.classname == "trigger_changelevel")
			{
				bprint (" tried to leave\n");
				return;
			}

			// in-water deaths
			...

// 1998-07-24 Wrong obituary messages fix by Zoid  start
/*
			// fell to their death?
			if (targ.deathtype == "falling")
			{
				targ.deathtype = "";
				bprint (" fell to his death\n");
				return;
			}
*/
// 1998-07-24 Wrong obituary messages fix by Zoid  end

			// hell if I know; he's just dead!!!
			bprint (" died\n");
		}
	}
};

Pentagram telefrag fix by Zoid
When a player tries to telefrag another one which has an active pentagram, then the player with the pentagram gets stucked and the other will be teleported like normal. Originally the intention was that the player with the pentagram is protected against telefrags and the other dies. To correct this you have to kill the player telefragging player in "tdeatch_touch" of "triggers.qc". Also the situation when both have an active pentagram has to be handled.
The following code is taken from the QW 2.21 source. I modified it a little bit, so that a double pentagram telefrag is handled like a normal telefrag.

"Triggers.qc"
void() tdeath_touch =
{
	if (other == self.owner)
		return;

// frag anyone who teleports in on top of an invincible player
	if (other.classname == "player")
	{
// 1998-07-26 Pentagram telefrag fix by Zoid/Maddes  start
		if (self.owner.classname != "player")
		{	// other monsters explode themselves
			T_Damage (self.owner, self, self, 50000);
			return;
		}
// 1998-07-26 Pentagram telefrag fix by Zoid/Maddes  end

		if (other.invincible_finished > time)
// 1998-07-26 Pentagram telefrag fix by Zoid/Maddes  start
		{	//player on spot has active pentagram
			if (self.owner.invincible_finished > time)
			{	// teleported player has active pentagram too
				// can happen often in deathmatch 4
				// and levels with more than one pentagram
				self.classname = "teledeath3";
				other.invincible_finished = 0;
				T_Damage (other, self, self, 50000);	// kill player on spot
/* 1998-07-26 only telefrag player on spot by Maddes
				local entity other2;
				other2 = self.owner;
				self.owner = other;
				other2.invincible_finished = 0;
				T_Damage (other2, self, self, 50000);	// kill teleported player
*/
			}
			else	// 1998-07-26 only telefrag player on spot by Maddes
			{	// 1998-07-26 only telefrag player on spot by Maddes
// 1998-07-26 Pentagram telefrag fix by Zoid/Maddes  end

				self.classname = "teledeath2";

// 1998-07-26 Pentagram telefrag fix by Zoid/Maddes  start
				T_Damage (self.owner, self, self, 50000);
			}	// 1998-07-26 only telefrag player on spot by Maddes
			return;
		}

/*
		if (self.owner.classname != "player")
		{	// other monsters explode themselves
			T_Damage (self.owner, self, self, 50000);
			return;
		}
*/
// 1998-07-26 Pentagram telefrag fix by Zoid/Maddes  end
	}

	if (other.health)
	{
		T_Damage (other, self, self, 50000);
	}
};
Now you have to handle the obituary message and the frag count for a double pentagram telefrag.
"Client.qc"
void() tdeath_touch =
{
...
		if (attacker.classname == "teledeath2")
		{
		...
		}

// 1998-07-26 Pentagram telefrag fix by Zoid/Maddes  start
		// double 666 telefrag
		// (can happen often in deathmatch 4 and levels with more than one pentagram)
		if (attacker.classname == "teledeath3")
		{
			bprint (targ.netname);
			bprint (" was telefragged by ");
			bprint (attacker.owner.netname);
			bprint ("'s Satan's power\n");
// 1998-07-26 only telefrag player on spot by Maddes  start
//			targ.frags = targ.frags - 1;
			attacker.owner.frags = attacker.owner.frags + 1;
// 1998-07-26 only telefrag player on spot by Maddes  end
			return;
		}
// 1998-07-26 Pentagram telefrag fix by Zoid/Maddes  end
...
};

Dead bodies glow and palette shift fix
To avoid killed players with quad/pentagram from glowing and the corresponding client from palette shift until respawn, just reset the items and effects when a player dies.

"Player.qc"
void() PlayerDie =
{
	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
	self.invisible_finished = 0;	// don't die as eyes
	self.invincible_finished = 0;
	self.super_damage_finished = 0;
	self.radsuit_finished = 0;
	self.effects = 0;	// 1998-07-23 Glowing corpse of players which had quad/pentagram until respawn fix by Maddes
	self.modelindex = modelindex_player;	// don't use eyes
...
};

Fraglimit and timelimit fix
As fraglimit and timelimit disturb SinglePlayer and Coop games, you just have to check for deathmatch.

"Client.qc"
void() CheckRules =
{
	local	float		timelimit;
	local	float		fraglimit;
	
	if (gameover)	// someone else quit the game already
		return;
		
	timelimit = cvar("timelimit") * 60;
	fraglimit = cvar("fraglimit");
	
	if (deathmatch && timelimit && time >= timelimit)	// 1998-07-27 Timelimit/Fraglimit fix by Maddes
	{
		NextLevel ();
		return;
	}
	
	if (deathmatch && fraglimit && self.frags >= fraglimit)	// 1998-07-27 Timelimit/Fraglimit fix by Maddes
	{
		NextLevel ();
		return;
	}	
};

Suicide during intermission fix by Yun Zheng "Zhenga" Hu
Players can still suicide during intermissions, which causes problems in Coop games or reactivate gameplay in deathmatch games, so you have to check for a running intermission and coop or deathmatch.

"Client.qc"
void() ClientKill =
{
// 1998-07-27 Suicide during intermission fix by Zhenga  start
	if ((intermission_running)&&((coop)||(deathmatch)))  // not allowed during intermission
		return;
// 1998-07-27 Suicide during intermission fix by Zhenga  end
...
};

Cheats Coop fix
As impulse cheats are not possible in Coop games, you have to check for deathmatch only.

"Weapons.qc"
void() CheckRules =
void() CheatCommand =
{
// 1998-07-29 Cheats coop fix by Maddes  start
//	if (deathmatch || coop)
	if (deathmatch)
// 1998-07-29 Cheats coop fix by Maddes  end
		return;
...
};

...

void() ServerflagsCommand =
{
// 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;
};

void() 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 ("quad cheat\n");
};

Teamplay 1 fix
Players can not hurt themselves in teamplay 1 mode, so you have to check if attacker gets hurt through a splash damage of his rocket, grenade, etc. Also doors should always hurt a player, no matter who triggered it.

"Combat.qc"
void(entity targ, entity inflictor, entity attacker, float damage) T_Damage=
{
...
// team play damage avoidance
// 1998-07-29 Teamplay 1 fix by Maddes  start
	if ( (teamplay == 1) && (targ.team > 0) && (targ.team == attacker.team)
	&& (targ != attacker) 			
	&& (attacker.classname == "player")
	&& (inflictor.classname != "door") )	// because squishing a teammate is still possible
// 1998-07-29 Teamplay 1 fix by Maddes  end
		return;
...
};

Shub kill count fix
The monster kill counter is not raised when telefragging shub.

"Oldone.qc"
void() finale_1 =
{
	local entity	pos, pl;
	local entity	timer;

// 1998-07-30 Shub kill count fix by Maddes  start
	killed_monsters = killed_monsters + 1;
	WriteByte (MSG_ALL, SVC_KILLEDMONSTER);	// FIXME: reliable broadcast
// 1998-07-30 Shub kill count fix by Maddes  end
...
};

Door unlock sound fix by Nolan "Radix" Pflug (QdQ Team)
When a door is unlocked by a key, the unlock sound is overwritten with the door opening sound.
Use the item sound channel for the unlock sound as a key item unlocks it.

"Doors.qc"
void() door_fire =
{
...
// play use key sound

	if (self.items)
// 1998-08-08 Door unlock sound fix by Nolan Pflug  start
//		sound (self, CHAN_VOICE, self.noise4, 1, ATTN_NORM);
		sound (self, CHAN_ITEM, self.noise4, 1, ATTN_NORM);
// 1998-08-08 Door unlock sound fix by Nolan Pflug  end
...
};

Fish death fix
Dying fishes block your way much longer and are not gibable than all other monsters.
Make them non-solid on their third death frame, and create a new death function which checks if they were gibbed.

"Fish.qc"
...
void() f_death1 =[      $death1,        f_death2        ] {
sound (self, CHAN_VOICE, "fish/death.wav", 1, ATTN_NORM);
};
void() f_death2 =[      $death2,        f_death3        ] {};
void() f_death3 =[      $death3,        f_death4        ] {
self.solid = SOLID_NOT;	// 1998-08-09 Dying fishes not immediately non-solid fix by Maddes/Athos
};
void() f_death4 =[      $death4,        f_death5        ] {};
...
void() f_death20 =[      $death20,       f_death21       ] {};
void() f_death21 =[      $death21,       f_death21       ] {
//self.solid = SOLID_NOT;	// 1998-08-09 Dying fishes not immediately non-solid fix by Maddes/Athos
};
...
void(entity attacker, float damage)	fish_pain =
{
// fish allways do pain frames
	f_pain1 ();
};

// 1998-08-09 Gibbable fishes by Maddes/Athos  start
void() f_die =
{
// check for gib
	if (self.health < -35)
	{
		sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM);
		ThrowHead ("progs/gib3.mdl", self.health);
		ThrowGib ("progs/gib3.mdl", self.health);
		return;
	}

// regular death
	f_death1 ();
};
// 1998-08-09 Gibbable fishes by Maddes/Athos  end

/*QUAKED monster_fish (1 0 0) (-16 -16 -24) (16 16 24) Ambush
*/
void() monster_fish =
{
	if (deathmatch)
	{
		remove(self);
		return;
	}
	precache_model2 ("progs/fish.mdl");

	precache_sound2 ("fish/death.wav");
	precache_sound2 ("fish/bite.wav");
	precache_sound2 ("fish/idle.wav");

	self.solid = SOLID_SLIDEBOX;
	self.movetype = MOVETYPE_STEP;

	setmodel (self, "progs/fish.mdl");

	setsize (self, '-16 -16 -24', '16 16 24');
	self.health = 25;
	
	self.th_stand = f_stand1;
	self.th_walk = f_walk1;
	self.th_run = f_run1;
// 1998-08-09 Gibbable fishes by Maddes/Athos  start
//	self.th_die = f_death1;
	self.th_die = f_die;
// 1998-08-09 Gibbable fishes by Maddes/Athos  end
	self.th_pain = fish_pain;
	self.th_melee = f_attack1;
	
	swimmonster_start ();
};

Slime hurt fix
Player do not spawn bubbles when hurt in slime, this a "FIXME" point from id.

"Player.qc"
void() PainSound =
{
...
// 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 == 3)
			DeathBubbles(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;
	}
...
};

Mega health rot fix
When a player has two or more megahealth active then his health rots by two or more points per second, because each megahealth rots it by one point per second. Also the taken megahealth items respawn when the player has normal health again and not in a given time.
You have to create a new entity which rots the health of a player and is used by all megahealth items.

"Items.qc"
void() item_health =
{
...
};

// 1998-08-11 Multiple megahealth rot down too fast fix by Maddes/Athos  start
void(entity rotowner) MakeHealthRot =
{
	local entity rot;
	rot = spawn ();
	rot.classname = "health_rot";
	rot.nextthink = time + 5;
	rot.think = item_megahealth_rot;
	rot.owner = rotowner;
};
// 1998-08-11 Multiple megahealth rot down too fast fix by Maddes/Athos  end

void() health_touch =
{
	local float	amount;
	local string	s;

	if (other.classname != "player")
		return;

	if (self.healtype == 2) // Megahealth?  Ignore max_health...
	{
		if (other.health >= 250)
			return;
		if (!T_Heal(other, self.healamount, 1))
			return;
	}
	else
	{
		if (!T_Heal(other, self.healamount, 0))
			return;
	}

	sprint(other, "You receive ");
	s = ftos(self.healamount);
	sprint(other, s);
	sprint(other, " health\n");

// health touch sound
	sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM);

	stuffcmd (other, "bf\n");

	self.model = string_null;
	self.solid = SOLID_NOT;

	// Megahealth = rot down the player's super health
	if (self.healtype == 2)
	{
// 1998-08-11 Multiple megahealth rot down too fast fix by Maddes/Athos  start
		local entity	stemp;

		// search player's health rot entity
		stemp = find (world, classname, "health_rot");
		while ( (stemp!=world) && (stemp.owner != other) )
		{
			stemp = find(stemp,classname,"health_rot");
		}

		if (stemp)
		{
			// delay health rotting again
			stemp.nextthink = time + 5;
			stemp.think = item_megahealth_rot;
		}
		else
			MakeHealthRot(other);	// create rot entity
// 1998-08-11 Multiple megahealth rot down too fast fix by Maddes/Athos  end
		other.items = other.items | IT_SUPERHEALTH;
// 1998-08-11 Multiple megahealth rot down too fast fix by Maddes/Athos  start
/*
		self.nextthink = time + 5;
		self.think = item_megahealth_rot;
		self.owner = other;
*/
		if (deathmatch == 1)	// deathmatch 2 is silly old rules
		{
			self.nextthink = time + self.healamount + 25;	// delay (5) + health + respawn wait (20)
			self.think = SUB_regen;
		}
// 1998-08-11 Multiple megahealth rot down too fast fix by Maddes/Athos  end
	}
	else
	{
		if (deathmatch != 2)		// deathmatch 2 is the silly old rules
		{
			if (deathmatch)
				self.nextthink = time + 20;
			self.think = SUB_regen;
		}
	}

	activator = other;
	SUB_UseTargets();				// fire all targets / killtargets
};	

void() item_megahealth_rot =
{
	other = self.owner;

	if (other.health > other.max_health)
// 1998-08-11 Multiple megahealth rot down too fast fix by Maddes/Athos  start
		other.health = other.health - 1;

	if (other.health > other.max_health)
	{
// 1998-08-11 Multiple megahealth rot down too fast fix by Maddes/Athos  end
		self.nextthink = time + 1;
		return;
	}

// it is possible for a player to die and respawn between rots, so don't
// just blindly subtract the flag off
	other.items = other.items - (other.items & IT_SUPERHEALTH);

// 1998-08-11 Multiple megahealth rot down too fast fix by Maddes/Athos  start
	remove (self);
/*
	if (deathmatch == 1)	// deathmatch 2 is silly old rules
	{
		self.nextthink = time + 20;
		self.think = SUB_regen;
	}
*/
// 1998-08-11 Multiple megahealth rot down too fast fix by Maddes/Athos  end
};

Item pickup fix
Players pick up weapons, although they already have it with full ammo.
On the other hand they do not pick up items like keys, when they already have it (through cheating, etc.) and the corresponding triggers are not fired, which may trap them in a deadlock situation as you cannot throw away keys by example.
The following code will do the job:

"Items.qc"
void() health_touch =
{
	local float	amount;
	local string	s;
	local float	donttake;	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

	if (other.classname != "player")
		return;

	donttake = 0;	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

	if (self.healtype == 2) // Megahealth?  Ignore max_health...
	{
		if (other.health >= 250)
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//			return;
			donttake = 1;
		else
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		if (!T_Heal(other, self.healamount, 1))
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//			return;
			donttake = 1;
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
	}
	else
	{
		if (!T_Heal(other, self.healamount, 0))
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//			return;
			donttake = 1;
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
	}

// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
	if (!donttake)
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
...
		// Megahealth = rot down the player's super health
		if (self.healtype == 2)
		{
...
		}
		else
		{
			if (deathmatch != 2)		// deathmatch 2 is the silly old rules
			{
				if (deathmatch)
					self.nextthink = time + 20;
				self.think = SUB_regen;
			}
		}

	}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

	activator = other;
	SUB_UseTargets();				// fire all targets / killtargets
};

...

void() armor_touch =
{
...
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//	if (other.armortype*other.armorvalue >= type*value)
//		return;
	if (other.armortype*other.armorvalue < type*value)
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
...
	}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

	activator = other;
	SUB_UseTargets();				// fire all targets / killtargets
};

....

void() weapon_touch =
{
//	local float	hadammo;	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes
	local float	best, new, old;
	local entity	stemp;
	local float	leave;
	local float	donttake;	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes
...
	donttake = 0;	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

	if (self.classname == "weapon_nailgun")
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//		if (leave && (other.items & IT_NAILGUN) )
//			return;
		if ( (other.items & IT_NAILGUN)
		&& (leave || (other.ammo_nails >= 200)) )
			donttake = 1;
		else
		{
//		hadammo = other.ammo_nails;
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		new = IT_NAILGUN;
		other.ammo_nails = other.ammo_nails + 30;
		}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes
	}
	else if (self.classname == "weapon_supernailgun")
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//		if (leave && (other.items & IT_SUPER_NAILGUN) )
//			return;
		if ( (other.items & IT_SUPER_NAILGUN)
		&& (leave || (other.ammo_nails >= 200)) )
			donttake = 1;
		else
		{
//		hadammo = other.ammo_rockets;
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		new = IT_SUPER_NAILGUN;
		other.ammo_nails = other.ammo_nails + 30;
		}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes
	}
	else if (self.classname == "weapon_supershotgun")
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//		if (leave && (other.items & IT_SUPER_SHOTGUN) )
//			return;
		if ( (other.items & IT_SUPER_SHOTGUN)
		&& (leave || (other.ammo_shells >= 100)) )
			donttake = 1;
		else
		{
//		hadammo = other.ammo_rockets;
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		new = IT_SUPER_SHOTGUN;
		other.ammo_shells = other.ammo_shells + 5;
		}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes
	}
	else if (self.classname == >weapon_rocketlauncher")
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//		if (leave && (other.items & IT_ROCKET_LAUNCHER) )
//			return;
		if ( (other.items & IT_ROCKET_LAUNCHER)
		&& (leave || (other.ammo_rockets >= 100)) )
			donttake = 1;
		else
		{
//		hadammo = other.ammo_rockets;
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		new = IT_ROCKET_LAUNCHER;
		other.ammo_rockets = other.ammo_rockets + 5;
		}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes
	}
	else if (self.classname == "weapon_grenadelauncher")
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//		if (leave && (other.items & IT_GRENADE_LAUNCHER) )
//			return;
		if ( (other.items & IT_GRENADE_LAUNCHER)
		&& (leave || (other.ammo_rockets >= 100)) )
			donttake = 1;
		else
		{
//		hadammo = other.ammo_rockets;			
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		new = IT_GRENADE_LAUNCHER;
		other.ammo_rockets = other.ammo_rockets + 5;
		}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes
	}
	else if (self.classname == "weapon_lightning")
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//		if (leave && (other.items & IT_LIGHTNING) )
//			return;
		if ( (other.items & IT_LIGHTNING)
		&& (leave || (other.ammo_cells >= 100)) )
			donttake = 1;
		else
		{
//		hadammo = other.ammo_rockets;			
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		new = IT_LIGHTNING;
		other.ammo_cells = other.ammo_cells + 15;
		}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes
	}
	else
		objerror ("weapon_touch: unknown classname");

// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
	if (!donttake)
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
...
	self = stemp;

// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//	if (leave)
//		return;
	if (!leave)
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end

// remove it in single player, or setup for respawning in deathmatch
	self.model = string_null;
	self.solid = SOLID_NOT;
	if (deathmatch == 1)
		self.nextthink = time + 30;
	self.think = SUB_regen;

	}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

	}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

	activator = other;
	SUB_UseTargets();				// fire all targets / killtargets
};

...

void() ammo_touch =
{
	local entity	stemp;
	local float	best;
	local float	donttake;	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes
...
	donttake = 0;	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

// shotgun
	if (self.weapon == 1)
	{
		if (other.ammo_shells >= 100)
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//			return;
			donttake = 1;
		else
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		other.ammo_shells = other.ammo_shells + self.aflag;
	}

// spikes
	else if (self.weapon == 2)
	{
		if (other.ammo_nails >= 200)
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//			return;
			donttake = 1;
		else
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		other.ammo_nails = other.ammo_nails + self.aflag;
	}

//	rockets
	else if (self.weapon == 3)
	{
		if (other.ammo_rockets >= 100)
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//			return;
			donttake = 1;
		else
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		other.ammo_rockets = other.ammo_rockets + self.aflag;
	}

//	cells
	else if (self.weapon == 4)
	{
		if (other.ammo_cells >= 100)
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//			return;
			donttake = 1;
		else
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
		other.ammo_cells = other.ammo_cells + self.aflag;
	}

// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
	if (!donttake)
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end

		bound_other_ammo ();
...
// remove it in single player, or setup for respawning in deathmatch
		self.model = string_null;
		self.solid = SOLID_NOT;
		if (deathmatch == 1)
			self.nextthink = time + 30;
		self.think = SUB_regen;

	}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

	activator = other;
	SUB_UseTargets();				// fire all targets / killtargets
};

...

void() key_touch =
{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes
//	local entity	stemp;
//	local float	best;
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

	if (other.classname != "player")
		return;
	if (other.health <= 0)
		return;

// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  start
//	if (other.items & self.items)
//		return;
	if (!other.items & self.items)
	{
// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes  end
...
	}	// 1998-08-15 Do not take unnecessary items but fire all targets by Maddes

	activator = other;
	SUB_UseTargets();				// fire all targets / killtargets
};

Misc_FireBall default speed typo fix by Jonathan "Perged" Down
A little typo that set the default speed of a lavaball to zero.

"Misc.qc"
void() misc_fireball =
{
	precache_model ("progs/lavaball.mdl");
	self.classname = "fireball";
	self.nextthink = time + (random() * 5);
	self.think = fire_fly;
	if (!self.speed)
// 1998-08-14 Misc_FireBall default speed typo fix by Perged  start
//		self.speed == 1000;
		self.speed = 1000;
// 1998-08-14 Misc_FireBall default speed typo fix by Perged  end
};

Constantly checking all impulses fix by Jonathan "Perged" Down
All impulse commands are checked every frame although no impulse command has been entered.

"Misc.qc"
void() W_WeaponFrame =
{
	if (time < self.attack_finished)
		return;

        if (self.impulse)	// 1998-08-14 Constantly checking all impulses fix by Perged
		ImpulseCommands ();

// check for attack
	if (self.button0)
	{
		SuperDamageSound ();
		W_Attack ();
	}
};

Bubbles fix
Under some circumstances bubble spawner entities are not removed, this is one reason for "No Free Edicts" errors. Also not all bubbles are spawned when a player dies.

"Player.qc"
void() DeathBubblesSpawn =
{
	local entity	bubble;

	if ((self.owner.waterlevel != 3) && (self.owner.health > 0))	// 1998-08-14 Improved bubble spawn by Maddes
// 1998-08-14 Bubblespawner remove fix by Perged  start
	{
		remove(self);	// remove bubble spawner
// 1998-08-14 Bubblespawner remove fix by Perged  end
		return;
	}	// 1998-08-14 Bubblespawner remove fix by Perged

	bubble = spawn();
	setmodel (bubble, "progs/s_bubble.spr");
	setorigin (bubble, self.owner.origin + '0 0 24');
	bubble.movetype = MOVETYPE_NOCLIP;
	bubble.solid = SOLID_NOT;
	bubble.velocity = '0 0 15';
	bubble.nextthink = time + 0.5;
	bubble.think = bubble_bob;
	bubble.classname = "bubble";
	bubble.frame = 0;
	bubble.cnt = 0;
	setsize (bubble, '-8 -8 -8', '8 8 8');

// 1998-08-14 Improved bubble spawn by Maddes  start
//	self.nextthink = time + 0.1;
	self.nextthink = time + 0.01;
// 1998-08-14 Improved bubble spawn by Maddes  end
	self.think = DeathBubblesSpawn;
	self.air_finished = self.air_finished + 1;
	if (self.air_finished >= self.bubble_count)
		remove(self);
};

void(float num_bubbles) DeathBubbles =
{
	local entity	bubble_spawner;

	bubble_spawner = spawn();
	setorigin (bubble_spawner, self.origin);
	bubble_spawner.movetype = MOVETYPE_NONE;
	bubble_spawner.solid = SOLID_NOT;
// 1998-08-14 Improved bubble spawn by Maddes  start
//	bubble_spawner.nextthink = time + 0.1;
	bubble_spawner.nextthink = time + 0.01;
// 1998-08-14 Improved bubble spawn by Maddes  end
	bubble_spawner.think = DeathBubblesSpawn;
	bubble_spawner.air_finished = 0;
	bubble_spawner.owner = self;
	bubble_spawner.bubble_count = num_bubbles;
//	return;	// 1998-08-14 unnecessary by Maddes
};

Incorrect setting of nextthink fix
In some functions .nextthink is not set correctly, so sometimes monster stop or even do not ever start to walk.
Always use the current time to set ".nextthink", also always add a constant value to it as the "random()" function can also return a zero (0 * x = 0!)
Fly and swim monsters can be affected by gravity, so they have to be made gravity-resistant in the start function.

"Misc.qc"
void() misc_fireball =
{
	precache_model ("progs/lavaball.mdl");
	self.classname = "fireball";
// 1998-08-14 Incorrect setting of nextthink fix by Maddes/Lord Sméagol
//	self.nextthink = time + (random() * 5);
	self.nextthink = time + 0.1 + (random() * 5);
// 1998-08-14 Incorrect setting of nextthink fix by Maddes/Lord Sméagol
	self.think = fire_fly;
	if (!self.speed)
// 1998-08-14 Misc_FireBall default speed typo fix by Perged  start
//		self.speed == 1000;
		self.speed = 1000;
// 1998-08-14 Misc_FireBall default speed typo fix by Perged  end
};

"Monsters.qc"
void() walkmonster_start_go =
{
...
// spread think times so they don't all happen at same time
// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol  start
//	self.nextthink = self.nextthink + random()*0.5;
	self.nextthink = time + 0.1 + random()*0.5;
// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol  end
};

void() walkmonster_start =
{
// delay drop to floor to make sure all doors have been spawned
// spread think times so they don't all happen at same time
// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol  start
//	self.nextthink = self.nextthink + random()*0.5;
	self.nextthink = time + 0.1 + random()*0.5;
// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol  end
	self.think = walkmonster_start_go;
	total_monsters = total_monsters + 1;
};


void() flymonster_start_go =
{
...
	self.nextthink = time + 0.1 + random()*0.5;	// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol
};

void() flymonster_start =
{
	self.flags = self.flags | FL_FLY;	// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol

// spread think times so they don't all happen at same time
// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol  start
//	self.nextthink = self.nextthink + random()*0.5;
	self.nextthink = time + 0.1 + random()*0.5;
// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol  end
	self.think = flymonster_start_go;
	total_monsters = total_monsters + 1;
};


void() swimmonster_start_go =
{
...
// spread think times so they don't all happen at same time
// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol  start
//	self.nextthink = self.nextthink + random()*0.5;
	self.nextthink = time + 0.1 + random()*0.5;
// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol  end
};

void() swimmonster_start =
{
	self.flags = self.flags | FL_SWIM;	// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol

// spread think times so they don't all happen at same time
// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol  start
//	self.nextthink = self.nextthink + random()*0.5;
	self.nextthink = time + 0.1 + random()*0.5;
// 1998-08-14 Monsters sometimes do not move fix by Lord Sméagol  end
	self.think = swimmonster_start_go;
	total_monsters = total_monsters + 1;
};

"Ogre.qc"
void() ogre_smash10	=[	$smash10,		ogre_smash11 ] {chainsaw(1);};
void() ogre_smash11	=[	$smash11,		ogre_smash12 ] {ai_charge(2); chainsaw(0);
// 1998-08-14 Incorrect setting of nextthink fix by Maddes/Lord Sméagol  start
//self.nextthink = self.nextthink + random()*0.2;};	// slight variation
self.nextthink = time + 0.1 + random()*0.2;};	// slight variation
// 1998-08-14 Incorrect setting of nextthink fix by Maddes/Lord Sméagol  end
void() ogre_smash12	=[	$smash12,		ogre_smash13 ] {ai_charge();};

"Shambler.qc"
void() sham_magic1     =[      $magic1,       sham_magic2    ] {ai_face();
	sound (self, CHAN_WEAPON, "shambler/sattck1.wav", 1, ATTN_NORM);
};
void() sham_magic2     =[      $magic2,       sham_magic3    ] {ai_face();};
// 1998-08-14 Incorrect setting of nextthink fix by Maddes/Lord Sméagol  start
//void() sham_magic3     =[      $magic3,       sham_magic4    ] {ai_face();self.nextthink = self.nextthink + 0.2;
void() sham_magic3     =[      $magic3,       sham_magic4    ] {ai_face();self.nextthink = time + 0.2;
// 1998-08-14 Incorrect setting of nextthink fix by Maddes/Lord Sméagol  end

"Zombie.qc"
void() zombie_paine10	=[	$paine10,	zombie_paine11	] {
sound (self, CHAN_BODY, "zombie/z_fall.wav", 1, ATTN_NORM);
self.solid = SOLID_NOT;
};
// 1998-08-14 Incorrect setting of nextthink fix by Maddes/Lord Sméagol  start
//void() zombie_paine11	=[	$paine11,	zombie_paine12	] {self.nextthink = self.nextthink + 5;self.health = 60;};
void() zombie_paine11	=[	$paine11,	zombie_paine12	] {self.nextthink = time + 5;self.health = 60;};
// 1998-08-14 Incorrect setting of nextthink fix by Maddes/Lord Sméagol  end

a Quake Info Pool page
© 1997-2006 by Maddes