//[/KnockdownSys] gentity_t *G_KickTrace( gentity_t *ent, vec3_t kickDir, float kickDist, vec3_t kickEnd, int kickDamage, float kickPush ) { vec3_t traceOrg, traceEnd, kickMins, kickMaxs; trace_t trace; gentity_t *hitEnt = NULL; VectorSet(kickMins, -2.0f, -2.0f, -2.0f); VectorSet(kickMaxs, 2.0f, 2.0f, 2.0f); //FIXME: variable kick height? if ( kickEnd && !VectorCompare( kickEnd, vec3_origin ) ) {//they passed us the end point of the trace, just use that //this makes the trace flat VectorSet( traceOrg, ent->r.currentOrigin[0], ent->r.currentOrigin[1], kickEnd[2] ); VectorCopy( kickEnd, traceEnd ); } else {//extrude VectorSet( traceOrg, ent->r.currentOrigin[0], ent->r.currentOrigin[1], ent->r.currentOrigin[2]+ent->r.maxs[2]*0.5f ); VectorMA( traceOrg, kickDist, kickDir, traceEnd ); } if (d_saberKickTweak.integer) { trap_G2Trace( &trace, traceOrg, kickMins, kickMaxs, traceEnd, ent->s.number, MASK_SHOT, G2TRFLAG_DOGHOULTRACE|G2TRFLAG_GETSURFINDEX|G2TRFLAG_THICK|G2TRFLAG_HITCORPSES, g_g2TraceLod.integer ); } else { trap_Trace( &trace, traceOrg, kickMins, kickMaxs, traceEnd, ent->s.number, MASK_SHOT ); } //G_TestLine(traceOrg, traceEnd, 0x0000ff, 5000); if ( trace.fraction < 1.0f && !trace.startsolid && !trace.allsolid ) { if (ent->client->jediKickTime > level.time) { if (trace.entityNum == ent->client->jediKickIndex) { //we are hitting the same ent we last hit in this same anim, don't hit it again return NULL; } } ent->client->jediKickIndex = trace.entityNum; ent->client->jediKickTime = level.time + ent->client->ps.legsTimer; hitEnt = &g_entities[trace.entityNum]; //FIXME: regardless of what we hit, do kick hit sound and impact effect //G_PlayEffect( "misc/kickHit", trace.endpos, trace.plane.normal ); if ( ent->client->ps.torsoAnim == BOTH_A7_HILT ) { G_Sound( ent, CHAN_AUTO, G_SoundIndex( "sound/movers/objects/saber_slam" ) ); } else { G_Sound( ent, CHAN_AUTO, G_SoundIndex( va( "sound/weapons/melee/punch%d", Q_irand( 1, 4 ) ) ) ); } if ( hitEnt->inuse ) {//we hit an entity //FIXME: don't hit same ent more than once per kick if ( hitEnt->takedamage ) {//hurt it if (hitEnt->client) { hitEnt->client->ps.otherKiller = ent->s.number; hitEnt->client->ps.otherKillerDebounceTime = level.time + 10000; hitEnt->client->ps.otherKillerTime = level.time + 10000; } if (d_saberKickTweak.integer) { G_Damage( hitEnt, ent, ent, kickDir, trace.endpos, kickDamage*0.2f, DAMAGE_NO_KNOCKBACK, MOD_MELEE ); } else { G_Damage( hitEnt, ent, ent, kickDir, trace.endpos, kickDamage, DAMAGE_NO_KNOCKBACK, MOD_MELEE ); } } if ( hitEnt->client && !(hitEnt->client->ps.pm_flags&PMF_TIME_KNOCKBACK) //not already flying through air? Intended to stop multiple hits, but... && G_CanBeEnemy(ent, hitEnt) ) {//FIXME: this should not always work if ( hitEnt->health <= 0 ) {//we kicked a dead guy //throw harder - FIXME: no matter how hard I push them, they don't go anywhere... corpses use less physics??? // G_Throw( hitEnt, kickDir, kickPush*4 ); //see if we should play a better looking death on them // G_ThrownDeathAnimForDeathAnim( hitEnt, trace.endpos ); //[KnockdownSys] //reenabled SP code since the knockdown code now based on the SP code again. G_Throw( hitEnt, kickDir, kickPush*4 ); //see if we should play a better looking death on them G_ThrownDeathAnimForDeathAnim( hitEnt, trace.endpos ); //G_TossTheMofo(hitEnt, kickDir, kickPush*4.0f); //[/KnockdownSys] } else { G_Throw( hitEnt, kickDir, kickPush ); if ( kickPush >= 75.0f && !Q_irand( 0, 2 ) ) { G_Knockdown( hitEnt, ent, kickDir, 300, qtrue ); } else { G_Knockdown( hitEnt, ent, kickDir, kickPush, qtrue ); } } } } } return (hitEnt); }
void G_RunMissile( gentity_t *ent ) { vec3_t origin, groundSpot; trace_t tr; int passent = ENTITYNUM_NONE; qboolean isKnockedSaber = qfalse; VectorSet(groundSpot, 0, 0, 0); if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF)) { isKnockedSaber = qtrue; ent->s.pos.trType = TR_GRAVITY; } // get current position BG_EvaluateTrajectory( &ent->s.pos, level.time, origin ); // if this missile bounced off an invulnerability sphere if ( ent->target_ent ) { passent = ent->target_ent->s.number; } else { // ignore interactions with the missile owner if ( (ent->r.svFlags&SVF_OWNERNOTSHARED) && (ent->s.eFlags&EF_JETPACK_ACTIVE) ) {//A vehicle missile that should be solid to its owner //I don't care about hitting my owner passent = ent->s.number; } else { passent = ent->r.ownerNum; } } // trace a line from the previous position to the current position if (d_projectileGhoul2Collision.integer) { trap_G2Trace(&tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, G2TRFLAG_DOGHOULTRACE | G2TRFLAG_GETSURFINDEX | G2TRFLAG_THICK | G2TRFLAG_HITCORPSES, g_g2TraceLod.integer); if (tr.fraction != 1.0 && tr.entityNum < ENTITYNUM_WORLD) { gentity_t *g2Hit = &g_entities[tr.entityNum]; if (g2Hit->inuse && g2Hit->client && g2Hit->ghoul2) { //since we used G2TRFLAG_GETSURFINDEX, tr.surfaceFlags will actually contain the index of the surface on the ghoul2 model we collided with. g2Hit->client->g2LastSurfaceHit = tr.surfaceFlags; g2Hit->client->g2LastSurfaceTime = level.time; } if (g2Hit->ghoul2) { tr.surfaceFlags = 0; //clear the surface flags after, since we actually care about them in here. } } } else { trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask ); } if ( tr.startsolid || tr.allsolid ) { // make sure the tr.entityNum is set to the entity we're stuck in trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask ); tr.fraction = 0; } else { VectorCopy( tr.endpos, ent->r.currentOrigin ); } if (ent->passThroughNum && tr.entityNum == (ent->passThroughNum-1)) { VectorCopy( origin, ent->r.currentOrigin ); trap_LinkEntity( ent ); goto passthrough; } trap_LinkEntity( ent ); if (ent->s.weapon == G2_MODEL_PART && !ent->bounceCount) { vec3_t lowerOrg; trace_t trG; VectorCopy(ent->r.currentOrigin, lowerOrg); lowerOrg[2] -= 1; trap_Trace( &trG, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, lowerOrg, passent, ent->clipmask ); VectorCopy(trG.endpos, groundSpot); if (!trG.startsolid && !trG.allsolid && trG.entityNum == ENTITYNUM_WORLD) { ent->s.groundEntityNum = trG.entityNum; } else { ent->s.groundEntityNum = ENTITYNUM_NONE; } } if ( tr.fraction != 1) { // never explode or bounce on sky if ( tr.surfaceFlags & SURF_NOIMPACT ) { // If grapple, reset owner if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) { ent->parent->client->hook = NULL; } if ((ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber) { G_RunThink( ent ); return; } else if (ent->s.weapon != G2_MODEL_PART) { G_FreeEntity( ent ); return; } } #if 0 //will get stomped with missile impact event... if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS && (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC)) { //player or NPC, try making a mark on him //ok, let's try adding it to the missile ent instead (tempents bad!) G_AddEvent(ent, EV_GHOUL2_MARK, 0); //copy current pos to s.origin, and current projected traj to origin2 VectorCopy(ent->r.currentOrigin, ent->s.origin); BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 ); //the index for whoever we are hitting ent->s.otherEntityNum = tr.entityNum; if (VectorCompare(ent->s.origin, ent->s.origin2)) { ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up. } } #else if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS && (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC)) { //player or NPC, try making a mark on him //copy current pos to s.origin, and current projected traj to origin2 VectorCopy(ent->r.currentOrigin, ent->s.origin); BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 ); if (VectorCompare(ent->s.origin, ent->s.origin2)) { ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up. } } #endif G_MissileImpact( ent, &tr ); if (tr.entityNum == ent->s.otherEntityNum) { //if the impact event other and the trace ent match then it's ok to do the g2 mark ent->s.trickedentindex = 1; } if ( ent->s.eType != ET_MISSILE && ent->s.weapon != G2_MODEL_PART ) { return; // exploded } } passthrough: if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) ) {//stuck missiles should check some special stuff G_RunStuckMissile( ent ); return; } if (ent->s.weapon == G2_MODEL_PART) { if (ent->s.groundEntityNum == ENTITYNUM_WORLD) { ent->s.pos.trType = TR_LINEAR; VectorClear(ent->s.pos.trDelta); ent->s.pos.trTime = level.time; VectorCopy(groundSpot, ent->s.pos.trBase); VectorCopy(groundSpot, ent->r.currentOrigin); if (ent->s.apos.trType != TR_STATIONARY) { ent->s.apos.trType = TR_STATIONARY; ent->s.apos.trTime = level.time; ent->s.apos.trBase[ROLL] = 0; ent->s.apos.trBase[PITCH] = 0; } } } // check think function after bouncing G_RunThink( ent ); }
void G_GrabSomeMofos(gentity_t *self) { renderInfo_t *ri = &self->client->renderInfo; mdxaBone_t boltMatrix; vec3_t flatAng; vec3_t pos; vec3_t grabMins, grabMaxs; trace_t trace; if (!self->ghoul2 || ri->handRBolt == -1) { //no good return; } VectorSet(flatAng, 0.0f, self->client->ps.viewangles[1], 0.0f); trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->handRBolt, &boltMatrix, flatAng, self->client->ps.origin, level.time, NULL, self->modelScale); BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, pos); VectorSet(grabMins, -4.0f, -4.0f, -4.0f); VectorSet(grabMaxs, 4.0f, 4.0f, 4.0f); //trace from my origin to my hand, if we hit anyone then get 'em trap_G2Trace( &trace, self->client->ps.origin, grabMins, grabMaxs, pos, self->s.number, MASK_SHOT, G2TRFLAG_DOGHOULTRACE|G2TRFLAG_GETSURFINDEX|G2TRFLAG_THICK|G2TRFLAG_HITCORPSES, g_g2TraceLod.integer ); if (trace.fraction != 1.0f && trace.entityNum < ENTITYNUM_WORLD) { gentity_t *grabbed = &g_entities[trace.entityNum]; if (grabbed->inuse && (grabbed->s.eType == ET_PLAYER || grabbed->s.eType == ET_NPC) && grabbed->client && grabbed->health > 0 && G_CanBeEnemy(self, grabbed) && G_PrettyCloseIGuess(grabbed->client->ps.origin[2], self->client->ps.origin[2], 4.0f) && (!BG_InGrappleMove(grabbed->client->ps.torsoAnim) || grabbed->client->ps.torsoAnim == BOTH_KYLE_GRAB) && (!BG_InGrappleMove(grabbed->client->ps.legsAnim) || grabbed->client->ps.legsAnim == BOTH_KYLE_GRAB)) { //grabbed an active player/npc int tortureAnim = -1; int correspondingAnim = -1; if (self->client->pers.cmd.forwardmove > 0) { //punch grab tortureAnim = BOTH_KYLE_PA_1; correspondingAnim = BOTH_PLAYER_PA_1; } else if (self->client->pers.cmd.forwardmove < 0) { //knee-throw tortureAnim = BOTH_KYLE_PA_2; correspondingAnim = BOTH_PLAYER_PA_2; } if (tortureAnim == -1 || correspondingAnim == -1) { if (self->client->ps.torsoTimer < 300 && !self->client->grappleState) { //you failed to grab anyone, play the "failed to grab" anim G_SetAnim(self, &self->client->pers.cmd, SETANIM_BOTH, BOTH_KYLE_MISS, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0); if (self->client->ps.torsoAnim == BOTH_KYLE_MISS) { //providing the anim set succeeded.. self->client->ps.weaponTime = self->client->ps.torsoTimer; } } return; } self->client->grappleIndex = grabbed->s.number; self->client->grappleState = 1; grabbed->client->grappleIndex = self->s.number; grabbed->client->grappleState = 20; //time to crack some heads G_SetAnim(self, &self->client->pers.cmd, SETANIM_BOTH, tortureAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0); if (self->client->ps.torsoAnim == tortureAnim) { //providing the anim set succeeded.. self->client->ps.weaponTime = self->client->ps.torsoTimer; } G_SetAnim(grabbed, &grabbed->client->pers.cmd, SETANIM_BOTH, correspondingAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0); if (grabbed->client->ps.torsoAnim == correspondingAnim) { //providing the anim set succeeded.. if (grabbed->client->ps.weapon == WP_SABER) { //turn it off if (!grabbed->client->ps.saberHolstered) { grabbed->client->ps.saberHolstered = 2; if (grabbed->client->saber[0].soundOff) { G_Sound(grabbed, CHAN_AUTO, grabbed->client->saber[0].soundOff); } if (grabbed->client->saber[1].soundOff && grabbed->client->saber[1].model[0]) { G_Sound(grabbed, CHAN_AUTO, grabbed->client->saber[1].soundOff); } } } if (grabbed->client->ps.torsoTimer < self->client->ps.torsoTimer) { //make sure they stay in the anim at least as long as the grabber grabbed->client->ps.torsoTimer = self->client->ps.torsoTimer; } grabbed->client->ps.weaponTime = grabbed->client->ps.torsoTimer; } } } if (self->client->ps.torsoTimer < 300 && !self->client->grappleState) { //you failed to grab anyone, play the "failed to grab" anim G_SetAnim(self, &self->client->pers.cmd, SETANIM_BOTH, BOTH_KYLE_MISS, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0); if (self->client->ps.torsoAnim == BOTH_KYLE_MISS) { //providing the anim set succeeded.. self->client->ps.weaponTime = self->client->ps.torsoTimer; } } }