Example #1
0
//
// this is the smarts for the rocket launcher in coop
//
// if there is a player behind/below the carrier, and we can shoot, and we can trace a LOS to them ..
// pick one of the group, and let it rip
void CCarrier::CoopCheck ()
{
	// no more than 4 players in coop, so..
	static std::vector<CPlayerEntity*> targets;
	targets.clear();

	// if we're not in coop, this is a noop
	if (!(Game.GameMode & GAME_COOPERATIVE))
		return;
	// if we are, and we have recently fired, bail
	if (RefireWait > Level.Frame)
		return;

	// cycle through players
	for (int player = 1; player <= Game.MaxClients; player++)
	{
		CPlayerEntity *ent = entity_cast<CPlayerEntity>(Game.Entities[player].Entity);

		if (!ent->GetInUse())
			continue;
		
		if (IsInBack(Entity, ent) || IsBelow(Entity, ent))
		{
			CTrace tr (Entity->State.GetOrigin(), ent->State.GetOrigin(), Entity, CONTENTS_MASK_SOLID);
		
			if (tr.Fraction == 1.0)
				targets.push_back (ent);
		}
	}

	if (targets.empty())
		return;

	int target = irandom(targets.size());

	// make sure to prevent rapid fire rockets
	RefireWait = Level.Frame + CARRIER_ROCKET_TIME;

	// save off the real enemy
	IBaseEntity *OldEnemy = *Entity->Enemy;
	// set the new guy as temporary enemy
	Entity->Enemy = targets[target];
	Rocket ();
	// put the real enemy back
	Entity->Enemy = OldEnemy;

	// we're done
	return;
}
/*
\brief 二分查找法,求多边形上方向是u的极点,设凸多边形是逆时针顺序的。
*/
int ExtremePoint_BinarySearch( const Point2D* p, int n, const Vector2D& u)
{
	int	a = 0, b = n, m;
	int upA = Direction(p[1] - p[0],u) , upM;
	if( upA<=0 && !IsAbove(p[n-1],p[0],u) )
		return 0;
	while(true)
	{
		m = (a + b) / 2;
		upM = Direction(p[(m+1)%n] - p[m],u);
		if( upM<=0 && !IsAbove(p[m-1],p[m],u) )
			return m;
		if( upA>0 )
		{
			if( upM<0 )
			{				//选择[a,m]
				b = m;		
			}
			else if( IsAbove(p[a],p[m],u) )
			{				//选择[a,m]
				b = m;		
			}
			else
			{				//选择[m,b]
				a = m;
				upA = upM;
			}
		}
		else
		{
			if( upM>0 )
			{				//选择[m,b]
				a = m;
				upA = upM;
			}
			else if( IsBelow(p[a],p[m],u) )
			{				//选择[a,m]
				b = m;
			}
			else
			{				//选择[m,b]
				a = m;
				upA = upM;
			}
		}
	}
	return 0;
}
Example #3
0
bool CCarrier::CheckAttack ()
{
	if ((Entity->Enemy->EntityFlags & EF_HURTABLE) && entity_cast<IHurtableEntity>(*Entity->Enemy)->Health > 0)
	{
	// see if any entities are in the way of the shot
		vec3f	spot1 = Entity->State.GetOrigin() + vec3f(0, 0, Entity->ViewHeight),
				spot2 = Entity->Enemy->State.GetOrigin() + vec3f(0, 0, Entity->Enemy->ViewHeight);

		CTrace tr (spot1, spot2, Entity, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);

		// do we have a clear shot?
		if (tr.Entity != Entity->Enemy)
		{	
			// go ahead and spawn stuff if we're mad a a client
			if ((Entity->Enemy->EntityFlags & EF_PLAYER) && MonsterSlots > 2)
			{
				AttackState = AS_BLIND;
				return true;
			}
				
			// PGM - we want them to go ahead and shoot at info_notnulls if they can.
			if (Entity->Enemy->GetSolid() != SOLID_NOT || tr.Fraction < 1.0)		//PGM
				return false;
		}
	}
	
	EnemyInfront = IsInFront(Entity, *Entity->Enemy);
	bool EnemyInback = IsInBack(Entity, *Entity->Enemy);
	bool EnemyBelow = IsBelow (Entity, *Entity->Enemy);

	EnemyRange = Range (Entity, *Entity->Enemy);
	IdealYaw = (Entity->Enemy->State.GetOrigin() - Entity->State.GetOrigin()).ToYaw();

	// PMM - shoot out the back if appropriate
	if ((EnemyInback) || (!EnemyInfront && EnemyBelow))
	{
		// this is using wait because the attack is supposed to be independent
		if (Level.Frame >= RefireWait)
		{
			RefireWait = Level.Frame + CARRIER_ROCKET_TIME;
			Attack ();
			if (frand() < 0.6)
				AttackState = AS_SLIDING;
			else
				AttackState = AS_STRAIGHT;
			return true;
		}
	}

	// melee attack
	if (EnemyRange == RANGE_MELEE)
	{
		AttackState = AS_MISSILE;
		return true;
	}
	
	float chance = 0.0f;
	if (AIFlags & AI_STAND_GROUND)
		chance = 0.4f;
	else 
	{
		switch (EnemyRange)
		{
		case RANGE_MELEE:
		case RANGE_NEAR:
		case RANGE_MID:
			chance = 0.8f;
			break;
		case RANGE_FAR:
			chance = 0.5f;
			break;
		};
	}

	// PGM - go ahead and shoot every time if it's a info_notnull
	if ((Entity->Enemy->GetSolid() == SOLID_NOT) || (frand () < chance))
	{
		AttackState = AS_MISSILE;
		return true;
	}

	if (AIFlags & AI_FLY)
	{
		if (frand() < 0.6)
			AttackState = AS_SLIDING;
		else
			AttackState = AS_STRAIGHT;
	}

	return false;
}
Example #4
0
void CCarrier::Attack ()
{	
	AIFlags &= ~AI_HOLD_FRAME;

	if (!Entity->Enemy)
		return;

	bool EnemyInback = IsInBack(Entity, *Entity->Enemy);
	EnemyInfront = IsInFront (Entity, *Entity->Enemy);
	bool EnemyBelow = IsBelow (Entity, *Entity->Enemy);

	if (BadArea)
	{
		if ((EnemyInback) || (EnemyBelow))
			CurrentMove = &CarrierMoveAttackRocket;
		else if ((frand() < 0.1) || (Level.Frame < AttackFinished))
			CurrentMove = &CarrierMovePreAttackMG;
		else
		{
			Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]);
			CurrentMove = &CarrierMoveAttackRail;
		}
		return;
	}

	if (AttackState == AS_BLIND)
	{
		CurrentMove = &CarrierMoveSpawn;
		return;
	}

	if (!EnemyInback && !EnemyInfront && !EnemyBelow) // to side and not under
	{
		if ((frand() < 0.1) || (Level.Frame < AttackFinished)) 
			CurrentMove = &CarrierMovePreAttackMG;
		else
		{
			Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]);
			CurrentMove = &CarrierMoveAttackRail;
		}
		return;
	}

	if (EnemyInfront)
	{
		float range = (Entity->Enemy->State.GetOrigin() - Entity->State.GetOrigin()).Length();
		if (range <= 125)
		{
			if ((frand() < 0.8) || (Level.Frame < AttackFinished))
				CurrentMove = &CarrierMovePreAttackMG;
			else
			{
				Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]);
				CurrentMove = &CarrierMoveAttackRail;
			}
		}
		else if (range < 600)
		{
			float luck = frand();
			if (MonsterSlots > 2)
			{
				if (luck <= 0.20)
					CurrentMove = &CarrierMovePreAttackMG;
				else if (luck <= 0.40)
					CurrentMove = &CarrierMoveAttackPreGrenade;
				else if ((luck <= 0.7) && !(Level.Frame < AttackFinished))
				{
					Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]);
					CurrentMove = &CarrierMoveAttackRail;
				}
				else
					CurrentMove = &CarrierMoveSpawn;
			}
			else
			{
				if (luck <= 0.30)
					CurrentMove = &CarrierMovePreAttackMG;
				else if (luck <= 0.65)
					CurrentMove = &CarrierMoveAttackPreGrenade;
				else if (Level.Frame >= AttackFinished)
				{
					Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]);
					CurrentMove = &CarrierMoveAttackRail;
				}
				else
					CurrentMove = &CarrierMovePreAttackMG;
			}
		}
		else // won't use grenades at this range
		{
			float luck = frand();
			if (MonsterSlots > 2)
			{
				if (luck < 0.3)
					CurrentMove = &CarrierMovePreAttackMG;
				else if ((luck < 0.65) && !(Level.Frame < AttackFinished))
				{
					Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]);
					RailFireSpot = Entity->Enemy->State.GetOrigin() + vec3f(0, 0, Entity->Enemy->ViewHeight);
					CurrentMove = &CarrierMoveAttackRail;
				}
				else
					CurrentMove = &CarrierMoveSpawn;
			}
			else
			{
				if ((luck < 0.45f) || (Level.Frame < AttackFinished))
					CurrentMove = &CarrierMovePreAttackMG;
				else
				{
					Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]);
					CurrentMove = &CarrierMoveAttackRail;
				}
			}
		}
	}
	else if ((EnemyBelow) || (EnemyInback))
		CurrentMove = &CarrierMoveAttackRocket;
}