1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198 |
- /*
- Copyright (C) 1997-2001 Id Software, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include "g_local.h"
- #include "m_player.h"
- typedef enum match_s {
- MATCH_NONE,
- MATCH_SETUP,
- MATCH_PREGAME,
- MATCH_GAME,
- MATCH_POST
- } match_t;
- typedef enum {
- ELECT_NONE,
- ELECT_MATCH,
- ELECT_ADMIN,
- ELECT_MAP
- } elect_t;
- typedef struct ctfgame_s
- {
- int team1, team2;
- int total1, total2; // these are only set when going into intermission!
- float last_flag_capture;
- int last_capture_team;
- match_t match; // match state
- float matchtime; // time for match start/end (depends on state)
- int lasttime; // last time update
- qboolean countdown; // has audio countdown started?
- elect_t election; // election type
- edict_t *etarget; // for admin election, who's being elected
- char elevel[32]; // for map election, target level
- int evotes; // votes so far
- int needvotes; // votes needed
- float electtime; // remaining time until election times out
- char emsg[256]; // election name
- int warnactive; // true if stat string 30 is active
- ghost_t ghosts[MAX_CLIENTS]; // ghost codes
- } ctfgame_t;
- ctfgame_t ctfgame;
- cvar_t *ctf;
- cvar_t *ctf_forcejoin;
- cvar_t *competition;
- cvar_t *matchlock;
- cvar_t *electpercentage;
- cvar_t *matchtime;
- cvar_t *matchsetuptime;
- cvar_t *matchstarttime;
- cvar_t *admin_password;
- cvar_t *allow_admin;
- cvar_t *warp_list;
- cvar_t *warn_unbalanced;
- // Index for various CTF pics, this saves us from calling gi.imageindex
- // all the time and saves a few CPU cycles since we don't have to do
- // a bunch of string compares all the time.
- // These are set in CTFPrecache() called from worldspawn
- int imageindex_i_ctf1;
- int imageindex_i_ctf2;
- int imageindex_i_ctf1d;
- int imageindex_i_ctf2d;
- int imageindex_i_ctf1t;
- int imageindex_i_ctf2t;
- int imageindex_i_ctfj;
- int imageindex_sbfctf1;
- int imageindex_sbfctf2;
- int imageindex_ctfsb1;
- int imageindex_ctfsb2;
- char *ctf_statusbar =
- "yb -24 "
- // health
- "xv 0 "
- "hnum "
- "xv 50 "
- "pic 0 "
- // ammo
- "if 2 "
- " xv 100 "
- " anum "
- " xv 150 "
- " pic 2 "
- "endif "
- // armor
- "if 4 "
- " xv 200 "
- " rnum "
- " xv 250 "
- " pic 4 "
- "endif "
- // selected item
- "if 6 "
- " xv 296 "
- " pic 6 "
- "endif "
- "yb -50 "
- // picked up item
- "if 7 "
- " xv 0 "
- " pic 7 "
- " xv 26 "
- " yb -42 "
- " stat_string 8 "
- " yb -50 "
- "endif "
- // timer
- "if 9 "
- "xv 246 "
- "num 2 10 "
- "xv 296 "
- "pic 9 "
- "endif "
- // help / weapon icon
- "if 11 "
- "xv 148 "
- "pic 11 "
- "endif "
- // frags
- "xr -50 "
- "yt 2 "
- "num 3 14 "
- //tech
- "yb -129 "
- "if 26 "
- "xr -26 "
- "pic 26 "
- "endif "
- // red team
- "yb -102 "
- "if 17 "
- "xr -26 "
- "pic 17 "
- "endif "
- "xr -62 "
- "num 2 18 "
- //joined overlay
- "if 22 "
- "yb -104 "
- "xr -28 "
- "pic 22 "
- "endif "
- // blue team
- "yb -75 "
- "if 19 "
- "xr -26 "
- "pic 19 "
- "endif "
- "xr -62 "
- "num 2 20 "
- "if 23 "
- "yb -77 "
- "xr -28 "
- "pic 23 "
- "endif "
- // have flag graph
- "if 21 "
- "yt 26 "
- "xr -24 "
- "pic 21 "
- "endif "
- // id view state
- "if 27 "
- "xv 112 "
- "yb -58 "
- "stat_string 27 "
- "endif "
- "if 29 "
- "xv 96 "
- "yb -58 "
- "pic 29 "
- "endif "
- "if 28 "
- "xl 0 "
- "yb -78 "
- "stat_string 28 "
- "endif "
- "if 30 "
- "xl 0 "
- "yb -88 "
- "stat_string 30 "
- "endif "
- ;
- static char *tnames[] = {
- "item_tech1", "item_tech2", "item_tech3", "item_tech4",
- NULL
- };
- void stuffcmd(edict_t *ent, char *s)
- {
- gi.WriteByte (11);
- gi.WriteString (s);
- gi.unicast (ent, true);
- }
- /*--------------------------------------------------------------------------*/
- /*
- =================
- findradius
- Returns entities that have origins within a spherical area
- findradius (origin, radius)
- =================
- */
- static edict_t *loc_findradius (edict_t *from, vec3_t org, float rad)
- {
- vec3_t eorg;
- int j;
- if (!from)
- from = g_edicts;
- else
- from++;
- for ( ; from < &g_edicts[globals.num_edicts]; from++)
- {
- if (!from->inuse)
- continue;
- #if 0
- if (from->solid == SOLID_NOT)
- continue;
- #endif
- for (j=0 ; j<3 ; j++)
- eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
- if (VectorLength(eorg) > rad)
- continue;
- return from;
- }
- return NULL;
- }
- static void loc_buildboxpoints(vec3_t p[8], vec3_t org, vec3_t mins, vec3_t maxs)
- {
- VectorAdd(org, mins, p[0]);
- VectorCopy(p[0], p[1]);
- p[1][0] -= mins[0];
- VectorCopy(p[0], p[2]);
- p[2][1] -= mins[1];
- VectorCopy(p[0], p[3]);
- p[3][0] -= mins[0];
- p[3][1] -= mins[1];
- VectorAdd(org, maxs, p[4]);
- VectorCopy(p[4], p[5]);
- p[5][0] -= maxs[0];
- VectorCopy(p[0], p[6]);
- p[6][1] -= maxs[1];
- VectorCopy(p[0], p[7]);
- p[7][0] -= maxs[0];
- p[7][1] -= maxs[1];
- }
- static qboolean loc_CanSee (edict_t *targ, edict_t *inflictor)
- {
- trace_t trace;
- vec3_t targpoints[8];
- int i;
- vec3_t viewpoint;
- // bmodels need special checking because their origin is 0,0,0
- if (targ->movetype == MOVETYPE_PUSH)
- return false; // bmodels not supported
- loc_buildboxpoints(targpoints, targ->s.origin, targ->mins, targ->maxs);
-
- VectorCopy(inflictor->s.origin, viewpoint);
- viewpoint[2] += inflictor->viewheight;
- for (i = 0; i < 8; i++) {
- trace = gi.trace (viewpoint, vec3_origin, vec3_origin, targpoints[i], inflictor, MASK_SOLID);
- if (trace.fraction == 1.0)
- return true;
- }
- return false;
- }
- /*--------------------------------------------------------------------------*/
- static gitem_t *flag1_item;
- static gitem_t *flag2_item;
- void CTFSpawn(void)
- {
- if (!flag1_item)
- flag1_item = FindItemByClassname("item_flag_team1");
- if (!flag2_item)
- flag2_item = FindItemByClassname("item_flag_team2");
- memset(&ctfgame, 0, sizeof(ctfgame));
- CTFSetupTechSpawn();
- if (competition->value > 1) {
- ctfgame.match = MATCH_SETUP;
- ctfgame.matchtime = level.time + matchsetuptime->value * 60;
- }
- }
- void CTFInit(void)
- {
- ctf = gi.cvar("ctf", "1", CVAR_SERVERINFO);
- ctf_forcejoin = gi.cvar("ctf_forcejoin", "", 0);
- competition = gi.cvar("competition", "0", CVAR_SERVERINFO);
- matchlock = gi.cvar("matchlock", "1", CVAR_SERVERINFO);
- electpercentage = gi.cvar("electpercentage", "66", 0);
- matchtime = gi.cvar("matchtime", "20", CVAR_SERVERINFO);
- matchsetuptime = gi.cvar("matchsetuptime", "10", 0);
- matchstarttime = gi.cvar("matchstarttime", "20", 0);
- admin_password = gi.cvar("admin_password", "", 0);
- allow_admin = gi.cvar("allow_admin", "1", 0);
- warp_list = gi.cvar("warp_list", "q2ctf1 q2ctf2 q2ctf3 q2ctf4 q2ctf5", 0);
- warn_unbalanced = gi.cvar("warn_unbalanced", "1", 0);
- }
- /*
- * Precache CTF items
- */
- void CTFPrecache(void)
- {
- imageindex_i_ctf1 = gi.imageindex("i_ctf1");
- imageindex_i_ctf2 = gi.imageindex("i_ctf2");
- imageindex_i_ctf1d = gi.imageindex("i_ctf1d");
- imageindex_i_ctf2d = gi.imageindex("i_ctf2d");
- imageindex_i_ctf1t = gi.imageindex("i_ctf1t");
- imageindex_i_ctf2t = gi.imageindex("i_ctf2t");
- imageindex_i_ctfj = gi.imageindex("i_ctfj");
- imageindex_sbfctf1 = gi.imageindex("sbfctf1");
- imageindex_sbfctf2 = gi.imageindex("sbfctf2");
- imageindex_ctfsb1 = gi.imageindex("ctfsb1");
- imageindex_ctfsb2 = gi.imageindex("ctfsb2");
- }
- /*--------------------------------------------------------------------------*/
- char *CTFTeamName(int team)
- {
- switch (team) {
- case CTF_TEAM1:
- return "RED";
- case CTF_TEAM2:
- return "BLUE";
- }
- return "UNKNOWN"; // Hanzo pointed out this was spelled wrong as "UKNOWN"
- }
- char *CTFOtherTeamName(int team)
- {
- switch (team) {
- case CTF_TEAM1:
- return "BLUE";
- case CTF_TEAM2:
- return "RED";
- }
- return "UNKNOWN"; // Hanzo pointed out this was spelled wrong as "UKNOWN"
- }
- int CTFOtherTeam(int team)
- {
- switch (team) {
- case CTF_TEAM1:
- return CTF_TEAM2;
- case CTF_TEAM2:
- return CTF_TEAM1;
- }
- return -1; // invalid value
- }
- /*--------------------------------------------------------------------------*/
- edict_t *SelectRandomDeathmatchSpawnPoint (void);
- edict_t *SelectFarthestDeathmatchSpawnPoint (void);
- float PlayersRangeFromSpot (edict_t *spot);
- void CTFAssignSkin(edict_t *ent, char *s)
- {
- int playernum = ent-g_edicts-1;
- char *p;
- char t[64];
- Com_sprintf(t, sizeof(t), "%s", s);
- if ((p = strchr(t, '/')) != NULL)
- p[1] = 0;
- else
- strcpy(t, "male/");
- switch (ent->client->resp.ctf_team) {
- case CTF_TEAM1:
- gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s%s",
- ent->client->pers.netname, t, CTF_TEAM1_SKIN) );
- break;
- case CTF_TEAM2:
- gi.configstring (CS_PLAYERSKINS+playernum,
- va("%s\\%s%s", ent->client->pers.netname, t, CTF_TEAM2_SKIN) );
- break;
- default:
- gi.configstring (CS_PLAYERSKINS+playernum,
- va("%s\\%s", ent->client->pers.netname, s) );
- break;
- }
- // gi.cprintf(ent, PRINT_HIGH, "You have been assigned to %s team.\n", ent->client->pers.netname);
- }
- void CTFAssignTeam(gclient_t *who)
- {
- edict_t *player;
- int i;
- int team1count = 0, team2count = 0;
- who->resp.ctf_state = 0;
- if (!((int)dmflags->value & DF_CTF_FORCEJOIN)) {
- who->resp.ctf_team = CTF_NOTEAM;
- return;
- }
- for (i = 1; i <= maxclients->value; i++) {
- player = &g_edicts[i];
- if (!player->inuse || player->client == who)
- continue;
- switch (player->client->resp.ctf_team) {
- case CTF_TEAM1:
- team1count++;
- break;
- case CTF_TEAM2:
- team2count++;
- }
- }
- if (team1count < team2count)
- who->resp.ctf_team = CTF_TEAM1;
- else if (team2count < team1count)
- who->resp.ctf_team = CTF_TEAM2;
- else if (rand() & 1)
- who->resp.ctf_team = CTF_TEAM1;
- else
- who->resp.ctf_team = CTF_TEAM2;
- }
- /*
- ================
- SelectCTFSpawnPoint
- go to a ctf point, but NOT the two points closest
- to other players
- ================
- */
- edict_t *SelectCTFSpawnPoint (edict_t *ent)
- {
- edict_t *spot, *spot1, *spot2;
- int count = 0;
- int selection;
- float range, range1, range2;
- char *cname;
- if (ent->client->resp.ctf_state)
- if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST)
- return SelectFarthestDeathmatchSpawnPoint ();
- else
- return SelectRandomDeathmatchSpawnPoint ();
- ent->client->resp.ctf_state++;
- switch (ent->client->resp.ctf_team) {
- case CTF_TEAM1:
- cname = "info_player_team1";
- break;
- case CTF_TEAM2:
- cname = "info_player_team2";
- break;
- default:
- return SelectRandomDeathmatchSpawnPoint();
- }
- spot = NULL;
- range1 = range2 = 99999;
- spot1 = spot2 = NULL;
- while ((spot = G_Find (spot, FOFS(classname), cname)) != NULL)
- {
- count++;
- range = PlayersRangeFromSpot(spot);
- if (range < range1)
- {
- range1 = range;
- spot1 = spot;
- }
- else if (range < range2)
- {
- range2 = range;
- spot2 = spot;
- }
- }
- if (!count)
- return SelectRandomDeathmatchSpawnPoint();
- if (count <= 2)
- {
- spot1 = spot2 = NULL;
- }
- else
- count -= 2;
- selection = rand() % count;
- spot = NULL;
- do
- {
- spot = G_Find (spot, FOFS(classname), cname);
- if (spot == spot1 || spot == spot2)
- selection++;
- } while(selection--);
- return spot;
- }
- /*------------------------------------------------------------------------*/
- /*
- CTFFragBonuses
- Calculate the bonuses for flag defense, flag carrier defense, etc.
- Note that bonuses are not cumaltive. You get one, they are in importance
- order.
- */
- void CTFFragBonuses(edict_t *targ, edict_t *inflictor, edict_t *attacker)
- {
- int i;
- edict_t *ent;
- gitem_t *flag_item, *enemy_flag_item;
- int otherteam;
- edict_t *flag, *carrier;
- char *c;
- vec3_t v1, v2;
- if (targ->client && attacker->client) {
- if (attacker->client->resp.ghost)
- if (attacker != targ)
- attacker->client->resp.ghost->kills++;
- if (targ->client->resp.ghost)
- targ->client->resp.ghost->deaths++;
- }
- // no bonus for fragging yourself
- if (!targ->client || !attacker->client || targ == attacker)
- return;
- otherteam = CTFOtherTeam(targ->client->resp.ctf_team);
- if (otherteam < 0)
- return; // whoever died isn't on a team
- // same team, if the flag at base, check to he has the enemy flag
- if (targ->client->resp.ctf_team == CTF_TEAM1) {
- flag_item = flag1_item;
- enemy_flag_item = flag2_item;
- } else {
- flag_item = flag2_item;
- enemy_flag_item = flag1_item;
- }
- // did the attacker frag the flag carrier?
- if (targ->client->pers.inventory[ITEM_INDEX(enemy_flag_item)]) {
- attacker->client->resp.ctf_lastfraggedcarrier = level.time;
- attacker->client->resp.score += CTF_FRAG_CARRIER_BONUS;
- gi.cprintf(attacker, PRINT_MEDIUM, "BONUS: %d points for fragging enemy flag carrier.\n",
- CTF_FRAG_CARRIER_BONUS);
- // the target had the flag, clear the hurt carrier
- // field on the other team
- for (i = 1; i <= maxclients->value; i++) {
- ent = g_edicts + i;
- if (ent->inuse && ent->client->resp.ctf_team == otherteam)
- ent->client->resp.ctf_lasthurtcarrier = 0;
- }
- return;
- }
- if (targ->client->resp.ctf_lasthurtcarrier &&
- level.time - targ->client->resp.ctf_lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT &&
- !attacker->client->pers.inventory[ITEM_INDEX(flag_item)]) {
- // attacker is on the same team as the flag carrier and
- // fragged a guy who hurt our flag carrier
- attacker->client->resp.score += CTF_CARRIER_DANGER_PROTECT_BONUS;
- gi.bprintf(PRINT_MEDIUM, "%s defends %s's flag carrier against an agressive enemy\n",
- attacker->client->pers.netname,
- CTFTeamName(attacker->client->resp.ctf_team));
- if (attacker->client->resp.ghost)
- attacker->client->resp.ghost->carrierdef++;
- return;
- }
- // flag and flag carrier area defense bonuses
- // we have to find the flag and carrier entities
- // find the flag
- switch (attacker->client->resp.ctf_team) {
- case CTF_TEAM1:
- c = "item_flag_team1";
- break;
- case CTF_TEAM2:
- c = "item_flag_team2";
- break;
- default:
- return;
- }
- flag = NULL;
- while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
- if (!(flag->spawnflags & DROPPED_ITEM))
- break;
- }
- if (!flag)
- return; // can't find attacker's flag
- // find attacker's team's flag carrier
- for (i = 1; i <= maxclients->value; i++) {
- carrier = g_edicts + i;
- if (carrier->inuse &&
- carrier->client->pers.inventory[ITEM_INDEX(flag_item)])
- break;
- carrier = NULL;
- }
- // ok we have the attackers flag and a pointer to the carrier
- // check to see if we are defending the base's flag
- VectorSubtract(targ->s.origin, flag->s.origin, v1);
- VectorSubtract(attacker->s.origin, flag->s.origin, v2);
- if ((VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS ||
- VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS ||
- loc_CanSee(flag, targ) || loc_CanSee(flag, attacker)) &&
- attacker->client->resp.ctf_team != targ->client->resp.ctf_team) {
- // we defended the base flag
- attacker->client->resp.score += CTF_FLAG_DEFENSE_BONUS;
- if (flag->solid == SOLID_NOT)
- gi.bprintf(PRINT_MEDIUM, "%s defends the %s base.\n",
- attacker->client->pers.netname,
- CTFTeamName(attacker->client->resp.ctf_team));
- else
- gi.bprintf(PRINT_MEDIUM, "%s defends the %s flag.\n",
- attacker->client->pers.netname,
- CTFTeamName(attacker->client->resp.ctf_team));
- if (attacker->client->resp.ghost)
- attacker->client->resp.ghost->basedef++;
- return;
- }
- if (carrier && carrier != attacker) {
- VectorSubtract(targ->s.origin, carrier->s.origin, v1);
- VectorSubtract(attacker->s.origin, carrier->s.origin, v1);
- if (VectorLength(v1) < CTF_ATTACKER_PROTECT_RADIUS ||
- VectorLength(v2) < CTF_ATTACKER_PROTECT_RADIUS ||
- loc_CanSee(carrier, targ) || loc_CanSee(carrier, attacker)) {
- attacker->client->resp.score += CTF_CARRIER_PROTECT_BONUS;
- gi.bprintf(PRINT_MEDIUM, "%s defends the %s's flag carrier.\n",
- attacker->client->pers.netname,
- CTFTeamName(attacker->client->resp.ctf_team));
- if (attacker->client->resp.ghost)
- attacker->client->resp.ghost->carrierdef++;
- return;
- }
- }
- }
- void CTFCheckHurtCarrier(edict_t *targ, edict_t *attacker)
- {
- gitem_t *flag_item;
- if (!targ->client || !attacker->client)
- return;
- if (targ->client->resp.ctf_team == CTF_TEAM1)
- flag_item = flag2_item;
- else
- flag_item = flag1_item;
- if (targ->client->pers.inventory[ITEM_INDEX(flag_item)] &&
- targ->client->resp.ctf_team != attacker->client->resp.ctf_team)
- attacker->client->resp.ctf_lasthurtcarrier = level.time;
- }
- /*------------------------------------------------------------------------*/
- void CTFResetFlag(int ctf_team)
- {
- char *c;
- edict_t *ent;
- switch (ctf_team) {
- case CTF_TEAM1:
- c = "item_flag_team1";
- break;
- case CTF_TEAM2:
- c = "item_flag_team2";
- break;
- default:
- return;
- }
- ent = NULL;
- while ((ent = G_Find (ent, FOFS(classname), c)) != NULL) {
- if (ent->spawnflags & DROPPED_ITEM)
- G_FreeEdict(ent);
- else {
- ent->svflags &= ~SVF_NOCLIENT;
- ent->solid = SOLID_TRIGGER;
- gi.linkentity(ent);
- ent->s.event = EV_ITEM_RESPAWN;
- }
- }
- }
- void CTFResetFlags(void)
- {
- CTFResetFlag(CTF_TEAM1);
- CTFResetFlag(CTF_TEAM2);
- }
- qboolean CTFPickup_Flag(edict_t *ent, edict_t *other)
- {
- int ctf_team;
- int i;
- edict_t *player;
- gitem_t *flag_item, *enemy_flag_item;
- // figure out what team this flag is
- if (strcmp(ent->classname, "item_flag_team1") == 0)
- ctf_team = CTF_TEAM1;
- else if (strcmp(ent->classname, "item_flag_team2") == 0)
- ctf_team = CTF_TEAM2;
- else {
- gi.cprintf(ent, PRINT_HIGH, "Don't know what team the flag is on.\n");
- return false;
- }
- // same team, if the flag at base, check to he has the enemy flag
- if (ctf_team == CTF_TEAM1) {
- flag_item = flag1_item;
- enemy_flag_item = flag2_item;
- } else {
- flag_item = flag2_item;
- enemy_flag_item = flag1_item;
- }
- if (ctf_team == other->client->resp.ctf_team) {
- if (!(ent->spawnflags & DROPPED_ITEM)) {
- // the flag is at home base. if the player has the enemy
- // flag, he's just won!
-
- if (other->client->pers.inventory[ITEM_INDEX(enemy_flag_item)]) {
- gi.bprintf(PRINT_HIGH, "%s captured the %s flag!\n",
- other->client->pers.netname, CTFOtherTeamName(ctf_team));
- other->client->pers.inventory[ITEM_INDEX(enemy_flag_item)] = 0;
- ctfgame.last_flag_capture = level.time;
- ctfgame.last_capture_team = ctf_team;
- if (ctf_team == CTF_TEAM1)
- ctfgame.team1++;
- else
- ctfgame.team2++;
- gi.sound (ent, CHAN_RELIABLE+CHAN_NO_PHS_ADD+CHAN_VOICE, gi.soundindex("ctf/flagcap.wav"), 1, ATTN_NONE, 0);
- // other gets another 10 frag bonus
- other->client->resp.score += CTF_CAPTURE_BONUS;
- if (other->client->resp.ghost)
- other->client->resp.ghost->caps++;
- // Ok, let's do the player loop, hand out the bonuses
- for (i = 1; i <= maxclients->value; i++) {
- player = &g_edicts[i];
- if (!player->inuse)
- continue;
- if (player->client->resp.ctf_team != other->client->resp.ctf_team)
- player->client->resp.ctf_lasthurtcarrier = -5;
- else if (player->client->resp.ctf_team == other->client->resp.ctf_team) {
- if (player != other)
- player->client->resp.score += CTF_TEAM_BONUS;
- // award extra points for capture assists
- if (player->client->resp.ctf_lastreturnedflag + CTF_RETURN_FLAG_ASSIST_TIMEOUT > level.time) {
- gi.bprintf(PRINT_HIGH, "%s gets an assist for returning the flag!\n", player->client->pers.netname);
- player->client->resp.score += CTF_RETURN_FLAG_ASSIST_BONUS;
- }
- if (player->client->resp.ctf_lastfraggedcarrier + CTF_FRAG_CARRIER_ASSIST_TIMEOUT > level.time) {
- gi.bprintf(PRINT_HIGH, "%s gets an assist for fragging the flag carrier!\n", player->client->pers.netname);
- player->client->resp.score += CTF_FRAG_CARRIER_ASSIST_BONUS;
- }
- }
- }
- CTFResetFlags();
- return false;
- }
- return false; // its at home base already
- }
- // hey, its not home. return it by teleporting it back
- gi.bprintf(PRINT_HIGH, "%s returned the %s flag!\n",
- other->client->pers.netname, CTFTeamName(ctf_team));
- other->client->resp.score += CTF_RECOVERY_BONUS;
- other->client->resp.ctf_lastreturnedflag = level.time;
- gi.sound (ent, CHAN_RELIABLE+CHAN_NO_PHS_ADD+CHAN_VOICE, gi.soundindex("ctf/flagret.wav"), 1, ATTN_NONE, 0);
- //CTFResetFlag will remove this entity! We must return false
- CTFResetFlag(ctf_team);
- return false;
- }
- // hey, its not our flag, pick it up
- gi.bprintf(PRINT_HIGH, "%s got the %s flag!\n",
- other->client->pers.netname, CTFTeamName(ctf_team));
- other->client->resp.score += CTF_FLAG_BONUS;
- other->client->pers.inventory[ITEM_INDEX(flag_item)] = 1;
- other->client->resp.ctf_flagsince = level.time;
- // pick up the flag
- // if it's not a dropped flag, we just make is disappear
- // if it's dropped, it will be removed by the pickup caller
- if (!(ent->spawnflags & DROPPED_ITEM)) {
- ent->flags |= FL_RESPAWN;
- ent->svflags |= SVF_NOCLIENT;
- ent->solid = SOLID_NOT;
- }
- return true;
- }
- static void CTFDropFlagTouch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
- {
- //owner (who dropped us) can't touch for two secs
- if (other == ent->owner &&
- ent->nextthink - level.time > CTF_AUTO_FLAG_RETURN_TIMEOUT-2)
- return;
- Touch_Item (ent, other, plane, surf);
- }
- static void CTFDropFlagThink(edict_t *ent)
- {
- // auto return the flag
- // reset flag will remove ourselves
- if (strcmp(ent->classname, "item_flag_team1") == 0) {
- CTFResetFlag(CTF_TEAM1);
- gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
- CTFTeamName(CTF_TEAM1));
- } else if (strcmp(ent->classname, "item_flag_team2") == 0) {
- CTFResetFlag(CTF_TEAM2);
- gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
- CTFTeamName(CTF_TEAM2));
- }
- }
- // Called from PlayerDie, to drop the flag from a dying player
- void CTFDeadDropFlag(edict_t *self)
- {
- edict_t *dropped = NULL;
- if (self->client->pers.inventory[ITEM_INDEX(flag1_item)]) {
- dropped = Drop_Item(self, flag1_item);
- self->client->pers.inventory[ITEM_INDEX(flag1_item)] = 0;
- gi.bprintf(PRINT_HIGH, "%s lost the %s flag!\n",
- self->client->pers.netname, CTFTeamName(CTF_TEAM1));
- } else if (self->client->pers.inventory[ITEM_INDEX(flag2_item)]) {
- dropped = Drop_Item(self, flag2_item);
- self->client->pers.inventory[ITEM_INDEX(flag2_item)] = 0;
- gi.bprintf(PRINT_HIGH, "%s lost the %s flag!\n",
- self->client->pers.netname, CTFTeamName(CTF_TEAM2));
- }
- if (dropped) {
- dropped->think = CTFDropFlagThink;
- dropped->nextthink = level.time + CTF_AUTO_FLAG_RETURN_TIMEOUT;
- dropped->touch = CTFDropFlagTouch;
- }
- }
- qboolean CTFDrop_Flag(edict_t *ent, gitem_t *item)
- {
- if (rand() & 1)
- gi.cprintf(ent, PRINT_HIGH, "Only lusers drop flags.\n");
- else
- gi.cprintf(ent, PRINT_HIGH, "Winners don't drop flags.\n");
- return false;
- }
- static void CTFFlagThink(edict_t *ent)
- {
- if (ent->solid != SOLID_NOT)
- ent->s.frame = 173 + (((ent->s.frame - 173) + 1) % 16);
- ent->nextthink = level.time + FRAMETIME;
- }
- void CTFFlagSetup (edict_t *ent)
- {
- trace_t tr;
- vec3_t dest;
- float *v;
- v = tv(-15,-15,-15);
- VectorCopy (v, ent->mins);
- v = tv(15,15,15);
- VectorCopy (v, ent->maxs);
- if (ent->model)
- gi.setmodel (ent, ent->model);
- else
- gi.setmodel (ent, ent->item->world_model);
- ent->solid = SOLID_TRIGGER;
- ent->movetype = MOVETYPE_TOSS;
- ent->touch = Touch_Item;
- v = tv(0,0,-128);
- VectorAdd (ent->s.origin, v, dest);
- tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID);
- if (tr.startsolid)
- {
- gi.dprintf ("CTFFlagSetup: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
- G_FreeEdict (ent);
- return;
- }
- VectorCopy (tr.endpos, ent->s.origin);
- gi.linkentity (ent);
- ent->nextthink = level.time + FRAMETIME;
- ent->think = CTFFlagThink;
- }
- void CTFEffects(edict_t *player)
- {
- player->s.effects &= ~(EF_FLAG1 | EF_FLAG2);
- if (player->health > 0) {
- if (player->client->pers.inventory[ITEM_INDEX(flag1_item)]) {
- player->s.effects |= EF_FLAG1;
- }
- if (player->client->pers.inventory[ITEM_INDEX(flag2_item)]) {
- player->s.effects |= EF_FLAG2;
- }
- }
- if (player->client->pers.inventory[ITEM_INDEX(flag1_item)])
- player->s.modelindex3 = gi.modelindex("players/male/flag1.md2");
- else if (player->client->pers.inventory[ITEM_INDEX(flag2_item)])
- player->s.modelindex3 = gi.modelindex("players/male/flag2.md2");
- else
- player->s.modelindex3 = 0;
- }
- // called when we enter the intermission
- void CTFCalcScores(void)
- {
- int i;
- ctfgame.total1 = ctfgame.total2 = 0;
- for (i = 0; i < maxclients->value; i++) {
- if (!g_edicts[i+1].inuse)
- continue;
- if (game.clients[i].resp.ctf_team == CTF_TEAM1)
- ctfgame.total1 += game.clients[i].resp.score;
- else if (game.clients[i].resp.ctf_team == CTF_TEAM2)
- ctfgame.total2 += game.clients[i].resp.score;
- }
- }
- void CTFID_f (edict_t *ent)
- {
- if (ent->client->resp.id_state) {
- gi.cprintf(ent, PRINT_HIGH, "Disabling player identication display.\n");
- ent->client->resp.id_state = false;
- } else {
- gi.cprintf(ent, PRINT_HIGH, "Activating player identication display.\n");
- ent->client->resp.id_state = true;
- }
- }
- static void CTFSetIDView(edict_t *ent)
- {
- vec3_t forward, dir;
- trace_t tr;
- edict_t *who, *best;
- float bd = 0, d;
- int i;
- // only check every few frames
- if (level.time - ent->client->resp.lastidtime < 0.25)
- return;
- ent->client->resp.lastidtime = level.time;
- ent->client->ps.stats[STAT_CTF_ID_VIEW] = 0;
- ent->client->ps.stats[STAT_CTF_ID_VIEW_COLOR] = 0;
- AngleVectors(ent->client->v_angle, forward, NULL, NULL);
- VectorScale(forward, 1024, forward);
- VectorAdd(ent->s.origin, forward, forward);
- tr = gi.trace(ent->s.origin, NULL, NULL, forward, ent, MASK_SOLID);
- if (tr.fraction < 1 && tr.ent && tr.ent->client) {
- ent->client->ps.stats[STAT_CTF_ID_VIEW] =
- CS_GENERAL + (tr.ent - g_edicts - 1);
- if (tr.ent->client->resp.ctf_team == CTF_TEAM1)
- ent->client->ps.stats[STAT_CTF_ID_VIEW_COLOR] = imageindex_sbfctf1;
- else if (tr.ent->client->resp.ctf_team == CTF_TEAM2)
- ent->client->ps.stats[STAT_CTF_ID_VIEW_COLOR] = imageindex_sbfctf2;
- return;
- }
- AngleVectors(ent->client->v_angle, forward, NULL, NULL);
- best = NULL;
- for (i = 1; i <= maxclients->value; i++) {
- who = g_edicts + i;
- if (!who->inuse || who->solid == SOLID_NOT)
- continue;
- VectorSubtract(who->s.origin, ent->s.origin, dir);
- VectorNormalize(dir);
- d = DotProduct(forward, dir);
- if (d > bd && loc_CanSee(ent, who)) {
- bd = d;
- best = who;
- }
- }
- if (bd > 0.90) {
- ent->client->ps.stats[STAT_CTF_ID_VIEW] =
- CS_GENERAL + (best - g_edicts - 1);
- if (best->client->resp.ctf_team == CTF_TEAM1)
- ent->client->ps.stats[STAT_CTF_ID_VIEW_COLOR] = imageindex_sbfctf1;
- else if (best->client->resp.ctf_team == CTF_TEAM2)
- ent->client->ps.stats[STAT_CTF_ID_VIEW_COLOR] = imageindex_sbfctf2;
- }
- }
- void SetCTFStats(edict_t *ent)
- {
- gitem_t *tech;
- int i;
- int p1, p2;
- edict_t *e;
- if (ctfgame.match > MATCH_NONE)
- ent->client->ps.stats[STAT_CTF_MATCH] = CONFIG_CTF_MATCH;
- else
- ent->client->ps.stats[STAT_CTF_MATCH] = 0;
- if (ctfgame.warnactive)
- ent->client->ps.stats[STAT_CTF_TEAMINFO] = CONFIG_CTF_TEAMINFO;
- else
- ent->client->ps.stats[STAT_CTF_TEAMINFO] = 0;
- //ghosting
- if (ent->client->resp.ghost) {
- ent->client->resp.ghost->score = ent->client->resp.score;
- strcpy(ent->client->resp.ghost->netname, ent->client->pers.netname);
- ent->client->resp.ghost->number = ent->s.number;
- }
- // logo headers for the frag display
- ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = imageindex_ctfsb1;
- ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = imageindex_ctfsb2;
- // if during intermission, we must blink the team header of the winning team
- if (level.intermissiontime && (level.framenum & 8)) { // blink 1/8th second
- // note that ctfgame.total[12] is set when we go to intermission
- if (ctfgame.team1 > ctfgame.team2)
- ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
- else if (ctfgame.team2 > ctfgame.team1)
- ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
- else if (ctfgame.total1 > ctfgame.total2) // frag tie breaker
- ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
- else if (ctfgame.total2 > ctfgame.total1)
- ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
- else { // tie game!
- ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
- ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
- }
- }
- // tech icon
- i = 0;
- ent->client->ps.stats[STAT_CTF_TECH] = 0;
- while (tnames[i]) {
- if ((tech = FindItemByClassname(tnames[i])) != NULL &&
- ent->client->pers.inventory[ITEM_INDEX(tech)]) {
- ent->client->ps.stats[STAT_CTF_TECH] = gi.imageindex(tech->icon);
- break;
- }
- i++;
- }
- // figure out what icon to display for team logos
- // three states:
- // flag at base
- // flag taken
- // flag dropped
- p1 = imageindex_i_ctf1;
- e = G_Find(NULL, FOFS(classname), "item_flag_team1");
- if (e != NULL) {
- if (e->solid == SOLID_NOT) {
- int i;
- // not at base
- // check if on player
- p1 = imageindex_i_ctf1d; // default to dropped
- for (i = 1; i <= maxclients->value; i++)
- if (g_edicts[i].inuse &&
- g_edicts[i].client->pers.inventory[ITEM_INDEX(flag1_item)]) {
- // enemy has it
- p1 = imageindex_i_ctf1t;
- break;
- }
- } else if (e->spawnflags & DROPPED_ITEM)
- p1 = imageindex_i_ctf1d; // must be dropped
- }
- p2 = imageindex_i_ctf2;
- e = G_Find(NULL, FOFS(classname), "item_flag_team2");
- if (e != NULL) {
- if (e->solid == SOLID_NOT) {
- int i;
- // not at base
- // check if on player
- p2 = imageindex_i_ctf2d; // default to dropped
- for (i = 1; i <= maxclients->value; i++)
- if (g_edicts[i].inuse &&
- g_edicts[i].client->pers.inventory[ITEM_INDEX(flag2_item)]) {
- // enemy has it
- p2 = imageindex_i_ctf2t;
- break;
- }
- } else if (e->spawnflags & DROPPED_ITEM)
- p2 = imageindex_i_ctf2d; // must be dropped
- }
- ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = p1;
- ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = p2;
- if (ctfgame.last_flag_capture && level.time - ctfgame.last_flag_capture < 5) {
- if (ctfgame.last_capture_team == CTF_TEAM1)
- if (level.framenum & 8)
- ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = p1;
- else
- ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = 0;
- else
- if (level.framenum & 8)
- ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = p2;
- else
- ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = 0;
- }
- ent->client->ps.stats[STAT_CTF_TEAM1_CAPS] = ctfgame.team1;
- ent->client->ps.stats[STAT_CTF_TEAM2_CAPS] = ctfgame.team2;
- ent->client->ps.stats[STAT_CTF_FLAG_PIC] = 0;
- if (ent->client->resp.ctf_team == CTF_TEAM1 &&
- ent->client->pers.inventory[ITEM_INDEX(flag2_item)] &&
- (level.framenum & 8))
- ent->client->ps.stats[STAT_CTF_FLAG_PIC] = imageindex_i_ctf2;
- else if (ent->client->resp.ctf_team == CTF_TEAM2 &&
- ent->client->pers.inventory[ITEM_INDEX(flag1_item)] &&
- (level.framenum & 8))
- ent->client->ps.stats[STAT_CTF_FLAG_PIC] = imageindex_i_ctf1;
- ent->client->ps.stats[STAT_CTF_JOINED_TEAM1_PIC] = 0;
- ent->client->ps.stats[STAT_CTF_JOINED_TEAM2_PIC] = 0;
- if (ent->client->resp.ctf_team == CTF_TEAM1)
- ent->client->ps.stats[STAT_CTF_JOINED_TEAM1_PIC] = imageindex_i_ctfj;
- else if (ent->client->resp.ctf_team == CTF_TEAM2)
- ent->client->ps.stats[STAT_CTF_JOINED_TEAM2_PIC] = imageindex_i_ctfj;
- if (ent->client->resp.id_state)
- CTFSetIDView(ent);
- else {
- ent->client->ps.stats[STAT_CTF_ID_VIEW] = 0;
- ent->client->ps.stats[STAT_CTF_ID_VIEW_COLOR] = 0;
- }
- }
- /*------------------------------------------------------------------------*/
- /*QUAKED info_player_team1 (1 0 0) (-16 -16 -24) (16 16 32)
- potential team1 spawning position for ctf games
- */
- void SP_info_player_team1(edict_t *self)
- {
- }
- /*QUAKED info_player_team2 (0 0 1) (-16 -16 -24) (16 16 32)
- potential team2 spawning position for ctf games
- */
- void SP_info_player_team2(edict_t *self)
- {
- }
- /*------------------------------------------------------------------------*/
- /* GRAPPLE */
- /*------------------------------------------------------------------------*/
- // ent is player
- void CTFPlayerResetGrapple(edict_t *ent)
- {
- if (ent->client && ent->client->ctf_grapple)
- CTFResetGrapple(ent->client->ctf_grapple);
- }
- // self is grapple, not player
- void CTFResetGrapple(edict_t *self)
- {
- if (self->owner->client->ctf_grapple) {
- float volume = 1.0;
- gclient_t *cl;
- if (self->owner->client->silencer_shots)
- volume = 0.2;
- gi.sound (self->owner, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grreset.wav"), volume, ATTN_NORM, 0);
- cl = self->owner->client;
- cl->ctf_grapple = NULL;
- cl->ctf_grapplereleasetime = level.time;
- cl->ctf_grapplestate = CTF_GRAPPLE_STATE_FLY; // we're firing, not on hook
- cl->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
- G_FreeEdict(self);
- }
- }
- void CTFGrappleTouch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
- {
- float volume = 1.0;
- if (other == self->owner)
- return;
- if (self->owner->client->ctf_grapplestate != CTF_GRAPPLE_STATE_FLY)
- return;
- if (surf && (surf->flags & SURF_SKY))
- {
- CTFResetGrapple(self);
- return;
- }
- VectorCopy(vec3_origin, self->velocity);
- PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
- if (other->takedamage) {
- T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, 0, MOD_GRAPPLE);
- CTFResetGrapple(self);
- return;
- }
- self->owner->client->ctf_grapplestate = CTF_GRAPPLE_STATE_PULL; // we're on hook
- self->enemy = other;
- self->solid = SOLID_NOT;
- if (self->owner->client->silencer_shots)
- volume = 0.2;
- gi.sound (self->owner, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grpull.wav"), volume, ATTN_NORM, 0);
- gi.sound (self, CHAN_WEAPON, gi.soundindex("weapons/grapple/grhit.wav"), volume, ATTN_NORM, 0);
- gi.WriteByte (svc_temp_entity);
- gi.WriteByte (TE_SPARKS);
- gi.WritePosition (self->s.origin);
- if (!plane)
- gi.WriteDir (vec3_origin);
- else
- gi.WriteDir (plane->normal);
- gi.multicast (self->s.origin, MULTICAST_PVS);
- }
- // draw beam between grapple and self
- void CTFGrappleDrawCable(edict_t *self)
- {
- vec3_t offset, start, end, f, r;
- vec3_t dir;
- float distance;
- AngleVectors (self->owner->client->v_angle, f, r, NULL);
- VectorSet(offset, 16, 16, self->owner->viewheight-8);
- P_ProjectSource (self->owner->client, self->owner->s.origin, offset, f, r, start);
- VectorSubtract(start, self->owner->s.origin, offset);
- VectorSubtract (start, self->s.origin, dir);
- distance = VectorLength(dir);
- // don't draw cable if close
- if (distance < 64)
- return;
- #if 0
- if (distance > 256)
- return;
- // check for min/max pitch
- vectoangles (dir, angles);
- if (angles[0] < -180)
- angles[0] += 360;
- if (fabs(angles[0]) > 45)
- return;
- trace_t tr; //!!
- tr = gi.trace (start, NULL, NULL, self->s.origin, self, MASK_SHOT);
- if (tr.ent != self) {
- CTFResetGrapple(self);
- return;
- }
- #endif
- // adjust start for beam origin being in middle of a segment
- // VectorMA (start, 8, f, start);
- VectorCopy (self->s.origin, end);
- // adjust end z for end spot since the monster is currently dead
- // end[2] = self->absmin[2] + self->size[2] / 2;
- gi.WriteByte (svc_temp_entity);
- #if 1 //def USE_GRAPPLE_CABLE
- gi.WriteByte (TE_GRAPPLE_CABLE);
- gi.WriteShort (self->owner - g_edicts);
- gi.WritePosition (self->owner->s.origin);
- gi.WritePosition (end);
- gi.WritePosition (offset);
- #else
- gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
- gi.WriteShort (self - g_edicts);
- gi.WritePosition (end);
- gi.WritePosition (start);
- #endif
- gi.multicast (self->s.origin, MULTICAST_PVS);
- }
- void SV_AddGravity (edict_t *ent);
- // pull the player toward the grapple
- void CTFGrapplePull(edict_t *self)
- {
- vec3_t hookdir, v;
- float vlen;
- if (strcmp(self->owner->client->pers.weapon->classname, "weapon_grapple") == 0 &&
- !self->owner->client->newweapon &&
- self->owner->client->weaponstate != WEAPON_FIRING &&
- self->owner->client->weaponstate != WEAPON_ACTIVATING) {
- CTFResetGrapple(self);
- return;
- }
- if (self->enemy) {
- if (self->enemy->solid == SOLID_NOT) {
- CTFResetGrapple(self);
- return;
- }
- if (self->enemy->solid == SOLID_BBOX) {
- VectorScale(self->enemy->size, 0.5, v);
- VectorAdd(v, self->enemy->s.origin, v);
- VectorAdd(v, self->enemy->mins, self->s.origin);
- gi.linkentity (self);
- } else
- VectorCopy(self->enemy->velocity, self->velocity);
- if (self->enemy->takedamage &&
- !CheckTeamDamage (self->enemy, self->owner)) {
- float volume = 1.0;
- if (self->owner->client->silencer_shots)
- volume = 0.2;
- T_Damage (self->enemy, self, self->owner, self->velocity, self->s.origin, vec3_origin, 1, 1, 0, MOD_GRAPPLE);
- gi.sound (self, CHAN_WEAPON, gi.soundindex("weapons/grapple/grhurt.wav"), volume, ATTN_NORM, 0);
- }
- if (self->enemy->deadflag) { // he died
- CTFResetGrapple(self);
- return;
- }
- }
- CTFGrappleDrawCable(self);
- if (self->owner->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY) {
- // pull player toward grapple
- // this causes icky stuff with prediction, we need to extend
- // the prediction layer to include two new fields in the player
- // move stuff: a point and a velocity. The client should add
- // that velociy in the direction of the point
- vec3_t forward, up;
- AngleVectors (self->owner->client->v_angle, forward, NULL, up);
- VectorCopy(self->owner->s.origin, v);
- v[2] += self->owner->viewheight;
- VectorSubtract (self->s.origin, v, hookdir);
- vlen = VectorLength(hookdir);
- if (self->owner->client->ctf_grapplestate == CTF_GRAPPLE_STATE_PULL &&
- vlen < 64) {
- float volume = 1.0;
- if (self->owner->client->silencer_shots)
- volume = 0.2;
- self->owner->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
- gi.sound (self->owner, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grhang.wav"), volume, ATTN_NORM, 0);
- self->owner->client->ctf_grapplestate = CTF_GRAPPLE_STATE_HANG;
- }
- VectorNormalize (hookdir);
- VectorScale(hookdir, CTF_GRAPPLE_PULL_SPEED, hookdir);
- VectorCopy(hookdir, self->owner->velocity);
- SV_AddGravity(self->owner);
- }
- }
- void CTFFireGrapple (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect)
- {
- edict_t *grapple;
- trace_t tr;
- VectorNormalize (dir);
- grapple = G_Spawn();
- VectorCopy (start, grapple->s.origin);
- VectorCopy (start, grapple->s.old_origin);
- vectoangles (dir, grapple->s.angles);
- VectorScale (dir, speed, grapple->velocity);
- grapple->movetype = MOVETYPE_FLYMISSILE;
- grapple->clipmask = MASK_SHOT;
- grapple->solid = SOLID_BBOX;
- grapple->s.effects |= effect;
- VectorClear (grapple->mins);
- VectorClear (grapple->maxs);
- grapple->s.modelindex = gi.modelindex ("models/weapons/grapple/hook/tris.md2");
- // grapple->s.sound = gi.soundindex ("misc/lasfly.wav");
- grapple->owner = self;
- grapple->touch = CTFGrappleTouch;
- // grapple->nextthink = level.time + FRAMETIME;
- // grapple->think = CTFGrappleThink;
- grapple->dmg = damage;
- self->client->ctf_grapple = grapple;
- self->client->ctf_grapplestate = CTF_GRAPPLE_STATE_FLY; // we're firing, not on hook
- gi.linkentity (grapple);
- tr = gi.trace (self->s.origin, NULL, NULL, grapple->s.origin, grapple, MASK_SHOT);
- if (tr.fraction < 1.0)
- {
- VectorMA (grapple->s.origin, -10, dir, grapple->s.origin);
- grapple->touch (grapple, tr.ent, NULL, NULL);
- }
- }
- void CTFGrappleFire (edict_t *ent, vec3_t g_offset, int damage, int effect)
- {
- vec3_t forward, right;
- vec3_t start;
- vec3_t offset;
- float volume = 1.0;
- if (ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY)
- return; // it's already out
- AngleVectors (ent->client->v_angle, forward, right, NULL);
- // VectorSet(offset, 24, 16, ent->viewheight-8+2);
- VectorSet(offset, 24, 8, ent->viewheight-8+2);
- VectorAdd (offset, g_offset, offset);
- P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
- VectorScale (forward, -2, ent->client->kick_origin);
- ent->client->kick_angles[0] = -1;
- if (ent->client->silencer_shots)
- volume = 0.2;
- gi.sound (ent, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grfire.wav"), volume, ATTN_NORM, 0);
- CTFFireGrapple (ent, start, forward, damage, CTF_GRAPPLE_SPEED, effect);
- #if 0
- // send muzzle flash
- gi.WriteByte (svc_muzzleflash);
- gi.WriteShort (ent-g_edicts);
- gi.WriteByte (MZ_BLASTER);
- gi.multicast (ent->s.origin, MULTICAST_PVS);
- #endif
- PlayerNoise(ent, start, PNOISE_WEAPON);
- }
- void CTFWeapon_Grapple_Fire (edict_t *ent)
- {
- int damage;
- damage = 10;
- CTFGrappleFire (ent, vec3_origin, damage, 0);
- ent->client->ps.gunframe++;
- }
- void CTFWeapon_Grapple (edict_t *ent)
- {
- static int pause_frames[] = {10, 18, 27, 0};
- static int fire_frames[] = {6, 0};
- int prevstate;
- // if the the attack button is still down, stay in the firing frame
- if ((ent->client->buttons & BUTTON_ATTACK) &&
- ent->client->weaponstate == WEAPON_FIRING &&
- ent->client->ctf_grapple)
- ent->client->ps.gunframe = 9;
- if (!(ent->client->buttons & BUTTON_ATTACK) &&
- ent->client->ctf_grapple) {
- CTFResetGrapple(ent->client->ctf_grapple);
- if (ent->client->weaponstate == WEAPON_FIRING)
- ent->client->weaponstate = WEAPON_READY;
- }
- if (ent->client->newweapon &&
- ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY &&
- ent->client->weaponstate == WEAPON_FIRING) {
- // he wants to change weapons while grappled
- ent->client->weaponstate = WEAPON_DROPPING;
- ent->client->ps.gunframe = 32;
- }
- prevstate = ent->client->weaponstate;
- Weapon_Generic (ent, 5, 9, 31, 36, pause_frames, fire_frames,
- CTFWeapon_Grapple_Fire);
- // if we just switched back to grapple, immediately go to fire frame
- if (prevstate == WEAPON_ACTIVATING &&
- ent->client->weaponstate == WEAPON_READY &&
- ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY) {
- if (!(ent->client->buttons & BUTTON_ATTACK))
- ent->client->ps.gunframe = 9;
- else
- ent->client->ps.gunframe = 5;
- ent->client->weaponstate = WEAPON_FIRING;
- }
- }
- void CTFTeam_f (edict_t *ent)
- {
- char *t, *s;
- int desired_team;
- t = gi.args();
- if (!*t) {
- gi.cprintf(ent, PRINT_HIGH, "You are on the %s team.\n",
- CTFTeamName(ent->client->resp.ctf_team));
- return;
- }
- if (ctfgame.match > MATCH_SETUP) {
- gi.cprintf(ent, PRINT_HIGH, "Can't change teams in a match.\n");
- return;
- }
- if (Q_stricmp(t, "red") == 0)
- desired_team = CTF_TEAM1;
- else if (Q_stricmp(t, "blue") == 0)
- desired_team = CTF_TEAM2;
- else {
- gi.cprintf(ent, PRINT_HIGH, "Unknown team %s.\n", t);
- return;
- }
- if (ent->client->resp.ctf_team == desired_team) {
- gi.cprintf(ent, PRINT_HIGH, "You are already on the %s team.\n",
- CTFTeamName(ent->client->resp.ctf_team));
- return;
- }
- ////
- ent->svflags = 0;
- ent->flags &= ~FL_GODMODE;
- ent->client->resp.ctf_team = desired_team;
- ent->client->resp.ctf_state = 0;
- s = Info_ValueForKey (ent->client->pers.userinfo, "skin");
- CTFAssignSkin(ent, s);
- if (ent->solid == SOLID_NOT) { // spectator
- PutClientInServer (ent);
- // add a teleportation effect
- ent->s.event = EV_PLAYER_TELEPORT;
- // hold in place briefly
- ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
- ent->client->ps.pmove.pm_time = 14;
- gi.bprintf(PRINT_HIGH, "%s joined the %s team.\n",
- ent->client->pers.netname, CTFTeamName(desired_team));
- return;
- }
- ent->health = 0;
- player_die (ent, ent, ent, 100000, vec3_origin);
- // don't even bother waiting for death frames
- ent->deadflag = DEAD_DEAD;
- respawn (ent);
- ent->client->resp.score = 0;
- gi.bprintf(PRINT_HIGH, "%s changed to the %s team.\n",
- ent->client->pers.netname, CTFTeamName(desired_team));
- }
- /*
- ==================
- CTFScoreboardMessage
- ==================
- */
- void CTFScoreboardMessage (edict_t *ent, edict_t *killer)
- {
- char entry[1024];
- char string[1400];
- int len;
- int i, j, k, n;
- int sorted[2][MAX_CLIENTS];
- int sortedscores[2][MAX_CLIENTS];
- int score, total[2], totalscore[2];
- int last[2];
- gclient_t *cl;
- edict_t *cl_ent;
- int team;
- int maxsize = 1000;
- // sort the clients by team and score
- total[0] = total[1] = 0;
- last[0] = last[1] = 0;
- totalscore[0] = totalscore[1] = 0;
- for (i=0 ; i<game.maxclients ; i++)
- {
- cl_ent = g_edicts + 1 + i;
- if (!cl_ent->inuse)
- continue;
- if (game.clients[i].resp.ctf_team == CTF_TEAM1)
- team = 0;
- else if (game.clients[i].resp.ctf_team == CTF_TEAM2)
- team = 1;
- else
- continue; // unknown team?
- score = game.clients[i].resp.score;
- for (j=0 ; j<total[team] ; j++)
- {
- if (score > sortedscores[team][j])
- break;
- }
- for (k=total[team] ; k>j ; k--)
- {
- sorted[team][k] = sorted[team][k-1];
- sortedscores[team][k] = sortedscores[team][k-1];
- }
- sorted[team][j] = i;
- sortedscores[team][j] = score;
- totalscore[team] += score;
- total[team]++;
- }
- // print level name and exit rules
- // add the clients in sorted order
- *string = 0;
- len = 0;
- // team one
- sprintf(string, "if 24 xv 8 yv 8 pic 24 endif "
- "xv 40 yv 28 string \"%4d/%-3d\" "
- "xv 98 yv 12 num 2 18 "
- "if 25 xv 168 yv 8 pic 25 endif "
- "xv 200 yv 28 string \"%4d/%-3d\" "
- "xv 256 yv 12 num 2 20 ",
- totalscore[0], total[0],
- totalscore[1], total[1]);
- len = strlen(string);
- for (i=0 ; i<16 ; i++)
- {
- if (i >= total[0] && i >= total[1])
- break; // we're done
- #if 0 //ndef NEW_SCORE
- // set up y
- sprintf(entry, "yv %d ", 42 + i * 8);
- if (maxsize - len > strlen(entry)) {
- strcat(string, entry);
- len = strlen(string);
- }
- #else
- *entry = 0;
- #endif
- // left side
- if (i < total[0]) {
- cl = &game.clients[sorted[0][i]];
- cl_ent = g_edicts + 1 + sorted[0][i];
- #if 0 //ndef NEW_SCORE
- sprintf(entry+strlen(entry),
- "xv 0 %s \"%3d %3d %-12.12s\" ",
- (cl_ent == ent) ? "string2" : "string",
- cl->resp.score,
- (cl->ping > 999) ? 999 : cl->ping,
- cl->pers.netname);
- if (cl_ent->client->pers.inventory[ITEM_INDEX(flag2_item)])
- strcat(entry, "xv 56 picn sbfctf2 ");
- #else
- sprintf(entry+strlen(entry),
- "ctf 0 %d %d %d %d ",
- 42 + i * 8,
- sorted[0][i],
- cl->resp.score,
- cl->ping > 999 ? 999 : cl->ping);
- if (cl_ent->client->pers.inventory[ITEM_INDEX(flag2_item)])
- sprintf(entry + strlen(entry), "xv 56 yv %d picn sbfctf2 ",
- 42 + i * 8);
- #endif
- if (maxsize - len > strlen(entry)) {
- strcat(string, entry);
- len = strlen(string);
- last[0] = i;
- }
- }
- // right side
- if (i < total[1]) {
- cl = &game.clients[sorted[1][i]];
- cl_ent = g_edicts + 1 + sorted[1][i];
- #if 0 //ndef NEW_SCORE
- sprintf(entry+strlen(entry),
- "xv 160 %s \"%3d %3d %-12.12s\" ",
- (cl_ent == ent) ? "string2" : "string",
- cl->resp.score,
- (cl->ping > 999) ? 999 : cl->ping,
- cl->pers.netname);
- if (cl_ent->client->pers.inventory[ITEM_INDEX(flag1_item)])
- strcat(entry, "xv 216 picn sbfctf1 ");
- #else
- sprintf(entry+strlen(entry),
- "ctf 160 %d %d %d %d ",
- 42 + i * 8,
- sorted[1][i],
- cl->resp.score,
- cl->ping > 999 ? 999 : cl->ping);
- if (cl_ent->client->pers.inventory[ITEM_INDEX(flag1_item)])
- sprintf(entry + strlen(entry), "xv 216 yv %d picn sbfctf1 ",
- 42 + i * 8);
- #endif
- if (maxsize - len > strlen(entry)) {
- strcat(string, entry);
- len = strlen(string);
- last[1] = i;
- }
- }
- }
- // put in spectators if we have enough room
- if (last[0] > last[1])
- j = last[0];
- else
- j = last[1];
- j = (j + 2) * 8 + 42;
- k = n = 0;
- if (maxsize - len > 50) {
- for (i = 0; i < maxclients->value; i++) {
- cl_ent = g_edicts + 1 + i;
- cl = &game.clients[i];
- if (!cl_ent->inuse ||
- cl_ent->solid != SOLID_NOT ||
- cl_ent->client->resp.ctf_team != CTF_NOTEAM)
- continue;
- if (!k) {
- k = 1;
- sprintf(entry, "xv 0 yv %d string2 \"Spectators\" ", j);
- strcat(string, entry);
- len = strlen(string);
- j += 8;
- }
- sprintf(entry+strlen(entry),
- "ctf %d %d %d %d %d ",
- (n & 1) ? 160 : 0, // x
- j, // y
- i, // playernum
- cl->resp.score,
- cl->ping > 999 ? 999 : cl->ping);
- if (maxsize - len > strlen(entry)) {
- strcat(string, entry);
- len = strlen(string);
- }
-
- if (n & 1)
- j += 8;
- n++;
- }
- }
- if (total[0] - last[0] > 1) // couldn't fit everyone
- sprintf(string + strlen(string), "xv 8 yv %d string \"..and %d more\" ",
- 42 + (last[0]+1)*8, total[0] - last[0] - 1);
- if (total[1] - last[1] > 1) // couldn't fit everyone
- sprintf(string + strlen(string), "xv 168 yv %d string \"..and %d more\" ",
- 42 + (last[1]+1)*8, total[1] - last[1] - 1);
- gi.WriteByte (svc_layout);
- gi.WriteString (string);
- }
- /*------------------------------------------------------------------------*/
- /* TECH */
- /*------------------------------------------------------------------------*/
- void CTFHasTech(edict_t *who)
- {
- if (level.time - who->client->ctf_lasttechmsg > 2) {
- gi.centerprintf(who, "You already have a TECH powerup.");
- who->client->ctf_lasttechmsg = level.time;
- }
- }
- gitem_t *CTFWhat_Tech(edict_t *ent)
- {
- gitem_t *tech;
- int i;
- i = 0;
- while (tnames[i]) {
- if ((tech = FindItemByClassname(tnames[i])) != NULL &&
- ent->client->pers.inventory[ITEM_INDEX(tech)]) {
- return tech;
- }
- i++;
- }
- return NULL;
- }
- qboolean CTFPickup_Tech (edict_t *ent, edict_t *other)
- {
- gitem_t *tech;
- int i;
- i = 0;
- while (tnames[i]) {
- if ((tech = FindItemByClassname(tnames[i])) != NULL &&
- other->client->pers.inventory[ITEM_INDEX(tech)]) {
- CTFHasTech(other);
- return false; // has this one
- }
- i++;
- }
-
- // client only gets one tech
- other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
- other->client->ctf_regentime = level.time;
- return true;
- }
- static void SpawnTech(gitem_t *item, edict_t *spot);
- static edict_t *FindTechSpawn(void)
- {
- edict_t *spot = NULL;
- int i = rand() % 16;
- while (i--)
- spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
- if (!spot)
- spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
- return spot;
- }
- static void TechThink(edict_t *tech)
- {
- edict_t *spot;
- if ((spot = FindTechSpawn()) != NULL) {
- SpawnTech(tech->item, spot);
- G_FreeEdict(tech);
- } else {
- tech->nextthink = level.time + CTF_TECH_TIMEOUT;
- tech->think = TechThink;
- }
- }
- void CTFDrop_Tech(edict_t *ent, gitem_t *item)
- {
- edict_t *tech;
- tech = Drop_Item(ent, item);
- tech->nextthink = level.time + CTF_TECH_TIMEOUT;
- tech->think = TechThink;
- ent->client->pers.inventory[ITEM_INDEX(item)] = 0;
- }
- void CTFDeadDropTech(edict_t *ent)
- {
- gitem_t *tech;
- edict_t *dropped;
- int i;
- i = 0;
- while (tnames[i]) {
- if ((tech = FindItemByClassname(tnames[i])) != NULL &&
- ent->client->pers.inventory[ITEM_INDEX(tech)]) {
- dropped = Drop_Item(ent, tech);
- // hack the velocity to make it bounce random
- dropped->velocity[0] = (rand() % 600) - 300;
- dropped->velocity[1] = (rand() % 600) - 300;
- dropped->nextthink = level.time + CTF_TECH_TIMEOUT;
- dropped->think = TechThink;
- dropped->owner = NULL;
- ent->client->pers.inventory[ITEM_INDEX(tech)] = 0;
- }
- i++;
- }
- }
- static void SpawnTech(gitem_t *item, edict_t *spot)
- {
- edict_t *ent;
- vec3_t forward, right;
- vec3_t angles;
- ent = G_Spawn();
- ent->classname = item->classname;
- ent->item = item;
- ent->spawnflags = DROPPED_ITEM;
- ent->s.effects = item->world_model_flags;
- ent->s.renderfx = RF_GLOW;
- VectorSet (ent->mins, -15, -15, -15);
- VectorSet (ent->maxs, 15, 15, 15);
- gi.setmodel (ent, ent->item->world_model);
- ent->solid = SOLID_TRIGGER;
- ent->movetype = MOVETYPE_TOSS;
- ent->touch = Touch_Item;
- ent->owner = ent;
- angles[0] = 0;
- angles[1] = rand() % 360;
- angles[2] = 0;
- AngleVectors (angles, forward, right, NULL);
- VectorCopy (spot->s.origin, ent->s.origin);
- ent->s.origin[2] += 16;
- VectorScale (forward, 100, ent->velocity);
- ent->velocity[2] = 300;
- ent->nextthink = level.time + CTF_TECH_TIMEOUT;
- ent->think = TechThink;
- gi.linkentity (ent);
- }
- static void SpawnTechs(edict_t *ent)
- {
- gitem_t *tech;
- edict_t *spot;
- int i;
- i = 0;
- while (tnames[i]) {
- if ((tech = FindItemByClassname(tnames[i])) != NULL &&
- (spot = FindTechSpawn()) != NULL)
- SpawnTech(tech, spot);
- i++;
- }
- if (ent)
- G_FreeEdict(ent);
- }
- // frees the passed edict!
- void CTFRespawnTech(edict_t *ent)
- {
- edict_t *spot;
- if ((spot = FindTechSpawn()) != NULL)
- SpawnTech(ent->item, spot);
- G_FreeEdict(ent);
- }
- void CTFSetupTechSpawn(void)
- {
- edict_t *ent;
- if (((int)dmflags->value & DF_CTF_NO_TECH))
- return;
- ent = G_Spawn();
- ent->nextthink = level.time + 2;
- ent->think = SpawnTechs;
- }
- void CTFResetTech(void)
- {
- edict_t *ent;
- int i;
- for (ent = g_edicts + 1, i = 1; i < globals.num_edicts; i++, ent++) {
- if (ent->inuse)
- if (ent->item && (ent->item->flags & IT_TECH))
- G_FreeEdict(ent);
- }
- SpawnTechs(NULL);
- }
- int CTFApplyResistance(edict_t *ent, int dmg)
- {
- static gitem_t *tech = NULL;
- float volume = 1.0;
- if (ent->client && ent->client->silencer_shots)
- volume = 0.2;
- if (!tech)
- tech = FindItemByClassname("item_tech1");
- if (dmg && tech && ent->client && ent->client->pers.inventory[ITEM_INDEX(tech)]) {
- // make noise
- gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech1.wav"), volume, ATTN_NORM, 0);
- return dmg / 2;
- }
- return dmg;
- }
- int CTFApplyStrength(edict_t *ent, int dmg)
- {
- static gitem_t *tech = NULL;
- if (!tech)
- tech = FindItemByClassname("item_tech2");
- if (dmg && tech && ent->client && ent->client->pers.inventory[ITEM_INDEX(tech)]) {
- return dmg * 2;
- }
- return dmg;
- }
- qboolean CTFApplyStrengthSound(edict_t *ent)
- {
- static gitem_t *tech = NULL;
- float volume = 1.0;
- if (ent->client && ent->client->silencer_shots)
- volume = 0.2;
- if (!tech)
- tech = FindItemByClassname("item_tech2");
- if (tech && ent->client &&
- ent->client->pers.inventory[ITEM_INDEX(tech)]) {
- if (ent->client->ctf_techsndtime < level.time) {
- ent->client->ctf_techsndtime = level.time + 1;
- if (ent->client->quad_framenum > level.framenum)
- gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech2x.wav"), volume, ATTN_NORM, 0);
- else
- gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech2.wav"), volume, ATTN_NORM, 0);
- }
- return true;
- }
- return false;
- }
- qboolean CTFApplyHaste(edict_t *ent)
- {
- static gitem_t *tech = NULL;
- if (!tech)
- tech = FindItemByClassname("item_tech3");
- if (tech && ent->client &&
- ent->client->pers.inventory[ITEM_INDEX(tech)])
- return true;
- return false;
- }
- void CTFApplyHasteSound(edict_t *ent)
- {
- static gitem_t *tech = NULL;
- float volume = 1.0;
- if (ent->client && ent->client->silencer_shots)
- volume = 0.2;
- if (!tech)
- tech = FindItemByClassname("item_tech3");
- if (tech && ent->client &&
- ent->client->pers.inventory[ITEM_INDEX(tech)] &&
- ent->client->ctf_techsndtime < level.time) {
- ent->client->ctf_techsndtime = level.time + 1;
- gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech3.wav"), volume, ATTN_NORM, 0);
- }
- }
- void CTFApplyRegeneration(edict_t *ent)
- {
- static gitem_t *tech = NULL;
- qboolean noise = false;
- gclient_t *client;
- int index;
- float volume = 1.0;
- client = ent->client;
- if (!client)
- return;
- if (ent->client->silencer_shots)
- volume = 0.2;
- if (!tech)
- tech = FindItemByClassname("item_tech4");
- if (tech && client->pers.inventory[ITEM_INDEX(tech)]) {
- if (client->ctf_regentime < level.time) {
- client->ctf_regentime = level.time;
- if (ent->health < 150) {
- ent->health += 5;
- if (ent->health > 150)
- ent->health = 150;
- client->ctf_regentime += 0.5;
- noise = true;
- }
- index = ArmorIndex (ent);
- if (index && client->pers.inventory[index] < 150) {
- client->pers.inventory[index] += 5;
- if (client->pers.inventory[index] > 150)
- client->pers.inventory[index] = 150;
- client->ctf_regentime += 0.5;
- noise = true;
- }
- }
- if (noise && ent->client->ctf_techsndtime < level.time) {
- ent->client->ctf_techsndtime = level.time + 1;
- gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech4.wav"), volume, ATTN_NORM, 0);
- }
- }
- }
- qboolean CTFHasRegeneration(edict_t *ent)
- {
- static gitem_t *tech = NULL;
- if (!tech)
- tech = FindItemByClassname("item_tech4");
- if (tech && ent->client &&
- ent->client->pers.inventory[ITEM_INDEX(tech)])
- return true;
- return false;
- }
- /*
- ======================================================================
- SAY_TEAM
- ======================================================================
- */
- // This array is in 'importance order', it indicates what items are
- // more important when reporting their names.
- struct {
- char *classname;
- int priority;
- } loc_names[] =
- {
- { "item_flag_team1", 1 },
- { "item_flag_team2", 1 },
- { "item_quad", 2 },
- { "item_invulnerability", 2 },
- { "weapon_bfg", 3 },
- { "weapon_railgun", 4 },
- { "weapon_rocketlauncher", 4 },
- { "weapon_hyperblaster", 4 },
- { "weapon_chaingun", 4 },
- { "weapon_grenadelauncher", 4 },
- { "weapon_machinegun", 4 },
- { "weapon_supershotgun", 4 },
- { "weapon_shotgun", 4 },
- { "item_power_screen", 5 },
- { "item_power_shield", 5 },
- { "item_armor_body", 6 },
- { "item_armor_combat", 6 },
- { "item_armor_jacket", 6 },
- { "item_silencer", 7 },
- { "item_breather", 7 },
- { "item_enviro", 7 },
- { "item_adrenaline", 7 },
- { "item_bandolier", 8 },
- { "item_pack", 8 },
- { NULL, 0 }
- };
- static void CTFSay_Team_Location(edict_t *who, char *buf)
- {
- edict_t *what = NULL;
- edict_t *hot = NULL;
- float hotdist = 999999, newdist;
- vec3_t v;
- int hotindex = 999;
- int i;
- gitem_t *item;
- int nearteam = -1;
- edict_t *flag1, *flag2;
- qboolean hotsee = false;
- qboolean cansee;
- while ((what = loc_findradius(what, who->s.origin, 1024)) != NULL) {
- // find what in loc_classnames
- for (i = 0; loc_names[i].classname; i++)
- if (strcmp(what->classname, loc_names[i].classname) == 0)
- break;
- if (!loc_names[i].classname)
- continue;
- // something we can see get priority over something we can't
- cansee = loc_CanSee(what, who);
- if (cansee && !hotsee) {
- hotsee = true;
- hotindex = loc_names[i].priority;
- hot = what;
- VectorSubtract(what->s.origin, who->s.origin, v);
- hotdist = VectorLength(v);
- continue;
- }
- // if we can't see this, but we have something we can see, skip it
- if (hotsee && !cansee)
- continue;
- if (hotsee && hotindex < loc_names[i].priority)
- continue;
- VectorSubtract(what->s.origin, who->s.origin, v);
- newdist = VectorLength(v);
- if (newdist < hotdist ||
- (cansee && loc_names[i].priority < hotindex)) {
- hot = what;
- hotdist = newdist;
- hotindex = i;
- hotsee = loc_CanSee(hot, who);
- }
- }
- if (!hot) {
- strcpy(buf, "nowhere");
- return;
- }
- // we now have the closest item
- // see if there's more than one in the map, if so
- // we need to determine what team is closest
- what = NULL;
- while ((what = G_Find(what, FOFS(classname), hot->classname)) != NULL) {
- if (what == hot)
- continue;
- // if we are here, there is more than one, find out if hot
- // is closer to red flag or blue flag
- if ((flag1 = G_Find(NULL, FOFS(classname), "item_flag_team1")) != NULL &&
- (flag2 = G_Find(NULL, FOFS(classname), "item_flag_team2")) != NULL) {
- VectorSubtract(hot->s.origin, flag1->s.origin, v);
- hotdist = VectorLength(v);
- VectorSubtract(hot->s.origin, flag2->s.origin, v);
- newdist = VectorLength(v);
- if (hotdist < newdist)
- nearteam = CTF_TEAM1;
- else if (hotdist > newdist)
- nearteam = CTF_TEAM2;
- }
- break;
- }
- if ((item = FindItemByClassname(hot->classname)) == NULL) {
- strcpy(buf, "nowhere");
- return;
- }
- // in water?
- if (who->waterlevel)
- strcpy(buf, "in the water ");
- else
- *buf = 0;
- // near or above
- VectorSubtract(who->s.origin, hot->s.origin, v);
- if (fabs(v[2]) > fabs(v[0]) && fabs(v[2]) > fabs(v[1]))
- if (v[2] > 0)
- strcat(buf, "above ");
- else
- strcat(buf, "below ");
- else
- strcat(buf, "near ");
- if (nearteam == CTF_TEAM1)
- strcat(buf, "the red ");
- else if (nearteam == CTF_TEAM2)
- strcat(buf, "the blue ");
- else
- strcat(buf, "the ");
- strcat(buf, item->pickup_name);
- }
- static void CTFSay_Team_Armor(edict_t *who, char *buf)
- {
- gitem_t *item;
- int index, cells;
- int power_armor_type;
- *buf = 0;
- power_armor_type = PowerArmorType (who);
- if (power_armor_type)
- {
- cells = who->client->pers.inventory[ITEM_INDEX(FindItem ("cells"))];
- if (cells)
- sprintf(buf+strlen(buf), "%s with %i cells ",
- (power_armor_type == POWER_ARMOR_SCREEN) ?
- "Power Screen" : "Power Shield", cells);
- }
- index = ArmorIndex (who);
- if (index)
- {
- item = GetItemByIndex (index);
- if (item) {
- if (*buf)
- strcat(buf, "and ");
- sprintf(buf+strlen(buf), "%i units of %s",
- who->client->pers.inventory[index], item->pickup_name);
- }
- }
- if (!*buf)
- strcpy(buf, "no armor");
- }
- static void CTFSay_Team_Health(edict_t *who, char *buf)
- {
- if (who->health <= 0)
- strcpy(buf, "dead");
- else
- sprintf(buf, "%i health", who->health);
- }
- static void CTFSay_Team_Tech(edict_t *who, char *buf)
- {
- gitem_t *tech;
- int i;
- // see if the player has a tech powerup
- i = 0;
- while (tnames[i]) {
- if ((tech = FindItemByClassname(tnames[i])) != NULL &&
- who->client->pers.inventory[ITEM_INDEX(tech)]) {
- sprintf(buf, "the %s", tech->pickup_name);
- return;
- }
- i++;
- }
- strcpy(buf, "no powerup");
- }
- static void CTFSay_Team_Weapon(edict_t *who, char *buf)
- {
- if (who->client->pers.weapon)
- strcpy(buf, who->client->pers.weapon->pickup_name);
- else
- strcpy(buf, "none");
- }
- static void CTFSay_Team_Sight(edict_t *who, char *buf)
- {
- int i;
- edict_t *targ;
- int n = 0;
- char s[1024];
- char s2[1024];
- *s = *s2 = 0;
- for (i = 1; i <= maxclients->value; i++) {
- targ = g_edicts + i;
- if (!targ->inuse ||
- targ == who ||
- !loc_CanSee(targ, who))
- continue;
- if (*s2) {
- if (strlen(s) + strlen(s2) + 3 < sizeof(s)) {
- if (n)
- strcat(s, ", ");
- strcat(s, s2);
- *s2 = 0;
- }
- n++;
- }
- strcpy(s2, targ->client->pers.netname);
- }
- if (*s2) {
- if (strlen(s) + strlen(s2) + 6 < sizeof(s)) {
- if (n)
- strcat(s, " and ");
- strcat(s, s2);
- }
- strcpy(buf, s);
- } else
- strcpy(buf, "no one");
- }
- void CTFSay_Team(edict_t *who, char *msg)
- {
- char outmsg[256];
- char buf[256];
- int i;
- char *p;
- edict_t *cl_ent;
- if (CheckFlood(who))
- return;
- outmsg[0] = 0;
- if (*msg == '\"') {
- msg[strlen(msg) - 1] = 0;
- msg++;
- }
- for (p = outmsg; *msg && (p - outmsg) < sizeof(outmsg) - 2; msg++) {
- if (*msg == '%') {
- switch (*++msg) {
- case 'l' :
- case 'L' :
- CTFSay_Team_Location(who, buf);
- if (strlen(buf) + (p - outmsg) < sizeof(outmsg) - 2) {
- strcpy(p, buf);
- p += strlen(buf);
- }
- break;
- case 'a' :
- case 'A' :
- CTFSay_Team_Armor(who, buf);
- if (strlen(buf) + (p - outmsg) < sizeof(outmsg) - 2) {
- strcpy(p, buf);
- p += strlen(buf);
- }
- break;
- case 'h' :
- case 'H' :
- CTFSay_Team_Health(who, buf);
- if (strlen(buf) + (p - outmsg) < sizeof(outmsg) - 2) {
- strcpy(p, buf);
- p += strlen(buf);
- }
- break;
- case 't' :
- case 'T' :
- CTFSay_Team_Tech(who, buf);
- if (strlen(buf) + (p - outmsg) < sizeof(outmsg) - 2) {
- strcpy(p, buf);
- p += strlen(buf);
- }
- break;
- case 'w' :
- case 'W' :
- CTFSay_Team_Weapon(who, buf);
- if (strlen(buf) + (p - outmsg) < sizeof(outmsg) - 2) {
- strcpy(p, buf);
- p += strlen(buf);
- }
- break;
- case 'n' :
- case 'N' :
- CTFSay_Team_Sight(who, buf);
- if (strlen(buf) + (p - outmsg) < sizeof(outmsg) - 2) {
- strcpy(p, buf);
- p += strlen(buf);
- }
- break;
- default :
- *p++ = *msg;
- }
- } else
- *p++ = *msg;
- }
- *p = 0;
- for (i = 0; i < maxclients->value; i++) {
- cl_ent = g_edicts + 1 + i;
- if (!cl_ent->inuse)
- continue;
- if (cl_ent->client->resp.ctf_team == who->client->resp.ctf_team)
- gi.cprintf(cl_ent, PRINT_CHAT, "(%s): %s\n",
- who->client->pers.netname, outmsg);
- }
- }
- /*-----------------------------------------------------------------------*/
- /*QUAKED misc_ctf_banner (1 .5 0) (-4 -64 0) (4 64 248) TEAM2
- The origin is the bottom of the banner.
- The banner is 248 tall.
- */
- static void misc_ctf_banner_think (edict_t *ent)
- {
- ent->s.frame = (ent->s.frame + 1) % 16;
- ent->nextthink = level.time + FRAMETIME;
- }
- void SP_misc_ctf_banner (edict_t *ent)
- {
- ent->movetype = MOVETYPE_NONE;
- ent->solid = SOLID_NOT;
- ent->s.modelindex = gi.modelindex ("models/ctf/banner/tris.md2");
- if (ent->spawnflags & 1) // team2
- ent->s.skinnum = 1;
- ent->s.frame = rand() % 16;
- gi.linkentity (ent);
- ent->think = misc_ctf_banner_think;
- ent->nextthink = level.time + FRAMETIME;
- }
- /*QUAKED misc_ctf_small_banner (1 .5 0) (-4 -32 0) (4 32 124) TEAM2
- The origin is the bottom of the banner.
- The banner is 124 tall.
- */
- void SP_misc_ctf_small_banner (edict_t *ent)
- {
- ent->movetype = MOVETYPE_NONE;
- ent->solid = SOLID_NOT;
- ent->s.modelindex = gi.modelindex ("models/ctf/banner/small.md2");
- if (ent->spawnflags & 1) // team2
- ent->s.skinnum = 1;
- ent->s.frame = rand() % 16;
- gi.linkentity (ent);
- ent->think = misc_ctf_banner_think;
- ent->nextthink = level.time + FRAMETIME;
- }
- /*-----------------------------------------------------------------------*/
- static void SetLevelName(pmenu_t *p)
- {
- static char levelname[33];
- levelname[0] = '*';
- if (g_edicts[0].message)
- strncpy(levelname+1, g_edicts[0].message, sizeof(levelname) - 2);
- else
- strncpy(levelname+1, level.mapname, sizeof(levelname) - 2);
- levelname[sizeof(levelname) - 1] = 0;
- p->text = levelname;
- }
- /*-----------------------------------------------------------------------*/
- /* ELECTIONS */
- qboolean CTFBeginElection(edict_t *ent, elect_t type, char *msg)
- {
- int i;
- int count;
- edict_t *e;
- if (electpercentage->value == 0) {
- gi.cprintf(ent, PRINT_HIGH, "Elections are disabled, only an admin can process this action.\n");
- return false;
- }
- if (ctfgame.election != ELECT_NONE) {
- gi.cprintf(ent, PRINT_HIGH, "Election already in progress.\n");
- return false;
- }
- // clear votes
- count = 0;
- for (i = 1; i <= maxclients->value; i++) {
- e = g_edicts + i;
- e->client->resp.voted = false;
- if (e->inuse)
- count++;
- }
- if (count < 2) {
- gi.cprintf(ent, PRINT_HIGH, "Not enough players for election.\n");
- return false;
- }
- ctfgame.etarget = ent;
- ctfgame.election = type;
- ctfgame.evotes = 0;
- ctfgame.needvotes = (count * electpercentage->value) / 100;
- ctfgame.electtime = level.time + 20; // twenty seconds for election
- strncpy(ctfgame.emsg, msg, sizeof(ctfgame.emsg) - 1);
- // tell everyone
- gi.bprintf(PRINT_CHAT, "%s\n", ctfgame.emsg);
- gi.bprintf(PRINT_HIGH, "Type YES or NO to vote on this request.\n");
- gi.bprintf(PRINT_HIGH, "Votes: %d Needed: %d Time left: %ds\n", ctfgame.evotes, ctfgame.needvotes,
- (int)(ctfgame.electtime - level.time));
- return true;
- }
- void DoRespawn (edict_t *ent);
- void CTFResetAllPlayers(void)
- {
- int i;
- edict_t *ent;
- for (i = 1; i <= maxclients->value; i++) {
- ent = g_edicts + i;
- if (!ent->inuse)
- continue;
- if (ent->client->menu)
- PMenu_Close(ent);
- CTFPlayerResetGrapple(ent);
- CTFDeadDropFlag(ent);
- CTFDeadDropTech(ent);
- ent->client->resp.ctf_team = CTF_NOTEAM;
- ent->client->resp.ready = false;
- ent->svflags = 0;
- ent->flags &= ~FL_GODMODE;
- PutClientInServer(ent);
- }
- // reset the level
- CTFResetTech();
- CTFResetFlags();
- for (ent = g_edicts + 1, i = 1; i < globals.num_edicts; i++, ent++) {
- if (ent->inuse && !ent->client) {
- if (ent->solid == SOLID_NOT && ent->think == DoRespawn &&
- ent->nextthink >= level.time) {
- ent->nextthink = 0;
- DoRespawn(ent);
- }
- }
- }
- if (ctfgame.match == MATCH_SETUP)
- ctfgame.matchtime = level.time + matchsetuptime->value * 60;
- }
- void CTFAssignGhost(edict_t *ent)
- {
- int ghost, i;
- for (ghost = 0; ghost < MAX_CLIENTS; ghost++)
- if (!ctfgame.ghosts[ghost].code)
- break;
- if (ghost == MAX_CLIENTS)
- return;
- ctfgame.ghosts[ghost].team = ent->client->resp.ctf_team;
- ctfgame.ghosts[ghost].score = 0;
- for (;;) {
- ctfgame.ghosts[ghost].code = 10000 + (rand() % 90000);
- for (i = 0; i < MAX_CLIENTS; i++)
- if (i != ghost && ctfgame.ghosts[i].code == ctfgame.ghosts[ghost].code)
- break;
- if (i == MAX_CLIENTS)
- break;
- }
- ctfgame.ghosts[ghost].ent = ent;
- strcpy(ctfgame.ghosts[ghost].netname, ent->client->pers.netname);
- ent->client->resp.ghost = ctfgame.ghosts + ghost;
- gi.cprintf(ent, PRINT_CHAT, "Your ghost code is **** %d ****\n", ctfgame.ghosts[ghost].code);
- gi.cprintf(ent, PRINT_HIGH, "If you lose connection, you can rejoin with your score "
- "intact by typing \"ghost %d\".\n", ctfgame.ghosts[ghost].code);
- }
- // start a match
- void CTFStartMatch(void)
- {
- int i;
- edict_t *ent;
- int ghost = 0;
- ctfgame.match = MATCH_GAME;
- ctfgame.matchtime = level.time + matchtime->value * 60;
- ctfgame.countdown = false;
- ctfgame.team1 = ctfgame.team2 = 0;
- memset(ctfgame.ghosts, 0, sizeof(ctfgame.ghosts));
- for (i = 1; i <= maxclients->value; i++) {
- ent = g_edicts + i;
- if (!ent->inuse)
- continue;
- ent->client->resp.score = 0;
- ent->client->resp.ctf_state = 0;
- ent->client->resp.ghost = NULL;
- gi.centerprintf(ent, "******************\n\nMATCH HAS STARTED!\n\n******************");
- if (ent->client->resp.ctf_team != CTF_NOTEAM) {
- // make up a ghost code
- CTFAssignGhost(ent);
- CTFPlayerResetGrapple(ent);
- ent->svflags = SVF_NOCLIENT;
- ent->flags &= ~FL_GODMODE;
- ent->client->respawn_time = level.time + 1.0 + ((rand()%30)/10.0);
- ent->client->ps.pmove.pm_type = PM_DEAD;
- ent->client->anim_priority = ANIM_DEATH;
- ent->s.frame = FRAME_death308-1;
- ent->client->anim_end = FRAME_death308;
- ent->deadflag = DEAD_DEAD;
- ent->movetype = MOVETYPE_NOCLIP;
- ent->client->ps.gunindex = 0;
- gi.linkentity (ent);
- }
- }
- }
- void CTFEndMatch(void)
- {
- ctfgame.match = MATCH_POST;
- gi.bprintf(PRINT_CHAT, "MATCH COMPLETED!\n");
- CTFCalcScores();
- gi.bprintf(PRINT_HIGH, "RED TEAM: %d captures, %d points\n",
- ctfgame.team1, ctfgame.total1);
- gi.bprintf(PRINT_HIGH, "BLUE TEAM: %d captures, %d points\n",
- ctfgame.team2, ctfgame.total2);
- if (ctfgame.team1 > ctfgame.team2)
- gi.bprintf(PRINT_CHAT, "RED team won over the BLUE team by %d CAPTURES!\n",
- ctfgame.team1 - ctfgame.team2);
- else if (ctfgame.team2 > ctfgame.team1)
- gi.bprintf(PRINT_CHAT, "BLUE team won over the RED team by %d CAPTURES!\n",
- ctfgame.team2 - ctfgame.team1);
- else if (ctfgame.total1 > ctfgame.total2) // frag tie breaker
- gi.bprintf(PRINT_CHAT, "RED team won over the BLUE team by %d POINTS!\n",
- ctfgame.total1 - ctfgame.total2);
- else if (ctfgame.total2 > ctfgame.total1)
- gi.bprintf(PRINT_CHAT, "BLUE team won over the RED team by %d POINTS!\n",
- ctfgame.total2 - ctfgame.total1);
- else
- gi.bprintf(PRINT_CHAT, "TIE GAME!\n");
- EndDMLevel();
- }
- qboolean CTFNextMap(void)
- {
- if (ctfgame.match == MATCH_POST) {
- ctfgame.match = MATCH_SETUP;
- CTFResetAllPlayers();
- return true;
- }
- return false;
- }
- void CTFWinElection(void)
- {
- switch (ctfgame.election) {
- case ELECT_MATCH :
- // reset into match mode
- if (competition->value < 3)
- gi.cvar_set("competition", "2");
- ctfgame.match = MATCH_SETUP;
- CTFResetAllPlayers();
- break;
- case ELECT_ADMIN :
- ctfgame.etarget->client->resp.admin = true;
- gi.bprintf(PRINT_HIGH, "%s has become an admin.\n", ctfgame.etarget->client->pers.netname);
- gi.cprintf(ctfgame.etarget, PRINT_HIGH, "Type 'admin' to access the adminstration menu.\n");
- break;
- case ELECT_MAP :
- gi.bprintf(PRINT_HIGH, "%s is warping to level %s.\n",
- ctfgame.etarget->client->pers.netname, ctfgame.elevel);
- strncpy(level.forcemap, ctfgame.elevel, sizeof(level.forcemap) - 1);
- EndDMLevel();
- break;
- }
- ctfgame.election = ELECT_NONE;
- }
- void CTFVoteYes(edict_t *ent)
- {
- if (ctfgame.election == ELECT_NONE) {
- gi.cprintf(ent, PRINT_HIGH, "No election is in progress.\n");
- return;
- }
- if (ent->client->resp.voted) {
- gi.cprintf(ent, PRINT_HIGH, "You already voted.\n");
- return;
- }
- if (ctfgame.etarget == ent) {
- gi.cprintf(ent, PRINT_HIGH, "You can't vote for yourself.\n");
- return;
- }
- ent->client->resp.voted = true;
- ctfgame.evotes++;
- if (ctfgame.evotes == ctfgame.needvotes) {
- // the election has been won
- CTFWinElection();
- return;
- }
- gi.bprintf(PRINT_HIGH, "%s\n", ctfgame.emsg);
- gi.bprintf(PRINT_CHAT, "Votes: %d Needed: %d Time left: %ds\n", ctfgame.evotes, ctfgame.needvotes,
- (int)(ctfgame.electtime - level.time));
- }
- void CTFVoteNo(edict_t *ent)
- {
- if (ctfgame.election == ELECT_NONE) {
- gi.cprintf(ent, PRINT_HIGH, "No election is in progress.\n");
- return;
- }
- if (ent->client->resp.voted) {
- gi.cprintf(ent, PRINT_HIGH, "You already voted.\n");
- return;
- }
- if (ctfgame.etarget == ent) {
- gi.cprintf(ent, PRINT_HIGH, "You can't vote for yourself.\n");
- return;
- }
- ent->client->resp.voted = true;
- gi.bprintf(PRINT_HIGH, "%s\n", ctfgame.emsg);
- gi.bprintf(PRINT_CHAT, "Votes: %d Needed: %d Time left: %ds\n", ctfgame.evotes, ctfgame.needvotes,
- (int)(ctfgame.electtime - level.time));
- }
- void CTFReady(edict_t *ent)
- {
- int i, j;
- edict_t *e;
- int t1, t2;
- if (ent->client->resp.ctf_team == CTF_NOTEAM) {
- gi.cprintf(ent, PRINT_HIGH, "Pick a team first (hit <TAB> for menu)\n");
- return;
- }
- if (ctfgame.match != MATCH_SETUP) {
- gi.cprintf(ent, PRINT_HIGH, "A match is not being setup.\n");
- return;
- }
- if (ent->client->resp.ready) {
- gi.cprintf(ent, PRINT_HIGH, "You have already commited.\n");
- return;
- }
- ent->client->resp.ready = true;
- gi.bprintf(PRINT_HIGH, "%s is ready.\n", ent->client->pers.netname);
- t1 = t2 = 0;
- for (j = 0, i = 1; i <= maxclients->value; i++) {
- e = g_edicts + i;
- if (!e->inuse)
- continue;
- if (e->client->resp.ctf_team != CTF_NOTEAM && !e->client->resp.ready)
- j++;
- if (e->client->resp.ctf_team == CTF_TEAM1)
- t1++;
- else if (e->client->resp.ctf_team == CTF_TEAM2)
- t2++;
- }
- if (!j && t1 && t2) {
- // everyone has commited
- gi.bprintf(PRINT_CHAT, "All players have commited. Match starting\n");
- ctfgame.match = MATCH_PREGAME;
- ctfgame.matchtime = level.time + matchstarttime->value;
- ctfgame.countdown = false;
- gi.positioned_sound (world->s.origin, world, CHAN_AUTO | CHAN_RELIABLE, gi.soundindex("misc/talk1.wav"), 1, ATTN_NONE, 0);
- }
- }
- void CTFNotReady(edict_t *ent)
- {
- if (ent->client->resp.ctf_team == CTF_NOTEAM) {
- gi.cprintf(ent, PRINT_HIGH, "Pick a team first (hit <TAB> for menu)\n");
- return;
- }
- if (ctfgame.match != MATCH_SETUP && ctfgame.match != MATCH_PREGAME) {
- gi.cprintf(ent, PRINT_HIGH, "A match is not being setup.\n");
- return;
- }
- if (!ent->client->resp.ready) {
- gi.cprintf(ent, PRINT_HIGH, "You haven't commited.\n");
- return;
- }
- ent->client->resp.ready = false;
- gi.bprintf(PRINT_HIGH, "%s is no longer ready.\n", ent->client->pers.netname);
- if (ctfgame.match == MATCH_PREGAME) {
- gi.bprintf(PRINT_CHAT, "Match halted.\n");
- ctfgame.match = MATCH_SETUP;
- ctfgame.matchtime = level.time + matchsetuptime->value * 60;
- }
- }
- void CTFGhost(edict_t *ent)
- {
- int i;
- int n;
- if (gi.argc() < 2) {
- gi.cprintf(ent, PRINT_HIGH, "Usage: ghost <code>\n");
- return;
- }
- if (ent->client->resp.ctf_team != CTF_NOTEAM) {
- gi.cprintf(ent, PRINT_HIGH, "You are already in the game.\n");
- return;
- }
- if (ctfgame.match != MATCH_GAME) {
- gi.cprintf(ent, PRINT_HIGH, "No match is in progress.\n");
- return;
- }
- n = atoi(gi.argv(1));
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (ctfgame.ghosts[i].code && ctfgame.ghosts[i].code == n) {
- gi.cprintf(ent, PRINT_HIGH, "Ghost code accepted, your position has been reinstated.\n");
- ctfgame.ghosts[i].ent->client->resp.ghost = NULL;
- ent->client->resp.ctf_team = ctfgame.ghosts[i].team;
- ent->client->resp.ghost = ctfgame.ghosts + i;
- ent->client->resp.score = ctfgame.ghosts[i].score;
- ent->client->resp.ctf_state = 0;
- ctfgame.ghosts[i].ent = ent;
- ent->svflags = 0;
- ent->flags &= ~FL_GODMODE;
- PutClientInServer(ent);
- gi.bprintf(PRINT_HIGH, "%s has been reinstated to %s team.\n",
- ent->client->pers.netname, CTFTeamName(ent->client->resp.ctf_team));
- return;
- }
- }
- gi.cprintf(ent, PRINT_HIGH, "Invalid ghost code.\n");
- }
- qboolean CTFMatchSetup(void)
- {
- if (ctfgame.match == MATCH_SETUP || ctfgame.match == MATCH_PREGAME)
- return true;
- return false;
- }
- qboolean CTFMatchOn(void)
- {
- if (ctfgame.match == MATCH_GAME)
- return true;
- return false;
- }
- /*-----------------------------------------------------------------------*/
- void CTFJoinTeam1(edict_t *ent, pmenuhnd_t *p);
- void CTFJoinTeam2(edict_t *ent, pmenuhnd_t *p);
- void CTFCredits(edict_t *ent, pmenuhnd_t *p);
- void CTFReturnToMain(edict_t *ent, pmenuhnd_t *p);
- void CTFChaseCam(edict_t *ent, pmenuhnd_t *p);
- pmenu_t creditsmenu[] = {
- { "*Quake II", PMENU_ALIGN_CENTER, NULL },
- { "*ThreeWave Capture the Flag", PMENU_ALIGN_CENTER, NULL },
- { NULL, PMENU_ALIGN_CENTER, NULL },
- { "*Programming", PMENU_ALIGN_CENTER, NULL },
- { "Dave 'Zoid' Kirsch", PMENU_ALIGN_CENTER, NULL },
- { "*Level Design", PMENU_ALIGN_CENTER, NULL },
- { "Christian Antkow", PMENU_ALIGN_CENTER, NULL },
- { "Tim Willits", PMENU_ALIGN_CENTER, NULL },
- { "Dave 'Zoid' Kirsch", PMENU_ALIGN_CENTER, NULL },
- { "*Art", PMENU_ALIGN_CENTER, NULL },
- { "Adrian Carmack Paul Steed", PMENU_ALIGN_CENTER, NULL },
- { "Kevin Cloud", PMENU_ALIGN_CENTER, NULL },
- { "*Sound", PMENU_ALIGN_CENTER, NULL },
- { "Tom 'Bjorn' Klok", PMENU_ALIGN_CENTER, NULL },
- { "*Original CTF Art Design", PMENU_ALIGN_CENTER, NULL },
- { "Brian 'Whaleboy' Cozzens", PMENU_ALIGN_CENTER, NULL },
- { NULL, PMENU_ALIGN_CENTER, NULL },
- { "Return to Main Menu", PMENU_ALIGN_LEFT, CTFReturnToMain }
- };
- static const int jmenu_level = 2;
- static const int jmenu_match = 3;
- static const int jmenu_red = 5;
- static const int jmenu_blue = 7;
- static const int jmenu_chase = 9;
- static const int jmenu_reqmatch = 11;
- pmenu_t joinmenu[] = {
- { "*Quake II", PMENU_ALIGN_CENTER, NULL },
- { "*ThreeWave Capture the Flag", PMENU_ALIGN_CENTER, NULL },
- { NULL, PMENU_ALIGN_CENTER, NULL },
- { NULL, PMENU_ALIGN_CENTER, NULL },
- { NULL, PMENU_ALIGN_CENTER, NULL },
- { "Join Red Team", PMENU_ALIGN_LEFT, CTFJoinTeam1 },
- { NULL, PMENU_ALIGN_LEFT, NULL },
- { "Join Blue Team", PMENU_ALIGN_LEFT, CTFJoinTeam2 },
- { NULL, PMENU_ALIGN_LEFT, NULL },
- { "Chase Camera", PMENU_ALIGN_LEFT, CTFChaseCam },
- { "Credits", PMENU_ALIGN_LEFT, CTFCredits },
- { NULL, PMENU_ALIGN_LEFT, NULL },
- { NULL, PMENU_ALIGN_LEFT, NULL },
- { "Use [ and ] to move cursor", PMENU_ALIGN_LEFT, NULL },
- { "ENTER to select", PMENU_ALIGN_LEFT, NULL },
- { "ESC to Exit Menu", PMENU_ALIGN_LEFT, NULL },
- { "(TAB to Return)", PMENU_ALIGN_LEFT, NULL },
- { "v" CTF_STRING_VERSION, PMENU_ALIGN_RIGHT, NULL },
- };
- pmenu_t nochasemenu[] = {
- { "*Quake II", PMENU_ALIGN_CENTER, NULL },
- { "*ThreeWave Capture the Flag", PMENU_ALIGN_CENTER, NULL },
- { NULL, PMENU_ALIGN_CENTER, NULL },
- { NULL, PMENU_ALIGN_CENTER, NULL },
- { "No one to chase", PMENU_ALIGN_LEFT, NULL },
- { NULL, PMENU_ALIGN_CENTER, NULL },
- { "Return to Main Menu", PMENU_ALIGN_LEFT, CTFReturnToMain }
- };
- void CTFJoinTeam(edict_t *ent, int desired_team)
- {
- char *s;
- PMenu_Close(ent);
- ent->svflags &= ~SVF_NOCLIENT;
- ent->client->resp.ctf_team = desired_team;
- ent->client->resp.ctf_state = 0;
- s = Info_ValueForKey (ent->client->pers.userinfo, "skin");
- CTFAssignSkin(ent, s);
- // assign a ghost if we are in match mode
- if (ctfgame.match == MATCH_GAME) {
- if (ent->client->resp.ghost)
- ent->client->resp.ghost->code = 0;
- ent->client->resp.ghost = NULL;
- CTFAssignGhost(ent);
- }
- PutClientInServer (ent);
- // add a teleportation effect
- ent->s.event = EV_PLAYER_TELEPORT;
- // hold in place briefly
- ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
- ent->client->ps.pmove.pm_time = 14;
- gi.bprintf(PRINT_HIGH, "%s joined the %s team.\n",
- ent->client->pers.netname, CTFTeamName(desired_team));
- if (ctfgame.match == MATCH_SETUP) {
- gi.centerprintf(ent, "***********************\n"
- "Type \"ready\" in console\n"
- "to ready up.\n"
- "***********************");
- }
- }
- void CTFJoinTeam1(edict_t *ent, pmenuhnd_t *p)
- {
- CTFJoinTeam(ent, CTF_TEAM1);
- }
- void CTFJoinTeam2(edict_t *ent, pmenuhnd_t *p)
- {
- CTFJoinTeam(ent, CTF_TEAM2);
- }
- void CTFChaseCam(edict_t *ent, pmenuhnd_t *p)
- {
- int i;
- edict_t *e;
- if (ent->client->chase_target) {
- ent->client->chase_target = NULL;
- ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
- PMenu_Close(ent);
- return;
- }
- for (i = 1; i <= maxclients->value; i++) {
- e = g_edicts + i;
- if (e->inuse && e->solid != SOLID_NOT) {
- ent->client->chase_target = e;
- PMenu_Close(ent);
- ent->client->update_chase = true;
- return;
- }
- }
- SetLevelName(nochasemenu + jmenu_level);
- PMenu_Close(ent);
- PMenu_Open(ent, nochasemenu, -1, sizeof(nochasemenu) / sizeof(pmenu_t), NULL);
- }
- void CTFReturnToMain(edict_t *ent, pmenuhnd_t *p)
- {
- PMenu_Close(ent);
- CTFOpenJoinMenu(ent);
- }
- void CTFRequestMatch(edict_t *ent, pmenuhnd_t *p)
- {
- char text[1024];
- PMenu_Close(ent);
- sprintf(text, "%s has requested to switch to competition mode.",
- ent->client->pers.netname);
- CTFBeginElection(ent, ELECT_MATCH, text);
- }
- void DeathmatchScoreboard (edict_t *ent);
- void CTFShowScores(edict_t *ent, pmenu_t *p)
- {
- PMenu_Close(ent);
- ent->client->showscores = true;
- ent->client->showinventory = false;
- DeathmatchScoreboard (ent);
- }
- int CTFUpdateJoinMenu(edict_t *ent)
- {
- static char team1players[32];
- static char team2players[32];
- int num1, num2, i;
- if (ctfgame.match >= MATCH_PREGAME && matchlock->value) {
- joinmenu[jmenu_red].text = "MATCH IS LOCKED";
- joinmenu[jmenu_red].SelectFunc = NULL;
- joinmenu[jmenu_blue].text = " (entry is not permitted)";
- joinmenu[jmenu_blue].SelectFunc = NULL;
- } else {
- if (ctfgame.match >= MATCH_PREGAME) {
- joinmenu[jmenu_red].text = "Join Red MATCH Team";
- joinmenu[jmenu_blue].text = "Join Blue MATCH Team";
- } else {
- joinmenu[jmenu_red].text = "Join Red Team";
- joinmenu[jmenu_blue].text = "Join Blue Team";
- }
- joinmenu[jmenu_red].SelectFunc = CTFJoinTeam1;
- joinmenu[jmenu_blue].SelectFunc = CTFJoinTeam2;
- }
- if (ctf_forcejoin->string && *ctf_forcejoin->string) {
- if (stricmp(ctf_forcejoin->string, "red") == 0) {
- joinmenu[jmenu_blue].text = NULL;
- joinmenu[jmenu_blue].SelectFunc = NULL;
- } else if (stricmp(ctf_forcejoin->string, "blue") == 0) {
- joinmenu[jmenu_red].text = NULL;
- joinmenu[jmenu_red].SelectFunc = NULL;
- }
- }
- if (ent->client->chase_target)
- joinmenu[jmenu_chase].text = "Leave Chase Camera";
- else
- joinmenu[jmenu_chase].text = "Chase Camera";
- SetLevelName(joinmenu + jmenu_level);
- num1 = num2 = 0;
- for (i = 0; i < maxclients->value; i++) {
- if (!g_edicts[i+1].inuse)
- continue;
- if (game.clients[i].resp.ctf_team == CTF_TEAM1)
- num1++;
- else if (game.clients[i].resp.ctf_team == CTF_TEAM2)
- num2++;
- }
- sprintf(team1players, " (%d players)", num1);
- sprintf(team2players, " (%d players)", num2);
- switch (ctfgame.match) {
- case MATCH_NONE :
- joinmenu[jmenu_match].text = NULL;
- break;
- case MATCH_SETUP :
- joinmenu[jmenu_match].text = "*MATCH SETUP IN PROGRESS";
- break;
- case MATCH_PREGAME :
- joinmenu[jmenu_match].text = "*MATCH STARTING";
- break;
- case MATCH_GAME :
- joinmenu[jmenu_match].text = "*MATCH IN PROGRESS";
- break;
- }
- if (joinmenu[jmenu_red].text)
- joinmenu[jmenu_red+1].text = team1players;
- else
- joinmenu[jmenu_red+1].text = NULL;
- if (joinmenu[jmenu_blue].text)
- joinmenu[jmenu_blue+1].text = team2players;
- else
- joinmenu[jmenu_blue+1].text = NULL;
- joinmenu[jmenu_reqmatch].text = NULL;
- joinmenu[jmenu_reqmatch].SelectFunc = NULL;
- if (competition->value && ctfgame.match < MATCH_SETUP) {
- joinmenu[jmenu_reqmatch].text = "Request Match";
- joinmenu[jmenu_reqmatch].SelectFunc = CTFRequestMatch;
- }
-
- if (num1 > num2)
- return CTF_TEAM1;
- else if (num2 > num1)
- return CTF_TEAM2;
- return (rand() & 1) ? CTF_TEAM1 : CTF_TEAM2;
- }
- void CTFOpenJoinMenu(edict_t *ent)
- {
- int team;
- team = CTFUpdateJoinMenu(ent);
- if (ent->client->chase_target)
- team = 8;
- else if (team == CTF_TEAM1)
- team = 4;
- else
- team = 6;
- PMenu_Open(ent, joinmenu, team, sizeof(joinmenu) / sizeof(pmenu_t), NULL);
- }
- void CTFCredits(edict_t *ent, pmenuhnd_t *p)
- {
- PMenu_Close(ent);
- PMenu_Open(ent, creditsmenu, -1, sizeof(creditsmenu) / sizeof(pmenu_t), NULL);
- }
- qboolean CTFStartClient(edict_t *ent)
- {
- if (ent->client->resp.ctf_team != CTF_NOTEAM)
- return false;
- if (!((int)dmflags->value & DF_CTF_FORCEJOIN) || ctfgame.match >= MATCH_SETUP) {
- // start as 'observer'
- ent->movetype = MOVETYPE_NOCLIP;
- ent->solid = SOLID_NOT;
- ent->svflags |= SVF_NOCLIENT;
- ent->client->resp.ctf_team = CTF_NOTEAM;
- ent->client->ps.gunindex = 0;
- gi.linkentity (ent);
- CTFOpenJoinMenu(ent);
- return true;
- }
- return false;
- }
- void CTFObserver(edict_t *ent)
- {
- char userinfo[MAX_INFO_STRING];
- // start as 'observer'
- if (ent->movetype == MOVETYPE_NOCLIP)
- CTFPlayerResetGrapple(ent);
- CTFDeadDropFlag(ent);
- CTFDeadDropTech(ent);
- ent->deadflag = DEAD_NO;
- ent->movetype = MOVETYPE_NOCLIP;
- ent->solid = SOLID_NOT;
- ent->svflags |= SVF_NOCLIENT;
- ent->client->resp.ctf_team = CTF_NOTEAM;
- ent->client->ps.gunindex = 0;
- ent->client->resp.score = 0;
- memcpy (userinfo, ent->client->pers.userinfo, sizeof(userinfo));
- InitClientPersistant(ent->client);
- ClientUserinfoChanged (ent, userinfo);
- gi.linkentity (ent);
- CTFOpenJoinMenu(ent);
- }
- qboolean CTFInMatch(void)
- {
- if (ctfgame.match > MATCH_NONE)
- return true;
- return false;
- }
- qboolean CTFCheckRules(void)
- {
- int t;
- int i, j;
- char text[64];
- edict_t *ent;
- if (ctfgame.election != ELECT_NONE && ctfgame.electtime <= level.time) {
- gi.bprintf(PRINT_CHAT, "Election timed out and has been cancelled.\n");
- ctfgame.election = ELECT_NONE;
- }
- if (ctfgame.match != MATCH_NONE) {
- t = ctfgame.matchtime - level.time;
- // no team warnings in match mode
- ctfgame.warnactive = 0;
- if (t <= 0) { // time ended on something
- switch (ctfgame.match) {
- case MATCH_SETUP :
- // go back to normal mode
- if (competition->value < 3) {
- ctfgame.match = MATCH_NONE;
- gi.cvar_set("competition", "1");
- CTFResetAllPlayers();
- } else {
- // reset the time
- ctfgame.matchtime = level.time + matchsetuptime->value * 60;
- }
- return false;
- case MATCH_PREGAME :
- // match started!
- CTFStartMatch();
- gi.positioned_sound (world->s.origin, world, CHAN_AUTO | CHAN_RELIABLE, gi.soundindex("misc/tele_up.wav"), 1, ATTN_NONE, 0);
- return false;
- case MATCH_GAME :
- // match ended!
- CTFEndMatch();
- gi.positioned_sound (world->s.origin, world, CHAN_AUTO | CHAN_RELIABLE, gi.soundindex("misc/bigtele.wav"), 1, ATTN_NONE, 0);
- return false;
- }
- }
- if (t == ctfgame.lasttime)
- return false;
- ctfgame.lasttime = t;
- switch (ctfgame.match) {
- case MATCH_SETUP :
- for (j = 0, i = 1; i <= maxclients->value; i++) {
- ent = g_edicts + i;
- if (!ent->inuse)
- continue;
- if (ent->client->resp.ctf_team != CTF_NOTEAM &&
- !ent->client->resp.ready)
- j++;
- }
- if (competition->value < 3)
- sprintf(text, "%02d:%02d SETUP: %d not ready",
- t / 60, t % 60, j);
- else
- sprintf(text, "SETUP: %d not ready", j);
- gi.configstring (CONFIG_CTF_MATCH, text);
- break;
- case MATCH_PREGAME :
- sprintf(text, "%02d:%02d UNTIL START",
- t / 60, t % 60);
- gi.configstring (CONFIG_CTF_MATCH, text);
- if (t <= 10 && !ctfgame.countdown) {
- ctfgame.countdown = true;
- gi.positioned_sound (world->s.origin, world, CHAN_AUTO | CHAN_RELIABLE, gi.soundindex("world/10_0.wav"), 1, ATTN_NONE, 0);
- }
- break;
- case MATCH_GAME:
- sprintf(text, "%02d:%02d MATCH",
- t / 60, t % 60);
- gi.configstring (CONFIG_CTF_MATCH, text);
- if (t <= 10 && !ctfgame.countdown) {
- ctfgame.countdown = true;
- gi.positioned_sound (world->s.origin, world, CHAN_AUTO | CHAN_RELIABLE, gi.soundindex("world/10_0.wav"), 1, ATTN_NONE, 0);
- }
- break;
- }
- return false;
- } else {
- int team1 = 0, team2 = 0;
- if (level.time == ctfgame.lasttime)
- return false;
- ctfgame.lasttime = level.time;
- // this is only done in non-match (public) mode
- if (warn_unbalanced->value) {
- // count up the team totals
- for (i = 1; i <= maxclients->value; i++) {
- ent = g_edicts + i;
- if (!ent->inuse)
- continue;
- if (ent->client->resp.ctf_team == CTF_TEAM1)
- team1++;
- else if (ent->client->resp.ctf_team == CTF_TEAM2)
- team2++;
- }
- if (team1 - team2 >= 2 && team2 >= 2) {
- if (ctfgame.warnactive != CTF_TEAM1) {
- ctfgame.warnactive = CTF_TEAM1;
- gi.configstring (CONFIG_CTF_TEAMINFO, "WARNING: Red has too many players");
- }
- } else if (team2 - team1 >= 2 && team1 >= 2) {
- if (ctfgame.warnactive != CTF_TEAM2) {
- ctfgame.warnactive = CTF_TEAM2;
- gi.configstring (CONFIG_CTF_TEAMINFO, "WARNING: Blue has too many players");
- }
- } else
- ctfgame.warnactive = 0;
- } else
- ctfgame.warnactive = 0;
- }
- if (capturelimit->value &&
- (ctfgame.team1 >= capturelimit->value ||
- ctfgame.team2 >= capturelimit->value)) {
- gi.bprintf (PRINT_HIGH, "Capturelimit hit.\n");
- return true;
- }
- return false;
- }
- /*--------------------------------------------------------------------------
- * just here to help old map conversions
- *--------------------------------------------------------------------------*/
- static void old_teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
- {
- edict_t *dest;
- int i;
- vec3_t forward;
- if (!other->client)
- return;
- dest = G_Find (NULL, FOFS(targetname), self->target);
- if (!dest)
- {
- gi.dprintf ("Couldn't find destination\n");
- return;
- }
- //ZOID
- CTFPlayerResetGrapple(other);
- //ZOID
- // unlink to make sure it can't possibly interfere with KillBox
- gi.unlinkentity (other);
- VectorCopy (dest->s.origin, other->s.origin);
- VectorCopy (dest->s.origin, other->s.old_origin);
- // other->s.origin[2] += 10;
- // clear the velocity and hold them in place briefly
- VectorClear (other->velocity);
- other->client->ps.pmove.pm_time = 160>>3; // hold time
- other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
- // draw the teleport splash at source and on the player
- self->enemy->s.event = EV_PLAYER_TELEPORT;
- other->s.event = EV_PLAYER_TELEPORT;
- // set angles
- for (i=0 ; i<3 ; i++)
- other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
- other->s.angles[PITCH] = 0;
- other->s.angles[YAW] = dest->s.angles[YAW];
- other->s.angles[ROLL] = 0;
- VectorCopy (dest->s.angles, other->client->ps.viewangles);
- VectorCopy (dest->s.angles, other->client->v_angle);
- // give a little forward velocity
- AngleVectors (other->client->v_angle, forward, NULL, NULL);
- VectorScale(forward, 200, other->velocity);
- // kill anything at the destination
- if (!KillBox (other))
- {
- }
- gi.linkentity (other);
- }
- /*QUAKED trigger_teleport (0.5 0.5 0.5) ?
- Players touching this will be teleported
- */
- void SP_trigger_teleport (edict_t *ent)
- {
- edict_t *s;
- int i;
- if (!ent->target)
- {
- gi.dprintf ("teleporter without a target.\n");
- G_FreeEdict (ent);
- return;
- }
- ent->svflags |= SVF_NOCLIENT;
- ent->solid = SOLID_TRIGGER;
- ent->touch = old_teleporter_touch;
- gi.setmodel (ent, ent->model);
- gi.linkentity (ent);
- // noise maker and splash effect dude
- s = G_Spawn();
- ent->enemy = s;
- for (i = 0; i < 3; i++)
- s->s.origin[i] = ent->mins[i] + (ent->maxs[i] - ent->mins[i])/2;
- s->s.sound = gi.soundindex ("world/hum1.wav");
- gi.linkentity(s);
-
- }
- /*QUAKED info_teleport_destination (0.5 0.5 0.5) (-16 -16 -24) (16 16 32)
- Point trigger_teleports at these.
- */
- void SP_info_teleport_destination (edict_t *ent)
- {
- ent->s.origin[2] += 16;
- }
- /*----------------------------------------------------------------------------------*/
- /* ADMIN */
- typedef struct admin_settings_s {
- int matchlen;
- int matchsetuplen;
- int matchstartlen;
- qboolean weaponsstay;
- qboolean instantitems;
- qboolean quaddrop;
- qboolean instantweap;
- qboolean matchlock;
- } admin_settings_t;
- #define SETMENU_SIZE (7 + 5)
- void CTFAdmin_UpdateSettings(edict_t *ent, pmenuhnd_t *setmenu);
- void CTFOpenAdminMenu(edict_t *ent);
- void CTFAdmin_SettingsApply(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings = p->arg;
- char st[80];
- int i;
- if (settings->matchlen != matchtime->value) {
- gi.bprintf(PRINT_HIGH, "%s changed the match length to %d minutes.\n",
- ent->client->pers.netname, settings->matchlen);
- if (ctfgame.match == MATCH_GAME) {
- // in the middle of a match, change it on the fly
- ctfgame.matchtime = (ctfgame.matchtime - matchtime->value*60) + settings->matchlen*60;
- }
- sprintf(st, "%d", settings->matchlen);
- gi.cvar_set("matchtime", st);
- }
- if (settings->matchsetuplen != matchsetuptime->value) {
- gi.bprintf(PRINT_HIGH, "%s changed the match setup time to %d minutes.\n",
- ent->client->pers.netname, settings->matchsetuplen);
- if (ctfgame.match == MATCH_SETUP) {
- // in the middle of a match, change it on the fly
- ctfgame.matchtime = (ctfgame.matchtime - matchsetuptime->value*60) + settings->matchsetuplen*60;
- }
- sprintf(st, "%d", settings->matchsetuplen);
- gi.cvar_set("matchsetuptime", st);
- }
- if (settings->matchstartlen != matchstarttime->value) {
- gi.bprintf(PRINT_HIGH, "%s changed the match start time to %d seconds.\n",
- ent->client->pers.netname, settings->matchstartlen);
- if (ctfgame.match == MATCH_PREGAME) {
- // in the middle of a match, change it on the fly
- ctfgame.matchtime = (ctfgame.matchtime - matchstarttime->value) + settings->matchstartlen;
- }
- sprintf(st, "%d", settings->matchstartlen);
- gi.cvar_set("matchstarttime", st);
- }
- if (settings->weaponsstay != !!((int)dmflags->value & DF_WEAPONS_STAY)) {
- gi.bprintf(PRINT_HIGH, "%s turned %s weapons stay.\n",
- ent->client->pers.netname, settings->weaponsstay ? "on" : "off");
- i = (int)dmflags->value;
- if (settings->weaponsstay)
- i |= DF_WEAPONS_STAY;
- else
- i &= ~DF_WEAPONS_STAY;
- sprintf(st, "%d", i);
- gi.cvar_set("dmflags", st);
- }
- if (settings->instantitems != !!((int)dmflags->value & DF_INSTANT_ITEMS)) {
- gi.bprintf(PRINT_HIGH, "%s turned %s instant items.\n",
- ent->client->pers.netname, settings->instantitems ? "on" : "off");
- i = (int)dmflags->value;
- if (settings->instantitems)
- i |= DF_INSTANT_ITEMS;
- else
- i &= ~DF_INSTANT_ITEMS;
- sprintf(st, "%d", i);
- gi.cvar_set("dmflags", st);
- }
- if (settings->quaddrop != !!((int)dmflags->value & DF_QUAD_DROP)) {
- gi.bprintf(PRINT_HIGH, "%s turned %s quad drop.\n",
- ent->client->pers.netname, settings->quaddrop ? "on" : "off");
- i = (int)dmflags->value;
- if (settings->quaddrop)
- i |= DF_QUAD_DROP;
- else
- i &= ~DF_QUAD_DROP;
- sprintf(st, "%d", i);
- gi.cvar_set("dmflags", st);
- }
- if (settings->instantweap != !!((int)instantweap->value)) {
- gi.bprintf(PRINT_HIGH, "%s turned %s instant weapons.\n",
- ent->client->pers.netname, settings->instantweap ? "on" : "off");
- sprintf(st, "%d", (int)settings->instantweap);
- gi.cvar_set("instantweap", st);
- }
- if (settings->matchlock != !!((int)matchlock->value)) {
- gi.bprintf(PRINT_HIGH, "%s turned %s match lock.\n",
- ent->client->pers.netname, settings->matchlock ? "on" : "off");
- sprintf(st, "%d", (int)settings->matchlock);
- gi.cvar_set("matchlock", st);
- }
- PMenu_Close(ent);
- CTFOpenAdminMenu(ent);
- }
- void CTFAdmin_SettingsCancel(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings = p->arg;
- PMenu_Close(ent);
- CTFOpenAdminMenu(ent);
- }
- void CTFAdmin_ChangeMatchLen(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings = p->arg;
- settings->matchlen = (settings->matchlen % 60) + 5;
- if (settings->matchlen < 5)
- settings->matchlen = 5;
- CTFAdmin_UpdateSettings(ent, p);
- }
- void CTFAdmin_ChangeMatchSetupLen(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings = p->arg;
- settings->matchsetuplen = (settings->matchsetuplen % 60) + 5;
- if (settings->matchsetuplen < 5)
- settings->matchsetuplen = 5;
- CTFAdmin_UpdateSettings(ent, p);
- }
- void CTFAdmin_ChangeMatchStartLen(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings = p->arg;
- settings->matchstartlen = (settings->matchstartlen % 600) + 10;
- if (settings->matchstartlen < 20)
- settings->matchstartlen = 20;
- CTFAdmin_UpdateSettings(ent, p);
- }
- void CTFAdmin_ChangeWeapStay(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings = p->arg;
- settings->weaponsstay = !settings->weaponsstay;
- CTFAdmin_UpdateSettings(ent, p);
- }
- void CTFAdmin_ChangeInstantItems(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings = p->arg;
- settings->instantitems = !settings->instantitems;
- CTFAdmin_UpdateSettings(ent, p);
- }
- void CTFAdmin_ChangeQuadDrop(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings = p->arg;
- settings->quaddrop = !settings->quaddrop;
- CTFAdmin_UpdateSettings(ent, p);
- }
- void CTFAdmin_ChangeInstantWeap(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings = p->arg;
- settings->instantweap = !settings->instantweap;
- CTFAdmin_UpdateSettings(ent, p);
- }
- void CTFAdmin_ChangeMatchLock(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings = p->arg;
- settings->matchlock = !settings->matchlock;
- CTFAdmin_UpdateSettings(ent, p);
- }
- void CTFAdmin_UpdateSettings(edict_t *ent, pmenuhnd_t *setmenu)
- {
- int i = 2;
- char text[64];
- admin_settings_t *settings = setmenu->arg;
- sprintf(text, "Match Len: %2d mins", settings->matchlen);
- PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeMatchLen);
- i++;
- sprintf(text, "Match Setup Len: %2d mins", settings->matchsetuplen);
- PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeMatchSetupLen);
- i++;
- sprintf(text, "Match Start Len: %2d secs", settings->matchstartlen);
- PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeMatchStartLen);
- i++;
- sprintf(text, "Weapons Stay: %s", settings->weaponsstay ? "Yes" : "No");
- PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeWeapStay);
- i++;
- sprintf(text, "Instant Items: %s", settings->instantitems ? "Yes" : "No");
- PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeInstantItems);
- i++;
- sprintf(text, "Quad Drop: %s", settings->quaddrop ? "Yes" : "No");
- PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeQuadDrop);
- i++;
- sprintf(text, "Instant Weapons: %s", settings->instantweap ? "Yes" : "No");
- PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeInstantWeap);
- i++;
- sprintf(text, "Match Lock: %s", settings->matchlock ? "Yes" : "No");
- PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeMatchLock);
- i++;
- PMenu_Update(ent);
- }
- pmenu_t def_setmenu[] = {
- { "*Settings Menu", PMENU_ALIGN_CENTER, NULL },
- { NULL, PMENU_ALIGN_CENTER, NULL },
- { NULL, PMENU_ALIGN_LEFT, NULL }, //int matchlen;
- { NULL, PMENU_ALIGN_LEFT, NULL }, //int matchsetuplen;
- { NULL, PMENU_ALIGN_LEFT, NULL }, //int matchstartlen;
- { NULL, PMENU_ALIGN_LEFT, NULL }, //qboolean weaponsstay;
- { NULL, PMENU_ALIGN_LEFT, NULL }, //qboolean instantitems;
- { NULL, PMENU_ALIGN_LEFT, NULL }, //qboolean quaddrop;
- { NULL, PMENU_ALIGN_LEFT, NULL }, //qboolean instantweap;
- { NULL, PMENU_ALIGN_LEFT, NULL }, //qboolean matchlock;
- { NULL, PMENU_ALIGN_LEFT, NULL },
- { "Apply", PMENU_ALIGN_LEFT, CTFAdmin_SettingsApply },
- { "Cancel", PMENU_ALIGN_LEFT, CTFAdmin_SettingsCancel }
- };
- void CTFAdmin_Settings(edict_t *ent, pmenuhnd_t *p)
- {
- admin_settings_t *settings;
- pmenuhnd_t *menu;
- PMenu_Close(ent);
- settings = malloc(sizeof(*settings));
- settings->matchlen = matchtime->value;
- settings->matchsetuplen = matchsetuptime->value;
- settings->matchstartlen = matchstarttime->value;
- settings->weaponsstay = !!((int)dmflags->value & DF_WEAPONS_STAY);
- settings->instantitems = !!((int)dmflags->value & DF_INSTANT_ITEMS);
- settings->quaddrop = !!((int)dmflags->value & DF_QUAD_DROP);
- settings->instantweap = instantweap->value != 0;
- settings->matchlock = matchlock->value != 0;
- menu = PMenu_Open(ent, def_setmenu, -1, sizeof(def_setmenu) / sizeof(pmenu_t), settings);
- CTFAdmin_UpdateSettings(ent, menu);
- }
- void CTFAdmin_MatchSet(edict_t *ent, pmenuhnd_t *p)
- {
- PMenu_Close(ent);
- if (ctfgame.match == MATCH_SETUP) {
- gi.bprintf(PRINT_CHAT, "Match has been forced to start.\n");
- ctfgame.match = MATCH_PREGAME;
- ctfgame.matchtime = level.time + matchstarttime->value;
- gi.positioned_sound (world->s.origin, world, CHAN_AUTO | CHAN_RELIABLE, gi.soundindex("misc/talk1.wav"), 1, ATTN_NONE, 0);
- ctfgame.countdown = false;
- } else if (ctfgame.match == MATCH_GAME) {
- gi.bprintf(PRINT_CHAT, "Match has been forced to terminate.\n");
- ctfgame.match = MATCH_SETUP;
- ctfgame.matchtime = level.time + matchsetuptime->value * 60;
- CTFResetAllPlayers();
- }
- }
- void CTFAdmin_MatchMode(edict_t *ent, pmenuhnd_t *p)
- {
- PMenu_Close(ent);
- if (ctfgame.match != MATCH_SETUP) {
- if (competition->value < 3)
- gi.cvar_set("competition", "2");
- ctfgame.match = MATCH_SETUP;
- CTFResetAllPlayers();
- }
- }
- void CTFAdmin_Reset(edict_t *ent, pmenuhnd_t *p)
- {
- PMenu_Close(ent);
- // go back to normal mode
- gi.bprintf(PRINT_CHAT, "Match mode has been terminated, reseting to normal game.\n");
- ctfgame.match = MATCH_NONE;
- gi.cvar_set("competition", "1");
- CTFResetAllPlayers();
- }
- void CTFAdmin_Cancel(edict_t *ent, pmenuhnd_t *p)
- {
- PMenu_Close(ent);
- }
- pmenu_t adminmenu[] = {
- { "*Administration Menu", PMENU_ALIGN_CENTER, NULL },
- { NULL, PMENU_ALIGN_CENTER, NULL }, // blank
- { "Settings", PMENU_ALIGN_LEFT, CTFAdmin_Settings },
- { NULL, PMENU_ALIGN_LEFT, NULL },
- { NULL, PMENU_ALIGN_LEFT, NULL },
- { "Cancel", PMENU_ALIGN_LEFT, CTFAdmin_Cancel },
- { NULL, PMENU_ALIGN_CENTER, NULL },
- };
- void CTFOpenAdminMenu(edict_t *ent)
- {
- adminmenu[3].text = NULL;
- adminmenu[3].SelectFunc = NULL;
- adminmenu[4].text = NULL;
- adminmenu[4].SelectFunc = NULL;
- if (ctfgame.match == MATCH_SETUP) {
- adminmenu[3].text = "Force start match";
- adminmenu[3].SelectFunc = CTFAdmin_MatchSet;
- adminmenu[4].text = "Reset to pickup mode";
- adminmenu[4].SelectFunc = CTFAdmin_Reset;
- } else if (ctfgame.match == MATCH_GAME || ctfgame.match == MATCH_PREGAME) {
- adminmenu[3].text = "Cancel match";
- adminmenu[3].SelectFunc = CTFAdmin_MatchSet;
- } else if (ctfgame.match == MATCH_NONE && competition->value) {
- adminmenu[3].text = "Switch to match mode";
- adminmenu[3].SelectFunc = CTFAdmin_MatchMode;
- }
- // if (ent->client->menu)
- // PMenu_Close(ent->client->menu);
- PMenu_Open(ent, adminmenu, -1, sizeof(adminmenu) / sizeof(pmenu_t), NULL);
- }
- void CTFAdmin(edict_t *ent)
- {
- char text[1024];
- if (!allow_admin->value) {
- gi.cprintf(ent, PRINT_HIGH, "Administration is disabled\n");
- return;
- }
- if (gi.argc() > 1 && admin_password->string && *admin_password->string &&
- !ent->client->resp.admin && strcmp(admin_password->string, gi.argv(1)) == 0) {
- ent->client->resp.admin = true;
- gi.bprintf(PRINT_HIGH, "%s has become an admin.\n", ent->client->pers.netname);
- gi.cprintf(ent, PRINT_HIGH, "Type 'admin' to access the adminstration menu.\n");
- }
- if (!ent->client->resp.admin) {
- sprintf(text, "%s has requested admin rights.",
- ent->client->pers.netname);
- CTFBeginElection(ent, ELECT_ADMIN, text);
- return;
- }
- if (ent->client->menu)
- PMenu_Close(ent);
- CTFOpenAdminMenu(ent);
- }
- /*----------------------------------------------------------------*/
- void CTFStats(edict_t *ent)
- {
- int i, e;
- ghost_t *g;
- char st[80];
- char text[1024];
- edict_t *e2;
- *text = 0;
- if (ctfgame.match == MATCH_SETUP) {
- for (i = 1; i <= maxclients->value; i++) {
- e2 = g_edicts + i;
- if (!e2->inuse)
- continue;
- if (!e2->client->resp.ready && e2->client->resp.ctf_team != CTF_NOTEAM) {
- sprintf(st, "%s is not ready.\n", e2->client->pers.netname);
- if (strlen(text) + strlen(st) < sizeof(text) - 50)
- strcat(text, st);
- }
- }
- }
- for (i = 0, g = ctfgame.ghosts; i < MAX_CLIENTS; i++, g++)
- if (g->ent)
- break;
- if (i == MAX_CLIENTS) {
- if (*text)
- gi.cprintf(ent, PRINT_HIGH, "%s", text);
- gi.cprintf(ent, PRINT_HIGH, "No statistics available.\n");
- return;
- }
- strcat(text, " #|Name |Score|Kills|Death|BasDf|CarDf|Effcy|\n");
- for (i = 0, g = ctfgame.ghosts; i < MAX_CLIENTS; i++, g++) {
- if (!*g->netname)
- continue;
- if (g->deaths + g->kills == 0)
- e = 50;
- else
- e = g->kills * 100 / (g->kills + g->deaths);
- sprintf(st, "%3d|%-16.16s|%5d|%5d|%5d|%5d|%5d|%4d%%|\n",
- g->number,
- g->netname,
- g->score,
- g->kills,
- g->deaths,
- g->basedef,
- g->carrierdef,
- e);
- if (strlen(text) + strlen(st) > sizeof(text) - 50) {
- sprintf(text+strlen(text), "And more...\n");
- gi.cprintf(ent, PRINT_HIGH, "%s", text);
- return;
- }
- strcat(text, st);
- }
- gi.cprintf(ent, PRINT_HIGH, "%s", text);
- }
- void CTFPlayerList(edict_t *ent)
- {
- int i;
- char st[80];
- char text[1400];
- edict_t *e2;
- #if 0
- *text = 0;
- if (ctfgame.match == MATCH_SETUP) {
- for (i = 1; i <= maxclients->value; i++) {
- e2 = g_edicts + i;
- if (!e2->inuse)
- continue;
- if (!e2->client->resp.ready && e2->client->resp.ctf_team != CTF_NOTEAM) {
- sprintf(st, "%s is not ready.\n", e2->client->pers.netname);
- if (strlen(text) + strlen(st) < sizeof(text) - 50)
- strcat(text, st);
- }
- }
- }
- #endif
- // number, name, connect time, ping, score, admin
- *text = 0;
- for (i = 1; i <= maxclients->value; i++) {
- e2 = g_edicts + i;
- if (!e2->inuse)
- continue;
- Com_sprintf(st, sizeof(st), "%3d %-16.16s %02d:%02d %4d %3d%s%s\n",
- i,
- e2->client->pers.netname,
- (level.framenum - e2->client->resp.enterframe) / 600,
- ((level.framenum - e2->client->resp.enterframe) % 600)/10,
- e2->client->ping,
- e2->client->resp.score,
- (ctfgame.match == MATCH_SETUP || ctfgame.match == MATCH_PREGAME) ?
- (e2->client->resp.ready ? " (ready)" : " (notready)") : "",
- e2->client->resp.admin ? " (admin)" : "");
- if (strlen(text) + strlen(st) > sizeof(text) - 50) {
- sprintf(text+strlen(text), "And more...\n");
- gi.cprintf(ent, PRINT_HIGH, "%s", text);
- return;
- }
- strcat(text, st);
- }
- gi.cprintf(ent, PRINT_HIGH, "%s", text);
- }
- void CTFWarp(edict_t *ent)
- {
- char text[1024];
- char *mlist, *token;
- static const char *seps = " \t\n\r";
- if (gi.argc() < 2) {
- gi.cprintf(ent, PRINT_HIGH, "Where do you want to warp to?\n");
- gi.cprintf(ent, PRINT_HIGH, "Available levels are: %s\n", warp_list->string);
- return;
- }
- mlist = strdup(warp_list->string);
- token = strtok(mlist, seps);
- while (token != NULL) {
- if (Q_stricmp(token, gi.argv(1)) == 0)
- break;
- token = strtok(NULL, seps);
- }
- if (token == NULL) {
- gi.cprintf(ent, PRINT_HIGH, "Unknown CTF level.\n");
- gi.cprintf(ent, PRINT_HIGH, "Available levels are: %s\n", warp_list->string);
- free(mlist);
- return;
- }
- free(mlist);
- if (ent->client->resp.admin) {
- gi.bprintf(PRINT_HIGH, "%s is warping to level %s.\n",
- ent->client->pers.netname, gi.argv(1));
- strncpy(level.forcemap, gi.argv(1), sizeof(level.forcemap) - 1);
- EndDMLevel();
- return;
- }
- sprintf(text, "%s has requested warping to level %s.",
- ent->client->pers.netname, gi.argv(1));
- if (CTFBeginElection(ent, ELECT_MAP, text))
- strncpy(ctfgame.elevel, gi.argv(1), sizeof(ctfgame.elevel) - 1);
- }
- void CTFBoot(edict_t *ent)
- {
- int i;
- edict_t *targ;
- char text[80];
- if (!ent->client->resp.admin) {
- gi.cprintf(ent, PRINT_HIGH, "You are not an admin.\n");
- return;
- }
- if (gi.argc() < 2) {
- gi.cprintf(ent, PRINT_HIGH, "Who do you want to kick?\n");
- return;
- }
- if (*gi.argv(1) < '0' && *gi.argv(1) > '9') {
- gi.cprintf(ent, PRINT_HIGH, "Specify the player number to kick.\n");
- return;
- }
- i = atoi(gi.argv(1));
- if (i < 1 || i > maxclients->value) {
- gi.cprintf(ent, PRINT_HIGH, "Invalid player number.\n");
- return;
- }
- targ = g_edicts + i;
- if (!targ->inuse) {
- gi.cprintf(ent, PRINT_HIGH, "That player number is not connected.\n");
- return;
- }
- sprintf(text, "kick %d\n", i - 1);
- gi.AddCommandString(text);
- }
- void CTFSetPowerUpEffect(edict_t *ent, int def)
- {
- if (ent->client->resp.ctf_team == CTF_TEAM1)
- ent->s.effects |= EF_PENT; // red
- else if (ent->client->resp.ctf_team == CTF_TEAM2)
- ent->s.effects |= EF_QUAD; // red
- else
- ent->s.effects |= def;
- }
|