Esempio n. 1
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;
}
Esempio n. 2
0
File: combat.c Progetto: meag/ktx
void T_Damage( gedict_t * targ, gedict_t * inflictor, gedict_t * attacker, float damage )
{
	vec3_t          dir;
	gedict_t       *oldself;
	float           save;
	float           take;
	int				i, c1 = 8, c2 = 4, hdp;
	float			dmg_dealt = 0, virtual_take = 0;
	float			non_hdp_damage; // save damage before handicap apply for kickback calculation
	float			native_damage = damage; // save damage before apply any modificator
	char            *attackerteam, *targteam, *attackername, *victimname;
	qbool			tp4teamdmg = false;

	//midair and instagib
	float playerheight = 0, midheight = 0;
	qbool midair = false, inwater = false, do_dmg = false, rl_dmg = false, stomp_dmg = false;

	// can't apply damage to dead
	if ( !targ->s.v.takedamage || ISDEAD( targ ) )
		return;

	// can't damage other players in race
	if ( isRACE() && ( attacker != targ ) )
	{
			if ( targ->ct == ctPlayer || attacker->ct == ctPlayer )
				return;
	}

	// ignore almost all damage in CA while coutdown
	if ( isCA() && match_in_progress && ra_match_fight != 2 )
	{
		if ( !( 	dtTELE1 == targ->deathtype	// always do tele damage
				 || dtTELE2 == targ->deathtype	// always do tele damage
				 || dtTELE3 == targ->deathtype	// always do tele damage
				 || dtSUICIDE == targ->deathtype // do suicide damage anyway
			  )
		)
			return;
	}	

	// used by buttons and triggers to set activator for target firing
	damage_attacker = attacker;
	damage_inflictor = inflictor;

	attackerteam = getteam( attacker );
	targteam = getteam( targ );

	if ( (int)cvar("k_midair") )
		midair = true;

	// in bloodfest boss damage factor.
	if ( k_bloodfest && attacker->bloodfest_boss )
	{
		damage *= 4;
	}

	// check for quad damage powerup on the attacker
	// midair quad makes rockets fast, but no change to damage
	if ( attacker->super_damage_finished > g_globalvars.time
	     && strneq( inflictor->s.v.classname, "door" ) && dtSTOMP != targ->deathtype
		 && !midair 
	   )
		damage *= ( deathmatch == 4 ? 8 : 4 ); // in dmm4 quad is octa actually

	// ctf strength rune
	if ( attacker->ctf_flag & CTF_RUNE_STR )
		damage *= 2;

	// ctf resistance rune
	if ( targ->ctf_flag & CTF_RUNE_RES )
	{
		damage /= 2;
		ResistanceSound( targ );
	}

	// did we hurt enemy flag carrier?
	if ( (targ->ctf_flag & CTF_FLAG) && (!streq(targteam, attackerteam)) )
	{
		attacker->carrier_hurt_time = g_globalvars.time;
	}

	// in teamplay 4 we do no armor or health damage to teammates (unless telefrag), but do apply velocity changes
	if ( tp_num() == 4 && streq(targteam, attackerteam) && ( isCA() || targ != attacker ) && !TELEDEATH(targ) )
	{
		tp4teamdmg = true;
	}

	if ( midair || cvar("k_instagib") )
	{
		traceline( PASSVEC3(targ->s.v.origin),
				targ->s.v.origin[0], 
				targ->s.v.origin[1], 
				targ->s.v.origin[2] - 2048,
				true, targ );

		playerheight = targ->s.v.absmin[2] - g_globalvars.trace_endpos[2] + ( cvar("k_instagib") ? 1 : 0 );
	}

	// get some data before apply damage in mid air mode
	if ( midair )
	{
		inwater = ( ((int)targ->s.v.flags & FL_INWATER) && targ->s.v.waterlevel > 1 );

		if ( streq( inflictor->s.v.classname, "rocket" ))
			midheight = targ->s.v.origin[2] - inflictor->s.v.oldorigin[2];

		rl_dmg = ( targ->ct == ctPlayer && dtRL == targ->deathtype );
		stomp_dmg = ( targ->ct == ctPlayer && dtSTOMP == targ->deathtype );

		if ( !rl_dmg ) {
			// damage types which ignore "lowheight"
			do_dmg =   targ->ct != ctPlayer				// always do damage to non player, secret doors etc...
				 	|| dtWATER_DMG == targ->deathtype	// always do water damage
				 	|| dtLAVA_DMG  == targ->deathtype	// always do lava damage
				 	|| dtSLIME_DMG == targ->deathtype	// always do slime damage
				 	|| dtSTOMP == targ->deathtype	// always do stomp damage
				 	|| dtTELE1 == targ->deathtype	// always do tele damage
				 	|| dtTELE2 == targ->deathtype	// always do tele damage
				 	|| dtTELE3 == targ->deathtype	// always do tele damage
					|| dtSUICIDE == targ->deathtype; // do suicide damage anyway
		}
	}

	non_hdp_damage = damage; // save damage before handicap apply for kickback calculation

	// #handicap#
	if ( attacker != targ ) // attack no self
	if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) // player vs player
	if ( ( hdp = GetHandicap(attacker) ) != 100 ) // skip checks if hdp == 100
	if (    dtAXE  == targ->deathtype
 		 || dtSG   == targ->deathtype
		 || dtSSG  == targ->deathtype
		 || dtNG   == targ->deathtype
		 || dtSNG  == targ->deathtype
		 || dtGL   == targ->deathtype
		 || dtRL   == targ->deathtype
		 || dtLG_BEAM     == targ->deathtype
		 || dtLG_DIS      == targ->deathtype
		 || dtLG_DIS_SELF == targ->deathtype // even that impossible
	   ) {
		damage *= 0.01f * hdp;
	}

	// save damage based on the target's armor level

	save = newceil( targ->s.v.armortype * damage );

	if ( tp4teamdmg )
		save = 0; // we do not touch armor

	if ( save >= targ->s.v.armorvalue )
	{
		save = targ->s.v.armorvalue;
		targ->s.v.armortype = 0;	// lost all armor
		targ->s.v.items -= ( ( int ) targ->s.v.items & ( IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3 ) );
	}

	dmg_dealt += save;

	if ( match_in_progress == 2 )
		targ->s.v.armorvalue = targ->s.v.armorvalue - save;

	take = newceil( damage - save );

	// mid air damage modificators
	if ( midair )
	{
		int k_midair_minheight, midair_minheight;

		k_midair_minheight = (int)cvar("k_midair_minheight");	

		if ( k_midair_minheight == 1 )
			midair_minheight = 128;
		else if ( k_midair_minheight == 2 )
			midair_minheight = 256;
		else if ( k_midair_minheight == 3 )
			midair_minheight = 512;
		else if ( k_midair_minheight == 4 )
			midair_minheight = 1024;
		else
			midair_minheight = 64;

		if ( rl_dmg || stomp_dmg )
			take = 9999;

		if ( playerheight < midair_minheight && rl_dmg )
			take = 0; // no dmg done if target is not high enough

		if ( playerheight < 45 && !inwater && rl_dmg )
			take = 0; // no rl dmg in such case

		if ( !rl_dmg && !do_dmg )
			take = 0; // unknown damage for midair, so do not damage

		if ( rl_dmg && targ == attacker )
			take = 0; // no self rl damage
	}

	// instagib damage modificators
	if ( cvar("k_instagib") )
	{
		if ( inflictor->ct == ctPlayer )
			take = 5000;

		if ( attacker == targ )
			take = 0;
	}

	// helps kill player in prewar at "wrong" places
	if ( match_in_progress != 2 && native_damage > 450 )
		take = 99999;

	// team play damage avoidance and godmode or invincibility check

	virtual_take = max(0, take); // virtual_take used for calculating dmg_dealt only in case of k_dmgfrags

	// ignore this checks for suicide damage
	if ( dtSUICIDE != targ->deathtype )
	{
		if ( ( int ) targ->s.v.flags & FL_GODMODE )
		{
			take = 0; // what if god was one of us
		}
		else if ( targ->invincible_finished >= g_globalvars.time )
		{
			if ( targ->invincible_sound < g_globalvars.time )
			{
				sound( targ, CHAN_AUTO, "items/protect3.wav", 1, ATTN_NORM );
				targ->invincible_sound = g_globalvars.time + 2;
			}

			take = 0;
		}
		else if ( ( tp_num() == 1 || ( tp_num() == 3 && targ != attacker ) )
		 	&& !strnull( attackerteam )
		 	&& streq( targteam, attackerteam )
		 	&& attacker->ct == ctPlayer
		 	&& strneq( inflictor->s.v.classname, "door" )
		 	&& !TELEDEATH( targ ) // do telefrag damage in tp
	   	)
	   	{
			// teamplay == 1 don't damage self and mates (armor affected anyway)
			// teamplay == 3 don't damage mates, do damage to self (armor affected anyway)

			take = 0;	   	
	   	}
	   	else if ( tp4teamdmg )
	   	{
			take = 0; // we do not touch health	   	
	   	}
	}

	take = max(0, take); // avoid negative take, if any

	if ( cvar("k_dmgfrags") )
	{
		if ( TELEDEATH( targ ) )
		{
			// tele doesn't count for any dmgfrags damage
			dmg_dealt = 0; 
		}
		else if ( targ->invincible_finished >= g_globalvars.time )
		{
			// damage dealt _not_ capped by victim's health if victim has pent
			dmg_dealt += virtual_take;
		}
		else
		{
			// damage dealt capped by victim's health
			dmg_dealt += bound( 0, virtual_take, targ->s.v.health );
		}
	}
	else
	{
		// damage dealt capped by victim's health
		dmg_dealt += bound( 0, take, targ->s.v.health );
	}

	// add to the damage total for clients, which will be sent as a single
	// message at the end of the frame
	// FIXME: remove after combining shotgun blasts?
	if ( targ->ct == ctPlayer )
	{
		targ->s.v.dmg_take += take;
		targ->s.v.dmg_save += save;
		targ->s.v.dmg_inflictor = EDICT_TO_PROG( inflictor );
	}

	if ( save )
	{
		if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname ))
	        	|| ( targ->deathtype == dtWATER_DMG )
	                || ( targ->deathtype == dtEXPLO_BOX )
	                || ( targ->deathtype == dtFALL )
	                || ( targ->deathtype == dtSQUISH )
	                || ( targ->deathtype == dtCHANGELEVEL )
	                || ( targ->deathtype == dtFIREBALL )
	                || ( targ->deathtype == dtSLIME_DMG )
	                || ( targ->deathtype == dtLAVA_DMG )
	                || ( targ->deathtype == dtTRIGGER_HURT )
		)
				attackername = "world";
		else
			attackername = attacker->s.v.netname;
			victimname = targ->s.v.netname;

		log_printf(
			"\t\t<event>\n"
			"\t\t\t<damage>\n"
			"\t\t\t\t<time>%f</time>\n"
			"\t\t\t\t<attacker>%s</attacker>\n"
			"\t\t\t\t<target>%s</target>\n"
			"\t\t\t\t<type>%s</type>\n"
			"\t\t\t\t<quad>%d</quad>\n"
			"\t\t\t\t<splash>%d</splash>\n"
			"\t\t\t\t<value>%d</value>\n"
			"\t\t\t\t<armor>1</armor>\n"
			"\t\t\t</damage>\n"
			"\t\t</event>\n",
			g_globalvars.time - match_start_time,
			cleantext(attackername),
			cleantext(victimname),
			death_type( targ->deathtype ),
			(int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ),
			dmg_is_splash,
			(int)save
		);
	}

	// figure momentum add
	if ( inflictor != world
		 && (	targ->s.v.movetype == MOVETYPE_WALK
			  || ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) )
			 )
	)
	{
		float nailkick;

		for ( i = 0; i < 3; i++ )
			dir[i] = targ->s.v.origin[i] - ( inflictor->s.v.absmin[i] + inflictor->s.v.absmax[i] ) * 0.5;

		VectorNormalize( dir );

		dir[2] = ((dtLG_DIS_SELF == targ->deathtype || dtLG_DIS == targ->deathtype) && dir[2] < 0) ? -dir[2] : dir[2];

		if ( midair && non_hdp_damage < 60 && attacker != targ ) {
			c1 = 11;
			c2 = 6;
		}

		// Yawnmode: nails increases kickback
		// - Molgrum
		if ( k_yawnmode && streq( inflictor->s.v.classname, "spike" ) )
			nailkick = 1.2;
		else
			nailkick = 1.0;

		for ( i = 0; i < 3; i++ ) 
			targ->s.v.velocity[i] += dir[i] * non_hdp_damage * c1 * nailkick * ( midair && playerheight >= 45 ? ( 1 + ( playerheight - 45 ) / 64 ) : 1 );

		if ( midair && playerheight < 45 )
			targ->s.v.velocity[2] += dir[2] * non_hdp_damage * c2 * nailkick; // only for z component

		if ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) )
		{
			targ->s.v.flags = (int)targ->s.v.flags & ~FL_ONGROUND;		
		}
	}

	if ( match_in_progress == 2 && (int)cvar("k_dmgfrags") )
	{
		if ( attacker->ct == ctPlayer && targ->ct == ctPlayer && attacker != targ )
		{
			if ( isDuel() || isFFA() || strneq(attackerteam, targteam) )
			{
				int dmg_frags;
				attacker->ps.dmg_frags += dmg_dealt; // add dealt
				dmg_frags = attacker->ps.dmg_frags / 100; // 1 frag = 100 damage
				attacker->s.v.frags = (int)(attacker->s.v.frags + dmg_frags);
				attacker->ps.dmg_frags -= dmg_frags * 100;
			}
		}
	}

	// do the damage

	if (    match_in_progress == 2
		 || dtSUICIDE == targ->deathtype // do suicide damage anyway
		 || TELEDEATH( targ )
		 || ( k_practice && targ->ct != ctPlayer ) // #practice mode#
		 || take >= 99999 // do such huge damage even in prewar, prewar because indirectly here match_in_progress != 2
	   ) 
	{
		targ->s.v.health -= take;

//		G_bprint( 2, "%s %f\n", targ->s.v.classname, targ->s.v.health );

		if ( take )
		{
			if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname ))
		        	|| ( targ->deathtype == dtWATER_DMG )
		                || ( targ->deathtype == dtEXPLO_BOX )
		                || ( targ->deathtype == dtFALL )
		                || ( targ->deathtype == dtSQUISH )
		                || ( targ->deathtype == dtCHANGELEVEL )
		                || ( targ->deathtype == dtFIREBALL )
		                || ( targ->deathtype == dtSLIME_DMG )
		                || ( targ->deathtype == dtLAVA_DMG )
		                || ( targ->deathtype == dtTRIGGER_HURT )
			)
				attackername = "world";
			else
				attackername = attacker->s.v.netname;
				victimname = targ->s.v.netname;

			log_printf(
				"\t\t<event>\n"
				"\t\t\t<damage>\n"
				"\t\t\t\t<time>%f</time>\n"
				"\t\t\t\t<attacker>%s</attacker>\n"
				"\t\t\t\t<target>%s</target>\n"
				"\t\t\t\t<type>%s</type>\n"
				"\t\t\t\t<quad>%d</quad>\n"
				"\t\t\t\t<splash>%d</splash>\n"
				"\t\t\t\t<value>%d</value>\n"
				"\t\t\t\t<armor>0</armor>\n"
				"\t\t\t</damage>\n"
				"\t\t</event>\n",
				g_globalvars.time - match_start_time,
				cleantext(attackername),
				cleantext(victimname),
				death_type( targ->deathtype ),
				(int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ),
				dmg_is_splash,
				(int)take
			);
		}

		if ( !targ->s.v.health || dtSUICIDE == targ->deathtype )
			targ->s.v.health = -1; // qqshka, no zero health, heh, imo less bugs after this
	}

	// show damage in sbar
	if ( match_in_progress != 2 && ISLIVE( targ ) && !k_matchLess )
	{
		if ( !midair || ( (int)targ->s.v.flags & FL_ONGROUND ) )
		{
			if ( targ->ct == ctPlayer )			
				targ->s.v.currentammo = 1000 + Q_rint(damage);

			if ( attacker != targ && attacker->ct == ctPlayer)
				attacker->s.v.health = 1000 + Q_rint(damage);
		}
	}

	// update damage stats like: give/taked/team damage
	if ( attacker->ct == ctPlayer && targ->ct == ctPlayer )
	{
		if ( attacker == targ )
		{
			// self damage

			attacker->ps.dmg_self += dmg_dealt;
		}
		else
		{
			int items = targ->s.v.items;

			// damage to enemy weapon
			if ( items & (IT_ROCKET_LAUNCHER | IT_LIGHTNING) )
			{
				attacker->ps.dmg_eweapon += dmg_dealt;
			}

			if ( tp_num() && streq(attackerteam, targteam) )
			{
				attacker->ps.dmg_team += dmg_dealt;
			}
			else 
			{
				attacker->ps.dmg_g += dmg_dealt;
				targ->ps.dmg_t     += dmg_dealt;
			}

			// real hits

			if ( take || save )
			{
				if ( dtRL == targ->deathtype )
					attacker->ps.wpn[wpRL].rhits++;

				if ( dtGL == targ->deathtype )
					attacker->ps.wpn[wpGL].rhits++;
			}

			// virtual hits

			if ( virtual_take || save )
			{
				if ( dtRL == targ->deathtype )
				{
					attacker->ps.wpn[wpRL].vhits++;
					// virtual given rl damage
					attacker->ps.dmg_g_rl += ( virtual_take + save );
				}

				if ( dtGL == targ->deathtype )
					attacker->ps.wpn[wpGL].vhits++;
			}
		}
	}

	// mid air bonuses
	if ( midair && match_in_progress == 2 && attacker != targ && take && rl_dmg)
			MidairDamageBonus(attacker, midheight);

	if ( midair && match_in_progress == 2 && stomp_dmg ) {
		attacker->ps.mid_stomps++;
		targ->s.v.frags -= 3;
	}

 	// if targed killed, do appropriate action and return
	if ( ISDEAD( targ ) )
	{
		Killed( targ, attacker, inflictor );
		return;
	}

	// react to the damage - call pain function
	oldself = self;
	self = targ;

  	if ( (int)self->s.v.flags & FL_MONSTER )
  	{
		GetMadAtAttacker( attacker );
  	}

	if ( self->th_pain )
	{
		self->th_pain( attacker, take );
	}

	self = oldself;
}
Esempio n. 3
0
File: player.c Progetto: deurk/ktx
void PainSound()
{
	int             rs;

	if ( ISDEAD( self ) )
		return;

// water pain sounds
	if ( (self->s.v.watertype == CONTENT_WATER || self->s.v.watertype == CONTENT_SLIME)  && self->s.v.waterlevel == 3 )
	{
		DeathBubbles( 1 );

        if ( match_in_progress != 2 )
            return;

		if ( g_random() > 0.5 )
			sound( self, CHAN_VOICE, "player/drown1.wav", 1, ATTN_NORM );
		else
			sound( self, CHAN_VOICE, "player/drown2.wav", 1, ATTN_NORM );
		return;
	}
// slime pain sounds
	if ( self->s.v.watertype == CONTENT_SLIME )
	{
// FIX ME       put in some steam here
        if ( match_in_progress != 2 )
            return;

		if ( g_random() > 0.5 )
			sound( self, CHAN_VOICE, "player/lburn1.wav", 1, ATTN_NORM );
		else
			sound( self, CHAN_VOICE, "player/lburn2.wav", 1, ATTN_NORM );
		return;
	}

	if ( self->s.v.watertype == CONTENT_LAVA )
	{
        if ( match_in_progress != 2 )
            return;

		if ( g_random() > 0.5 )
			sound( self, CHAN_VOICE, "player/lburn1.wav", 1, ATTN_NORM );
		else
			sound( self, CHAN_VOICE, "player/lburn2.wav", 1, ATTN_NORM );
		return;
	}

	if ( self->pain_finished > g_globalvars.time )
	{
		self->axhitme = 0;
		return;
	}
	self->pain_finished = g_globalvars.time + 0.5;

// don't make multiple pain sounds right after each other

// ax pain sound
	if ( self->axhitme == 1 )
	{
		self->axhitme = 0;
		sound( self, CHAN_VOICE, "player/axhit1.wav", 1, ATTN_NORM );
		return;
	}

	rs = ( g_random() * 5 ) + 1;

	self->noise = "";
	if ( rs == 1 )
		self->noise = "player/pain1.wav";
	else if ( rs == 2 )
		self->noise = "player/pain2.wav";
	else if ( rs == 3 )
		self->noise = "player/pain3.wav";
	else if ( rs == 4 )
		self->noise = "player/pain4.wav";
	else if ( rs == 5 )
		self->noise = "player/pain5.wav";
	else
		self->noise = "player/pain6.wav";

	sound( self, CHAN_VOICE, self->noise, 1, ATTN_NORM );
	return;
}
Esempio n. 4
0
void BotSetCommand (gedict_t* self)
{
	extern float last_frame_time;
	float msec_since_last = (last_frame_time - self->fb.last_cmd_sent) * 1000;
	int cmd_msec = (int)msec_since_last;
	int weapon_script_impulse = 0;
	int impulse = 0;
	qbool jumping;
	qbool firing;
	vec3_t direction;

	BotPerformRocketJump (self);

	if (cmd_msec) {
		self->fb.cmd_msec_lost += (msec_since_last - cmd_msec);
		if (self->fb.cmd_msec_lost >= 1) {
			self->fb.cmd_msec_lost -= 1;
			cmd_msec += 1;
		}
	}
	else if (self->fb.cmd_msec_last) {
		// Probably re-sending after blocked(), re-use old number
		cmd_msec = self->fb.cmd_msec_last;
	}
	else {
		cmd_msec = 12;
	}

	//G_sprint(self, PRINT_HIGH, "Movement length @ %f: %d\n", last_frame_time, cmd_msec);

	// dir_move_ is the direction we want to move in, but need to take inertia into effect
	// ... as rough guide (and save doubling physics calculations), scale command > 
	VectorNormalize (self->fb.dir_move_);
	VectorScale (self->fb.dir_move_, sv_maxspeed, self->fb.last_cmd_direction);

	trap_makevectors (self->fb.desired_angle);

	// During intermission, always do nothing and leave humans to change level
	if (intermission_running) {
		self->fb.firing = self->fb.jumping = false;
	}
	else if (teamplay && deathmatch == 1 && !self->fb.firing) {
		// Weaponscripts
		if (self->s.v.weapon != IT_SHOTGUN && self->s.v.weapon != IT_AXE) {
			weapon_script_impulse = (self->s.v.ammo_shells ? 2 : 1);
		}
	}

	impulse =
		self->fb.botchose ? self->fb.next_impulse :
		self->fb.firing ? self->fb.desired_weapon_impulse :
		weapon_script_impulse;

	if (self->fb.firing && BotUsingCorrectWeapon (self)) {
		impulse = 0; // we already have the requested weapon
	}

	jumping = self->fb.jumping || self->fb.waterjumping;
	firing = self->fb.firing;

	self->fb.waterjumping = false;

	if (self->fb.dbg_countdown > 0) {
		jumping = firing = false;
		VectorClear (direction);
		--self->fb.dbg_countdown;
	}
	else {
		if (jumping && ((int)self->s.v.flags & FL_ONGROUND)) {
			BestJumpingDirection (self);
		}
		else {
			ApplyPhysics (self);
		}

		if (self->s.v.waterlevel <= 1) {
			vec3_t hor;

			VectorCopy (self->fb.dir_move_, hor);
			hor[2] = 0;
			VectorNormalize (hor);
			VectorScale (hor, 800, hor);

			direction[0] = DotProduct (g_globalvars.v_forward, hor);
			direction[1] = DotProduct (g_globalvars.v_right, hor);
			direction[2] = 0;
		}
		else {
			direction[0] = DotProduct (g_globalvars.v_forward, self->fb.dir_move_) * 800;
			direction[1] = DotProduct (g_globalvars.v_right, self->fb.dir_move_) * 800;
			direction[2] = DotProduct (g_globalvars.v_up, self->fb.dir_move_) * 800;
		}
#ifdef DEBUG_MOVEMENT
		if (self->fb.debug_path) {
			G_bprint (PRINT_HIGH, "     : final direction sent [%4.1f %4.1f %4.1f]\n", PASSVEC3 (self->fb.dir_move_));
		}
#endif
	}
	self->fb.desired_angle[2] = 0;

	if (ISDEAD (self)) {
		firing = false;
		jumping = BotRequestRespawn (self);
		VectorClear (direction);
		impulse = 0;
	}
	else if (self->fb.min_move_time > g_globalvars.time) {
		VectorClear (direction);
	}

	// Keep bots on spawns before match start
	if (match_in_progress != 2 && cvar(FB_CVAR_FREEZE_PREWAR)) {
		jumping = firing = false;
		VectorClear(direction);
		impulse = 0;
	}

	trap_SetBotCMD (
		NUM_FOR_EDICT (self),
		cmd_msec,
		PASSVEC3(self->fb.desired_angle),
		PASSVEC3(direction),
		(firing ? 1 : 0) | (jumping ? 2 : 0),
		impulse
	);

	self->fb.next_impulse = 0;
	self->fb.botchose = false;
	self->fb.last_cmd_sent = last_frame_time;
	self->fb.cmd_msec_last = cmd_msec;

	VectorClear (self->fb.obstruction_normal);
	if (self->s.v.button0 && !firing) {
		// Stopped firing, randomise next time
		self->fb.last_rndaim_time = 0;
	}
	self->fb.prev_look_object = self->fb.look_object;
	VectorCopy (self->s.v.velocity, self->fb.prev_velocity);
}
void SCR_SetupAutoID (void)
{
	int		i, view[4];
	float		model[16], project[16], winz, *origin;
	entity_t	*state;
	autoid_player_t	*id;
	vec3_t	OurViewPoint;
	vec3_t  ThisClientPoint;
	vec3_t	stop;
	vec3_t	edist;
	void TraceLine (vec3_t start, vec3_t end, vec3_t impact);

	autoid_count = 0;

	if (!scr_autoid.value || cls.state != ca_connected || !cls.demoplayback)
		return;

	glGetFloatv (GL_MODELVIEW_MATRIX, model);
	glGetFloatv (GL_PROJECTION_MATRIX, project);

	glGetIntegerv (GL_VIEWPORT, view);

	for (i = 0 ; i < cl.maxclients ; i++)
	{
		state = &cl_entities[1+i];

		if (!state->model->name)		// NULL model
			continue;

		if (!(state->modelindex == cl_modelindex[mi_player]))	// Not a player model
			continue;

		if (ISDEAD(state->frame)) // Dead
			continue;

//		if (strcmp(state->model->name, "progs/player.mdl"))
//			continue;


		if (R_CullSphere(state->origin, 0))
			continue;

		// Logic
		// Fill in one value with our viewpoint and the next value with target
		// Do traceline


		VectorCopy (r_refdef.vieworg, OurViewPoint);
		VectorCopy (state->origin, ThisClientPoint);

		TraceLine (OurViewPoint, ThisClientPoint, stop);
		if (stop[0] != 0 || stop[1] != 0 || stop[2] != 0)  // Quick and dirty traceline
			continue;

#if 1
		if (!CL_Visible_To_Client(OurViewPoint, ThisClientPoint)) {
			// We can't see it
			//Con_Printf("Cannot see it\n");
			continue;

		}
#endif

		id = &autoids[autoid_count];
		id->player = &cl.scores[i];

#if 0
		Con_Printf("Player %s\n", id->player->name); // Print name of seen player
		Con_Printf("Client num %i\n", i);
		Con_Printf("modelname is %s\n", state->model->name);
		Con_Printf("modelindex is %i\n", state->modelindex);
		//Con_Printf("modelname char one is %i\n", state->model->name[0]);
		Con_Printf("playermodel index is %i\n", cl_modelindex[mi_player]);
#endif

		origin = state->origin;
		if (qglProject(origin[0], origin[1], origin[2] + 28, model, project, view, &id->x, &id->y, &winz))
			autoid_count++;
	}
}
Esempio n. 6
0
/*
=============
ai_run

The monster has an enemy it is trying to kill
=============
*/
void ai_run( float dist )
{
	vec3_t tmpv;

	if ( k_bloodfest )
	{
		if ( (int)self->s.v.flags & FL_SWIM )
		{
			dist *= 5; // let fish swim faster in bloodfest mode.
		}
		else if ( self->bloodfest_boss )
		{
			dist *= 2; // let boss move faster
		}
	}

	movedist = dist;

	// see if the enemy is dead
	if ( ISDEAD( PROG_TO_EDICT( self->s.v.enemy ) ) || ( (int)PROG_TO_EDICT( self->s.v.enemy )->s.v.flags & FL_NOTARGET ) )
	{
		self->s.v.enemy = EDICT_TO_PROG( world );

		// FIXME: look all around for other targets
		if ( self->oldenemy && ISLIVE( self->oldenemy ) && !( (int)self->oldenemy->s.v.flags & FL_NOTARGET ) )
		{
			self->s.v.enemy = EDICT_TO_PROG( self->oldenemy );
			HuntTarget ();
		}
		else
		{
			if ( !self->movetarget || self->movetarget == world )
			{
				if ( self->th_stand )
					self->th_stand();
			}
			else
			{
				if ( self->th_walk )
					self->th_walk();
			}

			return;
		}
	}

	self->show_hostile = g_globalvars.time + 1;		// wake up other monsters

// check knowledge of enemy
	enemy_vis = visible( PROG_TO_EDICT( self->s.v.enemy ) );
	if ( enemy_vis )
		self->search_time = g_globalvars.time + 5; // does not search for enemy next 5 seconds

// look for other coop players
	if ( coop && self->search_time < g_globalvars.time )
	{
		if ( FindTarget() )
		{
			// this is fix for too frequent enemy sighting, required for bloodfest mode.
			if ( !visible( PROG_TO_EDICT( self->s.v.enemy ) ) )
			{
				self->search_time = g_globalvars.time + 5; // does not search for enemy next 5 seconds
			}
			return;
		}
	}

	enemy_infront = infront( PROG_TO_EDICT( self->s.v.enemy ) );
	enemy_range   = range( PROG_TO_EDICT( self->s.v.enemy ) );
	VectorSubtract( PROG_TO_EDICT( self->s.v.enemy )->s.v.origin, self->s.v.origin, tmpv);
	enemy_yaw     = vectoyaw( tmpv );

	if ( self->attack_state == AS_MISSILE )
	{
		//dprint ("ai_run_missile\n");
		ai_run_missile();
		return;
	}

	if ( self->attack_state == AS_MELEE )
	{
		//dprint ("ai_run_melee\n");
		ai_run_melee();
		return;
	}

	if ( CheckAnyAttack() )
		return;					// beginning an attack

	if ( self->attack_state == AS_SLIDING )
	{
		ai_run_slide();
		return;
	}

	// head straight in
	movetogoal( dist );		// done in C code...
}