void CG_GibPlayer(centity_t *cent, vec3_t playerOrigin, vec3_t gdir) { int i, count = 0, tagIndex, gibIndex; vec3_t origin, velocity, dir; trace_t trace; qboolean foundtag; clientInfo_t *ci; int clientNum; bg_character_t *character; vec4_t projection, color; // Rafael // BloodCloud qboolean newjunction[MAXJUNCTIONS]; vec3_t junctionOrigin[MAXJUNCTIONS]; int junction; int j; vec3_t axis[3], angles; char *JunctiongibTags[] = { // leg tag "tag_footright", "tag_footleft", "tag_legright", "tag_legleft", // torsotags "tag_armright", "tag_armleft", "tag_torso", "tag_chest" }; char *ConnectTags[] = { // legs tags "tag_legright", "tag_legleft", "tag_torso", "tag_torso", // torso tags "tag_chest", "tag_chest", "tag_chest", "tag_torso", }; char *gibTags[] = { // tags in the legs "tag_footright", "tag_footleft", "tag_legright", "tag_legleft", "tag_torso", // tags in the torso "tag_chest", "tag_armright", "tag_armleft", "tag_head", NULL }; if (cg_blood.integer) { // Rafael for (i = 0; i < MAXJUNCTIONS; i++) newjunction[i] = qfalse; clientNum = cent->currentState.clientNum; if (clientNum < 0 || clientNum >= MAX_CLIENTS) { CG_Error("Bad clientNum on player entity"); } ci = &cgs.clientinfo[clientNum]; character = CG_CharacterForClientinfo(ci, cent); // Ridah, fetch the various positions of the tag_gib*'s // and spawn the gibs from the correct places (especially the head) for (gibIndex = 0, count = 0, foundtag = qtrue; foundtag && gibIndex < MAX_GIB_MODELS && gibTags[gibIndex]; gibIndex++) { refEntity_t *re = 0; foundtag = qfalse; if (!character->gibModels[gibIndex]) { continue; } re = ¢->pe.bodyRefEnt; for (tagIndex = 0; (tagIndex = CG_GetOriginForTag(cent, re, gibTags[gibIndex], tagIndex, origin, axis)) >= 0; count++, tagIndex++) { foundtag = qtrue; VectorSubtract(origin, re->origin, dir); VectorNormalize(dir); // spawn a gib velocity[0] = dir[0] * (0.5 + random()) * GIB_VELOCITY * 0.3; velocity[1] = dir[1] * (0.5 + random()) * GIB_VELOCITY * 0.3; velocity[2] = GIB_JUMP + dir[2] * (0.5 + random()) * GIB_VELOCITY * 0.5; VectorMA(velocity, GIB_VELOCITY, gdir, velocity); AxisToAngles(axis, angles); CG_LaunchGib(cent, origin, angles, velocity, character->gibModels[gibIndex], 1.0, 0); for (junction = 0; junction < MAXJUNCTIONS; junction++) { if (!Q_stricmp(gibTags[gibIndex], JunctiongibTags[junction])) { VectorCopy(origin, junctionOrigin[junction]); newjunction[junction] = qtrue; } } } } for (i = 0; i < MAXJUNCTIONS; i++) { if (newjunction[i] == qtrue) { for (j = 0; j < MAXJUNCTIONS; j++) { if (!Q_stricmp(JunctiongibTags[j], ConnectTags[i])) { if (newjunction[j] == qtrue) { // spawn a blood cloud somewhere on the vec from VectorSubtract(junctionOrigin[i], junctionOrigin[j], dir); CG_ParticleBloodCloud(cent, junctionOrigin[i], dir); } } } } } // Ridah, spawn a bunch of blood dots around the place #define GIB_BLOOD_DOTS 3 for (i = 0, count = 0; i < GIB_BLOOD_DOTS * 2; i++) { // TTimo: unused //static vec3_t mins = {-10,-10,-10}; //static vec3_t maxs = { 10, 10, 10}; if (i > 0) { velocity[0] = ((i % 2) * 2 - 1) * (40 + 40 * random()); velocity[1] = (((i / 2) % 2) * 2 - 1) * (40 + 40 * random()); velocity[2] = (((i < GIB_BLOOD_DOTS) * 2) - 1) * 40; } else { VectorClear(velocity); velocity[2] = -64; } VectorAdd(playerOrigin, velocity, origin); CG_Trace(&trace, playerOrigin, NULL, NULL, origin, -1, CONTENTS_SOLID); if (trace.fraction < 1.0) { //% BG_GetMarkDir( velocity, trace.plane.normal, velocity ); //% CG_ImpactMark( cgs.media.bloodDotShaders[rand()%5], trace.endpos, velocity, random()*360, //% 1,1,1,1, qtrue, 30, qfalse, cg_bloodTime.integer * 1000 ); #if 0 BG_GetMarkDir(velocity, trace.plane.normal, projection); VectorSubtract(vec3_origin, projection, projection); projection[3] = 64; VectorMA(trace.endpos, -8.0f, projection, markOrigin); CG_ImpactMark(cgs.media.bloodDotShaders[rand() % 5], markOrigin, projection, 30.0f, random() * 360.0f, 1.0f, 1.0f, 1.0f, 1.0f, cg_bloodTime.integer * 1000); #else VectorSet(projection, 0, 0, -1); projection[3] = 30.0f; Vector4Set(color, 1.0f, 1.0f, 1.0f, 1.0f); trap_R_ProjectDecal(cgs.media.bloodDotShaders[rand() % 5], 1, (vec3_t *) trace.endpos, projection, color, cg_bloodTime.integer * 1000, (cg_bloodTime.integer * 1000) >> 4); #endif if (count++ > GIB_BLOOD_DOTS) { break; } } } }
/* ================ G_MissileImpact impactDamage is how much damage the impact will do to func_explosives ================ */ void G_MissileImpact( gentity_t *ent, trace_t *trace, int impactDamage ) { gentity_t *other; qboolean hitClient = qfalse; vec3_t velocity; int etype; other = &g_entities[trace->entityNum]; // handle func_explosives if ( other->classname && Q_stricmp( other->classname, "func_explosive" ) == 0 ) { // the damage is sufficient to "break" the ent (health == 0 is non-breakable) if ( other->health && impactDamage >= other->health ) { // check for other->takedamage needs to be inside the health check since it is // likely that, if successfully destroyed by the missile, in the next runmissile() // update takedamage would be set to '0' and the func_explosive would not be // removed yet, causing a bounce. if ( other->takedamage ) { BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity ); G_Damage( other, ent, &g_entities[ent->r.ownerNum], velocity, ent->s.origin, impactDamage, 0, ent->methodOfDeath ); } // its possible of the func_explosive not to die from this and it // should reflect the missile or explode it not vanish into oblivion if ( other->health <= 0 ) { return; } } } // check for bounce if ( !other->takedamage && ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) { G_BounceMissile( ent, trace ); // JPW NERVE -- spotter White Phosphorous rounds shouldn't bounce noise if ( !Q_stricmp( ent->classname,"WP" ) ) { return; } // jpw if ( !Q_stricmp( ent->classname, "flamebarrel" ) ) { G_AddEvent( ent, EV_FLAMEBARREL_BOUNCE, 0 ); } else { G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 ); } return; } if ( other->takedamage && ent->s.density == 1 ) { G_ExplodeMissilePoisonGas( ent ); return; } // impact damage if ( other->takedamage ) { if ( ent->damage ) { if ( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) { if ( g_entities[ent->r.ownerNum].client ) { g_entities[ent->r.ownerNum].client->ps.persistant[PERS_ACCURACY_HITS]++; } hitClient = qtrue; } BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity ); if ( VectorLength( velocity ) == 0 ) { velocity[2] = 1; // stepped on a grenade } G_Damage( other, ent, &g_entities[ent->r.ownerNum], velocity, ent->s.origin, ent->damage, 0, ent->methodOfDeath ); } else // if no damage value, then this is a splash damage grenade only { G_BounceMissile( ent, trace ); return; } } // is it cheaper in bandwidth to just remove this ent and create a new // one, rather than changing the missile into the explosion? if ( other->takedamage && other->client ) { G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) ); ent->s.otherEntityNum = other->s.number; } else { // Ridah, try projecting it in the direction it came from, for better decals vec3_t dir; BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, dir ); BG_GetMarkDir( dir, trace->plane.normal, dir ); G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) ); } ent->freeAfterEvent = qtrue; // change over to a normal entity right at the point of impact etype = ent->s.eType; ent->s.eType = ET_GENERAL; SnapVectorTowards( trace->endpos, ent->s.pos.trBase ); // save net bandwidth G_SetOrigin( ent, trace->endpos ); // splash damage (doesn't apply to person directly hit) if ( ent->splashDamage ) { if ( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, other, ent->splashMethodOfDeath ) ) { if ( !hitClient && g_entities[ent->r.ownerNum].client ) { g_entities[ent->r.ownerNum].client->ps.persistant[PERS_ACCURACY_HITS]++; } } } trap_LinkEntity( ent ); }