Esempio n. 1
0
void
widow2_reattack_beam(edict_t *self)
{
	if (!self)
	{
		return;
	}

	self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;

	if (infront(self, self->enemy))
	{
		if (random() <= 0.5)
		{
			if ((random() < 0.7) || (SELF_SLOTS_LEFT < 2))
			{
				self->monsterinfo.currentmove = &widow2_move_attack_beam;
			}
			else
			{
				self->monsterinfo.currentmove = &widow2_move_spawn;
			}
		}
		else
		{
			self->monsterinfo.currentmove = &widow2_move_attack_post_beam;
		}
	}
	else
	{
		self->monsterinfo.currentmove = &widow2_move_attack_post_beam;
	}
}
Esempio n. 2
0
/*
=================
findclosestreticle

Returns the entity that matches the classname and is closest to the reticle

findclosestreticle (ent, radius, classname)
=================
*/
edict_t *findclosestreticle (edict_t *ent, float rad, unsigned int classid)
{
	edict_t *found = NULL, *from;
	float fdot = 0.8, dot;
	vec3_t vec, forward;

	for (from = g_edicts ; from < &g_edicts[globals.num_edicts]; from++)
	{
		if (!from->inuse)
			continue;
		if (from->solid == SOLID_NOT)
			continue;
		if (from->classid != classid)
			continue;
		if (!visible(ent, from) || !infront(ent, from))
			continue;

		// is this edict "better" than the last one?
		AngleVectors (ent->s.angles, forward, NULL, NULL);
		VectorSubtract (from->s.origin, ent->s.origin, vec);
		VectorNormalize (vec);
		dot = DotProduct (vec, forward);
		if (dot > fdot) {
			fdot = dot;
			found = from;
		}
	}

	return found;
}
Esempio n. 3
0
 /*
  * This is a support routine used when a client is firing
  * a non-instant attack weapon.  It checks to see if a
  * monster's dodge function should be called.
  */
 void
 check_dodge ( edict_t *self, vec3_t start, vec3_t dir, q_int32_t speed )
 {
   vec3_t end;
   vec3_t v;
   trace_t tr;
   float eta;

   if ( !self ) {
     return;
   }

   /* easy mode only ducks one quarter the time */
   if ( skill->value == 0 ) {
     if ( random() > 0.25 ) {
       return;
     }
   }

   VectorMA ( start, 8192, dir, end );
   tr = gi.trace ( start, NULL, NULL, end, self, MASK_SHOT );

   if ( ( tr.ent ) && ( tr.ent->svflags & SVF_MONSTER ) && ( tr.ent->health > 0 ) &&
        ( tr.ent->monsterinfo.dodge ) && infront ( tr.ent, self ) ) {
     VectorSubtract ( tr.endpos, start, v );
     eta = ( VectorLength ( v ) - tr.ent->maxs[0] ) / speed;
     tr.ent->monsterinfo.dodge ( tr.ent, self, eta );
   }
 }
Esempio n. 4
0
void
carrier_reattack_mg(edict_t *self)
{
	if (!self)
	{
		return;
	}

	CarrierCoopCheck(self);

	if (infront(self, self->enemy))
	{
		if (random() <= 0.5)
		{
			if ((random() < 0.7) || (self->monsterinfo.monster_slots <= 2))
			{
				self->monsterinfo.currentmove = &carrier_move_attack_mg;
			}
			else
			{
				self->monsterinfo.currentmove = &carrier_move_spawn;
			}
		}
		else
		{
			self->monsterinfo.currentmove = &carrier_move_attack_post_mg;
		}
	}
	else
	{
		self->monsterinfo.currentmove = &carrier_move_attack_post_mg;
	}
}
Esempio n. 5
0
///////////////////////////////////////////////////////////////////////
// Pick best goal based on importance and range. This function
// overrides the long range goal selection for items that
// are very close to the bot and are reachable.
///////////////////////////////////////////////////////////////////////
void ACEAI_PickShortRangeGoal(edict_t *self)
{
	edict_t *target;
	float weight,best_weight=0.0;
	edict_t *best;
	int index;
	
	// look for a target (should make more efficent later)
	target = findradius(NULL, self->s.origin, 200);
	
	while (target)
	{
		if (target->classname == NULL)
			return;
		
		// Missle avoidance code
		// Set our movetarget to be the rocket or grenade fired at us. 
		if (strcmp(target->classname,"rocket")==0 || strcmp(target->classname,"grenade")==0
			|| strcmp(target->classname,"homing rocket")==0)
		{
			if(debug_mode) 
				debug_printf("ROCKET ALERT!\n");

			self->movetarget = target;
			return;
		}
	
		if (ACEIT_IsReachable(self,target->s.origin))
		{
			if (infront(self, target))
			{
				index = ACEIT_ClassnameToIndex(target->classname);
				weight = ACEIT_ItemNeed(self, index);
				
				if(weight > best_weight)
				{
					best_weight = weight;
					best = target;
				}
			}
		}

		// next target
		target = findradius(target, self->s.origin, 200);
	}

	if (best_weight)
	{
		self->movetarget = best;
		
		if(debug_mode && self->goalentity != self->movetarget)
			debug_printf("%s selected a %s for SR goal.\n",self->client->pers.netname, self->movetarget->classname);
		
		self->goalentity = best;

	}

}
Esempio n. 6
0
int CheckTarget( gedict_t * Target )
{
    int     r;

    if ( tg_data.sg_allow_find == TG_SG_FIND_IGNORE_ALL )
        return 0;
    if ( !Target )
        return 0;
    if ( Target == self )
        return 0;
    if ( Target->has_disconnected == 1 )
        return 0;
    if ( !Target->s.v.takedamage )
        return 0;
    if ( Target->is_feigning )
        return 0;
    if ( ( int ) Target->s.v.flags & FL_NOTARGET )
        return 0;
    if ( ( int ) Target->s.v.items & IT_INVISIBILITY )
        return 0;
    if ( !visible( Target ) )
        return 0;
    r = range( Target );
    if ( r == 3 )
        return 0;
    else
    {
        if ( r == 2 && !infront( Target ) )
            return 0;
    }

    if ( tg_data.sg_allow_find == TG_SG_FIND_IGNORE_OFF )
        return 1;

    if ( teamplay )
    {
        if (  self->team_no && TeamFortress_isTeamsAllied (Target->team_no , self->team_no) )
        {
            if ( tg_data.sg_allow_find == TG_SG_FIND_IGNORE_TEAM )
                return 0;
        }
        if ( self->team_no && TeamFortress_isTeamsAllied(Target->undercover_team , self->team_no))
        {
            if ( tg_data.sg_allow_find == TG_SG_FIND_IGNORE_TEAM )
                return 0;
        }
    }
    if ( Target == self->real_owner )
    {
        if ( tg_data.sg_allow_find == TG_SG_FIND_IGNORE_OWNER )
            return 0;
    }


    return 1;
}
Esempio n. 7
0
void boss2_reattack_mg (edict_t *self)
{
	if ( infront(self, self->enemy) )
		if (random() <= 0.7)
			self->monsterinfo.currentmove = &boss2_move_attack_mg;
		else
			self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
	else
		self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
}
Esempio n. 8
0
void soldier_attack5_refire (edict_t *self)
{
	if ((!self->enemy) || (self->enemy->health <= 0))
		return;

	if (!visible(self, self->enemy) || !infront(self, self->enemy))
		return;

	if (random() < (0.3 + self->monsterinfo.skill * 0.05)) || (range(self, self->enemy) == RANGE_MELEE) )
		self->monsterinfo.nextframe = FRAME_attak505;
	else
Esempio n. 9
0
void mybrain_jumpattack_landing (edict_t *self)
{
	// expand the bbox again, we're standing up
	self->maxs[2] = 32;
	self->takedamage = DAMAGE_AIM;
	gi.linkentity (self);

	// attack right away if enemy is valid, visible, infront, and is moving
	if (G_EntIsAlive(self->enemy) && visible(self, self->enemy) 
		&& infront(self, self->enemy) && self->enemy->movetype)
		mybrain_attack3(self);
}
Esempio n. 10
0
void soldier_attack3_refire (edict_t *self)
{
	if (!self->enemy)
		return;
	if (!visible(self, self->enemy) || !infront(self, self->enemy))
		return;

	if ((level.time + 0.4) < self->monsterinfo.pausetime)
		self->monsterinfo.nextframe = FRAME_attak303;
	else
		self->monsterinfo.attack_finished = level.time + 1.0 + random();
}
Esempio n. 11
0
void ai_facing (edict_t *self, float dist)
{
	vec3_t v;

	if (infront (self, self->goalentity))
		self->monsterinfo.currentmove = &fixbot_move_forward;
	else
	{
		VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
		self->ideal_yaw = vectoyaw(v);	
		M_ChangeYaw (self);
	}

};
Esempio n. 12
0
qboolean G_EmplacedGunIsMountable( gentity_t* ent, gentity_t* other ) {
	if ( Q_stricmp( ent->classname, "misc_mg42" ) ) {
		return qfalse;
	}

	if ( !other->client ) {
		return qfalse;
	}

	if ( BG_IsScopedWeapon( other->client->ps.weapon ) ) {
		return qfalse;
	}

	if ( other->client->ps.pm_flags & PMF_DUCKED ) {
		return qfalse;
	}

	if ( other->client->ps.persistant[PERS_HWEAPON_USE] ) {
		return qfalse;
	}

	if ( ent->r.currentOrigin[2] - other->r.currentOrigin[2] >= 40 ) {
		return qfalse;
	}

	if ( ent->r.currentOrigin[2] - other->r.currentOrigin[2] < 0 ) {
		return qfalse;
	}

	if ( ent->s.frame != 0 ) {
		return qfalse;
	}

	if ( ent->active ) {
		return qfalse;
	}

	if ( other->client->ps.grenadeTimeLeft ) {
		return qfalse;
	}

	if ( infront( ent, other ) ) {
		return qfalse;
	}

	return qtrue;
}
Esempio n. 13
0
void soldier_attack2_refire2 (edict_t *self)
{
	if (self->s.skinnum < 2)
		return;

	if (!self->enemy)
		return;
	if (self->enemy->health <= 0)
		return;

	if (!visible(self, self->enemy) || !infront(self, self->enemy))
		return;

	if ( ((self->monsterinfo.skill > 1) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
		self->monsterinfo.attack_finished = level.time + 1.0 + random();
	self->monsterinfo.nextframe = FRAME_attak204;
}
Esempio n. 14
0
void CurseRadiusAttack (edict_t *caster, int type, int range, int radius, float duration, qboolean isCurse)
{
	edict_t *e=NULL, *f=NULL;

	// write a nice effect so everyone knows we've cast a spell
	gi.WriteByte (svc_temp_entity);
	gi.WriteByte (TE_TELEPORT_EFFECT);
	gi.WritePosition (caster->s.origin);
	gi.multicast (caster->s.origin, MULTICAST_PVS);

	caster->client->idle_frames = 0;
	caster->client->ability_delay = level.time;// for monster hearing (check if ability was recently used/cast)

	// find a target closest to the caster's reticle
	while ((e = findclosestreticle(e, caster, range)) != NULL)
	{
		if (!CanCurseTarget(caster, e, type, isCurse, true))
			continue;
		if (entdist(caster, e) > range)
			continue;
		if (!infront(caster, e))
			continue;
		if (!curse_add(e, caster, type, 0, duration))
			continue;
		CurseMessage(caster, e, type, duration, isCurse);

		// target anything in-range of this entity
		while ((f = findradius(f, e->s.origin, radius)) != NULL)
		{
			if (!CanCurseTarget(caster, f, type, isCurse, false))
				continue;
			if (f == e)
				continue;
			if (!visible(e, f))
				continue;
			if (!curse_add(f, caster, type, 0, duration))
				continue;
			CurseMessage(caster, f, type, duration, isCurse);
		}

		break;
	}
}
Esempio n. 15
0
qboolean boss_findtarget (edict_t *boss)
{
	edict_t *target = NULL;

	while ((target = findclosestradius(target, boss->s.origin, BOSS_TARGET_RADIUS)) != NULL)
	{
		if (!G_ValidTarget(boss, target, true))
			continue;
		if (!infront(boss, target))
			continue;
		boss->enemy = target;
		//if (target->client)
		//	gi.dprintf("found %s\n", target->client->pers.netname);
		//else
		//	gi.dprintf("found target %s\n", target->classname);
	//	gi.sound (boss, CHAN_WEAPON, gi.soundindex ("tank/sight1.wav"), 1, ATTN_NORM, 0);
		return true;
	}
	return false;
}
Esempio n. 16
0
void
carrier_reattack_gren(edict_t *self)
{
	if (!self)
	{
		return;
	}

	CarrierCoopCheck(self);

	if (infront(self, self->enemy))
	{
		if (self->timestamp + 1.3 > level.time)  /* four grenades */
		{
			self->monsterinfo.currentmove = &carrier_move_attack_gren;
			return;
		}
	}

	self->monsterinfo.currentmove = &carrier_move_attack_post_gren;
}
Esempio n. 17
0
bool Player::trypull( Direction dir, Map &map, vector<Movable*> &movables )
{
    Movable *box;
    if( engine.input.keys[ Key::Space ].down && direction() != dir ) {
        if(( box = infront( map, movables )) != NULL &&
                (( CHAIR_TYPE <= box->type() && box->type() <= DESK_TYPE &&
                level() > ( box->type() - CHAIR_TYPE )) ||
                ( ZOMBIE_MALE_TYPE <= box->type() && box->type() <=
                  ZOMBIE_FEMALE_TYPE))){
            rdir = direction();
            restore = true;
            direction( dir );
            trymove( map, movables );
            if( moving()) {
                box->direction( direction());
                box->trymove( map, movables );
                // test if there is a wall or block between future position
                if( !box->moving()) {
                    x( rx());
                    y( ry());
                    moving( 0 );
                } else {
                    if( map( x(), y()).block & block_dir[ rdir ] ||
                            map( box->x(), box->y()).block & block_rdir[ rdir ] ) {
                        x( rx());
                        y( ry());
                        moving( 0 );
                        box->moving( 0 );
                        box->x( box->rx());
                        box->y( box->ry());
                    }
                }
            }
            return true;
        }
    }
    return false;
}
Esempio n. 18
0
void
boss2_reattack_mg(edict_t *self)
{
	if (!self)
	{
		return;
	}

	if (infront(self, self->enemy))
	{
		if (random() <= 0.7)
		{
			self->monsterinfo.currentmove = &boss2_move_attack_mg;
		}
		else
		{
			self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
		}
	}
	else
	{
		self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
	}
}
Esempio n. 19
0
qboolean
Carrier_CheckAttack(edict_t *self)
{
	vec3_t spot1, spot2;
	vec3_t temp;
	float chance = 0;
	trace_t tr;
	qboolean enemy_infront, enemy_inback, enemy_below;
	int enemy_range;
	float enemy_yaw;

	if (!self)
	{
		return false;
	}

	if (self->enemy->health > 0)
	{
		/* see if any entities are in the way of the shot */
		VectorCopy(self->s.origin, spot1);
		spot1[2] += self->viewheight;
		VectorCopy(self->enemy->s.origin, spot2);
		spot2[2] += self->enemy->viewheight;

		tr = gi.trace(spot1, NULL, NULL, spot2, self,
				CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_SLIME |
				CONTENTS_LAVA);

		/* do we have a clear shot? */
		if (tr.ent != self->enemy)
		{
			/* go ahead and spawn stuff if we're mad a a client */
			if (self->enemy->client && (self->monsterinfo.monster_slots > 2))
			{
				self->monsterinfo.attack_state = AS_BLIND;
				return true;
			}

			/* we want them to go ahead and shoot at info_notnulls if they can. */
			if ((self->enemy->solid != SOLID_NOT) || (tr.fraction < 1.0))
			{
				return false;
			}
		}
	}

	enemy_infront = infront(self, self->enemy);
	enemy_inback = inback(self, self->enemy);
	enemy_below = below(self, self->enemy);

	enemy_range = range(self, self->enemy);
	VectorSubtract(self->enemy->s.origin, self->s.origin, temp);
	enemy_yaw = vectoyaw2(temp);

	self->ideal_yaw = enemy_yaw;

	/* shoot out the back if appropriate */
	if ((enemy_inback) || (!enemy_infront && enemy_below))
	{
		/* this is using wait because the attack is supposed to be independent */
		if (level.time >= self->wait)
		{
			self->wait = level.time + CARRIER_ROCKET_TIME;
			self->monsterinfo.attack(self);

			if (random() < 0.6)
			{
				self->monsterinfo.attack_state = AS_SLIDING;
			}
			else
			{
				self->monsterinfo.attack_state = AS_STRAIGHT;
			}

			return true;
		}
	}

	/* melee attack */
	if (enemy_range == RANGE_MELEE)
	{
		self->monsterinfo.attack_state = AS_MISSILE;
		return true;
	}

	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
	{
		chance = 0.4;
	}
	else if (enemy_range == RANGE_MELEE)
	{
		chance = 0.8;
	}
	else if (enemy_range == RANGE_NEAR)
	{
		chance = 0.8;
	}
	else if (enemy_range == RANGE_MID)
	{
		chance = 0.8;
	}
	else if (enemy_range == RANGE_FAR)
	{
		chance = 0.5;
	}

	/* go ahead and shoot every time if it's a info_notnull */
	if ((random() < chance) || (self->enemy->solid == SOLID_NOT))
	{
		self->monsterinfo.attack_state = AS_MISSILE;
		return true;
	}

	if (self->flags & FL_FLY)
	{
		if (random() < 0.6)
		{
			self->monsterinfo.attack_state = AS_SLIDING;
		}
		else
		{
			self->monsterinfo.attack_state = AS_STRAIGHT;
		}
	}

	return false;
}
Esempio n. 20
0
void
carrier_attack(edict_t *self)
{
	vec3_t vec;
	float range, luck;
	qboolean enemy_inback, enemy_infront, enemy_below;

	if (!self)
	{
		return;
	}

	self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;

	if ((!self->enemy) || (!self->enemy->inuse))
	{
		return;
	}

	enemy_inback = inback(self, self->enemy);
	enemy_infront = infront(self, self->enemy);
	enemy_below = below(self, self->enemy);

	if (self->bad_area)
	{
		if ((enemy_inback) || (enemy_below))
		{
			self->monsterinfo.currentmove = &carrier_move_attack_rocket;
		}
		else if ((random() < 0.1) ||
				 (level.time < self->monsterinfo.attack_finished))
		{
			self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
		}
		else
		{
			gi.sound(self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
			self->monsterinfo.currentmove = &carrier_move_attack_rail;
		}

		return;
	}

	if (self->monsterinfo.attack_state == AS_BLIND)
	{
		self->monsterinfo.currentmove = &carrier_move_spawn;
		return;
	}

	if (!enemy_inback && !enemy_infront && !enemy_below) /* to side and not under */
	{
		if ((random() < 0.1) ||
			(level.time < self->monsterinfo.attack_finished))
		{
			self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
		}
		else
		{
			gi.sound(self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
			self->monsterinfo.currentmove = &carrier_move_attack_rail;
		}

		return;
	}

	if (enemy_infront)
	{
		VectorSubtract(self->enemy->s.origin, self->s.origin, vec);
		range = VectorLength(vec);

		if (range <= 125)
		{
			if ((random() < 0.8) ||
				(level.time < self->monsterinfo.attack_finished))
			{
				self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
			}
			else
			{
				gi.sound(self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
				self->monsterinfo.currentmove = &carrier_move_attack_rail;
			}
		}
		else if (range < 600)
		{
			luck = random();

			if (self->monsterinfo.monster_slots > 2)
			{
				if (luck <= 0.20)
				{
					self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
				}
				else if (luck <= 0.40)
				{
					self->monsterinfo.currentmove =
						&carrier_move_attack_pre_gren;
				}
				else if ((luck <= 0.7) &&
						 !(level.time < self->monsterinfo.attack_finished))
				{
					gi.sound(self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
					self->monsterinfo.currentmove = &carrier_move_attack_rail;
				}
				else
				{
					self->monsterinfo.currentmove = &carrier_move_spawn;
				}
			}
			else
			{
				if (luck <= 0.30)
				{
					self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
				}
				else if (luck <= 0.65)
				{
					self->monsterinfo.currentmove =
						&carrier_move_attack_pre_gren;
				}
				else if (level.time >= self->monsterinfo.attack_finished)
				{
					gi.sound(self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
					self->monsterinfo.currentmove = &carrier_move_attack_rail;
				}
				else
				{
					self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
				}
			}
		}
		else /* won't use grenades at this range */
		{
			luck = random();

			if (self->monsterinfo.monster_slots > 2)
			{
				if (luck < 0.3)
				{
					self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
				}
				else if ((luck < 0.65) && !(level.time < self->monsterinfo.attack_finished))
				{
					gi.sound(self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
					VectorCopy(self->enemy->s.origin, self->pos1);  /* save for aiming the shot */
					self->pos1[2] += self->enemy->viewheight;
					self->monsterinfo.currentmove = &carrier_move_attack_rail;
				}
				else
				{
					self->monsterinfo.currentmove = &carrier_move_spawn;
				}
			}
			else
			{
				if ((luck < 0.45) ||
					(level.time < self->monsterinfo.attack_finished))
				{
					self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
				}
				else
				{
					gi.sound(self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
					self->monsterinfo.currentmove = &carrier_move_attack_rail;
				}
			}
		}
	}
	else if ((enemy_below) || (enemy_inback))
	{
		self->monsterinfo.currentmove = &carrier_move_attack_rocket;
	}
}
Esempio n. 21
0
//=======================================================================
void WhatIsIt (edict_t *ent)
{
	float       range;
	int			i, num;
	edict_t		*touch[MAX_EDICTS];
	edict_t	    *who, *best;
	trace_t     tr;
	vec3_t      dir, end, entp, forward, mins, maxs, start, viewp;

	/* Check for looking directly at a player or other non-trigger entity */
	VectorCopy(ent->s.origin, start);
	start[2] += ent->viewheight;
	AngleVectors(ent->client->v_angle, forward, NULL, NULL);
	VectorMA(start, 8192, forward, end);
	tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA);
	if (tr.ent > world)
	{
		if(tr.ent->common_name)
			ent->client->whatsit = tr.ent->common_name;
//		else
//			ent->client->whatsit = tr.ent->classname;
		return;
	}

	/* Check for looking directly at a pickup item */
	VectorCopy(ent->s.origin,viewp);
	viewp[2] += ent->viewheight;
	AngleVectors(ent->client->v_angle, forward, NULL, NULL);
	VectorSet(mins,-4096,-4096,-4096);
	VectorSet(maxs, 4096, 4096, 4096);
	num = gi.BoxEdicts (mins, maxs, touch, MAX_EDICTS, AREA_TRIGGERS);
	best = NULL;
	for (i=0 ; i<num ; i++)
	{
		who = touch[i];
		if (!who->inuse)
			continue;
		if (!who->item)
			continue;
		if (!visible(ent,who))
			continue;
		if (!infront(ent,who))
			continue;
		VectorSubtract(who->s.origin,viewp,dir);
		range = VectorLength(dir);
		VectorMA(viewp, range, forward, entp);
		if(entp[0] < who->s.origin[0] - 17) continue;
		if(entp[1] < who->s.origin[1] - 17) continue;
		if(entp[2] < who->s.origin[2] - 17) continue;
		if(entp[0] > who->s.origin[0] + 17) continue;
		if(entp[1] > who->s.origin[1] + 17) continue;
		if(entp[2] > who->s.origin[2] + 17) continue;
		best = who;
		break;
	}
	if(best)
	{
		ent->client->whatsit = best->item->pickup_name;
		return;
	}
}
Esempio n. 22
0
qboolean Makron_CheckAttack (edict_t *self)
{
	vec3_t	spot1, spot2;
	vec3_t	temp;
	float	chance;
	trace_t	tr;
	qboolean	enemy_infront;
	int			enemy_range;
	float		enemy_yaw;

	if (self->enemy->health > 0)
	{
	// see if any entities are in the way of the shot
		VectorCopy (self->s.origin, spot1);
		spot1[2] += self->viewheight;
		VectorCopy (self->enemy->s.origin, spot2);
		spot2[2] += self->enemy->viewheight;

	//Knightmare- don't shoot from behind a window
		tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_WINDOW);

		// do we have a clear shot?
		if (tr.ent != self->enemy)
			return false;
	}

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

	self->ideal_yaw = enemy_yaw;


	// melee attack
	if (enemy_range == RANGE_MELEE)
	{
		if (self->monsterinfo.melee)
			self->monsterinfo.attack_state = AS_MELEE;
		else
			self->monsterinfo.attack_state = AS_MISSILE;
		return true;
	}

// missile attack
	if (!self->monsterinfo.attack)
		return false;

	if (level.time < self->monsterinfo.attack_finished)
		return false;

	if (enemy_range == RANGE_FAR)
		return false;

	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
	{
		chance = 0.4;
	}
	else if (enemy_range == RANGE_MELEE)
	{
		chance = 0.8;
	}
	else if (enemy_range == RANGE_NEAR)
	{
		chance = 0.4;
	}
	else if (enemy_range == RANGE_MID)
	{
		chance = 0.2;
	}
	else
	{
		return false;
	}

	if (random () < chance)
	{
		self->monsterinfo.attack_state = AS_MISSILE;
		self->monsterinfo.attack_finished = level.time + 2*random();
		return true;
	}

	if (self->flags & FL_FLY)
	{
		if (random() < 0.3)
			self->monsterinfo.attack_state = AS_SLIDING;
		else
			self->monsterinfo.attack_state = AS_STRAIGHT;
	}

	return false;
}
Esempio n. 23
0
qboolean Widow2_CheckAttack (edict_t *self)
{
	vec3_t		spot1, spot2;
	vec3_t		temp;
	float		chance;
	trace_t		tr;
	qboolean	enemy_infront;
	int			enemy_range;
	float		enemy_yaw;
	float		real_enemy_range;
	vec3_t		f, r, u;

	if (!self->enemy)
		return false;

	WidowPowerups(self);

	if ((random() < 0.8) && (SELF_SLOTS_LEFT >= 2) && (realrange(self, self->enemy) > 150))
	{
		self->monsterinfo.aiflags |= AI_BLOCKED;
		self->monsterinfo.attack_state = AS_MISSILE;
		return true;
	}

	if (self->enemy->health > 0)
	{
	// see if any entities are in the way of the shot
		VectorCopy (self->s.origin, spot1);
		spot1[2] += self->viewheight;
		VectorCopy (self->enemy->s.origin, spot2);
		spot2[2] += self->enemy->viewheight;

		tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);

		// do we have a clear shot?
		if (tr.ent != self->enemy)
		{	
			// go ahead and spawn stuff if we're mad a a client
			if (self->enemy->client && SELF_SLOTS_LEFT >= 2)
			{
				self->monsterinfo.attack_state = AS_BLIND;
				return true;
			}
				
			// PGM - we want them to go ahead and shoot at info_notnulls if they can.
			if(self->enemy->solid != SOLID_NOT || tr.fraction < 1.0)		//PGM
				return false;
		}
	}
	
	enemy_infront = infront(self, self->enemy);

	enemy_range = range(self, self->enemy);
	VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
	enemy_yaw = vectoyaw2(temp);

	self->ideal_yaw = enemy_yaw;

	// melee attack
	if (self->timestamp < level.time)
	{
		real_enemy_range = realrange (self, self->enemy);
		if (real_enemy_range < 300)
		{
			AngleVectors (self->s.angles, f, r, u);
			G_ProjectSource2 (self->s.origin, offsets[0], f, r, u, spot1);
			VectorCopy (self->enemy->s.origin, spot2);
			if (widow2_tongue_attack_ok(spot1, spot2, 256))
			{
				// melee attack ok

				// be nice in easy mode
				if (skill->value == 0 && (rand()&3) )
					return false;

				if (self->monsterinfo.melee)
					self->monsterinfo.attack_state = AS_MELEE;
				else
					self->monsterinfo.attack_state = AS_MISSILE;
				return true;
			}
		}
	}
	
	if (level.time < self->monsterinfo.attack_finished)
		return false;
		
	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
	{
		chance = 0.4;
	}
	else if (enemy_range == RANGE_NEAR)
	{
		chance = 0.8;
	}
	else if (enemy_range == RANGE_MID)
	{
		chance = 0.8;
	}
	else if (enemy_range == RANGE_FAR)
	{
		chance = 0.5;
	}

	// PGM - go ahead and shoot every time if it's a info_notnull
	if ((random () < chance) || (self->enemy->solid == SOLID_NOT))
	{
		self->monsterinfo.attack_state = AS_MISSILE;
//		self->monsterinfo.attack_finished = level.time + 1.0 + 2*random();
		return true;
	}

	return false;
}
Esempio n. 24
0
// draws the line
void Tline::draw( Tsector *owner )
{
  coord3d x1r,y1r,x2r,y2r;
  coord3d t1,t2;
  coord2d x1,x2,x1c,x2c;
  Tmonotone mp,mph;
  Twall **w;

  coord3d ox1=verts[v1].x;
  coord3d oy1=verts[v1].y;
  coord3d ox2=verts[v2].x;
  coord3d oy2=verts[v2].y;
  // if the line is behind the portal, do nothing
  if (!infront(ox1,oy1) && !infront(ox2,oy2)) return;
  coord3d _portx1=portx1;
  coord3d _porty1=porty1;
  coord3d _portdx=portdx;
  coord3d _portdy=portdy;
  rotatez(ox1,oy1,&x1r,&y1r); // find the first vertex in camera space
  rotatez(ox2,oy2,&x2r,&y2r); // find the second vertex in camera space
  coord3d orx1=x1r;
  coord3d orx2=x2r;

  // calculates the vectors for the texture mapping
  Tvector a={x1r,y1r,view.z};
  Tvector p={512*(x2r-x1r)/len,512*(y2r-y1r)/len,0};
  Tvector q={0,0,512};
  rotateyxv(&a);
  rotateyxv(&p);
  rotateyxv(&q);
  int clipfl=0;
  // checks if the line is visible on the screen
  if (y1r<=MINZ && y2r<=MINZ) {
    if (y1r<0 && y2r<0) return;
    if (x1r<0 && x2r<0) return;
    if (x1r>0 && x2r>0) return;
    if (y1r*fabs(x2r)+y2r*fabs(x1r)<0) return;
    x1c=x2c=0;
    // if the line is too close and is visible, it fills the whole screen
    clipfl=clLEFT|clRIGHT;
  }
  else {
    // if the line crosses the near plane, clip it
    if (y1r<MINZ || y2r<MINZ) {
      if (y1r<MINZ) {
        clipfl=clLEFT;
        t1=MINZ-y1r;
        t2=y2r-MINZ;
        x1r=splitab(x1r,x2r,t1,t2);
        y1r=MINZ;
      }
      if (y2r<MINZ) {
        clipfl=clRIGHT;
        t1=y1r-MINZ;
        t2=MINZ-y2r;
        x2r=splitab(x1r,x2r,t1,t2);
        y2r=MINZ;
      }
    }
    x1=projectx(x1r,y1r);
    x2=projectx(x2r,y2r);
    x1c=x1;
    x2c=x2;

    if (x1c<cur_clip->xmin) {
      x1c=cur_clip->xmin;
      clipfl&=~clDRAWLEFT;
    }
    if (x2c>cur_clip->xmax) {
      x2c=cur_clip->xmax;
      clipfl&=~clDRAWRIGHT;
    }
  }

  // if the line is perpendicular to the screen, or backfacing
  if (x1c>=x2c) {
    if (clipfl&clDRAW) {
      if (clipfl&clDRAWLEFT) x1c=cur_clip->xmin;
      if (clipfl&clDRAWRIGHT) x2c=cur_clip->xmax;
      if (x1c>=x2c) return;
      coord3d z0=(owner->getzf(ox1,oy1)*orx2-owner->getzf(ox2,oy2)*orx1)/(orx2-orx1);
      w=walls;
      for (int wi=0;wi<wallsnum;wi++,NEXTWALL(w)) {
        Twall *wp=*w;
        coord3d z1=(wp->z1c*orx2-wp->z2c*orx1)/(orx2-orx1);
        if (z0<=view.z && z1>=view.z) {
          // if there is a visible wall, fill the whole clip with it
          if (is_visible(wp)) goto dr;
          else break;
        }
        z0=z1;
      }
      return;
    dr:
      // fills the whole clip
      portx1=ox1;
      porty1=oy1;
      portdx=ox2-ox1;
      portdy=oy2-oy1;
      setdrawdata(&a,&p,&q);
      cur_clip->cut(x1c,x2c);
      cur_clip->clip(x1c,x2c,gymax,gymin,gymax,gymin,&mp);
      (*w)->draw(&mp);
      deltraps(mp.traps);
      cur_clip->last=mp.traps=new Ttrap(x2c,gymin,gymax,gymin,gymax,0,0,NULL);
      cur_clip->restore(mp.traps);
      portx1=_portx1;
      porty1=_porty1;
      portdx=_portdx;
      portdy=_portdy;
      return;
    }
    return;
  }


  portx1=ox1;
  porty1=oy1;
  portdx=ox2-ox1;
  portdy=oy2-oy1;
  // clips the line in world space (x and y in world space are needed to calculate the correct z)
  if (clipfl&clCLIPLEFT) {
    ox1=splitab(ox1,ox2,t1,t2);
    oy1=splitab(oy1,oy2,t1,t2);
  }
  else if (clipfl&clCLIPRIGHT) {
    ox2=splitab(ox1,ox2,t1,t2);
    oy2=splitab(oy1,oy2,t1,t2);
  }
  coord3d zf1=owner->getzf(ox1,oy1);
  coord3d zf2=owner->getzf(ox2,oy2);
  coord3d zc1=owner->getzc(ox1,oy1);
  coord3d zc2=owner->getzc(ox2,oy2);

  // finds the screen y coordinates (the screen x-es are x1c and x2c)
  coord2d pf1=projectz(zf1,y1r);// floor
  coord2d pf2=projectz(zf2,y2r);
  coord2d pc1=projectz(zc1,y1r);// ceiling
  coord2d pc2=projectz(zc2,y2r);

  // interpolates the z-s if the x-es are changed by cur_clip
  if (x1<x1c) {
    pf1=splitab(pf1,pf2,x1c-x1,x2-x1c);
    pc1=splitab(pc1,pc2,x1c-x1,x2-x1c);
  }
  if (x2>x2c) {
    pf2=splitab(pf1,pf2,x2c-x1c,x2-x2c);
    pc2=splitab(pc1,pc2,x2c-x1c,x2-x2c);
  }
  // cuts the portion of cur_clip that is over the walls
  cur_clip->cut(x1c,x2c);
  // clips the floor polygon with cur_clip
  cur_clip->clip(x1c,x2c,pf1,cur_clip->ymin,pf2,cur_clip->ymin,&mp);
  owner->draw_floor(&mp);
  deltraps(mp.traps);
  // clips the ceiling polygon with cur_clip
  cur_clip->clip(x1c,x2c,cur_clip->ymax,pc1,cur_clip->ymax,pc2,&mp);
  owner->draw_ceiling(&mp);
  deltraps(mp.traps);

  mph.traps=NULL;
  int wi;
  w=walls;
  // draws all the walls
  for (wi=0;wi<wallsnum;wi++,NEXTWALL(w)) {
    Twall *wp=*w;
    coord3d zq1=wp->z1c;
    coord3d zq2=wp->z2c;
    // interpolates z-s if necessary
    if (clipfl&clCLIPLEFT) zq1=splitab(zq1,zq2,t1,t2);
    if (clipfl&clCLIPRIGHT) zq2=splitab(zq1,zq2,t1,t2);
    // project the z-s
    coord2d pq1=projectz(zq1,y1r);
    coord2d pq2=projectz(zq2,y2r);
    // interpolates the projection
    if (x1<x1c) pq1=splitab(pq1,pq2,x1c-x1,x2-x1c);
    if (x2>x2c) pq2=splitab(pq1,pq2,x2c-x1c,x2-x2c);
    if (is_visible(wp)) {
      // if the wall is visible (wall or portal), draw it
      cur_clip->clip(x1c,x2c,pq1,pf1,pq2,pf2,&mp);
      if ((clipfl&clDRAW)) {
        if ((clipfl&clDRAWLEFT) && pq1>0 && pf1<0) cur_clip->addbeg(&mp);
        else if ((clipfl&clDRAWRIGHT) && pq2>0 && pf2<0) cur_clip->addend(&mp);
      }
      setdrawdata(&a,&p,&q);
      (*w)->draw(&mp);
      deltraps(mp.traps);
    }
    else {
      // if the wall is a hole, clip it only
      cur_clip->clip(x1c,x2c,pq1,pf1,pq2,pf2,&mph);
    }
    pf1=pq1;
    pf2=pq2;
  }

  // restores cur_clip
  if (mph.traps) {
    Ttrap *t;
    for (t=mph.traps;t->next;t=t->next);
    cur_clip->last=t;
  }
  else {
    cur_clip->last=mph.traps=new Ttrap(x2c,gymin,gymax,gymin,gymax,0,0,NULL);
  }
  cur_clip->restore(mph.traps);
  portx1=_portx1;
  porty1=_porty1;
  portdx=_portdx;
  portdy=_portdy;
}
Esempio n. 25
0
edict_t	*LookingAt(edict_t *ent, int filter, vec3_t endpos, float *range)
{
	edict_t		*who;
	edict_t		*trigger[MAX_EDICTS];
	edict_t		*ignore;
	trace_t		tr;
	vec_t		r;
	vec3_t      end, forward, start;
	vec3_t		dir, entp, mins, maxs;
	int			i, num;

	if(!ent->client)
	{
		if(endpos) VectorClear(endpos);
		if(range) *range = 0;
		return NULL;
	}
	VectorClear(end);
	if (ent->client->chasetoggle)
	{
		AngleVectors(ent->client->v_angle, forward, NULL, NULL);
		VectorCopy(ent->client->chasecam->s.origin,start);
		ignore = ent->client->chasecam;
	}
	else if(ent->client->spycam)
	{
		AngleVectors(ent->client->ps.viewangles, forward, NULL, NULL);
		VectorCopy(ent->s.origin,start);
		ignore = ent->client->spycam;
	}
	else
	{
		AngleVectors(ent->client->v_angle, forward, NULL, NULL);
		VectorCopy(ent->s.origin, start);
		start[2] += ent->viewheight;
		ignore = ent;
	}

	VectorMA(start, 8192, forward, end);
	
	/* First check for looking directly at a pickup item */
	VectorSet(mins,-4096,-4096,-4096);
	VectorSet(maxs, 4096, 4096, 4096);
	num = gi.BoxEdicts (mins, maxs, trigger, MAX_EDICTS, AREA_TRIGGERS);
	for (i=0 ; i<num ; i++)
	{
		who = trigger[i];
		if (!who->inuse)
			continue;
		if (!who->item)
			continue;
		if (!visible(ent,who))
			continue;
		if (!infront(ent,who))
			continue;
		VectorSubtract(who->s.origin,start,dir);
		r = VectorLength(dir);
		VectorMA(start, r, forward, entp);
		if(entp[0] < who->s.origin[0] - 17) continue;
		if(entp[1] < who->s.origin[1] - 17) continue;
		if(entp[2] < who->s.origin[2] - 17) continue;
		if(entp[0] > who->s.origin[0] + 17) continue;
		if(entp[1] > who->s.origin[1] + 17) continue;
		if(entp[2] > who->s.origin[2] + 17) continue;
		if(endpos)
			VectorCopy(who->s.origin,endpos);
		if (range)
			*range = r;
		return who;
	}

	tr = gi.trace (start, NULL, NULL, end, ignore, MASK_SHOT);
	if (tr.fraction == 1.0)
	{
		// too far away
		gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
		return NULL;
	}
	if(!tr.ent)
	{
		// no hit
		gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
		return NULL;
	}
	if(!tr.ent->classname)
	{
		// should never happen
		gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
		return NULL;
	}

	if((strstr(tr.ent->classname,"func_") != NULL) && (filter & LOOKAT_NOBRUSHMODELS))
	{
		// don't hit on brush models
		gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
		return NULL;
	}
	if((Q_strcasecmp(tr.ent->classname,"worldspawn") == 0) && (filter & LOOKAT_NOWORLD))
	{
		// world brush
		gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
		return NULL;
	}
	if(endpos) {
		endpos[0] = tr.endpos[0];
		endpos[1] = tr.endpos[1];
		endpos[2] = tr.endpos[2];
	}
	if(range) {
		VectorSubtract(tr.endpos,start,start);
		*range = VectorLength(start);
	}
	return tr.ent;
}
Esempio n. 26
0
void
heat_think(edict_t *self)
{
	edict_t *target = NULL;
	edict_t *aquire = NULL;
	vec3_t vec;
	int len;
	int oldlen = 0;

	if (!self)
	{
		return;
	}

	VectorClear(vec);

	/* aquire new target */
	while ((target = findradius(target, self->s.origin, 1024)) != NULL)
	{
		if (self->owner == target)
		{
			continue;
		}

		if (!(target->svflags & SVF_MONSTER))
		{
			continue;
		}

		if (!target->client)
		{
			continue;
		}

		if (target->health <= 0)
		{
			continue;
		}

		if (!visible(self, target))
		{
			continue;
		}

		if (!infront(self, target))
		{
			continue;
		}

		VectorSubtract(self->s.origin, target->s.origin, vec);
		len = VectorLength(vec);

		if ((aquire == NULL) || (len < oldlen))
		{
			aquire = target;
			self->target_ent = aquire;
			oldlen = len;
		}
	}

	if (aquire != NULL)
	{
		VectorSubtract(aquire->s.origin, self->s.origin, vec);
		vectoangles(vec, self->s.angles);
		VectorNormalize(vec);
		VectorCopy(vec, self->movedir);
		VectorScale(vec, 500, self->velocity);
	}

	self->nextthink = level.time + 0.1;
}
Esempio n. 27
0
File: ai.c Progetto: yquake2/zaero
/*
=============
zSchoolAllVisiable

Create list of monsters of the same schooling type that are ahead of you. 
==============
*/
int zSchoolAllVisiable(edict_t *self)
{
  int max;
  edict_t *head, *list;

  max = 0;

  zCreateRaduisList(self);
	head = self->zRaduisList;
  list = self;

	while (head)
	{
    if(strcmp(head->classname, self->classname) == 0 && (self->monsterinfo.aiflags & AI_SCHOOLING) && (head->health > 0) && 
        (head->zDistance <= self->monsterinfo.zSchoolSightRadius) && (visible(self, head)) && (infront(self, head)))
		{
    	list->zSchoolChain = head;
      list = head;
      max++;
		}
		head = head->zRaduisList;
	}

  list->zSchoolChain = NULL;

  return max;
}
Esempio n. 28
0
qboolean Boss2_CheckAttack (edict_t *self)
{
	vec3_t	spot1, spot2;
	vec3_t	temp;
	float	chance;
	trace_t	tr;
	qboolean	enemy_infront;
	int			enemy_range;
	float		enemy_yaw;

	if (self->enemy->health > 0)
	{
	// see if any entities are in the way of the shot
		VectorCopy (self->s.origin, spot1);
		spot1[2] += self->viewheight;
		VectorCopy (self->enemy->s.origin, spot2);
		spot2[2] += self->enemy->viewheight;

		tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);

		// do we have a clear shot?
		if (tr.ent != self->enemy)
		{	
			// PGM - we want them to go ahead and shoot at info_notnulls if they can.
			if(self->enemy->solid != SOLID_NOT || tr.fraction < 1.0)		//PGM
				return false;
		}
	}
	
	enemy_infront = infront(self, self->enemy);
	enemy_range = range(self, self->enemy);
	VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
	enemy_yaw = vectoyaw(temp);

	self->ideal_yaw = enemy_yaw;


	// melee attack
	if (enemy_range == RANGE_MELEE)
	{
		if (self->monsterinfo.melee)
			self->monsterinfo.attack_state = AS_MELEE;
		else
			self->monsterinfo.attack_state = AS_MISSILE;
		return true;
	}
	
// missile attack
	if (!self->monsterinfo.attack)
		return false;
		
	if (level.time < self->monsterinfo.attack_finished)
		return false;
		
	if (enemy_range == RANGE_FAR)
		return false;

	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
	{
		chance = 0.4;
	}
	else if (enemy_range == RANGE_MELEE)
	{
		chance = 0.8;
	}
	else if (enemy_range == RANGE_NEAR)
	{
		chance = 0.8;
	}
	else if (enemy_range == RANGE_MID)
	{
		chance = 0.8;
	}
	else
	{
		return false;
	}

	// PGM - go ahead and shoot every time if it's a info_notnull
	if ((random () < chance) || (self->enemy->solid == SOLID_NOT))
	{
		self->monsterinfo.attack_state = AS_MISSILE;
		self->monsterinfo.attack_finished = level.time + 2*random();
		return true;
	}

	if (self->flags & FL_FLY)
	{
		if (random() < 0.3)
			self->monsterinfo.attack_state = AS_SLIDING;
		else
			self->monsterinfo.attack_state = AS_STRAIGHT;
	}

	return false;
}
Esempio n. 29
0
void heat_think (edict_t *self)
{
	edict_t		*target = NULL;
	edict_t		*aquire = NULL;
	vec3_t		vec;
	vec3_t		oldang;
	int			len;
	int			oldlen = 0;

	VectorClear (vec);

	// aquire new target
	while (( target = findradius (target, self->s.origin, 1024)) != NULL)
	{
		
		if (self->owner == target)
			continue;
		if (!target->svflags & SVF_MONSTER)
			continue;
		if (!target->client)
			continue;
		if (target->health <= 0)
			continue;
		if (!visible (self, target))
			continue;
		
		// if we need to reduce the tracking cone
		/*
		{
			vec3_t	vec;
			float	dot;
			vec3_t	forward;
	
			AngleVectors (self->s.angles, forward, NULL, NULL);
			VectorSubtract (target->s.origin, self->s.origin, vec);
			VectorNormalize (vec);
			dot = DotProduct (vec, forward);
	
			if (dot > 0.6)
				continue;
		}
		*/

		if (!infront (self, target))
			continue;

		VectorSubtract (self->s.origin, target->s.origin, vec);
		len = VectorLength (vec);

		if (aquire == NULL || len < oldlen)
		{
			aquire = target;
			self->target_ent = aquire;
			oldlen = len;
		}
	}

	if (aquire != NULL)
	{
		VectorCopy (self->s.angles, oldang);
		VectorSubtract (aquire->s.origin, self->s.origin, vec);
		
		vectoangles (vec, self->s.angles);
		
		VectorNormalize (vec);
		VectorCopy (vec, self->movedir);
		VectorScale (vec, 500, self->velocity);
	}

	self->nextthink = level.time + 0.1;
}
Esempio n. 30
0
/*
============
AICast_Die
============
*/
void AICast_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
	int contents;
	int killer;
	cast_state_t    *cs;
	qboolean nogib = qtrue;

	// print debugging message
	if ( aicast_debug.integer == 2 && attacker->s.number == 0 ) {
		G_Printf( "killed %s\n", self->aiName );
	}

	cs = AICast_GetCastState( self->s.number );

	if ( attacker ) {
		killer = attacker->s.number;
	} else {
		killer = ENTITYNUM_WORLD;
	}

	// record the sighting (FIXME: silent weapons shouldn't do this, but the AI should react in some way)
	if ( attacker->client ) {
		AICast_UpdateVisibility( self, attacker, qtrue, qtrue );
	}

	// the zombie should show special effect instead of gibbing
	if ( self->aiCharacter == AICHAR_ZOMBIE && cs->secondDeadTime ) {
		if ( cs->secondDeadTime > 1 ) {
			// we are already totally dead
			self->health += damage; // don't drop below gib_health if we weren't already below it
			return;
		}
/*
		if (!cs->rebirthTime)
		{
			self->health = -999;
			damage = 999;
		} else if ( self->health >= GIB_HEALTH ) {
			// while waiting for rebirth, we only "die" if we drop below gib health
			return;
		}
*/
		// always gib
		self->health = -999;
		damage = 999;
	}

	// Zombies are very fragile against highly explosives
	if ( self->aiCharacter == AICHAR_ZOMBIE && damage > 20 && inflictor != attacker ) {
		self->health = -999;
		damage = 999;
	}

	// process the event
	if ( self->client->ps.pm_type == PM_DEAD ) {
		// already dead
		if ( self->health < GIB_HEALTH ) {
			if ( self->aiCharacter == AICHAR_ZOMBIE ) {
				// RF, changed this so Zombies always gib now
				GibEntity( self, killer );
				nogib = qfalse;
/*
				// Zombie has special exploding cloud effect
				if (attacker != inflictor || attacker->s.weapon == WP_VENOM)
				{
					GibEntity( self, killer );
					nogib = qfalse;
				} else {
					// Zombie will decompose upon dying
					self->client->ps.eFlags |= EF_MONSTER_EFFECT2;
					self->s.effect2Time = level.time+200;
					self->health = -1;
				}
*/
				self->takedamage = qfalse;
				self->r.contents = 0;
				cs->secondDeadTime = 2;
				cs->rebirthTime = 0;
				cs->revivingTime = 0;
			} else {
				body_die( self, inflictor, attacker, damage, meansOfDeath );
				return;
			}
		}

	} else {    // this is our first death, so set everything up

		if ( level.intermissiontime ) {
			return;
		}

		self->client->ps.pm_type = PM_DEAD;

		self->enemy = attacker;

		// drop a weapon?
		// if client is in a nodrop area, don't drop anything
		contents = trap_PointContents( self->r.currentOrigin, -1 );
		if ( !( contents & CONTENTS_NODROP ) ) {
			TossClientItems( self );
		}

		// make sure the client doesn't forget about this entity until it's set to "dead" frame
		// otherwise it might replay it's death animation if it goes out and into client view
		self->r.svFlags |= SVF_BROADCAST;

		self->takedamage = qtrue;   // can still be gibbed

		self->s.weapon = WP_NONE;
		self->s.powerups = 0;
		self->r.contents = CONTENTS_CORPSE;

		self->s.angles[0] = 0;
		self->s.angles[1] = self->client->ps.viewangles[1];
		self->s.angles[2] = 0;

		VectorCopy( self->s.angles, self->client->ps.viewangles );

		self->s.loopSound = 0;

		self->r.maxs[2] = -8;
		self->client->ps.maxs[2] = self->r.maxs[2];

		// remove powerups
		memset( self->client->ps.powerups, 0, sizeof( self->client->ps.powerups ) );

		//cs->rebirthTime = 0;

		// never gib in a nodrop
		if ( self->health <= GIB_HEALTH ) {
			if ( self->aiCharacter == AICHAR_ZOMBIE ) {
				// RF, changed this so Zombies always gib now
				GibEntity( self, killer );
				nogib = qfalse;
/*
				// Zombie has special exploding cloud effect
				if (attacker != inflictor || attacker->s.weapon == WP_VENOM)
				{
					GibEntity( self, killer );
					nogib = qfalse;
					self->takedamage = qfalse;
					self->r.contents = 0;
					cs->secondDeadTime = 2;
				} else {
					self->client->ps.eFlags |= EF_MONSTER_EFFECT2;
					self->s.effect2Time = level.time+200;
					self->takedamage = qfalse;
					self->r.contents = 0;
					self->health = -1;
					cs->secondDeadTime = 2;
				}
*/
			} else if ( !( contents & CONTENTS_NODROP ) ) {
				body_die( self, inflictor, attacker, damage, meansOfDeath );
				//GibEntity( self, killer );
				nogib = qfalse;
			}
		}

		// if we are a zombie, and lying down during our first death, then we should just die
		if ( !( self->aiCharacter == AICHAR_ZOMBIE && cs->secondDeadTime && cs->rebirthTime ) ) {

			// set enemy weapon
			BG_UpdateConditionValue( self->s.number, ANIM_COND_ENEMY_WEAPON, 0, qfalse );
			if ( attacker->client ) {
				BG_UpdateConditionValue( self->s.number, ANIM_COND_ENEMY_WEAPON, inflictor->s.weapon, qtrue );
			} else {
				BG_UpdateConditionValue( self->s.number, ANIM_COND_ENEMY_WEAPON, 0, qfalse );
			}

			// set enemy location
			BG_UpdateConditionValue( self->s.number, ANIM_COND_ENEMY_POSITION, 0, qfalse );
			if ( infront( self, inflictor ) ) {
				BG_UpdateConditionValue( self->s.number, ANIM_COND_ENEMY_POSITION, POSITION_INFRONT, qtrue );
			} else {
				BG_UpdateConditionValue( self->s.number, ANIM_COND_ENEMY_POSITION, POSITION_BEHIND, qtrue );
			}

			// play the animation
			BG_AnimScriptEvent( &self->client->ps, ANIM_ET_DEATH, qfalse, qtrue );

			// set this flag so no other anims override us
			self->client->ps.eFlags |= EF_DEAD;
			self->s.eFlags |= EF_DEAD;

		}
	}

	if ( nogib ) {
		// set for rebirth
		if ( self->aiCharacter == AICHAR_ZOMBIE ) {
			if ( !cs->secondDeadTime ) {
				cs->rebirthTime = level.time + 5000 + rand() % 2000;
				cs->secondDeadTime = qtrue;
				cs->revivingTime = 0;
			} else if ( cs->secondDeadTime > 1 ) {
				cs->rebirthTime = 0;
				cs->revivingTime = 0;
				cs->deathTime = level.time;
			}
		} else {
			// the body can still be gibbed
			self->die = body_die;
		}
	}

	trap_LinkEntity( self );

	// mark the time of death
	cs->deathTime = level.time;

	// dying ai's can trigger a target
	if ( !cs->rebirthTime ) {
		G_UseTargets( self, self );
		// really dead now, so call the script
		AICast_ScriptEvent( cs, "death", "" );
		// call the deathfunc for this cast, so we can play associated sounds, or do any character-specific things
		if ( !( cs->aiFlags & AIFL_DENYACTION ) && cs->deathfunc ) {
			cs->deathfunc( self, attacker, damage, meansOfDeath );   //----(SA)	added mod
		}
	} else {
		// really dead now, so call the script
		AICast_ScriptEvent( cs, "fakedeath", "" );
		// call the deathfunc for this cast, so we can play associated sounds, or do any character-specific things
		if ( !( cs->aiFlags & AIFL_DENYACTION ) && cs->deathfunc ) {
			cs->deathfunc( self, attacker, damage, meansOfDeath );   //----(SA)	added mod
		}
	}
}