예제 #1
0
파일: m_flyer.c 프로젝트: basecq/q2dos
void
flyer_kamikaze_check(edict_t *self)
{
	float dist;

	if (!self)
	{
		return;
	}

	/* this needed because we could have gone away before we get here (blocked code) */
	if (!self->inuse)
	{
		return;
	}

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

	self->goalentity = self->enemy;

	dist = realrange(self, self->enemy);

	if (dist < 90)
	{
		flyer_kamikaze_explode(self);
	}
}
예제 #2
0
void flyer_kamikaze_check(edict_t *self)
{
	// PMM - this needed because we could have gone away before we get here (blocked code)
	if (!self->inuse)
		return;

	if (!self->enemy || !self->enemy->inuse || VectorCompare(self->s.old_origin, self->s.origin)) //mxd. Also explode when stuck...
	{
		flyer_kamikaze_explode(self);
		return;
	}

	self->goalentity = self->enemy;
	self->s.effects |= EF_ROCKET;
	VectorCopy(self->s.origin, self->s.old_origin); //mxd. Store old position...

	//mxd. Shrink bounding box to reduce the chance of getting STUK...
	if (self->maxs[0] != 8)
	{
		VectorSet(self->mins, -8, -8, -8);
		VectorSet(self->maxs, 8, 8, 8);
		gi.linkentity(self);
	}

	const float dist = realrange(self, self->enemy);
	if (dist < 90)
		flyer_kamikaze_explode(self);
	else if (dist < 128 || (level.framenum % 2 == 0)) //mxd. Play beep sound
		gi.sound(self, CHAN_VOICE, sound_suicide_beep, 1, ATTN_NORM, 0);
}
예제 #3
0
/* ----------------------------------------------------------------------------
   function:            myexp_()           author:              Andrew Cave
   creation date:       09-Feb-1987        last modification:   ##-###-####
   arguments:           none .
   description:

   See PostScript reference manual page 223.

---------------------------------------------------------------------------- */
Bool myexp_(ps_context_t *pscontext)
{
  SYSTEMVALUE args[ 2 ] ;
  SYSTEMVALUE result ;

  UNUSED_PARAM(ps_context_t *, pscontext) ;

  if ( ! stack_get_numeric(&operandstack, args, 2) )
    return FALSE ;

  if (( args[ 0 ] == OINFINITY_VALUE ) || ( args[ 1 ] == OINFINITY_VALUE ))
    return TRUE ;

  if (( args[ 0 ] < 0.0 ) && ( args[ 1 ] - (( int32 ) args[ 1 ] ) != 0.0 ))
    return error_handler( UNDEFINEDRESULT ) ;

  result = ( SYSTEMVALUE )pow(( double ) args[ 0 ] , ( double ) args[ 1 ] ) ;

  if ( ! realrange( result ))
    return error_handler( RANGECHECK ) ;
  if ( ! realprecision( result ))
    result = 0.0 ;

  npop( 2 , & operandstack ) ;

  return stack_push_real( result, &operandstack ) ;
}
예제 #4
0
edict_t *medic_FindDeadMonster (edict_t *self)
{
	float	radius;
	edict_t	*ent = NULL;
	edict_t	*best = NULL;

	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
		radius = MEDIC_MAX_HEAL_DISTANCE;
	else
		radius = 1024;

	while ((ent = findradius(ent, self->s.origin, radius)) != NULL)
	{
		if (ent == self)
			continue;
		if (!(ent->svflags & SVF_MONSTER))
			continue;
		if (ent->monsterinfo.aiflags & AI_GOOD_GUY)
			continue;
		// check to make sure we haven't bailed on this guy already
		if ((ent->monsterinfo.badMedic1 == self) || (ent->monsterinfo.badMedic2 == self))
			continue;
		if (ent->monsterinfo.healer)
			// FIXME - this is correcting a bug that is somewhere else
			// if the healer is a monster, and it's in medic mode .. continue .. otherwise
			//   we will override the healer, if it passes all the other tests
			if ((ent->monsterinfo.healer->inuse) && (ent->monsterinfo.healer->health > 0) &&
				(ent->monsterinfo.healer->svflags & SVF_MONSTER) && (ent->monsterinfo.healer->monsterinfo.aiflags & AI_MEDIC))
				continue;
		if (ent->health > 0)
			continue;
		if ((ent->nextthink) && !((ent->think == M_FliesOn) || (ent->think == M_FliesOff)))
			continue;
		if (!visible(self, ent))
//		if (!canReach(self, ent))
			continue;
		if (!strncmp(ent->classname, "player", 6))		 // stop it from trying to heal player_noise entities
			continue;
		// FIXME - there's got to be a better way ..
		// make sure we don't spawn people right on top of us
		if (realrange(self, ent) <= MEDIC_MIN_DISTANCE)
			continue;
		if (!best)
		{
			best = ent;
			continue;
		}
		if (ent->max_health <= best->max_health)
			continue;
		best = ent;
	}

	if (best)
		self->timestamp = level.time + MEDIC_TRY_TIME;

	return best;
}
예제 #5
0
/* ---------------------------------------------------------------------- */
Bool xforr(ps_context_t *pscontext)
{
  register OBJECT *theo , *other ;
  SYSTEMVALUE inc , current , limit ;

  UNUSED_PARAM(ps_context_t *, pscontext) ;

  theo = stackindex( 2 , & executionstack ) ;
  if ( oType(*theo) == OREAL )
    limit = oReal(*theo) ;
  else
    limit = OINFINITY_VALUE ;
  theo = stackindex( 4 , & executionstack ) ;
  if ( oType(*theo) == OREAL )
    current = oReal(*theo) ;
  else
    current = OINFINITY_VALUE ;
  other = stackindex( 3 , & executionstack ) ;
  if ( oType(*other) == OREAL )
    inc = oReal(*other) ;
  else
    inc = OINFINITY_VALUE ;

  if (( inc > 0.0 ) ? ( current > limit ) : ( current < limit )) {
    npop( 5 , & executionstack ) ;
    return TRUE ;
  }
  if ( ! stack_push_real( current, &operandstack ))
    return FALSE ;

  current += inc ;

  if ( realrange( current )) {
    if ( ! realprecision( current ))
      oReal(*theo) = 0.0f ;
    else
      oReal(*theo) = ( USERVALUE )current ;
  }
  else
    theTags(*theo) = OINFINITY | LITERAL ;

  theo = stackindex( 1 , & executionstack ) ;
  if ( oExecutable(*theo) )
    return push( theo , & executionstack ) ;
  else
    return push( theo , & operandstack ) ;
}
예제 #6
0
파일: widow.c 프로젝트: DrItanium/rogue
void widow_attack (edict_t *self)
{
	float	luck;
	qboolean rail_frames = false, blaster_frames = false, blocked = false, anger = false;

	self->movetarget = NULL;

	if (self->monsterinfo.aiflags & AI_BLOCKED)
	{
		blocked = true;
		self->monsterinfo.aiflags &= ~AI_BLOCKED;
	}
	
	if (self->monsterinfo.aiflags & AI_TARGET_ANGER)
	{
		anger = true;
		self->monsterinfo.aiflags &= ~AI_TARGET_ANGER;
	}

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

	if (self->bad_area)
	{
		if ((random() < 0.1) || (level.time < self->timestamp))
			self->monsterinfo.currentmove = &widow_move_attack_pre_blaster;
		else
		{
			gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
			self->monsterinfo.currentmove = &widow_move_attack_pre_rail;
		}
		return;
	}

	if ((self->s.frame == FRAME_walk13) || ((self->s.frame >= FRAME_walk01) && (self->s.frame <= FRAME_walk03)))
		rail_frames = true;

	if ((self->s.frame >= FRAME_walk09) && (self->s.frame <= FRAME_walk12))
		blaster_frames = true;

	WidowCalcSlots(self);

	// if we can't see the target, spawn stuff regardless of frame
	if ((self->monsterinfo.attack_state == AS_BLIND) && (SELF_SLOTS_LEFT >= 2))
	{
		self->monsterinfo.currentmove = &widow_move_spawn;
		return;
	}

	// accept bias towards spawning regardless of frame
	if (blocked && (SELF_SLOTS_LEFT >= 2))
	{
		self->monsterinfo.currentmove = &widow_move_spawn;
		return;
	}

	if ((realrange(self, self->enemy) > 300) && (!anger) && (random() < 0.5)  && (!blocked))
	{
		self->monsterinfo.currentmove = &widow_move_run_attack;
		return;
	}

	if (blaster_frames)
	{
		if (SELF_SLOTS_LEFT >= 2)
		{
			self->monsterinfo.currentmove = &widow_move_spawn;
			return;
		}
		else if (self->monsterinfo.pausetime + BLASTER_TIME <= level.time)
		{
			self->monsterinfo.currentmove = &widow_move_attack_pre_blaster;
			return;
		}
	}

	if (rail_frames)
	{
		if (!(level.time < self->timestamp))
		{
			gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
			self->monsterinfo.currentmove = &widow_move_attack_pre_rail;
		}
	}

	if ((rail_frames) || (blaster_frames))
		return;

	luck = random();
	if (SELF_SLOTS_LEFT >= 2)
	{
		if ((luck <= 0.40) && (self->monsterinfo.pausetime + BLASTER_TIME <= level.time))
			self->monsterinfo.currentmove = &widow_move_attack_pre_blaster;
		else if ((luck <= 0.7) && !(level.time < self->timestamp))
		{
			gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
			self->monsterinfo.currentmove = &widow_move_attack_pre_rail;
		}
		else
			self->monsterinfo.currentmove = &widow_move_spawn;
	}
	else
	{
		if (level.time < self->timestamp)
			self->monsterinfo.currentmove = &widow_move_attack_pre_blaster;
		else if ((luck <= 0.50) || (level.time + BLASTER_TIME >= self->monsterinfo.pausetime))
		{
			gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
			self->monsterinfo.currentmove = &widow_move_attack_pre_rail;
		}
		else // holdout to blaster
			self->monsterinfo.currentmove = &widow_move_attack_pre_blaster;
	}
}
예제 #7
0
파일: widow.c 프로젝트: DrItanium/rogue
qboolean Widow_CheckAttack (edict_t *self)
{
	vec3_t	spot1, spot2;
	vec3_t	temp;
	float	chance = 0;
	trace_t	tr;
	int			enemy_range;
	float		enemy_yaw;
	float		real_enemy_range;

	if (!self->enemy)
		return false;

	WidowPowerups(self);

	if (self->monsterinfo.currentmove == &widow_move_run)
	{
		// if we're in run, make sure we're in a good frame for attacking before doing anything else
		// frames 1,2,3,9,10,11,13 good to fire
		switch (self->s.frame)
		{
			case FRAME_walk04:
			case FRAME_walk05:
			case FRAME_walk06:
			case FRAME_walk07:
			case FRAME_walk08:
			case FRAME_walk12:
				{
					return false;
				}
			default:
				break;
		}
	}

	// give a LARGE bias to spawning things when we have room
	// use AI_BLOCKED as a signal to attack to spawn
	if ((random() < 0.8) && (SELF_SLOTS_LEFT >= 2) && (realrange(self, self->enemy) > 150))
	{
		self->monsterinfo.aiflags |= AI_BLOCKED;
		self->monsterinfo.attack_state = AS_MISSILE;
		return true;
	}

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

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

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

	self->ideal_yaw = enemy_yaw;

	real_enemy_range = realrange (self, self->enemy);

	if (real_enemy_range <= (MELEE_DISTANCE+20))
	{
		// don't always melee in easy mode
		if (skill->value == 0 && (rand()&3) )
			return false;
		if (self->monsterinfo.melee)
			self->monsterinfo.attack_state = AS_MELEE;
		else
			self->monsterinfo.attack_state = AS_MISSILE;
		return true;
	}

	if (level.time < self->monsterinfo.attack_finished)
		return false;
		
	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
	{
		chance = 0.4;
	}
	else if (enemy_range == RANGE_MELEE)
	{
		chance = 0.8;
	}
	else if (enemy_range == RANGE_NEAR)
	{
		chance = 0.7;
	}
	else if (enemy_range == RANGE_MID)
	{
		chance = 0.6;
	}
	else if (enemy_range == RANGE_FAR)
	{
		chance = 0.5;
	}

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

	return false;
}
예제 #8
0
qboolean medic_checkattack (edict_t *self)
{
	if (self->monsterinfo.aiflags & AI_MEDIC)
	{
		// if our target went away
		if ((!self->enemy) || (!self->enemy->inuse))
		{
//			if (g_showlogic && g_showlogic->value)
//				gi.dprintf ("aborting heal target due to gib\n");
			abortHeal (self, true, false, false);
			return false;
		}

		// if we ran out of time, give up
		if (self->timestamp < level.time)
		{
//			if (g_showlogic && g_showlogic->value)
//				gi.dprintf ("aborting heal target (%s) due to time\n", self->enemy->classname);
			abortHeal (self, true, false, true);
			self->timestamp = 0;
			return false;
		}
	
		if (realrange(self, self->enemy) < MEDIC_MAX_HEAL_DISTANCE+10)
		{
			medic_attack(self);
			return true;
		}
		else
		{
			self->monsterinfo.attack_state = AS_STRAIGHT;
			return false;
		}
	}

	if (self->enemy->client && !visible (self, self->enemy) && (self->monsterinfo.monster_slots > 2))
	{
		self->monsterinfo.attack_state = AS_BLIND;
		return true;
	}

	// give a LARGE bias to spawning things when we have room
	// use AI_BLOCKED as a signal to attack to spawn
	if ((random() < 0.8) && (self->monsterinfo.monster_slots > 5) && (realrange(self, self->enemy) > 150))
	{
		self->monsterinfo.aiflags |= AI_BLOCKED;
		self->monsterinfo.attack_state = AS_MISSILE;
		return true;
	}
	
	// ROGUE
	// since his idle animation looks kinda bad in combat, if we're not in easy mode, always attack
	// when he's on a combat point
	if (skill->value > 0)
		if (self->monsterinfo.aiflags & AI_STAND_GROUND)
		{
			self->monsterinfo.attack_state = AS_MISSILE;
			return true;
		}

	return M_CheckAttack (self);
}
예제 #9
0
파일: g_combat.c 프로젝트: DrItanium/rogue
void T_RadiusNukeDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod)
{
    float	points;
    edict_t	*ent = NULL;
    vec3_t	v;
    vec3_t	dir;
    float	len;
    float	killzone, killzone2;
    trace_t	tr;
    float	dist;

    killzone = radius;
    killzone2 = radius*2.0;

    while ((ent = findradius(ent, inflictor->s.origin, killzone2)) != NULL)
    {
        // ignore nobody
        if (ent == ignore)
            continue;
        if (!ent->takedamage)
            continue;
        if (!ent->inuse)
            continue;
        if (!(ent->client || (ent->svflags & SVF_MONSTER) || (ent->svflags & SVF_DAMAGEABLE)))
            continue;

        VectorAdd (ent->mins, ent->maxs, v);
        VectorMA (ent->s.origin, 0.5, v, v);
        VectorSubtract (inflictor->s.origin, v, v);
        len = VectorLength(v);
        if (len <= killzone)
        {
            if (ent->client)
                ent->flags |= FL_NOGIB;
            points = 10000;
        }
        else if (len <= killzone2)
            points = (damage/killzone)*(killzone2 - len);
        else
            points = 0;
        if (points > 0)
        {
            if (ent->client)
                ent->client->nuke_framenum = level.framenum + 20;
            VectorSubtract (ent->s.origin, inflictor->s.origin, dir);
            T_Damage (ent, inflictor, attacker, dir, inflictor->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
        }
    }
    ent = g_edicts+1; // skip the worldspawn
    // cycle through players
    while (ent)
    {
        if ((ent->client) && (ent->client->nuke_framenum != level.framenum+20) && (ent->inuse))
        {
            tr = gi.trace (inflictor->s.origin, NULL, NULL, ent->s.origin, inflictor, MASK_SOLID);
            if (tr.fraction == 1.0)
            {
                ent->client->nuke_framenum = level.framenum + 20;
            }
            else
            {
                dist = realrange (ent, inflictor);
                if (dist < 2048)
                    ent->client->nuke_framenum = max(ent->client->nuke_framenum,level.framenum + 15);
                else
                    ent->client->nuke_framenum = max(ent->client->nuke_framenum,level.framenum + 10);
            }
            ent++;
        }
        else
            ent = NULL;
    }
}
예제 #10
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);
}
예제 #11
0
qboolean hintcheck_monsterlost (edict_t *monster)
{
	edict_t		*ent;
	edict_t		*monster_node_list, *target_node_list, *prev_node;
	edict_t		*closest_node, *start_node, *dest_node;
	int			i;
	float		node_dist, closest_dist;
	qboolean	monster_pathchains_listed[MAX_HINT_CHAINS], target_pathchains_listed[MAX_HINT_CHAINS];
	qboolean	nodes_found = false;

	// If monster is standing at post, has no enemy,
	// or there are no hint_path chains in this map, get outta here.
	if ((monster->monsterinfo.aiflags & AI_STAND_GROUND)
		|| !monster->enemy || !hint_chains_exist)
		return false;

	monster_node_list = NULL;
	// Create linked list of all hint_path nodes in level
	for (i=0; i < hint_chain_count; i++)
	{
		ent = hint_chain_starts[i];
		while (ent)
		{	// Clean up previous monster_hint_chain pointers
			if (ent->monster_hint_chain)
				ent->monster_hint_chain = NULL;
			if (!monster_node_list)  // add first node
			{
				monster_node_list = ent;
				prev_node = ent;
			}
			else
			{
				prev_node->monster_hint_chain = ent;
				prev_node = ent;
			}
			ent = ent->hint_chain;
		}
	}
	
	// Remove inaccessible to monster nodes from monster_node_list linked list.
	ent = monster_node_list;
	prev_node = NULL;
	while (ent)
	{
		node_dist = realrange (monster, ent);
		if (node_dist > HINT_NODE_RANGE || !visible(monster, ent))
		{
			if (!prev_node)
			{
				edict_t *temp = ent;
				ent = ent->monster_hint_chain;
				temp->monster_hint_chain = NULL;
				// Since there is no previous valid node, move start pointer up to our new position.
				monster_node_list = ent;
				continue;
			}
			else
			{
				prev_node->monster_hint_chain = ent->monster_hint_chain;
				ent->monster_hint_chain = NULL;
				ent = prev_node->monster_hint_chain;
				continue;
			}
		}
		nodes_found = true;
		prev_node = ent;
		ent = ent->monster_hint_chain;
	}

	// If no hint_path nodes are accessible to the monster, get outta here.
	if (!nodes_found) return false;

/*
	We now have a linked list of all hint_path nodes accessible to the monster.

	The next step is to create a list of pathchains that the monster can access.
*/

	// Go through all monster- accessible nodes to see which pathchains have nodes in the linked list.
	for (i=0; i < hint_chain_count; i++)
		monster_pathchains_listed[i] = false;
	ent = monster_node_list;
	while (ent)
	{	// catch errors
		if ((ent->hint_chain_id < 0) || (ent->hint_chain_id > hint_chain_count))
			return false;
		monster_pathchains_listed[ent->hint_chain_id] = true;
		ent = ent->monster_hint_chain;
	}

	// Build a linked list of all nodes in the pathchains accessible to the monster.
	// This will be used to find nodes that are accessible to the monster's enemy.
	target_node_list = NULL;
	prev_node = NULL;
	for (i=0; i < hint_chain_count; i++)
	{
		if (monster_pathchains_listed[i]) // If pathchain is listed, add it to our new linked list.
		{
			ent = hint_chain_starts[i];
			while (ent)
			{
				if (!target_node_list) // add first node
				{
					target_node_list = ent;
					prev_node = ent;
				}
				else
				{
					prev_node->target_hint_chain = ent;
					prev_node = ent;
				}
				ent = ent->hint_chain;
			}
		}
	}

	// Remove inaccessible to monster's enemy nodes from target_node_list linked list.
	ent = target_node_list;
	prev_node = NULL;
	nodes_found = false;
	while (ent)
	{
		node_dist = realrange (monster->enemy, ent);
		if (node_dist > HINT_NODE_RANGE || !visible(monster->enemy, ent))
		{
			if (!prev_node)
			{
				edict_t *temp = ent;
				ent = ent->target_hint_chain;
				temp->target_hint_chain = NULL;
				// Since there is no previous valid node, move start pointer up to our new position.
				target_node_list = ent;
				continue;
			}
			else
			{
				prev_node->target_hint_chain = ent->target_hint_chain;
				ent->target_hint_chain = NULL;
				ent = prev_node->target_hint_chain;
				continue;
			}
		}
		nodes_found = true;
		prev_node = ent;
		ent = ent->target_hint_chain;
	}
	
	// If no hint_path nodes would bring us to our enemy, get outta here.
	if (!nodes_found) return false;

/*
	We now have two linked lists- one of hint_path nodes accessible to the monster, and one of hint_path nodes
	near the monster's enemy that are accessible from nodes near the monster.
	
	The next step is to find the closest node near the monster that will lead it to its enemy,
*/

	// Go through all monster's enemy-accessible nodes to see which pathchains have nodes in the linked list.
	for (i=0; i < hint_chain_count; i++)
		target_pathchains_listed[i] = false;
	ent = target_node_list;
	while (ent)
	{	// catch errors
		if ((ent->hint_chain_id < 0) || (ent->hint_chain_id > hint_chain_count))
			return false;
		target_pathchains_listed[ent->hint_chain_id] = true;
		ent = ent->target_hint_chain;
	}
	
	// Go through monster_node_list linked list to find the closest node to us
	// that leads to the monster's enemy (on the list).
	closest_dist = HINT_NODE_RANGE;
	closest_node = NULL;
	ent = monster_node_list;
	while (ent)
	{
		if (target_pathchains_listed[ent->hint_chain_id])
		{
			node_dist = realrange(monster, ent);
			if (node_dist < closest_dist)
			{
				closest_node = ent;
				closest_dist = node_dist;
			}
		}
		ent = ent->monster_hint_chain;
	}

	// If there are no nodes close enough that take us to our enemy, get outta here.
	if (!closest_node) return false;
	start_node = closest_node;

	// Finally we go through target_node_list linked list to find the node closest to
	// our target that is on the pathchain the monster will be using.
	closest_dist = HINT_NODE_RANGE;
	closest_node = NULL;
	ent = target_node_list;
	while (ent)
	{
		if (ent->hint_chain_id == start_node->hint_chain_id)
		{
			node_dist = realrange(monster->enemy, ent);
			if (node_dist < closest_dist)
			{
				closest_node = ent;
				closest_dist = node_dist;
			}
		}
		ent = ent->target_hint_chain;
	}

	// If there is no node close enough to our enemy, get outta here.
	if (!closest_node) return false;
	dest_node = closest_node;

	monster->monsterinfo.goal_hint = dest_node;
	hintpath_start (monster, start_node);
	return true;
}
예제 #12
0
파일: widow2.c 프로젝트: yquake2/rogue
void
widow2_attack(edict_t *self)
{
	float range, luck;
	qboolean blocked = false;

	if (!self)
	{
		return;
	}

	if (self->monsterinfo.aiflags & AI_BLOCKED)
	{
		blocked = true;
		self->monsterinfo.aiflags &= ~AI_BLOCKED;
	}

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

	if (self->bad_area)
	{
		if ((random() < 0.75) || (level.time < self->monsterinfo.attack_finished))
		{
			self->monsterinfo.currentmove = &widow2_move_attack_pre_beam;
		}
		else
		{
			self->monsterinfo.currentmove = &widow2_move_attack_disrupt;
		}

		return;
	}

	WidowCalcSlots(self);

	/* if we can't see the target, spawn stuff */
	if ((self->monsterinfo.attack_state == AS_BLIND) && (SELF_SLOTS_LEFT >= 2))
	{
		self->monsterinfo.currentmove = &widow2_move_spawn;
		return;
	}

	/* accept bias towards spawning */
	if (blocked && (SELF_SLOTS_LEFT >= 2))
	{
		self->monsterinfo.currentmove = &widow2_move_spawn;
		return;
	}

	range = realrange(self, self->enemy);

	if (range < 600)
	{
		luck = random();

		if (SELF_SLOTS_LEFT >= 2)
		{
			if (luck <= 0.40)
			{
				self->monsterinfo.currentmove = &widow2_move_attack_pre_beam;
			}
			else if ((luck <= 0.7) && !(level.time < self->monsterinfo.attack_finished))
			{
				self->monsterinfo.currentmove = &widow2_move_attack_disrupt;
			}
			else
			{
				self->monsterinfo.currentmove = &widow2_move_spawn;
			}
		}
		else
		{
			if ((luck <= 0.50) || (level.time < self->monsterinfo.attack_finished))
			{
				self->monsterinfo.currentmove = &widow2_move_attack_pre_beam;
			}
			else
			{
				self->monsterinfo.currentmove = &widow2_move_attack_disrupt;
			}
		}
	}
	else
	{
		luck = random();

		if (SELF_SLOTS_LEFT >= 2)
		{
			if (luck < 0.3)
			{
				self->monsterinfo.currentmove = &widow2_move_attack_pre_beam;
			}
			else if ((luck < 0.65) || (level.time < self->monsterinfo.attack_finished))
			{
				self->monsterinfo.currentmove = &widow2_move_spawn;
			}
			else
			{
				self->monsterinfo.currentmove = &widow2_move_attack_disrupt;
			}
		}
		else
		{
			if ((luck < 0.45) || (level.time < self->monsterinfo.attack_finished))
			{
				self->monsterinfo.currentmove = &widow2_move_attack_pre_beam;
			}
			else
			{
				self->monsterinfo.currentmove = &widow2_move_attack_disrupt;
			}
		}
	}
}
예제 #13
0
파일: widow2.c 프로젝트: yquake2/rogue
qboolean
Widow2_CheckAttack(edict_t *self)
{
	vec3_t spot1, spot2;
	vec3_t temp;
	float chance = 0;
	trace_t tr;
	int enemy_range;
	float enemy_yaw;
	float real_enemy_range;
	vec3_t f, r, u;

	if (!self)
	{
		return false;
	}

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

	WidowPowerups(self);

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

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

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

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

			if ((self->enemy->solid != SOLID_NOT) || (tr.fraction < 1.0))
			{
				return false;
			}
		}
	}

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

	self->ideal_yaw = enemy_yaw;

	/* melee attack */
	if (self->timestamp < level.time)
	{
		real_enemy_range = realrange(self, self->enemy);

		if (real_enemy_range < 300)
		{
			AngleVectors(self->s.angles, f, r, u);
			G_ProjectSource2(self->s.origin, offsets[0], f, r, u, spot1);
			VectorCopy(self->enemy->s.origin, spot2);

			if (widow2_tongue_attack_ok(spot1, spot2, 256))
			{
				/* be nice in easy mode */
				if ((skill->value == 0) && (rand() & 3))
				{
					return false;
				}

				if (self->monsterinfo.melee)
				{
					self->monsterinfo.attack_state = AS_MELEE;
				}
				else
				{
					self->monsterinfo.attack_state = AS_MISSILE;
				}

				return true;
			}
		}
	}

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

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

	if ((random() < chance) || (self->enemy->solid == SOLID_NOT))
	{
		self->monsterinfo.attack_state = AS_MISSILE;
		return true;
	}

	return false;
}
예제 #14
0
/*
======================
M_MoveToGoal
======================
*/
void M_MoveToGoal (edict_t *ent, float dist)
{
	edict_t		*goal;
	
	goal = ent->goalentity;

	if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
		return;

	// Lazarus range checks
	if (!(ent->monsterinfo.aiflags & (AI_CHASE_THING | AI_CHICKEN)))
	{
		if (ent->enemy && (ent->monsterinfo.min_range > 0) && ((goal==ent->enemy) || !goal) ) {
			float dist;
			dist = realrange(ent,ent->enemy);
			if(dist < ent->monsterinfo.min_range)
			{
				ent->monsterinfo.aiflags |= (AI_STAND_GROUND | AI_RANGE_PAUSE);
				ent->monsterinfo.rangetime = level.time + 0.5;
				ent->monsterinfo.stand(ent);
				return;
			}
		}
		if ((ent->enemy) && (level.time > ent->monsterinfo.rangetime + 0.5) && ((goal==ent->enemy) || !goal) )
		{
			float dist;
			dist = realrange(ent,ent->enemy);
			if((dist < ent->monsterinfo.ideal_range[0]) && (rand() & 3))
			{
				ent->monsterinfo.aiflags |= (AI_STAND_GROUND | AI_RANGE_PAUSE);
				ent->monsterinfo.rangetime = level.time + 1.0;
				ent->monsterinfo.stand(ent);
				return;
			}
			if((dist < ent->monsterinfo.ideal_range[1]) && (dist > ent->monsterinfo.ideal_range[0]) && (rand() & 1))
			{
				ent->monsterinfo.aiflags |= (AI_STAND_GROUND | AI_RANGE_PAUSE);
				ent->monsterinfo.rangetime = level.time + 0.2;
				ent->monsterinfo.stand(ent);
				return;
			}
		}
	}

	if( (ent->monsterinfo.aiflags & AI_FOLLOW_LEADER) &&
		(ent->movetarget) &&
		(ent->movetarget->inuse) &&
		(ent->movetarget->health > 0) ) {

		if(ent->enemy)
			ent->monsterinfo.currentmove = &actor_move_run;
		else
		{
			float	R;

			R = realrange(ent,ent->movetarget);
			if(R > ACTOR_FOLLOW_RUN_RANGE)
				ent->monsterinfo.currentmove = &actor_move_run;
			else if(R < ACTOR_FOLLOW_STAND_RANGE && ent->movetarget->client) {
				ent->monsterinfo.pausetime = level.time + 0.5;
				ent->monsterinfo.currentmove = &actor_move_stand;
				return;
			}
			else
				ent->monsterinfo.currentmove = &actor_move_walk;
		}
	}

//	If the next step hits the enemy, return immediately. Don't do this for
//	AI_CHASE_THING, since we want monster to actually touch or pass through
//	"thing"
	if (ent->enemy && !(ent->monsterinfo.aiflags & AI_CHASE_THING) && SV_CloseEnough (ent, ent->enemy, dist) )
		return;

// bump around...
	if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
	{
		if (ent->inuse)
			SV_NewChaseDir (ent, goal, dist);
	}
}