void G_RunMissile( gentity_t *ent ) { vector3 origin, groundSpot; trace_t tr; int passent; qboolean isKnockedSaber = qfalse; 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->Trace( &tr, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &origin, passent, ent->clipmask, qfalse, G2TRFLAG_DOGHOULTRACE | G2TRFLAG_GETSURFINDEX | G2TRFLAG_THICK | G2TRFLAG_HITCORPSES, g_g2TraceLod.integer ); if ( tr.fraction != 1.0f && 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. } //Raz: Portals! if ( g2Hit->s.eType == ET_SPECIAL && g2Hit->s.userInt1 ) { if ( g2Hit->touch ) { g2Hit->touch( g2Hit, ent, &tr ); } JPLua::Entity_CallFunction( g2Hit, JPLua::JPLUA_ENTITY_TOUCH, (intptr_t)ent, (intptr_t)&tr ); goto passthrough; } } } else { trap->Trace( &tr, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &origin, passent, ent->clipmask, qfalse, 0, 0 ); } 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, qfalse, 0, 0 ); 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( (sharedEntity_t *)ent ); goto passthrough; } trap->LinkEntity( (sharedEntity_t *)ent ); if ( ent->s.weapon == G2_MODEL_PART && !ent->bounceCount ) { vector3 lowerOrg; trace_t trG; VectorCopy( &ent->r.currentOrigin, &lowerOrg ); lowerOrg.z -= 1; trap->Trace( &trG, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &lowerOrg, passent, ent->clipmask, qfalse, 0, 0 ); 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 ( ent->parent && ent->parent->client && ent->parent->client->hook && ent->parent->client->hook == ent && (ent->parent->client->ps.duelInProgress || BG_SaberInSpecial( ent->parent->client->ps.saberMove ) || !(japp_allowHook.integer & (1 << level.gametype)) || ent->parent->client->pers.adminData.isSlept || g_entities[tr.entityNum].client) ) { // not allowed to have hook out Weapon_HookFree( ent ); return; } 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->parent && ent->parent->client && ent->parent->client->hook && ent->parent->client->hook == ent ) { Weapon_HookFree( ent->parent->client->hook ); } 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 ( 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.z += 2.0f; //whatever, at least it won't mess up. } } 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[0] = 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 ); }
/* ================ G_RunMissile ================ */ void G_RunMissile( gentity_t *ent ) { vec3_t origin, groundSpot; trace_t tr; int passent; qboolean isKnockedSaber = qfalse; 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->Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, 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, qfalse, 0, 0 ); } 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, qfalse, 0, 0 ); 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( (sharedEntity_t *)ent ); goto passthrough; } trap->LinkEntity( (sharedEntity_t *)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, qfalse, 0, 0 ); 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 /* gentity_t *evEnt = G_TempEntity(ent->r.currentOrigin, EV_GHOUL2_MARK); evEnt->s.owner = tr.entityNum; //the entity the mark should be placed on evEnt->s.weapon = ent->s.weapon; //the weapon used (to determine mark type) VectorCopy(ent->r.currentOrigin, evEnt->s.origin); //the point of impact //origin2 gets the predicted trajectory-based position. BG_EvaluateTrajectory( &ent->s.pos, level.time, evEnt->s.origin2 ); //If they are the same, there will be problems. if (VectorCompare(evEnt->s.origin, evEnt->s.origin2)) { evEnt->s.origin2[2] += 2; //whatever, at least it won't mess up. } */ //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 ); }
/* ================ G_RunMissile ================ */ void G_RunMissile( gentity_t *ent ) { vec3_t origin, groundSpot; trace_t tr; int passent; qboolean isKnockedSaber = qfalse; 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 its a rocket, and older than 500ms, make it solid to the shooter. if ((g_tweakWeapons.integer & WT_SOLID_ROCKET) && (ent->s.weapon == WP_ROCKET_LAUNCHER) && (!ent->raceModeShooter) && (ent->nextthink - level.time < 9500)) { ent->r.ownerNum = ENTITYNUM_WORLD; } // 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 == 1) //JAPRO - Serverside - Weapons - New Hitbox Option { JP_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, 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 { JP_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, 0, 0 ); } if ( tr.startsolid || tr.allsolid ) { // make sure the tr.entityNum is set to the entity we're stuck in JP_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask, qfalse, 0, 0 ); 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( (sharedEntity_t *)ent ); goto passthrough; } trap->LinkEntity( (sharedEntity_t *)ent ); if (ent->s.weapon == G2_MODEL_PART && !ent->bounceCount) { vec3_t lowerOrg; trace_t trG; VectorCopy(ent->r.currentOrigin, lowerOrg); lowerOrg[2] -= 1; JP_Trace( &trG, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, lowerOrg, passent, ent->clipmask, qfalse, 0, 0 ); 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) { //Hit something maybe qboolean skip = qfalse; gentity_t *other = &g_entities[tr.entityNum]; //Check to see if we hit a lightsaber and they are in another dimension, if so dont do the hit code.. if (other && other->r.contents & CONTENTS_LIGHTSABER) { gentity_t *otherOwner = &g_entities[other->r.ownerNum]; gentity_t *owner = &g_entities[ent->r.ownerNum]; /* if (owner->s.bolt1 && !otherOwner->s.bolt1)//We are dueling/racing and they are not skip = qtrue; else if (!owner->s.bolt1 && otherOwner->s.bolt1)//They are dueling/racing and we are not skip = qtrue; */ if (owner->s.bolt1 != otherOwner->s.bolt1) //Dont impact if its from another dimension skip = qtrue; } if ( tr.fraction != 1 && !skip) { // 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 (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. } } 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_RunMissile( gentity_t *ent ) { vec3_t oldOrg; trace_t tr; int trHitLoc=HL_NONE; if ( (ent->s.eFlags&EF_HELD_BY_SAND_CREATURE) ) {//in a sand creature's mouth if ( ent->activator ) { mdxaBone_t boltMatrix; // Getting the bolt here //in hand vec3_t scAngles = {0}; scAngles[YAW] = ent->activator->currentAngles[YAW]; gi.G2API_GetBoltMatrix( ent->activator->ghoul2, ent->activator->playerModel, ent->activator->gutBolt, &boltMatrix, scAngles, ent->activator->currentOrigin, (cg.time?cg.time:level.time), NULL, ent->activator->s.modelScale ); // Storing ent position, bolt position, and bolt axis gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->currentOrigin ); G_SetOrigin( ent, ent->currentOrigin ); } // check think function G_RunThink( ent ); return; } VectorCopy( ent->currentOrigin, oldOrg ); // get current position if ( ent->s.pos.trType == TR_INTERPOLATE ) {//rolling missile? //FIXME: WTF?!! Sticks to stick missiles? //FIXME: they stick inside the player G_RollMissile( ent ); if ( ent->s.eType != ET_GENERAL ) {//didn't explode VectorCopy( ent->currentOrigin, ent->s.pos.trBase ); gi.trace( &tr, oldOrg, ent->mins, ent->maxs, ent->currentOrigin, ent->s.number, ent->clipmask, G2_RETURNONHIT, 10 ); if ( VectorCompare( ent->s.pos.trDelta, vec3_origin ) ) { //VectorCopy( ent->currentAngles, ent->s.apos.trBase ); VectorClear( ent->s.apos.trDelta ); } else { vec3_t ang, fwdDir, rtDir; float speed; ent->s.apos.trType = TR_INTERPOLATE; VectorSet( ang, 0, ent->s.apos.trBase[1], 0 ); AngleVectors( ang, fwdDir, rtDir, NULL ); speed = VectorLength( ent->s.pos.trDelta )*4; //HMM, this works along an axis-aligned dir, but not along diagonals //This is because when roll gets to 90, pitch becomes yaw, and vice-versa //Maybe need to just set the angles directly? ent->s.apos.trDelta[0] = DotProduct( fwdDir, ent->s.pos.trDelta ); ent->s.apos.trDelta[1] = 0;//never spin! ent->s.apos.trDelta[2] = DotProduct( rtDir, ent->s.pos.trDelta ); VectorNormalize( ent->s.apos.trDelta ); VectorScale( ent->s.apos.trDelta, speed, ent->s.apos.trDelta ); ent->s.apos.trTime = level.previousTime; } } } else { vec3_t origin; EvaluateTrajectory( &ent->s.pos, level.time, origin ); // trace a line from the previous position to the current position, // ignoring interactions with the missile owner gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, ent->owner ? ent->owner->s.number : ent->s.number, ent->clipmask, G2_COLLIDE, 10 ); if ( tr.entityNum != ENTITYNUM_NONE ) { gentity_t *other = &g_entities[tr.entityNum]; // check for hitting a lightsaber if ( other->contents & CONTENTS_LIGHTSABER ) {//hit a lightsaber bbox if ( other->owner && other->owner->client && !other->owner->client->ps.saberInFlight && ( Q_irand( 0, (other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]*other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]) ) == 0 || !InFront( ent->currentOrigin, other->owner->currentOrigin, other->owner->client->ps.viewangles, SABER_REFLECT_MISSILE_CONE ) ) )//other->owner->s.number == 0 && {//Jedi cannot block shots from behind! //re-trace from here, ignoring the lightsaber gi.trace( &tr, tr.endpos, ent->mins, ent->maxs, origin, tr.entityNum, ent->clipmask, G2_RETURNONHIT, 10 ); } } } VectorCopy( tr.endpos, ent->currentOrigin ); } // get current angles VectorMA( ent->s.apos.trBase, (level.time - ent->s.apos.trTime) * 0.001, ent->s.apos.trDelta, ent->s.apos.trBase ); //FIXME: Rolling things hitting G2 polys is weird /////////////////////////////////////////////////////// //? if ( tr.fraction != 1 ) { // did we hit or go near a Ghoul2 model? // qboolean hitModel = qfalse; for (int i=0; i < MAX_G2_COLLISIONS; i++) { if (tr.G2CollisionMap[i].mEntityNum == -1) { break; } CCollisionRecord &coll = tr.G2CollisionMap[i]; gentity_t *hitEnt = &g_entities[coll.mEntityNum]; // process collision records here... // make sure we only do this once, not for all the entrance wounds we might generate if ((coll.mFlags & G2_FRONTFACE)/* && !(hitModel)*/ && hitEnt->health) { if (trHitLoc==HL_NONE) { G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, NULL, NULL, ent->methodOfDeath ); } break; // NOTE: the way this whole section was working, it would only get inside of this IF once anyway, might as well break out now } } } ///////////////////////////////////////////////////////// if ( tr.startsolid ) { tr.fraction = 0; } gi.linkentity( ent ); if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) ) {//stuck missiles should check some special stuff G_RunStuckMissile( ent ); return; } // check think function G_RunThink( ent ); if ( ent->s.eType != ET_MISSILE ) { return; // exploded } if ( ent->mass ) { G_MoverTouchPushTriggers( ent, oldOrg ); } /* if ( !(ent->s.eFlags & EF_TELEPORT_BIT) ) { G_MoverTouchTeleportTriggers( ent, oldOrg ); if ( ent->s.eFlags & EF_TELEPORT_BIT ) {//was teleported return; } } else { ent->s.eFlags &= ~EF_TELEPORT_BIT; } */ AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED, 75 );//wakes them up when see a shot passes in front of them if ( !Q_irand( 0, 10 ) ) {//not so often... if ( ent->splashDamage && ent->splashRadius ) {//I'm an exploder, let people around me know danger is coming if ( ent->s.weapon == WP_TRIP_MINE ) {//??? } else { if ( ent->s.weapon == WP_ROCKET_LAUNCHER && ent->e_ThinkFunc == thinkF_rocketThink ) {//homing rocket- run like hell! AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER_GREAT, 50 ); } else { AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER, 50 ); } AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER ); } } else {//makes them run from near misses AddSightEvent( ent->owner, ent->currentOrigin, 48, AEL_DANGER, 50 ); } } if ( tr.fraction == 1 ) { if ( ent->s.weapon == WP_THERMAL && ent->s.pos.trType == TR_INTERPOLATE ) {//a rolling thermal that didn't hit anything G_MissileAddAlerts( ent ); } return; } // never explode or bounce on sky if ( tr.surfaceFlags & SURF_NOIMPACT ) { G_FreeEntity( ent ); return; } G_MissileImpact( ent, &tr, trHitLoc ); }
void G_RunMissile( gentity_t *ent ) { vec3_t origin, oldOrg; trace_t tr; int trHitLoc=HL_NONE; VectorCopy( ent->currentOrigin, oldOrg ); // get current position if ( ent->s.pos.trType == TR_INTERPOLATE ) {//rolling missile? //FIXME: WTF?!! Sticks to stick missiles? //FIXME: they stick inside the player G_RollMissile( ent ); if ( ent->s.eType != ET_GENERAL ) {//didn't explode VectorCopy( ent->currentOrigin, ent->s.pos.trBase ); gi.trace( &tr, oldOrg, ent->mins, ent->maxs, ent->currentOrigin, ent->s.number, ent->clipmask, G2_RETURNONHIT, 10 ); if ( VectorCompare( ent->s.pos.trDelta, vec3_origin ) ) { //VectorCopy( ent->currentAngles, ent->s.apos.trBase ); VectorClear( ent->s.apos.trDelta ); } else { vec3_t ang, fwdDir, rtDir; float speed; ent->s.apos.trType = TR_INTERPOLATE; VectorSet( ang, 0, ent->s.apos.trBase[1], 0 ); AngleVectors( ang, fwdDir, rtDir, NULL ); speed = VectorLength( ent->s.pos.trDelta )*4; //HMM, this works along an axis-aligned dir, but not along diagonals //This is because when roll gets to 90, pitch becomes yaw, and vice-versa //Maybe need to just set the angles directly? ent->s.apos.trDelta[0] = DotProduct( fwdDir, ent->s.pos.trDelta ); ent->s.apos.trDelta[1] = 0;//never spin! ent->s.apos.trDelta[2] = DotProduct( rtDir, ent->s.pos.trDelta ); VectorNormalize( ent->s.apos.trDelta ); VectorScale( ent->s.apos.trDelta, speed, ent->s.apos.trDelta ); ent->s.apos.trTime = level.previousTime; } } } else { EvaluateTrajectory( &ent->s.pos, level.time, origin ); // trace a line from the previous position to the current position, // ignoring interactions with the missile owner /* gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask, G2_RETURNONHIT, 10 ); */ gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, ent->owner ? ent->owner->s.number : ent->s.number, ent->clipmask, G2_COLLIDE, 10 ); /* if ( !VectorCompare( ent->mins, vec3_origin ) || !VectorCompare( ent->maxs, vec3_origin ) ) {//don't do ghoul trace if ent has size because g2 just ignores that anyway gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask, G2_NOCOLLIDE, 10 ); } else //Now we always do ghoul trace, regardless of bbox size of missile, this is presuming that non-point ghoul traces will be possible...? { gi.trace( &tr, ent->currentOrigin, vec3_origin, vec3_origin, origin, ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask, G2_RETURNONHIT, 10 ); } */ /* if ( tr.fraction == 0.0f && tr.plane.normal[2] == 1.0f && origin[2] < ent->currentOrigin[2] ) { if ( ent->s.pos.trType == TR_GRAVITY && !(ent->s.eFlags&EF_BOUNCE) && !(ent->s.eFlags&EF_BOUNCE_HALF) && ent->s.weapon == WP_THERMAL )//FIXME: EF_ROLLING { //FIXME: Needs to stop sometime! ent->s.pos.trType = TR_LINEAR; ent->s.pos.trDelta[2] = 0; EvaluateTrajectory( &ent->s.pos, level.time, origin ); // trace a line from the previous position to the current position, // ignoring interactions with the missile owner gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask | CONTENTS_GHOUL2 ); if ( tr.fraction == 1.0f ) { VectorCopy( tr.endpos, ent->s.pos.trBase ); VectorScale( ent->s.pos.trDelta, 0.975f, ent->s.pos.trDelta ); ent->s.pos.trTime = level.time; } ent->s.pos.trType = TR_GRAVITY; } } */ if ( tr.entityNum != ENTITYNUM_NONE && &g_entities[tr.entityNum] != NULL ) { gentity_t *other = &g_entities[tr.entityNum]; // check for hitting a lightsaber if ( other->contents & CONTENTS_LIGHTSABER ) {//hit a lightsaber bbox if ( other->owner && other->owner->client && !other->owner->client->ps.saberInFlight && !InFront( ent->currentOrigin, other->owner->currentOrigin, other->owner->client->ps.viewangles, SABER_REFLECT_MISSILE_CONE ) )//other->owner->s.number == 0 && {//Jedi cannot block shots from behind! //re-trace from here, ignoring the lightsaber gi.trace( &tr, tr.endpos, ent->mins, ent->maxs, origin, tr.entityNum, ent->clipmask, G2_RETURNONHIT, 10 ); } } } VectorCopy( tr.endpos, ent->currentOrigin ); } // get current angles VectorMA( ent->s.apos.trBase, (level.time - ent->s.apos.trTime) * 0.001, ent->s.apos.trDelta, ent->s.apos.trBase ); //FIXME: Rolling things hitting G2 polys is weird /////////////////////////////////////////////////////// //? if ( tr.fraction != 1 ) { // did we hit or go near a Ghoul2 model? // qboolean hitModel = qfalse; for (int i=0; i < MAX_G2_COLLISIONS; i++) { if (tr.G2CollisionMap[i].mEntityNum == -1) { break; } CCollisionRecord &coll = tr.G2CollisionMap[i]; gentity_t *hitEnt = &g_entities[coll.mEntityNum]; /* Sorry...this was just getting in the way.... #if _DEBUG vec3_t delta; VectorSubtract(origin, coll.mCollisionPosition, delta); VectorNormalize(delta); VectorScale(delta, 30, delta); if (coll.mFlags & G2_BACKFACE) { VectorAdd(delta, coll.mCollisionPosition, delta); G_DebugLine(coll.mCollisionPosition, delta, 10000, 0x00ff0000, qtrue); } else { VectorSubtract(coll.mCollisionPosition, delta, delta); G_DebugLine(coll.mCollisionPosition, delta, 10000, 0x0000ff00, qtrue); } //loadsavecrash // VectorCopy(hitEnt->mins, hitEnt->s.mins); // VectorCopy(hitEnt->maxs, hitEnt->s.maxs); #endif */ // process collision records here... // make sure we only do this once, not for all the entrance wounds we might generate if ((coll.mFlags & G2_FRONTFACE)/* && !(hitModel)*/ && hitEnt->health) { // create a new surface using the details of what poly/surface/model we hit // int newSurface = gi.G2API_AddSurface(&hitEnt->ghoul2[coll.mModelIndex], coll.mSurfaceIndex, coll.mPolyIndex, coll.mBarycentricI, coll.mBarycentricJ, 10); // surfaceInfo_t *newSuf = &hitEnt->ghoul2[coll.mModelIndex].mSlist[newSurface]; // attach a bolt to this surface // int newBolt = gi.G2API_AddBoltSurfNum(&hitEnt->ghoul2[coll.mModelIndex], newSurface); // now attach an effect to this new bolt // Bolting on this effect just looks dumb and adds lots of unnecessary effects to the scene // // G_PlayEffect( G_EffectIndex( "blaster/smoke_bolton") , coll.mModelIndex, newBolt, hitEnt->s.number); // // // G_SetBoltSurfaceRemoval(coll.mEntityNum, coll.mModelIndex, newBolt, newSurface, 10000); // hitModel = qtrue; if (trHitLoc==HL_NONE) { G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, NULL, NULL, ent->methodOfDeath ); } break; // NOTE: the way this whole section was working, it would only get inside of this IF once anyway, might as well break out now } } } ///////////////////////////////////////////////////////// if ( tr.startsolid ) { tr.fraction = 0; } gi.linkentity( ent ); if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) ) {//stuck missiles should check some special stuff G_RunStuckMissile( ent ); return; } // check think function G_RunThink( ent ); if ( ent->s.eType != ET_MISSILE ) { return; // exploded } if ( ent->mass ) { G_MoverTouchPushTriggers( ent, oldOrg ); } /* if ( !(ent->s.eFlags & EF_TELEPORT_BIT) ) { G_MoverTouchTeleportTriggers( ent, oldOrg ); if ( ent->s.eFlags & EF_TELEPORT_BIT ) {//was teleported return; } } else { ent->s.eFlags &= ~EF_TELEPORT_BIT; } */ AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED, 75 );//wakes them up when see a shot passes in front of them if ( !Q_irand( 0, 10 ) ) {//not so often... if ( ent->splashDamage && ent->splashRadius ) {//I'm an exploder, let people around me know danger is coming if ( ent->s.weapon == WP_TRIP_MINE ) {//??? } else { if ( ent->s.weapon == WP_ROCKET_LAUNCHER && ent->e_ThinkFunc == thinkF_rocketThink ) {//homing rocket- run like hell! AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER_GREAT, 50 ); } else { AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER, 50 ); } AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER ); } } else {//makes them run from near misses AddSightEvent( ent->owner, ent->currentOrigin, 48, AEL_DANGER, 50 ); } } if ( tr.fraction == 1 ) { return; } // never explode or bounce on sky if ( tr.surfaceFlags & SURF_NOIMPACT ) { G_FreeEntity( ent ); return; } G_MissileImpact( ent, &tr, trHitLoc ); }
//[/RealTrace] void G_RunMissile( gentity_t *ent ) { vec3_t origin, groundSpot; trace_t tr; int passent; qboolean isKnockedSaber = qfalse; if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF)) { isKnockedSaber = qtrue; //[SaberThrowSys] if(!(ent->s.eFlags & EF_MISSILE_STICK) ) { //only go into gravity mode if we're not stuck to something ent->s.pos.trType = TR_GRAVITY; } //[/SaberThrowSys] } // 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 //[RealTrace] G_RealTrace( ent, &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, -1, -1 ); //[/RealTrace] if ( !tr.startsolid && !tr.allsolid ) 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 ); //racc - assign groundEntityNum for body parts. 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; } //racc - make dropped sabers think when they hit a non-impact surface. if ((ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber) { G_RunThink( ent ); return; } //just kill off other weapon shots when they hit a non-impact surface. else if (ent->s.weapon != G2_MODEL_PART) { G_FreeEntity( ent ); return; } } 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)) { //racc - don't allow the current origin/predicted origin be the same. ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up. } } //[DodgeSys] //changed G_MissileImpact to qboolean so that dodges will cause passthru behavor. if(!G_MissileImpact( ent, &tr )) { //target dodged the damage. VectorCopy( origin, ent->r.currentOrigin ); trap_LinkEntity( ent ); return; } //G_MissileImpact( ent, &tr ); //[/DodgeSys] 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; } } } if(ent->damageDecreaseTime && ent->damageDecreaseTime <= level.time) { ent->damage-=4; ent->damageDecreaseTime = level.time + 300; } // check think function after bouncing G_RunThink( ent ); }