12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022 |
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2016 RWS Inc, All Rights Reserved
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of version 2 of the GNU General Public License as published by
- // the Free Software Foundation
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License along
- // with this program; if not, write to the Free Software Foundation, Inc.,
- // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- //
- // bulletFest.CPP
- // Project: Postal
- //
- // History:
- // 02/18/97 JMI Started.
- //
- // 02/19/97 JMI Now Ricochet(), Impact(), and Flare() create animations.
- //
- // 02/19/97 JMI Now Fire() and FireDeluxe() take all 3 CSmash masks.
- //
- // 02/19/97 JMI FireDeluxe(), forces impact, if terrain contact is off
- // of realm.
- //
- // 02/27/97 JMI In progress.
- //
- // 02/27/97 JMI Experimented with various ways of determining the terrain
- // angle but it is very difficult considering the attribute
- // maps granularity is 8!
- //
- // 02/27/97 JMI Forgot to remove feedback flag to preprocessor.
- //
- // 02/27/97 JMI Fongoolishness.
- //
- // 03/03/97 JMI Now uses QuickCheckClosest() instead of QuickCheck().
- //
- // 03/05/97 JMI Fixed rspMod360() usage to current.
- //
- // 03/10/97 JMI Added unimplemented UpdateTarget() stub.
- //
- // 03/21/97 JMI Added optional tracers.
- //
- // 03/21/97 BRH Fixed a small divide by zero error check.
- //
- // 04/02/97 JMI Changed ms_ati to m_ati.
- // Also, added ms_u8TracerIndex.
- // Also, removed all the edge info crap.
- // Also, added two additional ways of displaying tracers.
- //
- // 04/02/97 JMI Feedback now uses CSpriteLine2d.
- // Also, now uses mapping using 4 clusters &'d together
- // as an index to determine the terrain angle.
- // Does not seem to work.
- //
- // 04/02/97 JMI Switched back to METHOD 2 and fixed a divide by zero bug
- // in there. Also, reduced TRACER_MAX_LENGTH to 3.
- //
- // 04/10/97 BRH Updated this to work with the new multi layer attribute
- // maps.
- //
- // 04/24/97 JMI Added smid parameter specifying type of ammo noise to
- // FireDeluxe() and Flare().
- //
- // 04/29/97 JMI Fire() now allows bullets to go 10 pixels off the realm
- // to make it appear as if the edge of the realm has no
- // affect on them (except the bottom edge which is greater
- // so that, if the bullet is exceptionally high, it will
- // go, hopefully, entirely off screen).
- //
- // 05/29/97 JMI Removed references to m_pRealm->m_pAttribMap which no longer
- // exists.
- //
- // 06/11/97 JMI Added Preload() for loading assets used during play.
- //
- // 06/17/97 JMI Converted all occurrences of rand() to GetRand() and
- // srand() to SeedRand().
- //
- // 06/26/97 JMI Now uses pRealm->Map3Dto2D() in Fire() (was using
- // the global version defined in reality.h which is no more).
- //
- // 06/28/97 JMI Missed some Map3Dto2D()'s that were #if 0'ed out.
- //
- // 06/30/97 JMI Now uses CRealm's new GetRealmWidth() and *Height()
- // for dimensions of realm's X/Z plane.
- //
- // 07/01/97 JMI Now bases ricochets on GetRandom().
- //
- // 07/09/97 JMI Now uses m_pRealm->Make2dResPath() to get the fullpath
- // for 2D image components.
- //
- // 07/09/97 JMI Changed Preload() to take a pointer to the calling realm
- // as a parameter.
- //
- // 07/18/97 JMI Got rid of bogus immitation PlaySample functions.
- // Now there is one PlaySample() function. Also, you now
- // MUST specify a category and you don't have to specify a
- // SoundInstance ptr to specify a volume.
- //
- // 07/27/97 JMI No longer calls CRealm::Make2dResPath() on res names
- // given to CAnimThing as it already does that
- // automatically.
- //
- // 08/20/97 BRH Changed ricochet sounds to Weapon volume control
- // instead of destruction.
- //
- // 09/18/97 JMI UpdateTracerColor() now takes a realm ptr and now is
- // color mapped on the first Fire() call.
- //
- //////////////////////////////////////////////////////////////////////////////
- //
- // bulletFest handles launching of bullets. Currently it doesn't seem like
- // much more than a function call, but eventually it will need to keep track
- // of some per instance data.
- //
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // C Headers -- Must be included before RSPiX.h b/c RSPiX utilizes SHMalloc.
- //////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- // RSPiX Headers.
- ///////////////////////////////////////////////////////////////////////////////
- #include "RSPiX.h"
- //////////////////////////////////////////////////////////////////////////////
- // Postal headers.
- //////////////////////////////////////////////////////////////////////////////
- #include "bulletFest.h"
- #include "AnimThing.h"
- #include "SampleMaster.h"
- #include "reality.h"
- //////////////////////////////////////////////////////////////////////////////
- // Module specific macros.
- //////////////////////////////////////////////////////////////////////////////
- #define IMPACT_RES_NAME "Ricochet.aan"
- #define RICOCHET_RES_NAME "Ricochet.aan"
- #define FLARE_RES_NAME "MuzzleFlare.aan"
- #define TERRAIN_CHECK_DIST 1
- #define TERRAIN_CHECK_GRANULARITY 4
- #define TRACER_COLOR_RED 250
- #define TRACER_COLOR_GREEN 200
- #define TRACER_COLOR_BLUE 50
- // The color range that is the same on all hoods.
- #define CONSTANT_COLOR_START_INDEX 95
- #define NUM_CONSTANT_COLOR_INDICES (256 - CONSTANT_COLOR_START_INDEX - 10)
- #define TRACER_WRAP_DISTANCE 10
- #define TRACER_MAX_LENGTH 3
- #define LEFT_TOP 0x1
- #define RIGHT_TOP 0x2
- #define LEFT_BOTTOM 0x4
- #define RIGHT_BOTTOM 0x8
- // This is done as a mask instead of a mod for speed.
- // Note that 0xFFFF is 100% of the time, 0x00FF is 50%, etc.
- // Chances are number of set bits out of 16.
- #define RICOCHET_CHANCE_MASK 0x0001
- #define BULLET_SND_HALF_LIFE 1000
- //////////////////////////////////////////////////////////////////////////////
- // Module specific typedefs.
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // Exported (extern) variables.
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // Module specific (static) variables / Instantiate class statics.
- //////////////////////////////////////////////////////////////////////////////
- U8 CBulletFest::ms_u8TracerIndex = 0; // The color index to use for tracers.
- // This value is gotten only once per
- // execution of this program; therefore,
- // it is gotten from the group of colors
- // that don't change from hood to hood.
- // Maps a combination of bits to an angle.
- // Each bit set to 1 indicates the terrain in that location is higher than
- // the specified height.
- // Less than 2 bits set is considered not enough info.
- // 2 diagonally adjacent bits is considered not enough info.
- static short ms_asTerrainAngleMap[16] =
- {
- -1, // 0000 ==
- -1, // 0001 == LEFT_TOP
- -1, // 0010 == RIGHT_TOP
- 0, // 0011 == RIGHT_TOP | LEFT_TOP
- -1, // 0100 == LEFT_BOTTOM
- 90, // 0101 == LEFT_BOTTOM | LEFT_TOP
- -1, // 0110 == LEFT_BOTTOM | RIGHT_TOP
- 45, // 0111 == LEFT_BOTTOM | RIGHT_TOP | LEFT_TOP
- -1, // 1000 == RIGHT_BOTTOM
- -1, // 1001 == RIGHT_BOTTOM | LEFT_TOP
- 270, // 1010 == RIGHT_BOTTOM | RIGHT_TOP
- 315, // 1011 == RIGHT_BOTTOM | RIGHT_TOP | LEFT_TOP
- 180, // 1100 == RIGHT_BOTTOM | LEFT_BOTTOM
- 135, // 1101 == RIGHT_BOTTOM | LEFT_BOTTOM | LEFT_TOP
- 225, // 1110 == RIGHT_BOTTOM | LEFT_BOTTOM | RIGHT_TOP
- -1, // 1111 == RIGHT_BOTTOM | LEFT_BOTTOM | RIGHT_TOP | LEFT_TOP
- };
- //////////////////////////////////////////////////////////////////////////////
- // Module specific (static) protos.
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // Functions.
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // Get max height in a rectangle.
- //////////////////////////////////////////////////////////////////////////////
- inline
- short GetMaxHeight(
- CRealm* pRealm, // In: Realm in question.
- short sX, // In: X position on terrain.
- short sZ, // In: Z position on terrain.
- short sW, // In: Amount in X direction.
- short sH) // In: Amount in Z direction.
- {
- short sX2 = sX + sW;
- short sZ2 = sZ + sH;
- short sIterX;
- short sIterZ;
- short sMaxHeight = -32767;
- for (sIterZ = sZ; sIterZ < sZ2; sIterZ++)
- {
- for (sIterX = sX; sIterX < sX2; sIterX++)
- {
- // Relying on NON-macro MAX (macro MAX would evaluate one of the paramters
- // twice).
- sMaxHeight = MAX(sMaxHeight, pRealm->GetHeight(sIterX, sIterZ));
- #if 0
- // FEEDBACK.
- // Create a line sprite.
- CSpriteLine2d* psl2d = new CSpriteLine2d;
- if (psl2d != NULL)
- {
- psl2d->m_sX2 = sIterX,
- psl2d->m_sY2 = sIterZ;
- psl2d->m_sX2End = sIterX + 1;
- psl2d->m_sY2End = sIterZ + 1;
- psl2d->m_sPriority = 0;
- psl2d->m_sLayer = CRealm::GetLayerViaAttrib(m_pRealm->GetLayer(sIterX, sIterZ));
- psl2d->m_u8Color = 250;
- // Destroy when done.
- psl2d->m_sInFlags = CSprite::InDeleteOnRender;
- // Put 'er there.
- pRealm->m_scene.UpdateSprite(psl2d);
- }
- #endif
- }
- }
- return sMaxHeight;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Take a point inside terrain and find our way out via X/Z plane.
- // Once out, scan along terrain to determine the angle of the terrain that
- // exceeds sY in height.
- // ASSUMPTION: sX, sY, sZ is a point inside terrain.
- //
- //////////////////////////////////////////////////////////////////////////////
- inline
- bool GetTerrainAngle( // true, if terrain angle determined.
- // false, if not enough iterations available to
- // determine angle.
- CRealm* pRealm, // In: Realm in question.
- short sX, // In: X position on terrain.
- short sY, // In: Y position on terrain.
- short sZ, // In: Z position on terrain.
- short sMaxOutIterations, // In: Max iterations to get out of terrain
- // (i.e., find terrain edge).
- short sNumScanIterations, // In: Num iterations to scan edge of terrain
- // in EACH direction.
- short sInAngle, // In: Angle from which object entered terrain.
- // This angle + 180 is used to scan out.
- short* psAngle) // Out: Angle of terrain at specified location
- // on X/Z plane.
- {
- bool bFoundAngle = false; // Assume not found.
- #if 0 // NOT WORKING CORRECTLY.
- ////////////////////// Get out of terrain /////////////////////////////////
-
- sInAngle = rspMod360(sInAngle);
- // Determine rate to get in deeper.
- float fInRateX = COSQ[sInAngle];
- float fInRateZ = -SINQ[sInAngle];
- // Get angles to get out.
- short sOutAngle = rspMod360(90 + sInAngle); // 180 + sInAngle - 90
- // Determine proper rate to get out of terrain.
- float fRateX = COSQ[sOutAngle]/* * pRealm->m_pAttribMap->m_sScaleX*/;
- float fRateZ = -SINQ[sOutAngle]/* * pRealm->m_pAttribMap->m_sScaleY*/;
- const float fInMult = (sMaxOutIterations - 3);
- // Set initial position inside terrain.
- float fPosX = sX + fInRateX * fInMult;
- float fPosZ = sZ + fInRateZ * fInMult;
- // Store extents.
- short sMaxX = pRealm->GetRealmWidth();
- short sMaxZ = pRealm->GetRealmHeight();
-
- short sIterations = 0;
- // Quicker access to attribute map for loop.
- RAttributeMap* pattrib = pRealm->m_pAttribMap;
- short sTerrainH;
- bool bGotOut = false;
- // Scan while in realm.
- while (
- fPosX > 0.0
- && fPosZ > 0.0
- && fPosX < sMaxX
- && fPosZ < sMaxZ
- && sIterations < sMaxOutIterations)
- {
- sTerrainH = m_pRealm->GetHeight((short) fPosX, (short) fPosZ);
- // If above terrain . . .
- if (sY > sTerrainH)
- {
- bGotOut = true;
- // fPosX -= fRateX;
- // fPosZ -= fRateZ;
- break;
- }
- fPosX += fRateX;
- fPosZ += fRateZ;
- sIterations++;
- }
- // If we did not find our way out . . .
- if (bGotOut == false)
- {
- sOutAngle = rspMod360(270 + sInAngle); // 180 + sInAngle + 90
- fRateX = COSQ[sOutAngle]/* * pRealm->m_pAttribMap->m_sScaleX*/;
- fRateZ = -SINQ[sOutAngle]/* * pRealm->m_pAttribMap->m_sScaleY*/;
- fPosX = sX + fInRateX * fInMult;
- fPosZ = sZ + fInRateZ * fInMult;
- sIterations = 0;
- // Scan while in realm.
- while (
- fPosX > 0.0
- && fPosZ > 0.0
- && fPosX < sMaxX
- && fPosZ < sMaxZ
- && sIterations < sMaxOutIterations)
- {
- sTerrainH = m_pRealm->GetHeight((short) fPosX, (short) fPosZ);
- // If above terrain . . .
- if (sY > sTerrainH)
- {
- bGotOut = true;
- // fPosX -= fRateX;
- // fPosZ -= fRateZ;
- break;
- }
- fPosX += fRateX;
- fPosZ += fRateZ;
- sIterations++;
- }
- }
- // If we found our way out in either case . . .
- if (bGotOut == true)
- {
- // Determine angle of a line between the two points.
- short sDeltaX = fPosX - (sX - fInRateX);
- short sDeltaZ = (sZ - fInRateZ) - fPosZ;
- *psAngle = rspATan(sDeltaX, sDeltaZ);
- // Found angle.
- bFoundAngle = true;
- }
- #else
- // Check 4 surrounding points.
- short sIndex = 0;
- if (GetMaxHeight(pRealm, sX - TERRAIN_CHECK_DIST - TERRAIN_CHECK_GRANULARITY / 2, sZ - TERRAIN_CHECK_DIST - TERRAIN_CHECK_GRANULARITY / 2, TERRAIN_CHECK_GRANULARITY, TERRAIN_CHECK_GRANULARITY) > sY)
- sIndex = LEFT_TOP;
- if (GetMaxHeight(pRealm, sX + TERRAIN_CHECK_DIST + TERRAIN_CHECK_GRANULARITY / 2, sZ - TERRAIN_CHECK_DIST - TERRAIN_CHECK_GRANULARITY / 2, TERRAIN_CHECK_GRANULARITY, TERRAIN_CHECK_GRANULARITY) > sY)
- sIndex |= RIGHT_TOP;
- if (GetMaxHeight(pRealm, sX - TERRAIN_CHECK_DIST - TERRAIN_CHECK_GRANULARITY / 2, sZ + TERRAIN_CHECK_DIST + TERRAIN_CHECK_GRANULARITY / 2, TERRAIN_CHECK_GRANULARITY, TERRAIN_CHECK_GRANULARITY) > sY)
- sIndex |= LEFT_BOTTOM;
- if (GetMaxHeight(pRealm, sX + TERRAIN_CHECK_DIST + TERRAIN_CHECK_GRANULARITY / 2, sZ + TERRAIN_CHECK_DIST + TERRAIN_CHECK_GRANULARITY / 2, TERRAIN_CHECK_GRANULARITY, TERRAIN_CHECK_GRANULARITY) > sY)
- sIndex |= RIGHT_BOTTOM;
- // Get terrain angle.
- *psAngle = ms_asTerrainAngleMap[sIndex];
- if (*psAngle > -1)
- {
- bFoundAngle = true;
- }
- #endif
- return bFoundAngle;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Launch a bullet, create a muzzle flare at the src (sX, sY, sZ), and,
- // if no CThing hit, create a ricochet at where the bullet contacted
- // terrain (*psX, *psY, *psZ).
- // This same process can be done in pieces with more control to the user
- // by calling Fire(), Flare(), and Ricochet().
- //
- //////////////////////////////////////////////////////////////////////////////
- bool CBulletFest::FireDeluxe( // Returns what and as Fire() would.
- short sAngleY, // In: Angle of launch in degrees (on X/Z plane).
- short sAngleZ, // In: Angle of launch in degrees (on X/Y plane).
- short sX, // In: Launch position.
- short sY, // In: Launch position.
- short sZ, // In: Launch position.
- short sRange, // In: Maximum distance.
- CRealm* pRealm, // In: Realm in which to fire.
- CSmash::Bits bitsInclude, // In: Mask of CSmash masks that this bullet can hit.
- CSmash::Bits bitsDontCare, // In: Mask of CSmash masks that this bullet does not care to hit.
- CSmash::Bits bitsExclude, // In: Mask of CSmash masks that this bullet cannot hit.
- short sMaxRicochetAngle, // In: Maximum angle with terrain that can cause
- // a ricochet (on X/Z plane).
- short sMaxRicochets, // In: The maximum number of ricochets.
- short* psX, // Out: Hit position.
- short* psY, // Out: Hit position.
- short* psZ, // Out: Hit position.
- CThing** ppthing, // Out: Ptr to thing hit or NULL.
- bool bTracer /*= true*/, // In: Draw a tracer at random point along path.
- SampleMasterID smid /*= g_smidBulletFire*/) // In: Use ammo sample.
- {
- bool bHit = false; // Assume no collision with CThing within u32ThingMask.
- // Create a muzzle flare.
- Flare(sAngleY, sX, sY, sZ, pRealm, smid);
- short sRicochets = 0;
- bool bImpact = false;
- short sTerrainAngle = 0;
- // While no hits and not out of ricochets . . .
- while (bHit == false && sRicochets <= sMaxRicochets && bImpact == false)
- {
- sAngleY = rspMod360(sAngleY);
- bHit = Fire(
- sAngleY, // In: Angle of launch in degrees (on X/Z plane).
- sAngleZ, // In: Angle of launch in degrees (on X/Y plane).
- sX, // In: Launch position.
- sY, // In: Launch position.
- sZ, // In: Launch position.
- sRange, // In: Maximum distance.
- pRealm, // In: Realm in which to fire.
- bitsInclude, // In: Mask of CSmash masks that this bullet can hit.
- bitsDontCare, // In: Mask of CSmash masks that this bullet does not care to hit.
- bitsExclude, // In: Mask of CSmash masks that this bullet cannot hit.
- psX, // Out: Hit position.
- psY, // Out: Hit position.
- psZ, // Out: Hit position.
- ppthing, // Out: Ptr to thing hit or NULL.
- bTracer); // In: Draw a tracer at random point along path.
- // If no hit . . .
- if (bHit == false)
- {
- // If on screen . . .
- if ( *psX > 0 && *psX < pRealm->GetRealmWidth()
- && *psZ > 0 && *psZ - *psY < pRealm->GetRealmHeight() )
- {
- #if 0
- // If out of ricochets . . .
- if (sRicochets >= sMaxRicochets)
- {
- // Impact.
- bImpact = true;
- }
- else
- {
- if (GetTerrainAngle(pRealm, *psX, *psY, *psZ, 10, 10, sAngleY, &sTerrainAngle) == true)
- {
- // Check for ricochet. If our contact angle is within sMaxRicochetAngle
- // of terrain angle . . .
- short sAngleDif = sTerrainAngle - sAngleY;
- if (ABS(sAngleDif) > sMaxRicochetAngle)
- {
- bImpact = true;
- }
- else
- {
- sAngleY = sTerrainAngle + sAngleDif;
- }
-
- #if 0
- // Might have to break this into four quadrants.
- // This works for the case when sAngle is in quadrant 1
- // and sTerrainAngle is in quadrant 2.
- short sAngleDif = (180 - sTerrainAngle) + sAngleY;
- if (sAngleDif > 90)
- {
- sAngleDif = 180 - sAngleDif;
- }
- if (sAngleDif > sMaxRicochetAngle)
- {
- // Impact.
- bImpact = true;
- }
- else // Ricochet.
- {
- // **** Determine deflection angle here.
- sAngleY = 360 - sAngleDif;
- }
- #endif
- }
- else
- {
- bImpact = true;
- }
- }
- // If impacting . . .
- if (bImpact == true)
- {
- // Impact at angle of shot.
- Impact(sAngleY, *psX, *psY, *psZ, pRealm);
- }
- else
- {
- // Ricochet at angle of deflection.
- Ricochet(sAngleY, *psX, *psY, *psZ, pRealm);
- sX = *psX;
- sY = *psY;
- sZ = *psZ;
- }
- #else
- // Ricochet is random.
- if (GetRandom() & RICOCHET_CHANCE_MASK)
- {
- // Impact at angle of shot.
- Impact(sAngleY, *psX, *psY, *psZ, pRealm);
- }
- else
- {
- // Ricochet at angle of deflection.
- Ricochet(sAngleY, *psX, *psY, *psZ, pRealm);
- }
- // Always stop though.
- bImpact = true;
- #endif
- }
- }
- sRicochets++;
- }
- return bHit;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Create a muzzle flare effect.
- //
- //////////////////////////////////////////////////////////////////////////////
- void CBulletFest::Flare( // Returns nothing.
- short sAngle, // In: Angle of launch in degrees (on X/Z plane).
- short sX, // In: Launch position.
- short sY, // In: Launch position.
- short sZ, // In: Launch position.
- CRealm* pRealm, // In: Realm in which to fire.
- SampleMasterID smid /*= g_smidBulletFire*/) // In: Use ammo sample.
- {
- // Create the animator . . .
- CAnimThing* pat = new CAnimThing(pRealm);
- ASSERT(pat != NULL);
- strcpy(pat->m_szResName, FLARE_RES_NAME);
- // Start it up:
- // No looping.
- pat->m_sLoop = FALSE;
- // No notification necessary.
- // NOTE: sAngle is currently not utilized.
- pat->Setup(sX, sY, sZ);
- // Start sample.
- PlaySample(
- smid,
- SampleMaster::Weapon,
- DistanceToVolume(sX, sY, sZ, BULLET_SND_HALF_LIFE) );
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Create a impact effect.
- //
- //////////////////////////////////////////////////////////////////////////////
- void CBulletFest::Impact( // Returns nothing.
- short sAngle, // In: Angle of launch in degrees (on X/Z plane).
- short sX, // In: Launch position.
- short sY, // In: Launch position.
- short sZ, // In: Launch position.
- CRealm* pRealm) // In: Realm in which to fire.
- {
- // Create the animator . . .
- CAnimThing* pat = new CAnimThing(pRealm);
- ASSERT(pat != NULL);
- strcpy(pat->m_szResName, IMPACT_RES_NAME);
- // Start it up:
- // No looping.
- pat->m_sLoop = FALSE;
- // No notification necessary.
- // NOTE: sAngle is currently not utilized.
- pat->Setup(sX, sY, sZ);
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Create a ricochet effect.
- //
- //////////////////////////////////////////////////////////////////////////////
- void CBulletFest::Ricochet( // Returns nothing.
- short sAngle, // In: Angle of launch in degrees (on X/Z plane).
- short sX, // In: Launch position.
- short sY, // In: Launch position.
- short sZ, // In: Launch position.
- CRealm* pRealm) // In: Realm in which to fire.
- {
- // Create the animator . . .
- CAnimThing* pat = new CAnimThing(pRealm);
- ASSERT(pat != NULL);
- strcpy(pat->m_szResName, RICOCHET_RES_NAME);
- // Start it up:
- // No looping.
- pat->m_sLoop = FALSE;
- // No notification necessary.
- // NOTE: sAngle is currently not utilized.
- pat->Setup(sX, sY, sZ);
- // Start sample.
- PlaySample(
- (GetRand() % 2) ? g_smidRicochet1 : g_smidRicochet2,
- SampleMaster::Weapon,
- DistanceToVolume(sX, sY, sZ, BULLET_SND_HALF_LIFE) );
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Launch a bullet.
- //
- //////////////////////////////////////////////////////////////////////////////
- bool CBulletFest::Fire( // Returns true if a hit, false otherwise.
- short sAngleY, // In: Angle of launch in degrees (on X/Z plane).
- short sAngleZ, // In: Angle of launch in degrees (on X/Y plane).
- short sX, // In: Launch position.
- short sY, // In: Launch position.
- short sZ, // In: Launch position.
- short sRange, // In: Maximum distance.
- CRealm* pRealm, // In: Realm in which to fire.
- CSmash::Bits bitsInclude, // In: Mask of CSmash masks that this bullet can hit.
- CSmash::Bits bitsDontCare, // In: Mask of CSmash masks that this bullet does not care to hit.
- CSmash::Bits bitsExclude, // In: Mask of CSmash masks that this bullet cannot hit.
- short* psX, // Out: Hit position.
- short* psY, // Out: Hit position.
- short* psZ, // Out: Hit position.
- CThing** ppthing, // Out: Ptr to thing hit or NULL.
- bool bTracer /*= true*/) // In: Draw a tracer at random point along path.
- {
- bool bHit = false; // Assume no collision with CThing within u32ThingMask.
- // If tracer color not yet color mapped . . .
- if (ms_u8TracerIndex == 0)
- {
- UpdateTracerColor(pRealm);
- }
-
- /////////// Determine length of travel if no CThings hit ///////////////////
- // Get most efficient increments that won't miss any attributes.
- // For the rates we use trig with a hypotenuse of 1 which will give
- // us a rate <= 1.0 and then multiply by the scaling of the map for
- // a reasonable doubling or so of the speed of this alg.
-
- // sAngle must be between 0 and 359.
- sAngleY = rspMod360(sAngleY);
- sAngleZ = rspMod360(sAngleZ);
- float fRateX = COSQ[sAngleY]/* * pRealm->m_pAttribMap->m_sScaleX*/;
- float fRateZ = -SINQ[sAngleY]/* * pRealm->m_pAttribMap->m_sScaleY*/;
- float fRateY = SINQ[sAngleZ];
- // Determine amount traveled per iteration just once.
- float fIterDist = sqrt(ABS2(fRateX, fRateY, fRateZ) );
- // Set initial position to first point to check (NEVER checks original position).
- float fPosX = sX + fRateX;
- float fPosY = sY + fRateY;
- float fPosZ = sZ + fRateZ;
- float fTotalDist = 0.0F;
- // Store extents allowing bullets to go 10 pixels off each boundary.
- // This makes them appear to be unhindered by the edge of the realm.
- // (except the bottom edge which is greater so that, if the bullet
- // is exceptionally high, it will go, hopefully, entirely off screen).
- short sMaxX = pRealm->GetRealmWidth() + 10;
- short sMaxY = 512; // Robustness: Guard against infinite loop
- // in the remote possibility that we shoot
- // straight up (currently one can only shoot
- // horizontally).
- short sMaxZ = pRealm->GetRealmHeight() + sY + 10;
- short sMinX = -10;
- short sMinY = -512;
- short sMinZ = -10;
- short sCurH;
- // Scan while in realm.
- while (
- fPosX > sMinX
- && fPosY > sMinY
- && fPosZ > sMinZ
- && fPosX < sMaxX
- && fPosY < sMaxY
- && fPosZ < sMaxZ)
- {
- sCurH = pRealm->GetHeight((short) fPosX, (short) fPosZ);
- // If bullet below or at terrain . . .
- if (fPosY <= sCurH)
- {
- break;
- }
- // If we've exceeded range . . .
- if (fTotalDist > sRange)
- {
- // Drop bullet via gravity.
- fPosY -= 1.0; // FUDGE!
- }
- fPosX += fRateX;
- fPosY += fRateY;
- fPosZ += fRateZ;
- fTotalDist += fIterDist;
- }
- // Create 3D line segment.
- R3DLine line;
- line.X1 = sX;
- line.Y1 = sY;
- line.Z1 = sZ;
- line.X2 = fPosX;
- line.Y2 = fPosY;
- line.Z2 = fPosZ;
- // Determine if anything with mask u32ThingMask was hit . . .
- CSmash* psmash;
- if (pRealm->m_smashatorium.QuickCheckClosest(
- &line,
- bitsInclude,
- bitsDontCare,
- bitsExclude,
- &psmash) == true)
- {
- // Set *ppthing to thing hit.
- *ppthing = psmash->m_pThing;
- bHit = true;
- // Set end pt.
- *psX = psmash->m_sphere.sphere.X;
- *psY = psmash->m_sphere.sphere.Y;
- *psZ = psmash->m_sphere.sphere.Z;
- }
- else
- {
- // Clear thing ptr.
- *ppthing = NULL;
- // Set end pt.
- *psX = fPosX;
- *psY = fPosY;
- *psZ = fPosZ;
- }
- if (bTracer == true)
- {
- // Create a line sprite.
- CSpriteLine2d* psl2d = new CSpriteLine2d;
- if (psl2d != NULL)
- {
- // Get distance. Since an interception may have occurred, we need to redetermine the
- // distance.
- // We use one coordinate of the end point against one coordinate of the interception point
- // to get a ratio and apply that to the total distance.
- short sDistance = 0;
- if (fPosX - sX != 0.0)
- {
- sDistance = fTotalDist * ((*psX - sX) / (fPosX - sX));
- }
- #define METHOD 2
- #define TRACER_ACCUMMULATION_STEP_MAX 80
- #define TRACER_ACCUMMULATION_STEP_MIN 10
- short sRand = 0;
- #if METHOD == 1 // Method 1: Random dist between here and there.
-
- if (sDistance != 0)
- {
- sRand = GetRand() % sDistance;
- }
- #elif METHOD == 2 // Method 2: Cummulating position with wrapping.
- if (sDistance != 0)
- {
- sRand = m_sCurTracerPos = (m_sCurTracerPos + GetRand() % TRACER_ACCUMMULATION_STEP_MAX) % sDistance;
- }
- #else METHOD == 3 // Method 3: Multiple Method 1 and Method 2's.
-
- // Reduce distance.
- sDistance -= TRACER_ACCUMMULATION_STEP_MAX;
- while (sRand < sDistance)
- {
- sRand += (GetRand() % (TRACER_ACCUMMULATION_STEP_MAX - TRACER_ACCUMMULATION_STEP_MIN)) + TRACER_ACCUMMULATION_STEP_MIN;
- // If no current sprite . . .
- if (psl2d == NULL)
- {
- // Create a line sprite.
- psl2d = new CSpriteLine2d;
- }
- // If we have a sprite . . .
- if (psl2d != NULL)
- {
- #endif
- short sRand2 = GetRand() % TRACER_MAX_LENGTH;
- float fStartX = sX + fRateX * sRand;
- float fStartY = sY + fRateY * sRand;
- float fStartZ = sZ + fRateZ * sRand;
- pRealm->Map3Dto2D(
- fStartX,
- fStartY,
- fStartZ,
- &(psl2d->m_sX2),
- &(psl2d->m_sY2) );
- pRealm->Map3Dto2D(
- fStartX + fRateX * sRand2,
- fStartY + fRateY * sRand2,
- fStartZ + fRateZ * sRand2,
- &(psl2d->m_sX2End),
- &(psl2d->m_sY2End) );
- psl2d->m_sPriority = fStartZ;
- psl2d->m_sLayer = CRealm::GetLayerViaAttrib(pRealm->GetLayer((short) fStartX, (short) fStartZ));
- psl2d->m_u8Color = ms_u8TracerIndex;
- // Destroy when done.
- psl2d->m_sInFlags = CSprite::InDeleteOnRender;
- // Put 'er there.
- pRealm->m_scene.UpdateSprite(psl2d);
- #if METHOD == 3
-
- // Done with this 'sprite'.
- psl2d = NULL;
- }
- }
- #endif
- }
- else
- {
- TRACE("Fire(): Unable to allocate CSpriteLine2d.\n");
- }
- }
- #if 0
- // FEEDBACK.
- // Create a line sprite.
- CSpriteLine2d* psl2d = new CSpriteLine2d;
- if (psl2d != NULL)
- {
- pRealm->Map3Dto2D(
- sX,
- sY,
- sZ,
- &(psl2d->m_sX2),
- &(psl2d->m_sY2) );
- pRealm->Map3Dto2D(
- sX + fRateX * fTotalDist,
- sY + fRateY * fTotalDist,
- sZ + fRateZ * fTotalDist,
- &(psl2d->m_sX2End),
- &(psl2d->m_sY2End) );
- psl2d->m_sPriority = sZ;
- psl2d->m_sLayer = CRealm::GetLayerViaAttrib(pRealm->GetLayer(sX, sZ));
- psl2d->m_u8Color = ms_u8TracerIndex;
- // Destroy when done.
- psl2d->m_sInFlags = CSprite::InDeleteOnRender;
- // Put 'er there.
- pRealm->m_scene.UpdateSprite(psl2d);
- }
- #endif
- return bHit;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Update current targeting information. This will function will
- // continually track the position of a target in order to determine
- // how much it is moving. The idea being that targets that move
- // irratically(sp?) and more often are harder to hit.
- ///////////////////////////////////////////////////////////////////////////////
- void CBulletFest::UpdateTarget( // Returns nothing.
- short sAngle, // In: Angle of aim in degrees (on X/Z plane).
- short sX, // In: Aim position.
- short sY, // In: Aim position.
- short sZ, // In: Aim position.
- CRealm* pRealm) // In: Realm in which to target.
- {
- // NYI!
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Updates the static tracer color.
- // (static)
- ///////////////////////////////////////////////////////////////////////////////
- void CBulletFest::UpdateTracerColor(
- CRealm* prealm) // In: Calling realm.
- {
- ASSERT(prealm->m_phood);
- ASSERT(prealm->m_phood->m_pimBackground);
- ASSERT(prealm->m_phood->m_pimBackground->m_pPalette);
- RPal* ppal = prealm->m_phood->m_pimBackground->m_pPalette;
- ms_u8TracerIndex = rspMatchColorRGB( // Out: Matched index.
- TRACER_COLOR_RED, // In: Pixel's red value.
- TRACER_COLOR_GREEN, // In: Pixel's green value.
- TRACER_COLOR_BLUE, // In: Pixel's blue value.
- CONSTANT_COLOR_START_INDEX, // In: Min mappable index (affects source).
- // Do NOT include the top 10 windows colors!
- NUM_CONSTANT_COLOR_INDICES, // In: Num mappable indices (affects source).
- ppal->Red(0), // In: Beginning of red color table.
- ppal->Green(0), // In: Beginning of green color table.
- ppal->Blue(0), // In: Beginning of blue color table.
- ppal->GetPalEntrySize() // In: Size to increment between each index in each table.
- );
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Preload any assets that may be used.
- // (static).
- ///////////////////////////////////////////////////////////////////////////////
- short CBulletFest::Preload(
- CRealm* prealm) // In: Calling realm.
- {
- CAnimThing::ChannelAA* paaCache;
- short sResult = 0;
- if (rspGetResource(&g_resmgrGame, prealm->Make2dResPath(IMPACT_RES_NAME), &paaCache) == 0)
- rspReleaseResource(&g_resmgrGame, &paaCache);
- else
- sResult |= 1;
- if (rspGetResource(&g_resmgrGame, prealm->Make2dResPath(RICOCHET_RES_NAME), &paaCache) == 0)
- rspReleaseResource(&g_resmgrGame, &paaCache);
- else
- sResult |= 1;
-
- if (rspGetResource(&g_resmgrGame, prealm->Make2dResPath(FLARE_RES_NAME), &paaCache) == 0)
- rspReleaseResource(&g_resmgrGame, &paaCache);
- else
- sResult |= 1;
- return sResult;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // EOF
- ///////////////////////////////////////////////////////////////////////////////
|