g_main.cpp 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301
  1. // leave this line at the top for all g_xxxx.cpp files...
  2. #include "g_headers.h"
  3. #include <xtl.h>
  4. #include "g_local.h"
  5. #include "g_functions.h"
  6. #include "Q3_Interface.h"
  7. #include "g_nav.h"
  8. #include "g_roff.h"
  9. #include "g_navigator.h"
  10. #include "b_local.h"
  11. #include "anims.h"
  12. #include "objectives.h"
  13. #include "../cgame/cg_local.h" // yeah I know this is naughty, but we're shipping soon...
  14. //rww - RAGDOLL_BEGIN
  15. #include "../ghoul2/ghoul2_gore.h"
  16. //rww - RAGDOLL_END
  17. extern void WP_SaberLoadParms( void );
  18. extern qboolean G_PlayerSpawned( void );
  19. extern void Rail_Initialize( void );
  20. extern void Rail_Update( void );
  21. extern void Rail_Reset(void);
  22. extern void Troop_Initialize( void );
  23. extern void Troop_Update( void );
  24. extern void Troop_Reset(void);
  25. extern void Pilot_Reset(void);
  26. extern void Pilot_Update(void);
  27. extern void G_ASPreCacheFree(void);
  28. static int navCalcPathTime = 0;
  29. int eventClearTime = 0;
  30. extern qboolean g_bCollidableRoffs;
  31. #define STEPSIZE 18
  32. level_locals_t level;
  33. game_import_t gi;
  34. game_export_t globals;
  35. //gentity_t g_entities[MAX_GENTITIES];
  36. gentity_t *g_entities = NULL;
  37. unsigned int g_entityInUseBits[MAX_GENTITIES/32];
  38. static void ClearAllInUse(void)
  39. {
  40. memset(g_entityInUseBits,0,sizeof(g_entityInUseBits));
  41. }
  42. void SetInUse(gentity_t *ent)
  43. {
  44. assert(((unsigned int)ent)>=(unsigned int)g_entities);
  45. assert(((unsigned int)ent)<=(unsigned int)(g_entities+MAX_GENTITIES-1));
  46. unsigned int entNum=ent-g_entities;
  47. g_entityInUseBits[entNum/32]|=((unsigned int)1)<<(entNum&0x1f);
  48. }
  49. void ClearInUse(gentity_t *ent)
  50. {
  51. assert(((unsigned int)ent)>=(unsigned int)g_entities);
  52. assert(((unsigned int)ent)<=(unsigned int)(g_entities+MAX_GENTITIES-1));
  53. unsigned int entNum=ent-g_entities;
  54. g_entityInUseBits[entNum/32]&=~(((unsigned int)1)<<(entNum&0x1f));
  55. }
  56. qboolean PInUse(unsigned int entNum)
  57. {
  58. assert(entNum>=0);
  59. assert(entNum<MAX_GENTITIES);
  60. return((g_entityInUseBits[entNum/32]&(((unsigned int)1)<<(entNum&0x1f)))!=0);
  61. }
  62. /*qboolean PInUse2(gentity_t *ent)
  63. {
  64. assert(((unsigned int)ent)>=(unsigned int)g_entities);
  65. assert(((unsigned int)ent)<=(unsigned int)(g_entities+MAX_GENTITIES-1));
  66. unsigned int entNum=ent-g_entities;
  67. return((g_entityInUseBits[entNum/32]&(((unsigned int)1)<<(entNum&0x1f)))!=0);
  68. }
  69. */
  70. void WriteInUseBits(void)
  71. {
  72. gi.AppendToSaveGame('INUS', &g_entityInUseBits, sizeof(g_entityInUseBits) );
  73. }
  74. void ReadInUseBits(void)
  75. {
  76. gi.ReadFromSaveGame('INUS', &g_entityInUseBits, sizeof(g_entityInUseBits));
  77. // This is only temporary. Once I have converted all the ent->inuse refs,
  78. // it won;t be needed -MW.
  79. for(int i=0;i<MAX_GENTITIES;i++)
  80. {
  81. g_entities[i].inuse=PInUse(i);
  82. }
  83. }
  84. #ifdef _DEBUG
  85. static void ValidateInUseBits(void)
  86. {
  87. for(int i=0;i<MAX_GENTITIES;i++)
  88. {
  89. assert(g_entities[i].inuse==PInUse(i));
  90. }
  91. }
  92. #endif
  93. gentity_t *player;
  94. cvar_t *g_speed;
  95. cvar_t *g_gravity;
  96. cvar_t *g_stepSlideFix;
  97. cvar_t *g_sex;
  98. cvar_t *g_spskill;
  99. cvar_t *g_cheats;
  100. cvar_t *g_developer;
  101. cvar_t *g_timescale;
  102. cvar_t *g_knockback;
  103. cvar_t *g_dismemberment;
  104. cvar_t *g_dismemberProbabilities;
  105. cvar_t *g_corpseRemovalTime;
  106. cvar_t *g_synchSplitAnims;
  107. #ifndef FINAL_BUILD
  108. cvar_t *g_AnimWarning;
  109. #endif
  110. cvar_t *g_noFootSlide;
  111. cvar_t *g_noFootSlideRunScale;
  112. cvar_t *g_noFootSlideWalkScale;
  113. cvar_t *g_nav1;
  114. cvar_t *g_nav2;
  115. cvar_t *g_bobaDebug;
  116. cvar_t *g_delayedShutdown;
  117. cvar_t *g_inactivity;
  118. cvar_t *g_debugMove;
  119. cvar_t *g_debugDamage;
  120. cvar_t *g_weaponRespawn;
  121. cvar_t *g_subtitles;
  122. cvar_t *g_ICARUSDebug;
  123. #ifdef _XBOX
  124. extern cvar_t *com_buildScript;
  125. #else
  126. cvar_t *com_buildScript;
  127. #endif
  128. cvar_t *g_skippingcin;
  129. cvar_t *g_AIsurrender;
  130. cvar_t *g_numEntities;
  131. //cvar_t *g_iscensored;
  132. cvar_t *g_saberAutoBlocking;
  133. cvar_t *g_saberRealisticCombat;
  134. cvar_t *g_saberDamageCapping;
  135. cvar_t *g_saberMoveSpeed;
  136. cvar_t *g_saberAnimSpeed;
  137. cvar_t *g_saberAutoAim;
  138. cvar_t *g_saberNewControlScheme;
  139. cvar_t *g_debugSaberLock;
  140. cvar_t *g_saberLockRandomNess;
  141. cvar_t *g_debugMelee;
  142. cvar_t *g_saberRestrictForce;
  143. cvar_t *g_speederControlScheme;
  144. cvar_t *g_char_model;
  145. cvar_t *g_char_skin_head;
  146. cvar_t *g_char_skin_torso;
  147. cvar_t *g_char_skin_legs;
  148. cvar_t *g_char_color_red;
  149. cvar_t *g_char_color_green;
  150. cvar_t *g_char_color_blue;
  151. cvar_t *g_saber;
  152. cvar_t *g_saber2;
  153. cvar_t *g_saber_color;
  154. cvar_t *g_saber2_color;
  155. cvar_t *g_saberDarkSideSaberColor;
  156. // kef -- used with DebugTraceForNPC
  157. cvar_t *g_npcdebug;
  158. // mcg -- testing: make NPCs obey do not enter brushes better?
  159. cvar_t *g_navSafetyChecks;
  160. cvar_t *g_broadsword;
  161. qboolean stop_icarus = qfalse;
  162. extern char *G_GetLocationForEnt( gentity_t *ent );
  163. extern void CP_FindCombatPointWaypoints( void );
  164. extern qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold = 0.0f );
  165. void G_RunFrame (int levelTime);
  166. void PrintEntClassname( int gentNum );
  167. void ClearNPCGlobals( void );
  168. extern void AI_UpdateGroups( void );
  169. void ClearPlayerAlertEvents( void );
  170. extern void NPC_ShowDebugInfo (void);
  171. extern int killPlayerTimer;
  172. /*
  173. static void G_DynamicMusicUpdate( usercmd_t *ucmd )
  174. FIXME: can we merge any of this with the G_ChooseLookEnemy stuff?
  175. */
  176. static void G_DynamicMusicUpdate( void )
  177. {
  178. gentity_t *ent;
  179. gentity_t *entityList[MAX_GENTITIES];
  180. int numListedEntities;
  181. vec3_t mins, maxs;
  182. int i, e;
  183. int distSq, radius = 2048;
  184. vec3_t center;
  185. int danger = 0;
  186. int battle = 0;
  187. int entTeam;
  188. qboolean dangerNear = qfalse;
  189. qboolean suspicious = qfalse;
  190. qboolean LOScalced = qfalse, clearLOS = qfalse;
  191. //FIXME: intro and/or other cues? (one-shot music sounds)
  192. //loops
  193. //player-based
  194. if ( !player )
  195. {//WTF?
  196. player = &g_entities[0];
  197. return;
  198. }
  199. if ( !G_PlayerSpawned() )
  200. {//player hasn't spawned yet!
  201. return;
  202. }
  203. if ( player->health <= 0 && player->max_health > 0 )
  204. {//defeat music
  205. if ( level.dmState != DM_DEATH )
  206. {
  207. level.dmState = DM_DEATH;
  208. }
  209. }
  210. if ( level.dmState == DM_DEATH )
  211. {
  212. gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "death" );
  213. return;
  214. }
  215. if ( level.dmState == DM_BOSS )
  216. {
  217. gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "boss" );
  218. return;
  219. }
  220. if ( level.dmState == DM_SILENCE )
  221. {
  222. gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "silence" );
  223. return;
  224. }
  225. if ( level.dmBeatTime > level.time )
  226. {//not on a beat
  227. return;
  228. }
  229. level.dmBeatTime = level.time + 1000;//1 second beats
  230. if ( player->health <= 20 )
  231. {
  232. danger = 1;
  233. }
  234. //enemy-based
  235. VectorCopy( player->currentOrigin, center );
  236. for ( i = 0 ; i < 3 ; i++ )
  237. {
  238. mins[i] = center[i] - radius;
  239. maxs[i] = center[i] + radius;
  240. }
  241. numListedEntities = gi.EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
  242. for ( e = 0 ; e < numListedEntities ; e++ )
  243. {
  244. ent = entityList[ e ];
  245. if ( !ent || !ent->inuse )
  246. {
  247. continue;
  248. }
  249. if ( !ent->client || !ent->NPC )
  250. {
  251. if ( ent->classname && (!Q_stricmp( "PAS", ent->classname )||!Q_stricmp( "misc_turret", ent->classname )) )
  252. {//a turret
  253. entTeam = ent->noDamageTeam;
  254. }
  255. else
  256. {
  257. continue;
  258. }
  259. }
  260. else
  261. {//an NPC
  262. entTeam = ent->client->playerTeam;
  263. }
  264. if ( entTeam == player->client->playerTeam )
  265. {//ally
  266. continue;
  267. }
  268. if ( entTeam == TEAM_NEUTRAL && (!ent->enemy || !ent->enemy->client || ent->enemy->client->playerTeam != player->client->playerTeam) )
  269. {//a droid that is not mad at me or my allies
  270. continue;
  271. }
  272. if ( !gi.inPVS( player->currentOrigin, ent->currentOrigin ) )
  273. {//not potentially visible
  274. continue;
  275. }
  276. if ( ent->client && ent->s.weapon == WP_NONE )
  277. {//they don't have a weapon... FIXME: only do this for droids?
  278. continue;
  279. }
  280. LOScalced = clearLOS = qfalse;
  281. if ( (ent->enemy==player&&(!ent->NPC||ent->NPC->confusionTime<level.time)) || (ent->client&&ent->client->ps.weaponTime) || (!ent->client&&ent->attackDebounceTime>level.time))
  282. {//mad
  283. if ( ent->health > 0 )
  284. {//alive
  285. //FIXME: do I really need this check?
  286. if ( ent->s.weapon == WP_SABER && ent->client && !ent->client->ps.SaberActive() && ent->enemy != player )
  287. {//a Jedi who has not yet gotten made at me
  288. continue;
  289. }
  290. if ( ent->NPC && ent->NPC->behaviorState == BS_CINEMATIC )
  291. {//they're not actually going to do anything about being mad at me...
  292. continue;
  293. }
  294. //okay, they're in my PVS, but how close are they? Are they actively attacking me?
  295. if ( !ent->client && ent->s.weapon == WP_TURRET && ent->fly_sound_debounce_time && ent->fly_sound_debounce_time - level.time < 10000 )
  296. {//a turret that shot at me less than ten seconds ago
  297. }
  298. else if ( ent->client && ent->client->ps.lastShotTime && ent->client->ps.lastShotTime - level.time < 10000 )
  299. {//an NPC that shot at me less than ten seconds ago
  300. }
  301. else
  302. {//not actively attacking me lately, see how far away they are
  303. distSq = DistanceSquared( ent->currentOrigin, player->currentOrigin );
  304. if ( distSq > 4194304/*2048*2048*/ )
  305. {//> 2048 away
  306. continue;
  307. }
  308. else if ( distSq > 1048576/*1024*1024*/ )
  309. {//> 1024 away
  310. clearLOS = G_ClearLOS( player, player->client->renderInfo.eyePoint, ent );
  311. LOScalced = qtrue;
  312. if ( clearLOS == qfalse )
  313. {//No LOS
  314. continue;
  315. }
  316. }
  317. }
  318. battle++;
  319. }
  320. }
  321. if ( level.dmState == DM_EXPLORE )
  322. {//only do these visibility checks if you're still in exploration mode
  323. if ( !InFront( ent->currentOrigin, player->currentOrigin, player->client->ps.viewangles, 0.0f) )
  324. {//not in front
  325. continue;
  326. }
  327. if ( !LOScalced )
  328. {
  329. clearLOS = G_ClearLOS( player, player->client->renderInfo.eyePoint, ent );
  330. }
  331. if ( !clearLOS )
  332. {//can't see them directly
  333. continue;
  334. }
  335. }
  336. if ( ent->health <= 0 )
  337. {//dead
  338. if ( !ent->client || level.time - ent->s.time > 10000 )
  339. {//corpse has been dead for more than 10 seconds
  340. //FIXME: coming across corpses should cause danger sounds too?
  341. continue;
  342. }
  343. }
  344. //we see enemies and/or corpses
  345. danger++;
  346. }
  347. if ( !battle )
  348. {//no active enemies, but look for missiles, shot impacts, etc...
  349. int alert = G_CheckAlertEvents( player, qtrue, qtrue, 1024, 1024, -1, qfalse, AEL_SUSPICIOUS );
  350. if ( alert != -1 )
  351. {//FIXME: maybe tripwires and other FIXED things need their own sound, some kind of danger/caution theme
  352. if ( G_CheckForDanger( player, alert ) )
  353. {//found danger near by
  354. danger++;
  355. battle = 1;
  356. }
  357. else if ( level.alertEvents[alert].owner && (level.alertEvents[alert].owner == player->enemy || (level.alertEvents[alert].owner->client && level.alertEvents[alert].owner->client->playerTeam == player->client->enemyTeam) ) )
  358. {//NPC on enemy team of player made some noise
  359. switch ( level.alertEvents[alert].level )
  360. {
  361. case AEL_DISCOVERED:
  362. dangerNear = qtrue;
  363. break;
  364. case AEL_SUSPICIOUS:
  365. suspicious = qtrue;
  366. break;
  367. case AEL_MINOR:
  368. //distraction = qtrue;
  369. break;
  370. }
  371. }
  372. }
  373. }
  374. if ( battle )
  375. {//battle - this can interrupt level.dmDebounceTime of lower intensity levels
  376. //play battle
  377. if ( level.dmState != DM_ACTION )
  378. {
  379. gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "action" );
  380. }
  381. level.dmState = DM_ACTION;
  382. if ( battle > 5 )
  383. {
  384. //level.dmDebounceTime = level.time + 8000;//don't change again for 5 seconds
  385. }
  386. else
  387. {
  388. //level.dmDebounceTime = level.time + 3000 + 1000*battle;
  389. }
  390. }
  391. else
  392. {
  393. if ( level.dmDebounceTime > level.time )
  394. {//not ready to switch yet
  395. return;
  396. }
  397. else
  398. {//at least 1 second (for beats)
  399. //level.dmDebounceTime = level.time + 1000;//FIXME: define beat time?
  400. }
  401. /*
  402. if ( danger || dangerNear )
  403. {//danger
  404. //stay on whatever we were on, action or exploration
  405. if ( !danger )
  406. {//minimum
  407. danger = 1;
  408. }
  409. if ( danger > 3 )
  410. {
  411. level.dmDebounceTime = level.time + 5000;
  412. }
  413. else
  414. {
  415. level.dmDebounceTime = level.time + 2000 + 1000*danger;
  416. }
  417. }
  418. else
  419. */
  420. {//still nothing dangerous going on
  421. if ( level.dmState != DM_EXPLORE )
  422. {//just went to explore, hold it for a couple seconds at least
  423. //level.dmDebounceTime = level.time + 2000;
  424. gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "explore" );
  425. }
  426. level.dmState = DM_EXPLORE;
  427. //FIXME: look for interest points and play "mysterious" music instead of exploration?
  428. //FIXME: suspicious and distraction sounds should play some cue or change music in a subtle way?
  429. //play exploration
  430. }
  431. //FIXME: when do we go to silence?
  432. }
  433. }
  434. void G_ConnectNavs( const char *mapname, int checkSum )
  435. {
  436. NAV::LoadFromEntitiesAndSaveToFile(mapname, checkSum);
  437. CP_FindCombatPointWaypoints();
  438. }
  439. /*
  440. ================
  441. G_FindTeams
  442. Chain together all entities with a matching team field.
  443. Entity teams are used for item groups and multi-entity mover groups.
  444. All but the first will have the FL_TEAMSLAVE flag set and teammaster field set
  445. All but the last will have the teamchain field set to the next one
  446. ================
  447. */
  448. void G_FindTeams( void ) {
  449. gentity_t *e, *e2;
  450. int i, j;
  451. int c, c2;
  452. c = 0;
  453. c2 = 0;
  454. // for ( i=1, e=g_entities,i ; i < globals.num_entities ; i++,e++ )
  455. for ( i=1 ; i < globals.num_entities ; i++ )
  456. {
  457. // if (!e->inuse)
  458. // continue;
  459. if(!PInUse(i))
  460. continue;
  461. e=&g_entities[i];
  462. if (!e->team)
  463. continue;
  464. if (e->flags & FL_TEAMSLAVE)
  465. continue;
  466. e->teammaster = e;
  467. c++;
  468. c2++;
  469. // for (j=i+1, e2=e+1 ; j < globals.num_entities ; j++,e2++)
  470. for (j=i+1; j < globals.num_entities ; j++)
  471. {
  472. // if (!e2->inuse)
  473. // continue;
  474. if(!PInUse(j))
  475. continue;
  476. e2=&g_entities[j];
  477. if (!e2->team)
  478. continue;
  479. if (e2->flags & FL_TEAMSLAVE)
  480. continue;
  481. if (!strcmp(e->team, e2->team))
  482. {
  483. c2++;
  484. e2->teamchain = e->teamchain;
  485. e->teamchain = e2;
  486. e2->teammaster = e;
  487. e2->flags |= FL_TEAMSLAVE;
  488. // make sure that targets only point at the master
  489. if ( e2->targetname ) {
  490. e->targetname = G_NewString(e2->targetname);
  491. e2->targetname = NULL;
  492. }
  493. }
  494. }
  495. }
  496. //gi.Printf ("%i teams with %i entities\n", c, c2);
  497. }
  498. /*
  499. ============
  500. G_InitCvars
  501. ============
  502. */
  503. void G_InitCvars( void ) {
  504. // don't override the cheat state set by the system
  505. g_cheats = gi.cvar ("helpUsObi", "", 0);
  506. g_developer = gi.cvar ("developer", "", 0);
  507. // noset vars
  508. gi.cvar( "gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM );
  509. gi.cvar( "gamedate", __DATE__ , CVAR_ROM );
  510. g_skippingcin = gi.cvar ("skippingCinematic", "0", CVAR_ROM);
  511. // latched vars
  512. // change anytime vars
  513. g_speed = gi.cvar( "g_speed", "250", CVAR_CHEAT );
  514. g_gravity = gi.cvar( "g_gravity", "800", CVAR_SAVEGAME|CVAR_ROM );
  515. g_stepSlideFix = gi.cvar( "g_stepSlideFix", "1", CVAR_ARCHIVE );
  516. g_sex = gi.cvar ("sex", "f", CVAR_USERINFO | CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  517. g_spskill = gi.cvar ("g_spskill", "0", CVAR_ARCHIVE | CVAR_SAVEGAME|CVAR_NORESTART);
  518. g_knockback = gi.cvar( "g_knockback", "1000", CVAR_CHEAT );
  519. g_dismemberment = gi.cvar ( "g_dismemberment", "3", CVAR_ARCHIVE );//0 = none, 1 = arms and hands, 2 = legs, 3 = waist and head, 4 = mega dismemberment
  520. g_dismemberProbabilities = gi.cvar ( "g_dismemberProbabilities", "1", CVAR_ARCHIVE );//0 = ignore probabilities, 1 = use probabilities
  521. // for now I'm making default 10 seconds
  522. g_corpseRemovalTime = gi.cvar ( "g_corpseRemovalTime", "10", CVAR_ARCHIVE );//number of seconds bodies stick around for, at least... 0 = never go away
  523. g_synchSplitAnims = gi.cvar ( "g_synchSplitAnims", "1", 0 );
  524. #ifndef FINAL_BUILD
  525. g_AnimWarning = gi.cvar ( "g_AnimWarning", "1", 0 );
  526. #endif
  527. g_noFootSlide = gi.cvar ( "g_noFootSlide", "1", 0 );
  528. g_noFootSlideRunScale = gi.cvar ( "g_noFootSlideRunScale", "150.0", 0 );
  529. g_noFootSlideWalkScale = gi.cvar ( "g_noFootSlideWalkScale", "50.0", 0 );
  530. g_nav1 = gi.cvar ( "g_nav1", "", 0 );
  531. g_nav2 = gi.cvar ( "g_nav2", "", 0 );
  532. g_bobaDebug = gi.cvar ( "g_bobaDebug", "", 0 );
  533. #if defined(FINAL_BUILD) || defined(_XBOX)
  534. g_delayedShutdown = gi.cvar ( "g_delayedShutdown", "0", 0 );
  535. #else
  536. g_delayedShutdown = gi.cvar ( "g_delayedShutdown", "1", 0 );
  537. #endif
  538. g_inactivity = gi.cvar ("g_inactivity", "0", 0);
  539. g_debugMove = gi.cvar ("g_debugMove", "0", CVAR_CHEAT );
  540. g_debugDamage = gi.cvar ("g_debugDamage", "0", CVAR_CHEAT );
  541. g_ICARUSDebug = gi.cvar( "g_ICARUSDebug", "0", CVAR_CHEAT );
  542. g_timescale = gi.cvar( "timescale", "1", 0 );
  543. g_npcdebug = gi.cvar( "g_npcdebug", "0", 0 );
  544. g_navSafetyChecks = gi.cvar( "g_navSafetyChecks", "0", 0 );
  545. // NOTE : I also create this is UI_Init()
  546. g_subtitles = gi.cvar( "g_subtitles", "0", CVAR_ARCHIVE );
  547. com_buildScript = gi.cvar ("com_buildscript", "0", 0);
  548. g_saberAutoBlocking = gi.cvar( "g_saberAutoBlocking", "1", CVAR_CHEAT );//must press +block button to do any blocking
  549. g_saberRealisticCombat = gi.cvar( "g_saberRealisticCombat", "0", CVAR_CHEAT );//makes collision more precise, increases damage
  550. g_saberDamageCapping = gi.cvar( "g_saberDamageCapping", "1", CVAR_CHEAT );//caps damage of sabers vs players and NPC who use sabers
  551. g_saberMoveSpeed = gi.cvar( "g_saberMoveSpeed", "1", CVAR_CHEAT );//how fast you run while attacking with a saber
  552. g_saberAnimSpeed = gi.cvar( "g_saberAnimSpeed", "1", CVAR_CHEAT );//how fast saber animations run
  553. g_saberAutoAim = gi.cvar( "g_saberAutoAim", "1", CVAR_CHEAT );//auto-aims at enemies when not moving or when just running forward
  554. g_saberNewControlScheme = gi.cvar( "g_saberNewControlScheme", "0", CVAR_ARCHIVE );//use +forcefocus to pull off all the special moves
  555. g_debugSaberLock = gi.cvar( "g_debugSaberLock", "0", CVAR_CHEAT );//just for debugging/development, makes saberlocks happen all the time
  556. g_saberLockRandomNess = gi.cvar( "g_saberLockRandomNess", "2", CVAR_ARCHIVE );//just for debugging/development, controls frequency of saberlocks
  557. g_debugMelee = gi.cvar( "g_debugMelee", "0", CVAR_CHEAT );//just for debugging/development, test kicks and grabs
  558. g_saberRestrictForce = gi.cvar( "g_saberRestrictForce", "0", CVAR_ARCHIVE );//restricts certain force powers when using a 2-handed saber or 2 sabers
  559. g_AIsurrender = gi.cvar( "g_AIsurrender", "0", CVAR_CHEAT );
  560. g_numEntities = gi.cvar( "g_numEntities", "0", 0 );
  561. gi.cvar( "newTotalSecrets", "0", CVAR_ROM );
  562. gi.cvar_set("newTotalSecrets", "0");//used to carry over the count from SP_target_secret to ClientBegin
  563. //g_iscensored = gi.cvar( "ui_iscensored", "0", CVAR_ARCHIVE|CVAR_ROM|CVAR_INIT|CVAR_CHEAT|CVAR_NORESTART );
  564. g_speederControlScheme = gi.cvar( "g_speederControlScheme", "2", CVAR_ARCHIVE|CVAR_ROM );//2 is default, 1 is alternate
  565. g_char_model = gi.cvar( "g_char_model", "jedi_tf", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  566. g_char_skin_head = gi.cvar( "g_char_skin_head", "head_a1", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  567. g_char_skin_torso = gi.cvar( "g_char_skin_torso", "torso_a1", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  568. g_char_skin_legs = gi.cvar( "g_char_skin_legs", "lower_a1", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  569. g_char_color_red = gi.cvar( "g_char_color_red", "255", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  570. g_char_color_green = gi.cvar( "g_char_color_green", "255", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  571. g_char_color_blue = gi.cvar( "g_char_color_blue", "255", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  572. g_saber = gi.cvar( "g_saber", "single_1", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  573. g_saber2 = gi.cvar( "g_saber2", "", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  574. g_saber_color = gi.cvar( "g_saber_color", "yellow", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  575. g_saber2_color = gi.cvar( "g_saber2_color", "yellow", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART );
  576. g_saberDarkSideSaberColor = gi.cvar( "g_saberDarkSideSaberColor", "0", CVAR_ARCHIVE ); //when you turn evil, it turns your saber red!
  577. g_broadsword = gi.cvar( "broadsword", "1", 0);
  578. gi.cvar( "tier_storyinfo", "0", CVAR_ROM|CVAR_SAVEGAME|CVAR_NORESTART);
  579. gi.cvar( "tiers_complete", "", CVAR_ROM|CVAR_SAVEGAME|CVAR_NORESTART);
  580. gi.cvar( "ui_prisonerobj_currtotal", "0", CVAR_ROM|CVAR_SAVEGAME|CVAR_NORESTART);
  581. gi.cvar( "ui_prisonerobj_maxtotal", "0", CVAR_ROM|CVAR_SAVEGAME|CVAR_NORESTART);
  582. gi.cvar( "g_clearstats", "1", CVAR_ROM|CVAR_NORESTART);
  583. }
  584. /*
  585. ============
  586. InitGame
  587. ============
  588. */
  589. // I'm just declaring a global here which I need to get at in NAV_GenerateSquadPaths for deciding if pre-calc'd
  590. // data is valid, and this saves changing the proto of G_SpawnEntitiesFromString() to include a checksum param which
  591. // may get changed anyway if a new nav system is ever used. This way saves messing with g_local.h each time -slc
  592. int giMapChecksum;
  593. SavedGameJustLoaded_e g_eSavedGameJustLoaded;
  594. qboolean g_qbLoadTransition = qfalse;
  595. void InitGame( const char *mapname, const char *spawntarget, int checkSum, const char *entities, int levelTime, int randomSeed, int globalTime, SavedGameJustLoaded_e eSavedGameJustLoaded, qboolean qbLoadTransition )
  596. {
  597. //rww - default this to 0, we will auto-set it to 1 if we run into a terrain ent
  598. gi.cvar_set("RMG", "0");
  599. g_bCollidableRoffs = false;
  600. giMapChecksum = checkSum;
  601. g_eSavedGameJustLoaded = eSavedGameJustLoaded;
  602. g_qbLoadTransition = qbLoadTransition;
  603. gi.Printf ("------- Game Initialization -------\n");
  604. gi.Printf ("gamename: %s\n", GAMEVERSION);
  605. gi.Printf ("gamedate: %s\n", __DATE__);
  606. srand( randomSeed );
  607. G_InitCvars();
  608. G_InitMemory();
  609. // set some level globals
  610. memset( &level, 0, sizeof( level ) );
  611. level.time = levelTime;
  612. level.globalTime = globalTime;
  613. Q_strncpyz( level.mapname, mapname, sizeof(level.mapname) );
  614. if ( spawntarget != NULL && spawntarget[0] )
  615. {
  616. Q_strncpyz( level.spawntarget, spawntarget, sizeof(level.spawntarget) );
  617. }
  618. else
  619. {
  620. level.spawntarget[0] = 0;
  621. }
  622. G_InitWorldSession();
  623. // initialize all entities for this game
  624. memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) );
  625. globals.gentities = g_entities;
  626. ClearAllInUse();
  627. // initialize all clients for this game
  628. level.maxclients = 1;
  629. level.clients = (struct gclient_s *) G_Alloc( level.maxclients * sizeof(level.clients[0]) );
  630. memset(level.clients, 0, level.maxclients * sizeof(level.clients[0]));
  631. // set client fields on player
  632. g_entities[0].client = level.clients;
  633. // always leave room for the max number of clients,
  634. // even if they aren't all used, so numbers inside that
  635. // range are NEVER anything but clients
  636. globals.num_entities = MAX_CLIENTS;
  637. //Load sabers.cfg data
  638. WP_SaberLoadParms();
  639. //Set up NPC init data
  640. NPC_InitGame();
  641. TIMER_Clear();
  642. Rail_Reset();
  643. Troop_Reset();
  644. Pilot_Reset();
  645. IT_LoadItemParms ();
  646. ClearRegisteredItems();
  647. // clear out old nav info, attempt to load from file
  648. NAV::LoadFromFile(level.mapname, giMapChecksum);
  649. // parse the key/value pairs and spawn gentities
  650. G_SpawnEntitiesFromString( entities );
  651. // general initialization
  652. G_FindTeams();
  653. // SaveRegisteredItems();
  654. gi.Printf ("-----------------------------------\n");
  655. Rail_Initialize();
  656. Troop_Initialize();
  657. player = &g_entities[0];
  658. //Init dynamic music
  659. level.dmState = DM_EXPLORE;
  660. level.dmDebounceTime = 0;
  661. level.dmBeatTime = 0;
  662. level.curAlertID = 1;//0 is default for lastAlertEvent, so...
  663. eventClearTime = 0;
  664. #ifdef _XBOX
  665. // clear out NPC water detection data
  666. npcsToUpdateTop = 0;
  667. npcsToUpdateCount = 0;
  668. memset(npcsToUpdate, -1, 2 * MAX_NPC_WATER_UPDATE);
  669. #endif // _XBOX
  670. }
  671. /*
  672. =================
  673. ShutdownGame
  674. =================
  675. */
  676. void ShutdownGame( void )
  677. {
  678. // write all the client session data so we can get it back
  679. G_WriteSessionData();
  680. #ifdef _XBOX
  681. // The following functions, cleverly disguised as memory freeing and dealloction,
  682. // actually allocate small blocks. Fooled you!
  683. extern void Z_SetNewDeleteTemporary(bool bTemp);
  684. Z_SetNewDeleteTemporary( true );
  685. #endif
  686. // Destroy the Game Interface.
  687. IGameInterface::Destroy();
  688. // Shut ICARUS down.
  689. IIcarusInterface::DestroyIcarus();
  690. // Destroy the Game Interface again. Only way to really free everything.
  691. IGameInterface::Destroy();
  692. #ifdef _XBOX
  693. Z_SetNewDeleteTemporary( false );
  694. #endif
  695. TAG_Init(); //Clear the reference tags
  696. /*
  697. Ghoul2 Insert Start
  698. */
  699. for (int i=0; i<MAX_GENTITIES; i++)
  700. {
  701. gi.G2API_CleanGhoul2Models(g_entities[i].ghoul2);
  702. }
  703. /*
  704. Ghoul2 Insert End
  705. */
  706. G_ASPreCacheFree();
  707. }
  708. //===================================================================
  709. static void G_Cvar_Create( const char *var_name, const char *var_value, int flags ) {
  710. gi.cvar( var_name, var_value, flags );
  711. }
  712. //BEGIN GAMESIDE RMG
  713. qboolean G_ParseSpawnVars( const char **data );
  714. void G_SpawnGEntityFromSpawnVars( void );
  715. void G_GameSpawnRMGEntity(char *s)
  716. {
  717. if (G_ParseSpawnVars((const char **)&s))
  718. {
  719. G_SpawnGEntityFromSpawnVars();
  720. }
  721. }
  722. //END GAMESIDE RMG
  723. /*
  724. =================
  725. GetGameAPI
  726. Returns a pointer to the structure with all entry points
  727. and global variables
  728. =================
  729. */
  730. extern int PM_ValidateAnimRange( const int startFrame, const int endFrame, const float animSpeed );
  731. game_export_t *GetGameAPI( game_import_t *import ) {
  732. gameinfo_import_t gameinfo_import;
  733. gi = *import;
  734. globals.apiversion = GAME_API_VERSION;
  735. globals.Init = InitGame;
  736. globals.Shutdown = ShutdownGame;
  737. globals.WriteLevel = WriteLevel;
  738. globals.ReadLevel = ReadLevel;
  739. globals.GameAllowedToSaveHere = GameAllowedToSaveHere;
  740. globals.ClientThink = ClientThink;
  741. globals.ClientConnect = ClientConnect;
  742. globals.ClientUserinfoChanged = ClientUserinfoChanged;
  743. globals.ClientDisconnect = ClientDisconnect;
  744. globals.ClientBegin = ClientBegin;
  745. globals.ClientCommand = ClientCommand;
  746. globals.RunFrame = G_RunFrame;
  747. globals.ConnectNavs = G_ConnectNavs;
  748. globals.ConsoleCommand = ConsoleCommand;
  749. //globals.PrintEntClassname = PrintEntClassname;
  750. //globals.ValidateAnimRange = PM_ValidateAnimRange;
  751. globals.GameSpawnRMGEntity = G_GameSpawnRMGEntity;
  752. globals.gentitySize = sizeof(gentity_t);
  753. gameinfo_import.FS_FOpenFile = gi.FS_FOpenFile;
  754. gameinfo_import.FS_Read = gi.FS_Read;
  755. gameinfo_import.FS_FCloseFile = gi.FS_FCloseFile;
  756. gameinfo_import.Cvar_Set = gi.cvar_set;
  757. gameinfo_import.Cvar_VariableStringBuffer = gi.Cvar_VariableStringBuffer;
  758. gameinfo_import.Cvar_Create = G_Cvar_Create;
  759. GI_Init( &gameinfo_import );
  760. return &globals;
  761. }
  762. void QDECL G_Error( const char *fmt, ... ) {
  763. va_list argptr;
  764. char text[1024];
  765. va_start (argptr, fmt);
  766. vsprintf (text, fmt, argptr);
  767. va_end (argptr);
  768. gi.Error( ERR_DROP, "%s", text);
  769. }
  770. #ifndef GAME_HARD_LINKED
  771. // this is only here so the functions in q_shared.c and bg_*.c can link
  772. /*
  773. -------------------------
  774. Com_Error
  775. -------------------------
  776. */
  777. void Com_Error ( int level, const char *error, ... ) {
  778. va_list argptr;
  779. char text[1024];
  780. va_start (argptr, error);
  781. vsprintf (text, error, argptr);
  782. va_end (argptr);
  783. gi.Error( level, "%s", text);
  784. }
  785. /*
  786. -------------------------
  787. Com_Printf
  788. -------------------------
  789. */
  790. void Com_Printf( const char *msg, ... ) {
  791. va_list argptr;
  792. char text[1024];
  793. va_start (argptr, msg);
  794. vsprintf (text, msg, argptr);
  795. va_end (argptr);
  796. gi.Printf ("%s", text);
  797. }
  798. #endif
  799. /*
  800. ========================================================================
  801. MAP CHANGING
  802. ========================================================================
  803. */
  804. /*
  805. ========================================================================
  806. FUNCTIONS CALLED EVERY FRAME
  807. ========================================================================
  808. */
  809. static void G_CheckTasksCompleted (gentity_t *ent)
  810. {
  811. if ( Q3_TaskIDPending( ent, TID_CHAN_VOICE ) )
  812. {
  813. if ( !gi.VoiceVolume[ent->s.number] )
  814. {//not playing a voice sound
  815. //return task_complete
  816. Q3_TaskIDComplete( ent, TID_CHAN_VOICE );
  817. }
  818. }
  819. if ( Q3_TaskIDPending( ent, TID_LOCATION ) )
  820. {
  821. char *currentLoc = G_GetLocationForEnt( ent );
  822. if ( currentLoc && currentLoc[0] && Q_stricmp( ent->message, currentLoc ) == 0 )
  823. {//we're in the desired location
  824. Q3_TaskIDComplete( ent, TID_LOCATION );
  825. }
  826. //FIXME: else see if were in other trigger_locations?
  827. }
  828. }
  829. static void G_CheckSpecialPersistentEvents( gentity_t *ent )
  830. {//special-case alerts that would be a pain in the ass to have the ent's think funcs generate
  831. if ( ent == NULL )
  832. {
  833. return;
  834. }
  835. if ( ent->s.eType == ET_MISSILE && ent->s.weapon == WP_THERMAL && ent->s.pos.trType == TR_STATIONARY )
  836. {
  837. if ( eventClearTime == level.time + ALERT_CLEAR_TIME )
  838. {//events were just cleared out so add me again
  839. AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius*2, AEL_DANGER, qfalse, qtrue );
  840. AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius*2, AEL_DANGER );
  841. }
  842. }
  843. if ( ent->forcePushTime >= level.time )
  844. {//being pushed
  845. if ( eventClearTime == level.time + ALERT_CLEAR_TIME )
  846. {//events were just cleared out so add me again
  847. //NOTE: presumes the player did the pushing, this is not always true, but shouldn't really matter?
  848. if ( ent->item && ent->item->giTag == INV_SECURITY_KEY )
  849. {
  850. AddSightEvent( player, ent->currentOrigin, 128, AEL_DISCOVERED );//security keys are more important
  851. }
  852. else
  853. {
  854. AddSightEvent( player, ent->currentOrigin, 128, AEL_SUSPICIOUS );//hmm... or should this always be discovered?
  855. }
  856. }
  857. }
  858. if ( ent->contents == CONTENTS_LIGHTSABER && !Q_stricmp( "lightsaber", ent->classname ) )
  859. {//lightsaber
  860. if( ent->owner && ent->owner->client )
  861. {
  862. if ( ent->owner->client->ps.SaberLength() > 0 )
  863. {//it's on
  864. //sight event
  865. AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED );
  866. }
  867. }
  868. }
  869. }
  870. /*
  871. =============
  872. G_RunThink
  873. Runs thinking code for this frame if necessary
  874. =============
  875. */
  876. #include "../client/client.h"
  877. void G_RunThink (gentity_t *ent)
  878. {
  879. if ( (ent->nextthink <= 0) || (ent->nextthink > level.time) )
  880. {
  881. goto runicarus;
  882. }
  883. ent->nextthink = 0;
  884. if ( ent->e_ThinkFunc == thinkF_NULL ) // actually you don't need this since I check for it in the next function -slc
  885. {
  886. goto runicarus;
  887. }
  888. GEntity_ThinkFunc( ent );
  889. runicarus:
  890. if ( ent->inuse ) // GEntity_ThinkFunc( ent ) can have freed up this ent if it was a type flier_child (stasis1 crash)
  891. {
  892. if ( ent->NPC == NULL )
  893. {
  894. if ( ent->m_iIcarusID != IIcarusInterface::ICARUS_INVALID && !stop_icarus && cls.state != CA_CONNECTED )
  895. {
  896. IIcarusInterface::GetIcarus()->Update( ent->m_iIcarusID );
  897. }
  898. }
  899. }
  900. }
  901. /*
  902. -------------------------
  903. G_Animate
  904. -------------------------
  905. */
  906. static void G_Animate ( gentity_t *self )
  907. {
  908. if ( self->s.eFlags & EF_SHADER_ANIM )
  909. {
  910. return;
  911. }
  912. if ( self->s.frame == self->endFrame )
  913. {
  914. if ( self->svFlags & SVF_ANIMATING )
  915. {
  916. // ghoul2 requires some extra checks to see if the animation is done since it doesn't set the current frame directly
  917. if ( self->ghoul2.size() )
  918. {
  919. float frame, junk2;
  920. int junk;
  921. // I guess query ghoul2 to find out what the current frame is and see if we are done.
  922. gi.G2API_GetBoneAnimIndex( &self->ghoul2[self->playerModel], self->rootBone,
  923. (cg.time?cg.time:level.time), &frame, &junk, &junk, &junk, &junk2, NULL );
  924. // It NEVER seems to get to what you'd think the last frame would be, so I'm doing this to try and catch when the animation has stopped
  925. if ( frame + 1 >= self->endFrame )
  926. {
  927. self->svFlags &= ~SVF_ANIMATING;
  928. Q3_TaskIDComplete( self, TID_ANIM_BOTH );
  929. }
  930. }
  931. else // not ghoul2
  932. {
  933. if ( self->loopAnim )
  934. {
  935. self->s.frame = self->startFrame;
  936. }
  937. else
  938. {
  939. self->svFlags &= ~SVF_ANIMATING;
  940. }
  941. //Finished sequence - FIXME: only do this once even on looping anims?
  942. Q3_TaskIDComplete( self, TID_ANIM_BOTH );
  943. }
  944. }
  945. return;
  946. }
  947. self->svFlags |= SVF_ANIMATING;
  948. // With ghoul2, we'll just set the desired start and end frame and let it do it's thing.
  949. if ( self->ghoul2.size())
  950. {
  951. self->s.frame = self->endFrame;
  952. gi.G2API_SetBoneAnimIndex( &self->ghoul2[self->playerModel], self->rootBone,
  953. self->startFrame, self->endFrame, BONE_ANIM_OVERRIDE_FREEZE, 1.0f, cg.time );
  954. return;
  955. }
  956. if ( self->startFrame < self->endFrame )
  957. {
  958. if ( self->s.frame < self->startFrame || self->s.frame > self->endFrame )
  959. {
  960. self->s.frame = self->startFrame;
  961. }
  962. else
  963. {
  964. self->s.frame++;
  965. }
  966. }
  967. else if ( self->startFrame > self->endFrame )
  968. {
  969. if ( self->s.frame > self->startFrame || self->s.frame < self->endFrame )
  970. {
  971. self->s.frame = self->startFrame;
  972. }
  973. else
  974. {
  975. self->s.frame--;
  976. }
  977. }
  978. else
  979. {
  980. self->s.frame = self->endFrame;
  981. }
  982. }
  983. /*
  984. -------------------------
  985. ResetTeamCounters
  986. -------------------------
  987. */
  988. /*
  989. void ResetTeamCounters( void )
  990. {
  991. //clear team enemy counters
  992. for ( int team = TEAM_FREE; team < TEAM_NUM_TEAMS; team++ )
  993. {
  994. teamEnemyCount[team] = 0;
  995. teamCount[team] = 0;
  996. }
  997. }
  998. */
  999. /*
  1000. -------------------------
  1001. UpdateTeamCounters
  1002. -------------------------
  1003. */
  1004. /*
  1005. void UpdateTeamCounters( gentity_t *ent )
  1006. {
  1007. if ( !ent->NPC )
  1008. {
  1009. return;
  1010. }
  1011. if ( !ent->client )
  1012. {
  1013. return;
  1014. }
  1015. if ( ent->health <= 0 )
  1016. {
  1017. return;
  1018. }
  1019. if ( (ent->s.eFlags&EF_NODRAW) )
  1020. {
  1021. return;
  1022. }
  1023. if ( ent->client->playerTeam == TEAM_FREE )
  1024. {
  1025. return;
  1026. }
  1027. //this is an NPC who is alive and visible and is on a specific team
  1028. teamCount[ent->client->playerTeam]++;
  1029. if ( !ent->enemy )
  1030. {
  1031. return;
  1032. }
  1033. //ent has an enemy
  1034. if ( !ent->enemy->client )
  1035. {//enemy is a normal ent
  1036. if ( ent->noDamageTeam == ent->client->playerTeam )
  1037. {//it's on my team, don't count it as an enemy
  1038. return;
  1039. }
  1040. }
  1041. else
  1042. {//enemy is another NPC/player
  1043. if ( ent->enemy->client->playerTeam == ent->client->playerTeam)
  1044. {//enemy is on the same team, don't count it as an enemy
  1045. return;
  1046. }
  1047. }
  1048. //ent's enemy is not on the same team
  1049. teamLastEnemyTime[ent->client->playerTeam] = level.time;
  1050. teamEnemyCount[ent->client->playerTeam]++;
  1051. }
  1052. */
  1053. void G_PlayerGuiltDeath( void )
  1054. {
  1055. if ( player && player->client )
  1056. {//simulate death
  1057. player->client->ps.stats[STAT_HEALTH] = 0;
  1058. //turn off saber
  1059. if ( player->client->ps.weapon == WP_SABER && player->client->ps.SaberActive() )
  1060. {
  1061. G_SoundIndexOnEnt( player, CHAN_WEAPON, player->client->ps.saber[0].soundOff );
  1062. player->client->ps.SaberDeactivate();
  1063. }
  1064. //play the "what have I done?!" anim
  1065. NPC_SetAnim( player, SETANIM_BOTH, BOTH_FORCEHEAL_START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
  1066. player->client->ps.legsAnimTimer = player->client->ps.torsoAnimTimer = -1;
  1067. //look at yourself
  1068. player->client->ps.stats[STAT_DEAD_YAW] = player->client->ps.viewangles[YAW]+180;
  1069. }
  1070. }
  1071. extern void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend);
  1072. extern void G_MakeTeamVulnerable( void );
  1073. int killPlayerTimer = 0;
  1074. static void G_CheckEndLevelTimers( gentity_t *ent )
  1075. {
  1076. if ( killPlayerTimer && level.time > killPlayerTimer )
  1077. {
  1078. killPlayerTimer = 0;
  1079. ent->health = 0;
  1080. if ( ent->client && ent->client->ps.stats[STAT_HEALTH] > 0 )
  1081. {
  1082. G_PlayerGuiltDeath();
  1083. //cg.missionStatusShow = qtrue;
  1084. statusTextIndex = MISSIONFAILED_TURNED;
  1085. //debounce respawn time
  1086. ent->client->respawnTime = level.time + 2000;
  1087. //stop all scripts
  1088. stop_icarus = qtrue;
  1089. //make the team killable
  1090. G_MakeTeamVulnerable();
  1091. }
  1092. }
  1093. }
  1094. //rww - RAGDOLL_BEGIN
  1095. class CGameRagDollUpdateParams : public CRagDollUpdateParams
  1096. {
  1097. void EffectorCollision(const SRagDollEffectorCollision &data)
  1098. {
  1099. //Com_Printf("Effector Collision at (%f %f %f)\n",data.effectorPosition[0],data.effectorPosition[1],data.effectorPosition[2]);
  1100. vec3_t effectorPosDif;
  1101. if (data.useTracePlane)
  1102. {
  1103. float magicFactor42=64.0f;
  1104. VectorScale(data.tr.plane.normal,magicFactor42,effectorPosDif);
  1105. }
  1106. else
  1107. {
  1108. gentity_t *thisguy = &g_entities[me];
  1109. if (thisguy && thisguy->client)
  1110. {
  1111. VectorSubtract(thisguy->client->ps.origin, data.effectorPosition, effectorPosDif);
  1112. }
  1113. else
  1114. {
  1115. return;
  1116. }
  1117. }
  1118. VectorAdd(effectorTotal, effectorPosDif, effectorTotal);
  1119. hasEffectorData = qtrue;
  1120. return;
  1121. }
  1122. void RagDollBegin()
  1123. {
  1124. return;
  1125. }
  1126. virtual void RagDollSettled()
  1127. {
  1128. return;
  1129. }
  1130. void Collision() // we had a collision, please stop animating and (sometime soon) call SetRagDoll RP_DEATH_COLLISION
  1131. {
  1132. return;
  1133. }
  1134. #ifdef _DEBUG
  1135. void DebugLine(vec3_t p1,vec3_t p2,int color,bool bbox)
  1136. {
  1137. if (!bbox)
  1138. {
  1139. CG_TestLine(p1, p2, 50, color, 1);
  1140. }
  1141. return;
  1142. }
  1143. #endif
  1144. public:
  1145. vec3_t effectorTotal;
  1146. qboolean hasEffectorData;
  1147. };
  1148. //list of valid ragdoll effectors
  1149. static const char *g_effectorStringTable[] =
  1150. { //commented out the ones I don't want dragging to affect
  1151. // "thoracic",
  1152. // "rhand",
  1153. "lhand",
  1154. "rtibia",
  1155. "ltibia",
  1156. "rtalus",
  1157. "ltalus",
  1158. // "rradiusX",
  1159. "lradiusX",
  1160. "rfemurX",
  1161. "lfemurX",
  1162. // "ceyebrow",
  1163. NULL //always terminate
  1164. };
  1165. extern qboolean G_StandardHumanoid( gentity_t *self );
  1166. extern void PM_SetTorsoAnimTimer( gentity_t *ent, int *torsoAnimTimer, int time );
  1167. extern void PM_SetLegsAnimTimer( gentity_t *ent, int *legsAnimTimer, int time );
  1168. extern qboolean G_ReleaseEntity( gentity_t *grabber );
  1169. static void G_BodyDragUpdate(gentity_t *ent, gentity_t *dragger)
  1170. {
  1171. vec3_t handVec;
  1172. float handDist;
  1173. assert(ent && ent->inuse && ent->client && ent->ghoul2.size() &&
  1174. dragger && dragger->inuse && dragger->client && dragger->ghoul2.size());
  1175. VectorSubtract(dragger->client->renderInfo.handRPoint, ent->client->renderInfo.torsoPoint, handVec);
  1176. handDist = VectorLength(handVec);
  1177. if (handDist > 64.0f)
  1178. {
  1179. G_ReleaseEntity(dragger);
  1180. }
  1181. else if (handDist > 12.0f)
  1182. {
  1183. VectorNormalize(handVec);
  1184. VectorScale(handVec, 256.0f, handVec);
  1185. handVec[2] = 0;
  1186. //VectorAdd(ent->client->ps.velocity, handVec, ent->client->ps.velocity);
  1187. //VectorCopy(handVec, ent->client->ps.velocity);
  1188. ent->client->ps.velocity[0] = handVec[0];
  1189. ent->client->ps.velocity[1] = handVec[1];
  1190. }
  1191. }
  1192. //we want to see which way the pelvis is facing to get a relatively oriented base settling frame
  1193. //this is to avoid the arms stretching in opposite directions on the body trying to reach the base
  1194. //pose if the pelvis is flipped opposite of the base pose or something -rww
  1195. static int G_RagAnimForPositioning(gentity_t *ent)
  1196. {
  1197. vec3_t dir;
  1198. mdxaBone_t matrix;
  1199. assert(ent->client);
  1200. vec3_t G2Angles = {0, ent->client->ps.viewangles[YAW], 0};
  1201. assert(ent->ghoul2.size() > 0);
  1202. assert(ent->crotchBolt > -1);
  1203. gi.G2API_GetBoltMatrix(ent->ghoul2, ent->playerModel, ent->crotchBolt, &matrix, G2Angles, ent->client->ps.origin,
  1204. (cg.time?cg.time:level.time), NULL, ent->s.modelScale);
  1205. gi.G2API_GiveMeVectorFromMatrix(matrix, NEGATIVE_Z, dir);
  1206. if (dir[2] > 0.1f)
  1207. { //facing up
  1208. return BOTH_DEADFLOP2;
  1209. }
  1210. else
  1211. { //facing down
  1212. return BOTH_DEADFLOP1;
  1213. }
  1214. }
  1215. static inline qboolean G_RagWantsHumanoidsOnly( CGhoul2Info *ghlInfo )
  1216. {
  1217. char *GLAName;
  1218. GLAName = gi.G2API_GetGLAName( ghlInfo );
  1219. assert(GLAName);
  1220. if ( !Q_stricmp( "models/players/_humanoid/_humanoid", GLAName ) )
  1221. {//only _humanoid skeleton is expected to have these
  1222. return qtrue;
  1223. }
  1224. return qfalse;
  1225. }
  1226. //rww - game interface for the ragdoll stuff.
  1227. //Returns qtrue if the entity is now in a ragdoll state, otherwise qfalse.
  1228. //(ported from MP's CG version)
  1229. qboolean G_RagDoll(gentity_t *ent, vec3_t forcedAngles)
  1230. {
  1231. vec3_t G2Angles;
  1232. vec3_t usedOrg;
  1233. qboolean inSomething = qfalse;
  1234. int ragAnim;
  1235. //int ragVar = gi.Cvar_VariableIntegerValue("broadsword");
  1236. int ragVar = g_broadsword->integer;
  1237. if (!ragVar)
  1238. {
  1239. return qfalse;
  1240. }
  1241. if (!ent ||
  1242. !ent->inuse ||
  1243. !ent->client ||
  1244. ent->health > 0 ||
  1245. ent->client->noRagTime >= level.time ||
  1246. ent->client->noRagTime==-1 ||
  1247. (ent->s.powerups & (1 << PW_DISRUPTION)) ||
  1248. !ent->e_DieFunc ||
  1249. ent->playerModel < 0 ||
  1250. !ent->ghoul2.size() ||
  1251. !G_RagWantsHumanoidsOnly(&ent->ghoul2[ent->playerModel])
  1252. )
  1253. {
  1254. return qfalse;
  1255. }
  1256. VectorCopy(forcedAngles, G2Angles);
  1257. forcedAngles[0] = forcedAngles[2] = 0;
  1258. if (ent->client->ps.heldByClient <= ENTITYNUM_WORLD)
  1259. {
  1260. gentity_t *grabbedBy = &g_entities[ent->client->ps.heldByClient];
  1261. if (grabbedBy->inuse && grabbedBy->client &&
  1262. grabbedBy->ghoul2.size())
  1263. {
  1264. G_BodyDragUpdate(ent, grabbedBy);
  1265. }
  1266. }
  1267. //--FIXME: do not go into ragdoll if in a spinning death anim or something, it really messes things up
  1268. //rww 12/17/02 - should be ok now actually with my new stuff
  1269. VectorCopy(ent->client->ps.origin, usedOrg);
  1270. if (!ent->client->isRagging)
  1271. { //If we're not in a ragdoll state, perform the checks.
  1272. if (ent->client->ps.heldByClient <= ENTITYNUM_WORLD)
  1273. { //want to rag no matter what then
  1274. inSomething = qtrue;
  1275. }
  1276. else if (ent->client->ps.groundEntityNum == ENTITYNUM_NONE)
  1277. {
  1278. vec3_t cVel;
  1279. VectorCopy(ent->client->ps.velocity, cVel);
  1280. if (VectorNormalize(cVel) > 400)
  1281. { //if he's flying through the air at a good enough speed, switch into ragdoll
  1282. inSomething = qtrue;
  1283. }
  1284. }
  1285. if (ragVar > 1)
  1286. { //go into rag instantly upon death
  1287. inSomething = qtrue;
  1288. //also shove them a tad so they don't just collapse onto the floor
  1289. //VectorScale(ent->client->ps.velocity, 1.3f, ent->client->ps.velocity);
  1290. ent->client->ps.velocity[2] += 32;
  1291. }
  1292. if (!inSomething)
  1293. {
  1294. int i = 0;
  1295. int boltChecks[5];
  1296. vec3_t boltPoints[5];
  1297. vec3_t trStart, trEnd;
  1298. vec3_t tAng;
  1299. qboolean deathDone = qfalse;
  1300. trace_t tr;
  1301. mdxaBone_t boltMatrix;
  1302. VectorSet( tAng, 0, ent->client->ps.viewangles[YAW], 0 );
  1303. if (ent->client->ps.legsAnimTimer <= 0)
  1304. { //Looks like the death anim is done playing
  1305. deathDone = qtrue;
  1306. }
  1307. //if (deathDone)
  1308. if (1)
  1309. { //only trace from the hands if the death anim is already done.
  1310. boltChecks[0] = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "rhand");
  1311. boltChecks[1] = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "lhand");
  1312. }
  1313. else
  1314. { //otherwise start the trace loop at the cranium.
  1315. i = 2;
  1316. }
  1317. boltChecks[2] = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "cranium");
  1318. boltChecks[3] = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "rtalus");
  1319. boltChecks[4] = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "ltalus");
  1320. //Do the head first, because the hands reference it anyway.
  1321. gi.G2API_GetBoltMatrix(ent->ghoul2, ent->playerModel, boltChecks[2], &boltMatrix, tAng, ent->client->ps.origin, (cg.time?cg.time:level.time), NULL, ent->s.modelScale);
  1322. gi.G2API_GiveMeVectorFromMatrix(boltMatrix, ORIGIN, boltPoints[2]);
  1323. while (i < 5)
  1324. {
  1325. if (i < 2)
  1326. { //when doing hands, trace to the head instead of origin
  1327. gi.G2API_GetBoltMatrix(ent->ghoul2, ent->playerModel, boltChecks[i], &boltMatrix, tAng, ent->client->ps.origin, (cg.time?cg.time:level.time), NULL, ent->s.modelScale);
  1328. gi.G2API_GiveMeVectorFromMatrix(boltMatrix, ORIGIN, boltPoints[i]);
  1329. VectorCopy(boltPoints[i], trStart);
  1330. VectorCopy(boltPoints[2], trEnd);
  1331. }
  1332. else
  1333. {
  1334. if (i > 2)
  1335. { //2 is the head, which already has the bolt point.
  1336. gi.G2API_GetBoltMatrix(ent->ghoul2, ent->playerModel, boltChecks[i], &boltMatrix, tAng, ent->client->ps.origin, (cg.time?cg.time:level.time), NULL, ent->s.modelScale);
  1337. gi.G2API_GiveMeVectorFromMatrix(boltMatrix, ORIGIN, boltPoints[i]);
  1338. }
  1339. VectorCopy(boltPoints[i], trStart);
  1340. VectorCopy(ent->client->ps.origin, trEnd);
  1341. }
  1342. //Now that we have all that sorted out, trace between the two points we desire.
  1343. gi.trace(&tr, trStart, NULL, NULL, trEnd, ent->s.number, MASK_SOLID);
  1344. if (tr.fraction != 1.0 || tr.startsolid || tr.allsolid)
  1345. { //Hit something or start in solid, so flag it and break.
  1346. //This is a slight hack, but if we aren't done with the death anim, we don't really want to
  1347. //go into ragdoll unless our body has a relatively "flat" pitch.
  1348. #if 0
  1349. vec3_t vSub;
  1350. //Check the pitch from the head to the right foot (should be reasonable)
  1351. VectorSubtract(boltPoints[2], boltPoints[3], vSub);
  1352. VectorNormalize(vSub);
  1353. vectoangles(vSub, vSub);
  1354. if (deathDone || (vSub[PITCH] < 50 && vSub[PITCH] > -50))
  1355. {
  1356. inSomething = qtrue;
  1357. }
  1358. #else
  1359. inSomething = qtrue;
  1360. #endif
  1361. break;
  1362. }
  1363. i++;
  1364. }
  1365. }
  1366. if (inSomething)
  1367. {
  1368. /*
  1369. PM_SetTorsoAnimTimer( ent, &ent->client->ps.torsoAnimTimer, 0 );
  1370. PM_SetLegsAnimTimer( ent, &ent->client->ps.legsAnimTimer, 0 );
  1371. PM_SetAnimFinal(&ent->client->ps.torsoAnim,&ent->client->ps.legsAnim,SETANIM_BOTH,ragAnim,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD,
  1372. &ent->client->ps.torsoAnimTimer,&ent->client->ps.legsAnimTimer,ent,500);
  1373. */
  1374. ent->client->isRagging = qtrue;
  1375. }
  1376. }
  1377. if (ent->client->isRagging)
  1378. { //We're in a ragdoll state, so make the call to keep our positions updated and whatnot.
  1379. CRagDollParams tParms;
  1380. CGameRagDollUpdateParams tuParms;
  1381. ragAnim = G_RagAnimForPositioning(ent);
  1382. /*
  1383. if (ent->ikStatus)
  1384. { //ik must be reset before ragdoll is started, or you'll get some interesting results.
  1385. trap_G2API_SetBoneIKState(cent->ghoul2, cg.time, NULL, IKS_NONE, NULL);
  1386. cent->ikStatus = qfalse;
  1387. }
  1388. */
  1389. //these will be used as "base" frames for the ragoll settling.
  1390. tParms.startFrame = level.knownAnimFileSets[ent->client->clientInfo.animFileIndex].animations[ragAnim].firstFrame;
  1391. tParms.endFrame = level.knownAnimFileSets[ent->client->clientInfo.animFileIndex].animations[ragAnim].firstFrame+level.knownAnimFileSets[ent->client->clientInfo.animFileIndex].animations[ragAnim].numFrames;
  1392. #if 1
  1393. {
  1394. float currentFrame;
  1395. int startFrame, endFrame;
  1396. int flags;
  1397. float animSpeed;
  1398. if (gi.G2API_GetBoneAnim(&ent->ghoul2[0], "model_root", (cg.time?cg.time:level.time), &currentFrame, &startFrame, &endFrame, &flags, &animSpeed, NULL))
  1399. { //lock the anim on the current frame.
  1400. int blendTime = 500;
  1401. gi.G2API_SetBoneAnim(&ent->ghoul2[0], "lower_lumbar", currentFrame, currentFrame+1, flags, animSpeed,(cg.time?cg.time:level.time), currentFrame, blendTime);
  1402. gi.G2API_SetBoneAnim(&ent->ghoul2[0], "model_root", currentFrame, currentFrame+1, flags, animSpeed, (cg.time?cg.time:level.time), currentFrame, blendTime);
  1403. gi.G2API_SetBoneAnim(&ent->ghoul2[0], "Motion", currentFrame, currentFrame+1, flags, animSpeed, (cg.time?cg.time:level.time), currentFrame, blendTime);
  1404. }
  1405. }
  1406. #endif
  1407. gi.G2API_SetBoneAngles( &ent->ghoul2[ent->playerModel], "upper_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 100, (cg.time?cg.time:level.time) );
  1408. gi.G2API_SetBoneAngles( &ent->ghoul2[ent->playerModel], "lower_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 100, (cg.time?cg.time:level.time) );
  1409. gi.G2API_SetBoneAngles( &ent->ghoul2[ent->playerModel], "thoracic", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 100, (cg.time?cg.time:level.time) );
  1410. gi.G2API_SetBoneAngles( &ent->ghoul2[ent->playerModel], "cervical", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 100, (cg.time?cg.time:level.time) );
  1411. VectorCopy(G2Angles, tParms.angles);
  1412. VectorCopy(usedOrg, tParms.position);
  1413. VectorCopy(ent->s.modelScale, tParms.scale);
  1414. tParms.me = ent->s.number;
  1415. tParms.groundEnt = ent->client->ps.groundEntityNum;
  1416. tParms.collisionType = 1;
  1417. tParms.RagPhase=CRagDollParams::ERagPhase::RP_DEATH_COLLISION;
  1418. tParms.fShotStrength = 4;
  1419. gi.G2API_SetRagDoll(ent->ghoul2, &tParms);
  1420. tuParms.hasEffectorData = qfalse;
  1421. VectorClear(tuParms.effectorTotal);
  1422. VectorCopy(G2Angles, tuParms.angles);
  1423. VectorCopy(usedOrg, tuParms.position);
  1424. VectorCopy(ent->s.modelScale, tuParms.scale);
  1425. tuParms.me = ent->s.number;
  1426. tuParms.settleFrame = tParms.endFrame-1;
  1427. tuParms.groundEnt = ent->client->ps.groundEntityNum;
  1428. if (ent->client->ps.groundEntityNum != ENTITYNUM_NONE)
  1429. {
  1430. VectorClear(tuParms.velocity);
  1431. }
  1432. else
  1433. {
  1434. VectorScale(ent->client->ps.velocity, 0.4f, tuParms.velocity);
  1435. }
  1436. gi.G2API_AnimateG2Models(ent->ghoul2, (cg.time?cg.time:level.time), &tuParms);
  1437. if (ent->client->ps.heldByClient <= ENTITYNUM_WORLD)
  1438. {
  1439. gentity_t *grabEnt;
  1440. grabEnt = &g_entities[ent->client->ps.heldByClient];
  1441. if (grabEnt->client && grabEnt->ghoul2.size())
  1442. {
  1443. vec3_t bOrg;
  1444. vec3_t thisHand;
  1445. vec3_t hands;
  1446. vec3_t pcjMin, pcjMax;
  1447. vec3_t pDif;
  1448. vec3_t thorPoint;
  1449. float difLen;
  1450. //Get the person who is holding our hand's hand location
  1451. //gi.G2API_GetBoltMatrix(grabEnt->ghoul2, 0, grabEnt->gent->client->renderInfo.handRPoint, &matrix, grabEnt->turAngles, grabEnt->lerpOrigin,
  1452. // cg.time, cgs.gameModels, grabEnt->modelScale);
  1453. //BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, bOrg);
  1454. VectorCopy(grabEnt->client->renderInfo.handRPoint, bOrg);
  1455. //Get our hand's location
  1456. //trap_G2API_GetBoltMatrix(cent->ghoul2, 0, 0, &matrix, cent->turAngles, cent->lerpOrigin,
  1457. // cg.time, cgs.gameModels, cent->modelScale);
  1458. //BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, thisHand);
  1459. VectorCopy(ent->client->renderInfo.handRPoint, thisHand);
  1460. //Get the position of the thoracic bone for hinting its velocity later on
  1461. //thorBolt = trap_G2API_AddBolt(cent->ghoul2, 0, "thoracic");
  1462. //trap_G2API_GetBoltMatrix(cent->ghoul2, 0, thorBolt, &matrix, cent->turAngles, cent->lerpOrigin,
  1463. // cg.time, cgs.gameModels, cent->modelScale);
  1464. //BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, thorPoint);
  1465. VectorCopy(ent->client->renderInfo.torsoPoint, thorPoint);
  1466. VectorSubtract(bOrg, thisHand, hands);
  1467. if (VectorLength(hands) < 3.0f)
  1468. {
  1469. gi.G2API_RagForceSolve(ent->ghoul2, qfalse);
  1470. }
  1471. else
  1472. {
  1473. gi.G2API_RagForceSolve(ent->ghoul2, qtrue);
  1474. }
  1475. //got the hand pos of him, now we want to make our hand go to it
  1476. gi.G2API_RagEffectorGoal(ent->ghoul2, "rhand", bOrg);
  1477. gi.G2API_RagEffectorGoal(ent->ghoul2, "rradius", bOrg);
  1478. gi.G2API_RagEffectorGoal(ent->ghoul2, "rradiusX", bOrg);
  1479. gi.G2API_RagEffectorGoal(ent->ghoul2, "rhumerusX", bOrg);
  1480. gi.G2API_RagEffectorGoal(ent->ghoul2, "rhumerus", bOrg);
  1481. //Make these two solve quickly so we can update decently
  1482. gi.G2API_RagPCJGradientSpeed(ent->ghoul2, "rhumerus", 1.5f);
  1483. gi.G2API_RagPCJGradientSpeed(ent->ghoul2, "rradius", 1.5f);
  1484. //Break the constraints on them I suppose
  1485. VectorSet(pcjMin, -999, -999, -999);
  1486. VectorSet(pcjMax, 999, 999, 999);
  1487. gi.G2API_RagPCJConstraint(ent->ghoul2, "rhumerus", pcjMin, pcjMax);
  1488. gi.G2API_RagPCJConstraint(ent->ghoul2, "rradius", pcjMin, pcjMax);
  1489. ent->client->overridingBones = level.time + 2000;
  1490. //hit the thoracic velocity to the hand point
  1491. VectorSubtract(bOrg, thorPoint, hands);
  1492. VectorNormalize(hands);
  1493. VectorScale(hands, 2048.0f, hands);
  1494. gi.G2API_RagEffectorKick(ent->ghoul2, "thoracic", hands);
  1495. gi.G2API_RagEffectorKick(ent->ghoul2, "ceyebrow", hands);
  1496. VectorSubtract(ent->client->ragLastOrigin, ent->client->ps.origin, pDif);
  1497. VectorCopy(ent->client->ps.origin, ent->client->ragLastOrigin);
  1498. if (ent->client->ragLastOriginTime >= level.time && ent->client->ps.groundEntityNum != ENTITYNUM_NONE)
  1499. { //make sure it's reasonably updated
  1500. difLen = VectorLength(pDif);
  1501. if (difLen > 0.0f)
  1502. { //if we're being dragged, then kick all the bones around a bit
  1503. vec3_t dVel;
  1504. vec3_t rVel;
  1505. int i = 0;
  1506. if (difLen < 12.0f)
  1507. {
  1508. VectorScale(pDif, 12.0f/difLen, pDif);
  1509. difLen = 12.0f;
  1510. }
  1511. while (g_effectorStringTable[i])
  1512. {
  1513. VectorCopy(pDif, dVel);
  1514. dVel[2] = 0;
  1515. //Factor in a random velocity
  1516. VectorSet(rVel, Q_flrand(-0.1f, 0.1f), Q_flrand(-0.1f, 0.1f), Q_flrand(0.1f, 0.5));
  1517. VectorScale(rVel, 8.0f, rVel);
  1518. VectorAdd(dVel, rVel, dVel);
  1519. VectorScale(dVel, 10.0f, dVel);
  1520. gi.G2API_RagEffectorKick(ent->ghoul2, g_effectorStringTable[i], dVel);
  1521. i++;
  1522. }
  1523. }
  1524. }
  1525. ent->client->ragLastOriginTime = level.time + 1000;
  1526. }
  1527. }
  1528. else if (ent->client->overridingBones)
  1529. { //reset things to their normal rag state
  1530. vec3_t pcjMin, pcjMax;
  1531. vec3_t dVel;
  1532. //got the hand pos of him, now we want to make our hand go to it
  1533. gi.G2API_RagEffectorGoal(ent->ghoul2, "rhand", NULL);
  1534. gi.G2API_RagEffectorGoal(ent->ghoul2, "rradius", NULL);
  1535. gi.G2API_RagEffectorGoal(ent->ghoul2, "rradiusX", NULL);
  1536. gi.G2API_RagEffectorGoal(ent->ghoul2, "rhumerusX", NULL);
  1537. gi.G2API_RagEffectorGoal(ent->ghoul2, "rhumerus", NULL);
  1538. VectorSet(dVel, 0.0f, 0.0f, -64.0f);
  1539. gi.G2API_RagEffectorKick(ent->ghoul2, "rhand", dVel);
  1540. gi.G2API_RagPCJGradientSpeed(ent->ghoul2, "rhumerus", 0.0f);
  1541. gi.G2API_RagPCJGradientSpeed(ent->ghoul2, "rradius", 0.0f);
  1542. VectorSet(pcjMin,-100.0f,-40.0f,-15.0f);
  1543. VectorSet(pcjMax,-15.0f,80.0f,15.0f);
  1544. gi.G2API_RagPCJConstraint(ent->ghoul2, "rhumerus", pcjMin, pcjMax);
  1545. VectorSet(pcjMin,-25.0f,-20.0f,-20.0f);
  1546. VectorSet(pcjMax,90.0f,20.0f,-20.0f);
  1547. gi.G2API_RagPCJConstraint(ent->ghoul2, "rradius", pcjMin, pcjMax);
  1548. if (ent->client->overridingBones < level.time)
  1549. {
  1550. gi.G2API_RagForceSolve(ent->ghoul2, qfalse);
  1551. ent->client->overridingBones = 0;
  1552. }
  1553. else
  1554. {
  1555. gi.G2API_RagForceSolve(ent->ghoul2, qtrue);
  1556. }
  1557. }
  1558. if (tuParms.hasEffectorData)
  1559. {
  1560. /*
  1561. vec3_t efDir;
  1562. vec3_t existingVelocity;
  1563. float evValue = 0;
  1564. VectorCopy(tuParms.effectorTotal, efDir);
  1565. VectorNormalize(efDir);
  1566. VectorCopy(ent->client->ps.velocity, existingVelocity);
  1567. evValue = VectorNormalize(existingVelocity);
  1568. if (evValue < 32)
  1569. {
  1570. ent->client->ps.velocity[0] += efDir[0]*64;
  1571. ent->client->ps.velocity[1] += efDir[1]*64;
  1572. ent->client->ps.velocity[2] += efDir[2]*64;
  1573. }
  1574. */
  1575. VectorNormalize(tuParms.effectorTotal);
  1576. VectorScale(tuParms.effectorTotal, 7.0f, tuParms.effectorTotal);
  1577. VectorAdd(ent->client->ps.velocity, tuParms.effectorTotal, ent->client->ps.velocity);
  1578. }
  1579. return qtrue;
  1580. }
  1581. return qfalse;
  1582. }
  1583. //rww - RAGDOLL_END
  1584. /*
  1585. ================
  1586. G_FreeUselessEnemies
  1587. Continually monitors for enemies that are no longer relevant,
  1588. and kills them off. TODO: Also kill off allies (jedi in kor[12])
  1589. ================
  1590. */
  1591. char current_speeders = 0;
  1592. void G_FreeUselessEnemies(void)
  1593. {
  1594. // We check three entities per frame, cuts down on CPU impact, still
  1595. // ends up checking every entity within about 10 seconds
  1596. static int freeEntNum = 1;
  1597. for( int j = 0; j < 3; ++j )
  1598. {
  1599. if( current_speeders > 24 && // too many speeders
  1600. PInUse(freeEntNum) && // not in use
  1601. g_entities[freeEntNum].health && // has health
  1602. g_entities[freeEntNum].m_pVehicle && // valid vehicle
  1603. g_entities[freeEntNum].m_pVehicle->m_pVehicleInfo && // valid vehicle info
  1604. g_entities[freeEntNum].m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER && // a speeder
  1605. !g_entities[freeEntNum].m_pVehicle->m_pPilot && // doesn't have a pilot
  1606. strcmp(g_entities[freeEntNum].m_pVehicle->m_pVehicleInfo->name, "Swoop_cin")) // not needed for a cinematic
  1607. {
  1608. // blow it up
  1609. G_Damage(&g_entities[freeEntNum], NULL, NULL, 0, 0, 200000, DAMAGE_NO_PROTECTION, MOD_UNKNOWN);
  1610. // decrement the number of speeders
  1611. current_speeders--;
  1612. // set the alreadyCleaned flag so that when the entitiy is removed current_speeders is not decremented again
  1613. g_entities[freeEntNum].m_pVehicle->alreadyCleaned = true;
  1614. }
  1615. // If the entity is an NPC which has no key, isn't invulnerable,
  1616. // has fired, but not in a while, has health, isn't on the player's team,
  1617. // and is far away, destroy it.
  1618. else if( PInUse(freeEntNum) &&
  1619. g_entities[freeEntNum].NPC &&
  1620. !g_entities[freeEntNum].message &&
  1621. g_entities[freeEntNum].client &&
  1622. g_entities[freeEntNum].health &&
  1623. g_entities[freeEntNum].client->playerTeam != TEAM_PLAYER &&
  1624. !(g_entities[freeEntNum].client->ps.powerups[PW_INVINCIBLE]>level.time) &&
  1625. !(g_entities[freeEntNum].flags & FL_UNDYING) &&
  1626. // !(g_entities[freeEntNum].client->ps.eFlags & EF_INVULNERABLE) &&
  1627. g_entities[freeEntNum].NPC->shotTime &&
  1628. g_entities[freeEntNum].NPC->shotTime + 10000 < level.time &&
  1629. DistanceSquared(g_entities[freeEntNum].currentOrigin,
  1630. g_entities[0].currentOrigin) > (2000 * 2000))
  1631. {
  1632. G_Damage(&g_entities[freeEntNum], NULL, NULL, 0, 0, 100000,
  1633. DAMAGE_NO_PROTECTION, MOD_UNKNOWN);
  1634. g_entities[freeEntNum].NPC->timeOfDeath = 0;
  1635. }
  1636. freeEntNum++;
  1637. freeEntNum %= MAX_GENTITIES;
  1638. }
  1639. }
  1640. /*
  1641. ================
  1642. G_RunFrame
  1643. Advances the non-player objects in the world
  1644. ================
  1645. */
  1646. void G_MassFreeUselessThings( void )
  1647. {
  1648. // We check three entities per frame, cuts down on CPU impact, still
  1649. // ends up checking every entity within about 10 seconds
  1650. for( int j = 0; j < MAX_GENTITIES; ++j )
  1651. {
  1652. if( PInUse(j) && // not in use
  1653. g_entities[j].health && // has health
  1654. g_entities[j].m_pVehicle && // valid vehicle
  1655. g_entities[j].m_pVehicle->m_pVehicleInfo && // valid vehicle info
  1656. g_entities[j].m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER && // a speeder
  1657. !g_entities[j].m_pVehicle->m_pPilot && // doesn't have a pilot
  1658. strcmp(g_entities[j].m_pVehicle->m_pVehicleInfo->name, "Swoop_cin")) // not needed for a cinematic
  1659. {
  1660. G_Damage(&g_entities[j], NULL, NULL, 0, 0, 200000, DAMAGE_NO_PROTECTION, MOD_UNKNOWN);
  1661. }
  1662. // If the entity is an NPC which has no key, isn't invulnerable,
  1663. // has fired, but not in a while, has health, isn't on the player's team,
  1664. // and is far away, destroy it.
  1665. else if( (PInUse(j) &&
  1666. g_entities[j].NPC &&
  1667. !g_entities[j].message &&
  1668. g_entities[j].client &&
  1669. g_entities[j].health &&
  1670. g_entities[j].client->playerTeam != TEAM_PLAYER &&
  1671. !(g_entities[j].client->ps.powerups[PW_INVINCIBLE]>level.time) &&
  1672. g_entities[j].NPC->shotTime &&
  1673. g_entities[j].NPC->shotTime + 10000 < level.time &&
  1674. DistanceSquared(g_entities[j].currentOrigin,
  1675. g_entities[0].currentOrigin) > (2000 * 2000)) )
  1676. {
  1677. G_Damage(&g_entities[j], NULL, NULL, 0, 0, 100000,
  1678. DAMAGE_NO_PROTECTION, MOD_UNKNOWN);
  1679. g_entities[j].NPC->timeOfDeath = 0;
  1680. }
  1681. }
  1682. }
  1683. /*
  1684. ================
  1685. G_RunFrame
  1686. Advances the non-player objects in the world
  1687. ================
  1688. */
  1689. #if AI_TIMERS
  1690. int AITime = 0;
  1691. int navTime = 0;
  1692. #endif// AI_TIMERS
  1693. extern cvar_t* in_shaking_rumble;
  1694. void G_RunFrame( int levelTime ) {
  1695. int i;
  1696. gentity_t *ent;
  1697. int msec;
  1698. int ents_inuse=0; // someone's gonna be pissed I put this here...
  1699. #if AI_TIMERS
  1700. AITime = 0;
  1701. navTime = 0;
  1702. #endif// AI_TIMERS
  1703. level.framenum++;
  1704. level.previousTime = level.time;
  1705. level.time = levelTime;
  1706. msec = level.time - level.previousTime;
  1707. //ResetTeamCounters();
  1708. NAV::DecayDangerSenses();
  1709. Rail_Update();
  1710. Troop_Update();
  1711. Pilot_Update();
  1712. if (player && gi.WE_IsShaking(player->currentOrigin))
  1713. {
  1714. CGCam_Shake(0.45f, 100, in_shaking_rumble->integer);
  1715. }
  1716. AI_UpdateGroups();
  1717. //Look to clear out old events
  1718. ClearPlayerAlertEvents();
  1719. //Run the frame for all entities
  1720. // for ( i = 0, ent = &g_entities[0]; i < globals.num_entities ; i++, ent++)
  1721. for ( i = 0; i < globals.num_entities ; i++)
  1722. {
  1723. // if ( !ent->inuse )
  1724. // continue;
  1725. if(!PInUse(i))
  1726. continue;
  1727. ents_inuse++;
  1728. ent = &g_entities[i];
  1729. // clear events that are too old
  1730. if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) {
  1731. if ( ent->s.event ) {
  1732. ent->s.event = 0; // &= EV_EVENT_BITS;
  1733. if ( ent->client ) {
  1734. ent->client->ps.externalEvent = 0;
  1735. }
  1736. }
  1737. if ( ent->freeAfterEvent ) {
  1738. // tempEntities or dropped items completely go away after their event
  1739. G_FreeEntity( ent );
  1740. continue;
  1741. }
  1742. /* // This is never set to true anywhere. Killing the field (BTO - VV)
  1743. else if ( ent->unlinkAfterEvent ) {
  1744. // items that will respawn will hide themselves after their pickup event
  1745. ent->unlinkAfterEvent = qfalse;
  1746. gi.unlinkentity( ent );
  1747. }
  1748. */
  1749. }
  1750. // temporary entities don't think
  1751. if ( ent->freeAfterEvent )
  1752. continue;
  1753. G_CheckTasksCompleted(ent);
  1754. G_Roff( ent );
  1755. if( !ent->client )
  1756. {
  1757. if ( !(ent->svFlags & SVF_SELF_ANIMATING) )
  1758. {//FIXME: make sure this is done only for models with frames?
  1759. //Or just flag as animating?
  1760. if ( ent->s.eFlags & EF_ANIM_ONCE )
  1761. {
  1762. ent->s.frame++;
  1763. }
  1764. else if ( !(ent->s.eFlags & EF_ANIM_ALLFAST) )
  1765. {
  1766. G_Animate( ent );
  1767. }
  1768. }
  1769. }
  1770. G_CheckSpecialPersistentEvents( ent );
  1771. if ( ent->s.eType == ET_MISSILE )
  1772. {
  1773. G_RunMissile( ent );
  1774. continue;
  1775. }
  1776. if ( ent->s.eType == ET_ITEM )
  1777. {
  1778. G_RunItem( ent );
  1779. continue;
  1780. }
  1781. if ( ent->s.eType == ET_MOVER )
  1782. {
  1783. if ( ent->model && Q_stricmp( "models/test/mikeg/tie_fighter.md3", ent->model ) == 0 )
  1784. {
  1785. TieFighterThink( ent );
  1786. }
  1787. G_RunMover( ent );
  1788. continue;
  1789. }
  1790. //The player
  1791. if ( i == 0 )
  1792. {
  1793. // decay batteries if the goggles are active
  1794. if ( cg.zoomMode == 1 && ent->client->ps.batteryCharge > 0 )
  1795. {
  1796. ent->client->ps.batteryCharge--;
  1797. }
  1798. else if ( cg.zoomMode == 3 && ent->client->ps.batteryCharge > 0 )
  1799. {
  1800. ent->client->ps.batteryCharge -= 2;
  1801. if ( ent->client->ps.batteryCharge < 0 )
  1802. {
  1803. ent->client->ps.batteryCharge = 0;
  1804. }
  1805. }
  1806. G_CheckEndLevelTimers( ent );
  1807. //Recalculate the nearest waypoint for the coming NPC updates
  1808. NAV::GetNearestNode( ent );
  1809. if( ent->m_iIcarusID != IIcarusInterface::ICARUS_INVALID && !stop_icarus )
  1810. {
  1811. IIcarusInterface::GetIcarus()->Update( ent->m_iIcarusID );
  1812. }
  1813. //dead
  1814. if ( ent->health <= 0 )
  1815. {
  1816. if ( ent->client->ps.groundEntityNum != ENTITYNUM_NONE )
  1817. {//on the ground
  1818. pitch_roll_for_slope( ent );
  1819. }
  1820. }
  1821. continue; // players are ucmd driven
  1822. }
  1823. G_RunThink( ent ); // be aware that ent may be free after returning from here, at least one func frees them
  1824. ClearNPCGlobals(); // but these 2 funcs are ok
  1825. //UpdateTeamCounters( ent ); // to call anyway on a freed ent.
  1826. }
  1827. // perform final fixups on the player
  1828. ent = &g_entities[0];
  1829. if ( ent->inuse )
  1830. {
  1831. ClientEndFrame( ent );
  1832. }
  1833. if( g_numEntities->integer )
  1834. {
  1835. gi.Printf( S_COLOR_WHITE"Number of Entities in use : %d\n", ents_inuse );
  1836. }
  1837. //DEBUG STUFF
  1838. NAV::ShowDebugInfo(ent->currentOrigin, ent->waypoint);
  1839. NPC_ShowDebugInfo();
  1840. G_DynamicMusicUpdate();
  1841. #if AI_TIMERS
  1842. AITime -= navTime;
  1843. if ( AITime > 20 )
  1844. {
  1845. gi.Printf( S_COLOR_RED"ERROR: total AI time: %d\n", AITime );
  1846. }
  1847. else if ( AITime > 10 )
  1848. {
  1849. gi.Printf( S_COLOR_YELLOW"WARNING: total AI time: %d\n", AITime );
  1850. }
  1851. else if ( AITime > 2 )
  1852. {
  1853. gi.Printf( S_COLOR_GREEN"total AI time: %d\n", AITime );
  1854. }
  1855. if ( navTime > 20 )
  1856. {
  1857. gi.Printf( S_COLOR_RED"ERROR: total nav time: %d\n", navTime );
  1858. }
  1859. else if ( navTime > 10 )
  1860. {
  1861. gi.Printf( S_COLOR_YELLOW"WARNING: total nav time: %d\n", navTime );
  1862. }
  1863. else if ( navTime > 2 )
  1864. {
  1865. gi.Printf( S_COLOR_GREEN"total nav time: %d\n", navTime );
  1866. }
  1867. #endif// AI_TIMERS
  1868. extern int delayedShutDown;
  1869. if ( g_delayedShutdown->integer && delayedShutDown != 0 && delayedShutDown < level.time )
  1870. {
  1871. assert(0);
  1872. G_Error( "Game Errors. Scroll up the console to read them.\n" );
  1873. }
  1874. #ifdef _DEBUG
  1875. if(!(level.framenum&0xff))
  1876. {
  1877. ValidateInUseBits();
  1878. }
  1879. #endif
  1880. #ifdef _XBOX
  1881. // update the water levels for npcs
  1882. extern void UpdateNPCWaterLevels(void);
  1883. UpdateNPCWaterLevels();
  1884. // Kill off any AI that are lingering!
  1885. G_FreeUselessEnemies();
  1886. #endif // _XBOX
  1887. }
  1888. extern qboolean player_locked;
  1889. void G_LoadSave_WriteMiscData(void)
  1890. {
  1891. gi.AppendToSaveGame('LCKD', &player_locked, sizeof(player_locked));
  1892. }
  1893. void G_LoadSave_ReadMiscData(void)
  1894. {
  1895. gi.ReadFromSaveGame('LCKD', &player_locked, sizeof(player_locked));
  1896. }
  1897. /*
  1898. void PrintEntClassname( int gentNum )
  1899. {
  1900. Com_Printf( "%d: %s in snapshot\n", gentNum, g_entities[gentNum].classname );
  1901. }
  1902. */
  1903. IGhoul2InfoArray &TheGameGhoul2InfoArray()
  1904. {
  1905. return gi.TheGhoul2InfoArray();
  1906. }
  1907. extern bool bHadPersistedSurface;
  1908. gentity_t *pReservedZoneGentities = NULL;
  1909. void G_ReserveZoneGentities( void )
  1910. {
  1911. pReservedZoneGentities = (gentity_t *) Z_Malloc( sizeof(gentity_t) * MAX_GENTITIES, TAG_TEMP_WORKSPACE, qfalse, 4 );
  1912. }
  1913. void G_AllocGentities( void )
  1914. {
  1915. g_entities = (gentity_t *) HeapAlloc( GetProcessHeap(), 0, sizeof(gentity_t) * MAX_GENTITIES );
  1916. // If it worked...
  1917. if( g_entities )
  1918. {
  1919. // And we had a persisted surface. (Normal case). Free the reserved zone:
  1920. if( bHadPersistedSurface )
  1921. {
  1922. Z_Free( pReservedZoneGentities );
  1923. pReservedZoneGentities = NULL;
  1924. return;
  1925. }
  1926. // Really bad case #1:
  1927. Com_PrintfAlways( "G_AllocGentities: Extreme failure #1\n" );
  1928. return;
  1929. }
  1930. else
  1931. {
  1932. // It failed. Hopefully that means that there was no persisted surface.
  1933. if( !bHadPersistedSurface )
  1934. {
  1935. g_entities = pReservedZoneGentities;
  1936. pReservedZoneGentities = NULL;
  1937. return;
  1938. }
  1939. // Really bad case #2:
  1940. Com_PrintfAlways( "G_AllocGentities: Extreme failure #2\n" );
  1941. return;
  1942. }
  1943. }