g_utils.cpp 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182
  1. // g_utils.c -- misc utility functions for game module
  2. // leave this line at the top for all g_xxxx.cpp files...
  3. #include "g_headers.h"
  4. #include "Q3_Interface.h"
  5. #include "g_local.h"
  6. #include "g_functions.h"
  7. #ifdef _XBOX
  8. #include "anims.h"
  9. #include "..\renderer\mdx_format.h"
  10. #include "..\qcommon\cm_public.h"
  11. #include "..\qcommon\cm_local.h"
  12. #endif
  13. #define ACT_ACTIVE qtrue
  14. #define ACT_INACTIVE qfalse
  15. extern void NPC_UseResponse ( gentity_t *self, gentity_t *user, qboolean useWhenDone );
  16. extern qboolean PM_CrouchAnim( int anim );
  17. /*
  18. =========================================================================
  19. model / sound configstring indexes
  20. =========================================================================
  21. */
  22. /*
  23. ================
  24. G_FindConfigstringIndex
  25. ================
  26. */
  27. extern void ForceTelepathy( gentity_t *self );
  28. int G_FindConfigstringIndex( const char *name, int start, int max, qboolean create ) {
  29. int i;
  30. char s[MAX_STRING_CHARS];
  31. if ( !name || !name[0] ) {
  32. return 0;
  33. }
  34. for ( i=1 ; i<max ; i++ ) {
  35. gi.GetConfigstring( start + i, s, sizeof( s ) );
  36. if ( !s[0] ) {
  37. break;
  38. }
  39. if ( !stricmp( s, name ) ) {
  40. return i;
  41. }
  42. }
  43. if ( !create ) {
  44. return 0;
  45. }
  46. if ( i == max ) {
  47. G_Error( "G_FindConfigstringIndex: overflow adding %s to set %d-%d", name, start, max );
  48. }
  49. gi.SetConfigstring( start + i, name );
  50. return i;
  51. }
  52. /*
  53. Ghoul2 Insert Start
  54. */
  55. int G_SkinIndex( const char *name ) {
  56. return G_FindConfigstringIndex (name, CS_CHARSKINS, MAX_CHARSKINS, qtrue);
  57. }
  58. /*
  59. Ghoul2 Insert End
  60. */
  61. int G_ModelIndex( const char *name ) {
  62. return G_FindConfigstringIndex (name, CS_MODELS, MAX_MODELS, qtrue);
  63. }
  64. int G_SoundIndex( const char *name ) {
  65. assert( name && name[0] );
  66. char stripped[MAX_QPATH];
  67. COM_StripExtension(name, stripped);
  68. return G_FindConfigstringIndex (stripped, CS_SOUNDS, MAX_SOUNDS, qtrue);
  69. }
  70. int G_EffectIndex( const char *name )
  71. {
  72. char temp[MAX_QPATH];
  73. // We just don't want extensions on the things we are registering
  74. COM_StripExtension( name, temp );
  75. return G_FindConfigstringIndex( temp, CS_EFFECTS, MAX_FX, qtrue );
  76. }
  77. int G_BSPIndex( char *name )
  78. {
  79. return G_FindConfigstringIndex (name, CS_BSP_MODELS, MAX_SUB_BSP, qtrue);
  80. }
  81. #define FX_ENT_RADIUS 32
  82. //-----------------------------
  83. // Effect playing utilities
  84. //-----------------------------
  85. //-----------------------------
  86. void G_PlayEffect( int fxID, const vec3_t origin, const vec3_t fwd )
  87. {
  88. gentity_t *tent;
  89. vec3_t temp;
  90. tent = G_TempEntity( origin, EV_PLAY_EFFECT );
  91. tent->s.eventParm = fxID;
  92. VectorSet( tent->maxs, FX_ENT_RADIUS, FX_ENT_RADIUS, FX_ENT_RADIUS );
  93. VectorScale( tent->maxs, -1, tent->mins );
  94. VectorCopy( fwd, tent->pos3 );
  95. // Assume angles, we'll do a cross product on the other end to finish up
  96. MakeNormalVectors( fwd, tent->pos4, temp );
  97. gi.linkentity( tent );
  98. }
  99. // Play an effect at the origin of the specified entity
  100. //----------------------------
  101. void G_PlayEffect( int fxID, int entNum, const vec3_t fwd )
  102. {
  103. gentity_t *tent;
  104. vec3_t temp;
  105. tent = G_TempEntity( g_entities[entNum].currentOrigin, EV_PLAY_EFFECT );
  106. tent->s.eventParm = fxID;
  107. tent->s.otherEntityNum = entNum;
  108. VectorSet( tent->maxs, FX_ENT_RADIUS, FX_ENT_RADIUS, FX_ENT_RADIUS );
  109. VectorScale( tent->maxs, -1, tent->mins );
  110. VectorCopy( fwd, tent->pos3 );
  111. // Assume angles, we'll do a cross product on the other end to finish up
  112. MakeNormalVectors( fwd, tent->pos4, temp );
  113. }
  114. // Play an effect bolted onto the muzzle of the specified client
  115. //----------------------------
  116. void G_PlayEffect( const char *name, int clientNum )
  117. {
  118. gentity_t *tent;
  119. tent = G_TempEntity( g_entities[clientNum].currentOrigin, EV_PLAY_MUZZLE_EFFECT );
  120. tent->s.eventParm = G_EffectIndex( name );
  121. tent->s.otherEntityNum = clientNum;
  122. VectorSet( tent->maxs, FX_ENT_RADIUS, FX_ENT_RADIUS, FX_ENT_RADIUS );
  123. VectorScale( tent->maxs, -1, tent->mins );
  124. }
  125. #ifdef _IMMERSION
  126. // Play an effect at a position on an entity.
  127. // Mostly for G_MissileBounceEffect so we can play an effect on the bouncee.
  128. //-----------------------------
  129. void G_PlayEffect( int fxID, int clientNum, const vec3_t origin, const vec3_t fwd )
  130. {
  131. gentity_t *tent;
  132. vec3_t temp;
  133. tent = G_TempEntity( origin, EV_PLAY_EFFECT );
  134. tent->s.eventParm = fxID;
  135. if ( clientNum != -1 )
  136. {
  137. tent->s.saberActive = 1;
  138. tent->s.otherEntityNum = clientNum;
  139. }
  140. VectorSet( tent->maxs, FX_ENT_RADIUS, FX_ENT_RADIUS, FX_ENT_RADIUS );
  141. VectorScale( tent->maxs, -1, tent->mins );
  142. VectorCopy( fwd, tent->pos3 );
  143. // Assume angles, we'll do a cross product on the other end to finish up
  144. MakeNormalVectors( fwd, tent->pos4, temp );
  145. }
  146. //-----------------------------
  147. void G_PlayEffect( const char *name, int clientNum, const vec3_t origin, const vec3_t fwd )
  148. {
  149. G_PlayEffect( G_EffectIndex( name ), clientNum, origin, fwd );
  150. }
  151. #endif // _IMMERSION
  152. //-----------------------------
  153. void G_PlayEffect( int fxID, const vec3_t origin, const vec3_t axis[3] )
  154. {
  155. gentity_t *tent;
  156. tent = G_TempEntity( origin, EV_PLAY_EFFECT );
  157. tent->s.eventParm = fxID;
  158. VectorSet( tent->maxs, FX_ENT_RADIUS, FX_ENT_RADIUS, FX_ENT_RADIUS );
  159. VectorScale( tent->maxs, -1, tent->mins );
  160. // We can just assume axis[2] from doing a cross product on these.
  161. VectorCopy( axis[0], tent->pos3 );
  162. VectorCopy( axis[1], tent->pos4 );
  163. }
  164. // Effect playing utilities - bolt an effect to a ghoul2 models bolton point
  165. //-----------------------------
  166. void G_PlayEffect( int fxID, const int modelIndex, const int boltIndex, const int entNum, const vec3_t origin, int iLoopTime, qboolean isRelative )//iLoopTime 0 = not looping, 1 for infinite, else duration
  167. {
  168. gentity_t *tent;
  169. tent = G_TempEntity( origin, EV_PLAY_EFFECT );
  170. tent->s.eventParm = fxID;
  171. tent->s.loopSound = iLoopTime;
  172. tent->s.weapon = isRelative;
  173. tent->svFlags |=SVF_BROADCAST;
  174. gi.G2API_AttachEnt(&tent->s.boltInfo, &g_entities[entNum].ghoul2[modelIndex], boltIndex, entNum, modelIndex);
  175. }
  176. //-----------------------------
  177. void G_PlayEffect( const char *name, const vec3_t origin )
  178. {
  179. vec3_t up = {0, 0, 1};
  180. G_PlayEffect( G_EffectIndex( name ), origin, up );
  181. }
  182. //-----------------------------
  183. void G_PlayEffect( const char *name, const vec3_t origin, const vec3_t fwd )
  184. {
  185. G_PlayEffect( G_EffectIndex( name ), origin, fwd );
  186. }
  187. //-----------------------------
  188. void G_PlayEffect( const char *name, const vec3_t origin, const vec3_t axis[3] )
  189. {
  190. G_PlayEffect( G_EffectIndex( name ), origin, axis );
  191. }
  192. void G_StopEffect( int fxID, const int modelIndex, const int boltIndex, const int entNum )
  193. {
  194. gentity_t *tent;
  195. tent = G_TempEntity( g_entities[entNum].currentOrigin, EV_STOP_EFFECT );
  196. tent->s.eventParm = fxID;
  197. tent->svFlags |= SVF_BROADCAST;
  198. gi.G2API_AttachEnt( &tent->s.boltInfo, &g_entities[entNum].ghoul2[modelIndex], boltIndex, entNum, modelIndex );
  199. }
  200. void G_StopEffect(const char *name, const int modelIndex, const int boltIndex, const int entNum )
  201. {
  202. G_StopEffect( G_EffectIndex( name ), modelIndex, boltIndex, entNum );
  203. }
  204. #ifdef _XBOX
  205. //-----------------------------
  206. void G_EntityPosition( int i, vec3_t ret )
  207. {
  208. if ( /*g_entities &&*/ i >= 0 && i < MAX_GENTITIES && g_entities[i].inuse)
  209. {
  210. gentity_t *ent = g_entities + i;
  211. if (ent->bmodel)
  212. {
  213. vec3_t mins, maxs;
  214. clipHandle_t h = CM_InlineModel( ent->s.modelindex );
  215. CM_ModelBounds( cmg, h, mins, maxs );
  216. ret[0] = (mins[0] + maxs[0]) / 2 + ent->currentOrigin[0];
  217. ret[1] = (mins[1] + maxs[1]) / 2 + ent->currentOrigin[1];
  218. ret[2] = (mins[2] + maxs[2]) / 2 + ent->currentOrigin[2];
  219. }
  220. else
  221. {
  222. VectorCopy(g_entities[i].currentOrigin, ret);
  223. }
  224. }
  225. else
  226. {
  227. ret[0] = ret[1] = ret[2] = 0;
  228. }
  229. }
  230. #endif
  231. //===Bypass network for sounds on specific channels====================
  232. extern void cgi_S_StartSound( const vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
  233. #include "..\cgame\cg_media.h" //access to cgs
  234. extern qboolean CG_TryPlayCustomSound( vec3_t origin, int entityNum, soundChannel_t channel, const char *soundName, int customSoundSet );
  235. extern cvar_t *g_timescale;
  236. //NOTE: Do NOT Try to use this before the cgame DLL is valid, it will NOT work!
  237. void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath )
  238. {
  239. int index = G_SoundIndex( (char *)soundPath );
  240. if ( !ent )
  241. {
  242. return;
  243. }
  244. if ( g_timescale->integer > 50 )
  245. {//Skip the sound!
  246. return;
  247. }
  248. cgi_S_UpdateEntityPosition( ent->s.number, ent->currentOrigin );
  249. if ( cgs.sound_precache[ index ] )
  250. {
  251. cgi_S_StartSound( NULL, ent->s.number, channel, cgs.sound_precache[ index ] );
  252. }
  253. else
  254. {
  255. CG_TryPlayCustomSound( NULL, ent->s.number, channel, soundPath, -1 );
  256. }
  257. }
  258. void G_SoundIndexOnEnt( gentity_t *ent, soundChannel_t channel, int index )
  259. {
  260. if ( !ent )
  261. {
  262. return;
  263. }
  264. cgi_S_UpdateEntityPosition( ent->s.number, ent->currentOrigin );
  265. if ( cgs.sound_precache[ index ] )
  266. {
  267. cgi_S_StartSound( NULL, ent->s.number, channel, cgs.sound_precache[ index ] );
  268. }
  269. }
  270. extern cvar_t *g_skippingcin;
  271. void G_SpeechEvent( gentity_t *self, int event )
  272. {
  273. if ( in_camera
  274. && g_skippingcin
  275. && g_skippingcin->integer )
  276. {//Skipping a cinematic, so skip NPC voice sounds...
  277. return;
  278. }
  279. //update entity pos, too
  280. cgi_S_UpdateEntityPosition( self->s.number, self->currentOrigin );
  281. switch ( event )
  282. {
  283. case EV_ANGER1: //Say when acquire an enemy when didn't have one before
  284. case EV_ANGER2:
  285. case EV_ANGER3:
  286. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*anger%i.wav", event - EV_ANGER1 + 1), CS_COMBAT );
  287. break;
  288. case EV_VICTORY1: //Say when killed an enemy
  289. case EV_VICTORY2:
  290. case EV_VICTORY3:
  291. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*victory%i.wav", event - EV_VICTORY1 + 1), CS_COMBAT );
  292. break;
  293. case EV_CONFUSE1: //Say when confused
  294. case EV_CONFUSE2:
  295. case EV_CONFUSE3:
  296. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*confuse%i.wav", event - EV_CONFUSE1 + 1), CS_COMBAT );
  297. break;
  298. case EV_PUSHED1: //Say when pushed
  299. case EV_PUSHED2:
  300. case EV_PUSHED3:
  301. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*pushed%i.wav", event - EV_PUSHED1 + 1), CS_COMBAT );
  302. break;
  303. case EV_CHOKE1: //Say when choking
  304. case EV_CHOKE2:
  305. case EV_CHOKE3:
  306. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*choke%i.wav", event - EV_CHOKE1 + 1), CS_COMBAT );
  307. break;
  308. case EV_FFWARN: //Warn ally to stop shooting you
  309. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, "*ffwarn.wav", CS_COMBAT );
  310. break;
  311. case EV_FFTURN: //Turn on ally after being shot by them
  312. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, "*ffturn.wav", CS_COMBAT );
  313. break;
  314. //extra sounds for ST
  315. case EV_CHASE1:
  316. case EV_CHASE2:
  317. case EV_CHASE3:
  318. if ( !CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*chase%i.wav", event - EV_CHASE1 + 1), CS_EXTRA ) )
  319. {
  320. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*anger%i.wav", Q_irand(1,3)), CS_COMBAT );
  321. }
  322. break;
  323. case EV_COVER1:
  324. case EV_COVER2:
  325. case EV_COVER3:
  326. case EV_COVER4:
  327. case EV_COVER5:
  328. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*cover%i.wav", event - EV_COVER1 + 1), CS_EXTRA );
  329. break;
  330. case EV_DETECTED1:
  331. case EV_DETECTED2:
  332. case EV_DETECTED3:
  333. case EV_DETECTED4:
  334. case EV_DETECTED5:
  335. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*detected%i.wav", event - EV_DETECTED1 + 1), CS_EXTRA );
  336. break;
  337. case EV_GIVEUP1:
  338. case EV_GIVEUP2:
  339. case EV_GIVEUP3:
  340. case EV_GIVEUP4:
  341. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*giveup%i.wav", event - EV_GIVEUP1 + 1), CS_EXTRA );
  342. break;
  343. case EV_LOOK1:
  344. case EV_LOOK2:
  345. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*look%i.wav", event - EV_LOOK1 + 1), CS_EXTRA );
  346. break;
  347. case EV_LOST1:
  348. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, "*lost1.wav", CS_EXTRA );
  349. break;
  350. case EV_OUTFLANK1:
  351. case EV_OUTFLANK2:
  352. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*outflank%i.wav", event - EV_OUTFLANK1 + 1), CS_EXTRA );
  353. break;
  354. case EV_ESCAPING1:
  355. case EV_ESCAPING2:
  356. case EV_ESCAPING3:
  357. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*escaping%i.wav", event - EV_ESCAPING1 + 1), CS_EXTRA );
  358. break;
  359. case EV_SIGHT1:
  360. case EV_SIGHT2:
  361. case EV_SIGHT3:
  362. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*sight%i.wav", event - EV_SIGHT1 + 1), CS_EXTRA );
  363. break;
  364. case EV_SOUND1:
  365. case EV_SOUND2:
  366. case EV_SOUND3:
  367. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*sound%i.wav", event - EV_SOUND1 + 1), CS_EXTRA );
  368. break;
  369. case EV_SUSPICIOUS1:
  370. case EV_SUSPICIOUS2:
  371. case EV_SUSPICIOUS3:
  372. case EV_SUSPICIOUS4:
  373. case EV_SUSPICIOUS5:
  374. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*suspicious%i.wav", event - EV_SUSPICIOUS1 + 1), CS_EXTRA );
  375. break;
  376. //extra sounds for Jedi
  377. case EV_COMBAT1:
  378. case EV_COMBAT2:
  379. case EV_COMBAT3:
  380. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*combat%i.wav", event - EV_COMBAT1 + 1), CS_JEDI );
  381. break;
  382. case EV_JDETECTED1:
  383. case EV_JDETECTED2:
  384. case EV_JDETECTED3:
  385. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*jdetected%i.wav", event - EV_JDETECTED1 + 1), CS_JEDI );
  386. break;
  387. case EV_TAUNT1:
  388. case EV_TAUNT2:
  389. case EV_TAUNT3:
  390. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*taunt%i.wav", event - EV_TAUNT1 + 1), CS_JEDI );
  391. break;
  392. case EV_JCHASE1:
  393. case EV_JCHASE2:
  394. case EV_JCHASE3:
  395. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*jchase%i.wav", event - EV_JCHASE1 + 1), CS_JEDI );
  396. break;
  397. case EV_JLOST1:
  398. case EV_JLOST2:
  399. case EV_JLOST3:
  400. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*jlost%i.wav", event - EV_JLOST1 + 1), CS_JEDI );
  401. break;
  402. case EV_DEFLECT1:
  403. case EV_DEFLECT2:
  404. case EV_DEFLECT3:
  405. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*deflect%i.wav", event - EV_DEFLECT1 + 1), CS_JEDI );
  406. break;
  407. case EV_GLOAT1:
  408. case EV_GLOAT2:
  409. case EV_GLOAT3:
  410. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*gloat%i.wav", event - EV_GLOAT1 + 1), CS_JEDI );
  411. break;
  412. case EV_PUSHFAIL:
  413. CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, "*pushfail.wav", CS_JEDI );
  414. break;
  415. }
  416. }
  417. //=====================================================================
  418. /*
  419. =============
  420. G_Find
  421. Searches all active entities for the next one that holds
  422. the matching string at fieldofs (use the FOFS() macro) in the structure.
  423. Searches beginning at the entity after from, or the beginning if NULL
  424. NULL will be returned if the end of the list is reached.
  425. =============
  426. */
  427. gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match)
  428. {
  429. char *s;
  430. if(!match || !match[0])
  431. {
  432. return NULL;
  433. }
  434. if (!from)
  435. from = g_entities;
  436. else
  437. from++;
  438. // for ( ; from < &g_entities[globals.num_entities] ; from++)
  439. int i=from-g_entities;
  440. for ( ; i < globals.num_entities ; i++)
  441. {
  442. // if (!from->inuse)
  443. if(!PInUse(i))
  444. continue;
  445. from=&g_entities[i];
  446. s = *(char **) ((byte *)from + fieldofs);
  447. if (!s)
  448. continue;
  449. if (!Q_stricmp (s, match))
  450. return from;
  451. }
  452. return NULL;
  453. }
  454. /*
  455. ============
  456. G_RadiusList - given an origin and a radius, return all entities that are in use that are within the list
  457. ============
  458. */
  459. int G_RadiusList ( vec3_t origin, float radius, gentity_t *ignore, qboolean takeDamage, gentity_t *ent_list[MAX_GENTITIES])
  460. {
  461. float dist;
  462. gentity_t *ent;
  463. gentity_t *entityList[MAX_GENTITIES];
  464. int numListedEntities;
  465. vec3_t mins, maxs;
  466. vec3_t v;
  467. int i, e;
  468. int ent_count = 0;
  469. if ( radius < 1 )
  470. {
  471. radius = 1;
  472. }
  473. for ( i = 0 ; i < 3 ; i++ )
  474. {
  475. mins[i] = origin[i] - radius;
  476. maxs[i] = origin[i] + radius;
  477. }
  478. numListedEntities = gi.EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
  479. radius *= radius; //square for the length squared below
  480. for ( e = 0 ; e < numListedEntities ; e++ )
  481. {
  482. ent = entityList[ e ];
  483. if ((ent == ignore) || !(ent->inuse) || ent->takedamage != takeDamage)
  484. continue;
  485. // find the distance from the edge of the bounding box
  486. for ( i = 0 ; i < 3 ; i++ )
  487. {
  488. if ( origin[i] < ent->absmin[i] )
  489. {
  490. v[i] = ent->absmin[i] - origin[i];
  491. } else if ( origin[i] > ent->absmax[i] )
  492. {
  493. v[i] = origin[i] - ent->absmax[i];
  494. } else
  495. {
  496. v[i] = 0;
  497. }
  498. }
  499. dist = VectorLengthSquared( v );
  500. if ( dist >= radius )
  501. {
  502. continue;
  503. }
  504. // ok, we are within the radius, add us to the incoming list
  505. ent_list[ent_count] = ent;
  506. ent_count++;
  507. }
  508. // we are done, return how many we found
  509. return(ent_count);
  510. }
  511. /*
  512. =============
  513. G_PickTarget
  514. Selects a random entity from among the targets
  515. =============
  516. */
  517. #define MAXCHOICES 32
  518. gentity_t *G_PickTarget (char *targetname)
  519. {
  520. gentity_t *ent = NULL;
  521. int num_choices = 0;
  522. gentity_t *choice[MAXCHOICES];
  523. if (!targetname)
  524. {
  525. gi.Printf("G_PickTarget called with NULL targetname\n");
  526. return NULL;
  527. }
  528. while(1)
  529. {
  530. ent = G_Find (ent, FOFS(targetname), targetname);
  531. if (!ent)
  532. break;
  533. choice[num_choices++] = ent;
  534. if (num_choices == MAXCHOICES)
  535. break;
  536. }
  537. if (!num_choices)
  538. {
  539. gi.Printf("G_PickTarget: target %s not found\n", targetname);
  540. return NULL;
  541. }
  542. return choice[rand() % num_choices];
  543. }
  544. void G_UseTargets2 (gentity_t *ent, gentity_t *activator, const char *string)
  545. {
  546. gentity_t *t;
  547. //
  548. // fire targets
  549. //
  550. if (string)
  551. {
  552. if( !stricmp( string, "self") )
  553. {
  554. t = ent;
  555. if (t->e_UseFunc != useF_NULL) // check can be omitted
  556. {
  557. GEntity_UseFunc(t, ent, activator);
  558. }
  559. if (!ent->inuse)
  560. {
  561. gi.Printf("entity was removed while using targets\n");
  562. return;
  563. }
  564. }
  565. else
  566. {
  567. t = NULL;
  568. while ( (t = G_Find (t, FOFS(targetname), (char *) string)) != NULL )
  569. {
  570. if (t == ent)
  571. {
  572. // gi.Printf ("WARNING: Entity used itself.\n");
  573. }
  574. if (t->e_UseFunc != useF_NULL) // check can be omitted
  575. {
  576. GEntity_UseFunc(t, ent, activator);
  577. }
  578. if (!ent->inuse)
  579. {
  580. gi.Printf("entity was removed while using targets\n");
  581. return;
  582. }
  583. }
  584. }
  585. }
  586. }
  587. /*
  588. ==============================
  589. G_UseTargets
  590. "activator" should be set to the entity that initiated the firing.
  591. Search for (string)targetname in all entities that
  592. match (string)self.target and call their .use function
  593. ==============================
  594. */
  595. void G_UseTargets (gentity_t *ent, gentity_t *activator)
  596. {
  597. //
  598. // fire targets
  599. //
  600. G_UseTargets2 (ent, activator, ent->target);
  601. }
  602. /*
  603. =============
  604. VectorToString
  605. This is just a convenience function
  606. for printing vectors
  607. =============
  608. */
  609. char *vtos( const vec3_t v ) {
  610. static int index;
  611. static char str[8][32];
  612. char *s;
  613. // use an array so that multiple vtos won't collide
  614. s = str[index];
  615. index = (index + 1)&7;
  616. Com_sprintf (s, 32, "(%4.2f %4.2f %4.2f)", v[0], v[1], v[2]);
  617. return s;
  618. }
  619. /*
  620. ===============
  621. G_SetMovedir
  622. The editor only specifies a single value for angles (yaw),
  623. but we have special constants to generate an up or down direction.
  624. Angles will be cleared, because it is being used to represent a direction
  625. instead of an orientation.
  626. ===============
  627. */
  628. void G_SetMovedir( vec3_t angles, vec3_t movedir ) {
  629. static vec3_t VEC_UP = {0, -1, 0};
  630. static vec3_t MOVEDIR_UP = {0, 0, 1};
  631. static vec3_t VEC_DOWN = {0, -2, 0};
  632. static vec3_t MOVEDIR_DOWN = {0, 0, -1};
  633. if ( VectorCompare (angles, VEC_UP) ) {
  634. VectorCopy (MOVEDIR_UP, movedir);
  635. } else if ( VectorCompare (angles, VEC_DOWN) ) {
  636. VectorCopy (MOVEDIR_DOWN, movedir);
  637. } else {
  638. AngleVectors (angles, movedir, NULL, NULL);
  639. }
  640. VectorClear( angles );
  641. }
  642. float vectoyaw( const vec3_t vec ) {
  643. float yaw;
  644. if (vec[YAW] == 0 && vec[PITCH] == 0) {
  645. yaw = 0;
  646. } else {
  647. if (vec[PITCH]) {
  648. yaw = ( atan2( vec[YAW], vec[PITCH]) * 180 / M_PI );
  649. } else if (vec[YAW] > 0) {
  650. yaw = 90;
  651. } else {
  652. yaw = 270;
  653. }
  654. if (yaw < 0) {
  655. yaw += 360;
  656. }
  657. }
  658. return yaw;
  659. }
  660. void G_InitGentity( gentity_t *e, qboolean bFreeG2 )
  661. {
  662. e->inuse = qtrue;
  663. SetInUse(e);
  664. e->m_iIcarusID = IIcarusInterface::ICARUS_INVALID;
  665. e->classname = "noclass";
  666. e->s.number = e - g_entities;
  667. // remove any ghoul2 models here in case we're reusing
  668. if (bFreeG2 && e->ghoul2.IsValid())
  669. {
  670. gi.G2API_CleanGhoul2Models(e->ghoul2);
  671. }
  672. //Navigational setups
  673. e->waypoint = WAYPOINT_NONE;
  674. e->lastWaypoint = WAYPOINT_NONE;
  675. }
  676. /*
  677. =================
  678. G_Spawn
  679. Either finds a free entity, or allocates a new one.
  680. The slots from 0 to MAX_CLIENTS-1 are always reserved for clients, and will
  681. never be used by anything else.
  682. Try to avoid reusing an entity that was recently freed, because it
  683. can cause the client to think the entity morphed into something else
  684. instead of being removed and recreated, which can cause interpolated
  685. angles and bad trails.
  686. =================
  687. */
  688. extern void G_MassFreeUselessThings( void );
  689. gentity_t *G_Spawn( int itr )
  690. {
  691. int i, force;
  692. gentity_t *e;
  693. e = NULL; // shut up warning
  694. i = 0; // shut up warning
  695. for ( force = 0 ; force < 2 ; force++ )
  696. {
  697. // if we go through all entities and can't find one to free,
  698. // override the normal minimum times before use
  699. e = &g_entities[MAX_CLIENTS];
  700. // for ( i = MAX_CLIENTS ; i<globals.num_entities ; i++, e++)
  701. // {
  702. // if ( e->inuse )
  703. // {
  704. // continue;
  705. // }
  706. for ( i = MAX_CLIENTS ; i<globals.num_entities ; i++)
  707. {
  708. if(PInUse(i))
  709. {
  710. continue;
  711. }
  712. e=&g_entities[i];
  713. // the first couple seconds of server time can involve a lot of
  714. // freeing and allocating, so relax the replacement policy
  715. if ( !force && e->freetime > 2000 && level.time - e->freetime < 1000 ) {
  716. continue;
  717. }
  718. // reuse this slot
  719. G_InitGentity( e, qtrue );
  720. return e;
  721. }
  722. e=&g_entities[i];
  723. if ( i != ENTITYNUM_MAX_NORMAL )
  724. {
  725. break;
  726. }
  727. }
  728. if ( i == ENTITYNUM_MAX_NORMAL )
  729. {
  730. #ifndef _XBOX
  731. //#ifndef FINAL_BUILD
  732. e = &g_entities[0];
  733. //--------------Use this to dump directly to a file
  734. char buff[256];
  735. FILE *fp;
  736. fp = fopen( "c:/nofreeentities.txt", "w" );
  737. for ( i = 0 ; i<globals.num_entities ; i++, e++)
  738. {
  739. if ( e->classname )
  740. {
  741. sprintf( buff, "%d: %s\n", i, e->classname );
  742. }
  743. fputs( buff, fp );
  744. }
  745. fclose( fp );
  746. /*
  747. //---------------Or use this to dump to the console -- beware though, the console will fill quickly and you probably won't see the full list
  748. for ( i = 0 ; i<globals.num_entities ; i++, e++)
  749. {
  750. if ( e->classname )
  751. {
  752. Com_Printf( "%d: %s\n", i, e->classname );
  753. }
  754. }
  755. */
  756. #endif//FINAL_BUILD
  757. if(itr)
  758. {
  759. G_MassFreeUselessThings();
  760. return G_Spawn( 0 );
  761. }
  762. else
  763. {
  764. G_Error( "G_Spawn: no free entities" );
  765. }
  766. }
  767. // open up a new slot
  768. globals.num_entities++;
  769. G_InitGentity( e, qtrue );
  770. return e;
  771. }
  772. extern void Vehicle_Remove(gentity_t *ent);
  773. /*
  774. =================
  775. G_FreeEntity
  776. Marks the entity as free
  777. =================
  778. */
  779. extern short max_speeders;
  780. extern char current_speeders;
  781. void G_FreeEntity( gentity_t *ed ) {
  782. if( ed->m_pVehicle &&
  783. ed->m_pVehicle->m_pVehicleInfo &&
  784. ed->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER)
  785. {
  786. // if this speeder was destroyed by cleanup code, alreadCleaned will be set, so
  787. // don't account for it again, otherwise the death occured somewhere else
  788. if(!ed->m_pVehicle->alreadyCleaned)
  789. current_speeders--;
  790. }
  791. gi.unlinkentity (ed); // unlink from world
  792. // Free the Game Element (the entity) and delete the Icarus ID.
  793. Quake3Game()->FreeEntity( ed );
  794. /*if ( ed->neverFree ) {
  795. return;
  796. }*/
  797. if (ed->wayedge!=0)
  798. {
  799. NAV::WayEdgesNowClear(ed);
  800. }
  801. // remove any ghoul2 models here
  802. gi.G2API_CleanGhoul2Models(ed->ghoul2);
  803. if (ed->client && ed->client->NPC_class == CLASS_VEHICLE)
  804. {
  805. int iVehIndex = BG_VehicleGetIndex( ed->NPC_type );
  806. Vehicle_Remove(ed);
  807. if ( ed->m_pVehicle )
  808. {
  809. gi.Free( ed->m_pVehicle );
  810. }
  811. //CVehicleNPC *pVeh = static_cast< CVehicleNPC * >( ed->NPC );
  812. //delete pVeh;
  813. //gi.Free((char*)ed->NPC-4);//crazy hack for class vtables
  814. }
  815. //free this stuff now, rather than waiting until the level ends.
  816. if (ed->NPC)
  817. {
  818. gi.Free(ed->NPC);
  819. if(ed->client->clientInfo.customBasicSoundDir && gi.bIsFromZone(ed->client->clientInfo.customBasicSoundDir, TAG_G_ALLOC)) {
  820. gi.Free(ed->client->clientInfo.customBasicSoundDir);
  821. }
  822. if(ed->client->clientInfo.customCombatSoundDir) {
  823. assert(*(int*)ed->client->clientInfo.customCombatSoundDir != 0xfeeefeee);
  824. gi.Free(ed->client->clientInfo.customCombatSoundDir);
  825. }
  826. if(ed->client->clientInfo.customExtraSoundDir) {
  827. assert(*(int*)ed->client->clientInfo.customExtraSoundDir != 0xfeeefeee);
  828. gi.Free(ed->client->clientInfo.customExtraSoundDir);
  829. }
  830. if(ed->client->clientInfo.customJediSoundDir) {
  831. gi.Free(ed->client->clientInfo.customJediSoundDir);
  832. }
  833. if(ed->client->ps.saber[0].name && gi.bIsFromZone(ed->client->ps.saber[0].name, TAG_G_ALLOC) ) {
  834. gi.Free(ed->client->ps.saber[0].name);
  835. }
  836. if(ed->client->ps.saber[0].model && gi.bIsFromZone(ed->client->ps.saber[0].model, TAG_G_ALLOC) ) {
  837. gi.Free(ed->client->ps.saber[0].model);
  838. }
  839. if(ed->client->ps.saber[1].name && gi.bIsFromZone(ed->client->ps.saber[1].name, TAG_G_ALLOC) ) {
  840. gi.Free(ed->client->ps.saber[1].name);
  841. }
  842. if(ed->client->ps.saber[1].model && gi.bIsFromZone(ed->client->ps.saber[1].model, TAG_G_ALLOC) ) {
  843. gi.Free(ed->client->ps.saber[1].model);
  844. }
  845. gi.Free(ed->client);
  846. }
  847. if (ed->soundSet && gi.bIsFromZone(ed->soundSet, TAG_G_ALLOC)) {
  848. gi.Free(ed->soundSet);
  849. }
  850. if (ed->targetname && gi.bIsFromZone(ed->targetname, TAG_G_ALLOC)) {
  851. gi.Free(ed->targetname);
  852. }
  853. if (ed->NPC_targetname && gi.bIsFromZone(ed->NPC_targetname, TAG_G_ALLOC)) {
  854. gi.Free(ed->NPC_targetname);
  855. }
  856. if (ed->NPC_type && gi.bIsFromZone(ed->NPC_type, TAG_G_ALLOC)) {
  857. gi.Free(ed->NPC_type);
  858. }
  859. if (ed->classname && gi.bIsFromZone(ed->classname, TAG_G_ALLOC)) {
  860. gi.Free(ed->classname );
  861. }
  862. if (ed->message && gi.bIsFromZone(ed->message, TAG_G_ALLOC)) {
  863. gi.Free(ed->message);
  864. }
  865. if (ed->model && gi.bIsFromZone(ed->model, TAG_G_ALLOC)) {
  866. gi.Free(ed->model);
  867. }
  868. //scripting
  869. if (ed->script_targetname && gi.bIsFromZone(ed->script_targetname, TAG_G_ALLOC)) {
  870. gi.Free(ed->script_targetname);
  871. }
  872. if (ed->cameraGroup && gi.bIsFromZone(ed->cameraGroup, TAG_G_ALLOC)) {
  873. gi.Free(ed->cameraGroup);
  874. }
  875. if (ed->paintarget && gi.bIsFromZone(ed->paintarget, TAG_G_ALLOC)) {
  876. gi.Free(ed->paintarget);
  877. }
  878. if(ed->parms) {
  879. gi.Free(ed->parms);
  880. }
  881. //Limbs
  882. if (ed->target && gi.bIsFromZone(ed->target , TAG_G_ALLOC)) {
  883. gi.Free(ed->target);
  884. }
  885. if (ed->target2 && gi.bIsFromZone(ed->target2 , TAG_G_ALLOC)) {
  886. gi.Free(ed->target2);
  887. }
  888. if (ed->target3 && gi.bIsFromZone(ed->target3 , TAG_G_ALLOC)) {
  889. gi.Free(ed->target3);
  890. }
  891. if (ed->target4 && gi.bIsFromZone(ed->target4 , TAG_G_ALLOC)) {
  892. gi.Free(ed->target4);
  893. }
  894. if (ed->opentarget) {
  895. gi.Free(ed->opentarget);
  896. }
  897. if (ed->closetarget) {
  898. gi.Free(ed->closetarget);
  899. }
  900. // Free any associated timers
  901. TIMER_Clear(ed->s.number);
  902. memset (ed, 0, sizeof(*ed));
  903. ed->s.number = ENTITYNUM_NONE;
  904. ed->classname = "freed";
  905. ed->freetime = level.time;
  906. ed->inuse = qfalse;
  907. ClearInUse(ed);
  908. }
  909. /*
  910. =================
  911. G_TempEntity
  912. Spawns an event entity that will be auto-removed
  913. The origin will be snapped to save net bandwidth, so care
  914. must be taken if the origin is right on a surface (snap towards start vector first)
  915. =================
  916. */
  917. gentity_t *G_TempEntity( const vec3_t origin, int event ) {
  918. gentity_t *e;
  919. vec3_t snapped;
  920. e = G_Spawn();
  921. e->s.eType = ET_EVENTS + event;
  922. e->classname = "tempEntity";
  923. e->eventTime = level.time;
  924. e->freeAfterEvent = qtrue;
  925. VectorCopy( origin, snapped );
  926. SnapVector( snapped ); // save network bandwidth
  927. G_SetOrigin( e, snapped );
  928. // find cluster for PVS
  929. gi.linkentity( e );
  930. return e;
  931. }
  932. /*
  933. ==============================================================================
  934. Kill box
  935. ==============================================================================
  936. */
  937. /*
  938. =================
  939. G_KillBox
  940. Kills all entities that would touch the proposed new positioning
  941. of ent. Ent should be unlinked before calling this!
  942. =================
  943. */
  944. void G_KillBox (gentity_t *ent) {
  945. int i, num;
  946. gentity_t *touch[MAX_GENTITIES], *hit;
  947. vec3_t mins, maxs;
  948. VectorAdd( ent->client->ps.origin, ent->mins, mins );
  949. VectorAdd( ent->client->ps.origin, ent->maxs, maxs );
  950. num = gi.EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
  951. for (i=0 ; i<num ; i++) {
  952. hit = touch[i];
  953. if ( !hit->client ) {
  954. continue;
  955. }
  956. if ( hit == ent ) {
  957. continue;
  958. }
  959. if ( ent->s.number && hit->client->ps.stats[STAT_HEALTH] <= 0 )
  960. {//NPC
  961. continue;
  962. }
  963. if ( ent->s.number )
  964. {//NPC
  965. if ( !(hit->contents&CONTENTS_BODY) )
  966. {
  967. continue;
  968. }
  969. }
  970. else
  971. {//player
  972. if ( !(hit->contents & ent->contents) )
  973. {
  974. continue;
  975. }
  976. }
  977. // nail it
  978. G_Damage ( hit, ent, ent, NULL, NULL,
  979. 100000, DAMAGE_NO_PROTECTION, MOD_UNKNOWN);
  980. }
  981. }
  982. //==============================================================================
  983. /*
  984. ===============
  985. G_AddEvent
  986. Adds an event+parm and twiddles the event counter
  987. ===============
  988. */
  989. void G_AddEvent( gentity_t *ent, int event, int eventParm ) {
  990. int bits;
  991. if ( !event ) {
  992. gi.Printf( "G_AddEvent: zero event added for entity %i\n", ent->s.number );
  993. return;
  994. }
  995. #if 0 // FIXME: allow multiple events on an entity
  996. // if the entity has an event that hasn't expired yet, don't overwrite
  997. // it unless it is identical (repeated footsteps / muzzleflashes / etc )
  998. if ( ent->s.event && ent->s.event != event ) {
  999. gentity_t *temp;
  1000. // generate a temp entity that references the original entity
  1001. gi.Printf( "eventPush\n" );
  1002. temp = G_Spawn();
  1003. temp->s.eType = ET_EVENT_ONLY;
  1004. temp->s.otherEntityNum = ent->s.number;
  1005. G_SetOrigin( temp, ent->s.origin );
  1006. G_AddEvent( temp, event, eventParm );
  1007. temp->freeAfterEvent = qtrue;
  1008. gi.linkentity( temp );
  1009. return;
  1010. }
  1011. #endif
  1012. // clients need to add the event in playerState_t instead of entityState_t
  1013. if ( !ent->s.number ) //only one client
  1014. {
  1015. #if 0
  1016. bits = ent->client->ps.externalEvent & EV_EVENT_BITS;
  1017. bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS;
  1018. ent->client->ps.externalEvent = event | bits;
  1019. ent->client->ps.externalEventParm = eventParm;
  1020. ent->client->ps.externalEventTime = level.time;
  1021. #endif
  1022. if ( eventParm > 255 )
  1023. {
  1024. if ( event == EV_PAIN )
  1025. {//must have cheated, in undying?
  1026. eventParm = 255;
  1027. }
  1028. else
  1029. {
  1030. assert( eventParm < 256 );
  1031. }
  1032. }
  1033. AddEventToPlayerstate( event, eventParm, &ent->client->ps );
  1034. } else {
  1035. bits = ent->s.event & EV_EVENT_BITS;
  1036. bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS;
  1037. ent->s.event = event | bits;
  1038. ent->s.eventParm = eventParm;
  1039. }
  1040. ent->eventTime = level.time;
  1041. }
  1042. /*
  1043. =============
  1044. G_Sound
  1045. =============
  1046. */
  1047. void G_Sound( gentity_t *ent, int soundIndex )
  1048. {
  1049. gentity_t *te;
  1050. te = G_TempEntity( ent->currentOrigin, EV_GENERAL_SOUND );
  1051. te->s.eventParm = soundIndex;
  1052. }
  1053. /*
  1054. =============
  1055. G_Sound
  1056. =============
  1057. */
  1058. void G_SoundAtSpot( vec3_t org, int soundIndex, qboolean broadcast )
  1059. {
  1060. gentity_t *te;
  1061. te = G_TempEntity( org, EV_GENERAL_SOUND );
  1062. te->s.eventParm = soundIndex;
  1063. if ( broadcast )
  1064. {
  1065. te->svFlags |= SVF_BROADCAST;
  1066. }
  1067. }
  1068. /*
  1069. =============
  1070. G_SoundBroadcast
  1071. Plays sound that can permeate PVS blockage
  1072. =============
  1073. */
  1074. void G_SoundBroadcast( gentity_t *ent, int soundIndex )
  1075. {
  1076. gentity_t *te;
  1077. te = G_TempEntity( ent->currentOrigin, EV_GLOBAL_SOUND ); //full volume
  1078. te->s.eventParm = soundIndex;
  1079. te->svFlags |= SVF_BROADCAST;
  1080. }
  1081. //==============================================================================
  1082. #ifdef _IMMERSION
  1083. int G_ForceIndex( const char *name, int channel )
  1084. {
  1085. if ( channel >= 0 && channel < FF_CHANNEL_MAX )
  1086. {
  1087. // no point in storing a name with a bogus channel
  1088. // (registering an effect on multiple channels will eat up memory)
  1089. char temp[512];
  1090. sprintf( temp, "%d,%s", channel, name );
  1091. return G_FindConfigstringIndex ( temp, CS_FORCES, MAX_FORCES, qtrue );
  1092. }
  1093. return 0;
  1094. }
  1095. gentity_t *G_OwnerClient( gentity_t *ent )
  1096. {
  1097. // This test is not adequate... should check for the following...
  1098. // 1) owned entity is touching client entity
  1099. // 2) owned entity is a weapon being used by client
  1100. for
  1101. (
  1102. ; ent
  1103. && !ent->client
  1104. ; ent = ent->owner
  1105. );
  1106. return ent;
  1107. }
  1108. void G_Force( gentity_t *ent, int forceIndex )
  1109. {
  1110. gentity_t *client = G_OwnerClient( ent );
  1111. if ( client )
  1112. {
  1113. G_AddEvent( client, EV_ENTITY_FORCE, forceIndex );
  1114. }
  1115. }
  1116. void G_ForceArea( gentity_t *ent, int forceIndex )
  1117. {
  1118. gentity_t *te;
  1119. te = G_TempEntity( ent->s.origin, EV_AREA_FORCE );
  1120. te->s.eventParm = forceIndex;
  1121. }
  1122. void G_ForceBroadcast( gentity_t *ent, int forceIndex )
  1123. {
  1124. gentity_t *te;
  1125. te = G_TempEntity( ent->s.origin, EV_GLOBAL_FORCE );
  1126. te->s.eventParm = forceIndex;
  1127. te->svFlags |= SVF_BROADCAST;
  1128. }
  1129. void G_ForceStop( gentity_t *ent, int forceIndex )
  1130. {
  1131. G_AddEvent( ent, EV_FORCE_STOP, forceIndex );
  1132. }
  1133. #endif // _IMMERSION
  1134. /*
  1135. ================
  1136. G_SetOrigin
  1137. Sets the pos trajectory for a fixed position
  1138. ================
  1139. */
  1140. void G_SetOrigin( gentity_t *ent, const vec3_t origin )
  1141. {
  1142. VectorCopy( origin, ent->s.pos.trBase );
  1143. if(ent->client)
  1144. {
  1145. VectorCopy( origin, ent->client->ps.origin );
  1146. VectorCopy( origin, ent->s.origin );
  1147. }
  1148. else
  1149. {
  1150. ent->s.pos.trType = TR_STATIONARY;
  1151. }
  1152. ent->s.pos.trTime = 0;
  1153. ent->s.pos.trDuration = 0;
  1154. VectorClear( ent->s.pos.trDelta );
  1155. VectorCopy( origin, ent->currentOrigin );
  1156. // clear waypoints
  1157. if( ent->client && ent->NPC )
  1158. {
  1159. ent->waypoint = 0;
  1160. ent->lastWaypoint = 0;
  1161. if( NAV::HasPath( ent ) )
  1162. {
  1163. NAV::ClearPath( ent );
  1164. }
  1165. }
  1166. }
  1167. qboolean G_CheckInSolidTeleport (const vec3_t& teleportPos, gentity_t *self)
  1168. {
  1169. trace_t trace;
  1170. vec3_t end, mins;
  1171. VectorCopy(teleportPos, end);
  1172. end[2] += self->mins[2];
  1173. VectorCopy(self->mins, mins);
  1174. mins[2] = 0;
  1175. gi.trace(&trace, teleportPos, mins, self->maxs, end, self->s.number, self->clipmask);
  1176. if(trace.allsolid || trace.startsolid)
  1177. {
  1178. return qtrue;
  1179. }
  1180. return qfalse;
  1181. }
  1182. //===============================================================================
  1183. qboolean G_CheckInSolid (gentity_t *self, qboolean fix)
  1184. {
  1185. trace_t trace;
  1186. vec3_t end, mins;
  1187. VectorCopy(self->currentOrigin, end);
  1188. end[2] += self->mins[2];
  1189. VectorCopy(self->mins, mins);
  1190. mins[2] = 0;
  1191. gi.trace(&trace, self->currentOrigin, mins, self->maxs, end, self->s.number, self->clipmask);
  1192. if(trace.allsolid || trace.startsolid)
  1193. {
  1194. return qtrue;
  1195. }
  1196. #ifdef _DEBUG
  1197. if(trace.fraction < 0.99999713)
  1198. #else
  1199. if(trace.fraction < 1.0)
  1200. #endif
  1201. {
  1202. if(fix)
  1203. {//Put them at end of trace and check again
  1204. vec3_t neworg;
  1205. VectorCopy(trace.endpos, neworg);
  1206. neworg[2] -= self->mins[2];
  1207. G_SetOrigin(self, neworg);
  1208. gi.linkentity(self);
  1209. return G_CheckInSolid(self, qfalse);
  1210. }
  1211. else
  1212. {
  1213. return qtrue;
  1214. }
  1215. }
  1216. return qfalse;
  1217. }
  1218. qboolean infront(gentity_t *from, gentity_t *to)
  1219. {
  1220. vec3_t angles, dir, forward;
  1221. float dot;
  1222. angles[PITCH] = angles[ROLL] = 0;
  1223. angles[YAW] = from->s.angles[YAW];
  1224. AngleVectors(angles, forward, NULL, NULL);
  1225. VectorSubtract(to->s.origin, from->s.origin, dir);
  1226. VectorNormalize(dir);
  1227. dot = DotProduct(forward, dir);
  1228. if(dot < 0.0f)
  1229. {
  1230. return qfalse;
  1231. }
  1232. return qtrue;
  1233. }
  1234. void Svcmd_Use_f( void )
  1235. {
  1236. char *cmd1 = gi.argv(1);
  1237. if ( !cmd1 || !cmd1[0] )
  1238. {
  1239. //FIXME: warning message
  1240. gi.Printf( "'use' takes targetname of ent or 'list' (lists all usable ents)\n" );
  1241. return;
  1242. }
  1243. else if ( !Q_stricmp("list", cmd1) )
  1244. {
  1245. gentity_t *ent;
  1246. gi.Printf("Listing all usable entities:\n");
  1247. for ( int i = 1; i < ENTITYNUM_WORLD; i++ )
  1248. {
  1249. ent = &g_entities[i];
  1250. if ( ent )
  1251. {
  1252. if ( ent->targetname && ent->targetname[0] )
  1253. {
  1254. if ( ent->e_UseFunc != useF_NULL )
  1255. {
  1256. if ( ent->NPC )
  1257. {
  1258. gi.Printf( "%s (NPC)\n", ent->targetname );
  1259. }
  1260. else
  1261. {
  1262. gi.Printf( "%s\n", ent->targetname );
  1263. }
  1264. }
  1265. }
  1266. }
  1267. }
  1268. gi.Printf("End of list.\n");
  1269. }
  1270. else
  1271. {
  1272. G_UseTargets2( &g_entities[0], &g_entities[0], cmd1 );
  1273. }
  1274. }
  1275. //======================================================
  1276. void G_SetActiveState(char *targetstring, qboolean actState)
  1277. {
  1278. gentity_t *target = NULL;
  1279. while( NULL != (target = G_Find(target, FOFS(targetname), targetstring)) )
  1280. {
  1281. target->svFlags = actState ? (target->svFlags&~SVF_INACTIVE) : (target->svFlags|SVF_INACTIVE);
  1282. }
  1283. }
  1284. void target_activate_use(gentity_t *self, gentity_t *other, gentity_t *activator)
  1285. {
  1286. G_ActivateBehavior(self,BSET_USE);
  1287. G_SetActiveState(self->target, ACT_ACTIVE);
  1288. }
  1289. void target_deactivate_use(gentity_t *self, gentity_t *other, gentity_t *activator)
  1290. {
  1291. G_ActivateBehavior(self,BSET_USE);
  1292. G_SetActiveState(self->target, ACT_INACTIVE);
  1293. }
  1294. //FIXME: make these apply to doors, etc too?
  1295. /*QUAKED target_activate (1 0 0) (-4 -4 -4) (4 4 4)
  1296. Will set the target(s) to be usable/triggerable
  1297. */
  1298. void SP_target_activate( gentity_t *self )
  1299. {
  1300. G_SetOrigin( self, self->s.origin );
  1301. self->e_UseFunc = useF_target_activate_use;
  1302. }
  1303. /*QUAKED target_deactivate (1 0 0) (-4 -4 -4) (4 4 4)
  1304. Will set the target(s) to be non-usable/triggerable
  1305. */
  1306. void SP_target_deactivate( gentity_t *self )
  1307. {
  1308. G_SetOrigin( self, self->s.origin );
  1309. self->e_UseFunc = useF_target_deactivate_use;
  1310. }
  1311. //======================================================
  1312. /*
  1313. ==============
  1314. ValidUseTarget
  1315. Returns whether or not the targeted entity is useable
  1316. ==============
  1317. */
  1318. qboolean ValidUseTarget( gentity_t *ent )
  1319. {
  1320. if ( ent->e_UseFunc == useF_NULL )
  1321. {
  1322. return qfalse;
  1323. }
  1324. if ( ent->svFlags & SVF_INACTIVE )
  1325. {//set by target_deactivate
  1326. return qfalse;
  1327. }
  1328. if ( !(ent->svFlags & SVF_PLAYER_USABLE) )
  1329. {//Check for flag that denotes BUTTON_USE useability
  1330. return qfalse;
  1331. }
  1332. //FIXME: This is only a temp fix..
  1333. if ( !Q_strncmp( ent->classname, "trigger", 7) )
  1334. {
  1335. return qfalse;
  1336. }
  1337. return qtrue;
  1338. }
  1339. static void DebugTraceForNPC(gentity_t *ent)
  1340. {
  1341. trace_t trace;
  1342. vec3_t src, dest, vf;
  1343. VectorCopy( ent->client->renderInfo.eyePoint, src );
  1344. AngleVectors( ent->client->ps.viewangles, vf, NULL, NULL );//ent->client->renderInfo.eyeAngles was cg.refdef.viewangles, basically
  1345. //extend to find end of use trace
  1346. VectorMA( src, 4096, vf, dest );
  1347. //Trace ahead to find a valid target
  1348. gi.trace( &trace, src, vec3_origin, vec3_origin, dest, ent->s.number, MASK_OPAQUE|CONTENTS_SOLID|CONTENTS_TERRAIN|CONTENTS_BODY|CONTENTS_ITEM|CONTENTS_CORPSE );
  1349. if (trace.fraction < 0.99f)
  1350. {
  1351. gentity_t *found = &g_entities[trace.entityNum];
  1352. if (found)
  1353. {
  1354. const char *targetName = found->targetname;
  1355. const char *className = found->classname;
  1356. if (targetName == 0)
  1357. {
  1358. targetName = "<NULL>";
  1359. }
  1360. if (className == 0)
  1361. {
  1362. className = "<NULL>";
  1363. }
  1364. Com_Printf("found targetname '%s', classname '%s'\n", targetName, className);
  1365. }
  1366. }
  1367. }
  1368. static qboolean G_ValidActivateBehavior (gentity_t* self, int bset)
  1369. {
  1370. if ( !self )
  1371. {
  1372. return qfalse;
  1373. }
  1374. const char *bs_name = self->behaviorSet[bset];
  1375. if( !(VALIDSTRING( bs_name )) )
  1376. {
  1377. return qfalse;
  1378. }
  1379. return qtrue;
  1380. }
  1381. static qboolean G_IsTriggerUsable(gentity_t* self, gentity_t* other)
  1382. {
  1383. if ( self->svFlags & SVF_INACTIVE )
  1384. {//set by target_deactivate
  1385. return qfalse;
  1386. }
  1387. if( self->noDamageTeam )
  1388. {
  1389. if ( other->client->playerTeam != self->noDamageTeam )
  1390. {
  1391. return qfalse;
  1392. }
  1393. }
  1394. if ( self->spawnflags & 4 )
  1395. {//USE_BUTTON
  1396. if ( !other->client )
  1397. {
  1398. return qfalse;
  1399. }
  1400. }
  1401. else
  1402. {
  1403. return qfalse;
  1404. }
  1405. if ( self->spawnflags & 2 )
  1406. {//FACING
  1407. vec3_t forward;
  1408. if ( other->client )
  1409. {
  1410. AngleVectors( other->client->ps.viewangles, forward, NULL, NULL );
  1411. }
  1412. else
  1413. {
  1414. AngleVectors( other->currentAngles, forward, NULL, NULL );
  1415. }
  1416. if ( DotProduct( self->movedir, forward ) < 0.5 )
  1417. {//Not Within 45 degrees
  1418. return qfalse;
  1419. }
  1420. }
  1421. if ((!G_ValidActivateBehavior (self, BSET_USE) && !self->target) ||
  1422. (self->target &&
  1423. (stricmp(self->target, "n") == 0 ||
  1424. (stricmp(self->target, "neveropen") == 0 ||
  1425. (stricmp(self->target, "run_gran_drop") == 0) ||
  1426. (stricmp(self->target, "speaker") == 0) ||
  1427. (stricmp(self->target, "locked") == 0)
  1428. ))))
  1429. {
  1430. return qfalse;
  1431. }
  1432. /*
  1433. //NOTE: This doesn't stop you from using it, just delays the use action!
  1434. if(self->delay && self->painDebounceTime < (level.time + self->delay) )
  1435. {
  1436. return qfalse;
  1437. }
  1438. */
  1439. return qtrue;
  1440. }
  1441. static qboolean CanUseInfrontOfPartOfLevel(gentity_t* ent ) //originally from VV
  1442. {
  1443. int i, num;
  1444. gentity_t *touch[MAX_GENTITIES], *hit;
  1445. vec3_t mins, maxs;
  1446. const vec3_t range = { 40, 40, 52 };
  1447. if ( !ent->client ) {
  1448. return qfalse;
  1449. }
  1450. VectorSubtract( ent->client->ps.origin, range, mins );
  1451. VectorAdd( ent->client->ps.origin, range, maxs );
  1452. num = gi.EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
  1453. // can't use ent->absmin, because that has a one unit pad
  1454. VectorAdd( ent->client->ps.origin, ent->mins, mins );
  1455. VectorAdd( ent->client->ps.origin, ent->maxs, maxs );
  1456. for ( i=0 ; i<num ; i++ ) {
  1457. hit = touch[i];
  1458. if ( (hit->e_TouchFunc == touchF_NULL) && (ent->e_TouchFunc == touchF_NULL) ) {
  1459. continue;
  1460. }
  1461. if ( !( hit->contents & CONTENTS_TRIGGER ) ) {
  1462. continue;
  1463. }
  1464. if ( !gi.EntityContact( mins, maxs, hit ) ) {
  1465. continue;
  1466. }
  1467. if ( hit->e_TouchFunc != touchF_NULL ) {
  1468. switch (hit->e_TouchFunc )
  1469. {
  1470. case touchF_Touch_Multi:
  1471. if (G_IsTriggerUsable(hit, ent))
  1472. {
  1473. return qtrue;
  1474. }
  1475. continue;
  1476. break;
  1477. default:
  1478. continue;
  1479. }
  1480. }
  1481. }
  1482. return qfalse;
  1483. }
  1484. #define USE_DISTANCE 64.0f
  1485. extern qboolean eweb_can_be_used( gentity_t *self, gentity_t *other, gentity_t *activator );
  1486. qboolean CanUseInfrontOf(gentity_t *ent)
  1487. {
  1488. gentity_t *target;
  1489. trace_t trace;
  1490. vec3_t src, dest, vf;
  1491. if ( ent->s.number && ent->client->NPC_class == CLASS_ATST )
  1492. {//a player trying to get out of his ATST
  1493. // GEntity_UseFunc( ent->activator, ent, ent );
  1494. return qfalse;
  1495. }
  1496. if (ent->client->ps.viewEntity != ent->s.number)
  1497. {
  1498. ent = &g_entities[ent->client->ps.viewEntity];
  1499. if ( !Q_stricmp( "misc_camera", ent->classname ) )
  1500. { // we are in a camera
  1501. gentity_t *next = 0;
  1502. if ( ent->target2 != NULL )
  1503. {
  1504. next = G_Find( NULL, FOFS(targetname), ent->target2 );
  1505. }
  1506. if ( next )
  1507. {//found another one
  1508. if ( !Q_stricmp( "misc_camera", next->classname ) )
  1509. {//make sure it's another camera
  1510. return qtrue;
  1511. }
  1512. }
  1513. else //if ( ent->health > 0 )
  1514. {//I was the last (only?) one, clear out the viewentity
  1515. return qfalse;
  1516. }
  1517. }
  1518. }
  1519. if ( !ent->client ) {
  1520. return qfalse;
  1521. }
  1522. //FIXME: this does not match where the new accurate crosshair aims...
  1523. //cg.refdef.vieworg, basically
  1524. VectorCopy( ent->client->renderInfo.eyePoint, src );
  1525. AngleVectors( ent->client->ps.viewangles, vf, NULL, NULL );
  1526. //extend to find end of use trace
  1527. VectorMA( src, USE_DISTANCE, vf, dest );
  1528. //Trace ahead to find a valid target
  1529. gi.trace( &trace, src, vec3_origin, vec3_origin, dest, ent->s.number, MASK_OPAQUE|CONTENTS_SOLID|CONTENTS_TERRAIN|CONTENTS_BODY|CONTENTS_ITEM|CONTENTS_CORPSE , G2_NOCOLLIDE, 10);
  1530. if ( trace.fraction == 1.0f || trace.entityNum >= ENTITYNUM_WORLD )
  1531. {
  1532. return (CanUseInfrontOfPartOfLevel(ent));
  1533. }
  1534. target = &g_entities[trace.entityNum];
  1535. if ( target && target->client && target->client->NPC_class == CLASS_VEHICLE )
  1536. {
  1537. // Attempt to board this vehicle.
  1538. return qtrue;
  1539. }
  1540. //Check for a use command
  1541. if (ValidUseTarget( target )) {
  1542. if ( target->s.eType == ET_ITEM )
  1543. {//item, see if we could actually pick it up
  1544. if ( !BG_CanItemBeGrabbed( &target->s, &ent->client->ps ) )
  1545. {//nope, so don't indicate that we can use it
  1546. return qfalse;
  1547. }
  1548. }
  1549. else if ( target->e_UseFunc == useF_misc_atst_use )
  1550. {//drivable AT-ST from JK2
  1551. if ( ent->client->ps.groundEntityNum != target->s.number )
  1552. {//must be standing on it to use it
  1553. return qfalse;
  1554. }
  1555. }
  1556. else if ( target->NPC!=NULL && target->health<=0 )
  1557. {
  1558. return qfalse;
  1559. }
  1560. else if ( target->e_UseFunc == useF_eweb_use )
  1561. {
  1562. if ( !eweb_can_be_used( target, ent, ent ) )
  1563. {
  1564. return qfalse;
  1565. }
  1566. }
  1567. return qtrue;
  1568. }
  1569. if ( target->client
  1570. && target->client->ps.pm_type < PM_DEAD
  1571. && target->NPC!=NULL
  1572. && target->client->playerTeam
  1573. && (target->client->playerTeam == ent->client->playerTeam || target->client->playerTeam == TEAM_NEUTRAL)
  1574. && !(target->NPC->scriptFlags&SCF_NO_RESPONSE)
  1575. && G_ValidActivateBehavior (target, BSET_USE))
  1576. {
  1577. return qtrue;
  1578. }
  1579. if (CanUseInfrontOfPartOfLevel(ent)) {
  1580. return qtrue;
  1581. }
  1582. return qfalse;
  1583. }
  1584. /*
  1585. ==============
  1586. TryUse
  1587. Try and use an entity in the world, directly ahead of us
  1588. ==============
  1589. */
  1590. void TryUse( gentity_t *ent )
  1591. {
  1592. gentity_t *target;
  1593. trace_t trace;
  1594. vec3_t src, dest, vf;
  1595. if (ent->s.number == 0 && g_npcdebug->integer == 1)
  1596. {
  1597. DebugTraceForNPC(ent);
  1598. }
  1599. if ( ent->s.number == 0 && ent->client->NPC_class == CLASS_ATST )
  1600. {//a player trying to get out of his ATST
  1601. GEntity_UseFunc( ent->activator, ent, ent );
  1602. return;
  1603. }
  1604. // TODO: turo-boost.
  1605. /* if ( ent->client->ps.vehicleIndex != VEHICLE_NONE )
  1606. {//in a vehicle, use key makes you turbo-boost
  1607. return;
  1608. }*/
  1609. //FIXME: this does not match where the new accurate crosshair aims...
  1610. //cg.refdef.vieworg, basically
  1611. VectorCopy( ent->client->renderInfo.eyePoint, src );
  1612. AngleVectors( ent->client->ps.viewangles, vf, NULL, NULL );//ent->client->renderInfo.eyeAngles was cg.refdef.viewangles, basically
  1613. //extend to find end of use trace
  1614. VectorMA( src, USE_DISTANCE, vf, dest );
  1615. //Trace ahead to find a valid target
  1616. gi.trace( &trace, src, vec3_origin, vec3_origin, dest, ent->s.number, MASK_OPAQUE|CONTENTS_SOLID|CONTENTS_TERRAIN|CONTENTS_BODY|CONTENTS_ITEM|CONTENTS_CORPSE , G2_NOCOLLIDE, 10);
  1617. if ( trace.fraction == 1.0f || trace.entityNum >= ENTITYNUM_WORLD )
  1618. {
  1619. //TODO: Play a failure sound
  1620. /*
  1621. if ( ent->s.number == 0 )
  1622. {//if nothing else, try the force telepathy power
  1623. ForceTelepathy( ent );
  1624. }
  1625. */
  1626. return;
  1627. }
  1628. target = &g_entities[trace.entityNum];
  1629. if ( target && target->client && target->client->NPC_class == CLASS_VEHICLE )
  1630. {
  1631. // Attempt to board this vehicle.
  1632. target->m_pVehicle->m_pVehicleInfo->Board( target->m_pVehicle, ent );
  1633. return;
  1634. }
  1635. //Check for a use command
  1636. if ( ValidUseTarget( target ) )
  1637. {
  1638. NPC_SetAnim( ent, SETANIM_TORSO, BOTH_BUTTON_HOLD, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
  1639. /*
  1640. if ( !VectorLengthSquared( ent->client->ps.velocity ) && !PM_CrouchAnim( ent->client->ps.legsAnim ) )
  1641. {
  1642. NPC_SetAnim( ent, SETANIM_LEGS, BOTH_BUTTON_HOLD, SETANIM_FLAG_NORMAL|SETANIM_FLAG_HOLD );
  1643. }
  1644. */
  1645. //ent->client->ps.weaponTime = ent->client->ps.torsoAnimTimer;
  1646. GEntity_UseFunc( target, ent, ent );
  1647. return;
  1648. }
  1649. else if ( target->client
  1650. && target->client->ps.pm_type < PM_DEAD
  1651. && target->NPC!=NULL
  1652. && target->client->playerTeam
  1653. && (target->client->playerTeam == ent->client->playerTeam || target->client->playerTeam == TEAM_NEUTRAL)
  1654. && !(target->NPC->scriptFlags&SCF_NO_RESPONSE) )
  1655. {
  1656. NPC_UseResponse ( target, ent, qfalse );
  1657. return;
  1658. }
  1659. /*
  1660. if ( ent->s.number == 0 )
  1661. {//if nothing else, try the force telepathy power
  1662. ForceTelepathy( ent );
  1663. }
  1664. */
  1665. }
  1666. extern int killPlayerTimer;
  1667. void G_ChangeMap (const char *mapname, const char *spawntarget, qboolean hub)
  1668. {
  1669. // gi.Printf("Loading...");
  1670. //ignore if player is dead
  1671. if (g_entities[0].client->ps.pm_type == PM_DEAD)
  1672. return;
  1673. if ( killPlayerTimer )
  1674. {//can't go to next map if your allies have turned on you
  1675. return;
  1676. }
  1677. if (mapname[0] == '+') //fire up the menu instead
  1678. {
  1679. // Flush sound memory to make room for any UI loading that doesn't happen
  1680. // until the end of the level:
  1681. extern int SND_FreeOldestSound( void );
  1682. SND_FreeOldestSound();
  1683. gi.SendConsoleCommand( va("uimenu %s\n", mapname+1) );
  1684. gi.cvar_set("skippingCinematic", "0");
  1685. gi.cvar_set("timescale", "1");
  1686. return;
  1687. }
  1688. if ( spawntarget == NULL ) {
  1689. spawntarget = ""; //prevent it from becoming "(null)"
  1690. }
  1691. if ( hub == qtrue )
  1692. {
  1693. gi.SendConsoleCommand( va("loadtransition %s %s\n", mapname, spawntarget) );
  1694. }
  1695. else
  1696. {
  1697. gi.SendConsoleCommand( va("maptransition %s %s\n", mapname, spawntarget) );
  1698. }
  1699. }
  1700. qboolean G_PointInBounds( const vec3_t point, const vec3_t mins, const vec3_t maxs )
  1701. {
  1702. for(int i = 0; i < 3; i++ )
  1703. {
  1704. if ( point[i] < mins[i] )
  1705. {
  1706. return qfalse;
  1707. }
  1708. if ( point[i] > maxs[i] )
  1709. {
  1710. return qfalse;
  1711. }
  1712. }
  1713. return qtrue;
  1714. }
  1715. qboolean G_BoxInBounds( const vec3_t point, const vec3_t mins, const vec3_t maxs, const vec3_t boundsMins, const vec3_t boundsMaxs )
  1716. {
  1717. vec3_t boxMins;
  1718. vec3_t boxMaxs;
  1719. VectorAdd( point, mins, boxMins );
  1720. VectorAdd( point, maxs, boxMaxs );
  1721. if(boxMaxs[0]>boundsMaxs[0])
  1722. return qfalse;
  1723. if(boxMaxs[1]>boundsMaxs[1])
  1724. return qfalse;
  1725. if(boxMaxs[2]>boundsMaxs[2])
  1726. return qfalse;
  1727. if(boxMins[0]<boundsMins[0])
  1728. return qfalse;
  1729. if(boxMins[1]<boundsMins[1])
  1730. return qfalse;
  1731. if(boxMins[2]<boundsMins[2])
  1732. return qfalse;
  1733. //box is completely contained within bounds
  1734. return qtrue;
  1735. }
  1736. void G_SetAngles( gentity_t *ent, const vec3_t angles )
  1737. {
  1738. VectorCopy( angles, ent->currentAngles );
  1739. VectorCopy( angles, ent->s.angles );
  1740. VectorCopy( angles, ent->s.apos.trBase );
  1741. }
  1742. qboolean G_ClearTrace( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int ignore, int clipmask )
  1743. {
  1744. static trace_t tr;
  1745. gi.trace( &tr, start, mins, maxs, end, ignore, clipmask );
  1746. if ( tr.allsolid || tr.startsolid || tr.fraction < 1.0 )
  1747. {
  1748. return qfalse;
  1749. }
  1750. return qtrue;
  1751. }
  1752. extern void CG_TestLine( vec3_t start, vec3_t end, int time, unsigned int color, int radius);
  1753. void G_DebugLine(vec3_t A, vec3_t B, int duration, int color, qboolean deleteornot)
  1754. {
  1755. /*
  1756. gentity_t *tent = G_TempEntity( A, EV_DEBUG_LINE );
  1757. VectorCopy(B, tent->s.origin2 );
  1758. tent->s.time = duration; // Pause
  1759. tent->s.time2 = color; // Color
  1760. tent->s.weapon = 1; // Dimater
  1761. tent->freeAfterEvent = deleteornot;
  1762. */
  1763. CG_TestLine( A, B, duration, color, 1 );
  1764. }
  1765. qboolean G_ExpandPointToBBox( vec3_t point, const vec3_t mins, const vec3_t maxs, int ignore, int clipmask )
  1766. {
  1767. trace_t tr;
  1768. vec3_t start, end;
  1769. VectorCopy( point, start );
  1770. for ( int i = 0; i < 3; i++ )
  1771. {
  1772. VectorCopy( start, end );
  1773. end[i] += mins[i];
  1774. gi.trace( &tr, start, vec3_origin, vec3_origin, end, ignore, clipmask );
  1775. if ( tr.allsolid || tr.startsolid )
  1776. {
  1777. return qfalse;
  1778. }
  1779. if ( tr.fraction < 1.0 )
  1780. {
  1781. VectorCopy( start, end );
  1782. end[i] += maxs[i]-(mins[i]*tr.fraction);
  1783. gi.trace( &tr, start, vec3_origin, vec3_origin, end, ignore, clipmask );
  1784. if ( tr.allsolid || tr.startsolid )
  1785. {
  1786. return qfalse;
  1787. }
  1788. if ( tr.fraction < 1.0 )
  1789. {
  1790. return qfalse;
  1791. }
  1792. VectorCopy( end, start );
  1793. }
  1794. }
  1795. //expanded it, now see if it's all clear
  1796. gi.trace( &tr, start, mins, maxs, start, ignore, clipmask );
  1797. if ( tr.allsolid || tr.startsolid )
  1798. {
  1799. return qfalse;
  1800. }
  1801. VectorCopy( start, point );
  1802. return qtrue;
  1803. }
  1804. /*
  1805. Ghoul2 Insert Start
  1806. */
  1807. void removeBoltSurface( gentity_t *ent)
  1808. {
  1809. gentity_t *hitEnt = &g_entities[ent->cantHitEnemyCounter];
  1810. // check first to be sure the bolt is still there on the model
  1811. if ((hitEnt->ghoul2.size() > ent->damage) &&
  1812. (hitEnt->ghoul2[ent->damage].mModelindex != -1) &&
  1813. (hitEnt->ghoul2[ent->damage].mSlist.size() > ent->aimDebounceTime) &&
  1814. (hitEnt->ghoul2[ent->damage].mSlist[ent->aimDebounceTime].surface != -1) &&
  1815. (hitEnt->ghoul2[ent->damage].mSlist[ent->aimDebounceTime].offFlags == G2SURFACEFLAG_GENERATED))
  1816. {
  1817. // remove the bolt
  1818. gi.G2API_RemoveBolt(&hitEnt->ghoul2[ent->damage], ent->attackDebounceTime);
  1819. // now remove a surface if there is one
  1820. if (ent->aimDebounceTime != -1)
  1821. {
  1822. gi.G2API_RemoveSurface(&hitEnt->ghoul2[ent->damage], ent->aimDebounceTime);
  1823. }
  1824. }
  1825. // we are done with this entity.
  1826. G_FreeEntity(ent);
  1827. }
  1828. void G_SetBoltSurfaceRemoval( const int entNum, const int modelIndex, const int boltIndex, const int surfaceIndex , float duration ) {
  1829. gentity_t *e;
  1830. vec3_t snapped = {0,0,0};
  1831. e = G_Spawn();
  1832. e->classname = "BoltRemoval";
  1833. e->cantHitEnemyCounter = entNum;
  1834. e->damage = modelIndex;
  1835. e->attackDebounceTime = boltIndex;
  1836. e->aimDebounceTime = surfaceIndex;
  1837. G_SetOrigin( e, snapped );
  1838. // find cluster for PVS
  1839. gi.linkentity( e );
  1840. e->nextthink = level.time + duration;
  1841. e->e_ThinkFunc = thinkF_removeBoltSurface;
  1842. }
  1843. /*
  1844. Ghoul2 Insert End
  1845. */