home *** CD-ROM | disk | FTP | other *** search
/ Learn 3D Graphics Programming on the PC / Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso / rwdos / gunbit.c < prev    next >
C/C++ Source or Header  |  1995-02-15  |  29KB  |  916 lines

  1. /**********************************************************************
  2.  *
  3.  * File :     gunbit.c
  4.  *
  5.  * Abstract : The gun and explosion bit handler. This module handles
  6.  *            the movement and display of the gun and the bits that
  7.  *            appear when an object is struck or explodes.
  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. /*--- Macros and Magic Number definitions */
  33.  
  34. #define GUN_UP              -0.26   /* The gun position when it is fully
  35.                                        up (ie the normal firing position */
  36.                                        
  37. #define GUN_REMOVE          -0.5    /* The gun is removed once it drops
  38.                                        below this value */
  39.  
  40. #define GUN_FORWARD         1.0     /* distance gun is in front of the 
  41.                                        camera */
  42. #define GUN_SPEED           0.05    /* When the gun is rising and falling
  43.                                        it moves at this rate */
  44. #define GUNSIGHT_POS        6.0     /* The distance that the gun is drawn
  45.                                        in front of the camera */
  46. #define EXPLOSION_HEIGHT    0.1     /* The start height for the bits of
  47.                                        explosion */
  48.  
  49. #define BIT_BOUNCE          (-1.0/2.0)  /* The change in velocity of a bit 
  50.                                            when it hits the ground */
  51.  
  52. /* Bit Definitions */
  53.  
  54. /*  define number of random matrices to create for random bit orientation 
  55.  *  Note: MAX_BIT_ROTATIONS must be n^2 to allow BIT_ROT_MASK to be used as a 
  56.  *  selector
  57.  */
  58.  
  59. #define MAX_BIT_ROTATIONS   8   /* Number of different bit rotations */
  60. #define BIT_ROT_MASK        (MAX_BIT_ROTATIONS - 1)
  61.  
  62. #define EXP_VEL             0.05    /* The maximum velocity of an 
  63.                                        exploding bit */
  64. #define BIT_SIZE            0.025   /* The size of a bit */
  65.  
  66. #define SPARK_BITS          1   /* no of bits created for a spark */
  67. #define TROPHY_BITS         2   /* no of bits created when the trophy is hit */
  68. #define HIT_BITS            5   /* no of bits created when a rat is hit */
  69. #define EXPLOSION_BITS      20  /* no of bits created when a rat explodes */
  70.  
  71. /*--- Structure Definitions ---*/
  72.  
  73. /*  Bit: A bit is one of the small particles that can be observed when the gun 
  74.  *  fires at a wall or the trophy (a spark) or when a Rat explodes. Bits are 
  75.  *  created in blocks. The size of the block depends on the type of bit being 
  76.  *  created.
  77.  */ 
  78.  
  79. typedef struct 
  80. {
  81.     Object oObj;            /* Bit's are objects just like everything else */
  82.     int *npCount;           /* Reference counter. When this is zero all Bits                                
  83.                                in the current group have been destroyed and 
  84.                                the global structure can also be destroyed */
  85.     int nPos;               /* identifies which of the Random bit rotation 
  86.                                matrices this Bit is using */
  87.     RwV3d vVel;             /* the velocity of the Bit */
  88. } Bit;
  89.  
  90.  
  91. /*  All Bits: A single global variable of this type is created and used as 
  92.  *  a global pool for the Bit Data
  93.  */
  94.  
  95. typedef struct 
  96. {
  97.     RwClump *cpExplode;                     /* The clump for the Explosion Bit */
  98.     RwClump *cpSpark;                       /* The clump for the Spark bit */
  99. #ifdef WITH_SHADOWS
  100.     RwClump *cpShadow;                      /* The clump for the Bit's shadow. Both
  101.                                                Bit types share the same shadow clump */
  102. #endif                                      
  103.     RwMatrix4d *mpaPos[MAX_BIT_ROTATIONS];  /* Random Bit orientation matrices */
  104.     RwMatrix4d *mpaRot[MAX_BIT_ROTATIONS];  /* Small rotations incrementally applied    
  105.                                             to mpaPos */
  106. } AllBits;
  107.  
  108.  
  109. /* Gun definition */
  110.  
  111. typedef struct 
  112. {
  113.     RwClump *cpGun;         /* The clump for the Gun */
  114.     RwClump *cpSight;       /* The clump for the Gun Sight */
  115.     RwClump *cpHit;
  116.     RwReal nPos;
  117.     RwTexture *tpTex;
  118.     int nFiring;            /* TRUE if gun is firing, FALSE otherwise */
  119.     int nFireFlag;          /* TRUE if gun has been fired */
  120.     RwInt32 nFrameCount;
  121.     int nEnabled;           /* 1 if enabled, 0 if disabled */
  122. } Gun;
  123.  
  124. /*--- Global Variable ---*/
  125.  
  126. static Gun          gGGun;
  127. static RwPickRecord prGCityPick;
  128. static RwPickRecord prGPick;
  129. static AllBits      abGBits;
  130.  
  131. /*--- Function Definitions ---*/
  132.  
  133. /* Bit Functions */
  134.  
  135. /************************************************************************
  136.  *
  137.  *      Function:       AllBitsSetup()
  138.  *                      
  139.  *      Description:    Initialise the global AllBits data structure
  140.  *
  141.  *      Return Value:   TRUE on success, FALSE on failure
  142.  *
  143.  ************************************************************************/
  144. int AllBitsSetup(void)
  145. {
  146.     int nCount;    RwV3d vTmp;
  147.  
  148.     /* Read the RenderWare script files for the 3 bit clump types */
  149.  
  150.     if (!(abGBits.cpExplode = DoRwReadShape("bit.rwx")) || 
  151. #ifdef WITH_SHADOWS
  152.         !(abGBits.cpShadow = DoRwReadShape("bitshad.rwx")) || 
  153. #endif
  154.         !(abGBits.cpSpark = DoRwReadShape("spark.rwx"))) 
  155.     {
  156.         return FALSE;       /* Unable to read script files - Error */
  157.     }
  158.  
  159.     /* Create the Random Rotation matrices */
  160.  
  161.     for (nCount=0; nCount < MAX_BIT_ROTATIONS; nCount++) 
  162.     {
  163.         if (!(abGBits.mpaRot[nCount] = RwCreateMatrix()) ||
  164.             !(abGBits.mpaPos[nCount] = RwCreateMatrix())) 
  165.         {
  166.             return FALSE;   /* Unable to create matrices - Error */
  167.         }
  168.  
  169.         /* The mpaRot matrices are rotation matrices about an arbitrary axis
  170.            with an angular component between +10.0 and -10.0 degrees */
  171.         
  172.         RandomVec(&vTmp);
  173.         
  174.         RwRotateMatrix(abGBits.mpaRot[nCount], 
  175.                        vTmp.x, vTmp.y, vTmp.z,
  176.                        RANDOM_REAL(CREAL(-10.0), CREAL(10.0)),                      
  177.                        rwREPLACE);
  178.         
  179.         /* The mpaPos matrices are rotation matrices about an arbitrary axis
  180.            with a random orientation */
  181.         
  182.         RandomVec(&vTmp);
  183.  
  184.         RwRotateMatrix(abGBits.mpaPos[nCount], 
  185.                        vTmp.x,vTmp.y,vTmp.z,
  186.                        RANDOM_REAL(CREAL(0.0), CREAL(360.0)),
  187.                        rwREPLACE);
  188.     }
  189.     return TRUE;    /* success */
  190. }
  191.  
  192. /************************************************************************
  193.  *
  194.  *      Function:       AllBitsDestroy()
  195.  *                      
  196.  *      Description:    Destroy the global AllBits data structure
  197.  *
  198.  *
  199.  ************************************************************************/
  200. void AllBitsDestroy(void)
  201. {
  202.     int nCount;
  203.  
  204.     RwDestroyClump(abGBits.cpExplode);          /* destroy the Explosion clump */
  205. #ifdef WITH_SHADOWS
  206.     RwDestroyClump(abGBits.cpShadow);           /* destroy the shadow clump */
  207. #endif
  208.     RwDestroyClump(abGBits.cpSpark);            /* destroy the spark clump */
  209.  
  210.     /* destroy the random rotation matrices */
  211.  
  212.     for (nCount=0; nCount < MAX_BIT_ROTATIONS; nCount++) 
  213.     {
  214.         RwDestroyMatrix(abGBits.mpaRot[nCount]);
  215.         RwDestroyMatrix(abGBits.mpaPos[nCount]);
  216.     }
  217. }
  218.  
  219. /************************************************************************
  220.  *
  221.  *      Function:       AllBitsUpdate()
  222.  *                      
  223.  *      Description:    Increment all of the orientation matrices in the
  224.  *                      global AllBits data structure. 
  225.  *
  226.  ************************************************************************/
  227. void AllBitsUpdate(void)
  228. {
  229.     int nCount;
  230.     static int nOrtho;  /* orthonormalise a different matrix each time this function 
  231.                            is called */   
  232.  
  233.  
  234.     for (nCount=0; nCount < MAX_BIT_ROTATIONS; nCount++) 
  235.     {
  236.         /* Postconcat the mpaRot incremental matrix
  237.            onto the mpaPos position matrix */
  238.  
  239.         RwTransformMatrix(abGBits.mpaPos[nCount],
  240.                           abGBits.mpaRot[nCount],
  241.                           rwPOSTCONCAT);
  242.     }
  243.  
  244.     nOrtho++;
  245.     RwOrthoNormalizeMatrix(abGBits.mpaPos[nOrtho & BIT_ROT_MASK],  
  246.                            abGBits.mpaPos[nOrtho & BIT_ROT_MASK]);
  247. }
  248.  
  249. /************************************************************************
  250.  *
  251.  *      Function:       BitObjectDestroy()                     
  252.  * 
  253.  *      Description:    Destroy a single Bit Object 
  254.  *
  255.  ************************************************************************/
  256. static void BitObjectDestroy(Object *opObj)
  257. {
  258.     Bit *bpBit;
  259.  
  260.     bpBit = opObj->pExtra;
  261.     
  262.     /* since Bit's are allocated in blocks, decrement the reference
  263.        count and only free the allocated space once all Bit's in the
  264.        block have been freed */
  265.  
  266.     if (--(*(bpBit->npCount)) <= 0) 
  267.     {
  268.         free(bpBit->npCount);
  269.     }
  270. }
  271.  
  272. /************************************************************************
  273.  *
  274.  *      Function:       BitRender()
  275.  *                      
  276.  *      Description:    Render a single Bit Object 
  277.  *
  278.  ************************************************************************/
  279. static void BitRender(Object *opObj)
  280. {
  281.     Bit *bpBit;
  282.  
  283.     bpBit = opObj->pExtra;
  284.  
  285. #ifdef WITH_SHADOWS
  286.     /* Render the shadow */
  287.  
  288.     /* Check if the bit is in the scene */
  289.  
  290.     if ((opObj->vPos.z > CREAL(FAR_STREET)) &&
  291.         (opObj->vPos.z < CREAL(NEAR_STREET))) 
  292.     {
  293.         /* Bit in the scene. Check whether the shadow is on the road
  294.            or on the kerb */
  295.  
  296.         if ((opObj->vPos.x < CREAL(LEFT_KERB)) ||
  297.             (opObj->vPos.x > CREAL(RIGHT_KERB)) ) 
  298.         {
  299.             /* Its on the kerb */
  300.             RwTranslateMatrix(RwScratchMatrix(),
  301.                               opObj->vPos.x,
  302.                               CREAL(KERB_HEIGHT),
  303.                               opObj->vPos.z,
  304.                               rwREPLACE);
  305.         } 
  306.         else 
  307.         {
  308.             /* Its on the street */
  309.             RwTranslateMatrix(RwScratchMatrix(),
  310.                               opObj->vPos.x,
  311.                               CREAL(STREET_HEIGHT),
  312.                               opObj->vPos.z,
  313.                               rwREPLACE);
  314.         }
  315.  
  316.         /* Position and Render the shadow */
  317.         RwTransformClump(abGBits.cpShadow, RwScratchMatrix(), rwREPLACE);
  318.         RwRenderClump(abGBits.cpShadow);
  319.     }
  320. #endif /* WITH_SHADOWS */
  321.  
  322.     /* Render the Bit */
  323.  
  324.     /* Get the rotation matrix for this Bit */    
  325.  
  326.      RwCopyMatrix(abGBits.mpaPos[bpBit->nPos], RwScratchMatrix());
  327.  
  328.     /* Position the bit */
  329.  
  330.      RwTranslateMatrix(RwScratchMatrix(),
  331.                        opObj->vPos.x,
  332.                        opObj->vPos.y,
  333.                        opObj->vPos.z,      
  334.                        rwPOSTCONCAT);
  335.  
  336.      RwTransformClump(opObj->cpClump, RwScratchMatrix(), rwREPLACE);
  337.  
  338.     /* And render it */
  339.  
  340.     RwRenderClump(opObj->cpClump);
  341. }
  342.  
  343. /************************************************************************
  344.  *
  345.  *      Function:       BitUpdate()
  346.  *                      
  347.  *      Description:    Update the position of a single Bit
  348.  *
  349.  ************************************************************************/
  350. static void BitUpdate(Object *opObj)
  351. {
  352.     Bit *bpBit;
  353.  
  354.     bpBit = (Bit *)opObj->pExtra;
  355.  
  356.     /* Move bit to new position */
  357.     RwAddVector(&bpBit->oObj.vPos, &bpBit->vVel, &bpBit->oObj.vPos);
  358.  
  359.     /* Apply gravity */
  360.     bpBit->vVel.y -= CREAL(GRAVITY);
  361.  
  362.     /* Test for collisions with the side walls */
  363.  
  364.     if(bpBit->vVel.x < CREAL(0.0)) 
  365.     {
  366.         /* moving towards left wall */
  367.         if (bpBit->oObj.vPos.x < CREAL(LEFT_STREET + BIT_SIZE)) 
  368.         {
  369.             /* collided with left wall - bounce */
  370.             bpBit->vVel.x = RMul(bpBit->vVel.x, CREAL(RICOCHET));
  371.         }
  372.     }
  373.     else
  374.     {
  375.         /* moving towards the right wall */
  376.  
  377.         if (bpBit->oObj.vPos.x > CREAL(RIGHT_STREET - BIT_SIZE)) 
  378.         {
  379.             bpBit->vVel.x = RMul(bpBit->vVel.x, CREAL(RICOCHET));
  380.         }
  381.     }
  382.  
  383.     /* Test for collisions with the end walls */
  384.  
  385.     if (bpBit->vVel.z < CREAL(0.0))
  386.     {
  387.         /* travelling towards the far wall */
  388.  
  389.         if (bpBit->oObj.vPos.z < CREAL(FAR_STREET + BIT_SIZE)) 
  390.         {
  391.             /* collided with far wall - bounce */
  392.  
  393.             bpBit->vVel.z = RMul(bpBit->vVel.z, CREAL(RICOCHET));
  394.         }
  395.     }
  396.     else
  397.     {
  398.         /* travelling towards the near wall */
  399.         if (bpBit->oObj.vPos.z > CREAL(NEAR_STREET - BIT_SIZE)) 
  400.         {
  401.             /* collided with near wall - bounce */
  402.  
  403.             bpBit->vVel.z = -RMul(bpBit->vVel.z, CREAL(RICOCHET));
  404.         }
  405.     }
  406.  
  407.     /* Test for collision with side of kerb */
  408.  
  409.     if (bpBit->oObj.vPos.y < CREAL(KERB_HEIGHT + BIT_SIZE)) 
  410.     {
  411.         /* below kerb height - possible collision */
  412.  
  413.         if (bpBit->vVel.x < CREAL(0.0)) 
  414.         {
  415.             /* moving to the left - test against left kerb */
  416.             if (bpBit->oObj.vPos.x < CREAL(LEFT_KERB + BIT_SIZE)) 
  417.             {
  418.                 /* collided with left kerb - bounce */
  419.                 bpBit->vVel.x = RMul(bpBit->vVel.x, CREAL(RICOCHET));
  420.             }
  421.         } 
  422.         else 
  423.         {
  424.             /* moving to the right - test against right kerb */
  425.             if (bpBit->oObj.vPos.x > CREAL(RIGHT_KERB - BIT_SIZE)) 
  426.             {
  427.                 /* collided with right kerb */
  428.                 bpBit->vVel.x = RMul(bpBit->vVel.x, CREAL(RICOCHET));
  429.             }
  430.         }
  431.     }
  432.  
  433.     /* Check for collisions with ground */
  434.  
  435.     if (bpBit->vVel.y < CREAL(0.0)) 
  436.     {
  437.         /* falling bit */
  438.  
  439.         if ((bpBit->oObj.vPos.x > CREAL(LEFT_KERB + BIT_SIZE)) &&
  440.             (bpBit->oObj.vPos.x < CREAL(RIGHT_KERB - BIT_SIZE))) 
  441.         {
  442.             /* Over the road - test against road height */
  443.  
  444.             if (bpBit->oObj.vPos.y < CREAL(STREET_HEIGHT + BIT_SIZE)) 
  445.             {
  446.                 /* collided with road - bounce */
  447.                 bpBit->vVel.y = RMul(bpBit->vVel.y, CREAL(BIT_BOUNCE));
  448.             }
  449.         } 
  450.         else 
  451.         {
  452.             /* Over the kerb - test against kerb height */
  453.  
  454.             if (bpBit->oObj.vPos.y < CREAL(KERB_HEIGHT + BIT_SIZE))
  455.             {
  456.                 /* collided with kerb - bounce */
  457.                 bpBit->vVel.y = RMul(bpBit->vVel.y, CREAL(BIT_BOUNCE));
  458.             }
  459.         }
  460.     }
  461.  
  462.     /* If the bit isn't moving in then destroy it */
  463.  
  464.     if ((bpBit->vVel.y < CREAL(0.0)) &&
  465.         (bpBit->vVel.y > CREAL(-0.001)) ) 
  466.     {
  467.         ObjectDelete(&bpBit->oObj);
  468.     }
  469. }
  470.  
  471. /************************************************************************
  472.  *
  473.  *      Function:       BitSetup()
  474.  *                      
  475.  *      Description:    Initialise a single Bit. 
  476.  *
  477.  ************************************************************************/
  478. static void BitSetup(
  479.               Bit *bpBit,         /* the bit to setup */
  480.               RwReal nX,          /* initial bit position */
  481.               RwReal nY,
  482.               RwReal nZ,
  483.               int *npCount,       /* the global reference counter location */
  484.               RwClump *cpClump    /* the clump type to use for the bit */
  485.               )
  486. {
  487.     static RwInt32 nPos;
  488.  
  489.     ObjectSetup(&bpBit->oObj,nX,nY,nZ,cpClump); /* initialise the object data */
  490.  
  491.     bpBit->oObj.fpUpdate = BitUpdate;         /* function to update object */ 
  492.     bpBit->oObj.fpRender = BitRender;         /* function to render object */
  493.     bpBit->oObj.fpDestroy = BitObjectDestroy; /* function to destroy object */    
  494.     bpBit->oObj.pExtra = (void *)bpBit;       /* how to get Bit from object */
  495.     bpBit->nPos = nPos & BIT_ROT_MASK;        /* pick a Bit rotation matrix */
  496.  
  497.     nPos++;                     /* next call picks next Bit rotation matrix */
  498.  
  499.     /* Set the initial Bit velocity */
  500.     
  501.     bpBit->vVel.x = RANDOM_REAL(CREAL(-EXP_VEL), CREAL(EXP_VEL));
  502.     bpBit->vVel.y = RANDOM_REAL(CREAL(-EXP_VEL), CREAL(EXP_VEL));
  503.     bpBit->vVel.z = RANDOM_REAL(CREAL(-EXP_VEL), CREAL(EXP_VEL));
  504.  
  505.     bpBit->npCount = npCount;  /* Set the Bit reference count */ 
  506.  
  507.     AllObjectsAddObject(&bpBit->oObj); /* Add this new object to the scene */
  508. }
  509.  
  510. /************************************************************************
  511.  *
  512.  *      Function:       BitExplosionSetup()
  513.  *                      
  514.  *      Description:    Create and Initialise all the Bits for an
  515.  *                      explosion.
  516.  *
  517.  ************************************************************************/
  518. static void BitExplosionSetup( 
  519.                        RwReal nX,   /* Start position for the explosion */
  520.                        RwReal nY,  
  521.                        RwReal nZ,
  522.                        int nAmo,    /* The number of Bits in the explosion */
  523.                        RwClump *cpClump  /* The Bit clump to use for this
  524.                                             explosion */
  525.                        )
  526. {
  527.     Bit *bpBit;
  528.     int *npCount;
  529.  
  530.     /* Allocate enough space for all the Bits and a reference counter */
  531.  
  532.     npCount = (int *)malloc(sizeof(int) + (sizeof(Bit) * nAmo));
  533.  
  534.     if (npCount) 
  535.     {
  536.         /* Initialise reference count with the number of bits */  
  537.  
  538.         (*npCount) = nAmo;  
  539.  
  540.         bpBit = (Bit *) (&npCount[1]);
  541.  
  542.         /* Set up each of the Bits in turn */       
  543.  
  544.         for (; nAmo > 0; nAmo--) 
  545.         {
  546.             BitSetup(bpBit, nX, nY, nZ, npCount, cpClump);
  547.             bpBit++;
  548.         }
  549.     }
  550. }
  551.  
  552. /*--- Gun Functions ---*/
  553.  
  554. /************************************************************************
  555.  *
  556.  *      Function:       GunVisible()
  557.  *                      
  558.  *      Description:    return TRUE if gun visible, FALSE otherwise
  559.  *
  560.  ************************************************************************/
  561. int GunVisible(void)
  562. {
  563.     return(!(gGGun.nPos <= CREAL(GUN_REMOVE)));
  564. }
  565.  
  566. /************************************************************************
  567.  *
  568.  *      Function:       GunEnable()
  569.  *                      
  570.  *      Description:    Enable display of the gun
  571.  *
  572.  ************************************************************************/
  573. void GunEnable(void)
  574. {
  575.     gGGun.nEnabled = 1;
  576. }
  577.  
  578. /************************************************************************
  579.  *
  580.  *      Function:       GunDisable()
  581.  *                      
  582.  *      Description:    Disable display of the gun
  583.  *
  584.  ************************************************************************/
  585. void GunDisable(void)
  586. {
  587.     gGGun.nEnabled = 0;
  588. }
  589.  
  590. /************************************************************************
  591.  *
  592.  *      Function:       GunToggle()
  593.  *                      
  594.  *      Description:    Toggle display of the gun
  595.  *
  596.  ************************************************************************/
  597. void GunToggle(void)
  598. {
  599.      gGGun.nEnabled^=1;
  600. }
  601.  
  602. /************************************************************************
  603.  *
  604.  *      Function:       GunFiring()
  605.  *                      
  606.  *      Description:    Set firing state for the gun
  607.  *
  608.  ************************************************************************/
  609. void GunFiring(int state)
  610. {
  611.     if (!gGGun.nFiring && state)
  612.     {
  613.         if (gGGun.nFrameCount==RwGetTextureNumFrames(gGGun.tpTex)-1)
  614.         {
  615.             gGGun.nFrameCount=0;
  616.             gGGun.nFireFlag = 1;
  617.         }
  618.     }
  619.     else
  620.     {
  621.         gGGun.nFireFlag = 0;
  622.     }
  623.     gGGun.nFiring=state;
  624. }
  625.  
  626. /************************************************************************
  627.  *
  628.  *      Function:       GunSetup()
  629.  *                      
  630.  *      Description:    Setup the gun
  631.  *
  632.  ************************************************************************/
  633. int GunSetup(void)
  634. {
  635.     /* Read the scripts for the gun */
  636.  
  637.     if (!(gGGun.cpGun =   DoRwReadShape("gun.rwx")) ||
  638.         !(gGGun.cpSight = DoRwReadShape("sight.rwx")) ||
  639.     !(gGGun.cpHit =   DoRwReadShape("hit.rwx")))
  640.     {
  641.         /* couldn't read the scripts - fail */
  642.         return FALSE;
  643.     }
  644.  
  645.     /* Find the gun texture and set the current frame to be the last one */
  646.  
  647.     gGGun.tpTex = RwFindNamedTexture("gun");
  648.     gGGun.nFrameCount = RwGetTextureNumFrames(gGGun.tpTex) - 1;
  649.  
  650.     gGGun.nPos     = CREAL(GUN_UP); /* gun starts in the visible position */
  651.     gGGun.nFiring  = FALSE;         /* gun isn't firing */
  652.     gGGun.nEnabled = 1;             /* gun is enabled */
  653.  
  654.     return TRUE;
  655. }
  656.  
  657. /************************************************************************
  658.  *
  659.  *      Function:       GunDestroy()
  660.  *                      
  661.  *      Description:    Destroy the gun
  662.  *
  663.  ************************************************************************/
  664. void GunDestroy(void)
  665. {
  666.     RwDestroyClump(gGGun.cpGun);
  667.     RwDestroyClump(gGGun.cpSight);
  668.     RwDestroyClump(gGGun.cpHit);
  669. }
  670.  
  671. /************************************************************************
  672.  *
  673.  *      Function:       GunUpdate()
  674.  *                      
  675.  *      Description:    Update the gun
  676.  *
  677.  ************************************************************************/
  678. void GunUpdate(void)
  679. {
  680. #ifdef WITH_SOUND
  681.     RwInt32 nRand;
  682. #endif
  683.     Object *opObj;
  684.     RwInt32 nW, nH; 
  685.  
  686.     if (!GunVisible())
  687.         return;
  688.  
  689.     RwGetCameraViewport(cpGCamera, NULL, NULL, &nW, &nH);
  690.  
  691.     /* First see if we are targetting a rat. The sight is in the
  692.        centre of the viewport */
  693.  
  694.     RwPickScene(spGTargetScene, nW/2, nH/2, cpGCamera, &prGPick);
  695.  
  696.     if (gGGun.nFireFlag) 
  697.     {
  698. #ifdef WITH_SOUND
  699.         /* Make the gun firing sound */
  700.         AllSoundsPlaySound("gun");
  701. #endif
  702.  
  703.         gGGun.nFireFlag = 0;    /* only fire once each round */
  704.  
  705.         if (prGPick.type == rwPICKCLUMP) 
  706.         {
  707.             /* Hit a target so destroy it. We identify whether the target is
  708.                a rat or the trophy by the number of polygons on the picked clump
  709.                Each rat only has one polygon in the target scene */
  710.  
  711.             if (RwGetClumpNumPolygons(prGPick.object.clump.clump) == 1)
  712.             {
  713.                 /* We've hit a rat. Identify the rat that has been hit */
  714.  
  715.                 opObj = (Object *) RwGetClumpData(prGPick.object.clump.clump);
  716.  
  717.                 /* Rat hit returns true if the rat has been destroyed, 
  718.                    false otherwise */
  719.  
  720.                 if (RatHit(opObj)) 
  721.                 {
  722.                     /* Explode the rat */
  723. #ifdef WITH_SOUND
  724.                     /* Make the squish sound */
  725.                     AllSoundsPlaySound("squish");
  726. #endif
  727.                     BitExplosionSetup(
  728.                              opObj->vPos.x,
  729.                                 opObj->vPos.y + CREAL(EXPLOSION_HEIGHT),
  730.                                opObj->vPos.z,
  731.                             EXPLOSION_BITS,
  732.                             abGBits.cpExplode);
  733.  
  734.                     /* Destroy the Rat */
  735.                     ObjectDelete(opObj);
  736.                     if (NumRats() == 1)
  737.                     {
  738.                         TrophyEnable();
  739.                     }
  740.                 } 
  741.                 else 
  742.                 {
  743.                     /* Have a little bit of an explosion */
  744.         
  745.                     BitExplosionSetup(
  746.                                 prGPick.object.clump.wcpoint.x,
  747.                                 prGPick.object.clump.wcpoint.y,
  748.                                 prGPick.object.clump.wcpoint.z,
  749.                                 HIT_BITS,
  750.                                 abGBits.cpExplode);
  751.  
  752. #ifdef WITH_SOUND
  753.                     /* Make the ricochet sound */
  754.                     nRand = RwRandom() & 255;
  755.  
  756.                     if (nRand < 80) 
  757.                     {
  758.                         AllSoundsPlaySound("squeak");
  759.                     } 
  760.                     else 
  761.                     {
  762.                         if (nRand < 160) 
  763.                         {
  764.                             AllSoundsPlaySound("ratty");
  765.                         } 
  766.                         else 
  767.                         {
  768.                             AllSoundsPlaySound("ratty2");
  769.                         }          
  770.                     }
  771. #endif
  772.                 }
  773.             } 
  774.             else 
  775.             {
  776.                 TrophyHit();
  777.                 /* must be a trophy */
  778. #ifdef WITH_SOUND
  779.                 /* Make the clang sound */
  780.                 AllSoundsPlaySound("clang");
  781. #endif
  782.                 BitExplosionSetup(
  783.                         prGPick.object.clump.wcpoint.x,
  784.                         prGPick.object.clump.wcpoint.y,
  785.                         prGPick.object.clump.wcpoint.z,
  786.                         TROPHY_BITS,
  787.                         abGBits.cpSpark);
  788.             }    
  789.         } 
  790.         else 
  791.         {
  792.             /* Nothing. See if we will hit a wall */
  793.  
  794.             RwPickScene(spGScene, nW/2, nH/2, cpGCamera, &prGCityPick);
  795.  
  796.             if (prGCityPick.type == rwPICKCLUMP) 
  797.             {
  798.                 /* A wall has been hit !!! */
  799. #ifdef WITH_SOUND
  800.                 /* Make the ricochet sound */
  801.                 AllSoundsPlaySound("ricochet");
  802. #endif
  803.                 /* Wall has been hit */
  804.                 BitExplosionSetup(
  805.                       prGCityPick.object.clump.wcpoint.x,
  806.                       prGCityPick.object.clump.wcpoint.y,
  807.                       prGCityPick.object.clump.wcpoint.z,
  808.                       SPARK_BITS,
  809.                       abGBits.cpSpark);
  810.             }
  811.         }
  812.     }
  813. }
  814.  
  815. /************************************************************************
  816.  *
  817.  *      Function:       GunRender()
  818.  *                      
  819.  *      Description:    Render the gun
  820.  *
  821.  ************************************************************************/
  822. void GunRender(void)
  823. {
  824.     RwV3d vPos;
  825.     RwV3d vAt;
  826.     RwV3d vUp;
  827.                       
  828.     if (gGGun.nPos <= CREAL(GUN_REMOVE)) 
  829.     {
  830.         /* The gun has been removed */
  831.  
  832.         if (gGGun.nEnabled) 
  833.         {
  834.             /* Bring it back */
  835.             gGGun.nPos += CREAL(GUN_SPEED);
  836.         }
  837.     } 
  838.     else 
  839.     {
  840.         /* The gun is on screen */
  841.  
  842.         RwSetTextureFrame(gGGun.tpTex, gGGun.nFrameCount);
  843.  
  844.         if (gGGun.nFrameCount < RwGetTextureNumFrames(gGGun.tpTex) - 1) 
  845.         {
  846.             gGGun.nFrameCount++;
  847.         }
  848.  
  849.         if (!gGGun.nEnabled) 
  850.         {
  851.             gGGun.nPos -= CREAL(GUN_SPEED);
  852.         } 
  853.         else 
  854.         {
  855.             if (gGGun.nPos >= CREAL(GUN_UP)) 
  856.             {
  857.                 gGGun.nPos = CREAL(GUN_UP);
  858.  
  859.                 if ((gGGun.nFrameCount==(RwGetTextureNumFrames(gGGun.tpTex)-1)) &&
  860.                     (gGGun.nFiring))
  861.                 {
  862.                         /* The gun has been fired !!!!!!!!!!!!!!! */
  863.  
  864.                     gGGun.nFrameCount=0;
  865.                     gGGun.nFireFlag = 1;
  866.                 }
  867.             } 
  868.             else 
  869.             {
  870.                 gGGun.nPos+= CREAL(GUN_SPEED);
  871.             }
  872.         }
  873.         /* Render the Sight */
  874.  
  875.         RwGetCameraPosition(cpGCamera, &vPos);
  876.         RwGetCameraLookAt(cpGCamera, &vAt);
  877.  
  878.         RwScaleVector(&vAt, CREAL(GUNSIGHT_POS), &vAt);
  879.         RwAddVector(&vPos, &vAt, &vPos);
  880.  
  881.         RwTranslateMatrix(RwScratchMatrix(), 
  882.                           vPos.x, vPos.y, vPos.z, rwREPLACE);
  883.  
  884.  
  885.         if (prGPick.type == rwPICKCLUMP) 
  886.         {
  887.             /* something has been targetted */
  888.  
  889.             RwTransformClump(gGGun.cpHit, RwScratchMatrix(), rwREPLACE);
  890.             RwRenderClump(gGGun.cpHit);
  891.         } 
  892.         else 
  893.         {
  894.             RwTransformClump(gGGun.cpSight, RwScratchMatrix(), rwREPLACE);
  895.             RwRenderClump(gGGun.cpSight);
  896.         }
  897.  
  898.         /* Render the gun */
  899.  
  900.         RwGetCameraPosition(cpGCamera, &vPos);
  901.         RwGetCameraLookAt(cpGCamera, &vAt);
  902.         RwScaleVector(&vAt, CREAL(GUN_FORWARD), &vAt);
  903.         RwAddVector(&vPos, &vAt, &vPos);
  904.         RwGetCameraLookUp(cpGCamera,&vUp);
  905.  
  906.         RwScaleVector(&vUp, gGGun.nPos, &vUp);
  907.         RwAddVector(&vPos, &vUp, &vPos);
  908.  
  909.         RwTranslateMatrix(RwScratchMatrix(), vPos.x, vPos.y, vPos.z, rwREPLACE);
  910.         RwTransformClump(gGGun.cpGun, RwScratchMatrix(), rwREPLACE);
  911.         RwRenderClump(gGGun.cpGun);
  912.     }
  913. }
  914.  
  915.  
  916.