NPC.cpp 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725
  1. //
  2. // NPC.cpp - generic functions
  3. //
  4. // leave this line at the top for all NPC_xxxx.cpp files...
  5. #include "g_headers.h"
  6. #include "b_local.h"
  7. #include "anims.h"
  8. #include "g_functions.h"
  9. #include "say.h"
  10. #include "Q3_Interface.h"
  11. #include "g_vehicles.h"
  12. extern vec3_t playerMins;
  13. extern vec3_t playerMaxs;
  14. //extern void PM_SetAnimFinal(int *torsoAnim,int *legsAnim,int type,int anim,int priority,int *torsoAnimTimer,int *legsAnimTimer,gentity_t *gent);
  15. extern void PM_SetTorsoAnimTimer( gentity_t *ent, int *torsoAnimTimer, int time );
  16. extern void PM_SetLegsAnimTimer( gentity_t *ent, int *legsAnimTimer, int time );
  17. extern void NPC_BSNoClip ( void );
  18. extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime );
  19. extern void NPC_ApplyRoff (void);
  20. extern void NPC_TempLookTarget ( gentity_t *self, int lookEntNum, int minLookTime, int maxLookTime );
  21. extern void NPC_CheckPlayerAim ( void );
  22. extern void NPC_CheckAllClear ( void );
  23. extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime );
  24. extern qboolean NPC_CheckLookTarget( gentity_t *self );
  25. extern void NPC_SetLookTarget( gentity_t *self, int entNum, int clearTime );
  26. extern void Mark1_dying( gentity_t *self );
  27. extern void NPC_BSCinematic( void );
  28. extern int GetTime ( int lastTime );
  29. extern void G_CheckCharmed( gentity_t *self );
  30. extern qboolean Boba_Flying( gentity_t *self );
  31. extern qboolean RT_Flying( gentity_t *self );
  32. extern qboolean Jedi_CultistDestroyer( gentity_t *self );
  33. extern void Boba_Update();
  34. extern bool Boba_Flee();
  35. extern bool Boba_Tactics();
  36. extern void BubbleShield_Update();
  37. extern qboolean PM_LockedAnim( int anim );
  38. extern cvar_t *g_dismemberment;
  39. extern cvar_t *g_saberRealisticCombat;
  40. extern cvar_t *g_corpseRemovalTime;
  41. //Local Variables
  42. // ai debug cvars
  43. cvar_t *debugNPCAI; // used to print out debug info about the bot AI
  44. cvar_t *debugNPCFreeze; // set to disable bot ai and temporarily freeze them in place
  45. cvar_t *debugNPCName;
  46. cvar_t *d_saberCombat;
  47. cvar_t *d_JediAI;
  48. cvar_t *d_noGroupAI;
  49. cvar_t *d_asynchronousGroupAI;
  50. cvar_t *d_slowmodeath;
  51. extern qboolean stop_icarus;
  52. gentity_t *NPC;
  53. gNPC_t *NPCInfo;
  54. gclient_t *client;
  55. usercmd_t ucmd;
  56. visibility_t enemyVisibility;
  57. void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend);
  58. static bState_t G_CurrentBState( gNPC_t *gNPC );
  59. extern int eventClearTime;
  60. void CorpsePhysics( gentity_t *self )
  61. {
  62. // run the bot through the server like it was a real client
  63. memset( &ucmd, 0, sizeof( ucmd ) );
  64. ClientThink( self->s.number, &ucmd );
  65. VectorCopy( self->s.origin, self->s.origin2 );
  66. //FIXME: match my pitch and roll for the slope of my groundPlane
  67. if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE && !(self->flags&FL_DISINTEGRATED) )
  68. {//on the ground
  69. //FIXME: check 4 corners
  70. pitch_roll_for_slope( self );
  71. }
  72. if ( eventClearTime == level.time + ALERT_CLEAR_TIME )
  73. {//events were just cleared out so add me again
  74. if ( !(self->client->ps.eFlags&EF_NODRAW) )
  75. {
  76. AddSightEvent( self->enemy, self->currentOrigin, 384, AEL_DISCOVERED );
  77. }
  78. }
  79. if ( level.time - self->s.time > 3000 )
  80. {//been dead for 3 seconds
  81. if ( g_dismemberment->integer < 11381138 && !g_saberRealisticCombat->integer )
  82. {//can't be dismembered once dead
  83. if ( self->client->NPC_class != CLASS_PROTOCOL )
  84. {
  85. self->client->dismembered = true;
  86. }
  87. }
  88. }
  89. if ( level.time - self->s.time > 500 )
  90. {//don't turn "nonsolid" until about 1 second after actual death
  91. if ((self->client->NPC_class != CLASS_MARK1) && (self->client->NPC_class != CLASS_INTERROGATOR)) // The Mark1 & Interrogator stays solid.
  92. {
  93. self->contents = CONTENTS_CORPSE;
  94. }
  95. if ( self->message )
  96. {
  97. self->contents |= CONTENTS_TRIGGER;
  98. }
  99. }
  100. }
  101. /*
  102. ----------------------------------------
  103. NPC_RemoveBody
  104. Determines when it's ok to ditch the corpse
  105. ----------------------------------------
  106. */
  107. #define REMOVE_DISTANCE 128
  108. #define REMOVE_DISTANCE_SQR (REMOVE_DISTANCE * REMOVE_DISTANCE)
  109. extern qboolean InFOVFromPlayerView ( gentity_t *ent, int hFOV, int vFOV );
  110. qboolean G_OkayToRemoveCorpse( gentity_t *self )
  111. {
  112. //if we're still on a vehicle, we won't remove ourselves until we get ejected
  113. if ( self->client && self->client->NPC_class != CLASS_VEHICLE && self->s.m_iVehicleNum != 0 )
  114. {
  115. Vehicle_t *pVeh = g_entities[self->s.m_iVehicleNum].m_pVehicle;
  116. if ( pVeh )
  117. {
  118. if ( !pVeh->m_pVehicleInfo->Eject( pVeh, self, qtrue ) )
  119. {//dammit, still can't get off the vehicle...
  120. return qfalse;
  121. }
  122. }
  123. else
  124. {
  125. assert(0);
  126. #ifndef FINAL_BUILD
  127. Com_Printf(S_COLOR_RED"ERROR: Dead pilot's vehicle removed while corpse was riding it (pilot: %s)???\n",self->targetname);
  128. #endif
  129. }
  130. }
  131. if ( self->message )
  132. {//I still have a key
  133. return qfalse;
  134. }
  135. if ( IIcarusInterface::GetIcarus()->IsRunning( self->m_iIcarusID ) )
  136. {//still running a script
  137. return qfalse;
  138. }
  139. if ( self->activator
  140. && self->activator->client
  141. && ((self->activator->client->ps.eFlags&EF_HELD_BY_RANCOR)
  142. || (self->activator->client->ps.eFlags&EF_HELD_BY_SAND_CREATURE)
  143. || (self->activator->client->ps.eFlags&EF_HELD_BY_WAMPA)) )
  144. {//still holding a victim?
  145. return qfalse;
  146. }
  147. if ( self->client
  148. && ((self->client->ps.eFlags&EF_HELD_BY_RANCOR)
  149. || (self->client->ps.eFlags&EF_HELD_BY_SAND_CREATURE)
  150. || (self->client->ps.eFlags&EF_HELD_BY_WAMPA) ) )
  151. {//being held by a creature
  152. return qfalse;
  153. }
  154. if ( self->client->ps.heldByClient < ENTITYNUM_WORLD )
  155. {//being dragged
  156. return qfalse;
  157. }
  158. //okay, well okay to remove us...?
  159. return qtrue;
  160. }
  161. void NPC_RemoveBody( gentity_t *self )
  162. {
  163. self->nextthink = level.time + FRAMETIME/2;
  164. //run physics at 20fps
  165. CorpsePhysics( self );
  166. if ( self->NPC->nextBStateThink <= level.time )
  167. {//run logic at 10 fps
  168. if( self->m_iIcarusID != IIcarusInterface::ICARUS_INVALID && !stop_icarus )
  169. {
  170. IIcarusInterface::GetIcarus()->Update( self->m_iIcarusID );
  171. }
  172. self->NPC->nextBStateThink = level.time + FRAMETIME;
  173. if ( !G_OkayToRemoveCorpse( self ) )
  174. {
  175. return;
  176. }
  177. // I don't consider this a hack, it's creative coding . . .
  178. // I agree, very creative... need something like this for ATST and GALAKMECH too!
  179. if (self->client->NPC_class == CLASS_MARK1)
  180. {
  181. Mark1_dying( self );
  182. }
  183. // Since these blow up, remove the bounding box.
  184. if ( self->client->NPC_class == CLASS_REMOTE
  185. || self->client->NPC_class == CLASS_SENTRY
  186. || self->client->NPC_class == CLASS_PROBE
  187. || self->client->NPC_class == CLASS_INTERROGATOR
  188. || self->client->NPC_class == CLASS_PROBE
  189. || self->client->NPC_class == CLASS_MARK2 )
  190. {
  191. G_FreeEntity( self );
  192. return;
  193. }
  194. //FIXME: don't ever inflate back up?
  195. self->maxs[2] = self->client->renderInfo.eyePoint[2] - self->currentOrigin[2] + 4;
  196. if ( self->maxs[2] < -8 )
  197. {
  198. self->maxs[2] = -8;
  199. }
  200. if ( (self->NPC->aiFlags&NPCAI_HEAL_ROSH) )
  201. {//kothos twins' bodies are never removed
  202. return;
  203. }
  204. if ( self->client->NPC_class == CLASS_GALAKMECH )
  205. {//never disappears
  206. return;
  207. }
  208. if ( self->NPC && self->NPC->timeOfDeath <= level.time )
  209. {
  210. self->NPC->timeOfDeath = level.time + 1000;
  211. // Only do all of this nonsense for Scav boys ( and girls )
  212. /// if ( self->client->playerTeam == TEAM_SCAVENGERS || self->client->playerTeam == TEAM_KLINGON
  213. // || self->client->playerTeam == TEAM_HIROGEN || self->client->playerTeam == TEAM_MALON )
  214. // should I check NPC_class here instead of TEAM ? - dmv
  215. if( self->client->playerTeam == TEAM_ENEMY || self->client->NPC_class == CLASS_PROTOCOL )
  216. {
  217. self->nextthink = level.time + FRAMETIME; // try back in a second
  218. if ( DistanceSquared( g_entities[0].currentOrigin, self->currentOrigin ) <= REMOVE_DISTANCE_SQR )
  219. {
  220. return;
  221. }
  222. if ( (InFOVFromPlayerView( self, 110, 90 )) ) // generous FOV check
  223. {
  224. if ( (NPC_ClearLOS( &g_entities[0], self->currentOrigin )) )
  225. {
  226. return;
  227. }
  228. }
  229. }
  230. //FIXME: there are some conditions - such as heavy combat - in which we want
  231. // to remove the bodies... but in other cases it's just weird, like
  232. // when they're right behind you in a closed room and when they've been
  233. // placed as dead NPCs by a designer...
  234. // For now we just assume that a corpse with no enemy was
  235. // placed in the map as a corpse
  236. if ( self->enemy )
  237. {
  238. if ( self->client && self->client->ps.saberEntityNum > 0 && self->client->ps.saberEntityNum < ENTITYNUM_WORLD )
  239. {
  240. gentity_t *saberent = &g_entities[self->client->ps.saberEntityNum];
  241. if ( saberent )
  242. {
  243. G_FreeEntity( saberent );
  244. }
  245. }
  246. G_FreeEntity( self );
  247. }
  248. }
  249. }
  250. }
  251. /*
  252. ----------------------------------------
  253. NPC_RemoveBody
  254. Determines when it's ok to ditch the corpse
  255. ----------------------------------------
  256. */
  257. int BodyRemovalPadTime( gentity_t *ent )
  258. {
  259. int time;
  260. if ( !ent || !ent->client )
  261. return 0;
  262. /*
  263. switch ( ent->client->playerTeam )
  264. {
  265. case TEAM_KLINGON: // no effect, we just remove them when the player isn't looking
  266. case TEAM_SCAVENGERS:
  267. case TEAM_HIROGEN:
  268. case TEAM_MALON:
  269. case TEAM_IMPERIAL:
  270. case TEAM_STARFLEET:
  271. time = 10000; // 15 secs.
  272. break;
  273. case TEAM_BORG:
  274. time = 2000;
  275. break;
  276. case TEAM_STASIS:
  277. return qtrue;
  278. break;
  279. case TEAM_FORGE:
  280. time = 1000;
  281. break;
  282. case TEAM_BOTS:
  283. // if (!Q_stricmp( ent->NPC_type, "mouse" ))
  284. // {
  285. time = 0;
  286. // }
  287. // else
  288. // {
  289. // time = 10000;
  290. // }
  291. break;
  292. case TEAM_8472:
  293. time = 2000;
  294. break;
  295. default:
  296. // never go away
  297. time = Q3_INFINITE;
  298. break;
  299. }
  300. */
  301. // team no longer indicates species/race, so in this case we'd use NPC_class, but
  302. switch( ent->client->NPC_class )
  303. {
  304. case CLASS_MOUSE:
  305. case CLASS_GONK:
  306. case CLASS_R2D2:
  307. case CLASS_R5D2:
  308. //case CLASS_PROTOCOL:
  309. case CLASS_MARK1:
  310. case CLASS_MARK2:
  311. case CLASS_PROBE:
  312. case CLASS_SEEKER:
  313. case CLASS_REMOTE:
  314. case CLASS_SENTRY:
  315. case CLASS_INTERROGATOR:
  316. time = 0;
  317. break;
  318. default:
  319. // never go away
  320. if ( g_corpseRemovalTime->integer <= 0 )
  321. {
  322. time = Q3_INFINITE;
  323. }
  324. else
  325. {
  326. time = g_corpseRemovalTime->integer*1000;
  327. }
  328. break;
  329. }
  330. return time;
  331. }
  332. /*
  333. ----------------------------------------
  334. NPC_RemoveBodyEffect
  335. Effect to be applied when ditching the corpse
  336. ----------------------------------------
  337. */
  338. static void NPC_RemoveBodyEffect(void)
  339. {
  340. // vec3_t org;
  341. // gentity_t *tent;
  342. if ( !NPC || !NPC->client || (NPC->s.eFlags & EF_NODRAW) )
  343. return;
  344. /*
  345. switch(NPC->client->playerTeam)
  346. {
  347. case TEAM_STARFLEET:
  348. //FIXME: Starfleet beam out
  349. break;
  350. case TEAM_BOTS:
  351. // VectorCopy( NPC->currentOrigin, org );
  352. // org[2] -= 16;
  353. // tent = G_TempEntity( org, EV_BOT_EXPLODE );
  354. // tent->owner = NPC;
  355. break;
  356. default:
  357. break;
  358. }
  359. */
  360. // team no longer indicates species/race, so in this case we'd use NPC_class, but
  361. // stub code
  362. switch(NPC->client->NPC_class)
  363. {
  364. case CLASS_PROBE:
  365. case CLASS_SEEKER:
  366. case CLASS_REMOTE:
  367. case CLASS_SENTRY:
  368. case CLASS_GONK:
  369. case CLASS_R2D2:
  370. case CLASS_R5D2:
  371. //case CLASS_PROTOCOL:
  372. case CLASS_MARK1:
  373. case CLASS_MARK2:
  374. case CLASS_INTERROGATOR:
  375. case CLASS_ATST: // yeah, this is a little weird, but for now I'm listing all droids
  376. // VectorCopy( NPC->currentOrigin, org );
  377. // org[2] -= 16;
  378. // tent = G_TempEntity( org, EV_BOT_EXPLODE );
  379. // tent->owner = NPC;
  380. break;
  381. default:
  382. break;
  383. }
  384. }
  385. /*
  386. ====================================================================
  387. void pitch_roll_for_slope (edict_t *forwhom, vec3_t *slope, vec3_t storeAngles )
  388. MG
  389. This will adjust the pitch and roll of a monster to match
  390. a given slope - if a non-'0 0 0' slope is passed, it will
  391. use that value, otherwise it will use the ground underneath
  392. the monster. If it doesn't find a surface, it does nothinh\g
  393. and returns.
  394. ====================================================================
  395. */
  396. void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope, vec3_t storeAngles )
  397. {
  398. vec3_t slope;
  399. vec3_t nvf, ovf, ovr, startspot, endspot, new_angles = { 0, 0, 0 };
  400. float pitch, mod, dot;
  401. //if we don't have a slope, get one
  402. if( !pass_slope || VectorCompare( vec3_origin, pass_slope ) )
  403. {
  404. trace_t trace;
  405. VectorCopy( forwhom->currentOrigin, startspot );
  406. startspot[2] += forwhom->mins[2] + 4;
  407. VectorCopy( startspot, endspot );
  408. endspot[2] -= 300;
  409. gi.trace( &trace, forwhom->currentOrigin, vec3_origin, vec3_origin, endspot, forwhom->s.number, MASK_SOLID );
  410. // if(trace_fraction>0.05&&forwhom.movetype==MOVETYPE_STEP)
  411. // forwhom.flags(-)FL_ONGROUND;
  412. if ( trace.fraction >= 1.0 )
  413. return;
  414. if( !( &trace.plane ) )
  415. return;
  416. if ( VectorCompare( vec3_origin, trace.plane.normal ) )
  417. return;
  418. VectorCopy( trace.plane.normal, slope );
  419. }
  420. else
  421. {
  422. VectorCopy( pass_slope, slope );
  423. }
  424. if ( forwhom->client && forwhom->client->NPC_class == CLASS_VEHICLE )
  425. {//special code for vehicles
  426. Vehicle_t *pVeh = forwhom->m_pVehicle;
  427. vec3_t tempAngles;
  428. tempAngles[PITCH] = tempAngles[ROLL] = 0;
  429. tempAngles[YAW] = pVeh->m_vOrientation[YAW];
  430. AngleVectors( tempAngles, ovf, ovr, NULL );
  431. }
  432. else
  433. {
  434. AngleVectors( forwhom->currentAngles, ovf, ovr, NULL );
  435. }
  436. vectoangles( slope, new_angles );
  437. pitch = new_angles[PITCH] + 90;
  438. new_angles[ROLL] = new_angles[PITCH] = 0;
  439. AngleVectors( new_angles, nvf, NULL, NULL );
  440. mod = DotProduct( nvf, ovr );
  441. if ( mod<0 )
  442. mod = -1;
  443. else
  444. mod = 1;
  445. dot = DotProduct( nvf, ovf );
  446. if ( storeAngles )
  447. {
  448. storeAngles[PITCH] = dot * pitch;
  449. storeAngles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod);
  450. }
  451. else if ( forwhom->client )
  452. {
  453. forwhom->client->ps.viewangles[PITCH] = dot * pitch;
  454. forwhom->client->ps.viewangles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod);
  455. float oldmins2 = forwhom->mins[2];
  456. forwhom->mins[2] = -24 + 12 * fabs(forwhom->client->ps.viewangles[PITCH])/180.0f;
  457. //FIXME: if it gets bigger, move up
  458. if ( oldmins2 > forwhom->mins[2] )
  459. {//our mins is now lower, need to move up
  460. //FIXME: trace?
  461. forwhom->client->ps.origin[2] += (oldmins2 - forwhom->mins[2]);
  462. forwhom->currentOrigin[2] = forwhom->client->ps.origin[2];
  463. gi.linkentity( forwhom );
  464. }
  465. }
  466. else
  467. {
  468. forwhom->currentAngles[PITCH] = dot * pitch;
  469. forwhom->currentAngles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod);
  470. }
  471. }
  472. /*
  473. void NPC_PostDeathThink( void )
  474. {
  475. float mostdist;
  476. trace_t trace1, trace2, trace3, trace4, movetrace;
  477. vec3_t org, endpos, startpos, forward, right;
  478. int whichtrace = 0;
  479. float cornerdist[4];
  480. qboolean frontbackbothclear = false;
  481. qboolean rightleftbothclear = false;
  482. if( NPC->client->ps.groundEntityNum == ENTITYNUM_NONE || !VectorCompare( vec3_origin, NPC->client->ps.velocity ) )
  483. {
  484. if ( NPC->client->ps.groundEntityNum != ENTITYNUM_NONE && NPC->client->ps.friction == 1.0 )//check avelocity?
  485. {
  486. pitch_roll_for_slope( NPC );
  487. }
  488. return;
  489. }
  490. cornerdist[FRONT] = cornerdist[BACK] = cornerdist[RIGHT] = cornerdist[LEFT] = 0.0f;
  491. mostdist = MIN_DROP_DIST;
  492. AngleVectors( NPC->currentAngles, forward, right, NULL );
  493. VectorCopy( NPC->currentOrigin, org );
  494. org[2] += NPC->mins[2];
  495. VectorMA( org, NPC->dead_size, forward, startpos );
  496. VectorCopy( startpos, endpos );
  497. endpos[2] -= 128;
  498. gi.trace( &trace1, startpos, vec3_origin, vec3_origin, endpos, NPC->s.number, MASK_SOLID, );
  499. if( !trace1.allsolid && !trace1.startsolid )
  500. {
  501. cornerdist[FRONT] = trace1.fraction;
  502. if ( trace1.fraction > mostdist )
  503. {
  504. mostdist = trace1.fraction;
  505. whichtrace = 1;
  506. }
  507. }
  508. VectorMA( org, -NPC->dead_size, forward, startpos );
  509. VectorCopy( startpos, endpos );
  510. endpos[2] -= 128;
  511. gi.trace( &trace2, startpos, vec3_origin, vec3_origin, endpos, NPC->s.number, MASK_SOLID );
  512. if( !trace2.allsolid && !trace2.startsolid )
  513. {
  514. cornerdist[BACK] = trace2.fraction;
  515. if ( trace2.fraction > mostdist )
  516. {
  517. mostdist = trace2.fraction;
  518. whichtrace = 2;
  519. }
  520. }
  521. VectorMA( org, NPC->dead_size/2, right, startpos );
  522. VectorCopy( startpos, endpos );
  523. endpos[2] -= 128;
  524. gi.trace( &trace3, startpos, vec3_origin, vec3_origin, endpos, NPC->s.number, MASK_SOLID );
  525. if ( !trace3.allsolid && !trace3.startsolid )
  526. {
  527. cornerdist[RIGHT] = trace3.fraction;
  528. if ( trace3.fraction>mostdist )
  529. {
  530. mostdist = trace3.fraction;
  531. whichtrace = 3;
  532. }
  533. }
  534. VectorMA( org, -NPC->dead_size/2, right, startpos );
  535. VectorCopy( startpos, endpos );
  536. endpos[2] -= 128;
  537. gi.trace( &trace4, startpos, vec3_origin, vec3_origin, endpos, NPC->s.number, MASK_SOLID );
  538. if ( !trace4.allsolid && !trace4.startsolid )
  539. {
  540. cornerdist[LEFT] = trace4.fraction;
  541. if ( trace4.fraction > mostdist )
  542. {
  543. mostdist = trace4.fraction;
  544. whichtrace = 4;
  545. }
  546. }
  547. //OK! Now if two opposite sides are hanging, use a third if any, else, do nothing
  548. if ( cornerdist[FRONT] > MIN_DROP_DIST && cornerdist[BACK] > MIN_DROP_DIST )
  549. frontbackbothclear = true;
  550. if ( cornerdist[RIGHT] > MIN_DROP_DIST && cornerdist[LEFT] > MIN_DROP_DIST )
  551. rightleftbothclear = true;
  552. if ( frontbackbothclear && rightleftbothclear )
  553. return;
  554. if ( frontbackbothclear )
  555. {
  556. if ( cornerdist[RIGHT] > MIN_DROP_DIST )
  557. whichtrace = 3;
  558. else if ( cornerdist[LEFT] > MIN_DROP_DIST )
  559. whichtrace = 4;
  560. else
  561. return;
  562. }
  563. if ( rightleftbothclear )
  564. {
  565. if ( cornerdist[FRONT] > MIN_DROP_DIST )
  566. whichtrace = 1;
  567. else if ( cornerdist[BACK] > MIN_DROP_DIST )
  568. whichtrace = 2;
  569. else
  570. return;
  571. }
  572. switch ( whichtrace )
  573. {//check for stuck
  574. case 1:
  575. VectorMA( NPC->currentOrigin, NPC->maxs[0], forward, endpos );
  576. gi.trace( &movetrace, NPC->currentOrigin, NPC->mins, NPC->maxs, endpos, NPC->s.number, MASK_MONSTERSOLID );
  577. if ( movetrace.allsolid || movetrace.startsolid || movetrace.fraction < 1.0 )
  578. if ( canmove( movetrace.ent ) )
  579. whichtrace = -1;
  580. else
  581. whichtrace = 0;
  582. break;
  583. case 2:
  584. VectorMA( NPC->currentOrigin, -NPC->maxs[0], forward, endpos );
  585. gi.trace( &movetrace, NPC->currentOrigin, NPC->mins, NPC->maxs, endpos, NPC->s.number, MASK_MONSTERSOLID );
  586. if ( movetrace.allsolid || movetrace.startsolid || movetrace.fraction < 1.0 )
  587. if ( canmove( movetrace.ent ) )
  588. whichtrace = -1;
  589. else
  590. whichtrace = 0;
  591. break;
  592. case 3:
  593. VectorMA( NPC->currentOrigin, NPC->maxs[0], right, endpos );
  594. gi.trace( &movetrace, NPC->currentOrigin, NPC->mins, NPC->maxs, endpos, NPC->s.number, MASK_MONSTERSOLID );
  595. if ( movetrace.allsolid || movetrace.startsolid || movetrace.fraction < 1.0 )
  596. if ( canmove( movetrace.ent ) )
  597. whichtrace = -1;
  598. else
  599. whichtrace = 0;
  600. break;
  601. case 4:
  602. VectorMA( NPC->currentOrigin, -NPC->maxs[0], right, endpos );
  603. gi.trace( &movetrace, NPC->currentOrigin, NPC->mins, NPC->maxs, endpos, NPC->s.number, MASK_MONSTERSOLID );
  604. if (movetrace.allsolid || movetrace.startsolid || movetrace.fraction < 1.0 )
  605. if ( canmove( movetrace.ent ) )
  606. whichtrace = -1;
  607. else
  608. whichtrace = 0;
  609. break;
  610. }
  611. switch ( whichtrace )
  612. {
  613. case 1:
  614. VectorMA( NPC->client->ps.velocity, 200, forward, NPC->client->ps.velocity );
  615. if ( trace1.fraction >= 0.9 )
  616. {
  617. //can't anymore, origin not in center of deathframe!
  618. // NPC->avelocity[PITCH] = -300;
  619. NPC->client->ps.friction = 1.0;
  620. }
  621. else
  622. {
  623. pitch_roll_for_slope( NPC, &trace1.plane.normal );
  624. NPC->client->ps.friction = trace1.plane.normal[2] * 0.1;
  625. }
  626. return;
  627. break;
  628. case 2:
  629. VectorMA( NPC->client->ps.velocity, -200, forward, NPC->client->ps.velocity );
  630. if(trace2.fraction >= 0.9)
  631. {
  632. //can't anymore, origin not in center of deathframe!
  633. // NPC->avelocity[PITCH] = 300;
  634. NPC->client->ps.friction = 1.0;
  635. }
  636. else
  637. {
  638. pitch_roll_for_slope( NPC, &trace2.plane.normal );
  639. NPC->client->ps.friction = trace2.plane.normal[2] * 0.1;
  640. }
  641. return;
  642. break;
  643. case 3:
  644. VectorMA( NPC->client->ps.velocity, 200, right, NPC->client->ps.velocity );
  645. if ( trace3.fraction >= 0.9 )
  646. {
  647. //can't anymore, origin not in center of deathframe!
  648. // NPC->avelocity[ROLL] = -300;
  649. NPC->client->ps.friction = 1.0;
  650. }
  651. else
  652. {
  653. pitch_roll_for_slope( NPC, &trace3.plane.normal );
  654. NPC->client->ps.friction = trace3.plane.normal[2] * 0.1;
  655. }
  656. return;
  657. break;
  658. case 4:
  659. VectorMA( NPC->client->ps.velocity, -200, right, NPC->client->ps.velocity );
  660. if ( trace4.fraction >= 0.9 )
  661. {
  662. //can't anymore, origin not in center of deathframe!
  663. // NPC->avelocity[ROLL] = 300;
  664. NPC->client->ps.friction = 1.0;
  665. }
  666. else
  667. {
  668. pitch_roll_for_slope( NPC, &trace4.plane.normal );
  669. NPC->client->ps.friction = trace4.plane.normal[2] * 0.1;
  670. }
  671. return;
  672. break;
  673. }
  674. //on solid ground
  675. if ( whichtrace == -1 )
  676. {
  677. return;
  678. }
  679. NPC->client->ps.friction = 1.0;
  680. //VectorClear( NPC->avelocity );
  681. pitch_roll_for_slope( NPC );
  682. //gi.linkentity (NPC);
  683. }
  684. */
  685. /*
  686. ----------------------------------------
  687. DeadThink
  688. ----------------------------------------
  689. */
  690. static void DeadThink ( void )
  691. {
  692. trace_t trace;
  693. //HACKHACKHACKHACKHACK
  694. //We should really have a seperate G2 bounding box (seperate from the physics bbox) for G2 collisions only
  695. //FIXME: don't ever inflate back up?
  696. //GAH! With Ragdoll, they get stuck in the ceiling
  697. float oldMaxs2 = NPC->maxs[2];
  698. NPC->maxs[2] = NPC->client->renderInfo.eyePoint[2] - NPC->currentOrigin[2] + 4;
  699. if ( NPC->maxs[2] < -8 )
  700. {
  701. NPC->maxs[2] = -8;
  702. }
  703. if ( NPC->maxs[2] > oldMaxs2 )
  704. {//inflating maxs, make sure we're not inflating into solid
  705. gi.trace (&trace, NPC->currentOrigin, NPC->mins, NPC->maxs, NPC->currentOrigin, NPC->s.number, NPC->clipmask );
  706. if ( trace.allsolid )
  707. {//must be inflating
  708. NPC->maxs[2] = oldMaxs2;
  709. }
  710. }
  711. /*
  712. {
  713. if ( VectorCompare( NPC->client->ps.velocity, vec3_origin ) )
  714. {//not flying through the air
  715. if ( NPC->mins[0] > -32 )
  716. {
  717. NPC->mins[0] -= 1;
  718. gi.trace (&trace, NPC->currentOrigin, NPC->mins, NPC->maxs, NPC->currentOrigin, NPC->s.number, NPC->clipmask );
  719. if ( trace.allsolid )
  720. {
  721. NPC->mins[0] += 1;
  722. }
  723. }
  724. if ( NPC->maxs[0] < 32 )
  725. {
  726. NPC->maxs[0] += 1;
  727. gi.trace (&trace, NPC->currentOrigin, NPC->mins, NPC->maxs, NPC->currentOrigin, NPC->s.number, NPC->clipmask );
  728. if ( trace.allsolid )
  729. {
  730. NPC->maxs[0] -= 1;
  731. }
  732. }
  733. if ( NPC->mins[1] > -32 )
  734. {
  735. NPC->mins[1] -= 1;
  736. gi.trace (&trace, NPC->currentOrigin, NPC->mins, NPC->maxs, NPC->currentOrigin, NPC->s.number, NPC->clipmask );
  737. if ( trace.allsolid )
  738. {
  739. NPC->mins[1] += 1;
  740. }
  741. }
  742. if ( NPC->maxs[1] < 32 )
  743. {
  744. NPC->maxs[1] += 1;
  745. gi.trace (&trace, NPC->currentOrigin, NPC->mins, NPC->maxs, NPC->currentOrigin, NPC->s.number, NPC->clipmask );
  746. if ( trace.allsolid )
  747. {
  748. NPC->maxs[1] -= 1;
  749. }
  750. }
  751. }
  752. }
  753. //HACKHACKHACKHACKHACK
  754. */
  755. //FIXME: tilt and fall off of ledges?
  756. //NPC_PostDeathThink();
  757. /*
  758. if ( !NPCInfo->timeOfDeath && NPC->client != NULL && NPCInfo != NULL )
  759. {
  760. //haven't finished death anim yet and were NOT given a specific amount of time to wait before removal
  761. int legsAnim = NPC->client->ps.legsAnim;
  762. animation_t *animations = knownAnimFileSets[NPC->client->clientInfo.animFileIndex].animations;
  763. NPC->bounceCount = -1; // This is a cheap hack for optimizing the pointcontents check below
  764. //ghoul doesn't tell us this anymore
  765. //if ( NPC->client->renderInfo.legsFrame == animations[legsAnim].firstFrame + (animations[legsAnim].numFrames - 1) )
  766. {
  767. //reached the end of the death anim
  768. NPCInfo->timeOfDeath = level.time + BodyRemovalPadTime( NPC );
  769. }
  770. }
  771. else
  772. */
  773. {
  774. //death anim done (or were given a specific amount of time to wait before removal), wait the requisite amount of time them remove
  775. if ( level.time >= NPCInfo->timeOfDeath + BodyRemovalPadTime( NPC ) )
  776. {
  777. if ( NPC->client->ps.eFlags & EF_NODRAW )
  778. {
  779. if ( !IIcarusInterface::GetIcarus()->IsRunning( NPC->m_iIcarusID ) )
  780. {
  781. NPC->e_ThinkFunc = thinkF_G_FreeEntity;
  782. NPC->nextthink = level.time + FRAMETIME;
  783. }
  784. }
  785. else
  786. {
  787. // Start the body effect first, then delay 400ms before ditching the corpse
  788. NPC_RemoveBodyEffect();
  789. //FIXME: keep it running through physics somehow?
  790. NPC->e_ThinkFunc = thinkF_NPC_RemoveBody;
  791. NPC->nextthink = level.time + FRAMETIME/2;
  792. // if ( NPC->client->playerTeam == TEAM_FORGE )
  793. // NPCInfo->timeOfDeath = level.time + FRAMETIME * 8;
  794. // else if ( NPC->client->playerTeam == TEAM_BOTS )
  795. class_t npc_class = NPC->client->NPC_class;
  796. // check for droids
  797. if ( npc_class == CLASS_SEEKER || npc_class == CLASS_REMOTE || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE ||
  798. npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 ||
  799. npc_class == CLASS_MARK2 || npc_class == CLASS_SENTRY )//npc_class == CLASS_PROTOCOL ||
  800. {
  801. NPC->client->ps.eFlags |= EF_NODRAW;
  802. NPCInfo->timeOfDeath = level.time + FRAMETIME * 8;
  803. }
  804. else
  805. {
  806. NPCInfo->timeOfDeath = level.time + FRAMETIME * 4;
  807. }
  808. }
  809. return;
  810. }
  811. }
  812. // If the player is on the ground and the resting position contents haven't been set yet...(BounceCount tracks the contents)
  813. if ( NPC->bounceCount < 0 && NPC->s.groundEntityNum >= 0 )
  814. {
  815. // if client is in a nodrop area, make him/her nodraw
  816. int contents = NPC->bounceCount = gi.pointcontents( NPC->currentOrigin, -1 );
  817. if ( ( contents & CONTENTS_NODROP ) )
  818. {
  819. NPC->client->ps.eFlags |= EF_NODRAW;
  820. }
  821. }
  822. CorpsePhysics( NPC );
  823. }
  824. /*
  825. ===============
  826. SetNPCGlobals
  827. local function to set globals used throughout the AI code
  828. ===============
  829. */
  830. void SetNPCGlobals( gentity_t *ent )
  831. {
  832. NPC = ent;
  833. NPCInfo = ent->NPC;
  834. client = ent->client;
  835. memset( &ucmd, 0, sizeof( usercmd_t ) );
  836. }
  837. gentity_t *_saved_NPC;
  838. gNPC_t *_saved_NPCInfo;
  839. gclient_t *_saved_client;
  840. usercmd_t _saved_ucmd;
  841. void SaveNPCGlobals()
  842. {
  843. _saved_NPC = NPC;
  844. _saved_NPCInfo = NPCInfo;
  845. _saved_client = client;
  846. memcpy( &_saved_ucmd, &ucmd, sizeof( usercmd_t ) );
  847. }
  848. void RestoreNPCGlobals()
  849. {
  850. NPC = _saved_NPC;
  851. NPCInfo = _saved_NPCInfo;
  852. client = _saved_client;
  853. memcpy( &ucmd, &_saved_ucmd, sizeof( usercmd_t ) );
  854. }
  855. //We MUST do this, other funcs were using NPC illegally when "self" wasn't the global NPC
  856. void ClearNPCGlobals( void )
  857. {
  858. NPC = NULL;
  859. NPCInfo = NULL;
  860. client = NULL;
  861. }
  862. //===============
  863. extern qboolean showBBoxes;
  864. vec3_t NPCDEBUG_RED = {1.0, 0.0, 0.0};
  865. vec3_t NPCDEBUG_GREEN = {0.0, 1.0, 0.0};
  866. vec3_t NPCDEBUG_BLUE = {0.0, 0.0, 1.0};
  867. vec3_t NPCDEBUG_LIGHT_BLUE = {0.3f, 0.7f, 1.0};
  868. extern void CG_Cube( vec3_t mins, vec3_t maxs, vec3_t color, float alpha );
  869. extern void CG_Line( vec3_t start, vec3_t end, vec3_t color, float alpha );
  870. extern void CG_Cylinder( vec3_t start, vec3_t end, float radius, vec3_t color );
  871. void NPC_ShowDebugInfo (void)
  872. {
  873. if ( showBBoxes )
  874. {
  875. gentity_t *found = NULL;
  876. vec3_t mins, maxs;
  877. //do player, too
  878. VectorAdd( player->currentOrigin, player->mins, mins );
  879. VectorAdd( player->currentOrigin, player->maxs, maxs );
  880. CG_Cube( mins, maxs, NPCDEBUG_RED, 0.25 );
  881. //do NPCs
  882. while( (found = G_Find( found, FOFS(classname), "NPC" ) ) != NULL )
  883. {
  884. if ( gi.inPVS( found->currentOrigin, g_entities[0].currentOrigin ) )
  885. {
  886. VectorAdd( found->currentOrigin, found->mins, mins );
  887. VectorAdd( found->currentOrigin, found->maxs, maxs );
  888. CG_Cube( mins, maxs, NPCDEBUG_RED, 0.25 );
  889. }
  890. }
  891. }
  892. }
  893. void NPC_ApplyScriptFlags (void)
  894. {
  895. if ( NPCInfo->scriptFlags & SCF_CROUCHED )
  896. {
  897. if ( NPCInfo->charmedTime > level.time && (ucmd.forwardmove || ucmd.rightmove) )
  898. {//ugh, if charmed and moving, ignore the crouched command
  899. }
  900. else
  901. {
  902. ucmd.upmove = -127;
  903. }
  904. }
  905. if(NPCInfo->scriptFlags & SCF_RUNNING)
  906. {
  907. ucmd.buttons &= ~BUTTON_WALKING;
  908. }
  909. else if(NPCInfo->scriptFlags & SCF_WALKING)
  910. {
  911. if ( NPCInfo->charmedTime > level.time && (ucmd.forwardmove || ucmd.rightmove) )
  912. {//ugh, if charmed and moving, ignore the walking command
  913. }
  914. else
  915. {
  916. ucmd.buttons |= BUTTON_WALKING;
  917. }
  918. }
  919. /*
  920. if(NPCInfo->scriptFlags & SCF_CAREFUL)
  921. {
  922. ucmd.buttons |= BUTTON_CAREFUL;
  923. }
  924. */
  925. if(NPCInfo->scriptFlags & SCF_LEAN_RIGHT)
  926. {
  927. ucmd.buttons |= BUTTON_USE;
  928. ucmd.rightmove = 127;
  929. ucmd.forwardmove = 0;
  930. ucmd.upmove = 0;
  931. }
  932. else if(NPCInfo->scriptFlags & SCF_LEAN_LEFT)
  933. {
  934. ucmd.buttons |= BUTTON_USE;
  935. ucmd.rightmove = -127;
  936. ucmd.forwardmove = 0;
  937. ucmd.upmove = 0;
  938. }
  939. if ( (NPCInfo->scriptFlags & SCF_ALT_FIRE) && (ucmd.buttons & BUTTON_ATTACK) )
  940. {//Use altfire instead
  941. ucmd.buttons |= BUTTON_ALT_ATTACK;
  942. }
  943. // only removes NPC when it's safe too (Player is out of PVS)
  944. if( NPCInfo->scriptFlags & SCF_SAFE_REMOVE )
  945. {
  946. // take from BSRemove
  947. if( !gi.inPVS( NPC->currentOrigin, g_entities[0].currentOrigin ) )//FIXME: use cg.vieworg?
  948. {
  949. G_UseTargets2( NPC, NPC, NPC->target3 );
  950. NPC->s.eFlags |= EF_NODRAW;
  951. NPC->svFlags &= ~SVF_NPC;
  952. NPC->s.eType = ET_INVISIBLE;
  953. NPC->contents = 0;
  954. NPC->health = 0;
  955. NPC->targetname = NULL;
  956. //Disappear in half a second
  957. NPC->e_ThinkFunc = thinkF_G_FreeEntity;
  958. NPC->nextthink = level.time + FRAMETIME;
  959. }//FIXME: else allow for out of FOV???
  960. }
  961. }
  962. extern qboolean JET_Flying( gentity_t *self );
  963. extern void JET_FlyStart( gentity_t *self );
  964. extern void JET_FlyStop( gentity_t *self );
  965. void NPC_HandleAIFlags (void)
  966. {
  967. // Update Guys With Jet Packs
  968. //----------------------------
  969. if (NPCInfo->scriptFlags & SCF_FLY_WITH_JET)
  970. {
  971. bool ShouldFly = !!(NPCInfo->aiFlags & NPCAI_FLY);
  972. bool IsFlying = !!(JET_Flying(NPC));
  973. bool IsInTheAir = (NPC->client->ps.groundEntityNum==ENTITYNUM_NONE);
  974. if (IsFlying)
  975. {
  976. // Don't Stop Flying Until Near The Ground
  977. //-----------------------------------------
  978. if (IsInTheAir)
  979. {
  980. vec3_t ground;
  981. trace_t trace;
  982. VectorCopy(NPC->currentOrigin, ground);
  983. ground[2] -= 60.0f;
  984. gi.trace(&trace, NPC->currentOrigin, 0, 0, ground, NPC->s.number, NPC->clipmask);
  985. IsInTheAir = (!trace.allsolid && !trace.startsolid && trace.fraction>0.9f);
  986. }
  987. // If Flying, Remember The Last Time
  988. //-----------------------------------
  989. if (IsInTheAir)
  990. {
  991. NPC->lastInAirTime = level.time;
  992. ShouldFly = true;
  993. }
  994. // Auto Turn Off Jet Pack After 1 Second On The Ground
  995. //-----------------------------------------------------
  996. else if (!ShouldFly && (level.time - NPC->lastInAirTime)>3000)
  997. {
  998. NPCInfo->aiFlags &= ~NPCAI_FLY;
  999. }
  1000. }
  1001. // If We Should Be Flying And Are Not, Start Er Up
  1002. //-------------------------------------------------
  1003. if (ShouldFly && !IsFlying)
  1004. {
  1005. JET_FlyStart(NPC); // EVENTUALLY, Remove All Other Calls
  1006. }
  1007. // Otherwise, If Needed, Shut It Off
  1008. //-----------------------------------
  1009. else if (!ShouldFly && IsFlying)
  1010. {
  1011. JET_FlyStop(NPC); // EVENTUALLY, Remove All Other Calls
  1012. }
  1013. }
  1014. //FIXME: make these flags checks a function call like NPC_CheckAIFlagsAndTimers
  1015. if ( NPCInfo->aiFlags & NPCAI_LOST )
  1016. {//Print that you need help!
  1017. //FIXME: shouldn't remove this just yet if cg_draw needs it
  1018. NPCInfo->aiFlags &= ~NPCAI_LOST;
  1019. /*
  1020. if ( showWaypoints )
  1021. {
  1022. Quake3Game()->DebugPrint(WL_WARNING, "%s can't navigate to target %s (my wp: %d, goal wp: %d)\n", NPC->targetname, NPCInfo->goalEntity->targetname, NPC->waypoint, NPCInfo->goalEntity->waypoint );
  1023. }
  1024. */
  1025. if ( NPCInfo->goalEntity && NPCInfo->goalEntity == NPC->enemy )
  1026. {//We can't nav to our enemy
  1027. //Drop enemy and see if we should search for him
  1028. NPC_LostEnemyDecideChase();
  1029. }
  1030. }
  1031. //been told to play a victory sound after a delay
  1032. if ( NPCInfo->greetingDebounceTime && NPCInfo->greetingDebounceTime < level.time )
  1033. {
  1034. G_AddVoiceEvent( NPC, Q_irand(EV_VICTORY1, EV_VICTORY3), Q_irand( 2000, 4000 ) );
  1035. NPCInfo->greetingDebounceTime = 0;
  1036. }
  1037. if ( NPCInfo->ffireCount > 0 )
  1038. {
  1039. if ( NPCInfo->ffireFadeDebounce < level.time )
  1040. {
  1041. NPCInfo->ffireCount--;
  1042. //Com_Printf( "drop: %d < %d\n", NPCInfo->ffireCount, 3+((2-g_spskill->integer)*2) );
  1043. NPCInfo->ffireFadeDebounce = level.time + 3000;
  1044. }
  1045. }
  1046. }
  1047. void NPC_AvoidWallsAndCliffs (void)
  1048. {
  1049. /*
  1050. vec3_t forward, right, testPos, angles, mins;
  1051. trace_t trace;
  1052. float fwdDist, rtDist;
  1053. //FIXME: set things like this forward dir once at the beginning
  1054. //of a frame instead of over and over again
  1055. if ( NPCInfo->aiFlags & NPCAI_NO_COLL_AVOID )
  1056. {
  1057. return;
  1058. }
  1059. if ( ucmd.upmove > 0 || NPC->client->ps.groundEntityNum == ENTITYNUM_NONE )
  1060. {//Going to jump or in the air
  1061. return;
  1062. }
  1063. if ( !ucmd.forwardmove && !ucmd.rightmove )
  1064. {
  1065. return;
  1066. }
  1067. if ( fabs( AngleDelta( NPC->currentAngles[YAW], NPCInfo->desiredYaw ) ) < 5.0 )//!ucmd.angles[YAW] )
  1068. {//Not turning much, don't do this
  1069. //NOTE: Should this not happen only if you're not turning AT ALL?
  1070. // You could be turning slowly but moving fast, so that would
  1071. // still let you walk right off a cliff...
  1072. //NOTE: Or maybe it is a good idea to ALWAYS do this, regardless
  1073. // of whether ot not we're turning? But why would we be walking
  1074. // straight into a wall or off a cliff unless we really wanted to?
  1075. return;
  1076. }
  1077. VectorCopy( NPC->mins, mins );
  1078. mins[2] += STEPSIZE;
  1079. angles[YAW] = NPC->client->ps.viewangles[YAW];//Add ucmd.angles[YAW]?
  1080. AngleVectors( angles, forward, right, NULL );
  1081. fwdDist = ((float)ucmd.forwardmove)/16.0f;
  1082. rtDist = ((float)ucmd.rightmove)/16.0f;
  1083. VectorMA( NPC->currentOrigin, fwdDist, forward, testPos );
  1084. VectorMA( testPos, rtDist, right, testPos );
  1085. gi.trace( &trace, NPC->currentOrigin, mins, NPC->maxs, testPos, NPC->s.number, NPC->clipmask );
  1086. if ( trace.allsolid || trace.startsolid || trace.fraction < 1.0 )
  1087. {//Going to bump into something, don't move, just turn
  1088. ucmd.forwardmove = 0;
  1089. ucmd.rightmove = 0;
  1090. return;
  1091. }
  1092. VectorCopy(trace.endpos, testPos);
  1093. testPos[2] -= 128;
  1094. gi.trace( &trace, trace.endpos, mins, NPC->maxs, testPos, NPC->s.number, NPC->clipmask );
  1095. if ( trace.allsolid || trace.startsolid || trace.fraction < 1.0 )
  1096. {//Not going off a cliff
  1097. return;
  1098. }
  1099. //going to fall at least 128, don't move, just turn... is this bad, though? What if we want them to drop off?
  1100. ucmd.forwardmove = 0;
  1101. ucmd.rightmove = 0;
  1102. return;
  1103. */
  1104. }
  1105. void NPC_CheckAttackScript(void)
  1106. {
  1107. if(!(ucmd.buttons & BUTTON_ATTACK))
  1108. {
  1109. return;
  1110. }
  1111. G_ActivateBehavior(NPC, BSET_ATTACK);
  1112. }
  1113. float NPC_MaxDistSquaredForWeapon (void);
  1114. void NPC_CheckAttackHold(void)
  1115. {
  1116. vec3_t vec;
  1117. // If they don't have an enemy they shouldn't hold their attack anim.
  1118. if ( !NPC->enemy )
  1119. {
  1120. NPCInfo->attackHoldTime = 0;
  1121. return;
  1122. }
  1123. //FIXME: need to tie this into AI somehow?
  1124. VectorSubtract(NPC->enemy->currentOrigin, NPC->currentOrigin, vec);
  1125. if( VectorLengthSquared(vec) > NPC_MaxDistSquaredForWeapon() )
  1126. {
  1127. NPCInfo->attackHoldTime = 0;
  1128. }
  1129. else if( NPCInfo->attackHoldTime && NPCInfo->attackHoldTime > level.time )
  1130. {
  1131. ucmd.buttons |= BUTTON_ATTACK;
  1132. }
  1133. else if ( ( NPCInfo->attackHold ) && ( ucmd.buttons & BUTTON_ATTACK ) )
  1134. {
  1135. NPCInfo->attackHoldTime = level.time + NPCInfo->attackHold;
  1136. }
  1137. else
  1138. {
  1139. NPCInfo->attackHoldTime = 0;
  1140. }
  1141. }
  1142. /*
  1143. void NPC_KeepCurrentFacing(void)
  1144. Fills in a default ucmd to keep current angles facing
  1145. */
  1146. void NPC_KeepCurrentFacing(void)
  1147. {
  1148. if(!ucmd.angles[YAW])
  1149. {
  1150. ucmd.angles[YAW] = ANGLE2SHORT( client->ps.viewangles[YAW] ) - client->ps.delta_angles[YAW];
  1151. }
  1152. if(!ucmd.angles[PITCH])
  1153. {
  1154. ucmd.angles[PITCH] = ANGLE2SHORT( client->ps.viewangles[PITCH] ) - client->ps.delta_angles[PITCH];
  1155. }
  1156. }
  1157. /*
  1158. -------------------------
  1159. NPC_BehaviorSet_Charmed
  1160. -------------------------
  1161. */
  1162. void NPC_BehaviorSet_Charmed( int bState )
  1163. {
  1164. switch( bState )
  1165. {
  1166. case BS_FOLLOW_LEADER://# 40: Follow your leader and shoot any enemies you come across
  1167. NPC_BSFollowLeader();
  1168. break;
  1169. case BS_REMOVE:
  1170. NPC_BSRemove();
  1171. break;
  1172. case BS_SEARCH: //# 43: Using current waypoint as a base, search the immediate branches of waypoints for enemies
  1173. NPC_BSSearch();
  1174. break;
  1175. case BS_WANDER: //# 46: Wander down random waypoint paths
  1176. NPC_BSWander();
  1177. break;
  1178. case BS_FLEE:
  1179. NPC_BSFlee();
  1180. break;
  1181. default:
  1182. case BS_DEFAULT://whatever
  1183. NPC_BSDefault();
  1184. break;
  1185. }
  1186. }
  1187. /*
  1188. -------------------------
  1189. NPC_BehaviorSet_Default
  1190. -------------------------
  1191. */
  1192. void NPC_BehaviorSet_Default( int bState )
  1193. {
  1194. switch( bState )
  1195. {
  1196. case BS_ADVANCE_FIGHT://head toward captureGoal, shoot anything that gets in the way
  1197. NPC_BSAdvanceFight ();
  1198. break;
  1199. case BS_SLEEP://Follow a path, looking for enemies
  1200. NPC_BSSleep ();
  1201. break;
  1202. case BS_FOLLOW_LEADER://# 40: Follow your leader and shoot any enemies you come across
  1203. NPC_BSFollowLeader();
  1204. break;
  1205. case BS_JUMP: //41: Face navgoal and jump to it.
  1206. NPC_BSJump();
  1207. break;
  1208. case BS_REMOVE:
  1209. NPC_BSRemove();
  1210. break;
  1211. case BS_SEARCH: //# 43: Using current waypoint as a base, search the immediate branches of waypoints for enemies
  1212. NPC_BSSearch();
  1213. break;
  1214. case BS_NOCLIP:
  1215. NPC_BSNoClip();
  1216. break;
  1217. case BS_WANDER: //# 46: Wander down random waypoint paths
  1218. NPC_BSWander();
  1219. break;
  1220. case BS_FLEE:
  1221. NPC_BSFlee();
  1222. break;
  1223. case BS_WAIT:
  1224. NPC_BSWait();
  1225. break;
  1226. case BS_CINEMATIC:
  1227. NPC_BSCinematic();
  1228. break;
  1229. default:
  1230. case BS_DEFAULT://whatever
  1231. NPC_BSDefault();
  1232. break;
  1233. }
  1234. }
  1235. /*
  1236. -------------------------
  1237. NPC_BehaviorSet_Interrogator
  1238. -------------------------
  1239. */
  1240. void NPC_BehaviorSet_Interrogator( int bState )
  1241. {
  1242. switch( bState )
  1243. {
  1244. case BS_STAND_GUARD:
  1245. case BS_PATROL:
  1246. case BS_STAND_AND_SHOOT:
  1247. case BS_HUNT_AND_KILL:
  1248. case BS_DEFAULT:
  1249. NPC_BSInterrogator_Default();
  1250. break;
  1251. default:
  1252. NPC_BehaviorSet_Default( bState );
  1253. break;
  1254. }
  1255. }
  1256. void NPC_BSImperialProbe_Attack( void );
  1257. void NPC_BSImperialProbe_Patrol( void );
  1258. void NPC_BSImperialProbe_Wait(void);
  1259. /*
  1260. -------------------------
  1261. NPC_BehaviorSet_ImperialProbe
  1262. -------------------------
  1263. */
  1264. void NPC_BehaviorSet_ImperialProbe( int bState )
  1265. {
  1266. switch( bState )
  1267. {
  1268. case BS_STAND_GUARD:
  1269. case BS_PATROL:
  1270. case BS_STAND_AND_SHOOT:
  1271. case BS_HUNT_AND_KILL:
  1272. case BS_DEFAULT:
  1273. NPC_BSImperialProbe_Default();
  1274. break;
  1275. default:
  1276. NPC_BehaviorSet_Default( bState );
  1277. break;
  1278. }
  1279. }
  1280. void NPC_BSSeeker_Default( void );
  1281. /*
  1282. -------------------------
  1283. NPC_BehaviorSet_Seeker
  1284. -------------------------
  1285. */
  1286. void NPC_BehaviorSet_Seeker( int bState )
  1287. {
  1288. switch( bState )
  1289. {
  1290. case BS_STAND_GUARD:
  1291. case BS_PATROL:
  1292. case BS_STAND_AND_SHOOT:
  1293. case BS_HUNT_AND_KILL:
  1294. case BS_DEFAULT:
  1295. default:
  1296. NPC_BSSeeker_Default();
  1297. break;
  1298. }
  1299. }
  1300. void NPC_BSRemote_Default( void );
  1301. /*
  1302. -------------------------
  1303. NPC_BehaviorSet_Remote
  1304. -------------------------
  1305. */
  1306. void NPC_BehaviorSet_Remote( int bState )
  1307. {
  1308. switch( bState )
  1309. {
  1310. case BS_STAND_GUARD:
  1311. case BS_PATROL:
  1312. case BS_STAND_AND_SHOOT:
  1313. case BS_HUNT_AND_KILL:
  1314. case BS_DEFAULT:
  1315. NPC_BSRemote_Default();
  1316. break;
  1317. default:
  1318. NPC_BehaviorSet_Default( bState );
  1319. break;
  1320. }
  1321. }
  1322. void NPC_BSSentry_Default( void );
  1323. /*
  1324. -------------------------
  1325. NPC_BehaviorSet_Sentry
  1326. -------------------------
  1327. */
  1328. void NPC_BehaviorSet_Sentry( int bState )
  1329. {
  1330. switch( bState )
  1331. {
  1332. case BS_STAND_GUARD:
  1333. case BS_PATROL:
  1334. case BS_STAND_AND_SHOOT:
  1335. case BS_HUNT_AND_KILL:
  1336. case BS_DEFAULT:
  1337. NPC_BSSentry_Default();
  1338. break;
  1339. default:
  1340. NPC_BehaviorSet_Default( bState );
  1341. break;
  1342. }
  1343. }
  1344. /*
  1345. -------------------------
  1346. NPC_BehaviorSet_Grenadier
  1347. -------------------------
  1348. */
  1349. void NPC_BehaviorSet_Grenadier( int bState )
  1350. {
  1351. switch( bState )
  1352. {
  1353. case BS_STAND_GUARD:
  1354. case BS_PATROL:
  1355. case BS_STAND_AND_SHOOT:
  1356. case BS_HUNT_AND_KILL:
  1357. case BS_DEFAULT:
  1358. NPC_BSGrenadier_Default();
  1359. break;
  1360. default:
  1361. NPC_BehaviorSet_Default( bState );
  1362. break;
  1363. }
  1364. }
  1365. /*
  1366. -------------------------
  1367. NPC_BehaviorSet_Tusken
  1368. -------------------------
  1369. */
  1370. void NPC_BehaviorSet_Tusken( int bState )
  1371. {
  1372. switch( bState )
  1373. {
  1374. case BS_STAND_GUARD:
  1375. case BS_PATROL:
  1376. case BS_STAND_AND_SHOOT:
  1377. case BS_HUNT_AND_KILL:
  1378. case BS_DEFAULT:
  1379. NPC_BSTusken_Default();
  1380. break;
  1381. default:
  1382. NPC_BehaviorSet_Default( bState );
  1383. break;
  1384. }
  1385. }
  1386. /*
  1387. -------------------------
  1388. NPC_BehaviorSet_Sniper
  1389. -------------------------
  1390. */
  1391. void NPC_BehaviorSet_Sniper( int bState )
  1392. {
  1393. switch( bState )
  1394. {
  1395. case BS_STAND_GUARD:
  1396. case BS_PATROL:
  1397. case BS_STAND_AND_SHOOT:
  1398. case BS_HUNT_AND_KILL:
  1399. case BS_DEFAULT:
  1400. NPC_BSSniper_Default();
  1401. break;
  1402. default:
  1403. NPC_BehaviorSet_Default( bState );
  1404. break;
  1405. }
  1406. }
  1407. /*
  1408. -------------------------
  1409. NPC_BehaviorSet_Stormtrooper
  1410. -------------------------
  1411. */
  1412. void NPC_BehaviorSet_Stormtrooper( int bState )
  1413. {
  1414. switch( bState )
  1415. {
  1416. case BS_STAND_GUARD:
  1417. case BS_PATROL:
  1418. case BS_STAND_AND_SHOOT:
  1419. case BS_HUNT_AND_KILL:
  1420. case BS_DEFAULT:
  1421. NPC_BSST_Default();
  1422. break;
  1423. case BS_INVESTIGATE:
  1424. NPC_BSST_Investigate();
  1425. break;
  1426. case BS_SLEEP:
  1427. NPC_BSST_Sleep();
  1428. break;
  1429. default:
  1430. NPC_BehaviorSet_Default( bState );
  1431. break;
  1432. }
  1433. }
  1434. /*
  1435. -------------------------
  1436. NPC_BehaviorSet_Jedi
  1437. -------------------------
  1438. */
  1439. void NPC_BehaviorSet_Jedi( int bState )
  1440. {
  1441. switch( bState )
  1442. {
  1443. case BS_STAND_GUARD:
  1444. case BS_PATROL:
  1445. case BS_STAND_AND_SHOOT:
  1446. case BS_HUNT_AND_KILL:
  1447. case BS_INVESTIGATE://WTF???!!
  1448. case BS_DEFAULT:
  1449. NPC_BSJedi_Default();
  1450. break;
  1451. case BS_FOLLOW_LEADER:
  1452. NPC_BSJedi_FollowLeader();
  1453. break;
  1454. default:
  1455. NPC_BehaviorSet_Default( bState );
  1456. break;
  1457. }
  1458. }
  1459. qboolean G_JediInNormalAI( gentity_t *ent )
  1460. {//NOTE: should match above func's switch!
  1461. //check our bState
  1462. bState_t bState = G_CurrentBState( ent->NPC );
  1463. switch ( bState )
  1464. {
  1465. case BS_STAND_GUARD:
  1466. case BS_PATROL:
  1467. case BS_STAND_AND_SHOOT:
  1468. case BS_HUNT_AND_KILL:
  1469. case BS_INVESTIGATE:
  1470. case BS_DEFAULT:
  1471. case BS_FOLLOW_LEADER:
  1472. return qtrue;
  1473. break;
  1474. }
  1475. return qfalse;
  1476. }
  1477. /*
  1478. -------------------------
  1479. NPC_BehaviorSet_Droid
  1480. -------------------------
  1481. */
  1482. void NPC_BehaviorSet_Droid( int bState )
  1483. {
  1484. switch( bState )
  1485. {
  1486. case BS_DEFAULT:
  1487. case BS_STAND_GUARD:
  1488. case BS_PATROL:
  1489. NPC_BSDroid_Default();
  1490. break;
  1491. default:
  1492. NPC_BehaviorSet_Default( bState );
  1493. break;
  1494. }
  1495. }
  1496. /*
  1497. -------------------------
  1498. NPC_BehaviorSet_Mark1
  1499. -------------------------
  1500. */
  1501. void NPC_BehaviorSet_Mark1( int bState )
  1502. {
  1503. switch( bState )
  1504. {
  1505. case BS_DEFAULT:
  1506. case BS_STAND_GUARD:
  1507. case BS_PATROL:
  1508. NPC_BSMark1_Default();
  1509. break;
  1510. default:
  1511. NPC_BehaviorSet_Default( bState );
  1512. break;
  1513. }
  1514. }
  1515. /*
  1516. -------------------------
  1517. NPC_BehaviorSet_Mark2
  1518. -------------------------
  1519. */
  1520. void NPC_BehaviorSet_Mark2( int bState )
  1521. {
  1522. switch( bState )
  1523. {
  1524. case BS_DEFAULT:
  1525. case BS_PATROL:
  1526. case BS_STAND_AND_SHOOT:
  1527. case BS_HUNT_AND_KILL:
  1528. NPC_BSMark2_Default();
  1529. break;
  1530. default:
  1531. NPC_BehaviorSet_Default( bState );
  1532. break;
  1533. }
  1534. }
  1535. /*
  1536. -------------------------
  1537. NPC_BehaviorSet_ATST
  1538. -------------------------
  1539. */
  1540. void NPC_BehaviorSet_ATST( int bState )
  1541. {
  1542. switch( bState )
  1543. {
  1544. case BS_DEFAULT:
  1545. case BS_PATROL:
  1546. case BS_STAND_AND_SHOOT:
  1547. case BS_HUNT_AND_KILL:
  1548. NPC_BSATST_Default();
  1549. break;
  1550. default:
  1551. NPC_BehaviorSet_Default( bState );
  1552. break;
  1553. }
  1554. }
  1555. /*
  1556. -------------------------
  1557. NPC_BehaviorSet_MineMonster
  1558. -------------------------
  1559. */
  1560. void NPC_BehaviorSet_MineMonster( int bState )
  1561. {
  1562. switch( bState )
  1563. {
  1564. case BS_STAND_GUARD:
  1565. case BS_PATROL:
  1566. case BS_STAND_AND_SHOOT:
  1567. case BS_HUNT_AND_KILL:
  1568. case BS_DEFAULT:
  1569. NPC_BSMineMonster_Default();
  1570. break;
  1571. default:
  1572. NPC_BehaviorSet_Default( bState );
  1573. break;
  1574. }
  1575. }
  1576. /*
  1577. -------------------------
  1578. NPC_BehaviorSet_Howler
  1579. -------------------------
  1580. */
  1581. void NPC_BehaviorSet_Howler( int bState )
  1582. {
  1583. switch( bState )
  1584. {
  1585. case BS_STAND_GUARD:
  1586. case BS_PATROL:
  1587. case BS_STAND_AND_SHOOT:
  1588. case BS_HUNT_AND_KILL:
  1589. case BS_DEFAULT:
  1590. NPC_BSHowler_Default();
  1591. break;
  1592. default:
  1593. NPC_BehaviorSet_Default( bState );
  1594. break;
  1595. }
  1596. }
  1597. /*
  1598. -------------------------
  1599. NPC_BehaviorSet_Rancor
  1600. -------------------------
  1601. */
  1602. void NPC_BehaviorSet_Rancor( int bState )
  1603. {
  1604. switch( bState )
  1605. {
  1606. case BS_STAND_GUARD:
  1607. case BS_PATROL:
  1608. case BS_STAND_AND_SHOOT:
  1609. case BS_HUNT_AND_KILL:
  1610. case BS_DEFAULT:
  1611. NPC_BSRancor_Default();
  1612. break;
  1613. default:
  1614. NPC_BehaviorSet_Default( bState );
  1615. break;
  1616. }
  1617. }
  1618. /*
  1619. -------------------------
  1620. NPC_BehaviorSet_Wampa
  1621. -------------------------
  1622. */
  1623. void NPC_BehaviorSet_Wampa( int bState )
  1624. {
  1625. switch( bState )
  1626. {
  1627. case BS_STAND_GUARD:
  1628. case BS_PATROL:
  1629. case BS_STAND_AND_SHOOT:
  1630. case BS_HUNT_AND_KILL:
  1631. case BS_DEFAULT:
  1632. NPC_BSWampa_Default();
  1633. break;
  1634. default:
  1635. NPC_BehaviorSet_Default( bState );
  1636. break;
  1637. }
  1638. }
  1639. /*
  1640. -------------------------
  1641. NPC_BehaviorSet_SandCreature
  1642. -------------------------
  1643. */
  1644. void NPC_BehaviorSet_SandCreature( int bState )
  1645. {
  1646. switch( bState )
  1647. {
  1648. case BS_STAND_GUARD:
  1649. case BS_PATROL:
  1650. case BS_STAND_AND_SHOOT:
  1651. case BS_HUNT_AND_KILL:
  1652. case BS_DEFAULT:
  1653. NPC_BSSandCreature_Default();
  1654. break;
  1655. default:
  1656. NPC_BehaviorSet_Default( bState );
  1657. break;
  1658. }
  1659. }
  1660. /*
  1661. -------------------------
  1662. NPC_BehaviorSet_Droid
  1663. -------------------------
  1664. */
  1665. // Added 01/21/03 by AReis.
  1666. void NPC_BehaviorSet_Animal( int bState )
  1667. {
  1668. switch( bState )
  1669. {
  1670. case BS_DEFAULT:
  1671. case BS_STAND_GUARD:
  1672. case BS_PATROL:
  1673. NPC_BSAnimal_Default();
  1674. //NPC_BSDroid_Default();
  1675. break;
  1676. default:
  1677. NPC_BehaviorSet_Default( bState );
  1678. break;
  1679. }
  1680. }
  1681. /*
  1682. -------------------------
  1683. NPC_RunBehavior
  1684. -------------------------
  1685. */
  1686. extern void NPC_BSEmplaced( void );
  1687. extern qboolean NPC_CheckSurrender( void );
  1688. extern void NPC_BSRT_Default( void );
  1689. extern void NPC_BSCivilian_Default( int bState );
  1690. extern void NPC_BSSD_Default( void );
  1691. extern void NPC_BehaviorSet_Trooper( int bState );
  1692. extern bool NPC_IsTrooper( gentity_t *ent );
  1693. extern bool Pilot_MasterUpdate();
  1694. void NPC_RunBehavior( int team, int bState )
  1695. {
  1696. qboolean dontSetAim = qfalse;
  1697. //
  1698. if ( bState == BS_CINEMATIC )
  1699. {
  1700. NPC_BSCinematic();
  1701. }
  1702. else if ( (NPCInfo->scriptFlags&SCF_PILOT) && Pilot_MasterUpdate())
  1703. {
  1704. return;
  1705. }
  1706. else if ( NPC_JumpBackingUp() )
  1707. {
  1708. return;
  1709. }
  1710. else if ( !TIMER_Done(NPC, "DEMP2_StunTime"))
  1711. {
  1712. NPC_UpdateAngles(qtrue, qtrue);
  1713. return;
  1714. }
  1715. else if ( NPC->client->ps.weapon == WP_EMPLACED_GUN )
  1716. {
  1717. NPC_BSEmplaced();
  1718. G_CheckCharmed( NPC );
  1719. return;
  1720. }
  1721. else if ( NPC->client->NPC_class == CLASS_HOWLER )
  1722. {
  1723. NPC_BehaviorSet_Howler( bState );
  1724. return;
  1725. }
  1726. else if ( Jedi_CultistDestroyer( NPC ) )
  1727. {
  1728. NPC_BSJedi_Default();
  1729. dontSetAim = qtrue;
  1730. }
  1731. else if ( NPC->client->NPC_class == CLASS_SABER_DROID )
  1732. {//saber droid
  1733. NPC_BSSD_Default();
  1734. }
  1735. else if ( NPC->client->ps.weapon == WP_SABER )
  1736. {//jedi
  1737. NPC_BehaviorSet_Jedi( bState );
  1738. dontSetAim = qtrue;
  1739. }
  1740. else if ( NPC->client->NPC_class == CLASS_REBORN && NPC->client->ps.weapon == WP_MELEE )
  1741. {//force-only reborn
  1742. NPC_BehaviorSet_Jedi( bState );
  1743. dontSetAim = qtrue;
  1744. }
  1745. else if ( NPC->client->NPC_class == CLASS_BOBAFETT )
  1746. {
  1747. Boba_Update();
  1748. if (NPCInfo->surrenderTime)
  1749. {
  1750. Boba_Flee();
  1751. }
  1752. else
  1753. {
  1754. if (!Boba_Tactics())
  1755. {
  1756. if ( Boba_Flying( NPC ) )
  1757. {
  1758. NPC_BehaviorSet_Seeker(bState);
  1759. }
  1760. else
  1761. {
  1762. NPC_BehaviorSet_Jedi( bState );
  1763. }
  1764. }
  1765. }
  1766. dontSetAim = qtrue;
  1767. }
  1768. else if ( NPC->client->NPC_class == CLASS_ROCKETTROOPER )
  1769. {//bounty hunter
  1770. if ( RT_Flying( NPC ) || NPC->enemy != NULL )
  1771. {
  1772. NPC_BSRT_Default();
  1773. }
  1774. else
  1775. {
  1776. NPC_BehaviorSet_Stormtrooper( bState );
  1777. }
  1778. G_CheckCharmed( NPC );
  1779. dontSetAim = qtrue;
  1780. }
  1781. else if ( NPC->client->NPC_class == CLASS_RANCOR )
  1782. {
  1783. NPC_BehaviorSet_Rancor( bState );
  1784. }
  1785. else if ( NPC->client->NPC_class == CLASS_SAND_CREATURE )
  1786. {
  1787. NPC_BehaviorSet_SandCreature( bState );
  1788. }
  1789. else if ( NPC->client->NPC_class == CLASS_WAMPA )
  1790. {
  1791. NPC_BehaviorSet_Wampa( bState );
  1792. G_CheckCharmed( NPC );
  1793. }
  1794. else if ( NPCInfo->scriptFlags & SCF_FORCED_MARCH )
  1795. {//being forced to march
  1796. NPC_BSDefault();
  1797. }
  1798. else if ( NPC->client->ps.weapon == WP_TUSKEN_RIFLE )
  1799. {
  1800. if ( (NPCInfo->scriptFlags & SCF_ALT_FIRE) )
  1801. {
  1802. NPC_BehaviorSet_Sniper( bState );
  1803. G_CheckCharmed( NPC );
  1804. return;
  1805. }
  1806. else
  1807. {
  1808. NPC_BehaviorSet_Tusken( bState );
  1809. G_CheckCharmed( NPC );
  1810. return;
  1811. }
  1812. }
  1813. else if ( NPC->client->ps.weapon == WP_TUSKEN_STAFF )
  1814. {
  1815. NPC_BehaviorSet_Tusken( bState );
  1816. G_CheckCharmed( NPC );
  1817. return;
  1818. }
  1819. else if ( NPC->client->ps.weapon == WP_NOGHRI_STICK )
  1820. {
  1821. NPC_BehaviorSet_Stormtrooper( bState );
  1822. G_CheckCharmed( NPC );
  1823. }
  1824. else
  1825. {
  1826. switch( team )
  1827. {
  1828. // case TEAM_SCAVENGERS:
  1829. // case TEAM_IMPERIAL:
  1830. // case TEAM_KLINGON:
  1831. // case TEAM_HIROGEN:
  1832. // case TEAM_MALON:
  1833. // not sure if TEAM_ENEMY is appropriate here, I think I should be using NPC_class to check for behavior - dmv
  1834. case TEAM_ENEMY:
  1835. // special cases for enemy droids
  1836. switch( NPC->client->NPC_class)
  1837. {
  1838. case CLASS_ATST:
  1839. NPC_BehaviorSet_ATST( bState );
  1840. return;
  1841. case CLASS_PROBE:
  1842. NPC_BehaviorSet_ImperialProbe(bState);
  1843. return;
  1844. case CLASS_REMOTE:
  1845. NPC_BehaviorSet_Remote( bState );
  1846. return;
  1847. case CLASS_SENTRY:
  1848. NPC_BehaviorSet_Sentry(bState);
  1849. return;
  1850. case CLASS_INTERROGATOR:
  1851. NPC_BehaviorSet_Interrogator( bState );
  1852. return;
  1853. case CLASS_MINEMONSTER:
  1854. NPC_BehaviorSet_MineMonster( bState );
  1855. return;
  1856. case CLASS_HOWLER:
  1857. NPC_BehaviorSet_Howler( bState );
  1858. return;
  1859. case CLASS_RANCOR:
  1860. NPC_BehaviorSet_Rancor( bState );
  1861. return;
  1862. case CLASS_SAND_CREATURE:
  1863. NPC_BehaviorSet_SandCreature( bState );
  1864. return;
  1865. case CLASS_MARK1:
  1866. NPC_BehaviorSet_Mark1( bState );
  1867. return;
  1868. case CLASS_MARK2:
  1869. NPC_BehaviorSet_Mark2( bState );
  1870. return;
  1871. }
  1872. if (NPC->client->NPC_class==CLASS_ASSASSIN_DROID)
  1873. {
  1874. BubbleShield_Update();
  1875. }
  1876. if (NPC_IsTrooper(NPC))
  1877. {
  1878. NPC_BehaviorSet_Trooper( bState);
  1879. return;
  1880. }
  1881. if ( NPC->enemy && NPC->client->ps.weapon == WP_NONE && bState != BS_HUNT_AND_KILL && !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) )
  1882. {//if in battle and have no weapon, run away, fixme: when in BS_HUNT_AND_KILL, they just stand there
  1883. if ( bState != BS_FLEE )
  1884. {
  1885. NPC_StartFlee( NPC->enemy, NPC->enemy->currentOrigin, AEL_DANGER_GREAT, 5000, 10000 );
  1886. }
  1887. else
  1888. {
  1889. NPC_BSFlee();
  1890. }
  1891. return;
  1892. }
  1893. if ( NPC->client->ps.weapon == WP_SABER )
  1894. {//special melee exception
  1895. NPC_BehaviorSet_Default( bState );
  1896. return;
  1897. }
  1898. if ( NPC->client->ps.weapon == WP_DISRUPTOR && (NPCInfo->scriptFlags & SCF_ALT_FIRE) )
  1899. {//a sniper
  1900. NPC_BehaviorSet_Sniper( bState );
  1901. return;
  1902. }
  1903. if ( NPC->client->ps.weapon == WP_THERMAL
  1904. || NPC->client->ps.weapon == WP_MELEE )//FIXME: separate AI for melee fighters
  1905. {//a grenadier
  1906. NPC_BehaviorSet_Grenadier( bState );
  1907. return;
  1908. }
  1909. if ( NPC_CheckSurrender() )
  1910. {
  1911. return;
  1912. }
  1913. NPC_BehaviorSet_Stormtrooper( bState );
  1914. break;
  1915. case TEAM_NEUTRAL:
  1916. // special cases for enemy droids
  1917. if ( NPC->client->NPC_class == CLASS_PROTOCOL )
  1918. {
  1919. NPC_BehaviorSet_Default(bState);
  1920. }
  1921. else if ( NPC->client->NPC_class == CLASS_UGNAUGHT
  1922. || NPC->client->NPC_class == CLASS_JAWA )
  1923. {//others, too?
  1924. NPC_BSCivilian_Default( bState );
  1925. return;
  1926. }
  1927. // Add special vehicle behavior here.
  1928. else if ( NPC->client->NPC_class == CLASS_VEHICLE )
  1929. {
  1930. Vehicle_t *pVehicle = NPC->m_pVehicle;
  1931. if ( !pVehicle->m_pPilot && pVehicle->m_iBoarding==0 )
  1932. {
  1933. if (pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
  1934. {
  1935. NPC_BehaviorSet_Animal( bState );
  1936. }
  1937. // TODO: The only other case were we want a vehicle to do something specifically is
  1938. // perhaps in multiplayer where we want the shuttle to be able to lift off when not
  1939. // occupied and in a landing zone.
  1940. }
  1941. }
  1942. else
  1943. {
  1944. // Just one of the average droids
  1945. NPC_BehaviorSet_Droid( bState );
  1946. }
  1947. break;
  1948. default:
  1949. if ( NPC->client->NPC_class == CLASS_SEEKER )
  1950. {
  1951. NPC_BehaviorSet_Seeker(bState);
  1952. }
  1953. else
  1954. {
  1955. if ( NPCInfo->charmedTime > level.time )
  1956. {
  1957. NPC_BehaviorSet_Charmed( bState );
  1958. }
  1959. else
  1960. {
  1961. NPC_BehaviorSet_Default( bState );
  1962. }
  1963. G_CheckCharmed( NPC );
  1964. dontSetAim = qtrue;
  1965. }
  1966. break;
  1967. }
  1968. }
  1969. }
  1970. static bState_t G_CurrentBState( gNPC_t *gNPC )
  1971. {
  1972. if ( gNPC->tempBehavior != BS_DEFAULT )
  1973. {//Overrides normal behavior until cleared
  1974. return (gNPC->tempBehavior);
  1975. }
  1976. if( gNPC->behaviorState == BS_DEFAULT )
  1977. {
  1978. gNPC->behaviorState = gNPC->defaultBehavior;
  1979. }
  1980. return (gNPC->behaviorState);
  1981. }
  1982. /*
  1983. ===============
  1984. NPC_ExecuteBState
  1985. MCG
  1986. NPC Behavior state thinking
  1987. ===============
  1988. */
  1989. void NPC_ExecuteBState ( gentity_t *self)//, int msec )
  1990. {
  1991. bState_t bState;
  1992. NPC_HandleAIFlags();
  1993. //FIXME: these next three bits could be a function call, some sort of setup/cleanup func
  1994. //Lookmode must be reset every think cycle
  1995. if(NPC->delayScriptTime && NPC->delayScriptTime <= level.time)
  1996. {
  1997. G_ActivateBehavior( NPC, BSET_DELAYED);
  1998. NPC->delayScriptTime = 0;
  1999. }
  2000. //Clear this and let bState set it itself, so it automatically handles changing bStates... but we need a set bState wrapper func
  2001. NPCInfo->combatMove = qfalse;
  2002. //Execute our bState
  2003. bState = G_CurrentBState( NPCInfo );
  2004. //Pick the proper bstate for us and run it
  2005. NPC_RunBehavior( self->client->playerTeam, bState );
  2006. // if(bState != BS_POINT_COMBAT && NPCInfo->combatPoint != -1)
  2007. // {
  2008. //level.combatPoints[NPCInfo->combatPoint].occupied = qfalse;
  2009. //NPCInfo->combatPoint = -1;
  2010. // }
  2011. //Here we need to see what the scripted stuff told us to do
  2012. //Only process snapshot if independant and in combat mode- this would pick enemies and go after needed items
  2013. // ProcessSnapshot();
  2014. //Ignore my needs if I'm under script control- this would set needs for items
  2015. // CheckSelf();
  2016. //Back to normal? All decisions made?
  2017. //FIXME: don't walk off ledges unless we can get to our goal faster that way, or that's our goal's surface
  2018. //NPCPredict();
  2019. if ( NPC->enemy )
  2020. {
  2021. if ( !NPC->enemy->inuse )
  2022. {//just in case bState doesn't catch this
  2023. G_ClearEnemy( NPC );
  2024. }
  2025. }
  2026. if ( NPC->client->ps.saberLockTime && NPC->client->ps.saberLockEnemy != ENTITYNUM_NONE )
  2027. {
  2028. NPC_SetLookTarget( NPC, NPC->client->ps.saberLockEnemy, level.time+1000 );
  2029. }
  2030. else if ( !NPC_CheckLookTarget( NPC ) )
  2031. {
  2032. if ( NPC->enemy )
  2033. {
  2034. NPC_SetLookTarget( NPC, NPC->enemy->s.number, 0 );
  2035. }
  2036. }
  2037. if ( NPC->enemy )
  2038. {
  2039. if(NPC->enemy->flags & FL_DONT_SHOOT)
  2040. {
  2041. ucmd.buttons &= ~BUTTON_ATTACK;
  2042. ucmd.buttons &= ~BUTTON_ALT_ATTACK;
  2043. }
  2044. else if ( NPC->client->playerTeam != TEAM_ENEMY //not an enemy
  2045. && (NPC->client->playerTeam != TEAM_FREE || (NPC->client->NPC_class == CLASS_TUSKEN && Q_irand( 0, 4 )))//not a rampaging creature or I'm a tusken and I feel generous (temporarily)
  2046. && NPC->enemy->NPC
  2047. && (NPC->enemy->NPC->surrenderTime > level.time || (NPC->enemy->NPC->scriptFlags&SCF_FORCED_MARCH)) )
  2048. {//don't shoot someone who's surrendering if you're a good guy
  2049. ucmd.buttons &= ~BUTTON_ATTACK;
  2050. ucmd.buttons &= ~BUTTON_ALT_ATTACK;
  2051. }
  2052. if(client->ps.weaponstate == WEAPON_IDLE)
  2053. {
  2054. client->ps.weaponstate = WEAPON_READY;
  2055. }
  2056. }
  2057. else
  2058. {
  2059. if(client->ps.weaponstate == WEAPON_READY)
  2060. {
  2061. client->ps.weaponstate = WEAPON_IDLE;
  2062. }
  2063. }
  2064. if(!(ucmd.buttons & BUTTON_ATTACK) && NPC->attackDebounceTime > level.time)
  2065. {//We just shot but aren't still shooting, so hold the gun up for a while
  2066. if(client->ps.weapon == WP_SABER )
  2067. {//One-handed
  2068. NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONREADY1,SETANIM_FLAG_NORMAL);
  2069. }
  2070. else if(client->ps.weapon == WP_BRYAR_PISTOL)
  2071. {//Sniper pose
  2072. NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONREADY3,SETANIM_FLAG_NORMAL);
  2073. }
  2074. /*//FIXME: What's the proper solution here?
  2075. else
  2076. {//heavy weapon
  2077. NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONREADY3,SETANIM_FLAG_NORMAL);
  2078. }
  2079. */
  2080. }
  2081. NPC_CheckAttackHold();
  2082. NPC_ApplyScriptFlags();
  2083. //cliff and wall avoidance
  2084. NPC_AvoidWallsAndCliffs();
  2085. // run the bot through the server like it was a real client
  2086. //=== Save the ucmd for the second no-think Pmove ============================
  2087. ucmd.serverTime = level.time - 50;
  2088. memcpy( &NPCInfo->last_ucmd, &ucmd, sizeof( usercmd_t ) );
  2089. if ( !NPCInfo->attackHoldTime )
  2090. {
  2091. NPCInfo->last_ucmd.buttons &= ~(BUTTON_ATTACK|BUTTON_ALT_ATTACK|BUTTON_FORCE_FOCUS);//so we don't fire twice in one think
  2092. }
  2093. //============================================================================
  2094. NPC_CheckAttackScript();
  2095. NPC_KeepCurrentFacing();
  2096. if ( !NPC->next_roff_time || NPC->next_roff_time < level.time )
  2097. {//If we were following a roff, we don't do normal pmoves.
  2098. ClientThink( NPC->s.number, &ucmd );
  2099. }
  2100. else
  2101. {
  2102. NPC_ApplyRoff();
  2103. }
  2104. // end of thinking cleanup
  2105. NPCInfo->touchedByPlayer = NULL;
  2106. NPC_CheckPlayerAim();
  2107. NPC_CheckAllClear();
  2108. /*if( ucmd.forwardmove || ucmd.rightmove )
  2109. {
  2110. int i, la = -1, ta = -1;
  2111. for(i = 0; i < MAX_ANIMATIONS; i++)
  2112. {
  2113. if( NPC->client->ps.legsAnim == i )
  2114. {
  2115. la = i;
  2116. }
  2117. if( NPC->client->ps.torsoAnim == i )
  2118. {
  2119. ta = i;
  2120. }
  2121. if(la != -1 && ta != -1)
  2122. {
  2123. break;
  2124. }
  2125. }
  2126. if(la != -1 && ta != -1)
  2127. {//FIXME: should never play same frame twice or restart an anim before finishing it
  2128. gi.Printf("LegsAnim: %s(%d) TorsoAnim: %s(%d)\n", animTable[la].name, NPC->renderInfo.legsFrame, animTable[ta].name, NPC->client->renderInfo.torsoFrame);
  2129. }
  2130. }*/
  2131. }
  2132. void NPC_CheckInSolid(void)
  2133. {
  2134. trace_t trace;
  2135. vec3_t point;
  2136. VectorCopy(NPC->currentOrigin, point);
  2137. point[2] -= 0.25;
  2138. gi.trace(&trace, NPC->currentOrigin, NPC->mins, NPC->maxs, point, NPC->s.number, NPC->clipmask);
  2139. if(!trace.startsolid && !trace.allsolid)
  2140. {
  2141. VectorCopy(NPC->currentOrigin, NPCInfo->lastClearOrigin);
  2142. }
  2143. else
  2144. {
  2145. if(VectorLengthSquared(NPCInfo->lastClearOrigin))
  2146. {
  2147. // gi.Printf("%s stuck in solid at %s: fixing...\n", NPC->script_targetname, vtos(NPC->currentOrigin));
  2148. G_SetOrigin(NPC, NPCInfo->lastClearOrigin);
  2149. gi.linkentity(NPC);
  2150. }
  2151. }
  2152. }
  2153. /*
  2154. ===============
  2155. NPC_Think
  2156. Main NPC AI - called once per frame
  2157. ===============
  2158. */
  2159. #if AI_TIMERS
  2160. extern int AITime;
  2161. #endif// AI_TIMERS
  2162. void NPC_Think ( gentity_t *self)//, int msec )
  2163. {
  2164. vec3_t oldMoveDir;
  2165. self->nextthink = level.time + FRAMETIME/2;
  2166. SetNPCGlobals( self );
  2167. memset( &ucmd, 0, sizeof( ucmd ) );
  2168. VectorCopy( self->client->ps.moveDir, oldMoveDir );
  2169. VectorClear( self->client->ps.moveDir );
  2170. // see if NPC ai is frozen
  2171. if ( debugNPCFreeze->integer || (NPC->svFlags&SVF_ICARUS_FREEZE) )
  2172. {
  2173. NPC_UpdateAngles( qtrue, qtrue );
  2174. ClientThink(self->s.number, &ucmd);
  2175. VectorCopy(self->s.origin, self->s.origin2 );
  2176. return;
  2177. }
  2178. if(!self || !self->NPC || !self->client)
  2179. {
  2180. return;
  2181. }
  2182. // dead NPCs have a special think, don't run scripts (for now)
  2183. //FIXME: this breaks deathscripts
  2184. if ( self->health <= 0 )
  2185. {
  2186. DeadThink();
  2187. if ( NPCInfo->nextBStateThink <= level.time )
  2188. {
  2189. if( self->m_iIcarusID != IIcarusInterface::ICARUS_INVALID && !stop_icarus )
  2190. {
  2191. IIcarusInterface::GetIcarus()->Update( self->m_iIcarusID );
  2192. }
  2193. }
  2194. return;
  2195. }
  2196. // TODO! Tauntaun's (and other creature vehicles?) think, we'll need to make an exception here to allow that.
  2197. if ( self->client
  2198. && self->client->NPC_class == CLASS_VEHICLE
  2199. && self->NPC_type
  2200. && ( !self->m_pVehicle->m_pVehicleInfo->Inhabited( self->m_pVehicle ) ) )
  2201. {//empty swoop logic
  2202. if ( self->owner )
  2203. {//still have attached owner, check and see if can forget him (so he can use me later)
  2204. vec3_t dir2owner;
  2205. VectorSubtract( self->owner->currentOrigin, self->currentOrigin, dir2owner );
  2206. gentity_t *oldOwner = self->owner;
  2207. self->owner = NULL;//clear here for that SpotWouldTelefrag check...?
  2208. if ( VectorLengthSquared( dir2owner ) > 128*128
  2209. || !(self->clipmask&oldOwner->clipmask)
  2210. || (DotProduct( self->client->ps.velocity, oldOwner->client->ps.velocity ) < -200.0f &&!G_BoundsOverlap( self->absmin, self->absmin, oldOwner->absmin, oldOwner->absmax )) )
  2211. {//all clear, become solid to our owner now
  2212. gi.linkentity( self );
  2213. }
  2214. else
  2215. {//blocked, retain owner
  2216. self->owner = oldOwner;
  2217. }
  2218. }
  2219. }
  2220. if ( player->client->ps.viewEntity == self->s.number )
  2221. {//being controlled by player
  2222. if ( self->client )
  2223. {//make the noises
  2224. if ( TIMER_Done( self, "patrolNoise" ) && !Q_irand( 0, 20 ) )
  2225. {
  2226. switch( self->client->NPC_class )
  2227. {
  2228. case CLASS_R2D2: // droid
  2229. G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/r2d2/misc/r2d2talk0%d.wav",Q_irand(1, 3)) );
  2230. break;
  2231. case CLASS_R5D2: // droid
  2232. G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/r5d2/misc/r5talk%d.wav",Q_irand(1, 4)) );
  2233. break;
  2234. case CLASS_PROBE: // droid
  2235. G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/probe/misc/probetalk%d.wav",Q_irand(1, 3)) );
  2236. break;
  2237. case CLASS_MOUSE: // droid
  2238. G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/mouse/misc/mousego%d.wav",Q_irand(1, 3)) );
  2239. break;
  2240. case CLASS_GONK: // droid
  2241. G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/gonk/misc/gonktalk%d.wav",Q_irand(1, 2)) );
  2242. break;
  2243. }
  2244. TIMER_Set( self, "patrolNoise", Q_irand( 2000, 4000 ) );
  2245. }
  2246. }
  2247. //FIXME: might want to at least make sounds or something?
  2248. //NPC_UpdateAngles(qtrue, qtrue);
  2249. //Which ucmd should we send? Does it matter, since it gets overridden anyway?
  2250. NPCInfo->last_ucmd.serverTime = level.time - 50;
  2251. ClientThink( NPC->s.number, &ucmd );
  2252. VectorCopy(self->s.origin, self->s.origin2 );
  2253. return;
  2254. }
  2255. if ( NPCInfo->nextBStateThink <= level.time )
  2256. {
  2257. #if AI_TIMERS
  2258. int startTime = GetTime(0);
  2259. #endif// AI_TIMERS
  2260. if ( NPC->s.eType != ET_PLAYER )
  2261. {//Something drastic happened in our script
  2262. return;
  2263. }
  2264. if ( NPC->s.weapon == WP_SABER && g_spskill->integer >= 2 && NPCInfo->rank > RANK_LT_JG )
  2265. {//Jedi think faster on hard difficulty, except low-rank (reborn)
  2266. NPCInfo->nextBStateThink = level.time + FRAMETIME/2;
  2267. }
  2268. else
  2269. {//Maybe even 200 ms?
  2270. NPCInfo->nextBStateThink = level.time + FRAMETIME;
  2271. }
  2272. //nextthink is set before this so something in here can override it
  2273. NPC_ExecuteBState( self );
  2274. #if AI_TIMERS
  2275. int addTime = GetTime( startTime );
  2276. if ( addTime > 50 )
  2277. {
  2278. gi.Printf( S_COLOR_RED"ERROR: NPC number %d, %s %s at %s, weaponnum: %d, using %d of AI time!!!\n", NPC->s.number, NPC->NPC_type, NPC->targetname, vtos(NPC->currentOrigin), NPC->s.weapon, addTime );
  2279. }
  2280. AITime += addTime;
  2281. #endif// AI_TIMERS
  2282. }
  2283. else
  2284. {
  2285. if ( NPC->client
  2286. && NPC->client->NPC_class == CLASS_ROCKETTROOPER
  2287. && (NPC->client->ps.eFlags&EF_FORCE_GRIPPED)
  2288. && NPC->client->moveType == MT_FLYSWIM
  2289. && NPC->client->ps.groundEntityNum == ENTITYNUM_NONE )
  2290. {//reduce velocity
  2291. VectorScale( NPC->client->ps.velocity, 0.75f, NPC->client->ps.velocity );
  2292. }
  2293. VectorCopy( oldMoveDir, self->client->ps.moveDir );
  2294. //or use client->pers.lastCommand?
  2295. NPCInfo->last_ucmd.serverTime = level.time - 50;
  2296. if ( !NPC->next_roff_time || NPC->next_roff_time < level.time )
  2297. {//If we were following a roff, we don't do normal pmoves.
  2298. //FIXME: firing angles (no aim offset) or regular angles?
  2299. NPC_UpdateAngles(qtrue, qtrue);
  2300. memcpy( &ucmd, &NPCInfo->last_ucmd, sizeof( usercmd_t ) );
  2301. ClientThink(NPC->s.number, &ucmd);
  2302. }
  2303. else
  2304. {
  2305. NPC_ApplyRoff();
  2306. }
  2307. VectorCopy(self->s.origin, self->s.origin2 );
  2308. }
  2309. //must update icarus *every* frame because of certain animation completions in the pmove stuff that can leave a 50ms gap between ICARUS animation commands
  2310. if( self->m_iIcarusID != IIcarusInterface::ICARUS_INVALID && !stop_icarus )
  2311. {
  2312. IIcarusInterface::GetIcarus()->Update( self->m_iIcarusID );
  2313. }
  2314. }
  2315. void NPC_InitAI ( void )
  2316. {
  2317. debugNPCAI = gi.cvar ( "d_npcai", "0", CVAR_CHEAT );
  2318. debugNPCFreeze = gi.cvar ( "d_npcfreeze", "0", CVAR_CHEAT);
  2319. d_JediAI = gi.cvar ( "d_JediAI", "0", CVAR_CHEAT );
  2320. d_noGroupAI = gi.cvar ( "d_noGroupAI", "0", CVAR_CHEAT );
  2321. d_asynchronousGroupAI = gi.cvar ( "d_asynchronousGroupAI", "1", CVAR_CHEAT );
  2322. //0 = never (BORING)
  2323. //1 = kyle only
  2324. //2 = kyle and last enemy jedi
  2325. //3 = kyle and any enemy jedi
  2326. //4 = kyle and last enemy in a group, special kicks
  2327. //5 = kyle and any enemy
  2328. //6 = also when kyle takes pain or enemy jedi dodges player saber swing or does an acrobatic evasion
  2329. // NOTE : I also create this in UI_Init()
  2330. d_slowmodeath = gi.cvar ( "d_slowmodeath", "3", CVAR_ARCHIVE );//save this setting
  2331. d_saberCombat = gi.cvar ( "d_saberCombat", "0", CVAR_CHEAT );
  2332. }
  2333. /*
  2334. ==================================
  2335. void NPC_InitAnimTable( void )
  2336. Need to initialize this table.
  2337. If someone tried to play an anim
  2338. before table is filled in with
  2339. values, causes tasks that wait for
  2340. anim completion to never finish.
  2341. (frameLerp of 0 * numFrames of 0 = 0)
  2342. ==================================
  2343. */
  2344. void NPC_InitAnimTable( void )
  2345. {
  2346. for ( int i = 0; i < MAX_ANIM_FILES; i++ )
  2347. {
  2348. for ( int j = 0; j < MAX_ANIMATIONS; j++ )
  2349. {
  2350. level.knownAnimFileSets[i].animations[j].firstFrame = 0;
  2351. level.knownAnimFileSets[i].animations[j].frameLerp = 100;
  2352. // level.knownAnimFileSets[i].animations[j].initialLerp = 100;
  2353. level.knownAnimFileSets[i].animations[j].numFrames = 0;
  2354. }
  2355. }
  2356. }
  2357. extern int G_ParseAnimFileSet( const char *skeletonName, const char *modelName=0);
  2358. void NPC_InitGame( void )
  2359. {
  2360. // globals.NPCs = (gNPC_t *) gi.TagMalloc(game.maxclients * sizeof(game.bots[0]), TAG_GAME);
  2361. debugNPCName = gi.cvar ( "d_npc", "", 0 );
  2362. NPC_LoadParms();
  2363. NPC_InitAI();
  2364. NPC_InitAnimTable();
  2365. G_ParseAnimFileSet("_humanoid"); //GET THIS CACHED NOW BEFORE CGAME STARTS
  2366. /*
  2367. ResetTeamCounters();
  2368. for ( int team = TEAM_FREE; team < TEAM_NUM_TEAMS; team++ )
  2369. {
  2370. teamLastEnemyTime[team] = -10000;
  2371. }
  2372. */
  2373. }
  2374. void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend)
  2375. { // FIXME : once torsoAnim and legsAnim are in the same structure for NCP and Players
  2376. // rename PM_SETAnimFinal to PM_SetAnim and have both NCP and Players call PM_SetAnim
  2377. if ( !ent )
  2378. {
  2379. return;
  2380. }
  2381. if ( ent->health > 0 )
  2382. {//don't lock anims if the guy is dead
  2383. if ( ent->client->ps.torsoAnimTimer
  2384. && PM_LockedAnim( ent->client->ps.torsoAnim )
  2385. && !PM_LockedAnim( anim ) )
  2386. {//nothing can override these special anims
  2387. setAnimParts &= ~SETANIM_TORSO;
  2388. }
  2389. if ( ent->client->ps.legsAnimTimer
  2390. && PM_LockedAnim( ent->client->ps.legsAnim )
  2391. && !PM_LockedAnim( anim ) )
  2392. {//nothing can override these special anims
  2393. setAnimParts &= ~SETANIM_LEGS;
  2394. }
  2395. }
  2396. if ( !setAnimParts )
  2397. {
  2398. return;
  2399. }
  2400. if(ent->client)
  2401. {//Players, NPCs
  2402. if (setAnimFlags&SETANIM_FLAG_OVERRIDE)
  2403. {
  2404. if (setAnimParts & SETANIM_TORSO)
  2405. {
  2406. if( (setAnimFlags & SETANIM_FLAG_RESTART) || ent->client->ps.torsoAnim != anim )
  2407. {
  2408. PM_SetTorsoAnimTimer( ent, &ent->client->ps.torsoAnimTimer, 0 );
  2409. }
  2410. }
  2411. if (setAnimParts & SETANIM_LEGS)
  2412. {
  2413. if( (setAnimFlags & SETANIM_FLAG_RESTART) || ent->client->ps.legsAnim != anim )
  2414. {
  2415. PM_SetLegsAnimTimer( ent, &ent->client->ps.legsAnimTimer, 0 );
  2416. }
  2417. }
  2418. }
  2419. PM_SetAnimFinal(&ent->client->ps.torsoAnim,&ent->client->ps.legsAnim,setAnimParts,anim,setAnimFlags,
  2420. &ent->client->ps.torsoAnimTimer,&ent->client->ps.legsAnimTimer,ent, iBlend );
  2421. }
  2422. else
  2423. {//bodies, etc.
  2424. if (setAnimFlags&SETANIM_FLAG_OVERRIDE)
  2425. {
  2426. if (setAnimParts & SETANIM_TORSO)
  2427. {
  2428. if( (setAnimFlags & SETANIM_FLAG_RESTART) || ent->s.torsoAnim != anim )
  2429. {
  2430. PM_SetTorsoAnimTimer( ent, &ent->s.torsoAnimTimer, 0 );
  2431. }
  2432. }
  2433. if (setAnimParts & SETANIM_LEGS)
  2434. {
  2435. if( (setAnimFlags & SETANIM_FLAG_RESTART) || ent->s.legsAnim != anim )
  2436. {
  2437. PM_SetLegsAnimTimer( ent, &ent->s.legsAnimTimer, 0 );
  2438. }
  2439. }
  2440. }
  2441. PM_SetAnimFinal(&ent->s.torsoAnim,&ent->s.legsAnim,setAnimParts,anim,setAnimFlags,
  2442. &ent->s.torsoAnimTimer,&ent->s.legsAnimTimer,ent);
  2443. }
  2444. }