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 endIf 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" 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