Ejemplo n.º 1
0
// Called from client.c
void GrappleService()
{
    vec3_t hookVector, hookVelocity;
    gedict_t *enemy;

    // drop the hook if player lets go of fire
    if ( !self->s.v.button0 )
    {
        if ( self->s.v.weapon == IT_HOOK )
        {
            GrappleReset( self->hook );
            return;
        }
    }

    enemy = PROG_TO_EDICT( self->hook->s.v.enemy );

    // If hooked to a player, track them directly!
    if ( enemy->ct == ctPlayer )
    {
        VectorSubtract( enemy->s.v.origin, self->s.v.origin, hookVector );
    }
    else
        VectorSubtract( self->hook->s.v.origin, self->s.v.origin, hookVector );

    // No longer going to factor maxspeed into grapple velocity
    // Using standard grapple velocity of 800 set from original 3wave
    // purectf velocity = 2.35 * 320 or 360 * 1 = 750 or 846

    VectorCopy( hookVector, hookVelocity );
    VectorNormalize( hookVelocity );

    if ( self->ctf_flag & CTF_RUNE_HST )
        VectorScale( hookVelocity, 1000, self->s.v.velocity );
    else
        VectorScale( hookVelocity, 800, self->s.v.velocity );

    if ( vlen(hookVector) <= 100 ) // cancel chain sound
    {
        FreezeGravity( self );
        if ( self->ctf_sound )
        {
            // If there is a chain, ditch it now. We're
            // close enough. Having extra entities lying around
            // is never a good idea.
            if ( self->hook->s.v.goalentity )
            {
                PROG_TO_EDICT(self->hook->s.v.goalentity)->s.v.think     = (func_t) RemoveChain;
                PROG_TO_EDICT(self->hook->s.v.goalentity)->s.v.nextthink = g_globalvars.time;
            }

            sound( self, CHAN_NO_PHS_ADD + CHAN_WEAPON, "weapons/chain3.wav", 1, ATTN_NORM );
            self->ctf_sound = false; // reset the sound channel.
        }
    }
}
Ejemplo n.º 2
0
//
// GrappleTrack - Constantly updates the hook's position relative to
//                 what it's hooked to. Inflicts damage if attached to
//                 a player that is not on the same team as the hook's
//                 owner.
//
void GrappleTrack()
{
    gedict_t *enemy = PROG_TO_EDICT(self->s.v.enemy);
    gedict_t *owner = PROG_TO_EDICT(self->s.v.owner);

    // Release dead targets
    if ( enemy->ct == ctPlayer && ISDEAD( enemy ) )
        owner->on_hook = false;

    // drop the hook if owner is dead or has released the button
    if ( !owner->on_hook || owner->s.v.health <= 0 )
    {
        GrappleReset( self );
        return;
    }

    if ( enemy->ct == ctPlayer )
    {
        if ( !CanDamage(enemy, owner) )
        {
            GrappleReset( self );
            return;
        }

        // move the hook along with the player.  It's invisible, but
        // we need this to make the sound come from the right spot
        setorigin( self, PASSVEC3(enemy->s.v.origin) );

        sound ( self, CHAN_WEAPON, "blob/land1.wav", 1, ATTN_NORM );
        enemy->deathtype = dtHOOK;
        T_Damage ( enemy, self, owner, 1 );
        trap_makevectors ( self->s.v.v_angle );
        SpawnBlood( enemy->s.v.origin, 1 );
    }

    // If the hook is not attached to the player, constantly copy
    // the target's velocity. Velocity copying DOES NOT work properly
    // for a hooked client.
    if ( enemy->ct != ctPlayer )
        VectorCopy( enemy->s.v.velocity, self->s.v.velocity );

    self->s.v.nextthink = g_globalvars.time + 0.1;
}
Ejemplo n.º 3
0
// add/remove hook item to/from player
void AddHook( qbool yes )
{
	gedict_t *e, *oself;

	oself = self;

	for ( e = world; (e = find_plr( e )); ) {
		e->s.v.items = (yes ? ((int) e->s.v.items | IT_HOOK) : ((int) e->s.v.items & ~IT_HOOK));

		self = e; // warning

		if ( self->hook_out )
			GrappleReset( self->hook );
		self->hook_out = false;
		self->on_hook = false;

		if ( !yes && self->s.v.weapon == IT_HOOK ) { // actually remove hook from hands if hold, not just from items
			self->s.v.weapon = 0;
			W_SetCurrentAmmo();
		}
	}

	self = oself;
}
Ejemplo n.º 4
0
void GrappleAnchor()
{
    gedict_t *owner = PROG_TO_EDICT( self->s.v.owner );

    if (other == owner)
        return;

    // DO NOT allow the grapple to hook to any projectiles, no matter WHAT!
    // if you create new types of projectiles, make sure you use one of the
    // classnames below or write code to exclude your new classname so
    // grapples will not stick to them.

    if ( streq(other->s.v.classname, "rocket")  ||
            streq(other->s.v.classname, "grenade") ||
            streq(other->s.v.classname, "spike"  ) ||
            streq(other->s.v.classname, "hook"   ))
        return;

    if ( other->ct == ctPlayer )
    {
        // grappling players in prewar is annoying
        if ( match_in_progress != 2 || (tp_num() == 4 && streq(getteam(other), getteam(owner))) )
        {
            GrappleReset( self );
            return;
        }

        sound ( self, CHAN_WEAPON, "player/axhit1.wav", 1, ATTN_NORM );

        // previously 10 damage per hit, but at close range that could be exploited
        other->deathtype = dtHOOK;
        T_Damage ( other, self, owner, 1 );

        // make hook invisible since we will be pulling directly
        // towards the player the hook hit. Quakeworld makes it
        // too quirky to try to match hook's velocity with that of
        // the client that it hit.
        setmodel ( self, "" );
    }
    else
    {
        sound ( self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM );

        // One point of damage inflicted upon impact. Subsequent
        // damage will only be done to PLAYERS... this way secret
        // doors and triggers will only be damaged once.
        if ( other->s.v.takedamage ) {
            other->deathtype = dtHOOK;
            T_Damage ( other, self, owner, 1 );
        }

        SetVector( self->s.v.velocity , 0, 0, 0 );
        SetVector( self->s.v.avelocity, 0, 0, 0 );
    }

    // conveniently clears the sound channel of the CHAIN1 sound,
    // which is a looping sample and would continue to play. Tink1 is
    // the least offensive choice, as NULL.WAV loops and clogs the
    // channel with silence
    sound ( owner, CHAN_NO_PHS_ADD + CHAN_WEAPON, "weapons/tink1.wav", 1, ATTN_NORM );

    if ( !owner->s.v.button0 )
    {
        GrappleReset( self );
        return;
    }

    if ( (int)owner->s.v.flags & FL_ONGROUND )
        owner->s.v.flags -= FL_ONGROUND;

    owner->on_hook = true;
    sound ( owner, CHAN_WEAPON, "weapons/chain2.wav", 1, ATTN_NORM );
    owner->ctf_sound = true;

    self->s.v.enemy     = EDICT_TO_PROG( other );
    self->s.v.think     = (func_t) GrappleTrack;
    self->s.v.nextthink = g_globalvars.time;
    self->s.v.solid     = SOLID_NOT;
    self->s.v.touch     = (func_t) SUB_Null;
}
Ejemplo n.º 5
0
Archivo: player.c Proyecto: deurk/ktx
void PlayerDie()
{
	self->ca_alive = false;

	DropPowerups();

	if ( isCTF() )
	{
		if ( self->hook_out )
		{
			GrappleReset( self->hook );
			self->attack_finished = g_globalvars.time + 0.75;
			self->hook_out = true; // FIXME: for which reason this set to true?
		}

		DropRune();
		PlayerDropFlag( self, false );
	}

	TeamplayDeathEvent (self);
#ifdef BOT_SUPPORT
	BotPlayerDeathEvent (self);
#endif

	self->s.v.items -= ( int ) self->s.v.items & IT_INVISIBILITY;
	self->invisible_finished = 0;	// don't die as eyes
	self->invincible_finished = 0;
// so we have quad few milleseconds after death
//	self->super_damage_finished = 0; // moved to prethink, like in ktpro
	self->radsuit_finished = 0;

	self->s.v.modelindex = modelindex_player;	// don't use eyes

	DropBackpack();

	self->weaponmodel = "";
	if (vw_enabled)
		self->vw_index = 9;	// null vwep model

	SetVector( self->s.v.view_ofs, 0, 0, -8 );
	self->s.v.deadflag = DEAD_DYING;
	self->s.v.solid = SOLID_NOT;
	self->s.v.flags -= ( ( int ) ( self->s.v.flags ) ) & FL_ONGROUND;
	self->s.v.movetype = MOVETYPE_TOSS;
	if ( self->s.v.velocity[2] < 10 )
		self->s.v.velocity[2] = self->s.v.velocity[2] + g_random() * 300;

    if ( self->s.v.health < -40 || dtSQUISH == self->deathtype || dtSUICIDE == self->deathtype || isRA() || isCA() )
	{
		GibPlayer();

		// Yawnmode: respawn has the same delay (900ms) regardless of deathtype gib/normal
		// - Molgrum

		// Hoonymode: Also force some time, e.g. to prevent instant respawn after /kill which
		// can cause bug if kill telefrags an idle player (counts as two points...)
		// only ever happens in testing, but oh well --phil
		if ( k_yawnmode || isHoonyModeDuel() )
		{
			self->s.v.nextthink = g_globalvars.time + 0.9;
			self->think = ( func_t ) PlayerDead;
			return;
		}

		PlayerDead();
		return;
	}

    if( match_in_progress == 2 )
		DeathSound();

	self->s.v.angles[0] = 0;
	self->s.v.angles[2] = 0;


    // function part split and called here
	StartDie();
}