Quake Info Pool - Classic Quake - QuakeC Fixes

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
- Spelling error
- Fish count fix
- New episode fix
- Thunderbolt fix
- "NoExit" SinglePlayer/Coop fix
- Respawn velocity fix by Xian
- Classname trigger_hurt entity fix by Robert Field
- Respawning where player died fix by Robert Field
- Wrong obituary messages fix by Zoid
- Pentagram telefrag fix by Zoid
- Dead bodies glow and palette shift fix
- Fraglimit and timelimit fix
- Suicide during intermission fix by Yun Zheng "Zhenga" Hu
- Cheats Coop fix
- Teamplay 1 fix
- Shub kill count fix
- Door unlock sound fix by Nolan "Radix" Pflug (QdQ Team)
- Fish death fix
- Slime hurt fix
- Mega health rot fix
- Item pickup fix
- Misc_FireBall default speed typo fix by Jonathan "Perged" Down
- Constantly checking all impulses fix by Jonathan "Perged" Down
- Bubbles fix
- Incorrect setting of nextthink fix

New-line problems
Some lines in the second half of "Items.qc" are missing a new-line or carriage-return character, so they is 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-2022 by Maddes