1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code 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 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "Game_local.h"
- #ifdef GAME_DLL
- idSys * sys = NULL;
- idCommon * common = NULL;
- idCmdSystem * cmdSystem = NULL;
- idCVarSystem * cvarSystem = NULL;
- idFileSystem * fileSystem = NULL;
- idRenderSystem * renderSystem = NULL;
- idSoundSystem * soundSystem = NULL;
- idRenderModelManager * renderModelManager = NULL;
- idUserInterfaceManager * uiManager = NULL;
- idDeclManager * declManager = NULL;
- idAASFileManager * AASFileManager = NULL;
- idCollisionModelManager * collisionModelManager = NULL;
- idCVar * idCVar::staticVars = NULL;
- idCVar com_forceGenericSIMD( "com_forceGenericSIMD", "0", CVAR_BOOL|CVAR_SYSTEM, "force generic platform independent SIMD" );
- #endif
- idRenderWorld * gameRenderWorld = NULL; // all drawing is done to this world
- idSoundWorld * gameSoundWorld = NULL; // all audio goes to this world
- static gameExport_t gameExport;
- // global animation lib
- idAnimManager animationLib;
- // the rest of the engine will only reference the "game" variable, while all local aspects stay hidden
- idGameLocal gameLocal;
- idGame * game = &gameLocal; // statically pointed at an idGameLocal
- const char *idGameLocal::sufaceTypeNames[ MAX_SURFACE_TYPES ] = {
- "none", "metal", "stone", "flesh", "wood", "cardboard", "liquid", "glass", "plastic",
- "ricochet", "surftype10", "surftype11", "surftype12", "surftype13", "surftype14", "surftype15"
- };
- idCVar net_usercmd_timing_debug( "net_usercmd_timing_debug", "0", CVAR_BOOL, "Print messages about usercmd timing." );
- // List of all defs used by the player that will stay on the fast timeline
- static char* fastEntityList[] = {
- "player_doommarine",
- "weapon_chainsaw",
- "weapon_fists",
- "weapon_flashlight",
- "weapon_rocketlauncher",
- "projectile_rocket",
- "weapon_machinegun",
- "projectile_bullet_machinegun",
- "weapon_pistol",
- "projectile_bullet_pistol",
- "weapon_handgrenade",
- "projectile_grenade",
- "weapon_bfg",
- "projectile_bfg",
- "weapon_chaingun",
- "projectile_chaingunbullet",
- "weapon_pda",
- "weapon_plasmagun",
- "projectile_plasmablast",
- "weapon_shotgun",
- "projectile_bullet_shotgun",
- "weapon_soulcube",
- "projectile_soulblast",
- "weapon_shotgun_double",
- "projectile_shotgunbullet_double",
- "weapon_grabber",
- "weapon_bloodstone_active1",
- "weapon_bloodstone_active2",
- "weapon_bloodstone_active3",
- "weapon_bloodstone_passive",
- NULL };
- /*
- ===========
- GetGameAPI
- ============
- */
- #if __MWERKS__
- #pragma export on
- #endif
- #if __GNUC__ >= 4
- #pragma GCC visibility push(default)
- #endif
- extern "C" gameExport_t *GetGameAPI( gameImport_t *import ) {
- #if __MWERKS__
- #pragma export off
- #endif
- if ( import->version == GAME_API_VERSION ) {
- // set interface pointers used by the game
- sys = import->sys;
- common = import->common;
- cmdSystem = import->cmdSystem;
- cvarSystem = import->cvarSystem;
- fileSystem = import->fileSystem;
- renderSystem = import->renderSystem;
- soundSystem = import->soundSystem;
- renderModelManager = import->renderModelManager;
- uiManager = import->uiManager;
- declManager = import->declManager;
- AASFileManager = import->AASFileManager;
- collisionModelManager = import->collisionModelManager;
- }
- // set interface pointers used by idLib
- idLib::sys = sys;
- idLib::common = common;
- idLib::cvarSystem = cvarSystem;
- idLib::fileSystem = fileSystem;
- // setup export interface
- gameExport.version = GAME_API_VERSION;
- gameExport.game = game;
- gameExport.gameEdit = gameEdit;
- return &gameExport;
- }
- #if __GNUC__ >= 4
- #pragma GCC visibility pop
- #endif
- /*
- ===========
- TestGameAPI
- ============
- */
- void TestGameAPI() {
- gameImport_t testImport;
- gameExport_t testExport;
- testImport.sys = ::sys;
- testImport.common = ::common;
- testImport.cmdSystem = ::cmdSystem;
- testImport.cvarSystem = ::cvarSystem;
- testImport.fileSystem = ::fileSystem;
- testImport.renderSystem = ::renderSystem;
- testImport.soundSystem = ::soundSystem;
- testImport.renderModelManager = ::renderModelManager;
- testImport.uiManager = ::uiManager;
- testImport.declManager = ::declManager;
- testImport.AASFileManager = ::AASFileManager;
- testImport.collisionModelManager = ::collisionModelManager;
- testExport = *GetGameAPI( &testImport );
- }
- /*
- ===========
- idGameLocal::idGameLocal
- ============
- */
- idGameLocal::idGameLocal() {
- Clear();
- }
- /*
- ===========
- idGameLocal::Clear
- ============
- */
- void idGameLocal::Clear() {
- int i;
- serverInfo.Clear();
- numClients = 0;
- for ( i = 0; i < MAX_CLIENTS; i++ ) {
- persistentPlayerInfo[i].Clear();
- }
- memset( entities, 0, sizeof( entities ) );
- memset( spawnIds, -1, sizeof( spawnIds ) );
- firstFreeEntityIndex[0] = 0;
- firstFreeEntityIndex[1] = ENTITYNUM_FIRST_NON_REPLICATED;
- num_entities = 0;
- spawnedEntities.Clear();
- activeEntities.Clear();
- numEntitiesToDeactivate = 0;
- sortPushers = false;
- sortTeamMasters = false;
- persistentLevelInfo.Clear();
- memset( globalShaderParms, 0, sizeof( globalShaderParms ) );
- random.SetSeed( 0 );
- world = NULL;
- frameCommandThread = NULL;
- testmodel = NULL;
- testFx = NULL;
- clip.Shutdown();
- pvs.Shutdown();
- sessionCommand.Clear();
- locationEntities = NULL;
- smokeParticles = NULL;
- editEntities = NULL;
- entityHash.Clear( 1024, MAX_GENTITIES );
- inCinematic = false;
- framenum = 0;
- previousTime = 0;
- time = 0;
- vacuumAreaNum = 0;
- mapFileName.Clear();
- mapFile = NULL;
- spawnCount = INITIAL_SPAWN_COUNT;
- mapSpawnCount = 0;
- camera = NULL;
- aasList.Clear();
- aasNames.Clear();
- lastAIAlertEntity = NULL;
- lastAIAlertTime = 0;
- spawnArgs.Clear();
- gravity.Set( 0, 0, -1 );
- playerPVS.h = (unsigned int)-1;
- playerConnectedAreas.h = (unsigned int)-1;
- gamestate = GAMESTATE_UNINITIALIZED;
- influenceActive = false;
- realClientTime = 0;
- isNewFrame = true;
- clientSmoothing = 0.1f;
- entityDefBits = 0;
- nextGibTime = 0;
- globalMaterial = NULL;
- newInfo.Clear();
- lastGUIEnt = NULL;
- lastGUI = 0;
- eventQueue.Init();
- savedEventQueue.Init();
-
- shellHandler = NULL;
- selectedGroup = 0;
- portalSkyEnt = NULL;
- portalSkyActive = false;
- ResetSlowTimeVars();
- lastCmdRunTimeOnClient.Zero();
- lastCmdRunTimeOnServer.Zero();
- }
- /*
- ===========
- idGameLocal::Init
- initialize the game object, only happens once at startup, not each level load
- ============
- */
- void idGameLocal::Init() {
- const idDict *dict;
- idAAS *aas;
- #ifndef GAME_DLL
- TestGameAPI();
- #else
- // initialize idLib
- idLib::Init();
- // register static cvars declared in the game
- idCVar::RegisterStaticVars();
- // initialize processor specific SIMD
- idSIMD::InitProcessor( "game", com_forceGenericSIMD.GetBool() );
- #endif
- Printf( "--------- Initializing Game ----------\n" );
- Printf( "gamename: %s\n", GAME_VERSION );
- Printf( "gamedate: %s\n", __DATE__ );
- // register game specific decl types
- declManager->RegisterDeclType( "model", DECL_MODELDEF, idDeclAllocator<idDeclModelDef> );
- declManager->RegisterDeclType( "export", DECL_MODELEXPORT, idDeclAllocator<idDecl> );
- // register game specific decl folders
- declManager->RegisterDeclFolder( "def", ".def", DECL_ENTITYDEF );
- declManager->RegisterDeclFolder( "fx", ".fx", DECL_FX );
- declManager->RegisterDeclFolder( "particles", ".prt", DECL_PARTICLE );
- declManager->RegisterDeclFolder( "af", ".af", DECL_AF );
- declManager->RegisterDeclFolder( "newpdas", ".pda", DECL_PDA );
- cmdSystem->AddCommand( "listModelDefs", idListDecls_f<DECL_MODELDEF>, CMD_FL_SYSTEM|CMD_FL_GAME, "lists model defs" );
- cmdSystem->AddCommand( "printModelDefs", idPrintDecls_f<DECL_MODELDEF>, CMD_FL_SYSTEM|CMD_FL_GAME, "prints a model def", idCmdSystem::ArgCompletion_Decl<DECL_MODELDEF> );
- Clear();
- idEvent::Init();
- idClass::Init();
- InitConsoleCommands();
- shellHandler = new (TAG_SWF) idMenuHandler_Shell();
- if(!g_xp_bind_run_once.GetBool()) {
- //The default config file contains remapped controls that support the XP weapons
- //We want to run this once after the base doom config file has run so we can
- //have the correct xp binds
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec default.cfg\n" );
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "seta g_xp_bind_run_once 1\n" );
- cmdSystem->ExecuteCommandBuffer();
- }
- // load default scripts
- program.Startup( SCRIPT_DEFAULT );
-
- smokeParticles = new (TAG_PARTICLE) idSmokeParticles;
- // set up the aas
- dict = FindEntityDefDict( "aas_types" );
- if ( dict == NULL ) {
- Error( "Unable to find entityDef for 'aas_types'" );
- return;
- }
- // allocate space for the aas
- const idKeyValue *kv = dict->MatchPrefix( "type" );
- while( kv != NULL ) {
- aas = idAAS::Alloc();
- aasList.Append( aas );
- aasNames.Append( kv->GetValue() );
- kv = dict->MatchPrefix( "type", kv );
- }
- gamestate = GAMESTATE_NOMAP;
- Printf( "...%d aas types\n", aasList.Num() );
- Printf( "game initialized.\n" );
- Printf( "--------------------------------------\n" );
- }
- /*
- ===========
- idGameLocal::Shutdown
- shut down the entire game
- ============
- */
- void idGameLocal::Shutdown() {
- if ( !common ) {
- return;
- }
- Printf( "------------ Game Shutdown -----------\n" );
- Shell_Cleanup();
- mpGame.Shutdown();
- MapShutdown();
- aasList.DeleteContents( true );
- aasNames.Clear();
- idAI::FreeObstacleAvoidanceNodes();
- idEvent::Shutdown();
- delete[] locationEntities;
- locationEntities = NULL;
- delete smokeParticles;
- smokeParticles = NULL;
- idClass::Shutdown();
- // clear list with forces
- idForce::ClearForceList();
- // free the program data
- program.FreeData();
- // delete the .map file
- delete mapFile;
- mapFile = NULL;
- // free the collision map
- collisionModelManager->FreeMap();
- ShutdownConsoleCommands();
- // free memory allocated by class objects
- Clear();
- // shut down the animation manager
- animationLib.Shutdown();
- Printf( "--------------------------------------\n" );
- #ifdef GAME_DLL
- // remove auto-completion function pointers pointing into this DLL
- cvarSystem->RemoveFlaggedAutoCompletion( CVAR_GAME );
- // enable leak test
- Mem_EnableLeakTest( "game" );
- // shutdown idLib
- idLib::ShutDown();
- #endif
- }
- idCVar g_recordSaveGameTrace( "g_recordSaveGameTrace", "0", CVAR_BOOL, "" );
- /*
- ===========
- idGameLocal::SaveGame
- save the current player state, level name, and level state
- the session may have written some data to the file already
- ============
- */
- void idGameLocal::SaveGame( idFile *f, idFile *strings ) {
- int i;
- idEntity *ent;
- idEntity *link;
- int startTimeMs = Sys_Milliseconds();
- if ( g_recordSaveGameTrace.GetBool() ) {
- bool result = BeginTraceRecording( "e:\\savegame_trace.pix2" );
- if ( !result ) {
- //idLib::Printf( "BeginTraceRecording: error %d\n", GetLastError() );
- }
- }
- idSaveGame savegame( f, strings, BUILD_NUMBER );
- if ( g_flushSave.GetBool( ) == true ) {
- // force flushing with each write... for tracking down
- // save game bugs.
- f->ForceFlush();
- }
- // go through all entities and threads and add them to the object list
- for( i = 0; i < MAX_GENTITIES; i++ ) {
- ent = entities[i];
- if ( ent ) {
- if ( ent->GetTeamMaster() && ent->GetTeamMaster() != ent ) {
- continue;
- }
- for ( link = ent; link != NULL; link = link->GetNextTeamEntity() ) {
- savegame.AddObject( link );
- }
- }
- }
- idList<idThread *> threads;
- threads = idThread::GetThreads();
- for( i = 0; i < threads.Num(); i++ ) {
- savegame.AddObject( threads[i] );
- }
- // write out complete object list
- savegame.WriteObjectList();
- program.Save( &savegame );
- savegame.WriteInt( g_skill.GetInteger() );
- savegame.WriteDecls();
- savegame.WriteDict( &serverInfo );
- savegame.WriteInt( numClients );
- for( i = 0; i < numClients; i++ ) {
- //savegame.WriteUsercmd( usercmds[ i ] );
- // Now that usercmds are handled by the idUserCmdMgr,
- // do we need another solution here?
- usercmd_t dummy;
- savegame.WriteUsercmd( dummy );
-
- savegame.WriteDict( &persistentPlayerInfo[ i ] );
- }
- for( i = 0; i < MAX_GENTITIES; i++ ) {
- savegame.WriteObject( entities[ i ] );
- savegame.WriteInt( spawnIds[ i ] );
- }
- // There shouldn't be any non-replicated entities in SP,
- // so we shouldn't have to save the first free replicated entity index.
- savegame.WriteInt( firstFreeEntityIndex[0] );
- savegame.WriteInt( num_entities );
- // enityHash is restored by idEntity::Restore setting the entity name.
- savegame.WriteObject( world );
- savegame.WriteInt( spawnedEntities.Num() );
- for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
- savegame.WriteObject( ent );
- }
- savegame.WriteInt( activeEntities.Num() );
- for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
- savegame.WriteObject( ent );
- }
- savegame.WriteInt( numEntitiesToDeactivate );
- savegame.WriteBool( sortPushers );
- savegame.WriteBool( sortTeamMasters );
- savegame.WriteDict( &persistentLevelInfo );
- for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
- savegame.WriteFloat( globalShaderParms[ i ] );
- }
- savegame.WriteInt( random.GetSeed() );
- savegame.WriteObject( frameCommandThread );
- // clip
- // push
- // pvs
- testmodel = NULL;
- testFx = NULL;
- savegame.WriteString( sessionCommand );
- // FIXME: save smoke particles
- savegame.WriteBool( inCinematic );
- savegame.WriteInt( gameType );
- savegame.WriteInt( framenum );
- savegame.WriteInt( previousTime );
- savegame.WriteInt( time );
- savegame.WriteInt( vacuumAreaNum );
- savegame.WriteInt( entityDefBits );
- savegame.WriteInt( GetLocalClientNum() );
- // snapshotEntities is used for multiplayer only
- savegame.WriteInt( realClientTime );
- savegame.WriteBool( isNewFrame );
- savegame.WriteFloat( clientSmoothing );
- portalSkyEnt.Save( &savegame );
- savegame.WriteBool( portalSkyActive );
- fast.Save( &savegame );
- slow.Save( &savegame );
- savegame.WriteInt( slowmoState );
- savegame.WriteFloat( slowmoScale );
- savegame.WriteBool( quickSlowmoReset );
- savegame.WriteBool( mapCycleLoaded );
- savegame.WriteInt( spawnCount );
- if ( !locationEntities ) {
- savegame.WriteInt( 0 );
- } else {
- savegame.WriteInt( gameRenderWorld->NumAreas() );
- for( i = 0; i < gameRenderWorld->NumAreas(); i++ ) {
- savegame.WriteObject( locationEntities[ i ] );
- }
- }
- savegame.WriteObject( camera );
- savegame.WriteMaterial( globalMaterial );
- lastAIAlertEntity.Save( &savegame );
- savegame.WriteInt( lastAIAlertTime );
- savegame.WriteDict( &spawnArgs );
- savegame.WriteInt( playerPVS.i );
- savegame.WriteInt( playerPVS.h );
- savegame.WriteInt( playerConnectedAreas.i );
- savegame.WriteInt( playerConnectedAreas.h );
- savegame.WriteVec3( gravity );
- // gamestate
- savegame.WriteBool( influenceActive );
- savegame.WriteInt( nextGibTime );
- // spawnSpots
- // initialSpots
- // currentInitialSpot
- // newInfo
- // makingBuild
- // shakeSounds
- // write out pending events
- idEvent::Save( &savegame );
- savegame.Close();
- int endTimeMs = Sys_Milliseconds();
- idLib::Printf( "Save time: %dms\n", ( endTimeMs - startTimeMs ) );
- if ( g_recordSaveGameTrace.GetBool() ) {
- EndTraceRecording();
- g_recordSaveGameTrace.SetBool( false );
- }
- }
- /*
- ===========
- idGameLocal::GetSaveGameDetails
- ============
- */
- void idGameLocal::GetSaveGameDetails( idSaveGameDetails & gameDetails ) {
- idLocationEntity * locationEnt = LocationForPoint( gameLocal.GetLocalPlayer()->GetEyePosition() );
- const char * locationStr = locationEnt ? locationEnt->GetLocation() : idLocalization::GetString( "#str_02911" );
- idStrStatic< MAX_OSPATH > shortMapName = mapFileName;
- shortMapName.StripFileExtension();
- shortMapName.StripLeading( "maps/" );
- const idDeclEntityDef * mapDef = static_cast<const idDeclEntityDef *>(declManager->FindType( DECL_MAPDEF, shortMapName, false ));
- const char * mapPrettyName = mapDef ? idLocalization::GetString( mapDef->dict.GetString( "name", shortMapName ) ) : shortMapName.c_str();
- idPlayer * player = GetClientByNum( 0 );
- int playTime = player ? player->GetPlayedTime() : 0;
- gameExpansionType_t expansionType = player ? player->GetExpansionType() : GAME_BASE;
- gameDetails.descriptors.Clear();
- gameDetails.descriptors.SetInt( SAVEGAME_DETAIL_FIELD_EXPANSION, expansionType );
- gameDetails.descriptors.Set( SAVEGAME_DETAIL_FIELD_MAP, mapPrettyName );
- gameDetails.descriptors.Set( SAVEGAME_DETAIL_FIELD_MAP_LOCATE, locationStr );
- gameDetails.descriptors.SetInt( SAVEGAME_DETAIL_FIELD_SAVE_VERSION, BUILD_NUMBER );
- gameDetails.descriptors.SetInt( SAVEGAME_DETAIL_FIELD_DIFFICULTY, g_skill.GetInteger() );
- gameDetails.descriptors.SetInt( SAVEGAME_DETAIL_FIELD_PLAYTIME, playTime );
- // PS3 only strings that use the dict just set
- // even though we don't use this when we enumerate, when we save, we use this descriptors file later so we need the date populated now
- gameDetails.date = ::time( NULL );
- }
- /*
- ===========
- idGameLocal::GetPersistentPlayerInfo
- ============
- */
- const idDict &idGameLocal::GetPersistentPlayerInfo( int clientNum ) {
- idEntity *ent;
- persistentPlayerInfo[ clientNum ].Clear();
- ent = entities[ clientNum ];
- if ( ent && ent->IsType( idPlayer::Type ) ) {
- static_cast<idPlayer *>(ent)->SavePersistantInfo();
- }
- return persistentPlayerInfo[ clientNum ];
- }
- /*
- ===========
- idGameLocal::SetPersistentPlayerInfo
- ============
- */
- void idGameLocal::SetPersistentPlayerInfo( int clientNum, const idDict &playerInfo ) {
- persistentPlayerInfo[ clientNum ] = playerInfo;
- }
- /*
- ============
- idGameLocal::Printf
- ============
- */
- void idGameLocal::Printf( const char *fmt, ... ) const {
- va_list argptr;
- char text[MAX_STRING_CHARS];
- va_start( argptr, fmt );
- idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
- va_end( argptr );
- common->Printf( "%s", text );
- }
- /*
- ============
- idGameLocal::DPrintf
- ============
- */
- void idGameLocal::DPrintf( const char *fmt, ... ) const {
- va_list argptr;
- char text[MAX_STRING_CHARS];
- if ( !developer.GetBool() ) {
- return;
- }
- va_start( argptr, fmt );
- idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
- va_end( argptr );
- common->Printf( "%s", text );
- }
- /*
- ============
- idGameLocal::Warning
- ============
- */
- void idGameLocal::Warning( const char *fmt, ... ) const {
- va_list argptr;
- char text[MAX_STRING_CHARS];
- idThread * thread;
- va_start( argptr, fmt );
- idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
- va_end( argptr );
- thread = idThread::CurrentThread();
- if ( thread ) {
- thread->Warning( "%s", text );
- } else {
- common->Warning( "%s", text );
- }
- }
- /*
- ============
- idGameLocal::DWarning
- ============
- */
- void idGameLocal::DWarning( const char *fmt, ... ) const {
- va_list argptr;
- char text[MAX_STRING_CHARS];
- idThread * thread;
- if ( !developer.GetBool() ) {
- return;
- }
- va_start( argptr, fmt );
- idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
- va_end( argptr );
- thread = idThread::CurrentThread();
- if ( thread ) {
- thread->Warning( "%s", text );
- } else {
- common->DWarning( "%s", text );
- }
- }
- /*
- ============
- idGameLocal::Error
- ============
- */
- void idGameLocal::Error( const char *fmt, ... ) const {
- va_list argptr;
- char text[MAX_STRING_CHARS];
- idThread * thread;
- va_start( argptr, fmt );
- idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
- va_end( argptr );
- thread = idThread::CurrentThread();
- if ( thread ) {
- thread->Error( "%s", text );
- } else {
- common->Error( "%s", text );
- }
- }
- /*
- ===============
- gameError
- ===============
- */
- void gameError( const char *fmt, ... ) {
- va_list argptr;
- char text[MAX_STRING_CHARS];
- va_start( argptr, fmt );
- idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
- va_end( argptr );
- gameLocal.Error( "%s", text );
- }
- /*
- ========================
- idGameLocal::SetServerGameTimeMs
- ========================
- */
- void idGameLocal::SetServerGameTimeMs( const int time ) {
- previousServerTime = this->serverTime;
- this->serverTime = time;
- }
- /*
- ========================
- idGameLocal::GetServerGameTimeMs
- ========================
- */
- int idGameLocal::GetServerGameTimeMs() const {
- return serverTime;
- }
- /*
- ===========
- idGameLocal::SetServerInfo
- ============
- */
- void idGameLocal::SetServerInfo( const idDict &_serverInfo ) {
- serverInfo = _serverInfo;
- if ( gameType == GAME_LASTMAN ) {
- if ( serverInfo.GetInt( "si_fraglimit" ) <= 0 ) {
- common->Warning( "Last Man Standing - setting fraglimit 1" );
- serverInfo.SetInt( "si_fraglimit", 1 );
- }
- }
- }
- /*
- ===========
- idGameLocal::GetServerInfo
- ============
- */
- const idDict & idGameLocal::GetServerInfo() {
- return serverInfo;
- }
- /*
- ===================
- idGameLocal::LoadMap
- Initializes all map variables common to both save games and spawned games.
- ===================
- */
- void idGameLocal::LoadMap( const char * mapName, int randseed ) {
- bool sameMap = (mapFile && idStr::Icmp(mapFileName, mapName) == 0);
- // clear the sound system
- gameSoundWorld->ClearAllSoundEmitters();
- // clear envirosuit sound fx
- gameSoundWorld->SetEnviroSuit( false );
- gameSoundWorld->SetSlowmoSpeed( 1.0f );
- InitAsyncNetwork();
- if ( !sameMap || ( mapFile && mapFile->NeedsReload() ) ) {
- // load the .map file
- if ( mapFile ) {
- delete mapFile;
- }
- mapFile = new (TAG_GAME) idMapFile;
- if ( !mapFile->Parse( idStr( mapName ) + ".map" ) ) {
- delete mapFile;
- mapFile = NULL;
- Error( "Couldn't load %s", mapName );
- }
- }
- mapFileName = mapFile->GetName();
- // load the collision map
- collisionModelManager->LoadMap( mapFile );
- collisionModelManager->Preload( mapName );
- numClients = 0;
- // initialize all entities for this game
- memset( entities, 0, sizeof( entities ) );
- memset( spawnIds, -1, sizeof( spawnIds ) );
- spawnCount = INITIAL_SPAWN_COUNT;
-
- spawnedEntities.Clear();
- activeEntities.Clear();
- aimAssistEntities.Clear();
- numEntitiesToDeactivate = 0;
- sortTeamMasters = false;
- sortPushers = false;
- lastGUIEnt = NULL;
- lastGUI = 0;
- globalMaterial = NULL;
- memset( globalShaderParms, 0, sizeof( globalShaderParms ) );
- // These used to be a non-pot adjustment for portal skies
- // they're no longer needed, but we can't update the materials
- globalShaderParms[4] = 1.0f;
- globalShaderParms[5] = 1.0f;
- // always leave room for the max number of clients,
- // even if they aren't all used, so numbers inside that
- // range are NEVER anything but clients
- num_entities = MAX_CLIENTS;
- firstFreeEntityIndex[0] = MAX_CLIENTS;
- // reset the random number generator.
- random.SetSeed( common->IsMultiplayer() ? randseed : 0 );
- camera = NULL;
- world = NULL;
- testmodel = NULL;
- testFx = NULL;
- lastAIAlertEntity = NULL;
- lastAIAlertTime = 0;
-
- previousTime = 0;
- time = 0;
- framenum = 0;
- sessionCommand = "";
- nextGibTime = 0;
- portalSkyEnt = NULL;
- portalSkyActive = false;
- ResetSlowTimeVars();
- vacuumAreaNum = -1; // if an info_vacuum is spawned, it will set this
- if ( !editEntities ) {
- editEntities = new (TAG_GAME) idEditEntities;
- }
- gravity.Set( 0, 0, -g_gravity.GetFloat() );
- spawnArgs.Clear();
- inCinematic = false;
- clip.Init();
- common->UpdateLevelLoadPacifier();
- pvs.Init();
- common->UpdateLevelLoadPacifier();
- playerPVS.i = -1;
- playerConnectedAreas.i = -1;
- // load navigation system for all the different monster sizes
- for ( int i = 0; i < aasNames.Num(); i++ ) {
- aasList[ i ]->Init( idStr( mapFileName ).SetFileExtension( aasNames[ i ] ).c_str(), mapFile->GetGeometryCRC() );
- }
- // clear the smoke particle free list
- smokeParticles->Init();
- common->UpdateLevelLoadPacifier();
- // cache miscellaneous media references
- FindEntityDef( "preCacheExtras", false );
- FindEntityDef( "ammo_types", false );
- FindEntityDef( "ammo_names", false );
- FindEntityDef( "ammo_types_d3xp", false );
- FindEntityDef( "damage_noair", false );
- FindEntityDef( "damage_moverCrush", false );
- FindEntityDef( "damage_crush", false );
- FindEntityDef( "damage_triggerhurt_1000", false );
- FindEntityDef( "damage_telefrag", false );
- FindEntityDef( "damage_suicide", false );
- FindEntityDef( "damage_explosion", false );
- FindEntityDef( "damage_generic", false );
- FindEntityDef( "damage_painTrigger", false );
- FindEntityDef( "damage_thrown_ragdoll", false );
- FindEntityDef( "damage_gib", false );
- FindEntityDef( "damage_softfall", false );
- FindEntityDef( "damage_hardfall", false );
- FindEntityDef( "damage_fatalfall", false );
- FindEntityDef( "envirosuit_light", false );
- declManager->FindType( DECL_EMAIL, "highScore", false );
- declManager->FindType( DECL_EMAIL, "MartianBuddyGameComplete", false );
- declManager->FindMaterial( "itemHighlightShell" );
- common->UpdateLevelLoadPacifier();
- if ( !sameMap ) {
- mapFile->RemovePrimitiveData();
- }
- }
- /*
- ===================
- idGameLocal::LocalMapRestart
- ===================
- */
- void idGameLocal::LocalMapRestart( ) {
- int i, latchSpawnCount;
- Printf( "----------- Game Map Restart ------------\n" );
- gamestate = GAMESTATE_SHUTDOWN;
- for ( i = 0; i < MAX_CLIENTS; i++ ) {
- if ( entities[ i ] && entities[ i ]->IsType( idPlayer::Type ) ) {
- static_cast< idPlayer * >( entities[ i ] )->PrepareForRestart();
- }
- }
- eventQueue.Shutdown();
- savedEventQueue.Shutdown();
- MapClear( false );
- // clear the smoke particle free list
- smokeParticles->Init();
- // clear the sound system
- if ( gameSoundWorld ) {
- gameSoundWorld->ClearAllSoundEmitters();
- // clear envirosuit sound fx
- gameSoundWorld->SetEnviroSuit( false );
- gameSoundWorld->SetSlowmoSpeed( 1.0f );
- }
- // the spawnCount is reset to zero temporarily to spawn the map entities with the same spawnId
- // if we don't do that, network clients are confused and don't show any map entities
- latchSpawnCount = spawnCount;
- spawnCount = INITIAL_SPAWN_COUNT;
- gamestate = GAMESTATE_STARTUP;
- program.Restart();
- InitScriptForMap();
- MapPopulate();
- // once the map is populated, set the spawnCount back to where it was so we don't risk any collision
- // (note that if there are no players in the game, we could just leave it at it's current value)
- spawnCount = latchSpawnCount;
- // setup the client entities again
- for ( i = 0; i < MAX_CLIENTS; i++ ) {
- if ( entities[ i ] && entities[ i ]->IsType( idPlayer::Type ) ) {
- static_cast< idPlayer * >( entities[ i ] )->Restart();
- }
- }
-
- gamestate = GAMESTATE_ACTIVE;
- Printf( "--------------------------------------\n" );
- }
- /*
- ===================
- idGameLocal::MapRestart
- ===================
- */
- void idGameLocal::MapRestart() {
- if ( common->IsClient() ) {
- LocalMapRestart();
- } else {
- idBitMsg msg;
- session->GetActingGameStateLobbyBase().SendReliable( GAME_RELIABLE_MESSAGE_RESTART, msg, false );
- LocalMapRestart();
- mpGame.MapRestart();
- }
- if ( common->IsMultiplayer() ) {
- gameLocal.mpGame.ReloadScoreboard();
- }
- }
- /*
- ===================
- idGameLocal::MapRestart_f
- ===================
- */
- void idGameLocal::MapRestart_f( const idCmdArgs &args ) {
- if ( !common->IsMultiplayer() || common->IsClient() ) {
- common->Printf( "server is not running - use spawnServer\n" );
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "spawnServer\n" );
- return;
- }
- gameLocal.MapRestart( );
- }
- /*
- ===================
- idGameLocal::MapPopulate
- ===================
- */
- void idGameLocal::MapPopulate() {
- if ( common->IsMultiplayer() ) {
- cvarSystem->SetCVarBool( "r_skipSpecular", false );
- }
- // parse the key/value pairs and spawn entities
- SpawnMapEntities();
- // mark location entities in all connected areas
- SpreadLocations();
- // prepare the list of randomized initial spawn spots
- RandomizeInitialSpawns();
- // spawnCount - 1 is the number of entities spawned into the map, their indexes started at MAX_CLIENTS (included)
- // mapSpawnCount is used as the max index of map entities, it's the first index of non-map entities
- mapSpawnCount = MAX_CLIENTS + spawnCount - 1;
- // execute pending events before the very first game frame
- // this makes sure the map script main() function is called
- // before the physics are run so entities can bind correctly
- Printf( "==== Processing events ====\n" );
- idEvent::ServiceEvents();
- // Must set GAME_FPS for script after populating, because some maps run their own scripts
- // when spawning the world, and GAME_FPS will not be found before then.
- SetScriptFPS( com_engineHz_latched );
- }
- /*
- ===================
- idGameLocal::InitFromNewMap
- ===================
- */
- void idGameLocal::InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, int gameMode, int randseed ) {
- this->gameType = (gameType_t)idMath::ClampInt( GAME_SP, GAME_COUNT-1, gameMode );
- if ( mapFileName.Length() ) {
- MapShutdown();
- }
- Printf( "----------- Game Map Init ------------\n" );
- gamestate = GAMESTATE_STARTUP;
- gameRenderWorld = renderWorld;
- gameSoundWorld = soundWorld;
- if ( common->IsMultiplayer() ) {
- g_skill.SetInteger( 1 );
- } else {
- g_skill.SetInteger( idMath::ClampInt( 0, 3, g_skill.GetInteger() ) );
- }
- LoadMap( mapName, randseed );
- InitScriptForMap();
- MapPopulate();
- mpGame.Reset();
- mpGame.Precache();
- SyncPlayersWithLobbyUsers( true );
- // free up any unused animations
- animationLib.FlushUnusedAnims();
- gamestate = GAMESTATE_ACTIVE;
- Printf( "--------------------------------------\n" );
- }
- /*
- =================
- idGameLocal::InitFromSaveGame
- =================
- */
- bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile * saveGameFile, idFile * stringTableFile, int saveGameVersion ) {
- int i;
- int num;
- idEntity *ent;
- idDict si;
- if ( mapFileName.Length() ) {
- MapShutdown();
- }
- Printf( "------- Game Map Init SaveGame -------\n" );
- gamestate = GAMESTATE_STARTUP;
- gameRenderWorld = renderWorld;
- gameSoundWorld = soundWorld;
- SetScriptFPS( com_engineHz_latched );
- // load the map needed for this savegame
- LoadMap( mapName, 0 );
- idFile_SaveGamePipelined * pipelineFile = new (TAG_SAVEGAMES) idFile_SaveGamePipelined();
- pipelineFile->OpenForReading( saveGameFile );
- idRestoreGame savegame( pipelineFile, stringTableFile, saveGameVersion );
- // Create the list of all objects in the game
- savegame.CreateObjects();
- // Load the idProgram, also checking to make sure scripting hasn't changed since the savegame
- if ( program.Restore( &savegame ) == false ) {
- // Abort the load process, and let the session know so that it can restart the level
- // with the player persistent data.
- savegame.DeleteObjects();
- program.Restart();
- return false;
- }
- savegame.ReadInt( i );
- g_skill.SetInteger( i );
- // precache any media specified in the map
- savegame.ReadDecls();
- savegame.ReadDict( &si );
- SetServerInfo( si );
- savegame.ReadInt( numClients );
- for( i = 0; i < numClients; i++ ) {
- //savegame.ReadUsercmd( usercmds[ i ] );
- // Now that usercmds are handled by the idUserCmdMgr,
- // do we need another solution here?
- usercmd_t dummy;
- savegame.ReadUsercmd( dummy );
- savegame.ReadDict( &persistentPlayerInfo[ i ] );
- }
- for( i = 0; i < MAX_GENTITIES; i++ ) {
- savegame.ReadObject( reinterpret_cast<idClass *&>( entities[ i ] ) );
- savegame.ReadInt( spawnIds[ i ] );
- // restore the entityNumber
- if ( entities[ i ] != NULL ) {
- entities[ i ]->entityNumber = i;
- }
- }
- // Connect players with lobby users
- // There should only be 1 player and 1 lobby user, but I'm using a loop just to be safe
- idLobbyBase & lobby = session->GetActingGameStateLobbyBase();
- int numLobbyUsers = lobby.GetNumLobbyUsers();
- int lobbyUserNum = 0;
- assert( numLobbyUsers == 1 );
- for ( int i = 0; i < MAX_PLAYERS && lobbyUserNum < numLobbyUsers; i++ ) {
- if ( entities[i] == NULL ) {
- continue;
- }
- lobbyUserIDs[i] = lobby.GetLobbyUserIdByOrdinal( lobbyUserNum++ );
- }
- savegame.ReadInt( firstFreeEntityIndex[0] );
- savegame.ReadInt( num_entities );
- // enityHash is restored by idEntity::Restore setting the entity name.
- savegame.ReadObject( reinterpret_cast<idClass *&>( world ) );
- savegame.ReadInt( num );
- for( i = 0; i < num; i++ ) {
- savegame.ReadObject( reinterpret_cast<idClass *&>( ent ) );
- assert( ent );
- if ( ent ) {
- ent->spawnNode.AddToEnd( spawnedEntities );
- }
- }
- savegame.ReadInt( num );
- for( i = 0; i < num; i++ ) {
- savegame.ReadObject( reinterpret_cast<idClass *&>( ent ) );
- assert( ent );
- if ( ent ) {
- ent->activeNode.AddToEnd( activeEntities );
- }
- }
- savegame.ReadInt( numEntitiesToDeactivate );
- savegame.ReadBool( sortPushers );
- savegame.ReadBool( sortTeamMasters );
- savegame.ReadDict( &persistentLevelInfo );
- for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
- savegame.ReadFloat( globalShaderParms[ i ] );
- }
- savegame.ReadInt( i );
- random.SetSeed( i );
- savegame.ReadObject( reinterpret_cast<idClass *&>( frameCommandThread ) );
- // clip
- // push
- // pvs
- // testmodel = "<NULL>"
- // testFx = "<NULL>"
- savegame.ReadString( sessionCommand );
- // FIXME: save smoke particles
- savegame.ReadBool( inCinematic );
- savegame.ReadInt( (int &)gameType );
- savegame.ReadInt( framenum );
- savegame.ReadInt( previousTime );
- savegame.ReadInt( time );
- savegame.ReadInt( vacuumAreaNum );
- savegame.ReadInt( entityDefBits );
- // the localClientNum member of idGameLocal was removed,
- // but to preserve savegame compatibility, we still need
- // to read an int here even though it's not used.
- int dummyLocalClientNum = 0;
- savegame.ReadInt( dummyLocalClientNum );
- // snapshotEntities is used for multiplayer only
- savegame.ReadInt( realClientTime );
- savegame.ReadBool( isNewFrame );
- savegame.ReadFloat( clientSmoothing );
- portalSkyEnt.Restore( &savegame );
- savegame.ReadBool( portalSkyActive );
- fast.Restore( &savegame );
- slow.Restore( &savegame );
- framenum = MSEC_TO_FRAME_FLOOR( fast.time );
- int blah;
- savegame.ReadInt( blah );
- slowmoState = (slowmoState_t)blah;
- savegame.ReadFloat( slowmoScale );
- savegame.ReadBool( quickSlowmoReset );
- if ( gameSoundWorld ) {
- gameSoundWorld->SetSlowmoSpeed( slowmoScale );
- }
- savegame.ReadBool( mapCycleLoaded );
- savegame.ReadInt( spawnCount );
- savegame.ReadInt( num );
- if ( num ) {
- if ( num != gameRenderWorld->NumAreas() ) {
- savegame.Error( "idGameLocal::InitFromSaveGame: number of areas in map differs from save game." );
- }
- locationEntities = new (TAG_GAME) idLocationEntity *[ num ];
- for( i = 0; i < num; i++ ) {
- savegame.ReadObject( reinterpret_cast<idClass *&>( locationEntities[ i ] ) );
- }
- }
- savegame.ReadObject( reinterpret_cast<idClass *&>( camera ) );
- savegame.ReadMaterial( globalMaterial );
- lastAIAlertEntity.Restore( &savegame );
- savegame.ReadInt( lastAIAlertTime );
- savegame.ReadDict( &spawnArgs );
- savegame.ReadInt( playerPVS.i );
- savegame.ReadInt( (int &)playerPVS.h );
- savegame.ReadInt( playerConnectedAreas.i );
- savegame.ReadInt( (int &)playerConnectedAreas.h );
- savegame.ReadVec3( gravity );
- // gamestate is restored after restoring everything else
- savegame.ReadBool( influenceActive );
- savegame.ReadInt( nextGibTime );
- // spawnSpots
- // initialSpots
- // currentInitialSpot
- // newInfo
- // makingBuild
- // shakeSounds
- // Read out pending events
- idEvent::Restore( &savegame );
- savegame.RestoreObjects();
- mpGame.Reset();
- mpGame.Precache();
- // free up any unused animations
- animationLib.FlushUnusedAnims();
- gamestate = GAMESTATE_ACTIVE;
- Printf( "--------------------------------------\n" );
- delete pipelineFile;
- pipelineFile = NULL;
- return true;
- }
- /*
- ===========
- idGameLocal::MapClear
- ===========
- */
- void idGameLocal::MapClear( bool clearClients ) {
- int i;
- for( i = ( clearClients ? 0 : MAX_CLIENTS ); i < MAX_GENTITIES; i++ ) {
- delete entities[ i ];
- // ~idEntity is in charge of setting the pointer to NULL
- // it will also clear pending events for this entity
- assert( !entities[ i ] );
- spawnIds[ i ] = -1;
- }
- entityHash.Clear( 1024, MAX_GENTITIES );
- if ( !clearClients ) {
- // add back the hashes of the clients
- for ( i = 0; i < MAX_CLIENTS; i++ ) {
- if ( !entities[ i ] ) {
- continue;
- }
- entityHash.Add( entityHash.GenerateKey( entities[ i ]->name.c_str(), true ), i );
- }
- }
- delete frameCommandThread;
- frameCommandThread = NULL;
- if ( editEntities ) {
- delete editEntities;
- editEntities = NULL;
- }
- delete[] locationEntities;
- locationEntities = NULL;
- }
- /*
- ===========
- idGameLocal::MapShutdown
- ============
- */
- void idGameLocal::MapShutdown() {
- Printf( "--------- Game Map Shutdown ----------\n" );
-
- gamestate = GAMESTATE_SHUTDOWN;
- if ( gameRenderWorld ) {
- // clear any debug lines, text, and polygons
- gameRenderWorld->DebugClearLines( 0 );
- gameRenderWorld->DebugClearPolygons( 0 );
- }
- // clear out camera if we're in a cinematic
- if ( inCinematic ) {
- camera = NULL;
- inCinematic = false;
- }
- MapClear( true );
- common->UpdateLevelLoadPacifier();
- // reset the script to the state it was before the map was started
- program.Restart();
- if ( smokeParticles ) {
- smokeParticles->Shutdown();
- }
- pvs.Shutdown();
- common->UpdateLevelLoadPacifier();
- clip.Shutdown();
- idClipModel::ClearTraceModelCache();
- common->UpdateLevelLoadPacifier();
- collisionModelManager->FreeMap(); // Fixes an issue where when maps were reloaded the materials wouldn't get their surfaceFlags re-set. Now we free the map collision model forcing materials to be reparsed.
- common->UpdateLevelLoadPacifier();
- ShutdownAsyncNetwork();
- idStrStatic< MAX_OSPATH > mapName = mapFileName;
- mapName.StripPath();
- mapName.StripFileExtension();
- fileSystem->UnloadMapResources( mapName );
- mapFileName.Clear();
- gameRenderWorld = NULL;
- gameSoundWorld = NULL;
- gamestate = GAMESTATE_NOMAP;
- Printf( "--------------------------------------\n" );
- }
- /*
- ========================
- idGameLocal::GetAimAssistAngles
- ========================
- */
- void idGameLocal::GetAimAssistAngles( idAngles & angles ) {
- angles.Zero();
- // Take a look at serializing this to the clients
- idPlayer * player = GetLocalPlayer();
- if ( player == NULL ) {
- return;
- }
- idAimAssist * aimAssist = player->GetAimAssist();
- if ( aimAssist == NULL ) {
- return;
- }
- aimAssist->GetAngleCorrection( angles );
- }
- /*
- ========================
- idGameLocal::GetAimAssistSensitivity
- ========================
- */
- float idGameLocal::GetAimAssistSensitivity() {
- // Take a look at serializing this to the clients
- idPlayer * player = GetLocalPlayer();
- if ( player == NULL ) {
- return 1.0f;
- }
- idAimAssist * aimAssist = player->GetAimAssist();
- if ( aimAssist == NULL ) {
- return 1.0f;
- }
- return aimAssist->GetFrictionScalar();
- }
- /*
- ========================
- idGameLocal::MapPeerToClient
- ========================
- */
- int idGameLocal::MapPeerToClient( int peer ) const {
- idLobbyBase & lobby = session->GetActingGameStateLobbyBase();
- for ( int userNum = 0; userNum < lobbyUserIDs.Num(); ++userNum ) {
- const int peerForUser = lobby.PeerIndexFromLobbyUser( lobbyUserIDs[userNum] );
- if ( peerForUser == peer ) {
- return userNum;
- }
- }
- return -1;
- }
- /*
- ========================
- idGameLocal::GetLocalClientNum
- ========================
- */
- int idGameLocal::GetLocalClientNum() const {
- localUserHandle_t localUserHandle = session->GetSignInManager().GetMasterLocalUserHandle();
- if ( !localUserHandle.IsValid() ) {
- return 0;
- }
-
- for ( int i = 0; i < lobbyUserIDs.Num(); i++ ) {
- lobbyUserID_t lobbyUserID = lobbyUserIDs[i];
- if ( localUserHandle == lobbyUserID.GetLocalUserHandle() ) {
- return i;
- }
- }
- return 0;
- }
- /*
- ===================
- idGameLocal::Preload
- ===================
- */
- void idGameLocal::Preload( const idPreloadManifest &manifest ) {
- animationLib.Preload( manifest );
- }
- /*
- ===================
- idGameLocal::CacheDictionaryMedia
- This is called after parsing an EntityDef and for each entity spawnArgs before
- merging the entitydef. It could be done post-merge, but that would
- avoid the fast pre-cache check associated with each entityDef
- ===================
- */
- void idGameLocal::CacheDictionaryMedia( const idDict *dict ) {
- const idKeyValue *kv;
- kv = dict->MatchPrefix( "model" );
- while( kv ) {
- if ( kv->GetValue().Length() ) {
- declManager->MediaPrint( "Precaching model %s\n", kv->GetValue().c_str() );
- // precache model/animations
- if ( declManager->FindType( DECL_MODELDEF, kv->GetValue(), false ) == NULL ) {
- // precache the render model
- renderModelManager->FindModel( kv->GetValue() );
- // precache .cm files only
- collisionModelManager->LoadModel( kv->GetValue() );
- }
- }
- kv = dict->MatchPrefix( "model", kv );
- }
- kv = dict->FindKey( "s_shader" );
- if ( kv != NULL && kv->GetValue().Length() ) {
- declManager->FindType( DECL_SOUND, kv->GetValue() );
- }
- kv = dict->MatchPrefix( "snd", NULL );
- while ( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- declManager->FindType( DECL_SOUND, kv->GetValue() );
- }
- kv = dict->MatchPrefix( "snd", kv );
- }
- kv = dict->MatchPrefix( "gui", NULL );
- while( kv ) {
- if ( kv->GetValue().Length() ) {
- if ( !idStr::Icmp( kv->GetKey(), "gui_noninteractive" )
- || !idStr::Icmpn( kv->GetKey(), "gui_parm", 8 )
- || !idStr::Icmp( kv->GetKey(), "gui_inventory" ) ) {
- // unfortunate flag names, they aren't actually a gui
- } else {
- declManager->MediaPrint( "Precaching gui %s\n", kv->GetValue().c_str() );
- idUserInterface *gui = uiManager->Alloc();
- if ( gui ) {
- gui->InitFromFile( kv->GetValue() );
- uiManager->DeAlloc( gui );
- }
- }
- }
- kv = dict->MatchPrefix( "gui", kv );
- }
- kv = dict->FindKey( "texture" );
- if ( kv != NULL && kv->GetValue().Length() ) {
- declManager->FindType( DECL_MATERIAL, kv->GetValue() );
- }
- kv = dict->MatchPrefix( "mtr", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- declManager->FindType( DECL_MATERIAL, kv->GetValue() );
- }
- kv = dict->MatchPrefix( "mtr", kv );
- }
- // handles hud icons
- kv = dict->MatchPrefix( "inv_icon", NULL );
- while ( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- declManager->FindType( DECL_MATERIAL, kv->GetValue() );
- }
- kv = dict->MatchPrefix( "inv_icon", kv );
- }
- // handles teleport fx.. this is not ideal but the actual decision on which fx to use
- // is handled by script code based on the teleport number
- kv = dict->MatchPrefix( "teleport", NULL );
- if ( kv != NULL && kv->GetValue().Length() ) {
- int teleportType = atoi( kv->GetValue() );
- const char *p = ( teleportType ) ? va( "fx/teleporter%i.fx", teleportType ) : "fx/teleporter.fx";
- declManager->FindType( DECL_FX, p );
- }
- kv = dict->MatchPrefix( "fx", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- declManager->MediaPrint( "Precaching fx %s\n", kv->GetValue().c_str() );
- declManager->FindType( DECL_FX, kv->GetValue() );
- }
- kv = dict->MatchPrefix( "fx", kv );
- }
- kv = dict->MatchPrefix( "smoke", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- idStr prtName = kv->GetValue();
- int dash = prtName.Find('-');
- if ( dash > 0 ) {
- prtName = prtName.Left( dash );
- }
- declManager->FindType( DECL_PARTICLE, prtName );
- }
- kv = dict->MatchPrefix( "smoke", kv );
- }
- kv = dict->MatchPrefix( "skin", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- declManager->MediaPrint( "Precaching skin %s\n", kv->GetValue().c_str() );
- declManager->FindType( DECL_SKIN, kv->GetValue() );
- }
- kv = dict->MatchPrefix( "skin", kv );
- }
- kv = dict->MatchPrefix( "def", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- FindEntityDef( kv->GetValue().c_str(), false );
- }
- kv = dict->MatchPrefix( "def", kv );
- }
- // Precache all available grabber "catch" damage decls
- kv = dict->MatchPrefix( "def_damage", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- FindEntityDef( kv->GetValue() + "_catch", false );
- }
- kv = dict->MatchPrefix( "def_damage", kv );
- }
- // Should have been def_monster_damage!!
- kv = dict->FindKey( "monster_damage" );
- if ( kv != NULL && kv->GetValue().Length() ) {
- FindEntityDef( kv->GetValue(), false );
- }
-
- kv = dict->MatchPrefix( "item", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- FindEntityDefDict( kv->GetValue().c_str(), false );
- }
- kv = dict->MatchPrefix( "item", kv );
- }
- kv = dict->MatchPrefix( "pda_name", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- declManager->FindType( DECL_PDA, kv->GetValue().c_str(), false );
- }
- kv = dict->MatchPrefix( "pda_name", kv );
- }
- kv = dict->MatchPrefix( "video", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- declManager->FindType( DECL_VIDEO, kv->GetValue().c_str(), false );
- }
- kv = dict->MatchPrefix( "video", kv );
- }
- kv = dict->MatchPrefix( "audio", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- declManager->FindType( DECL_AUDIO, kv->GetValue().c_str(), false );
- }
- kv = dict->MatchPrefix( "audio", kv );
- }
- kv = dict->MatchPrefix( "email", NULL );
- while( kv != NULL ) {
- if ( kv->GetValue().Length() ) {
- declManager->FindType( DECL_EMAIL, kv->GetValue().c_str(), false );
- }
- kv = dict->MatchPrefix( "email", kv );
- }
- }
- /*
- ===========
- idGameLocal::InitScriptForMap
- ============
- */
- void idGameLocal::InitScriptForMap() {
- // create a thread to run frame commands on
- frameCommandThread = new idThread();
- frameCommandThread->ManualDelete();
- frameCommandThread->SetThreadName( "frameCommands" );
- // run the main game script function (not the level specific main)
- const function_t *func = program.FindFunction( SCRIPT_DEFAULTFUNC );
- if ( func != NULL ) {
- idThread *thread = new idThread( func );
- if ( thread->Start() ) {
- // thread has finished executing, so delete it
- delete thread;
- }
- }
- }
- /*
- ===================
- idGameLocal::SetScriptFPS
- ===================
- */
- void idGameLocal::SetScriptFPS( const float engineHz ) {
- idVarDef * fpsDef = program.GetDef( &type_float, "GAME_FPS", &def_namespace );
- if ( fpsDef != NULL ) {
- eval_t fpsValue;
- fpsValue._float = engineHz;
- fpsDef->SetValue( fpsValue, false );
- }
- }
- /*
- ===========
- idGameLocal::GetMPPlayerDefName
- ============
- */
- const char * idGameLocal::GetMPPlayerDefName() const {
- if ( gameType == GAME_CTF ) {
- return "player_doommarine_ctf";
- }
- return "player_doommarine_mp";
- }
- /*
- ===========
- idGameLocal::SpawnPlayer
- ============
- */
- void idGameLocal::SpawnPlayer( int clientNum ) {
- idEntity *ent;
- idDict args;
- // they can connect
- Printf( "SpawnPlayer: %i\n", clientNum );
- args.SetInt( "spawn_entnum", clientNum );
- args.Set( "name", va( "player%d", clientNum + 1 ) );
- if ( common->IsMultiplayer() ) {
- args.Set( "classname", GetMPPlayerDefName() );
- } else {
- // precache the player
- args.Set( "classname", gameLocal.world->spawnArgs.GetString( "def_player", "player_doommarine" ) );
- }
- // It's important that we increment numClients before calling SpawnEntityDef, because some
- // entities want to check gameLocal.numClients to see who to operate on (such as target_removeweapons)
- if ( clientNum >= numClients ) {
- numClients = clientNum + 1;
- }
- if ( !SpawnEntityDef( args, &ent ) || clientNum >= MAX_GENTITIES || entities[ clientNum ] == NULL ) {
- Error( "Failed to spawn player as '%s'", args.GetString( "classname" ) );
- }
- // make sure it's a compatible class
- if ( !ent->IsType( idPlayer::Type ) ) {
- Error( "'%s' spawned the player as a '%s'. Player spawnclass must be a subclass of idPlayer.", args.GetString( "classname" ), ent->GetClassname() );
- }
- mpGame.SpawnPlayer( clientNum );
- }
- /*
- ================
- idGameLocal::GetClientByNum
- ================
- */
- idPlayer *idGameLocal::GetClientByNum( int current ) const {
- if ( current < 0 || current >= numClients ) {
- current = 0;
- }
- if ( entities[current] ) {
- return static_cast<idPlayer *>( entities[ current ] );
- }
- return NULL;
- }
- /*
- ================
- idGameLocal::GetNextClientNum
- ================
- */
- int idGameLocal::GetNextClientNum( int _current ) const {
- int i, current;
- current = 0;
- for ( i = 0; i < numClients; i++) {
- current = ( _current + i + 1 ) % numClients;
- if ( entities[ current ] && entities[ current ]->IsType( idPlayer::Type ) ) {
- return current;
- }
- }
- return current;
- }
- /*
- ================
- idGameLocal::GetLocalPlayer
- Nothing in the game tic should EVER make a decision based on what the
- local client number is, it shouldn't even be aware that there is a
- draw phase even happening. This just returns client 0, which will
- be correct for single player.
- ================
- */
- idPlayer *idGameLocal::GetLocalPlayer() const {
- if ( GetLocalClientNum() < 0 ) {
- return NULL;
- }
- if ( !entities[ GetLocalClientNum() ] || !entities[ GetLocalClientNum() ]->IsType( idPlayer::Type ) ) {
- // not fully in game yet
- return NULL;
- }
- return static_cast<idPlayer *>( entities[ GetLocalClientNum() ] );
- }
- /*
- ================
- idGameLocal::SetupClientPVS
- ================
- */
- pvsHandle_t idGameLocal::GetClientPVS( idPlayer *player, pvsType_t type ) {
- if ( player->GetPrivateCameraView() ) {
- return pvs.SetupCurrentPVS( player->GetPrivateCameraView()->GetPVSAreas(), player->GetPrivateCameraView()->GetNumPVSAreas() );
- } else if ( camera ) {
- return pvs.SetupCurrentPVS( camera->GetPVSAreas(), camera->GetNumPVSAreas() );
- } else {
- return pvs.SetupCurrentPVS( player->GetPVSAreas(), player->GetNumPVSAreas() );
- }
- }
- /*
- ================
- idGameLocal::SetupPlayerPVS
- ================
- */
- void idGameLocal::SetupPlayerPVS() {
- int i;
- idEntity * ent;
- idPlayer * player;
- pvsHandle_t otherPVS, newPVS;
- playerPVS.i = -1;
- for ( i = 0; i < numClients; i++ ) {
- ent = entities[i];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- player = static_cast<idPlayer *>(ent);
- if ( playerPVS.i == -1 ) {
- playerPVS = GetClientPVS( player, PVS_NORMAL );
- } else {
- otherPVS = GetClientPVS( player, PVS_NORMAL );
- newPVS = pvs.MergeCurrentPVS( playerPVS, otherPVS );
- pvs.FreeCurrentPVS( playerPVS );
- pvs.FreeCurrentPVS( otherPVS );
- playerPVS = newPVS;
- }
- if ( playerConnectedAreas.i == -1 ) {
- playerConnectedAreas = GetClientPVS( player, PVS_CONNECTED_AREAS );
- } else {
- otherPVS = GetClientPVS( player, PVS_CONNECTED_AREAS );
- newPVS = pvs.MergeCurrentPVS( playerConnectedAreas, otherPVS );
- pvs.FreeCurrentPVS( playerConnectedAreas );
- pvs.FreeCurrentPVS( otherPVS );
- playerConnectedAreas = newPVS;
- }
- // if portalSky is preset, then merge into pvs so we get rotating brushes, etc
- if ( portalSkyEnt.GetEntity() ) {
- idEntity *skyEnt = portalSkyEnt.GetEntity();
- otherPVS = pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() );
- newPVS = pvs.MergeCurrentPVS( playerPVS, otherPVS );
- pvs.FreeCurrentPVS( playerPVS );
- pvs.FreeCurrentPVS( otherPVS );
- playerPVS = newPVS;
- otherPVS = pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() );
- newPVS = pvs.MergeCurrentPVS( playerConnectedAreas, otherPVS );
- pvs.FreeCurrentPVS( playerConnectedAreas );
- pvs.FreeCurrentPVS( otherPVS );
- playerConnectedAreas = newPVS;
- }
- }
- }
- /*
- ================
- idGameLocal::FreePlayerPVS
- ================
- */
- void idGameLocal::FreePlayerPVS() {
- if ( playerPVS.i != -1 ) {
- pvs.FreeCurrentPVS( playerPVS );
- playerPVS.i = -1;
- }
- if ( playerConnectedAreas.i != -1 ) {
- pvs.FreeCurrentPVS( playerConnectedAreas );
- playerConnectedAreas.i = -1;
- }
- }
- /*
- ================
- idGameLocal::InPlayerPVS
- should only be called during entity thinking and event handling
- ================
- */
- bool idGameLocal::InPlayerPVS( idEntity *ent ) const {
- if ( playerPVS.i == -1 ) {
- return false;
- }
- return pvs.InCurrentPVS( playerPVS, ent->GetPVSAreas(), ent->GetNumPVSAreas() );
- }
- /*
- ================
- idGameLocal::InPlayerConnectedArea
- should only be called during entity thinking and event handling
- ================
- */
- bool idGameLocal::InPlayerConnectedArea( idEntity *ent ) const {
- if ( playerConnectedAreas.i == -1 ) {
- return false;
- }
- return pvs.InCurrentPVS( playerConnectedAreas, ent->GetPVSAreas(), ent->GetNumPVSAreas() );
- }
- /*
- ================
- idGameLocal::UpdateGravity
- ================
- */
- void idGameLocal::UpdateGravity() {
- idEntity *ent;
- if ( g_gravity.IsModified() ) {
- if ( g_gravity.GetFloat() == 0.0f ) {
- g_gravity.SetFloat( 1.0f );
- }
- gravity.Set( 0, 0, -g_gravity.GetFloat() );
- // update all physics objects
- for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
- if ( ent->IsType( idAFEntity_Generic::Type ) ) {
- idPhysics *phys = ent->GetPhysics();
- if ( phys ) {
- phys->SetGravity( gravity );
- }
- }
- }
- g_gravity.ClearModified();
- }
- }
- /*
- ================
- idGameLocal::GetGravity
- ================
- */
- const idVec3 &idGameLocal::GetGravity() const {
- return gravity;
- }
- /*
- ================
- idGameLocal::SortActiveEntityList
- Sorts the active entity list such that pushing entities come first,
- actors come next and physics team slaves appear after their master.
- ================
- */
- void idGameLocal::SortActiveEntityList() {
- idEntity *ent, *next_ent, *master, *part;
- // if the active entity list needs to be reordered to place physics team masters at the front
- if ( sortTeamMasters ) {
- for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
- next_ent = ent->activeNode.Next();
- master = ent->GetTeamMaster();
- if ( master && master == ent ) {
- ent->activeNode.Remove();
- ent->activeNode.AddToFront( activeEntities );
- }
- }
- }
- // if the active entity list needs to be reordered to place pushers at the front
- if ( sortPushers ) {
- for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
- next_ent = ent->activeNode.Next();
- master = ent->GetTeamMaster();
- if ( !master || master == ent ) {
- // check if there is an actor on the team
- for ( part = ent; part != NULL; part = part->GetNextTeamEntity() ) {
- if ( part->GetPhysics()->IsType( idPhysics_Actor::Type ) ) {
- break;
- }
- }
- // if there is an actor on the team
- if ( part ) {
- ent->activeNode.Remove();
- ent->activeNode.AddToFront( activeEntities );
- }
- }
- }
- for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
- next_ent = ent->activeNode.Next();
- master = ent->GetTeamMaster();
- if ( !master || master == ent ) {
- // check if there is an entity on the team using parametric physics
- for ( part = ent; part != NULL; part = part->GetNextTeamEntity() ) {
- if ( part->GetPhysics()->IsType( idPhysics_Parametric::Type ) ) {
- break;
- }
- }
- // if there is an entity on the team using parametric physics
- if ( part ) {
- ent->activeNode.Remove();
- ent->activeNode.AddToFront( activeEntities );
- }
- }
- }
- }
- sortTeamMasters = false;
- sortPushers = false;
- }
- /*
- ========================
- idGameLocal::SetInterpolation
- ========================
- */
- void idGameLocal::SetInterpolation( const float fraction, const int serverGameMS, const int ssStartTime, const int ssEndTime ) {
- netInterpolationInfo.previousServerGameMs = netInterpolationInfo.serverGameMs;
- netInterpolationInfo.pct = fraction;
- netInterpolationInfo.serverGameMs = serverGameMS;
- netInterpolationInfo.ssStartTime = ssStartTime;
- netInterpolationInfo.ssEndTime = ssEndTime;
- }
- /*
- ================
- idGameLocal::RunTimeGroup2
- ================
- */
- void idGameLocal::RunTimeGroup2( idUserCmdMgr & userCmdMgr ) {
- idEntity *ent;
- int num = 0;
- SelectTimeGroup( true );
- for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
- if ( ent->timeGroup != TIME_GROUP2 ) {
- continue;
- }
- RunEntityThink( *ent, userCmdMgr );
- num++;
- }
- SelectTimeGroup( false );
- }
- /*
- ================
- idGameLocal::RunEntityThink
- ================
- */
- void idGameLocal::RunEntityThink( idEntity & ent, idUserCmdMgr & userCmdMgr ) {
- if ( ent.entityNumber < MAX_PLAYERS ) {
- // Players may run more than one think per frame in MP,
- // if there is a large buffer of usercmds from the network.
- // Players will always run exactly one think in singleplayer.
- RunAllUserCmdsForPlayer( userCmdMgr, ent.entityNumber );
- } else {
- // Non-player entities always run one think.
- ent.Think();
- }
- }
- idCVar g_recordTrace( "g_recordTrace", "0", CVAR_BOOL, "" );
- /*
- ================
- idGameLocal::RunFrame
- ================
- */
- void idGameLocal::RunFrame( idUserCmdMgr & cmdMgr, gameReturn_t & ret ) {
- idEntity * ent;
- int num;
- float ms;
- idTimer timer_think, timer_events, timer_singlethink;
- idPlayer *player;
- const renderView_t *view;
- if ( g_recordTrace.GetBool() ) {
- bool result = BeginTraceRecording( "e:\\gametrace.pix2" );
- if ( !result ) {
- //idLib::Printf( "BeginTraceRecording: error %d\n", GetLastError() );
- }
- }
- #ifdef _DEBUG
- if ( common->IsMultiplayer() ) {
- assert( !common->IsClient() );
- }
- #endif
- if ( gameRenderWorld == NULL ) {
- return;
- }
- SyncPlayersWithLobbyUsers( false );
- ServerSendNetworkSyncCvars();
- player = GetLocalPlayer();
- if ( !common->IsMultiplayer() && g_stopTime.GetBool() ) {
- // clear any debug lines from a previous frame
- gameRenderWorld->DebugClearLines( time + 1 );
- // set the user commands for this frame
- if ( player ) {
- player->HandleUserCmds( cmdMgr.GetUserCmdForPlayer( GetLocalClientNum() ) );
- cmdMgr.MakeReadPtrCurrentForPlayer( GetLocalClientNum() );
- player->Think();
- }
- } else {
- // update the game time
- framenum++;
- fast.previousTime = FRAME_TO_MSEC( framenum - 1 );
- fast.time = FRAME_TO_MSEC( framenum );
- fast.realClientTime = fast.time;
- SetServerGameTimeMs( fast.time );
- ComputeSlowScale();
- slow.previousTime = slow.time;
- slow.time += idMath::Ftoi( ( fast.time - fast.previousTime ) * slowmoScale );
- slow.realClientTime = slow.time;
- SelectTimeGroup( false );
- #ifdef GAME_DLL
- // allow changing SIMD usage on the fly
- if ( com_forceGenericSIMD.IsModified() ) {
- idSIMD::InitProcessor( "game", com_forceGenericSIMD.GetBool() );
- }
- #endif
- // make sure the random number counter is used each frame so random events
- // are influenced by the player's actions
- random.RandomInt();
- if ( player ) {
- // update the renderview so that any gui videos play from the right frame
- view = player->GetRenderView();
- if ( view ) {
- gameRenderWorld->SetRenderView( view );
- }
- }
- // clear any debug lines from a previous frame
- gameRenderWorld->DebugClearLines( time );
- // clear any debug polygons from a previous frame
- gameRenderWorld->DebugClearPolygons( time );
- // free old smoke particles
- smokeParticles->FreeSmokes();
- // process events on the server
- ServerProcessEntityNetworkEventQueue();
- // update our gravity vector if needed.
- UpdateGravity();
- // create a merged pvs for all players
- SetupPlayerPVS();
- // sort the active entity list
- SortActiveEntityList();
- timer_think.Clear();
- timer_think.Start();
- // let entities think
- if ( g_timeentities.GetFloat() ) {
- num = 0;
- for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
- if ( g_cinematic.GetBool() && inCinematic && !ent->cinematic ) {
- ent->GetPhysics()->UpdateTime( time );
- continue;
- }
- timer_singlethink.Clear();
- timer_singlethink.Start();
- RunEntityThink( *ent, cmdMgr );
- timer_singlethink.Stop();
- ms = timer_singlethink.Milliseconds();
- if ( ms >= g_timeentities.GetFloat() ) {
- Printf( "%d: entity '%s': %.1f ms\n", time, ent->name.c_str(), ms );
- }
- num++;
- }
- } else {
- if ( inCinematic ) {
- num = 0;
- for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
- if ( g_cinematic.GetBool() && !ent->cinematic ) {
- ent->GetPhysics()->UpdateTime( time );
- continue;
- }
- RunEntityThink( *ent, cmdMgr );
- num++;
- }
- } else {
- num = 0;
- for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
- if ( ent->timeGroup != TIME_GROUP1 ) {
- continue;
- }
- RunEntityThink( *ent, cmdMgr );
- num++;
- }
- }
- }
- RunTimeGroup2( cmdMgr );
- // Run catch-up for any client projectiles.
- // This is done after the main think so that all projectiles will be up-to-date
- // when snapshots are created.
- //if ( common->IsMultiplayer() ) {
- //while ( SimulateProjectiles() ) {
- //clientGame.gameLibEffects.Update( clientGame.GetGameMs(), clientGame.GetGameMsPerFrame(), clientGame.GetServerGameTime() );
- //}
- //}
- // remove any entities that have stopped thinking
- if ( numEntitiesToDeactivate ) {
- idEntity *next_ent;
- int c = 0;
- for( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
- next_ent = ent->activeNode.Next();
- if ( !ent->thinkFlags ) {
- ent->activeNode.Remove();
- c++;
- }
- }
- //assert( numEntitiesToDeactivate == c );
- numEntitiesToDeactivate = 0;
- }
- timer_think.Stop();
- timer_events.Clear();
- timer_events.Start();
- // service any pending events
- idEvent::ServiceEvents();
- // service pending fast events
- SelectTimeGroup( true );
- idEvent::ServiceFastEvents();
- SelectTimeGroup( false );
- timer_events.Stop();
- // free the player pvs
- FreePlayerPVS();
- // do multiplayer related stuff
- if ( common->IsMultiplayer() ) {
- mpGame.Run();
- }
- // display how long it took to calculate the current game frame
- if ( g_frametime.GetBool() ) {
- Printf( "game %d: all:%.1f th:%.1f ev:%.1f %d ents \n",
- time, timer_think.Milliseconds() + timer_events.Milliseconds(),
- timer_think.Milliseconds(), timer_events.Milliseconds(), num );
- }
- BuildReturnValue( ret );
- }
- // show any debug info for this frame
- RunDebugInfo();
- D_DrawDebugLines();
- if ( g_recordTrace.GetBool() ) {
- EndTraceRecording();
- g_recordTrace.SetBool( false );
- }
- }
- /*
- ====================
- idGameLocal::BuildReturnValue
- Fills out gameReturn_t, called on server and clients.
- ====================
- */
- void idGameLocal::BuildReturnValue( gameReturn_t & ret ) {
- ret.sessionCommand[0] = 0;
- if ( GetLocalPlayer() != NULL ) {
- GetLocalPlayer()->GetControllerShake( ret.vibrationLow, ret.vibrationHigh );
- } else {
- // Dedicated server?
- ret.vibrationLow = 0;
- ret.vibrationHigh = 0;
- }
- // see if a target_sessionCommand has forced a changelevel
- if ( sessionCommand.Length() ) {
- strncpy( ret.sessionCommand, sessionCommand, sizeof( ret.sessionCommand ) );
- sessionCommand.Clear(); // Fixes a double loading bug for the e3 demo. Since we run the game thread in SMP mode, we could run this twice and re-set the ret.sessionCommand to a stale sessionCommand (since that doesn't get cleared until LoadMap is called!)
- }
- }
- /*
- ====================
- idGameLocal::RunSinglelUserCmd
- Runs a Think or a ClientThink for a player. Will write the client's
- position and firecount to the usercmd.
- ====================
- */
- void idGameLocal::RunSingleUserCmd( usercmd_t & cmd, idPlayer & player ) {
- player.HandleUserCmds( cmd );
-
- // To fix the stupid chaingun script that depends on frame counts instead of
- // milliseconds in the case of the server running at 60Hz and the client running
- // at 120Hz, we need to set the script's GAME_FPS value to the client's effective rate.
- // (I'd like to just fix the script to use milliseconds, but we don't want to change assets
- // at this point.)
- if ( !player.IsLocallyControlled() ) {
- const float usercmdMillisecondDelta = player.usercmd.clientGameMilliseconds - player.oldCmd.clientGameMilliseconds;
- const float clientEngineHz = 1000.0f / usercmdMillisecondDelta;
-
- // Force to 60 or 120, those are the only values allowed in multiplayer.
- const float forcedClientEngineHz = ( clientEngineHz < 90.0f ) ? 60.0f : 120.0f;
- SetScriptFPS( forcedClientEngineHz );
- }
- if ( !common->IsMultiplayer() || common->IsServer() ) {
- player.Think();
- // Keep track of the client time of the usercmd we just ran. We will send this back to clients
- // in a snapshot so they know when they can stop predicting certain things.
- usercmdLastClientMilliseconds[ player.GetEntityNumber() ] = cmd.clientGameMilliseconds;
- } else {
- player.ClientThink( netInterpolationInfo.serverGameMs, netInterpolationInfo.pct, true );
- }
- // Since the client is authoritative on its position, we have to update the usercmd
- // that will be sent over the network after the player thinks.
- cmd.pos = player.usercmd.pos;
- cmd.fireCount = player.GetClientFireCount();
- if ( player.GetPhysics() ) {
- cmd.speedSquared = player.GetPhysics()->GetLinearVelocity().LengthSqr();
- }
- }
- /*
- ====================
- idGameLocal::RunAllUserCmdsForPlayer
- Runs a Think or ClientThink for each usercmd, but leaves a few cmds in the buffer
- so that we have something to process while we wait for more from the network.
- ====================
- */
- void idGameLocal::RunAllUserCmdsForPlayer( idUserCmdMgr & cmdMgr, const int playerNumber ) {
- //idLib::Printf( "Frame: %i = [%i-%i] ", gameLocal.framenum,
- //cmdMgr.readFrame[0], cmdMgr.writeFrame[0] ); // !@#
-
- // Run thinks on any players that have queued up usercmds for networking.
- assert( playerNumber < MAX_PLAYERS );
- if ( entities[ playerNumber ] == NULL ) {
- return;
- }
- idPlayer & player = static_cast< idPlayer & >( *entities[ playerNumber ] );
- // Only run a single userCmd each game frame for local players, otherwise when
- // we are running < 60fps things like footstep sounds may get started right on top
- // of each other instead of spread out in time.
- if ( player.IsLocallyControlled() ) {
- if ( cmdMgr.HasUserCmdForPlayer( playerNumber ) ) {
- if ( net_usercmd_timing_debug.GetBool() ) {
- idLib::Printf( "[%d]Running local cmd for player %d, %d buffered.\n",
- common->GetGameFrame(), playerNumber, cmdMgr.GetNumUnreadFrames( playerNumber ) );
- }
- RunSingleUserCmd( cmdMgr.GetWritableUserCmdForPlayer( playerNumber ), player );
- } else {
- RunSingleUserCmd( player.usercmd, player );
- }
- return;
- }
- // Only the server runs remote commands.
- if ( common->IsClient() ) {
- return;
- }
-
- // Make sure to run a command for remote players. May duplicate the previous command
- // if the server is running faster, or run an "empty" command if the buffer
- // underflows.
- if ( cmdMgr.HasUserCmdForPlayer( player.GetEntityNumber() ) ) {
- const int clientTimeOfNextCommand = cmdMgr.GetNextUserCmdClientTime( playerNumber );
- const int timeDeltaBetweenClientCommands = clientTimeOfNextCommand - lastCmdRunTimeOnClient[ playerNumber ];
- const int timeSinceServerRanLastCommand = gameLocal.time - lastCmdRunTimeOnServer[ playerNumber ];
- int clientTimeRunSoFar = 0;
- // Handle clients who may be running faster than the server. Potentiallly runs multiple
- // usercmds so that the server can catch up.
- if ( timeDeltaBetweenClientCommands - timeSinceServerRanLastCommand <= 1 ) {
- while ( clientTimeRunSoFar < ( timeSinceServerRanLastCommand - 1 ) && cmdMgr.HasUserCmdForPlayer( player.GetEntityNumber() ) ) {
- usercmd_t & currentCommand = cmdMgr.GetWritableUserCmdForPlayer( playerNumber );
- RunSingleUserCmd( currentCommand, player );
- lastCmdRunTimeOnClient[ playerNumber ] = currentCommand.clientGameMilliseconds;
- lastCmdRunTimeOnServer[ playerNumber ] = gameLocal.serverTime;
- clientTimeRunSoFar += timeDeltaBetweenClientCommands;
- if ( clientTimeRunSoFar == 0 ) {
- // Hack to avoid infinite loop
- break;
- }
- if ( net_usercmd_timing_debug.GetBool() ) {
- idLib::Printf( "[%d]Running initial cmd for player %d, %d buffered, %d so far, %d serverDelta.\n",
- common->GetGameFrame(), playerNumber, cmdMgr.GetNumUnreadFrames( playerNumber ),
- clientTimeRunSoFar, timeSinceServerRanLastCommand );
- }
- }
- } else {
- // If we get here, it is likely that the client is running at 60Hz but the server
- // is running at 120Hz. Duplicate the previous
- // usercmd and run it so that the server doesn't starve.
- usercmd_t lastPlayerCmd = player.usercmd;
- RunSingleUserCmd( lastPlayerCmd, player );
- if ( net_usercmd_timing_debug.GetBool() ) {
- idLib::Printf( "[%d]Running duplicated command for player %d to prevent server from starving. clientCmdTimeDelta = %d, runCmdTimeDeltaOnServer = %d.\n",
- common->GetGameFrame(), playerNumber, timeDeltaBetweenClientCommands, timeSinceServerRanLastCommand );
- }
- }
- } else {
- // Run an "empty" cmd, ran out of buffer.
- usercmd_t emptyCmd = player.usercmd;
- emptyCmd.forwardmove = 0;
- emptyCmd.rightmove = 0;
- RunSingleUserCmd( emptyCmd, player );
- lastCmdRunTimeOnServer[ playerNumber ] = gameLocal.serverTime;
- if ( net_usercmd_timing_debug.GetBool() ) {
- idLib::Printf( "[%d]Ran out of commands for player %d.\n", common->GetGameFrame(), playerNumber );
- }
- }
- // For remote players on the server, run enough commands
- // to leave only a buffer that will hold us over for a
- // number of milliseconds equal to the net_ucmdRate + one frame.
- const int MaxExtraCommandsPerFrame = 15;
- int numPasses = 0;
- for ( ; numPasses < MaxExtraCommandsPerFrame; numPasses++ ) {
- // Run remote player extra commands
- extern idCVar net_ucmdRate;
- // Add some extra time to smooth out network inconsistencies.
- const int extraFrameMilliseconds = FRAME_TO_MSEC( common->GetGameFrame() + 2 ) - FRAME_TO_MSEC( common->GetGameFrame() );
- const int millisecondBuffer = MSEC_ALIGN_TO_FRAME( net_ucmdRate.GetInteger() + extraFrameMilliseconds );
- const bool hasNextCmd = cmdMgr.HasUserCmdForClientTimeBuffer( playerNumber, millisecondBuffer );
- if ( hasNextCmd ) {
- usercmd_t & currentCommand = cmdMgr.GetWritableUserCmdForPlayer( playerNumber );
-
- if ( net_usercmd_timing_debug.GetBool() ) {
- idLib::Printf( "[%d]Pass %d, running extra cmd for player %d, %d buffered\n", common->GetGameFrame(), numPasses, playerNumber, cmdMgr.GetNumUnreadFrames( playerNumber ) );
- }
-
- RunSingleUserCmd( currentCommand, player );
- lastCmdRunTimeOnClient[ playerNumber ] = currentCommand.clientGameMilliseconds;
- lastCmdRunTimeOnServer[ playerNumber ] = gameLocal.serverTime;
- } else {
- break;
- }
- }
- // Reset the script FPS in case it was changed to accomodate an MP client
- // running at a different framerate.
- SetScriptFPS( com_engineHz_latched );
- //idLib::Printf( "\n" );//!@#
- }
- /*
- ======================================================================
- Game view drawing
- ======================================================================
- */
- /*
- ====================
- idGameLocal::CalcFov
- Calculates the horizontal and vertical field of view based on a horizontal field of view and custom aspect ratio
- ====================
- */
- void idGameLocal::CalcFov( float base_fov, float &fov_x, float &fov_y ) const {
- const int width = renderSystem->GetWidth();
- const int height = renderSystem->GetHeight();
- if ( width == height ) {
- // this is the Rift, so don't mess with our aspect ratio corrections
- fov_x = base_fov;
- fov_y = base_fov;
- return;
- }
- // Calculate the fov_y based on an ideal aspect ratio
- const float ideal_ratio_x = 16.0f;
- const float ideal_ratio_y = 9.0f;
- const float tanHalfX = idMath::Tan( DEG2RAD( base_fov * 0.5f ) );
- fov_y = 2.0f * RAD2DEG( idMath::ATan( ideal_ratio_y * tanHalfX, ideal_ratio_x ) );
- // Then calculate fov_x based on the true aspect ratio
- const float ratio_x = width * renderSystem->GetPixelAspect();
- const float ratio_y = height;
- const float tanHalfY = idMath::Tan( DEG2RAD( fov_y * 0.5f ) );
- fov_x = 2.0f * RAD2DEG( idMath::ATan( ratio_x * tanHalfY, ratio_y ) );
- }
- /*
- ================
- idGameLocal::Draw
- makes rendering and sound system calls
- ================
- */
- bool idGameLocal::Draw( int clientNum ) {
- if( clientNum == -1 ) {
- return false;
- }
- if ( common->IsMultiplayer() && session->GetState() == idSession::INGAME ) {
- return mpGame.Draw( clientNum );
- }
- // chose the optimized or legacy device context code
- uiManager->SetDrawingDC();
- idPlayer *player = static_cast<idPlayer *>(entities[ clientNum ]);
- if ( ( player == NULL ) || ( player->GetRenderView() == NULL ) ) {
- return false;
- }
- // render the scene
- player->playerView.RenderPlayerView( player->hudManager );
- return true;
- }
- /*
- ================
- idGameLocal::HandleGuiCommands
- ================
- */
- bool idGameLocal::HandlePlayerGuiEvent( const sysEvent_t * ev ) {
- idPlayer * player = GetLocalPlayer();
- bool handled = false;
- if ( player != NULL ) {
- handled = player->HandleGuiEvents( ev );
- }
- if ( common->IsMultiplayer() && !handled ) {
- handled = mpGame.HandleGuiEvent( ev );
- }
- return handled;
- }
- /*
- ================
- idGameLocal::GetLevelMap
- should only be used for in-game level editing
- ================
- */
- idMapFile *idGameLocal::GetLevelMap() {
- if ( mapFile && mapFile->HasPrimitiveData()) {
- return mapFile;
- }
- if ( !mapFileName.Length() ) {
- return NULL;
- }
- if ( mapFile ) {
- delete mapFile;
- }
- mapFile = new (TAG_GAME) idMapFile;
- if ( !mapFile->Parse( mapFileName ) ) {
- delete mapFile;
- mapFile = NULL;
- }
- return mapFile;
- }
- /*
- ================
- idGameLocal::GetMapName
- ================
- */
- const char *idGameLocal::GetMapName() const {
- return mapFileName.c_str();
- }
- /*
- ================
- idGameLocal::CallFrameCommand
- ================
- */
- void idGameLocal::CallFrameCommand( idEntity *ent, const function_t *frameCommand ) {
- frameCommandThread->CallFunction( ent, frameCommand, true );
- frameCommandThread->Execute();
- }
- /*
- ================
- idGameLocal::CallObjectFrameCommand
- ================
- */
- void idGameLocal::CallObjectFrameCommand( idEntity *ent, const char *frameCommand ) {
- const function_t *func;
- func = ent->scriptObject.GetFunction( frameCommand );
- if ( !func ) {
- if ( !ent->IsType( idTestModel::Type ) ) {
- Error( "Unknown function '%s' called for frame command on entity '%s'", frameCommand, ent->name.c_str() );
- }
- } else {
- frameCommandThread->CallFunction( ent, func, true );
- frameCommandThread->Execute();
- }
- }
- /*
- ================
- idGameLocal::ShowTargets
- ================
- */
- void idGameLocal::ShowTargets() {
- idMat3 axis = GetLocalPlayer()->viewAngles.ToMat3();
- idVec3 up = axis[ 2 ] * 5.0f;
- const idVec3 &viewPos = GetLocalPlayer()->GetPhysics()->GetOrigin();
- idBounds viewTextBounds( viewPos );
- idBounds viewBounds( viewPos );
- idBounds box( idVec3( -4.0f, -4.0f, -4.0f ), idVec3( 4.0f, 4.0f, 4.0f ) );
- idEntity *ent;
- idEntity *target;
- int i;
- idBounds totalBounds;
- viewTextBounds.ExpandSelf( 128.0f );
- viewBounds.ExpandSelf( 512.0f );
- for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
- totalBounds = ent->GetPhysics()->GetAbsBounds();
- for( i = 0; i < ent->targets.Num(); i++ ) {
- target = ent->targets[ i ].GetEntity();
- if ( target ) {
- totalBounds.AddBounds( target->GetPhysics()->GetAbsBounds() );
- }
- }
- if ( !viewBounds.IntersectsBounds( totalBounds ) ) {
- continue;
- }
- float dist;
- idVec3 dir = totalBounds.GetCenter() - viewPos;
- dir.NormalizeFast();
- totalBounds.RayIntersection( viewPos, dir, dist );
- float frac = ( 512.0f - dist ) / 512.0f;
- if ( frac < 0.0f ) {
- continue;
- }
- gameRenderWorld->DebugBounds( ( ent->IsHidden() ? colorLtGrey : colorOrange ) * frac, ent->GetPhysics()->GetAbsBounds() );
- if ( viewTextBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ) ) {
- idVec3 center = ent->GetPhysics()->GetAbsBounds().GetCenter();
- gameRenderWorld->DrawText( ent->name.c_str(), center - up, 0.1f, colorWhite * frac, axis, 1 );
- gameRenderWorld->DrawText( ent->GetEntityDefName(), center, 0.1f, colorWhite * frac, axis, 1 );
- gameRenderWorld->DrawText( va( "#%d", ent->entityNumber ), center + up, 0.1f, colorWhite * frac, axis, 1 );
- }
- for( i = 0; i < ent->targets.Num(); i++ ) {
- target = ent->targets[ i ].GetEntity();
- if ( target ) {
- gameRenderWorld->DebugArrow( colorYellow * frac, ent->GetPhysics()->GetAbsBounds().GetCenter(), target->GetPhysics()->GetOrigin(), 10, 0 );
- gameRenderWorld->DebugBounds( colorGreen * frac, box, target->GetPhysics()->GetOrigin() );
- }
- }
- }
- }
- /*
- ================
- idGameLocal::RunDebugInfo
- ================
- */
- void idGameLocal::RunDebugInfo() {
- idEntity *ent;
- idPlayer *player;
- player = GetLocalPlayer();
- if ( !player ) {
- return;
- }
- const idVec3 &origin = player->GetPhysics()->GetOrigin();
- if ( g_showEntityInfo.GetBool() ) {
- idMat3 axis = player->viewAngles.ToMat3();
- idVec3 up = axis[ 2 ] * 5.0f;
- idBounds viewTextBounds( origin );
- idBounds viewBounds( origin );
- viewTextBounds.ExpandSelf( 128.0f );
- viewBounds.ExpandSelf( 512.0f );
- for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
- // don't draw the worldspawn
- if ( ent == world ) {
- continue;
- }
- // skip if the entity is very far away
- if ( !viewBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ) ) {
- continue;
- }
- const idBounds &entBounds = ent->GetPhysics()->GetAbsBounds();
- int contents = ent->GetPhysics()->GetContents();
- if ( contents & CONTENTS_BODY ) {
- gameRenderWorld->DebugBounds( colorCyan, entBounds );
- } else if ( contents & CONTENTS_TRIGGER ) {
- gameRenderWorld->DebugBounds( colorOrange, entBounds );
- } else if ( contents & CONTENTS_SOLID ) {
- gameRenderWorld->DebugBounds( colorGreen, entBounds );
- } else {
- if ( !entBounds.GetVolume() ) {
- gameRenderWorld->DebugBounds( colorMdGrey, entBounds.Expand( 8.0f ) );
- } else {
- gameRenderWorld->DebugBounds( colorMdGrey, entBounds );
- }
- }
- if ( viewTextBounds.IntersectsBounds( entBounds ) ) {
- gameRenderWorld->DrawText( ent->name.c_str(), entBounds.GetCenter(), 0.1f, colorWhite, axis, 1 );
- gameRenderWorld->DrawText( va( "#%d", ent->entityNumber ), entBounds.GetCenter() + up, 0.1f, colorWhite, axis, 1 );
- }
- }
- }
- // debug tool to draw bounding boxes around active entities
- if ( g_showActiveEntities.GetBool() ) {
- for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
- idBounds b = ent->GetPhysics()->GetBounds();
- if ( b.GetVolume() <= 0 ) {
- b[0][0] = b[0][1] = b[0][2] = -8;
- b[1][0] = b[1][1] = b[1][2] = 8;
- }
- if ( ent->fl.isDormant ) {
- gameRenderWorld->DebugBounds( colorYellow, b, ent->GetPhysics()->GetOrigin() );
- } else {
- gameRenderWorld->DebugBounds( colorGreen, b, ent->GetPhysics()->GetOrigin() );
- }
- }
- }
- if ( g_showTargets.GetBool() ) {
- ShowTargets();
- }
- if ( g_showTriggers.GetBool() ) {
- idTrigger::DrawDebugInfo();
- }
- if ( ai_showCombatNodes.GetBool() ) {
- idCombatNode::DrawDebugInfo();
- }
- if ( ai_showPaths.GetBool() ) {
- idPathCorner::DrawDebugInfo();
- }
- if ( g_editEntityMode.GetBool() ) {
- editEntities->DisplayEntities();
- }
- if ( g_showCollisionWorld.GetBool() ) {
- collisionModelManager->DrawModel( 0, vec3_origin, mat3_identity, origin, 128.0f );
- }
- if ( g_showCollisionModels.GetBool() ) {
- clip.DrawClipModels( player->GetEyePosition(), g_maxShowDistance.GetFloat(), pm_thirdPerson.GetBool() ? NULL : player );
- }
- if ( g_showCollisionTraces.GetBool() ) {
- clip.PrintStatistics();
- }
- if ( g_showPVS.GetInteger() ) {
- pvs.DrawPVS( origin, ( g_showPVS.GetInteger() == 2 ) ? PVS_ALL_PORTALS_OPEN : PVS_NORMAL );
- }
- if ( aas_test.GetInteger() >= 0 ) {
- idAAS *aas = GetAAS( aas_test.GetInteger() );
- if ( aas ) {
- aas->Test( origin );
- if ( ai_testPredictPath.GetBool() ) {
- idVec3 velocity;
- predictedPath_t path;
- velocity.x = cos( DEG2RAD( player->viewAngles.yaw ) ) * 100.0f;
- velocity.y = sin( DEG2RAD( player->viewAngles.yaw ) ) * 100.0f;
- velocity.z = 0.0f;
- idAI::PredictPath( player, aas, origin, velocity, 1000, 100, SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA, path );
- }
- }
- }
- if ( ai_showObstacleAvoidance.GetInteger() == 2 ) {
- idAAS *aas = GetAAS( 0 );
- if ( aas ) {
- idVec3 seekPos;
- obstaclePath_t path;
- seekPos = player->GetPhysics()->GetOrigin() + player->viewAxis[0] * 200.0f;
- idAI::FindPathAroundObstacles( player->GetPhysics(), aas, NULL, player->GetPhysics()->GetOrigin(), seekPos, path );
- }
- }
- // collision map debug output
- collisionModelManager->DebugOutput( player->GetEyePosition() );
- }
- /*
- ==================
- idGameLocal::NumAAS
- ==================
- */
- int idGameLocal::NumAAS() const {
- return aasList.Num();
- }
- /*
- ==================
- idGameLocal::GetAAS
- ==================
- */
- idAAS *idGameLocal::GetAAS( int num ) const {
- if ( ( num >= 0 ) && ( num < aasList.Num() ) ) {
- if ( aasList[ num ] && aasList[ num ]->GetSettings() ) {
- return aasList[ num ];
- }
- }
- return NULL;
- }
- /*
- ==================
- idGameLocal::GetAAS
- ==================
- */
- idAAS *idGameLocal::GetAAS( const char *name ) const {
- int i;
- for ( i = 0; i < aasNames.Num(); i++ ) {
- if ( aasNames[ i ] == name ) {
- if ( !aasList[ i ]->GetSettings() ) {
- return NULL;
- } else {
- return aasList[ i ];
- }
- }
- }
- return NULL;
- }
- /*
- ==================
- idGameLocal::SetAASAreaState
- ==================
- */
- void idGameLocal::SetAASAreaState( const idBounds &bounds, const int areaContents, bool closed ) {
- int i;
- for( i = 0; i < aasList.Num(); i++ ) {
- aasList[ i ]->SetAreaState( bounds, areaContents, closed );
- }
- }
- /*
- ==================
- idGameLocal::AddAASObstacle
- ==================
- */
- aasHandle_t idGameLocal::AddAASObstacle( const idBounds &bounds ) {
- int i;
- aasHandle_t obstacle;
- aasHandle_t check;
- if ( !aasList.Num() ) {
- return -1;
- }
- obstacle = aasList[ 0 ]->AddObstacle( bounds );
- for( i = 1; i < aasList.Num(); i++ ) {
- check = aasList[ i ]->AddObstacle( bounds );
- assert( check == obstacle );
- }
- return obstacle;
- }
- /*
- ==================
- idGameLocal::RemoveAASObstacle
- ==================
- */
- void idGameLocal::RemoveAASObstacle( const aasHandle_t handle ) {
- int i;
- for( i = 0; i < aasList.Num(); i++ ) {
- aasList[ i ]->RemoveObstacle( handle );
- }
- }
- /*
- ==================
- idGameLocal::RemoveAllAASObstacles
- ==================
- */
- void idGameLocal::RemoveAllAASObstacles() {
- int i;
- for( i = 0; i < aasList.Num(); i++ ) {
- aasList[ i ]->RemoveAllObstacles();
- }
- }
- /*
- ==================
- idGameLocal::CheatsOk
- ==================
- */
- bool idGameLocal::CheatsOk( bool requirePlayer ) {
- extern idCVar net_allowCheats;
- if ( common->IsMultiplayer() && !net_allowCheats.GetBool() ) {
- Printf( "Not allowed in multiplayer.\n" );
- return false;
- }
- if ( developer.GetBool() ) {
- return true;
- }
- idPlayer * player = GetLocalPlayer();
- if ( !requirePlayer || ( player != NULL && ( player->health > 0 ) ) ) {
- return true;
- }
- Printf( "You must be alive to use this command.\n" );
- return false;
- }
- /*
- ===================
- idGameLocal::RegisterEntity
- ===================
- */
- void idGameLocal::RegisterEntity( idEntity *ent, int forceSpawnId, const idDict & spawnArgsToCopy ) {
- int spawn_entnum;
- ent->fl.skipReplication = spawnArgsToCopy.GetBool( "net_skip_replication", false );
- if ( spawnCount >= ( 1 << ( 32 - GENTITYNUM_BITS ) ) ) {
- Error( "idGameLocal::RegisterEntity: spawn count overflow" );
- }
- if ( !spawnArgsToCopy.GetInt( "spawn_entnum", "0", spawn_entnum ) ) {
- const int freeListType = ( common->IsMultiplayer() && ent->GetSkipReplication() ) ? 1 : 0;
- const int maxEntityNum = ( common->IsMultiplayer() && !ent->GetSkipReplication() ) ? ENTITYNUM_FIRST_NON_REPLICATED : ENTITYNUM_MAX_NORMAL;
- int freeIndex = firstFreeEntityIndex[ freeListType ];
- while( entities[ freeIndex ] != NULL && freeIndex < maxEntityNum ) {
- freeIndex++;
- }
- if ( freeIndex >= maxEntityNum ) {
- Error( "no free entities[%d]", freeListType );
- }
- spawn_entnum = freeIndex++;
- firstFreeEntityIndex[ freeListType ] = freeIndex;
- }
-
- entities[ spawn_entnum ] = ent;
- spawnIds[ spawn_entnum ] = ( forceSpawnId >= 0 ) ? forceSpawnId : spawnCount++;
- ent->entityNumber = spawn_entnum;
- ent->spawnNode.AddToEnd( spawnedEntities );
- // Make a copy because TransferKeyValues clears the input parameter.
- idDict copiedArgs = spawnArgsToCopy;
- ent->spawnArgs.TransferKeyValues( copiedArgs );
- if ( spawn_entnum >= num_entities ) {
- num_entities++;
- }
- }
- /*
- ===================
- idGameLocal::UnregisterEntity
- ===================
- */
- void idGameLocal::UnregisterEntity( idEntity *ent ) {
- assert( ent );
- if ( editEntities ) {
- editEntities->RemoveSelectedEntity( ent );
- }
- if ( !verify( ent->entityNumber < MAX_GENTITIES ) ) {
- idLib::Error( "invalid entity number" );
- return;
- }
- if ( ( ent->entityNumber != ENTITYNUM_NONE ) && ( entities[ ent->entityNumber ] == ent ) ) {
- ent->spawnNode.Remove();
- entities[ ent->entityNumber ] = NULL;
- spawnIds[ ent->entityNumber ] = -1;
- int freeListType = ( common->IsMultiplayer() && ent->entityNumber >= ENTITYNUM_FIRST_NON_REPLICATED ) ? 1 : 0;
- if ( ent->entityNumber >= MAX_CLIENTS && ent->entityNumber < firstFreeEntityIndex[ freeListType ] ) {
- firstFreeEntityIndex[ freeListType ] = ent->entityNumber;
- }
- ent->entityNumber = ENTITYNUM_NONE;
- }
- }
- /*
- ================
- idGameLocal::SpawnEntityType
- ================
- */
- idEntity *idGameLocal::SpawnEntityType( const idTypeInfo &classdef, const idDict *args, bool bIsClientReadSnapshot ) {
- idClass *obj;
- #if _DEBUG
- if ( common->IsClient() ) {
- assert( bIsClientReadSnapshot );
- }
- #endif
- if ( !classdef.IsType( idEntity::Type ) ) {
- Error( "Attempted to spawn non-entity class '%s'", classdef.classname );
- }
- try {
- if ( args ) {
- spawnArgs = *args;
- } else {
- spawnArgs.Clear();
- }
- obj = classdef.CreateInstance();
- obj->CallSpawn();
- }
-
- catch( idAllocError & ) {
- obj = NULL;
- }
- spawnArgs.Clear();
- return static_cast<idEntity *>(obj);
- }
- /*
- ===================
- idGameLocal::SpawnEntityDef
- Finds the spawn function for the entity and calls it,
- returning false if not found
- ===================
- */
- bool idGameLocal::SpawnEntityDef( const idDict &args, idEntity **ent, bool setDefaults ) {
- const char *classname;
- const char *spawn;
- idTypeInfo *cls;
- idClass *obj;
- idStr error;
- const char *name;
- if ( ent ) {
- *ent = NULL;
- }
- spawnArgs = args;
- if ( spawnArgs.GetString( "name", "", &name ) ) {
- sprintf( error, " on '%s'", name);
- }
- spawnArgs.GetString( "classname", NULL, &classname );
- const idDeclEntityDef *def = FindEntityDef( classname, false );
- if ( !def ) {
- Warning( "Unknown classname '%s'%s.", classname, error.c_str() );
- return false;
- }
- spawnArgs.SetDefaults( &def->dict );
- if ( !spawnArgs.FindKey( "slowmo" ) ) {
- bool slowmo = true;
- for ( int i = 0; fastEntityList[i]; i++ ) {
- if ( !idStr::Cmp( classname, fastEntityList[i] ) ) {
- slowmo = false;
- break;
- }
- }
- if ( !slowmo ) {
- spawnArgs.SetBool( "slowmo", slowmo );
- }
- }
- // check if we should spawn a class object
- spawnArgs.GetString( "spawnclass", NULL, &spawn );
- if ( spawn ) {
- cls = idClass::GetClass( spawn );
- if ( !cls ) {
- Warning( "Could not spawn '%s'. Class '%s' not found%s.", classname, spawn, error.c_str() );
- return false;
- }
- obj = cls->CreateInstance();
- if ( !obj ) {
- Warning( "Could not spawn '%s'. Instance could not be created%s.", classname, error.c_str() );
- return false;
- }
- obj->CallSpawn();
- if ( ent && obj->IsType( idEntity::Type ) ) {
- *ent = static_cast<idEntity *>(obj);
- }
- return true;
- }
- // check if we should call a script function to spawn
- spawnArgs.GetString( "spawnfunc", NULL, &spawn );
- if ( spawn ) {
- const function_t *func = program.FindFunction( spawn );
- if ( !func ) {
- Warning( "Could not spawn '%s'. Script function '%s' not found%s.", classname, spawn, error.c_str() );
- return false;
- }
- idThread *thread = new idThread( func );
- thread->DelayedStart( 0 );
- return true;
- }
- Warning( "%s doesn't include a spawnfunc or spawnclass%s.", classname, error.c_str() );
- return false;
- }
- /*
- ================
- idGameLocal::FindEntityDef
- ================
- */
- const idDeclEntityDef *idGameLocal::FindEntityDef( const char *name, bool makeDefault ) const {
- const idDecl *decl = NULL;
- if ( common->IsMultiplayer() ) {
- decl = declManager->FindType( DECL_ENTITYDEF, va( "%s_mp", name ), false );
- }
- if ( !decl ) {
- decl = declManager->FindType( DECL_ENTITYDEF, name, makeDefault );
- }
- return static_cast<const idDeclEntityDef *>( decl );
- }
- /*
- ================
- idGameLocal::FindEntityDefDict
- ================
- */
- const idDict *idGameLocal::FindEntityDefDict( const char *name, bool makeDefault ) const {
- const idDeclEntityDef *decl = FindEntityDef( name, makeDefault );
- return decl ? &decl->dict : NULL;
- }
- /*
- ================
- idGameLocal::InhibitEntitySpawn
- ================
- */
- bool idGameLocal::InhibitEntitySpawn( idDict &spawnArgs ) {
-
- bool result = false;
- if ( common->IsMultiplayer() ) {
- spawnArgs.GetBool( "not_multiplayer", "0", result );
- } else if ( g_skill.GetInteger() == 0 ) {
- spawnArgs.GetBool( "not_easy", "0", result );
- } else if ( g_skill.GetInteger() == 1 ) {
- spawnArgs.GetBool( "not_medium", "0", result );
- } else {
- spawnArgs.GetBool( "not_hard", "0", result );
- if ( !result && g_skill.GetInteger() == 3 ) {
- spawnArgs.GetBool( "not_nightmare", "0", result );
- }
- }
- if ( g_skill.GetInteger() == 3 ) {
- const char * name = spawnArgs.GetString( "classname" );
- // _D3XP :: remove moveable medkit packs also
- if ( idStr::Icmp( name, "item_medkit" ) == 0 || idStr::Icmp( name, "item_medkit_small" ) == 0 ||
- idStr::Icmp( name, "moveable_item_medkit" ) == 0 || idStr::Icmp( name, "moveable_item_medkit_small" ) == 0 ) {
- result = true;
- }
- }
- if ( common->IsMultiplayer() ) {
- const char * name = spawnArgs.GetString( "classname" );
- if ( idStr::Icmp( name, "weapon_bfg" ) == 0 || idStr::Icmp( name, "weapon_soulcube" ) == 0 ) {
- result = true;
- }
- }
- return result;
- }
- /*
- ==============
- idGameLocal::GameState
- Used to allow entities to know if they're being spawned during the initial spawn.
- ==============
- */
- gameState_t idGameLocal::GameState() const {
- return gamestate;
- }
- /*
- ==============
- idGameLocal::SpawnMapEntities
- Parses textual entity definitions out of an entstring and spawns gentities.
- ==============
- */
- void idGameLocal::SpawnMapEntities() {
- int i;
- int num;
- int inhibit;
- idMapEntity *mapEnt;
- int numEntities;
- idDict args;
- Printf( "Spawning entities\n" );
- if ( mapFile == NULL ) {
- Printf("No mapfile present\n");
- return;
- }
- numEntities = mapFile->GetNumEntities();
- if ( numEntities == 0 ) {
- Error( "...no entities" );
- }
- // the worldspawn is a special that performs any global setup
- // needed by a level
- mapEnt = mapFile->GetEntity( 0 );
- args = mapEnt->epairs;
- args.SetInt( "spawn_entnum", ENTITYNUM_WORLD );
- if ( !SpawnEntityDef( args ) || !entities[ ENTITYNUM_WORLD ] || !entities[ ENTITYNUM_WORLD ]->IsType( idWorldspawn::Type ) ) {
- Error( "Problem spawning world entity" );
- }
- num = 1;
- inhibit = 0;
- for ( i = 1 ; i < numEntities ; i++ ) {
- common->UpdateLevelLoadPacifier();
- mapEnt = mapFile->GetEntity( i );
- args = mapEnt->epairs;
- if ( !InhibitEntitySpawn( args ) ) {
- // precache any media specified in the map entity
- CacheDictionaryMedia( &args );
- SpawnEntityDef( args );
- num++;
- } else {
- inhibit++;
- }
- }
- Printf( "...%i entities spawned, %i inhibited\n\n", num, inhibit );
- }
- /*
- ================
- idGameLocal::AddEntityToHash
- ================
- */
- void idGameLocal::AddEntityToHash( const char *name, idEntity *ent ) {
- if ( FindEntity( name ) ) {
- Error( "Multiple entities named '%s'", name );
- }
- entityHash.Add( entityHash.GenerateKey( name, true ), ent->entityNumber );
- }
- /*
- ================
- idGameLocal::RemoveEntityFromHash
- ================
- */
- bool idGameLocal::RemoveEntityFromHash( const char *name, idEntity *ent ) {
- int hash, i;
- hash = entityHash.GenerateKey( name, true );
- for ( i = entityHash.First( hash ); i != -1; i = entityHash.Next( i ) ) {
- if ( entities[i] && entities[i] == ent && entities[i]->name.Icmp( name ) == 0 ) {
- entityHash.Remove( hash, i );
- return true;
- }
- }
- return false;
- }
- /*
- ================
- idGameLocal::GetTargets
- ================
- */
- int idGameLocal::GetTargets( const idDict &args, idList< idEntityPtr<idEntity> > &list, const char *ref ) const {
- int i, num, refLength;
- const idKeyValue *arg;
- idEntity *ent;
- list.Clear();
- refLength = strlen( ref );
- num = args.GetNumKeyVals();
- for( i = 0; i < num; i++ ) {
- arg = args.GetKeyVal( i );
- if ( arg->GetKey().Icmpn( ref, refLength ) == 0 ) {
- ent = FindEntity( arg->GetValue() );
- if ( ent ) {
- idEntityPtr<idEntity> &entityPtr = list.Alloc();
- entityPtr = ent;
- }
- }
- }
- return list.Num();
- }
- /*
- =============
- idGameLocal::GetTraceEntity
- returns the master entity of a trace. for example, if the trace entity is the player's head, it will return the player.
- =============
- */
- idEntity *idGameLocal::GetTraceEntity( const trace_t &trace ) const {
- idEntity *master;
- if ( !entities[ trace.c.entityNum ] ) {
- return NULL;
- }
- master = entities[ trace.c.entityNum ]->GetBindMaster();
- if ( master ) {
- return master;
- }
- return entities[ trace.c.entityNum ];
- }
- /*
- =============
- idGameLocal::ArgCompletion_EntityName
- Argument completion for entity names
- =============
- */
- void idGameLocal::ArgCompletion_EntityName( const idCmdArgs &args, void(*callback)( const char *s ) ) {
- int i;
- for( i = 0; i < gameLocal.num_entities; i++ ) {
- if ( gameLocal.entities[ i ] ) {
- callback( va( "%s %s", args.Argv( 0 ), gameLocal.entities[ i ]->name.c_str() ) );
- }
- }
- }
- /*
- =============
- idGameLocal::FindEntity
- Returns the entity whose name matches the specified string.
- =============
- */
- idEntity *idGameLocal::FindEntity( const char *name ) const {
- int hash, i;
- hash = entityHash.GenerateKey( name, true );
- for ( i = entityHash.First( hash ); i != -1; i = entityHash.Next( i ) ) {
- if ( entities[i] && entities[i]->name.Icmp( name ) == 0 ) {
- return entities[i];
- }
- }
- return NULL;
- }
- /*
- =============
- idGameLocal::FindEntityUsingDef
- Searches all active entities for the next one using the specified entityDef.
- Searches beginning at the entity after from, or the beginning if NULL
- NULL will be returned if the end of the list is reached.
- =============
- */
- idEntity *idGameLocal::FindEntityUsingDef( idEntity *from, const char *match ) const {
- idEntity *ent;
- if ( !from ) {
- ent = spawnedEntities.Next();
- } else {
- ent = from->spawnNode.Next();
- }
- for ( ; ent != NULL; ent = ent->spawnNode.Next() ) {
- assert( ent );
- if ( idStr::Icmp( ent->GetEntityDefName(), match ) == 0 ) {
- return ent;
- }
- }
- return NULL;
- }
- /*
- =============
- idGameLocal::FindTraceEntity
- Searches all active entities for the closest ( to start ) match that intersects
- the line start,end
- =============
- */
- idEntity *idGameLocal::FindTraceEntity( idVec3 start, idVec3 end, const idTypeInfo &c, const idEntity *skip ) const {
- idEntity *ent;
- idEntity *bestEnt;
- float scale;
- float bestScale;
- idBounds b;
- bestEnt = NULL;
- bestScale = 1.0f;
- for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
- if ( ent->IsType( c ) && ent != skip ) {
- b = ent->GetPhysics()->GetAbsBounds().Expand( 16 );
- if ( b.RayIntersection( start, end-start, scale ) ) {
- if ( scale >= 0.0f && scale < bestScale ) {
- bestEnt = ent;
- bestScale = scale;
- }
- }
- }
- }
- return bestEnt;
- }
- /*
- ================
- idGameLocal::EntitiesWithinRadius
- ================
- */
- int idGameLocal::EntitiesWithinRadius( const idVec3 org, float radius, idEntity **entityList, int maxCount ) const {
- idEntity *ent;
- idBounds bo( org );
- int entCount = 0;
- bo.ExpandSelf( radius );
- for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
- if ( ent->GetPhysics()->GetAbsBounds().IntersectsBounds( bo ) ) {
- entityList[entCount++] = ent;
- }
- }
- return entCount;
- }
- /*
- =================
- idGameLocal::KillBox
- Kills all entities that would touch the proposed new positioning of ent. The ent itself will not being killed.
- Checks if player entities are in the teleporter, and marks them to die at teleport exit instead of immediately.
- If catch_teleport, this only marks teleport players for death on exit
- =================
- */
- void idGameLocal::KillBox( idEntity *ent, bool catch_teleport ) {
- int i;
- int num;
- idEntity * hit;
- idClipModel *cm;
- idClipModel *clipModels[ MAX_GENTITIES ];
- idPhysics *phys;
- phys = ent->GetPhysics();
- if ( !phys->GetNumClipModels() ) {
- return;
- }
- num = clip.ClipModelsTouchingBounds( phys->GetAbsBounds(), phys->GetClipMask(), clipModels, MAX_GENTITIES );
- for ( i = 0; i < num; i++ ) {
- cm = clipModels[ i ];
- // don't check render entities
- if ( cm->IsRenderModel() ) {
- continue;
- }
- hit = cm->GetEntity();
- if ( ( hit == ent ) || !hit->fl.takedamage ) {
- continue;
- }
- if ( !phys->ClipContents( cm ) ) {
- continue;
- }
- // nail it
- idPlayer *otherPlayer = NULL;
- if ( hit->IsType( idPlayer::Type ) ) {
- otherPlayer = static_cast< idPlayer * >( hit );
- }
- if ( otherPlayer != NULL ) {
- if ( otherPlayer->IsInTeleport() ) {
- otherPlayer->TeleportDeath( ent->entityNumber );
- } else if ( !catch_teleport ) {
- hit->Damage( ent, ent, vec3_origin, "damage_telefrag", 1.0f, INVALID_JOINT );
- }
- } else if ( !catch_teleport ) {
- hit->Damage( ent, ent, vec3_origin, "damage_telefrag", 1.0f, INVALID_JOINT );
- }
- }
- }
- /*
- ================
- idGameLocal::RequirementMet
- ================
- */
- bool idGameLocal::RequirementMet( idEntity *activator, const idStr &requires, int removeItem ) {
- if ( requires.Length() ) {
- if ( activator->IsType( idPlayer::Type ) ) {
- idPlayer *player = static_cast<idPlayer *>(activator);
- idDict *item = player->FindInventoryItem( requires );
- if ( item ) {
- if ( removeItem ) {
- player->RemoveInventoryItem( item );
- }
- return true;
- } else {
- return false;
- }
- }
- }
- return true;
- }
- /*
- ============
- idGameLocal::AlertAI
- ============
- */
- void idGameLocal::AlertAI( idEntity *ent ) {
- if ( ent && ent->IsType( idActor::Type ) ) {
- // alert them for the next frame
- lastAIAlertTime = time + 1;
- lastAIAlertEntity = static_cast<idActor *>( ent );
- }
- }
- /*
- ============
- idGameLocal::GetAlertEntity
- ============
- */
- idActor *idGameLocal::GetAlertEntity() {
- int timeGroup = 0;
- if ( lastAIAlertTime && lastAIAlertEntity.GetEntity() ) {
- timeGroup = lastAIAlertEntity.GetEntity()->timeGroup;
- }
- SetTimeState ts( timeGroup );
- if ( lastAIAlertTime >= time ) {
- return lastAIAlertEntity.GetEntity();
- }
- return NULL;
- }
- /*
- ============
- idGameLocal::RadiusDamage
- ============
- */
- void idGameLocal::RadiusDamage( const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignoreDamage, idEntity *ignorePush, const char *damageDefName, float dmgPower ) {
- float dist, damageScale, attackerDamageScale, attackerPushScale;
- idEntity * ent;
- idEntity * entityList[ MAX_GENTITIES ];
- int numListedEntities;
- idBounds bounds;
- idVec3 v, damagePoint, dir;
- int i, e, damage, radius, push;
- const idDict *damageDef = FindEntityDefDict( damageDefName, false );
- if ( !damageDef ) {
- Warning( "Unknown damageDef '%s'", damageDefName );
- return;
- }
- damageDef->GetInt( "damage", "20", damage );
- damageDef->GetInt( "radius", "50", radius );
- damageDef->GetInt( "push", va( "%d", damage * 100 ), push );
- damageDef->GetFloat( "attackerDamageScale", "0.5", attackerDamageScale );
- damageDef->GetFloat( "attackerPushScale", "0", attackerPushScale );
- if ( radius < 1 ) {
- radius = 1;
- }
- bounds = idBounds( origin ).Expand( radius );
- // get all entities touching the bounds
- numListedEntities = clip.EntitiesTouchingBounds( bounds, -1, entityList, MAX_GENTITIES );
- if ( inflictor && inflictor->IsType( idAFAttachment::Type ) ) {
- inflictor = static_cast<idAFAttachment*>(inflictor)->GetBody();
- }
- if ( attacker && attacker->IsType( idAFAttachment::Type ) ) {
- attacker = static_cast<idAFAttachment*>(attacker)->GetBody();
- }
- if ( ignoreDamage && ignoreDamage->IsType( idAFAttachment::Type ) ) {
- ignoreDamage = static_cast<idAFAttachment*>(ignoreDamage)->GetBody();
- }
- // apply damage to the entities
- for ( e = 0; e < numListedEntities; e++ ) {
- ent = entityList[ e ];
- assert( ent );
- if ( !ent->fl.takedamage ) {
- continue;
- }
- if ( ent == inflictor || ( ent->IsType( idAFAttachment::Type ) && static_cast<idAFAttachment*>(ent)->GetBody() == inflictor ) ) {
- continue;
- }
- if ( ent == ignoreDamage || ( ent->IsType( idAFAttachment::Type ) && static_cast<idAFAttachment*>(ent)->GetBody() == ignoreDamage ) ) {
- continue;
- }
- // don't damage a dead player
- if ( common->IsMultiplayer() && ent->entityNumber < MAX_CLIENTS && ent->IsType( idPlayer::Type ) && static_cast< idPlayer * >( ent )->health < 0 ) {
- continue;
- }
- // find the distance from the edge of the bounding box
- for ( i = 0; i < 3; i++ ) {
- if ( origin[ i ] < ent->GetPhysics()->GetAbsBounds()[0][ i ] ) {
- v[ i ] = ent->GetPhysics()->GetAbsBounds()[0][ i ] - origin[ i ];
- } else if ( origin[ i ] > ent->GetPhysics()->GetAbsBounds()[1][ i ] ) {
- v[ i ] = origin[ i ] - ent->GetPhysics()->GetAbsBounds()[1][ i ];
- } else {
- v[ i ] = 0;
- }
- }
- dist = v.Length();
- if ( dist >= radius ) {
- continue;
- }
- if ( ent->CanDamage( origin, damagePoint ) ) {
- // push the center of mass higher than the origin so players
- // get knocked into the air more
- dir = ent->GetPhysics()->GetOrigin() - origin;
- dir[ 2 ] += 24;
- // get the damage scale
- damageScale = dmgPower * ( 1.0f - dist / radius );
- if ( ent == attacker || ( ent->IsType( idAFAttachment::Type ) && static_cast<idAFAttachment*>(ent)->GetBody() == attacker ) ) {
- damageScale *= attackerDamageScale;
- }
- bool killedBySplash = true;
- if( ent->health <= 0 ) {
- killedBySplash = false;
- }
- ent->Damage( inflictor, attacker, dir, damageDefName, damageScale, INVALID_JOINT );
- // If the player is local. SHAkkkkkkeeee!
- if( !common->IsMultiplayer() && ent->entityNumber == GetLocalClientNum() ) {
- if( ent->IsType( idPlayer::Type ) ) {
- idPlayer * player = static_cast< idPlayer* >( ent );
- if( player ) {
- player->ControllerShakeFromDamage( damage );
- }
- }
- }
- // if our inflictor is a projectile, we want to count up how many kills the splash damage has chalked up.
- if( ent->health <= 0 && killedBySplash ) {
- if( inflictor && inflictor->IsType( idProjectile::Type ) ) {
- if ( attacker && attacker->IsType( idPlayer::Type ) ) {
- if ( ent->IsType( idActor::Type ) && ent != attacker ) {
- idPlayer *player = static_cast<idPlayer *>( attacker );
- player->AddProjectileKills();
- }
- }
- }
- }
- }
- }
- // push physics objects
- if ( push ) {
- RadiusPush( origin, radius, push * dmgPower, attacker, ignorePush, attackerPushScale, false );
- }
- }
- /*
- ==============
- idGameLocal::RadiusPush
- ==============
- */
- void idGameLocal::RadiusPush( const idVec3 &origin, const float radius, const float push, const idEntity *inflictor, const idEntity *ignore, float inflictorScale, const bool quake ) {
- int i, numListedClipModels;
- idClipModel *clipModel;
- idClipModel *clipModelList[ MAX_GENTITIES ];
- idVec3 dir;
- idBounds bounds;
- modelTrace_t result;
- idEntity *ent;
- float scale;
- dir.Set( 0.0f, 0.0f, 1.0f );
- bounds = idBounds( origin ).Expand( radius );
- // get all clip models touching the bounds
- numListedClipModels = clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES );
- if ( inflictor && inflictor->IsType( idAFAttachment::Type ) ) {
- inflictor = static_cast<const idAFAttachment*>(inflictor)->GetBody();
- }
- if ( ignore && ignore->IsType( idAFAttachment::Type ) ) {
- ignore = static_cast<const idAFAttachment*>(ignore)->GetBody();
- }
- // apply impact to all the clip models through their associated physics objects
- for ( i = 0; i < numListedClipModels; i++ ) {
- clipModel = clipModelList[i];
- // never push render models
- if ( clipModel->IsRenderModel() ) {
- continue;
- }
- ent = clipModel->GetEntity();
- // never push projectiles
- if ( ent->IsType( idProjectile::Type ) ) {
- continue;
- }
- // players use "knockback" in idPlayer::Damage
- if ( ent->IsType( idPlayer::Type ) && !quake ) {
- continue;
- }
- // don't push the ignore entity
- if ( ent == ignore || ( ent->IsType( idAFAttachment::Type ) && static_cast<idAFAttachment*>(ent)->GetBody() == ignore ) ) {
- continue;
- }
- if ( gameRenderWorld->FastWorldTrace( result, origin, clipModel->GetOrigin() ) ) {
- continue;
- }
- // scale the push for the inflictor
- if ( ent == inflictor || ( ent->IsType( idAFAttachment::Type ) && static_cast<idAFAttachment*>(ent)->GetBody() == inflictor ) ) {
- scale = inflictorScale;
- } else {
- scale = 1.0f;
- }
- if ( quake ) {
- clipModel->GetEntity()->ApplyImpulse( world, clipModel->GetId(), clipModel->GetOrigin(), scale * push * dir );
- } else {
- RadiusPushClipModel( origin, scale * push, clipModel );
- }
- }
- }
- /*
- ==============
- idGameLocal::RadiusPushClipModel
- ==============
- */
- void idGameLocal::RadiusPushClipModel( const idVec3 &origin, const float push, const idClipModel *clipModel ) {
- int i, j;
- float dot, dist, area;
- const idTraceModel *trm;
- const traceModelPoly_t *poly;
- idFixedWinding w;
- idVec3 v, localOrigin, center, impulse;
- trm = clipModel->GetTraceModel();
- if ( !trm || 1 ) {
- impulse = clipModel->GetAbsBounds().GetCenter() - origin;
- impulse.Normalize();
- impulse.z += 1.0f;
- clipModel->GetEntity()->ApplyImpulse( world, clipModel->GetId(), clipModel->GetOrigin(), push * impulse );
- return;
- }
- localOrigin = ( origin - clipModel->GetOrigin() ) * clipModel->GetAxis().Transpose();
- for ( i = 0; i < trm->numPolys; i++ ) {
- poly = &trm->polys[i];
- center.Zero();
- for ( j = 0; j < poly->numEdges; j++ ) {
- v = trm->verts[ trm->edges[ abs(poly->edges[j]) ].v[ INT32_SIGNBITSET( poly->edges[j] ) ] ];
- center += v;
- v -= localOrigin;
- v.NormalizeFast(); // project point on a unit sphere
- w.AddPoint( v );
- }
- center /= poly->numEdges;
- v = center - localOrigin;
- dist = v.NormalizeFast();
- dot = v * poly->normal;
- if ( dot > 0.0f ) {
- continue;
- }
- area = w.GetArea();
- // impulse in polygon normal direction
- impulse = poly->normal * clipModel->GetAxis();
- // always push up for nicer effect
- impulse.z -= 1.0f;
- // scale impulse based on visible surface area and polygon angle
- impulse *= push * ( dot * area * ( 1.0f / ( 4.0f * idMath::PI ) ) );
- // scale away distance for nicer effect
- impulse *= ( dist * 2.0f );
- // impulse is applied to the center of the polygon
- center = clipModel->GetOrigin() + center * clipModel->GetAxis();
- clipModel->GetEntity()->ApplyImpulse( world, clipModel->GetId(), center, impulse );
- }
- }
- /*
- ===============
- idGameLocal::ProjectDecal
- ===============
- */
- void idGameLocal::ProjectDecal( const idVec3 &origin, const idVec3 &dir, float depth, bool parallel, float size, const char *material, float angle ) {
- float s, c;
- idMat3 axis, axistemp;
- idFixedWinding winding;
- idVec3 windingOrigin, projectionOrigin;
- static idVec3 decalWinding[4] = {
- idVec3( 1.0f, 1.0f, 0.0f ),
- idVec3( -1.0f, 1.0f, 0.0f ),
- idVec3( -1.0f, -1.0f, 0.0f ),
- idVec3( 1.0f, -1.0f, 0.0f )
- };
- if ( !g_decals.GetBool() ) {
- return;
- }
- // randomly rotate the decal winding
- idMath::SinCos16( ( angle ) ? angle : random.RandomFloat() * idMath::TWO_PI, s, c );
- // winding orientation
- axis[2] = dir;
- axis[2].Normalize();
- axis[2].NormalVectors( axistemp[0], axistemp[1] );
- axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s;
- axis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c;
- windingOrigin = origin + depth * axis[2];
- if ( parallel ) {
- projectionOrigin = origin - depth * axis[2];
- } else {
- projectionOrigin = origin;
- }
- size *= 0.5f;
- winding.Clear();
- winding += idVec5( windingOrigin + ( axis * decalWinding[0] ) * size, idVec2( 1, 1 ) );
- winding += idVec5( windingOrigin + ( axis * decalWinding[1] ) * size, idVec2( 0, 1 ) );
- winding += idVec5( windingOrigin + ( axis * decalWinding[2] ) * size, idVec2( 0, 0 ) );
- winding += idVec5( windingOrigin + ( axis * decalWinding[3] ) * size, idVec2( 1, 0 ) );
- gameRenderWorld->ProjectDecalOntoWorld( winding, projectionOrigin, parallel, depth * 0.5f, declManager->FindMaterial( material ), gameLocal.slow.time /* _D3XP */ );
- }
- /*
- ==============
- idGameLocal::BloodSplat
- ==============
- */
- void idGameLocal::BloodSplat( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) {
- float halfSize = size * 0.5f;
- idVec3 verts[] = { idVec3( 0.0f, +halfSize, +halfSize ),
- idVec3( 0.0f, +halfSize, -halfSize ),
- idVec3( 0.0f, -halfSize, -halfSize ),
- idVec3( 0.0f, -halfSize, +halfSize ) };
- idTraceModel trm;
- idClipModel mdl;
- trace_t results;
- // FIXME: get from damage def
- if ( !g_bloodEffects.GetBool() ) {
- return;
- }
- size = halfSize + random.RandomFloat() * halfSize;
- trm.SetupPolygon( verts, 4 );
- mdl.LoadModel( trm );
- clip.Translation( results, origin, origin + dir * 64.0f, &mdl, mat3_identity, CONTENTS_SOLID, NULL );
- ProjectDecal( results.endpos, dir, 2.0f * size, true, size, material );
- }
- /*
- =============
- idGameLocal::SetCamera
- =============
- */
- void idGameLocal::SetCamera( idCamera *cam ) {
- int i;
- idEntity *ent;
- idAI *ai;
- // this should fix going into a cinematic when dead.. rare but happens
- idPlayer *client = GetLocalPlayer();
- if ( client->health <= 0 || client->AI_DEAD ) {
- return;
- }
- camera = cam;
- if ( camera ) {
- inCinematic = true;
- // set r_znear so that transitioning into/out of the player's head doesn't clip through the view
- cvarSystem->SetCVarFloat( "r_znear", 1.0f );
-
- // hide all the player models
- for( i = 0; i < numClients; i++ ) {
- if ( entities[ i ] ) {
- client = static_cast< idPlayer* >( entities[ i ] );
- client->EnterCinematic();
- }
- }
- if ( !cam->spawnArgs.GetBool( "ignore_enemies" ) ) {
- // kill any active monsters that are enemies of the player
- for ( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
- if ( ent->cinematic || ent->fl.isDormant ) {
- // only kill entities that aren't needed for cinematics and aren't dormant
- continue;
- }
-
- if ( ent->IsType( idAI::Type ) ) {
- ai = static_cast<idAI *>( ent );
- if ( !ai->GetEnemy() || !ai->IsActive() ) {
- // no enemy, or inactive, so probably safe to ignore
- continue;
- }
- } else if ( ent->IsType( idProjectile::Type ) ) {
- // remove all projectiles
- } else if ( ent->spawnArgs.GetBool( "cinematic_remove" ) ) {
- // remove anything marked to be removed during cinematics
- } else {
- // ignore everything else
- continue;
- }
- // remove it
- DPrintf( "removing '%s' for cinematic\n", ent->GetName() );
- ent->PostEventMS( &EV_Remove, 0 );
- }
- }
- } else {
- inCinematic = false;
- // restore r_znear
- cvarSystem->SetCVarFloat( "r_znear", 3.0f );
- // show all the player models
- for( i = 0; i < numClients; i++ ) {
- if ( entities[ i ] ) {
- idPlayer *client = static_cast< idPlayer* >( entities[ i ] );
- client->ExitCinematic();
- }
- }
- }
- }
- /*
- =============
- idGameLocal::GetCamera
- =============
- */
- idCamera *idGameLocal::GetCamera() const {
- return camera;
- }
- /*
- ======================
- idGameLocal::SpreadLocations
- Now that everything has been spawned, associate areas with location entities
- ======================
- */
- void idGameLocal::SpreadLocations() {
- idEntity *ent;
- // allocate the area table
- int numAreas = gameRenderWorld->NumAreas();
- locationEntities = new (TAG_GAME) idLocationEntity *[ numAreas ];
- memset( locationEntities, 0, numAreas * sizeof( *locationEntities ) );
- // for each location entity, make pointers from every area it touches
- for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
- if ( !ent->IsType( idLocationEntity::Type ) ) {
- continue;
- }
- idVec3 point = ent->spawnArgs.GetVector( "origin" );
- int areaNum = gameRenderWorld->PointInArea( point );
- if ( areaNum < 0 ) {
- Printf( "SpreadLocations: location '%s' is not in a valid area\n", ent->spawnArgs.GetString( "name" ) );
- continue;
- }
- if ( areaNum >= numAreas ) {
- Error( "idGameLocal::SpreadLocations: areaNum >= gameRenderWorld->NumAreas()" );
- }
- if ( locationEntities[areaNum] ) {
- Warning( "location entity '%s' overlaps '%s'", ent->spawnArgs.GetString( "name" ),
- locationEntities[areaNum]->spawnArgs.GetString( "name" ) );
- continue;
- }
- locationEntities[areaNum] = static_cast<idLocationEntity *>(ent);
- // spread to all other connected areas
- for ( int i = 0 ; i < numAreas ; i++ ) {
- if ( i == areaNum ) {
- continue;
- }
- if ( gameRenderWorld->AreasAreConnected( areaNum, i, PS_BLOCK_LOCATION ) ) {
- locationEntities[i] = static_cast<idLocationEntity *>(ent);
- }
- }
- }
- }
- /*
- ===================
- idGameLocal::LocationForPoint
- The player checks the location each frame to update the HUD text display
- May return NULL
- ===================
- */
- idLocationEntity *idGameLocal::LocationForPoint( const idVec3 &point ) {
- if ( !locationEntities ) {
- // before SpreadLocations() has been called
- return NULL;
- }
- int areaNum = gameRenderWorld->PointInArea( point );
- if ( areaNum < 0 ) {
- return NULL;
- }
- if ( areaNum >= gameRenderWorld->NumAreas() ) {
- Error( "idGameLocal::LocationForPoint: areaNum >= gameRenderWorld->NumAreas()" );
- }
- return locationEntities[ areaNum ];
- }
- /*
- ============
- idGameLocal::SetPortalState
- ============
- */
- void idGameLocal::SetPortalState( qhandle_t portal, int blockingBits ) {
- gameRenderWorld->SetPortalState( portal, blockingBits );
- }
- /*
- ============
- idGameLocal::sortSpawnPoints
- ============
- */
- int idGameLocal::sortSpawnPoints( const void *ptr1, const void *ptr2 ) {
- const spawnSpot_t *spot1 = static_cast<const spawnSpot_t *>( ptr1 );
- const spawnSpot_t *spot2 = static_cast<const spawnSpot_t *>( ptr2 );
- float diff;
- diff = spot1->dist - spot2->dist;
- if ( diff < 0.0f ) {
- return 1;
- } else if ( diff > 0.0f ) {
- return -1;
- } else {
- return 0;
- }
- }
- /*
- ===========
- idGameLocal::RandomizeInitialSpawns
- randomize the order of the initial spawns
- prepare for a sequence of initial player spawns
- ============
- */
- void idGameLocal::RandomizeInitialSpawns() {
- spawnSpot_t spot;
- int i, j;
- int k;
-
- idEntity *ent;
- if ( !common->IsServer() ) {
- return;
- }
- spawnSpots.Clear();
- initialSpots.Clear();
- teamSpawnSpots[0].Clear();
- teamSpawnSpots[1].Clear();
- teamInitialSpots[0].Clear();
- teamInitialSpots[1].Clear();
-
- spot.dist = 0;
- spot.ent = FindEntityUsingDef( NULL, "info_player_deathmatch" );
- while( spot.ent ) {
- spot.ent->spawnArgs.GetInt( "team", "-1", spot.team );
- if ( mpGame.IsGametypeFlagBased() ) /* CTF */
- {
- if ( spot.team == 0 || spot.team == 1 )
- teamSpawnSpots[spot.team].Append( spot );
- else
- common->Warning( "info_player_deathmatch : invalid or no team attached to spawn point\n");
- }
- spawnSpots.Append( spot );
- if ( spot.ent->spawnArgs.GetBool( "initial" ) ) {
- if ( mpGame.IsGametypeFlagBased() ) /* CTF */
- {
- assert( spot.team == 0 || spot.team == 1 );
- teamInitialSpots[ spot.team ].Append( spot.ent );
- }
-
- initialSpots.Append( spot.ent );
- }
- spot.ent = FindEntityUsingDef( spot.ent, "info_player_deathmatch" );
- }
- if ( mpGame.IsGametypeFlagBased() ) { /* CTF */
- if ( !teamSpawnSpots[0].Num() )
- common->Warning( "red team : no info_player_deathmatch in map" );
- if ( !teamSpawnSpots[1].Num() )
- common->Warning( "blue team : no info_player_deathmatch in map" );
- if ( !teamSpawnSpots[0].Num() || !teamSpawnSpots[1].Num() )
- return;
- }
-
- if ( !spawnSpots.Num() ) {
- common->Warning( "no info_player_deathmatch in map" );
- return;
- }
- if ( mpGame.IsGametypeFlagBased() ) { /* CTF */
- common->Printf( "red team : %d spawns (%d initials)\n", teamSpawnSpots[ 0 ].Num(), teamInitialSpots[ 0 ].Num() );
- // if there are no initial spots in the map, consider they can all be used as initial
- if ( !teamInitialSpots[ 0 ].Num() ) {
- common->Warning( "red team : no info_player_deathmatch entities marked initial in map" );
- for ( i = 0; i < teamSpawnSpots[ 0 ].Num(); i++ ) {
- teamInitialSpots[ 0 ].Append( teamSpawnSpots[ 0 ][ i ].ent );
- }
- }
- common->Printf( "blue team : %d spawns (%d initials)\n", teamSpawnSpots[ 1 ].Num(), teamInitialSpots[ 1 ].Num() );
- // if there are no initial spots in the map, consider they can all be used as initial
- if ( !teamInitialSpots[ 1 ].Num() ) {
- common->Warning( "blue team : no info_player_deathmatch entities marked initial in map" );
- for ( i = 0; i < teamSpawnSpots[ 1 ].Num(); i++ ) {
- teamInitialSpots[ 1 ].Append( teamSpawnSpots[ 1 ][ i ].ent );
- }
- }
- }
-
- common->Printf( "%d spawns (%d initials)\n", spawnSpots.Num(), initialSpots.Num() );
- // if there are no initial spots in the map, consider they can all be used as initial
- if ( !initialSpots.Num() ) {
- common->Warning( "no info_player_deathmatch entities marked initial in map" );
- for ( i = 0; i < spawnSpots.Num(); i++ ) {
- initialSpots.Append( spawnSpots[ i ].ent );
- }
- }
- for ( k = 0; k < 2; k++ ) {
- for ( i = 0; i < teamInitialSpots[ k ].Num(); i++ ) {
- j = random.RandomInt( teamInitialSpots[ k ].Num() );
- ent = teamInitialSpots[ k ][ i ];
- teamInitialSpots[ k ][ i ] = teamInitialSpots[ k ][ j ];
- teamInitialSpots[ k ][ j ] = ent;
- }
- }
-
- for ( i = 0; i < initialSpots.Num(); i++ ) {
- j = random.RandomInt( initialSpots.Num() );
- ent = initialSpots[ i ];
- initialSpots[ i ] = initialSpots[ j ];
- initialSpots[ j ] = ent;
- }
- // reset the counter
- currentInitialSpot = 0;
- teamCurrentInitialSpot[0] = 0;
- teamCurrentInitialSpot[1] = 0;
- }
- /*
- ===========
- idGameLocal::SelectInitialSpawnPoint
- spectators are spawned randomly anywhere
- in-game clients are spawned based on distance to active players (randomized on the first half)
- upon map restart, initial spawns are used (randomized ordered list of spawns flagged "initial")
- if there are more players than initial spots, overflow to regular spawning
- ============
- */
- idEntity *idGameLocal::SelectInitialSpawnPoint( idPlayer *player ) {
- int i, j, which;
- spawnSpot_t spot;
- idVec3 pos;
- float dist;
- bool alone;
- if ( !common->IsMultiplayer() || !spawnSpots.Num() || ( mpGame.IsGametypeFlagBased() && ( !teamSpawnSpots[0].Num() || !teamSpawnSpots[1].Num() ) ) ) { /* CTF */
- spot.ent = FindEntityUsingDef( NULL, "info_player_start" );
- if ( !spot.ent ) {
- Error( "No info_player_start on map.\n" );
- }
- return spot.ent;
- }
- bool useInitialSpots = false;
- if ( mpGame.IsGametypeFlagBased() ) { /* CTF */
- assert( player->team == 0 || player->team == 1 );
- useInitialSpots = player->useInitialSpawns && teamCurrentInitialSpot[ player->team ] < teamInitialSpots[ player->team ].Num();
- } else {
- useInitialSpots = player->useInitialSpawns && currentInitialSpot < initialSpots.Num();
- }
-
- if ( player->spectating ) {
- // plain random spot, don't bother
- return spawnSpots[ random.RandomInt( spawnSpots.Num() ) ].ent;
- } else if ( useInitialSpots ) {
- if ( mpGame.IsGametypeFlagBased() ) { /* CTF */
- assert( player->team == 0 || player->team == 1 );
- player->useInitialSpawns = false; // only use the initial spawn once
- return teamInitialSpots[ player->team ][ teamCurrentInitialSpot[ player->team ]++ ];
- }
- return initialSpots[ currentInitialSpot++ ];
- } else {
- // check if we are alone in map
- alone = true;
- for ( j = 0; j < MAX_CLIENTS; j++ ) {
- if ( entities[ j ] && entities[ j ] != player ) {
- alone = false;
- break;
- }
- }
- if ( alone ) {
- if ( mpGame.IsGametypeFlagBased() ) { /* CTF */
- assert( player->team == 0 || player->team == 1 );
- return teamSpawnSpots[ player->team ][ random.RandomInt( teamSpawnSpots[ player->team ].Num() ) ].ent;
- }
- // don't do distance-based
- return spawnSpots[ random.RandomInt( spawnSpots.Num() ) ].ent;
- }
- if ( mpGame.IsGametypeFlagBased() ) { /* CTF */
- // TODO : make as reusable method, same code as below
- int team = player->team;
- assert( team == 0 || team == 1 );
- // find the distance to the closest active player for each spawn spot
- for ( i = 0; i < teamSpawnSpots[ team ].Num(); i++ ) {
- pos = teamSpawnSpots[ team ][ i ].ent->GetPhysics()->GetOrigin();
- // skip initial spawn points for CTF
- if ( teamSpawnSpots[ team ][ i ].ent->spawnArgs.GetBool("initial") ) {
- teamSpawnSpots[ team ][ i ].dist = 0x0;
- continue;
- }
- teamSpawnSpots[ team ][ i ].dist = 0x7fffffff;
- for( j = 0; j < MAX_CLIENTS; j++ ) {
- if ( !entities[ j ] || !entities[ j ]->IsType( idPlayer::Type )
- || entities[ j ] == player
- || static_cast< idPlayer * >( entities[ j ] )->spectating ) {
- continue;
- }
-
- dist = ( pos - entities[ j ]->GetPhysics()->GetOrigin() ).LengthSqr();
- if ( dist < teamSpawnSpots[ team ][ i ].dist ) {
- teamSpawnSpots[ team ][ i ].dist = dist;
- }
- }
- }
- // sort the list
- qsort( ( void * )teamSpawnSpots[ team ].Ptr(), teamSpawnSpots[ team ].Num(), sizeof( spawnSpot_t ), ( int (*)(const void *, const void *) )sortSpawnPoints );
- // choose a random one in the top half
- which = random.RandomInt( teamSpawnSpots[ team ].Num() / 2 );
- spot = teamSpawnSpots[ team ][ which ];
- // assert( teamSpawnSpots[ team ][ which ].dist != 0 );
- return spot.ent;
- }
-
- // find the distance to the closest active player for each spawn spot
- for( i = 0; i < spawnSpots.Num(); i++ ) {
- pos = spawnSpots[ i ].ent->GetPhysics()->GetOrigin();
- spawnSpots[ i ].dist = 0x7fffffff;
- for( j = 0; j < MAX_CLIENTS; j++ ) {
- if ( !entities[ j ] || !entities[ j ]->IsType( idPlayer::Type )
- || entities[ j ] == player
- || static_cast< idPlayer * >( entities[ j ] )->spectating ) {
- continue;
- }
-
- dist = ( pos - entities[ j ]->GetPhysics()->GetOrigin() ).LengthSqr();
- if ( dist < spawnSpots[ i ].dist ) {
- spawnSpots[ i ].dist = dist;
- }
- }
- }
- // sort the list
- qsort( ( void * )spawnSpots.Ptr(), spawnSpots.Num(), sizeof( spawnSpot_t ), ( int (*)(const void *, const void *) )sortSpawnPoints );
- // choose a random one in the top half
- which = random.RandomInt( spawnSpots.Num() / 2 );
- spot = spawnSpots[ which ];
- }
- return spot.ent;
- }
- /*
- ================
- idGameLocal::SetGlobalMaterial
- ================
- */
- void idGameLocal::SetGlobalMaterial( const idMaterial *mat ) {
- globalMaterial = mat;
- }
- /*
- ================
- idGameLocal::GetGlobalMaterial
- ================
- */
- const idMaterial *idGameLocal::GetGlobalMaterial() {
- return globalMaterial;
- }
- /*
- ================
- idGameLocal::GetSpawnId
- ================
- */
- int idGameLocal::GetSpawnId( const idEntity* ent ) const {
- return ( gameLocal.spawnIds[ ent->entityNumber ] << GENTITYNUM_BITS ) | ent->entityNumber;
- }
- /*
- =================
- idPlayer::SetPortalSkyEnt
- =================
- */
- void idGameLocal::SetPortalSkyEnt( idEntity *ent ) {
- portalSkyEnt = ent;
- }
- /*
- =================
- idPlayer::IsPortalSkyAcive
- =================
- */
- bool idGameLocal::IsPortalSkyAcive() {
- return portalSkyActive;
- }
- /*
- ===========
- idGameLocal::SelectTimeGroup
- ============
- */
- void idGameLocal::SelectTimeGroup( int timeGroup ) {
- if ( timeGroup ) {
- fast.Get( time, previousTime, realClientTime );
- } else {
- slow.Get( time, previousTime, realClientTime );
- }
- selectedGroup = timeGroup;
- }
- /*
- ===========
- idGameLocal::GetTimeGroupTime
- ============
- */
- int idGameLocal::GetTimeGroupTime( int timeGroup ) {
- if ( timeGroup ) {
- return fast.time;
- } else {
- return slow.time;
- }
- }
- /*
- ===========
- idGameLocal::ComputeSlowScale
- ============
- */
- void idGameLocal::ComputeSlowScale() {
- // check if we need to do a quick reset
- if ( quickSlowmoReset ) {
- quickSlowmoReset = false;
- // stop the sounds
- if ( gameSoundWorld ) {
- gameSoundWorld->SetSlowmoSpeed( 1.0f );
- }
- // stop the state
- slowmoState = SLOWMO_STATE_OFF;
- slowmoScale = 1.0f;
- }
- // check the player state
- idPlayer * player = GetLocalPlayer();
- bool powerupOn = false;
- if ( player != NULL && player->PowerUpActive( HELLTIME ) ) {
- powerupOn = true;
- }
- else if ( g_enableSlowmo.GetBool() ) {
- powerupOn = true;
- }
- // determine proper slowmo state
- if ( powerupOn && slowmoState == SLOWMO_STATE_OFF ) {
- slowmoState = SLOWMO_STATE_RAMPUP;
- if ( gameSoundWorld ) {
- gameSoundWorld->SetSlowmoSpeed( slowmoScale );
- }
- }
- else if ( !powerupOn && slowmoState == SLOWMO_STATE_ON ) {
- slowmoState = SLOWMO_STATE_RAMPDOWN;
- // play the stop sound
- if ( player != NULL ) {
- player->PlayHelltimeStopSound();
- }
- }
- // do any necessary ramping
- if ( slowmoState == SLOWMO_STATE_RAMPUP ) {
- float delta = ( 0.25f - slowmoScale );
- if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) {
- slowmoScale = 0.25f;
- slowmoState = SLOWMO_STATE_ON;
- } else {
- slowmoScale += delta * g_slowmoStepRate.GetFloat();
- }
- if ( gameSoundWorld != NULL ) {
- gameSoundWorld->SetSlowmoSpeed( slowmoScale );
- }
- }
- else if ( slowmoState == SLOWMO_STATE_RAMPDOWN ) {
- float delta = ( 1.0f - slowmoScale );
- if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) {
- slowmoScale = 1.0f;
- slowmoState = SLOWMO_STATE_OFF;
- } else {
- slowmoScale += delta * g_slowmoStepRate.GetFloat();
- }
- if ( gameSoundWorld != NULL ) {
- gameSoundWorld->SetSlowmoSpeed( slowmoScale );
- }
- }
- }
- /*
- ===========
- idGameLocal::ResetSlowTimeVars
- ============
- */
- void idGameLocal::ResetSlowTimeVars() {
- slowmoScale = 1.0f;
- slowmoState = SLOWMO_STATE_OFF;
- fast.previousTime = 0;
- fast.time = 0;
- slow.previousTime = 0;
- slow.time = 0;
- }
- /*
- ===========
- idGameLocal::QuickSlowmoReset
- ============
- */
- void idGameLocal::QuickSlowmoReset() {
- quickSlowmoReset = true;
- }
- /*
- ================
- idGameLocal::GetClientStats
- ================
- */
- void idGameLocal::GetClientStats( int clientNum, char *data, const int len ) {
- mpGame.PlayerStats( clientNum, data, len );
- }
- /*
- ================
- idGameLocal::GetMPGameModes
- ================
- */
- int idGameLocal::GetMPGameModes( const char *** gameModes, const char *** gameModesDisplay ) {
- return mpGame.GetGameModes( gameModes, gameModesDisplay );
- }
- /*
- ========================
- idGameLocal::IsPDAOpen
- ========================
- */
- bool idGameLocal::IsPDAOpen() const {
- return GetLocalPlayer() && GetLocalPlayer()->objectiveSystemOpen;
- }
- /*
- ========================
- idGameLocal::IsPlayerChatting
- ========================
- */
- bool idGameLocal::IsPlayerChatting() const {
- return GetLocalPlayer() && ( GetLocalPlayer()->isChatting > 0 ) && !GetLocalPlayer()->spectating;
- }
- /*
- ========================
- idGameLocal::InhibitControls
- ========================
- */
- bool idGameLocal::InhibitControls() {
- return ( Shell_IsActive() || IsPDAOpen() || IsPlayerChatting() || ( common->IsMultiplayer() && mpGame.IsScoreboardActive() ) );
- }
- /*
- ===============================
- idGameLocal::Leaderboards_Init
- ===============================
- */
- void idGameLocal::Leaderboards_Init() {
- LeaderboardLocal_Init();
- }
- /*
- ===============================
- idGameLocal::Leaderboards_Shutdown
- ===============================
- */
- void idGameLocal::Leaderboards_Shutdown() {
- LeaderboardLocal_Shutdown();
- }
- /*
- ========================
- idGameLocal::Shell_ClearRepeater
- ========================
- */
- void idGameLocal::Shell_ClearRepeater() {
- if ( shellHandler != NULL ) {
- shellHandler->ClearWidgetActionRepeater();
- }
- }
- /*
- ========================
- idGameLocal::Shell_Init
- ========================
- */
- void idGameLocal::Shell_Init( const char * filename, idSoundWorld * sw ) {
- if ( shellHandler != NULL ) {
- shellHandler->Initialize( filename, sw );
- }
- }
- /*
- ========================
- idGameLocal::Shell_Init
- ========================
- */
- void idGameLocal::Shell_Cleanup() {
- if ( shellHandler != NULL ) {
- delete shellHandler;
- shellHandler = NULL;
- }
- mpGame.CleanupScoreboard();
- }
- /*
- ========================
- idGameLocal::Shell_CreateMenu
- ========================
- */
- void idGameLocal::Shell_CreateMenu( bool inGame ) {
- Shell_ResetMenu();
- if ( shellHandler != NULL ) {
- if ( !inGame ) {
- shellHandler->SetInGame( false );
- Shell_Init( "shell", common->MenuSW() );
- } else {
- shellHandler->SetInGame( true );
- if ( common->IsMultiplayer() ) {
- Shell_Init( "pause", common->SW() );
- } else {
- Shell_Init( "pause", common->MenuSW() );
- }
- }
- }
- }
- /*
- ========================
- idGameLocal::Shell_ClosePause
- ========================
- */
- void idGameLocal::Shell_ClosePause() {
- if ( shellHandler != NULL ) {
- if ( !common->IsMultiplayer() && GetLocalPlayer() && GetLocalPlayer()->health <= 0 ) {
- return;
- }
- if ( shellHandler->GetGameComplete() ) {
- return;
- }
- shellHandler->SetNextScreen( SHELL_AREA_INVALID, MENU_TRANSITION_SIMPLE );
- }
- }
- /*
- ========================
- idGameLocal::Shell_Show
- ========================
- */
- void idGameLocal::Shell_Show( bool show ) {
- if ( shellHandler != NULL ) {
- shellHandler->ActivateMenu( show );
- }
- }
- /*
- ========================
- idGameLocal::Shell_IsActive
- ========================
- */
- bool idGameLocal::Shell_IsActive() const {
- if ( shellHandler != NULL ) {
- return shellHandler->IsActive();
- }
- return false;
- }
- /*
- ========================
- idGameLocal::Shell_HandleGuiEvent
- ========================
- */
- bool idGameLocal::Shell_HandleGuiEvent( const sysEvent_t * sev ) {
- if ( shellHandler != NULL ) {
- return shellHandler->HandleGuiEvent( sev );
- }
- return false;
- }
- /*
- ========================
- idGameLocal::Shell_Render
- ========================
- */
- void idGameLocal::Shell_Render() {
- if ( shellHandler != NULL ) {
- shellHandler->Update();
- }
- }
- /*
- ========================
- idGameLocal::Shell_ResetMenu
- ========================
- */
- void idGameLocal::Shell_ResetMenu() {
- if ( shellHandler != NULL ) {
- delete shellHandler;
- shellHandler = new (TAG_SWF) idMenuHandler_Shell();
- }
- }
- /*
- =================
- idGameLocal::Shell_SyncWithSession
- =================
- */
- void idGameLocal::Shell_SyncWithSession() {
- if ( shellHandler == NULL ) {
- return;
- }
- switch ( session->GetState() ) {
- case idSession::PRESS_START:
- shellHandler->SetShellState( SHELL_STATE_PRESS_START );
- break;
- case idSession::INGAME:
- shellHandler->SetShellState( SHELL_STATE_PAUSED );
- break;
- case idSession::IDLE:
- shellHandler->SetShellState( SHELL_STATE_IDLE );
- break;
- case idSession::PARTY_LOBBY:
- shellHandler->SetShellState( SHELL_STATE_PARTY_LOBBY );
- break;
- case idSession::GAME_LOBBY:
- shellHandler->SetShellState( SHELL_STATE_GAME_LOBBY );
- break;
- case idSession::SEARCHING:
- shellHandler->SetShellState( SHELL_STATE_SEARCHING );
- break;
- case idSession::LOADING:
- shellHandler->SetShellState( SHELL_STATE_LOADING );
- break;
- case idSession::CONNECTING:
- shellHandler->SetShellState( SHELL_STATE_CONNECTING );
- break;
- case idSession::BUSY:
- shellHandler->SetShellState( SHELL_STATE_BUSY );
- break;
- }
- }
- void idGameLocal::Shell_SetGameComplete() {
- if ( shellHandler != NULL ) {
- shellHandler->SetGameComplete();
- Shell_Show( true );
- }
- }
- /*
- ========================
- idGameLocal::Shell_SetState_GameLobby
- ========================
- */
- void idGameLocal::Shell_UpdateSavedGames() {
- if ( shellHandler != NULL ) {
- shellHandler->UpdateSavedGames();
- }
- }
- /*
- ========================
- idGameLocal::Shell_SetCanContinue
- ========================
- */
- void idGameLocal::Shell_SetCanContinue( bool valid ) {
- if ( shellHandler != NULL ) {
- shellHandler->SetCanContinue( valid );
- }
- }
- /*
- ========================
- idGameLocal::Shell_SetState_GameLobby
- ========================
- */
- void idGameLocal::Shell_UpdateClientCountdown( int countdown ) {
- if ( shellHandler != NULL ) {
- shellHandler->SetTimeRemaining( countdown );
- }
- }
- /*
- ========================
- idGameLocal::Shell_SetState_GameLobby
- ========================
- */
- void idGameLocal::Shell_UpdateLeaderboard( const idLeaderboardCallback * callback ) {
- if ( shellHandler != NULL ) {
- shellHandler->UpdateLeaderboard( callback );
- }
- }
- /*
- ========================
- idGameLocal::SimulateProjectiles
- ========================
- */
- bool idGameLocal::SimulateProjectiles() {
- bool moreProjectiles = false;
- // Simulate projectiles
- for ( int i = 0; i < idProjectile::MAX_SIMULATED_PROJECTILES; i++ ) {
- if ( idProjectile::projectilesToSimulate[i].projectile != NULL && idProjectile::projectilesToSimulate[i].startTime != 0 ) {
- const int startTime = idProjectile::projectilesToSimulate[i].startTime;
- const int startFrame = MSEC_TO_FRAME_FLOOR( startTime );
- const int endFrame = startFrame + 1;
- const int endTime = FRAME_TO_MSEC( endFrame );
- idProjectile::projectilesToSimulate[i].projectile->SimulateProjectileFrame( endTime - startTime, endTime );
-
- if ( idProjectile::projectilesToSimulate[i].projectile != NULL ) {
- if ( endTime >= previousServerTime ) {
- idProjectile::projectilesToSimulate[i].projectile->PostSimulate( endTime );
- idProjectile::projectilesToSimulate[i].startTime = 0;
- idProjectile::projectilesToSimulate[i].projectile = NULL;
- } else {
- idProjectile::projectilesToSimulate[i].startTime = endTime;
- moreProjectiles = true;
- }
- }
- }
- }
-
- return moreProjectiles;
- }
|