//QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8) //Spawns an explosion temporary entity when used. // //"delay" wait this long before going off //"dmg" how much radius damage should be done, defaults to 0 static void target_explosion_explode( edict_t *self ) { float save; int radius; edict_t *event; G_RadiusDamage( self, self->activator, NULL, NULL, MOD_EXPLOSIVE ); if( ( self->projectileInfo.radius * 1/8 ) > 255 ) { radius = ( self->projectileInfo.radius * 1/16 ) & 0xFF; if( radius < 1 ) radius = 1; event = G_SpawnEvent( EV_EXPLOSION2, radius, self->s.origin ); } else { radius = ( self->projectileInfo.radius * 1/8 ) & 0xFF; if( radius < 1 ) radius = 1; event = G_SpawnEvent( EV_EXPLOSION1, radius, self->s.origin ); } save = self->delay; self->delay = 0; G_UseTargets( self, self->activator ); self->delay = save; }
//========================================== // AITools_DrawPath // Draws the current path (floods as hell also) //========================================== void AITools_DrawPath( edict_t *self, int node_to ) { static unsigned int drawnpath_timeout; int count = 0; int pos = 0; //don't draw it every frame (flood) if( level.time < drawnpath_timeout ) return; drawnpath_timeout = level.time + 4 * game.snapFrameTime; if( self->ai->path.goalNode != node_to ) return; pos = self->ai->path.numNodes; // Now set up and display the path while( self->ai->path.nodes[pos] != node_to && count < 32 && pos > 0 ) { edict_t *event; event = G_SpawnEvent( EV_GREEN_LASER, 0, nodes[self->ai->path.nodes[pos]].origin ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorCopy( nodes[self->ai->path.nodes[pos-1]].origin, event->s.origin2 ); G_SetBoundsForSpanEntity( event, 8 ); GClip_LinkEntity( event ); pos--; count++; } }
//========================================== // AITools_DrawLine // Just so I don't hate to write the event every time //========================================== void AITools_DrawLine( vec3_t origin, vec3_t dest ) { edict_t *event; event = G_SpawnEvent( EV_GREEN_LASER, 0, origin ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorCopy( dest, event->s.origin2 ); }
/* * W_Touch_Rocket */ static void W_Touch_Rocket( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) { int mod_splash; vec3_t dir; int hitType; if( surfFlags & SURF_NOIMPACT ) { G_FreeEdict( ent ); return; } hitType = G_Projectile_HitStyle( ent, other ); if( hitType == PROJECTILE_TOUCH_NOT ) { return; } if( other->takedamage ) { int directHitDamage = ent->projectileInfo.maxDamage; VectorNormalize2( ent->velocity, dir ); if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) { // use hybrid direction from splash and projectile G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta ); } else { VectorNormalize2( ent->velocity, dir ); if( hitType == PROJECTILE_TOUCH_DIRECTAIRHIT ) { directHitDamage += DIRECTAIRTHIT_DAMAGE_BONUS; } else if( hitType == PROJECTILE_TOUCH_DIRECTHIT ) { directHitDamage += DIRECTHIT_DAMAGE_BONUS; } } G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, directHitDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, 0, ent->style ); } if( ent->s.effects & EF_STRONG_WEAPON ) { mod_splash = MOD_ROCKET_SPLASH_S; } else { mod_splash = MOD_ROCKET_SPLASH_W; } G_RadiusDamage( ent, ent->r.owner, plane, other, mod_splash ); // spawn the explosion if( !( surfFlags & SURF_NOIMPACT ) ) { edict_t *event; vec3_t explosion_origin; VectorMA( ent->s.origin, -0.02, ent->velocity, explosion_origin ); event = G_SpawnEvent( EV_ROCKET_EXPLOSION, DirToByte( plane ? plane->normal : NULL ), explosion_origin ); event->s.firemode = ( ent->s.effects & EF_STRONG_WEAPON ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; event->s.weapon = ( ( ent->projectileInfo.radius * 1 / 8 ) > 255 ) ? 255 : ( ent->projectileInfo.radius * 1 / 8 ); } // free the rocket at next frame G_FreeEdict( ent ); }
//========================================== // AITools_DrawLine // Just so I don't hate to write the event every time //========================================== void AITools_DrawLine( vec3_t origin, vec3_t dest ) { edict_t *event; event = G_SpawnEvent( EV_GREEN_LASER, 0, origin ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorCopy( dest, event->s.origin2 ); G_SetBoundsForSpanEntity( event, 8 ); GClip_LinkEntity( event ); }
//========================================== // AITools_DrawColorLine // Just so I don't hate to write the event every time //========================================== void AITools_DrawColorLine( vec3_t origin, vec3_t dest, int color, int parm ) { edict_t *event; event = G_SpawnEvent( EV_PNODE, parm, origin ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorCopy( dest, event->s.origin2 ); event->s.colorRGBA = color; }
//========================================== // AITools_DrawColorLine // Just so I don't hate to write the event every time //========================================== void AITools_DrawColorLine( vec3_t origin, vec3_t dest, int color, int parm ) { edict_t *event; event = G_SpawnEvent( EV_PNODE, parm, origin ); event->s.colorRGBA = color; event->r.svflags = SVF_TRANSMITORIGIN2; VectorCopy( dest, event->s.origin2 ); G_SetBoundsForSpanEntity( event, 8 ); GClip_LinkEntity( event ); }
/* * W_Touch_Bolt */ static void W_Touch_Bolt( edict_t *self, edict_t *other, cplane_t *plane, int surfFlags ) { edict_t *event; qboolean missed = qtrue; int hitType; if( surfFlags & SURF_NOIMPACT ) { G_FreeEdict( self ); return; } if( other == self->enemy ) return; hitType = G_Projectile_HitStyle( self, other ); if( hitType == PROJECTILE_TOUCH_NOT ) return; if( other->takedamage ) { vec3_t invdir; G_Damage( other, self, self->r.owner, self->velocity, self->velocity, self->s.origin, self->projectileInfo.maxDamage, self->projectileInfo.maxKnockback, self->projectileInfo.stun, 0, MOD_ELECTROBOLT_W ); VectorNormalize2( self->velocity, invdir ); VectorScale( invdir, -1, invdir ); event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( invdir ), self->s.origin ); event->s.firemode = FIRE_MODE_WEAK; if( other->r.client ) missed = qfalse; } else if( !( surfFlags & SURF_NOIMPACT ) ) { // add explosion event event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( plane ? plane->normal : NULL ), self->s.origin ); event->s.firemode = FIRE_MODE_WEAK; } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self->r.owner, MOD_ELECTROBOLT_W ); // hit something that isnt a player G_FreeEdict( self ); }
static void W_Plasma_Explosion( edict_t *ent, edict_t *ignore, cplane_t *plane, int surfFlags ) { edict_t *event; int radius = ( ( ent->projectileInfo.radius * 1 / 8 ) > 127 ) ? 127 : ( ent->projectileInfo.radius * 1 / 8 ); event = G_SpawnEvent( EV_PLASMA_EXPLOSION, DirToByte( plane ? plane->normal : NULL ), ent->s.origin ); event->s.firemode = ( ent->s.effects & EF_STRONG_WEAPON ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; event->s.weapon = radius & 127; G_RadiusDamage( ent, ent->r.owner, plane, ignore, ent->style ); G_FreeEdict( ent ); }
/* * W_Touch_GunbladeBlast */ static void W_Touch_GunbladeBlast( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) { vec3_t dir; int hitType; if( surfFlags & SURF_NOIMPACT ) { G_FreeEdict( ent ); return; } hitType = G_Projectile_HitStyle( ent, other ); if( hitType == PROJECTILE_TOUCH_NOT ) return; if( other->takedamage ) { VectorNormalize2( ent->velocity, dir ); if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) // use hybrid direction from splash and projectile { G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta ); } else { VectorNormalize2( ent->velocity, dir ); } G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, ent->projectileInfo.maxDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, 0, ent->style ); } G_RadiusDamage( ent, ent->r.owner, plane, other, MOD_GUNBLADE_S ); // add explosion event if( ( !other->takedamage || ISBRUSHMODEL( other->s.modelindex ) ) ) { edict_t *event; event = G_SpawnEvent( EV_GUNBLADEBLAST_IMPACT, DirToByte( plane ? plane->normal : NULL ), ent->s.origin ); event->s.weapon = ( ( ent->projectileInfo.radius * 1/8 ) > 127 ) ? 127 : ( ent->projectileInfo.radius * 1/8 ); event->s.skinnum = ( ( ent->projectileInfo.maxKnockback * 1/8 ) > 255 ) ? 255 : ( ent->projectileInfo.maxKnockback * 1/8 ); } // free at next frame G_FreeEdict( ent ); }
void ThrowSmallPileOfGibs( edict_t *self, int damage ) { vec3_t origin; edict_t *event; int contents; int i; contents = G_PointContents( self->s.origin ); if( contents & CONTENTS_NODROP ) return; for( i = 0; i < 3; i++ ) origin[i] = self->s.origin[i] + ( 0.5f * ( self->r.maxs[i] + self->r.mins[i] ) ) + 24; event = G_SpawnEvent( EV_SPOG, damage, origin ); event->r.svflags |= SVF_TRANSMITORIGIN2; VectorCopy( self->velocity, event->s.origin2 ); }
/* * W_Fire_Bullet */ void W_Fire_Bullet( edict_t *self, vec3_t start, vec3_t angles, int seed, int range, int spread, float damage, int knockback, int stun, int mod, int timeDelta ) { vec3_t dir; edict_t *event; float r, u; double alpha, s; trace_t trace; int dmgflags = DAMAGE_STUN_CLAMP|DAMAGE_KNOCKBACK_SOFT; if( GS_Instagib() ) damage = 9999; AngleVectors( angles, dir, NULL, NULL ); // send the event event = G_SpawnEvent( EV_FIRE_BULLET, seed, start ); event->s.ownerNum = ENTNUM( self ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 4096, event->s.origin2 ); // DirToByte is too inaccurate event->s.weapon = WEAP_MACHINEGUN; if( mod == MOD_MACHINEGUN_S ) event->s.weapon |= EV_INVERSE; // circle shape alpha = M_PI * Q_crandom( &seed ); // [-PI ..+PI] s = fabs( Q_crandom( &seed ) ); // [0..1] r = s * cos( alpha ) * spread; u = s * sin( alpha ) * spread; GS_TraceBullet( &trace, start, dir, r, u, range, ENTNUM( self ), timeDelta ); if( trace.ent != -1 ) { if( game.edicts[trace.ent].takedamage ) { G_Damage( &game.edicts[trace.ent], self, self, dir, dir, trace.endpos, damage, knockback, stun, dmgflags, mod ); } else { if( !( trace.surfFlags & SURF_NOIMPACT ) ) { } } } }
void W_Fire_Riotgun( edict_t *self, vec3_t start, vec3_t fv, vec3_t rv, vec3_t uv, int seed, int range, int hspread, int vspread, int count, float damage, int knockback, int stun, int mod, int timeDelta ) { edict_t *event; int dmgflags = 0; if( GS_Instagib() ) { damage = 9999; } // send the event event = G_SpawnEvent( EV_FIRE_RIOTGUN, seed, start ); event->s.ownerNum = ENTNUM( self ); VectorCopy( fv, event->s.origin2 ); VectorCopy( rv, event->s.origin3 ); event->s.weapon = WEAP_RIOTGUN; event->s.firemode = ( mod == MOD_RIOTGUN_S ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; W_Fire_SunflowerBucket( self, start, fv, rv, uv, &seed, count, hspread, vspread, range, damage, knockback, stun, dmgflags, mod, timeDelta ); }
/* * W_Grenade_ExplodeDir */ static void W_Grenade_ExplodeDir( edict_t *ent, vec3_t normal ) { vec3_t origin; int radius; edict_t *event; vec3_t up = { 0, 0, 1 }; vec_t *dir = normal ? normal : up; G_RadiusDamage( ent, ent->r.owner, NULL, ent->enemy, ( ent->s.effects & EF_STRONG_WEAPON ) ? MOD_GRENADE_SPLASH_S : MOD_GRENADE_SPLASH_W ); radius = ( ( ent->projectileInfo.radius * 1 / 8 ) > 127 ) ? 127 : ( ent->projectileInfo.radius * 1 / 8 ); VectorMA( ent->s.origin, -0.02, ent->velocity, origin ); event = G_SpawnEvent( EV_GRENADE_EXPLOSION, ( dir ? DirToByte( dir ) : 0 ), ent->s.origin ); event->s.firemode = ( ent->s.effects & EF_STRONG_WEAPON ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; event->s.weapon = radius; G_FreeEdict( ent ); }
void G_BOTvsay_f( edict_t *ent, const char *msg, bool team ) { edict_t *event = NULL; g_vsays_t *vsay; const char *text = NULL; if( !( ent->r.svflags & SVF_FAKECLIENT ) ) return; if( ent->r.client && ( ent->r.client->muted & 2 ) ) return; for( vsay = g_vsays; vsay->name; vsay++ ) { if( !Q_stricmp( msg, vsay->name ) ) { event = G_SpawnEvent( EV_VSAY, vsay->id, NULL ); text = vsay->message; break; } } if( event && text ) { event->r.svflags |= SVF_BROADCAST; // force sending even when not in PVS event->s.ownerNum = ent->s.number; if( team ) { event->s.team = ent->s.team; event->r.svflags |= SVF_ONLYTEAM; // send only to clients with the same ->s.team value } if( team ) G_Say_Team( ent, va( "(v) %s", text ), false ); else G_ChatMsg( NULL, ent, false, "(v) %s", text ); } }
/* * W_Fire_Blade */ void W_Fire_Blade( edict_t *self, int range, vec3_t start, vec3_t angles, float damage, int knockback, int stun, int mod, int timeDelta ) { edict_t *event, *other = NULL; vec3_t end; trace_t trace; int mask = MASK_SHOT; vec3_t dir; int dmgflags = 0; if( GS_Instagib() ) damage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); if( GS_RaceGametype() ) mask = MASK_SOLID; G_Trace4D( &trace, start, NULL, NULL, end, self, MASK_SHOT, timeDelta ); if( trace.ent == -1 ) //didn't touch anything return; // find out what touched other = &game.edicts[trace.ent]; if( !other->takedamage ) // it was the world { // wall impact VectorMA( trace.endpos, -0.02, dir, end ); event = G_SpawnEvent( EV_BLADE_IMPACT, 0, end ); event->s.ownerNum = ENTNUM( self ); VectorScale( trace.plane.normal, 1024, event->s.origin2 ); event->r.svflags = SVF_TRANSMITORIGIN2; return; } // it was a player G_Damage( other, self, self, dir, dir, other->s.origin, damage, knockback, stun, dmgflags, mod ); }
void W_Fire_Riotgun( edict_t *self, vec3_t start, vec3_t angles, int seed, int range, int spread, int count, float damage, int knockback, int stun, int mod, int timeDelta ) { vec3_t dir; edict_t *event; int dmgflags = 0; if( GS_Instagib() ) damage = 9999; AngleVectors( angles, dir, NULL, NULL ); // send the event event = G_SpawnEvent( EV_FIRE_RIOTGUN, seed, start ); event->s.ownerNum = ENTNUM( self ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 4096, event->s.origin2 ); // DirToByte is too inaccurate event->s.weapon = WEAP_RIOTGUN; if( mod == MOD_RIOTGUN_S ) event->s.weapon |= EV_INVERSE; G_Fire_SpiralPattern( self, start, dir, &seed, count, spread, range, damage, knockback, stun, dmgflags, mod, timeDelta ); }
/* * W_Fire_Bullet */ void W_Fire_Bullet( edict_t *self, vec3_t start, vec3_t fv, vec3_t rv, vec3_t uv, int seed, int range, int hspread, int vspread, float damage, int knockback, int stun, int mod, int timeDelta ) { edict_t *event; float r, u; double alpha, s; trace_t trace; int dmgflags = DAMAGE_STUN_CLAMP | DAMAGE_KNOCKBACK_SOFT; if( GS_Instagib() ) { damage = 9999; } // send the event event = G_SpawnEvent( EV_FIRE_BULLET, seed, start ); event->s.ownerNum = ENTNUM( self ); VectorCopy( fv, event->s.origin2 ); VectorCopy( rv, event->s.origin3 ); event->s.weapon = WEAP_MACHINEGUN; event->s.firemode = ( mod == MOD_MACHINEGUN_S ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; // circle shape alpha = M_PI * Q_crandom( &seed ); // [-PI ..+PI] s = fabs( Q_crandom( &seed ) ); // [0..1] r = s * cos( alpha ) * hspread; u = s * sin( alpha ) * vspread; GS_TraceBullet( &trace, start, fv, rv, uv, r, u, range, ENTNUM( self ), timeDelta ); if( trace.ent != -1 ) { if( game.edicts[trace.ent].takedamage ) { G_Damage( &game.edicts[trace.ent], self, self, fv, fv, trace.endpos, damage, knockback, stun, dmgflags, mod ); } else { if( !( trace.surfFlags & SURF_NOIMPACT ) ) { } } } }
/* * G_vsay_f */ static void G_vsay_f( edict_t *ent, bool team ) { edict_t *event = NULL; g_vsays_t *vsay; const char *text = NULL; char *msg = trap_Cmd_Argv( 1 ); if( ent->r.client && ent->r.client->muted & 2 ) return; if( ( !GS_TeamBasedGametype() || GS_InvidualGameType() ) && ent->s.team != TEAM_SPECTATOR ) team = false; if( !( ent->r.svflags & SVF_FAKECLIENT ) ) { // ignore flood checks on bots if( ent->r.client->level.last_vsay > game.realtime - 500 ) return; // ignore silently vsays in that come in rapid succession ent->r.client->level.last_vsay = game.realtime; if( CheckFlood( ent, false ) ) return; } for( vsay = g_vsays; vsay->name; vsay++ ) { if( !Q_stricmp( msg, vsay->name ) ) { event = G_SpawnEvent( EV_VSAY, vsay->id, NULL ); text = vsay->message; break; } } if( event && text ) { char saystring[256]; event->r.svflags |= SVF_BROADCAST; // force sending even when not in PVS event->s.ownerNum = ent->s.number; if( team ) { event->s.team = ent->s.team; event->r.svflags |= SVF_ONLYTEAM; // send only to clients with the same ->s.team value } if( trap_Cmd_Argc() > 2 ) { int i; saystring[0] = 0; for( i = 2; i < trap_Cmd_Argc(); i++ ) { Q_strncatz( saystring, trap_Cmd_Argv( i ), sizeof( saystring ) ); Q_strncatz( saystring, " ", sizeof( saystring ) ); } text = saystring; } if( team ) G_Say_Team( ent, va( "(v) %s", text ), false ); else G_ChatMsg( NULL, ent, false, "(v) %s", text ); return; } // unknown token, print help { char string[MAX_STRING_CHARS]; // print information string[0] = 0; if( msg && msg[0] != '\0' ) Q_strncatz( string, va( "%sUnknown vsay token%s \"%s\"\n", S_COLOR_YELLOW, S_COLOR_WHITE, msg ), sizeof( string ) ); Q_strncatz( string, va( "%svsays:%s\n", S_COLOR_YELLOW, S_COLOR_WHITE ), sizeof( string ) ); for( vsay = g_vsays; vsay->name; vsay++ ) { if( strlen( vsay->name ) + strlen( string ) < sizeof( string ) - 6 ) { Q_strncatz( string, va( "%s ", vsay->name ), sizeof( string ) ); } } Q_strncatz( string, "\n", sizeof( string ) ); G_PrintMsg( ent, string ); } }
/* * G_EdictsAddSnapEffects * add effects based on accumulated info along the server frame */ static void G_SnapEntities( void ) { edict_t *ent; int i; vec3_t dir, origin; for( i = 0, ent = &game.edicts[0]; i < game.numentities; i++, ent++ ) { if( !ent->r.inuse || ( ent->r.svflags & SVF_NOCLIENT ) ) continue; if( ent->s.type == ET_PARTICLES ) // particles use a special configuration { ent->s.frame = ent->particlesInfo.speed; ent->s.modelindex = ent->particlesInfo.shaderIndex; ent->s.modelindex2 = ent->particlesInfo.spread; ent->s.counterNum = ent->particlesInfo.time; ent->s.weapon = ent->particlesInfo.frequency; ent->s.effects = ent->particlesInfo.size & 0xFF; if( ent->particlesInfo.spherical ) ent->s.effects |= ( 1<<8 ); if( ent->particlesInfo.bounce ) ent->s.effects |= ( 1<<9 ); if( ent->particlesInfo.gravity ) ent->s.effects |= ( 1<<10 ); if( ent->particlesInfo.expandEffect ) ent->s.effects |= ( 1<<11 ); if( ent->particlesInfo.shrinkEffect ) ent->s.effects |= ( 1<<11 ); GClip_LinkEntity( ent ); continue; } if( ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE ) { // this is pretty hackish. We exploit the fact that 0.5 servers *do not* transmit // origin2/old_origin for ET_PLAYER/ET_CORPSE entities, and we use it for sending the player velocity if( !G_ISGHOSTING( ent ) ) { ent->r.svflags |= SVF_TRANSMITORIGIN2; VectorCopy( ent->velocity, ent->s.origin2 ); } else ent->r.svflags &= ~SVF_TRANSMITORIGIN2; } if( ISEVENTENTITY( ent ) || G_ISGHOSTING( ent ) || !ent->takedamage ) continue; // types which can have accumulated damage effects if( ( ent->s.type == ET_GENERIC || ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE ) ) // doors don't bleed { // Until we get a proper damage saved effect, we accumulate both into the blood fx // so, at least, we don't send 2 entities where we can send one ent->snap.damage_taken += ent->snap.damage_saved; //ent->snap.damage_saved = 0; //spawn accumulated damage if( ent->snap.damage_taken && !( ent->flags & FL_GODMODE ) && HEALTH_TO_INT( ent->health ) > 0 ) { edict_t *event; float damage = ent->snap.damage_taken; if( damage > 120 ) damage = 120; VectorCopy( ent->snap.damage_dir, dir ); VectorNormalize( dir ); VectorAdd( ent->s.origin, ent->snap.damage_at, origin ); if( ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE ) { event = G_SpawnEvent( EV_BLOOD, DirToByte( dir ), origin ); event->s.damage = HEALTH_TO_INT( damage ); event->s.ownerNum = i; // set owner // ET_PLAYERS can also spawn sound events if( ent->s.type == ET_PLAYER ) { // play an apropriate pain sound if( level.time >= ent->pain_debounce_time ) { // see if it should pain for a FALL or for damage received if( ent->snap.damage_fall ) { ent->pain_debounce_time = level.time + 200; } else if( !G_IsDead( ent ) ) { if( ent->r.client->ps.inventory[POWERUP_SHELL] > 0 ) G_AddEvent( ent, EV_PAIN, PAIN_WARSHELL, true ); else if( ent->health <= 20 ) G_AddEvent( ent, EV_PAIN, PAIN_20, true ); else if( ent->health <= 35 ) G_AddEvent( ent, EV_PAIN, PAIN_30, true ); else if( ent->health <= 60 ) G_AddEvent( ent, EV_PAIN, PAIN_60, true ); else G_AddEvent( ent, EV_PAIN, PAIN_100, true ); ent->pain_debounce_time = level.time + 400; } } } } else { event = G_SpawnEvent( EV_SPARKS, DirToByte( dir ), origin ); event->s.damage = HEALTH_TO_INT( damage ); } } } } }
/* * W_Fire_Instagun_Strong */ void W_Fire_Instagun( edict_t *self, vec3_t start, vec3_t angles, float damage, int knockback, int stun, int radius, int range, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event; int mask; qboolean missed = qtrue; int dmgflags = 0; if( GS_Instagib() ) damage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched if( tr.ent == world->s.number || game.edicts[tr.ent].movetype == MOVETYPE_NONE || game.edicts[tr.ent].movetype == MOVETYPE_PUSH ) { if( g_instajump->integer && self && self->r.client ) { // create a temporary inflictor entity edict_t *inflictor; inflictor = G_Spawn(); inflictor->s.solid = SOLID_NOT; inflictor->timeDelta = 0; VectorCopy( tr.endpos, inflictor->s.origin ); inflictor->s.ownerNum = ENTNUM( self ); inflictor->projectileInfo.maxDamage = 0; inflictor->projectileInfo.minDamage = 0; inflictor->projectileInfo.maxKnockback = knockback; inflictor->projectileInfo.minKnockback = 1; inflictor->projectileInfo.stun = 0; inflictor->projectileInfo.radius = radius; G_RadiusDamage( inflictor, self, &tr.plane, NULL, mod ); G_FreeEdict( inflictor ); } break; } // allow trail to go through SOLID_BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( game.edicts[tr.ent].s.modelindex ) ) ignore = &game.edicts[tr.ent]; if( ( &game.edicts[tr.ent] != self ) && ( game.edicts[tr.ent].takedamage ) ) { G_Damage( &game.edicts[tr.ent], self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_INSTA_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = FIRE_MODE_STRONG; if( game.edicts[tr.ent].r.client ) missed = qfalse; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_INSTATRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); }
void W_Fire_Electrobolt_FullInstant( edict_t *self, vec3_t start, vec3_t angles, float maxdamage, float mindamage, int maxknockback, int minknockback, int stun, int range, int minDamageRange, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event, *hit, *damaged; int mask; qboolean missed = qtrue; int dmgflags = 0; #define FULL_DAMAGE_RANGE g_projectile_prestep->value if( GS_Instagib() ) maxdamage = mindamage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; hit = damaged = NULL; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); clamp_high( minDamageRange, range ); if( minDamageRange <= FULL_DAMAGE_RANGE ) minDamageRange = FULL_DAMAGE_RANGE + 1; if( range <= FULL_DAMAGE_RANGE + 1 ) range = FULL_DAMAGE_RANGE + 1; tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched hit = &game.edicts[tr.ent]; if( hit == world ) // stop dead if hit the world break; if( hit->movetype == MOVETYPE_NONE || hit->movetype == MOVETYPE_PUSH ) break; // allow trail to go through BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( hit->s.modelindex ) ) ignore = hit; if( ( hit != self ) && ( hit->takedamage ) ) { float frac, damage, knockback, dist; dist = DistanceFast( tr.endpos, start ); if( dist <= FULL_DAMAGE_RANGE ) frac = 0.0f; else { frac = ( dist - FULL_DAMAGE_RANGE ) / (float)( minDamageRange - FULL_DAMAGE_RANGE ); clamp( frac, 0.0f, 1.0f ); } damage = maxdamage - ( ( maxdamage - mindamage ) * frac ); knockback = maxknockback - ( ( maxknockback - minknockback ) * frac ); //G_Printf( "mindamagerange %i frac %.1f damage %i\n", minDamageRange, 1.0f - frac, (int)damage ); G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = FIRE_MODE_STRONG; if( hit->r.client ) missed = qfalse; damaged = hit; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_ELECTROTRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); event->s.firemode = FIRE_MODE_STRONG; #undef FULL_DAMAGE_RANGE }
/* * W_Fire_Electrobolt_Combined */ void W_Fire_Electrobolt_Combined( edict_t *self, vec3_t start, vec3_t angles, float maxdamage, float mindamage, float maxknockback, float minknockback, int stun, int range, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event, *hit, *damaged; int mask; qboolean missed = qtrue; int dmgflags = 0; int fireMode; #ifdef ELECTROBOLT_TEST fireMode = FIRE_MODE_WEAK; #else fireMode = FIRE_MODE_STRONG; #endif if( GS_Instagib() ) maxdamage = mindamage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; hit = damaged = NULL; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched hit = &game.edicts[tr.ent]; if( hit == world ) // stop dead if hit the world break; if( hit->movetype == MOVETYPE_NONE || hit->movetype == MOVETYPE_PUSH ) break; // allow trail to go through BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( hit->s.modelindex ) ) ignore = hit; if( ( hit != self ) && ( hit->takedamage ) ) { float frac, damage, knockback; frac = DistanceFast( tr.endpos, start ) / (float)range; clamp( frac, 0.0f, 1.0f ); damage = maxdamage - ( ( maxdamage - mindamage ) * frac ); knockback = maxknockback - ( ( maxknockback - minknockback ) * frac ); G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = fireMode; if( hit->r.client ) missed = qfalse; damaged = hit; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_ELECTROTRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); event->s.firemode = fireMode; if( !GS_Instagib() && tr.ent == -1 ) // didn't touch anything, not even a wall { edict_t *bolt; gs_weapon_definition_t *weapondef = GS_GetWeaponDef( self->s.weapon ); // fire a weak EB from the end position bolt = W_Fire_Electrobolt_Weak( self, end, angles, weapondef->firedef_weak.speed, mindamage, minknockback, minknockback, stun, weapondef->firedef_weak.timeout, mod, timeDelta ); bolt->enemy = damaged; } }
//QUAKED target_laser (0 .5 0) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE YELLOW ORANGE FAT //When triggered, fires a laser. You can either set a target or a direction. //-------- KEYS -------- //angles: alternate "pitch, yaw, roll" angles method of aiming laser (default 0 0 0). //target : point this to a target_position entity to set the laser's aiming direction. //targetname : the activating trigger points to this. //notsingle : when set to 1, entity will not spawn in Single Player mode //notfree : when set to 1, entity will not spawn in "Free for all" and "Tournament" modes. //notduel : when set to 1, entity will not spawn in "Teamplay" and "CTF" modes. (jal: todo) //notteam : when set to 1, entity will not spawn in "Teamplay" and "CTF" modes. //notctf : when set to 1, entity will not spawn in "Teamplay" and "CTF" modes. (jal: todo) //-------- SPAWNFLAGS -------- //START_ON : when set, the laser will start on in the game. //RED : //GREEN : BLUE : //YELLOW : //ORANGE : //FAT : static void target_laser_think( edict_t *self ) { edict_t *ignore; vec3_t start; vec3_t end; trace_t tr; vec3_t point; vec3_t last_movedir; int count; // our lifetime has expired if( self->delay && ( self->wait * 1000 < level.time ) ) { if( self->r.owner && self->r.owner->use ) G_CallUse( self->r.owner, self, self->activator ); G_FreeEdict( self ); return; } if( self->spawnflags & 0x80000000 ) count = 8; else count = 4; if( self->enemy ) { VectorCopy( self->moveinfo.movedir, last_movedir ); VectorMA( self->enemy->r.absmin, 0.5, self->enemy->r.size, point ); VectorSubtract( point, self->s.origin, self->moveinfo.movedir ); VectorNormalize( self->moveinfo.movedir ); if( !VectorCompare( self->moveinfo.movedir, last_movedir ) ) self->spawnflags |= 0x80000000; } ignore = self; VectorCopy( self->s.origin, start ); VectorMA( start, 2048, self->moveinfo.movedir, end ); VectorClear( tr.endpos ); // shut up compiler while( 1 ) { G_Trace( &tr, start, NULL, NULL, end, ignore, MASK_SHOT ); if( tr.fraction == 1 ) break; // hurt it if we can if( ( game.edicts[tr.ent].takedamage ) && !( game.edicts[tr.ent].flags & FL_IMMUNE_LASER ) ) { if( game.edicts[tr.ent].r.client && self->activator->r.client ) { if( !GS_TeamBasedGametype() || game.edicts[tr.ent].s.team != self->activator->s.team ) G_Damage( &game.edicts[tr.ent], self, self->activator, self->moveinfo.movedir, self->moveinfo.movedir, tr.endpos, self->dmg, 1, 0, 0, self->count ); } else { G_Damage( &game.edicts[tr.ent], self, self->activator, self->moveinfo.movedir, self->moveinfo.movedir, tr.endpos, self->dmg, 1, 0, 0, self->count ); } } // if we hit something that's not a monster or player or is immune to lasers, we're done if( !game.edicts[tr.ent].r.client ) { if( self->spawnflags & 0x80000000 ) { edict_t *event; self->spawnflags &= ~0x80000000; event = G_SpawnEvent( EV_LASER_SPARKS, DirToByte( tr.plane.normal ), tr.endpos ); event->s.eventCount = count; event->s.colorRGBA = self->s.colorRGBA; } break; } ignore = &game.edicts[tr.ent]; VectorCopy( tr.endpos, start ); } VectorCopy( tr.endpos, self->s.origin2 ); G_SetBoundsForSpanEntity( self, 8 ); GClip_LinkEntity( self ); self->nextThink = level.time + 1; }
//QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8) //Fire an origin based temp entity event to the clients. //"style" type byte static void Use_Target_Tent( edict_t *ent, edict_t *other, edict_t *activator ) { G_SpawnEvent( ent->style, 0, ent->s.origin ); }