示例#1
0
void SabBeh_RunSaberBehavior( gentity_t *self, sabmech_t *mechSelf, 
								gentity_t *otherOwner, sabmech_t *mechOther, vec3_t hitLoc, 
								qboolean *didHit, qboolean otherHitSaberBlade )
{	
	qboolean selfMishap = qfalse;
	qboolean otherMishap = qfalse;

	//initalize the sab mechanic data.
	ClearSabMech(mechSelf);
	ClearSabMech(mechOther);

	if(!otherOwner)
	{//not a saber-on-saber hit, no mishap handling.
		return;
	}

	//G_Printf("BG_SaberInNonIdleDamageMove\n");
	if(BG_SaberInNonIdleDamageMove(&self->client->ps, self->localAnimIndex) )
	{//self is attacking
		//G_Printf("(y)\n");
		if(BG_SaberInNonIdleDamageMove(&otherOwner->client->ps, otherOwner->localAnimIndex)) 
		{//and otherOwner is attacking
			SabBeh_AttackVsAttack(self, mechSelf, otherOwner, mechOther, &selfMishap, &otherMishap);
		}
		else if(OJP_SaberCanBlock(otherOwner, self, qfalse, hitLoc, -1, -1))
		{//and otherOwner is blocking or parrying
			//this is called with dual with both sabers[DUALRAWR]
			SabBeh_AttackVsBlock(self, mechSelf, otherOwner, mechOther, hitLoc, otherHitSaberBlade,
				&selfMishap, &otherMishap);
			*didHit = qfalse;
		}
		else
		{//otherOwner in some other state
			//no mishaps for this at the moment.
		}
	}
	else if( OJP_SaberCanBlock(self, otherOwner, qfalse, hitLoc, -1, -1) )
	{//self is blocking or parrying
		if(BG_SaberInNonIdleDamageMove(&otherOwner->client->ps, otherOwner->localAnimIndex))
		{//and otherOwner is attacking
			SabBeh_AttackVsBlock(otherOwner, mechOther, self, mechSelf, hitLoc, qtrue,
				&otherMishap, &selfMishap);
		}
		else if(OJP_SaberCanBlock(otherOwner, self, qfalse, hitLoc, -1, -1))
		{//and otherOwner is blocking or parrying
		}
		else
		{//otherOwner in some other state
			//no mishaps for this at the moment.
		}
	}
	else
	{//whatever other states self can be in.  (returns, bounces, or something)
		//just act like no mishaps can happen
	}
}
示例#2
0
文件: g_missile.c 项目: jwginge/ojpa
//G_MissileImpact now returns qfalse if and only if the player physically dodged the damage.
//this allows G_RunMissile to properly handle he
qboolean G_MissileImpact( gentity_t *ent, trace_t *trace ) {
//void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
//[/DodgeSys]
    gentity_t		*other;
    qboolean		isKnockedSaber = qfalse;
    //[DodgeSys]
    int missileDmg;
    //[/DodgeSys]

    other = &g_entities[trace->entityNum];

    // check for bounce
    //[WeaponSys]
    //allow thermals to bounce off players and such.
    if ( (!other->takedamage || ent->s.weapon == WP_THERMAL) &&
            //if ( !other->takedamage &&
            //[/WeaponSys]
            (ent->bounceCount > 0 || ent->bounceCount == -5) &&
            ( ent->flags & ( FL_BOUNCE | FL_BOUNCE_HALF ) ) ) {
        G_BounceMissile( ent, trace );
        G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
        //[DodgeSys]
        return qtrue;
        //return;
        //[/DodgeSys]
    }
    else if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
    {   //this is a knocked-away saber
        if (ent->bounceCount > 0 || ent->bounceCount == -5)
        {
            G_BounceMissile( ent, trace );
            G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
            //[DodgeSys]
            return qtrue;
            //return;
            //[/DodgeSys]
        }

        isKnockedSaber = qtrue;
    }

    // I would glom onto the FL_BOUNCE code section above, but don't feel like risking breaking something else
    if (/* (!other->takedamage && (ent->bounceCount > 0 || ent->bounceCount == -5) && ( ent->flags&(FL_BOUNCE_SHRAPNEL) ) ) ||*/ ((trace->surfaceFlags&SURF_FORCEFIELD)&&!ent->splashDamage&&!ent->splashRadius&&(ent->bounceCount > 0 || ent->bounceCount == -5)) )
    {
        G_BounceMissile( ent, trace );

        if ( ent->bounceCount < 1 )
        {
            ent->flags &= ~FL_BOUNCE_SHRAPNEL;
        }
        //[DodgeSys]
        return qtrue;
        //return;
        //[/DodgeSys]
    }

    if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber)
    {   //hit this person's saber, so..
        gentity_t *otherOwner = &g_entities[other->r.ownerNum];

        if (otherOwner->takedamage && otherOwner->client && otherOwner->client->ps.duelInProgress &&
                otherOwner->client->ps.duelIndex != ent->r.ownerNum)
        {
            goto killProj;
        }
    }
    else if (!isKnockedSaber)
    {
        if (other->takedamage && other->client && other->client->ps.duelInProgress &&
                other->client->ps.duelIndex != ent->r.ownerNum)
        {
            goto killProj;
        }
    }

    if (other->flags & FL_DMG_BY_HEAVY_WEAP_ONLY)
    {
        if (ent->methodOfDeath != MOD_REPEATER_ALT &&
                ent->methodOfDeath != MOD_ROCKET &&
                ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
                ent->methodOfDeath != MOD_ROCKET_HOMING &&
                ent->methodOfDeath != MOD_THERMAL &&
                ent->methodOfDeath != MOD_THERMAL_SPLASH &&
                ent->methodOfDeath != MOD_TRIP_MINE_SPLASH &&
                ent->methodOfDeath != MOD_TIMED_MINE_SPLASH &&
                ent->methodOfDeath != MOD_DET_PACK_SPLASH &&
                ent->methodOfDeath != MOD_VEHICLE &&
                ent->methodOfDeath != MOD_CONC &&
                ent->methodOfDeath != MOD_CONC_ALT &&
                ent->methodOfDeath != MOD_SABER &&
                //[Asteroids]
                ent->methodOfDeath != MOD_TURBLAST &&
                ent->methodOfDeath != MOD_TARGET_LASER)
            //[/Asteroids]
        {
            vec3_t fwd;

            if (trace)
            {
                VectorCopy(trace->plane.normal, fwd);
            }
            else
            {   //oh well
                AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
            }

            G_DeflectMissile(other, ent, fwd);
            G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
            //[DodgeSys]
            return qtrue;
            //return;
            //[/DodgeSys]
        }
    }

    //ROP VEHICLE_IMP START
    if((other->s.NPC_class == CLASS_VEHICLE && other->m_pVehicle
            && !other->m_pVehicle->m_pVehicleInfo->AllWeaponsDoDamageToShields
            && other->client->ps.stats[STAT_ARMOR] > 0) || other->flags & FL_SHIELDED)
    {
        if (ent->s.weapon != WP_ROCKET_LAUNCHER &&
                ent->s.weapon != WP_THERMAL &&
                ent->s.weapon != WP_GRENADE &&
                ent->s.weapon != WP_DET_PACK &&
                ent->s.weapon != WP_DEMP2 &&
                ent->s.weapon != WP_EMPLACED_GUN &&
                ent->s.weapon != WP_TURRET &&
                ent->methodOfDeath != MOD_REPEATER_ALT &&
                ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
                ent->methodOfDeath != MOD_TURBLAST &&
                ent->methodOfDeath != MOD_VEHICLE &&
                ent->methodOfDeath != MOD_CONC &&
                ent->methodOfDeath != MOD_CONC_ALT &&
                !(ent->dflags&DAMAGE_HEAVY_WEAP_CLASS) )
        {
            vec3_t fwd;

            if (other->client)
            {
                AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL);
            }
            else
            {
                AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
            }

            G_DeflectMissile(other, ent, fwd);
            G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
            //[DodgeSys]
            return qtrue;
            //return;
            //[/DodgeSys]
        }
    }
    //ROP VEHICLE_IMP END

    //[BoltBlockSys]
    if (OJP_SaberCanBlock(other, ent, qfalse, trace->endpos, -1, -1))
        //[/BoltBlockSys]
    {   //only block one projectile per 200ms (to prevent giant swarms of projectiles being blocked)
        //[BoltBlockSys]
        //racc - missile hit the actual player and it's a type of missile that you can deflect/ref with the saber.

        //racc - play projectile block animation
        other->client->ps.weaponTime = 0;
        WP_SaberBlockNonRandom(other, ent->r.currentOrigin, qtrue);

        OJP_HandleBoltBlock(ent, other, trace);
        //[DodgeSys]
        return qtrue;
        //return;
        //[/DodgeSys]
        //[/BoltBlockSys]
    }
    else if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber)
    {   //hit this person's saber, so..
        gentity_t *otherOwner = &g_entities[other->r.ownerNum];

        if (otherOwner->takedamage && otherOwner->client &&
                ent->s.weapon != WP_TUSKEN_RIFLE &&
                ent->s.weapon != WP_ROCKET_LAUNCHER &&
                ent->s.weapon != WP_THERMAL &&
                ent->s.weapon != WP_GRENADE &&
                ent->s.weapon != WP_DET_PACK &&
                //[BoltBlockSys]
                //ent->s.weapon != WP_DEMP2 &&
                //[BoltBlockSys]
                ent->methodOfDeath != MOD_REPEATER_ALT &&
                ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
                ent->methodOfDeath != MOD_CONC &&
                ent->methodOfDeath != MOD_CONC_ALT /*&&
			otherOwner->client->ps.saberBlockTime < level.time*/)
        {   //for now still deflect even if saberBlockTime >= level.time because it hit the actual saber

            //in this case, deflect it even if we can't actually block it because it hit our saber
            //WP_SaberCanBlock(otherOwner, ent->r.currentOrigin, 0, 0, qtrue, 0);
            if ((otherOwner->client && !BG_SaberInAttack(otherOwner->client->ps.saberMove))
                    || (otherOwner->client && (pm->cmd.buttons & BUTTON_FORCEPOWER || pm->cmd.buttons & BUTTON_FORCEGRIP
                                               || pm->cmd.buttons & BUTTON_FORCE_LIGHTNING) ))
            {   //racc - play projectile block animation even in .
                otherOwner->client->ps.weaponTime = 0;
                WP_SaberBlockNonRandom(otherOwner, ent->r.currentOrigin, qtrue);
            }

            //[BoltBlockSys]
            OJP_HandleBoltBlock(ent, otherOwner, trace);
            //[/BoltBlockSys]
            //[DodgeSys]
            return qtrue;
            //return;
            //[/DodgeSys]
        }
    }

    // check for sticking
    //[SaberThrowSys]
    if ( !other->takedamage && ( ent->s.eFlags & EF_MISSILE_STICK )
            && ent->s.weapon != WP_SABER)
        //if ( !other->takedamage && ( ent->s.eFlags & EF_MISSILE_STICK ) )
        //[/SaberThrowSys]
    {
        laserTrapStick( ent, trace->endpos, trace->plane.normal );
        G_AddEvent( ent, EV_MISSILE_STICK, 0 );
        //[DodgeSys]
        return qtrue;
        //return;
        //[/DodgeSys]
    }

    // impact damage
    if (other->takedamage && !isKnockedSaber) {
        //[DodgeSys]
        //make players be able to dodge projectiles.
        missileDmg = ent->damage;
        if(G_DoDodge(other, &g_entities[ent->r.ownerNum], trace->endpos, -1, &missileDmg, ent->methodOfDeath))
        {   //player dodged the damage, have missile continue moving.
            if(ent->s.weapon == WP_ROCKET_LAUNCHER)
                ent->genericValue1 = 0;
            return qfalse;
        }
        //[/DodgeSys]

        // FIXME: wrong damage direction?
        //[DodgeSys]
        if ( missileDmg ) {
            //if ( ent->damage ) {
            //[/DodgeSys]
            vec3_t	velocity;
            qboolean didDmg = qfalse;

            BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
            if ( VectorLength( velocity ) == 0 ) {
                velocity[2] = 1;	// stepped on a grenade
            }

            if (ent->s.weapon == WP_BOWCASTER || ent->s.weapon == WP_FLECHETTE ||
                    ent->s.weapon == WP_ROCKET_LAUNCHER)
            {
                if (ent->s.weapon == WP_FLECHETTE && (ent->s.eFlags & EF_ALT_FIRING))
                {
                    ent->think(ent);
                }
                else
                {
                    G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
                              //[DodgeSys]
                              ent->r.currentOrigin, missileDmg,
                              //[/DodgeSys]
                              DAMAGE_HALF_ABSORB, ent->methodOfDeath);
                    didDmg = qtrue;
                }
            }
            else {
                gentity_t *owner = &g_entities[ent->r.ownerNum];
                float distance = VectorDistance(owner->r.currentOrigin,other->r.currentOrigin);

                if(distance <= 100.0f)
                {
                    G_Damage (other, ent, owner, velocity,
                              //[DodgeSys]
                              ent->r.currentOrigin, missileDmg * 2,
                              //[/DodgeSys]
                              0, ent->methodOfDeath);
                }
                else if (distance <= 300.0f)
                {
                    G_Damage (other, ent, owner, velocity,
                              //[DodgeSys]
                              ent->r.currentOrigin, missileDmg * 1.5,
                              //[/DodgeSys]
                              0, ent->methodOfDeath);
                }
                else
                {
                    G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
                              //[DodgeSys]
                              ent->r.currentOrigin, missileDmg,
                              //[/DodgeSys]
                              0, ent->methodOfDeath);
                }
                didDmg = qtrue;
            }


            if (didDmg && other && other->client)
            {   //What I'm wondering is why this isn't in the NPC pain funcs. But this is what SP does, so whatever.
                class_t	npc_class = other->client->NPC_class;

                // If we are a robot and we aren't currently doing the full body electricity...
                if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE ||
                        npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 || npc_class == CLASS_REMOTE ||
                        npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || //npc_class == CLASS_PROTOCOL ||//no protocol, looks odd
                        npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY )
                {
                    // special droid only behaviors
                    if ( other->client->ps.electrifyTime < level.time + 100 )
                    {
                        // ... do the effect for a split second for some more feedback
                        other->client->ps.electrifyTime = level.time + 450;
                    }
                    //FIXME: throw some sparks off droids,too
                }
            }
        }

        if ( ent->s.weapon == WP_DEMP2 )
        {   //a hit with demp2 decloaks people, disables ships
            if ( other && other->client && other->client->NPC_class == CLASS_VEHICLE )
            {   //hit a vehicle
                if ( other->m_pVehicle //valid vehicle ent
                        && other->m_pVehicle->m_pVehicleInfo//valid stats
                        && (other->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER//always affect speeders
                            ||(other->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER && ent->classname && Q_stricmp("vehicle_proj", ent->classname ) == 0) )//only vehicle ion weapons affect a fighter in this manner
                        && !FighterIsLanded( other->m_pVehicle , &other->client->ps )//not landed
                        && !(other->spawnflags&2) )//and not suspended
                {   //vehicles hit by "ion cannons" lose control
                    if ( other->client->ps.electrifyTime > level.time )
                    {   //add onto it
                        //FIXME: extern the length of the "out of control" time?
                        other->client->ps.electrifyTime += Q_irand(200,500);
                        if ( other->client->ps.electrifyTime > level.time + 4000 )
                        {   //cap it
                            other->client->ps.electrifyTime = level.time + 4000;
                        }
                    }
                    else
                    {   //start it
                        //FIXME: extern the length of the "out of control" time?
                        other->client->ps.electrifyTime = level.time + Q_irand(200,500);
                    }
                }
            }
            else if ( other && other->client && other->client->ps.powerups[PW_CLOAKED] )
            {
                Jedi_Decloak( other );
                if ( ent->methodOfDeath == MOD_DEMP2_ALT )
                {   //direct hit with alt disables cloak forever
                    //permanently disable the saboteur's cloak
                    other->client->cloakToggleTime = Q3_INFINITE;
                }
                else
                {   //temp disable
                    other->client->cloakToggleTime = level.time + Q_irand( 3000, 10000 );
                }
            }
        }
    }
killProj:
    // 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 && !isKnockedSaber ) {
        G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
        ent->s.otherEntityNum = other->s.number;
    } else if( trace->surfaceFlags & SURF_METALSTEPS ) {
        G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
    } else if (ent->s.weapon != G2_MODEL_PART && !isKnockedSaber) {
        G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
    }

    if (!isKnockedSaber)
    {
        ent->freeAfterEvent = qtrue;

        // change over to a normal entity right at the point of impact
        ent->s.eType = ET_GENERAL;
    }

    SnapVectorTowards( trace->endpos, ent->s.pos.trBase );	// save net bandwidth

    G_SetOrigin( ent, trace->endpos );

    ent->takedamage = qfalse;
    // splash damage (doesn't apply to person directly hit)
    if ( ent->splashDamage ) {
        G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
                        other, ent, ent->splashMethodOfDeath );
    }

    if (ent->s.weapon == G2_MODEL_PART)
    {
        ent->freeAfterEvent = qfalse; //it will free itself
    }

    trap_LinkEntity( ent );

    //[DodgeSys]
    return qtrue;
    //[/DodgeSys]
}