home *** CD-ROM | disk | FTP | other *** search
/ PC Gamer 3.2 / 1997-05_Disc_3.2.iso / QUAKECTF / SRC / CTF / TEAMPLAY.QC < prev    next >
Text File  |  1997-01-31  |  45KB  |  1,626 lines

  1. /* teamplay.qc
  2.  
  3.    From
  4.         The Complete Enhanced Teamplay
  5.  
  6.    John Spickes -- jspickes@eng.umd.edu
  7.  
  8.     $Id: teamplay.qc 1.17 1996/08/17 16:52:45 jspickes Exp $
  9.  
  10.     $Log: teamplay.qc $
  11.     Revision 1.17  1996/08/17 16:52:45  jspickes
  12.     Fixed a problem with displaying the current team settings that could cause
  13.     the wrong output when teamplay was negative.  Also added code to indicate
  14.     when ID's silly teamplay code is being used.
  15.  
  16.     Revision 1.16  1996/08/17 00:41:52  jspickes
  17.     Turned off strict coop by default.
  18.     Fixed a bug that could have caused strange behavior if TEAM_COLOR* was
  19.     set to -2.
  20.  
  21.     Revision 1.15  1996/08/17 00:34:17  jspickes
  22.     Added instructions on drop-item use in current settings output.
  23.     Fixed a problem that would allow you to drop lots of backpacks with
  24.     nothing in them.
  25.  
  26. */
  27.  
  28. /** Defs **/
  29.  
  30. /** MODIFIABLE CONSTANTS **/
  31.  
  32. float TEAM_DEFAULT_PENALTY =    1;      // Default frag penalty
  33. float TEAM_STRICT_COOP =    0;    // Strict Coop
  34.  
  35. // Allowed team colors
  36. // -1 indicates no color
  37.  
  38. float TEAM_COLOR1       =       4;
  39. float TEAM_COLOR2       =       13;
  40. float TEAM_COLOR3       =       -1;
  41. float TEAM_COLOR4       =       -1;
  42.  
  43. /** End of MODIFIABLE CONSTANTS **/
  44.  
  45. // Globals
  46.  
  47. entity team1_lastspawn;
  48. entity team2_lastspawn;
  49. float    nextteamupdtime;    // time until next team update
  50.  
  51. // Teamplay bitfield entries
  52.  
  53. float TEAM_HEALTH_PROTECT =     1;      // No health damage from friendly fire
  54. float TEAM_ARMOR_PROTECT =      2;      // No armor damage from friendly fire
  55. float TEAM_ATTACKER_DAMAGE =    4;      // Attacker takes damage from hitting teammates
  56. float TEAM_FRAG_PENALTY =       8;      // One frag penalty for killing teammate
  57. float TEAM_DEATH_PENALTY =      16;     // Die when you kill a teammate.
  58. float TEAM_LOCK_COLORS =        32;     // Allow only team colors
  59. float TEAM_STATIC_TEAMS =       64;     // Don't allow players to switch teams
  60. float TEAM_DROP_ITEMS =     128;    // Allow players to drop packs and 
  61. float TEAM_CAPTURE_FLAG =    256;    // Play capture the flag
  62. float TEAM_CAPTURE_CUSTOM = 512;    // custom models
  63. float TEAM_CAPTURE_SELECT_TEAM = 1024; // team selection
  64.  
  65. // CTFBOT [[[
  66. float TEAM_CAPTURE_CTFBOT_ADMIN = 2048;            // CTFBOT enable ctf bot admin functions
  67. float TEAM_CAPTURE_AUTO_EVEN_TEAMS = 4096;        // CTFBOT always keep teams even
  68. float TEAM_NO_RUNE_DROP = 8192;                    // CTFBOT disable rune dropping
  69. float TEAM_CAPTURE_NO_BOT_FLAG_PICKUP = 16384;    // CTFBOT disable bot flag pickups
  70. float TEAM_FIX_BOT_COLORS = 32768;
  71. float TEAM_DAMAGE_THE_FLAG = 65536;
  72. float TEAM_INVASION =  131072;
  73. // CTFBOT ]]]
  74.  
  75. float TEAM_CAPTURE_CAPTURE_BONUS = 15; // what you get for capture
  76. float TEAM_CAPTURE_TEAM_BONUS = 10; // what your team gets for capture
  77. float TEAM_CAPTURE_RECOVERY_BONUS = 1; // what you get for recovery
  78. float TEAM_CAPTURE_FLAG_BONUS = 0; // what you get for picking up enemy flag
  79. float TEAM_CAPTURE_FRAG_CARRIER_BONUS = 2; // what you get for fragging
  80.     //enemy flag carrier
  81. float TEAM_CAPTURE_FLAG_RETURN_TIME = 40; // seconds until auto return
  82.  
  83. // XXX EXPERT CTF Additional scoring system
  84.  
  85. // bonuses
  86.  
  87. float TEAM_CAPTURE_CARRIER_DANGER_PROTECT_BONUS = 2; // bonus for fraggin someone
  88. // who has recently hurt your flag carrier
  89. float TEAM_CAPTURE_CARRIER_PROTECT_BONUS = 1; // bonus for fraggin someone while
  90. // either you or your target are near your flag carrier
  91. float TEAM_CAPTURE_FLAG_DEFENSE_BONUS = 1; // bonus for fraggin someone while
  92. // either you or your target are near your flag
  93. float TEAM_CAPTURE_RETURN_FLAG_ASSIST_BONUS = 1; // awarded for returning a flag that causes a
  94. // capture to happen almost immediately
  95. float TEAM_CAPTURE_FRAG_CARRIER_ASSIST_BONUS = 2; // award for fragging a flag carrier if a
  96. // capture happens almost immediately
  97.  
  98. // radii
  99.  
  100. float TEAM_CAPTURE_TARGET_PROTECT_RADIUS = 400; // the radius around an object being
  101. // defended where a target will be worth extra frags
  102. float TEAM_CAPTURE_ATTACKER_PROTECT_RADIUS = 400; // the radius around an object being
  103. // defended where an attacker will get extra frags when making kills
  104.  
  105. // timeouts
  106.  
  107. float TEAM_CAPTURE_CARRIER_DANGER_PROTECT_TIMEOUT = 4;
  108. float TEAM_CAPTURE_CARRIER_FLAG_SINCE_TIMEOUT = 2;
  109. float TEAM_CAPTURE_FRAG_CARRIER_ASSIST_TIMEOUT = 6;
  110. float TEAM_CAPTURE_RETURN_FLAG_ASSIST_TIMEOUT = 4;
  111.  
  112. float TEAM_CAPTURE_UPDATE_TIME = 120;
  113.  
  114. // END EXPERT CTF
  115.  
  116. // flag status used in cnt field of flag
  117. float FLAG_AT_BASE = 0;
  118. float FLAG_CARRIED = 1;
  119. float FLAG_DROPPED = 2;
  120.  
  121.  
  122. // Prototypes
  123. float() W_BestWeapon;
  124. void() W_SetCurrentAmmo;
  125. void() bound_other_ammo;
  126. void(float o, float n) Deathmatch_Weapon;
  127. void() BackpackTouch;
  128.  
  129. // Return a name for the color of a team
  130. string(float Team) GetTeamColor =
  131. {
  132.     if(Team == 0) return("Blue");
  133.     else if(Team == 1) return("Steel blue");
  134.     else if(Team == 2) return("Brown");
  135.     else if(Team == 3) return("Baby blue");
  136.     else if(Team == 4) return("Green");
  137.     else if(Team == 5) return("Red");
  138.     else if(Team == 6) return("Olive");
  139.     else if(Team == 7) return("Orange");
  140.     else if(Team == 8) return("Peech");
  141.     else if(Team == 9) return("Purple");
  142.     else if(Team == 10) return("Majenta");
  143.     else if(Team == 11) return("Grey");
  144.     else if(Team == 12) return("Aqua");
  145.     else if(Team == 13) return("Yellow");
  146.     else if(Team == 14) return("Blue");
  147.     return "Unknown";
  148. };
  149.  
  150. // *XXX* EXPERT CTF
  151. // Just a quickie to return the ASCII-ized team names for CTF
  152. string(float Team) GetCTFTeam =
  153. {
  154.  
  155.     if (Team == (TEAM_COLOR1 + 1)) return "╥┼─";
  156.     if (Team == (TEAM_COLOR2 + 1)) return "┬╠╒┼";
  157.     return "";
  158.  
  159. };
  160.  
  161.  
  162. /*
  163. ================
  164. TeamPrintSettings
  165.  
  166. Print out current teamplay options
  167. ================
  168. */
  169.  
  170. void() TeamPrintSettings =
  171. {
  172.     local string st;
  173.     
  174.     sprint(self,"The following Teamplay options are set:\n");
  175.     
  176.     if(teamplay < 0)
  177.     {
  178.         sprint(self, "Frag penalty manually set to ");
  179.         st = ftos(teamplay);
  180.         sprint(self, st);
  181.         sprint(self, "\n");
  182.         return;
  183.     }
  184.     
  185.     if(!teamplay) 
  186.     {
  187.         sprint(self, "None\n");
  188.         return;
  189.     }
  190.     
  191.     if(1 == teamplay)
  192.     {
  193.         sprint(self, "ID's original teamplay 1\n");
  194.         return;
  195.     }
  196.     
  197.     if(teamplay & TEAM_HEALTH_PROTECT)
  198.         sprint(self, "Health-Protect\n");    // CTFBOT EXTRAS added \n
  199.     
  200.     if(teamplay & TEAM_ARMOR_PROTECT)
  201.         sprint(self, "Armor-Protect\n");    // CTFBOT EXTRAS added \n
  202.         
  203.     if(teamplay & TEAM_ATTACKER_DAMAGE)
  204.         sprint(self, "Mirror-Damage\n");    // CTFBOT EXTRAS added \n
  205.         
  206.     if(teamplay & TEAM_FRAG_PENALTY)
  207.         sprint(self, "Frag-Penalty\n");    // CTFBOT EXTRAS added \n
  208.         
  209.     if(teamplay & TEAM_DEATH_PENALTY)
  210.         sprint(self, "Death-Penalty\n");    // CTFBOT EXTRAS added \n
  211.         
  212.     if(teamplay & TEAM_LOCK_COLORS)
  213.         sprint(self, "Lock-Colors\n");    // CTFBOT EXTRAS added \n
  214.         
  215.     if(teamplay & TEAM_STATIC_TEAMS)
  216.         sprint(self, "Static-Teams\n");    // CTFBOT EXTRAS added \n
  217.         
  218.     if(teamplay & TEAM_DROP_ITEMS)
  219.         sprint(self, "Drop-Items (Backpack Impulse 20, Weapon Impulse 21)\n");    // CTFBOT EXTRAS added \n
  220.         
  221.     if(teamplay & TEAM_CAPTURE_FLAG)
  222.         sprint(self, "Capture-The-Flag\n");    // CTFBOT EXTRAS added \n
  223.         
  224.     if(teamplay & TEAM_CAPTURE_CUSTOM)                // CTFBOT EXTRAS
  225.         sprint(self, "Custom-Capture-The-Flag\n");    // CTFBOT EXTRAS
  226.  
  227.     if(teamplay & TEAM_CAPTURE_SELECT_TEAM)            // CTFBOT EXTRAS
  228.         sprint(self, "Capture-Select-Team\n");        // CTFBOT EXTRAS
  229.  
  230.     if(teamplay & TEAM_CAPTURE_CTFBOT_ADMIN)            // CTFBOT EXTRAS
  231.         sprint(self, "Capture-Total-Freedom\n");        // CTFBOT EXTRAS
  232.  
  233.     if(teamplay & TEAM_CAPTURE_AUTO_EVEN_TEAMS)            // CTFBOT EXTRAS
  234.         sprint(self, "Auto-Even-Team\n");        // CTFBOT EXTRAS
  235.  
  236.     if(teamplay & TEAM_NO_RUNE_DROP)            // CTFBOT EXTRAS
  237.         sprint(self, "No-Rune-Dropping\n");        // CTFBOT EXTRAS
  238.  
  239.     // CTFBOT EXTRAS removed sprint here
  240. };
  241.  
  242. /*
  243. ================
  244. TeamArmorDam
  245.  
  246. Return TRUE if the target's armor can take damage from this attacker.
  247. ================
  248. */
  249.  
  250. float(entity targ, entity inflictor, entity attacker, float damage) TeamArmorDam =
  251. {
  252.         if( teamplay < 0 )
  253.                 return TRUE;
  254.         if( (teamplay & TEAM_ARMOR_PROTECT) && 
  255.             (attacker.lastteam == targ.lastteam) && 
  256.             (attacker != targ) && (targ.lastteam > 0) )
  257.         {
  258.                 // Armor is protected
  259.                 return FALSE;
  260.         }
  261.         return TRUE;
  262. };
  263.  
  264. /*
  265. ================
  266. TeamHealthDam
  267.  
  268. Return TRUE if the target can take health damage from this attacker.
  269. ================
  270. */
  271.  
  272. float(entity targ, entity inflictor, entity attacker, float damage) TeamHealthDam =
  273. {
  274.         if( teamplay < 0 )
  275.         {
  276.                 return TRUE;
  277.         }
  278.         
  279.         // CTFBOT DTF [[[
  280.         // flag damage always taken, regardless of teamplay settings
  281.         if ((attacker.classname == "item_flag_team1") 
  282.             || (attacker.classname == "item_flag_team2"))
  283.             return TRUE;
  284.         // CTFBOT DTF ]]]
  285.         
  286.         if( (attacker.lastteam == targ.lastteam) && 
  287.             (attacker != targ) && (targ.lastteam > 0) )
  288.         {
  289.                 // Attacker and target are on the same team.
  290.                 if( teamplay & TEAM_ATTACKER_DAMAGE )
  291.                 {
  292.                         // Damage applied to teammate.
  293.                         T_Damage(attacker, inflictor, attacker, damage);
  294.                 }
  295.                 if( teamplay & TEAM_HEALTH_PROTECT )
  296.                 {
  297.                         // Health is protected
  298.                         return FALSE;
  299.                 }
  300.         }
  301.         return TRUE;
  302. };
  303.  
  304. /*
  305. ================
  306. TeamPFrags
  307.  
  308. Return the number of frags we should penalize attacker for killing targ.
  309. ================
  310. */
  311.  
  312. float(entity targ, entity attacker) TeamPFrags =
  313. {
  314.         if( teamplay < 0 )
  315.                 return (-1 * teamplay);
  316.         if( (targ.lastteam > 0) && (targ != attacker) && (targ.lastteam ==
  317.             attacker.lastteam) )
  318.         {
  319.                 // targ and attacker are on the same team
  320.                 if( teamplay < 0 )
  321.                 {
  322.                         // teamplay indicates frag penalty
  323.                         return ( -1 * teamplay );
  324.                 }
  325.                 if( teamplay & TEAM_FRAG_PENALTY )
  326.                 {
  327.                         // default penalty
  328.                         return TEAM_DEFAULT_PENALTY;
  329.                 }
  330.         }
  331.         // No frag penalty
  332.         return 0;
  333. };
  334.  
  335. /*
  336. ================
  337. TeamFragPenalty
  338.  
  339. If attacker should be penalized for killing targ, penalize attacker
  340. and return TRUE.
  341. ================
  342. */
  343.  
  344. float(entity targ, entity attacker) TeamFragPenalty =
  345. {
  346.         local float f;
  347.  
  348.         f = TeamPFrags(targ, attacker);
  349.  
  350.         if( f )
  351.         {
  352.                 // We should penalize some frags.
  353.                 attacker.frags = attacker.frags - f;
  354.                 return TRUE;
  355.         }
  356.         // No penalty
  357.         return FALSE;
  358. };
  359.  
  360. /*
  361. =================
  362. TeamDeathPenalty
  363.  
  364. If attacker should be killed for killing targ, kill attacker and
  365. add a frag to offset the one attacker will lose for killing himself.
  366. */
  367.  
  368. void(entity targ, entity attacker) TeamDeathPenalty =
  369. {
  370.         //Don't kill anyone if teamplay is negative.
  371.         if ( teamplay < 0 )
  372.                 return;
  373.  
  374.         if ( (teamplay & TEAM_DEATH_PENALTY) && (targ.lastteam > 0) &&
  375.             (attacker != targ) && (attacker.lastteam == targ.lastteam) )
  376.         {
  377.                 //We should kill the attacker.
  378.                 T_Damage(attacker,attacker,attacker,50000);    // CTFBOT EXTRAS increased
  379.                 //Add a frag to offset the self-kill penalty.
  380.                 attacker.frags = attacker.frags + 1;
  381.         }
  382. };
  383.  
  384. /*
  385. ==================
  386. TeamColorIsLegal
  387.  
  388. Return TRUE if the indicated color is legal
  389. ==================
  390. */
  391. float(float color) TeamColorIsLegal =
  392. {
  393.         // All colors are legal if teamplay is negative.
  394.         if( teamplay < 0 )
  395.                 return TRUE;
  396.         // All colors are legal if TEAM_LOCK_COLORS is off.
  397.         if( !(teamplay & TEAM_LOCK_COLORS) )
  398.                 return TRUE;
  399.         if( (color == TEAM_COLOR1) && (TEAM_COLOR1 >= 0) )
  400.                 return TRUE;
  401.         if( (color == TEAM_COLOR2) && (TEAM_COLOR2 >= 0) )
  402.                 return TRUE;
  403.         if( (color == TEAM_COLOR3) && (TEAM_COLOR3 >= 0) )
  404.                 return TRUE;
  405.         if( (color == TEAM_COLOR4) && (TEAM_COLOR4 >= 0) )
  406.                 return TRUE;
  407. };
  408.  
  409. /*
  410. ==================
  411. TeamCheckTeam
  412.  
  413. Check if the team self is on is legal, and put self in a legal team if not.
  414. ==================
  415. */
  416. void() TeamCheckTeam =
  417. {
  418.     local float TEAM1;
  419.     local float TEAM2;
  420.     local float TEAM3;
  421.     local float TEAM4;
  422.  
  423.     local float newcolor;
  424.     local float t;
  425.  
  426.     local entity p;
  427.  
  428.     local string n; 
  429.  
  430.     if( self.lastteam >= 0 )
  431.     {
  432.             if(TeamColorIsLegal(self.team - 1)) {
  433.                 self.lastteam = self.team;
  434.                 return;
  435.             }
  436.     }
  437.  
  438.     // Assign the player to a team.
  439.  
  440.     // Sum the players on all the teams.
  441.  
  442.     TEAM1 = 0;
  443.     TEAM2 = 0;
  444.     TEAM3 = 0;
  445.     TEAM4 = 0;
  446.  
  447.     p = find (world, classname, "player");
  448.  
  449.     while(p)
  450.     {
  451.         if (p != self) {
  452.             if( (TEAM_COLOR1 >= 0) && (p.team == (TEAM_COLOR1 +1)) )
  453.                     TEAM1 = TEAM1 + 1;
  454.             if( (TEAM_COLOR2 >= 0) && (p.team == (TEAM_COLOR2 +1)) )
  455.                     TEAM2 = TEAM2 + 1;
  456.             if( (TEAM_COLOR3 >= 0) && (p.team == (TEAM_COLOR3 +1)) )
  457.                     TEAM3 = TEAM3 + 1;
  458.             if( (TEAM_COLOR4 >= 0) && (p.team == (TEAM_COLOR4 +1)) )
  459.                     TEAM4 = TEAM4 + 1;
  460.         }
  461.  
  462.         p = FindNextPlayerOrBot(p); // CTFBOT replaced find, so we find bots also
  463.     }
  464.  
  465.     // Find the team with the least players.
  466.     newcolor = TEAM_COLOR1;
  467.     t = TEAM1;
  468.  
  469.     if ( (TEAM_COLOR2 >= 0) && ((TEAM2 < t) || (TEAM2 == t && random() < 0.5))) {
  470.             newcolor = TEAM_COLOR2;
  471.             t = TEAM2;
  472.     }
  473.  
  474.     if ( (TEAM_COLOR3 >= 0) && ((TEAM3 < t) || (TEAM2 == t && random() < 0.5))) {
  475.             newcolor = TEAM_COLOR3;
  476.             t = TEAM3;
  477.     }
  478.  
  479.     if ( (TEAM_COLOR4 >= 0) && ((TEAM4 < t) || (TEAM2 == t && random() < 0.5))) {
  480.             newcolor = TEAM_COLOR4;
  481.             t = TEAM4;
  482.     }
  483.  
  484.     // Put the player on a the new team.
  485.     if (self.classname == "player")    // CTFBOT
  486.  
  487.     {        // CTFBOT
  488.     n = ftos(newcolor);
  489.     stuffcmd(self, "color ");
  490.     stuffcmd(self, n);
  491.     stuffcmd(self, "\n");
  492.  
  493.     sprint(self, "You have been assigned color ");
  494.     sprint(self, n);
  495.     sprint(self, "\nLegal colors are:");
  496.     if(TEAM_COLOR1 >= 0)
  497.     {
  498.             n = ftos(TEAM_COLOR1);
  499.             sprint(self, " ");
  500.             sprint(self, n);
  501.     }
  502.     if(TEAM_COLOR2 >= 0)
  503.     {
  504.             n = ftos(TEAM_COLOR2);
  505.             sprint(self, " ");
  506.             sprint(self, n);
  507.     }
  508.     if(TEAM_COLOR3 >= 0)
  509.     {
  510.             n = ftos(TEAM_COLOR3);
  511.             sprint(self, " ");
  512.             sprint(self, n);
  513.     }
  514.     if(TEAM_COLOR4 >= 0)
  515.     {
  516.             n = ftos(TEAM_COLOR4);
  517.             sprint(self, " ");
  518.             sprint(self, n);
  519.     }
  520.  
  521.     sprint(self, "\n");
  522.     } // CTFBOT
  523.  
  524.  
  525.  
  526.     self.lastteam = newcolor + 1;      // Remember what team we're on
  527.     self.team = newcolor + 1;
  528. };
  529.  
  530. /*
  531. ===============
  532. TeamCheckLock
  533.  
  534. Check for team changing and perform whatever actions are neccessary.
  535. ===============
  536. */
  537. void() TeamCheckLock =
  538. {
  539.         local   float   n;
  540.         local   string  s;
  541.  
  542.         // Don't do anything if teamplay is negative
  543.         if ( teamplay < 0 )
  544.                 return;
  545.         
  546.         if (self.observer || self.do_observer) {
  547.             if (self.team != 1)
  548.             if (self.classname == "player")        // CTFBOT
  549.                 stuffcmd(self, "color 0\n");
  550.             return;
  551.         }
  552.  
  553.         if (self.player_flag & TEAM_STUFF_COLOR) {
  554.             self.player_flag = self.player_flag - TEAM_STUFF_COLOR;
  555.             stuffcmd(self, "color ");
  556.             n = self.lastteam - 1;
  557.             s = ftos(n);
  558.             stuffcmd(self, s);
  559.             stuffcmd(self, "\n");
  560.             return;
  561.         }
  562.  
  563.         if ( !TeamColorIsLegal(self.team - 1) && (self.team == self.lastteam)) {
  564.             self.lastteam = -1;
  565.         }
  566.  
  567.         // Check to see if the player has changed colors
  568.         if (self.team != self.lastteam)
  569.         {
  570.                 // Player has changed colors
  571.  
  572.                 // If teams are static and we've been on some team already,
  573.                 // put us back on the team we were on.
  574.  
  575.                 if ( (teamplay & TEAM_STATIC_TEAMS) && (self.lastteam >= 0) )
  576.                 {
  577.                         if ( TeamColorIsLegal(self.lastteam - 1) )
  578.                         {
  579.                                 // changing teams sucks, kill him
  580.  
  581.                                 // if he has tried to change teams several
  582.                                 // times, kick him off the server.
  583.                                 if (self.suicide_count > 3) {
  584.                                     sprint(self, "You were told you can't change teams.\nGo play color games somewhere else.\n");
  585.                                     stuffcmd(self, "disconnect\n");
  586.                                     bprint(self.netname);
  587.                                     bprint(" has bad color sense\n");
  588.                                 }
  589.                                 // case base respawn
  590.                                 if (self.killed != 1)
  591.                                     self.killed = 2;
  592.                                 T_Damage(self,self,self,50000);  // Kill the player CTFBOT EXTRAS increased
  593.                                 // trying to change teams counts as a suicide
  594.                                 self.suicide_count = self.suicide_count + 1;
  595.  
  596.                                 sprint(self, "You cannot change teams.\n");
  597.                                 stuffcmd(self, "color ");
  598.                                 n = self.lastteam - 1;
  599.                                 s = ftos(n);
  600.                                 stuffcmd(self, s);
  601.                                 stuffcmd(self, "\n");
  602.                     self.team = self.lastteam;
  603.                                 return;
  604.                         }
  605.                         else {
  606.                                 // If we're on an illegal team, force a change.
  607.                                 self.lastteam = -50;
  608.                         }
  609.                 }
  610.  
  611.                 // If teamlock is turned off, don't do anything more.
  612.                 if ( !(teamplay & TEAM_LOCK_COLORS) )
  613.                 {
  614.                         self.lastteam = self.team;
  615.                         return;
  616.                 }
  617.  
  618.                 if(self.lastteam > 0) {
  619.                     // case base respawn
  620.                     if (self.killed != 1)
  621.                         self.killed = 2;
  622.                     T_Damage(self,self,self,50000);  // Kill the player CTFBOT EXTRAS increased 
  623.                 }
  624.                 self.frags = 0;                 // Zero out frags
  625.                 TeamCheckTeam();
  626.         }
  627. };
  628.  
  629. /*
  630. =======================
  631. TossBackPack
  632.  
  633. Original idea by Vhold
  634. Rewritten by John Spickes
  635.  
  636. Toss out a backpack containing some ammo from your current weapon,
  637. and any weapons you don't have.
  638. =======================
  639. */
  640. void() TossBackpack =
  641. {
  642.     local entity     item;
  643.  
  644.     // If we don't have any ammo, return
  645.     if(self.currentammo <= 0)
  646.         return;
  647.  
  648.     item = spawn();
  649.  
  650.     // See if you have the Shotgun or Super Shotgun on
  651.         if ( (self.weapon == IT_SHOTGUN) || (self.weapon == IT_SUPER_SHOTGUN)) {
  652.         if( self.ammo_shells >= 20 ) {
  653.             item.ammo_shells = 20;
  654.             self.ammo_shells = self.ammo_shells - 20;
  655.         }
  656.         else
  657.         {
  658.             item.ammo_shells = self.ammo_shells;
  659.             self.ammo_shells = 0;
  660.         }
  661.     }        
  662.     
  663.     // See if you have neither the Shotgun or Super Shotgun
  664.         if ( !(self.items & IT_SHOTGUN) && !(self.items & IT_SUPER_SHOTGUN)) {
  665.         if( self.ammo_shells >= 20 ) {
  666.             item.ammo_shells = 20;
  667.             self.ammo_shells = self.ammo_shells - 20;
  668.         }
  669.         else
  670.         {
  671.             item.ammo_shells = self.ammo_shells;
  672.             self.ammo_shells = 0;
  673.         }
  674.     }        
  675.     
  676.     // See if we are using a nailgun
  677.         if ( (self.weapon == IT_NAILGUN) || (self.weapon == IT_SUPER_NAILGUN) )
  678.     {
  679.         if( self.ammo_nails >= 20 )
  680.         {
  681.             item.ammo_nails = 20;
  682.             self.ammo_nails = self.ammo_nails - 20;
  683.         }
  684.         else
  685.         {
  686.             item.ammo_nails = self.ammo_nails;
  687.             self.ammo_nails = 0;
  688.         }
  689.     }    
  690.     // Check to see if we have neither nailgun
  691.         if ( !(self.items & IT_NAILGUN) && !(self.items & IT_SUPER_NAILGUN) )
  692.     {
  693.         if( self.ammo_nails >= 20 )
  694.         {
  695.             item.ammo_nails = 20;
  696.             self.ammo_nails = self.ammo_nails - 20;
  697.         }
  698.         else
  699.         {
  700.             item.ammo_nails = self.ammo_nails;
  701.             self.ammo_nails = 0;
  702.         }
  703.     }    
  704.     
  705.     // See if we are using a grenade or rocket launcher
  706.         if ( (self.weapon == IT_GRENADE_LAUNCHER) || (self.weapon == IT_ROCKET_LAUNCHER) )
  707.     {
  708.         if( self.ammo_rockets >= 10 )
  709.         {
  710.             item.ammo_rockets = 10;
  711.             self.ammo_rockets = self.ammo_rockets - 10;
  712.         }
  713.         else
  714.         {
  715.             item.ammo_rockets = self.ammo_rockets;
  716.             self.ammo_rockets = 0;
  717.         }
  718.     }
  719.     // See if we have neither the Grenade or rocket launcher
  720.         if ( !(self.items & IT_GRENADE_LAUNCHER) && !(self.items & IT_ROCKET_LAUNCHER) )
  721.     {
  722.         if( self.ammo_rockets >= 10 )
  723.         {
  724.             item.ammo_rockets = 10;
  725.             self.ammo_rockets = self.ammo_rockets - 10;
  726.         }
  727.         else
  728.         {
  729.             item.ammo_rockets = self.ammo_rockets;
  730.             self.ammo_rockets = 0;
  731.         }
  732.     }
  733.  
  734.     // See if we're using the lightning gun
  735.     if ( self.weapon == IT_LIGHTNING )
  736.     {    
  737.         if( self.ammo_cells >= 20 )
  738.         {
  739.             item.ammo_cells = 20;
  740.             self.ammo_cells = self.ammo_cells - 20;
  741.         }
  742.         else
  743.         {
  744.             item.ammo_cells = self.ammo_cells;
  745.             self.ammo_cells = 0;
  746.         }
  747.     }
  748.     // see if we don't have the lightning gun
  749.         if ( !(self.items & IT_LIGHTNING) )
  750.     {    
  751.         if( self.ammo_cells >= 20 )
  752.         {
  753.             item.ammo_cells = 20;
  754.             self.ammo_cells = self.ammo_cells - 20;
  755.         }
  756.         else
  757.         {
  758.             item.ammo_cells = self.ammo_cells;
  759.             self.ammo_cells = 0;
  760.         }
  761.     }
  762.      
  763.     item.owner = self;
  764.     makevectors(self.v_angle);
  765.  
  766.     setorigin(item, self.origin + '0 0 16');
  767.     item.velocity = aim(self, 1000);
  768.     item.velocity = item.velocity * 500;
  769.     item.flags = FL_ITEM;
  770.     item.solid = SOLID_TRIGGER;
  771.     item.movetype = MOVETYPE_BOUNCE;
  772.  
  773.     setmodel (item, "progs/backpack.mdl");
  774.     setsize(item, '-16 -16 0', '16 16 56');
  775.     item.touch = BackpackTouch;
  776.     item.nextthink = time + 120;    // remove after 2 minutes
  777.     item.think = SUB_Remove;
  778.  
  779.     W_SetCurrentAmmo();
  780.  
  781.     item.bot_wants_item = TRUE;        // CTFBOT optimization
  782.  
  783.     item.classname = "backpack";    // CTFBOT give backpacks a class name
  784.                                     // CTFBOT so bots can see them
  785.     item.netname = "backpack";        // CTFBOT give backpacks a net name
  786.                                     // CTFBOT for better debug messages
  787.  
  788. };
  789.  
  790. void() Team_weapon_touch =
  791. {
  792.     local    float    hadammo, best, new, old;
  793.     local entity stemp;
  794.  
  795.     if (!(other.flags & FL_CLIENT))
  796.         return;
  797.     // Don't let the owner pick up his own weapon for a second.
  798.     if ( (other == self.owner) && ( (self.nextthink - time) > 119 ) )
  799.         return;
  800.  
  801. // if the player was using his best weapon, change up to the new one if better        
  802.     stemp = self;
  803.     self = other;
  804.     best = W_BestWeapon();
  805.     self = stemp;
  806.  
  807.     if (self.classname == "weapon_nailgun")
  808.     {
  809.         hadammo = other.ammo_nails;            
  810.         new = IT_NAILGUN;
  811.     }
  812.     else if (self.classname == "weapon_supernailgun")
  813.     {
  814.         hadammo = other.ammo_rockets;            
  815.         new = IT_SUPER_NAILGUN;
  816.     }
  817.     else if (self.classname == "weapon_supershotgun")
  818.     {
  819.         hadammo = other.ammo_rockets;            
  820.         new = IT_SUPER_SHOTGUN;
  821.     }
  822.     else if (self.classname == "weapon_rocketlauncher")
  823.     {
  824.         hadammo = other.ammo_rockets;            
  825.         new = IT_ROCKET_LAUNCHER;
  826.     }
  827.     else if (self.classname == "weapon_grenadelauncher")
  828.     {
  829.         hadammo = other.ammo_rockets;            
  830.         new = IT_GRENADE_LAUNCHER;
  831.     }
  832.     else if (self.classname == "weapon_lightning")
  833.     {
  834.         hadammo = other.ammo_rockets;            
  835.         new = IT_LIGHTNING;
  836.     }
  837.     else
  838.         objerror ("Team_weapon_touch: unknown classname");
  839.  
  840.  
  841.     if (other.classname == "player")    // CTFBOT
  842.  
  843.     {    // CTFBOT
  844.         sprint (other, "You got the ");
  845.         sprint (other, self.netname);
  846.         sprint (other, "\n");
  847.         stuffcmd (other, "bf\n");
  848.  
  849.     }    // CTFBOT
  850.  
  851.  
  852. // weapon touch sound CTFBOT moved from above
  853.  
  854.     sound (other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM);     // CTFBOT moved
  855.  
  856.  
  857.     bound_other_ammo ();
  858.  
  859. // change to the weapon
  860.     old = other.items;
  861.     other.items = other.items | new;
  862.     
  863.     remove(self);
  864.     self = other;
  865.  
  866.     if (!deathmatch)
  867.         self.weapon = new;
  868.     else
  869.         Deathmatch_Weapon (old, new);
  870.  
  871.     W_SetCurrentAmmo();
  872.  
  873.     activator = other;
  874.     SUB_UseTargets();                // fire all targets / killtargets
  875. };
  876.         
  877. void() TossWeapon =
  878. {
  879.     local entity item;
  880.     
  881.     if (deathmatch != 1)
  882.         return;  // only in deathmatch 1
  883.  
  884.     if((self.weapon == IT_AXE) || (self.weapon == IT_SHOTGUN) ||
  885.         (self.weapon == IT_HOOK))
  886.         return;
  887.         
  888.     item = spawn();
  889.     item.owner = self;
  890.     makevectors(self.v_angle);
  891.  
  892.     setorigin(item, self.origin + '0 0 16');
  893.     item.velocity = aim(self, 1000);
  894.     item.velocity = item.velocity * 500;
  895.     item.flags = FL_ITEM;
  896.     item.solid = SOLID_TRIGGER;
  897.     item.movetype = MOVETYPE_BOUNCE;
  898.  
  899.     item.bot_wants_item = TRUE;        // CTFBOT optimization
  900.     
  901.     if(self.weapon == IT_SUPER_SHOTGUN)
  902.     {
  903.         setmodel (item, "progs/g_shot.mdl");
  904.         item.weapon = IT_SUPER_SHOTGUN;
  905.         item.netname = "Double-barrelled Shotgun";
  906.         item.classname = "weapon_supershotgun";
  907.         self.items = self.items - IT_SUPER_SHOTGUN;
  908.     }
  909.  
  910.     if( self.weapon == IT_NAILGUN )
  911.     {
  912.         setmodel (item, "progs/g_nail.mdl");
  913.         item.weapon = IT_NAILGUN;
  914.         item.netname = "nailgun";
  915.         item.classname = "weapon_nailgun";
  916.         self.items = self.items - IT_NAILGUN;
  917.     }
  918.         
  919.     if( self.weapon == IT_SUPER_NAILGUN)
  920.     {
  921.         setmodel (item, "progs/g_nail2.mdl");
  922.         item.weapon = IT_SUPER_NAILGUN;
  923.         item.netname = "Super Nailgun";
  924.         item.classname = "weapon_supernailgun";
  925.         self.items = self.items - IT_SUPER_NAILGUN;
  926.     }
  927.     
  928.     if( self.weapon == IT_GRENADE_LAUNCHER)
  929.     {
  930.         setmodel (item, "progs/g_rock.mdl");
  931.         item.weapon = 3;
  932.         item.netname = "Grenade Launcher";
  933.         item.classname = "weapon_grenadelauncher";
  934.         self.items = self.items - IT_GRENADE_LAUNCHER;
  935.     }
  936.     
  937.     if( self.weapon == IT_ROCKET_LAUNCHER )
  938.     {
  939.         setmodel (item, "progs/g_rock2.mdl");
  940.         item.weapon = 3;
  941.         item.netname = "Rocket Launcher";
  942.         item.classname = "weapon_rocketlauncher";
  943.         self.items = self.items - IT_ROCKET_LAUNCHER;
  944.     }
  945.     
  946.     if( self.weapon == IT_LIGHTNING )
  947.     {
  948.         setmodel (item, "progs/g_light.mdl");
  949.         item.weapon = 3;
  950.         item.netname = "Thunderbolt";
  951.         item.classname = "weapon_lightning";
  952.         self.items = self.items - IT_LIGHTNING;
  953.     }
  954.     setsize(item, '-16 -16 0', '16 16 56');
  955.     item.touch = Team_weapon_touch;
  956.     item.think = SUB_Remove;
  957.     item.nextthink = time + 120;
  958.     
  959.     self.weapon = W_BestWeapon();
  960.     W_SetCurrentAmmo();
  961. };
  962.  
  963. void(entity flg) RegenFlag =
  964. {
  965.     flg.movetype = MOVETYPE_TOSS;
  966.     flg.solid = SOLID_TRIGGER;
  967.     sound (flg, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);    // play respawn sound
  968.     setorigin(flg, flg.oldorigin);
  969.     flg.angles = flg.mangle;
  970.     flg.cnt = FLAG_AT_BASE; // it's at home base
  971.     flg.owner = world;
  972. };
  973.  
  974. void(entity flg) TeamCaptureReturnFlag =
  975. {
  976.     local entity p;
  977.  
  978.     RegenFlag(flg);
  979.  
  980.     p = find(world, classname, "player");
  981.     while (p != world) {
  982.         if (p.team != flg.team)
  983.             centerprint(p, "Enemy flag has been returned to base!\n");
  984.         else if (p.team == flg.team)
  985.             centerprint(p, "Your flag has been returned to base!\n");
  986.         p = find(p, classname, "player");
  987.     }
  988. };
  989.  
  990. void () TeamCaptureRegenFlags =
  991. {
  992.     local entity f;
  993.  
  994.     f = find(world, classname, "item_flag_team1");
  995.     if (f != world)
  996.         RegenFlag(f);
  997.     f = find(world, classname, "item_flag_team2");
  998.     if (f != world)
  999.         RegenFlag(f);
  1000. };
  1001.  
  1002. void(entity flg) TeamDropFlag =
  1003. {
  1004.     local entity item, f, oself;
  1005.     local entity p;
  1006.  
  1007.     p = flg.owner;
  1008.  
  1009.     bprint(p.netname);
  1010.     if (p.lastteam == TEAM_COLOR1 + 1)
  1011.         bprint(" ∞∩≤⌠ the ┬╠╒┼ flag!\n"); // blue
  1012.     else
  1013.         bprint(" ∞∩≤⌠ the ╥┼─ flag!\n"); // red
  1014.     LogMsg(p, "FLAG-DROP");
  1015.  
  1016.     flg.origin = p.origin - '0 0 24';
  1017.     flg.cnt = FLAG_DROPPED;
  1018.     //NOTE! We check lastteam here instead of team--this is because
  1019.     //in the mode where we change colors, we get killed
  1020.     flg.velocity_z = 300;
  1021.     flg.velocity_x = 0;
  1022.     flg.velocity_y = 0;
  1023.     flg.flags = FL_ITEM;
  1024.     flg.solid = SOLID_TRIGGER;
  1025.     flg.movetype = MOVETYPE_TOSS;
  1026.     if (teamplay & TEAM_CAPTURE_CUSTOM)
  1027.         setsize(flg, '-16 -16 0', '16 16 74');
  1028.     else
  1029.         setsize(flg, '-16 -16 -24', '16 16 32');
  1030.     // return it after so long
  1031.     flg.super_time = time + TEAM_CAPTURE_FLAG_RETURN_TIME;
  1032. };
  1033.  
  1034. void(entity player) TeamCaptureDropFlagOfPlayer =
  1035. {
  1036.     local string kn;
  1037.     local entity e;
  1038.  
  1039.     if (!(player.player_flag & ITEM_ENEMY_FLAG))
  1040.         return;
  1041.     if (player.lastteam == TEAM_COLOR1 + 1) 
  1042.         kn = "item_flag_team2";
  1043.     else
  1044.         kn = "item_flag_team1";
  1045.     player.player_flag = player.player_flag - ITEM_ENEMY_FLAG;
  1046.     e = find(world, classname, kn);
  1047.     if (e != world)
  1048.         TeamDropFlag(e);
  1049. };
  1050.  
  1051. void(float force_update) TeamCaptureCheckUpdate;        // CTFBOT EXTRAS
  1052.  
  1053.  
  1054. void() TeamCaptureFlagTouch =
  1055. {
  1056.     local entity p, oself;
  1057.  
  1058.     if (other.classname != "player" && other.classname != "bot")    // CTFBOT
  1059.         return;
  1060.     if (other.health <= 0)
  1061.         return;
  1062.  
  1063.     if (other.team != other.lastteam)
  1064.         return; // something is fishy, somebody is playing with colors
  1065.  
  1066.     if (self.team == other.team) {
  1067.         // same team, if the flag is *not* at the base, return
  1068.         // it to base.  we overload the 'cnt' field for this
  1069.         if (self.cnt == FLAG_AT_BASE) {
  1070.             // the flag is at home base.  if the player has the enemy
  1071.             // flag, he's just won!
  1072.  
  1073.             if (other.player_flag & ITEM_ENEMY_FLAG) {
  1074.                 bprint(other.netname);
  1075.                 if (other.team == TEAM_COLOR1 + 1)
  1076.                     bprint(" πß≡⌠⌡≥σΣ the ┬╠╒┼ flag!\n"); // blue
  1077.                 else
  1078.                     bprint(" πß≡⌠⌡≥σΣ the ╥┼─ flag!\n"); // red
  1079.                 LogMsg(other, "FLAG-CAPTURE");
  1080.                 
  1081.                 last_flag_capture = time;    // CTFBOT
  1082.                 last_capture_team = other.team;
  1083.                 
  1084.                 other.items = other.items - (other.items & (IT_KEY1 | IT_KEY2));
  1085.  
  1086.                 if (cvar("teamplay") & TEAM_CAPTURE_CUSTOM)
  1087.                     sound (other, CHAN_AUTO, "misc/flagcap.wav", 1, ATTN_NONE);
  1088.                 else
  1089.                     sound (other, CHAN_AUTO, "doors/meduse.wav", 1, ATTN_NONE);
  1090.  
  1091.                 // other gets another 10 frag bonus
  1092.                 other.frags = other.frags + TEAM_CAPTURE_CAPTURE_BONUS;
  1093.                 
  1094.                 other.num_captures = other.num_captures + 1;        // CTFBOT EXTRAS
  1095.  
  1096.                 // Ok, let's do the player loop, hand out the bonuses
  1097.                 p = find(world, classname, "player");
  1098.                 while (p != world) {
  1099.                     self = p;
  1100.                     self.killed = 0;
  1101.                     if (self.team == other.team && self != other)
  1102.                         self.frags = self.frags + TEAM_CAPTURE_TEAM_BONUS;
  1103.                     if (self.team != other.team) {
  1104.  
  1105.                         if (self.classname == "player")
  1106.                             centerprint(self, "Your flag was captured!\n");
  1107.                         
  1108.                         // *XXX* EXPERT CTF
  1109.                         // reset the last_hurt_carrier variable in all enemy players, so that you don't get
  1110.                         // bonuses for defending the flag carrier if the flag carrier has already
  1111.                         // completed a capture
  1112.                         self.last_hurt_carrier = -5;
  1113.                     } else if (self.team == other.team) {
  1114.                         // done to all players on the capturing team
  1115.                         if (self.classname == "player")
  1116.  
  1117.                             centerprint(self, "Your team captured the flag!\n");
  1118.  
  1119.                         // *XXX* EXPERT CTF
  1120.     
  1121.                         // award extra points for capture assists
  1122.                         if (self.last_returned_flag + TEAM_CAPTURE_RETURN_FLAG_ASSIST_TIMEOUT > time) {
  1123.                             bprint(self.netname);
  1124.                             bprint(" gets an assist for returning his flag!\n");
  1125.                             self.frags = self.frags + TEAM_CAPTURE_RETURN_FLAG_ASSIST_BONUS;
  1126.                             
  1127.                             self.num_assists = self.num_assists + 1;    // CTFBOT EXTRAS
  1128.                         }
  1129.                         if (self.last_fragged_carrier + TEAM_CAPTURE_FRAG_CARRIER_ASSIST_TIMEOUT > time) {
  1130.                             bprint(self.netname);
  1131.                             bprint(" gets an assist for fragging the flag carrier!\n");
  1132.                             self.frags = self.frags + TEAM_CAPTURE_FRAG_CARRIER_ASSIST_BONUS;
  1133.                             
  1134.                             self.num_assists = self.num_assists + 1;    // CTFBOT EXTRAS
  1135.                         }
  1136.                     }
  1137.                     self.player_flag = self.player_flag - (self.player_flag & ITEM_ENEMY_FLAG);
  1138.                     
  1139.                     // CTFBOT replaced find, so we find bots also [[[
  1140.                     if (p.classname == "bot")
  1141.                         p = find(p, classname, "bot");
  1142.                     else
  1143.                     { 
  1144.                         p = find(p, classname, "player");
  1145.                         if (p == world)
  1146.                             p = find(p, classname, "bot");
  1147.                     }
  1148.                     // CTFBOT ]]]
  1149.                 }
  1150.                                 
  1151.                 TeamCaptureCheckUpdate(TRUE);        // CTFBOT EXTRAS immediate score update
  1152.  
  1153.                 // respawn flags
  1154.                 TeamCaptureRegenFlags();
  1155.                 return;
  1156.             }
  1157.             return; // its at home base already
  1158.         }    
  1159.         // hey, its not home.  return it by teleporting it back
  1160.         bprint(other.netname);
  1161.         if (other.team == TEAM_COLOR1 + 1)
  1162.             bprint(" ≥σ⌠⌡≥εσΣ the ╥┼─ flag!\n"); // red
  1163.         else
  1164.             bprint(" ≥σ⌠⌡≥εσΣ the ┬╠╒┼ flag!\n"); // blue
  1165.         LogMsg(other, "FLAG-RECOVERY");
  1166.         other.frags = other.frags + TEAM_CAPTURE_RECOVERY_BONUS;
  1167.         
  1168.         other.num_recovery = other.num_recovery + 1;        // CTFBOT EXTRAS
  1169.         
  1170.         // *XXX* EXPERT CTF set time when player last returned his flag
  1171.         other.last_returned_flag = time;
  1172.         sound (other, CHAN_AUTO, self.noise1, 1, ATTN_NONE);    // CTFBOT EXTRAS changed to ATTN_NONE
  1173.         TeamCaptureReturnFlag(self);
  1174.         return;
  1175.     }
  1176.  
  1177.     // CTFBOT [[[
  1178.     // if we get here, the flag is the enemy flag
  1179.     if ((teamplay & TEAM_CAPTURE_NO_BOT_FLAG_PICKUP) && (other.classname == "bot"))
  1180.         return;        // if no bot pickup, bots can't get enemy flag
  1181.     // CTFBOT ]]]
  1182.  
  1183.     // hey, its not our flag, pick it up
  1184.     bprint(other.netname);
  1185.     if (other.team == TEAM_COLOR1 + 1)
  1186.         bprint(" τ∩⌠ the ┬╠╒┼ flag!\n"); // blue
  1187.     else
  1188.         bprint(" τ∩⌠ the ╥┼─ flag!\n"); // red
  1189.     LogMsg(other, "FLAG-PICKUP");
  1190.     if (TEAM_CAPTURE_FLAG_BONUS)
  1191.         other.frags = other.frags + TEAM_CAPTURE_FLAG_BONUS;
  1192.         
  1193.     other.num_pickups = other.num_pickups + 1;        // CTFBOT EXTRAS
  1194.  
  1195.     if (other.classname == "player")        // CTFBOT    
  1196.     //    centerprint(other, "YOU GOT THE ENEMY FLAG\n\nRETURN TO BASE\n");
  1197.         centerprint(other, "┘╧╒ ╟╧╘ ╘╚┼ ┼╬┼═┘ ╞╠┴╟\n\n╥┼╘╒╥╬ ╘╧ ┬┴╙┼\n");
  1198.         
  1199.     sound (other, CHAN_AUTO, self.noise, 1, ATTN_NONE);        // CTFBOT EXTRAS changed to ATTN_NONE
  1200.  
  1201.     other.player_flag = other.player_flag + ITEM_ENEMY_FLAG;
  1202.     other.items = other.items | self.items;
  1203.  
  1204.     // *XXX* EXPERT CTF set the time at which the carrier picked up the flag
  1205.     other.flag_since = time;
  1206.  
  1207.     // pick up the flag
  1208.     self.cnt = FLAG_CARRIED;
  1209.     self.movetype = MOVETYPE_NOCLIP;
  1210.     self.solid = SOLID_NOT;
  1211.     self.owner = other;
  1212.  
  1213.     last_flag_pickup = time;    // CTFBOT
  1214.     last_pickup_team = other.team;
  1215.  
  1216.     p = find(world, classname, "player");
  1217.     while (p != world) {
  1218.         if (p != other) {
  1219.             if (p.team != other.team)
  1220.                 centerprint(p, "Your flag has been taken!\n");
  1221.             else if (p.team == other.team)
  1222.                 centerprint(p, "Your team has the enemy flag!\n");
  1223.         }
  1224.         p = find(p, classname, "player");
  1225.     }
  1226. };
  1227.  
  1228. void() TeamCaptureFlagThink =
  1229. {
  1230.     local entity e;
  1231.     local vector v;
  1232.     local float f;
  1233.     local string s;
  1234.  
  1235.     self.nextthink = time + 0.1;
  1236.  
  1237.     if (self.cnt == FLAG_AT_BASE)
  1238.         return; // just sitting around waiting to be picked up
  1239.  
  1240.     if (self.cnt == FLAG_DROPPED) {
  1241.         if (time - self.super_time > TEAM_CAPTURE_FLAG_RETURN_TIME)
  1242.             TeamCaptureReturnFlag(self);
  1243.         return;
  1244.     }
  1245.  
  1246.     if (self.cnt != FLAG_CARRIED)
  1247.         objerror("Flag in invalid state\n");
  1248.  
  1249.     e = self.owner;
  1250.     if ((e.classname != "player" && e.classname != "bot") || (e.deadflag) ||   // CTFBOT
  1251.         (!(e.player_flag & ITEM_ENEMY_FLAG))) {
  1252.         TeamDropFlag(self);
  1253.         return;
  1254.     }
  1255.     makevectors (e.angles);
  1256.     v = v_forward;
  1257. //dprint("fwd: ");
  1258. //s = vtos(v);
  1259. //dprint(s);
  1260. //dprint("\n");
  1261. //    if (v_z < 0) { 
  1262. //        v_z = (-1)*v_z; 
  1263. //        v = v + v * 1.2 * v_z; 
  1264. //    }
  1265. //dprint("adj: ");
  1266. //s = vtos(v);
  1267. //dprint(s);
  1268. //dprint("\n");
  1269.     v_z = (-1) * v_z; // reverse z component
  1270.  
  1271.     f = 14;
  1272.     if (self.owner.frame >= 29 && self.owner.frame <= 40) {
  1273.         if (self.owner.frame >= 29 && self.owner.frame <= 34) { //axpain
  1274.             if      (self.owner.frame == 29) f = f + 2; 
  1275.             else if (self.owner.frame == 30) f = f + 8;
  1276.             else if (self.owner.frame == 31) f = f + 12;
  1277.             else if (self.owner.frame == 32) f = f + 11;
  1278.             else if (self.owner.frame == 33) f = f + 10;
  1279.             else if (self.owner.frame == 34) f = f + 4;
  1280.         } else if (self.owner.frame >= 35 && self.owner.frame <= 40) { // pain
  1281.             if      (self.owner.frame == 35) f = f + 2; 
  1282.             else if (self.owner.frame == 36) f = f + 10;
  1283.             else if (self.owner.frame == 37) f = f + 10;
  1284.             else if (self.owner.frame == 38) f = f + 8;
  1285.             else if (self.owner.frame == 39) f = f + 4;
  1286.             else if (self.owner.frame == 40) f = f + 2;
  1287.         }
  1288.     } else if (self.owner.frame >= 103 && self.owner.frame <= 118) {
  1289.         if      (self.owner.frame >= 103 && self.owner.frame <= 104) f = f + 6;  //nailattack
  1290.         else if (self.owner.frame >= 105 && self.owner.frame <= 106) f = f + 6;  //light 
  1291.         else if (self.owner.frame >= 107 && self.owner.frame <= 112) f = f + 7;  //rocketattack
  1292.         else if (self.owner.frame >= 112 && self.owner.frame <= 118) f = f + 7;  //shotattack
  1293.     }
  1294.     self.origin = e.origin + '0 0 -16' - f*v + v_right * 22;
  1295.     self.angles = e.angles + '0 0 -45';
  1296.     setorigin (self, self.origin);
  1297.     self.nextthink = time + 0.01;
  1298. };
  1299.  
  1300. // self is player
  1301. entity() TeamCaptureSpawn =
  1302. {
  1303.     
  1304.     if (!(teamplay & TEAM_CAPTURE_FLAG))
  1305.         return world;
  1306.  
  1307.     if (self.team == TEAM_COLOR1 + 1) {
  1308.         team1_lastspawn = find(team1_lastspawn, classname, "info_player_team1");
  1309.         if (team1_lastspawn == world)
  1310.             team1_lastspawn = find(team1_lastspawn, classname, "info_player_team1");
  1311.         return team1_lastspawn;
  1312.     } else if (self.team == TEAM_COLOR2 + 1) {
  1313.         team2_lastspawn = find(team2_lastspawn, classname, "info_player_team2");
  1314.         if (team2_lastspawn == world)
  1315.             team2_lastspawn = find(team2_lastspawn, classname, "info_player_team2");
  1316.         return team2_lastspawn;
  1317.     }
  1318.     return world;
  1319. };
  1320.  
  1321. /*
  1322.     From byron@caseware.com Wed Oct 16 18:57:44 1996
  1323.     Date: Wed, 16 Oct 1996 21:22:37 -0400
  1324.     From: Byron Long <byron@caseware.com>
  1325.     To: zoid@mindlink.net
  1326.     Subject: Team Status Command (source code included) :-)
  1327.  
  1328.     A co-worker of mine wondered if it was possible to add a function to
  1329.     your capture the flag code that would give a status report on an
  1330.     impulse. I think he may have mailed you, but I wrote a quick version
  1331.     myself, which your welcome to use if you like the feature (it offsets
  1332.     some of the problems with the chat capabilities in Quake so it seems
  1333.     like a worthwhile feature). Feel free to change it
  1334.     as necessary.
  1335. */
  1336.  
  1337. // *Capture The Flag - Status report by Wonko
  1338. void() TeamFlagStatusReport =
  1339. {
  1340.     local entity flag1, flag2, p;
  1341.  
  1342.     // CTFBOT [[[
  1343.     // no status for anything but players
  1344.     if (self.classname != "player")
  1345.         return;    
  1346.         
  1347.     // DTF [[[
  1348.     if (teamplay & TEAM_DAMAGE_THE_FLAG)
  1349.     {
  1350.         flag1 = find (world,classname, "item_flag_team1");
  1351.         flag2 = find (world,classname, "item_flag_team2");
  1352.         
  1353.         if (self.team == TEAM_COLOR1 + 1)
  1354.         {
  1355.             sprint2("Your flag has ");
  1356.             sprintfloat(self, flag1.health);
  1357.             sprint2(" health\n");
  1358.             sprint2("The enemy flag has ");
  1359.             sprintfloat(self, flag2.health);
  1360.             sprint2(" health\n");
  1361.         }
  1362.         else if (self.team == TEAM_COLOR2 + 1)
  1363.         {
  1364.             sprint2("Your flag has ");
  1365.             sprintfloat(self, flag2.health);
  1366.             sprint2(" health\n");
  1367.             sprint2("The enemy flag has ");
  1368.             sprintfloat(self, flag1.health);
  1369.             sprint2(" health\n");
  1370.         }
  1371.         return;
  1372.     }
  1373.     // DTF ]]]
  1374.         
  1375.     // CTFBOT ]]]
  1376.  
  1377.     if (!(teamplay & TEAM_CAPTURE_FLAG)) {
  1378.         sprint(self, "Capture the Flag is not enabled.\n");
  1379.         return;
  1380.     }
  1381.  
  1382.     // Find the flags at home base
  1383.     flag1 = find (world,classname, "item_flag_team1");
  1384.     flag2 = find (world,classname, "item_flag_team2");
  1385.  
  1386.     // If on team 2 switch meanings of flags
  1387.     if (self.team != TEAM_COLOR1 + 1) {
  1388.         p = flag1;
  1389.         flag1 = flag2;
  1390.         flag2 = p;
  1391.     }
  1392.  
  1393.     if (flag1 != world && flag1.cnt == FLAG_CARRIED) {
  1394.         sprint(self, flag1.owner.netname);
  1395.         sprint(self, " has your flag. ");
  1396.     } else {
  1397.         sprint(self, "Your flag is ");
  1398.         if (flag1 == world)
  1399.             sprint(self, "missing!\n");            // CTFBOT EXTRAS added '\n' for better readability
  1400.         else if (flag1.cnt == FLAG_AT_BASE)        // CTFBOT EXTRAS added else
  1401.             sprint(self, "in your base.\n");    // CTFBOT EXTRAS added '\n' for better readability
  1402.         else if (flag1.cnt == FLAG_DROPPED)
  1403.             sprint(self, "lying about.\n");        // CTFBOT EXTRAS added '\n' for better readability
  1404.         else
  1405.             sprint(self, " corrupt.\n");        // CTFBOT EXTRAS added '\n' for better readability
  1406.     }    
  1407.  
  1408.     if (flag2 != world && flag2.cnt == FLAG_CARRIED) {
  1409.         if (self == flag2.owner) 
  1410.             sprint(self, "You have the enemy flag.\n");
  1411.         else {
  1412.             sprint(self, flag2.owner.netname);
  1413.             sprint(self, " has the enemy flag.\n");
  1414.         }
  1415.     } else {
  1416.         sprint(self, "The enemy flag is ");
  1417.         if (flag2 == world)
  1418.             sprint(self, "missing!\n");
  1419.         else if (flag2.cnt == FLAG_AT_BASE)        // CTFBOT EXTRAS added else
  1420.             sprint(self, "in their base.\n");
  1421.         else if (flag2.cnt == FLAG_DROPPED)
  1422.             sprint(self, "lying about.\n");
  1423.         else
  1424.             sprint(self, " corrupt.\n");
  1425.     }
  1426. };
  1427.  
  1428. /////////////////////////////////////////////////////////////////////////
  1429.  
  1430. $cd id1/models/flag
  1431. $base base
  1432. $skin skin
  1433.  
  1434. void() place_flag = {
  1435.     self.mdl = self.model;        // so it can be restored on respawn
  1436.     self.flags = FL_ITEM;        // make extra wide
  1437.     self.movetype = MOVETYPE_TOSS;    
  1438.     self.velocity = '0 0 0';
  1439.     self.origin_z = self.origin_z + 6;
  1440.     
  1441.     // CTFBOT DTF [[[
  1442.     if (teamplay & TEAM_DAMAGE_THE_FLAG)
  1443.     {
  1444.         self.takedamage = DAMAGE_AIM;
  1445.         self.solid = SOLID_SLIDEBOX;
  1446.         self.deadflag = DEAD_NO;
  1447.         self.health = FLAG_INITIAL_HEALTH;
  1448.         self.max_health = FLAG_MAX_HEALTH;
  1449.  
  1450.         self.touch = DTFFlagTouch;
  1451.         self.th_pain = DTFFlagPain;
  1452.         self.th_die = DTFFlagDie;
  1453.  
  1454.         self.lastteam = self.team;
  1455.     }
  1456.     // CTFBOT DTF ]]]
  1457.     else
  1458.     {
  1459.         self.solid = SOLID_TRIGGER;
  1460.         self.think = TeamCaptureFlagThink;
  1461.         self.touch = TeamCaptureFlagTouch;
  1462.         self.nextthink = time + 0.1;
  1463.     }
  1464.     
  1465.     self.cnt = FLAG_AT_BASE;
  1466.     self.bot_wants_item = TRUE;        // CTFBOT optimization
  1467.     self.mangle = self.angles;
  1468.     self.effects = self.effects | EF_DIMLIGHT;
  1469.     if (!droptofloor()) {
  1470.         dprint ("Flag fell out of level at ");
  1471.         dprint (vtos(self.origin));
  1472.         dprint ("\n");
  1473.         dprint ("flag removed\n");    // CTFBOT EXTRAS
  1474.  
  1475.         remove(self);
  1476.         return;
  1477.     }
  1478.     self.oldorigin = self.origin; // save for flag return
  1479. };
  1480.  
  1481. // ZOID Capture the flag
  1482. void() item_flag_team1 =
  1483. {
  1484.     if (!deathmatch || !(cvar("teamplay") & TEAM_CAPTURE_FLAG)) {
  1485.         remove(self);
  1486.         return;
  1487.     }
  1488.  
  1489.     self.team = TEAM_COLOR1 + 1;
  1490.     self.enemy_team = TEAM_COLOR2 + 1;        // CTFBOT DTF
  1491.     self.items = IT_KEY2;
  1492.     if (cvar("teamplay") & TEAM_CAPTURE_CUSTOM) {
  1493.         precache_model ("progs/flag.mdl");
  1494.         setmodel (self, "progs/flag.mdl");
  1495.         self.skin = 0;
  1496.         precache_sound ("misc/flagtk.wav");            // flag taken
  1497.         precache_sound ("misc/flagcap.wav");            // flag capture
  1498.         precache_sound ("doors/runetry.wav");
  1499.         self.noise = "misc/flagtk.wav";
  1500.         self.noise1 = "doors/runetry.wav";
  1501.         setsize(self, '-16 -16 0', '16 16 74');
  1502.     } else {
  1503.         precache_model ("progs/w_g_key.mdl");
  1504.         setmodel (self, "progs/w_g_key.mdl");
  1505.         precache_sound ("misc/medkey.wav");
  1506.         precache_sound ("doors/meduse.wav");
  1507.         precache_sound ("doors/runetry.wav");
  1508.         self.noise = "misc/medkey.wav";
  1509.         self.noise1 = "doors/runetry.wav";
  1510.         setsize(self, '-16 -16 -24', '16 16 32');
  1511.     }
  1512.     self.nextthink = time + 0.2;    // items start after other solids
  1513.     self.think = place_flag;
  1514. };
  1515.  
  1516. void() item_flag_team2 =
  1517. {
  1518.     if (!deathmatch || !(cvar("teamplay") & TEAM_CAPTURE_FLAG)) {
  1519.         remove(self);
  1520.         return;
  1521.     }
  1522.  
  1523.     self.team = TEAM_COLOR2 + 1;
  1524.     self.enemy_team = TEAM_COLOR1 + 1;        // CTFBOT DTF
  1525.     self.items = IT_KEY1;
  1526.     if (cvar("teamplay") & TEAM_CAPTURE_CUSTOM) {
  1527.         precache_model ("progs/flag.mdl");
  1528.         setmodel (self, "progs/flag.mdl");
  1529.         self.skin = 1;
  1530.         precache_sound ("misc/flagtk.wav");            // flag taken
  1531.         precache_sound ("misc/flagcap.wav");            // flag capture
  1532.         precache_sound ("doors/runetry.wav");
  1533.         self.noise = "misc/flagtk.wav";
  1534.         self.noise1 = "doors/runetry.wav";
  1535.         setsize(self, '-16 -16 0', '16 16 74');
  1536.     } else {
  1537.         precache_model ("progs/w_s_key.mdl");
  1538.         setmodel (self, "progs/w_s_key.mdl");
  1539.         precache_sound ("misc/medkey.wav");
  1540.         precache_sound ("doors/meduse.wav");
  1541.         precache_sound ("doors/runetry.wav");
  1542.         self.noise = "misc/medkey.wav";
  1543.         self.noise1 = "doors/runetry.wav";
  1544.         setsize(self, '-16 -16 -24', '16 16 32');
  1545.     }
  1546.     // make it glow
  1547.     self.nextthink = time + 0.2;    // items start after other solids
  1548.     self.think = place_flag;
  1549. };
  1550.  
  1551. void() TeamCaptureSetUpdate = 
  1552. {
  1553.     nextteamupdtime = time + TEAM_CAPTURE_UPDATE_TIME;
  1554. };
  1555.  
  1556. void(float force_update) TeamCaptureCheckUpdate =        // CTFBOT EXTRAS
  1557. {
  1558.     local float total1, total2;
  1559.     local entity p;
  1560.     local string s;
  1561.     
  1562.     // CTFBOT DTF [[[
  1563.     if (teamplay & TEAM_DAMAGE_THE_FLAG)
  1564.         return;
  1565.     // CTFBOT DTF ]]]
  1566.  
  1567.     if (((nextteamupdtime) > time && (!force_update)) || !(teamplay & TEAM_CAPTURE_FLAG))        // CTFBOT EXTRAS
  1568.         return;
  1569.  
  1570.     TeamCaptureSetUpdate();
  1571.  
  1572.     // count up total
  1573.     total1 = total2 = 0;
  1574.     p = find(world, classname, "player");
  1575.     while (p != world) {
  1576.         if (p.lastteam == TEAM_COLOR1 + 1)
  1577.             total1 = total1 + p.frags;
  1578.         else if (p.lastteam == TEAM_COLOR2 + 1)
  1579.             total2 = total2 + p.frags;
  1580.     
  1581.         // CTFBOT replaced find, so we find bots also [[[
  1582.         if (p.classname == "bot")
  1583.             p = find(p, classname, "bot");
  1584.         else
  1585.         { 
  1586.             p = find(p, classname, "player");
  1587.             if (p == world)
  1588.                 p = find(p, classname, "bot");
  1589.         }
  1590.         // CTFBOT ]]]
  1591.     }
  1592.  
  1593.     if (total1 > total2) {
  1594.         bprint("╥┼─ team is leading by ");
  1595.         s = ftos(total1 - total2);
  1596.         bprint(s);
  1597.         bprint(" points!\n");
  1598.     } else if (total1 < total2) {
  1599.         bprint("┬╠╒┼ team is leading by ");
  1600.         s = ftos(total2 - total1);
  1601.         bprint(s);
  1602.         bprint(" points!\n");
  1603.     } else {
  1604.         bprint("┬╠╒┼ and ╥┼─ team are tied with ");
  1605.         s = ftos(total1);
  1606.         bprint(s);
  1607.         bprint(" points!\n");
  1608.     }
  1609. };
  1610.  
  1611. /*QUAKED func_ctf_wall (0 .5 .8) ?
  1612. This is just a solid wall if not inhibitted
  1613. Only appears in CTF teamplay
  1614. */
  1615. void() func_ctf_wall =
  1616. {
  1617.     if (cvar("teamplay") & TEAM_CAPTURE_FLAG) {
  1618.         self.angles = '0 0 0';
  1619.         self.movetype = MOVETYPE_PUSH;    // so it doesn't get pushed by anything
  1620.         self.solid = SOLID_BSP;
  1621.         setmodel (self, self.model);
  1622.     } else
  1623.         remove(self);
  1624. };
  1625.  
  1626.