/*
======================
SV_StepDirection

Turns to the movement direction, and walks the current distance if
facing it.

======================
*/
qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
{
	vec3_t		move, oldorigin;
	float		delta;
	
	ent->ideal_yaw = yaw;
	M_ChangeYaw (ent);
	
	yaw = yaw*M_PI*2 / 360;
	move[0] = cos(yaw)*dist;
	move[1] = sin(yaw)*dist;
	move[2] = 0;

	VectorCopy (ent->s.origin, oldorigin);
	if (SV_movestep (ent, move, false))
	{
		delta = ent->s.angles[YAW] - ent->ideal_yaw;
		if (delta > 45 && delta < 315)
		{		// not turned far enough, so don't take the step
			VectorCopy (oldorigin, ent->s.origin);
		}
		gi.linkentity (ent);
		G_TouchTriggers (ent);
		return true;
	}
	gi.linkentity (ent);
	G_TouchTriggers (ent);
	return false;
}
Example #2
0
void
body_think(edict_t *self)
{
	float r;

	if (fabsf(self->ideal_yaw - anglemod(self->s.angles[YAW])) < 2)
	{
		if (self->timestamp < level.time)
		{
			r = random();

			if (r < 0.10)
			{
				self->ideal_yaw = random() * 350.0;
				self->timestamp = level.time + 1;
			}
		}
	}
	else
	{
		M_ChangeYaw(self);
	}

	self->s.frame++;

	if (self->s.frame > FRAME_stand40)
	{
		self->s.frame = FRAME_stand01;
	}

	self->nextthink = level.time + 0.1;
}
Example #3
0
void fly_vertical (edict_t *self)
{
	int i;
	vec3_t v;
	vec3_t forward, right, up;
	vec3_t start;
	vec3_t tempvec;
	
	VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
	self->ideal_yaw = vectoyaw(v);	
	M_ChangeYaw (self);
	
	if (self->s.frame == FRAME_landing_58 || self->s.frame == FRAME_takeoff_16)
	{
		self->goalentity->nextthink = level.time + 0.1;
		self->goalentity->think = G_FreeEdict;
		self->monsterinfo.currentmove = &fixbot_move_stand;
		self->goalentity = self->enemy = NULL;
	}

	// kick up some particles
	VectorCopy (self->s.angles, tempvec);
	tempvec[PITCH] += 90;

	AngleVectors (tempvec, forward, right, up);
	VectorCopy (self->s.origin, start);
	
	for (i=0; i< 10; i++)
		blastoff (self, start, forward, 2, 1, TE_SHOTGUN, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD);

	// needs sound
}
Example #4
0
void mybrain_suxor (edict_t *self)
{
	int		damage, range, pull;
	vec3_t	start, v, end;
	trace_t	tr;

	if (!self->enemy)
		return;
	if (!self->enemy->inuse)
		return;

	self->lastsound = level.framenum;

	G_EntMidPoint(self->enemy, start);
	VectorSubtract(start, self->s.origin, v);
	self->ideal_yaw = vectoyaw(v);
	M_ChangeYaw (self);
	range = VectorLength(v);
	VectorNormalize(v);
	VectorMA(self->s.origin, 512, v, end);
	tr = gi.trace(self->s.origin, NULL, NULL, end, self, MASK_SHOT);
	if (G_EntExists(tr.ent) && (tr.ent == self->enemy))
	{
		damage = BRAIN_INITIAL_TENTACLE_DMG + BRAIN_ADDON_TENTACLE_DMG*self->monsterinfo.level;
		pull = BRAIN_INITIAL_PULL + BRAIN_ADDON_PULL*self->monsterinfo.level;

		if (tr.ent->groundentity)
			pull *= 2;

		if (range > 64)
			T_Damage(tr.ent, self, self, v, tr.endpos, tr.plane.normal, 0, pull, 0, MOD_UNKNOWN);
		else
			T_Damage(tr.ent, self, self, v, tr.endpos, tr.plane.normal, damage, pull, 0, MOD_UNKNOWN);
	}
}
Example #5
0
void thing_think_pause(edict_t *self)
{
	edict_t	*monster;
	if(level.time > self->touch_debounce_time)
	{
		thing_think(self);
		return;
	}
	monster = self->target_ent;
	if(!monster || !monster->inuse)
	{
		G_FreeEdict(self);
		return;
	}
	if(has_valid_enemy(monster))
	{
		vec3_t	dir;
		vec3_t	angles;

		if(visible(monster->enemy,monster))
		{
			self->touch_debounce_time = 0;
			thing_think(self);
			return;
		}
		VectorSubtract(monster->enemy->s.origin,monster->s.origin,dir);
		VectorNormalize(dir);
		vectoangles(dir,angles);
		monster->ideal_yaw = angles[YAW];
		M_ChangeYaw(monster);
	}
	self->nextthink = level.time + FRAMETIME;
}
Example #6
0
// NOTE: pos should be the final goal, because monster will stop moving after reaching it!
void M_MoveToPosition (edict_t *ent, vec3_t pos, float dist)
{
	vec3_t v;

	// stay in-place for medic healing
	if (ent->holdtime > level.time) 
		return;

	// need to be touching the ground
	if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)) && !ent->waterlevel)
	{
		//gi.dprintf("not touching ground\n");
		return;
	}

	// we are close enough
	if (distance(ent->s.origin, pos) < 32)
	{
		//gi.dprintf("close enough %.0f\n", distance(ent->s.origin, pos));
		// look at the final position
		VectorSubtract(pos, ent->s.origin, v);
		VectorNormalize(v);
		ent->ideal_yaw = vectoyaw(v);
		M_ChangeYaw(ent);
		return;
	}

	// dont move so fast in the water
	if (!(ent->flags & (FL_FLY|FL_SWIM)) && (ent->waterlevel > 1))
		dist *= 0.5;

	// if we can't take a step, try moving in another direction
	if (!SV_StepDirection (ent, ent->ideal_yaw, dist, true))
	{
		//gi.dprintf("couldn't step\n");
		// if the monster hasn't moved much, then increment
		// the number of frames it has been stuck
		if (distance(ent->s.origin, ent->monsterinfo.stuck_org) < 64)
			ent->monsterinfo.stuck_frames++;
		else
			ent->monsterinfo.stuck_frames = 0;

		// record current position for comparison
		VectorCopy(ent->s.origin, ent->monsterinfo.stuck_org);

		// attempt a course-correction
		if (ent->inuse && (level.time > ent->monsterinfo.bump_delay))
		{
			//gi.dprintf("tried course correction\n");
			//SV_NewChaseDir (ent, goal, dist);
			SV_NewChaseDir2(ent, pos, dist);
			ent->monsterinfo.bump_delay = level.time + FRAMETIME*GetRandom(3, 9);
			return;
		}
	}
	//else
		//gi.dprintf("step OK\n");
}
Example #7
0
void minisentry_idle (edict_t *self)
{
	float	min_yaw, max_yaw;

	if (self->delay > level.time)
		return;
	if (self->delay == level.time)
		gi.sound(self, CHAN_AUTO, gi.soundindex("weapons/gunidle1.wav"), 0.5, ATTN_NORM, 0);

//	self->yaw_speed = 5;
	max_yaw = self->move_angles[YAW] + 45;
	min_yaw = self->move_angles[YAW] - 45;
	// validate angles
	if (max_yaw < 0)
		max_yaw += 360;
	else if (max_yaw > 360)
		max_yaw -= 360;
	if (min_yaw < 0)
		min_yaw += 360;
	else if (min_yaw > 360)
		min_yaw -= 360;
	// sentry scans side-to-side looking for targets
	if (self->style == SENTRY_IDLE_RIGHT)
	{
		self->ideal_yaw = max_yaw;
		M_ChangeYaw(self);
		if (self->s.angles[YAW] == self->ideal_yaw)
		{
			self->style = SENTRY_IDLE_LEFT;
			self->delay = level.time + 1.0;
		}
	}
	else
	{	
		self->ideal_yaw = min_yaw;
		M_ChangeYaw(self);
		if (self->s.angles[YAW] == self->ideal_yaw)
		{
			self->style = SENTRY_IDLE_RIGHT;
			self->delay = level.time + 1.0;
		}
	}	
}
Example #8
0
/*
=============
ai_turn

don't move, but turn towards ideal_yaw
Distance is for slight position adjustments needed by the animations
=============
*/
void ai_turn (edict_t *self, float dist)
{
	if (dist)
		M_walkmove (self, self->s.angles[YAW], dist);

	if (FindTarget (self))
		return;
	
	M_ChangeYaw (self);
}
Example #9
0
/*
=============
ai_run_missile

Turn in place until within an angle to launch a missile attack
=============
*/
void ai_run_missile(edict_t *self)
{
	self->ideal_yaw = enemy_yaw;
	M_ChangeYaw (self);

	if (FacingIdeal(self))
	{
		self->monsterinfo.attack (self);
		self->monsterinfo.attack_state = AS_STRAIGHT;
	}
}
Example #10
0
/*
=============
ai_charge

Turns towards target and advances
Use this call with a distnace of 0 to replace ai_face
==============
*/
void ai_charge (edict_t *self, float dist)
{
	vec3_t	v;

	VectorSubtract (self->enemy->s.origin, self->s.origin, v);
	self->ideal_yaw = vectoyaw(v);
	M_ChangeYaw (self);

	if (dist)
		M_walkmove (self, self->s.angles[YAW], dist);
}
Example #11
0
void ai_move2 (edict_t *self, float dist)
{
	vec3_t v;
	
	if (dist)
		M_walkmove (self, self->s.angles[YAW], dist);

	VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
	self->ideal_yaw = vectoyaw(v);	
	M_ChangeYaw (self);
};
Example #12
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);
	}

};
Example #13
0
/*
=============
ai_stand

Used for standing around and looking for players
Distance is for slight position adjustments needed by the animations
==============
*/
void ai_stand (edict_t *self, float dist)
{
	vec3_t	v;

	if (dist)
		M_walkmove (self, self->s.angles[YAW], dist);

	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
	{
		if (self->enemy)
		{
			VectorSubtract (self->enemy->s.origin, self->s.origin, v);
			self->ideal_yaw = vectoyaw(v);
			if (self->s.angles[YAW] != self->ideal_yaw && self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND)
			{
				self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
				self->monsterinfo.run (self);
			}
			M_ChangeYaw (self);
			ai_checkattack (self, 0);
		}
		else
			FindTarget (self);
		return;
	}

	if (FindTarget (self))
		return;
	
	if (level.time > self->monsterinfo.pausetime)
	{
		self->monsterinfo.walk (self);
		return;
	}

	if (!(self->spawnflags & 1) && (self->monsterinfo.idle) && (level.time > self->monsterinfo.idle_time))
	{
		if (self->monsterinfo.idle_time)
		{
			self->monsterinfo.idle (self);
			self->monsterinfo.idle_time = level.time + 15000 + random() * 15000;
		}
		else
		{
			self->monsterinfo.idle_time = level.time + random() * 15000;
		}
	}
}
Example #14
0
void
Widow2TonguePull(edict_t *self)
{
	vec3_t vec;
	vec3_t f, r, u;
	vec3_t start, end;

	if (!self)
	{
		return;
	}

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

	AngleVectors(self->s.angles, f, r, u);
	G_ProjectSource2(self->s.origin, offsets[self->s.frame - FRAME_tongs01],
			f, r, u, start);
	VectorCopy(self->enemy->s.origin, end);

	if (!widow2_tongue_attack_ok(start, end, 256))
	{
		return;
	}

	if (self->enemy->groundentity)
	{
		self->enemy->s.origin[2] += 1;
		self->enemy->groundentity = NULL;
	}

	VectorSubtract(self->s.origin, self->enemy->s.origin, vec);

	if (self->enemy->client)
	{
		VectorNormalize(vec);
		VectorMA(self->enemy->velocity, 1000, vec, self->enemy->velocity);
	}
	else
	{
		self->enemy->ideal_yaw = vectoyaw(vec);
		M_ChangeYaw(self->enemy);
		VectorScale(f, 1000, self->enemy->velocity);
	}
}
Example #15
0
void mybrain_jump_hold (edict_t *self)
{
	vec3_t	v;

	if (G_EntIsAlive(self->monsterinfo.attacker))
	{
		// face the attacker
		VectorSubtract(self->monsterinfo.attacker->s.origin, self->s.origin, v);
		self->ideal_yaw = vectoyaw(v);
		M_ChangeYaw(self);
	}

	// check for landing or jump timeout
	if (self->waterlevel || self->groundentity || (level.time > self->monsterinfo.pausetime))
		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
	else
		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
Example #16
0
/*
=============
ai_run_slide

Strafe sideways, but stay at aproximately the same range
=============
*/
void ai_run_slide(edict_t *self, float distance)
{
	float	ofs;
	
	self->ideal_yaw = enemy_yaw;
	M_ChangeYaw (self);

	if (self->monsterinfo.lefty)
		ofs = 90;
	else
		ofs = -90;
	
	if (M_walkmove (self, self->ideal_yaw + ofs, distance))
		return;
		
	self->monsterinfo.lefty = 1 - self->monsterinfo.lefty;
	M_walkmove (self, self->ideal_yaw - ofs, distance);
}
Example #17
0
void MakronHyperblaster (edict_t *self)
{
	vec3_t	v;
	vec3_t	dir;
	vec3_t	vec;
	vec3_t	start;
	vec3_t	forward, right;
	int		flash_number;
	int damage;

	if (!self->enemy)
		return;

	if (self->radius_dmg)
		damage = 40 + 6 * self->monsterinfo.skill;
	else
		damage = 20 + 3 * self->monsterinfo.skill;

	flash_number = MZ2_MAKRON_BLASTER_1 + (self->s.frame - FRAME_attak405);

	AngleVectors (self->s.angles, forward, right, NULL);
	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);

	VectorSubtract (self->enemy->s.origin, self->s.origin, v);
	self->ideal_yaw = vectoyaw(v);
	M_ChangeYaw (self);
	VectorMA(self->enemy->s.origin, 0.3, self->enemy->velocity, vec);
//	VectorCopy (self->enemy->s.origin, vec);
	vec[2] += self->enemy->viewheight;
	VectorSubtract (vec, start, vec);
	vectoangles (vec, vec);
	dir[0] = vec[0];

	if (self->s.frame <= FRAME_attak413)
		dir[1] = self->s.angles[1] - (1.5 - 0.01 * self->monsterinfo.skill) * (self->s.frame - FRAME_attak413);
	else
		dir[1] = self->s.angles[1] + (1.5 - 0.01 * self->monsterinfo.skill) * (self->s.frame - FRAME_attak421);

	dir[2] = 0;

	AngleVectors (dir, forward, NULL, NULL);

	monster_fire_blaster (self, start, forward, damage, 600 + 15 * self->monsterinfo.skill, MZ2_MAKRON_BLASTER_1, EF_BLASTER);
}
Example #18
0
void fly_vertical2 (edict_t *self)
{
	vec3_t v;
	int len;
	
	VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
	len = VectorLength (v);
	self->ideal_yaw = vectoyaw(v);	
	M_ChangeYaw (self);
	
	if (len < 32)
	{
		self->goalentity->nextthink = level.time + 0.1;
		self->goalentity->think = G_FreeEdict;
		self->monsterinfo.currentmove = &fixbot_move_stand;
		self->goalentity = self->enemy = NULL;
	}
		
	// needs sound
}
Example #19
0
void minisentry_lockon (edict_t *self)
{
	float	max, temp;
	vec3_t	angles, v;

	// curse causes minisentry to fail to lock-on to enemy
	if ((que_typeexists(self->curses, CURSE)) && random() <= 0.8)
		return;

	temp = self->yaw_speed;
	self->yaw_speed *= 3;
	VectorSubtract(self->enemy->s.origin, self->s.origin, v);
	vectoangles(v, angles);
	self->ideal_yaw = vectoyaw(v);
	M_ChangeYaw(self);
	self->yaw_speed = temp; // restore original yaw speed
	self->s.angles[PITCH] = angles[PITCH];
	ValidateAngles(self->s.angles);
	// maximum pitch is 65 degrees in either direction
	if (self->enemy->s.origin[2] > self->s.origin[2]) // if the enemy is above
	{	
		if (self->owner && self->owner->style == SENTRY_FLIPPED)
			max = 340; // allow 20 degrees up
		else
			max = 315; // allow 45 degrees up
		if (self->s.angles[PITCH] < max)
			self->s.angles[PITCH] = max;
	}
	else
	{
		if (self->owner && self->owner->style == SENTRY_FLIPPED)
			max = 45; // allow 45 degrees down
		else
			max = 20; // allow 20 degrees down
		if (self->s.angles[PITCH] > max)
			self->s.angles[PITCH] = max;
	}
}
Example #20
0
void mymedic_jump_hold (edict_t *self)
{
	vec3_t	v;

	if (G_EntExists(self->monsterinfo.attacker))
	{
		// face the attacker
		VectorSubtract(self->monsterinfo.attacker->s.origin, self->s.origin, v);
		self->ideal_yaw = vectoyaw(v);
		M_ChangeYaw(self);
	}
	// check for landing or jump timeout
	if (self->groundentity || (level.time > self->monsterinfo.pausetime))
	{
		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
		VectorClear(self->velocity);
	}
	else
	{
		// we're still in the air
		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
	}
}
Example #21
0
/*
======================
SV_StepDirection

Turns to the movement direction, and walks the current distance if
facing it.

======================
*/
qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
{
    vec3_t		move, oldorigin;
    float		delta;

    if(!ent->inuse)	return true;		// PGM g_touchtrigger free problem

    ent->ideal_yaw = yaw;
    M_ChangeYaw (ent);

    yaw = yaw*M_PI*2 / 360;
    move[0] = cos(yaw)*dist;
    move[1] = sin(yaw)*dist;
    move[2] = 0;

    VectorCopy (ent->s.origin, oldorigin);
    if (SV_movestep (ent, move, false))
    {
        ent->monsterinfo.aiflags &= ~AI_BLOCKED;
        if(!ent->inuse)	return true;		// PGM g_touchtrigger free problem

        delta = ent->s.angles[YAW] - ent->ideal_yaw;
        if (strncmp(ent->classname, "monster_widow", 13))
        {
            if (delta > 45 && delta < 315)
            {   // not turned far enough, so don't take the step
                VectorCopy (oldorigin, ent->s.origin);
            }
        }
        gi.linkentity (ent);
        G_TouchTriggers (ent);
        return true;
    }
    gi.linkentity (ent);
    G_TouchTriggers (ent);
    return false;
}
Example #22
0
void mybrain_jumpattack_hold (edict_t *self)
{
	int value=0;

	// we are on ground
	if (self->groundentity)
		value = 1;
	// we are in the water or passed jump timeout value
	else if (self->waterlevel || level.time > self->monsterinfo.pausetime)
		value = 2;

	// discontinue holding this frame
	if (value)
	{
		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;

		if (value == 1)
			gi.sound (self, CHAN_WEAPON, sound_thud, 1, ATTN_NORM, 0);
	}
	
	else
	{
		vec3_t v;

		// hold this frame
		self->monsterinfo.aiflags |= AI_HOLD_FRAME;

		// face the enemy if he's alive and visible
		if (G_EntIsAlive(self->enemy) && visible(self, self->enemy))
		{
			VectorSubtract(self->enemy->s.origin, self->s.origin, v);
			self->ideal_yaw = vectoyaw(v);
			M_ChangeYaw(self);
		}
	}
}
Example #23
0
/*
===========
FindTarget

Self is currently not attacking anything, so try to find a target

Returns TRUE if an enemy was sighted

When a player fires a missile, the point of impact becomes a fakeplayer so
that monsters that see the impact will respond as if they had seen the
player.

To avoid spending too much time, only a single client (or fakeclient) is
checked each frame.  This means multi player games will have slightly
slower noticing monsters.
============
*/
bool FindTarget (edict_t *self)
{
	edict_t		*client;
	bool	heardit;
	bool    noise;
	int			r;

	if (self->monsterinfo.aiflags & AI_GOOD_GUY)
	{
		if (self->goalentity && self->goalentity->r.inuse && self->goalentity->classname)
		{
			if (strcmp(self->goalentity->classname, "target_actor") == 0)
				return false;
		}

		//FIXME look for monsters?
		return false;
	}

	// if we're going to a combat point, just proceed
	if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
		return false;

// if the first spawnflag bit is set, the monster will only wake up on
// really seeing the player, not another monster getting angry or hearing
// something

// revised behavior so they will wake up if they "see" a player make a noise
// but not weapon impact/explosion noises

	heardit = false;
	if ((level.sight_entity_framenum+1 >= level.framenum) && !(self->spawnflags & 1) )
	{
		client = level.sight_entity;
		if (client->enemy == self->enemy)
		{
			return false;
		}
	}
	else if (level.sound_entity_framenum+1 >= level.framenum)
	{
		client = level.sound_entity;
		heardit = true;
	}
	else if (!(self->enemy) && (level.sound2_entity_framenum+1 >= level.framenum) && !(self->spawnflags & 1) )
	{
		client = level.sound2_entity;
		heardit = true;
	}
	else
	{
		client = level.sight_client;
		if (!client)
			return false;	// no clients to get mad at
	}

	// if the entity went away, forget it
	if (!client->r.inuse)
		return false;
	if (client == self->enemy)
		return true;	// JDC false;

	noise = strcmp(client->classname, "player_noise") == 0;
	if (!noise && (client->r.svflags & SVF_NOCLIENT))
		return false;

	if (client->r.client)
	{
		if (client->flags & FL_NOTARGET)
			return false;
	}
	else if (client->r.svflags & SVF_MONSTER)
	{
		if (!client->enemy)
			return false;
		if (client->enemy->flags & FL_NOTARGET)
			return false;
	}
	else if (heardit)
	{
		if (client->r.owner->flags & FL_NOTARGET)
			return false;
	}
	else
		return false;

	if (!heardit)
	{
		r = range (self, client);

		if (r == RANGE_FAR)
			return false;

// this is where we would check invisibility

		// is client in an spot too dark to be seen?
//		if (client->light_level <= 5)
//			return false;

		if (!G_Visible (self, client))
		{
			return false;
		}

		if (r == RANGE_NEAR)
		{
			if (client->show_hostile < level.time && !G_InFront (self, client))
			{
				return false;
			}
		}
		else if (r == RANGE_MID)
		{
			if (!G_InFront (self, client))
			{
				return false;
			}
		}

		self->enemy = client;

		if (!noise)
		{
			self->monsterinfo.aiflags &= ~AI_SOUND_TARGET;

			if (!self->enemy->r.client)
			{
				self->enemy = self->enemy->enemy;
				if (!self->enemy->r.client)
				{
					self->enemy = NULL;
					return false;
				}
			}
		}
	}
	else	// heardit
	{
		vec3_t	temp;

		if (self->spawnflags & 1)
		{
			if (!G_Visible (self, client))
				return false;
		}

		VectorSubtract (client->s.origin, self->s.origin, temp);

		if (VectorLength(temp) > 1000)	// too far to hear
		{
			return false;
		}

		// check area portals - if they are different and not connected then we can't hear it
		if (client->r.areanum != self->r.areanum)
			if (!trap_CM_AreasConnected(self->r.areanum, client->r.areanum))
				return false;

		self->ideal_yaw = vectoyaw(temp);
		M_ChangeYaw (self);

		// hunt the sound for a bit; hopefully find the real player
		self->monsterinfo.aiflags |= AI_SOUND_TARGET;
		self->enemy = client;
	}

//
// got one
//
	FoundTarget (self);

	if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET) && (self->monsterinfo.sight))
		self->monsterinfo.sight (self, self->enemy);

	return true;
}
Example #24
0
void
hunter_think(edict_t *self)
{
	edict_t *owner;
	vec3_t dir, ang;

	if (!self)
	{
		return;
	}

	/* if we've exited the level, just remove ourselves. */
	if (level.intermissiontime)
	{
		sphere_think_explode(self);
		return;
	}

	owner = self->owner;

	if (!owner && !(self->spawnflags & SPHERE_DOPPLEGANGER))
	{
		G_FreeEdict(self);
		return;
	}

	if (owner)
	{
		self->ideal_yaw = owner->s.angles[YAW];
	}
	else if (self->enemy) /* fired by doppleganger */
	{
		VectorSubtract(self->enemy->s.origin, self->s.origin, dir);
		vectoangles2(dir, ang);
		self->ideal_yaw = ang[YAW];
	}

	M_ChangeYaw(self);

	if (self->enemy)
	{
		sphere_chase(self, 0);

		/* deal with sam raimi cam */
		if (owner && (owner->flags & FL_SAM_RAIMI))
		{
			if (self->inuse)
			{
				owner->movetype = MOVETYPE_FLYMISSILE;
				LookAtKiller(owner, self, self->enemy);

				/* owner is flying with us, move him too */
				owner->movetype = MOVETYPE_FLYMISSILE;
				owner->viewheight = self->s.origin[2] - owner->s.origin[2];
				VectorCopy(self->s.origin, owner->s.origin);
				VectorCopy(self->velocity, owner->velocity);
				VectorClear(owner->mins);
				VectorClear(owner->maxs);
				gi.linkentity(owner);
			}
			else /* sphere timed out */
			{
				VectorClear(owner->velocity);
				owner->movetype = MOVETYPE_NONE;
				gi.linkentity(owner);
			}
		}
	}
	else
	{
		sphere_fly(self);
	}

	if (self->inuse)
	{
		self->nextthink = level.time + 0.1;
	}
}
Example #25
0
/*
======================
M_MoveToGoal
======================
*/
void M_MoveToGoal (edict_t *ent, float dist)
{
	edict_t		*goal;

	goal = ent->goalentity;

	if (ent->holdtime > level.time) // stay in-place for medic healing
		return;

	if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)) && !ent->waterlevel)
	{
		//gi.dprintf("not touching ground\n");
		return;
	}

// if the next step hits the enemy, return immediately
	if (ent->enemy && (ent->enemy->solid == SOLID_BBOX) 
		&& SV_CloseEnough (ent, ent->enemy, dist) )
//GHz START
	{
		vec3_t v;

		// we need to keep turning to avoid getting stuck doing nothing
		if (ent->goalentity && ent->goalentity->inuse) // 3.89 make sure the monster still has a goal!
		{
			VectorSubtract(ent->goalentity->s.origin, ent->s.origin, v);
			VectorNormalize(v);
			ent->ideal_yaw = vectoyaw(v);
			M_ChangeYaw(ent);
		}
		return;
	}
//GHz END

	// dont move so fast in the water
	if (!(ent->flags & (FL_FLY|FL_SWIM)) && (ent->waterlevel > 1))
		dist *= 0.5;

// bump around...
	// if we can't take a step, try moving in another direction
	if (!SV_StepDirection (ent, ent->ideal_yaw, dist, true))
	{
		//gi.dprintf("couldnt step\n");
		// if the monster hasn't moved much, then increment
		// the number of frames it has been stuck
		if (distance(ent->s.origin, ent->monsterinfo.stuck_org) < 64)
			ent->monsterinfo.stuck_frames++;
		else
			ent->monsterinfo.stuck_frames = 0;

		// record current position for comparison
		VectorCopy(ent->s.origin, ent->monsterinfo.stuck_org);

		// attempt a course-correction
		if (ent->inuse && (level.time > ent->monsterinfo.bump_delay))
		{
			//gi.dprintf("tried course correction %s\n", ent->goalentity?"true":"false");
			SV_NewChaseDir (ent, goal, dist);
			ent->monsterinfo.bump_delay = level.time + FRAMETIME*GetRandom(2, 5);
			return;
		}
	}
}
Example #26
0
/*
======================
SV_StepDirection

Turns to the movement direction, and walks the current distance if
facing it.

======================
*/
qboolean SV_StepDirection (edict_t *ent, float yaw, float dist, qboolean try_smallstep)
{
	vec3_t		move, oldorigin;
	//float		delta;
	float		old_dist;
	
	// dist = dist);

	//gi.dprintf("SV_StepDirection\n");
	old_dist = dist;
	ent->ideal_yaw = yaw;
	M_ChangeYaw (ent);

	if (!dist || fabs(dist) < 1)
		return true;

	yaw = yaw*M_PI*2 / 360;
	VectorCopy (ent->s.origin, oldorigin);

	// loop until we can move successfully
	while ((int)dist != 0)
	{
		move[0] = cos(yaw)*dist;
		move[1] = sin(yaw)*dist;
		move[2] = 0;

		
		if (SV_movestep (ent, move, false))
		{
			/*
			delta = ent->s.angles[YAW] - ent->ideal_yaw;
			if (delta > 45 && delta < 315)
			{		// not turned far enough, so don't take the step
				VectorCopy (oldorigin, ent->s.origin);
				gi.dprintf("not turned far enough!\n");
			}
			*/
			gi.linkentity (ent);
			G_TouchTriggers (ent);
			/*
			if (old_dist != dist)
				gi.dprintf("took a smaller step of %d instead of %d\n", (int)dist, (int)old_dist);
			else
				gi.dprintf("moved full distance\n");
			*/
			return true;
		}

		if (!try_smallstep)
			break;
		if (dist > 0)
			dist--;
		else
			dist++;
	}

	gi.linkentity (ent);
	G_TouchTriggers (ent);
	//gi.dprintf("%d: %s can't walk forward!\n", level.framenum, V_GetMonsterName(ent));
	return false;
}
Example #27
0
/*
==================
AI_BeginAttack

  Returns true if OK to attack, false otherwise

  May start a new movement for the character, to straighten up, or avoid something/someone
==================
*/
qboolean AI_BeginAttack( edict_t *self )
{
	vec3_t	vec;
	float	dist;


	// Ridah, 7-5-99, If they've been ordered to attack us by a client, get mad at them also
	if (self->enemy && self->enemy->leader)
		AI_MakeEnemy( self, self->enemy->leader, 0 );


	if (!self->enemy || (self->enemy->health <= 0))
	{
		self->cast_info.currentmove = self->cast_info.move_stand;
		return false;
	}

	dist = VectorDistance( self->s.origin, self->enemy->s.origin );


	// Ridah, 19-may-99, Grenade AI
	if (self->cast_info.aiflags & AI_GRENADE_GUY)
	{
		if (( self->s.origin[2] - self->enemy->s.origin[2] ) < -256)
		{
			if (self->cast_info.currentmove != self->cast_info.move_avoid_run)
				AI_EndAttack(self);		// try find something else to do

			return false;
		}
	}


	if (	!(self->cast_info.aiflags & AI_SIDE_ATTACK))
// Ridah 7/5/99, fixes shooting with back to player (happens in SR1 courtyard sometimes)
//		&&	(	(dist > FACE_ANIM_DIST)
//			 ||	(self->cast_info.aiflags & AI_FACE_ATTACK)))
	{

		if (!directly_infront(self, self->enemy))
		{	// we need to straighten up
			float	dist;

			VectorSubtract( self->enemy->s.origin, self->s.origin, vec );
			dist = VectorNormalize( vec );
			self->ideal_yaw = vectoyaw( vec );

			if ((dist > 384) && (self->maxs[2] == self->cast_info.standing_max_z))
			{
				int side_result;

				side_result = AI_SideTrace( self, 48, 90, SIDE_RANDOM );

				if (side_result && self->cast_info.move_lside_step)
				{
					if (side_result < 0)
						self->cast_info.currentmove = self->cast_info.move_lside_step;
					else
						self->cast_info.currentmove = self->cast_info.move_rside_step;
				}
				else
				{
					self->cast_info.currentmove = self->cast_info.move_avoid_walk;
				}

				return false;
			}
			else
			{
				M_ChangeYaw(self);
			}

		}

	}
/*
	if (	(self->cast_info.move_avoid_reverse_run)
		&&	(self->cast_info.last_reverse < (level.time - 5))
		&&	(dist < 64))
	{
		// trace a line backwards, make sure we can move there
		if ( AI_YawTrace( self, 64, 180 ) )
		{
			self->cast_info.currentmove = self->cast_info.move_avoid_reverse_run;
			self->cast_info.last_reverse = level.time;
			return false;
		}
	}
*/
	if (!AI_ClearSight(self, self->enemy, true))
	{	// can't see them directly, will we hit another enemy? if so keep firing

		static vec3_t mins = { -8, -8,  -4 };
		static vec3_t maxs = {  8,  8,   4 };
		vec3_t	start, end;
		trace_t tr;
		cast_memory_t	*tr_memory;

		VectorCopy( self->s.origin, start );
		start[2] += self->viewheight - 8;

		VectorCopy( self->enemy->s.origin, end );
		end[2] += self->enemy->viewheight - 8;

		tr = gi.trace( start, mins, maxs, end, self, MASK_PLAYERSOLID );

		if (tr.fraction < 1)
		{
			if (tr.ent == world)
			{
				if (self->cast_info.currentmove != self->cast_info.move_avoid_run)
					AI_EndAttack(self);		// try find something else to do

				return false;
			}
			else if (tr.ent->svflags & SVF_MONSTER || tr.ent->client)
			{
				tr_memory = level.global_cast_memory[self->character_index][tr.ent->character_index];

				if (!tr_memory || !(tr_memory->flags & MEMORY_HOSTILE_ENEMY))
				{
					if (self->cast_info.currentmove != self->cast_info.move_avoid_run)
						AI_EndAttack(self);		// try find something else to do

					return false;
				}
			}
		}
	}

	if (self->dont_takecover_time == 99999)
	{	// attack for at least 2 seconds
		if (!(self->cast_info.aiflags & AI_MELEE))
			self->dont_takecover_time = level.time + 2 + random()*4;
		else
			self->dont_takecover_time = 0;
	}

	return true;
}
Example #28
0
// ====================
// ====================
int stalker_do_pounce(edict_t *self, vec3_t dest)
{
	vec3_t	forward, right;
	vec3_t	dist;
	vec_t	length;
	vec3_t	jumpAngles;
	vec3_t	jumpLZ;
	float	velocity = 400.1;
	trace_t	trace;
	int		preferHighJump;

	// don't pounce when we're on the ceiling
	if(STALKER_ON_CEILING(self))
		return false;

	if(!stalker_check_lz (self, self->enemy, dest))
		return false;

	VectorSubtract(dest, self->s.origin, dist);
	
	// make sure we're pointing in that direction 15deg margin of error.
	vectoangles2 (dist, jumpAngles);
	if(abs(jumpAngles[YAW] - self->s.angles[YAW]) > 45)
		return false;			// not facing the player...

	self->ideal_yaw = jumpAngles[YAW];
	M_ChangeYaw(self);

	length = VectorLength(dist);
	if(length > 450)
		return false;			// can't jump that far...

	VectorCopy(dest, jumpLZ);

	preferHighJump = 0;

	// if we're having to jump up a distance, jump a little too high to compensate.
	if(dist[2] >= 32.0)
	{
		preferHighJump = 1;
		jumpLZ[2] += 32;
	}

	trace = gi.trace (self->s.origin, vec3_origin, vec3_origin, dest, self, MASK_MONSTERSOLID);
	if((trace.fraction < 1) && (trace.ent != self->enemy))
	{
//		gi.dprintf("prefer high jump angle\n");
		preferHighJump = 1; 
	}

	// find a valid angle/velocity combination
	while(velocity <= 800)
	{
		calcJumpAngle(self->s.origin, jumpLZ, velocity, jumpAngles);
		if((!_isnan(jumpAngles[0]))  || (!_isnan(jumpAngles[1])))
			break;
		
		velocity+=200;
	};

	if(!preferHighJump && (!_isnan(jumpAngles[0])) )
	{
		AngleVectors (self->s.angles, forward, right, NULL);
		VectorNormalize ( forward ) ;

		VectorScale( forward, velocity * cos(DEG2RAD(jumpAngles[0])), self->velocity);
		self->velocity[2] = velocity * sin(DEG2RAD(jumpAngles[0])) + (0.5 * sv_gravity->value * FRAMETIME);
//		gi.dprintf("  pouncing! %0.1f,%0.1f (%0.1f)  --> %0.1f, %0.1f, %0.1f\n", 
//				jumpAngles[0], jumpAngles[1], jumpAngles[0],
//				self->velocity[0], self->velocity[1], self->velocity[2]);
		return 1;
	}

	if(!_isnan(jumpAngles[1]))
	{
		AngleVectors (self->s.angles, forward, right, NULL);
		VectorNormalize ( forward ) ;

		VectorScale( forward, velocity * cos(DEG2RAD(jumpAngles[1])), self->velocity);
		self->velocity[2] = velocity * sin(DEG2RAD(jumpAngles[1])) + (0.5 * sv_gravity->value * FRAMETIME);
//		gi.dprintf("  pouncing! %0.1f,%0.1f (%0.1f)  --> %0.1f, %0.1f, %0.1f\n", 
//				jumpAngles[0], jumpAngles[1], jumpAngles[1],
//				self->velocity[0], self->velocity[1], self->velocity[2]);
		return 1;
	}

//	gi.dprintf("  nan\n");
	return 0;
}
Example #29
0
void
Trap_Think(edict_t *ent)
{
	edict_t *target = NULL;
	edict_t *best = NULL;
	vec3_t vec;
	int len, i;
	int oldlen = 8000;
	vec3_t forward, right, up;

	if (!ent)
	{
		return;
	}

	if (ent->timestamp < level.time)
	{
		BecomeExplosion1(ent);
		return;
	}

	ent->nextthink = level.time + 0.1;

	if (!ent->groundentity)
	{
		return;
	}

	/* ok lets do the blood effect */
	if (ent->s.frame > 4)
	{
		if (ent->s.frame == 5)
		{
			if (ent->wait == 64)
			{
				gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/trapdown.wav"),
					   	1, ATTN_IDLE, 0);
			}

			ent->wait -= 2;
			ent->delay += level.time;

			for (i = 0; i < 3; i++)
			{
				best = G_Spawn();

				if (strcmp(ent->enemy->classname, "monster_gekk") == 0)
				{
					best->s.modelindex = gi.modelindex("models/objects/gekkgib/torso/tris.md2");
					best->s.effects |= TE_GREENBLOOD;
				}
				else if (ent->mass > 200)
				{
					best->s.modelindex = gi.modelindex("models/objects/gibs/chest/tris.md2");
					best->s.effects |= TE_BLOOD;
				}
				else
				{
					best->s.modelindex = gi.modelindex("models/objects/gibs/sm_meat/tris.md2");
					best->s.effects |= TE_BLOOD;
				}

				AngleVectors(ent->s.angles, forward, right, up);

				RotatePointAroundVector(vec, up, right, ((360.0 / 3) * i) + ent->delay);
				VectorMA(vec, ent->wait / 2, vec, vec);
				VectorAdd(vec, ent->s.origin, vec);
				VectorAdd(vec, forward, best->s.origin);

				best->s.origin[2] = ent->s.origin[2] + ent->wait;

				VectorCopy(ent->s.angles, best->s.angles);

				best->solid = SOLID_NOT;
				best->s.effects |= EF_GIB;
				best->takedamage = DAMAGE_YES;

				best->movetype = MOVETYPE_TOSS;
				best->svflags |= SVF_MONSTER;
				best->deadflag = DEAD_DEAD;

				VectorClear(best->mins);
				VectorClear(best->maxs);

				best->watertype = gi.pointcontents(best->s.origin);

				if (best->watertype & MASK_WATER)
				{
					best->waterlevel = 1;
				}

				best->nextthink = level.time + 0.1;
				best->think = G_FreeEdict;
				gi.linkentity(best);
			}

			if (ent->wait < 19)
			{
				ent->s.frame++;
			}

			return;
		}

		ent->s.frame++;

		if (ent->s.frame == 8)
		{
			ent->nextthink = level.time + 1.0;
			ent->think = G_FreeEdict;

			best = G_Spawn();
			SP_item_foodcube(best);
			VectorCopy(ent->s.origin, best->s.origin);
			best->s.origin[2] += 16;
			best->velocity[2] = 400;
			best->count = ent->mass;
			gi.linkentity(best);
			return;
		}

		return;
	}

	ent->s.effects &= ~EF_TRAP;

	if (ent->s.frame >= 4)
	{
		ent->s.effects |= EF_TRAP;
		VectorClear(ent->mins);
		VectorClear(ent->maxs);
	}

	if (ent->s.frame < 4)
	{
		ent->s.frame++;
	}

	while ((target = findradius(target, ent->s.origin, 256)) != NULL)
	{
		if (target == ent)
		{
			continue;
		}

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

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

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

		if (!best)
		{
			best = target;
			continue;
		}

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

		if (len < oldlen)
		{
			oldlen = len;
			best = target;
		}
	}

	/* pull the enemy in */
	if (best)
	{
		vec3_t forward;

		if (best->groundentity)
		{
			best->s.origin[2] += 1;
			best->groundentity = NULL;
		}

		VectorSubtract(ent->s.origin, best->s.origin, vec);
		len = VectorLength(vec);

		if (best->client)
		{
			VectorNormalize(vec);
			VectorMA(best->velocity, 250, vec, best->velocity);
		}
		else
		{
			best->ideal_yaw = vectoyaw(vec);
			M_ChangeYaw(best);
			AngleVectors(best->s.angles, forward, NULL, NULL);
			VectorScale(forward, 256, best->velocity);
		}

		gi.sound(ent, CHAN_VOICE, gi.soundindex(
						"weapons/trapsuck.wav"), 1, ATTN_IDLE, 0);

		if (len < 32)
		{
			if (best->mass < 400)
			{
				T_Damage(best, ent, ent->owner, vec3_origin, best->s.origin,
						vec3_origin, 100000, 1, 0, MOD_TRAP);
				ent->enemy = best;
				ent->wait = 64;
				VectorCopy(ent->s.origin, ent->s.old_origin);
				ent->timestamp = level.time + 30;

				if (deathmatch->value)
				{
					ent->mass = best->mass / 4;
				}
				else
				{
					ent->mass = best->mass / 10;
				}

				/* ok spawn the food cube */
				ent->s.frame = 5;
			}
			else
			{
				BecomeExplosion1(ent);
				return;
			}
		}
	}
}
Example #30
0
// =================
// =================
void hunter_think (edict_t *self)
{
	edict_t *owner;
	vec3_t	dir, ang;

	// if we've exited the level, just remove ourselves.
	if (level.intermissiontime)
	{	
		sphere_think_explode(self);
		return;
	}	

	owner = self->owner;
	if(!owner && !(self->spawnflags & SPHERE_DOPPLEGANGER))
	{
//		gi.dprintf("think: no owner\n");
		G_FreeEdict(self);
		return;
	}

	if(owner)
		self->ideal_yaw = owner->s.angles[YAW];
	else if(self->enemy)		// fired by doppleganger
	{
		VectorSubtract(self->enemy->s.origin, self->s.origin, dir);
		vectoangles2(dir, ang);
		self->ideal_yaw = ang[YAW];
	}

	M_ChangeYaw(self);

//	if(level.time - self->timestamp > 1)
//	{
//		gi.sound (self, CHAN_VOICE, gi.soundindex ("powerup/hsphere.wav"), 0.5, ATTN_NORM, 0);
//		self->timestamp = level.time;
//	}

	if(self->enemy)
	{
		sphere_chase (self, 0);

		// deal with sam raimi cam
		if(owner && (owner->flags & FL_SAM_RAIMI)) 
		{
			if(self->inuse)
			{
				owner->movetype = MOVETYPE_FLYMISSILE;
//				VectorCopy(self->s.angles, owner->s.angles);
//				VectorCopy(self->s.angles, owner->client->v_angle);
				LookAtKiller (owner, self, self->enemy);
//				owner->viewheight = 22;

//				owner->client->v_angle[YAW]+=5;
				// owner is flying with us, move him too
				owner->movetype = MOVETYPE_FLYMISSILE;
				owner->viewheight = self->s.origin[2] - owner->s.origin[2];
//				VectorCopy(self->s.angles, owner->s.angles);
//				VectorCopy(self->s.angles, owner->client->v_angle);
				VectorCopy(self->s.origin, owner->s.origin);
				VectorCopy(self->velocity, owner->velocity);
				VectorClear(owner->mins);
				VectorClear(owner->maxs);
				gi.linkentity(owner);
			}
			else	// sphere timed out
			{
				VectorClear(owner->velocity);
				owner->movetype = MOVETYPE_NONE;
				gi.linkentity(owner);
			}
		}
	}
	else 
	{
//		self->ideal_yaw+=3;
//		M_ChangeYaw (self);
		sphere_fly (self);
	}

	if(self->inuse)
		self->nextthink = level.time + 0.1;
}