teamplay.qc 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887
  1. /* Copyright (C) 1996-2022 id Software LLC
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  13. See file, 'COPYING', for details.
  14. */
  15. // Rogue Teamplay Variants
  16. // Jan'97 by ZOID <zoid@threewave.com>
  17. // Under contract to id software for Rogue Entertainment
  18. // New entity fields
  19. .float steam; // selected team
  20. .float suicide_count; // how many times has this player done something silly?
  21. .float ctf_flags; // various flags for CTF
  22. .float ctf_killed; // used for base spawning
  23. .float ctf_flagsince; // when we picked up the flag
  24. .float ctf_lasthurtcarrier; // when we last hurt the carrier
  25. .float ctf_lastreturnedflag; // when we returned the flag
  26. .float ctf_lastfraggedcarrier; // when we last fragged the carrier
  27. float TEAM1 = 5; // color of team1 (red), note that this is self.team which
  28. //is one more than the color setting, so 'color 4' is red.
  29. float TEAM2 = 14; // color of team2 (blue), note that this is self.team which
  30. //is one more than the color setting, so 'color 13' is blue.
  31. float TEAM3 = 1; // color of team3 (grey) in alt CTF
  32. entity team1_lastspawn; // last spawn spot for team1
  33. entity team2_lastspawn; // last spawn spot for team2
  34. float nextteamupdtime; // next time for a broadcast update
  35. // TEAMPLAY VALUES
  36. float TEAM_NORMAL_NODAMAGE = 1; // id's normal teamplay, can't hurt self
  37. float TEAM_NORMAL_DAMAGE = 2; // id's alt teamplay, can hurt self/team
  38. float TEAM_DMATCH_TAG = 3; // deathmatch tag, no 'team' stuff
  39. float TEAM_CTF = 4; // regular CTF, locked colors
  40. float TEAM_CTF_ONEFLAG = 5; // one flag CTF
  41. float TEAM_CTF_ALT = 6; // alternate CTF (three teams)
  42. // gamecfg cvar fields
  43. float GAMECFG_ENABLE_RUNES = 1; // enable runes (default is disabled)
  44. float GAMECFG_TEAM_ARMOR_DMG = 2; // 2 team damage affects armor (default is not)
  45. float GAMECFG_TEAM_HEALTH_DMG = 4; // 4 team damage affects health (default is not)
  46. float GAMECFG_USE_COLOR = 8; // use color player joins as (if you join and start with blue, you will go
  47. // to blue team, same with red/green. If you are an illegal color, you'll
  48. // get assigned).
  49. float GAMECFG_ALLOW_CHG = 16; // allow people to change teams
  50. float CTF_CAPTURE_BONUS = 15; // what you get for capture
  51. float CTF_TEAM_BONUS = 10; // what your team gets for capture
  52. float CTF_ALT_CAPTURE_BONUS = 8; // what you get for capture
  53. float CTF_ALT_TEAM_BONUS = 4; // what your team gets for capture
  54. float CTF_RECOVERY_BONUS = 1; // what you get for recovery
  55. float CTF_FLAG_BONUS = 0; // what you get for picking up enemy flag
  56. float CTF_FRAG_CARRIER_BONUS = 2; // what you get for fragging enemy flag carrier
  57. float CTF_FLAG_RETURN_TIME = 40; // seconds until auto return
  58. float CTF_CARRIER_DANGER_PROTECT_BONUS = 2; // bonus for fraggin someone
  59. // who has recently hurt your flag carrier
  60. float CTF_CARRIER_PROTECT_BONUS = 1; // bonus for fraggin someone while
  61. // either you or your target are near your flag carrier
  62. float CTF_FLAG_DEFENSE_BONUS = 1; // bonus for fraggin someone while
  63. // either you or your target are near your flag
  64. float CTF_RETURN_FLAG_ASSIST_BONUS = 1; // awarded for returning a flag that causes a
  65. // capture to happen almost immediately
  66. float CTF_FRAG_CARRIER_ASSIST_BONUS = 2; // award for fragging a flag carrier if a
  67. // capture happens almost immediately
  68. float CTF_TARGET_PROTECT_RADIUS = 400; // the radius around an object being
  69. // defended where a target will be worth extra frags
  70. float CTF_ATTACKER_PROTECT_RADIUS = 400; // the radius around an object being
  71. // defended where an attacker will get extra frags when making kills
  72. float CTF_CARRIER_DANGER_PROTECT_TIMEOUT = 4;
  73. float CTF_CARRIER_FLAG_SINCE_TIMEOUT = 2;
  74. float CTF_FRAG_CARRIER_ASSIST_TIMEOUT = 6;
  75. float CTF_RETURN_FLAG_ASSIST_TIMEOUT = 4;
  76. float CTF_UPDATE_TIME = 120;
  77. // CTF flags
  78. float CTF_FLAG_FLAG = 1; // palyer has flag in one flag mode
  79. float CTF_FLAG_TEAM1 = 1; // player has team1's flag
  80. float CTF_FLAG_TEAM2 = 2; // player has team2's flag
  81. float CTF_FLAG_STUFF_COLOR = 4; // gotta stuff his color
  82. // flag status used in cnt field of flag
  83. float FLAG_AT_BASE = 0;
  84. float FLAG_CARRIED = 1;
  85. float FLAG_DROPPED = 2;
  86. // Prototypes
  87. float() W_BestWeapon;
  88. void() W_SetCurrentAmmo;
  89. void() bound_other_ammo;
  90. void(float o, float n) Deathmatch_Weapon;
  91. void() BackpackTouch;
  92. void(entity comboOwner) EnableComboWeapons;
  93. // Return a name for the color of a team
  94. string(float Team) GetTeamColor =
  95. {
  96. if(Team == 1) return("White");
  97. else if(Team == 2) return("Brown");
  98. else if(Team == 3) return("Light blue");
  99. else if(Team == 4) return("Green");
  100. else if(Team == 5) return("Red");
  101. else if(Team == 6) return("Olive");
  102. else if(Team == 7) return("Orange");
  103. else if(Team == 8) return("Peech");
  104. else if(Team == 9) return("Purple");
  105. else if(Team == 10) return("Majenta");
  106. else if(Team == 11) return("Grey");
  107. else if(Team == 12) return("Aqua");
  108. else if(Team == 13) return("Yellow");
  109. else if(Team == 14) return("Blue");
  110. return "Unknown";
  111. };
  112. string(float Team) GetCTFTeam =
  113. {
  114. if (Team == TEAM1) return "���";
  115. else if (Team == TEAM2) return "����";
  116. else if (Team == TEAM3) return "����";
  117. return "UNKNOWN";
  118. };
  119. /*
  120. ================
  121. TeamArmorDam
  122. Return TRUE if the target's armor can take damage from this attacker.
  123. ================
  124. */
  125. float(entity targ, entity inflictor, entity attacker, float damage) TeamArmorDam =
  126. {
  127. if (teamplay <= 0)
  128. return TRUE; // PGM bug? fix
  129. // teamplay modes 4,5,6 protect armor
  130. if ((teamplay == TEAM_CTF ||
  131. teamplay == TEAM_CTF_ONEFLAG ||
  132. teamplay == TEAM_CTF_ALT) &&
  133. attacker.steam == targ.steam &&
  134. attacker != targ &&
  135. !(cvar("gamecfg") & GAMECFG_TEAM_ARMOR_DMG)) {
  136. // Armor is protected
  137. return FALSE;
  138. }
  139. return TRUE;
  140. };
  141. /*
  142. ================
  143. TeamHealthDam
  144. Return TRUE if the target can take health damage from this attacker.
  145. ================
  146. */
  147. float(entity targ, entity inflictor, entity attacker, float damage) TeamHealthDam =
  148. {
  149. if (teamplay <= 0)
  150. return TRUE;
  151. if (teamplay == TEAM_NORMAL_NODAMAGE && attacker.steam == targ.steam)
  152. return FALSE;
  153. // teamplay modes 4,5,6 protect health
  154. if ((teamplay == TEAM_CTF ||
  155. teamplay == TEAM_CTF_ONEFLAG ||
  156. teamplay == TEAM_CTF_ALT) &&
  157. attacker.steam == targ.steam &&
  158. attacker != targ &&
  159. !(cvar("gamecfg") & GAMECFG_TEAM_HEALTH_DMG)) {
  160. // Health is protected
  161. return FALSE;
  162. }
  163. return TRUE;
  164. };
  165. void(entity who) TeamResetCarrier =
  166. {
  167. local entity head;
  168. // When the flag carrier dies, reset the last_hurt_carrier field in
  169. // all players on the opposite team from the flag carrier. The carrier
  170. // has been killed, so there is no longer a reason to award points for
  171. // killing off his assailants
  172. if (teamplay >= TEAM_CTF &&
  173. (who.ctf_flags & (CTF_FLAG_TEAM1 | CTF_FLAG_TEAM2))) {
  174. head = find(world, classname, "player");
  175. while (head != world) {
  176. if (teamplay == TEAM_CTF_ONEFLAG ||
  177. ((who.ctf_flags & CTF_FLAG_TEAM1) && head.steam == TEAM1) ||
  178. ((who.ctf_flags & CTF_FLAG_TEAM2) && head.steam == TEAM2))
  179. head.ctf_lasthurtcarrier = -10;
  180. head = find(head, classname, "player");
  181. }
  182. }
  183. };
  184. void(entity targ, entity attacker) TeamAssists =
  185. {
  186. local float flag_radius;
  187. local float flag_carrier_radius;
  188. local string s;
  189. local entity head;
  190. if ((targ.ctf_flags & (CTF_FLAG_TEAM1 | CTF_FLAG_TEAM2)) &&
  191. targ.steam != attacker.steam) {
  192. //ZOID: one team fragged the other team's flag carrier
  193. // Mark the attacker with the time at which he killed the flag
  194. // carrier, for awarding assist points
  195. attacker.ctf_lastfraggedcarrier = time;
  196. // give player only the normal amount of frags
  197. // if the carrier has only had the flag for a few seconds, to
  198. // prevent ppl intentionally allowing enemies to grab the flag,
  199. // then immediately fragging them
  200. if (targ.ctf_flagsince + CTF_CARRIER_FLAG_SINCE_TIMEOUT > time) {
  201. sprint(attacker, "$qc_enemy_killed_no_bonus");
  202. } else {
  203. attacker.frags = attacker.frags + CTF_FRAG_CARRIER_BONUS;
  204. s = ftos(CTF_FRAG_CARRIER_BONUS);
  205. sprint(attacker, "$qc_enemy_killed_bonus", s);
  206. }
  207. }
  208. // This code checks for all game-critical kills OTHER THAN fragging the enemy
  209. // flag carrier, like killing players who are trying to kill your flag carrier
  210. // or trying to grab your flag, and hands out bonus frags.
  211. // The two variables below track whether special bonus frags have already
  212. // been awarded for the attacker or target being near the flag or flag carrier.
  213. flag_radius = 0;
  214. flag_carrier_radius = 0;
  215. // get a string for the attacker's team now, for later announcements
  216. s = GetCTFTeam(attacker.steam);
  217. if ((targ.ctf_lasthurtcarrier + CTF_CARRIER_DANGER_PROTECT_TIMEOUT > time) &&
  218. !(attacker.ctf_flags & (CTF_FLAG_TEAM1 | CTF_FLAG_TEAM2))) {
  219. // a player on the same team as the flag carrier killed
  220. // someone who recently shot the flag carrier
  221. attacker.frags = attacker.frags + CTF_CARRIER_DANGER_PROTECT_BONUS;
  222. flag_carrier_radius = 1;
  223. // NOTE: getting CARRIER_DANGER_PROTECT_BONUS precludes getting
  224. // other kinds of bonuses for defending the flag carrier, since
  225. // it's worth more points
  226. bprint("$qc_defend_flag_carrier_aggressive", attacker.netname, s);
  227. }
  228. // Bonusus for defending the flag carrier or the flag itself.
  229. // Extra frags are awarded if either the attacker or the target are
  230. // 1. within 40 feet of a flag carrier on the same team as the attacker
  231. // 2. within 40 feet of the attacker's flag
  232. // These bonuses are cumulative with respect to defending both the
  233. // flag and the flag carrier at the same time, but not cumulative with
  234. // respect to both the target and attacker being near the object being defended
  235. // find flags or flag carriers within a radius of the attacker
  236. head = findradius(attacker.origin, CTF_ATTACKER_PROTECT_RADIUS);
  237. while (head) {
  238. if (head.classname == "player") {
  239. if ( (head.steam == attacker.steam) &&
  240. (head.ctf_flags & (CTF_FLAG_TEAM1 | CTF_FLAG_TEAM2)) &&
  241. (head != attacker) && // self defense
  242. (!flag_carrier_radius) ) {
  243. // attacker was near his own flag carrier
  244. attacker.frags = attacker.frags + CTF_CARRIER_PROTECT_BONUS;
  245. flag_carrier_radius = 1;
  246. bprint("$qc_defend_flag_carrier", attacker.netname, s);
  247. }
  248. }
  249. if ((attacker.steam == TEAM1 && head.classname == "item_flag_team1") ||
  250. (attacker.steam == TEAM2 && head.classname == "item_flag_team2") ||
  251. head.classname == "item_flag") { // one flag mode
  252. // attacker was near his own flag
  253. attacker.frags = attacker.frags + CTF_FLAG_DEFENSE_BONUS;
  254. flag_radius = 1;
  255. if (teamplay != TEAM_CTF_ONEFLAG) {
  256. bprint("$qc_defend_team_flag", attacker.netname, s);
  257. } else {
  258. bprint("$qc_defends_flag", attacker.netname);
  259. }
  260. }
  261. head = head.chain;
  262. }
  263. // find flags or flag carriers within a radius from the target
  264. head = findradius(targ.origin, CTF_TARGET_PROTECT_RADIUS);
  265. while (head) {
  266. if (head.classname == "player") {
  267. if ( (head.steam == attacker.steam) &&
  268. (head.ctf_flags & (CTF_FLAG_TEAM1 | CTF_FLAG_TEAM2)) &&
  269. (head != attacker) &&
  270. (!flag_carrier_radius)) { // prevents redundant points awarded
  271. // target was near attacker's flag carrier
  272. attacker.frags = attacker.frags + CTF_CARRIER_PROTECT_BONUS;
  273. flag_carrier_radius = 1;
  274. bprint("$qc_defend_flag_carrier", attacker.netname, s);
  275. }
  276. }
  277. if ((attacker.steam == TEAM1 && head.classname == "item_flag_team1") ||
  278. (attacker.steam == TEAM2 && head.classname == "item_flag_team2") ||
  279. head.classname == "item_flag" && // one flag mode
  280. (!flag_radius)) { // prevents redundant points awarded
  281. // target was near attacker's flag
  282. attacker.frags = attacker.frags + CTF_FLAG_DEFENSE_BONUS;
  283. flag_radius = 1;
  284. if (teamplay != TEAM_CTF_ONEFLAG) {
  285. bprint("$qc_defend_team_flag", attacker.netname, s);
  286. } else {
  287. bprint("$qc_defends_flag", attacker.netname);
  288. }
  289. }
  290. head = head.chain;
  291. }
  292. };
  293. /*
  294. ==================
  295. TeamColorIsLegal
  296. Return TRUE if the indicated color is legal
  297. ==================
  298. */
  299. float(float color) TeamColorIsLegal =
  300. {
  301. // All colors are legal if teamplay is not CTF
  302. if( teamplay < TEAM_CTF) {
  303. if (color > 0)
  304. return TRUE;
  305. return FALSE;
  306. }
  307. // In regular CTF and CTF_ONEFLAG, only two colors are legal
  308. if (teamplay == TEAM_CTF || teamplay == TEAM_CTF_ONEFLAG)
  309. if (color == TEAM1 || color == TEAM2)
  310. return TRUE;
  311. else
  312. return FALSE;
  313. // In ALT CTF, three colors are legal
  314. if (teamplay == TEAM_CTF_ALT)
  315. if (color == TEAM1 || color == TEAM2 || color == TEAM3)
  316. return TRUE;
  317. else
  318. return FALSE;
  319. // dunno what teamplay we're in, let'em all be ok
  320. return TRUE;
  321. };
  322. /* TeamSetSkin - set the skin of the player model to the
  323. apropriate skin based on team and teamplay settings.
  324. */
  325. void() TeamSetSkin =
  326. {
  327. self.skin = 0;
  328. if (deathmatch)
  329. {
  330. if (teamplay >= TEAM_CTF)
  331. self.skin = 1;
  332. }
  333. /*
  334. if ( deathmatch )
  335. {
  336. if ( teamplay >= TEAM_CTF )
  337. {
  338. // if (self.team == TEAM3)
  339. // self.skin = 2;
  340. // else
  341. self.skin = 1;
  342. }
  343. if ( teamplay < TEAM_CTF )
  344. self.skin = 1;
  345. else
  346. {
  347. if (self.team == TEAM1)
  348. self.skin = 2;
  349. else if (self.team == TEAM2)
  350. self.skin = 3;
  351. else if (self.team == TEAM3)
  352. self.skin = 4;
  353. }
  354. }
  355. */
  356. };
  357. /*
  358. ==================
  359. TeamCheckTeam
  360. Check if the team self is on is legal, and put self in a legal team if not.
  361. ==================
  362. */
  363. void() TeamCheckTeam =
  364. {
  365. local float team1count;
  366. local float team2count;
  367. local float team3count;
  368. local float newcolor;
  369. local float t;
  370. local entity p;
  371. local string n;
  372. if (self.steam >= 0 || teamplay < TEAM_CTF) {
  373. if(TeamColorIsLegal(self.team)) {
  374. self.steam = self.team;
  375. TeamSetSkin();
  376. return;
  377. }
  378. }
  379. // Assign the player to a team.
  380. // Sum the players on all the teams.
  381. team1count = 0;
  382. team2count = 0;
  383. team3count = 0;
  384. p = find (world, classname, "player");
  385. while(p) {
  386. if (p != self) {
  387. if (p.steam == TEAM1)
  388. team1count = team1count + 1;
  389. else if (p.steam == TEAM2)
  390. team2count = team2count + 1;
  391. else if (p.steam == TEAM3)
  392. team3count = team3count + 1;
  393. }
  394. p = find(p, classname, "player");
  395. }
  396. // Find the team with the least players.
  397. newcolor = TEAM1;
  398. t = team1count;
  399. if (team2count < t || (team2count == t && random() < 0.5)) {
  400. newcolor = TEAM2;
  401. t = team2count;
  402. }
  403. // in CTF_ALT, there's three teams
  404. team3count = team3count * 2; // grey team only gets half as many players
  405. if (teamplay == TEAM_CTF_ALT && team3count < t) {
  406. newcolor = TEAM3;
  407. t = team3count;
  408. }
  409. // Put the player on a the new team.
  410. self.ctf_flags = self.ctf_flags | CTF_FLAG_STUFF_COLOR;
  411. n = GetCTFTeam(newcolor);
  412. sprint(self, "$qc_assigned_team", n);
  413. self.steam = newcolor; // Remember what team we're on
  414. self.team = newcolor;
  415. TeamSetSkin();
  416. };
  417. /* Check for team changing and perform whatever actions are neccessary. */
  418. void() TeamCheckLock =
  419. {
  420. local float n;
  421. local string s;
  422. if (!deathmatch || teamplay < TEAM_CTF) {
  423. // all colors are legal, no force
  424. self.steam = self.team;
  425. return;
  426. }
  427. if (self.ctf_flags & CTF_FLAG_STUFF_COLOR) {
  428. self.ctf_flags = self.ctf_flags - CTF_FLAG_STUFF_COLOR;
  429. stuffcmd(self, "color ");
  430. n = self.steam - 1;
  431. s = ftos(n);
  432. stuffcmd(self, s);
  433. stuffcmd(self, "\n");
  434. TeamSetSkin();
  435. return;
  436. }
  437. if (!TeamColorIsLegal(self.team) && self.team == self.steam)
  438. self.steam = -1; // full reset
  439. // Check to see if the player has changed colors
  440. if (self.team != self.steam) {
  441. if (self.steam >= 0) {
  442. if (TeamColorIsLegal(self.steam)) {
  443. if (!(cvar("gamecfg") & GAMECFG_ALLOW_CHG)) {
  444. // changing teams sucks, kill him
  445. // if he has tried to change teams several
  446. // times, kick him off the server.
  447. if (self.suicide_count > 3) {
  448. sprint(self, "$qc_color_games");
  449. stuffcmd(self, "disconnect\n");
  450. bprint("$qc_death_color_sense", self.netname);
  451. }
  452. // case base respawn
  453. if (self.ctf_killed != 1)
  454. self.ctf_killed = 2;
  455. T_Damage(self,self,self,1000); // Kill the player
  456. // trying to change teams counts as a suicide
  457. self.suicide_count = self.suicide_count + 1;
  458. sprint(self, "$qc_cannot_change_teams");
  459. stuffcmd(self, "color ");
  460. n = self.steam - 1;
  461. s = ftos(n);
  462. stuffcmd(self, s);
  463. stuffcmd(self, "\n");
  464. self.team = self.steam;
  465. return;
  466. }
  467. } else {
  468. // If we're on an illegal team, force a change.
  469. self.steam = -50;
  470. }
  471. }
  472. if (self.steam > 0) {
  473. // case base respawn
  474. if (self.ctf_killed != 1)
  475. self.ctf_killed = 2;
  476. T_Damage(self,self,self,1000); // Kill the player
  477. }
  478. self.frags = 0; // Zero out frags
  479. TeamCheckTeam(); // re-assignment
  480. }
  481. };
  482. /* Toss out a backpack containing some ammo from your current weapon,
  483. and any weapons you don't have.
  484. */
  485. void() TossBackpack =
  486. {
  487. local entity item;
  488. // If we don't have any ammo, return
  489. if(self.currentammo <= 0)
  490. return;
  491. // only valid in teamplay modes
  492. if (teamplay < 1)
  493. return;
  494. item = spawn();
  495. // See if you have the Shotgun or Super Shotgun on
  496. if ((self.weapon == IT_SHOTGUN) || (self.weapon == IT_SUPER_SHOTGUN)) {
  497. if( self.ammo_shells1 >= 20 ) {
  498. item.ammo_shells1 = 20;
  499. self.ammo_shells1 = self.ammo_shells1 - 20;
  500. }
  501. else
  502. {
  503. item.ammo_shells1 = self.ammo_shells1;
  504. self.ammo_shells1 = 0;
  505. }
  506. }
  507. // See if you have neither the Shotgun or Super Shotgun
  508. if ( !(self.items & IT_SHOTGUN) && !(self.items & IT_SUPER_SHOTGUN)) {
  509. if( self.ammo_shells1 >= 20 ) {
  510. item.ammo_shells1 = 20;
  511. self.ammo_shells1 = self.ammo_shells1 - 20;
  512. } else {
  513. item.ammo_shells1 = self.ammo_shells1;
  514. self.ammo_shells1 = 0;
  515. }
  516. }
  517. // See if we are using a nailgun
  518. if ((self.weapon == IT_NAILGUN) || (self.weapon == IT_SUPER_NAILGUN) ) {
  519. if( self.ammo_nails1 >= 20 ) {
  520. item.ammo_nails1 = 20;
  521. self.ammo_nails1 = self.ammo_nails1 - 20;
  522. } else {
  523. item.ammo_nails1 = self.ammo_nails1;
  524. self.ammo_nails1 = 0;
  525. }
  526. }
  527. // See if we are using the lava nailguns
  528. if ((self.weapon == IT_LAVA_NAILGUN) || (self.weapon == IT_LAVA_SUPER_NAILGUN) ) {
  529. if( self.ammo_lava_nails >= 20 ) {
  530. item.ammo_lava_nails = 20;
  531. self.ammo_lava_nails = self.ammo_lava_nails - 20;
  532. } else {
  533. item.ammo_lava_nails = self.ammo_lava_nails;
  534. self.ammo_lava_nails = 0;
  535. }
  536. }
  537. // Check to see if we have neither nailgun
  538. if (!(self.items & IT_NAILGUN) && !(self.items & IT_SUPER_NAILGUN)) {
  539. // put both regular and lava nails in
  540. if (self.ammo_nails1 >= 20) {
  541. item.ammo_nails1 = 20;
  542. self.ammo_nails1 = self.ammo_nails1 - 20;
  543. } else {
  544. item.ammo_nails1 = self.ammo_nails1;
  545. self.ammo_nails1 = 0;
  546. }
  547. if( self.ammo_lava_nails >= 20 ) {
  548. item.ammo_lava_nails = 20;
  549. self.ammo_lava_nails = self.ammo_lava_nails - 20;
  550. } else {
  551. item.ammo_lava_nails = self.ammo_lava_nails;
  552. self.ammo_lava_nails = 0;
  553. }
  554. }
  555. // See if we are using a grenade or rocket launcher
  556. if ((self.weapon == IT_GRENADE_LAUNCHER) || (self.weapon == IT_ROCKET_LAUNCHER)) {
  557. if( self.ammo_rockets1 >= 10 ) {
  558. item.ammo_rockets1 = 10;
  559. self.ammo_rockets1 = self.ammo_rockets1 - 10;
  560. } else {
  561. item.ammo_rockets1 = self.ammo_rockets1;
  562. self.ammo_rockets1 = 0;
  563. }
  564. }
  565. // See if we are using the multi grenade or rocket launcher
  566. if ((self.weapon == IT_MULTI_GRENADE) || (self.weapon == IT_MULTI_ROCKET)) {
  567. if (self.ammo_multi_rockets >= 10 ) {
  568. item.ammo_multi_rockets = 10;
  569. self.ammo_multi_rockets = self.ammo_multi_rockets - 10;
  570. } else {
  571. item.ammo_multi_rockets = self.ammo_multi_rockets;
  572. self.ammo_multi_rockets = 0;
  573. }
  574. }
  575. // See if we have neither the Grenade or rocket launcher
  576. if ( !(self.items & IT_GRENADE_LAUNCHER) && !(self.items & IT_ROCKET_LAUNCHER) ) {
  577. if( self.ammo_rockets1 >= 10 ) {
  578. item.ammo_rockets1 = 10;
  579. self.ammo_rockets1 = self.ammo_rockets1 - 10;
  580. } else {
  581. item.ammo_rockets1 = self.ammo_rockets1;
  582. self.ammo_rockets1 = 0;
  583. }
  584. if (self.ammo_multi_rockets >= 10 ) {
  585. item.ammo_multi_rockets = 10;
  586. self.ammo_multi_rockets = self.ammo_multi_rockets - 10;
  587. } else {
  588. item.ammo_multi_rockets = self.ammo_multi_rockets;
  589. self.ammo_multi_rockets = 0;
  590. }
  591. }
  592. // See if we're using the lightning gun
  593. if (self.weapon == IT_LIGHTNING) {
  594. if( self.ammo_cells1 >= 20 ) {
  595. item.ammo_cells1 = 20;
  596. self.ammo_cells1 = self.ammo_cells1 - 20;
  597. } else {
  598. item.ammo_cells1 = self.ammo_cells1;
  599. self.ammo_cells1 = 0;
  600. }
  601. }
  602. // see if we are using the plasma gun
  603. if (self.weapon == IT_PLASMA_GUN) {
  604. if( self.ammo_plasma >= 10 ) {
  605. item.ammo_plasma = 10;
  606. self.ammo_plasma = self.ammo_plasma - 10;
  607. } else {
  608. item.ammo_plasma = self.ammo_plasma;
  609. self.ammo_plasma = 0;
  610. }
  611. }
  612. // see if we don't have the lightning gun
  613. if (!(self.items & IT_LIGHTNING)) {
  614. if( self.ammo_cells1 >= 20 ) {
  615. item.ammo_cells1 = 20;
  616. self.ammo_cells1 = self.ammo_cells1 - 20;
  617. } else {
  618. item.ammo_cells1 = self.ammo_cells1;
  619. self.ammo_cells1 = 0;
  620. }
  621. if( self.ammo_plasma >= 10 ) {
  622. item.ammo_plasma = 10;
  623. self.ammo_plasma = self.ammo_plasma - 10;
  624. } else {
  625. item.ammo_plasma = self.ammo_plasma;
  626. self.ammo_plasma = 0;
  627. }
  628. }
  629. if (item.ammo_shells1 + item.ammo_nails1 + item.ammo_lava_nails +
  630. item.ammo_rockets1 + item.ammo_multi_rockets + item.ammo_cells1 +
  631. item.ammo_plasma == 0) {
  632. sprint(self, "$qc_no_ammo_available");
  633. remove(item);
  634. return;
  635. }
  636. item.owner = self;
  637. makevectors(self.v_angle);
  638. setorigin(item, self.origin + '0 0 16');
  639. item.velocity = aim(self, 1000);
  640. item.velocity = item.velocity * 500;
  641. item.flags = FL_ITEM;
  642. item.solid = SOLID_TRIGGER;
  643. item.movetype = MOVETYPE_BOUNCE;
  644. setmodel (item, "progs/backpack.mdl");
  645. setsize(item, '-16 -16 0', '16 16 56');
  646. item.touch = BackpackTouch;
  647. item.nextthink = time + 120; // remove after 2 minutes
  648. item.think = SUB_Remove;
  649. W_SetCurrentAmmo();
  650. };
  651. void() Team_weapon_touch =
  652. {
  653. local float hadammo, best, new, old;
  654. local entity stemp;
  655. if (!(other.flags & FL_CLIENT))
  656. return;
  657. // Don't let the owner pick up his own weapon for a second.
  658. if ((other == self.owner) && ((self.nextthink - time) > 119))
  659. return;
  660. // if the player was using his best weapon, change up to the new one if better
  661. stemp = self;
  662. self = other;
  663. best = W_BestWeapon();
  664. self = stemp;
  665. if (self.classname == "weapon_nailgun")
  666. new = IT_NAILGUN;
  667. else if (self.classname == "weapon_supernailgun")
  668. new = IT_SUPER_NAILGUN;
  669. else if (self.classname == "weapon_supershotgun")
  670. new = IT_SUPER_SHOTGUN;
  671. else if (self.classname == "weapon_rocketlauncher")
  672. new = IT_ROCKET_LAUNCHER;
  673. else if (self.classname == "weapon_grenadelauncher")
  674. new = IT_GRENADE_LAUNCHER;
  675. else if (self.classname == "weapon_lightning")
  676. new = IT_LIGHTNING;
  677. else
  678. objerror ("Team_weapon_touch: unknown classname");
  679. sprint(other, "$qc_got_item", self.netname);
  680. // weapon touch sound
  681. sound (other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM);
  682. stuffcmd (other, "bf\n");
  683. bound_other_ammo ();
  684. // change to the weapon
  685. old = other.items;
  686. other.items = other.items | new;
  687. remove(self);
  688. self = other;
  689. if (!deathmatch)
  690. self.weapon = new;
  691. else
  692. Deathmatch_Weapon (old, new);
  693. EnableComboWeapons(self);
  694. UpdateAmmoCounts(self);
  695. W_SetCurrentAmmo();
  696. // dropped weapon doesn't target, so no need to call UseTargets
  697. };
  698. void() TossWeapon =
  699. {
  700. local entity item;
  701. if (deathmatch != 1)
  702. return; // only in deathmatch 1
  703. // only valid in teamplay modes
  704. if (teamplay < 1)
  705. return;
  706. if((self.weapon == IT_AXE) || (self.weapon == IT_SHOTGUN) ||
  707. (self.weapon == IT_GRAPPLE))
  708. return;
  709. item = spawn();
  710. item.owner = self;
  711. makevectors(self.v_angle);
  712. item.weapon = 0;
  713. setorigin(item, self.origin + '0 0 16');
  714. item.velocity = aim(self, 1000);
  715. item.velocity = item.velocity * 500;
  716. item.flags = FL_ITEM;
  717. item.solid = SOLID_TRIGGER;
  718. item.movetype = MOVETYPE_BOUNCE;
  719. if(self.weapon == IT_SUPER_SHOTGUN)
  720. {
  721. setmodel (item, "progs/g_shot.mdl");
  722. item.weapon = IT_SUPER_SHOTGUN;
  723. item.netname = "$qc_double_shotgun";
  724. item.classname = "weapon_supershotgun";
  725. self.items = self.items - IT_SUPER_SHOTGUN;
  726. }
  727. if( self.weapon == IT_NAILGUN || self.weapon == IT_LAVA_NAILGUN )
  728. {
  729. setmodel (item, "progs/g_nail.mdl");
  730. item.weapon = IT_NAILGUN;
  731. item.netname = "$qc_nailgun";
  732. item.classname = "weapon_nailgun";
  733. self.items = self.items - (self.items & (IT_NAILGUN | IT_LAVA_NAILGUN));
  734. }
  735. if( self.weapon == IT_SUPER_NAILGUN || self.weapon == IT_LAVA_SUPER_NAILGUN)
  736. {
  737. setmodel (item, "progs/g_nail2.mdl");
  738. item.weapon = IT_SUPER_NAILGUN;
  739. item.netname = "$qc_super_nailgun";
  740. item.classname = "weapon_supernailgun";
  741. self.items = self.items - (self.items & (IT_SUPER_NAILGUN | IT_LAVA_SUPER_NAILGUN));
  742. }
  743. if( self.weapon == IT_GRENADE_LAUNCHER || self.weapon == IT_MULTI_GRENADE)
  744. {
  745. setmodel (item, "progs/g_rock.mdl");
  746. item.weapon = IT_GRENADE_LAUNCHER;
  747. item.netname = "$qc_grenade_launcher";
  748. item.classname = "weapon_grenadelauncher";
  749. self.items = self.items - (self.items & (IT_GRENADE_LAUNCHER | IT_MULTI_GRENADE));
  750. }
  751. if( self.weapon == IT_ROCKET_LAUNCHER || self.weapon == IT_MULTI_ROCKET)
  752. {
  753. setmodel (item, "progs/g_rock2.mdl");
  754. item.weapon = IT_ROCKET_LAUNCHER;
  755. item.netname = "$qc_rocket_launcher";
  756. item.classname = "weapon_rocketlauncher";
  757. self.items = self.items - (self.items & (IT_ROCKET_LAUNCHER | IT_MULTI_ROCKET));
  758. }
  759. if( self.weapon == IT_LIGHTNING || self.weapon == IT_PLASMA_GUN)
  760. {
  761. setmodel (item, "progs/g_light.mdl");
  762. item.weapon = IT_LIGHTNING;
  763. item.netname = "$qc_thunderbolt";
  764. item.classname = "weapon_lightning";
  765. self.items = self.items - (self.items & (IT_LIGHTNING | IT_PLASMA_GUN));
  766. }
  767. setsize(item, '-16 -16 0', '16 16 56');
  768. item.touch = Team_weapon_touch;
  769. item.think = SUB_Remove;
  770. item.nextthink = time + 120;
  771. self.weapon = W_BestWeapon();
  772. W_SetCurrentAmmo();
  773. };
  774. void(entity flg) RegenFlag =
  775. {
  776. flg.movetype = MOVETYPE_TOSS;
  777. flg.solid = SOLID_TRIGGER;
  778. sound (flg, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM); // play respawn sound
  779. setorigin(flg, flg.oldorigin);
  780. flg.angles = flg.mangle;
  781. flg.cnt = FLAG_AT_BASE; // it's at home base
  782. flg.owner = world;
  783. };
  784. void(entity flg) TeamReturnFlag =
  785. {
  786. local entity p;
  787. local string n;
  788. RegenFlag(flg);
  789. p = find(world, classname, "player");
  790. while (p != world) {
  791. if (teamplay == TEAM_CTF_ONEFLAG) // one flag mode?
  792. centerprint(p, "$qc_flag_returned");
  793. else {
  794. if (teamplay == TEAM_CTF_ALT) {
  795. if (flg.team == TEAM1)
  796. centerprint(p, "��� flag has been returned to base!\n");
  797. else if (flg.team == TEAM2)
  798. centerprint(p, "���� flag has been returned to base!\n");
  799. else
  800. centerprint(p, "$qc_some_flag_returned_base");
  801. } else {
  802. if (p.steam != flg.team)
  803. centerprint(p, "$qc_enemy_flag_returned_base");
  804. else if (p.steam == flg.team)
  805. centerprint(p, "$qc_your_flag_returned_base");
  806. }
  807. }
  808. p = find(p, classname, "player");
  809. }
  810. };
  811. void () TeamRegenFlags =
  812. {
  813. local entity f;
  814. if (teamplay == TEAM_CTF_ONEFLAG) {
  815. f = find(world, classname, "item_flag");
  816. if (f != world)
  817. RegenFlag(f);
  818. return;
  819. }
  820. f = find(world, classname, "item_flag_team1");
  821. if (f != world)
  822. RegenFlag(f);
  823. f = find(world, classname, "item_flag_team2");
  824. if (f != world)
  825. RegenFlag(f);
  826. };
  827. void(entity flg) TeamDropFlag =
  828. {
  829. local entity item, f, oself;
  830. local entity p;
  831. p = flg.owner;
  832. bprint(p.netname);
  833. if (teamplay == TEAM_CTF_ONEFLAG)
  834. bprint(" ���� the flag!\n");
  835. else {
  836. if (flg.team == TEAM1)
  837. bprint(" ���� the ��� flag!\n"); // red
  838. else
  839. bprint(" ���� the ���� flag!\n"); // blue
  840. }
  841. setorigin(flg, p.origin - '0 0 24');
  842. flg.cnt = FLAG_DROPPED;
  843. flg.velocity_z = 300;
  844. flg.velocity_x = 0;
  845. flg.velocity_y = 0;
  846. flg.flags = FL_ITEM | FL_OBJECTIVE;
  847. flg.solid = SOLID_TRIGGER;
  848. flg.movetype = MOVETYPE_TOSS;
  849. setsize(flg, '-16 -16 0', '16 16 74');
  850. // return it after so long
  851. flg.super_time = time + CTF_FLAG_RETURN_TIME;
  852. };
  853. void(entity player) TeamDropFlagOfPlayer =
  854. {
  855. local string kn;
  856. local entity e;
  857. if (teamplay == TEAM_CTF_ONEFLAG && (player.ctf_flags & CTF_FLAG_FLAG))
  858. kn = "item_flag";
  859. else if (player.ctf_flags & CTF_FLAG_TEAM1)
  860. kn = "item_flag_team1";
  861. else if (player.ctf_flags & CTF_FLAG_TEAM2)
  862. kn = "item_flag_team2";
  863. else
  864. return; // doesn't have a flg
  865. player.ctf_flags = player.ctf_flags -
  866. (player.ctf_flags & (CTF_FLAG_FLAG | CTF_FLAG_TEAM1 | CTF_FLAG_TEAM2));
  867. e = find(world, classname, kn);
  868. if (e != world)
  869. TeamDropFlag(e);
  870. };
  871. // A flag was touched. In one flag mode, the player always just picks it up
  872. // (the flagbase models at each base will cause the score). In two flag mode,
  873. // it could be the guy returning his flag, or the guy getting the enemy flag
  874. // Three team mode gets more complicated as the third team touches the
  875. // flagbase to score
  876. void() TeamFlagTouch =
  877. {
  878. local entity p, oself;
  879. if (other.classname != "player")
  880. return;
  881. if (other.health <= 0)
  882. return;
  883. if (other.team != other.steam)
  884. return; // something is fishy, somebody is playing with colors
  885. if (self.cnt == FLAG_CARRIED)
  886. return; // huh?
  887. // Ok, first up, let's do it for one flag mode
  888. if (teamplay == TEAM_CTF_ONEFLAG) {
  889. // in one flag mode, we always pick up the flag. The touch of the
  890. // flagbase entities does the scoring
  891. bprint(other.netname);
  892. bprint(" ��� the flag!\n");
  893. if (CTF_FLAG_BONUS)
  894. other.frags = other.frags + CTF_FLAG_BONUS;
  895. //centerprint(other, "$qc_got_flag_enemy_base");
  896. centerprint(other, "��� ��� ��� ����\n\n���� �� �� ����� ����\n");
  897. sound (other, CHAN_ITEM, self.noise, 1, ATTN_NORM);
  898. other.ctf_flags = other.ctf_flags | CTF_FLAG_FLAG;
  899. other.items = other.items | self.items;
  900. other.ctf_flagsince = time;
  901. // pick up the flag
  902. self.cnt = FLAG_CARRIED;
  903. self.movetype = MOVETYPE_NOCLIP;
  904. self.solid = SOLID_NOT;
  905. self.owner = other;
  906. p = find(world, classname, "player");
  907. while (p != world) {
  908. if (p != other)
  909. centerprint(p, "$qc_flag_taken");
  910. p = find(p, classname, "player");
  911. }
  912. return;
  913. }
  914. // Regular and Alt CTF mode
  915. if (teamplay != TEAM_CTF && teamplay != TEAM_CTF_ALT)
  916. return; // odd, but ignore it
  917. if (self.team == other.steam) {
  918. // same team, if the flag is *not* at the base, return
  919. // it to base. we overload the 'cnt' field for this
  920. if (self.cnt == FLAG_AT_BASE) {
  921. // the flag is at home base. if the player has the enemy
  922. // flag, he's just won!
  923. if ((self.team == TEAM1 && (other.ctf_flags & CTF_FLAG_TEAM2)) ||
  924. (self.team == TEAM2 && (other.ctf_flags & CTF_FLAG_TEAM1))) {
  925. bprint(other.netname);
  926. if (other.team == TEAM1)
  927. bprint(" �������� the ���� flag!\n"); // blue
  928. else
  929. bprint(" �������� the ��� flag!\n"); // red
  930. other.items = other.items - (other.items & (IT_KEY1 | IT_KEY2));
  931. sound (other, CHAN_VOICE, "misc/flagcap.wav", 1, ATTN_NONE);
  932. // other gets another 10 frag bonus
  933. other.frags = other.frags + CTF_CAPTURE_BONUS;
  934. // Ok, let's do the player loop, hand out the bonuses
  935. p = find(world, classname, "player");
  936. while (p != world) {
  937. self = p;
  938. if (self.team == other.team && self != other)
  939. self.frags = self.frags + CTF_TEAM_BONUS;
  940. if (self.team != other.team) {
  941. if (self.team == TEAM3)
  942. if (other.team == TEAM1)
  943. centerprint(self, "���� flag was captured!\n");
  944. else
  945. centerprint(self, "��� flag was captured!\n");
  946. else
  947. centerprint(self, "$qc_your_flag_captured");
  948. // reset the last_hurt_carrier variable in all enemy players, so that you don't get
  949. // bonuses for defending the flag carrier if the flag carrier has already
  950. // completed a capture
  951. self.ctf_lasthurtcarrier = -5;
  952. } else if (self.team == other.team) {
  953. // done to all players on the capturing team
  954. centerprint(self, "$qc_your_team_captured");
  955. // award extra points for capture assists
  956. if (self.ctf_lastreturnedflag + CTF_RETURN_FLAG_ASSIST_TIMEOUT > time) {
  957. bprint(self.netname);
  958. if (self.team == TEAM1)
  959. bprint(" gets an assist for returning the ��� flag!\n");
  960. else
  961. bprint(" gets an assist for returning the ���� flag!\n");
  962. self.frags = self.frags + CTF_RETURN_FLAG_ASSIST_BONUS;
  963. }
  964. if (self.ctf_lastfraggedcarrier + CTF_FRAG_CARRIER_ASSIST_TIMEOUT > time) {
  965. bprint(self.netname);
  966. bprint(" gets an assist for fragging the flag carrier!\n");
  967. self.frags = self.frags + CTF_FRAG_CARRIER_ASSIST_BONUS;
  968. }
  969. }
  970. self.ctf_flags = self.ctf_flags - (self.ctf_flags &
  971. (CTF_FLAG_TEAM1 | CTF_FLAG_TEAM2));
  972. p = find(p, classname, "player");
  973. }
  974. // respawn flags
  975. TeamRegenFlags();
  976. return;
  977. }
  978. return; // its at home base already
  979. }
  980. // hey, its not home. return it by teleporting it back
  981. bprint(other.netname);
  982. if (other.team == TEAM1)
  983. bprint(" �������� the ��� flag!\n"); // red
  984. else
  985. bprint(" �������� the ���� flag!\n"); // blue
  986. other.frags = other.frags + CTF_RECOVERY_BONUS;
  987. other.ctf_lastreturnedflag = time;
  988. sound (other, CHAN_ITEM, self.noise1, 1, ATTN_NORM);
  989. TeamReturnFlag(self);
  990. return;
  991. }
  992. // if we have any flags, leave now
  993. if (other.ctf_flags & (CTF_FLAG_TEAM1 | CTF_FLAG_TEAM2))
  994. return;
  995. // hey, its not our flag, pick it up
  996. bprint(other.netname);
  997. if (self.team == TEAM1)
  998. bprint(" ��� the ��� flag!\n"); // red
  999. else
  1000. bprint(" ��� the ���� flag!\n"); // blue
  1001. other.frags = other.frags + CTF_FLAG_BONUS;
  1002. // if in three team, messages are a little different
  1003. if (other.team == TEAM3) {
  1004. // centerprint(other, "$qc_got_flag_other");
  1005. centerprint(other, "��� ��� ��� ����� ����\n\n������ �� �� ��� ����� ����\n");
  1006. } else {
  1007. // centerprint(other, "$qc_got_flag_return_base");
  1008. centerprint(other, "��� ��� ��� ����� ����\n\n������ �� ����\n");
  1009. }
  1010. sound (other, CHAN_ITEM, self.noise, 1, ATTN_NORM);
  1011. if (self.team == TEAM1)
  1012. other.ctf_flags = other.ctf_flags | CTF_FLAG_TEAM1;
  1013. else
  1014. other.ctf_flags = other.ctf_flags | CTF_FLAG_TEAM2;
  1015. other.items = other.items | self.items;
  1016. other.ctf_flagsince = time;
  1017. // pick up the flag
  1018. self.cnt = FLAG_CARRIED;
  1019. self.movetype = MOVETYPE_NOCLIP;
  1020. self.solid = SOLID_NOT;
  1021. self.owner = other;
  1022. // PGM Fix - 03/06/97 Made it work right in three team.
  1023. p = find(world, classname, "player");
  1024. while (p != world)
  1025. {
  1026. if (p != other)
  1027. {
  1028. if (p.steam == self.team)
  1029. {
  1030. centerprint(p, "$qc_your_flag_taken");
  1031. }
  1032. else if (p.steam == other.team)
  1033. {
  1034. if (self.team == TEAM1)
  1035. centerprint(p, "Your team has the ��� flag!\n"); // Red Flag
  1036. else
  1037. centerprint(p, "Your team has the ���� flag!\n"); // Blue Flag
  1038. }
  1039. else
  1040. {
  1041. if (self.team == TEAM1)
  1042. if (other.steam == TEAM2)
  1043. centerprint(p, "���� team has the ��� flag!\n"); // Blue has red
  1044. else // must be team3
  1045. centerprint(p, "���� team has the ��� flag!\n"); // grey has red
  1046. else
  1047. if (other.steam == TEAM1)
  1048. centerprint(p, "��� team has the ���� flag!\n"); // red has blue
  1049. else // must be team3
  1050. centerprint(p, "���� team has the ���� flag!\n");// grey has blue
  1051. }
  1052. }
  1053. p = find(p, classname, "player");
  1054. }
  1055. };
  1056. // A flagbase was touched. In one flag mode, this is how a capture is made.
  1057. // in three team mode, only team3 touches this. In regular CTF, this is
  1058. // ignored
  1059. void() TeamFlagBaseTouch =
  1060. {
  1061. local entity p, oself, f;
  1062. if (other.classname != "player")
  1063. return;
  1064. if (other.health <= 0)
  1065. return;
  1066. if (other.team != other.steam)
  1067. return; // something is fishy, somebody is playing with colors
  1068. // Ok, first up, let's do it for one flag mode
  1069. if (teamplay == TEAM_CTF_ONEFLAG) {
  1070. // ok, if they guy touching it has the flag and this is his
  1071. // base, capture!
  1072. if (((self.team == TEAM1 && other.steam == TEAM2) ||
  1073. (self.team == TEAM2 && other.steam == TEAM1)) &&
  1074. (other.ctf_flags & CTF_FLAG_FLAG)) {
  1075. // he just touched enemy base, capture it
  1076. bprint(other.netname);
  1077. bprint(" �������� the flag!\n"); // blue
  1078. other.items = other.items - (other.items & (IT_KEY1 | IT_KEY2));
  1079. sound (other, CHAN_VOICE, "misc/flagcap.wav", 1, ATTN_NONE);
  1080. // other gets another 10 frag bonus
  1081. other.frags = other.frags + CTF_CAPTURE_BONUS;
  1082. // Ok, let's do the player loop, hand out the bonuses
  1083. p = find(world, classname, "player");
  1084. while (p != world) {
  1085. self = p;
  1086. if (self.team == other.team && self != other)
  1087. self.frags = self.frags + CTF_TEAM_BONUS;
  1088. if (self.team != other.team) {
  1089. self.ctf_lasthurtcarrier = -5;
  1090. } else if (self.team == other.team) {
  1091. // award extra points for capture assists
  1092. if (self.ctf_lastfraggedcarrier + CTF_FRAG_CARRIER_ASSIST_TIMEOUT > time) {
  1093. bprint(self.netname);
  1094. bprint(" gets an assist for fragging the flag carrier!\n");
  1095. self.frags = self.frags + CTF_FRAG_CARRIER_ASSIST_BONUS;
  1096. }
  1097. }
  1098. self.ctf_flags = self.ctf_flags - (self.ctf_flags & CTF_FLAG_FLAG);
  1099. p = find(p, classname, "player");
  1100. }
  1101. // respawn flags
  1102. TeamRegenFlags();
  1103. return;
  1104. }
  1105. }
  1106. // in three team mode (TEAM_CTF_ALT) and we're on team3, see if we capture
  1107. if (teamplay != TEAM_CTF_ALT || other.steam != TEAM3)
  1108. return;
  1109. if (((other.ctf_flags & CTF_FLAG_TEAM1) && (self.team == TEAM2)) ||
  1110. ((other.ctf_flags & CTF_FLAG_TEAM2) && (self.team == TEAM1))) {
  1111. // third team captured
  1112. bprint(other.netname);
  1113. if (self.team == TEAM1)
  1114. bprint(" �������� the ���� flag!\n"); // blue
  1115. else
  1116. bprint(" �������� the ��� flag!\n"); // red
  1117. other.items = other.items - (other.items & (IT_KEY1 | IT_KEY2));
  1118. sound (other, CHAN_VOICE, "misc/flagcap.wav", 1, ATTN_NONE);
  1119. // other gets another 10 frag bonus
  1120. other.frags = other.frags + CTF_ALT_CAPTURE_BONUS;
  1121. // Ok, let's do the player loop, hand out the bonuses
  1122. p = find(world, classname, "player");
  1123. while (p != world) {
  1124. self = p;
  1125. if (self.team == other.team && self != other)
  1126. self.frags = self.frags + CTF_ALT_TEAM_BONUS;
  1127. if (self.team != other.team) {
  1128. if ((other.ctf_flags & CTF_FLAG_TEAM1) && self.team == TEAM1)
  1129. centerprint(self, "$qc_your_flag_captured");
  1130. else if ((other.ctf_flags & CTF_FLAG_TEAM2) && self.team == TEAM2)
  1131. centerprint(self, "$qc_enemy_flag_captured");
  1132. // reset the last_hurt_carrier variable in all enemy players, so that you don't get
  1133. // bonuses for defending the flag carrier if the flag carrier has already
  1134. // completed a capture
  1135. self.ctf_lasthurtcarrier = -5;
  1136. } else if (self.team == other.team) {
  1137. // done to all players on the capturing team
  1138. centerprint(self, "$qc_your_team_captured");
  1139. }
  1140. p = find(p, classname, "player");
  1141. }
  1142. // respawn flags
  1143. if (other.ctf_flags & CTF_FLAG_TEAM1) {
  1144. f = find(world, classname, "item_flag_team1");
  1145. if (f != world)
  1146. RegenFlag(f);
  1147. } else { // must be flag2
  1148. f = find(world, classname, "item_flag_team2");
  1149. if (f != world)
  1150. RegenFlag(f);
  1151. }
  1152. other.ctf_flags = other.ctf_flags - (other.ctf_flags &
  1153. (CTF_FLAG_TEAM1 | CTF_FLAG_TEAM2));
  1154. return;
  1155. }
  1156. };
  1157. void() TeamFlagThink =
  1158. {
  1159. local entity e;
  1160. local vector v;
  1161. local float f;
  1162. local string s;
  1163. self.nextthink = time + 0.1;
  1164. if (self.cnt == FLAG_AT_BASE)
  1165. return; // just sitting around waiting to be picked up
  1166. if (self.cnt == FLAG_DROPPED) {
  1167. if (time - self.super_time > CTF_FLAG_RETURN_TIME)
  1168. TeamReturnFlag(self);
  1169. return;
  1170. }
  1171. if (self.cnt != FLAG_CARRIED)
  1172. objerror("Flag in invalid state\n");
  1173. e = self.owner;
  1174. if (e.classname != "player" || e.deadflag) {
  1175. TeamDropFlag(self);
  1176. return;
  1177. }
  1178. if (teamplay == TEAM_CTF_ONEFLAG && !(e.ctf_flags & CTF_FLAG_FLAG)) {
  1179. TeamDropFlag(self);
  1180. return;
  1181. }
  1182. // must be TEAM_CTF or TEAM_CTF_ALT
  1183. if ((!(e.ctf_flags & CTF_FLAG_TEAM1) && self.team == TEAM1) ||
  1184. (!(e.ctf_flags & CTF_FLAG_TEAM2) && self.team == TEAM2)) {
  1185. TeamDropFlag(self);
  1186. return;
  1187. }
  1188. makevectors (e.angles);
  1189. v = v_forward;
  1190. v_z = (-1) * v_z; // reverse z component
  1191. f = 14;
  1192. if (self.owner.frame >= 29 && self.owner.frame <= 40) {
  1193. if (self.owner.frame >= 29 && self.owner.frame <= 34) { //axpain
  1194. if (self.owner.frame == 29) f = f + 2;
  1195. else if (self.owner.frame == 30) f = f + 8;
  1196. else if (self.owner.frame == 31) f = f + 12;
  1197. else if (self.owner.frame == 32) f = f + 11;
  1198. else if (self.owner.frame == 33) f = f + 10;
  1199. else if (self.owner.frame == 34) f = f + 4;
  1200. } else if (self.owner.frame >= 35 && self.owner.frame <= 40) { // pain
  1201. if (self.owner.frame == 35) f = f + 2;
  1202. else if (self.owner.frame == 36) f = f + 10;
  1203. else if (self.owner.frame == 37) f = f + 10;
  1204. else if (self.owner.frame == 38) f = f + 8;
  1205. else if (self.owner.frame == 39) f = f + 4;
  1206. else if (self.owner.frame == 40) f = f + 2;
  1207. }
  1208. } else if (self.owner.frame >= 103 && self.owner.frame <= 118) {
  1209. if (self.owner.frame >= 103 && self.owner.frame <= 104) f = f + 6; //nailattack
  1210. else if (self.owner.frame >= 105 && self.owner.frame <= 106) f = f + 6; //light
  1211. else if (self.owner.frame >= 107 && self.owner.frame <= 112) f = f + 7; //rocketattack
  1212. else if (self.owner.frame >= 112 && self.owner.frame <= 118) f = f + 7; //shotattack
  1213. }
  1214. self.origin = e.origin + '0 0 -16' - f*v + v_right * 22;
  1215. self.angles = e.angles + '0 0 -45';
  1216. setorigin (self, self.origin);
  1217. self.nextthink = time + 0.01;
  1218. };
  1219. void() TeamFlagStatusReport =
  1220. {
  1221. local entity flag1, flag2, p;
  1222. local string n;
  1223. if (!deathmatch)
  1224. return;
  1225. if (teamplay != TEAM_CTF && teamplay != TEAM_CTF_ONEFLAG &&
  1226. teamplay != TEAM_CTF_ALT) {
  1227. sprint(self, "$qc_ctf_disabled");
  1228. return;
  1229. }
  1230. if (teamplay == TEAM_CTF_ONEFLAG) {
  1231. flag1 = find (world, classname, "item_flag");
  1232. if (flag1 == world)
  1233. sprint(self, "$qc_flag_missing");
  1234. else if (flag1.cnt == FLAG_AT_BASE)
  1235. sprint(self, "$qc_flag_at_base");
  1236. else if (flag1.cnt == FLAG_DROPPED)
  1237. sprint(self, "$qc_flag_lying_about");
  1238. else if (flag1.cnt == FLAG_CARRIED) {
  1239. if (flag1.owner == self)
  1240. sprint(self, "$qc_you_have_flag");
  1241. else {
  1242. sprint(self, flag1.owner.netname);
  1243. n = GetCTFTeam(flag1.owner.steam);
  1244. sprint(self, " of the ");
  1245. sprint(self, n);
  1246. sprint(self, " team has the flag!\n");
  1247. }
  1248. } else
  1249. sprint(self, "$qc_flag_screwed_up");
  1250. return;
  1251. }
  1252. // normal CTF
  1253. if (teamplay == TEAM_CTF) {
  1254. // Find the flags at home base
  1255. flag1 = find (world,classname, "item_flag_team1");
  1256. flag2 = find (world,classname, "item_flag_team2");
  1257. // If on team 2 switch meanings of flags
  1258. if (self.team != TEAM1) {
  1259. p = flag1;
  1260. flag1 = flag2;
  1261. flag2 = p;
  1262. }
  1263. if (flag1 != world && flag1.cnt == FLAG_CARRIED) {
  1264. sprint(self, flag1.owner.netname);
  1265. sprint(self, " has your flag. ");
  1266. } else {
  1267. sprint(self, "Your flag is ");
  1268. if (flag1 == world)
  1269. sprint(self, "missing!\n");
  1270. if (flag1.cnt == FLAG_AT_BASE)
  1271. sprint(self, "in your base.\n");
  1272. else if (flag1.cnt == FLAG_DROPPED)
  1273. sprint(self, "lying about.\n");
  1274. else
  1275. sprint(self, " corrupt.\n");
  1276. }
  1277. if (flag2 != world && flag2.cnt == FLAG_CARRIED) {
  1278. if (self == flag2.owner)
  1279. sprint(self, "$qc_you_have_enemy_flag");
  1280. else {
  1281. sprint(self, flag2.owner.netname);
  1282. sprint(self, " has the enemy flag.\n");
  1283. }
  1284. } else {
  1285. sprint(self, "The enemy flag is ");
  1286. if (flag2 == world)
  1287. sprint(self, "missing!\n");
  1288. if (flag2.cnt == FLAG_AT_BASE)
  1289. sprint(self, "in their base.\n");
  1290. else if (flag2.cnt == FLAG_DROPPED)
  1291. sprint(self, "lying about.\n");
  1292. else
  1293. sprint(self, " corrupt.\n");
  1294. }
  1295. }
  1296. // three team CTF
  1297. if (teamplay == TEAM_CTF_ALT) {
  1298. // Find the flags at home base
  1299. flag1 = find (world,classname, "item_flag_team1");
  1300. flag2 = find (world,classname, "item_flag_team2");
  1301. if (flag1 != world && flag1.cnt == FLAG_CARRIED) {
  1302. if (flag1.owner == self)
  1303. sprint(self, "You have the ��� flag!\n");
  1304. else {
  1305. sprint(self, flag1.owner.netname);
  1306. n = GetCTFTeam(flag1.owner.steam);
  1307. sprint(self, " of the ");
  1308. sprint(self, n);
  1309. sprint(self, " team has the ��� flag.\n");
  1310. }
  1311. } else {
  1312. if (self.steam == flag1.team)
  1313. sprint(self, "Your flag is ");
  1314. else
  1315. sprint(self, "��� flag is ");
  1316. if (flag1 == world)
  1317. sprint(self, "missing!\n");
  1318. if (flag1.cnt == FLAG_AT_BASE)
  1319. sprint(self, "at base.\n");
  1320. else if (flag1.cnt == FLAG_DROPPED)
  1321. sprint(self, "lying about.\n");
  1322. else
  1323. sprint(self, " corrupt.\n");
  1324. }
  1325. if (flag2 != world && flag2.cnt == FLAG_CARRIED) {
  1326. if (flag2.owner == self)
  1327. sprint(self, "You have the ���� flag.\n");
  1328. else {
  1329. sprint(self, flag2.owner.netname);
  1330. n = GetCTFTeam(flag2.owner.steam);
  1331. sprint(self, " of the ");
  1332. sprint(self, n);
  1333. sprint(self, " team has the ���� flag.\n");
  1334. }
  1335. } else {
  1336. if (self.steam == flag1.team)
  1337. sprint(self, "Your flag is ");
  1338. else
  1339. sprint(self, "���� flag is ");
  1340. if (flag2 == world)
  1341. sprint(self, "missing!\n");
  1342. if (flag2.cnt == FLAG_AT_BASE)
  1343. sprint(self, "at base.\n");
  1344. else if (flag2.cnt == FLAG_DROPPED)
  1345. sprint(self, "lying about.\n");
  1346. else
  1347. sprint(self, " corrupt.\n");
  1348. }
  1349. }
  1350. };
  1351. /////////////////////////////////////////////////////////////////////////
  1352. $cd id1/models/flag
  1353. $base base
  1354. $skin skin
  1355. void() place_flag = {
  1356. self.mdl = self.model; // so it can be restored on respawn
  1357. self.flags = FL_ITEM | FL_OBJECTIVE; // make extra wide
  1358. self.solid = SOLID_TRIGGER;
  1359. self.movetype = MOVETYPE_TOSS;
  1360. self.velocity = '0 0 0';
  1361. self.origin_z = self.origin_z + 6;
  1362. self.think = TeamFlagThink;
  1363. self.touch = TeamFlagTouch;
  1364. self.nextthink = time + 0.1;
  1365. self.cnt = FLAG_AT_BASE;
  1366. self.mangle = self.angles;
  1367. self.effects = self.effects | EF_DIMLIGHT;
  1368. if (!droptofloor()) {
  1369. dprint ("Flag fell out of level at ");
  1370. dprint (vtos(self.origin));
  1371. dprint ("\n");
  1372. remove(self);
  1373. return;
  1374. }
  1375. self.oldorigin = self.origin; // save for flag return
  1376. };
  1377. void(entity flg, string cname) place_flagbase =
  1378. {
  1379. local entity oself;
  1380. teamplay = cvar("teamplay");
  1381. oself = self;
  1382. self = spawn();
  1383. self.classname = cname;
  1384. setorigin(self, flg.origin);
  1385. self.angles = flg.angles;
  1386. precache_model ("progs/ctfbase.mdl");
  1387. setmodel (self, "progs/ctfbase.mdl");
  1388. self.skin = flg.skin;
  1389. self.team = flg.team;
  1390. // setsize(self, '-8 -8 -4', '8 8 4');
  1391. setsize(self, '-8 -8 0', '8 8 8');
  1392. self.flags = FL_ITEM; // make extra wide
  1393. self.movetype = MOVETYPE_TOSS;
  1394. self.velocity = '0 0 0';
  1395. self.origin_z = self.origin_z + 6;
  1396. if (teamplay == TEAM_CTF_ONEFLAG || teamplay == TEAM_CTF_ALT) {
  1397. self.solid = SOLID_TRIGGER;
  1398. self.touch = TeamFlagBaseTouch;
  1399. } else
  1400. self.solid = SOLID_NOT;
  1401. if (!droptofloor()) {
  1402. dprint ("Flagbase fell out of level at ");
  1403. dprint (vtos(self.origin));
  1404. dprint ("\n");
  1405. remove(self);
  1406. self = oself;
  1407. return;
  1408. }
  1409. self = oself;
  1410. };
  1411. // ZOID Capture the flag
  1412. /*QUAKED item_flag_team1 (0 .5 .8) (-8 -8 -32) (8 8 24)
  1413. red team flag
  1414. Only appears in CTF teamplay
  1415. The flag waves 90 degrees off from the entity angle. If
  1416. you want the flag to point at 180, set then entity angle
  1417. to 90.
  1418. */
  1419. void() item_flag_team1 =
  1420. {
  1421. if (!deathmatch) {
  1422. remove(self);
  1423. return;
  1424. }
  1425. teamplay = cvar("teamplay");
  1426. if (teamplay == TEAM_CTF_ONEFLAG) {
  1427. precache_sound ("misc/flagtk.wav"); // flag taken
  1428. precache_sound ("misc/flagcap.wav"); // flag capture
  1429. self.skin = 0;
  1430. self.team = TEAM1;
  1431. place_flagbase(self, "item_flagbase_team1");
  1432. remove(self);
  1433. return;
  1434. }
  1435. if (teamplay == TEAM_CTF || teamplay == TEAM_CTF_ALT) {
  1436. self.team = TEAM1;
  1437. self.items = IT_KEY2;
  1438. precache_model ("progs/ctfmodel.mdl");
  1439. setmodel (self, "progs/ctfmodel.mdl");
  1440. self.skin = 0;
  1441. precache_sound ("misc/flagtk.wav"); // flag taken
  1442. precache_sound ("misc/flagcap.wav"); // flag capture
  1443. precache_sound ("misc/flagret.wav"); // flag return
  1444. self.noise = "misc/flagtk.wav";
  1445. self.noise1 = "misc/flagret.wav";
  1446. setsize(self, '-16 -16 0', '16 16 74');
  1447. self.nextthink = time + 0.2; // items start after other solids
  1448. self.think = place_flag;
  1449. place_flagbase(self, "item_flagbase_team1");
  1450. } else {
  1451. remove(self); // not teamplay or deathmatch
  1452. }
  1453. };
  1454. /*QUAKED item_flag_team2 (0 .5 .8) (-8 -8 -32) (8 8 24)
  1455. blue team flag
  1456. Only appears in CTF teamplay
  1457. The flag waves 90 degrees off from the entity angle. If
  1458. you want the flag to point at 180, set then entity angle
  1459. to 90.
  1460. */
  1461. void() item_flag_team2 =
  1462. {
  1463. if (!deathmatch) {
  1464. remove(self);
  1465. return;
  1466. }
  1467. teamplay = cvar("teamplay");
  1468. if (teamplay == TEAM_CTF_ONEFLAG) {
  1469. precache_sound ("misc/flagtk.wav"); // flag taken
  1470. precache_sound ("misc/flagcap.wav"); // flag capture
  1471. self.team = TEAM2;
  1472. self.skin = 1;
  1473. place_flagbase(self, "item_flagbase_team2");
  1474. remove(self);
  1475. return;
  1476. }
  1477. if (teamplay == TEAM_CTF || teamplay == TEAM_CTF_ALT) {
  1478. self.team = TEAM2;
  1479. self.items = IT_KEY1;
  1480. precache_model ("progs/ctfmodel.mdl");
  1481. setmodel (self, "progs/ctfmodel.mdl");
  1482. self.skin = 1;
  1483. precache_sound ("misc/flagtk.wav"); // flag taken
  1484. precache_sound ("misc/flagcap.wav"); // flag capture
  1485. precache_sound ("misc/flagret.wav"); // flag return
  1486. self.noise = "misc/flagtk.wav";
  1487. self.noise1 = "misc/flagret.wav";
  1488. setsize(self, '-16 -16 0', '16 16 74');
  1489. self.nextthink = time + 0.2; // items start after other solids
  1490. self.think = place_flag;
  1491. place_flagbase(self, "item_flagbase_team2");
  1492. } else {
  1493. remove(self); // not teamplay or deathmatch
  1494. }
  1495. };
  1496. /*QUAKED item_flag (0 .5 .8) (-8 -8 -32) (8 8 24)
  1497. flag for OneTeam play.
  1498. Only appears in CTF teamplay
  1499. The flag waves 90 degrees off from the entity angle. If
  1500. you want the flag to point at 180, set then entity angle
  1501. to 90.
  1502. */
  1503. void() item_flag =
  1504. {
  1505. if (cvar("teamplay") != TEAM_CTF_ONEFLAG) {
  1506. remove(self);
  1507. return;
  1508. }
  1509. self.team = 0; // no team
  1510. self.items = IT_KEY1 | IT_KEY2;
  1511. // precache_model ("progs/flag.mdl");
  1512. // setmodel (self, "progs/flag.mdl");
  1513. precache_model ("progs/ctfmodel.mdl"); // PGM 01/18/97
  1514. setmodel (self, "progs/ctfmodel.mdl"); // PGM 01/18/97
  1515. self.skin = 2;
  1516. precache_sound ("misc/flagtk.wav"); // flag taken
  1517. precache_sound ("misc/flagcap.wav"); // flag capture
  1518. precache_sound ("misc/flagret.wav"); // flag return
  1519. self.noise = "misc/flagtk.wav";
  1520. self.noise1 = "misc/flagret.wav";
  1521. setsize(self, '-16 -16 0', '16 16 74');
  1522. self.nextthink = time + 0.2; // items start after other solids
  1523. self.think = place_flag;
  1524. place_flagbase(self, "item_flagbase");
  1525. };
  1526. /*QUAKED info_player_team1 (1 0 1) (-16 -16 -24) (16 16 24)
  1527. potential spawning position for CTF games team 1.
  1528. */
  1529. void() info_player_team1 =
  1530. {
  1531. };
  1532. /*QUAKED info_player_team2 (1 0 1) (-16 -16 -24) (16 16 24)
  1533. potential spawning position for CTF games team 2.
  1534. */
  1535. void() info_player_team2 =
  1536. {
  1537. };
  1538. void() TeamSetUpdate =
  1539. {
  1540. nextteamupdtime = time + CTF_UPDATE_TIME;
  1541. };
  1542. void() TeamCheckUpdate =
  1543. {
  1544. local float total1, total2, total3;
  1545. local entity p;
  1546. local string s;
  1547. local string ts1, ts2, ts3;
  1548. if (nextteamupdtime > time || teamplay < 1 || !deathmatch)
  1549. return;
  1550. TeamSetUpdate();
  1551. // count up total
  1552. total1 = total2 = total3 = 0;
  1553. ts1 = GetCTFTeam(TEAM1);
  1554. ts2 = GetCTFTeam(TEAM2);
  1555. ts3 = GetCTFTeam(TEAM3);
  1556. if (teamplay == TEAM_CTF || teamplay == TEAM_CTF_ALT || teamplay == TEAM_CTF_ONEFLAG) {
  1557. p = find(world, classname, "player");
  1558. while (p != world) {
  1559. if (p.steam == TEAM1)
  1560. total1 = total1 + p.frags;
  1561. else if (p.steam == TEAM2)
  1562. total2 = total2 + p.frags;
  1563. else if (p.steam == TEAM3)
  1564. total3 = total3 + p.frags;
  1565. p = find(p, classname, "player");
  1566. }
  1567. if (teamplay == TEAM_CTF || teamplay == TEAM_CTF_ONEFLAG) {
  1568. if (total1 > total2) {
  1569. bprint(ts1);
  1570. bprint(" team is leading by ");
  1571. s = ftos(total1 - total2);
  1572. bprint(s);
  1573. bprint(" points!\n");
  1574. } else if (total1 < total2) {
  1575. bprint(ts2);
  1576. bprint(" team is leading by ");
  1577. s = ftos(total2 - total1);
  1578. bprint(s);
  1579. bprint(" points!\n");
  1580. } else {
  1581. bprint(ts1);
  1582. bprint(" and ");
  1583. bprint(ts2);
  1584. bprint(" teams are tied with ");
  1585. s = ftos(total1);
  1586. bprint(s);
  1587. bprint(" points!\n");
  1588. }
  1589. } else if (teamplay == TEAM_CTF_ALT) {
  1590. if (total1 > total2 && total1 > total3) {
  1591. bprint(ts1);
  1592. bprint(" team is leading by ");
  1593. if (total2 > total3)
  1594. s = ftos(total1 - total2);
  1595. else
  1596. s = ftos(total1 - total3);
  1597. bprint(s);
  1598. bprint(" points!\n");
  1599. } else if (total2 > total1 && total2 > total3) {
  1600. bprint(ts2);
  1601. bprint(" team is leading by ");
  1602. if (total1 > total3)
  1603. s = ftos(total2 - total1);
  1604. else
  1605. s = ftos(total2 - total3);
  1606. bprint(s);
  1607. bprint(" points!\n");
  1608. } else if (total3 > total1 && total3 > total2) {
  1609. bprint(ts3);
  1610. bprint(" team is leading by ");
  1611. if (total1 > total2)
  1612. s = ftos(total3 - total1);
  1613. else
  1614. s = ftos(total3 - total2);
  1615. bprint(s);
  1616. bprint(" points!\n");
  1617. } else if (total1 == total2) {
  1618. bprint(ts1);
  1619. bprint(" and ");
  1620. bprint(ts2);
  1621. bprint(" teams are tied with ");
  1622. s = ftos(total1);
  1623. bprint(s);
  1624. bprint(" points!\n");
  1625. } else if (total3 == total2) {
  1626. bprint(ts2);
  1627. bprint(" and ");
  1628. bprint(ts3);
  1629. bprint(" teams are tied with ");
  1630. s = ftos(total3);
  1631. bprint(s);
  1632. bprint(" points!\n");
  1633. } else if (total3 == total1) {
  1634. bprint(ts1);
  1635. bprint(" and ");
  1636. bprint(ts3);
  1637. bprint(" teams are tied with ");
  1638. s = ftos(total1);
  1639. bprint(s);
  1640. bprint(" points!\n");
  1641. } else {
  1642. bprint(ts1);
  1643. bprint(", ");
  1644. bprint(ts2);
  1645. bprint(" and ");
  1646. bprint(ts3);
  1647. bprint(" teams are tied with ");
  1648. s = ftos(total1);
  1649. bprint(s);
  1650. bprint(" points!\n");
  1651. }
  1652. }
  1653. }
  1654. };
  1655. /*QUAKED func_ctf_wall (0 .5 .8) ?
  1656. This is just a solid wall if not inhibitted
  1657. Only appears in CTF teamplay
  1658. */
  1659. void() func_ctf_wall =
  1660. {
  1661. teamplay = cvar("teamplay");
  1662. if (teamplay == TEAM_CTF || teamplay == TEAM_CTF_ONEFLAG ||
  1663. teamplay == TEAM_CTF_ALT) {
  1664. self.angles = '0 0 0';
  1665. self.movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything
  1666. self.solid = SOLID_BSP;
  1667. setmodel (self, self.model);
  1668. } else
  1669. remove(self);
  1670. };