home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / programs / tf1_1src / tfort.qc < prev    next >
Encoding:
Text File  |  1996-08-30  |  53.5 KB  |  2,007 lines

  1. /*
  2.     TeamFortress 1.1    -    27/8/96
  3.  
  4.     Robin Walker, John Cook, Ian Caughley.
  5.  
  6.     Functions specific to the TeamFortress QuakeC patch.
  7. */
  8.  
  9. // Function Prototypes
  10. void() GrenadeExplode;
  11. void() spike_touch;
  12.  
  13. // Help Functions
  14. void() TeamFortress_MOTD;
  15. void() TeamFortress_HelpIndex;
  16. void() TeamFortress_HelpWeapon;
  17. void() TeamFortress_HelpClass;
  18. void() TeamFortress_HelpItem;
  19. void() TeamFortress_HelpGeneral;
  20. void() TeamFortress_HelpPreImp;
  21. void() TeamFortress_HelpShowPreImp;
  22.  
  23. // Multiskin Functions
  24. void(float skinno) Multiskin_SetSkin;
  25.  
  26. // Team Functions
  27. float(float tno) TeamFortress_TeamGetColor;
  28. void(float tno) TeamFortress_TeamSetColor;
  29.  
  30. // Impulse Functions
  31. void() TeamFortress_ChangeClass;
  32. void() TeamFortress_Inventory;
  33. void() TeamFortress_PrimeGrenade;
  34. void() TeamFortress_ThrowGrenade;
  35. void() TeamFortress_DetonatePipebombs;
  36. // Pre-Impulse Functions
  37. void(float tflag) TeamFortress_Toggle;
  38. void(float scanrange) TeamFortress_Scan;
  39. void(float timer) TeamFortress_SetDetpack;
  40. void(float skinno) TeamFortress_Multiskin;
  41.  
  42. // Player Class Handling Functions
  43. void() TeamFortress_SetHealth;
  44. void() TeamFortress_SetEquipment;
  45. void() TeamFortress_SetSpeed;
  46. void() TeamFortress_SetSkin;
  47. float(entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo;
  48. float(entity Retriever, float WeaponType) TeamFortress_CanGetWeapon;
  49. float(entity Retriever, entity Armor) TeamFortress_CanGetArmor;
  50. float(entity Retriever, entity Items) TeamFortress_AddBackpackItems;
  51.  
  52. // Weapon Handling Functions
  53. void() TeamFortress_SniperWeapon;
  54. void() TeamFortress_ExplodePerson;
  55. void() NormalGrenadeTouch;
  56. void() NormalGrenadeExplode;
  57. void() ConcussionGrenadeTouch;
  58. void() ConcussionGrenadeExplode;
  59. void() ConcussionGrenadeTimer;
  60. void() NailGrenadeTouch;
  61. void() NailGrenadeExplode;
  62. void() NailGrenadeNailEm;
  63. void() NailGrenadeLaunchNail;
  64. void() MirvGrenadeTouch;
  65. void() MirvGrenadeExplode;
  66. void(vector org, entity shooter) MirvGrenadeLaunch;
  67. void() PipebombTouch;
  68.  
  69. // Item Handling Functions
  70. void() TeamFortress_DetpackSet;
  71. void() TeamFortress_DetpackExplode;
  72. void() TeamFortress_DetpackTouch;
  73. void() TeamFortress_DetpackCountDown;
  74.  
  75. // Utility Functions
  76. void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce;
  77. entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan;
  78. void(string halias, float himpulse1, float himpulse2) TeamFortress_Alias;
  79.  
  80. // Cyclic Event Functions
  81. void() TeamFortress_Regenerate;
  82. void() TeamFortress_CheckforCheats;
  83.  
  84. //=========================================================================
  85. // IMPULSE FUNCTIONS
  86. //=========================================================================
  87. //=========================================================================
  88. // Impulse function which Toggles Game Settings
  89. void(float tflag) TeamFortress_Toggle =
  90. {
  91.     local entity e,bak;
  92.  
  93.     // prevent help pre-impulse from triggering anything else
  94.     self.impulse = 0;
  95.     self.last_impulse = 0;
  96.  
  97.     // Classkin/Multiskin
  98.     if (tflag == TF_TOGGLE_SKIN)
  99.     {
  100.         if (toggleflags & TFLAG_SKIN)
  101.         {
  102.             bprint("Classkin On.\n");
  103.             toggleflags = toggleflags - (toggleflags & TFLAG_SKIN);
  104.  
  105.             bak = self;
  106.             // Change everyone's skins to their class
  107.             e = find(world, classname, "player");
  108.             while (e)
  109.             {
  110.                 self = e;
  111.                 TeamFortress_SetSkin();
  112.                 
  113.                 e = find(e, classname, "player");
  114.             }
  115.             self = bak;
  116.         }
  117.         else
  118.         {
  119.             bprint("Multiskin On.\n");
  120.             toggleflags = (toggleflags | TFLAG_SKIN);
  121.         }
  122.  
  123.         return;
  124.     }
  125.  
  126.     // Class Persistence between lvls On/Off
  127.     if (tflag == TF_TOGGLE_CLASS_PERSIST)
  128.     {
  129.         if (toggleflags & TFLAG_CLASS_PERSIST)
  130.         {
  131.             bprint("Class Persistence Off.\n");
  132.             toggleflags = toggleflags - (toggleflags & TFLAG_CLASS_PERSIST);
  133.         }
  134.         else
  135.         {
  136.             bprint("Class Persistence On.\n");
  137.             toggleflags = (toggleflags | TFLAG_CLASS_PERSIST);
  138.         }
  139.  
  140.         return;
  141.     }
  142.  
  143.     // Cheat Checking On/Off
  144.     if (tflag == TF_TOGGLE_CHEATCHECK)
  145.     {
  146.         if (toggleflags & TFLAG_CHEATCHECK)
  147.         {
  148.             bprint("Cheat Checking Off.\n");
  149.             toggleflags = toggleflags - (toggleflags & TFLAG_CHEATCHECK);
  150.  
  151.             // Remove everyone's cheattimers
  152.             e = find(world, classname, "player");
  153.             while (e)
  154.             {
  155.                 if (e.cheattimer)
  156.                     remove(e.cheattimer);
  157.                 
  158.                 e = find(e, classname, "player");
  159.             }
  160.         }
  161.         else
  162.         {
  163.             bprint("Cheat Checking On.\n");
  164.             toggleflags = (toggleflags | TFLAG_CHEATCHECK);
  165.             // Create everyone's cheattimers
  166.             e = find(world, classname, "player");
  167.             while (e)
  168.             {
  169.                 if (!(e.cheattimer))
  170.                 {
  171.                     e.cheattimer = spawn();
  172.                     e.cheattimer.nextthink = time + 20;
  173.                     e.cheattimer.think = TeamFortress_CheckforCheats;
  174.                     e.cheattimer.owner = e;
  175.                 }
  176.                 
  177.                 e = find(e, classname, "player");
  178.             }
  179.         }
  180.  
  181.         return;
  182.     }
  183.  
  184.     // FortressMap details On/Off    (see readme.txt for more info)
  185.     if (tflag == TF_TOGGLE_FORTRESSMAP)
  186.     {
  187.         if (toggleflags & TFLAG_FORTRESSMAP)
  188.         {
  189.             bprint("FortressMap Off.\n");
  190.             toggleflags = toggleflags - (toggleflags & TFLAG_FORTRESSMAP);
  191.         }
  192.         else
  193.         {
  194.             bprint("FortressMap On.\n");
  195.             toggleflags = (toggleflags | TFLAG_FORTRESSMAP);
  196.         }
  197.  
  198.         return;
  199.     }
  200.  
  201. };
  202.  
  203. //=========================================================================
  204. // Handles the Multiskin Pre-Impulse to Set Skin
  205. void(float skinno) TeamFortress_Multiskin =
  206. {
  207.     // prevent help pre-impulse from triggering anything else
  208.     self.impulse = 0;
  209.     self.last_impulse = 0;
  210.  
  211.     Multiskin_SetSkin(skinno);
  212. };
  213.  
  214. //=========================================================================
  215. // Player change class function
  216. void() TeamFortress_ChangeClass =
  217. {
  218.     cvar_set("sv_maxspeed", "600");
  219.     // Only change playerclass once - remove this if you want to change on the fly
  220. //    if ( self.playerclass != PC_UNDEFINED )
  221. //        return;
  222.  
  223.     self.playerclass = self.impulse - TF_CHANGEPC;
  224.  
  225.     // Turn off PC_UNDEFINED's nomove and invincibility
  226.     self.takedamage = 1;
  227.     self.movetype = MOVETYPE_WALK;
  228.  
  229.     self.teamno = 0;
  230.  
  231.     // Display chosen class, and Tell rest of the team in the future
  232.     if ( self.playerclass == PC_SCOUT )
  233.     {
  234.         sprint(self, "SCOUT.\n");
  235.     }
  236.     else if ( self.playerclass == PC_SNIPER )
  237.     {
  238.         sprint(self, "SNIPER.\n");
  239.     }
  240.     else if ( self.playerclass == PC_SOLDIER )
  241.     {
  242.         sprint(self, "SOLDIER.\n");
  243.     }
  244.     else if ( self.playerclass == PC_DEMOMAN )
  245.     {
  246.         sprint(self, "DEMOLITIONS MAN.\n");
  247.     }
  248.     else if ( self.playerclass == PC_MEDIC )
  249.     {
  250.         sprint(self, "COMBAT MEDIC.\n");
  251.     }
  252.     else if ( self.playerclass == PC_HVYWEAP )
  253.     {
  254.         sprint(self, "HEAVY WEAPONS GUY.\n");
  255.     }
  256.  
  257.     TeamFortress_SetEquipment();
  258.     TeamFortress_SetHealth();
  259.     TeamFortress_SetSpeed();
  260.     TeamFortress_SetSkin();
  261. };
  262.  
  263. //=========================================================================
  264. // Displays the player's inventory
  265. void() TeamFortress_Inventory =
  266. {
  267.     local string ac;
  268.     local float col;
  269.  
  270.     // Display Team
  271.     sprint(self, "You're in team ");
  272.     ac = ftos(self.teamno);
  273.     sprint(self, ac);
  274.     sprint(self, ", color ");
  275.     col = TeamFortress_TeamGetColor(self.teamno);
  276.     ac = ftos(col);
  277.     sprint(self, ac);
  278.     sprint(self, ".\n");
  279.  
  280.     // Display Number of Grenades of each type
  281.     if (self.no_grenades_1 > 0)
  282.     {
  283.         ac = ftos(self.no_grenades_1);
  284.         sprint(self, ac);
  285.         if (self.tp_grenades_1 == GR_TYPE_CONCUSSION)
  286.             sprint(self, " concussion");
  287.         if (self.tp_grenades_1 == GR_TYPE_NAIL)
  288.             sprint(self, " nail");
  289.         if (self.tp_grenades_1 == GR_TYPE_MIRV)
  290.             sprint(self, " Mirv");
  291.  
  292.         sprint(self, " grenades. ");
  293.     }
  294.     if (self.no_grenades_2 > 0)
  295.     {
  296.         ac = ftos(self.no_grenades_2);
  297.         sprint(self, ac);
  298.         if (self.tp_grenades_2 == GR_TYPE_CONCUSSION)
  299.             sprint(self, " concussion");
  300.         if (self.tp_grenades_2 == GR_TYPE_NAIL)
  301.             sprint(self, " nail");
  302.         if (self.tp_grenades_2 == GR_TYPE_MIRV)
  303.             sprint(self, " Mirv");
  304.  
  305.         sprint(self, " grenades. ");
  306.     }
  307.  
  308.     if (self.tf_items & NIT_SCANNER)
  309.         sprint(self, "Scanner. ");
  310.  
  311.     if (self.secondary_items & NIT_MEDIKIT)
  312.     {
  313.         sprint(self, "Medikit (");
  314.         ac = ftos(self.ammo_medikit);
  315.         sprint(self, ac);
  316.         sprint(self,") ");
  317.     }
  318.  
  319.     if (self.secondary_items & NIT_DETPACK)
  320.     {
  321.         if (self.ammo_detpack > 0)
  322.         {
  323.             ac = ftos(self.ammo_detpack);
  324.             sprint(self, ac);
  325.             sprint(self, " Detpack");
  326.             if (self.ammo_detpack > 1)
  327.                 sprint(self, "s");
  328.             sprint(self, ".");
  329.         }
  330.     }
  331.         
  332.     sprint(self, "\n");
  333. };
  334.  
  335. //=========================================================================
  336. // Primes a grenade of the type corresponding to the player's impulse
  337. void() TeamFortress_PrimeGrenade =
  338. {
  339.     local float gtype;
  340.     local string gs, ptime;
  341.  
  342.     // If you've already primed a grenade, return
  343.     if (self.grenadeprimed)
  344.         return;
  345.  
  346.     if (self.impulse == TF_GRENADE_1)
  347.     {
  348.         gtype = self.tp_grenades_1;
  349.         if (self.tp_grenades_1 == GR_TYPE_CONCUSSION)
  350.             gs = "Concussion grenade";
  351.         else if (self.tp_grenades_1 == GR_TYPE_NAIL)
  352.             gs = "Nail grenade";
  353.         else if (self.tp_grenades_1 == GR_TYPE_MIRV)
  354.             gs = "Mirv grenade";
  355.         else
  356.             gs = "Grenade";
  357.  
  358.         if (self.no_grenades_1 > 0)
  359.         {
  360.             ptime = ftos( GR_PRIMETIME );
  361.             sprint(self, gs);
  362.             sprint(self, " primed, ");
  363.             sprint(self, ptime);
  364.             sprint(self, " seconds...\n");
  365.             self.no_grenades_1 = self.no_grenades_1 - 1;
  366.         }
  367.         else
  368.         {
  369.             sprint(self, "No ");
  370.             sprint(self, gs);
  371.             sprint(self, "s left.\n");
  372.             return;
  373.         }
  374.     }
  375.     if (self.impulse == TF_GRENADE_2)
  376.     {
  377.         gtype = self.tp_grenades_2;
  378.         if (self.tp_grenades_2 == GR_TYPE_CONCUSSION)
  379.             gs = "Concussion grenade";
  380.         else if (self.tp_grenades_2 == GR_TYPE_NAIL)
  381.             gs = "Nail grenade";
  382.         else if (self.tp_grenades_2 == GR_TYPE_MIRV)
  383.             gs = "Mirv grenade";
  384.         else
  385.             gs = "Grenade";
  386.  
  387.         if (self.no_grenades_2 > 0)
  388.         {
  389.             ptime = ftos( GR_PRIMETIME );
  390.             sprint(self, gs);
  391.             sprint(self, " primed, ");
  392.             sprint(self, ptime);
  393.             sprint(self, " seconds...\n");
  394.             self.no_grenades_2 = self.no_grenades_2 - 1;
  395.         }
  396.         else
  397.         {
  398.             sprint(self, "No ");
  399.             sprint(self, gs);
  400.             sprint(self, "s left.\n");
  401.             return;
  402.         }
  403.     }
  404.  
  405.     self.grenadeprimed = 1;
  406.     self.Grenade = spawn();
  407.     self.Grenade.owner = self;
  408.     self.Grenade.weapon = gtype;
  409.     self.Grenade.nextthink = time + GR_PRIMETIME;
  410.     self.Grenade.think = TeamFortress_ExplodePerson;
  411. };
  412.  
  413. //=========================================================================
  414. // Throws a currently primed grenade
  415. void() TeamFortress_ThrowGrenade =
  416. {
  417.     local    entity missile;
  418.  
  419.     // If no grenade is primed, return
  420.     if (self.grenadeprimed == 0)
  421.         return;
  422.  
  423.     self.grenadeprimed = 0;
  424.  
  425.     sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  426.  
  427.     self.punchangle_x = -2;
  428.  
  429.     missile = spawn ();
  430.     missile.owner = self;
  431.     missile.movetype = MOVETYPE_BOUNCE;
  432.     missile.solid = SOLID_BBOX;
  433.     missile.classname = "grenade";
  434.         
  435.     // set grenade speed
  436.  
  437.     makevectors (self.v_angle);
  438.  
  439.     if (self.v_angle_x)
  440.         missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  441.     else
  442.     {
  443.         missile.velocity = aim(self, 10000);
  444.         missile.velocity = missile.velocity * 600;
  445.         missile.velocity_z = 200;
  446.     }
  447.  
  448.     missile.avelocity = '300 300 300';
  449.  
  450.     missile.angles = vectoangles(missile.velocity);
  451.  
  452.     // set the grenade's alternative kill flag
  453.     missile.altkill = 1;
  454.     
  455.     // set the grenade's thinktime to when the PRIMETIME runs out
  456.     missile.nextthink = self.Grenade.nextthink;
  457.  
  458.     // set the think and touches to the appropriate grenade type
  459.     if (self.Grenade.weapon == GR_TYPE_NORMAL)
  460.     {
  461.         missile.touch = NormalGrenadeTouch;
  462.         missile.think = NormalGrenadeExplode;
  463.         missile.altkillweapon = AK_GRENADE;
  464.     }
  465.     if (self.Grenade.weapon == GR_TYPE_CONCUSSION)
  466.     {
  467.         missile.touch = ConcussionGrenadeTouch;
  468.         missile.think = ConcussionGrenadeExplode;
  469.     }
  470.     if (self.Grenade.weapon == GR_TYPE_NAIL)
  471.     {
  472.         missile.touch = NailGrenadeTouch;
  473.         missile.think = NailGrenadeExplode;
  474.         missile.altkillweapon = AK_GRENADE_NAIL;
  475.     }
  476.     if (self.Grenade.weapon == GR_TYPE_MIRV)
  477.     {
  478.         missile.touch = MirvGrenadeTouch;
  479.         missile.think = MirvGrenadeExplode;
  480.         missile.altkillweapon = AK_GRENADE_MIRV;
  481.     }
  482.  
  483.     setmodel (missile, "progs/grenade.mdl");
  484.     setsize (missile, '0 0 0', '0 0 0');        
  485.     setorigin (missile, self.origin);
  486.  
  487. // Remove primed grenade object    
  488.     remove(self.Grenade);
  489. };
  490.  
  491. //=========================================================================
  492. // PLAYER CLASS HANDLING FUNCTIONS
  493. //=========================================================================
  494. //=========================================================================
  495. // Alter the player's Movement based on class
  496. void() TeamFortress_SetSpeed =
  497. {
  498.     local string sp;
  499.     local float tf;
  500.  
  501.     stuffcmd(self,"v_idlescale 0\n");
  502.     stuffcmd(self,"cl_movespeedkey 1\n");
  503.  
  504.     if ( self.playerclass == PC_SCOUT )
  505.     {
  506.         self.maxfbspeed = PC_SCOUT_MAXSPEED;
  507.         self.maxstrafespeed = PC_SCOUT_MAXSTRAFESPEED;
  508.     }
  509.     else if ( self.playerclass == PC_SNIPER )
  510.     {
  511.         self.maxfbspeed = PC_SNIPER_MAXSPEED;
  512.         self.maxstrafespeed = PC_SNIPER_MAXSTRAFESPEED;
  513.     }
  514.     else if ( self.playerclass == PC_SOLDIER )
  515.     {
  516.         self.maxfbspeed = PC_SOLDIER_MAXSPEED;
  517.         self.maxstrafespeed = PC_SOLDIER_MAXSTRAFESPEED;
  518.     }
  519.     else if ( self.playerclass == PC_DEMOMAN )
  520.     {
  521.         self.maxfbspeed = PC_DEMOMAN_MAXSPEED;
  522.         self.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED;
  523.     }
  524.     else if ( self.playerclass == PC_MEDIC )
  525.     {
  526.         self.maxfbspeed = PC_MEDIC_MAXSPEED;
  527.         self.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED;
  528.     }
  529.     else if ( self.playerclass == PC_HVYWEAP )
  530.     {
  531.         self.maxfbspeed = PC_HVYWEAP_MAXSPEED;
  532.         self.maxstrafespeed = PC_HVYWEAP_MAXSTRAFESPEED;
  533.     }
  534.     else if ( self.playerclass == PC_UNDEFINED )
  535.     {
  536.         self.maxfbspeed = 50;
  537.         self.maxstrafespeed = 50;
  538.         self.movetype = MOVETYPE_NONE;
  539.     }
  540.  
  541.     sp = ftos(self.maxfbspeed);
  542.     stuffcmd(self,"cl_backspeed ");
  543.     stuffcmd(self,sp);
  544.     stuffcmd(self,"\n");
  545.     stuffcmd(self,"cl_forwardspeed ");
  546.     stuffcmd(self,sp);
  547.     stuffcmd(self,"\n");
  548.     sp = ftos(self.maxstrafespeed);
  549.     stuffcmd(self,"cl_sidespeed ");
  550.     stuffcmd(self,sp);
  551.     stuffcmd(self,"\n");
  552. };
  553.  
  554. //=========================================================================
  555. // Set the max_health of a player based on his/her class
  556. void() TeamFortress_SetHealth = 
  557. {
  558.     if ( self.playerclass == PC_SCOUT )
  559.         self.max_health = PC_SCOUT_MAXHEALTH;
  560.     else if ( self.playerclass == PC_SNIPER )
  561.         self.max_health = PC_SNIPER_MAXHEALTH;
  562.     else if ( self.playerclass == PC_SOLDIER )
  563.         self.max_health = PC_SOLDIER_MAXHEALTH;
  564.     else if ( self.playerclass == PC_DEMOMAN )
  565.         self.max_health = PC_DEMOMAN_MAXHEALTH;
  566.     else if ( self.playerclass == PC_MEDIC )
  567.         self.max_health = PC_MEDIC_MAXHEALTH;
  568.     else if ( self.playerclass == PC_HVYWEAP )
  569.         self.max_health = PC_HVYWEAP_MAXHEALTH;
  570.     else if ( self.playerclass == PC_UNDEFINED )
  571.     {
  572.         self.max_health = 1; 
  573.         self.takedamage = 0; // Prevent damage to PC_UNDEFINED players
  574.     }
  575.  
  576.     self.health = self.max_health;
  577. };
  578.  
  579. //=========================================================================
  580. // Set the skin of a player based on his/her class, if Classkin is on
  581. void() TeamFortress_SetSkin = 
  582. {
  583.     local string st;
  584.  
  585.     // If Multiskin is on, return
  586.     if (toggleflags & TFLAG_SKIN)
  587.         return;
  588.  
  589.     if ( self.playerclass == PC_SCOUT )
  590.         self.skin = PC_SCOUT_SKIN;
  591.     else if ( self.playerclass == PC_SNIPER )
  592.         self.skin = PC_SNIPER_SKIN;
  593.     else if ( self.playerclass == PC_SOLDIER )
  594.         self.skin = PC_SOLDIER_SKIN;
  595.     else if ( self.playerclass == PC_DEMOMAN )
  596.         self.skin = PC_DEMOMAN_SKIN;
  597.     else if ( self.playerclass == PC_MEDIC )
  598.         self.skin = PC_MEDIC_SKIN;
  599.     else if ( self.playerclass == PC_HVYWEAP )
  600.         self.skin = PC_HVYWEAP_SKIN;
  601.     else if ( self.playerclass == PC_UNDEFINED )
  602.         self.skin = 1;
  603.  
  604. };
  605.  
  606. //=========================================================================
  607. // Set the details of a player based on his/her class
  608. void() TeamFortress_SetEquipment =
  609. {
  610.     if (self.classname != "player")
  611.         return;
  612.  
  613.     self.items = 0;
  614.     self.secondary_weapon = 0;
  615.     self.secondary_items = 0;
  616.     self.tf_items = 0;
  617.     self.tf_items_flags = 0;
  618.     self.armorclass = 0;
  619.     self.grenadeprimed = 0;
  620.     self.impulse = 0;
  621.  
  622.     self.ammo_medikit = 0;
  623.     self.maxammo_medikit = 0;
  624.     self.ammo_detpack = 0;
  625.     self.maxammo_detpack = 0;
  626.     self.items_allowed = 0;
  627.     self.secondary_items_allowed = 0;
  628.        self.armor_allowed = 0;
  629.        self.maxarmor = 0;
  630.     self.weaponmode = 0;
  631.     self.altkill = 0;
  632.     self.altkillweapon = 0;
  633.     self.heat = 0;
  634.  
  635.     self.is_concussed = FALSE;
  636.  
  637.     // Start the Cheat-Checking Cyclic Event if CheatChecking Toggleflag is on
  638.     if (toggleflags & TFLAG_CHEATCHECK)
  639.     {
  640.         self.cheattimer = spawn();
  641.         self.cheattimer.nextthink = time + 20;
  642.         self.cheattimer.think = TeamFortress_CheckforCheats;
  643.         self.cheattimer.owner = self;
  644.     }
  645.  
  646.     if ( self.playerclass == PC_SCOUT )
  647.     {
  648.         self.items = self.items | PC_SCOUT_WEAPONS;
  649.         self.ammo_rockets = PC_SCOUT_INITAMMO_ROCKET;
  650.         self.ammo_nails = PC_SCOUT_INITAMMO_NAIL;
  651.         self.ammo_shells = PC_SCOUT_INITAMMO_SHOT;
  652.         self.ammo_cells = PC_SCOUT_INITAMMO_CELL;
  653.         self.maxammo_rockets = PC_SCOUT_MAXAMMO_ROCKET;
  654.         self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL;
  655.         self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT;
  656.         self.maxammo_cells = PC_SCOUT_MAXAMMO_CELL;
  657.  
  658.         self.no_grenades_1 = PC_SCOUT_GRENADE_INIT_1;
  659.         self.no_grenades_2 = PC_SCOUT_GRENADE_INIT_2;
  660.         self.tp_grenades_1 = PC_SCOUT_GRENADE_TYPE_1;
  661.         self.tp_grenades_2 = PC_SCOUT_GRENADE_TYPE_2;
  662.         self.tf_items = PC_SCOUT_TF_ITEMS;
  663.  
  664.         // the scanner defaults to enemy scanning ON, friendly scanning OFF
  665.         // and movement scanner only OFF
  666.         self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY;
  667.  
  668.         self.armorclass = self.armorclass | PC_SCOUT_INITARMORCLASS;
  669.         self.armortype = PC_SCOUT_INITARMORTYPE;
  670.         self.armorvalue = PC_SCOUT_INITARMOR;
  671.            self.armor_allowed = PC_SCOUT_MAXARMORTYPE;
  672.            self.maxarmor = PC_SCOUT_MAXARMOR;
  673.         self.weapon = IT_NAILGUN;
  674.  
  675.         self.items_allowed = PC_SCOUT_WEAPONS;
  676.     }
  677.     else if ( self.playerclass == PC_SNIPER )
  678.     {
  679.         self.items = self.items | PC_SNIPER_WEAPONS;
  680.         self.ammo_rockets = PC_SNIPER_INITAMMO_ROCKET;
  681.         self.ammo_nails = PC_SNIPER_INITAMMO_NAIL;
  682.         self.ammo_shells = PC_SNIPER_INITAMMO_SHOT;
  683.         self.ammo_cells = PC_SNIPER_INITAMMO_CELL;
  684.         self.maxammo_rockets = PC_SNIPER_MAXAMMO_ROCKET;
  685.         self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL;
  686.         self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT;
  687.         self.maxammo_cells = PC_SNIPER_MAXAMMO_CELL;
  688.     
  689.         self.no_grenades_1 = PC_SNIPER_GRENADE_INIT_1;
  690.         self.no_grenades_2 = PC_SNIPER_GRENADE_INIT_2;
  691.         self.tp_grenades_1 = PC_SNIPER_GRENADE_TYPE_1;
  692.         self.tp_grenades_2 = PC_SNIPER_GRENADE_TYPE_2;
  693.         self.tf_items = PC_SNIPER_TF_ITEMS;
  694.  
  695.         // Get the sniper's weapon
  696.         self.secondary_items = self.secondary_items | NIT_SNIPER_RIFLE | NIT_AUTO_RIFLE;
  697.  
  698.         self.armorclass = self.armorclass | PC_SNIPER_INITARMORCLASS;
  699.         self.armortype = PC_SNIPER_INITARMORTYPE;
  700.         self.armorvalue = PC_SNIPER_INITARMOR;
  701.            self.armor_allowed = PC_SNIPER_MAXARMORTYPE;
  702.            self.maxarmor = PC_SNIPER_MAXARMOR;
  703.         self.weapon = IT_EXTRA_WEAPON;
  704.         self.secondary_weapon = NIT_SNIPER_RIFLE;
  705.  
  706.         self.items_allowed = PC_SNIPER_WEAPONS;
  707.     }
  708.     else if ( self.playerclass == PC_SOLDIER )
  709.     {
  710.         self.items = self.items | PC_SOLDIER_WEAPONS;
  711.         self.ammo_rockets = PC_SOLDIER_INITAMMO_ROCKET;
  712.         self.ammo_nails = PC_SOLDIER_INITAMMO_NAIL;
  713.         self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT;
  714.         self.ammo_cells = PC_SOLDIER_INITAMMO_CELL;
  715.         self.maxammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET;
  716.         self.maxammo_nails = PC_SOLDIER_MAXAMMO_NAIL;
  717.         self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT;
  718.         self.maxammo_cells = PC_SOLDIER_MAXAMMO_CELL;
  719.     
  720.         self.no_grenades_1 = PC_SOLDIER_GRENADE_INIT_1;
  721.         self.no_grenades_2 = PC_SOLDIER_GRENADE_INIT_2;
  722.         self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1;
  723.         self.tp_grenades_2 = PC_SOLDIER_GRENADE_TYPE_2;
  724.         self.tf_items = PC_SOLDIER_TF_ITEMS;
  725.  
  726.         self.armorclass = self.armorclass | PC_SOLDIER_INITARMORCLASS;
  727.         self.armortype = PC_SOLDIER_INITARMORTYPE;
  728.         self.armorvalue = PC_SOLDIER_INITARMOR;
  729.            self.armor_allowed = PC_SOLDIER_MAXARMORTYPE;
  730.            self.maxarmor = PC_SOLDIER_MAXARMOR;
  731.         self.weapon = IT_ROCKET_LAUNCHER;
  732.  
  733.         self.items_allowed = PC_SOLDIER_WEAPONS;
  734.     }
  735.     else if ( self.playerclass == PC_DEMOMAN )
  736.     {
  737.         self.items = self.items | PC_DEMOMAN_WEAPONS;
  738.         self.ammo_rockets = PC_DEMOMAN_INITAMMO_ROCKET;
  739.         self.ammo_nails = PC_DEMOMAN_INITAMMO_NAIL;
  740.         self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT;
  741.         self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL;
  742.         self.maxammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET;
  743.         self.maxammo_nails = PC_DEMOMAN_MAXAMMO_NAIL;
  744.         self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT;
  745.         self.maxammo_cells = PC_DEMOMAN_MAXAMMO_CELL;
  746.     
  747.         self.no_grenades_1 = PC_DEMOMAN_GRENADE_INIT_1;
  748.         self.no_grenades_2 = PC_DEMOMAN_GRENADE_INIT_2;
  749.         self.tp_grenades_1 = PC_DEMOMAN_GRENADE_TYPE_1;
  750.         self.tp_grenades_2 = PC_DEMOMAN_GRENADE_TYPE_2;
  751.         self.tf_items = PC_DEMOMAN_TF_ITEMS;
  752.  
  753.         // Detpacks
  754.         self.secondary_items = self.secondary_items | NIT_DETPACK;
  755.         self.ammo_detpack = PC_DEMOMAN_INITAMMO_DETPACK;
  756.         self.maxammo_detpack = PC_DEMOMAN_MAXAMMO_DETPACK;
  757.  
  758.         self.armorclass = self.armorclass | PC_DEMOMAN_INITARMORCLASS;
  759.         self.armortype = PC_DEMOMAN_INITARMORTYPE;
  760.         self.armorvalue = PC_DEMOMAN_INITARMOR;
  761.            self.armor_allowed = PC_DEMOMAN_MAXARMORTYPE;
  762.            self.maxarmor = PC_DEMOMAN_MAXARMOR;
  763.         self.weapon = IT_GRENADE_LAUNCHER;
  764.  
  765.         self.items_allowed = PC_DEMOMAN_WEAPONS;
  766.     }
  767.     else if ( self.playerclass == PC_MEDIC )
  768.     {
  769.         self.items = self.items | PC_MEDIC_WEAPONS;
  770.         self.ammo_rockets = PC_MEDIC_INITAMMO_ROCKET;
  771.         self.ammo_nails = PC_MEDIC_INITAMMO_NAIL;
  772.         self.ammo_shells = PC_MEDIC_INITAMMO_SHOT;
  773.         self.ammo_cells = PC_MEDIC_INITAMMO_CELL;
  774.         self.maxammo_rockets = PC_MEDIC_MAXAMMO_ROCKET;
  775.         self.maxammo_nails = PC_MEDIC_MAXAMMO_NAIL;
  776.         self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT;
  777.         self.maxammo_cells = PC_MEDIC_MAXAMMO_CELL;
  778.     
  779.         self.no_grenades_1 = PC_MEDIC_GRENADE_INIT_1;
  780.         self.no_grenades_2 = PC_MEDIC_GRENADE_INIT_2;
  781.         self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1;
  782.         self.tp_grenades_2 = PC_MEDIC_GRENADE_TYPE_2;
  783.         self.tf_items = PC_MEDIC_TF_ITEMS;
  784.  
  785.         self.armorclass = self.armorclass | PC_MEDIC_INITARMORCLASS;
  786.         self.armortype = PC_MEDIC_INITARMORTYPE;
  787.         self.armorvalue = PC_MEDIC_INITARMOR;
  788.            self.armor_allowed = PC_MEDIC_MAXARMORTYPE;
  789.            self.maxarmor = PC_MEDIC_MAXARMOR;
  790.         self.weapon = IT_SUPER_NAILGUN;
  791.  
  792.         // Medikit
  793.         self.secondary_items = self.secondary_items | NIT_MEDIKIT;
  794.         self.ammo_medikit = PC_MEDIC_INITAMMO_MEDIKIT;
  795.         self.maxammo_medikit = PC_MEDIC_MAXAMMO_MEDIKIT;
  796.  
  797.         // Start the Regeneration Cyclic Event
  798.         self.cyclictimer = spawn();
  799.         self.cyclictimer.nextthink = time + PC_MEDIC_REGEN_TIME;
  800.         self.cyclictimer.think = TeamFortress_Regenerate;
  801.         self.cyclictimer.owner = self;
  802.  
  803.         self.items_allowed = PC_MEDIC_WEAPONS;
  804.     }
  805.     else if ( self.playerclass == PC_HVYWEAP )
  806.     {
  807.         self.items = self.items | PC_HVYWEAP_WEAPONS;
  808.         self.ammo_rockets = PC_HVYWEAP_INITAMMO_ROCKET;
  809.         self.ammo_nails = PC_HVYWEAP_INITAMMO_NAIL;
  810.         self.ammo_shells = PC_HVYWEAP_INITAMMO_SHOT;
  811.         self.ammo_cells = PC_HVYWEAP_INITAMMO_CELL;
  812.         self.maxammo_rockets = PC_HVYWEAP_MAXAMMO_ROCKET;
  813.         self.maxammo_nails = PC_HVYWEAP_MAXAMMO_NAIL;
  814.         self.maxammo_shells = PC_HVYWEAP_MAXAMMO_SHOT;
  815.         self.maxammo_cells = PC_HVYWEAP_MAXAMMO_CELL;
  816.     
  817.         self.no_grenades_1 = PC_HVYWEAP_GRENADE_INIT_1;
  818.         self.no_grenades_2 = PC_HVYWEAP_GRENADE_INIT_2;
  819.         self.tp_grenades_1 = PC_HVYWEAP_GRENADE_TYPE_1;
  820.         self.tp_grenades_2 = PC_HVYWEAP_GRENADE_TYPE_2;
  821.         self.tf_items = PC_HVYWEAP_TF_ITEMS;
  822.  
  823.         // Get the Assault Cannon
  824.         self.secondary_items = self.secondary_items | NIT_ASSAULT_CANNON;
  825.  
  826.         self.armorclass = self.armorclass | PC_HVYWEAP_INITARMORCLASS;
  827.         self.armortype = PC_HVYWEAP_INITARMORTYPE;
  828.         self.armorvalue = PC_HVYWEAP_INITARMOR;
  829.            self.armor_allowed = PC_HVYWEAP_MAXARMORTYPE;
  830.            self.maxarmor = PC_HVYWEAP_MAXARMOR;
  831.         self.weapon = IT_NAILGUN;
  832.  
  833.         self.items_allowed = PC_HVYWEAP_WEAPONS;
  834.     }
  835.     else if ( self.playerclass == PC_UNDEFINED )
  836.     {
  837.         self.items = self.items | IT_AXE;
  838.         self.ammo_rockets = 0;
  839.         self.ammo_nails = 0;
  840.         self.ammo_shells = 0;
  841.         self.ammo_cells = 0;
  842.  
  843.         self.no_grenades_1 = 0;
  844.         self.no_grenades_2 = 0;
  845.         self.tp_grenades_1 = 0;
  846.         self.tp_grenades_2 = 0;
  847.     
  848.         self.armorclass = 0;
  849.         self.armortype = 0;
  850.         self.armorvalue = 0;
  851.         self.weapon = IT_AXE;
  852.     }
  853.  
  854.     W_SetCurrentAmmo ();
  855. };
  856.  
  857. //=========================================================================
  858. // Return the max amount of ammo the Retriever can carry, based on his class
  859. float(entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo =
  860. {
  861.     if (AmmoType == IT_SHELLS)
  862.     {
  863.         return Retriever.maxammo_shells;
  864.     }
  865.     else if (AmmoType == IT_NAILS)
  866.     {
  867.         return Retriever.maxammo_nails;
  868.     }
  869.     else if (AmmoType == IT_CELLS)
  870.     {
  871.         return Retriever.maxammo_cells;
  872.     }
  873.     else if (AmmoType == IT_ROCKETS)
  874.     {
  875.         return Retriever.maxammo_rockets;
  876.     }
  877.  
  878.     dprint("Error in TeamFortress_GetMaxAmmo()\n");
  879.     dprint("Invalid ammo type passed.\n");
  880.     return 0;
  881. };
  882.  
  883. //=========================================================================
  884. // Return 1 if the Retriever is allowed to pick up the Weapon
  885. float(entity Retriever, float WeaponType) TeamFortress_CanGetWeapon =
  886. {
  887.     if ( Retriever.items_allowed & WeaponType )
  888.         return 1;
  889.  
  890.     return 0;
  891. };
  892.  
  893. //=========================================================================
  894. // Return 1 if the Retriever is allowed to pick up the Armor
  895. float(entity Retriever, entity Armor) TeamFortress_CanGetArmor =
  896. {
  897.     local float    type;
  898.     local float af;
  899.     local string at;
  900.  
  901.     if (Armor.classname == "item_armor1")
  902.     {
  903.         type = 0.3;
  904.     }
  905.     else if (Armor.classname == "item_armor2")
  906.     {
  907.         type = 0.6;
  908.     }
  909.     else if (Armor.classname == "item_armorInv")
  910.     {
  911.         type = 0.8;
  912.     }
  913.     else
  914.     {
  915.         dprint("Error in TeamFortress_CanGetArmor()\n");
  916.         dprint("Invalid armor type passed.\n");
  917.         return 0;
  918.     }
  919.  
  920.     af = Armor.spawnflags - (Armor.spawnflags & AT_NORMAL);
  921.  
  922.     if ( type > Retriever.armor_allowed )
  923.         return 0;
  924.  
  925.     return 1;
  926.  
  927.     if (!af)
  928.         return 1;
  929.     if (PC_SCOUT_ARMORCLASSES & af)
  930.         return 1;
  931.  
  932.     return 0;
  933. };
  934.  
  935.  
  936. //=========================================================================
  937. // Controls the equipment a class receives from backpacks
  938. float(entity Retriever, entity Items) TeamFortress_AddBackpackItems =
  939. {
  940.     // If you want the classes to _not_ start off with all their legal
  941.     // weapons, then you may want them to be able to pick up weapons
  942.     // from backpacks. If so, this is where to do it.
  943.     // For now, return. 
  944.     return;
  945. };
  946.  
  947. //=========================================================================
  948. // WEAPON HANDLING FUNCTIONS
  949. //=========================================================================
  950. //=========================================================================
  951. // Sniper/Auto Rifle selection function
  952. void() TeamFortress_SniperWeapon =
  953. {
  954.     local    float    it;
  955.     
  956.     self.impulse = 0;
  957.  
  958.     if (self.reloading)
  959.            return;
  960.  
  961.     if (!((self.secondary_items & NIT_SNIPER_RIFLE) && (self.secondary_items & NIT_AUTO_RIFLE)))
  962.         return;
  963.  
  964.     if (self.ammo_shells < 1)
  965.     {    // don't have the ammo
  966.         sprint (self, "not enough ammo.\n");
  967.         return;
  968.     }
  969.  
  970.     if (self.weapon == IT_EXTRA_WEAPON && self.secondary_weapon == NIT_SNIPER_RIFLE)
  971.     {
  972.         self.secondary_weapon = NIT_AUTO_RIFLE;
  973.     }
  974.     else if (self.weapon == IT_EXTRA_WEAPON && self.secondary_weapon == NIT_AUTO_RIFLE)
  975.     {
  976.         self.secondary_weapon = NIT_SNIPER_RIFLE;
  977.     }
  978.     else
  979.     {
  980.         self.secondary_weapon = NIT_SNIPER_RIFLE;
  981.         self.weapon = IT_EXTRA_WEAPON;
  982.     }
  983.  
  984.     W_SetCurrentAmmo ();
  985. };
  986.  
  987. //=========================================================================
  988. // Assault Cannon selection function
  989. void() TeamFortress_AssaultWeapon =
  990. {
  991.     local    float    it;
  992.     
  993.     self.impulse = 0;
  994.  
  995.     if (self.reloading)
  996.            return;
  997.  
  998.     if (!(self.secondary_items & NIT_ASSAULT_CANNON)) 
  999.         return;
  1000.  
  1001.     if (self.heat > 0)
  1002.     {
  1003.         sprint(self, "the assault cannon is still overheated.\n");
  1004.         return;
  1005.     }
  1006.  
  1007.     if (self.ammo_shells < 1)
  1008.     {    // don't have the ammo
  1009.         sprint (self, "not enough ammo.\n");
  1010.         return;
  1011.     }
  1012.     // The cannon also nees 10 cells to power up 
  1013.     if (self.ammo_cells < 10)
  1014.     {
  1015.         sprint(self, "not enough cells to power the assault cannon.\n");
  1016.         return;
  1017.     }
  1018.  
  1019.     self.secondary_weapon = NIT_ASSAULT_CANNON;
  1020.     self.weapon = IT_EXTRA_WEAPON;
  1021.  
  1022.     W_SetCurrentAmmo ();
  1023. };
  1024.  
  1025. //=========================================================================
  1026. // If this gets called, the players holding onto an exploding grenade :)
  1027. void() TeamFortress_ExplodePerson =
  1028. {
  1029.     local    entity missile;
  1030.  
  1031.     // Removes the owners grenade
  1032.     self.owner.grenadeprimed = 0;
  1033.  
  1034.     self.owner.punchangle_x = -2;
  1035.  
  1036.     missile = spawn ();
  1037.     missile.movetype = MOVETYPE_BOUNCE;
  1038.     missile.solid = SOLID_BBOX;
  1039.     missile.classname = "grenade";
  1040.         
  1041.     // Don't bother calculating a velocity
  1042.     missile.velocity = '0 0 0';
  1043.     missile.avelocity = '300 300 300';
  1044.  
  1045.     missile.angles = vectoangles(missile.velocity);
  1046.     
  1047.     // set the grenade's alternative kill flag
  1048.     missile.altkill = 1;
  1049.  
  1050.     // set the grenades thinktime to now
  1051.     missile.nextthink = time + 0.1;
  1052.  
  1053.     // set the think and touches to the appropriate grenade type
  1054.     if (self.weapon == GR_TYPE_NORMAL)
  1055.     {
  1056.         missile.touch = NormalGrenadeTouch;
  1057.         missile.think = NormalGrenadeExplode;
  1058.         missile.altkillweapon = AK_GRENADE;
  1059.     }
  1060.     if (self.weapon == GR_TYPE_CONCUSSION)
  1061.     {
  1062.         missile.touch = ConcussionGrenadeTouch;
  1063.         missile.think = ConcussionGrenadeExplode;
  1064.     }
  1065.     if (self.weapon == GR_TYPE_NAIL)
  1066.     {
  1067.         missile.touch = NailGrenadeTouch;
  1068.         missile.think = NailGrenadeExplode;
  1069.         missile.altkillweapon = AK_GRENADE_NAIL;
  1070.     }
  1071.     if (self.weapon == GR_TYPE_MIRV)
  1072.     {
  1073.         missile.touch = MirvGrenadeTouch;
  1074.         missile.think = MirvGrenadeExplode;
  1075.         missile.altkillweapon = AK_GRENADE_MIRV;
  1076.     }
  1077.  
  1078.     setmodel (missile, "progs/grenade.mdl");
  1079.     setsize (missile, '0 0 0', '0 0 0');        
  1080.     setorigin (missile, self.owner.origin);
  1081.  
  1082.     bprint("No ");
  1083.     bprint(self.owner.netname);
  1084.     bprint(", throw the grenade, not the pin!\n");
  1085.  
  1086. // Remove primed grenade object    
  1087.     remove(self);
  1088. };
  1089.  
  1090. //=========================================================================
  1091. // Touch function for a concussion grenade
  1092. void() ConcussionGrenadeTouch =
  1093. {
  1094.     if (other.takedamage == DAMAGE_AIM)
  1095.     {
  1096.         // A person hit by a concussion grenade doesn't move much,
  1097.         // since their origin is pretty much right on the grenade's
  1098.         // explosion point, so we'll give him a kick.
  1099.         other.velocity_x = self.velocity_x - 300;
  1100.         other.velocity_y = self.velocity_y - 300;
  1101.         other.velocity_z = 300;
  1102.  
  1103.         if (other.classname != "player")
  1104.         {
  1105.             if(other.flags & FL_ONGROUND)
  1106.                 other.flags = other.flags - FL_ONGROUND;
  1107.         }
  1108.  
  1109.         ConcussionGrenadeExplode();
  1110.         return;
  1111.     }
  1112.  
  1113.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  1114.     if (self.velocity == '0 0 0')
  1115.         self.avelocity = '0 0 0';
  1116. };
  1117.  
  1118. //=========================================================================
  1119. // Concussion grenade explosion function
  1120. void() ConcussionGrenadeExplode =
  1121. {    
  1122.     T_RadiusBounce (self, self.owner, 240, world);
  1123.  
  1124.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1125.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1126.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1127.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1128.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1129.         
  1130.     BecomeExplosion ();
  1131. };
  1132.  
  1133. //=========================================================================
  1134. // Concussion grenade timer to remove idlescale
  1135. void() ConcussionGrenadeTimer =
  1136. {
  1137.     local string st;
  1138.  
  1139.     // checks the flag which stops all concussions
  1140.     // this flag is set when a player dies
  1141.     if (self.owner.is_concussed == FALSE)
  1142.     {
  1143.         remove(self);
  1144.         return;
  1145.      }
  1146.  
  1147.     self.health = self.health - GR_CONCUSS_DEC;
  1148.     if (self.health < 0)
  1149.         self.health = 0;
  1150.     self.nextthink = time + GR_CONCUSS_TIME;
  1151.  
  1152.     st = ftos(self.health);
  1153.     stuffcmd(self.owner, "v_idlescale ");
  1154.     stuffcmd(self.owner, st);
  1155.     stuffcmd(self.owner, "\n");
  1156.  
  1157.     if (self.health == 0)
  1158.     {
  1159.         remove(self);
  1160.         return;
  1161.     }
  1162.  
  1163. };
  1164.  
  1165. //=========================================================================
  1166. // Touch Function for Nail Grenade
  1167. void() NailGrenadeTouch =
  1168. {
  1169.     if (other == self.owner)
  1170.         return;        // don't explode on owner
  1171.  
  1172.     // If the Nail Grenade hits a player, it just bounces off
  1173.  
  1174.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  1175.     if (self.velocity == '0 0 0')
  1176.         self.avelocity = '0 0 0';
  1177. };
  1178.  
  1179. //=========================================================================
  1180. // Explode Function for Nail Grenade
  1181. void() NailGrenadeExplode =
  1182. {
  1183.     // Raise into the air
  1184.     self.movetype = MOVETYPE_NOCLIP;
  1185.     self.velocity = '0 0 100';
  1186.     self.avelocity = '0 500 0';
  1187.     self.nextthink = time + 0.5;
  1188.     self.think = NailGrenadeNailEm;
  1189. };
  1190.  
  1191. //=========================================================================
  1192. // Nail function for Nail Grenade
  1193. void() NailGrenadeNailEm =
  1194. {
  1195.     // Rotate and spew Nails
  1196.     self.velocity = '0 0 0';
  1197.  
  1198.     self.nextthink = time + 0.1;
  1199.     self.think = NailGrenadeLaunchNail;
  1200.     self.playerclass = 0;
  1201. };
  1202.  
  1203. //=========================================================================
  1204. // Nail function for Nail Grenade
  1205. void() NailGrenadeLaunchNail =
  1206. {
  1207.     local float i,j;
  1208.  
  1209.     i = 0;
  1210.     while (i < 3)
  1211.     {
  1212.         j = (random() + 2) * 2;
  1213.         current_yaw = anglemod( self.angles_y );
  1214.         current_yaw = anglemod(current_yaw + j);
  1215.         self.angles_y = current_yaw;
  1216.         self.angles_x = 0;
  1217.         self.angles_z = 0;
  1218.         makevectors(self.angles);
  1219.  
  1220.         launch_spike(self.origin, v_forward, 1, AK_GRENADE_NAIL);
  1221.  
  1222.         i = i + 1;
  1223.     }
  1224.  
  1225.     self.playerclass = self.playerclass + 1;
  1226.     self.nextthink = time + 0.1;
  1227.  
  1228.     // Explode 
  1229.     if (self.playerclass > 50)
  1230.         self.think = GrenadeExplode;
  1231. };
  1232.  
  1233. //=========================================================================
  1234. // Touch Function for Mirv Grenade
  1235. // Mirv Grenade heavily influenced by the Firewall Grenade by Steve Bond (wedge@nuc.net)
  1236. void() MirvGrenadeTouch =
  1237. {
  1238.     if (other == self.owner)
  1239.         return;        // don't explode on owner
  1240.  
  1241.     // If the Mirv Grenade hits a player, it just bounces off
  1242.  
  1243.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  1244.     if (self.velocity == '0 0 0')
  1245.         self.avelocity = '0 0 0';
  1246. };
  1247.  
  1248. //=========================================================================
  1249. // Mirv Grenade explode function, for when the PRIMETIME runs out
  1250. void() MirvGrenadeExplode =
  1251. {
  1252.     local float i;
  1253.  
  1254.     T_RadiusDamage (self, self.owner, 250, world);
  1255.  
  1256.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1257.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1258.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1259.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1260.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1261.  
  1262.     self.solid=SOLID_NOT;
  1263.     BecomeExplosion ();
  1264.  
  1265.     // Launch mirvs
  1266.     i = 0;
  1267.     while (i < GR_TYPE_MIRV_NO)
  1268.     {
  1269.         MirvGrenadeLaunch (self.origin + '0 0 -1',self.owner);
  1270.         i = i + 1;
  1271.     }
  1272. };
  1273.  
  1274. //=========================================================================
  1275. // Launch a Mirv
  1276. void (vector org, entity shooter) MirvGrenadeLaunch =
  1277. {
  1278.     local float xdir,ydir,zdir, spin;
  1279.     
  1280.     xdir = 150 * random() - 75;
  1281.     ydir = 150 * random() - 75;
  1282.     zdir = 40 * random();
  1283.  
  1284.     newmis = spawn ();
  1285.     newmis.owner = shooter;
  1286.     newmis.movetype = MOVETYPE_BOUNCE;
  1287.     self.touch = SUB_Null;
  1288.     newmis.solid = SOLID_BBOX;
  1289.  
  1290.     newmis.classname = "grenade";
  1291.     newmis.touch = GrenadeTouch;
  1292.     newmis.think =     GrenadeExplode;
  1293.     newmis.nextthink = time + 2;
  1294.     
  1295.     newmis.velocity_x = xdir * 2;
  1296.     newmis.velocity_y = ydir * 2;
  1297.     newmis.velocity_z = zdir * 15;
  1298.  
  1299.     spin = (random() * 10) / 2;
  1300.     if (spin <= 0)
  1301.         newmis.avelocity='250 300 400';
  1302.     if (spin == 1)
  1303.         newmis.avelocity='400 250 300';
  1304.     if (spin == 2)
  1305.         newmis.avelocity='300 400 250';
  1306.     if (spin == 3)
  1307.         newmis.avelocity='300 300 300';
  1308.     if (spin >= 4) 
  1309.         newmis.avelocity='400 250 400';
  1310.  
  1311.     setmodel (newmis, "progs/grenade.mdl");
  1312.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  1313.     setorigin (newmis, org);
  1314. };
  1315.  
  1316. //=========================================================================
  1317. // Thrown Grenade touch function.
  1318. void() NormalGrenadeTouch =
  1319. {
  1320.     if (other == self.owner)
  1321.         return;        // don't explode on owner
  1322.  
  1323.     // Thrown grenades don't detonate when hitting an enemy
  1324.  
  1325.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  1326.     if (self.velocity == '0 0 0')
  1327.         self.avelocity = '0 0 0';
  1328. };
  1329.  
  1330. //=========================================================================
  1331. // Thrown grenade explosion. Twice as powerful as grenade launcher grenades.
  1332. void() NormalGrenadeExplode =
  1333. {
  1334.     T_RadiusDamage (self, self.owner, 240, world);
  1335.  
  1336.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1337.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1338.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1339.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1340.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1341.  
  1342.     BecomeExplosion ();
  1343. };
  1344.  
  1345. //=========================================================================
  1346. // Detonate all thrown pipebombs
  1347. void() TeamFortress_DetonatePipebombs =
  1348. {
  1349.     local entity e;
  1350.  
  1351. // Find all this players pipebombs
  1352.     e = find(world, classname, "pipebomb");
  1353.     while (e)
  1354.     {
  1355.         if(e.owner == self)
  1356.             e.nextthink = time;
  1357.         
  1358.         e = find(e, classname, "pipebomb");
  1359.     }
  1360. };
  1361.  
  1362. //=========================================================================
  1363. // Pipebomb touch function
  1364. void() PipebombTouch =
  1365. {
  1366.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  1367.     if (self.velocity == '0 0 0')
  1368.         self.avelocity = '0 0 0';
  1369. };
  1370.  
  1371. //=========================================================================
  1372. // ITEM HANDLING FUNCTIONS
  1373. //=========================================================================
  1374. //=========================================================================
  1375. // Handles the scanner function for scouts, and Base Defences
  1376. void(float scanrange) TeamFortress_Scan = 
  1377. {
  1378.     local string power;
  1379.     local entity list;
  1380.     local float scen, scfr;
  1381.  
  1382.     // added in for the direction scanner code
  1383.     local float enemy_detected;
  1384.     local float any_detected;
  1385.  
  1386.     local vector vf, vr, e;  // transformed versions of v_forward, v_right and the enemy vector
  1387.     local float res1, res2, res3; // for the vector work
  1388.     local float vf_e_angle, vr_e_angle; // results
  1389.  
  1390.     // prevent scan impulse from triggering anything else
  1391.     self.impulse = 0;
  1392.     self.last_impulse = 0;
  1393.  
  1394.     if (self.classname == "player")
  1395.     {
  1396.         if (!(self.tf_items & NIT_SCANNER))
  1397.             return;
  1398.  
  1399.         // If Impulse is TF_SCAN_ENEMY, toggle Scanning for Enemies
  1400.         if (scanrange == TF_SCAN_ENEMY)
  1401.         {
  1402.             if (self.tf_items_flags & NIT_SCANNER_ENEMY)
  1403.             {
  1404.                 sprint(self, "Enemy Scanning disabled.\n");
  1405.                 self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_ENEMY;
  1406.                 return;
  1407.             }
  1408.             sprint(self, "Enemy Scanning enabled.\n");
  1409.             self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY;
  1410.             return;
  1411.         }
  1412.  
  1413.         // If Impulse is TF_SCAN_FRIENDLY, toggle Scanning for Friendlies
  1414.         if (scanrange == TF_SCAN_FRIENDLY)
  1415.         {
  1416.             if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
  1417.             {
  1418.                 sprint(self, "Friendly Scanning disabled.\n");
  1419.                 self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_FRIENDLY;
  1420.                 return;
  1421.             }
  1422.             sprint(self, "Friendly Scanning enabled.\n");
  1423.             self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_FRIENDLY;
  1424.             return;
  1425.         }
  1426.  
  1427.         // If the user doesn't have as many cells as he/she specified, just
  1428.         // use as many as they've got.
  1429.  
  1430.         if (scanrange > self.ammo_cells)
  1431.             scanrange = self.ammo_cells;
  1432.  
  1433.         if (scanrange <= 0)
  1434.         {
  1435.             sprint(self,"No cells.\n");
  1436.             return;
  1437.         }
  1438.  
  1439.         if (scanrange > NIT_SCANNER_MAXCELL)
  1440.             scanrange = NIT_SCANNER_MAXCELL;
  1441.  
  1442.         scen = 0;
  1443.         scfr = 0;
  1444.         // Set the Scanner flags
  1445.         if (self.tf_items_flags & NIT_SCANNER_ENEMY)
  1446.             scen = 1;
  1447.         if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
  1448.             scfr = 1;
  1449.  
  1450.         // If no entity type is enabled, don't scan
  1451.         if ((scen == 0) && (scfr == 0))
  1452.         {
  1453.             sprint(self,"All scanner functions are disabled.\n");
  1454.             return;
  1455.         }
  1456.  
  1457.         sprint(self, "Power Usage: ");
  1458.         power = ftos(scanrange);
  1459.         sprint(self, power);
  1460.         sprint(self, ". Scanning...\n");
  1461.  
  1462.         // Use up cells to power the scanner
  1463.         // additions:
  1464.         // altered this so scanner could be more easily tested
  1465.         self.ammo_cells = self.ammo_cells - rint(scanrange / 5);
  1466.         scanrange = scanrange * NIT_SCANNER_POWER;
  1467.  
  1468.         // Get the list of entities the scanner finds
  1469.         list = T_RadiusScan(self, scanrange, scen, scfr);
  1470.     }
  1471.     // Base Defence scanning code here
  1472.  
  1473.     // Reset the entity counts
  1474.     scen = 0;
  1475.     scfr = 0;
  1476.  
  1477.     // the vectors v_forward and v_right are required to 
  1478.     // 'triangulate' the enemies position
  1479.     makevectors(self.v_angle);
  1480.  
  1481.     // Walk the list
  1482.     // For now, just count the entities.
  1483.     // In the future, we'll display bearings :)
  1484.     // additions: the future is now!
  1485.     while (list)
  1486.     {
  1487.         // sets the enemy_detected flag to TRUE if not on your team, FALSE if so
  1488.         any_detected = TRUE; // this flag is set to false if bogie is moving
  1489.                              // too slow to be detected (and velocity checking is on)
  1490.  
  1491.         // If this scanner is a motion detector, don't record
  1492.         // object that don't have the required velocity to be detected.
  1493.         if (self.tf_items_flags & NIT_SCANNER_MOVEMENT)
  1494.         {
  1495.             if (vlen(list.velocity) > NIT_SCANNER_MIN_MOVEMENT)
  1496.             {
  1497.                 if ((list.team > 0) && (self.team > 0) && (list.team == self.team)) 
  1498.                 {
  1499.                     scfr = scfr + 1;
  1500.                     enemy_detected = FALSE;
  1501.                 }
  1502.                 else
  1503.                 {
  1504.                     scen = scen + 1;
  1505.                     enemy_detected = TRUE;
  1506.                 }
  1507.             }
  1508.             else
  1509.             {
  1510.                 any_detected = FALSE;
  1511.             }
  1512.         }
  1513.         else
  1514.         {
  1515.              if ((list.team > 0) && (self.team > 0) && (list.team == self.team))
  1516.             {
  1517.                 scfr = scfr + 1;
  1518.                 enemy_detected = FALSE;
  1519.             }
  1520.             else
  1521.             {
  1522.                 scen = scen + 1;
  1523.                 enemy_detected = TRUE;
  1524.             }
  1525.         }
  1526.  
  1527.         // this displays the direction of the detected player
  1528.         // using the cosine rule to find the angle   
  1529.         //  cos theta = A.B divided by |A||B|
  1530.         // it should return a value between 1 and -1
  1531.         if (any_detected)
  1532.         {
  1533.             if (enemy_detected)
  1534.                 sprint(self, "Enemy detected at ");
  1535.             else
  1536.                 sprint(self, "Comrade detected at ");
  1537.  
  1538.             // finding the angle from v_forward gives the forward-back angle
  1539.             vf = v_forward;
  1540.             vf_z = 0;
  1541.  
  1542.             // finding the angle from v_right gives the left-right angle
  1543.             vr = v_right;
  1544.             vr_z = 0;
  1545.             
  1546.             // make a vector from the player to the detected one
  1547.             e = list.origin - self.origin;
  1548.             e_z = 0;
  1549.    
  1550.             res1 = vlen(e);
  1551.             if (res1 > 1200)
  1552.                 sprint(self, "very far ");
  1553.             else if (res1 > 600)
  1554.                 sprint(self, "far ");
  1555.  
  1556.        
  1557.             // dot product of vf and e   (A.B)
  1558.             res1 = (vf_x * e_x) + (vf_y * e_y);
  1559.  
  1560.             // multiple the vector lengths of vf and e (eg |A||B| )
  1561.             res2 = vlen(vf);
  1562.             res3 = vlen(e);
  1563.             res2 = res2 * res3;
  1564.             
  1565.             // divide the results
  1566.             vf_e_angle = res1 / res2;
  1567.  
  1568.             // finding the inverse cos of this gives the angle
  1569.             // but we don't need to do that because we realise:
  1570.  
  1571.             // if res3 is 1, then the arcos would be 0 degrees (directly ahead)
  1572.             // if res3 is 0.7, then the arcos would be 45 degrees (forward and off to one side)
  1573.             // if res3 is 0, then the arcos would be 90 degrees (directly to the side)
  1574.             // if res3 is -1, the the arcos would be 180 degrees (directly behind)
  1575.  
  1576.             // to narrow it right down, we need to find the angle between the enemy and v_right
  1577.  
  1578.             res1 = (vr_x * e_x) + (vr_y * e_y);
  1579.             res2 = vlen(vr);
  1580.             res3 = vlen(e);
  1581.             res2 = res2 * res3;
  1582.             vr_e_angle = res1 / res2;
  1583.  
  1584.             // if the vr_e_angle is positive, then the enemy is on the right-hand side
  1585.             // otherwise it is on the left
  1586.             // if vr_e_angle is 0, then the enemy is either directly in front or behind
  1587.  
  1588.             // the o'clock value is determined by a degree range
  1589.             // eg 1 o'clock is cos 15deg to cos 45deg
  1590.             //    2 o'clock is cos 45deg to cos 75deg
  1591.             if (vr_e_angle > 0)
  1592.             {
  1593.                 if (vf_e_angle >= 0.96)            // cos15
  1594.                     sprint(self, "12");
  1595.                 else if (vf_e_angle >= 0.7)     // cos45
  1596.                     sprint(self, "1");
  1597.                 else if (vf_e_angle >= 0.25)    // cos75
  1598.                     sprint(self, "2");
  1599.                 else if (vf_e_angle >= -0.25)    // cos105
  1600.                     sprint(self, "3");
  1601.                 else if (vf_e_angle >= -0.7)    // cos135
  1602.                     sprint(self, "4");
  1603.                 else if (vf_e_angle >= -0.96)      // cos165
  1604.                     sprint(self, "5");
  1605.                 else
  1606.                     sprint(self, "6");
  1607.             }
  1608.             else if (vr_e_angle < 0)
  1609.             {
  1610.                 if (vf_e_angle >= 0.96)
  1611.                     sprint(self, "12");
  1612.                 else if (vf_e_angle >= 0.7)
  1613.                     sprint(self, "11");
  1614.                 else if (vf_e_angle >= 0.25)
  1615.                     sprint(self, "10");
  1616.                 else if (vf_e_angle >= -0.25)
  1617.                     sprint(self, "9");
  1618.                 else if (vf_e_angle >= -0.7)
  1619.                     sprint(self, "8");
  1620.                 else if (vf_e_angle >= -0.96)
  1621.                     sprint(self, "7");
  1622.                 else
  1623.                     sprint(self, "6");
  1624.                     
  1625.             }
  1626.             else // vr_e_angle must be 0
  1627.             {
  1628.                 if (vf_e_angle < 0)
  1629.                     sprint(self, "12");
  1630.                 else
  1631.                     sprint(self, "6");
  1632.             }
  1633.  
  1634.  
  1635.             sprint(self, " o'clock");
  1636.  
  1637.             // do the up-down (z) direction
  1638.             res1 = list.origin_z - self.origin_z;
  1639.  
  1640.             if (res1 > 200)
  1641.                 sprint(self, ", really high");
  1642.             else if (res1 > 60)
  1643.                 sprint(self, ", high");
  1644.             else if (res1 < -200)
  1645.                 sprint(self, ", really low");
  1646.             else if (res1 < -60)
  1647.                 sprint(self, ", low");
  1648.             
  1649.             sprint(self, "\n");
  1650.         } // end if(any_detected)
  1651.  
  1652.  
  1653.         list = list.linked_list;
  1654.     }
  1655.  
  1656.     // Display the counts
  1657.     // For Base Defences, it will display the counts to all team members
  1658.     if ((scen == 0) && (scfr == 0))
  1659.     {
  1660.         sprint(self, "No blips.\n");
  1661.         return;
  1662.     }
  1663.  
  1664.     // Update ammo levels
  1665.     W_SetCurrentAmmo ();
  1666.  
  1667.     return;
  1668. };
  1669.  
  1670. //=========================================================================
  1671. // Handles the Setting of Detpacks
  1672. void(float timer) TeamFortress_SetDetpack =
  1673. {
  1674.     local string stimer;
  1675.  
  1676.     // prevent detpack impulse from triggering anything else
  1677.     self.impulse = 0;
  1678.     self.last_impulse = 0;
  1679.  
  1680.     if (!(self.secondary_items & NIT_DETPACK))
  1681.         return;
  1682.  
  1683.     if (self.ammo_detpack <= 0)
  1684.         return;
  1685.  
  1686.     self.ammo_detpack = self.ammo_detpack - 1;
  1687.     //stuffcmd(self, "cl_forwardspeed 0\n");
  1688.     //stuffcmd(self, "cl_backspeed 0\n");
  1689.     //stuffcmd(self, "cl_sidespeed 0\n");
  1690.     self.movetype = MOVETYPE_NONE;
  1691.  
  1692.     sprint(self, "Setting detpack for ");
  1693.     stimer = ftos(timer);
  1694.     sprint(self, stimer);
  1695.     sprint(self, " seconds...\n");
  1696.  
  1697.     self.detpack = spawn();
  1698.     self.detpack.owner = self;
  1699.     self.detpack.nextthink = time + NIT_DETPACK_SETTIME;
  1700.     self.detpack.think = TeamFortress_DetpackSet;
  1701.     self.detpack.health = timer;
  1702. };
  1703.  
  1704. //=========================================================================
  1705. // The detpack is set, let the player go and start timer
  1706. void() TeamFortress_DetpackSet =
  1707. {
  1708.     local entity countd, dp;
  1709.  
  1710.     self.owner.movetype = MOVETYPE_WALK;
  1711.  
  1712.     dp = spawn ();
  1713.     dp.owner = self.owner;
  1714.     dp.origin = self.owner.origin - '0 0 23';
  1715.     dp.movetype = MOVETYPE_BOUNCE;
  1716.     dp.solid = SOLID_TRIGGER;
  1717.     dp.classname = "detpack";
  1718.     dp.flags = FL_ITEM;
  1719.         
  1720.     dp.velocity = '0 0 0';
  1721.     dp.avelocity = '0 0 0';
  1722.     dp.angles = vectoangles(dp.velocity);
  1723.  
  1724.     // Set the Detpack alternative kill flag
  1725.     dp.altkill = 1;
  1726.     dp.altkillweapon = AK_DETPACK;
  1727.  
  1728.        dp.touch = TeamFortress_DetpackTouch;
  1729.  
  1730.     setmodel (dp, "progs/backpack.mdl");
  1731.     setsize (dp, '-16 -16 0', '16 16 56');        
  1732.     setorigin (dp, self.owner.origin);
  1733.  
  1734.     // Create the CountDown entity
  1735.     countd = spawn();
  1736.     countd.think = TeamFortress_DetpackCountDown;
  1737.     countd.health = self.health - 1;
  1738.     countd.owner = self.owner;
  1739.     if (self.health <= 10)
  1740.         countd.nextthink = time + 1;
  1741.     else
  1742.     {
  1743.         countd.nextthink = time + self.health - 10;
  1744.         countd.health = 9;
  1745.     }
  1746.     dp.nextthink = time + self.health;
  1747.     dp.think = TeamFortress_DetpackExplode;
  1748.  
  1749.     sprint(self.owner, "Detpack set!\n");
  1750.     remove(self);
  1751. };
  1752.  
  1753. //=========================================================================
  1754. // The detpack goes BOOM!
  1755. void() TeamFortress_DetpackExplode = 
  1756. {
  1757.     bprint("FIRE IN THE HOLE!!!!\n");
  1758.     T_RadiusDamage (self, self.owner, NIT_DETPACK_SIZE, world);
  1759.  
  1760.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1761.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1762.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1763.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1764.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1765.  
  1766.     BecomeExplosion ();
  1767. };
  1768.  
  1769. //=========================================================================
  1770. // The detpack touch function. Scouts can disarm it
  1771. void() TeamFortress_DetpackTouch = 
  1772. {
  1773.     if (other.classname != "player")
  1774.         return;
  1775.  
  1776.     if (other.playerclass != PC_SCOUT)
  1777.         return;
  1778.  
  1779.     bprint(other.netname);
  1780.     bprint(" snuffs ");
  1781.     bprint(self.owner.netname);
  1782.     bprint("'s fuse!\n");
  1783.  
  1784.     remove(self);
  1785. };
  1786.  
  1787. //=========================================================================
  1788. // The Detpack CountDown function. Displays the seconds left before the
  1789. // detpack detonates to the owner of the detpack, if <10
  1790. void() TeamFortress_DetpackCountDown = 
  1791. {
  1792.     local string cd;
  1793.  
  1794.     cd = ftos(self.health);
  1795.     sprint(self.owner, cd);
  1796.     sprint(self.owner, "...\n");
  1797.  
  1798.     self.nextthink = time + 1;
  1799.     self.health = self.health - 1;
  1800.  
  1801.     if (self.health == 0)
  1802.         remove(self);
  1803. };
  1804.  
  1805. //=========================================================================
  1806. // UTILITY FUNCTIONS
  1807. //=========================================================================
  1808. //=========================================================================
  1809. // Acts just like T_RadiusDamage, but doesn't damage things, just pushes them away
  1810. // from the explosion at a speed relative to the distance from the explosion's origin.
  1811. void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce =
  1812. {
  1813.     local    float     points;
  1814.     local    entity    head, timer;
  1815.     local    vector    org;
  1816.     local    string    st;
  1817.  
  1818.     head = findradius(inflictor.origin, bounce+40);
  1819.     
  1820.     while (head)
  1821.     {
  1822.         if (head != ignore)
  1823.         {
  1824.             if (head.takedamage)
  1825.             {
  1826.                 org = head.origin + (head.mins + head.maxs)*0.5;
  1827.                 points = 0.5*vlen (org - inflictor.origin);
  1828.                 if (points < 0)
  1829.                     points = 0;
  1830.                 points = bounce - points;
  1831.                 if (points > 0)
  1832.                 {
  1833.                     // Bounce!!
  1834.                     head.velocity = org - inflictor.origin;
  1835.                     head.velocity = head.velocity * (points / 10);
  1836.  
  1837.                     if (head.classname != "player")
  1838.                     {
  1839.                         if(head.flags & FL_ONGROUND)
  1840.                             head.flags = head.flags - FL_ONGROUND;
  1841.                     }
  1842.                     else
  1843.                     {
  1844.                         // Concuss 'em!!
  1845.                         head.is_concussed = TRUE;
  1846.                         stuffcmd(head,"v_idlescale 100\n");
  1847.                         stuffcmd(head,"bf\n");
  1848.                         // Create a timer entity
  1849.                         head.concusstimer = spawn();
  1850.                         head.concusstimer.nextthink = time + GR_CONCUSS_TIME;
  1851.                         head.concusstimer.think = ConcussionGrenadeTimer;
  1852.                         head.concusstimer.owner = head;
  1853.                         head.concusstimer.health = 100;
  1854.                     }
  1855.                 }
  1856.             }
  1857.         }
  1858.         head = head.chain;
  1859.     }
  1860. };
  1861.  
  1862. //=========================================================================
  1863. // Returns a list of players within a radius around the origin, like findradius,
  1864. // except that some parsing of the list can be done based on the parameters passed in.
  1865. // Make sure you check that the return value is not NULL b4 using it.
  1866. entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan =
  1867. {
  1868.     local entity head;
  1869.     local entity list_head;
  1870.     local entity list;
  1871.     local float gotatarget;
  1872.  
  1873.     head = findradius(scanner.origin, scanrange+40);
  1874.  
  1875.     while (head)
  1876.     {
  1877.         gotatarget = 0;
  1878.         if (head != scanner)            // Don't pick up the entity that's scanning
  1879.         {
  1880.             if (head.takedamage)
  1881.             {
  1882.                 if ((head.classname == "player") && (friends || enemies))
  1883.                 {
  1884.                     if (teamplay == 1)
  1885.                     {
  1886.                         if ( friends && (head.team > 0) && (scanner.team > 0) && (head.team == scanner.team) )
  1887.                             gotatarget = 1;
  1888.                         if ( enemies && (head.team > 0) && (scanner.team > 0) && (head.team != scanner.team) )
  1889.                             gotatarget = 1;
  1890.                     }
  1891.                     else
  1892.                         gotatarget = 1;
  1893.                 }
  1894.             }
  1895.         }
  1896.  
  1897.         // Add this entity to the linked list if it matches the target criteria
  1898.         if (gotatarget)
  1899.         {
  1900.             if (list)
  1901.             {
  1902.                 list.linked_list = head;
  1903.                 list = list.linked_list;
  1904.             }
  1905.             else
  1906.             {
  1907.                 list_head = head;
  1908.                 list = head;
  1909.             }
  1910.         }
  1911.  
  1912.         head = head.chain;
  1913.     }
  1914.  
  1915.     return list_head;
  1916. };
  1917.  
  1918. //=========================================================================
  1919. // Stuff an alias. This is a little messy since we insisted
  1920. // on maintaining the ability to alter the impulse numbers in the defs.qc 
  1921. // and not have to change any code. 
  1922. void(string halias, float himpulse1, float himpulse2) TeamFortress_Alias =
  1923. {
  1924.     local string imp;
  1925.  
  1926.     stuffcmd(self, "alias ");
  1927.     stuffcmd(self, halias);
  1928.     stuffcmd(self, " \"impulse ");
  1929.     imp = ftos(himpulse1);
  1930.     stuffcmd(self, imp);
  1931.  
  1932.     // if himpulse2 is not zero, assume that himpulse1 is a preimpulse 
  1933.     // and complete the alias
  1934.     if (himpulse1)
  1935.     {
  1936.         stuffcmd(self, ";wait; impulse ");
  1937.         imp = ftos(himpulse2);
  1938.         stuffcmd(self, imp);
  1939.     }
  1940.     stuffcmd(self, "\"\n");
  1941. };
  1942.  
  1943. //=========================================================================
  1944. // CYCLIC EVENT FUNCTIONS
  1945. //=========================================================================
  1946. //=========================================================================
  1947. // Regenerates the entity which owns this cyclictimer
  1948. void() TeamFortress_Regenerate =
  1949. {
  1950.     if (self.owner.playerclass == PC_MEDIC)
  1951.     {
  1952.         self.nextthink = time + PC_MEDIC_REGEN_TIME;
  1953.  
  1954.         if (self.owner.health >= self.owner.max_health)
  1955.             return;
  1956.  
  1957.         self.owner.health = self.owner.health + PC_MEDIC_REGEN_AMOUNT;
  1958.         if (self.owner.health > self.owner.max_health)
  1959.             self.owner.health = self.owner.max_health;
  1960.         return;
  1961.     }
  1962.  
  1963.     return;
  1964. };
  1965.  
  1966. //=========================================================================
  1967. // Check for cheats :) Mainly for internet play
  1968. // This is _far_ from a good solution. It will catch non-scouts that
  1969. // set their speeds to maxspeed, but not much else.
  1970. // It will occasionally catch someone who only sets their speed up 
  1971. // by a little bit.
  1972. // Still, in my opinion it was better than noth checking at all.
  1973. // If you trust people, or play only with friends, remove the creation
  1974. // of the cheattimer ( See TeamFortress_SetEquipment() above )
  1975. // If anyone knows of a better way to do this, or knows how to
  1976. // get the value of a _client_ cvar, please mail me.
  1977. void() TeamFortress_CheckforCheats =
  1978. {
  1979.     local float tf;
  1980.     local string st;
  1981.  
  1982.     tf = random() * 50;
  1983.     self.nextthink = time + 10 + tf;
  1984.  
  1985.     tf = vlen(self.owner.velocity);
  1986.  
  1987.     // Since players still exceed their maxfbspeed when strafing
  1988.     // as well as moving forward or backward, I played around a
  1989.     // while until I decided on 200. I've never broken this.
  1990.     // If you do exceed this when not cheating, please mail me.
  1991.     if (tf > (self.owner.maxfbspeed + 300))
  1992.     {
  1993.         // Make sure they're on the ground
  1994.         if ((self.owner.flags & FL_ONGROUND) && (self.velocity_z == 0))
  1995.         {
  1996.             bprint(self.owner.netname);
  1997.             bprint(" has been fined 5 frags for cheating!\n");
  1998.             self.owner.frags = self.owner.frags - 5;
  1999.             T_Damage(self.owner, world, world, 400);
  2000.     
  2001.             // Make sure they don't get fined again before they respawn
  2002.             self.owner.maxfbspeed = 1000;
  2003.         }
  2004.      }
  2005.  };
  2006.  
  2007.