home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / programs / fortv1_0 / tfort.qc < prev    next >
Encoding:
Text File  |  1996-08-22  |  42.7 KB  |  1,579 lines

  1. /*
  2.     TeamFortress 1.0    -    10/8/96
  3.  
  4.     Robin Walker, John Cook, Ian Caughley.
  5.  
  6.     Functions specific to the TeamFortress QuakeC patch.
  7. */
  8.  
  9. // Function declarations
  10. void() GrenadeExplode;
  11. void() spike_touch;
  12.  
  13. // Impulse Functions
  14. void() TeamFortress_ChangeClass;
  15. void() TeamFortress_Help;
  16. void() TeamFortress_Inventory;
  17. void() TeamFortress_PrimeGrenade;
  18. void() TeamFortress_ThrowGrenade;
  19. void() TeamFortress_DetonatePipebombs;
  20.  
  21. // Player Class Handling Functions
  22. void() TeamFortress_SetHealth;
  23. void() TeamFortress_SetEquipment;
  24. void() TeamFortress_SetSpeed;
  25. float(entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo;
  26. float(entity Retriever, float WeaponType) TeamFortress_CanGetWeapon;
  27. float(entity Retriever, entity Armor) TeamFortress_CanGetArmor;
  28. float(entity Retriever, entity Items) TeamFortress_AddBackpackItems;
  29.  
  30. // Weapon Handling Functions
  31. void() TeamFortress_SniperWeapon;
  32. void() TeamFortress_ExplodePerson;
  33. void() NormalGrenadeTouch;
  34. void() NormalGrenadeExplode;
  35. void() ConcussionGrenadeTouch;
  36. void() ConcussionGrenadeExplode;
  37. void() ConcussionGrenadeTimer;
  38. void() NailGrenadeTouch;
  39. void() NailGrenadeExplode;
  40. void() NailGrenadeNailEm;
  41. void() NailGrenadeLaunchNail;
  42. void() MirvGrenadeTouch;
  43. void() MirvGrenadeExplode;
  44. void(vector org, entity shooter) MirvGrenadeLaunch;
  45. void() PipebombTouch;
  46.  
  47. // Item Handling Functions
  48. void(float scanrange) TeamFortress_Scan;
  49. void(float timer) TeamFortress_SetDetpack;
  50. void() TeamFortress_DetpackSet;
  51. void() TeamFortress_DetpackExplode;
  52. void() TeamFortress_DetpackTouch;
  53.  
  54. // Utility Functions
  55. void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce;
  56. entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan;
  57.  
  58. // Cyclic Event Functions
  59. void() TeamFortress_Regenerate;
  60. void() TeamFortress_CheckforCheats;
  61.  
  62. //=========================================================================
  63. // IMPULSE FUNCTIONS
  64. //=========================================================================
  65. //=========================================================================
  66. // Player change class function
  67. void() TeamFortress_ChangeClass =
  68. {
  69.     cvar_set("sv_maxspeed", "600");
  70.     // Only change playerclass once
  71.     if ( self.playerclass != PC_UNDEFINED )
  72.         return;
  73.  
  74.     self.playerclass = self.impulse - TF_CHANGEPC;
  75.  
  76.     // Display chosen class, and Tell rest of the team
  77.     if ( self.playerclass == PC_SCOUT )
  78.     {
  79.         sprint(self, "SCOUT.\n");
  80.     }
  81.     else if ( self.playerclass == PC_SNIPER )
  82.     {
  83.         sprint(self, "SNIPER.\n");
  84.     }
  85.     else if ( self.playerclass == PC_SOLDIER )
  86.     {
  87.         sprint(self, "SOLDIER.\n");
  88.     }
  89.     else if ( self.playerclass == PC_DEMOMAN )
  90.     {
  91.         sprint(self, "DEMOLITIONS MAN.\n");
  92.     }
  93.     else if ( self.playerclass == PC_MEDIC )
  94.     {
  95.         sprint(self, "COMBAT MEDIC.\n");
  96.     }
  97.  
  98.     TeamFortress_SetEquipment();
  99.     TeamFortress_SetHealth();
  100.     TeamFortress_SetSpeed();
  101. };
  102.  
  103. //=========================================================================
  104. // Help for the Impulse commands in TeamFortress
  105. void() TeamFortress_Help =
  106. {
  107.     local string imp;
  108.  
  109.     sprint(self, "Welcome to TeamFortress! v1.0\n");
  110.     sprint(self, "Robin Walker, John Cook, Ian Cawley.");
  111.     sprint(self, "====================================");
  112.     sprint(self, "Impulse Commands are as follows:\n");
  113.     sprint(self, "Inventory       :   ");
  114.     imp = ftos(TF_INVENTORY);
  115.     sprint(self, imp);
  116.     sprint(self, "\nPrime Grenade 1 :   ");
  117.     imp = ftos(TF_GRENADE_1);
  118.     sprint(self, imp);
  119.     sprint(self, "\nPrime Grenade 2 :   ");
  120.     imp = ftos(TF_GRENADE_2);
  121.     sprint(self, imp);
  122.     sprint(self, "\nThrow Grenade   :   ");
  123.     imp = ftos(TF_GRENADE_T);
  124.     sprint(self, imp);
  125.     sprint(self, "\nScanner Pre-Imp :   ");
  126.     imp = ftos(TF_SCAN);
  127.     sprint(self, imp);
  128.     sprint(self, "\nToggle Friends  :   ");
  129.     imp = ftos(TF_SCAN_FRIENDLY);
  130.     sprint(self, imp);
  131.     sprint(self, "\nToggle Enemies  :   ");
  132.     imp = ftos(TF_SCAN_ENEMY);
  133.     sprint(self, imp);
  134.     sprint(self, "\nDetpack Pre-Imp :   ");
  135.     imp = ftos(TF_DETPACK);
  136.     sprint(self, imp);
  137.     sprint(self, "\nDet. Pipebombs  :   ");
  138.     imp = ftos(TF_PB_DETONATE);
  139.     sprint(self, imp);
  140.     sprint(self, "\nScout           :   ");
  141.     imp = ftos(TF_CHANGEPC + PC_SCOUT);
  142.     sprint(self, imp);
  143.     sprint(self, "\nSniper          :   ");
  144.     imp = ftos(TF_CHANGEPC + PC_SNIPER);
  145.     sprint(self, imp);
  146.     sprint(self, "\nSoldier         :   ");
  147.     imp = ftos(TF_CHANGEPC + PC_SOLDIER);
  148.     sprint(self, imp);
  149.     sprint(self, "\nDemolitions Man :   ");
  150.     imp = ftos(TF_CHANGEPC + PC_DEMOMAN);
  151.     sprint(self, imp);
  152.     sprint(self, "\nCombat Medic    :   ");
  153.     imp = ftos(TF_CHANGEPC + PC_MEDIC);
  154.     sprint(self, imp);
  155.     sprint(self, "\nComments : walker@netspace.net.au\n");
  156.     sprint(self, "Full command descriptions in Readme.txt\n");
  157.     sprint(self, "Use pageup in the console to see all the impulses above :)\n");
  158. };
  159.  
  160. //=========================================================================
  161. // Displays the player's inventory
  162. void() TeamFortress_Inventory =
  163. {
  164.     local string ac;
  165.  
  166.     // Display Number of Grenades of each type
  167.     if (self.no_grenades_1 > 0)
  168.     {
  169.         ac = ftos(self.no_grenades_1);
  170.         sprint(self, ac);
  171.         if (self.tp_grenades_1 == GR_TYPE_CONCUSSION)
  172.             sprint(self, " concussion");
  173.         if (self.tp_grenades_1 == GR_TYPE_NAIL)
  174.             sprint(self, " nail");
  175.         if (self.tp_grenades_1 == GR_TYPE_MIRV)
  176.             sprint(self, " Mirv");
  177.  
  178.         sprint(self, " grenades. ");
  179.     }
  180.     if (self.no_grenades_2 > 0)
  181.     {
  182.         ac = ftos(self.no_grenades_2);
  183.         sprint(self, ac);
  184.         if (self.tp_grenades_2 == GR_TYPE_CONCUSSION)
  185.             sprint(self, " concussion");
  186.         if (self.tp_grenades_2 == GR_TYPE_NAIL)
  187.             sprint(self, " nail");
  188.         if (self.tp_grenades_2 == GR_TYPE_MIRV)
  189.             sprint(self, " Mirv");
  190.  
  191.         sprint(self, " grenades. ");
  192.     }
  193.  
  194.     if (self.tf_items & NIT_SCANNER)
  195.         sprint(self, "Scanner. ");
  196.  
  197.     if (self.secondary_items & NIT_MEDIKIT)
  198.     {
  199.         sprint(self, "Medikit (");
  200.         ac = ftos(self.ammo_medikit);
  201.         sprint(self, ac);
  202.         sprint(self,") ");
  203.     }
  204.         
  205.     sprint(self, "\n");
  206. };
  207.  
  208. //=========================================================================
  209. // Primes a grenade of the type corresponding to the player's impulse
  210. void() TeamFortress_PrimeGrenade =
  211. {
  212.     local float gtype;
  213.     local string gs, ptime;
  214.  
  215.     // If you've already primed a grenade, return
  216.     if (self.grenadeprimed)
  217.         return;
  218.  
  219.     if (self.impulse == TF_GRENADE_1)
  220.     {
  221.         gtype = self.tp_grenades_1;
  222.         if (self.tp_grenades_1 == GR_TYPE_CONCUSSION)
  223.             gs = "Concussion grenade";
  224.         else if (self.tp_grenades_1 == GR_TYPE_NAIL)
  225.             gs = "Nail grenade";
  226.         else if (self.tp_grenades_1 == GR_TYPE_MIRV)
  227.             gs = "Mirv grenade";
  228.         else
  229.             gs = "Grenade";
  230.  
  231.         if (self.no_grenades_1 > 0)
  232.         {
  233.             ptime = ftos( GR_PRIMETIME );
  234.             sprint(self, gs);
  235.             sprint(self, " primed, ");
  236.             sprint(self, ptime);
  237.             sprint(self, " seconds...\n");
  238.             self.no_grenades_1 = self.no_grenades_1 - 1;
  239.         }
  240.         else
  241.         {
  242.             sprint(self, "No ");
  243.             sprint(self, gs);
  244.             sprint(self, "s left.\n");
  245.             return;
  246.         }
  247.     }
  248.     if (self.impulse == TF_GRENADE_2)
  249.     {
  250.         gtype = self.tp_grenades_2;
  251.         if (self.tp_grenades_2 == GR_TYPE_CONCUSSION)
  252.             gs = "Concussion grenade";
  253.         else if (self.tp_grenades_2 == GR_TYPE_NAIL)
  254.             gs = "Nail grenade";
  255.         else if (self.tp_grenades_2 == GR_TYPE_MIRV)
  256.             gs = "Mirv grenade";
  257.         else
  258.             gs = "Grenade";
  259.  
  260.         if (self.no_grenades_2 > 0)
  261.         {
  262.             ptime = ftos( GR_PRIMETIME );
  263.             sprint(self, gs);
  264.             sprint(self, " primed, ");
  265.             sprint(self, ptime);
  266.             sprint(self, " seconds...\n");
  267.             self.no_grenades_2 = self.no_grenades_2 - 1;
  268.         }
  269.         else
  270.         {
  271.             sprint(self, "No ");
  272.             sprint(self, gs);
  273.             sprint(self, "s left.\n");
  274.             return;
  275.         }
  276.     }
  277.  
  278.     self.grenadeprimed = 1;
  279.     self.Grenade = spawn();
  280.     self.Grenade.owner = self;
  281.     self.Grenade.weapon = gtype;
  282.     self.Grenade.nextthink = time + GR_PRIMETIME;
  283.     self.Grenade.think = TeamFortress_ExplodePerson;
  284. };
  285.  
  286. //=========================================================================
  287. // Throws a currently primed grenade
  288. void() TeamFortress_ThrowGrenade =
  289. {
  290.     local    entity missile;
  291.  
  292.     // If no grenade is primed, return
  293.     if (self.grenadeprimed == 0)
  294.         return;
  295.  
  296.     self.grenadeprimed = 0;
  297.  
  298.     sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  299.  
  300.     self.punchangle_x = -2;
  301.  
  302.     missile = spawn ();
  303.     missile.owner = self;
  304.     missile.movetype = MOVETYPE_BOUNCE;
  305.     missile.solid = SOLID_BBOX;
  306.     missile.classname = "grenade";
  307.         
  308.     // set grenade speed
  309.  
  310.     makevectors (self.v_angle);
  311.  
  312.     if (self.v_angle_x)
  313.         missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  314.     else
  315.     {
  316.         missile.velocity = aim(self, 10000);
  317.         missile.velocity = missile.velocity * 600;
  318.         missile.velocity_z = 200;
  319.     }
  320.  
  321.     missile.avelocity = '300 300 300';
  322.  
  323.     missile.angles = vectoangles(missile.velocity);
  324.  
  325.     // set the grenade's alternative kill flag
  326.     missile.altkill = 1;
  327.     
  328.     // set the grenade's thinktime to when the PRIMETIME runs out
  329.     missile.nextthink = self.Grenade.nextthink;
  330.  
  331.     // set the think and touches to the appropriate grenade type
  332.     if (self.Grenade.weapon == GR_TYPE_NORMAL)
  333.     {
  334.         missile.touch = NormalGrenadeTouch;
  335.         missile.think = NormalGrenadeExplode;
  336.         missile.altkillweapon = AK_GRENADE;
  337.     }
  338.     if (self.Grenade.weapon == GR_TYPE_CONCUSSION)
  339.     {
  340.         missile.touch = ConcussionGrenadeTouch;
  341.         missile.think = ConcussionGrenadeExplode;
  342.     }
  343.     if (self.Grenade.weapon == GR_TYPE_NAIL)
  344.     {
  345.         missile.touch = NailGrenadeTouch;
  346.         missile.think = NailGrenadeExplode;
  347.         missile.altkillweapon = AK_GRENADE_NAIL;
  348.     }
  349.     if (self.Grenade.weapon == GR_TYPE_MIRV)
  350.     {
  351.         missile.touch = MirvGrenadeTouch;
  352.         missile.think = MirvGrenadeExplode;
  353.         missile.altkillweapon = AK_GRENADE_MIRV;
  354.     }
  355.  
  356.     setmodel (missile, "progs/grenade.mdl");
  357.     setsize (missile, '0 0 0', '0 0 0');        
  358.     setorigin (missile, self.origin);
  359.  
  360. // Remove primed grenade object    
  361.     remove(self.Grenade);
  362. };
  363.  
  364. //=========================================================================
  365. // PLAYER CLASS HANDLING FUNCTIONS
  366. //=========================================================================
  367. //=========================================================================
  368. // Alter the player's Movement based on class
  369. void() TeamFortress_SetSpeed =
  370. {
  371.     local string sp;
  372.     local float tf;
  373.  
  374.     stuffcmd(self,"v_idlescale 0\n");
  375.     stuffcmd(self,"cl_movespeedkey 1\n");
  376.  
  377.     if ( self.playerclass == PC_SCOUT )
  378.     {
  379.         self.maxfbspeed = PC_SCOUT_MAXSPEED;
  380.         self.maxstrafespeed = PC_SCOUT_MAXSTRAFESPEED;
  381.     }
  382.     else if ( self.playerclass == PC_SNIPER )
  383.     {
  384.         self.maxfbspeed = PC_SNIPER_MAXSPEED;
  385.         self.maxstrafespeed = PC_SNIPER_MAXSTRAFESPEED;
  386.     }
  387.     else if ( self.playerclass == PC_SOLDIER )
  388.     {
  389.         self.maxfbspeed = PC_SOLDIER_MAXSPEED;
  390.         self.maxstrafespeed = PC_SOLDIER_MAXSTRAFESPEED;
  391.     }
  392.     else if ( self.playerclass == PC_DEMOMAN )
  393.     {
  394.         self.maxfbspeed = PC_DEMOMAN_MAXSPEED;
  395.         self.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED;
  396.     }
  397.     else if ( self.playerclass == PC_MEDIC )
  398.     {
  399.         self.maxfbspeed = PC_MEDIC_MAXSPEED;
  400.         self.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED;
  401.     }
  402.     else if ( self.playerclass == PC_UNDEFINED )
  403.     {
  404.         self.maxfbspeed = 0;
  405.         self.maxstrafespeed = 0;
  406.     }
  407.  
  408.     sp = ftos(self.maxfbspeed);
  409.     stuffcmd(self,"cl_backspeed ");
  410.     stuffcmd(self,sp);
  411.     stuffcmd(self,"\n");
  412.     stuffcmd(self,"cl_forwardspeed ");
  413.     stuffcmd(self,sp);
  414.     stuffcmd(self,"\n");
  415.     sp = ftos(self.maxstrafespeed);
  416.     stuffcmd(self,"cl_sidespeed ");
  417.     stuffcmd(self,sp);
  418.     stuffcmd(self,"\n");
  419. };
  420.  
  421. //=========================================================================
  422. // Set the max_health of a player based on his/her class
  423. void() TeamFortress_SetHealth = 
  424. {
  425.     if (self.classname != "player")
  426.         return;
  427.  
  428.     if ( self.playerclass == PC_SCOUT )
  429.     {
  430.         self.max_health = PC_SCOUT_MAXHEALTH;
  431.     }
  432.     else if ( self.playerclass == PC_SNIPER )
  433.     {
  434.         self.max_health = PC_SNIPER_MAXHEALTH;
  435.     }
  436.     else if ( self.playerclass == PC_SOLDIER )
  437.     {
  438.         self.max_health = PC_SOLDIER_MAXHEALTH;
  439.     }
  440.     else if ( self.playerclass == PC_DEMOMAN )
  441.     {
  442.         self.max_health = PC_DEMOMAN_MAXHEALTH;
  443.     }
  444.     else if ( self.playerclass == PC_MEDIC )
  445.     {
  446.         self.max_health = PC_MEDIC_MAXHEALTH;
  447.     }
  448.     else if ( self.playerclass == PC_UNDEFINED )
  449.     {
  450.         self.max_health = 1;
  451.     }
  452.  
  453.     self.health = self.max_health;
  454. };
  455.  
  456. //=========================================================================
  457. // Set the max_health of a player based on his/her class
  458. void() TeamFortress_SetEquipment =
  459. {
  460.     if (self.classname != "player")
  461.         return;
  462.  
  463.     self.items = 0;
  464.     self.secondary_weapon = 0;
  465.     self.secondary_items = 0;
  466.     self.tf_items = 0;
  467.     self.tf_items_flags = 0;
  468.     self.armorclass = 0;
  469.     self.grenadeprimed = 0;
  470.     self.impulse = 0;
  471.  
  472.     self.ammo_medikit = 0;
  473.     self.maxammo_medikit = 0;
  474.     self.ammo_detpack = 0;
  475.     self.maxammo_detpack = 0;
  476.     self.items_allowed = 0;
  477.     self.secondary_items_allowed = 0;
  478.        self.armor_allowed = 0;
  479.        self.maxarmor = 0;
  480.     self.weaponmode = 0;
  481.     self.altkill = 0;
  482.     self.altkillweapon = 0;
  483.  
  484.     // Start the Cheat-Checking Cyclic Event
  485.     self.cheattimer = spawn();
  486.     self.cheattimer.nextthink = time + 20;
  487.     self.cheattimer.think = TeamFortress_CheckforCheats;
  488.     self.cheattimer.owner = self;
  489.  
  490.     if ( self.playerclass == PC_SCOUT )
  491.     {
  492.         self.items = self.items | PC_SCOUT_WEAPONS;
  493.         self.ammo_rockets = PC_SCOUT_INITAMMO_ROCKET;
  494.         self.ammo_nails = PC_SCOUT_INITAMMO_NAIL;
  495.         self.ammo_shells = PC_SCOUT_INITAMMO_SHOT;
  496.         self.ammo_cells = PC_SCOUT_INITAMMO_CELL;
  497.         self.maxammo_rockets = PC_SCOUT_MAXAMMO_ROCKET;
  498.         self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL;
  499.         self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT;
  500.         self.maxammo_cells = PC_SCOUT_MAXAMMO_CELL;
  501.  
  502.         self.no_grenades_1 = PC_SCOUT_GRENADE_INIT_1;
  503.         self.no_grenades_2 = PC_SCOUT_GRENADE_INIT_2;
  504.         self.tp_grenades_1 = PC_SCOUT_GRENADE_TYPE_1;
  505.         self.tp_grenades_2 = PC_SCOUT_GRENADE_TYPE_2;
  506.         self.tf_items = PC_SCOUT_TF_ITEMS;
  507.  
  508.         self.armorclass = self.armorclass | PC_SCOUT_INITARMORCLASS;
  509.         self.armortype = PC_SCOUT_INITARMORTYPE;
  510.         self.armorvalue = PC_SCOUT_INITARMOR;
  511.            self.armor_allowed = PC_SCOUT_MAXARMORTYPE;
  512.            self.maxarmor = PC_SCOUT_MAXARMOR;
  513.         self.weapon = IT_NAILGUN;
  514.  
  515.         self.items_allowed = PC_SCOUT_WEAPONS;
  516.     }
  517.     else if ( self.playerclass == PC_SNIPER )
  518.     {
  519.         self.items = self.items | PC_SNIPER_WEAPONS;
  520.         self.ammo_rockets = PC_SNIPER_INITAMMO_ROCKET;
  521.         self.ammo_nails = PC_SNIPER_INITAMMO_NAIL;
  522.         self.ammo_shells = PC_SNIPER_INITAMMO_SHOT;
  523.         self.ammo_cells = PC_SNIPER_INITAMMO_CELL;
  524.         self.maxammo_rockets = PC_SNIPER_MAXAMMO_ROCKET;
  525.         self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL;
  526.         self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT;
  527.         self.maxammo_cells = PC_SNIPER_MAXAMMO_CELL;
  528.     
  529.         self.no_grenades_1 = PC_SNIPER_GRENADE_INIT_1;
  530.         self.no_grenades_2 = PC_SNIPER_GRENADE_INIT_2;
  531.         self.tp_grenades_1 = PC_SNIPER_GRENADE_TYPE_1;
  532.         self.tp_grenades_2 = PC_SNIPER_GRENADE_TYPE_2;
  533.         self.tf_items = PC_SNIPER_TF_ITEMS;
  534.  
  535.         // Get the sniper's weapon
  536.         self.secondary_items = self.secondary_items | NIT_SNIPER_RIFLE | NIT_AUTO_RIFLE;
  537.  
  538.         self.armorclass = self.armorclass | PC_SNIPER_INITARMORCLASS;
  539.         self.armortype = PC_SNIPER_INITARMORTYPE;
  540.         self.armorvalue = PC_SNIPER_INITARMOR;
  541.            self.armor_allowed = PC_SNIPER_MAXARMORTYPE;
  542.            self.maxarmor = PC_SNIPER_MAXARMOR;
  543.         self.weapon = IT_EXTRA_WEAPON;
  544.         self.secondary_weapon = NIT_SNIPER_RIFLE;
  545.  
  546.         self.items_allowed = PC_SNIPER_WEAPONS;
  547.     }
  548.     else if ( self.playerclass == PC_SOLDIER )
  549.     {
  550.         self.items = self.items | PC_SOLDIER_WEAPONS;
  551.         self.ammo_rockets = PC_SOLDIER_INITAMMO_ROCKET;
  552.         self.ammo_nails = PC_SOLDIER_INITAMMO_NAIL;
  553.         self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT;
  554.         self.ammo_cells = PC_SOLDIER_INITAMMO_CELL;
  555.         self.maxammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET;
  556.         self.maxammo_nails = PC_SOLDIER_MAXAMMO_NAIL;
  557.         self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT;
  558.         self.maxammo_cells = PC_SOLDIER_MAXAMMO_CELL;
  559.     
  560.         self.no_grenades_1 = PC_SOLDIER_GRENADE_INIT_1;
  561.         self.no_grenades_2 = PC_SOLDIER_GRENADE_INIT_2;
  562.         self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1;
  563.         self.tp_grenades_2 = PC_SOLDIER_GRENADE_TYPE_2;
  564.         self.tf_items = PC_SOLDIER_TF_ITEMS;
  565.  
  566.         self.armorclass = self.armorclass | PC_SOLDIER_INITARMORCLASS;
  567.         self.armortype = PC_SOLDIER_INITARMORTYPE;
  568.         self.armorvalue = PC_SOLDIER_INITARMOR;
  569.            self.armor_allowed = PC_SOLDIER_MAXARMORTYPE;
  570.            self.maxarmor = PC_SOLDIER_MAXARMOR;
  571.         self.weapon = IT_ROCKET_LAUNCHER;
  572.  
  573.         self.items_allowed = PC_SOLDIER_WEAPONS;
  574.     }
  575.     else if ( self.playerclass == PC_DEMOMAN )
  576.     {
  577.         self.items = self.items | PC_DEMOMAN_WEAPONS;
  578.         self.ammo_rockets = PC_DEMOMAN_INITAMMO_ROCKET;
  579.         self.ammo_nails = PC_DEMOMAN_INITAMMO_NAIL;
  580.         self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT;
  581.         self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL;
  582.         self.maxammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET;
  583.         self.maxammo_nails = PC_DEMOMAN_MAXAMMO_NAIL;
  584.         self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT;
  585.         self.maxammo_cells = PC_DEMOMAN_MAXAMMO_CELL;
  586.     
  587.         self.no_grenades_1 = PC_DEMOMAN_GRENADE_INIT_1;
  588.         self.no_grenades_2 = PC_DEMOMAN_GRENADE_INIT_2;
  589.         self.tp_grenades_1 = PC_DEMOMAN_GRENADE_TYPE_1;
  590.         self.tp_grenades_2 = PC_DEMOMAN_GRENADE_TYPE_2;
  591.         self.tf_items = PC_DEMOMAN_TF_ITEMS;
  592.  
  593.         // Detpacks
  594.         self.secondary_items = self.secondary_items | NIT_DETPACK;
  595.         self.ammo_detpack = PC_DEMOMAN_INITAMMO_DETPACK;
  596.         self.maxammo_detpack = PC_DEMOMAN_MAXAMMO_DETPACK;
  597.  
  598.         self.armorclass = self.armorclass | PC_DEMOMAN_INITARMORCLASS;
  599.         self.armortype = PC_DEMOMAN_INITARMORTYPE;
  600.         self.armorvalue = PC_DEMOMAN_INITARMOR;
  601.            self.armor_allowed = PC_DEMOMAN_MAXARMORTYPE;
  602.            self.maxarmor = PC_DEMOMAN_MAXARMOR;
  603.         self.weapon = IT_GRENADE_LAUNCHER;
  604.  
  605.         self.items_allowed = PC_DEMOMAN_WEAPONS;
  606.     }
  607.     else if ( self.playerclass == PC_MEDIC )
  608.     {
  609.         self.items = self.items | PC_MEDIC_WEAPONS;
  610.         self.ammo_rockets = PC_MEDIC_INITAMMO_ROCKET;
  611.         self.ammo_nails = PC_MEDIC_INITAMMO_NAIL;
  612.         self.ammo_shells = PC_MEDIC_INITAMMO_SHOT;
  613.         self.ammo_cells = PC_MEDIC_INITAMMO_CELL;
  614.         self.maxammo_rockets = PC_MEDIC_MAXAMMO_ROCKET;
  615.         self.maxammo_nails = PC_MEDIC_MAXAMMO_NAIL;
  616.         self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT;
  617.         self.maxammo_cells = PC_MEDIC_MAXAMMO_CELL;
  618.     
  619.         self.no_grenades_1 = PC_MEDIC_GRENADE_INIT_1;
  620.         self.no_grenades_2 = PC_MEDIC_GRENADE_INIT_2;
  621.         self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1;
  622.         self.tp_grenades_2 = PC_MEDIC_GRENADE_TYPE_2;
  623.         self.tf_items = PC_MEDIC_TF_ITEMS;
  624.  
  625.         self.armorclass = self.armorclass | PC_MEDIC_INITARMORCLASS;
  626.         self.armortype = PC_MEDIC_INITARMORTYPE;
  627.         self.armorvalue = PC_MEDIC_INITARMOR;
  628.            self.armor_allowed = PC_MEDIC_MAXARMORTYPE;
  629.            self.maxarmor = PC_MEDIC_MAXARMOR;
  630.         self.weapon = IT_SUPER_NAILGUN;
  631.  
  632.         // Medikit
  633.         self.secondary_items = self.secondary_items | NIT_MEDIKIT;
  634.         self.ammo_medikit = PC_MEDIC_INITAMMO_MEDIKIT;
  635.         self.maxammo_medikit = PC_MEDIC_MAXAMMO_MEDIKIT;
  636.  
  637.         // Start the Regeneration Cyclic Event
  638.         self.cyclictimer = spawn();
  639.         self.cyclictimer.nextthink = time + PC_MEDIC_REGEN_TIME;
  640.         self.cyclictimer.think = TeamFortress_Regenerate;
  641.         self.cyclictimer.owner = self;
  642.  
  643.         self.items_allowed = PC_MEDIC_WEAPONS;
  644.     }
  645.     else if ( self.playerclass == PC_UNDEFINED )
  646.     {
  647.         self.items = self.items | IT_AXE;
  648.         self.ammo_rockets = 0;
  649.         self.ammo_nails = 0;
  650.         self.ammo_shells = 0;
  651.         self.ammo_cells = 0;
  652.  
  653.         self.no_grenades_1 = 0;
  654.         self.no_grenades_2 = 0;
  655.         self.tp_grenades_1 = 0;
  656.         self.tp_grenades_2 = 0;
  657.     
  658.         self.armorclass = 0;
  659.         self.armortype = 0;
  660.         self.armorvalue = 0;
  661.         self.weapon = IT_AXE;
  662.     }
  663.  
  664.     W_SetCurrentAmmo ();
  665. };
  666.  
  667. //=========================================================================
  668. // Return the max amount of ammo the Retriever can carry, based on his class
  669. float(entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo =
  670. {
  671.     if (AmmoType == IT_SHELLS)
  672.     {
  673.         return Retriever.maxammo_shells;
  674.     }
  675.     else if (AmmoType == IT_NAILS)
  676.     {
  677.         return Retriever.maxammo_nails;
  678.     }
  679.     else if (AmmoType == IT_CELLS)
  680.     {
  681.         return Retriever.maxammo_cells;
  682.     }
  683.     else if (AmmoType == IT_ROCKETS)
  684.     {
  685.         return Retriever.maxammo_rockets;
  686.     }
  687.  
  688.     dprint("Error in TeamFortress_GetMaxAmmo()\n");
  689.     dprint("Invalid ammo type passed.\n");
  690.     return 0;
  691. };
  692.  
  693. //=========================================================================
  694. // Return 1 if the Retriever is allowed to pick up the Weapon
  695. float(entity Retriever, float WeaponType) TeamFortress_CanGetWeapon =
  696. {
  697.     if ( Retriever.items_allowed & WeaponType )
  698.         return 1;
  699.  
  700.     return 0;
  701. };
  702.  
  703. //=========================================================================
  704. // Return 1 if the Retriever is allowed to pick up the Armor
  705. float(entity Retriever, entity Armor) TeamFortress_CanGetArmor =
  706. {
  707.     local float    type;
  708.     local float af;
  709.     local string at;
  710.  
  711.     if (Armor.classname == "item_armor1")
  712.     {
  713.         type = 0.3;
  714.     }
  715.     else if (Armor.classname == "item_armor2")
  716.     {
  717.         type = 0.6;
  718.     }
  719.     else if (Armor.classname == "item_armorInv")
  720.     {
  721.         type = 0.8;
  722.     }
  723.     else
  724.     {
  725.         dprint("Error in TeamFortress_CanGetArmor()\n");
  726.         dprint("Invalid armor type passed.\n");
  727.         return 0;
  728.     }
  729.  
  730.     af = Armor.spawnflags - (Armor.spawnflags & AT_NORMAL);
  731.  
  732.     if ( type > Retriever.armor_allowed )
  733.         return 0;
  734.  
  735.     return 1;
  736.  
  737.     if (!af)
  738.         return 1;
  739.     if (PC_SCOUT_ARMORCLASSES & af)
  740.         return 1;
  741.  
  742.     return 0;
  743. };
  744.  
  745.  
  746. //=========================================================================
  747. // Controls the equipment a class receives from backpacks
  748. float(entity Retriever, entity Items) TeamFortress_AddBackpackItems =
  749. {
  750.     // If you want the classes to _not_ start off with all their legal
  751.     // weapons, then you may want them to be able to pick up weapons
  752.     // from backpacks. If so, this is where to do it.
  753.     // For now, return. 
  754.     return;
  755. };
  756.  
  757. //=========================================================================
  758. // WEAPON HANDLING FUNCTIONS
  759. //=========================================================================
  760. //=========================================================================
  761. // Sniper's Weapon choice function
  762. void() TeamFortress_SniperWeapon =
  763. {
  764.     local    float    it;
  765.     
  766.     if (self.reloading)
  767.            return;
  768.  
  769.     if (!((self.secondary_items & NIT_SNIPER_RIFLE) && (self.secondary_items & NIT_AUTO_RIFLE)))
  770.         return;
  771.  
  772.     self.impulse = 0;
  773.  
  774.     if (self.playerclass != PC_SNIPER)
  775.         return;
  776.  
  777.     if (self.ammo_shells < 1)
  778.     {    // don't have the ammo
  779.         sprint (self, "not enough ammo.\n");
  780.         return;
  781.     }
  782.  
  783.     if (self.weapon == IT_EXTRA_WEAPON && self.secondary_weapon == NIT_SNIPER_RIFLE)
  784.     {
  785.         self.secondary_weapon = NIT_AUTO_RIFLE;
  786.     }
  787.     else if (self.weapon == IT_EXTRA_WEAPON && self.secondary_weapon == NIT_AUTO_RIFLE)
  788.     {
  789.         self.secondary_weapon = NIT_SNIPER_RIFLE;
  790.     }
  791.     else
  792.     {
  793.         self.secondary_weapon = NIT_SNIPER_RIFLE;
  794.         self.weapon = IT_EXTRA_WEAPON;
  795.     }
  796.  
  797.     W_SetCurrentAmmo ();
  798. };
  799.  
  800. //=========================================================================
  801. // If this gets called, the players holding onto an exploding grenade :)
  802. void() TeamFortress_ExplodePerson =
  803. {
  804.     local    entity missile;
  805.  
  806.     // Removes the owners grenade
  807.     self.owner.grenadeprimed = 0;
  808.  
  809.     self.owner.punchangle_x = -2;
  810.  
  811.     missile = spawn ();
  812.     missile.movetype = MOVETYPE_BOUNCE;
  813.     missile.solid = SOLID_BBOX;
  814.     missile.classname = "grenade";
  815.         
  816.     // Don't bother calculating a velocity
  817.     missile.velocity = '0 0 0';
  818.     missile.avelocity = '300 300 300';
  819.  
  820.     missile.angles = vectoangles(missile.velocity);
  821.     
  822.     // set the grenade's alternative kill flag
  823.     missile.altkill = 1;
  824.  
  825.     // set the grenades thinktime to now
  826.     missile.nextthink = time + 0.1;
  827.  
  828.     // set the think and touches to the appropriate grenade type
  829.     if (self.weapon == GR_TYPE_NORMAL)
  830.     {
  831.         missile.touch = NormalGrenadeTouch;
  832.         missile.think = NormalGrenadeExplode;
  833.         missile.altkillweapon = AK_GRENADE;
  834.     }
  835.     if (self.weapon == GR_TYPE_CONCUSSION)
  836.     {
  837.         missile.touch = ConcussionGrenadeTouch;
  838.         missile.think = ConcussionGrenadeExplode;
  839.     }
  840.     if (self.weapon == GR_TYPE_NAIL)
  841.     {
  842.         missile.touch = NailGrenadeTouch;
  843.         missile.think = NailGrenadeExplode;
  844.         missile.altkillweapon = AK_GRENADE_NAIL;
  845.     }
  846.     if (self.weapon == GR_TYPE_MIRV)
  847.     {
  848.         missile.touch = MirvGrenadeTouch;
  849.         missile.think = MirvGrenadeExplode;
  850.         missile.altkillweapon = AK_GRENADE_MIRV;
  851.     }
  852.  
  853.     setmodel (missile, "progs/grenade.mdl");
  854.     setsize (missile, '0 0 0', '0 0 0');        
  855.     setorigin (missile, self.owner.origin);
  856.  
  857.     bprint("No ");
  858.     bprint(self.owner.netname);
  859.     bprint(", throw the grenade, not the pin!\n");
  860.  
  861. // Remove primed grenade object    
  862.     remove(self);
  863. };
  864.  
  865. //=========================================================================
  866. // Touch function for a concussion grenade
  867. void() ConcussionGrenadeTouch =
  868. {
  869.     local entity timer;
  870.  
  871.     if (other.takedamage == DAMAGE_AIM)
  872.     {
  873.         // A person hit by a concussion grenade doesn't move much,
  874.         // since their origin is pretty much right on the grenade's
  875.         // explosion point, so we'll give him a kick.
  876.         other.velocity_x = self.velocity_x - 300;
  877.         other.velocity_y = self.velocity_y - 300;
  878.         other.velocity_z = 300;
  879.  
  880.         if (other.classname != "player")
  881.         {
  882.             if(other.flags & FL_ONGROUND)
  883.                 other.flags = other.flags - FL_ONGROUND;
  884.         }
  885.         else
  886.         {
  887.             // Concuss 'em!!
  888.             stuffcmd(other,"v_idlescale 100\n");
  889.             // Create a timer entity
  890.             timer = spawn();
  891.             timer.nextthink = time + GR_CONCUSS_TIME;
  892.             timer.think = ConcussionGrenadeTimer;
  893.             timer.owner = other;
  894.             timer.health = 100;
  895.         }
  896.  
  897.         ConcussionGrenadeExplode();
  898.         return;
  899.     }
  900.  
  901.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  902.     if (self.velocity == '0 0 0')
  903.         self.avelocity = '0 0 0';
  904. };
  905.  
  906. //=========================================================================
  907. // Concussion grenade explosion function
  908. void() ConcussionGrenadeExplode =
  909. {
  910.     T_RadiusBounce (self, self.owner, 240, world);
  911.  
  912.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  913.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  914.     WriteCoord (MSG_BROADCAST, self.origin_x);
  915.     WriteCoord (MSG_BROADCAST, self.origin_y);
  916.     WriteCoord (MSG_BROADCAST, self.origin_z);
  917.  
  918.     BecomeExplosion ();
  919. };
  920.  
  921. //=========================================================================
  922. // Concussion grenade timer to remove idlescale
  923. void() ConcussionGrenadeTimer =
  924. {
  925.     local string st;
  926.  
  927.     if (self.health <= 0)
  928.     {
  929.         remove(self);
  930.         return;
  931.     }
  932.  
  933.     self.health = self.health - GR_CONCUSS_DEC;
  934.     self.nextthink = time + GR_CONCUSS_TIME;
  935.  
  936.     st = ftos(self.health);
  937.     stuffcmd(self.owner, "v_idlescale ");
  938.     stuffcmd(self.owner, st);
  939.     stuffcmd(self.owner, "\n");
  940. };
  941.  
  942. //=========================================================================
  943. // Touch Function for Nail Grenade
  944. void() NailGrenadeTouch =
  945. {
  946.     if (other == self.owner)
  947.         return;        // don't explode on owner
  948.  
  949.     // If the Nail Grenade hits a player, it just bounces off
  950.  
  951.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  952.     if (self.velocity == '0 0 0')
  953.         self.avelocity = '0 0 0';
  954. };
  955.  
  956. //=========================================================================
  957. // Explode Function for Nail Grenade
  958. void() NailGrenadeExplode =
  959. {
  960.     // Raise into the air
  961.     self.movetype = MOVETYPE_NOCLIP;
  962.     self.velocity = '0 0 100';
  963.     self.avelocity = '0 500 0';
  964.     self.nextthink = time + 0.5;
  965.     self.think = NailGrenadeNailEm;
  966. };
  967.  
  968. //=========================================================================
  969. // Nail function for Nail Grenade
  970. void() NailGrenadeNailEm =
  971. {
  972.     // Rotate and spew Nails
  973.     self.velocity = '0 0 0';
  974.  
  975.     self.nextthink = time + 0.1;
  976.     self.think = NailGrenadeLaunchNail;
  977.     self.playerclass = 0;
  978. };
  979.  
  980. //=========================================================================
  981. // Nail function for Nail Grenade
  982. void() NailGrenadeLaunchNail =
  983. {
  984.     local float i,j;
  985.  
  986.     i = 0;
  987.     while (i < 3)
  988.     {
  989.         j = (random() + 2) * 2;
  990.         current_yaw = anglemod( self.angles_y );
  991.         current_yaw = anglemod(current_yaw + j);
  992.         self.angles_y = current_yaw;
  993.         self.angles_x = 0;
  994.         self.angles_z = 0;
  995.         makevectors(self.angles);
  996.  
  997.         launch_spike(self.origin, v_forward, 1, AK_GRENADE_NAIL);
  998.  
  999.         i = i + 1;
  1000.     }
  1001.  
  1002.     self.playerclass = self.playerclass + 1;
  1003.     self.nextthink = time + 0.1;
  1004.  
  1005.     // Explode 
  1006.     if (self.playerclass > 50)
  1007.         self.think = GrenadeExplode;
  1008. };
  1009.  
  1010. //=========================================================================
  1011. // Touch Function for Mirv Grenade
  1012. // Mirv Grenade heavily influenced by the Firewall Grenade by Steve Bond (wedge@nuc.net)
  1013. void() MirvGrenadeTouch =
  1014. {
  1015.     if (other == self.owner)
  1016.         return;        // don't explode on owner
  1017.  
  1018.     // If the Mirv Grenade hits a player, it just bounces off
  1019.  
  1020.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  1021.     if (self.velocity == '0 0 0')
  1022.         self.avelocity = '0 0 0';
  1023. };
  1024.  
  1025. //=========================================================================
  1026. // Mirv Grenade explode function, for when the PRIMETIME runs out
  1027. void() MirvGrenadeExplode =
  1028. {
  1029.     local float i;
  1030.  
  1031.     T_RadiusDamage (self, self.owner, 250, world);
  1032.  
  1033.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1034.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1035.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1036.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1037.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1038.  
  1039.     self.solid=SOLID_NOT;
  1040.     BecomeExplosion ();
  1041.  
  1042.     // Launch mirvs
  1043.     i = 0;
  1044.     while (i < GR_TYPE_MIRV_NO)
  1045.     {
  1046.         MirvGrenadeLaunch (self.origin + '0 0 -1',self.owner);
  1047.         i = i + 1;
  1048.     }
  1049. };
  1050.  
  1051. //=========================================================================
  1052. // Launch a Mirv
  1053. void (vector org, entity shooter) MirvGrenadeLaunch =
  1054. {
  1055.     local float xdir,ydir,zdir, spin;
  1056.     
  1057.     xdir = 150 * random() - 75;
  1058.     ydir = 150 * random() - 75;
  1059.     zdir = 40 * random();
  1060.  
  1061.     newmis = spawn ();
  1062.     newmis.owner = shooter;
  1063.     newmis.movetype = MOVETYPE_BOUNCE;
  1064.     self.touch = SUB_Null;
  1065.     newmis.solid = SOLID_BBOX;
  1066.  
  1067.     newmis.classname = "grenade";
  1068.     newmis.touch = GrenadeTouch;
  1069.     newmis.think =     GrenadeExplode;
  1070.     newmis.nextthink = time + 2;
  1071.     
  1072.     newmis.velocity_x = xdir * 2;
  1073.     newmis.velocity_y = ydir * 2;
  1074.     newmis.velocity_z = zdir * 15;
  1075.  
  1076.     spin = (random() * 10) / 2;
  1077.     if (spin <= 0)
  1078.         newmis.avelocity='250 300 400';
  1079.     if (spin == 1)
  1080.         newmis.avelocity='400 250 300';
  1081.     if (spin == 2)
  1082.         newmis.avelocity='300 400 250';
  1083.     if (spin == 3)
  1084.         newmis.avelocity='300 300 300';
  1085.     if (spin >= 4) 
  1086.         newmis.avelocity='400 250 400';
  1087.  
  1088.     setmodel (newmis, "progs/grenade.mdl");
  1089.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  1090.     setorigin (newmis, org);
  1091. };
  1092.  
  1093. //=========================================================================
  1094. // Thrown Grenade touch function.
  1095. void() NormalGrenadeTouch =
  1096. {
  1097.     if (other == self.owner)
  1098.         return;        // don't explode on owner
  1099.  
  1100.     // Thrown grenades don't detonate when hitting an enemy
  1101.  
  1102.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  1103.     if (self.velocity == '0 0 0')
  1104.         self.avelocity = '0 0 0';
  1105. };
  1106.  
  1107. //=========================================================================
  1108. // Thrown grenade explosion. Twice as powerful as grenade launcher grenades.
  1109. void() NormalGrenadeExplode =
  1110. {
  1111.     T_RadiusDamage (self, self.owner, 240, world);
  1112.  
  1113.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1114.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1115.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1116.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1117.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1118.  
  1119.     BecomeExplosion ();
  1120. };
  1121.  
  1122. //=========================================================================
  1123. // Detonate all thrown pipebombs
  1124. void() TeamFortress_DetonatePipebombs =
  1125. {
  1126.     local entity e;
  1127.  
  1128. // Find all this players pipebombs
  1129.     e = find(world, classname, "pipebomb");
  1130.     while (e)
  1131.     {
  1132.         if(e.owner == self)
  1133.             e.nextthink = time;
  1134.         
  1135.         e = find(e, classname, "pipebomb");
  1136.     }
  1137. };
  1138.  
  1139. //=========================================================================
  1140. // Pipebomb touch function
  1141. void() PipebombTouch =
  1142. {
  1143.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  1144.     if (self.velocity == '0 0 0')
  1145.         self.avelocity = '0 0 0';
  1146. };
  1147.  
  1148. //=========================================================================
  1149. // ITEM HANDLING FUNCTIONS
  1150. //=========================================================================
  1151. //=========================================================================
  1152. // Handles the scanner function for scouts, and Base Defences
  1153. void(float scanrange) TeamFortress_Scan = 
  1154. {
  1155.     local string power;
  1156.     local entity list;
  1157.     local float scen, scfr;
  1158.  
  1159.     // prevent scan impulse from triggering anything else
  1160.     self.impulse = 0;
  1161.     self.last_impulse = 0;
  1162.  
  1163.     if (self.classname == "player")
  1164.     {
  1165.         if (!(self.tf_items & NIT_SCANNER))
  1166.             return;
  1167.  
  1168.         // If Impulse is TF_SCAN_ENEMY, toggle Scanning for Enemies
  1169.         if (scanrange == TF_SCAN_ENEMY)
  1170.         {
  1171.             if (self.tf_items_flags & NIT_SCANNER_ENEMY)
  1172.             {
  1173.                 sprint(self, "Enemy Scanning disabled.\n");
  1174.                 self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_ENEMY;
  1175.                 return;
  1176.             }
  1177.             sprint(self, "Enemy Scanning enabled.\n");
  1178.             self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY;
  1179.             return;
  1180.         }
  1181.  
  1182.         // If Impulse is TF_SCAN_FRIENDLY, toggle Scanning for Friendlies
  1183.         if (scanrange == TF_SCAN_FRIENDLY)
  1184.         {
  1185.             if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
  1186.             {
  1187.                 sprint(self, "Friendly Scanning disabled.\n");
  1188.                 self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_FRIENDLY;
  1189.                 return;
  1190.             }
  1191.             sprint(self, "Friendly Scanning enabled.\n");
  1192.             self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_FRIENDLY;
  1193.             return;
  1194.         }
  1195.  
  1196.         // If the user doesn't have as many cells as he/she specified, just
  1197.         // use as many as they've got.
  1198.         if (scanrange > self.ammo_cells)
  1199.             scanrange = self.ammo_cells;
  1200.  
  1201.         if (scanrange <= 0)
  1202.         {
  1203.             sprint(self,"No cells.\n");
  1204.             return;
  1205.         }
  1206.  
  1207.         if (scanrange > NIT_SCANNER_MAXCELL)
  1208.             scanrange = NIT_SCANNER_MAXCELL;
  1209.  
  1210.         scen = 0;
  1211.         scfr = 0;
  1212.         // Set the Scanner flags
  1213.         if (self.tf_items_flags & NIT_SCANNER_ENEMY)
  1214.             scen = 1;
  1215.         if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
  1216.             scfr = 1;
  1217.  
  1218.         // If no entity type is enabled, don't scan
  1219.         if ((scen == 0) && (scfr == 0))
  1220.         {
  1221.             sprint(self,"All scanner functions are disabled.\n");
  1222.             return;
  1223.         }
  1224.  
  1225.         sprint(self, "Power Usage: ");
  1226.         power = ftos(scanrange);
  1227.         sprint(self, power);
  1228.         sprint(self, ". Scanning...\n");
  1229.  
  1230.         // Use up cells to power the scanner
  1231.         self.ammo_cells = self.ammo_cells - scanrange;
  1232.         scanrange = scanrange * NIT_SCANNER_POWER;
  1233.  
  1234.         // Get the list of entities the scanner finds
  1235.         list = T_RadiusScan(self, scanrange, scen, scfr);
  1236.     }
  1237.     // Base Defence scanning code here
  1238.  
  1239.     // Reset the entity counts
  1240.     scen = 0;
  1241.     scfr = 0;
  1242.  
  1243.     // Walk the list
  1244.     // For now, just count the entities.
  1245.     // In the future, we'll display bearings :)
  1246.     while (list)
  1247.     {
  1248.         // If this scanner is a motion detector, don't record
  1249.         // object that don't have the required velocity to be detected.
  1250.         if (self.tf_items_flags & NIT_SCANNER_MOVEMENT)
  1251.         {
  1252.             if (vlen(list.velocity) > NIT_SCANNER_MIN_MOVEMENT)
  1253.             {
  1254.                 if ((list.team > 0) && (self.team > 0) && (list.team == self.team)) 
  1255.                     scfr = scfr + 1;
  1256.                 else
  1257.                     scen = scen + 1;
  1258.             }
  1259.         }
  1260.         else
  1261.         {
  1262.             if ((list.team > 0) && (self.team > 0) && (list.team == self.team))
  1263.                 scfr = scfr + 1;
  1264.             else
  1265.                 scen = scen + 1;
  1266.         }
  1267.  
  1268.         list = list.linked_list;
  1269.     }
  1270.  
  1271.     // Display the counts
  1272.     // For Base Defences, it will display the counts to all team members
  1273.     if ((scen == 0) && (scfr == 0))
  1274.     {
  1275.         sprint(self, "No blips.\n");
  1276.         return;
  1277.     }
  1278.  
  1279.     if (scen > 0)
  1280.     {
  1281.         power = ftos(scen);
  1282.         sprint(self, power);
  1283.         if (scen > 1)
  1284.             sprint(self, " enemies. ");
  1285.         else
  1286.             sprint(self, " enemy. ");
  1287.     }
  1288.     if (scfr > 0)
  1289.     {
  1290.         power = ftos(scfr);
  1291.         sprint(self, power);
  1292.         if (scfr > 1)
  1293.             sprint(self, " friendlies. ");
  1294.         else
  1295.             sprint(self, " friendly. ");
  1296.     }
  1297.     sprint(self, "\n");
  1298.  
  1299.     // Update ammo levels
  1300.     W_SetCurrentAmmo ();
  1301.  
  1302.     return;
  1303. };
  1304.  
  1305. //=========================================================================
  1306. // Handles the Setting of Detpacks
  1307. void(float timer) TeamFortress_SetDetpack =
  1308. {
  1309.     // prevent detpack impulse from triggering anything else
  1310.     self.impulse = 0;
  1311.     self.last_impulse = 0;
  1312.  
  1313.     if (!(self.secondary_items & NIT_DETPACK))
  1314.         return;
  1315.  
  1316.     if (self.ammo_detpack <= 0)
  1317.         return;
  1318.  
  1319.     self.ammo_detpack = self.ammo_detpack - 1;
  1320.     stuffcmd(self, "cl_forwardspeed 0\n");
  1321.     stuffcmd(self, "cl_backspeed 0\n");
  1322.     stuffcmd(self, "cl_sidespeed 0\n");
  1323.  
  1324.     self.detpack = spawn();
  1325.     self.detpack.owner = self;
  1326.     self.detpack.nextthink = time + NIT_DETPACK_SETTIME;
  1327.     self.detpack.think = TeamFortress_DetpackSet;
  1328.     self.detpack.health = timer;
  1329. };
  1330.  
  1331. //=========================================================================
  1332. // The detpack is set, let the player go and start timer
  1333. void() TeamFortress_DetpackSet =
  1334. {
  1335.     local entity tmp;
  1336.  
  1337.     self.nextthink = time + self.health; 
  1338.     self.think = TeamFortress_DetpackExplode;
  1339.  
  1340.     tmp = self;
  1341.     self = self.owner;
  1342.     TeamFortress_SetSpeed();
  1343.     self = tmp;
  1344.  
  1345.     self.owner.detpack = spawn ();
  1346.     self.owner.detpack.owner = self.owner;
  1347.     self.owner.detpack.origin = self.owner.origin - '0 0 23';
  1348.     self.owner.detpack.movetype = MOVETYPE_BOUNCE;
  1349.     self.owner.detpack.solid = SOLID_TRIGGER;
  1350.     self.owner.detpack.classname = "detpack";
  1351.     self.owner.detpack.flags = FL_ITEM;
  1352.         
  1353.     self.owner.detpack.velocity = '0 0 0';
  1354.     self.owner.detpack.avelocity = '0 0 0';
  1355.     self.owner.detpack.angles = vectoangles(self.owner.detpack.velocity);
  1356.  
  1357.     // Set the Detpack alternative kill flag
  1358.     self.owner.detpack.altkill = 1;
  1359.     self.owner.detpack.altkillweapon = AK_DETPACK;
  1360.     
  1361.     self.owner.detpack.nextthink = time + self.health;
  1362.     self.owner.detpack.think = TeamFortress_DetpackExplode;
  1363.  
  1364.        self.owner.detpack.touch = TeamFortress_DetpackTouch;
  1365.  
  1366.     setmodel (self.owner.detpack, "progs/backpack.mdl");
  1367.     setsize (self.owner.detpack, '-16 -16 0', '16 16 56');        
  1368.     setorigin (self.owner.detpack, self.owner.origin);
  1369. };
  1370.  
  1371. //=========================================================================
  1372. // The detpack goes BOOM!
  1373. void() TeamFortress_DetpackExplode = 
  1374. {
  1375.     T_RadiusDamage (self, self.owner, NIT_DETPACK_SIZE, world);
  1376.  
  1377.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1378.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1379.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1380.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1381.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1382.  
  1383.     BecomeExplosion ();
  1384. };
  1385.  
  1386. //=========================================================================
  1387. // The detpack touch function. Scouts can disarm it
  1388. void() TeamFortress_DetpackTouch = 
  1389. {
  1390.     if (other.classname != "player")
  1391.         return;
  1392.  
  1393.     if (other.playerclass != PC_SCOUT)
  1394.         return;
  1395.  
  1396.     bprint(other.netname);
  1397.     bprint(" snuffs ");
  1398.     bprint(self.owner.netname);
  1399.     bprint("'s fuse!\n");
  1400.  
  1401.     remove(self);
  1402. };
  1403.  
  1404. //=========================================================================
  1405. // UTILITY FUNCTIONS
  1406. //=========================================================================
  1407. //=========================================================================
  1408. // Acts just like T_RadiusDamage, but doesn't damage things, just pushes them away
  1409. // from the explosion at a speed relative to the distance from the explosion's origin.
  1410. void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce =
  1411. {
  1412.     local    float     points;
  1413.     local    entity    head, timer;
  1414.     local    vector    org;
  1415.     local    string    st;
  1416.  
  1417.     head = findradius(inflictor.origin, bounce+40);
  1418.     
  1419.     while (head)
  1420.     {
  1421.         if (head != ignore)
  1422.         {
  1423.             if (head.takedamage)
  1424.             {
  1425.                 org = head.origin + (head.mins + head.maxs)*0.5;
  1426.                 points = 0.5*vlen (org - inflictor.origin);
  1427.                 if (points < 0)
  1428.                     points = 0;
  1429.                 points = bounce - points;
  1430.                 if (points > 0)
  1431.                 {
  1432.                     // Bounce!!
  1433.                     head.velocity = org - inflictor.origin;
  1434.                     head.velocity = head.velocity * (points / 10);
  1435.  
  1436.                     if (head.classname != "player")
  1437.                     {
  1438.                         if(head.flags & FL_ONGROUND)
  1439.                             head.flags = head.flags - FL_ONGROUND;
  1440.                     }
  1441.                     else
  1442.                     {
  1443.                         // Concuss 'em!!
  1444.                         stuffcmd(head,"v_idlescale 100\n");
  1445.                         // Create a timer entity
  1446.                         timer = spawn();
  1447.                         timer.nextthink = time + GR_CONCUSS_TIME;
  1448.                         timer.think = ConcussionGrenadeTimer;
  1449.                         timer.owner = head;
  1450.                         timer.health = 100;
  1451.                     }
  1452.                 }
  1453.             }
  1454.         }
  1455.         head = head.chain;
  1456.     }
  1457. };
  1458.  
  1459. //=========================================================================
  1460. // Returns a list of players within a radius around the origin, like findradius,
  1461. // except that some parsing of the list can be done based on the parameters passed in.
  1462. // Make sure you check that the return value is not NULL b4 using it.
  1463. entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan =
  1464. {
  1465.     local entity head;
  1466.     local entity list_head;
  1467.     local entity list;
  1468.     local float gotatarget;
  1469.  
  1470.     head = findradius(scanner.origin, scanrange+40);
  1471.  
  1472.     while (head)
  1473.     {
  1474.         gotatarget = 0;
  1475.         if (head != scanner)            // Don't pick up the entity that's scanning
  1476.         {
  1477.             if (head.takedamage)
  1478.             {
  1479.                 if ((head.classname == "player") && (friends || enemies))
  1480.                 {
  1481.                     if (teamplay == 1)
  1482.                     {
  1483.                         if ( friends && (head.team > 0) && (scanner.team > 0) && (head.team == scanner.team) )
  1484.                             gotatarget = 1;
  1485.                         if ( enemies && (head.team > 0) && (scanner.team > 0) && (head.team != scanner.team) )
  1486.                             gotatarget = 1;
  1487.                     }
  1488.                     else
  1489.                         gotatarget = 1;
  1490.                 }
  1491.             }
  1492.         }
  1493.  
  1494.         // Add this entity to the linked list if it matches the target criteria
  1495.         if (gotatarget)
  1496.         {
  1497.             if (list)
  1498.             {
  1499.                 list.linked_list = head;
  1500.                 list = list.linked_list;
  1501.             }
  1502.             else
  1503.             {
  1504.                 list_head = head;
  1505.                 list = head;
  1506.             }
  1507.         }
  1508.  
  1509.         head = head.chain;
  1510.     }
  1511.  
  1512.     return list_head;
  1513. };
  1514.  
  1515. //=========================================================================
  1516. // CYCLIC EVENT FUNCTIONS
  1517. //=========================================================================
  1518. //=========================================================================
  1519. // Regenerates the entity which owns this cyclictimer
  1520. void() TeamFortress_Regenerate =
  1521. {
  1522.     if (self.owner.playerclass == PC_MEDIC)
  1523.     {
  1524.         self.nextthink = time + PC_MEDIC_REGEN_TIME;
  1525.  
  1526.         if (self.owner.health >= self.owner.max_health)
  1527.             return;
  1528.  
  1529.         self.owner.health = self.owner.health + PC_MEDIC_REGEN_AMOUNT;
  1530.         if (self.owner.health > self.owner.max_health)
  1531.             self.owner.health = self.owner.max_health;
  1532.         return;
  1533.     }
  1534.  
  1535.     return;
  1536. };
  1537.  
  1538. //=========================================================================
  1539. // Check for cheats :) Mainly for internet play
  1540. // This is _far_ from a good solution. It will catch non-scouts that
  1541. // set their speeds to maxspeed, but not much else.
  1542. // It will occasionally catch someone who only sets their speed up 
  1543. // by a little bit.
  1544. // Still, in my opinion it was better than noth checking at all.
  1545. // If you trust people, or play only with friends, remove the creation
  1546. // of the cheattimer ( See TeamFortress_SetEquipment() above )
  1547. // If anyone knows of a better way to do this, or knows how to
  1548. // get the value of a _client_ cvar, please mail me.
  1549. void() TeamFortress_CheckforCheats =
  1550. {
  1551.     local float tf;
  1552.     local string st;
  1553.  
  1554.     tf = random() * 50;
  1555.     self.nextthink = time + 10 + tf;
  1556.  
  1557.     tf = vlen(self.owner.velocity);
  1558.  
  1559.     // Since players still exceed their maxfbspeed when strafing
  1560.     // as well as moving forward or backward, I played around a
  1561.     // while until I decided on 200. I've never broken this.
  1562.     // If you do exceed this when not cheating, please mail me.
  1563.     if (tf > (self.owner.maxfbspeed + 200))
  1564.     {
  1565.         // Make sure they're on the ground
  1566.         if ((self.owner.flags & FL_ONGROUND) && (self.velocity_z == 0))
  1567.         {
  1568.             bprint(self.owner.netname);
  1569.             bprint(" has been fined 5 frags for cheating!\n");
  1570.             self.owner.frags = self.owner.frags - 5;
  1571.             T_Damage(self.owner, world, world, 400);
  1572.     
  1573.             // Make sure they don't get fined again before they respawn
  1574.             self.owner.maxfbspeed = 1000;
  1575.         }
  1576.      }
  1577.  };
  1578.  
  1579.