Beispiel #1
0
//	-----------------------------------------------------------------------------
//	Fire Laser:  Registers a laser fire, and performs special stuff for the fusion
//				    cannon.
void ChargeFusion (void)
{
if ((LOCALPLAYER.energy < I2X (2)) && (gameData.fusion.xAutoFireTime == 0)) {
	gameData.laser.nGlobalFiringCount = 0;
	}
else {
	gameData.fusion.xFrameTime += gameData.time.xFrame;
	if (!gameData.FusionCharge ())
		LOCALPLAYER.energy -= I2X (2);
	fix h = (gameData.fusion.xFrameTime <= LOCALPLAYER.energy) ? gameData.fusion.xFrameTime : LOCALPLAYER.energy;
	gameData.SetFusionCharge (gameData.FusionCharge () + h);
	LOCALPLAYER.energy -= h;
	if (LOCALPLAYER.energy > 0) 
		gameData.fusion.xAutoFireTime = gameData.time.xGame + gameData.fusion.xFrameTime / 2 + 1;
	else {
		LOCALPLAYER.energy = 0;
		gameData.fusion.xAutoFireTime = gameData.time.xGame - 1;	//	Fire now!
		}
	if (gameStates.limitFPS.bFusion && !gameStates.app.tick40fps.bTick)
		return;

	float fScale = float (gameData.FusionCharge () >> 11) / 64.0f;
	tRgbaColorf* colorP = gameData.weapons.color + FUSION_ID;

	if (gameData.FusionCharge () < I2X (2)) 
		paletteManager.BumpEffect (colorP->red * fScale, colorP->green * fScale, colorP->blue * fScale);
	else 
		paletteManager.BumpEffect (colorP->blue * fScale, colorP->red * fScale, colorP->green * fScale);
	if (gameData.time.xGame < gameData.fusion.xLastSoundTime)		//gametime has wrapped
		gameData.fusion.xNextSoundTime = gameData.fusion.xLastSoundTime = gameData.time.xGame;
	if (gameData.fusion.xNextSoundTime < gameData.time.xGame) {
		if (gameData.FusionCharge () > I2X (2)) {
			audio.PlaySound (11);
			gameData.objs.consoleP->ApplyDamageToPlayer (gameData.objs.consoleP, d_rand () * 4);
			}
		else {
			CreateAwarenessEvent (gameData.objs.consoleP, WEAPON_ROBOT_COLLISION);
			audio.PlaySound (SOUND_FUSION_WARMUP);
			if (IsMultiGame)
				MultiSendPlaySound (SOUND_FUSION_WARMUP, I2X (1));
				}
		gameData.fusion.xLastSoundTime = gameData.time.xGame;
		gameData.fusion.xNextSoundTime = gameData.time.xGame + I2X (1) / 8 + d_rand () / 4;
		}
	gameData.fusion.xFrameTime = 0;
	}
}
Beispiel #2
0
// --------------------------------------------------------------------------------------------------------------------
//	Note: Parameter gameData.ai.vVecToPlayer is only passed now because guns which aren't on the forward vector from the
//	center of the robot will not fire right at the player.  We need to aim the guns at the player.  Barring that, we cheat.
//	When this routine is complete, the parameter gameData.ai.vVecToPlayer should not be necessary.
void AIFireLaserAtPlayer (CObject *objP, CFixVector *vFirePoint, int nGun, CFixVector *vBelievedPlayerPos)
{
	short				nShot, nObject = objP->Index ();
	tAILocalInfo	*ailP = gameData.ai.localInfo + nObject;
	tRobotInfo		*botInfoP = &ROBOTINFO (objP->info.nId);
	CFixVector		vFire;
	CFixVector		bpp_diff;
	short				nWeaponType;
	fix				aim, dot;
	int				count, i;

Assert (nObject >= 0);
//	If this robot is only awake because a camera woke it up, don't fire.
if (objP->cType.aiInfo.SUB_FLAGS & SUB_FLAGS_CAMERA_AWAKE)
	return;
if (!gameStates.app.cheats.bRobotsFiring)
	return;
if (objP->info.controlType == CT_MORPH)
	return;
//	If player is exploded, stop firing.
if (gameStates.app.bPlayerExploded)
	return;
if (objP->cType.aiInfo.xDyingStartTime)
	return;		//	No firing while in death roll.
//	Don't let the boss fire while in death roll.  Sorry, this is the easiest way to do this.
//	If you try to key the boss off objP->cType.aiInfo.xDyingStartTime, it will hose the endlevel stuff.
if (ROBOTINFO (objP->info.nId).bossFlag) {
	i = gameData.bosses.Find (nObject);
	if ((i < 0) || (gameData.bosses [i].m_nDyingStartTime))
		return;
	}
//	If CPlayerData is cloaked, maybe don't fire based on how long cloaked and randomness.
if (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) {
	fix	xCloakTime = gameData.ai.cloakInfo [nObject % MAX_AI_CLOAK_INFO].lastTime;
	if ((gameData.time.xGame - xCloakTime > CLOAK_TIME_MAX/4) &&
		 (d_rand () > FixDiv (gameData.time.xGame - xCloakTime, CLOAK_TIME_MAX)/2)) {
		SetNextFireTime (objP, ailP, botInfoP, nGun);
		return;
		}
	}
//	Handle problem of a robot firing through a CWall because its gun tip is on the other
//	CSide of the CWall than the robot's center.  For speed reasons, we normally only compute
//	the vector from the gun point to the player.  But we need to know whether the gun point
//	is separated from the robot's center by a CWall.  If so, don't fire!
if (objP->cType.aiInfo.SUB_FLAGS & SUB_FLAGS_GUNSEG) {
	//	Well, the gun point is in a different CSegment than the robot's center.
	//	This is almost always ok, but it is not ok if something solid is in between.
	int	nGunSeg = FindSegByPos (*vFirePoint, objP->info.nSegment, 1, 0);
	//	See if these segments are connected, which should almost always be the case.
	short nConnSide = SEGMENTS [nGunSeg].ConnectedSide (&SEGMENTS [objP->info.nSegment]);
	if (nConnSide != -1) {
		//	They are connected via nConnSide in CSegment objP->info.nSegment.
		//	See if they are unobstructed.
		if (!(SEGMENTS [objP->info.nSegment].IsDoorWay (nConnSide, NULL) & WID_FLY_FLAG)) {
			//	Can't fly through, so don't let this bot fire through!
			return;
			}
		}
	else {
		//	Well, they are not directly connected, so use FindVectorIntersection to see if they are unobstructed.
		tFVIQuery	fq;
		tFVIData		hit_data;
		int			fate;

		fq.startSeg			= objP->info.nSegment;
		fq.p0					= &objP->info.position.vPos;
		fq.p1					= vFirePoint;
		fq.radP0				=
		fq.radP1				= 0;
		fq.thisObjNum		= objP->Index ();
		fq.ignoreObjList	= NULL;
		fq.flags				= FQ_TRANSWALL;

		fate = FindVectorIntersection (&fq, &hit_data);
		if (fate != HIT_NONE) {
			Int3 ();		//	This bot's gun is poking through a CWall, so don't fire.
			MoveTowardsSegmentCenter (objP);		//	And decrease chances it will happen again.
			return;
			}
		}
	}
//	Set position to fire at based on difficulty level and robot's aiming ability
aim = I2X (FIRE_K) - (FIRE_K-1)* (botInfoP->aim << 8);	//	I2X (1) in bitmaps.tbl = same as used to be.  Worst is 50% more error.
//	Robots aim more poorly during seismic disturbance.
if (gameStates.gameplay.seismic.nMagnitude) {
	fix temp = I2X (1) - abs (gameStates.gameplay.seismic.nMagnitude);
	if (temp < I2X (1)/2)
		temp = I2X (1)/2;
	aim = FixMul (aim, temp);
	}
//	Lead the CPlayerData half the time.
//	Note that when leading the CPlayerData, aim is perfect.  This is probably acceptable since leading is so hacked in.
//	Problem is all robots will lead equally badly.
if (d_rand () < 16384) {
	if (LeadPlayer (objP, vFirePoint, vBelievedPlayerPos, nGun, &vFire))		//	Stuff direction to fire at in vFirePoint.
		goto player_led;
}

dot = 0;
count = 0;			//	Don't want to sit in this loop foreverd:\temp\dm_test.
i = (NDL - gameStates.app.nDifficultyLevel - 1) * 4;
while ((count < 4) && (dot < I2X (1)/4)) {
	bpp_diff[X] = (*vBelievedPlayerPos)[X] + FixMul ((d_rand ()-16384) * i, aim);
	bpp_diff[Y] = (*vBelievedPlayerPos)[Y] + FixMul ((d_rand ()-16384) * i, aim);
	bpp_diff[Z] = (*vBelievedPlayerPos)[Z] + FixMul ((d_rand ()-16384) * i, aim);
	CFixVector::NormalizedDir(vFire, bpp_diff, *vFirePoint);
	dot = CFixVector::Dot (objP->info.position.mOrient.FVec (), vFire);
	count++;
	}

player_led:

nWeaponType = botInfoP->nWeaponType;
if ((botInfoP->nSecWeaponType != -1) && ((nWeaponType < 0) || !nGun))
	nWeaponType = botInfoP->nSecWeaponType;
if (nWeaponType < 0)
	return;
if (0 > (nShot = CreateNewLaserEasy (&vFire, vFirePoint, objP->Index (), (ubyte) nWeaponType, 1)))
	return;

lightClusterManager.AddForAI (objP, nObject, nShot);
objP->Shots ().nObject = nShot;
objP->Shots ().nSignature = OBJECTS [nShot].info.nSignature;

if (IsMultiGame) {
	AIMultiSendRobotPos (nObject, -1);
	MultiSendRobotFire (nObject, objP->cType.aiInfo.CURRENT_GUN, &vFire);
	}
#if 1
if (++(objP->cType.aiInfo.CURRENT_GUN) >= botInfoP->nGuns) {
	if ((botInfoP->nGuns == 1) || (botInfoP->nSecWeaponType == -1))
		objP->cType.aiInfo.CURRENT_GUN = 0;
	else
		objP->cType.aiInfo.CURRENT_GUN = 1;
	}
#endif
CreateAwarenessEvent (objP, PA_NEARBY_ROBOT_FIRED);
SetNextFireTime (objP, ailP, botInfoP, nGun);
}
int FireWeaponDelayedWithSpread (
	CObject *objP,
	ubyte nLaserType,
	int nGun,
	fix xSpreadR,
	fix xSpreadU,
	fix xDelay,
	int bMakeSound,
	int bHarmless,
	short	nLightObj)
{
	short					nLaserSeg;
	int					nFate;
	CFixVector			vLaserPos, vLaserDir, *vGunPoints;
	CHitQuery			fq;
	CHitData				hitData;
	int					nObject;
	CObject*				laserP;
#if FULL_COCKPIT_OFFS
	int bLaserOffs = ((gameStates.render.cockpit.nType == CM_FULL_COCKPIT) &&
							(objP->Index () == LOCALPLAYER.nObject));
#else
	int bLaserOffs = 0;
#endif
	CFixMatrix				m;
	int						bSpectate = SPECTATOR (objP);
	tObjTransformation*	posP = bSpectate ? &gameStates.app.playerPos : &objP->info.position;

#if DBG
if (nLaserType == SMARTMINE_BLOB_ID)
	nLaserType = nLaserType;
#endif
CreateAwarenessEvent (objP, PA_WEAPON_WALL_COLLISION);
// Find the initial vPosition of the laser
if (!(vGunPoints = GetGunPoints (objP, nGun)))
	return 0;
TransformGunPoint (objP, vGunPoints, nGun, xDelay, nLaserType, &vLaserPos, &m);

//--------------- Find vLaserPos and nLaserSeg ------------------
fq.p0					= &posP->vPos;
fq.startSeg			= bSpectate ? gameStates.app.nPlayerSegment : objP->info.nSegment;
fq.p1					= &vLaserPos;
fq.radP0				=
fq.radP1				= 0x10;
fq.thisObjNum		= objP->Index ();
fq.ignoreObjList	= NULL;
fq.flags				= FQ_CHECK_OBJS | FQ_IGNORE_POWERUPS;
fq.bCheckVisibility = false;
nFate = FindHitpoint (&fq, &hitData);
nLaserSeg = hitData.hit.nSegment;
if (nLaserSeg == -1) {	//some sort of annoying error
	return -1;
	}
//SORT OF HACK... IF ABOVE WAS CORRECT THIS WOULDNT BE NECESSARY.
if (CFixVector::Dist (vLaserPos, posP->vPos) > 3 * objP->info.xSize / 2) {
	return -1;
	}
if (nFate == HIT_WALL) {
	return -1;
	}
#if 0
//as of 12/6/94, we don't care if the laser is stuck in an object. We
//just fire away normally
if (nFate == HIT_OBJECT) {
	if (OBJECTS [hitData.hitObject].nType == OBJ_ROBOT)
		OBJECTS [hitData.hitObject].Die ();
	if (OBJECTS [hitData.hitObject].nType != OBJ_POWERUP)
		return;
	}
#endif
//	Now, make laser spread out.
vLaserDir = m.FVec ();
if (xSpreadR || xSpreadU) {
	vLaserDir += m.RVec () * xSpreadR;
	vLaserDir += m.UVec () * xSpreadU;
	}
if (bLaserOffs)
	vLaserDir += m.UVec () * LASER_OFFS;
nObject = CreateNewWeapon (&vLaserDir, &vLaserPos, nLaserSeg, objP->Index (), nLaserType, bMakeSound);
//	Omega cannon is a hack, not surprisingly.  Don't want to do the rest of this stuff.
if (nLaserType == OMEGA_ID)
	return -1;
if (nObject == -1)
	return -1;
//TrackWeaponObject (nObject, int (objP->info.nId));
laserP = OBJECTS + nObject;
if ((nLaserType == GUIDEDMSL_ID) && gameData.multigame.bIsGuided)
	gameData.objs.guidedMissile [objP->info.nId].objP = laserP;
gameData.multigame.bIsGuided = 0;
if (gameData.objs.bIsMissile [nLaserType] && (nLaserType != GUIDEDMSL_ID)) {
	if (!gameData.objs.missileViewerP && (objP->info.nId == gameData.multiplayer.nLocalPlayer))
		gameData.objs.missileViewerP = laserP;
	}
//	If this weapon is supposed to be silent, set that bit!
if (!bMakeSound)
	laserP->info.nFlags |= OF_SILENT;
//	If this weapon is supposed to be silent, set that bit!
if (bHarmless)
	laserP->info.nFlags |= OF_HARMLESS;

//	If the object firing the laser is the CPlayerData, then indicate the laser object so robots can dodge.
//	New by MK on 6/8/95, don't let robots evade proximity bombs, thereby decreasing uselessness of bombs.
if ((objP == gameData.objs.consoleP) && !WeaponIsPlayerMine (laserP->info.nId))
	gameStates.app.bPlayerFiredLaserThisFrame = nObject;

if (gameStates.app.cheats.bHomingWeapons || gameData.weapons.info [nLaserType].homingFlag) {
	if (objP == gameData.objs.consoleP) {
		laserP->cType.laserInfo.nHomingTarget = FindHomingObject (&vLaserPos, laserP);
		gameData.multigame.laser.nTrack = laserP->cType.laserInfo.nHomingTarget;
		}
	else {// Some other CPlayerData shot the homing thing
		Assert (IsMultiGame);
		laserP->cType.laserInfo.nHomingTarget = gameData.multigame.laser.nTrack;
		}
	}
lightClusterManager.Add (nObject, nLightObj);
return nObject;
}