示例#1
0
void M_ReactToDamage(edict_t *targ, edict_t *attacker){
	if(!(attacker->client) && !(attacker->svflags & SVF_MONSTER))
		return;
		
	if(attacker == targ || attacker == targ->enemy)
		return;
		
	// if we are a good guy monster and our attacker is a player
	// or another good guy, do not get mad at them
	if(targ->monsterinfo.aiflags & AI_GOOD_GUY){
		if(attacker->client ||(attacker->monsterinfo.aiflags & AI_GOOD_GUY))
			return;
	}
	
	// we now know that we are not both good guys
	
	// if attacker is a client, get mad at them because he's good and we're not
	if(attacker->client){
		// this can only happen in coop(both new and old enemies are clients)
		// only switch if can't see the current enemy
		if(targ->enemy && targ->enemy->client){
			if(visible(targ, targ->enemy)){
				targ->oldenemy = attacker;
				return;
			}
			targ->oldenemy = targ->enemy;
		}
		targ->enemy = attacker;
		if(!(targ->monsterinfo.aiflags & AI_DUCKED))
			FoundTarget(targ);
		return;
	}
	
	// it's the same base(walk/swim/fly) type and a different classname and it's not a tank
	//(they spray too much), get mad at them
	if(((targ->flags &(FL_FLY | FL_SWIM)) ==(attacker->flags &(FL_FLY | FL_SWIM))) &&
			(strcmp(targ->classname, attacker->classname) != 0) &&
			(strcmp(attacker->classname, "monster_tank") != 0) &&
			(strcmp(attacker->classname, "monster_supertank") != 0) &&
			(strcmp(attacker->classname, "monster_makron") != 0) &&
			(strcmp(attacker->classname, "monster_jorg") != 0)){
		if(targ->enemy)
			if(targ->enemy->client)
				targ->oldenemy = targ->enemy;
		targ->enemy = attacker;
		if(!(targ->monsterinfo.aiflags & AI_DUCKED))
			FoundTarget(targ);
	} else
		// otherwise get mad at whoever they are mad at(help our buddy)
	{
		if(targ->enemy)
			if(targ->enemy->client)
				targ->oldenemy = targ->enemy;
		targ->enemy = attacker->enemy;
		FoundTarget(targ);
	}
}
示例#2
0
/*
=============
GetMadAtAttacker

T_Damage calls this when a monster is hurt
=============
*/
void GetMadAtAttacker( gedict_t *attacker )
{
	if ( !attacker || attacker == world )
		return; // ignore world attacks

	if ( k_bloodfest && attacker->ct != ctPlayer)
		return; // in bloodfest mode get mad only on players.

	if ( attacker == self )
		return; // do not mad on self.
	
	if ( attacker == PROG_TO_EDICT( self->s.v.enemy ))
		return; // alredy mad on this.

	// get mad unless of the same class (except for soldiers)
	if (   streq( self->s.v.classname, attacker->s.v.classname )
		&& strneq( self->s.v.classname, "monster_army" ) 
	)
		return; 

	// OK, we are MAD!

	// remember current enemy if it was "player enemy", later we restore it
	if ( PROG_TO_EDICT( self->s.v.enemy )->ct == ctPlayer )
		self->oldenemy = PROG_TO_EDICT( self->s.v.enemy );

	// set new enemy
	self->s.v.enemy = EDICT_TO_PROG( attacker );

	FoundTarget ();
}
void medic_run (edict_t *self)
{
	monster_done_dodge (self);
	if (!(self->monsterinfo.aiflags & AI_MEDIC))
	{
		edict_t	*ent;

		ent = medic_FindDeadMonster(self);
		if (ent)
		{
			self->oldenemy = self->enemy;
			self->enemy = ent;
			self->enemy->monsterinfo.healer = self;
			self->monsterinfo.aiflags |= AI_MEDIC;
			FoundTarget (self);
			return;
		}
	}
//	else if (!canReach(self, self->enemy))
//	{
//		abortHeal (self, 0);
//	}

	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
		self->monsterinfo.currentmove = &medic_move_stand;
	else
		self->monsterinfo.currentmove = &medic_move_run;
}
示例#4
0
void
medic_search(edict_t *self)
{
	edict_t *ent;

	if (!self)
	{
		return;
	}

	gi.sound(self, CHAN_VOICE, sound_search, 1, ATTN_IDLE, 0);

	if (!self->oldenemy)
	{
		ent = medic_FindDeadMonster(self);

		if (ent)
		{
			self->oldenemy = self->enemy;
			self->enemy = ent;
			self->enemy->owner = self;
			self->monsterinfo.aiflags |= AI_MEDIC;
			FoundTarget(self);
		}
	}
}
示例#5
0
文件: g_monster.c 项目: qbism/qbq2
/*
================
monster_use

Using a monster makes it angry at the current activator
================
*/
void monster_use (edict_t *self, edict_t *other, edict_t *activator)
{
	if (self->enemy)
		return;
	if (self->health <= 0)
		return;
	if (activator->flags & FL_NOTARGET)
		return;
	if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY))
		return;
	if (activator->flags & FL_DISGUISED)
		return;

	// if monster is "used" by player, turn off good guy stuff
	if (activator->client)
	{
		self->spawnflags &= ~SF_MONSTER_GOODGUY;
		self->monsterinfo.aiflags &= ~(AI_GOOD_GUY + AI_FOLLOW_LEADER);
		if(self->dmgteam && !Q_strcasecmp(self->dmgteam,"player"))
			self->dmgteam = NULL;
	}

// delay reaction so if the monster is teleported, its sound is still heard
	self->enemy = activator;
	FoundTarget (self);
}
示例#6
0
void
medic_run(edict_t *self)
{
	if (!self)
	{
		return;
	}

	if (!(self->monsterinfo.aiflags & AI_MEDIC))
	{
		edict_t *ent;

		ent = medic_FindDeadMonster(self);

		if (ent)
		{
			self->oldenemy = self->enemy;
			self->enemy = ent;
			self->enemy->owner = self;
			self->monsterinfo.aiflags |= AI_MEDIC;
			FoundTarget(self);
			return;
		}
	}

	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
	{
		self->monsterinfo.currentmove = &medic_move_stand;
	}
	else
	{
		self->monsterinfo.currentmove = &medic_move_run;
	}
}
示例#7
0
void monster_triggered_spawn(edict_t *self)
{
    self->s.origin[2] += 1;
    KillBox(self);

    self->solid        = SOLID_BBOX;
    self->movetype     = MOVETYPE_STEP;
    self->svflags     &= ~SVF_NOCLIENT;
    self->air_finished = level.time + 12;
    gi.linkentity(self);

    monster_start_go(self);

    if (self->enemy && !(self->spawnflags & SF_MONSTER_SIGHT) && !(self->enemy->flags & FL_NOTARGET))
    {
        if (!(self->enemy->flags & FL_DISGUISED))
        {
            FoundTarget(self);
        }
        else
        {
            self->enemy = NULL;
        }
    }
    else
    {
        self->enemy = NULL;
    }
}
示例#8
0
void
stalker_dodge(edict_t *self, edict_t *attacker, float eta, trace_t *tr /* unused */)
{
	if (!self || !attacker)
	{
		return;
	}

	if (!self->groundentity || (self->health <= 0))
	{
		return;
	}

	if (!self->enemy)
	{
		self->enemy = attacker;
		FoundTarget(self);
		return;
	}

	if ((eta < 0.1) || (eta > 5))
	{
		return;
	}

	/* this will override the foundtarget call of stalker_run */
	stalker_dodge_jump(self);
}
示例#9
0
文件: g_monster.c 项目: yquake2/zaero
void monster_triggered_spawn (edict_t *self)
{
	self->s.origin[2] += 1;
	MonsterKillBox (self);

	self->solid = SOLID_BBOX;
	self->movetype = MOVETYPE_STEP;
	self->svflags &= ~SVF_NOCLIENT;
	self->air_finished = level.time + 12;
	gi.linkentity (self);

	monster_start_go (self);

	if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET))
	{
		FoundTarget (self);
	}
	else
	{
		self->enemy = NULL;
	}

	// some sort of spawn effect
	// TODO good enough?
	self->s.event = EV_PLAYER_TELEPORT;
	MonsterPlayerKillBox(self);
}
示例#10
0
文件: m_medic.c 项目: qbism/qbq2
edict_t *medic_FindDeadMonster (edict_t *self)
{
	edict_t	*ent = NULL;
	edict_t	*best = NULL;

	while ((ent = findradius(ent, self->s.origin, 1024)) != NULL)
	{
		if (ent == self)
			continue;
		if (!(ent->svflags & SVF_MONSTER))
			continue;
		if (ent->monsterinfo.aiflags & AI_GOOD_GUY)
			continue;
		if (ent->owner)
			continue;
		if (ent->health > 0)
			continue;
		if (ent->nextthink && (ent->think != M_FliesOff) && (ent->think != M_FliesOn))
			continue;
		// check to make sure we haven't bailed on this guy already
		if ((ent->monsterinfo.badMedic1 == self) || (ent->monsterinfo.badMedic2 == self))
			continue;
		if (!visible(self, ent))
			continue;
		if (embedded(ent))
			continue;
		if (!canReach(self,ent))
			continue;
		if (!best)
		{
			best = ent;
			continue;
		}
		if (ent->max_health <= best->max_health)
			continue;
		best = ent;
	}

	if(best)
	{
		self->oldenemy = self->enemy;
		self->enemy = best;
		self->enemy->owner = best;
		self->monsterinfo.aiflags |= AI_MEDIC;
		self->monsterinfo.aiflags &= ~AI_MEDIC_PATROL;
		self->monsterinfo.medicTries = 0;
		self->movetarget = self->goalentity = NULL;
		self->enemy->monsterinfo.healer = self;
		self->timestamp = level.time + MEDIC_TRY_TIME;
		FoundTarget (self);

		if(developer->value)
			gi.dprintf("medic found dead monster: %s at %s\n",
			best->classname,vtos(best->s.origin));

	}
	return best;
}
示例#11
0
/*
================
monster_use
 
Using a monster makes it angry at the current activator
================
*/
void monster_use(edict_t *self, edict_t *other, edict_t *activator){
	if(self->enemy)
		return;
	if(self->health <= 0)
		return;
	if(activator->flags & FL_NOTARGET)
		return;
	if(!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY))
		return;
		
	// delay reaction so if the monster is teleported, its sound is still heard
	self->enemy = activator;
	FoundTarget(self);
}
示例#12
0
void medic_idle(edict_t * self)
{
	edict_t *ent;

	gi.sound(self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);

	ent = medic_FindDeadMonster(self);
	if (ent) {
		self->enemy = ent;
		self->enemy->owner = self;
		self->monsterinfo.aiflags |= AI_MEDIC;
		FoundTarget(self);
	}
}
示例#13
0
void
WidowSpawn(edict_t *self)
{
	vec3_t f, r, u, offset, startpoint, spawnpoint;
	edict_t *ent, *designated_enemy;
	int i;

	if (!self)
	{
		return;
	}

	AngleVectors(self->s.angles, f, r, u);

	for (i = 0; i < 2; i++)
	{
		VectorCopy(spawnpoints[i], offset);

		G_ProjectSource2(self->s.origin, offset, f, r, u, startpoint);

		if (FindSpawnPoint(startpoint, stalker_mins, stalker_maxs, spawnpoint,
					64))
		{
			ent = CreateGroundMonster(spawnpoint, self->s.angles, stalker_mins, stalker_maxs,
					"monster_stalker", 256);

			if (!ent)
			{
				continue;
			}

			self->monsterinfo.monster_used++;
			ent->monsterinfo.commander = self;
			ent->nextthink = level.time;
			ent->think(ent);

			ent->monsterinfo.aiflags |= /* AI_SPAWNED_WIDOW | */ AI_DO_NOT_COUNT | AI_IGNORE_SHOTS;

			designated_enemy = self->enemy;

			if ((designated_enemy->inuse) && (designated_enemy->health > 0))
			{
				ent->enemy = designated_enemy;
				FoundTarget(ent);
				ent->monsterinfo.attack(ent);
			}
		}
	}
}
示例#14
0
文件: fixbot.c 项目: DrItanium/xatrix
int fixbot_search (edict_t *self)
{
	edict_t	*ent;

	if (!self->goalentity)
	{
		ent = fixbot_FindDeadMonster(self);
		if (ent)
		{
			self->oldenemy = self->enemy;
			self->enemy = ent;
			self->enemy->owner = self;
			self->monsterinfo.aiflags |= AI_MEDIC;
			FoundTarget (self);
			return (1);
		}
	}
	return (0);
}
示例#15
0
/*
=====================
hintpath_stop

Makes a monster stop following hint_paths.
=====================
*/
void hintpath_stop (edict_t *monster)
{
	monster->movetarget = monster->goalentity = NULL;
	monster->monsterinfo.last_hint_time = level.time;
	monster->monsterinfo.goal_hint = NULL;
	monster->monsterinfo.aiflags &= ~AI_HINT_PATH;

	// If we don't have an enemy to get mad at, just stand around like an unactivated monster.
	if (!has_valid_enemy(monster))
	{
		monster->enemy = NULL;
		monster->monsterinfo.pausetime = level.time + 100000000;
		monster->monsterinfo.stand (monster);
	}
	else if (visible(monster, monster->enemy)) 	// attack if we can see our foe
		FoundTarget (monster);
	else // keep pursuing
		HuntTarget (monster);
}
示例#16
0
文件: m_stalker.c 项目: ZwS/qudos
void stalker_dodge (edict_t *self, edict_t *attacker, float eta, trace_t *tr)
{
	if (!self->groundentity || self->health <= 0)
		return;

	if (!self->enemy)
	{
		self->enemy = attacker;
		FoundTarget(self);
		return;
	}
	
	// PMM - don't bother if it's going to hit anyway; fix for weird in-your-face etas (I was
	// seeing numbers like 13 and 14)
	if ((eta < 0.1) || (eta > 5))
		return;

	// this will override the foundtarget call of stalker_run
	stalker_dodge_jump(self);
}
示例#17
0
文件: m_medic.c 项目: qbism/qbq2
void medic_StopPatrolling (edict_t *self)
{
	self->goalentity = NULL;
	self->movetarget = NULL;
	self->monsterinfo.aiflags &= ~AI_MEDIC_PATROL;
	if (!(self->monsterinfo.aiflags & AI_MEDIC))
	{
		if(medic_FindDeadMonster(self))
			return;
	}
	if (has_valid_enemy(self))
	{
		if (visible(self, self->enemy))
		{
			FoundTarget (self);
			return;
		}
		HuntTarget (self);
		return;
	}
	if(self->monsterinfo.aiflags & AI_MEDIC)
		abortHeal(self,false);
}
示例#18
0
void medic_search (edict_t *self)
{
	edict_t	*ent;

	// PMM - commander sounds
	if (self->mass == 400)
		gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_IDLE, 0);
	else
		gi.sound (self, CHAN_VOICE, commander_sound_search, 1, ATTN_IDLE, 0);

	if (!self->oldenemy)
	{
		ent = medic_FindDeadMonster(self);
		if (ent)
		{
			self->oldenemy = self->enemy;
			self->enemy = ent;
			self->enemy->monsterinfo.healer = self;
			self->monsterinfo.aiflags |= AI_MEDIC;
			FoundTarget (self);
		}
	}
}
示例#19
0
//-----------------------------------------------------------------------------
// Look for a target
//-----------------------------------------------------------------------------
bool CObjectSentrygun::FindTarget()
{
	// Disable the sentry guns for ifm.
	if ( tf_sentrygun_notarget.GetBool() )
		return false;

	if ( IsInCommentaryMode() )
		return false;

	// Sapper, etc.
	if ( IsDisabled() )
		return false;

	// Loop through players within 1100 units (sentry range).
	Vector vecSentryOrigin = EyePosition();

	// Find the opposing team list.
	CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
	CUtlVector<CTFTeam *> pTeamList;
	CTFTeam *pTeam = NULL;

	//CTFTeam *pTeam = pPlayer->GetOpposingTFTeam();
	//if ( !pTeam )
	//	return false;

	if ( pPlayer )
	{
		// Try builder's team.
		pTeam = pPlayer->GetTFTeam();
	}
	else
	{
		// If we have no builder use our own team number instead.
		pTeam = GetTFTeam();
	}

	if ( pTeam )
		pTeam->GetOpposingTFTeamList( &pTeamList );
	else
		return false;

	// If we have an enemy get his minimum distance to check against.
	Vector vecSegment;
	Vector vecTargetCenter;
	float flMinDist2 = 1100.0f * 1100.0f;
	CBaseEntity *pTargetCurrent = NULL;
	CBaseEntity *pTargetOld = m_hEnemy.Get();
	float flOldTargetDist2 = FLT_MAX;

	// Sentries will try to target players first, then objects.  However, if the enemy held was an object it will continue
	// to try and attack it first.

	for (int i = 0; i < pTeamList.Size(); i++)
	{
		int nTeamCount = pTeamList[i]->GetNumPlayers();
		for (int iPlayer = 0; iPlayer < nTeamCount; ++iPlayer)
		{
			CTFPlayer *pTargetPlayer = static_cast<CTFPlayer*>(pTeamList[i]->GetPlayer(iPlayer));
			if (pTargetPlayer == NULL)
				continue;

			// Make sure the player is alive.
			if (!pTargetPlayer->IsAlive())
				continue;

			if (pTargetPlayer->GetFlags() & FL_NOTARGET)
				continue;

			vecTargetCenter = pTargetPlayer->GetAbsOrigin();
			vecTargetCenter += pTargetPlayer->GetViewOffset();
			VectorSubtract(vecTargetCenter, vecSentryOrigin, vecSegment);
			float flDist2 = vecSegment.LengthSqr();

			// Store the current target distance if we come across it
			if (pTargetPlayer == pTargetOld)
			{
				flOldTargetDist2 = flDist2;
			}

			// Check to see if the target is closer than the already validated target.
			if (flDist2 > flMinDist2)
				continue;

			// It is closer, check to see if the target is valid.
			if (ValidTargetPlayer(pTargetPlayer, vecSentryOrigin, vecTargetCenter))
			{
				flMinDist2 = flDist2;
				pTargetCurrent = pTargetPlayer;
			}
		}

		// If we already have a target, don't check objects.
		if (pTargetCurrent == NULL)
		{
			int nTeamObjectCount = pTeamList[i]->GetNumObjects();
			for (int iObject = 0; iObject < nTeamObjectCount; ++iObject)
			{
				CBaseObject *pTargetObject = pTeamList[i]->GetObject(iObject);
				if (!pTargetObject)
					continue;

				vecTargetCenter = pTargetObject->GetAbsOrigin();
				vecTargetCenter += pTargetObject->GetViewOffset();
				VectorSubtract(vecTargetCenter, vecSentryOrigin, vecSegment);
				float flDist2 = vecSegment.LengthSqr();

				// Store the current target distance if we come across it
				if (pTargetObject == pTargetOld)
				{
					flOldTargetDist2 = flDist2;
				}

				// Check to see if the target is closer than the already validated target.
				if (flDist2 > flMinDist2)
					continue;

				// It is closer, check to see if the target is valid.
				if (ValidTargetObject(pTargetObject, vecSentryOrigin, vecTargetCenter))
				{
					flMinDist2 = flDist2;
					pTargetCurrent = pTargetObject;
				}
			}
		}
		// We have a target.
		if (pTargetCurrent)
		{
			if (pTargetCurrent != pTargetOld)
			{
				// flMinDist2 is the new target's distance
				// flOldTargetDist2 is the old target's distance
				// Don't switch unless the new target is closer by some percentage
				if (flMinDist2 < (flOldTargetDist2 * 0.75f))
				{
					FoundTarget(pTargetCurrent, vecSentryOrigin);
				}
			}
			return true;
		}
	}

	return false;
}
示例#20
0
/*
===============
PlayerNoise

Each player can have two noise objects associated with it:
a personal noise (jumping, pain, weapon firing), and a weapon
target noise (bullet wall impacts)

Monsters that don't directly see the player can move
to a noise in hopes of seeing the player from there.
===============
*/
void PlayerNoise(edict_t *who, vec3_t where, int type) {
	edict_t		*noise;
	edict_t		*blip = NULL;
return;
	if (deathmatch->value && !dmmonsters->value)
		return;

	if (who->flags & FL_NOTARGET)
		return;

	if (type == PNOISE_WEAPON) {
		if (who->client->silencer_shots > 0) {
			who->client->silencer_shots--;
			return;
		} else {
			who->client->silencer_shots = 0;
		}
	}

	if (!who->mynoise) {
		noise = G_Spawn();
		noise->classid = CI_P_NOISE;
		noise->classname = "player noise";
		VectorSet (noise->mins, -8, -8, -8);
		VectorSet (noise->maxs, 8, 8, 8);
		noise->owner = who;
		noise->svflags = SVF_NOCLIENT;
		who->mynoise = noise;

		noise = G_Spawn();
		noise->classid = CI_P_NOISE;
		noise->classname = "player noise";
		VectorSet (noise->mins, -8, -8, -8);
		VectorSet (noise->maxs, 8, 8, 8);
		noise->owner = who;
		noise->svflags = SVF_NOCLIENT;
		who->mynoise2 = noise;
	}

	// Zheele
	while ((blip = findradius(blip, where, 750)) != NULL) {
		if (!blip->inuse)
			continue;
		if (!blip->takedamage)
			continue;
		if (!(blip->svflags & SVF_MONSTER) || (blip->monsterinfo.aiflags & AI_GOOD_GUY))
			continue;
		if ((!blip->monsterinfo.aggressive) && (deathmatch->value) && (game.craze != 10) && (game.monsterhunt != 10))
			continue;
		if (blip->enemy)
			continue;
		if (((float) pow(who->radius_dmg, GIEX_MONSTER_PLAYERLEVEL_MULT_POW) * GIEX_MONSTER_PLAYERLEVEL_MULT) < ((float) blip->monsterinfo.skill * 0.75) && (game.monsterhunt != 10)) {
			continue;
		}
		blip->enemy = who;
		FoundTarget(blip);
		if (!(blip->monsterinfo.aiflags & AI_SOUND_TARGET) && (blip->monsterinfo.sight))
			blip->monsterinfo.sight (blip, blip->enemy);
	}

	if (type == PNOISE_SELF || type == PNOISE_WEAPON)
	{
		noise = who->mynoise;
		level.sound_entity = noise;
		level.sound_entity_framenum = level.framenum;
	}
	else // type == PNOISE_IMPACT
	{
		noise = who->mynoise2;
		level.sound2_entity = noise;
		level.sound2_entity_framenum = level.framenum;
	}

	VectorCopy (where, noise->s.origin);
	VectorSubtract (where, noise->maxs, noise->absmin);
	VectorAdd (where, noise->maxs, noise->absmax);
	noise->teleport_time = level.time;
	gi.linkentity (noise);
}
示例#21
0
void
medic_cable_attack(edict_t *self)
{
	vec3_t offset, start, end, f, r;
	trace_t tr;
	vec3_t dir, angles;
	float distance;

	if (!self)
	{
		return;
	}

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

	AngleVectors(self->s.angles, f, r, NULL);
	VectorCopy(medic_cable_offsets[self->s.frame - FRAME_attack42], offset);
	G_ProjectSource(self->s.origin, offset, f, r, start);

	/* check for max distance */
	VectorSubtract(start, self->enemy->s.origin, dir);
	distance = VectorLength(dir);

	if (distance > 256)
	{
		return;
	}

	/* check for min/max pitch */
	vectoangles(dir, angles);

	if (angles[0] < -180)
	{
		angles[0] += 360;
	}

	if (fabs(angles[0]) > 45)
	{
		return;
	}

	tr = gi.trace(start, NULL, NULL, self->enemy->s.origin, self, MASK_SHOT);

	if ((tr.fraction != 1.0) && (tr.ent != self->enemy))
	{
		return;
	}

	if (self->s.frame == FRAME_attack43)
	{
		gi.sound(self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0);
		self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
	}
	else if (self->s.frame == FRAME_attack50)
	{
		self->enemy->spawnflags = 0;
		self->enemy->monsterinfo.aiflags = 0;
		self->enemy->target = NULL;
		self->enemy->targetname = NULL;
		self->enemy->combattarget = NULL;
		self->enemy->deathtarget = NULL;
		self->enemy->owner = self;
		ED_CallSpawn(self->enemy);
		self->enemy->owner = NULL;

		if (self->enemy->think)
		{
			self->enemy->nextthink = level.time;
			self->enemy->think(self->enemy);
		}

		self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;

		if (self->oldenemy && self->oldenemy->client)
		{
			self->enemy->enemy = self->oldenemy;
			FoundTarget(self->enemy);
		}
	}
	else
	{
		if (self->s.frame == FRAME_attack44)
		{
			gi.sound(self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0);
		}
	}

	/* adjust start for beam origin being in middle of a segment */
	VectorMA(start, 8, f, start);

	/* adjust end z for end spot since the monster is currently dead */
	VectorCopy(self->enemy->s.origin, end);
	end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2;

	gi.WriteByte(svc_temp_entity);
	gi.WriteByte(TE_MEDIC_CABLE_ATTACK);
	gi.WriteShort(self - g_edicts);
	gi.WritePosition(start);
	gi.WritePosition(end);
	gi.multicast(self->s.origin, MULTICAST_PVS);
}
示例#22
0
文件: m_medic.c 项目: qbism/qbq2
qboolean medic_checkattack (edict_t *self)
{
	if (!(self->monsterinfo.aiflags & AI_MEDIC))
	{
		if( medic_FindDeadMonster(self) )
			return false;
	}

	if (self->monsterinfo.aiflags & AI_MEDIC)
	{
		float	r;
		vec3_t	forward, right, offset, start;
		trace_t	tr;

		// if we have 5 seconds or less before a timeout,
		// look for a hint_path to the target
		if ( (self->timestamp < level.time + 5) &&
			 (self->monsterinfo.last_hint_time + 5 < level.time) )
		{
			// check for hint_paths.
			self->monsterinfo.last_hint_time = level.time;
			if (hintcheck_monsterlost(self))
			{
				if(developer->value)
					gi.dprintf("medic at %s using hint_paths to find %s\n",
					vtos(self->s.origin), self->enemy->classname);
				self->timestamp = level.time + MEDIC_TRY_TIME;
				return false;
			}
		}

		// if we ran out of time, give up
		if (self->timestamp < level.time)
		{
			//if(developer->value)
			//	gi.dprintf("medic at %s timed out, abort heal\n",vtos(self->s.origin));
			abortHeal (self, true);
			self->timestamp = 0;
			return false;
		}
		
		// if our target went away
		if ((!self->enemy) || (!self->enemy->inuse)) {
			abortHeal (self,false);
			return false;
		}
		// if target is embedded in a solid
		if (embedded(self->enemy))
		{
			abortHeal (self,false);
			return false;
		}
		r = realrange(self,self->enemy);
		if (r > MEDIC_MAX_HEAL_DISTANCE+10) {
			self->monsterinfo.attack_state = AS_STRAIGHT;
			//abortHeal(self,false);
			return false;
		} else if(r < MEDIC_MIN_DISTANCE) {
			abortHeal(self,false);
			return false;
		}
		// Lazarus 1.6.2.3: if point-to-point vector from cable to
		// target is blocked by a solid
		AngleVectors (self->s.angles, forward, right, NULL);
		// Offset [8] has the largest displacement to the left... not a sure
		// thing but this one should be the most severe test.
		VectorCopy (medic_cable_offsets[8], offset);
		G_ProjectSource (self->s.origin, offset, forward, right, start);
		tr = gi.trace(start,NULL,NULL,self->enemy->s.origin,self,MASK_SHOT|MASK_WATER);
		if (tr.fraction < 1.0 && tr.ent != self->enemy)
			return false;
		medic_attack(self);
		return true;
	}

	// Lazarus: NEVER attack other monsters
	if ((self->enemy) && (self->enemy->svflags & SVF_MONSTER))
	{
		self->enemy = self->oldenemy;
		self->oldenemy = NULL;
		if(self->enemy && self->enemy->inuse)
		{
			if(visible(self,self->enemy))
				FoundTarget(self);
			else
				HuntTarget(self);
		}
		return false;
	}

	return M_CheckAttack (self);
}
示例#23
0
void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
{
    // pmm
    qboolean new_tesla;

    if (!(attacker->client) && !(attacker->svflags & SVF_MONSTER))
        return;

    //=======
    //ROGUE
    // logic for tesla - if you are hit by a tesla, and can't see who you should be mad at (attacker)
    // attack the tesla
    // also, target the tesla if it's a "new" tesla
    if ((inflictor) && (!strcmp(inflictor->classname, "tesla")))
    {
        new_tesla = MarkTeslaArea(targ, inflictor);
        if (new_tesla)
            TargetTesla (targ, inflictor);
        return;
    }
    //ROGUE
    //=======

    if (attacker == targ || attacker == targ->enemy)
        return;

    // if we are a good guy monster and our attacker is a player
    // or another good guy, do not get mad at them
    if (targ->monsterinfo.aiflags & AI_GOOD_GUY)
    {
        if (attacker->client || (attacker->monsterinfo.aiflags & AI_GOOD_GUY))
            return;
    }

    //PGM
    // if we're currently mad at something a target_anger made us mad at, ignore
    // damage
    if (targ->enemy && targ->monsterinfo.aiflags & AI_TARGET_ANGER)
    {
        float	percentHealth;

        // make sure whatever we were pissed at is still around.
        if(targ->enemy->inuse)
        {
            percentHealth = (float)(targ->health) / (float)(targ->max_health);
            if( targ->enemy->inuse && percentHealth > 0.33)
                return;
        }

        // remove the target anger flag
        targ->monsterinfo.aiflags &= ~AI_TARGET_ANGER;
    }
    //PGM

    // PMM
    // if we're healing someone, do like above and try to stay with them
    if ((targ->enemy) && (targ->monsterinfo.aiflags & AI_MEDIC))
    {
        float	percentHealth;

        percentHealth = (float)(targ->health) / (float)(targ->max_health);
        // ignore it some of the time
        if( targ->enemy->inuse && percentHealth > 0.25)
            return;

        // remove the medic flag
        targ->monsterinfo.aiflags &= ~AI_MEDIC;
        cleanupHealTarget (targ->enemy);
    }
    // PMM

    // we now know that we are not both good guys

    // if attacker is a client, get mad at them because he's good and we're not
    if (attacker->client)
    {
        targ->monsterinfo.aiflags &= ~AI_SOUND_TARGET;

        // this can only happen in coop (both new and old enemies are clients)
        // only switch if can't see the current enemy
        if (targ->enemy && targ->enemy->client)
        {
            if (visible(targ, targ->enemy))
            {
                targ->oldenemy = attacker;
                return;
            }
            targ->oldenemy = targ->enemy;
        }
        targ->enemy = attacker;
        if (!(targ->monsterinfo.aiflags & AI_DUCKED))
            FoundTarget (targ);
        return;
    }

    // it's the same base (walk/swim/fly) type and a different classname and it's not a tank
    // (they spray too much), get mad at them
    // PMM
    // added medics to this
    // FIXME -
    // this really should be turned into an AI flag marking appropriate monsters as "don't shoot me"
    //   this also leads to the problem of tanks and medics being able to, at will, kill monsters with
    //   no chance of retaliation.  My vote is to make those monsters who are designed as "don't shoot me"
    //   such that they also ignore being shot by monsters as well
    if (((targ->flags & (FL_FLY|FL_SWIM)) == (attacker->flags & (FL_FLY|FL_SWIM))) &&
            (strcmp (targ->classname, attacker->classname) != 0) &&
            !(attacker->monsterinfo.aiflags & AI_IGNORE_SHOTS) &&
            !(targ->monsterinfo.aiflags & AI_IGNORE_SHOTS) )
    {
        if (targ->enemy && targ->enemy->client)
            targ->oldenemy = targ->enemy;
        targ->enemy = attacker;
        if (!(targ->monsterinfo.aiflags & AI_DUCKED))
            FoundTarget (targ);
    }
    // if they *meant* to shoot us, then shoot back
    else if (attacker->enemy == targ)
    {
        if (targ->enemy && targ->enemy->client)
            targ->oldenemy = targ->enemy;
        targ->enemy = attacker;
        if (!(targ->monsterinfo.aiflags & AI_DUCKED))
            FoundTarget (targ);
    }
    // otherwise get mad at whoever they are mad at (help our buddy) unless it is us!
    else if (attacker->enemy && attacker->enemy != targ)
    {
        if (targ->enemy && targ->enemy->client)
            targ->oldenemy = targ->enemy;
        targ->enemy = attacker->enemy;
        if (!(targ->monsterinfo.aiflags & AI_DUCKED))
            FoundTarget (targ);
    }
}
示例#24
0
void thing_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
	if(self->target_ent != other)
		return;
	if(other->health <= 0)
	{
		G_FreeEdict(self);
		return;
	}
	self->touch = NULL;
	if( self->target_ent->monsterinfo.aiflags & AI_SEEK_COVER )
	{
		edict_t	*monster;
		// For monster/actor seeking cover after firing, 
		// pause a random bit before resuming attack
		self->touch_debounce_time = level.time + random()*6.;
		monster = self->target_ent;
		monster->monsterinfo.stand(monster);
		monster->monsterinfo.pausetime = self->touch_debounce_time;
		self->think = thing_think_pause;
		self->think(self);
		return;
	}
	if( self->target_ent->monsterinfo.aiflags & AI_EVADE_GRENADE )
	{
		edict_t	*grenade = other->next_grenade;

		if(other->goalentity == self)
			other->goalentity = NULL;
		if(other->movetarget == self)
			other->movetarget = NULL;
		other->vehicle = NULL;
		if(grenade)
		{
			// make sure this is still a grenade
			if(grenade->inuse)
			{
				if(Q_strcasecmp(grenade->classname,"grenade") && Q_strcasecmp(grenade->classname,"hgrenade"))
					other->next_grenade = grenade = NULL;
			}
			else
				other->next_grenade = grenade = NULL;
		}
		if(grenade)
		{
			if(self->touch_debounce_time > level.time)
			{
				other->monsterinfo.pausetime = self->touch_debounce_time + 0.1;
				other->monsterinfo.aiflags |= AI_STAND_GROUND;
				other->monsterinfo.stand(other);
			}
			else
				other->monsterinfo.pausetime = 0;

			other->enemy = grenade->owner;
			if (has_valid_enemy(other))
			{
				other->goalentity = other->enemy;
				if (visible(other, other->enemy))
					FoundTarget (other);
				else
					HuntTarget (other);
			}
			else
			{
				other->enemy = NULL;
				other->monsterinfo.stand (other);
			}
			if(other->monsterinfo.pausetime > 0)
			{
				self->think = thing_grenade_boom;
				self->nextthink = other->monsterinfo.pausetime;
				return;
			}
			other->monsterinfo.aiflags &= ~(AI_CHASE_THING | AI_EVADE_GRENADE);
		}
		else if (has_valid_enemy(other))
		{
			other->monsterinfo.aiflags &= ~(AI_CHASE_THING | AI_EVADE_GRENADE);
			other->goalentity = other->enemy;
			if (visible(other, other->enemy))
				FoundTarget (other);
			else
				HuntTarget (other);
		}
		else
		{
			other->enemy = NULL;
			other->monsterinfo.pausetime = level.time + 100000000;
			other->monsterinfo.aiflags &= ~(AI_CHASE_THING | AI_EVADE_GRENADE);
			other->monsterinfo.stand (other);
		}
		G_FreeEdict(self);
		return;
	}
	self->touch_debounce_time = 0;
	thing_think(self);
}
示例#25
0
void medic_cable_attack (edict_t *self)
{
	vec3_t	offset, start, end, f, r;
	trace_t	tr;
	vec3_t	dir;
//	vec3_t  angles;
	float	distance;

	if ((!self->enemy) || (!self->enemy->inuse) || (self->enemy->s.effects & EF_GIB))
	{
//		if ((g_showlogic) && (g_showlogic->value))
//			gi.dprintf ("medic_commander - aborting heal due to target's disappearance\n");
		abortHeal (self, true, false, false);
		return;
	}

	// see if our enemy has changed to a client, or our target has more than 0 health,
	// abort it .. we got switched to someone else due to damage
	if ((self->enemy->client) || (self->enemy->health > 0))
	{
		abortHeal (self, true, false, false);
		return;
	}
	AngleVectors (self->s.angles, f, r, NULL);
	VectorCopy (medic_cable_offsets[self->s.frame - FRAME_attack42], offset);
	G_ProjectSource (self->s.origin, offset, f, r, start);

	// check for max distance
	// not needed, done in checkattack
	// check for min distance
	VectorSubtract (start, self->enemy->s.origin, dir);
	distance = VectorLength(dir);
	if (distance < MEDIC_MIN_DISTANCE)
	{
//		if ((g_showlogic) && (g_showlogic->value))
//			gi.dprintf ("medic_commander - aborting heal due to proximity to target ");
		abortHeal (self, true, true, false );
		return;
	}
//	if ((g_showlogic)&&(g_showlogic->value))
//		gi.dprintf ("distance to target is %f\n", distance);
//	if (distance > 300)
//		return;

	// check for min/max pitch
	// PMM -- took out since it doesn't look bad when it fails
//	vectoangles (dir, angles);
//	if (angles[0] < -180)
//		angles[0] += 360;
//	if (fabs(angles[0]) > 45)
//	{
//		if ((g_showlogic) && (g_showlogic->value))
//			gi.dprintf ("medic_commander - aborting heal due to bad angle\n");
//		abortHeal(self);
//		return;
//	}

	tr = gi.trace (start, NULL, NULL, self->enemy->s.origin, self, MASK_SOLID);
	if (tr.fraction != 1.0 && tr.ent != self->enemy)
	{
		if (tr.ent == world)
		{
			// give up on second try
			if (self->monsterinfo.medicTries > 1)
			{
				abortHeal (self, true, false, true);
				return;
			}
			self->monsterinfo.medicTries++;
			cleanupHeal (self, 1);
			return;
		}
//		if ((g_showlogic) && (g_showlogic->value))
//			gi.dprintf ("medic_commander - aborting heal due to beamus interruptus\n");
		abortHeal (self, true, false, false);
		return;
	}

	if (self->s.frame == FRAME_attack43)
	{
		// PMM - commander sounds
		if (self->mass == 400)
			gi.sound (self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0);
		else
			gi.sound (self->enemy, CHAN_AUTO, commander_sound_hook_hit, 1, ATTN_NORM, 0);

		self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
		self->enemy->takedamage = DAMAGE_NO;
		M_SetEffects (self->enemy);
	}
	else if (self->s.frame == FRAME_attack50)
	{
		vec3_t	maxs;
		self->enemy->spawnflags = 0;
		self->enemy->monsterinfo.aiflags = 0;
		self->enemy->target = NULL;
		self->enemy->targetname = NULL;
		self->enemy->combattarget = NULL;
		self->enemy->deathtarget = NULL;
		self->enemy->monsterinfo.healer = self;

		VectorCopy (self->enemy->maxs, maxs);
		maxs[2] += 48;   // compensate for change when they die

		tr = gi.trace (self->enemy->s.origin, self->enemy->mins, maxs, self->enemy->s.origin, self->enemy, MASK_MONSTERSOLID);
		if (tr.startsolid || tr.allsolid)
		{
//			if ((g_showlogic) && (g_showlogic->value))
//				gi.dprintf ("Spawn point obstructed, aborting heal!\n");
			abortHeal (self, true, true, false);
			return;
		} 
		else if (tr.ent != world)
		{
//			if ((g_showlogic) && (g_showlogic->value))
//				gi.dprintf("heal in entity %s\n", tr.ent->classname);
			abortHeal (self, true, true, false);
			return;
		}
/*		else if (tr.ent == world)
		{
			if ((g_showlogic) && (g_showlogic->value))
				gi.dprintf ("heal in world, aborting!\n");
			abortHeal (self, 1);
			return;
		}
*/		else
		{
			self->enemy->monsterinfo.aiflags |= AI_DO_NOT_COUNT;
			ED_CallSpawn (self->enemy);

			if (self->enemy->think)
			{
				self->enemy->nextthink = level.time;
				self->enemy->think (self->enemy);
			}
	//		self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
			self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING;
			self->enemy->monsterinfo.aiflags |= AI_IGNORE_SHOTS|AI_DO_NOT_COUNT;
			// turn off flies
			self->enemy->s.effects &= ~EF_FLIES;
			self->enemy->monsterinfo.healer = NULL;

			if ((self->oldenemy) && (self->oldenemy->inuse) && (self->oldenemy->health > 0))
			{
//				if ((g_showlogic) && (g_showlogic->value))
//					gi.dprintf ("setting heal target's enemy to %s\n", self->oldenemy->classname);
				self->enemy->enemy = self->oldenemy;
//				HuntTarget (self->enemy);
				FoundTarget (self->enemy);
			}
			else
			{
//				if (g_showlogic && g_showlogic->value)
//					gi.dprintf ("no valid enemy to set!\n");
				self->enemy->enemy = NULL;
				if (!FindTarget (self->enemy))
				{
					// no valid enemy, so stop acting
					self->enemy->monsterinfo.pausetime = level.time + 100000000;
					self->enemy->monsterinfo.stand (self->enemy);
				}
				self->enemy = NULL;
				self->oldenemy = NULL;
				if (!FindTarget (self))
				{
					// no valid enemy, so stop acting
					self->monsterinfo.pausetime = level.time + 100000000;
					self->monsterinfo.stand (self);
					return;
				}
			}
		}
	}
	else
	{
		if (self->s.frame == FRAME_attack44)
			// PMM - medic commander sounds
			if (self->mass == 400)
				gi.sound (self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0);
			else
				gi.sound (self, CHAN_WEAPON, commander_sound_hook_heal, 1, ATTN_NORM, 0);
	}

	// adjust start for beam origin being in middle of a segment
	VectorMA (start, 8, f, start);

	// adjust end z for end spot since the monster is currently dead
	VectorCopy (self->enemy->s.origin, end);
	end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2;

	gi.WriteByte (svc_temp_entity);
	gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
	gi.WriteShort (self - g_edicts);
	gi.WritePosition (start);
	gi.WritePosition (end);
	gi.multicast (self->s.origin, MULTICAST_PVS);
}
示例#26
0
void medic_finish_spawn (edict_t *self)
{
	edict_t *ent;
	vec3_t	f, r, offset, startpoint, spawnpoint;
	int		summonStr;
	int		count;
	int		inc;
	int		num_summoned; // should be 1, 3, or 5
	qboolean	behind = false;
	edict_t	*designated_enemy;

//	trace_t		tr;
//	vec3_t mins, maxs;

	// this is one bigger than the soldier's real mins .. just for paranoia's sake
//	VectorSet (mins, -17, -17, -25);
//	VectorSet (maxs, 17, 17, 33);

	//FIXME - better place to store this info?
	if (self->plat2flags < 0)
	{
		behind = true;
		self->plat2flags *= -1;
	}
	summonStr = self->plat2flags;

	AngleVectors (self->s.angles, f, r, NULL);

//	num_summoned = ((((summonStr-1)/2)+1)*2)-1;  // this yields either 1, 3, or 5
	if (summonStr)
		num_summoned = (summonStr - 1) + (summonStr % 2);
	else
		num_summoned = 1;

//	if ((g_showlogic) && (g_showlogic->value))
//		gi.dprintf ("medic_commander: summonStr = %d num = %d\n", summonStr, num_summoned);

	for (count = 0; count < num_summoned; count++)
	{
		inc = count + (count%2); // 0, 2, 2, 4, 4
		VectorCopy (reinforcement_position[count], offset);

		G_ProjectSource (self->s.origin, offset, f, r, startpoint);

		// a little off the ground
		startpoint[2] += 10;

		ent = NULL;
		if (FindSpawnPoint (startpoint, reinforcement_mins[summonStr-inc], reinforcement_maxs[summonStr-inc], spawnpoint, 32))
		{
			if (CheckSpawnPoint (spawnpoint, reinforcement_mins[summonStr-inc], reinforcement_maxs[summonStr-inc]))
				ent = CreateGroundMonster (spawnpoint, self->s.angles,
					reinforcement_mins[summonStr-inc], reinforcement_maxs[summonStr-inc],
					reinforcements[summonStr-inc], 256);
//			else if ((g_showlogic) && (g_showlogic->value))
//				gi.dprintf ("CheckSpawnPoint failed volume check!\n");
		}
		else
		{
//			if ((g_showlogic) && (g_showlogic->value))
//				gi.dprintf ("FindSpawnPoint failed to find a point!\n");
		}

		if (!ent)
		{
//			if ((g_showlogic) && (g_showlogic->value))
//				gi.dprintf ("Spawn point obstructed for %s, aborting!\n", reinforcements[summonStr-inc]);
			continue;
		}

//		gi.sound (self, CHAN_WEAPON, commander_sound_spawn, 1, ATTN_NORM, 0);

		if (ent->think)
		{
			ent->nextthink = level.time;
			ent->think (ent);
		}

		ent->monsterinfo.aiflags |= AI_IGNORE_SHOTS|AI_DO_NOT_COUNT|AI_SPAWNED_MEDIC_C;
		ent->monsterinfo.commander = self;
		self->monsterinfo.monster_slots--;
//		if ((g_showlogic) && (g_showlogic->value))
//			gi.dprintf ("medic_commander: %d slots remaining\n", self->monsterinfo.monster_slots);

		if (self->monsterinfo.aiflags & AI_MEDIC)
			designated_enemy = self->oldenemy;
		else
			designated_enemy = self->enemy;

		if (coop && coop->value)
		{
			designated_enemy = PickCoopTarget(ent);
			if (designated_enemy)
			{
				// try to avoid using my enemy
				if (designated_enemy == self->enemy)
				{
					designated_enemy = PickCoopTarget(ent);
					if (designated_enemy)
					{
//						if ((g_showlogic) && (g_showlogic->value))
//						{
//							gi.dprintf ("PickCoopTarget returned a %s - ", designated_enemy->classname);
//							if (designated_enemy->client)
//								gi.dprintf ("with name %s\n", designated_enemy->client->pers.netname);
//							else
//								gi.dprintf ("NOT A CLIENT\n");
//						}
					}
					else
					{
//						if ((g_showlogic) && (g_showlogic->value))
//							gi.dprintf ("pick coop failed, using my current enemy\n");
						designated_enemy = self->enemy;
					}
				}
			}
			else
			{
//				if ((g_showlogic) && (g_showlogic->value))
//					gi.dprintf ("pick coop failed, using my current enemy\n");
				designated_enemy = self->enemy;
			}
		}

		if ((designated_enemy) && (designated_enemy->inuse) && (designated_enemy->health > 0))
		{
			// fixme
//			if ((g_showlogic) && (g_showlogic -> value))
//				gi.dprintf  ("setting enemy to %s\n", designated_enemy->classname);
			ent->enemy = designated_enemy;
			FoundTarget (ent);
		}
		else
		{
			ent->enemy = NULL;
			ent->monsterinfo.stand (ent);
		}
//		ent->s.event = EV_PLAYER_TELEPORT;
	}
}
示例#27
0
文件: m_medic.c 项目: qbism/qbq2
void medic_cable_attack (edict_t *self)
{
	vec3_t	offset, start, end, f, r;
	trace_t	tr;
	vec3_t	dir;
	float	distance;

	if ((!self->enemy) || (!self->enemy->inuse) || (self->enemy->svflags & SVF_GIB))
	{
		//gi.dprintf ("medic_cable_attack: aborting heal due to target being removed or gibbed\n");
		abortHeal (self,false);
		return;
	}

	//Knightmare- don't heal insanes or actors or critters
	if (!strcmp (self->enemy->classname, "misc_insane") || !strcmp (self->enemy->classname, "misc_actor")
		|| !strcmp (self->enemy->classname, "monster_mutant") || !strcmp (self->enemy->classname, "monster_flipper")) 
	{
		//gi.dprintf ("medic_cable_attack: not healing insane or actor or critter\n");
		abortHeal (self, true);
		return;
	}

	// Lazarus: check embeddment
	if (embedded(self->enemy))
	{
		//gi.dprintf ("medic_cable_attack: dead monster embedded in solid, aborting heal\n");
		abortHeal (self,false);
		return;
	}

	// see if our enemy has changed to a client, or our target has more than 0 health,
	// abort it .. we got switched to someone else due to damage
	if ((self->enemy->client) || (self->enemy->health > 0))
	{
		//gi.dprintf ("medic_cable_attack: aborting heal due to target health > 0 or client\n");
		abortHeal (self,false);
		return;
	}

	AngleVectors (self->s.angles, f, r, NULL);
	VectorCopy (medic_cable_offsets[self->s.frame - FRAME_attack42], offset);
	G_ProjectSource (self->s.origin, offset, f, r, start);

	// check for max distance
	// Lazarus: Not needed, done in checkattack
	// check for min distance
	VectorSubtract (self->enemy->s.origin, start, dir);
	distance = VectorLength(dir);
	if (distance < MEDIC_MIN_DISTANCE)
	{
		//gi.dprintf("medic_cable_attack: MEDIC_MIN_DISTANCE\n");
		abortHeal (self,false);
		return;
	}

	// Lazarus: Check for enemy behind muzzle... don't do these guys, 'cause usually this
	// results in monster entanglement
	VectorNormalize(dir);
	if(DotProduct(dir,f) < 0.)
	{
		//gi.dprintf ("medic_cable_attack: aborting heal due to possible entanglment\n");
		abortHeal (self,false);
		return;
	}

	// check for min/max pitch
	// Rogue takes this out... makes medic more likely to heal and 
	// comments say "doesn't look bad when it fails"... we'll see
/*	vectoangles (dir, angles);
	if (angles[0] < -180)
		angles[0] += 360;
	if (fabs(angles[0]) > 45)
		return; */

	tr = gi.trace (start, NULL, NULL, self->enemy->s.origin, self, MASK_SHOT);
	if (tr.fraction != 1.0 && tr.ent != self->enemy)
	{
		if (tr.ent == world)
		{
			// give up on second try
			if (self->monsterinfo.medicTries > 1)
			{
				abortHeal (self,true);
				return;
			}
			self->monsterinfo.medicTries++;
			cleanupHeal (self, 1);
			return;
		}
		abortHeal (self,false);
		return;
	}

	if (self->s.frame == FRAME_attack43)
	{
		gi.sound (self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0);
		self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
		M_SetEffects(self->enemy);
	}
	else if (self->s.frame == FRAME_attack50)
	{
		self->enemy->spawnflags &= SF_MONSTER_NOGIB;
		self->enemy->monsterinfo.aiflags = 0;
		self->enemy->target = NULL;
		self->enemy->targetname = NULL;
		self->enemy->combattarget = NULL;
		self->enemy->deathtarget = NULL;
		self->enemy->owner = self;
		// Lazarus: reset initially dead monsters to use the INVERSE of their
		// initial health, and force gib_health to default value
		if(self->enemy->max_health < 0)
		{
			self->enemy->max_health = -self->enemy->max_health;
			self->enemy->gib_health = 0;
		}
		self->enemy->health = self->enemy->max_health;
		self->enemy->takedamage = DAMAGE_AIM;
		self->enemy->flags &= ~FL_NO_KNOCKBACK;
		self->enemy->pain_debounce_time = 0;
		self->enemy->damage_debounce_time = 0;
		self->enemy->deadflag = DEAD_NO;
		if(self->enemy->s.effects & EF_FLIES)
			M_FliesOff(self->enemy);
		ED_CallSpawn (self->enemy);
		self->enemy->monsterinfo.healer = NULL;
		self->enemy->owner = NULL;

		// Knightmare- disable deadmonster_think
		if (self->enemy->postthink)
			self->enemy->postthink = NULL;

		if (self->enemy->think)
		{
			self->enemy->nextthink = level.time;
			self->enemy->think (self->enemy);
		}
		self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING;
		M_SetEffects(self->enemy);
		if (self->oldenemy && self->oldenemy->client)
		{
			self->enemy->enemy = self->oldenemy;
			FoundTarget (self->enemy);
		}
		else
		{
			// Lazarus: this should make oblivious monsters 
			// find player again
			self->enemy->enemy = NULL;
		}
	}
	else
	{
		if (self->s.frame == FRAME_attack44)
			gi.sound (self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0);
	}

	// adjust start for beam origin being in middle of a segment
	// Lazarus: This isn't right... this causes cable start point to be well above muzzle
	//          when target is closeby. f should be vector from muzzle to target, not
	//          the forward viewing direction. PLUS... 8 isn't right... the model is
	//          actually 32 units long, so use 16.. fixed below.
//	VectorMA (start, 8, f, start);

	//Knightmare- if enemy went away, like after returning from another level, return
	if (!self->enemy)
		return;

	// adjust end z for end spot since the monster is currently dead
	VectorCopy (self->enemy->s.origin, end);
	end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2;

	// Lazarus fix
	VectorSubtract(end,start,f);
	VectorNormalize(f);
	VectorMA(start,16,f,start);

	gi.WriteByte (svc_temp_entity);
	gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
	gi.WriteShort (self - g_edicts);
	gi.WritePosition (start);
	gi.WritePosition (end);
	gi.multicast (self->s.origin, MULTICAST_PVS);
}
示例#28
0
void thing_think (edict_t *self)
{
	vec3_t	vec;
	vec_t	dist;
	edict_t	*monster;

	monster = self->target_ent;
	if(level.time <= self->touch_debounce_time)
	{
		if(monster && monster->inuse)
		{
			if(monster->movetarget == self)
			{
				if(monster->health > 0)
				{
					VectorSubtract(monster->s.origin,self->s.origin,vec);
					vec[2] = 0;
					dist = VectorLength(vec);
					if(dist >= monster->size[0])
					{
						self->nextthink = level.time + FRAMETIME;
						return;
					}
				}
			}
		}
	}
	if(!monster || !monster->inuse || (monster->health <= 0))
	{
		G_FreeEdict(self);
		return;
	}
	if(monster->goalentity == self)
		monster->goalentity = NULL;
	if(monster->movetarget == self)
		monster->movetarget = NULL;
	if(monster->monsterinfo.aiflags & AI_FOLLOW_LEADER)
	{
		monster->monsterinfo.leader = NULL;
		if(monster->monsterinfo.old_leader && monster->monsterinfo.old_leader->inuse)
		{
			monster->monsterinfo.pausetime = level.time + 2;
			monster->monsterinfo.stand(monster);
			VectorCopy(monster->monsterinfo.old_leader->s.origin,self->move_origin);
			self->nextthink = level.time + 2;
			self->think     = thing_restore_leader;
			gi.linkentity(monster);
			return;
		}
		else
		{
			monster->monsterinfo.aiflags &= ~AI_FOLLOW_LEADER;
		}
	}
	if(monster->monsterinfo.aiflags & AI_CHICKEN)
	{
		monster->monsterinfo.stand(monster);
		monster->monsterinfo.aiflags |= AI_STAND_GROUND;
		monster->monsterinfo.pausetime = level.time + 100000;
	}
	monster->vehicle = NULL;
	monster->monsterinfo.aiflags &= ~(AI_CHASE_THING | AI_SEEK_COVER | AI_EVADE_GRENADE);

	G_FreeEdict(self);
	if (has_valid_enemy(monster))
	{
		monster->monsterinfo.pausetime = 0;
		monster->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
		monster->goalentity = monster->enemy;
		if (visible(monster, monster->enemy))
		{
			FoundTarget (monster);
			return;
		}
		HuntTarget (monster);
		return;
	}
	monster->enemy = NULL;
	monster->monsterinfo.pausetime = level.time + 100000000;
	monster->monsterinfo.stand (monster);
}
示例#29
0
文件: carrier.c 项目: yquake2/rogue
void
CarrierSpawn(edict_t *self)
{
	vec3_t f, r, offset, startpoint, spawnpoint;
	edict_t *ent;
	int mytime;

	if (!self)
	{
		return;
	}

	VectorSet(offset, 105, 0, -58);
	AngleVectors(self->s.angles, f, r, NULL);

	G_ProjectSource(self->s.origin, offset, f, r, startpoint);

	/* the +0.1 is because level.time is sometimes a little low */
	mytime = (int)((level.time + 0.1 - self->timestamp) / 0.5);

	if (FindSpawnPoint(startpoint, flyer_mins, flyer_maxs, spawnpoint, 32))
	{
		/* the second flier should be a kamikaze flyer */
		if (mytime != 2)
		{
			ent = CreateMonster(spawnpoint, self->s.angles, "monster_flyer");
		}
		else
		{
			ent = CreateMonster(spawnpoint, self->s.angles, "monster_kamikaze");
		}

		if (!ent)
		{
			return;
		}

		gi.sound(self, CHAN_BODY, sound_spawn, 1, ATTN_NONE, 0);

		self->monsterinfo.monster_slots--;

		ent->nextthink = level.time;
		ent->think(ent);

		ent->monsterinfo.aiflags |= AI_SPAWNED_CARRIER | AI_DO_NOT_COUNT |
									AI_IGNORE_SHOTS;
		ent->monsterinfo.commander = self;

		if ((self->enemy->inuse) && (self->enemy->health > 0))
		{
			ent->enemy = self->enemy;
			FoundTarget(ent);

			if (mytime == 1)
			{
				ent->monsterinfo.lefty = 0;
				ent->monsterinfo.attack_state = AS_SLIDING;
				ent->monsterinfo.currentmove = &flyer_move_attack3;
			}
			else if (mytime == 2)
			{
				ent->monsterinfo.lefty = 0;
				ent->monsterinfo.attack_state = AS_STRAIGHT;
				ent->monsterinfo.currentmove = &flyer_move_kamikaze;
				ent->mass = 100;
				ent->monsterinfo.aiflags |= AI_CHARGING;
			}
			else if (mytime == 3)
			{
				ent->monsterinfo.lefty = 1;
				ent->monsterinfo.attack_state = AS_SLIDING;
				ent->monsterinfo.currentmove = &flyer_move_attack3;
			}
		}
	}
}
示例#30
0
文件: g_combat.c 项目: phine4s/xatrix
void
M_ReactToDamage(edict_t *targ, edict_t *attacker)
{
	if (!targ || !attacker)
	{
		return;
	}
	
	if (targ->health <= 0)
	{
		return;
	}

	if (!(attacker->client) && !(attacker->svflags & SVF_MONSTER))
	{
		return;
	}

	if ((attacker == targ) || (attacker == targ->enemy))
	{
		return;
	}

	/* if we are a good guy monster and our attacker is a
	   player or another good guy, do not get mad at them */
	if (targ->monsterinfo.aiflags & AI_GOOD_GUY)
	{
		if (attacker->client || (attacker->monsterinfo.aiflags & AI_GOOD_GUY))
		{
			return;
		}
	}

	/* if attacker is a client, get mad at
	   them because he's good and we're not */
	if (attacker->client)
	{
		targ->monsterinfo.aiflags &= ~AI_SOUND_TARGET;

		/* this can only happen in coop (both new and old
		   enemies are clients) only switch if can't see the
		   current enemy */
		if (targ->enemy && targ->enemy->client)
		{
			if (visible(targ, targ->enemy))
			{
				targ->oldenemy = attacker;
				return;
			}

			targ->oldenemy = targ->enemy;
		}

		targ->enemy = attacker;

		if (!(targ->monsterinfo.aiflags & AI_DUCKED))
		{
			FoundTarget(targ);
		}

		return;
	}

	/* it's the same base (walk/swim/fly) type and
	   a different classname and it's not a tank
	   (they spray too much), get mad at them */
	if (((targ->flags & (FL_FLY | FL_SWIM)) ==
		 (attacker->flags & (FL_FLY | FL_SWIM))) &&
		(strcmp(targ->classname, attacker->classname) != 0) &&
		(strcmp(attacker->classname, "monster_tank") != 0) &&
		(strcmp(attacker->classname, "monster_supertank") != 0) &&
		(strcmp(attacker->classname, "monster_makron") != 0) &&
		(strcmp(attacker->classname, "monster_jorg") != 0))
	{
		if (targ->enemy && targ->enemy->client)
		{
			targ->oldenemy = targ->enemy;
		}

		targ->enemy = attacker;

		if (!(targ->monsterinfo.aiflags & AI_DUCKED))
		{
			FoundTarget(targ);
		}
	}
	/* if they *meant* to shoot us, then shoot back */
	else if (attacker->enemy == targ)
	{
		if (targ->enemy && targ->enemy->client)
		{
			targ->oldenemy = targ->enemy;
		}

		targ->enemy = attacker;

		if (!(targ->monsterinfo.aiflags & AI_DUCKED))
		{
			FoundTarget(targ);
		}
	}
	/* otherwise get mad at whoever they are mad at (help our buddy) unless it is us! */
	else if (attacker->enemy && (attacker->enemy != targ))
	{
		if (targ->enemy && targ->enemy->client)
		{
			targ->oldenemy = targ->enemy;
		}

		targ->enemy = attacker->enemy;

		if (!(targ->monsterinfo.aiflags & AI_DUCKED))
		{
			FoundTarget(targ);
		}
	}
}