/** * @brief */ static void G_trigger_hurt_Touch(g_entity_t *self, g_entity_t *other, const cm_bsp_plane_t *plane, const cm_bsp_texinfo_t *surf) { if (!other->locals.take_damage) { // deal with items that land on us if (other->locals.item) { if (other->locals.item->type == ITEM_FLAG) { G_ResetDroppedFlag(other); } else if (other->locals.item->type == ITEM_TECH) { G_ResetDroppedTech(other); } else { G_FreeEntity(other); } } gi.Debug("%s\n", etos(other)); return; } if (self->locals.timestamp > g_level.time) { return; } if (self->locals.spawn_flags & 16) { self->locals.timestamp = g_level.time + 1000; } else { self->locals.timestamp = g_level.time + 100; } const int16_t d = self->locals.damage; int32_t dflags = DMG_NO_ARMOR; if (self->locals.spawn_flags & 8) { dflags = DMG_NO_GOD; } G_Damage(other, self, NULL, NULL, NULL, NULL, d, d, dflags, MOD_TRIGGER_HURT); }
void env_afx_hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { int dflags; if ( !other->takedamage ) { return; } if ( self->timestamp > level.time ) { return; } if ( self->spawnflags & 16 ) { self->timestamp = level.time + 1000; } else { self->timestamp = level.time + FRAMETIME; } // play sound if ( !( self->spawnflags & 4 ) ) { G_Sound( other, CHAN_AUTO, self->soundIndex ); } if ( self->spawnflags & 8 ) { dflags = DAMAGE_NO_PROTECTION; } else { dflags = 0; } G_Damage( other, self, self, NULL, NULL, self->damage, dflags, MOD_TRIGGER_HURT ); }
/* =============== meleeAttack =============== */ void meleeAttack( gentity_t *ent, float range, float width, int damage, meansOfDeath_t mod ) { trace_t tr; vec3_t end; gentity_t *tent; gentity_t *traceEnt; vec3_t mins, maxs; VectorSet( mins, -width, -width, -width ); VectorSet( maxs, width, width, width ); // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); VectorMA( muzzle, range, forward, end ); G_UnlaggedOn( muzzle, range ); trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT ); G_UnlaggedOff( ); if( tr.surfaceFlags & SURF_NOIMPACT ) return; traceEnt = &g_entities[ tr.entityNum ]; // send blood impact if( traceEnt->takedamage && traceEnt->client ) { tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); tent->s.otherEntityNum = traceEnt->s.number; tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.weapon = ent->s.weapon; tent->s.generic1 = ent->s.generic1; //weaponMode } if( traceEnt->takedamage ) G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, mod ); }
/* ================ ProximityMine_ExplodeOnPlayer ================ */ static void ProximityMine_ExplodeOnPlayer(gentity_t * mine) { gentity_t *player; player = mine->enemy; player->client->ps.eFlags &= ~EF_TICKING; if(player->client->invulnerabilityTime > level.time) { G_Damage(player, mine->parent, mine->parent, vec3_origin, mine->s.origin, 1000, DAMAGE_NO_KNOCKBACK, MOD_JUICED); player->client->invulnerabilityTime = 0; G_TempEntity(player->client->ps.origin, EV_JUICED); } else { G_SetOrigin(mine, player->s.pos.trBase); // make sure the explosion gets to the client mine->r.svFlags &= ~SVF_NOCLIENT; mine->splashMethodOfDeath = MOD_PROXIMITY_MINE; G_ExplodeMissile(mine); } }
/* ====================================================================== TESLA GENERATOR ====================================================================== */ void teslaFire( gentity_t *self ) { trace_t tr; vec3_t origin, target; gentity_t *tent; if( !self->enemy ) return; // Move the muzzle from the entity origin up a bit to fire over turrets VectorMA( muzzle, self->r.maxs[ 2 ], self->s.origin2, origin ); // Don't aim for the center, aim at the top of the bounding box VectorCopy( self->enemy->s.origin, target ); target[ 2 ] += self->enemy->r.maxs[ 2 ]; // Trace to the target entity trap_Trace( &tr, origin, NULL, NULL, target, self->s.number, MASK_SHOT ); if( tr.entityNum != self->enemy->s.number ) return; // Client side firing effect self->s.eFlags |= EF_FIRING; // Deal damage if( self->enemy->takedamage ) { vec3_t dir; VectorSubtract( target, origin, dir ); G_Damage( self->enemy, self, self, dir, tr.endpos, TESLAGEN_DMG, 0, MOD_TESLAGEN ); } // Send tesla zap trail tent = G_TempEntity( tr.endpos, EV_TESLATRAIL ); tent->s.generic1 = self->s.number; // src tent->s.clientNum = self->enemy->s.number; // dest }
void G_KillEnts(const char *target, gentity_t *ignore, gentity_t *killer, meansOfDeath_t mod) { gentity_t *targ = NULL; while ((targ = G_FindByTargetname(targ, target))) { // make sure it isn't going to respawn or show any events targ->nextthink = 0; if (targ == ignore) { continue; } // script_movers should die! if (targ->s.eType == ET_MOVER && !Q_stricmp(targ->classname, "script_mover") && targ->die) { G_Damage(targ, killer, killer, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG); continue; } if (targ->s.eType == ET_CONSTRUCTIBLE) { if (killer) { G_AddKillSkillPointsForDestruction(killer, mod, &targ->constructibleStats); } targ->die(targ, killer, killer, targ->health, 0); continue; } trap_UnlinkEntity(targ); targ->nextthink = level.time + FRAMETIME; targ->use = NULL; targ->touch = NULL; targ->think = G_FreeEntity; } }
/* ================= G_KillBox Kills all entities that would touch the proposed new positioning of ent. Ent should be unlinked before calling this! ================= */ void G_KillBox (gentity_t *ent) { int i, num; int touch[MAX_GENTITIES]; gentity_t *hit; vec3_t mins, maxs; VectorAdd( ent->client->ps.origin, ent->r.mins, mins ); VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs ); num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES ); for (i=0 ; i<num ; i++) { hit = &g_entities[touch[i]]; if ( !hit->client ) { continue; } // nail it G_Damage ( hit, ent, ent, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG); } }
void script_mover_blocked(gentity_t *ent, gentity_t *other) { // remove it, we must not stop for anything or it will screw up script timing if (!other->client && other->s.eType != ET_CORPSE) { // /me slaps nerve // except CTF flags!!!! if (other->s.eType == ET_ITEM && other->item->giType == IT_TEAM) { Team_DroppedFlagThink(other); return; } G_TempEntity(other->s.origin, EV_ITEM_POP); G_FreeEntity(other); return; } // FIXME: we could have certain entities stop us, thereby "pausing" movement // until they move out the way. then we can just call the GotoMarker() again, // telling it that we are just now calling it for the first time, so it should // start us on our way again (theoretically speaking). // kill them G_Damage(other, ent, ent, NULL, NULL, 9999, 0, MOD_CRUSH); }
/* =============== lasGunFire =============== */ void lasGunFire( gentity_t *ent ) { trace_t tr; vec3_t end; gentity_t *tent; gentity_t *traceEnt; VectorMA( muzzle, 8192 * 16, forward, end ); trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); if( tr.surfaceFlags & SURF_NOIMPACT ) return; traceEnt = &g_entities[ tr.entityNum ]; // snap the endpos to integers, but nudged towards the line SnapVectorTowards( tr.endpos, muzzle ); // send impact if( traceEnt->takedamage && traceEnt->client ) { tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); tent->s.otherEntityNum = traceEnt->s.number; tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.weapon = ent->s.weapon; tent->s.generic1 = ent->s.generic1; //weaponMode } else { tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS ); tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.weapon = ent->s.weapon; tent->s.generic1 = ent->s.generic1; //weaponMode } if( traceEnt->takedamage ) G_Damage( traceEnt, ent, ent, forward, tr.endpos, LASGUN_DAMAGE, 0, MOD_LASGUN ); }
/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF - SILENT NO_PROTECTION SLOW ONCE Any entity that touches this will be hurt. It does dmg points of damage each server frame Targeting the trigger will toggle its on / off state. SILENT supresses playing the sound SLOW changes the damage rate to once per second NO_PROTECTION *nothing* stops the damage "dmg" default 5 (whole numbers only) "life" time this brush will exist if value is zero will live for ever ei 0.5 sec 2.sec default is zero the entity must be used first before it will count down its life */ void hurt_touch(gentity_t *self, gentity_t *other, trace_t *trace) { int dflags; // Nico, silent GCC (void)trace; if (!other->takedamage) { return; } if (self->timestamp > level.time) { return; } // Nico, make hurt triggers slow if (self->spawnflags & 16) { self->timestamp = level.time + 1000; } else { self->timestamp = level.time + FRAMETIME; } // play sound if (!(self->spawnflags & 4)) { G_Sound(other, self->noise_index); } if (self->spawnflags & 8) { dflags = DAMAGE_NO_PROTECTION; } else { dflags = 0; } G_Damage(other, self, self, NULL, NULL, self->damage, dflags, MOD_TRIGGER_HURT); if (self->spawnflags & 32) { self->touch = NULL; } }
/* =============== AIFunc_LoperAttack1() Loper's close range melee attack =============== */ char *AIFunc_LoperAttack1( cast_state_t *cs ) { trace_t *tr; gentity_t *ent; int anim; // ent = &g_entities[cs->entityNum]; // // draw the client-side lightning effect //ent->client->ps.eFlags |= EF_MONSTER_EFFECT; // // have we inflicted the damage? if ( cs->weaponFireTimes[WP_MONSTER_ATTACK1] > cs->thinkFuncChangeTime ) { // has the animation finished? if ( !ent->client->ps.legsTimer ) { return AIFunc_DefaultStart( cs ); } return NULL; // just wait for anim to finish } // ready to inflict damage? anim = ( ent->client->ps.legsAnim & ~ANIM_TOGGLEBIT ) - BG_AnimationIndexForString( "legs_extra", cs->entityNum ); if ( cs->thinkFuncChangeTime < level.time - loperHitTimes[anim] ) { // check for damage // TTimo: gcc: suggests () around assignment used as truth value if ( ( tr = CheckMeleeAttack( &g_entities[cs->entityNum], LOPER_MELEE_RANGE, qfalse ) ) ) { G_Damage( &g_entities[tr->entityNum], ent, ent, vec3_origin, tr->endpos, LOPER_MELEE_DAMAGE, 0, MOD_LOPER_HIT ); // sound if ( anim == 0 ) { G_AddEvent( ent, EV_GENERAL_SOUND, G_SoundIndex( aiDefaults[ent->aiCharacter].soundScripts[ORDERSDENYSOUNDSCRIPT] ) ); } else { G_AddEvent( ent, EV_GENERAL_SOUND, G_SoundIndex( aiDefaults[ent->aiCharacter].soundScripts[MISC1SOUNDSCRIPT] ) ); } } cs->weaponFireTimes[WP_MONSTER_ATTACK1] = level.time; } return NULL; }
/* ================ G_ProcessFlare If an player is close to the entity, hurt! ================ */ void G_ProcessFlare(gentity_t *ent) { int i, total_entities, entityList[MAX_GENTITIES]; vec3_t range, mins, maxs; gentity_t *target; if (level.time > ent->s.time + 30000) { ent->nextthink = level.time + 100; ent->think = G_ExplodeMissile; return; } // Set the next time to run this check (can be overwritten below) ent->nextthink = level.time + FLARE_CHECK_FREQUENCY; // Grab all entities around us VectorSet(range, FLARE_DETECT, FLARE_DETECT, FLARE_DETECT); VectorAdd(ent->s.origin, range, maxs); VectorSubtract(ent->s.origin, range, mins); total_entities = trap_EntitiesInBox(mins, maxs, entityList, MAX_GENTITIES); // Loop entities looking for an enemy body for(i=0; i<total_entities; i++) { target = &g_entities[entityList[i]]; if(target->client) { if (G_Visible( ent, target, MASK_SHOT )) { // Found an enemy, hurt time! G_Damage( target, ent, ent->parent, NULL, ent->s.origin, ent->damage, 0, ent->methodOfDeath ); //ent->nextthink = level.time + MINE_BOOM_TIME; //ent->think = G_ExplodeMissile; return; } } } }
/* * 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 shipboundary_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { gentity_t *ent; if (!other || !other->inuse || !other->client || other->s.number < MAX_CLIENTS || !other->m_pVehicle) { //only let vehicles touch return; } if ( other->client->ps.hyperSpaceTime && level.time - other->client->ps.hyperSpaceTime < HYPERSPACE_TIME ) {//don't interfere with hyperspacing ships return; } ent = G_Find (NULL, FOFS(targetname), self->target); if (!ent || !ent->inuse) { //this is bad trap->Error(ERR_DROP, "trigger_shipboundary has invalid target '%s'\n", self->target); return; } if (!other->client->ps.m_iVehicleNum || other->m_pVehicle->m_iRemovedSurfaces) { //if a vehicle touches a boundary without a pilot in it or with parts missing, just blow the thing up G_Damage(other, other, other, NULL, other->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE); return; } //make sure this sucker is linked so the prediction knows where to go trap->LinkEntity((sharedEntity_t *)ent); other->client->ps.vehTurnaroundIndex = ent->s.number; other->client->ps.vehTurnaroundTime = level.time + (self->genericValue1*2); //keep up the detailed checks for another 2 seconds self->genericValue7 = level.time + 2000; }
/* ================ ShotgunPellet ================ */ void ShotgunPellet( vec3_t start, vec3_t end, gentity_t *ent ) { trace_t tr; int passent; gentity_t *traceEnt; vec3_t tr_start, tr_end; passent = ent->s.number; VectorCopy( start, tr_start ); VectorCopy( end, tr_end ); trap_Trace (&tr, tr_start, NULL, NULL, tr_end, passent, MASK_SHOT); traceEnt = &g_entities[ tr.entityNum ]; // send bullet impact if ( tr.surfaceFlags & SURF_NOIMPACT ) { return; } if ( traceEnt->takedamage ) { shotEnt = traceEnt; G_Damage( traceEnt, ent, ent, forward, tr.endpos, weLi[ent->s.weapon].damage, 0, weLi[ent->s.weapon].mod); } }
/* ================ Blocked_Door ================ */ void Blocked_Door( gentity_t *ent, gentity_t *other ) { // remove anything other than a client if ( !other->client ) { // except CTF flags!!!! if( other->s.eType == ET_ITEM && other->item->giType == IT_TEAM ) { Team_DroppedFlagThink( other ); return; } G_TempEntity( other->s.origin, EV_ITEM_POP ); G_FreeEntity( other ); return; } if ( ent->damage ) { G_Damage( other, ent, ent, NULL, NULL, ent->damage, 0, MOD_CRUSH ); } if ( ent->spawnflags & 4 ) { return; // crushers don't reverse } // reverse direction Use_BinaryMover( ent, ent, other ); }
void W_Fire_RandomBucket( edict_t *self, vec3_t start, vec3_t fv, vec3_t rv, vec3_t uv, int *seed, int count, int hspread, int vspread, int range, float damage, int kick, int stun, int dflags, int mod, int timeDelta ) { int i; float r; float u; trace_t trace; for( i = 0; i < count; i++ ) { r = Q_crandom( seed ) * hspread; u = Q_crandom( seed ) * 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, kick, stun, dflags, mod ); } else { if( !( trace.surfFlags & SURF_NOIMPACT ) ) { } } } } }
// this should match CG_ShotgunPattern void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) { int i; float r, u; vec3_t end; vec3_t forward, right, up; trace_t tr; gentity_t *traceEnt; // derive the right and up vectors from the forward vector, because // the client won't have any other information VectorNormalize2( origin2, forward ); PerpendicularVector( right, forward ); CrossProduct( forward, right, up ); // generate the "random" spread pattern for ( i = 0; i < SHOTGUN_PELLETS; i++ ) { r = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16; u = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16; VectorMA( origin, SHOTGUN_RANGE, forward, end ); VectorMA( end, r, right, end ); VectorMA( end, u, up, end ); trap_Trace( &tr, origin, NULL, NULL, end, ent->s.number, MASK_SHOT ); traceEnt = &g_entities[ tr.entityNum ]; // send bullet impact if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) { if ( traceEnt->takedamage ) { G_Damage( traceEnt, ent, ent, forward, tr.endpos, SHOTGUN_DMG, 0, MOD_SHOTGUN ); } } } }
/* =============== G_CrushAttack Should only be called if there was an impact between a tyrant and another player =============== */ void G_CrushAttack( gentity_t *ent, gentity_t *victim ) { vec3_t dir; float jump; int damage; if( !victim->takedamage || ent->client->ps.origin[ 2 ] + ent->r.mins[ 2 ] < victim->s.origin[ 2 ] + victim->r.maxs[ 2 ] || ( victim->client && victim->client->ps.groundEntityNum == ENTITYNUM_NONE ) ) return; // Deal velocity based damage to target jump = BG_Class( ent->client->ps.stats[ STAT_CLASS ] )->jumpMagnitude; damage = ( ent->client->pmext.fallVelocity + jump ) * -LEVEL4_CRUSH_DAMAGE_PER_V; if( damage < 0 ) damage = 0; // Players also get damaged periodically if( victim->client && ent->client->lastCrushTime + LEVEL4_CRUSH_REPEAT < level.time ) { ent->client->lastCrushTime = level.time; damage += LEVEL4_CRUSH_DAMAGE; } if( damage < 1 ) return; // Crush the victim over a period of time VectorSubtract( victim->s.origin, ent->client->ps.origin, dir ); G_Damage( victim, ent, ent, dir, victim->s.origin, damage, DAMAGE_NO_LOCDAMAGE, MOD_LEVEL4_CRUSH ); }
//----------------------------------------------------- void funcGlassDie( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc ) { vec3_t verts[4], normal; // if a missile is stuck to us, blow it up so we don't look dumb....we could, alternately, just let the missile drop off?? for ( int i = 0; i < MAX_GENTITIES; i++ ) { if ( g_entities[i].s.groundEntityNum == self->s.number && ( g_entities[i].s.eFlags & EF_MISSILE_STICK )) { G_Damage( &g_entities[i], self, self, NULL, NULL, 99999, 0, MOD_CRUSH ); //?? MOD? } } // Really naughty cheating. Put in an EVENT at some point... cgi_R_GetBModelVerts( cgs.inlineDrawModel[self->s.modelindex], verts, normal ); CG_DoGlass( verts, normal, self->pos1, self->pos2, self->splashRadius ); self->takedamage = qfalse;//stop chain reaction runaway loops G_SetEnemy( self, self->enemy ); //NOTE: MUST do this BEFORE clearing contents, or you may not open the area portal!!! gi.AdjustAreaPortalState( self, qtrue ); //So chunks don't get stuck inside me self->s.solid = 0; self->contents = 0; self->clipmask = 0; gi.linkentity(self); if ( self->target && attacker != NULL ) { G_UseTargets( self, attacker ); } G_FreeEntity( self ); }
bool G_CheckVenomAttack( gentity_t *self ) { trace_t tr; gentity_t *traceEnt; int damage = LEVEL0_BITE_DMG; if ( self->client->ps.weaponTime ) { return false; } // Calculate muzzle point AngleVectors( self->client->ps.viewangles, forward, right, up ); G_CalcMuzzlePoint( self, forward, right, up, muzzle ); G_WideTrace( &tr, self, LEVEL0_BITE_RANGE, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH, &traceEnt ); if ( !traceEnt || !traceEnt->takedamage || traceEnt->health <= 0 || G_OnSameTeam( self, traceEnt ) ) { return false; } // only allow bites to work against buildables in construction if ( traceEnt->s.eType == ET_BUILDABLE && traceEnt->spawned ) { return false; } SendMeleeHitEvent( self, traceEnt, &tr ); G_Damage( traceEnt, self, self, forward, tr.endpos, damage, 0, MOD_LEVEL0_BITE ); self->client->ps.weaponTime += LEVEL0_BITE_REPEAT; return true; }
/* ==================== G_KillBrushModel ==================== */ void G_KillBrushModel( gentity_t *ent, gentity_t *activator ) { gentity_t *e; vec3_t mins, maxs; trace_t tr; for( e = &g_entities[ 0 ]; e < &g_entities[ level.num_entities ]; ++e ) { if( !e->takedamage || !e->r.linked || !e->clipmask || ( e->client && e->client->noclip ) ) continue; VectorAdd( e->r.currentOrigin, e->r.mins, mins ); VectorAdd( e->r.currentOrigin, e->r.maxs, maxs ); if( !trap_EntityContact( mins, maxs, ent ) ) continue; trap_Trace( &tr, e->r.currentOrigin, e->r.mins, e->r.maxs, e->r.currentOrigin, e->s.number, e->clipmask ); if( tr.entityNum != ENTITYNUM_NONE ) G_Damage( e, ent, activator, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_CRUSH ); } }
//Sunflower spiral with Fibonacci numbers void W_Fire_SunflowerBucket( edict_t *self, vec3_t start, vec3_t fv, vec3_t rv, vec3_t uv, int *seed, int count, int hspread, int vspread, int range, float damage, int kick, int stun, int dflags, int mod, int timeDelta ) { int i; float r; float u; float fi; trace_t trace; for( i = 0; i < count; i++ ) { fi = i * 2.4; //magic value creating Fibonacci numbers r = cos( (float)*seed + fi ) * hspread * sqrt( fi ); u = sin( (float)*seed + fi ) * vspread * sqrt( fi ); 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, kick, stun, dflags, mod ); } else { if( !( trace.surfFlags & SURF_NOIMPACT ) ) { } } } } }
void G_BurnMeGood( gentity_t *self, gentity_t *body ) { // add the new damage body->flameQuota += 5; body->flameQuotaTime = level.time; // JPW NERVE -- yet another flamethrower damage model, trying to find a feels-good damage combo that isn't overpowered if ( body->lastBurnedFrameNumber != level.framenum ) { G_Damage( body, self->parent, self->parent, vec3_origin, self->r.currentOrigin, 5, 0, MOD_FLAMETHROWER ); // was 2 dmg in release ver, hit avg. 2.5 times per frame body->lastBurnedFrameNumber = level.framenum; } // jpw // make em burn if ( body->client && ( body->health <= 0 || body->flameQuota > 0 ) ) { // JPW NERVE was > FLAME_THRESHOLD if ( body->s.onFireEnd < level.time ) { body->s.onFireStart = level.time; } body->s.onFireEnd = level.time + FIRE_FLASH_TIME; body->flameBurnEnt = self->r.ownerNum; // add to playerState for client-side effect body->client->ps.onFireStart = level.time; } }
/* * W_Touch_Projectile - Generic projectile touch func. Only for replacement in tests */ static void W_Touch_Projectile( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) { vec3_t dir, normal; 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_EXPLOSIVE ); if( !plane ) { VectorSet( normal, 0, 0, 1 ); } else { VectorCopy( plane->normal, normal ); } G_Gametype_ScoreEvent( NULL, "projectilehit", va( "%i %i %f %f %f", ent->s.number, surfFlags, normal[0], normal[1], normal[2] ) ); }
/* * 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 ) ) { } } } }
//------------------------------------------ void fx_target_beam_fire( gentity_t *ent ) { trace_t trace; vec3_t dir, org, end; int ignore; qboolean open; if ( !ent->enemy || !ent->enemy->inuse ) {//info_null most likely ignore = ent->s.number; ent->enemy = NULL; VectorCopy( ent->s.origin2, org ); } else { ignore = ent->enemy->s.number; VectorCopy( ent->enemy->currentOrigin, org ); } VectorCopy( org, ent->s.origin2 ); VectorSubtract( org, ent->s.origin, dir ); VectorNormalize( dir ); gi.trace( &trace, ent->s.origin, NULL, NULL, org, ENTITYNUM_NONE, MASK_SHOT );//ignore if ( ent->spawnflags & 2 ) { open = qtrue; VectorCopy( org, end ); } else { open = qfalse; VectorCopy( trace.endpos, end ); } if ( trace.fraction < 1.0 ) { if ( trace.entityNum < ENTITYNUM_WORLD ) { gentity_t *victim = &g_entities[trace.entityNum]; if ( victim && victim->takedamage ) { if ( ent->spawnflags & 4 ) // NO_KNOCKBACK { G_Damage( victim, ent, ent->activator, dir, trace.endpos, ent->damage, DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN ); } else { G_Damage( victim, ent, ent->activator, dir, trace.endpos, ent->damage, 0, MOD_UNKNOWN ); } } } } G_AddEvent( ent, EV_TARGET_BEAM_DRAW, ent->fxID ); VectorCopy( end, ent->s.origin2 ); if ( open ) { VectorScale( dir, -1, ent->pos1 ); } else { VectorCopy( trace.plane.normal, ent->pos1 ); } ent->e_ThinkFunc = thinkF_fx_target_beam_think; ent->nextthink = level.time + FRAMETIME; }
void Weapon_LightningFire( gentity_t *ent ) { trace_t tr; vec3_t end; #if 1 vec3_t impactpoint, bouncedir; #endif gentity_t *traceEnt, *tent; int damage, i, passent; damage = 8 * s_quadFactor; passent = ent->s.number; for (i = 0; i < 10; i++) { VectorMA( muzzle, LIGHTNING_RANGE, forward, end ); trap_Trace( &tr, muzzle, NULL, NULL, end, passent, MASK_SHOT ); #if 1 // if not the first trace (the lightning bounced of an invulnerability sphere) if (i) { // add bounced off lightning bolt temp entity // the first lightning bolt is a cgame only visual // tent = G_TempEntity( muzzle, EV_LIGHTNINGBOLT ); VectorCopy( tr.endpos, end ); SnapVector( end ); VectorCopy( end, tent->s.origin2 ); } #endif if ( tr.entityNum == ENTITYNUM_NONE ) { return; } traceEnt = &g_entities[ tr.entityNum ]; if ( traceEnt->takedamage) { #if 1 if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) { if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) { G_BounceProjectile( muzzle, impactpoint, bouncedir, end ); VectorCopy( impactpoint, muzzle ); VectorSubtract( end, impactpoint, forward ); VectorNormalize(forward); // the player can hit him/herself with the bounced lightning passent = ENTITYNUM_NONE; } else { VectorCopy( tr.endpos, muzzle ); passent = traceEnt->s.number; } continue; } else { G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_LIGHTNING); } #else G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_LIGHTNING); #endif } if ( traceEnt->takedamage && traceEnt->client ) { tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); tent->s.otherEntityNum = traceEnt->s.number; tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.weapon = ent->s.weapon; if( LogAccuracyHit( traceEnt, ent ) ) { ent->client->accuracy_hits++; } } else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) { tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS ); tent->s.eventParm = DirToByte( tr.plane.normal ); } break; } }
void Bullet_Fire (gentity_t *ent, float spread, int damage ) { trace_t tr; vec3_t end; #if 1 vec3_t impactpoint, bouncedir; #endif float r, f, d; float u; gentity_t *tent; gentity_t *traceEnt; int i, passent; vec3_t forward, right, up; AngleVectors (ent->client->ps.viewangles, forward, right, up); CalcMuzzlePoint ( ent, forward, right, up, muzzle ); ent->client->accuracy_shots++; f = ((float)(ent->client->accuracy_shots % SPIRAL_SIZE)) / SPIRAL_SIZE; // 0 >= f >= 1 d = (f+(1/SPIRAL_SIZE)) * 2.0 * M_PI; damage *= s_quadFactor; //Com_Printf("f: %f, d: %f\n, a: %i", f, d, ent->client->accuracy_shots); u = sin(d) * (f * spread); r = cos(d) * (f * spread); //Com_Printf("end1 : [%f, %f, %f]\n", end[0], end[1], end[2]); VectorMA (muzzle, 8192, forward, end); //Com_Printf("end2 : [%f, %f, %f]\n", end[0], end[1], end[2]); //Com_Printf("right : [%f, %f, %f]\n", right[0], right[1], right[2]); VectorMA (end, r, right, end); //Com_Printf("end3 : [%f, %f, %f]\n", end[0], end[1], end[2]); //Com_Printf("up : [%f, %f, %f]\n", up[0], up[1], up[2]); VectorMA (end, u, up, end); //Com_Printf("end4 : [%f, %f, %f]\n", end[0], end[1], end[2]); passent = ent->s.number; for (i = 0; i < 10; i++) { trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT); if ( tr.surfaceFlags & SURF_NOIMPACT ) { return; } traceEnt = &g_entities[ tr.entityNum ]; // snap the endpos to integers, but nudged towards the line SnapVectorTowards( tr.endpos, muzzle ); // send bullet impact if ( traceEnt->takedamage && traceEnt->client ) { tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH ); tent->s.eventParm = traceEnt->s.number; if( LogAccuracyHit( traceEnt, ent ) ) { ent->client->accuracy_hits++; } } else { tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL ); tent->s.eventParm = DirToByte( tr.plane.normal ); } tent->s.otherEntityNum = ent->s.number; if ( traceEnt->takedamage) { #if 1 if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) { if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) { G_BounceProjectile( muzzle, impactpoint, bouncedir, end ); VectorCopy( impactpoint, muzzle ); // the player can hit him/herself with the bounced rail passent = ENTITYNUM_NONE; } else { VectorCopy( tr.endpos, muzzle ); passent = traceEnt->s.number; } continue; } else { #endif G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_MACHINEGUN); #if 1 } #endif } break; } }
void weapon_railgun_fire (gentity_t *ent) { vec3_t end; trace_t trace; gentity_t *tent; gentity_t *traceEnt; int damage; int i; int hits; int unlinked; int passent; gentity_t *unlinkedEntities[MAX_RAIL_HITS]; if (0) { tent = fire_bfg (ent, muzzle, forward); tent->damage *= s_quadFactor; tent->splashDamage *= s_quadFactor; return; } damage = 80 * s_quadFactor; VectorMA (muzzle, 8192, forward, end); // trace only against the solids, so the railgun will go through people unlinked = 0; hits = 0; passent = ent->s.number; do { trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT ); if ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) { break; } traceEnt = &g_entities[ trace.entityNum ]; if ( traceEnt->takedamage ) { if( LogAccuracyHit( traceEnt, ent ) ) { hits++; } G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN); } if ( trace.contents & CONTENTS_SOLID ) { break; // we hit something solid enough to stop the beam } // unlink this entity, so the next trace will go past it trap_UnlinkEntity( traceEnt ); unlinkedEntities[unlinked] = traceEnt; unlinked++; } while ( unlinked < MAX_RAIL_HITS ); // link back in any entities we unlinked for ( i = 0 ; i < unlinked ; i++ ) { trap_LinkEntity( unlinkedEntities[i] ); } // the final trace endpos will be the terminal point of the rail trail // snap the endpos to integers to save net bandwidth, but nudged towards the line SnapVectorTowards( trace.endpos, muzzle ); // send railgun beam effect tent = G_TempEntity( trace.endpos, EV_RAILTRAIL ); // set player number for custom colors on the railtrail tent->s.clientNum = ent->s.clientNum; VectorCopy( muzzle, tent->s.origin2 ); // move origin a bit to come closer to the drawn gun muzzle VectorMA( tent->s.origin2, 4, right, tent->s.origin2 ); VectorMA( tent->s.origin2, -1, up, tent->s.origin2 ); // no explosion at end if SURF_NOIMPACT, but still make the trail if ( trace.surfaceFlags & SURF_NOIMPACT ) { tent->s.eventParm = 255; // don't make the explosion at the end } else { tent->s.eventParm = DirToByte( trace.plane.normal ); } tent->s.clientNum = ent->s.clientNum; // give the shooter a reward sound if they have made two railgun hits in a row if ( hits == 0 ) { // complete miss ent->client->accurateCount = 0; } else { // check for "impressive" reward sound ent->client->accurateCount += hits; if ( ent->client->accurateCount >= 2 ) { ent->client->accurateCount -= 2; ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++; // add the sprite over the player's head ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP ); ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE; ent->client->rewardTime = level.time + REWARD_SPRITE_TIME; } ent->client->accuracy_hits++; } }