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 >
C/C++ Source or Header  |  1995-02-15  |  36KB  |  1,117 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.                 int nVolume = REAL2INT(RMul(-rpRat->vVel.y, CREAL(50.0)));
  343.                 if (nVolume > 0x2f) 
  344.                 {
  345.                     nVolume = 0x2f;
  346.                 }
  347.                 AllSoundsPlaySoundVolume(nVolume, "boink");
  348.             }
  349.  
  350. #endif /* WITH_SOUND */
  351.  
  352.             /* Bounce the rat !*/
  353.  
  354.             rpRat->vVel.y = RMul(rpRat->vVel.y, CREAL(RAT_BOUNCE));
  355.  
  356.             /* Take into account friction */
  357.  
  358.             rpRat->vVel.x = RMul(rpRat->vVel.x, CREAL(RAT_FRICTION));
  359.             rpRat->vVel.z = RMul(rpRat->vVel.z, CREAL(RAT_FRICTION));
  360.             nY = CREAL(KERB_HEIGHT);
  361.         }
  362.     }
  363.     else 
  364.     {
  365.         /* On the road */
  366.  
  367.         if (nY <= CREAL(STREET_HEIGHT)) 
  368.         {
  369.             RwTranslateMatrix(rpRat->mpDir, 
  370.                               CREAL(0.0), RSub(CREAL(STREET_HEIGHT), nY), CREAL(0.0), rwPOSTCONCAT);
  371.  
  372. #ifdef WITH_SOUND
  373.             /* Make the sound */
  374.  
  375.             if (rpRat->vVel.y < CREAL(-0.05)) 
  376.             {
  377.                 int nVolume = REAL2INT(RMul(-rpRat->vVel.y, CREAL(50)));
  378.                 if (nVolume > 0x2f) 
  379.                 {
  380.                     nVolume = 0x2f;
  381.                 }
  382.                 AllSoundsPlaySoundVolume(nVolume, "boink");
  383.             }
  384.  
  385. #endif /* SOUND */
  386.  
  387.             /* Bounce the rat !*/
  388.  
  389.             rpRat->vVel.y = RMul(rpRat->vVel.y, CREAL(RAT_BOUNCE));
  390.  
  391.             /* Take into account friction */
  392.  
  393.             rpRat->vVel.x = RMul(rpRat->vVel.x, CREAL(RAT_FRICTION));
  394.             rpRat->vVel.z = RMul(rpRat->vVel.z, CREAL(RAT_FRICTION));
  395.             nY = CREAL(STREET_HEIGHT);
  396.         }
  397.     }
  398.     /* If on the ground make it do things */
  399.  
  400.     if ( (nY < CREAL(KERB_HEIGHT + GROUND_TRAP)) && 
  401.         (rpRat->vVel.y < CREAL(GRAVITY)))
  402.     {
  403.         if (rpRat->nCount-- < 0) 
  404.         {
  405.             /* previous movement completed */
  406.             RatGivePurpose(rpRat);
  407.         }
  408.  
  409.         switch (rpRat->nState) 
  410.         {
  411.             case RAT_WAIT: 
  412.                 break;
  413.  
  414.             case RAT_TURN_LEFT: 
  415.                 RwTransformMatrix(rpRat->mpDir, arGRats.mpTurnLeft, rwPRECONCAT);
  416.                 break;
  417.  
  418.             case RAT_TURN_RIGHT:
  419.                 RwTransformMatrix(rpRat->mpDir, arGRats.mpTurnRight, rwPRECONCAT);
  420.                 break;
  421.  
  422.             case RAT_FORWARD:
  423.                 RwTranslateMatrix(rpRat->mpDir, 
  424.                                   CREAL(0.0), CREAL(0.0), CREAL(RAT_SPEED),
  425.                                   rwPRECONCAT);
  426.                 if (!(rpRat->nCount)) 
  427.                 {
  428.                     /* If its the last frame then ortho normalize it */
  429.                     RwOrthoNormalizeMatrix(rpRat->mpDir,rpRat->mpDir);
  430.                 }
  431.                 rpRat->nFrame++;
  432.  
  433.                 if (rpRat->nFrame >= RAT_MAX_FRAMES) 
  434.                 {
  435.                     rpRat->nFrame = 0;
  436.                 }
  437.                 break;
  438.  
  439.             default:
  440.                 break;
  441.         }
  442.  
  443.         /* Bound the movement of ratty */
  444.  
  445.         if (nY == CREAL(STREET_HEIGHT)) 
  446.         {
  447.             if (nX < CREAL(LEFT_KERB + RAT_TRAP_SIZE)) 
  448.             {
  449.                 RwSetMatrixElement(rpRat->mpDir, 3, 0, 
  450.                                    CREAL(LEFT_KERB + RAT_TRAP_SIZE));
  451.                 RatGivePurpose(rpRat);
  452.             }
  453.             if (nX > CREAL(RIGHT_KERB - RAT_TRAP_SIZE)) 
  454.             {
  455.                 RwSetMatrixElement(rpRat->mpDir, 3, 0, 
  456.                                    CREAL(RIGHT_KERB - RAT_TRAP_SIZE));
  457.                 RatGivePurpose(rpRat);
  458.             }
  459.         } 
  460.         else 
  461.         {
  462.             if (nX < CREAL(LEFT_STREET + RAT_MOVE_SIZE)) 
  463.             {
  464.                 RwSetMatrixElement(rpRat->mpDir, 3, 0, CREAL(LEFT_STREET + RAT_MOVE_SIZE));
  465.                 RatGivePurpose(rpRat);
  466.             }
  467.             if (nX > CREAL(RIGHT_STREET - RAT_MOVE_SIZE)) 
  468.             {
  469.                 RwSetMatrixElement(rpRat->mpDir, 3, 0, CREAL(RIGHT_STREET - RAT_MOVE_SIZE));
  470.                 RatGivePurpose(rpRat);
  471.             }
  472.         }
  473.  
  474.         if (nZ < CREAL(FAR_STREET + RAT_MOVE_SIZE)) 
  475.         {
  476.              RwSetMatrixElement(rpRat->mpDir, 3, 2, CREAL(FAR_STREET + RAT_MOVE_SIZE));
  477.              RatGivePurpose(rpRat);
  478.         }
  479.         else if (nZ > CREAL(NEAR_STREET - RAT_MOVE_SIZE)) 
  480.         {
  481.             RwSetMatrixElement(rpRat->mpDir, 3, 2, CREAL(NEAR_STREET - RAT_MOVE_SIZE));
  482.             RatGivePurpose(rpRat);
  483.         }
  484.     } 
  485.     opObj->cpClump = arGRats.cpaFrames[rpRat->nFrame];
  486.     opObj->vPos.x = RwGetMatrixElement(rpRat->mpDir,3,0);
  487.     opObj->vPos.y = RwGetMatrixElement(rpRat->mpDir,3,1);
  488.     opObj->vPos.z = RwGetMatrixElement(rpRat->mpDir,3,2);
  489.  
  490.     RwTransformClump(rpRat->cpCollision, rpRat->mpDir, rwREPLACE);
  491. }
  492.  
  493. /************************************************************************
  494.  *
  495.  *      Function:       RatRender()
  496.  *                     
  497.  *      Description:    Render a single rat. This function
  498.  *                      is called by the generic object handler on every
  499.  *                      frame for each rat in the street
  500.  *
  501.  *      Parameters:     opObj - the object that defines the rat
  502.  *
  503.  *      Return Value:   None
  504.  *
  505.  ************************************************************************/
  506. static void RatRender(Object *opObj)
  507. {
  508.   Rat *rpRat;
  509.   RwReal nX;
  510.  
  511.     /* extract the Rat data from the generic object */
  512.  
  513.     rpRat = (Rat *)opObj->pExtra;
  514.  
  515. #ifdef WITH_SHADOWS
  516.     
  517.     /* Render the shadow below the rat. The location of the rat on the
  518.      * street needs to be taken into consideration to allow for the
  519.      * different heights of the street and the kerb 
  520.      */
  521.  
  522.     /* Extract the location in X from the matrix */
  523.  
  524.      nX = RwGetMatrixElement(rpRat->mpDir, 3, 0);
  525.  
  526.     /* Extract the position and orientation info from the rat */
  527.  
  528.     RwCopyMatrix(rpRat->mpDir, RwScratchMatrix());
  529.  
  530.     /* Adjust the matrix to place the shadow on the street of the kerb */
  531.  
  532.     if ( (nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB)) ) 
  533.     {
  534.         RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(KERB_HEIGHT + SHADOW_HEIGHT));
  535.     } 
  536.     else 
  537.     {
  538.         RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(STREET_HEIGHT + SHADOW_HEIGHT));
  539.     }
  540.  
  541.     /* Transform and render the shadow */
  542.     RwTransformClump(rpRat->cpShadow, RwScratchMatrix(), rwREPLACE);
  543.     RwRenderClump(rpRat->cpShadow);
  544. #endif
  545.  
  546.   /* Transform and Render the rat */
  547.  
  548.   RwTransformClump(opObj->cpClump, rpRat->mpDir, rwREPLACE);
  549.   RwRenderClump(opObj->cpClump);
  550. }
  551.  
  552. /************************************************************************
  553.  *
  554.  *      Function:       RatDestroy()
  555.  *                     
  556.  *      Description:    Destroy a single rat. This function
  557.  *                      is called by the generic object handler once the
  558.  *                      object has been deleted.
  559.  *
  560.  *      Parameters:     opObj - the object that defines the rat
  561.  *
  562.  *      Return Value:   None
  563.  *
  564.  ************************************************************************/
  565. static void RatDestroy(Object *opObj)
  566. {
  567.     Rat *rpRat;
  568.  
  569.     /* extract the rat data from the generic object */
  570.  
  571.     rpRat = (Rat *)opObj->pExtra;
  572.  
  573.     /* Remove the collision object for this rat from the collision scene */
  574.  
  575.     RwRemoveClumpFromScene(rpRat->cpCollision);
  576.     RwDestroyClump(rpRat->cpCollision);
  577.  
  578.     /* Destroy the position matrix for this rat */
  579.  
  580.     RwDestroyMatrix(rpRat->mpDir);
  581.  
  582.     /* There is one less rat in the world */
  583.  
  584.     arGRats.nRats--;
  585.  
  586.     /* Add 1 to the number of dead rats */
  587.  
  588.     arGRats.nDeadRats++;
  589.  
  590.     /* free up the rat data */
  591.     free(rpRat);
  592. }
  593.  
  594. /************************************************************************
  595.  *
  596.  *      Function:       RatSetup()
  597.  *                     
  598.  *      Description:    Create a new rat and drop it into the street
  599.  *
  600.  *      Parameters:     None
  601.  *
  602.  *      Return Value:   None
  603.  *
  604.  ************************************************************************/
  605. static void RatSetup(void)
  606. {  
  607.     RwReal nX, nY, nZ;
  608.     Rat *rpRat;
  609.  
  610.     /* Generate a random start position for the rat */
  611.  
  612.     nX = RANDOM_REAL(CREAL(LEFT_STREET + 0.2), CREAL(RIGHT_STREET - 0.2));
  613.     nY = CREAL(RAT_START_HEIGHT);
  614.     nZ = RANDOM_REAL(CREAL(FAR_STREET + 0.2), CREAL(NEAR_STREET - 0.2));
  615.  
  616.     /* Create a new rat */
  617.     rpRat = (Rat *)malloc(sizeof(Rat));
  618.  
  619.     /* initialise the generic bit */
  620.     ObjectSetup(&rpRat->oObj, nX, nY, nZ, NULL);
  621.  
  622.     /* define the functions that the generic object handler needs to
  623.        control the rat */
  624.  
  625.     rpRat->oObj.fpUpdate = RatUpdate;
  626.     rpRat->oObj.fpRender = RatRender;
  627.     rpRat->oObj.fpDestroy = RatDestroy;
  628.     rpRat->oObj.pExtra = (void *)rpRat;
  629.  
  630.     /* We want to assign some behaviour as soon as the rat hits the ground */
  631.     rpRat->nFrame = 0;
  632.  
  633.     /* Start with zero velocity. Gravity will start things moving */
  634.     rpRat->vVel.x = CREAL(0.0);
  635.     rpRat->vVel.y = CREAL(0.0);
  636.     rpRat->vVel.z = CREAL(0.0);
  637.  
  638.     /* Give the rat some behaviour */
  639.     RatGivePurpose(rpRat);
  640.  
  641.     /* Generate and initialise the transformation matrix for this rat */
  642.     rpRat->mpDir = RwCreateMatrix();
  643.     RwTranslateMatrix(rpRat->mpDir, nX, nY, nZ, rwREPLACE);
  644.  
  645.     /* Copy the generic rat collision object, transform it to the position
  646.        and orientation of the rat and add it to the collision scene */
  647.  
  648.     rpRat->cpCollision = RwDuplicateClump(arGRats.cpCollision);
  649.     RwSetClumpData(rpRat->cpCollision, &rpRat->oObj);
  650.     RwTransformClump(rpRat->cpCollision, rpRat->mpDir, rwREPLACE);
  651.     RwAddClumpToScene(spGTargetScene, rpRat->cpCollision);
  652.  
  653.     /* Set the Shadow image */
  654.  
  655.     rpRat->cpShadow = arGRats.cpShadow;
  656.  
  657.     /* Set the amount of hits it can take before being destroyed */
  658.  
  659.     rpRat->nHit = RAT_HITS;
  660.  
  661.     /* Just added a new rat so add one more to the number in the street */
  662.  
  663.     arGRats.nRats++;
  664.  
  665.     /* Add to the generic object scene management stuff */
  666.  
  667.     AllObjectsAddObject(&rpRat->oObj);
  668.  
  669.     /* Give the rat a random direction */
  670.  
  671.     RwRotateMatrix(RwScratchMatrix(), 
  672.                    CREAL(0.0), CREAL(1.0), CREAL(0.0),
  673.                    RANDOM_REAL(CREAL(0.0), CREAL(360.0)),
  674.                    rwREPLACE );
  675.  
  676.     RwTransformMatrix(rpRat->mpDir, RwScratchMatrix(), rwPRECONCAT);
  677. }
  678. /************************************************************************
  679.  *
  680.  *      Function:       AllRatsDestroy()
  681.  *                     
  682.  *      Description:    Destroy the shared rat data.
  683.  *
  684.  *      Parameters:     None
  685.  *
  686.  *      Return Value:   None
  687.  *
  688.  ************************************************************************/
  689. void AllRatsDestroy(void)
  690. {
  691.     RwDestroyClump(arGRats.cpShadow);
  692.     RwDestroyClump(arGRats.cpCollision);
  693.     RwDestroyClump(arGRats.cpaFrames[0]);
  694.     RwDestroyClump(arGRats.cpaFrames[1]);
  695.     RwDestroyClump(arGRats.cpaFrames[2]);
  696.     RwDestroyClump(arGRats.cpaFrames[3]);
  697.     RwDestroyClump(arGRats.cpaFrames[4]);
  698.     RwDestroyClump(arGRats.cpaFrames[5]);
  699.     RwDestroyClump(arGRats.cpaFrames[6]);
  700.  
  701.     RwDestroyMatrix(arGRats.mpTurnLeft);
  702.     RwDestroyMatrix(arGRats.mpTurnRight);
  703. }
  704.  
  705. /************************************************************************
  706.  *
  707.  *      Function:       AllRatsSetup()
  708.  *                     
  709.  *      Description:    Create the shared rat data.
  710.  *
  711.  *      Parameters:     None
  712.  *
  713.  *      Return Value:   TRUE if successful, FALSE otherwise
  714.  *
  715.  ************************************************************************/
  716. int AllRatsSetup(void)
  717. {
  718.     /* start with zero rats */
  719.  
  720.     arGRats.nRats = 0;
  721.  
  722.     /* Read all of the clumps needed for the rats*/
  723.     if (!(arGRats.cpCollision = DoRwReadShape("collisio.rwx")) ||
  724. #ifdef WITH_SHADOWS
  725.         !(arGRats.cpShadow = DoRwReadShape("ratshad.rwx")) ||
  726. #endif
  727.     /* Get the rat animation frames */
  728.  
  729.         !(arGRats.cpaFrames[0] = DoRwReadShape("rat1.rwx")) ||
  730.         !(arGRats.cpaFrames[2] = DoRwReadShape("rat3.rwx")) ||
  731.         !(arGRats.cpaFrames[4] = DoRwReadShape("rat5.rwx")) ||
  732.         !(arGRats.cpaFrames[6] = DoRwReadShape("rat7.rwx")) ||
  733.         !(arGRats.cpaFrames[1] = DoRwReadShape("rat2.rwx")) || 
  734.         !(arGRats.cpaFrames[3] = DoRwReadShape("rat4.rwx")) ||
  735.         !(arGRats.cpaFrames[5] = DoRwReadShape("rat6.rwx")))
  736.     {
  737.         /* Failed to read something - error */
  738.         return FALSE;
  739.     }
  740.  
  741.     /* Create The matrices used to turn the rats to the left and right */
  742.  
  743.     if (!(arGRats.mpTurnLeft = RwCreateMatrix()) ||
  744.         !(arGRats.mpTurnRight = RwCreateMatrix())) 
  745.     {
  746.         /* failed to create the matrices - error */
  747.         return FALSE;
  748.     }
  749.  
  750.     /* And initialise these matrices */
  751.     RwRotateMatrix(arGRats.mpTurnLeft,CREAL(0.0),CREAL(1.0),CREAL(0.0),
  752.                    CREAL(3.0),rwREPLACE);
  753.  
  754.     RwRotateMatrix(arGRats.mpTurnRight,CREAL(0.0),CREAL(1.0),CREAL(0.0),
  755.                    CREAL(-3.0),rwREPLACE);
  756.  
  757.  
  758.     /* Create the initial amount of rats. Use half of the maximum */
  759.  
  760.     arGRats.nCreateCount=0;  
  761.  
  762.     while (arGRats.nRats < RAT_MAXIMUM/2)
  763.     {
  764.         RatSetup();
  765.     }
  766.     return TRUE;
  767. }
  768.  
  769. /************************************************************************
  770.  *
  771.  *      Function:       AllRatsRelease()
  772.  *                     
  773.  *      Description:    Control the steady flow of rats into the street
  774.  *
  775.  *      Parameters:     None. Uses global rat data
  776.  *
  777.  *      Return Value:   None
  778.  *
  779.  ************************************************************************/
  780. void AllRatsRelease(void)
  781. {
  782.     /* Increment the creation timer */
  783.     arGRats.nCreateCount++;
  784.  
  785.     if ( (arGRats.nCreateCount >= RAT_CREATE_TIME) &&
  786.          (arGRats.nRats) ) 
  787.     {
  788.         /* It's time to create a rat */
  789.         arGRats.nCreateCount = 0;
  790.  
  791.         if (arGRats.nRats < RAT_MAXIMUM) 
  792.         {
  793.             /* We haven't reached the limit yet. Create anothe one */
  794.             RatSetup();
  795.         }
  796.     }
  797. }
  798.  
  799. /* Trophy Functions */
  800.  
  801. /************************************************************************
  802.  *
  803.  *      Function:       TrophyHit()
  804.  *                     
  805.  *      Description:    Move the trophy in response to a hit
  806.  *
  807.  *      Parameters:     None. Uses the global trophy data object
  808.  *
  809.  *      Return Value:   None
  810.  *
  811.  ************************************************************************/
  812. void TrophyHit(void)
  813. {
  814.     RwV3d vPos;
  815.  
  816.     /* Use the vector from the camera to the trophy to determine the strike
  817.        direction */
  818.  
  819.     RwGetCameraPosition(cpGCamera, &vPos);
  820.     RwSubtractVector(&(tpGTrophy.oObj.vPos), &vPos, &vPos);
  821.     RwNormalize(&vPos);
  822.  
  823.     /* Move the trophy in the direction of the strike */
  824.     RwScaleVector(&vPos, CREAL(TARGET_HITFORCE), &vPos);
  825.     RwAddVector(&tpGTrophy.vVel, &vPos, &tpGTrophy.vVel);
  826. }
  827.  
  828. /************************************************************************
  829.  *
  830.  *      Function:       TrophyUpdate()
  831.  *                     
  832.  *      Description:    This function is called every frame to 
  833.  *                      update the position of the trophy,
  834.  *
  835.  *      Parameters:     opObj - the generic object
  836.  *
  837.  *      Return Value:   None
  838.  *
  839.  ************************************************************************/
  840. static void TrophyUpdate(Object *opObj)
  841. {
  842.     RwReal nX,nY,nZ;
  843.  
  844.     /* Apply the force of gravity */
  845.  
  846.     tpGTrophy.vVel.y -= CREAL(GRAVITY);  
  847.  
  848.     /* Preserve the momentum of the trophy */
  849.     
  850.     RwTranslateMatrix(tpGTrophy.mpDir,
  851.                       tpGTrophy.vVel.x, tpGTrophy.vVel.y, tpGTrophy.vVel.z,
  852.                       rwPOSTCONCAT);
  853.     nX = RwGetMatrixElement(tpGTrophy.mpDir,3,0);
  854.     nY = RwGetMatrixElement(tpGTrophy.mpDir,3,1);
  855.     nZ = RwGetMatrixElement(tpGTrophy.mpDir,3,2);
  856.  
  857.     /* Test for collisions with the side walls */
  858.  
  859.     if (tpGTrophy.vVel.x < CREAL(0.0))
  860.     {
  861.         /* Moving to the left - check against left wall */
  862.         if (nX < CREAL(LEFT_STREET + RAT_MOVE_SIZE))
  863.         {
  864.             /* collision - bounce */
  865.             tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RICOCHET));
  866.             nX = CREAL(LEFT_STREET + RAT_MOVE_SIZE);
  867.         }
  868.     }
  869.     else
  870.     {
  871.         /* Moving to the right - check against right wall */
  872.         if (nX > CREAL(RIGHT_STREET - RAT_MOVE_SIZE)) 
  873.         {
  874.             tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RICOCHET));
  875.             nX = CREAL(RIGHT_STREET - RAT_MOVE_SIZE);
  876.         }
  877.     }
  878.  
  879.     /* Test for collisions with the end walls */
  880.  
  881.     if (tpGTrophy.vVel.z < CREAL(0))
  882.     {
  883.         /* moving towards far wall */
  884.         if (nZ < CREAL(FAR_STREET + RAT_MOVE_SIZE)) 
  885.         {
  886.             tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RICOCHET));
  887.             nZ = CREAL(FAR_STREET + RAT_MOVE_SIZE);
  888.         }
  889.     }
  890.     else
  891.     {
  892.         /* moving towards near wall */
  893.         if (nZ > CREAL(NEAR_STREET - RAT_MOVE_SIZE)) 
  894.         {
  895.             tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RICOCHET));
  896.             nZ = CREAL(NEAR_STREET - RAT_MOVE_SIZE);
  897.         }
  898.     }
  899.  
  900.     /* Test for collisions with the ground */
  901.  
  902.     if ((nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB))) 
  903.     {
  904.         /* On the pavement */
  905.  
  906.         if (nY <= CREAL(KERB_HEIGHT)) 
  907.         {
  908.             RwTranslateMatrix(tpGTrophy.mpDir, 
  909.                               CREAL(0.0), CREAL(KERB_HEIGHT), CREAL(0.0), 
  910.                               rwPOSTCONCAT);
  911. #ifdef WITH_SOUND
  912.             /* Make the sound */
  913.  
  914.             if (tpGTrophy.vVel.y < CREAL(-0.05)) 
  915.             {
  916.                 int nVolume = REAL2INT(RMul(-tpGTrophy.vVel.y, CREAL(50)));
  917.                 if (nVolume > 0x2f) 
  918.                 {
  919.                     nVolume = 0x2f;
  920.                 }
  921.                 AllSoundsPlaySoundVolume(nVolume, "boink");
  922.             }
  923. #endif /* SOUND */
  924.  
  925.             /* Bounce the trophy. Use the rat friction and bounce parameters */
  926.  
  927.             tpGTrophy.vVel.y = RMul(tpGTrophy.vVel.y, CREAL(RAT_BOUNCE));
  928.  
  929.             /* Take into account friction */
  930.  
  931.             tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RAT_FRICTION));
  932.             tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RAT_FRICTION));
  933.             nY = CREAL(KERB_HEIGHT);
  934.         }
  935.     }
  936.     else 
  937.     {
  938.         /* On the road */
  939.  
  940.         if (nY <= CREAL(STREET_HEIGHT)) 
  941.         {
  942.             RwTranslateMatrix(tpGTrophy.mpDir, 
  943.                               CREAL(0.0), CREAL(STREET_HEIGHT) - nY, CREAL(0.0), rwPOSTCONCAT);
  944.  
  945. #ifdef WITH_SOUND
  946.             /* Make the sound */
  947.  
  948.             if (tpGTrophy.vVel.y < CREAL(-0.05)) 
  949.             {
  950.                 int nVolume = REAL2INT(RMul(-tpGTrophy.vVel.y, CREAL(50)));
  951.                 if (nVolume > 0x2f) 
  952.                 {
  953.                     nVolume = 0x2f;
  954.                 }
  955.                 AllSoundsPlaySoundVolume(nVolume, "boink");
  956.             }
  957. #endif /* SOUND */
  958.  
  959.             /* Bounce the trophy !*/
  960.  
  961.             tpGTrophy.vVel.y = RMul(tpGTrophy.vVel.y, CREAL(RAT_BOUNCE));
  962.  
  963.             /* Take into account friction */
  964.  
  965.             tpGTrophy.vVel.x = RMul(tpGTrophy.vVel.x, CREAL(RAT_FRICTION));
  966.             tpGTrophy.vVel.z = RMul(tpGTrophy.vVel.z, CREAL(RAT_FRICTION));
  967.             nY = CREAL(STREET_HEIGHT);
  968.         }
  969.     }
  970.     /* Move the trophy to its new position */
  971.     RwSetMatrixElement(tpGTrophy.mpDir,3,0, nX);
  972.     RwSetMatrixElement(tpGTrophy.mpDir,3,1, nY);
  973.     RwSetMatrixElement(tpGTrophy.mpDir,3,2, nZ);
  974.  
  975.     opObj->vPos.x = nX;
  976.     opObj->vPos.y = nY;
  977.     opObj->vPos.z = nZ;
  978.  
  979.     RwTransformClump(tpGTrophy.cpCollision, tpGTrophy.mpDir, rwREPLACE);
  980. }
  981.  
  982. /************************************************************************
  983.  *
  984.  *      Function:       TrophyRender()
  985.  *                     
  986.  *      Description:    This function is called every frame to 
  987.  *                      render the position of the trophy,
  988.  *
  989.  *      Parameters:     opObj - generic object data
  990.  *
  991.  *      Return Value:   None
  992.  *
  993.  ************************************************************************/
  994. void TrophyRender(Object *opObj)
  995. {  
  996.     RwReal nX;
  997.  
  998. #ifdef WITH_SHADOWS
  999.     /* Render the shadow below the trophy. The location of the trophy on the
  1000.      * street needs to be taken into consideration to allow for the
  1001.      * different heights of the street and the kerb 
  1002.      */
  1003.  
  1004.     /* Extract the location in X from the matrix */
  1005.  
  1006.     nX = RwGetMatrixElement(tpGTrophy.mpDir, 3, 0);
  1007.  
  1008.     /* Extract the position and orientation info from the trophy */
  1009.  
  1010.     RwCopyMatrix(tpGTrophy.mpDir, RwScratchMatrix());
  1011.  
  1012.     /* Adjust the matrix to place the shadow on the street of the kerb */
  1013.  
  1014.     if ( (nX < CREAL(LEFT_KERB)) || (nX > CREAL(RIGHT_KERB)) ) 
  1015.     {
  1016.         RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(KERB_HEIGHT + SHADOW_HEIGHT));
  1017.     } 
  1018.     else 
  1019.     {
  1020.         RwSetMatrixElement(RwScratchMatrix(), 3, 1, CREAL(STREET_HEIGHT + SHADOW_HEIGHT));
  1021.     }
  1022.  
  1023.     /* Position and Render the shadow */
  1024.  
  1025.     RwTransformClump(tpGTrophy.cpShadow, RwScratchMatrix(), rwREPLACE);
  1026.     RwRenderClump(tpGTrophy.cpShadow);
  1027. #endif
  1028.  
  1029.   /* Render the trophy */
  1030.   RwTransformClump(opObj->cpClump, tpGTrophy.mpDir, rwREPLACE);
  1031.   RwRenderClump(opObj->cpClump);
  1032. }
  1033.  
  1034. /************************************************************************
  1035.  *
  1036.  *      Function:       TrophyEnable()
  1037.  *                     
  1038.  *      Description:    Enable the trophy. Note that all of the trophy
  1039.  *                      data was initialised at load time so all we need
  1040.  *                      top do is drop it into the street .
  1041.  *
  1042.  *      Parameters:     None. Uses global trophy data object
  1043.  *
  1044.  *      Return Value:   None
  1045.  *
  1046.  ************************************************************************/
  1047. void TrophyEnable(void)
  1048. {
  1049.     AllObjectsAddObject(&tpGTrophy.oObj);
  1050. }
  1051.  
  1052. /************************************************************************
  1053.  *
  1054.  *      Function:       TrophySetup()
  1055.  *                     
  1056.  *      Description:    Create and initialise the trophy
  1057.  *
  1058.  *      Parameters:     None. Uses global trophy data object
  1059.  *
  1060.  *      Return Value:   None
  1061.  *
  1062.  ************************************************************************/
  1063. int TrophySetup(void)
  1064. {
  1065.     /* Initialise the generic object bit */
  1066.  
  1067.     ObjectSetup(&tpGTrophy.oObj, CREAL(TROPHY_X), CREAL(TROPHY_Y), CREAL(TROPHY_Z), NULL);
  1068.  
  1069.     /* Define the functions that the generic handler will call to update
  1070.        and render the trophy */
  1071.  
  1072.     tpGTrophy.oObj.fpUpdate = TrophyUpdate;
  1073.     tpGTrophy.oObj.fpRender = TrophyRender;
  1074.  
  1075.     /* Don't define a destroy here since the trophy is only destroyed when 
  1076.        we exit from cyberstreet */
  1077.  
  1078.     tpGTrophy.oObj.pExtra = (void *)&tpGTrophy;
  1079.  
  1080.     /* Trophy starts with zero velocity but gravity soon changes that */
  1081.     tpGTrophy.vVel.x = CREAL(0.0);
  1082.     tpGTrophy.vVel.y = CREAL(0.0);
  1083.     tpGTrophy.vVel.z = CREAL(0.0);
  1084.  
  1085.     /* Create the position matrix for the trophy */
  1086.     if (tpGTrophy.mpDir = RwCreateMatrix())
  1087.     {
  1088.         /* Initialise the trophy's position */
  1089.         RwTranslateMatrix(tpGTrophy.mpDir, CREAL(TROPHY_X), CREAL(TROPHY_Y), CREAL(TROPHY_Z), rwREPLACE);
  1090.  
  1091.         /* Read the trophy script file */ 
  1092.         if (tpGTrophy.oObj.cpClump = DoRwReadShape("trophy.rwx"))
  1093.         {
  1094.             /* Create the collision data for teh trophy. Use the entire 
  1095.                trophy for the collision */
  1096.            if (tpGTrophy.cpCollision = RwDuplicateClump(tpGTrophy.oObj.cpClump))
  1097.        {
  1098.                 /* Initialise the collision data and add it to the 
  1099.                    collision scene */
  1100.                RwSetClumpData(tpGTrophy.cpCollision, &tpGTrophy.oObj);
  1101.         RwTransformClump(tpGTrophy.cpCollision, tpGTrophy.mpDir, rwREPLACE);
  1102.             RwAddClumpToScene(spGTargetScene, tpGTrophy.cpCollision);
  1103.                 /* Read the shadow script file */
  1104.             if (tpGTrophy.cpShadow = DoRwReadShape("trophys.rwx"))
  1105.         {
  1106.           return(TRUE);
  1107.         }
  1108.         RwDestroyClump(tpGTrophy.cpCollision);
  1109.        }
  1110.        RwDestroyClump(tpGTrophy.oObj.cpClump);
  1111.         }
  1112.         RwDestroyMatrix(tpGTrophy.mpDir);
  1113.     }
  1114.     return(FALSE);
  1115. }
  1116.  
  1117.