Back | Last changes: 1998-09-01 | Contact Maddes |
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()".
"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)).
"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"At last you should initialize every player's deathtype every frame and recognize it on their death.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 ... };
"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