home *** CD-ROM | disk | FTP | other *** search
/ Learn 3D Graphics Programming on the PC / Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso / rwwin / ratrophy.c_ / ratrophy.bin
Text File  |  1995-11-14  |  36KB  |  1,097 lines

  1. /**********************************************************************
  2.  *
  3.  * File :     ratrophy.c
  4.  *
  5.  * Abstract : The rat and trophy bit handler. This module handles
  6.  *            the movement and display of the rats and the trophy that
  7.  *            appears once all the rats are destroyed.
  8.  *
  9.  **********************************************************************
  10.  *
  11.  * This file is a product of Criterion Software Ltd.
  12.  *
  13.  * This file is provided as is with no warranties of any kind and is
  14.  * provided without any obligation on Criterion Software Ltd. or
  15.  * Canon Inc. to assist in its use or modification.
  16.  *
  17.  * Criterion Software Ltd. will not, under any
  18.  * circumstances, be liable for any lost revenue or other damages arising
  19.  * from the use of this file.
  20.  *
  21.  * Copyright (c) 1995 Criterion Software Ltd.
  22.  * All Rights Reserved.
  23.  *
  24.  * RenderWare is a trademark of Canon Inc.
  25.  *
  26.  ************************************************************************/
  27.  
  28. /*--- Include Files ---*/
  29.  
  30. #include "global.h"     /* Application general includes */
  31.  
  32. #define TARGET_HITFORCE     0.3  /* Objects that are hit move at this velocity */
  33.  
  34. #define RAT_CREATE_TIME     200  /* No of frames before a new rat is created */
  35.  
  36. /* Rat State definitions: These are the different ways that a rat can move */
  37.  
  38. #define RAT_WAIT            1
  39. #define RAT_TURN_LEFT       2
  40. #define RAT_TURN_RIGHT      3
  41. #define RAT_LOOK            4
  42. #define RAT_FORWARD         5
  43.  
  44. #define RAT_MOVE_SIZE       0.15  /* Once a rat gets this close to a wall or
  45.                                      the ground it bounces */
  46. #define RAT_TRAP_SIZE       0.05  /* If the rat is on the ground and it gets
  47.                                      this close to a wall or the kerb then 
  48.                                      change its behaviour */
  49.  
  50. #define TROPHY_MOVE_SIZE    0.5   /* Once the trophy gets this close to a wall
  51.                                      or the ground it bounces */
  52.  
  53. /* The start position for the trophy when it enters the street */
  54.  
  55. #define TROPHY_X            0.0
  56. #define TROPHY_Y            4.0
  57. #define TROPHY_Z        2.0
  58.  
  59.  
  60. #define RAT_START_HEIGHT    4.0     /* The height that the rats fall from */
  61. #define RAT_SPEED           0.02    /* The speed that rats move forward at */
  62. #define RAT_HITS            4       /* The number of hits that a rat can take 
  63.                                        before it explodes */
  64. #define RAT_BOUNCE          (-1.0/4.0) /* Change in velocity for a rat when it
  65.                                           bounces off of a wall or the ground */
  66. #define RAT_FRICTION        (1.0/4.0)  /* When a rat bounces of the ground, its
  67.                                           forward momentum is damped by this amount */
  68.  
  69. #define RAT_MAX_FRAMES      7       /* the number of different clumps that
  70.                                        make up the rat animation */
  71.  
  72. #define GROUND_TRAP         0.01    /* When a rat gets this close to the
  73.                                        ground it behaves as though it is
  74.                                        on the ground */
  75.  
  76. /* All Rats: A single global variable of this type is defined. It holds all 
  77.  * of the rat related items that are shared across mulitple instances 
  78.  */
  79. typedef struct 
  80. {
  81.     RwClump *cpaFrames[RAT_MAX_FRAMES]; /* Rat animation clumps */
  82.     RwClump *cpShadow;                  /* Rat shadow clumps */
  83.     RwMatrix4d *mpTurnLeft;             /* Matrix for a rat turning left */
  84.     RwMatrix4d *mpTurnRight;            /* Matrix for a rat turning right */
  85.     RwClump *cpCollision;               /* minimal rat used for picking */
  86.     int nRats;                          /* number of rats */
  87.     int nDeadRats;                      /* number of dead rats */
  88.     int nCreateCount;                   /* number of frames since last rat 
  89.                                            was created */
  90. } AllRats;
  91.  
  92. /* Rat: This is the basic structure for a rat. One of these is created for
  93.  * each rat in the scene */
  94.  
  95. typedef struct 
  96. {
  97.     Object oObj;            /* see object.c for this definition */
  98.     RwClump *cpCollision;   /* collision clump for this rat */
  99.     RwClump *cpShadow;      /* Rat shadow clump */
  100.     int nState;             /* current rat motion type */
  101.     int nCount;             /* number of frames to have this motion */
  102.     int nFrame;             /* current rat animation frame */
  103.     RwMatrix4d *mpDir;      /* rat direction matrix */
  104.     RwV3d vVel;             /* Current rat velocity */
  105.     int nHit;               /* Number of times that this rat has been hit */
  106. } Rat;
  107.  
  108. /* Trophy: The trophy is loaded at startup time but only dropped into the
  109.  * scene once all of the rats have been destroyed. This structure stores
  110.  * the transient trophy data.
  111.  */
  112.  
  113. typedef struct 
  114. {
  115.     Object oObj;
  116.     RwClump *cpCollision;   /* collision clump for the trophy */
  117.     RwClump *cpShadow;      /* shadow clump for the trophy */
  118.     RwMatrix4d *mpDir;      /* trophy direction */
  119.     RwV3d vVel;             /* Current trophy velocity */
  120. } Trophy;
  121.  
  122. static AllRats arGRats;   
  123. static Trophy  tpGTrophy;
  124.  
  125. /* Rat Functions */
  126.  
  127. /************************************************************************
  128.  *
  129.  *      Function:       NumRats()
  130.  *                      
  131.  *      Description:    Returns the number of rats in the street
  132.  *
  133.  *      Return Value:   The number of rats
  134.  *
  135.  ************************************************************************/
  136. int NumRats(void)
  137. {
  138.     return(arGRats.nRats);
  139. }
  140.  
  141. /************************************************************************
  142.  *
  143.  *      Function:       NumDeadRats()
  144.  *                      
  145.  *      Description:    Returns the number of rats that have been destroyed
  146.  *
  147.  *      Return Value:   The number of dead rats
  148.  *
  149.  ************************************************************************/
  150. int NumDeadRats(void)
  151. {
  152.     return(arGRats.nDeadRats);
  153. }
  154.  
  155. /************************************************************************
  156.  *
  157.  *      Function:       RatHit()
  158.  *                      
  159.  *      Description:    Decrement the hit count for the rat
  160.  *
  161.  *      Parameters:     opObj - the object structure that represents the rat
  162.  *
  163.  *      Return Value:   TRUE if the rat has been destroyed, FALSE otherwise
  164.  *
  165.  ************************************************************************/
  166. int RatHit(Object *opObj)
  167. {
  168.     RwV3d vPos;
  169.     Rat *rpRat;
  170.  
  171.     /* Extract the Rat data from the Object */
  172.  
  173.     rpRat = (Rat *)opObj->pExtra;
  174.  
  175.     /* Make the target move as a result of the hit by determining the vector
  176.      * from the camera to the object and moving the rat in that direction 
  177.      */
  178.  
  179.     /* Determine the unit vector from the camera to the rat */
  180.     RwGetCameraPosition(cpGCamera, &vPos);
  181.     RwSubtractVector(&(opObj->vPos), &vPos, &vPos);
  182.     RwNormalize(&vPos);
  183.  
  184.     /* Make the rat move in the strike direction */
  185.     RwScaleVector(&vPos, CREAL(TARGET_HITFORCE), &vPos);
  186.     RwAddVector(&rpRat->vVel, &vPos, &rpRat->vVel);
  187.  
  188.     /* Can the rat take any more hits ?? */
  189.     if (--(rpRat->nHit) < 0)
  190.         return(TRUE);
  191.     else
  192.         return(FALSE); 
  193. }
  194.  
  195. /************************************************************************
  196.  *
  197.  *      Function:       RatGivePurpose()
  198.  *                     
  199.  *      Description:    Assign a random rat movement type to the rat
  200.  *
  201.  *      Parameters:    Rat - the rat to assign the behaviour to
  202.  *
  203.  *      Return Value:  None
  204.  *
  205.  ************************************************************************/
  206. static void RatGivePurpose(Rat *rpRat)
  207. {
  208.     RwInt32 nRand1,nRand2;
  209.  
  210.     /* Generate 2 Random numbers */
  211.  
  212.     nRand1 = RwRandom();
  213.     nRand2 = (nRand1>>8);
  214.     nRand1 &= 0xff;
  215.  
  216.     if (nRand1 < 10) 
  217.     {
  218.         rpRat->nState = RAT_TURN_LEFT;
  219.         rpRat->nCount = (nRand2 & 0xf) + 15;  /* stay in this state for 
  220.                                                  15 to 30 frames */
  221.     } 
  222.     else if (nRand1 < 20) 
  223.     {
  224.         rpRat->nState = RAT_TURN_RIGHT;
  225.         rpRat->nCount = (nRand2 & 0xf) + 15;  /* stay in this state for 
  226.                                                  15 to 30 frames */
  227.     } 
  228.     else if (nRand1 < 40) 
  229.     {
  230.         rpRat->nState = RAT_WAIT;
  231.         rpRat->nCount = (nRand2 & 0x1f) + 4; /* stay in this state for 
  232.                                                  4 to 35 frames */
  233.  
  234.     } 
  235.     else 
  236.     {
  237.         rpRat->nState = RAT_FORWARD;
  238.         rpRat->nCount = (nRand2 & 0xf) + 10; /* stay in this state for 
  239.                                                 10 to 25 frames */
  240.     }
  241. }
  242.  
  243. /************************************************************************
  244.  *
  245.  *      Function:       RatUpdate()
  246.  *                     
  247.  *      Description:    Update the position of a single rat. This function
  248.  *                      is called by the generic object handler on every
  249.  *                      frame for each rat in the street
  250.  *
  251.  *      Parameters:     opObj - the object that defines the rat
  252.  *
  253.  *      Return Value:   None
  254.  *
  255.  ************************************************************************/
  256. static void RatUpdate(Object *opObj)
  257. {
  258.     Rat *rpRat;
  259.     RwReal nX,nY,nZ;
  260.  
  261.     /* Extract the rat data from the object */
  262.  
  263.     rpRat = (Rat *)opObj->pExtra;
  264.  
  265.     /* Apply the force of gravity to the rat */
  266.  
  267.     rpRat->vVel.y -= CREAL(GRAVITY);  
  268.  
  269.     /* Move the rat to its new position */
  270.  
  271.     RwTranslateMatrix(rpRat->mpDir,
  272.                       rpRat->vVel.x, rpRat->vVel.y, rpRat->vVel.z,
  273.                       rwPOSTCONCAT);
  274.     nX = RwGetMatrixElement(rpRat->mpDir,3,0);
  275.     nY = RwGetMatrixElement(rpRat->mpDir,3,1);
  276.     nZ = RwGetMatrixElement(rpRat->mpDir,3,2);
  277.  
  278.     /* Test for collisions with the side walls */
  279.  
  280.     if (rpRat->vVel.x < CREAL(0.0))
  281.     {
  282.         /* Moving to the left - check against left wall */
  283.         if (rpRat->oObj.vPos.x < CREAL(LEFT_STREET + RAT_MOVE_SIZE))
  284.         {
  285.             /* collision - bounce */
  286.             rpRat->vVel.x = RMul(rpRat->vVel.x, CREAL(RICOCHET));
  287.             nX = CREAL(LEFT_STREET + RAT_MOVE_SIZE);
  288.             RwSetMatrixElement(rpRat->mpDir, 3, 0, nX);
  289.         }
  290.     }
  291.     else
  292.     {
  293.         /* Moving to the right - check against right wall */
  294.         if (rpRat->oObj.vPos.x > CREAL(RIGHT_STREET - RAT_MOVE_SIZE)) 
  295.         {
  296.             rpRat->vVel.x = RMul(rpRat->vVel.x, CREAL(RICOCHET));
  297.             nX = CREAL(RIGHT_STREET - RAT_MOVE_SIZE);
  298.             RwSetMatrixElement(rpRat->mpDir, 3, 0, nX);
  299.         }
  300.     }
  301.  
  302.     /* Test for collisions with the end walls */
  303.  
  304.     if (rpRat->vVel.z < CREAL(0))
  305.     {
  306.         /* moving towards far wall */
  307.         if (rpRat->oObj.vPos.z < CREAL(FAR_STREET + RAT_MOVE_SIZE)) 
  308.         {
  309.             rpRat->vVel.z = RMul(rpRat->vVel.z, CREAL(RICOCHET));
  310.             nZ = CREAL(FAR_STREET + RAT_MOVE_SIZE);
  311.             RwSetMatrixElement(rpRat->mpDir, 3, 2, nZ);
  312.         }
  313.     }
  314.     else
  315.     {
  316.         /* moving towards near wall */
  317.         if (rpRat->oObj.vPos.z > CREAL(NEAR_STREET - RAT_MOVE_SIZE)) 
  318.         {
  319.             rpRat->vVel.z = RMul(rpRat->vVel.z, CREAL(RICOCHET));
  320.             nZ = CREAL(NEAR_STREET - RAT_MOVE_SIZE);
  321.             RwSetMatrixElement(rpRat->mpDir,3,2,nZ);
  322.         }
  323.     }
  324.  
  325.     /* Test for collisions with the ground */
  326.  
  327.     if ((nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB))) 
  328.     {
  329.         /* On the pavement */
  330.  
  331.         if (nY <= CREAL(KERB_HEIGHT)) 
  332.         {
  333.             RwTranslateMatrix(rpRat->mpDir, 
  334.                               CREAL(0.0), RSub(CREAL(KERB_HEIGHT), nY), CREAL(0.0), 
  335.                               rwPOSTCONCAT);
  336.  
  337. #ifdef WITH_SOUND
  338.             /* Make the sound */
  339.  
  340.             if (rpRat->vVel.y < CREAL(-0.05)) 
  341.             {
  342.                 AllSoundsPlaySound("boink");
  343.             }
  344.  
  345. #endif /* WITH_SOUND */
  346.  
  347.             /* Bounce the rat !*/
  348.  
  349.             rpRat->vVel.y = RMul(rpRat->vVel.y, CREAL(RAT_BOUNCE));
  350.  
  351.             /* Take into account friction */
  352.  
  353.             rpRat->vVel.x = RMul(rpRat->vVel.x, CREAL(RAT_FRICTION));
  354.             rpRat->vVel.z = RMul(rpRat->vVel.z, CREAL(RAT_FRICTION));
  355.             nY = CREAL(KERB_HEIGHT);
  356.         }
  357.     }
  358.     else 
  359.     {
  360.         /* On the road */
  361.  
  362.         if (nY <= CREAL(STREET_HEIGHT)) 
  363.         {
  364.             RwTranslateMatrix(rpRat->mpDir, 
  365.                               CREAL(0.0), RSub(CREAL(STREET_HEIGHT), nY), CREAL(0.0), rwPOSTCONCAT);
  366.  
  367. #ifdef WITH_SOUND
  368.             /* Make the sound */
  369.  
  370.             if (rpRat->vVel.y < CREAL(-0.05)) 
  371.             {
  372.                 AllSoundsPlaySound("boink");
  373.             }
  374.  
  375. #endif /* SOUND */
  376.  
  377.             /* Bounce the rat !*/
  378.  
  379.             rpRat->vVel.y = RMul(rpRat->vVel.y, CREAL(RAT_BOUNCE));
  380.  
  381.             /* Take into account friction */
  382.  
  383.             rpRat->vVel.x = RMul(rpRat->vVel.x, CREAL(RAT_FRICTION));
  384.             rpRat->vVel.z = RMul(rpRat->vVel.z, CREAL(RAT_FRICTION));
  385.             nY = CREAL(STREET_HEIGHT);
  386.         }
  387.     }
  388.     /* If on the ground make it do things */
  389.  
  390.     if ( (nY < CREAL(KERB_HEIGHT + GROUND_TRAP)) && 
  391.         (rpRat->vVel.y < CREAL(GRAVITY)))
  392.     {
  393.         if (rpRat->nCount-- < 0) 
  394.         {
  395.             /* previous movement completed */
  396.             RatGivePurpose(rpRat);
  397.         }
  398.  
  399.         switch (rpRat->nState) 
  400.         {
  401.             case RAT_WAIT: 
  402.                 break;
  403.  
  404.             case RAT_TURN_LEFT: 
  405.                 RwTransformMatrix(rpRat->mpDir, arGRats.mpTurnLeft, rwPRECONCAT);
  406.                 break;
  407.  
  408.             case RAT_TURN_RIGHT:
  409.                 RwTransformMatrix(rpRat->mpDir, arGRats.mpTurnRight, rwPRECONCAT);
  410.                 break;
  411.  
  412.             case RAT_FORWARD:
  413.                 RwTranslateMatrix(rpRat->mpDir, 
  414.                                   CREAL(0.0), CREAL(0.0), CREAL(RAT_SPEED),
  415.                                   rwPRECONCAT);
  416.                 if (!(rpRat->nCount)) 
  417.                 {
  418.                     /* If its the last frame then ortho normalize it */
  419.                     RwOrthoNormalizeMatrix(rpRat->mpDir,rpRat->mpDir);
  420.                 }
  421.                 rpRat->nFrame++;
  422.  
  423.                 if (rpRat->nFrame >= RAT_MAX_FRAMES) 
  424.                 {
  425.                     rpRat->nFrame = 0;
  426.                 }
  427.                 break;
  428.  
  429.             default:
  430.                 break;
  431.         }
  432.  
  433.         /* Bound the movement of ratty */
  434.  
  435.         if (nY == CREAL(STREET_HEIGHT)) 
  436.         {
  437.             if (nX < CREAL(LEFT_KERB + RAT_TRAP_SIZE)) 
  438.             {
  439.                 RwSetMatrixElement(rpRat->mpDir, 3, 0, 
  440.                                    CREAL(LEFT_KERB + RAT_TRAP_SIZE));
  441.                 RatGivePurpose(rpRat);
  442.             }
  443.             if (nX > CREAL(RIGHT_KERB - RAT_TRAP_SIZE)) 
  444.             {
  445.                 RwSetMatrixElement(rpRat->mpDir, 3, 0, 
  446.                                    CREAL(RIGHT_KERB - RAT_TRAP_SIZE));
  447.                 RatGivePurpose(rpRat);
  448.             }
  449.         } 
  450.         else 
  451.         {
  452.             if (nX < CREAL(LEFT_STREET + RAT_MOVE_SIZE)) 
  453.             {
  454.                 RwSetMatrixElement(rpRat->mpDir, 3, 0, CREAL(LEFT_STREET + RAT_MOVE_SIZE));
  455.                 RatGivePurpose(rpRat);
  456.             }
  457.             if (nX > CREAL(RIGHT_STREET - RAT_MOVE_SIZE)) 
  458.             {
  459.                 RwSetMatrixElement(rpRat->mpDir, 3, 0, CREAL(RIGHT_STREET - RAT_MOVE_SIZE));
  460.                 RatGivePurpose(rpRat);
  461.             }
  462.         }
  463.  
  464.         if (nZ < CREAL(FAR_STREET + RAT_MOVE_SIZE)) 
  465.         {
  466.              RwSetMatrixElement(rpRat->mpDir, 3, 2, CREAL(FAR_STREET + RAT_MOVE_SIZE));
  467.              RatGivePurpose(rpRat);
  468.         }
  469.         else if (nZ > CREAL(NEAR_STREET - RAT_MOVE_SIZE)) 
  470.         {
  471.             RwSetMatrixElement(rpRat->mpDir, 3, 2, CREAL(NEAR_STREET - RAT_MOVE_SIZE));
  472.             RatGivePurpose(rpRat);
  473.         }
  474.     } 
  475.     opObj->cpClump = arGRats.cpaFrames[rpRat->nFrame];
  476.     opObj->vPos.x = RwGetMatrixElement(rpRat->mpDir,3,0);
  477.     opObj->vPos.y = RwGetMatrixElement(rpRat->mpDir,3,1);
  478.     opObj->vPos.z = RwGetMatrixElement(rpRat->mpDir,3,2);
  479.  
  480.     RwTransformClump(rpRat->cpCollision, rpRat->mpDir, rwREPLACE);
  481. }
  482.  
  483. /************************************************************************
  484.  *
  485.  *      Function:       RatRender()
  486.  *                     
  487.  *      Description:    Render a single rat. This function
  488.  *                      is called by the generic object handler on every
  489.  *                      frame for each rat in the street
  490.  *
  491.  *      Parameters:     opObj - the object that defines the rat
  492.  *
  493.  *      Return Value:   None
  494.  *
  495.  ************************************************************************/
  496. static void RatRender(Object *opObj)
  497. {
  498.   Rat *rpRat;
  499.   RwReal nX;
  500.  
  501.     /* extract the Rat data from the generic object */
  502.  
  503.     rpRat = (Rat *)opObj->pExtra;
  504.  
  505. #ifdef WITH_SHADOWS
  506.     
  507.     /* Render the shadow below the rat. The location of the rat on the
  508.      * street needs to be taken into consideration to allow for the
  509.      * different heights of the street and the kerb 
  510.      */
  511.  
  512.     /* Extract the location in X from the matrix */
  513.  
  514.      nX = RwGetMatrixElement(rpRat->mpDir, 3, 0);
  515.  
  516.     /* Extract the position and orientation info from the rat */
  517.  
  518.     RwCopyMatrix(rpRat->mpDir, RwScratchMatrix());
  519.  
  520.     /* Adjust the matrix to place the shadow on the street of the kerb */
  521.  
  522.     if ( (nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB)) ) 
  523.     {
  524.         RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(KERB_HEIGHT + SHADOW_HEIGHT));
  525.     } 
  526.     else 
  527.     {
  528.         RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(STREET_HEIGHT + SHADOW_HEIGHT));
  529.     }
  530.  
  531.     /* Transform and render the shadow */
  532.     RwTransformClump(rpRat->cpShadow, RwScratchMatrix(), rwREPLACE);
  533.     RwRenderClump(rpRat->cpShadow);
  534. #endif
  535.  
  536.   /* Transform and Render the rat */
  537.  
  538.   RwTransformClump(opObj->cpClump, rpRat->mpDir, rwREPLACE);
  539.   RwRenderClump(opObj->cpClump);
  540. }
  541.  
  542. /************************************************************************
  543.  *
  544.  *      Function:       RatDestroy()
  545.  *                     
  546.  *      Description:    Destroy a single rat. This function
  547.  *                      is called by the generic object handler once the
  548.  *                      object has been deleted.
  549.  *
  550.  *      Parameters:     opObj - the object that defines the rat
  551.  *
  552.  *      Return Value:   None
  553.  *
  554.  ************************************************************************/
  555. static void RatDestroy(Object *opObj)
  556. {
  557.     Rat *rpRat;
  558.  
  559.     /* extract the rat data from the generic object */
  560.  
  561.     rpRat = (Rat *)opObj->pExtra;
  562.  
  563.     /* Remove the collision object for this rat from the collision scene */
  564.  
  565.     RwRemoveClumpFromScene(rpRat->cpCollision);
  566.     RwDestroyClump(rpRat->cpCollision);
  567.  
  568.     /* Destroy the position matrix for this rat */
  569.  
  570.     RwDestroyMatrix(rpRat->mpDir);
  571.  
  572.     /* There is one less rat in the world */
  573.  
  574.     arGRats.nRats--;
  575.  
  576.     /* Add 1 to the number of dead rats */
  577.  
  578.     arGRats.nDeadRats++;
  579.  
  580.     /* free up the rat data */
  581.     free(rpRat);
  582. }
  583.  
  584. /************************************************************************
  585.  *
  586.  *      Function:       RatSetup()
  587.  *                     
  588.  *      Description:    Create a new rat and drop it into the street
  589.  *
  590.  *      Parameters:     None
  591.  *
  592.  *      Return Value:   None
  593.  *
  594.  ************************************************************************/
  595. static void RatSetup(void)
  596. {  
  597.     RwReal nX, nY, nZ;
  598.     Rat *rpRat;
  599.  
  600.     /* Generate a random start position for the rat */
  601.  
  602.     nX = RANDOM_REAL(CREAL(LEFT_STREET + 0.2), CREAL(RIGHT_STREET - 0.2));
  603.     nY = CREAL(RAT_START_HEIGHT);
  604.     nZ = RANDOM_REAL(CREAL(FAR_STREET + 0.2), CREAL(NEAR_STREET - 0.2));
  605.  
  606.     /* Create a new rat */
  607.     rpRat = (Rat *)malloc(sizeof(Rat));
  608.  
  609.     /* initialise the generic bit */
  610.     ObjectSetup(&rpRat->oObj, nX, nY, nZ, NULL);
  611.  
  612.     /* define the functions that the generic object handler needs to
  613.        control the rat */
  614.  
  615.     rpRat->oObj.fpUpdate = RatUpdate;
  616.     rpRat->oObj.fpRender = RatRender;
  617.     rpRat->oObj.fpDestroy = RatDestroy;
  618.     rpRat->oObj.pExtra = (void *)rpRat;
  619.  
  620.     /* We want to assign some behaviour as soon as the rat hits the ground */
  621.     rpRat->nFrame = 0;
  622.  
  623.     /* Start with zero velocity. Gravity will start things moving */
  624.     rpRat->vVel.x = CREAL(0.0);
  625.     rpRat->vVel.y = CREAL(0.0);
  626.     rpRat->vVel.z = CREAL(0.0);
  627.  
  628.     /* Give the rat some behaviour */
  629.     RatGivePurpose(rpRat);
  630.  
  631.     /* Generate and initialise the transformation matrix for this rat */
  632.     rpRat->mpDir = RwCreateMatrix();
  633.     RwTranslateMatrix(rpRat->mpDir, nX, nY, nZ, rwREPLACE);
  634.  
  635.     /* Copy the generic rat collision object, transform it to the position
  636.        and orientation of the rat and add it to the collision scene */
  637.  
  638.     rpRat->cpCollision = RwDuplicateClump(arGRats.cpCollision);
  639.     RwSetClumpData(rpRat->cpCollision, &rpRat->oObj);
  640.     RwTransformClump(rpRat->cpCollision, rpRat->mpDir, rwREPLACE);
  641.     RwAddClumpToScene(spGTargetScene, rpRat->cpCollision);
  642.  
  643.     /* Set the Shadow image */
  644.  
  645.     rpRat->cpShadow = arGRats.cpShadow;
  646.  
  647.     /* Set the amount of hits it can take before being destroyed */
  648.  
  649.     rpRat->nHit = RAT_HITS;
  650.  
  651.     /* Just added a new rat so add one more to the number in the street */
  652.  
  653.     arGRats.nRats++;
  654.  
  655.     /* Add to the generic object scene management stuff */
  656.  
  657.     AllObjectsAddObject(&rpRat->oObj);
  658.  
  659.     /* Give the rat a random direction */
  660.  
  661.     RwRotateMatrix(RwScratchMatrix(), 
  662.                    CREAL(0.0), CREAL(1.0), CREAL(0.0),
  663.                    RANDOM_REAL(CREAL(0.0), CREAL(360.0)),
  664.                    rwREPLACE );
  665.  
  666.     RwTransformMatrix(rpRat->mpDir, RwScratchMatrix(), rwPRECONCAT);
  667. }
  668. /************************************************************************
  669.  *
  670.  *      Function:       AllRatsDestroy()
  671.  *                     
  672.  *      Description:    Destroy the shared rat data.
  673.  *
  674.  *      Parameters:     None
  675.  *
  676.  *      Return Value:   None
  677.  *
  678.  ************************************************************************/
  679. void AllRatsDestroy(void)
  680. {
  681.     RwDestroyClump(arGRats.cpShadow);
  682.     RwDestroyClump(arGRats.cpCollision);
  683.     RwDestroyClump(arGRats.cpaFrames[0]);
  684.     RwDestroyClump(arGRats.cpaFrames[1]);
  685.     RwDestroyClump(arGRats.cpaFrames[2]);
  686.     RwDestroyClump(arGRats.cpaFrames[3]);
  687.     RwDestroyClump(arGRats.cpaFrames[4]);
  688.     RwDestroyClump(arGRats.cpaFrames[5]);
  689.     RwDestroyClump(arGRats.cpaFrames[6]);
  690.  
  691.     RwDestroyMatrix(arGRats.mpTurnLeft);
  692.     RwDestroyMatrix(arGRats.mpTurnRight);
  693. }
  694.  
  695. /************************************************************************
  696.  *
  697.  *      Function:       AllRatsSetup()
  698.  *                     
  699.  *      Description:    Create the shared rat data.
  700.  *
  701.  *      Parameters:     None
  702.  *
  703.  *      Return Value:   TRUE if successful, FALSE otherwise
  704.  *
  705.  ************************************************************************/
  706. int AllRatsSetup(void)
  707. {
  708.     /* start with zero rats */
  709.  
  710.     arGRats.nRats = 0;
  711.  
  712.     /* Read all of the clumps needed for the rats*/
  713.     if (!(arGRats.cpCollision = DoRwReadShape("collisio.rwx")) ||
  714. #ifdef WITH_SHADOWS
  715.         !(arGRats.cpShadow = DoRwReadShape("ratshad.rwx")) ||
  716. #endif
  717.     /* Get the rat animation frames */
  718.  
  719.         !(arGRats.cpaFrames[0] = DoRwReadShape("rat1.rwx")) ||
  720.         !(arGRats.cpaFrames[2] = DoRwReadShape("rat3.rwx")) ||
  721.         !(arGRats.cpaFrames[4] = DoRwReadShape("rat5.rwx")) ||
  722.         !(arGRats.cpaFrames[6] = DoRwReadShape("rat7.rwx")) ||
  723.         !(arGRats.cpaFrames[1] = DoRwReadShape("rat2.rwx")) || 
  724.         !(arGRats.cpaFrames[3] = DoRwReadShape("rat4.rwx")) ||
  725.         !(arGRats.cpaFrames[5] = DoRwReadShape("rat6.rwx")))
  726.     {
  727.         /* Failed to read something - error */
  728.         return FALSE;
  729.     }
  730.  
  731.     /* Create The matrices used to turn the rats to the left and right */
  732.  
  733.     if (!(arGRats.mpTurnLeft = RwCreateMatrix()) ||
  734.         !(arGRats.mpTurnRight = RwCreateMatrix())) 
  735.     {
  736.         /* failed to create the matrices - error */
  737.         return FALSE;
  738.     }
  739.  
  740.     /* And initialise these matrices */
  741.     RwRotateMatrix(arGRats.mpTurnLeft,CREAL(0.0),CREAL(1.0),CREAL(0.0),
  742.                    CREAL(3.0),rwREPLACE);
  743.  
  744.     RwRotateMatrix(arGRats.mpTurnRight,CREAL(0.0),CREAL(1.0),CREAL(0.0),
  745.                    CREAL(-3.0),rwREPLACE);
  746.  
  747.  
  748.     /* Create the initial amount of rats. Use half of the maximum */
  749.  
  750.     arGRats.nCreateCount=0;  
  751.  
  752.     while (arGRats.nRats < RAT_MAXIMUM/2)
  753.     {
  754.         RatSetup();
  755.     }
  756.     return TRUE;
  757. }
  758.  
  759. /************************************************************************
  760.  *
  761.  *      Function:       AllRatsRelease()
  762.  *                     
  763.  *      Description:    Control the steady flow of rats into the street
  764.  *
  765.  *      Parameters:     None. Uses global rat data
  766.  *
  767.  *      Return Value:   None
  768.  *
  769.  ************************************************************************/
  770. void AllRatsRelease(void)
  771. {
  772.     /* Increment the creation timer */
  773.     arGRats.nCreateCount++;
  774.  
  775.     if ( (arGRats.nCreateCount >= RAT_CREATE_TIME) &&
  776.          (arGRats.nRats) ) 
  777.     {
  778.         /* It's time to create a rat */
  779.         arGRats.nCreateCount = 0;
  780.  
  781.         if (arGRats.nRats < RAT_MAXIMUM) 
  782.         {
  783.             /* We haven't reached the limit yet. Create anothe one */
  784.             RatSetup();
  785.         }
  786.     }
  787. }
  788.  
  789. /* Trophy Functions */
  790.  
  791. /************************************************************************
  792.  *
  793.  *      Function:       TrophyHit()
  794.  *                     
  795.  *      Description:    Move the trophy in response to a hit
  796.  *
  797.  *      Parameters:     None. Uses the global trophy data object
  798.  *
  799.  *      Return Value:   None
  800.  *
  801.  ************************************************************************/
  802. void TrophyHit(void)
  803. {
  804.     RwV3d vPos;
  805.  
  806.     /* Use the vector from the camera to the trophy to determine the strike
  807.        direction */
  808.  
  809.     RwGetCameraPosition(cpGCamera, &vPos);
  810.     RwSubtractVector(&(tpGTrophy.oObj.vPos), &vPos, &vPos);
  811.     RwNormalize(&vPos);
  812.  
  813.     /* Move the trophy in the direction of the strike */
  814.     RwScaleVector(&vPos, CREAL(TARGET_HITFORCE), &vPos);
  815.     RwAddVector(&tpGTrophy.vVel, &vPos, &tpGTrophy.vVel);
  816. }
  817.  
  818. /************************************************************************
  819.  *
  820.  *      Function:       TrophyUpdate()
  821.  *                     
  822.  *      Description:    This function is called every frame to 
  823.  *                      update the position of the trophy,
  824.  *
  825.  *      Parameters:     opObj - the generic object
  826.  *
  827.  *      Return Value:   None
  828.  *
  829.  ************************************************************************/
  830. static void TrophyUpdate(Object *opObj)
  831. {
  832.     RwReal nX,nY,nZ;
  833.  
  834.     /* Apply the force of gravity */
  835.  
  836.     tpGTrophy.vVel.y -= CREAL(GRAVITY);  
  837.  
  838.     /* Preserve the momentum of the trophy */
  839.     
  840.     RwTranslateMatrix(tpGTrophy.mpDir,
  841.                       tpGTrophy.vVel.x, tpGTrophy.vVel.y, tpGTrophy.vVel.z,
  842.                       rwPOSTCONCAT);
  843.     nX = RwGetMatrixElement(tpGTrophy.mpDir,3,0);
  844.     nY = RwGetMatrixElement(tpGTrophy.mpDir,3,1);
  845.     nZ = RwGetMatrixElement(tpGTrophy.mpDir,3,2);
  846.  
  847.     /* Test for collisions with the side walls */
  848.  
  849.     if (tpGTrophy.vVel.x < CREAL(0.0))
  850.     {
  851.         /* Moving to the left - check against left wall */
  852.         if (nX < CREAL(LEFT_STREET + RAT_MOVE_SIZE))
  853.         {
  854.             /* collision - bounce */
  855.             tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RICOCHET));
  856.             nX = CREAL(LEFT_STREET + RAT_MOVE_SIZE);
  857.         }
  858.     }
  859.     else
  860.     {
  861.         /* Moving to the right - check against right wall */
  862.         if (nX > CREAL(RIGHT_STREET - RAT_MOVE_SIZE)) 
  863.         {
  864.             tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RICOCHET));
  865.             nX = CREAL(RIGHT_STREET - RAT_MOVE_SIZE);
  866.         }
  867.     }
  868.  
  869.     /* Test for collisions with the end walls */
  870.  
  871.     if (tpGTrophy.vVel.z < CREAL(0))
  872.     {
  873.         /* moving towards far wall */
  874.         if (nZ < CREAL(FAR_STREET + RAT_MOVE_SIZE)) 
  875.         {
  876.             tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RICOCHET));
  877.             nZ = CREAL(FAR_STREET + RAT_MOVE_SIZE);
  878.         }
  879.     }
  880.     else
  881.     {
  882.         /* moving towards near wall */
  883.         if (nZ > CREAL(NEAR_STREET - RAT_MOVE_SIZE)) 
  884.         {
  885.             tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RICOCHET));
  886.             nZ = CREAL(NEAR_STREET - RAT_MOVE_SIZE);
  887.         }
  888.     }
  889.  
  890.     /* Test for collisions with the ground */
  891.  
  892.     if ((nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB))) 
  893.     {
  894.         /* On the pavement */
  895.  
  896.         if (nY <= CREAL(KERB_HEIGHT)) 
  897.         {
  898.             RwTranslateMatrix(tpGTrophy.mpDir, 
  899.                               CREAL(0.0), CREAL(KERB_HEIGHT), CREAL(0.0), 
  900.                               rwPOSTCONCAT);
  901. #ifdef WITH_SOUND
  902.             /* Make the sound */
  903.  
  904.             if (tpGTrophy.vVel.y < CREAL(-0.05)) 
  905.             {
  906.                 AllSoundsPlaySound("boink");
  907.             }
  908. #endif /* SOUND */
  909.  
  910.             /* Bounce the trophy. Use the rat friction and bounce parameters */
  911.  
  912.             tpGTrophy.vVel.y = RMul(tpGTrophy.vVel.y, CREAL(RAT_BOUNCE));
  913.  
  914.             /* Take into account friction */
  915.  
  916.             tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RAT_FRICTION));
  917.             tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RAT_FRICTION));
  918.             nY = CREAL(KERB_HEIGHT);
  919.         }
  920.     }
  921.     else 
  922.     {
  923.         /* On the road */
  924.  
  925.         if (nY <= CREAL(STREET_HEIGHT)) 
  926.         {
  927.             RwTranslateMatrix(tpGTrophy.mpDir, 
  928.                               CREAL(0.0), CREAL(STREET_HEIGHT) - nY, CREAL(0.0), rwPOSTCONCAT);
  929.  
  930. #ifdef WITH_SOUND
  931.             /* Make the sound */
  932.  
  933.             if (tpGTrophy.vVel.y < CREAL(-0.05)) 
  934.             {
  935.                 AllSoundsPlaySound("boink");
  936.             }
  937. #endif /* SOUND */
  938.  
  939.             /* Bounce the trophy !*/
  940.  
  941.             tpGTrophy.vVel.y = RMul(tpGTrophy.vVel.y, CREAL(RAT_BOUNCE));
  942.  
  943.             /* Take into account friction */
  944.  
  945.             tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RAT_FRICTION));
  946.             tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RAT_FRICTION));
  947.             nY = CREAL(STREET_HEIGHT);
  948.         }
  949.     }
  950.     /* Move the trophy to its new position */
  951.     RwSetMatrixElement(tpGTrophy.mpDir,3,0, nX);
  952.     RwSetMatrixElement(tpGTrophy.mpDir,3,1, nY);
  953.     RwSetMatrixElement(tpGTrophy.mpDir,3,2, nZ);
  954.  
  955.     opObj->vPos.x = nX;
  956.     opObj->vPos.y = nY;
  957.     opObj->vPos.z = nZ;
  958.  
  959.     RwTransformClump(tpGTrophy.cpCollision, tpGTrophy.mpDir, rwREPLACE);
  960. }
  961.  
  962. /************************************************************************
  963.  *
  964.  *      Function:       TrophyRender()
  965.  *                     
  966.  *      Description:    This function is called every frame to 
  967.  *                      render the position of the trophy,
  968.  *
  969.  *      Parameters:     opObj - generic object data
  970.  *
  971.  *      Return Value:   None
  972.  *
  973.  ************************************************************************/
  974. void TrophyRender(Object *opObj)
  975. {  
  976.     RwReal nX;
  977.  
  978. #ifdef WITH_SHADOWS
  979.     /* Render the shadow below the trophy. The location of the trophy on the
  980.      * street needs to be taken into consideration to allow for the
  981.      * different heights of the street and the kerb 
  982.      */
  983.  
  984.     /* Extract the location in X from the matrix */
  985.  
  986.     nX = RwGetMatrixElement(tpGTrophy.mpDir, 3, 0);
  987.  
  988.     /* Extract the position and orientation info from the trophy */
  989.  
  990.     RwCopyMatrix(tpGTrophy.mpDir, RwScratchMatrix());
  991.  
  992.     /* Adjust the matrix to place the shadow on the street of the kerb */
  993.  
  994.     if ( (nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB)) ) 
  995.     {
  996.         RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(KERB_HEIGHT + SHADOW_HEIGHT));
  997.     } 
  998.     else 
  999.     {
  1000.         RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(STREET_HEIGHT + SHADOW_HEIGHT));
  1001.     }
  1002.  
  1003.     /* Position and Render the shadow */
  1004.  
  1005.     RwTransformClump(tpGTrophy.cpShadow, RwScratchMatrix(), rwREPLACE);
  1006.     RwRenderClump(tpGTrophy.cpShadow);
  1007. #endif
  1008.  
  1009.   /* Render the trophy */
  1010.   RwTransformClump(opObj->cpClump, tpGTrophy.mpDir, rwREPLACE);
  1011.   RwRenderClump(opObj->cpClump);
  1012. }
  1013.  
  1014. /************************************************************************
  1015.  *
  1016.  *      Function:       TrophyEnable()
  1017.  *                     
  1018.  *      Description:    Enable the trophy. Note that all of the trophy
  1019.  *                      data was initialised at load time so all we need
  1020.  *                      top do is drop it into the street .
  1021.  *
  1022.  *      Parameters:     None. Uses global trophy data object
  1023.  *
  1024.  *      Return Value:   None
  1025.  *
  1026.  ************************************************************************/
  1027. void TrophyEnable(void)
  1028. {
  1029.     AllObjectsAddObject(&tpGTrophy.oObj);
  1030. }
  1031.  
  1032. /************************************************************************
  1033.  *
  1034.  *      Function:       TrophySetup()
  1035.  *                     
  1036.  *      Description:    Create and initialise the trophy
  1037.  *
  1038.  *      Parameters:     None. Uses global trophy data object
  1039.  *
  1040.  *      Return Value:   None
  1041.  *
  1042.  ************************************************************************/
  1043. int TrophySetup(void)
  1044. {
  1045.     /* Initialise the generic object bit */
  1046.  
  1047.     ObjectSetup(&tpGTrophy.oObj, CREAL(TROPHY_X), CREAL(TROPHY_Y), CREAL(TROPHY_Z), NULL);
  1048.  
  1049.     /* Define the functions that the generic handler will call to update
  1050.        and render the trophy */
  1051.  
  1052.     tpGTrophy.oObj.fpUpdate = TrophyUpdate;
  1053.     tpGTrophy.oObj.fpRender = TrophyRender;
  1054.  
  1055.     /* Don't define a destroy here since the trophy is only destroyed when 
  1056.        we exit from cyberstreet */
  1057.  
  1058.     tpGTrophy.oObj.pExtra = (void *)&tpGTrophy;
  1059.  
  1060.     /* Trophy starts with zero velocity but gravity soon changes that */
  1061.     tpGTrophy.vVel.x = CREAL(0.0);
  1062.     tpGTrophy.vVel.y = CREAL(0.0);
  1063.     tpGTrophy.vVel.z = CREAL(0.0);
  1064.  
  1065.     /* Create the position matrix for the trophy */
  1066.     if (tpGTrophy.mpDir = RwCreateMatrix())
  1067.     {
  1068.         /* Initialise the trophy's position */
  1069.         RwTranslateMatrix(tpGTrophy.mpDir, CREAL(TROPHY_X), CREAL(TROPHY_Y), CREAL(TROPHY_Z), rwREPLACE);
  1070.  
  1071.         /* Read the trophy script file */ 
  1072.         if (tpGTrophy.oObj.cpClump = DoRwReadShape("trophy.rwx"))
  1073.         {
  1074.             /* Create the collision data for teh trophy. Use the entire 
  1075.                trophy for the collision */
  1076.            if (tpGTrophy.cpCollision = RwDuplicateClump(tpGTrophy.oObj.cpClump))
  1077.        {
  1078.                 /* Initialise the collision data and add it to the 
  1079.                    collision scene */
  1080.                RwSetClumpData(tpGTrophy.cpCollision, &tpGTrophy.oObj);
  1081.         RwTransformClump(tpGTrophy.cpCollision, tpGTrophy.mpDir, rwREPLACE);
  1082.             RwAddClumpToScene(spGTargetScene, tpGTrophy.cpCollision);
  1083.                 /* Read the shadow script file */
  1084.             if (tpGTrophy.cpShadow = DoRwReadShape("trophys.rwx"))
  1085.         {
  1086.           return(TRUE);
  1087.         }
  1088.         RwDestroyClump(tpGTrophy.cpCollision);
  1089.        }
  1090.        RwDestroyClump(tpGTrophy.oObj.cpClump);
  1091.         }
  1092.         RwDestroyMatrix(tpGTrophy.mpDir);
  1093.     }
  1094.     return(FALSE);
  1095. }
  1096.  
  1097.