Example #1
0
File: m_medic.c Project: qbism/qbq2
void abortHeal (edict_t *self, qboolean mark)
{
	edict_t	*temp;

	// clean up target
	cleanupHeal (self, true);

	if ((mark) && (self->enemy) && (self->enemy->inuse))
	{
		if ((self->enemy->monsterinfo.badMedic1) && (self->enemy->monsterinfo.badMedic1->inuse)
			&& (!strncmp(self->enemy->monsterinfo.badMedic1->classname, "monster_medic", 13)) )
			self->enemy->monsterinfo.badMedic2 = self;
		else
			self->enemy->monsterinfo.badMedic1 = self;

		temp = G_Spawn();
		temp->activator = self->enemy;
		if(self == self->enemy->monsterinfo.badMedic1)
			temp->monsterinfo.badMedic1 = self;
		else
			temp->monsterinfo.badMedic2 = self;
		temp->think = DeleteBadMedic;
		temp->nextthink = level.time + 60;
	}

	// clean up self
	self->monsterinfo.aiflags &= ~AI_MEDIC;
	if ((self->oldenemy) && (self->oldenemy->inuse))
		self->enemy = self->oldenemy;
	else
		self->enemy = NULL;

	self->monsterinfo.medicTries = 0;
}
void abortHeal (edict_t *self, qboolean change_frame, qboolean gib, qboolean mark)
{
	int hurt;
	static vec3_t	pain_normal = { 0, 0, 1 };

	// clean up target
	cleanupHeal (self, change_frame);
	// gib em!
	if ((mark) && (self->enemy) && (self->enemy->inuse))
	{
//		if ((g_showlogic) && (g_showlogic->value))
//			gi.dprintf ("%s - marking target as bad\n", self->classname);
		// if the first badMedic slot is filled by a medic, skip it and use the second one
		if ((self->enemy->monsterinfo.badMedic1) && (self->enemy->monsterinfo.badMedic1->inuse)
			&& (!strncmp(self->enemy->monsterinfo.badMedic1->classname, "monster_medic", 13)) )
		{
			self->enemy->monsterinfo.badMedic2 = self;
		}
		else
		{
			self->enemy->monsterinfo.badMedic1 = self;
		}
	}
	if ((gib) && (self->enemy) && (self->enemy->inuse))
	{
//		if ((g_showlogic) && (g_showlogic->value))
//			gi.dprintf ("%s - gibbing bad heal target", self->classname);

		if(self->enemy->gib_health)
			hurt = - self->enemy->gib_health;
		else
			hurt = 500;

		T_Damage (self->enemy, self, self, vec3_origin, self->enemy->s.origin,
					pain_normal, hurt, 0, 0, MOD_UNKNOWN);
	}
	// clean up self

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

	self->monsterinfo.medicTries = 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);
}
Example #4
0
File: m_medic.c Project: 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);
}