home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Learn 3D Graphics Programming on the PC
/
Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso
/
rwdos
/
ratrophy.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-15
|
36KB
|
1,117 lines
/**********************************************************************
*
* File : ratrophy.c
*
* Abstract : The rat and trophy bit handler. This module handles
* the movement and display of the rats and the trophy that
* appears once all the rats are destroyed.
*
**********************************************************************
*
* This file is a product of Criterion Software Ltd.
*
* This file is provided as is with no warranties of any kind and is
* provided without any obligation on Criterion Software Ltd. or
* Canon Inc. to assist in its use or modification.
*
* Criterion Software Ltd. will not, under any
* circumstances, be liable for any lost revenue or other damages arising
* from the use of this file.
*
* Copyright (c) 1995 Criterion Software Ltd.
* All Rights Reserved.
*
* RenderWare is a trademark of Canon Inc.
*
************************************************************************/
/*--- Include Files ---*/
#include "global.h" /* Application general includes */
#define TARGET_HITFORCE 0.3 /* Objects that are hit move at this velocity */
#define RAT_CREATE_TIME 200 /* No of frames before a new rat is created */
/* Rat State definitions: These are the different ways that a rat can move */
#define RAT_WAIT 1
#define RAT_TURN_LEFT 2
#define RAT_TURN_RIGHT 3
#define RAT_LOOK 4
#define RAT_FORWARD 5
#define RAT_MOVE_SIZE 0.15 /* Once a rat gets this close to a wall or
the ground it bounces */
#define RAT_TRAP_SIZE 0.05 /* If the rat is on the ground and it gets
this close to a wall or the kerb then
change its behaviour */
#define TROPHY_MOVE_SIZE 0.5 /* Once the trophy gets this close to a wall
or the ground it bounces */
/* The start position for the trophy when it enters the street */
#define TROPHY_X 0.0
#define TROPHY_Y 4.0
#define TROPHY_Z 2.0
#define RAT_START_HEIGHT 4.0 /* The height that the rats fall from */
#define RAT_SPEED 0.02 /* The speed that rats move forward at */
#define RAT_HITS 4 /* The number of hits that a rat can take
before it explodes */
#define RAT_BOUNCE (-1.0/4.0) /* Change in velocity for a rat when it
bounces off of a wall or the ground */
#define RAT_FRICTION (1.0/4.0) /* When a rat bounces of the ground, its
forward momentum is damped by this amount */
#define RAT_MAX_FRAMES 7 /* the number of different clumps that
make up the rat animation */
#define GROUND_TRAP 0.01 /* When a rat gets this close to the
ground it behaves as though it is
on the ground */
/* All Rats: A single global variable of this type is defined. It holds all
* of the rat related items that are shared across mulitple instances
*/
typedef struct
{
RwClump *cpaFrames[RAT_MAX_FRAMES]; /* Rat animation clumps */
RwClump *cpShadow; /* Rat shadow clumps */
RwMatrix4d *mpTurnLeft; /* Matrix for a rat turning left */
RwMatrix4d *mpTurnRight; /* Matrix for a rat turning right */
RwClump *cpCollision; /* minimal rat used for picking */
int nRats; /* number of rats */
int nDeadRats; /* number of dead rats */
int nCreateCount; /* number of frames since last rat
was created */
} AllRats;
/* Rat: This is the basic structure for a rat. One of these is created for
* each rat in the scene */
typedef struct
{
Object oObj; /* see object.c for this definition */
RwClump *cpCollision; /* collision clump for this rat */
RwClump *cpShadow; /* Rat shadow clump */
int nState; /* current rat motion type */
int nCount; /* number of frames to have this motion */
int nFrame; /* current rat animation frame */
RwMatrix4d *mpDir; /* rat direction matrix */
RwV3d vVel; /* Current rat velocity */
int nHit; /* Number of times that this rat has been hit */
} Rat;
/* Trophy: The trophy is loaded at startup time but only dropped into the
* scene once all of the rats have been destroyed. This structure stores
* the transient trophy data.
*/
typedef struct
{
Object oObj;
RwClump *cpCollision; /* collision clump for the trophy */
RwClump *cpShadow; /* shadow clump for the trophy */
RwMatrix4d *mpDir; /* trophy direction */
RwV3d vVel; /* Current trophy velocity */
} Trophy;
static AllRats arGRats;
static Trophy tpGTrophy;
/* Rat Functions */
/************************************************************************
*
* Function: NumRats()
*
* Description: Returns the number of rats in the street
*
* Return Value: The number of rats
*
************************************************************************/
int NumRats(void)
{
return(arGRats.nRats);
}
/************************************************************************
*
* Function: NumDeadRats()
*
* Description: Returns the number of rats that have been destroyed
*
* Return Value: The number of dead rats
*
************************************************************************/
int NumDeadRats(void)
{
return(arGRats.nDeadRats);
}
/************************************************************************
*
* Function: RatHit()
*
* Description: Decrement the hit count for the rat
*
* Parameters: opObj - the object structure that represents the rat
*
* Return Value: TRUE if the rat has been destroyed, FALSE otherwise
*
************************************************************************/
int RatHit(Object *opObj)
{
RwV3d vPos;
Rat *rpRat;
/* Extract the Rat data from the Object */
rpRat = (Rat *)opObj->pExtra;
/* Make the target move as a result of the hit by determining the vector
* from the camera to the object and moving the rat in that direction
*/
/* Determine the unit vector from the camera to the rat */
RwGetCameraPosition(cpGCamera, &vPos);
RwSubtractVector(&(opObj->vPos), &vPos, &vPos);
RwNormalize(&vPos);
/* Make the rat move in the strike direction */
RwScaleVector(&vPos, CREAL(TARGET_HITFORCE), &vPos);
RwAddVector(&rpRat->vVel, &vPos, &rpRat->vVel);
/* Can the rat take any more hits ?? */
if (--(rpRat->nHit) < 0)
return(TRUE);
else
return(FALSE);
}
/************************************************************************
*
* Function: RatGivePurpose()
*
* Description: Assign a random rat movement type to the rat
*
* Parameters: Rat - the rat to assign the behaviour to
*
* Return Value: None
*
************************************************************************/
static void RatGivePurpose(Rat *rpRat)
{
RwInt32 nRand1,nRand2;
/* Generate 2 Random numbers */
nRand1 = RwRandom();
nRand2 = (nRand1>>8);
nRand1 &= 0xff;
if (nRand1 < 10)
{
rpRat->nState = RAT_TURN_LEFT;
rpRat->nCount = (nRand2 & 0xf) + 15; /* stay in this state for
15 to 30 frames */
}
else if (nRand1 < 20)
{
rpRat->nState = RAT_TURN_RIGHT;
rpRat->nCount = (nRand2 & 0xf) + 15; /* stay in this state for
15 to 30 frames */
}
else if (nRand1 < 40)
{
rpRat->nState = RAT_WAIT;
rpRat->nCount = (nRand2 & 0x1f) + 4; /* stay in this state for
4 to 35 frames */
}
else
{
rpRat->nState = RAT_FORWARD;
rpRat->nCount = (nRand2 & 0xf) + 10; /* stay in this state for
10 to 25 frames */
}
}
/************************************************************************
*
* Function: RatUpdate()
*
* Description: Update the position of a single rat. This function
* is called by the generic object handler on every
* frame for each rat in the street
*
* Parameters: opObj - the object that defines the rat
*
* Return Value: None
*
************************************************************************/
static void RatUpdate(Object *opObj)
{
Rat *rpRat;
RwReal nX,nY,nZ;
/* Extract the rat data from the object */
rpRat = (Rat *)opObj->pExtra;
/* Apply the force of gravity to the rat */
rpRat->vVel.y -= CREAL(GRAVITY);
/* Move the rat to its new position */
RwTranslateMatrix(rpRat->mpDir,
rpRat->vVel.x, rpRat->vVel.y, rpRat->vVel.z,
rwPOSTCONCAT);
nX = RwGetMatrixElement(rpRat->mpDir,3,0);
nY = RwGetMatrixElement(rpRat->mpDir,3,1);
nZ = RwGetMatrixElement(rpRat->mpDir,3,2);
/* Test for collisions with the side walls */
if (rpRat->vVel.x < CREAL(0.0))
{
/* Moving to the left - check against left wall */
if (rpRat->oObj.vPos.x < CREAL(LEFT_STREET + RAT_MOVE_SIZE))
{
/* collision - bounce */
rpRat->vVel.x = RMul(rpRat->vVel.x, CREAL(RICOCHET));
nX = CREAL(LEFT_STREET + RAT_MOVE_SIZE);
RwSetMatrixElement(rpRat->mpDir, 3, 0, nX);
}
}
else
{
/* Moving to the right - check against right wall */
if (rpRat->oObj.vPos.x > CREAL(RIGHT_STREET - RAT_MOVE_SIZE))
{
rpRat->vVel.x = RMul(rpRat->vVel.x, CREAL(RICOCHET));
nX = CREAL(RIGHT_STREET - RAT_MOVE_SIZE);
RwSetMatrixElement(rpRat->mpDir, 3, 0, nX);
}
}
/* Test for collisions with the end walls */
if (rpRat->vVel.z < CREAL(0))
{
/* moving towards far wall */
if (rpRat->oObj.vPos.z < CREAL(FAR_STREET + RAT_MOVE_SIZE))
{
rpRat->vVel.z = RMul(rpRat->vVel.z, CREAL(RICOCHET));
nZ = CREAL(FAR_STREET + RAT_MOVE_SIZE);
RwSetMatrixElement(rpRat->mpDir, 3, 2, nZ);
}
}
else
{
/* moving towards near wall */
if (rpRat->oObj.vPos.z > CREAL(NEAR_STREET - RAT_MOVE_SIZE))
{
rpRat->vVel.z = RMul(rpRat->vVel.z, CREAL(RICOCHET));
nZ = CREAL(NEAR_STREET - RAT_MOVE_SIZE);
RwSetMatrixElement(rpRat->mpDir,3,2,nZ);
}
}
/* Test for collisions with the ground */
if ((nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB)))
{
/* On the pavement */
if (nY <= CREAL(KERB_HEIGHT))
{
RwTranslateMatrix(rpRat->mpDir,
CREAL(0.0), RSub(CREAL(KERB_HEIGHT), nY), CREAL(0.0),
rwPOSTCONCAT);
#ifdef WITH_SOUND
/* Make the sound */
if (rpRat->vVel.y < CREAL(-0.05))
{
int nVolume = REAL2INT(RMul(-rpRat->vVel.y, CREAL(50.0)));
if (nVolume > 0x2f)
{
nVolume = 0x2f;
}
AllSoundsPlaySoundVolume(nVolume, "boink");
}
#endif /* WITH_SOUND */
/* Bounce the rat !*/
rpRat->vVel.y = RMul(rpRat->vVel.y, CREAL(RAT_BOUNCE));
/* Take into account friction */
rpRat->vVel.x = RMul(rpRat->vVel.x, CREAL(RAT_FRICTION));
rpRat->vVel.z = RMul(rpRat->vVel.z, CREAL(RAT_FRICTION));
nY = CREAL(KERB_HEIGHT);
}
}
else
{
/* On the road */
if (nY <= CREAL(STREET_HEIGHT))
{
RwTranslateMatrix(rpRat->mpDir,
CREAL(0.0), RSub(CREAL(STREET_HEIGHT), nY), CREAL(0.0), rwPOSTCONCAT);
#ifdef WITH_SOUND
/* Make the sound */
if (rpRat->vVel.y < CREAL(-0.05))
{
int nVolume = REAL2INT(RMul(-rpRat->vVel.y, CREAL(50)));
if (nVolume > 0x2f)
{
nVolume = 0x2f;
}
AllSoundsPlaySoundVolume(nVolume, "boink");
}
#endif /* SOUND */
/* Bounce the rat !*/
rpRat->vVel.y = RMul(rpRat->vVel.y, CREAL(RAT_BOUNCE));
/* Take into account friction */
rpRat->vVel.x = RMul(rpRat->vVel.x, CREAL(RAT_FRICTION));
rpRat->vVel.z = RMul(rpRat->vVel.z, CREAL(RAT_FRICTION));
nY = CREAL(STREET_HEIGHT);
}
}
/* If on the ground make it do things */
if ( (nY < CREAL(KERB_HEIGHT + GROUND_TRAP)) &&
(rpRat->vVel.y < CREAL(GRAVITY)))
{
if (rpRat->nCount-- < 0)
{
/* previous movement completed */
RatGivePurpose(rpRat);
}
switch (rpRat->nState)
{
case RAT_WAIT:
break;
case RAT_TURN_LEFT:
RwTransformMatrix(rpRat->mpDir, arGRats.mpTurnLeft, rwPRECONCAT);
break;
case RAT_TURN_RIGHT:
RwTransformMatrix(rpRat->mpDir, arGRats.mpTurnRight, rwPRECONCAT);
break;
case RAT_FORWARD:
RwTranslateMatrix(rpRat->mpDir,
CREAL(0.0), CREAL(0.0), CREAL(RAT_SPEED),
rwPRECONCAT);
if (!(rpRat->nCount))
{
/* If its the last frame then ortho normalize it */
RwOrthoNormalizeMatrix(rpRat->mpDir,rpRat->mpDir);
}
rpRat->nFrame++;
if (rpRat->nFrame >= RAT_MAX_FRAMES)
{
rpRat->nFrame = 0;
}
break;
default:
break;
}
/* Bound the movement of ratty */
if (nY == CREAL(STREET_HEIGHT))
{
if (nX < CREAL(LEFT_KERB + RAT_TRAP_SIZE))
{
RwSetMatrixElement(rpRat->mpDir, 3, 0,
CREAL(LEFT_KERB + RAT_TRAP_SIZE));
RatGivePurpose(rpRat);
}
if (nX > CREAL(RIGHT_KERB - RAT_TRAP_SIZE))
{
RwSetMatrixElement(rpRat->mpDir, 3, 0,
CREAL(RIGHT_KERB - RAT_TRAP_SIZE));
RatGivePurpose(rpRat);
}
}
else
{
if (nX < CREAL(LEFT_STREET + RAT_MOVE_SIZE))
{
RwSetMatrixElement(rpRat->mpDir, 3, 0, CREAL(LEFT_STREET + RAT_MOVE_SIZE));
RatGivePurpose(rpRat);
}
if (nX > CREAL(RIGHT_STREET - RAT_MOVE_SIZE))
{
RwSetMatrixElement(rpRat->mpDir, 3, 0, CREAL(RIGHT_STREET - RAT_MOVE_SIZE));
RatGivePurpose(rpRat);
}
}
if (nZ < CREAL(FAR_STREET + RAT_MOVE_SIZE))
{
RwSetMatrixElement(rpRat->mpDir, 3, 2, CREAL(FAR_STREET + RAT_MOVE_SIZE));
RatGivePurpose(rpRat);
}
else if (nZ > CREAL(NEAR_STREET - RAT_MOVE_SIZE))
{
RwSetMatrixElement(rpRat->mpDir, 3, 2, CREAL(NEAR_STREET - RAT_MOVE_SIZE));
RatGivePurpose(rpRat);
}
}
opObj->cpClump = arGRats.cpaFrames[rpRat->nFrame];
opObj->vPos.x = RwGetMatrixElement(rpRat->mpDir,3,0);
opObj->vPos.y = RwGetMatrixElement(rpRat->mpDir,3,1);
opObj->vPos.z = RwGetMatrixElement(rpRat->mpDir,3,2);
RwTransformClump(rpRat->cpCollision, rpRat->mpDir, rwREPLACE);
}
/************************************************************************
*
* Function: RatRender()
*
* Description: Render a single rat. This function
* is called by the generic object handler on every
* frame for each rat in the street
*
* Parameters: opObj - the object that defines the rat
*
* Return Value: None
*
************************************************************************/
static void RatRender(Object *opObj)
{
Rat *rpRat;
RwReal nX;
/* extract the Rat data from the generic object */
rpRat = (Rat *)opObj->pExtra;
#ifdef WITH_SHADOWS
/* Render the shadow below the rat. The location of the rat on the
* street needs to be taken into consideration to allow for the
* different heights of the street and the kerb
*/
/* Extract the location in X from the matrix */
nX = RwGetMatrixElement(rpRat->mpDir, 3, 0);
/* Extract the position and orientation info from the rat */
RwCopyMatrix(rpRat->mpDir, RwScratchMatrix());
/* Adjust the matrix to place the shadow on the street of the kerb */
if ( (nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB)) )
{
RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(KERB_HEIGHT + SHADOW_HEIGHT));
}
else
{
RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(STREET_HEIGHT + SHADOW_HEIGHT));
}
/* Transform and render the shadow */
RwTransformClump(rpRat->cpShadow, RwScratchMatrix(), rwREPLACE);
RwRenderClump(rpRat->cpShadow);
#endif
/* Transform and Render the rat */
RwTransformClump(opObj->cpClump, rpRat->mpDir, rwREPLACE);
RwRenderClump(opObj->cpClump);
}
/************************************************************************
*
* Function: RatDestroy()
*
* Description: Destroy a single rat. This function
* is called by the generic object handler once the
* object has been deleted.
*
* Parameters: opObj - the object that defines the rat
*
* Return Value: None
*
************************************************************************/
static void RatDestroy(Object *opObj)
{
Rat *rpRat;
/* extract the rat data from the generic object */
rpRat = (Rat *)opObj->pExtra;
/* Remove the collision object for this rat from the collision scene */
RwRemoveClumpFromScene(rpRat->cpCollision);
RwDestroyClump(rpRat->cpCollision);
/* Destroy the position matrix for this rat */
RwDestroyMatrix(rpRat->mpDir);
/* There is one less rat in the world */
arGRats.nRats--;
/* Add 1 to the number of dead rats */
arGRats.nDeadRats++;
/* free up the rat data */
free(rpRat);
}
/************************************************************************
*
* Function: RatSetup()
*
* Description: Create a new rat and drop it into the street
*
* Parameters: None
*
* Return Value: None
*
************************************************************************/
static void RatSetup(void)
{
RwReal nX, nY, nZ;
Rat *rpRat;
/* Generate a random start position for the rat */
nX = RANDOM_REAL(CREAL(LEFT_STREET + 0.2), CREAL(RIGHT_STREET - 0.2));
nY = CREAL(RAT_START_HEIGHT);
nZ = RANDOM_REAL(CREAL(FAR_STREET + 0.2), CREAL(NEAR_STREET - 0.2));
/* Create a new rat */
rpRat = (Rat *)malloc(sizeof(Rat));
/* initialise the generic bit */
ObjectSetup(&rpRat->oObj, nX, nY, nZ, NULL);
/* define the functions that the generic object handler needs to
control the rat */
rpRat->oObj.fpUpdate = RatUpdate;
rpRat->oObj.fpRender = RatRender;
rpRat->oObj.fpDestroy = RatDestroy;
rpRat->oObj.pExtra = (void *)rpRat;
/* We want to assign some behaviour as soon as the rat hits the ground */
rpRat->nFrame = 0;
/* Start with zero velocity. Gravity will start things moving */
rpRat->vVel.x = CREAL(0.0);
rpRat->vVel.y = CREAL(0.0);
rpRat->vVel.z = CREAL(0.0);
/* Give the rat some behaviour */
RatGivePurpose(rpRat);
/* Generate and initialise the transformation matrix for this rat */
rpRat->mpDir = RwCreateMatrix();
RwTranslateMatrix(rpRat->mpDir, nX, nY, nZ, rwREPLACE);
/* Copy the generic rat collision object, transform it to the position
and orientation of the rat and add it to the collision scene */
rpRat->cpCollision = RwDuplicateClump(arGRats.cpCollision);
RwSetClumpData(rpRat->cpCollision, &rpRat->oObj);
RwTransformClump(rpRat->cpCollision, rpRat->mpDir, rwREPLACE);
RwAddClumpToScene(spGTargetScene, rpRat->cpCollision);
/* Set the Shadow image */
rpRat->cpShadow = arGRats.cpShadow;
/* Set the amount of hits it can take before being destroyed */
rpRat->nHit = RAT_HITS;
/* Just added a new rat so add one more to the number in the street */
arGRats.nRats++;
/* Add to the generic object scene management stuff */
AllObjectsAddObject(&rpRat->oObj);
/* Give the rat a random direction */
RwRotateMatrix(RwScratchMatrix(),
CREAL(0.0), CREAL(1.0), CREAL(0.0),
RANDOM_REAL(CREAL(0.0), CREAL(360.0)),
rwREPLACE );
RwTransformMatrix(rpRat->mpDir, RwScratchMatrix(), rwPRECONCAT);
}
/************************************************************************
*
* Function: AllRatsDestroy()
*
* Description: Destroy the shared rat data.
*
* Parameters: None
*
* Return Value: None
*
************************************************************************/
void AllRatsDestroy(void)
{
RwDestroyClump(arGRats.cpShadow);
RwDestroyClump(arGRats.cpCollision);
RwDestroyClump(arGRats.cpaFrames[0]);
RwDestroyClump(arGRats.cpaFrames[1]);
RwDestroyClump(arGRats.cpaFrames[2]);
RwDestroyClump(arGRats.cpaFrames[3]);
RwDestroyClump(arGRats.cpaFrames[4]);
RwDestroyClump(arGRats.cpaFrames[5]);
RwDestroyClump(arGRats.cpaFrames[6]);
RwDestroyMatrix(arGRats.mpTurnLeft);
RwDestroyMatrix(arGRats.mpTurnRight);
}
/************************************************************************
*
* Function: AllRatsSetup()
*
* Description: Create the shared rat data.
*
* Parameters: None
*
* Return Value: TRUE if successful, FALSE otherwise
*
************************************************************************/
int AllRatsSetup(void)
{
/* start with zero rats */
arGRats.nRats = 0;
/* Read all of the clumps needed for the rats*/
if (!(arGRats.cpCollision = DoRwReadShape("collisio.rwx")) ||
#ifdef WITH_SHADOWS
!(arGRats.cpShadow = DoRwReadShape("ratshad.rwx")) ||
#endif
/* Get the rat animation frames */
!(arGRats.cpaFrames[0] = DoRwReadShape("rat1.rwx")) ||
!(arGRats.cpaFrames[2] = DoRwReadShape("rat3.rwx")) ||
!(arGRats.cpaFrames[4] = DoRwReadShape("rat5.rwx")) ||
!(arGRats.cpaFrames[6] = DoRwReadShape("rat7.rwx")) ||
!(arGRats.cpaFrames[1] = DoRwReadShape("rat2.rwx")) ||
!(arGRats.cpaFrames[3] = DoRwReadShape("rat4.rwx")) ||
!(arGRats.cpaFrames[5] = DoRwReadShape("rat6.rwx")))
{
/* Failed to read something - error */
return FALSE;
}
/* Create The matrices used to turn the rats to the left and right */
if (!(arGRats.mpTurnLeft = RwCreateMatrix()) ||
!(arGRats.mpTurnRight = RwCreateMatrix()))
{
/* failed to create the matrices - error */
return FALSE;
}
/* And initialise these matrices */
RwRotateMatrix(arGRats.mpTurnLeft,CREAL(0.0),CREAL(1.0),CREAL(0.0),
CREAL(3.0),rwREPLACE);
RwRotateMatrix(arGRats.mpTurnRight,CREAL(0.0),CREAL(1.0),CREAL(0.0),
CREAL(-3.0),rwREPLACE);
/* Create the initial amount of rats. Use half of the maximum */
arGRats.nCreateCount=0;
while (arGRats.nRats < RAT_MAXIMUM/2)
{
RatSetup();
}
return TRUE;
}
/************************************************************************
*
* Function: AllRatsRelease()
*
* Description: Control the steady flow of rats into the street
*
* Parameters: None. Uses global rat data
*
* Return Value: None
*
************************************************************************/
void AllRatsRelease(void)
{
/* Increment the creation timer */
arGRats.nCreateCount++;
if ( (arGRats.nCreateCount >= RAT_CREATE_TIME) &&
(arGRats.nRats) )
{
/* It's time to create a rat */
arGRats.nCreateCount = 0;
if (arGRats.nRats < RAT_MAXIMUM)
{
/* We haven't reached the limit yet. Create anothe one */
RatSetup();
}
}
}
/* Trophy Functions */
/************************************************************************
*
* Function: TrophyHit()
*
* Description: Move the trophy in response to a hit
*
* Parameters: None. Uses the global trophy data object
*
* Return Value: None
*
************************************************************************/
void TrophyHit(void)
{
RwV3d vPos;
/* Use the vector from the camera to the trophy to determine the strike
direction */
RwGetCameraPosition(cpGCamera, &vPos);
RwSubtractVector(&(tpGTrophy.oObj.vPos), &vPos, &vPos);
RwNormalize(&vPos);
/* Move the trophy in the direction of the strike */
RwScaleVector(&vPos, CREAL(TARGET_HITFORCE), &vPos);
RwAddVector(&tpGTrophy.vVel, &vPos, &tpGTrophy.vVel);
}
/************************************************************************
*
* Function: TrophyUpdate()
*
* Description: This function is called every frame to
* update the position of the trophy,
*
* Parameters: opObj - the generic object
*
* Return Value: None
*
************************************************************************/
static void TrophyUpdate(Object *opObj)
{
RwReal nX,nY,nZ;
/* Apply the force of gravity */
tpGTrophy.vVel.y -= CREAL(GRAVITY);
/* Preserve the momentum of the trophy */
RwTranslateMatrix(tpGTrophy.mpDir,
tpGTrophy.vVel.x, tpGTrophy.vVel.y, tpGTrophy.vVel.z,
rwPOSTCONCAT);
nX = RwGetMatrixElement(tpGTrophy.mpDir,3,0);
nY = RwGetMatrixElement(tpGTrophy.mpDir,3,1);
nZ = RwGetMatrixElement(tpGTrophy.mpDir,3,2);
/* Test for collisions with the side walls */
if (tpGTrophy.vVel.x < CREAL(0.0))
{
/* Moving to the left - check against left wall */
if (nX < CREAL(LEFT_STREET + RAT_MOVE_SIZE))
{
/* collision - bounce */
tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RICOCHET));
nX = CREAL(LEFT_STREET + RAT_MOVE_SIZE);
}
}
else
{
/* Moving to the right - check against right wall */
if (nX > CREAL(RIGHT_STREET - RAT_MOVE_SIZE))
{
tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RICOCHET));
nX = CREAL(RIGHT_STREET - RAT_MOVE_SIZE);
}
}
/* Test for collisions with the end walls */
if (tpGTrophy.vVel.z < CREAL(0))
{
/* moving towards far wall */
if (nZ < CREAL(FAR_STREET + RAT_MOVE_SIZE))
{
tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RICOCHET));
nZ = CREAL(FAR_STREET + RAT_MOVE_SIZE);
}
}
else
{
/* moving towards near wall */
if (nZ > CREAL(NEAR_STREET - RAT_MOVE_SIZE))
{
tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RICOCHET));
nZ = CREAL(NEAR_STREET - RAT_MOVE_SIZE);
}
}
/* Test for collisions with the ground */
if ((nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB)))
{
/* On the pavement */
if (nY <= CREAL(KERB_HEIGHT))
{
RwTranslateMatrix(tpGTrophy.mpDir,
CREAL(0.0), CREAL(KERB_HEIGHT), CREAL(0.0),
rwPOSTCONCAT);
#ifdef WITH_SOUND
/* Make the sound */
if (tpGTrophy.vVel.y < CREAL(-0.05))
{
int nVolume = REAL2INT(RMul(-tpGTrophy.vVel.y, CREAL(50)));
if (nVolume > 0x2f)
{
nVolume = 0x2f;
}
AllSoundsPlaySoundVolume(nVolume, "boink");
}
#endif /* SOUND */
/* Bounce the trophy. Use the rat friction and bounce parameters */
tpGTrophy.vVel.y = RMul(tpGTrophy.vVel.y, CREAL(RAT_BOUNCE));
/* Take into account friction */
tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RAT_FRICTION));
tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RAT_FRICTION));
nY = CREAL(KERB_HEIGHT);
}
}
else
{
/* On the road */
if (nY <= CREAL(STREET_HEIGHT))
{
RwTranslateMatrix(tpGTrophy.mpDir,
CREAL(0.0), CREAL(STREET_HEIGHT) - nY, CREAL(0.0), rwPOSTCONCAT);
#ifdef WITH_SOUND
/* Make the sound */
if (tpGTrophy.vVel.y < CREAL(-0.05))
{
int nVolume = REAL2INT(RMul(-tpGTrophy.vVel.y, CREAL(50)));
if (nVolume > 0x2f)
{
nVolume = 0x2f;
}
AllSoundsPlaySoundVolume(nVolume, "boink");
}
#endif /* SOUND */
/* Bounce the trophy !*/
tpGTrophy.vVel.y = RMul(tpGTrophy.vVel.y, CREAL(RAT_BOUNCE));
/* Take into account friction */
tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RAT_FRICTION));
tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RAT_FRICTION));
nY = CREAL(STREET_HEIGHT);
}
}
/* Move the trophy to its new position */
RwSetMatrixElement(tpGTrophy.mpDir,3,0, nX);
RwSetMatrixElement(tpGTrophy.mpDir,3,1, nY);
RwSetMatrixElement(tpGTrophy.mpDir,3,2, nZ);
opObj->vPos.x = nX;
opObj->vPos.y = nY;
opObj->vPos.z = nZ;
RwTransformClump(tpGTrophy.cpCollision, tpGTrophy.mpDir, rwREPLACE);
}
/************************************************************************
*
* Function: TrophyRender()
*
* Description: This function is called every frame to
* render the position of the trophy,
*
* Parameters: opObj - generic object data
*
* Return Value: None
*
************************************************************************/
void TrophyRender(Object *opObj)
{
RwReal nX;
#ifdef WITH_SHADOWS
/* Render the shadow below the trophy. The location of the trophy on the
* street needs to be taken into consideration to allow for the
* different heights of the street and the kerb
*/
/* Extract the location in X from the matrix */
nX = RwGetMatrixElement(tpGTrophy.mpDir, 3, 0);
/* Extract the position and orientation info from the trophy */
RwCopyMatrix(tpGTrophy.mpDir, RwScratchMatrix());
/* Adjust the matrix to place the shadow on the street of the kerb */
if ( (nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB)) )
{
RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(KERB_HEIGHT + SHADOW_HEIGHT));
}
else
{
RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(STREET_HEIGHT + SHADOW_HEIGHT));
}
/* Position and Render the shadow */
RwTransformClump(tpGTrophy.cpShadow, RwScratchMatrix(), rwREPLACE);
RwRenderClump(tpGTrophy.cpShadow);
#endif
/* Render the trophy */
RwTransformClump(opObj->cpClump, tpGTrophy.mpDir, rwREPLACE);
RwRenderClump(opObj->cpClump);
}
/************************************************************************
*
* Function: TrophyEnable()
*
* Description: Enable the trophy. Note that all of the trophy
* data was initialised at load time so all we need
* top do is drop it into the street .
*
* Parameters: None. Uses global trophy data object
*
* Return Value: None
*
************************************************************************/
void TrophyEnable(void)
{
AllObjectsAddObject(&tpGTrophy.oObj);
}
/************************************************************************
*
* Function: TrophySetup()
*
* Description: Create and initialise the trophy
*
* Parameters: None. Uses global trophy data object
*
* Return Value: None
*
************************************************************************/
int TrophySetup(void)
{
/* Initialise the generic object bit */
ObjectSetup(&tpGTrophy.oObj, CREAL(TROPHY_X), CREAL(TROPHY_Y), CREAL(TROPHY_Z), NULL);
/* Define the functions that the generic handler will call to update
and render the trophy */
tpGTrophy.oObj.fpUpdate = TrophyUpdate;
tpGTrophy.oObj.fpRender = TrophyRender;
/* Don't define a destroy here since the trophy is only destroyed when
we exit from cyberstreet */
tpGTrophy.oObj.pExtra = (void *)&tpGTrophy;
/* Trophy starts with zero velocity but gravity soon changes that */
tpGTrophy.vVel.x = CREAL(0.0);
tpGTrophy.vVel.y = CREAL(0.0);
tpGTrophy.vVel.z = CREAL(0.0);
/* Create the position matrix for the trophy */
if (tpGTrophy.mpDir = RwCreateMatrix())
{
/* Initialise the trophy's position */
RwTranslateMatrix(tpGTrophy.mpDir, CREAL(TROPHY_X), CREAL(TROPHY_Y), CREAL(TROPHY_Z), rwREPLACE);
/* Read the trophy script file */
if (tpGTrophy.oObj.cpClump = DoRwReadShape("trophy.rwx"))
{
/* Create the collision data for teh trophy. Use the entire
trophy for the collision */
if (tpGTrophy.cpCollision = RwDuplicateClump(tpGTrophy.oObj.cpClump))
{
/* Initialise the collision data and add it to the
collision scene */
RwSetClumpData(tpGTrophy.cpCollision, &tpGTrophy.oObj);
RwTransformClump(tpGTrophy.cpCollision, tpGTrophy.mpDir, rwREPLACE);
RwAddClumpToScene(spGTargetScene, tpGTrophy.cpCollision);
/* Read the shadow script file */
if (tpGTrophy.cpShadow = DoRwReadShape("trophys.rwx"))
{
return(TRUE);
}
RwDestroyClump(tpGTrophy.cpCollision);
}
RwDestroyClump(tpGTrophy.oObj.cpClump);
}
RwDestroyMatrix(tpGTrophy.mpDir);
}
return(FALSE);
}