codemp/game/g_turret.c File Reference

#include "g_local.h"
#include "q_shared.h"

Go to the source code of this file.

Defines

#define START_DIS   15

Functions

void G_SetEnemy (gentity_t *self, gentity_t *enemy)
qboolean turret_base_spawn_top (gentity_t *base)
void ObjectDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath)
void TurretPain (gentity_t *self, gentity_t *attacker, int damage)
void TurretBasePain (gentity_t *self, gentity_t *attacker, int damage)
void auto_turret_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath)
void bottom_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath)
void turret_head_think (gentity_t *self)
void turret_base_think (gentity_t *self)
void turret_base_use (gentity_t *self, gentity_t *other, gentity_t *activator)
void SP_misc_turret (gentity_t *base)


Define Documentation

#define START_DIS   15
 

Definition at line 126 of file g_turret.c.

Referenced by turret_head_think(), and turretG2_head_think().


Function Documentation

void auto_turret_die gentity_t self,
gentity_t inflictor,
gentity_t attacker,
int  damage,
int  meansOfDeath
 

Definition at line 51 of file g_turret.c.

References entityState_s::apos, entityShared_t::currentAngles, entityShared_t::currentOrigin, gentity_s::die, EFFECT_EXPLOSION_TURRET, G_EffectIndex(), g_entities, G_PlayEffect(), G_PlayEffectID(), G_RadiusDamage(), G_UseTargets(), gentity_t, gentity_s::health, entityState_s::health, entityState_s::loopSound, entityShared_t::maxs, MOD_UNKNOWN, entityState_s::modelindex, entityState_s::modelindex2, NULL, ObjectDie(), entityShared_t::ownerNum, qfalse, gentity_s::r, gentity_s::s, entityState_s::shouldtarget, gentity_s::splashDamage, gentity_s::splashRadius, gentity_s::takedamage, gentity_s::target, gentity_s::target_ent, trajectory_t::trBase, trajectory_t::trDelta, vec3_t, VectorClear, VectorCopy, and entityState_s::weapon.

Referenced by bottom_die(), and turret_base_spawn_top().

00053 {
00054         vec3_t  forward = { 0,0, 1 }, pos;
00055 
00056         // Turn off the thinking of the base & use it's targets
00057         g_entities[self->r.ownerNum].think = NULL;
00058         g_entities[self->r.ownerNum].use = NULL;
00059 
00060         // clear my data
00061         self->die = NULL;
00062         self->takedamage = qfalse;
00063         self->s.health = self->health = 0;
00064         self->s.loopSound = 0;
00065         self->s.shouldtarget = qfalse;
00066         //self->s.owner = MAX_CLIENTS; //not owned by any client
00067 
00068         VectorCopy( self->r.currentOrigin, pos );
00069         pos[2] += self->r.maxs[2]*0.5f;
00070         G_PlayEffect( EFFECT_EXPLOSION_TURRET, pos, forward );
00071         G_PlayEffectID( G_EffectIndex( "turret/explode" ), pos, forward );
00072         
00073         if ( self->splashDamage > 0 && self->splashRadius > 0 )
00074         {
00075                 G_RadiusDamage( self->r.currentOrigin, 
00076                                                 attacker, 
00077                                                 self->splashDamage, 
00078                                                 self->splashRadius, 
00079                                                 attacker,
00080                                                 NULL,
00081                                                 MOD_UNKNOWN );
00082         }
00083 
00084         self->s.weapon = 0; // crosshair code uses this to mark crosshair red
00085 
00086 
00087         if ( self->s.modelindex2 )
00088         {
00089                 // switch to damage model if we should
00090                 self->s.modelindex = self->s.modelindex2;
00091 
00092                 if (self->target_ent && self->target_ent->s.modelindex2)
00093                 {
00094                         self->target_ent->s.modelindex = self->target_ent->s.modelindex2;
00095                 }
00096 
00097                 VectorCopy( self->r.currentAngles, self->s.apos.trBase );
00098                 VectorClear( self->s.apos.trDelta );
00099                 
00100                 if ( self->target )
00101                 {
00102                         G_UseTargets( self, attacker );
00103                 }
00104         }
00105         else
00106         {
00107                 ObjectDie( self, inflictor, attacker, damage, meansOfDeath );
00108         }
00109 }

void bottom_die gentity_t self,
gentity_t inflictor,
gentity_t attacker,
int  damage,
int  meansOfDeath
 

Definition at line 112 of file g_turret.c.

References auto_turret_die(), G_ScaleNetHealth(), gentity_t, gentity_s::health, gentity_s::maxHealth, and gentity_s::target_ent.

Referenced by turret_base_spawn_top().

00114 {
00115         if (self->target_ent && self->target_ent->health > 0)
00116         {
00117                 self->target_ent->health = self->health;
00118                 if (self->target_ent->maxHealth)
00119                 {
00120                         G_ScaleNetHealth(self->target_ent);
00121                 }
00122                 auto_turret_die(self->target_ent, inflictor, attacker, damage, meansOfDeath);
00123         }
00124 }

void G_SetEnemy gentity_t self,
gentity_t enemy
 

void ObjectDie gentity_t self,
gentity_t inflictor,
gentity_t attacker,
int  damage,
int  meansOfDeath
 

Definition at line 21 of file g_combat.c.

00022 {
00023         if(self->target)
00024         {
00025                 G_UseTargets(self, attacker);
00026         }
00027 
00028         //remove my script_targetname
00029         G_FreeEntity( self );
00030 }

void SP_misc_turret gentity_t base  ) 
 

Definition at line 663 of file g_turret.c.

References entityState_s::angles, entityShared_t::contents, CONTENTS_BODY, FRAMETIME, G_FreeEntity(), G_IconIndex(), G_ModelIndex(), G_SetAngles(), G_SetOrigin(), G_SpawnString(), entityState_s::genericenemyindex, gentity_t, level, entityShared_t::maxs, entityShared_t::mins, entityState_s::modelindex, entityState_s::modelindex2, gentity_s::nextthink, entityState_s::origin, gentity_s::r, gentity_s::s, gentity_s::think, level_locals_t::time, trap_LinkEntity(), turret_base_spawn_top(), turret_base_think(), turret_base_use(), gentity_s::use, and VectorSet.

00665 {
00666         char* s;
00667 
00668         base->s.modelindex2 = G_ModelIndex( "models/map_objects/hoth/turret_bottom.md3" );
00669         base->s.modelindex = G_ModelIndex( "models/map_objects/hoth/turret_base.md3" );
00670         //base->playerModel = gi.G2API_InitGhoul2Model( base->ghoul2, "models/map_objects/imp_mine/turret_canon.glm", base->s.modelindex );
00671         //base->s.radius = 80.0f;
00672 
00673         //gi.G2API_SetBoneAngles( &base->ghoul2[base->playerModel], "Bone_body", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL ); 
00674         //base->torsoBolt = gi.G2API_AddBolt( &base->ghoul2[base->playerModel], "*flash03" );
00675 
00676         G_SpawnString( "icon", "", &s );
00677         if (s && s[0])
00678         { 
00679                 // We have an icon, so index it now.  We are reusing the genericenemyindex
00680                 // variable rather than adding a new one to the entity state.
00681                 base->s.genericenemyindex = G_IconIndex(s);
00682         }
00683 
00684         G_SetAngles( base, base->s.angles );
00685         G_SetOrigin( base, base->s.origin );
00686 
00687         base->r.contents = CONTENTS_BODY;
00688 
00689         VectorSet( base->r.maxs, 32.0f, 32.0f, 128.0f );
00690         VectorSet( base->r.mins, -32.0f, -32.0f, 0.0f );
00691 
00692         base->use = turret_base_use;
00693         base->think = turret_base_think;
00694         // don't start working right away
00695         base->nextthink = level.time + FRAMETIME * 5;
00696 
00697         trap_LinkEntity( base );
00698 
00699         if ( !turret_base_spawn_top( base ) )
00700         {
00701                 G_FreeEntity( base );
00702         }
00703 }

qboolean turret_base_spawn_top gentity_t base  ) 
 

Definition at line 706 of file g_turret.c.

References gentity_s::alliedTeam, entityState_s::angles, atoi(), auto_turret_die(), BG_FindItemForWeapon(), bottom_die(), entityShared_t::contents, CONTENTS_BODY, gentity_s::count, gentity_s::damage, gentity_s::die, ET_GENERAL, entityState_s::eType, G_EffectIndex(), G_ModelIndex(), G_ScaleNetHealth(), G_SetAngles(), G_SetOrigin(), G_SoundIndex(), G_Spawn(), G_SpawnFloat(), G_SpawnInt(), gentity_s::genericValue13, gentity_s::genericValue14, gentity_s::genericValue15, gentity_t, gentity_s::health, gentity_s::mass, MAT_METAL, gentity_s::material, gentity_s::maxHealth, entityShared_t::maxs, entityShared_t::mins, entityState_s::modelindex, entityState_s::modelindex2, NULL, entityState_s::number, entityState_s::origin, entityShared_t::ownerNum, gentity_s::pain, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::radius, random, RegisterItem(), gentity_s::s, entityState_s::shouldtarget, gentity_s::speed, gentity_s::splashDamage, gentity_s::splashRadius, gentity_s::takedamage, gentity_s::target_ent, gentity_s::team, gentity_s::teamnodmg, entityState_s::teamowner, trap_LinkEntity(), TurretBasePain(), TurretPain(), vec3_t, VectorCopy, VectorSet, gentity_s::wait, entityState_s::weapon, and WP_EMPLACED_GUN.

Referenced by SP_misc_turret().

00707 {
00708         vec3_t          org;
00709         int                     t;
00710 
00711         gentity_t *top = G_Spawn();
00712         if ( !top )
00713         {
00714                 return qfalse;
00715         }
00716 
00717         top->s.modelindex = G_ModelIndex( "models/map_objects/hoth/turret_top_new.md3" );
00718         top->s.modelindex2 = G_ModelIndex( "models/map_objects/hoth/turret_top.md3" );
00719         G_SetAngles( top, base->s.angles );
00720         VectorCopy( base->s.origin, org );
00721         org[2] += 128;
00722         G_SetOrigin( top, org );
00723 
00724         base->r.ownerNum = top->s.number;
00725         top->r.ownerNum = base->s.number;
00726 
00727         if ( base->team && base->team[0] && //g_gametype.integer == GT_SIEGE &&
00728                 !base->teamnodmg)
00729         {
00730                 base->teamnodmg = atoi(base->team);
00731         }
00732         base->team = NULL;
00733         top->teamnodmg = base->teamnodmg;
00734         top->alliedTeam = base->alliedTeam;
00735 
00736         base->s.eType = ET_GENERAL;
00737 
00738         // Set up our explosion effect for the ExplodeDeath code....
00739         G_EffectIndex( "turret/explode" );
00740         G_EffectIndex( "sparks/spark_exp_nosnd" );
00741         G_EffectIndex( "turret/hoth_muzzle_flash" );
00742 
00743         // this is really the pitch angle.....
00744         top->speed = 0;
00745 
00746         // this is a random time offset for the no-enemy-search-around-mode
00747         top->count = random() * 9000;
00748 
00749         if ( !base->health )
00750         {
00751                 base->health = 3000;
00752         }
00753         top->health = base->health;
00754 
00755         G_SpawnInt( "showhealth", "0", &t );
00756 
00757         if (t)
00758         { //a non-0 maxhealth value will mean we want to show the health on the hud
00759                 top->maxHealth = base->health; //acts as "maxhealth"
00760                 G_ScaleNetHealth(top);
00761 
00762                 base->maxHealth = base->health;
00763                 G_ScaleNetHealth(base);
00764         }
00765 
00766         base->takedamage = qtrue;
00767         base->pain = TurretBasePain;
00768         base->die = bottom_die;
00769 
00770         //design specified shot speed
00771         G_SpawnFloat( "shotspeed", "1100", &base->mass );
00772         top->mass = base->mass;
00773 
00774         //even if we don't want to show health, let's at least light the crosshair up properly over ourself
00775         if ( !top->s.teamowner )
00776         {
00777                 top->s.teamowner = top->alliedTeam;
00778         }
00779 
00780         base->alliedTeam = top->alliedTeam;
00781         base->s.teamowner = top->s.teamowner;
00782 
00783         base->s.shouldtarget = qtrue;
00784         top->s.shouldtarget = qtrue;
00785 
00786         //link them to each other
00787         base->target_ent = top;
00788         top->target_ent = base;
00789 
00790         //top->s.owner = MAX_CLIENTS; //not owned by any client
00791 
00792         // search radius
00793         if ( !base->radius )
00794         {
00795                 base->radius = 1024;
00796         }
00797         top->radius = base->radius;
00798 
00799         // How quickly to fire
00800         if ( !base->wait )
00801         {
00802                 base->wait = 300 + random() * 55;
00803         }
00804         top->wait = base->wait;
00805 
00806         if ( !base->splashDamage )
00807         {
00808                 base->splashDamage = 300;
00809         }
00810         top->splashDamage = base->splashDamage;
00811 
00812         if ( !base->splashRadius )
00813         {
00814                 base->splashRadius = 128;
00815         }
00816         top->splashRadius = base->splashRadius;
00817 
00818         // how much damage each shot does
00819         if ( !base->damage )
00820         {
00821                 base->damage = 100;
00822         }
00823         top->damage = base->damage;
00824 
00825         // how fast it turns
00826         if ( !base->speed )
00827         {
00828                 base->speed = 20;
00829         }
00830         top->speed = base->speed;
00831 
00832         VectorSet( top->r.maxs, 48.0f, 48.0f, 16.0f );
00833         VectorSet( top->r.mins, -48.0f, -48.0f, 0.0f );
00834         // Precache moving sounds
00835         //G_SoundIndex( "sound/chars/turret/startup.wav" );
00836         //G_SoundIndex( "sound/chars/turret/shutdown.wav" );
00837         //G_SoundIndex( "sound/chars/turret/ping.wav" );
00838         G_SoundIndex( "sound/vehicles/weapons/hoth_turret/turn.wav" );
00839         top->genericValue13 = G_EffectIndex( "turret/hoth_muzzle_flash" );
00840         top->genericValue14 = G_EffectIndex( "turret/hoth_shot" );
00841         top->genericValue15 = G_EffectIndex( "turret/hoth_impact" );
00842 
00843         top->r.contents = CONTENTS_BODY;
00844 
00845         //base->max_health = base->health;
00846         top->takedamage = qtrue;
00847         top->pain = TurretPain;
00848         top->die  = auto_turret_die;
00849 
00850         top->material = MAT_METAL;
00851         //base->r.svFlags |= SVF_NO_TELEPORT|SVF_NONNPC_ENEMY|SVF_SELF_ANIMATING;
00852 
00853         // Register this so that we can use it for the missile effect
00854         RegisterItem( BG_FindItemForWeapon( WP_EMPLACED_GUN ));
00855 
00856         // But set us as a turret so that we can be identified as a turret
00857         top->s.weapon = WP_EMPLACED_GUN;
00858 
00859         trap_LinkEntity( top );
00860         return qtrue;
00861 }

void turret_base_think gentity_t self  ) 
 

Definition at line 505 of file g_turret.c.

References trace_t::allsolid, gentity_s::bounceCount, gentity_s::client, entityShared_t::currentOrigin, gentity_s::enemy, enemyDist, trace_t::entityNum, renderInfo_s::eyePoint, FL_NOTARGET, gentity_s::flags, FRAMETIME, gentity_t, gentity_s::health, level, MASK_SHOT, gentity_s::nextthink, NULL, entityState_s::number, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::radius, random, gclient_s::renderInfo, gentity_s::s, gclient_s::sess, clientSession_t::sessionTeam, gentity_s::spawnflags, trace_t::startsolid, TEAM_SPECTATOR, level_locals_t::time, trap_InPVS(), trap_Trace(), turret_head_think(), vec3_t, VectorCopy, and VectorSubtract.

Referenced by SP_misc_turret().

00507 {
00508         qboolean        turnOff = qtrue;
00509         float           enemyDist;
00510         vec3_t          enemyDir, org, org2;
00511 
00512         if ( self->spawnflags & 1 )
00513         {
00514                 // not turned on
00515                 turret_turnoff( self );
00516 
00517                 // No target
00518                 self->flags |= FL_NOTARGET;
00519                 self->nextthink = -1;//never think again
00520                 return;
00521         }
00522         else
00523         {
00524                 // I'm all hot and bothered
00525                 self->flags &= ~FL_NOTARGET;
00526                 //remember to keep thinking!
00527                 self->nextthink = level.time + FRAMETIME;
00528         }
00529 
00530         if ( !self->enemy )
00531         {
00532                 if ( turret_find_enemies( self ))
00533                 {
00534                         turnOff = qfalse;
00535                 }
00536         }
00537         else if ( self->enemy->client && self->enemy->client->sess.sessionTeam == TEAM_SPECTATOR )
00538         {//don't keep going after spectators
00539                 self->enemy = NULL;
00540         }
00541         else
00542         {//FIXME: remain single-minded or look for a new enemy every now and then?
00543                 if ( self->enemy->health > 0 )
00544                 {
00545                         // enemy is alive
00546                         VectorSubtract( self->enemy->r.currentOrigin, self->r.currentOrigin, enemyDir );
00547                         enemyDist = VectorLengthSquared( enemyDir );
00548 
00549                         if ( enemyDist < (self->radius * self->radius) )
00550                         {
00551                                 // was in valid radius
00552                                 if ( trap_InPVS( self->r.currentOrigin, self->enemy->r.currentOrigin ) )
00553                                 {
00554                                         // Every now and again, check to see if we can even trace to the enemy
00555                                         trace_t tr;
00556 
00557                                         if ( self->enemy->client )
00558                                         {
00559                                                 VectorCopy( self->enemy->client->renderInfo.eyePoint, org );
00560                                         }
00561                                         else
00562                                         {
00563                                                 VectorCopy( self->enemy->r.currentOrigin, org );
00564                                         }
00565                                         VectorCopy( self->r.currentOrigin, org2 );
00566                                         if ( self->spawnflags & 2 )
00567                                         {
00568                                                 org2[2] += 10;
00569                                         }
00570                                         else
00571                                         {
00572                                                 org2[2] -= 10;
00573                                         }
00574                                         trap_Trace( &tr, org2, NULL, NULL, org, self->s.number, MASK_SHOT );
00575 
00576                                         if ( !tr.allsolid && !tr.startsolid && tr.entityNum == self->enemy->s.number )
00577                                         {
00578                                                 turnOff = qfalse;       // Can see our enemy
00579                                         }
00580                                 }
00581                         }
00582                 }
00583 
00584                 turret_head_think( self );
00585         }
00586 
00587         if ( turnOff )
00588         {
00589                 if ( self->bounceCount < level.time ) // bounceCount is used to keep the thing from ping-ponging from on to off
00590                 {
00591                         turret_sleep( self );
00592                 }
00593         }
00594         else
00595         {
00596                 // keep our enemy for a minimum of 2 seconds from now
00597                 self->bounceCount = level.time + 2000 + random() * 150;
00598         }
00599 
00600         turret_aim( self );
00601 }

void turret_base_use gentity_t self,
gentity_t other,
gentity_t activator
 

Definition at line 604 of file g_turret.c.

References gentity_t, and gentity_s::spawnflags.

Referenced by SP_misc_turret().

00606 {
00607         // Toggle on and off
00608         self->spawnflags = (self->spawnflags ^ 1);
00609 
00610         /*
00611         if (( self->s.eFlags & EF_SHADER_ANIM ) && ( self->spawnflags & 1 )) // Start_Off
00612         {
00613                 self->s.frame = 1; // black
00614         }
00615         else
00616         {
00617                 self->s.frame = 0; // glow
00618         }
00619         */
00620 }

void turret_head_think gentity_t self  ) 
 

Definition at line 179 of file g_turret.c.

References AngleVectors(), gentity_s::attackDebounceTime, entityShared_t::currentAngles, entityShared_t::currentOrigin, EFFECT_SPARKS, gentity_s::enemy, gentity_s::fly_sound_debounce_time, g_entities, G_PlayEffect(), gentity_t, level, entityShared_t::maxs, NULL, entityShared_t::ownerNum, gentity_s::painDebounceTime, Q_irand(), gentity_s::r, gentity_s::setTime, START_DIS, level_locals_t::time, vec3_t, VectorCopy, VectorMA, VectorSet, and gentity_s::wait.

Referenced by turret_base_think().

00181 {
00182         gentity_t *top = &g_entities[self->r.ownerNum];
00183         if ( !top )
00184         {
00185                 return;
00186         }
00187         if ( self->painDebounceTime > level.time )
00188         {
00189                 vec3_t  v_up;
00190                 VectorSet( v_up, 0, 0, 1 );
00191                 G_PlayEffect( EFFECT_SPARKS, self->r.currentOrigin, v_up );
00192                 if ( Q_irand( 0, 3) )
00193                 {//25% chance of still firing
00194                         return;
00195                 }
00196         }
00197         // if it's time to fire and we have an enemy, then gun 'em down!  pushDebounce time controls next fire time
00198         if ( self->enemy && self->setTime < level.time && self->attackDebounceTime < level.time )
00199         {
00200                 vec3_t          fwd, org;
00201                 // set up our next fire time
00202                 self->setTime = level.time + self->wait;
00203 
00204                 /*
00205                 mdxaBone_t      boltMatrix;
00206 
00207                 // Getting the flash bolt here
00208                 gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel, 
00209                                         self->torsoBolt,
00210                                         &boltMatrix, self->r.currentAngles, self->r.currentOrigin, (cg.time?cg.time:level.time),
00211                                         NULL, self->s.modelScale );
00212 
00213                 gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org );
00214                 gi.G2API_GiveMeVectorFromMatrix( boltMatrix, POSITIVE_Y, fwd );
00215                 */
00216                 VectorCopy( top->r.currentOrigin, org );
00217                 org[2] += top->r.maxs[2]-8;
00218                 AngleVectors( top->r.currentAngles, fwd, NULL, NULL );
00219 
00220                 VectorMA( org, START_DIS, fwd, org );
00221 
00222                 turret_fire( top, org, fwd );
00223                 self->fly_sound_debounce_time = level.time;//used as lastShotTime
00224         }
00225 }

void TurretBasePain gentity_t self,
gentity_t attacker,
int  damage
 

Definition at line 35 of file g_turret.c.

References G_ScaleNetHealth(), gentity_t, gentity_s::health, gentity_s::maxHealth, gentity_s::target_ent, and TurretPain().

Referenced by turret_base_spawn_top().

00037 {
00038         if (self->target_ent)
00039         {
00040                 self->target_ent->health = self->health;
00041                 if (self->target_ent->maxHealth)
00042                 {
00043                         G_ScaleNetHealth(self->target_ent);
00044                 }
00045 
00046                 TurretPain(self->target_ent, attacker, damage);
00047         }
00048 }

void TurretPain gentity_t self,
gentity_t attacker,
int  damage
 

Definition at line 11 of file g_turret.c.

References gentity_s::attackDebounceTime, gentity_s::client, gentity_s::enemy, G_ScaleNetHealth(), G_SetEnemy(), gentity_t, gentity_s::health, level, gentity_s::maxHealth, gentity_s::painDebounceTime, gclient_s::ps, random, gentity_s::target_ent, level_locals_t::time, playerState_s::weapon, and WP_DEMP2.

Referenced by turret_base_spawn_top(), and TurretBasePain().

00013 {
00014         if (self->target_ent)
00015         {
00016                 self->target_ent->health = self->health;
00017                 if (self->target_ent->maxHealth)
00018                 {
00019                         G_ScaleNetHealth(self->target_ent);
00020                 }
00021         }
00022 
00023         if ( attacker->client && attacker->client->ps.weapon == WP_DEMP2 )
00024         {
00025                 self->attackDebounceTime = level.time + 800 + random() * 500;
00026                 self->painDebounceTime = self->attackDebounceTime;
00027         }
00028         if ( !self->enemy )
00029         {//react to being hit
00030                 G_SetEnemy( self, attacker );
00031         }
00032 }