doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Projectile.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "Game_local.h"
33 
34 /*
35 ===============================================================================
36 
37  idProjectile
38 
39 ===============================================================================
40 */
41 
42 
43 static const int BFG_DAMAGE_FREQUENCY = 333;
44 static const float BOUNCE_SOUND_MIN_VELOCITY = 200.0f;
45 static const float BOUNCE_SOUND_MAX_VELOCITY = 400.0f;
46 
47 const idEventDef EV_Explode( "<explode>", NULL );
48 const idEventDef EV_Fizzle( "<fizzle>", NULL );
49 const idEventDef EV_RadiusDamage( "<radiusdmg>", "e" );
50 const idEventDef EV_GetProjectileState( "getProjectileState", NULL, 'd' );
51 
52 #ifdef _D3XP
53 const idEventDef EV_CreateProjectile( "projectileCreateProjectile", "evv" );
54 const idEventDef EV_LaunchProjectile( "projectileLaunchProjectile", "vvv" );
55 const idEventDef EV_SetGravity( "setGravity", "f" );
56 #endif
57 
59  EVENT( EV_Explode, idProjectile::Event_Explode )
60  EVENT( EV_Fizzle, idProjectile::Event_Fizzle )
61  EVENT( EV_Touch, idProjectile::Event_Touch )
62  EVENT( EV_RadiusDamage, idProjectile::Event_RadiusDamage )
63  EVENT( EV_GetProjectileState, idProjectile::Event_GetProjectileState )
64 #ifdef _D3XP
65  EVENT( EV_CreateProjectile, idProjectile::Event_CreateProjectile )
66  EVENT( EV_LaunchProjectile, idProjectile::Event_LaunchProjectile )
67  EVENT( EV_SetGravity, idProjectile::Event_SetGravity )
68 #endif
70 
71 /*
72 ================
73 idProjectile::idProjectile
74 ================
75 */
77  owner = NULL;
78  lightDefHandle = -1;
79  thrust = 0.0f;
80  thrust_end = 0;
81  smokeFly = NULL;
82  smokeFlyTime = 0;
83  state = SPAWNED;
85  lightStartTime = 0;
86  lightEndTime = 0;
88  state = SPAWNED;
89  damagePower = 1.0f;
90  memset( &projectileFlags, 0, sizeof( projectileFlags ) );
91  memset( &renderLight, 0, sizeof( renderLight ) );
92 
93  // note: for net_instanthit projectiles, we will force this back to false at spawn time
94  fl.networkSync = true;
95 
96  netSyncPhysics = false;
97 }
98 
99 /*
100 ================
101 idProjectile::Spawn
102 ================
103 */
104 void idProjectile::Spawn( void ) {
105  physicsObj.SetSelf( this );
106  physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f );
107  physicsObj.SetContents( 0 );
108  physicsObj.SetClipMask( 0 );
111 }
112 
113 /*
114 ================
115 idProjectile::Save
116 ================
117 */
118 void idProjectile::Save( idSaveGame *savefile ) const {
119 
120  owner.Save( savefile );
121 
123  LittleBitField( &flags, sizeof( flags ) );
124  savefile->Write( &flags, sizeof( flags ) );
125 
126  savefile->WriteFloat( thrust );
127  savefile->WriteInt( thrust_end );
128 
129  savefile->WriteRenderLight( renderLight );
130  savefile->WriteInt( (int)lightDefHandle );
131  savefile->WriteVec3( lightOffset );
132  savefile->WriteInt( lightStartTime );
133  savefile->WriteInt( lightEndTime );
134  savefile->WriteVec3( lightColor );
135 
136  savefile->WriteParticle( smokeFly );
137  savefile->WriteInt( smokeFlyTime );
138 
139 #ifdef _D3XP
140  savefile->WriteInt( originalTimeGroup );
141 #endif
142 
143  savefile->WriteInt( (int)state );
144 
145  savefile->WriteFloat( damagePower );
146 
147  savefile->WriteStaticObject( physicsObj );
148  savefile->WriteStaticObject( thruster );
149 }
150 
151 /*
152 ================
153 idProjectile::Restore
154 ================
155 */
157 
158  owner.Restore( savefile );
159 
160  savefile->Read( &projectileFlags, sizeof( projectileFlags ) );
162 
163  savefile->ReadFloat( thrust );
164  savefile->ReadInt( thrust_end );
165 
166  savefile->ReadRenderLight( renderLight );
167  savefile->ReadInt( (int &)lightDefHandle );
168  savefile->ReadVec3( lightOffset );
169  savefile->ReadInt( lightStartTime );
170  savefile->ReadInt( lightEndTime );
171  savefile->ReadVec3( lightColor );
172 
173  savefile->ReadParticle( smokeFly );
174  savefile->ReadInt( smokeFlyTime );
175 
176 #ifdef _D3XP
177  savefile->ReadInt( originalTimeGroup );
178 #endif
179 
180  savefile->ReadInt( (int &)state );
181 
182  savefile->ReadFloat( damagePower );
183 
184  savefile->ReadStaticObject( physicsObj );
186 
187  savefile->ReadStaticObject( thruster );
189 
190  if ( smokeFly != NULL ) {
191  idVec3 dir;
193  dir.NormalizeFast();
195  }
196 
197 #ifdef _D3XP
198  if ( lightDefHandle >= 0 ) {
199  lightDefHandle = gameRenderWorld->AddLightDef( &renderLight );
200  }
201 #endif
202 }
203 
204 /*
205 ================
206 idProjectile::GetOwner
207 ================
208 */
210  return owner.GetEntity();
211 }
212 
213 /*
214 ================
215 idProjectile::Create
216 ================
217 */
218 void idProjectile::Create( idEntity *owner, const idVec3 &start, const idVec3 &dir ) {
219  idDict args;
220  idStr shaderName;
221  idVec3 light_color;
222  idVec3 light_offset;
223  idVec3 tmp;
224  idMat3 axis;
225 
226  Unbind();
227 
228  // align z-axis of model with the direction
229  axis = dir.ToMat3();
230  tmp = axis[2];
231  axis[2] = axis[0];
232  axis[0] = -tmp;
233 
234  physicsObj.SetOrigin( start );
235  physicsObj.SetAxis( axis );
236 
237  physicsObj.GetClipModel()->SetOwner( owner );
238 
239  this->owner = owner;
240 
241  memset( &renderLight, 0, sizeof( renderLight ) );
242  shaderName = spawnArgs.GetString( "mtr_light_shader" );
243  if ( *(const char *)shaderName ) {
244  renderLight.shader = declManager->FindMaterial( shaderName, false );
245  renderLight.pointLight = true;
248  renderLight.lightRadius[2] = spawnArgs.GetFloat( "light_radius" );
249  spawnArgs.GetVector( "light_color", "1 1 1", light_color );
250  renderLight.shaderParms[0] = light_color[0];
251  renderLight.shaderParms[1] = light_color[1];
252  renderLight.shaderParms[2] = light_color[2];
253  renderLight.shaderParms[3] = 1.0f;
254  }
255 
256  spawnArgs.GetVector( "light_offset", "0 0 0", lightOffset );
257 
258  lightStartTime = 0;
259  lightEndTime = 0;
260  smokeFlyTime = 0;
261 
262  damagePower = 1.0f;
263 
264 #ifdef _D3XP
265  if(spawnArgs.GetBool("reset_time_offset", "0")) {
267  }
268 #endif
269 
270  UpdateVisuals();
271 
272  state = CREATED;
273 
274  if ( spawnArgs.GetBool( "net_fullphysics" ) ) {
275  netSyncPhysics = true;
276  }
277 }
278 
279 /*
280 =================
281 idProjectile::~idProjectile
282 =================
283 */
285  StopSound( SND_CHANNEL_ANY, false );
286  FreeLightDef();
287 }
288 
289 /*
290 =================
291 idProjectile::FreeLightDef
292 =================
293 */
295  if ( lightDefHandle != -1 ) {
297  lightDefHandle = -1;
298  }
299 }
300 
301 /*
302 =================
303 idProjectile::Launch
304 =================
305 */
306 void idProjectile::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float launchPower, const float dmgPower ) {
307  float fuse;
308  float startthrust;
309  float endthrust;
310  idVec3 velocity;
311  idAngles angular_velocity;
312  float linear_friction;
313  float angular_friction;
314  float contact_friction;
315  float bounce;
316  float mass;
317  float speed;
318  float gravity;
319  idVec3 gravVec;
320  idVec3 tmp;
321  idMat3 axis;
322  int thrust_start;
323  int contents;
324  int clipMask;
325 
326  // allow characters to throw projectiles during cinematics, but not the player
327  if ( owner.GetEntity() && !owner.GetEntity()->IsType( idPlayer::Type ) ) {
329  } else {
330  cinematic = false;
331  }
332 
333  thrust = spawnArgs.GetFloat( "thrust" );
334  startthrust = spawnArgs.GetFloat( "thrust_start" );
335  endthrust = spawnArgs.GetFloat( "thrust_end" );
336 
337  spawnArgs.GetVector( "velocity", "0 0 0", velocity );
338 
339  speed = velocity.Length() * launchPower;
340 
341  damagePower = dmgPower;
342 
343  spawnArgs.GetAngles( "angular_velocity", "0 0 0", angular_velocity );
344 
345  linear_friction = spawnArgs.GetFloat( "linear_friction" );
346  angular_friction = spawnArgs.GetFloat( "angular_friction" );
347  contact_friction = spawnArgs.GetFloat( "contact_friction" );
348  bounce = spawnArgs.GetFloat( "bounce" );
349  mass = spawnArgs.GetFloat( "mass" );
350  gravity = spawnArgs.GetFloat( "gravity" );
351  fuse = spawnArgs.GetFloat( "fuse" );
352 
353  projectileFlags.detonate_on_world = spawnArgs.GetBool( "detonate_on_world" );
354  projectileFlags.detonate_on_actor = spawnArgs.GetBool( "detonate_on_actor" );
355  projectileFlags.randomShaderSpin = spawnArgs.GetBool( "random_shader_spin" );
356 
357  if ( mass <= 0 ) {
358  gameLocal.Error( "Invalid mass on '%s'\n", GetEntityDefName() );
359  }
360 
361  thrust *= mass;
362  thrust_start = SEC2MS( startthrust ) + gameLocal.time;
363  thrust_end = SEC2MS( endthrust ) + gameLocal.time;
364 
365  lightStartTime = 0;
366  lightEndTime = 0;
367 
368  if ( health ) {
369  fl.takedamage = true;
370  }
371 
372  gravVec = gameLocal.GetGravity();
373  gravVec.NormalizeFast();
374 
375  Unbind();
376 
377  // align z-axis of model with the direction
378  axis = dir.ToMat3();
379  tmp = axis[2];
380  axis[2] = axis[0];
381  axis[0] = -tmp;
382 
383  contents = 0;
384  clipMask = MASK_SHOT_RENDERMODEL;
385  if ( spawnArgs.GetBool( "detonate_on_trigger" ) ) {
386  contents |= CONTENTS_TRIGGER;
387  }
388  if ( !spawnArgs.GetBool( "no_contents" ) ) {
389  contents |= CONTENTS_PROJECTILE;
390  clipMask |= CONTENTS_PROJECTILE;
391  }
392 
393 #ifdef _D3XP
394  if ( !idStr::Cmp( this->GetEntityDefName(), "projectile_helltime_killer" ) ) {
395  contents = CONTENTS_MOVEABLECLIP;
396  clipMask = CONTENTS_MOVEABLECLIP;
397  }
398 #endif
399 
400  // don't do tracers on client, we don't know origin and direction
401  if ( spawnArgs.GetBool( "tracers" ) && gameLocal.random.RandomFloat() > 0.5f ) {
402  SetModel( spawnArgs.GetString( "model_tracer" ) );
403  projectileFlags.isTracer = true;
404  }
405 
406  physicsObj.SetMass( mass );
407  physicsObj.SetFriction( linear_friction, angular_friction, contact_friction );
408  if ( contact_friction == 0.0f ) {
410  }
411  physicsObj.SetBouncyness( bounce );
412  physicsObj.SetGravity( gravVec * gravity );
413  physicsObj.SetContents( contents );
414  physicsObj.SetClipMask( clipMask );
415  physicsObj.SetLinearVelocity( axis[ 2 ] * speed + pushVelocity );
416  physicsObj.SetAngularVelocity( angular_velocity.ToAngularVelocity() * axis );
417  physicsObj.SetOrigin( start );
418  physicsObj.SetAxis( axis );
419 
420  thruster.SetPosition( &physicsObj, 0, idVec3( GetPhysics()->GetBounds()[ 0 ].x, 0, 0 ) );
421 
422  if ( !gameLocal.isClient ) {
423  if ( fuse <= 0 ) {
424  // run physics for 1 second
425  RunPhysics();
426  PostEventMS( &EV_Remove, spawnArgs.GetInt( "remove_time", "1500" ) );
427  } else if ( spawnArgs.GetBool( "detonate_on_fuse" ) ) {
428  fuse -= timeSinceFire;
429  if ( fuse < 0.0f ) {
430  fuse = 0.0f;
431  }
432  PostEventSec( &EV_Explode, fuse );
433  } else {
434  fuse -= timeSinceFire;
435  if ( fuse < 0.0f ) {
436  fuse = 0.0f;
437  }
438  PostEventSec( &EV_Fizzle, fuse );
439  }
440  }
441 
442  if ( projectileFlags.isTracer ) {
443  StartSound( "snd_tracer", SND_CHANNEL_BODY, 0, false, NULL );
444  } else {
445  StartSound( "snd_fly", SND_CHANNEL_BODY, 0, false, NULL );
446  }
447 
448  smokeFlyTime = 0;
449  const char *smokeName = spawnArgs.GetString( "smoke_fly" );
450  if ( *smokeName != '\0' ) {
451  smokeFly = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
453  }
454 
455 #ifdef _D3XP
456  originalTimeGroup = timeGroup;
457 #endif
458 
459  // used for the plasma bolts but may have other uses as well
461  float f = gameLocal.random.RandomFloat();
462  f *= 0.5f;
464  }
465 
466  UpdateVisuals();
467 
468  state = LAUNCHED;
469 }
470 
471 /*
472 ================
473 idProjectile::Think
474 ================
475 */
476 void idProjectile::Think( void ) {
477 
478  if ( thinkFlags & TH_THINK ) {
479  if ( thrust && ( gameLocal.time < thrust_end ) ) {
480  // evaluate force
481  thruster.SetForce( GetPhysics()->GetAxis()[ 0 ] * thrust );
483  }
484  }
485 
486  // run physics
487  RunPhysics();
488 
489  Present();
490 
491  // add the particles
492  if ( smokeFly != NULL && smokeFlyTime && !IsHidden() ) {
493  idVec3 dir = -GetPhysics()->GetLinearVelocity();
494  dir.Normalize();
495 #ifdef _D3XP
496  SetTimeState ts(originalTimeGroup);
497 #endif
498  if ( !gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.RandomFloat(), GetPhysics()->GetOrigin(), dir.ToMat3(), timeGroup /*_D3XP*/ ) ) {
500  }
501  }
502 
503  // add the light
504  if ( renderLight.lightRadius.x > 0.0f && g_projectileLights.GetBool() ) {
507  if ( ( lightDefHandle != -1 ) ) {
509  idVec3 color( 0, 0, 0 );
510  if ( gameLocal.time < lightEndTime ) {
511  float frac = ( float )( gameLocal.time - lightStartTime ) / ( float )( lightEndTime - lightStartTime );
512  color.Lerp( lightColor, color, frac );
513  }
517  }
519  } else {
521  }
522  }
523 }
524 
525 /*
526 =================
527 idProjectile::Collide
528 =================
529 */
530 bool idProjectile::Collide( const trace_t &collision, const idVec3 &velocity ) {
531  idEntity *ent;
532  idEntity *ignore;
533  const char *damageDefName;
534  idVec3 dir;
535  float push;
536  float damageScale;
537 
538  if ( state == EXPLODED || state == FIZZLED ) {
539  return true;
540  }
541 
542  // predict the explosion
543  if ( gameLocal.isClient ) {
544  if ( ClientPredictionCollide( this, spawnArgs, collision, velocity, !spawnArgs.GetBool( "net_instanthit" ) ) ) {
545  Explode( collision, NULL );
546  return true;
547  }
548  return false;
549  }
550 
551  // remove projectile when a 'noimpact' surface is hit
552  if ( ( collision.c.material != NULL ) && ( collision.c.material->GetSurfaceFlags() & SURF_NOIMPACT ) ) {
553  PostEventMS( &EV_Remove, 0 );
554  common->DPrintf( "Projectile collision no impact\n" );
555  return true;
556  }
557 
558  // get the entity the projectile collided with
559  ent = gameLocal.entities[ collision.c.entityNum ];
560  if ( ent == owner.GetEntity() ) {
561  assert( 0 );
562  return true;
563  }
564 
565  // just get rid of the projectile when it hits a player in noclip
566  if ( ent->IsType( idPlayer::Type ) && static_cast<idPlayer *>( ent )->noclip ) {
567  PostEventMS( &EV_Remove, 0 );
568  return true;
569  }
570 
571  // direction of projectile
572  dir = velocity;
573  dir.Normalize();
574 
575  // projectiles can apply an additional impulse next to the rigid body physics impulse
576  if ( spawnArgs.GetFloat( "push", "0", push ) && push > 0.0f ) {
577  ent->ApplyImpulse( this, collision.c.id, collision.c.point, push * dir );
578  }
579 
580  // MP: projectiles open doors
581  if ( gameLocal.isMultiplayer && ent->IsType( idDoor::Type ) && !static_cast< idDoor * >(ent)->IsOpen() && !ent->spawnArgs.GetBool( "no_touch" ) ) {
582  ent->ProcessEvent( &EV_Activate , this );
583  }
584 
585  if ( ent->IsType( idActor::Type ) || ( ent->IsType( idAFAttachment::Type ) && static_cast<const idAFAttachment*>(ent)->GetBody()->IsType( idActor::Type ) ) ) {
587  return false;
588  }
589  } else {
591  if ( !StartSound( "snd_ricochet", SND_CHANNEL_ITEM, 0, true, NULL ) ) {
592  float len = velocity.Length();
593  if ( len > BOUNCE_SOUND_MIN_VELOCITY ) {
594  SetSoundVolume( len > BOUNCE_SOUND_MAX_VELOCITY ? 1.0f : idMath::Sqrt( len - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / idMath::Sqrt( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) ) );
595  StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, true, NULL );
596  }
597  }
598  return false;
599  }
600  }
601 
602  SetOrigin( collision.endpos );
603  SetAxis( collision.endAxis );
604 
605  // unlink the clip model because we no longer need it
606  GetPhysics()->UnlinkClip();
607 
608  damageDefName = spawnArgs.GetString( "def_damage" );
609 
610  ignore = NULL;
611 
612  // if the hit entity takes damage
613  if ( ent->fl.takedamage ) {
614  if ( damagePower ) {
615  damageScale = damagePower;
616  } else {
617  damageScale = 1.0f;
618  }
619 
620  // if the projectile owner is a player
621  if ( owner.GetEntity() && owner.GetEntity()->IsType( idPlayer::Type ) ) {
622  // if the projectile hit an actor
623  if ( ent->IsType( idActor::Type ) ) {
624  idPlayer *player = static_cast<idPlayer *>( owner.GetEntity() );
625  player->AddProjectileHits( 1 );
626  damageScale *= player->PowerUpModifier( PROJECTILE_DAMAGE );
627  }
628  }
629 
630  if ( damageDefName[0] != '\0' ) {
631  ent->Damage( this, owner.GetEntity(), dir, damageDefName, damageScale, CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id ) );
632  ignore = ent;
633  }
634  }
635 
636  // if the projectile causes a damage effect
637  if ( spawnArgs.GetBool( "impact_damage_effect" ) ) {
638  // if the hit entity has a special damage effect
639  if ( ent->spawnArgs.GetBool( "bleed" ) ) {
640  ent->AddDamageEffect( collision, velocity, damageDefName );
641  } else {
642  AddDefaultDamageEffect( collision, velocity );
643  }
644  }
645 
646  Explode( collision, ignore );
647 
648  return true;
649 }
650 
651 /*
652 =================
653 idProjectile::DefaultDamageEffect
654 =================
655 */
656 void idProjectile::DefaultDamageEffect( idEntity *soundEnt, const idDict &projectileDef, const trace_t &collision, const idVec3 &velocity ) {
657  const char *decal, *sound, *typeName;
658  surfTypes_t materialType;
659 
660  if ( collision.c.material != NULL ) {
661  materialType = collision.c.material->GetSurfaceType();
662  } else {
663  materialType = SURFTYPE_METAL;
664  }
665 
666  // get material type name
667  typeName = gameLocal.sufaceTypeNames[ materialType ];
668 
669  // play impact sound
670  sound = projectileDef.GetString( va( "snd_%s", typeName ) );
671  if ( *sound == '\0' ) {
672  sound = projectileDef.GetString( "snd_metal" );
673  }
674  if ( *sound == '\0' ) {
675  sound = projectileDef.GetString( "snd_impact" );
676  }
677  if ( *sound != '\0' ) {
678  soundEnt->StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL );
679  }
680 
681  // project decal
682  decal = projectileDef.GetString( va( "mtr_detonate_%s", typeName ) );
683  if ( *decal == '\0' ) {
684  decal = projectileDef.GetString( "mtr_detonate" );
685  }
686  if ( *decal != '\0' ) {
687  gameLocal.ProjectDecal( collision.c.point, -collision.c.normal, 8.0f, true, projectileDef.GetFloat( "decal_size", "6.0" ), decal );
688  }
689 }
690 
691 /*
692 =================
693 idProjectile::AddDefaultDamageEffect
694 =================
695 */
696 void idProjectile::AddDefaultDamageEffect( const trace_t &collision, const idVec3 &velocity ) {
697 
698  DefaultDamageEffect( this, spawnArgs, collision, velocity );
699 
700  if ( gameLocal.isServer && fl.networkSync ) {
701  idBitMsg msg;
702  byte msgBuf[MAX_EVENT_PARAM_SIZE];
703  int excludeClient;
704 
705  if ( spawnArgs.GetBool( "net_instanthit" ) ) {
706  excludeClient = owner.GetEntityNum();
707  } else {
708  excludeClient = -1;
709  }
710 
711  msg.Init( msgBuf, sizeof( msgBuf ) );
712  msg.BeginWriting();
713  msg.WriteFloat( collision.c.point[0] );
714  msg.WriteFloat( collision.c.point[1] );
715  msg.WriteFloat( collision.c.point[2] );
716  msg.WriteDir( collision.c.normal, 24 );
717  msg.WriteLong( ( collision.c.material != NULL ) ? gameLocal.ServerRemapDecl( -1, DECL_MATERIAL, collision.c.material->Index() ) : -1 );
718  msg.WriteFloat( velocity[0], 5, 10 );
719  msg.WriteFloat( velocity[1], 5, 10 );
720  msg.WriteFloat( velocity[2], 5, 10 );
721  ServerSendEvent( EVENT_DAMAGE_EFFECT, &msg, false, excludeClient );
722  }
723 }
724 
725 /*
726 ================
727 idProjectile::Killed
728 ================
729 */
730 void idProjectile::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
731  if ( spawnArgs.GetBool( "detonate_on_death" ) ) {
732  trace_t collision;
733 
734  memset( &collision, 0, sizeof( collision ) );
735  collision.endAxis = GetPhysics()->GetAxis();
736  collision.endpos = GetPhysics()->GetOrigin();
737  collision.c.point = GetPhysics()->GetOrigin();
738  collision.c.normal.Set( 0, 0, 1 );
739  Explode( collision, NULL );
742  } else {
743  Fizzle();
744  }
745 }
746 
747 /*
748 ================
749 idProjectile::Fizzle
750 ================
751 */
752 void idProjectile::Fizzle( void ) {
753 
754  if ( state == EXPLODED || state == FIZZLED ) {
755  return;
756  }
757 
758  StopSound( SND_CHANNEL_BODY, false );
759  StartSound( "snd_fizzle", SND_CHANNEL_BODY, 0, false, NULL );
760 
761  // fizzle FX
762  const char *psystem = spawnArgs.GetString( "smoke_fuse" );
763  if ( psystem && *psystem ) {
764 //FIXME:SMOKE gameLocal.particles->SpawnParticles( GetPhysics()->GetOrigin(), vec3_origin, psystem );
765  }
766 
767  // we need to work out how long the effects last and then remove them at that time
768  // for example, bullets have no real effects
769  if ( smokeFly && smokeFlyTime ) {
770  smokeFlyTime = 0;
771  }
772 
773  fl.takedamage = false;
774  physicsObj.SetContents( 0 );
777 
778  Hide();
779  FreeLightDef();
780 
781  state = FIZZLED;
782 
783  if ( gameLocal.isClient ) {
784  return;
785  }
786 
787  CancelEvents( &EV_Fizzle );
788  PostEventMS( &EV_Remove, spawnArgs.GetInt( "remove_time", "1500" ) );
789 }
790 
791 /*
792 ================
793 idProjectile::Event_RadiusDamage
794 ================
795 */
797  const char *splash_damage = spawnArgs.GetString( "def_splash_damage" );
798  if ( splash_damage[0] != '\0' ) {
799  gameLocal.RadiusDamage( physicsObj.GetOrigin(), this, owner.GetEntity(), ignore, this, splash_damage, damagePower );
800  }
801 }
802 
803 /*
804 ================
805 idProjectile::Event_RadiusDamage
806 ================
807 */
810 }
811 
812 /*
813 ================
814 idProjectile::Explode
815 ================
816 */
817 void idProjectile::Explode( const trace_t &collision, idEntity *ignore ) {
818  const char *fxname, *light_shader, *sndExplode;
819  float light_fadetime;
820  idVec3 normal;
821  int removeTime;
822 
823  if ( state == EXPLODED || state == FIZZLED ) {
824  return;
825  }
826 
827  // stop sound
828  StopSound( SND_CHANNEL_BODY2, false );
829 
830  // play explode sound
831  switch ( ( int ) damagePower ) {
832  case 2: sndExplode = "snd_explode2"; break;
833  case 3: sndExplode = "snd_explode3"; break;
834  case 4: sndExplode = "snd_explode4"; break;
835  default: sndExplode = "snd_explode"; break;
836  }
837  StartSound( sndExplode, SND_CHANNEL_BODY, 0, true, NULL );
838 
839  // we need to work out how long the effects last and then remove them at that time
840  // for example, bullets have no real effects
841  if ( smokeFly && smokeFlyTime ) {
842  smokeFlyTime = 0;
843  }
844 
845  Hide();
846  FreeLightDef();
847 
848  if ( spawnArgs.GetVector( "detonation_axis", "", normal ) ) {
849  GetPhysics()->SetAxis( normal.ToMat3() );
850  }
851  GetPhysics()->SetOrigin( collision.endpos + 2.0f * collision.c.normal );
852 
853  // default remove time
854  removeTime = spawnArgs.GetInt( "remove_time", "1500" );
855 
856  // change the model, usually to a PRT
857  fxname = NULL;
859  fxname = g_testParticleName.GetString();
860  } else {
861  fxname = spawnArgs.GetString( "model_detonate" );
862  }
863 
864  int surfaceType = collision.c.material != NULL ? collision.c.material->GetSurfaceType() : SURFTYPE_METAL;
865  if ( !( fxname && *fxname ) ) {
866  if ( ( surfaceType == SURFTYPE_NONE ) || ( surfaceType == SURFTYPE_METAL ) || ( surfaceType == SURFTYPE_STONE ) ) {
867  fxname = spawnArgs.GetString( "model_smokespark" );
868  } else if ( surfaceType == SURFTYPE_RICOCHET ) {
869  fxname = spawnArgs.GetString( "model_ricochet" );
870  } else {
871  fxname = spawnArgs.GetString( "model_smoke" );
872  }
873  }
874 
875 #ifdef _D3XP
876  // If the explosion is in liquid, spawn a particle splash
877  idVec3 testOrg = GetPhysics()->GetOrigin();
878  int testC = gameLocal.clip.Contents( testOrg, NULL, mat3_identity, CONTENTS_WATER, this );
879  if ( testC & CONTENTS_WATER ) {
880  idFuncEmitter *splashEnt;
881  idDict splashArgs;
882 
883  splashArgs.Set( "model", "sludgebulletimpact.prt" );
884  splashArgs.Set( "start_off", "1" );
885  splashEnt = static_cast<idFuncEmitter *>( gameLocal.SpawnEntityType( idFuncEmitter::Type, &splashArgs ) );
886 
887  splashEnt->GetPhysics()->SetOrigin( testOrg );
888  splashEnt->PostEventMS( &EV_Activate, 0, this );
889  splashEnt->PostEventMS( &EV_Remove, 1500 );
890 
891  // HACK - if this is a chaingun bullet, don't do the normal effect
892  if ( !idStr::Cmp( spawnArgs.GetString( "def_damage" ), "damage_bullet_chaingun" ) ) {
893  fxname = NULL;
894  }
895  }
896 #endif
897 
898  if ( fxname && *fxname ) {
899  SetModel( fxname );
906  Show();
907  removeTime = ( removeTime > 3000 ) ? removeTime : 3000;
908  }
909 
910  // explosion light
911  light_shader = spawnArgs.GetString( "mtr_explode_light_shader" );
912 
913 #ifdef CTF
915  {
916  light_shader = "lights/midnight_grenade";
917  }
918 #endif
919 
920  if ( *light_shader ) {
921  renderLight.shader = declManager->FindMaterial( light_shader, false );
922  renderLight.pointLight = true;
925  renderLight.lightRadius[2] = spawnArgs.GetFloat( "explode_light_radius" );
926 
927 #ifdef CTF
928  // Midnight ctf
930  {
933  renderLight.lightRadius[2] = spawnArgs.GetFloat( "explode_light_radius" ) * 2;
934  }
935 
936 #endif
937 
938  spawnArgs.GetVector( "explode_light_color", "1 1 1", lightColor );
944 
945 #ifdef CTF
946  // Midnight ctf
948  {
949  light_fadetime = 3.0f;
950  }
951  else
952 #endif
953  light_fadetime = spawnArgs.GetFloat( "explode_light_fadetime", "0.5" );
955  lightEndTime = gameLocal.time + SEC2MS( light_fadetime );
957  }
958 
959  fl.takedamage = false;
960  physicsObj.SetContents( 0 );
962 
963  state = EXPLODED;
964 
965  if ( gameLocal.isClient ) {
966  return;
967  }
968 
969  // alert the ai
971 
972  // bind the projectile to the impact entity if necesary
973  if ( gameLocal.entities[collision.c.entityNum] && spawnArgs.GetBool( "bindOnImpact" ) ) {
974  Bind( gameLocal.entities[collision.c.entityNum], true );
975  }
976 
977  // splash damage
979  float delay = spawnArgs.GetFloat( "delay_splash" );
980  if ( delay ) {
981  if ( removeTime < delay * 1000 ) {
982  removeTime = ( delay + 0.10 ) * 1000;
983  }
984  PostEventSec( &EV_RadiusDamage, delay, ignore );
985  } else {
986  Event_RadiusDamage( ignore );
987  }
988  }
989 
990  // spawn debris entities
991  int fxdebris = spawnArgs.GetInt( "debris_count" );
992  if ( fxdebris ) {
993  const idDict *debris = gameLocal.FindEntityDefDict( "projectile_debris", false );
994  if ( debris ) {
995  int amount = gameLocal.random.RandomInt( fxdebris );
996  for ( int i = 0; i < amount; i++ ) {
997  idEntity *ent;
998  idVec3 dir;
999  dir.x = gameLocal.random.CRandomFloat() * 4.0f;
1000  dir.y = gameLocal.random.CRandomFloat() * 4.0f;
1001  dir.z = gameLocal.random.RandomFloat() * 8.0f;
1002  dir.Normalize();
1003 
1004  gameLocal.SpawnEntityDef( *debris, &ent, false );
1005  if ( !ent || !ent->IsType( idDebris::Type ) ) {
1006  gameLocal.Error( "'projectile_debris' is not an idDebris" );
1007  }
1008 
1009  idDebris *debris = static_cast<idDebris *>(ent);
1010  debris->Create( owner.GetEntity(), physicsObj.GetOrigin(), dir.ToMat3() );
1011  debris->Launch();
1012  }
1013  }
1014  debris = gameLocal.FindEntityDefDict( "projectile_shrapnel", false );
1015  if ( debris ) {
1016  int amount = gameLocal.random.RandomInt( fxdebris );
1017  for ( int i = 0; i < amount; i++ ) {
1018  idEntity *ent;
1019  idVec3 dir;
1020  dir.x = gameLocal.random.CRandomFloat() * 8.0f;
1021  dir.y = gameLocal.random.CRandomFloat() * 8.0f;
1022  dir.z = gameLocal.random.RandomFloat() * 8.0f + 8.0f;
1023  dir.Normalize();
1024 
1025  gameLocal.SpawnEntityDef( *debris, &ent, false );
1026  if ( !ent || !ent->IsType( idDebris::Type ) ) {
1027  gameLocal.Error( "'projectile_shrapnel' is not an idDebris" );
1028  }
1029 
1030  idDebris *debris = static_cast<idDebris *>(ent);
1031  debris->Create( owner.GetEntity(), physicsObj.GetOrigin(), dir.ToMat3() );
1032  debris->Launch();
1033  }
1034  }
1035  }
1036 
1037  CancelEvents( &EV_Explode );
1038  PostEventMS( &EV_Remove, removeTime );
1039 }
1040 
1041 /*
1042 ================
1043 idProjectile::GetVelocity
1044 ================
1045 */
1047  idVec3 velocity;
1048 
1049  projectile->GetVector( "velocity", "0 0 0", velocity );
1050  return velocity;
1051 }
1052 
1053 /*
1054 ================
1055 idProjectile::GetGravity
1056 ================
1057 */
1059  float gravity;
1060 
1061  gravity = projectile->GetFloat( "gravity" );
1062  return idVec3( 0, 0, -gravity );
1063 }
1064 
1065 /*
1066 ================
1067 idProjectile::Event_Explode
1068 ================
1069 */
1071  trace_t collision;
1072 
1073  memset( &collision, 0, sizeof( collision ) );
1074  collision.endAxis = GetPhysics()->GetAxis();
1075  collision.endpos = GetPhysics()->GetOrigin();
1076  collision.c.point = GetPhysics()->GetOrigin();
1077  collision.c.normal.Set( 0, 0, 1 );
1078  AddDefaultDamageEffect( collision, collision.c.normal );
1079  Explode( collision, NULL );
1080 }
1081 
1082 /*
1083 ================
1084 idProjectile::Event_Fizzle
1085 ================
1086 */
1088  Fizzle();
1089 }
1090 
1091 /*
1092 ================
1093 idProjectile::Event_Touch
1094 ================
1095 */
1097 
1098  if ( IsHidden() ) {
1099  return;
1100  }
1101 
1102 #ifdef CTF
1103  // Projectiles do not collide with flags
1104  if ( other->IsType( idItemTeam::Type ) )
1105  return;
1106 #endif
1107 
1108  if ( other != owner.GetEntity() ) {
1109  trace_t collision;
1110 
1111  memset( &collision, 0, sizeof( collision ) );
1112  collision.endAxis = GetPhysics()->GetAxis();
1113  collision.endpos = GetPhysics()->GetOrigin();
1114  collision.c.point = GetPhysics()->GetOrigin();
1115  collision.c.normal.Set( 0, 0, 1 );
1116  AddDefaultDamageEffect( collision, collision.c.normal );
1117  Explode( collision, NULL );
1118  }
1119 }
1120 
1121 #ifdef _D3XP
1122 /*
1123 ================
1124 idProjectile::CatchProjectile
1125 ================
1126 */
1127 void idProjectile::CatchProjectile( idEntity* o, const char* reflectName ) {
1128  idEntity *prevowner = owner.GetEntity();
1129 
1130  owner = o;
1132 
1133  if ( this->IsType( idGuidedProjectile::Type ) ) {
1134  idGuidedProjectile *proj = static_cast<idGuidedProjectile*>(this);
1135 
1136  proj->SetEnemy( prevowner );
1137  }
1138 
1139  idStr s = spawnArgs.GetString( "def_damage" );
1140  s += reflectName;
1141 
1142  const idDict *damageDef = gameLocal.FindEntityDefDict( s, false );
1143  if ( damageDef ) {
1144  spawnArgs.Set( "def_damage", s );
1145  }
1146 }
1147 
1148 /*
1149 ================
1150 idProjectile::GetProjectileState
1151 ================
1152 */
1153 int idProjectile::GetProjectileState( void ) {
1154 
1155  return (int)state;
1156 }
1157 
1158 /*
1159 ================
1160 idProjectile::Event_CreateProjectile
1161 ================
1162 */
1163 void idProjectile::Event_CreateProjectile( idEntity *owner, const idVec3 &start, const idVec3 &dir ) {
1164  Create(owner, start, dir);
1165 }
1166 
1167 /*
1168 ================
1169 idProjectile::Event_LaunchProjectile
1170 ================
1171 */
1172 void idProjectile::Event_LaunchProjectile( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity ) {
1173  Launch(start, dir, pushVelocity);
1174 }
1175 
1176 /*
1177 ================
1178 idProjectile::Event_SetGravity
1179 ================
1180 */
1181 void idProjectile::Event_SetGravity( float gravity ) {
1182  idVec3 gravVec;
1183 
1184  gravVec = gameLocal.GetGravity();
1185  gravVec.NormalizeFast();
1186  physicsObj.SetGravity(gravVec * gravity);
1187 }
1188 #endif
1189 
1190 /*
1191 =================
1192 idProjectile::ClientPredictionCollide
1193 =================
1194 */
1195 bool idProjectile::ClientPredictionCollide( idEntity *soundEnt, const idDict &projectileDef, const trace_t &collision, const idVec3 &velocity, bool addDamageEffect ) {
1196  idEntity *ent;
1197 
1198  // remove projectile when a 'noimpact' surface is hit
1199  if ( collision.c.material && ( collision.c.material->GetSurfaceFlags() & SURF_NOIMPACT ) ) {
1200  return false;
1201  }
1202 
1203  // get the entity the projectile collided with
1204  ent = gameLocal.entities[ collision.c.entityNum ];
1205  if ( ent == NULL ) {
1206  return false;
1207  }
1208 
1209  // don't do anything if hitting a noclip player
1210  if ( ent->IsType( idPlayer::Type ) && static_cast<idPlayer *>( ent )->noclip ) {
1211  return false;
1212  }
1213 
1214  if ( ent->IsType( idActor::Type ) || ( ent->IsType( idAFAttachment::Type ) && static_cast<const idAFAttachment*>(ent)->GetBody()->IsType( idActor::Type ) ) ) {
1215  if ( !projectileDef.GetBool( "detonate_on_actor" ) ) {
1216  return false;
1217  }
1218  } else {
1219  if ( !projectileDef.GetBool( "detonate_on_world" ) ) {
1220  return false;
1221  }
1222  }
1223 
1224  // if the projectile causes a damage effect
1225  if ( addDamageEffect && projectileDef.GetBool( "impact_damage_effect" ) ) {
1226  // if the hit entity does not have a special damage effect
1227  if ( !ent->spawnArgs.GetBool( "bleed" ) ) {
1228  // predict damage effect
1229  DefaultDamageEffect( soundEnt, projectileDef, collision, velocity );
1230  }
1231  }
1232  return true;
1233 }
1234 
1235 /*
1236 ================
1237 idProjectile::ClientPredictionThink
1238 ================
1239 */
1241  if ( !renderEntity.hModel ) {
1242  return;
1243  }
1244  Think();
1245 }
1246 
1247 /*
1248 ================
1249 idProjectile::WriteToSnapshot
1250 ================
1251 */
1253  msg.WriteBits( owner.GetSpawnId(), 32 );
1254  msg.WriteBits( state, 3 );
1255  msg.WriteBits( fl.hidden, 1 );
1256  if ( netSyncPhysics ) {
1257  msg.WriteBits( 1, 1 );
1258  physicsObj.WriteToSnapshot( msg );
1259  } else {
1260  msg.WriteBits( 0, 1 );
1261  const idVec3 &origin = physicsObj.GetOrigin();
1262  const idVec3 &velocity = physicsObj.GetLinearVelocity();
1263 
1264  msg.WriteFloat( origin.x );
1265  msg.WriteFloat( origin.y );
1266  msg.WriteFloat( origin.z );
1267 
1271  }
1272 }
1273 
1274 /*
1275 ================
1276 idProjectile::ReadFromSnapshot
1277 ================
1278 */
1280  projectileState_t newState;
1281 
1282  owner.SetSpawnId( msg.ReadBits( 32 ) );
1283  newState = (projectileState_t) msg.ReadBits( 3 );
1284  if ( msg.ReadBits( 1 ) ) {
1285  Hide();
1286  } else {
1287  Show();
1288  }
1289 
1290  while( state != newState ) {
1291  switch( state ) {
1292  case SPAWNED: {
1293  Create( owner.GetEntity(), vec3_origin, idVec3( 1, 0, 0 ) );
1294  break;
1295  }
1296  case CREATED: {
1297  // the right origin and direction are required if you want bullet traces
1298  Launch( vec3_origin, idVec3( 1, 0, 0 ), vec3_origin );
1299  break;
1300  }
1301  case LAUNCHED: {
1302  if ( newState == FIZZLED ) {
1303  Fizzle();
1304  } else {
1305  trace_t collision;
1306  memset( &collision, 0, sizeof( collision ) );
1307  collision.endAxis = GetPhysics()->GetAxis();
1308  collision.endpos = GetPhysics()->GetOrigin();
1309  collision.c.point = GetPhysics()->GetOrigin();
1310  collision.c.normal.Set( 0, 0, 1 );
1311  Explode( collision, NULL );
1312  }
1313  break;
1314  }
1315  case FIZZLED:
1316  case EXPLODED: {
1317  StopSound( SND_CHANNEL_BODY2, false );
1319  state = SPAWNED;
1320  break;
1321  }
1322  }
1323  }
1324 
1325  if ( msg.ReadBits( 1 ) ) {
1327  } else {
1328  idVec3 origin;
1329  idVec3 velocity;
1330  idVec3 tmp;
1331  idMat3 axis;
1332 
1333  origin.x = msg.ReadFloat();
1334  origin.y = msg.ReadFloat();
1335  origin.z = msg.ReadFloat();
1336 
1340 
1341  physicsObj.SetOrigin( origin );
1342  physicsObj.SetLinearVelocity( velocity );
1343 
1344  // align z-axis of model with the direction
1345  velocity.NormalizeFast();
1346  axis = velocity.ToMat3();
1347  tmp = axis[2];
1348  axis[2] = axis[0];
1349  axis[0] = -tmp;
1350  physicsObj.SetAxis( axis );
1351  }
1352 
1353  if ( msg.HasChanged() ) {
1354  UpdateVisuals();
1355  }
1356 }
1357 
1358 /*
1359 ================
1360 idProjectile::ClientReceiveEvent
1361 ================
1362 */
1363 bool idProjectile::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
1364  trace_t collision;
1365  idVec3 velocity;
1366 
1367  switch( event ) {
1368  case EVENT_DAMAGE_EFFECT: {
1369  memset( &collision, 0, sizeof( collision ) );
1370  collision.c.point[0] = msg.ReadFloat();
1371  collision.c.point[1] = msg.ReadFloat();
1372  collision.c.point[2] = msg.ReadFloat();
1373  collision.c.normal = msg.ReadDir( 24 );
1375  collision.c.material = ( index != -1 ) ? static_cast<const idMaterial *>( declManager->DeclByIndex( DECL_MATERIAL, index ) ) : NULL;
1376  velocity[0] = msg.ReadFloat( 5, 10 );
1377  velocity[1] = msg.ReadFloat( 5, 10 );
1378  velocity[2] = msg.ReadFloat( 5, 10 );
1379  DefaultDamageEffect( this, spawnArgs, collision, velocity );
1380  return true;
1381  }
1382  default: {
1383  return idEntity::ClientReceiveEvent( event, time, msg );
1384  }
1385  }
1386  return false;
1387 }
1388 
1389 /*
1390 ===============================================================================
1391 
1392  idGuidedProjectile
1393 
1394 ===============================================================================
1395 */
1396 
1397 #ifdef _D3XP
1398 const idEventDef EV_SetEnemy( "setEnemy", "E" );
1399 #endif
1400 
1402 #ifdef _D3XP
1403  EVENT( EV_SetEnemy, idGuidedProjectile::Event_SetEnemy )
1404 #endif
1405 END_CLASS
1406 
1407 /*
1408 ================
1409 idGuidedProjectile::idGuidedProjectile
1410 ================
1411 */
1413  enemy = NULL;
1414  speed = 0.0f;
1415  turn_max = 0.0f;
1416  clamp_dist = 0.0f;
1417  rndScale = ang_zero;
1418  rndAng = ang_zero;
1419  rndUpdateTime = 0;
1420  angles = ang_zero;
1421  burstMode = false;
1422  burstDist = 0;
1423  burstVelocity = 0.0f;
1424  unGuided = false;
1425 }
1426 
1427 /*
1428 =================
1429 idGuidedProjectile::~idGuidedProjectile
1430 =================
1431 */
1433 }
1434 
1435 /*
1436 ================
1437 idGuidedProjectile::Spawn
1438 ================
1439 */
1441 }
1442 
1443 /*
1444 ================
1445 idGuidedProjectile::Save
1446 ================
1447 */
1448 void idGuidedProjectile::Save( idSaveGame *savefile ) const {
1449  enemy.Save( savefile );
1450  savefile->WriteFloat( speed );
1451  savefile->WriteAngles( rndScale );
1452  savefile->WriteAngles( rndAng );
1453  savefile->WriteInt( rndUpdateTime );
1454  savefile->WriteFloat( turn_max );
1455  savefile->WriteFloat( clamp_dist );
1456  savefile->WriteAngles( angles );
1457  savefile->WriteBool( burstMode );
1458  savefile->WriteBool( unGuided );
1459  savefile->WriteFloat( burstDist );
1460  savefile->WriteFloat( burstVelocity );
1461 }
1462 
1463 /*
1464 ================
1465 idGuidedProjectile::Restore
1466 ================
1467 */
1469  enemy.Restore( savefile );
1470  savefile->ReadFloat( speed );
1471  savefile->ReadAngles( rndScale );
1472  savefile->ReadAngles( rndAng );
1473  savefile->ReadInt( rndUpdateTime );
1474  savefile->ReadFloat( turn_max );
1475  savefile->ReadFloat( clamp_dist );
1476  savefile->ReadAngles( angles );
1477  savefile->ReadBool( burstMode );
1478  savefile->ReadBool( unGuided );
1479  savefile->ReadFloat( burstDist );
1480  savefile->ReadFloat( burstVelocity );
1481 }
1482 
1483 
1484 /*
1485 ================
1486 idGuidedProjectile::GetSeekPos
1487 ================
1488 */
1490  idEntity *enemyEnt = enemy.GetEntity();
1491  if ( enemyEnt ) {
1492  if ( enemyEnt->IsType( idActor::Type ) ) {
1493  out = static_cast<idActor *>(enemyEnt)->GetEyePosition();
1494  out.z -= 12.0f;
1495  } else {
1496  out = enemyEnt->GetPhysics()->GetOrigin();
1497  }
1498  } else {
1499  out = GetPhysics()->GetOrigin() + physicsObj.GetLinearVelocity() * 2.0f;
1500  }
1501 }
1502 
1503 /*
1504 ================
1505 idGuidedProjectile::Think
1506 ================
1507 */
1509  idVec3 dir;
1510  idVec3 seekPos;
1511  idVec3 velocity;
1512  idVec3 nose;
1513  idVec3 tmp;
1514  idMat3 axis;
1515  idAngles dirAng;
1516  idAngles diff;
1517  float dist;
1518  float frac;
1519  int i;
1520 
1521  if ( state == LAUNCHED && !unGuided ) {
1522 
1523  GetSeekPos( seekPos );
1524 
1525  if ( rndUpdateTime < gameLocal.time ) {
1526  rndAng[ 0 ] = rndScale[ 0 ] * gameLocal.random.CRandomFloat();
1527  rndAng[ 1 ] = rndScale[ 1 ] * gameLocal.random.CRandomFloat();
1528  rndAng[ 2 ] = rndScale[ 2 ] * gameLocal.random.CRandomFloat();
1529  rndUpdateTime = gameLocal.time + 200;
1530  }
1531 
1532  nose = physicsObj.GetOrigin() + 10.0f * physicsObj.GetAxis()[0];
1533 
1534  dir = seekPos - nose;
1535  dist = dir.Normalize();
1536  dirAng = dir.ToAngles();
1537 
1538  // make it more accurate as it gets closer
1539  frac = dist / clamp_dist;
1540  if ( frac > 1.0f ) {
1541  frac = 1.0f;
1542  }
1543 
1544  diff = dirAng - angles + rndAng * frac;
1545 
1546  // clamp the to the max turn rate
1547  diff.Normalize180();
1548  for( i = 0; i < 3; i++ ) {
1549  if ( diff[ i ] > turn_max ) {
1550  diff[ i ] = turn_max;
1551  } else if ( diff[ i ] < -turn_max ) {
1552  diff[ i ] = -turn_max;
1553  }
1554  }
1555  angles += diff;
1556 
1557  // make the visual model always points the dir we're traveling
1558  dir = angles.ToForward();
1559  velocity = dir * speed;
1560 
1561  if ( burstMode && dist < burstDist ) {
1562  unGuided = true;
1563  velocity *= burstVelocity;
1564  }
1565 
1566  physicsObj.SetLinearVelocity( velocity );
1567 
1568  // align z-axis of model with the direction
1569  axis = dir.ToMat3();
1570  tmp = axis[2];
1571  axis[2] = axis[0];
1572  axis[0] = -tmp;
1573 
1574  GetPhysics()->SetAxis( axis );
1575  }
1576 
1578 }
1579 
1580 /*
1581 =================
1582 idGuidedProjectile::Launch
1583 =================
1584 */
1585 void idGuidedProjectile::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float launchPower, float dmgPower ) {
1586  idProjectile::Launch( start, dir, pushVelocity, timeSinceFire, launchPower, dmgPower );
1587  if ( owner.GetEntity() ) {
1588  if ( owner.GetEntity()->IsType( idAI::Type ) ) {
1589  enemy = static_cast<idAI *>( owner.GetEntity() )->GetEnemy();
1590  } else if ( owner.GetEntity()->IsType( idPlayer::Type ) ) {
1591  trace_t tr;
1592  idPlayer *player = static_cast<idPlayer*>( owner.GetEntity() );
1593  idVec3 start = player->GetEyePosition();
1594  idVec3 end = start + player->viewAxis[0] * 1000.0f;
1596  if ( tr.fraction < 1.0f ) {
1597  enemy = gameLocal.GetTraceEntity( tr );
1598  }
1599  // ignore actors on the player's team
1600  if ( enemy.GetEntity() == NULL || !enemy.GetEntity()->IsType( idActor::Type ) || ( static_cast<idActor *>( enemy.GetEntity() )->team == player->team ) ) {
1601  enemy = player->EnemyWithMostHealth();
1602  }
1603  }
1604  }
1605  const idVec3 &vel = physicsObj.GetLinearVelocity();
1606  angles = vel.ToAngles();
1607  speed = vel.Length();
1608  rndScale = spawnArgs.GetAngles( "random", "15 15 0" );
1609  turn_max = spawnArgs.GetFloat( "turn_max", "180" ) / ( float )USERCMD_HZ;
1610  clamp_dist = spawnArgs.GetFloat( "clamp_dist", "256" );
1611  burstMode = spawnArgs.GetBool( "burstMode" );
1612  unGuided = false;
1613  burstDist = spawnArgs.GetFloat( "burstDist", "64" );
1614  burstVelocity = spawnArgs.GetFloat( "burstVelocity", "1.25" );
1615  UpdateVisuals();
1616 }
1617 
1618 #ifdef _D3XP
1619 void idGuidedProjectile::SetEnemy( idEntity *ent ) {
1620  enemy = ent;
1621 }
1622 void idGuidedProjectile::Event_SetEnemy(idEntity *ent) {
1623  SetEnemy(ent);
1624 }
1625 #endif
1626 
1627 /*
1628 ===============================================================================
1629 
1630 idSoulCubeMissile
1631 
1632 ===============================================================================
1633 */
1634 
1636 END_CLASS
1637 
1638 /*
1639 ================
1640 idSoulCubeMissile::Spawn( void )
1641 ================
1642 */
1643 void idSoulCubeMissile::Spawn( void ) {
1644  startingVelocity.Zero();
1645  endingVelocity.Zero();
1646  accelTime = 0.0f;
1647  launchTime = 0;
1648  killPhase = false;
1649  returnPhase = false;
1650  smokeKillTime = 0;
1651  smokeKill = NULL;
1652 }
1653 
1654 /*
1655 =================
1656 idSoulCubeMissile::~idSoulCubeMissile
1657 =================
1658 */
1660 }
1661 
1662 /*
1663 ================
1664 idSoulCubeMissile::Save
1665 ================
1666 */
1667 void idSoulCubeMissile::Save( idSaveGame *savefile ) const {
1668  savefile->WriteVec3( startingVelocity );
1669  savefile->WriteVec3( endingVelocity );
1670  savefile->WriteFloat( accelTime );
1671  savefile->WriteInt( launchTime );
1672  savefile->WriteBool( killPhase );
1673  savefile->WriteBool( returnPhase );
1674  savefile->WriteVec3( destOrg);
1675  savefile->WriteInt( orbitTime );
1676  savefile->WriteVec3( orbitOrg );
1677  savefile->WriteInt( smokeKillTime );
1678  savefile->WriteParticle( smokeKill );
1679 }
1680 
1681 /*
1682 ================
1683 idSoulCubeMissile::Restore
1684 ================
1685 */
1687  savefile->ReadVec3( startingVelocity );
1688  savefile->ReadVec3( endingVelocity );
1689  savefile->ReadFloat( accelTime );
1690  savefile->ReadInt( launchTime );
1691  savefile->ReadBool( killPhase );
1692  savefile->ReadBool( returnPhase );
1693  savefile->ReadVec3( destOrg);
1694  savefile->ReadInt( orbitTime );
1695  savefile->ReadVec3( orbitOrg );
1696  savefile->ReadInt( smokeKillTime );
1697  savefile->ReadParticle( smokeKill );
1698 }
1699 
1700 /*
1701 ================
1702 idSoulCubeMissile::KillTarget
1703 ================
1704 */
1706  idEntity *ownerEnt;
1707  const char *smokeName;
1708  idActor *act;
1709 
1710  ReturnToOwner();
1711  if ( enemy.GetEntity() && enemy.GetEntity()->IsType( idActor::Type ) ) {
1712  act = static_cast<idActor*>( enemy.GetEntity() );
1713  killPhase = true;
1714  orbitOrg = act->GetPhysics()->GetAbsBounds().GetCenter();
1716  smokeKillTime = 0;
1717  smokeName = spawnArgs.GetString( "smoke_kill" );
1718  if ( *smokeName != '\0' ) {
1719  smokeKill = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
1721  }
1722  ownerEnt = owner.GetEntity();
1723  if ( ( act->health > 0 ) && ownerEnt && ownerEnt->IsType( idPlayer::Type ) && ( ownerEnt->health > 0 ) && !act->spawnArgs.GetBool( "boss" ) ) {
1724  static_cast<idPlayer *>( ownerEnt )->GiveHealthPool( act->health );
1725  }
1726  act->Damage( this, owner.GetEntity(), dir, spawnArgs.GetString( "def_damage" ), 1.0f, INVALID_JOINT );
1727  act->GetAFPhysics()->SetTimeScale( 0.25 );
1728  StartSound( "snd_explode", SND_CHANNEL_BODY, 0, false, NULL );
1729  }
1730 }
1731 
1732 /*
1733 ================
1734 idSoulCubeMissile::Think
1735 ================
1736 */
1738  float pct;
1739  idVec3 seekPos;
1740  idEntity *ownerEnt;
1741 
1742  if ( state == LAUNCHED ) {
1743  if ( killPhase ) {
1744  // orbit the mob, cascading down
1745  if ( gameLocal.time < orbitTime + 1500 ) {
1748  }
1749  }
1750  } else {
1751  if ( accelTime && gameLocal.time < launchTime + accelTime * 1000 ) {
1752  pct = ( gameLocal.time - launchTime ) / ( accelTime * 1000 );
1753  speed = ( startingVelocity + ( startingVelocity + endingVelocity ) * pct ).Length();
1754  }
1755  }
1757  GetSeekPos( seekPos );
1758  if ( ( seekPos - physicsObj.GetOrigin() ).Length() < 32.0f ) {
1759  if ( returnPhase ) {
1760  StopSound( SND_CHANNEL_ANY, false );
1761  StartSound( "snd_return", SND_CHANNEL_BODY2, 0, false, NULL );
1762  Hide();
1763  PostEventSec( &EV_Remove, 2.0f );
1764 
1765  ownerEnt = owner.GetEntity();
1766  if ( ownerEnt && ownerEnt->IsType( idPlayer::Type ) ) {
1767  static_cast<idPlayer *>( ownerEnt )->SetSoulCubeProjectile( NULL );
1768  }
1769 
1770  state = FIZZLED;
1771  } else if ( !killPhase ){
1772  KillTarget( physicsObj.GetAxis()[0] );
1773  }
1774  }
1775  }
1776 }
1777 
1778 /*
1779 ================
1780 idSoulCubeMissile::GetSeekPos
1781 ================
1782 */
1784  if ( returnPhase && owner.GetEntity() && owner.GetEntity()->IsType( idActor::Type ) ) {
1785  idActor *act = static_cast<idActor*>( owner.GetEntity() );
1786  out = act->GetEyePosition();
1787  return;
1788  }
1789  if ( destOrg != vec3_zero ) {
1790  out = destOrg;
1791  return;
1792  }
1794 }
1795 
1796 
1797 /*
1798 ================
1799 idSoulCubeMissile::Event_ReturnToOwner
1800 ================
1801 */
1803  speed *= 0.65f;
1804  killPhase = false;
1805  returnPhase = true;
1806  smokeFlyTime = 0;
1807 }
1808 
1809 
1810 /*
1811 =================
1812 idSoulCubeMissile::Launch
1813 =================
1814 */
1815 void idSoulCubeMissile::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float launchPower, float dmgPower ) {
1816  idVec3 newStart;
1817  idVec3 offs;
1818  idEntity *ownerEnt;
1819 
1820  // push it out a little
1821  newStart = start + dir * spawnArgs.GetFloat( "launchDist" );
1822  offs = spawnArgs.GetVector( "launchOffset", "0 0 -4" );
1823  newStart += offs;
1824  idGuidedProjectile::Launch( newStart, dir, pushVelocity, timeSinceFire, launchPower, dmgPower );
1825  if ( enemy.GetEntity() == NULL || !enemy.GetEntity()->IsType( idActor::Type ) ) {
1826  destOrg = start + dir * 256.0f;
1827  } else {
1828  destOrg.Zero();
1829  }
1830  physicsObj.SetClipMask( 0 ); // never collide.. think routine will decide when to detonate
1831  startingVelocity = spawnArgs.GetVector( "startingVelocity", "15 0 0" );
1832  endingVelocity = spawnArgs.GetVector( "endingVelocity", "1500 0 0" );
1833  accelTime = spawnArgs.GetFloat( "accelTime", "5" );
1836  killPhase = false;
1837  UpdateVisuals();
1838 
1839  ownerEnt = owner.GetEntity();
1840  if ( ownerEnt && ownerEnt->IsType( idPlayer::Type ) ) {
1841  static_cast<idPlayer *>( ownerEnt )->SetSoulCubeProjectile( this );
1842  }
1843 
1844 }
1845 
1846 
1847 /*
1848 ===============================================================================
1849 
1850 idBFGProjectile
1851 
1852 ===============================================================================
1853 */
1854 const idEventDef EV_RemoveBeams( "<removeBeams>", NULL );
1855 
1857  EVENT( EV_RemoveBeams, idBFGProjectile::Event_RemoveBeams )
1858 END_CLASS
1859 
1860 
1861 /*
1862 =================
1863 idBFGProjectile::idBFGProjectile
1864 =================
1865 */
1867  memset( &secondModel, 0, sizeof( secondModel ) );
1868  secondModelDefHandle = -1;
1869  nextDamageTime = 0;
1870 }
1871 
1872 /*
1873 =================
1874 idBFGProjectile::~idBFGProjectile
1875 =================
1876 */
1878  FreeBeams();
1879 
1880  if ( secondModelDefHandle >= 0 ) {
1882  secondModelDefHandle = -1;
1883  }
1884 }
1885 
1886 /*
1887 ================
1888 idBFGProjectile::Spawn
1889 ================
1890 */
1892  beamTargets.Clear();
1893  memset( &secondModel, 0, sizeof( secondModel ) );
1894  secondModelDefHandle = -1;
1895  const char *temp = spawnArgs.GetString( "model_two" );
1896  if ( temp && *temp ) {
1903  secondModel.noSelfShadow = true;
1904  secondModel.noShadow = true;
1905  }
1906  nextDamageTime = 0;
1907  damageFreq = NULL;
1908 }
1909 
1910 /*
1911 ================
1912 idBFGProjectile::Save
1913 ================
1914 */
1915 void idBFGProjectile::Save( idSaveGame *savefile ) const {
1916  int i;
1917 
1918  savefile->WriteInt( beamTargets.Num() );
1919  for ( i = 0; i < beamTargets.Num(); i++ ) {
1920  beamTargets[i].target.Save( savefile );
1921  savefile->WriteRenderEntity( beamTargets[i].renderEntity );
1922  savefile->WriteInt( beamTargets[i].modelDefHandle );
1923  }
1924 
1925  savefile->WriteRenderEntity( secondModel );
1926  savefile->WriteInt( secondModelDefHandle );
1927  savefile->WriteInt( nextDamageTime );
1928  savefile->WriteString( damageFreq );
1929 }
1930 
1931 /*
1932 ================
1933 idBFGProjectile::Restore
1934 ================
1935 */
1937  int i, num;
1938 
1939  savefile->ReadInt( num );
1940  beamTargets.SetNum( num );
1941  for ( i = 0; i < num; i++ ) {
1942  beamTargets[i].target.Restore( savefile );
1943  savefile->ReadRenderEntity( beamTargets[i].renderEntity );
1944  savefile->ReadInt( beamTargets[i].modelDefHandle );
1945 
1946  if ( beamTargets[i].modelDefHandle >= 0 ) {
1947  beamTargets[i].modelDefHandle = gameRenderWorld->AddEntityDef( &beamTargets[i].renderEntity );
1948  }
1949  }
1950 
1951  savefile->ReadRenderEntity( secondModel );
1952  savefile->ReadInt( secondModelDefHandle );
1953  savefile->ReadInt( nextDamageTime );
1954  savefile->ReadString( damageFreq );
1955 
1956  if ( secondModelDefHandle >= 0 ) {
1958  }
1959 }
1960 
1961 /*
1962 =================
1963 idBFGProjectile::FreeBeams
1964 =================
1965 */
1967  for ( int i = 0; i < beamTargets.Num(); i++ ) {
1968  if ( beamTargets[i].modelDefHandle >= 0 ) {
1970  beamTargets[i].modelDefHandle = -1;
1971  }
1972  }
1973 
1974  idPlayer *player = gameLocal.GetLocalPlayer();
1975  if ( player ) {
1976  player->playerView.EnableBFGVision( false );
1977  }
1978 }
1979 
1980 /*
1981 ================
1982 idBFGProjectile::Think
1983 ================
1984 */
1986  if ( state == LAUNCHED ) {
1987 
1988  // update beam targets
1989  for ( int i = 0; i < beamTargets.Num(); i++ ) {
1990  if ( beamTargets[i].target.GetEntity() == NULL ) {
1991  continue;
1992  }
1993  idPlayer *player = ( beamTargets[i].target.GetEntity()->IsType( idPlayer::Type ) ) ? static_cast<idPlayer*>( beamTargets[i].target.GetEntity() ) : NULL;
1994 #ifdef _D3XP
1995  // Major hack for end boss. :(
1996  idAnimatedEntity *beamEnt;
1997  idVec3 org;
1998  bool forceDamage = false;
1999 
2000  beamEnt = static_cast<idAnimatedEntity*>(beamTargets[i].target.GetEntity());
2001  if ( !idStr::Cmp( beamEnt->GetEntityDefName(), "monster_boss_d3xp_maledict" ) ) {
2002  SetTimeState ts( beamEnt->timeGroup );
2003  idMat3 temp;
2004  jointHandle_t bodyJoint;
2005 
2006  bodyJoint = beamEnt->GetAnimator()->GetJointHandle( "Chest1" );
2007  beamEnt->GetJointWorldTransform( bodyJoint, gameLocal.time, org, temp );
2008 
2009  forceDamage = true;
2010  } else {
2011  org = beamEnt->GetPhysics()->GetAbsBounds().GetCenter();
2012  }
2013 #else
2014  idVec3 org = beamTargets[i].target.GetEntity()->GetPhysics()->GetAbsBounds().GetCenter();
2015 #endif
2016  beamTargets[i].renderEntity.origin = GetPhysics()->GetOrigin();
2017  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] = org.x;
2018  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] = org.y;
2019  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BEAM_END_Z ] = org.z;
2020  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_RED ] =
2021  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_GREEN ] =
2022  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BLUE ] =
2023  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 1.0f;
2024  if ( gameLocal.time > nextDamageTime ) {
2025  bool bfgVision = true;
2026 #ifdef _D3XP
2027  if ( damageFreq && *(const char *)damageFreq && beamTargets[i].target.GetEntity() && ( forceDamage || beamTargets[i].target.GetEntity()->CanDamage( GetPhysics()->GetOrigin(), org ) ) ) {
2028 #else
2029  if ( damageFreq && *(const char *)damageFreq && beamTargets[i].target.GetEntity() && beamTargets[i].target.GetEntity()->CanDamage( GetPhysics()->GetOrigin(), org ) ) {
2030 #endif
2031  org = beamTargets[i].target.GetEntity()->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
2032  org.Normalize();
2033  beamTargets[i].target.GetEntity()->Damage( this, owner.GetEntity(), org, damageFreq, ( damagePower ) ? damagePower : 1.0f, INVALID_JOINT );
2034  } else {
2035  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_RED ] =
2036  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_GREEN ] =
2037  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BLUE ] =
2038  beamTargets[i].renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 0.0f;
2039  bfgVision = false;
2040  }
2041  if ( player ) {
2042  player->playerView.EnableBFGVision( bfgVision );
2043  }
2044  nextDamageTime = gameLocal.time + BFG_DAMAGE_FREQUENCY;
2045  }
2047  }
2048 
2049  if ( secondModelDefHandle >= 0 ) {
2052  }
2053 
2054  idAngles ang;
2055 
2056  ang.pitch = ( gameLocal.time & 4095 ) * 360.0f / -4096.0f;
2057  ang.yaw = ang.pitch;
2058  ang.roll = 0.0f;
2059  SetAngles( ang );
2060 
2061  ang.pitch = ( gameLocal.time & 2047 ) * 360.0f / -2048.0f;
2062  ang.yaw = ang.pitch;
2063  ang.roll = 0.0f;
2064  secondModel.axis = ang.ToMat3();
2065 
2066  UpdateVisuals();
2067  }
2068 
2070 }
2071 
2072 /*
2073 =================
2074 idBFGProjectile::Launch
2075 =================
2076 */
2077 void idBFGProjectile::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float power, const float dmgPower ) {
2078  idProjectile::Launch( start, dir, pushVelocity, 0.0f, power, dmgPower );
2079 
2080  // dmgPower * radius is the target acquisition area
2081  // acquisition should make sure that monsters are not dormant
2082  // which will cut down on hitting monsters not actively fighting
2083  // but saves on the traces making sure they are visible
2084  // damage is not applied until the projectile explodes
2085 
2086  idEntity * ent;
2087  idEntity * entityList[ MAX_GENTITIES ];
2088  int numListedEntities;
2089  idBounds bounds;
2090  idVec3 damagePoint;
2091 
2092  float radius;
2093  spawnArgs.GetFloat( "damageRadius", "512", radius );
2094  bounds = idBounds( GetPhysics()->GetOrigin() ).Expand( radius );
2095 
2096  float beamWidth = spawnArgs.GetFloat( "beam_WidthFly" );
2097  const char *skin = spawnArgs.GetString( "skin_beam" );
2098 
2099  memset( &secondModel, 0, sizeof( secondModel ) );
2100  secondModelDefHandle = -1;
2101  const char *temp = spawnArgs.GetString( "model_two" );
2102  if ( temp && *temp ) {
2109  secondModel.noSelfShadow = true;
2110  secondModel.noShadow = true;
2114  }
2115 
2116  idVec3 delta( 15.0f, 15.0f, 15.0f );
2117  //physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, physicsObj.GetAxis().ToAngles(), delta, ang_zero );
2118 
2119  // get all entities touching the bounds
2120  numListedEntities = gameLocal.clip.EntitiesTouchingBounds( bounds, CONTENTS_BODY, entityList, MAX_GENTITIES );
2121  for ( int e = 0; e < numListedEntities; e++ ) {
2122  ent = entityList[ e ];
2123  assert( ent );
2124 
2125  if ( ent == this || ent == owner.GetEntity() || ent->IsHidden() || !ent->IsActive() || !ent->fl.takedamage || ent->health <= 0 || !ent->IsType( idActor::Type ) ) {
2126  continue;
2127  }
2128 
2129  if ( !ent->CanDamage( GetPhysics()->GetOrigin(), damagePoint ) ) {
2130  continue;
2131  }
2132 
2133  if ( ent->IsType( idPlayer::Type ) ) {
2134  idPlayer *player = static_cast<idPlayer*>( ent );
2135  player->playerView.EnableBFGVision( true );
2136  }
2137 
2138  beamTarget_t bt;
2139  memset( &bt.renderEntity, 0, sizeof( renderEntity_t ) );
2141  bt.renderEntity.axis = GetPhysics()->GetAxis();
2149  bt.renderEntity.callback = NULL;
2150  bt.renderEntity.numJoints = 0;
2151  bt.renderEntity.joints = NULL;
2152  bt.renderEntity.bounds.Clear();
2154  bt.target = ent;
2156  beamTargets.Append( bt );
2157  }
2158 
2159 #ifdef _D3XP
2160  // Major hack for end boss. :(
2161  idAnimatedEntity *maledict = static_cast<idAnimatedEntity*>(gameLocal.FindEntity( "monster_boss_d3xp_maledict_1" ));
2162 
2163  if ( maledict ) {
2164  SetTimeState ts( maledict->timeGroup );
2165 
2166  idVec3 realPoint;
2167  idMat3 temp;
2168  float dist;
2169  jointHandle_t bodyJoint;
2170 
2171  bodyJoint = maledict->GetAnimator()->GetJointHandle( "Chest1" );
2172  maledict->GetJointWorldTransform( bodyJoint, gameLocal.time, realPoint, temp );
2173 
2174  dist = idVec3( realPoint - GetPhysics()->GetOrigin() ).Length();
2175 
2176  if ( dist < radius ) {
2177  beamTarget_t bt;
2178  memset( &bt.renderEntity, 0, sizeof( renderEntity_t ) );
2180  bt.renderEntity.axis = GetPhysics()->GetAxis();
2188  bt.renderEntity.callback = NULL;
2189  bt.renderEntity.numJoints = 0;
2190  bt.renderEntity.joints = NULL;
2191  bt.renderEntity.bounds.Clear();
2193  bt.target = maledict;
2195  beamTargets.Append( bt );
2196 
2197  numListedEntities++;
2198  }
2199  }
2200 #endif
2201 
2202  if ( numListedEntities ) {
2203  StartSound( "snd_beam", SND_CHANNEL_BODY2, 0, false, NULL );
2204  }
2205  damageFreq = spawnArgs.GetString( "def_damageFreq" );
2206  nextDamageTime = gameLocal.time + BFG_DAMAGE_FREQUENCY;
2207  UpdateVisuals();
2208 }
2209 
2210 /*
2211 ================
2212 idProjectile::Event_RemoveBeams
2213 ================
2214 */
2216  FreeBeams();
2217  UpdateVisuals();
2218 }
2219 
2220 /*
2221 ================
2222 idProjectile::Explode
2223 ================
2224 */
2225 void idBFGProjectile::Explode( const trace_t &collision, idEntity *ignore ) {
2226  int i;
2227  idVec3 dmgPoint;
2228  idVec3 dir;
2229  float beamWidth;
2230  float damageScale;
2231  const char *damage;
2232  idPlayer * player;
2233  idEntity * ownerEnt;
2234 
2235  ownerEnt = owner.GetEntity();
2236  if ( ownerEnt && ownerEnt->IsType( idPlayer::Type ) ) {
2237  player = static_cast< idPlayer * >( ownerEnt );
2238  } else {
2239  player = NULL;
2240  }
2241 
2242  beamWidth = spawnArgs.GetFloat( "beam_WidthExplode" );
2243  damage = spawnArgs.GetString( "def_damage" );
2244 
2245  for ( i = 0; i < beamTargets.Num(); i++ ) {
2246  if ( ( beamTargets[i].target.GetEntity() == NULL ) || ( ownerEnt == NULL ) ) {
2247  continue;
2248  }
2249 
2250  if ( !beamTargets[i].target.GetEntity()->CanDamage( GetPhysics()->GetOrigin(), dmgPoint ) ) {
2251  continue;
2252  }
2253 
2254  beamTargets[i].renderEntity.shaderParms[SHADERPARM_BEAM_WIDTH] = beamWidth;
2255 
2256  // if the hit entity takes damage
2257  if ( damagePower ) {
2258  damageScale = damagePower;
2259  } else {
2260  damageScale = 1.0f;
2261  }
2262 
2263  // if the projectile owner is a player
2264  if ( player ) {
2265  // if the projectile hit an actor
2266  if ( beamTargets[i].target.GetEntity()->IsType( idActor::Type ) ) {
2267  player->SetLastHitTime( gameLocal.time );
2268  player->AddProjectileHits( 1 );
2269  damageScale *= player->PowerUpModifier( PROJECTILE_DAMAGE );
2270  }
2271  }
2272 
2273  if ( damage[0] && ( beamTargets[i].target.GetEntity()->entityNumber > gameLocal.numClients - 1 ) ) {
2274  dir = beamTargets[i].target.GetEntity()->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
2275  dir.Normalize();
2276  beamTargets[i].target.GetEntity()->Damage( this, ownerEnt, dir, damage, damageScale, ( collision.c.id < 0 ) ? CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id ) : INVALID_JOINT );
2277  }
2278  }
2279 
2280  if ( secondModelDefHandle >= 0 ) {
2282  secondModelDefHandle = -1;
2283  }
2284 
2285  if ( ignore == NULL ) {
2287  }
2288 
2289  if ( !gameLocal.isClient ) {
2290  if ( ignore != NULL ) {
2291  PostEventMS( &EV_RemoveBeams, 750 );
2292  } else {
2293  PostEventMS( &EV_RemoveBeams, 0 );
2294  }
2295  }
2296 
2297  return idProjectile::Explode( collision, ignore );
2298 }
2299 
2300 
2301 /*
2302 ===============================================================================
2303 
2304  idDebris
2305 
2306 ===============================================================================
2307 */
2308 
2310 EVENT( EV_Explode, idDebris::Event_Explode )
2311 EVENT( EV_Fizzle, idDebris::Event_Fizzle )
2312 END_CLASS
2313 
2314 /*
2315 ================
2316 idDebris::Spawn
2317 ================
2318 */
2319 void idDebris::Spawn( void ) {
2320  owner = NULL;
2321  smokeFly = NULL;
2322  smokeFlyTime = 0;
2323 }
2324 
2325 /*
2326 ================
2327 idDebris::Create
2328 ================
2329 */
2330 void idDebris::Create( idEntity *owner, const idVec3 &start, const idMat3 &axis ) {
2331  Unbind();
2332  GetPhysics()->SetOrigin( start );
2333  GetPhysics()->SetAxis( axis );
2334  GetPhysics()->SetContents( 0 );
2335  this->owner = owner;
2336  smokeFly = NULL;
2337  smokeFlyTime = 0;
2338  sndBounce = NULL;
2339 #ifdef _D3XP
2340  noGrab = true;
2341 #endif
2342  UpdateVisuals();
2343 }
2344 
2345 /*
2346 =================
2347 idDebris::idDebris
2348 =================
2349 */
2351  owner = NULL;
2352  smokeFly = NULL;
2353  smokeFlyTime = 0;
2354  sndBounce = NULL;
2355 }
2356 
2357 /*
2358 =================
2359 idDebris::~idDebris
2360 =================
2361 */
2363 }
2364 
2365 /*
2366 =================
2367 idDebris::Save
2368 =================
2369 */
2370 void idDebris::Save( idSaveGame *savefile ) const {
2371  owner.Save( savefile );
2372 
2373  savefile->WriteStaticObject( physicsObj );
2374 
2375  savefile->WriteParticle( smokeFly );
2376  savefile->WriteInt( smokeFlyTime );
2377  savefile->WriteSoundShader( sndBounce );
2378 }
2379 
2380 /*
2381 =================
2382 idDebris::Restore
2383 =================
2384 */
2386  owner.Restore( savefile );
2387 
2388  savefile->ReadStaticObject( physicsObj );
2390 
2391  savefile->ReadParticle( smokeFly );
2392  savefile->ReadInt( smokeFlyTime );
2393  savefile->ReadSoundShader( sndBounce );
2394 }
2395 
2396 /*
2397 =================
2398 idDebris::Launch
2399 =================
2400 */
2401 void idDebris::Launch( void ) {
2402  float fuse;
2403  idVec3 velocity;
2404  idAngles angular_velocity;
2405  float linear_friction;
2406  float angular_friction;
2407  float contact_friction;
2408  float bounce;
2409  float mass;
2410  float gravity;
2411  idVec3 gravVec;
2412  bool randomVelocity;
2413  idMat3 axis;
2414 
2416 
2417  spawnArgs.GetVector( "velocity", "0 0 0", velocity );
2418  spawnArgs.GetAngles( "angular_velocity", "0 0 0", angular_velocity );
2419 
2420  linear_friction = spawnArgs.GetFloat( "linear_friction" );
2421  angular_friction = spawnArgs.GetFloat( "angular_friction" );
2422  contact_friction = spawnArgs.GetFloat( "contact_friction" );
2423  bounce = spawnArgs.GetFloat( "bounce" );
2424  mass = spawnArgs.GetFloat( "mass" );
2425  gravity = spawnArgs.GetFloat( "gravity" );
2426  fuse = spawnArgs.GetFloat( "fuse" );
2427  randomVelocity = spawnArgs.GetBool ( "random_velocity" );
2428 
2429  if ( mass <= 0 ) {
2430  gameLocal.Error( "Invalid mass on '%s'\n", GetEntityDefName() );
2431  }
2432 
2433  if ( randomVelocity ) {
2434  velocity.x *= gameLocal.random.RandomFloat() + 0.5f;
2435  velocity.y *= gameLocal.random.RandomFloat() + 0.5f;
2436  velocity.z *= gameLocal.random.RandomFloat() + 0.5f;
2437  }
2438 
2439  if ( health ) {
2440  fl.takedamage = true;
2441  }
2442 
2443  gravVec = gameLocal.GetGravity();
2444  gravVec.NormalizeFast();
2445  axis = GetPhysics()->GetAxis();
2446 
2447  Unbind();
2448 
2449  physicsObj.SetSelf( this );
2450 
2451  // check if a clip model is set
2452  const char *clipModelName;
2453  idTraceModel trm;
2454  spawnArgs.GetString( "clipmodel", "", &clipModelName );
2455  if ( !clipModelName[0] ) {
2456  clipModelName = spawnArgs.GetString( "model" ); // use the visual model
2457  }
2458 
2459  // load the trace model
2460  if ( !collisionModelManager->TrmFromModel( clipModelName, trm ) ) {
2461  // default to a box
2463  } else {
2464  physicsObj.SetClipModel( new idClipModel( trm ), 1.0f );
2465  }
2466 
2468  physicsObj.SetMass( mass );
2469  physicsObj.SetFriction( linear_friction, angular_friction, contact_friction );
2470  if ( contact_friction == 0.0f ) {
2472  }
2473  physicsObj.SetBouncyness( bounce );
2474  physicsObj.SetGravity( gravVec * gravity );
2475  physicsObj.SetContents( 0 );
2477  physicsObj.SetLinearVelocity( axis[ 0 ] * velocity[ 0 ] + axis[ 1 ] * velocity[ 1 ] + axis[ 2 ] * velocity[ 2 ] );
2478  physicsObj.SetAngularVelocity( angular_velocity.ToAngularVelocity() * axis );
2479  physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
2480  physicsObj.SetAxis( axis );
2481  SetPhysics( &physicsObj );
2482 
2483  if ( !gameLocal.isClient ) {
2484  if ( fuse <= 0 ) {
2485  // run physics for 1 second
2486  RunPhysics();
2487  PostEventMS( &EV_Remove, 0 );
2488  } else if ( spawnArgs.GetBool( "detonate_on_fuse" ) ) {
2489  if ( fuse < 0.0f ) {
2490  fuse = 0.0f;
2491  }
2492  RunPhysics();
2493  PostEventSec( &EV_Explode, fuse );
2494  } else {
2495  if ( fuse < 0.0f ) {
2496  fuse = 0.0f;
2497  }
2498  PostEventSec( &EV_Fizzle, fuse );
2499  }
2500  }
2501 
2502  StartSound( "snd_fly", SND_CHANNEL_BODY, 0, false, NULL );
2503 
2504  smokeFly = NULL;
2505  smokeFlyTime = 0;
2506  const char *smokeName = spawnArgs.GetString( "smoke_fly" );
2507  if ( *smokeName != '\0' ) {
2508  smokeFly = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
2511  }
2512 
2513  const char *sndName = spawnArgs.GetString( "snd_bounce" );
2514  if ( *sndName != '\0' ) {
2515  sndBounce = declManager->FindSound( sndName );
2516  }
2517 
2518  UpdateVisuals();
2519 }
2520 
2521 /*
2522 ================
2523 idDebris::Think
2524 ================
2525 */
2526 void idDebris::Think( void ) {
2527 
2528  // run physics
2529  RunPhysics();
2530  Present();
2531 
2532  if ( smokeFly && smokeFlyTime ) {
2534  smokeFlyTime = 0;
2535  }
2536  }
2537 }
2538 
2539 /*
2540 ================
2541 idDebris::Killed
2542 ================
2543 */
2544 void idDebris::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
2545  if ( spawnArgs.GetBool( "detonate_on_death" ) ) {
2546  Explode();
2547  } else {
2548  Fizzle();
2549  }
2550 }
2551 
2552 /*
2553 =================
2554 idDebris::Collide
2555 =================
2556 */
2557 bool idDebris::Collide( const trace_t &collision, const idVec3 &velocity ) {
2558  if ( sndBounce != NULL ) {
2559  StartSoundShader( sndBounce, SND_CHANNEL_BODY, 0, false, NULL );
2560  }
2561  sndBounce = NULL;
2562  return false;
2563 }
2564 
2565 
2566 /*
2567 ================
2568 idDebris::Fizzle
2569 ================
2570 */
2571 void idDebris::Fizzle( void ) {
2572  if ( IsHidden() ) {
2573  // already exploded
2574  return;
2575  }
2576 
2577  StopSound( SND_CHANNEL_ANY, false );
2578  StartSound( "snd_fizzle", SND_CHANNEL_BODY, 0, false, NULL );
2579 
2580  // fizzle FX
2581  const char *smokeName = spawnArgs.GetString( "smoke_fuse" );
2582  if ( *smokeName != '\0' ) {
2583  smokeFly = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
2586  }
2587 
2588  fl.takedamage = false;
2589  physicsObj.SetContents( 0 );
2591 
2592  Hide();
2593 
2594  if ( gameLocal.isClient ) {
2595  return;
2596  }
2597 
2598  CancelEvents( &EV_Fizzle );
2599  PostEventMS( &EV_Remove, 0 );
2600 }
2601 
2602 /*
2603 ================
2604 idDebris::Explode
2605 ================
2606 */
2607 void idDebris::Explode( void ) {
2608  if ( IsHidden() ) {
2609  // already exploded
2610  return;
2611  }
2612 
2613  StopSound( SND_CHANNEL_ANY, false );
2614  StartSound( "snd_explode", SND_CHANNEL_BODY, 0, false, NULL );
2615 
2616  Hide();
2617 
2618  // these must not be "live forever" particle systems
2619  smokeFly = NULL;
2620  smokeFlyTime = 0;
2621  const char *smokeName = spawnArgs.GetString( "smoke_detonate" );
2622  if ( *smokeName != '\0' ) {
2623  smokeFly = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
2626  }
2627 
2628  fl.takedamage = false;
2629  physicsObj.SetContents( 0 );
2631 
2632  CancelEvents( &EV_Explode );
2633  PostEventMS( &EV_Remove, 0 );
2634 }
2635 
2636 /*
2637 ================
2638 idDebris::Event_Explode
2639 ================
2640 */
2642  Explode();
2643 }
2644 
2645 /*
2646 ================
2647 idDebris::Event_Fizzle
2648 ================
2649 */
2651  Fizzle();
2652 }
virtual const idVec3 & GetOrigin(int id=0) const =0
jointHandle_t
Definition: Model.h:156
idPlayer * GetLocalPlayer() const
void AddDefaultDamageEffect(const trace_t &collision, const idVec3 &velocity)
Definition: Projectile.cpp:696
void SetAngularVelocity(const idVec3 &newAngularVelocity, int id=0)
void SetClipModel(idClipModel *model, float density, int id=0, bool freeOld=true)
byte color[4]
Definition: MegaTexture.cpp:54
renderEntity_t renderEntity
Definition: Entity.h:371
void BeginWriting(void)
Definition: BitMsg.h:265
bool TracePoint(trace_t &results, const idVec3 &start, const idVec3 &end, int contentMask, const idEntity *passEntity)
Definition: Clip.h:333
idVec3 lightColor
Definition: Projectile.h:108
float GetFloat(const char *key, const char *defaultString="0") const
Definition: Dict.h:248
int lightEndTime
Definition: Projectile.h:107
idMat3 ToMat3(void) const
Definition: Vector.cpp:195
virtual bool TrmFromModel(const char *modelName, idTraceModel &trm)=0
static void DefaultDamageEffect(idEntity *soundEnt, const idDict &projectileDef, const trace_t &collision, const idVec3 &velocity)
Definition: Projectile.cpp:656
virtual void ReadFromSnapshot(const idBitMsgDelta &msg)
void WriteString(const char *string)
Definition: SaveGame.cpp:231
float Normalize(void)
Definition: Vector.h:646
bool EmitSmoke(const idDeclParticle *smoke, const int startTime, const float diversity, const idVec3 &origin, const idMat3 &axis, int timeGroup)
int GetInt(const char *key, const char *defaultString="0") const
Definition: Dict.h:252
void SetLinearVelocity(const idVec3 &newLinearVelocity, int id=0)
bool PostEventSec(const idEventDef *ev, float time)
Definition: Class.cpp:747
virtual void WriteToSnapshot(idBitMsgDelta &msg) const
void ReadSoundShader(const idSoundShader *&shader)
Definition: SaveGame.cpp:1196
assert(prefInfo.fullscreenBtn)
virtual const idSoundShader * FindSound(const char *name, bool makeDefault=true)=0
const idDict * FindEntityDefDict(const char *name, bool makeDefault=true) const
void ReadParticle(const idDeclParticle *&particle)
Definition: SaveGame.cpp:1164
void Restore(idRestoreGame *savefile)
Definition: Game_local.h:661
#define CLIPMODEL_ID_TO_JOINT_HANDLE(id)
Definition: Clip.h:40
idVec3 startingVelocity
Definition: Projectile.h:196
const int SHADERPARM_DIVERSITY
Definition: RenderWorld.h:52
int Cmp(const char *text) const
Definition: Str.h:652
virtual void FreeLightDef(qhandle_t lightHandle)=0
idMat3 mat3_identity(idVec3(1, 0, 0), idVec3(0, 1, 0), idVec3(0, 0, 1))
virtual void SetContents(int contents, int id=-1)=0
void Event_Touch(idEntity *other, trace_t *trace)
idVec3 GetCenter(void) const
Definition: Bounds.h:211
static bool ClientPredictionCollide(idEntity *soundEnt, const idDict &projectileDef, const trace_t &collision, const idVec3 &velocity, bool addDamageEffect)
idClip clip
Definition: Game_local.h:296
float damagePower
Definition: Projectile.h:101
virtual void Launch(const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire=0.0f, const float launchPower=1.0f, const float dmgPower=1.0f)
Definition: Projectile.cpp:306
struct idEntity::entityFlags_s fl
#define MAX_GENTITIES
Definition: Game_local.h:83
void Bind(idEntity *master, bool orientated)
Definition: Entity.cpp:1896
type * GetEntity(void) const
Definition: Game_local.h:695
const int MAX_EVENT_PARAM_SIZE
Definition: Game_local.h:132
virtual void SetClipBox(const idBounds &bounds, float density)
Definition: Physics.cpp:67
idSmokeParticles * smokeParticles
Definition: Game_local.h:307
const int SHADERPARM_BEAM_END_Z
Definition: RenderWorld.h:65
virtual bool ClientReceiveEvent(int event, int time, const idBitMsg &msg)
void SetNum(int newnum, bool resize=true)
Definition: List.h:289
const idEventDef EV_Activate("activate","e")
void Event_Fizzle(void)
virtual qhandle_t AddEntityDef(const renderEntity_t *re)=0
void Explode(void)
GLint location
Definition: glext.h:3631
void Fizzle(void)
idRandom random
Definition: Game_local.h:291
projectileState_t state
Definition: Projectile.h:129
void SetAxis(const idMat3 &axis)
Definition: Entity.cpp:2796
renderEntity_t secondModel
Definition: Projectile.h:232
void void void void void Error(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:783
const idDeclParticle * smokeFly
Definition: Projectile.h:113
bool isMultiplayer
Definition: Game_local.h:325
idPhysics_RigidBody physicsObj
Definition: Projectile.h:111
idAngles GetAngles(const char *key, const char *defaultString=NULL) const
Definition: Dict.h:278
bool IsType(const idTypeInfo &c) const
Definition: Class.h:337
void WriteFloat(float f)
Definition: BitMsg.h:299
void Set(const float x, const float y, const float z)
Definition: Vector.h:409
int ClientRemapDecl(declType_t type, int index)
void Write(const void *buffer, int len)
Definition: SaveGame.cpp:159
void SetAngles(const idAngles &ang)
Definition: Entity.cpp:2812
idEntity * FindEntity(const char *name) const
virtual void UnlinkClip(void)=0
int ReadLong(void) const
Definition: BitMsg.h:375
float z
Definition: Vector.h:320
#define MASK_SOLID
Definition: Game_local.h:735
idVec3 GetEyePosition(void) const
int GetMSec() const
Definition: Game_local.h:505
float PowerUpModifier(int type)
bool ProcessEvent(const idEventDef *ev)
Definition: Class.cpp:858
renderLight_t renderLight
Definition: Projectile.h:103
Definition: Mover.h:377
void WriteBits(int value, int numBits)
Definition: BitMsg.cpp:648
const int RB_VELOCITY_MANTISSA_BITS
void RadiusDamage(const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignoreDamage, idEntity *ignorePush, const char *damageDefName, float dmgPower=1.0f)
jointHandle_t GetJointHandle(const char *name) const
virtual void GetSeekPos(idVec3 &out)
idEntityPtr< idEntity > owner
Definition: Projectile.h:89
bool isClient
Definition: Game_local.h:327
Definition: Vector.h:316
virtual void Explode(const trace_t &collision, idEntity *ignore)
case const float
Definition: Callbacks.cpp:62
void ReadBool(bool &value)
Definition: SaveGame.cpp:976
idAngles ang_zero(0.0f, 0.0f, 0.0f)
bool isServer
Definition: Game_local.h:326
virtual const idVec3 & GetLinearVelocity(int id=0) const =0
const int SHADERPARM_BEAM_END_Y
Definition: RenderWorld.h:64
void WriteStaticObject(const idClass &obj)
Definition: SaveGame.cpp:348
static float Sqrt(float x)
Definition: Math.h:302
const idEventDef EV_RadiusDamage("<radiusdmg>","e")
const idVec3 & GetOrigin(int id=0) const
const int SHADERPARM_GREEN
Definition: RenderWorld.h:47
int team
Definition: Actor.h:115
void Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location)
bool SetSpawnId(int id)
Definition: Game_local.h:676
void Spawn(void)
Definition: Projectile.cpp:104
idAngles & Normalize180(void)
Definition: Angles.cpp:70
virtual void GetSeekPos(idVec3 &out)
float thrust
Definition: Projectile.h:99
void Clear(void)
Definition: Bounds.h:201
void KillTarget(const idVec3 &dir)
void Create(idEntity *owner, const idVec3 &start, const idVec3 &dir)
Definition: Projectile.cpp:218
virtual qhandle_t AddLightDef(const renderLight_t *rlight)=0
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
void ReadFromSnapshot(const idBitMsgDelta &msg)
void SetSoundVolume(float volume)
Definition: Entity.cpp:1740
const int SHADERPARM_BEAM_END_X
Definition: RenderWorld.h:63
void WriteFloat(float f)
Definition: BitMsg.h:558
GLdouble s
Definition: glext.h:2935
void Event_Fizzle(void)
GLenum GLsizei len
Definition: glext.h:3472
void Set(const char *key, const char *value)
Definition: Dict.cpp:275
struct idProjectile::projectileFlags_s projectileFlags
virtual void ApplyImpulse(idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse)
Definition: Entity.cpp:2887
bool cinematic
Definition: Entity.h:127
int ReadBits(int numBits) const
Definition: BitMsg.cpp:709
const int SHADERPARM_BEAM_WIDTH
Definition: RenderWorld.h:66
float x
Definition: Vector.h:318
idDict spawnArgs
Definition: Entity.h:122
const int RB_VELOCITY_EXPONENT_BITS
idEntityPtr< idEntity > target
Definition: Projectile.h:210
GLenum GLint x
Definition: glext.h:2849
int i
Definition: process.py:33
void LittleBitField(void *bp, int elsize)
Definition: Lib.cpp:286
void SetLastHitTime(int time)
contactInfo_t c
idForce_Constant thruster
Definition: Projectile.h:110
deferredEntityCallback_t callback
Definition: RenderWorld.h:96
GLuint GLuint num
Definition: glext.h:5390
void WriteVec3(const idVec3 &vec)
Definition: SaveGame.cpp:253
bool HasChanged(void) const
Definition: BitMsg.h:534
void ReadRenderEntity(renderEntity_t &renderEntity)
Definition: SaveGame.cpp:1269
virtual void SetModel(const char *modelname)
Definition: Entity.cpp:1150
void Restore(idRestoreGame *savefile)
void WriteSoundShader(const idSoundShader *shader)
Definition: SaveGame.cpp:445
idCVar g_testParticleName("g_testParticleName","", CVAR_GAME,"name of the particle being tested by the particle editor")
const int SHADERPARM_ALPHA
Definition: RenderWorld.h:49
#define EVENT(event, function)
Definition: Class.h:53
idMat3 viewAxis
Definition: Actor.h:117
const idEventDef EV_Explode("<explode>", NULL)
void Init(byte *data, int length)
Definition: BitMsg.h:155
virtual void Think(void)
Definition: Projectile.cpp:476
int EntitiesTouchingBounds(const idBounds &bounds, int contentMask, idEntity **entityList, int maxCount) const
Definition: Clip.cpp:833
float fraction
idVec3 endpos
void WriteBool(const bool value)
Definition: SaveGame.cpp:222
idGameEdit * gameEdit
Definition: GameEdit.cpp:668
float shaderParms[MAX_ENTITY_SHADER_PARMS]
Definition: RenderWorld.h:201
virtual void Launch(const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire=0.0f, const float power=1.0f, const float dmgPower=1.0f)
bool IsHidden(void) const
Definition: Entity.cpp:1217
idEntity * SpawnEntityType(const idTypeInfo &classdef, const idDict *args=NULL, bool bIsClientReadSnapshot=false)
qhandle_t secondModelDefHandle
Definition: Projectile.h:233
bool StartSoundShader(const idSoundShader *shader, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length)
Definition: Entity.cpp:1656
const int SHADERPARM_BLUE
Definition: RenderWorld.h:48
class idPlayerView playerView
Definition: Player.h:251
int ServerRemapDecl(int clientNum, declType_t type, int index)
int RandomInt(void)
Definition: Random.h:70
virtual void Show(void)
Definition: Entity.cpp:1239
idVec3 lightOffset
Definition: Projectile.h:105
idVec3 GetEyePosition(void) const
Definition: Actor.cpp:1454
idEntityPtr< idEntity > enemy
Definition: Projectile.h:163
void SetSelf(idEntity *e)
virtual void FreeEntityDef(qhandle_t entityHandle)=0
const idMaterial * material
virtual void AddDamageEffect(const trace_t &collision, const idVec3 &velocity, const char *damageDefName)
Definition: Entity.cpp:3108
int Index(void) const
Definition: DeclManager.h:165
void SetTimeScale(const float ts)
Definition: Physics_AF.h:859
void SetOwner(idEntity *newOwner)
Definition: Clip.h:190
idPhysics * GetPhysics(void) const
Definition: Entity.cpp:2607
idAngles ToAngles(void) const
Definition: Vector.cpp:130
GLuint index
Definition: glext.h:3476
surfTypes_t
Definition: Material.h:301
const char * GetString(const char *key, const char *defaultString="") const
Definition: Dict.h:240
bool SpawnEntityDef(const idDict &args, idEntity **ent=NULL, bool setDefaults=true)
void ReadFloat(float &value)
Definition: SaveGame.cpp:967
idVec3 lightRadius
Definition: RenderWorld.h:178
float Length(void) const
Definition: Vector.h:631
idVec3 ToForward(void) const
Definition: Angles.cpp:117
void WriteDeltaFloat(float oldValue, float newValue)
Definition: BitMsg.h:595
float RandomFloat(void)
Definition: Random.h:82
bool StartSound(const char *soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length)
Definition: Entity.cpp:1622
idVec3 vec3_origin(0.0f, 0.0f, 0.0f)
void ReadRenderLight(renderLight_t &renderLight)
Definition: SaveGame.cpp:1333
void void Read(void *buffer, int len)
Definition: SaveGame.cpp:913
#define vec3_zero
Definition: Vector.h:390
void SetPhysics(idPhysics *phys)
Definition: Entity.cpp:2574
void Restore(idRestoreGame *savefile)
void Unbind(void)
Definition: Entity.cpp:2011
void Launch(void)
void WriteToSnapshot(idBitMsgDelta &msg) const
const idVec3 & GetLinearVelocity(int id=0) const
void WriteLong(int c)
Definition: BitMsg.h:295
GLuint GLuint end
Definition: glext.h:2845
void WriteFloat(const float value)
Definition: SaveGame.cpp:213
idPhysics_AF * GetAFPhysics(void)
Definition: AFEntity.h:170
idCommon * common
Definition: Common.cpp:206
static const char * sufaceTypeNames[MAX_SURFACE_TYPES]
Definition: Game_local.h:337
idJointMat * joints
Definition: RenderWorld.h:135
bool GetBool(const char *key, const char *defaultString="0") const
Definition: Dict.h:256
Definition: Dict.h:65
#define NULL
Definition: Lib.h:88
const idDeclSkin * customSkin
Definition: RenderWorld.h:125
virtual idRenderModel * FindModel(const char *modelName)=0
virtual const idDecl * FindType(declType_t type, const char *name, bool makeDefault=true)=0
float y
Definition: Vector.h:319
int GetSpawnId(void) const
Definition: Game_local.h:231
int GetInteger(void) const
Definition: CVarSystem.h:143
idVec3 GetVector(const char *key, const char *defaultString=NULL) const
Definition: Dict.h:260
void ServerSendEvent(int eventId, const idBitMsg *msg, bool saveEvent, int excludeClient) const
Definition: Entity.cpp:4897
void Save(idSaveGame *savefile) const
float ReadFloat(void) const
Definition: BitMsg.h:379
virtual void SetOrigin(const idVec3 &newOrigin, int id=-1)=0
void CancelEvents(const idEventDef *ev)
Definition: Class.cpp:619
const idEventDef EV_Fizzle("<fizzle>", NULL)
void Spawn(void)
const idVec3 & GetGravity(void) const
const int GetSurfaceFlags(void) const
Definition: Material.h:500
idMat3 endAxis
float roll
Definition: Angles.h:55
float ReadDeltaFloat(float oldValue) const
Definition: BitMsg.h:664
virtual const idMat3 & GetAxis(int id=0) const =0
virtual void ClientPredictionThink(void)
virtual idAnimator * GetAnimator(void)
Definition: Entity.cpp:5213
virtual void UpdateEntityDef(qhandle_t entityHandle, const renderEntity_t *re)=0
void SetFriction(const float linear, const float angular, const float contact)
float NormalizeFast(void)
Definition: Vector.h:524
#define MASK_SHOT_RENDERMODEL
Definition: Game_local.h:741
idVec3 ReadDir(int numBits) const
Definition: BitMsg.h:398
void Event_GetProjectileState(void)
Definition: Projectile.cpp:808
float pitch
Definition: Angles.h:53
idGameLocal gameLocal
Definition: Game_local.cpp:64
bool RunPhysics(void)
Definition: Entity.cpp:2616
const int SHADERPARM_TIMEOFFSET
Definition: RenderWorld.h:51
void WriteRenderEntity(const renderEntity_t &renderEntity)
Definition: SaveGame.cpp:497
qhandle_t modelDefHandle
Definition: Projectile.h:212
void AlertAI(idEntity *ent)
virtual void Damage(idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location)
Definition: Entity.cpp:3061
#define END_CLASS
Definition: Class.h:54
idRenderModel * hModel
Definition: RenderWorld.h:81
void Restore(idRestoreGame *savefile)
virtual void UpdateLightDef(qhandle_t lightHandle, const renderLight_t *rlight)=0
idBounds Expand(const float d) const
Definition: Bounds.h:317
void Event_RadiusDamage(idEntity *ignore)
Definition: Projectile.cpp:796
virtual idBounds Bounds(const struct renderEntity_s *ent=NULL) const =0
virtual ~idProjectile()
Definition: Projectile.cpp:284
void SetPosition(idPhysics *physics, int id, const idVec3 &point)
void Save(idSaveGame *savefile) const
virtual void Hide(void)
Definition: Entity.cpp:1226
const surfTypes_t GetSurfaceType(void) const
Definition: Material.h:503
void SetAxis(const idMat3 &newAxis, int id=-1)
virtual bool Collide(const trace_t &collision, const idVec3 &velocity)
renderEntity_t renderEntity
Definition: Projectile.h:211
void WriteInt(const int value)
Definition: SaveGame.cpp:168
virtual void Launch(const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire=0.0f, const float launchPower=1.0f, const float dmgPower=1.0f)
int numClients
Definition: Game_local.h:271
virtual void Present(void)
Definition: Entity.cpp:1471
idActor * EnemyWithMostHealth()
Definition: Actor.cpp:1876
idDeclManager * declManager
#define SEC2MS(t)
Definition: Math.h:59
virtual bool Collide(const trace_t &collision, const idVec3 &velocity)
Definition: Projectile.cpp:530
idEntity * entities[MAX_GENTITIES]
Definition: Game_local.h:275
virtual bool ClientReceiveEvent(int event, int time, const idBitMsg &msg)
Definition: Entity.cpp:4988
const char * GetString(void) const
Definition: CVarSystem.h:141
int health
Definition: Entity.h:134
idEntity * GetTraceEntity(const trace_t &trace) const
void SetContents(int contents, int id=-1)
virtual void Think(void)
void ReadStaticObject(idClass &obj)
Definition: SaveGame.cpp:1098
int Append(const type &obj)
Definition: List.h:646
idDict serverInfo
Definition: Game_local.h:270
idRenderModelManager * renderModelManager
Definition: Matrix.h:333
const int SHADERPARM_RED
Definition: RenderWorld.h:46
idCVar g_projectileLights("g_projectileLights","1", CVAR_GAME|CVAR_ARCHIVE|CVAR_BOOL,"show dynamic lights on projectiles")
void WriteAngles(const idAngles &angles)
Definition: SaveGame.cpp:318
void SetForce(const idVec3 &force)
void SetClipMask(int mask, int id=-1)
float yaw
Definition: Angles.h:54
idList< beamTarget_t > beamTargets
Definition: Projectile.h:231
void UpdateVisuals(void)
Definition: Entity.cpp:1310
bool GetBool(void) const
Definition: CVarSystem.h:142
virtual const idDecl * DeclByIndex(declType_t type, int index, bool forceParse=true)=0
void Event_Explode(void)
tuple f
Definition: idal.py:89
void ProjectDecal(const idVec3 &origin, const idVec3 &dir, float depth, bool parallel, float size, const char *material, float angle=0)
static idVec3 GetGravity(const idDict *projectile)
Definition: Actor.h:111
bool IsGametypeFlagBased(void)
int lightStartTime
Definition: Projectile.h:106
const idEventDef EV_GetProjectileState("getProjectileState", NULL, 'd')
int Num(void) const
Definition: List.h:265
idMat3 ToMat3(void) const
Definition: Angles.cpp:199
unsigned char byte
Definition: Lib.h:75
virtual const idBounds & GetAbsBounds(int id=-1) const =0
int modelDefHandle
Definition: Entity.h:372
void Create(idEntity *owner, const idVec3 &start, const idMat3 &axis)
bool GetJointWorldTransform(jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis)
Definition: Entity.cpp:5248
int Contents(const idVec3 &start, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity)
Definition: Clip.cpp:1429
virtual void Evaluate(int time)
virtual void Damage(idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location)
Definition: Actor.cpp:2203
#define CLASS_DECLARATION(nameofsuperclass, nameofclass)
Definition: Class.h:110
Definition: Str.h:116
idBounds bounds
Definition: RenderWorld.h:95
void Save(idSaveGame *savefile) const
Definition: Projectile.cpp:118
idVec3 ToAngularVelocity(void) const
Definition: Angles.cpp:228
void AddProjectileHits(int count)
int GetEntityNum(void) const
Definition: Game_local.h:704
void Save(idSaveGame *savefile) const
Definition: Game_local.h:656
void ReadVec3(idVec3 &vec)
Definition: SaveGame.cpp:1011
static idVec3 GetVelocity(const idDict *projectile)
virtual void Launch(const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire=0.0f, const float launchPower=1.0f, const float dmgPower=1.0f)
idVec3 endingVelocity
Definition: Projectile.h:197
void ClearContacts(void)
virtual void ParseSpawnArgsToRenderEntity(const idDict *args, renderEntity_t *renderEntity)
Definition: Entity.cpp:229
void ReadAngles(idAngles &angles)
Definition: SaveGame.cpp:1073
void RestorePhysics(idPhysics *phys)
Definition: Entity.cpp:2596
void BecomeActive(int flags)
Definition: Entity.cpp:995
idRenderSystemLocal tr
const idEventDef EV_Remove("<immediateremove>", NULL)
bool IsActive(void) const
Definition: Entity.cpp:986
float ReadFloat(void) const
Definition: BitMsg.h:625
virtual void Explode(const trace_t &collision, idEntity *ignore)
Definition: Projectile.cpp:817
void Restore(idRestoreGame *savefile)
virtual bool CanDamage(const idVec3 &origin, idVec3 &damagePoint) const
Definition: Entity.cpp:2961
virtual const idDeclSkin * FindSkin(const char *name, bool makeDefault=true)=0
idCVar g_testParticle("g_testParticle","0", CVAR_GAME|CVAR_INTEGER,"test particle visualation, set by the particle editor")
const int USERCMD_HZ
Definition: UsercmdGen.h:40
void Think(void)
void Lerp(const idVec3 &v1, const idVec3 &v2, const float l)
Definition: Vector.cpp:232
void SetGravity(const idVec3 &newGravity)
const char * GetEntityDefName(void) const
Definition: Entity.cpp:842
virtual void Think(void)
idRenderWorld * gameRenderWorld
Definition: Game_local.cpp:55
void Event_Explode(void)
void ReturnToOwner(void)
void EnableBFGVision(bool b)
Definition: PlayerView.h:381
char * va(const char *fmt,...)
Definition: Str.cpp:1568
qhandle_t lightDefHandle
Definition: Projectile.h:104
void SetOrigin(const idVec3 &org)
Definition: Entity.cpp:2784
bool PostEventMS(const idEventDef *ev, int time)
Definition: Class.cpp:666
virtual void DPrintf(const char *fmt,...) id_attribute((format(printf
void WriteDir(const idVec3 &dir, int numBits)
Definition: BitMsg.h:316
int smokeFlyTime
Definition: Projectile.h:114
idMultiplayerGame mpGame
Definition: Game_local.h:305
void Event_RemoveBeams()
const idMaterial * shader
Definition: RenderWorld.h:200
int thinkFlags
Definition: Entity.h:125
virtual void Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location)
Definition: Projectile.cpp:730
void Unlink(void)
Definition: Clip.cpp:491
const idEventDef EV_RemoveBeams("<removeBeams>", NULL)
const idEventDef EV_Touch("<touch>","et")
void WriteParticle(const idDeclParticle *particle)
Definition: SaveGame.cpp:406
void SetBouncyness(const float b)
void Save(idSaveGame *savefile) const
void Zero(void)
Definition: Vector.h:415
float shaderParms[MAX_ENTITY_SHADER_PARMS]
Definition: RenderWorld.h:127
void ReadString(idStr &string)
Definition: SaveGame.cpp:985
const idDeclParticle * smokeKill
Definition: Projectile.h:206
void WriteRenderLight(const renderLight_t &renderLight)
Definition: SaveGame.cpp:555
static void ReturnInt(int value)
virtual void FreeLightDef(void)
Definition: Projectile.cpp:294
void SetPhysics(idPhysics *physics)
void ReadInt(int &value)
Definition: SaveGame.cpp:922
float CRandomFloat(void)
Definition: Random.h:86
const idMat3 & GetAxis(int id=0) const
idClipModel * GetClipModel(int id=0) const
idCollisionModelManager * collisionModelManager
GLuint start
Definition: glext.h:2845
void StopSound(const s_channelType channel, bool broadcast)
Definition: Entity.cpp:1713
Definition: AI.h:253
void Save(idSaveGame *savefile) const
#define MS2SEC(t)
Definition: Math.h:60
void Restore(idRestoreGame *savefile)
Definition: Projectile.cpp:156
void SetOrigin(const idVec3 &newOrigin, int id=-1)
void Fizzle(void)
Definition: Projectile.cpp:752
idEntity * GetOwner(void) const
Definition: Projectile.cpp:209
virtual void SetAxis(const idMat3 &newAxis, int id=-1)=0
void SetMass(float mass, int id=-1)
void Clear(void)
Definition: List.h:184
virtual void Think(void)
bool netSyncPhysics
Definition: Projectile.h:132