home *** CD-ROM | disk | FTP | other *** search
/ Learn 3D Graphics Programming on the PC / Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso / rwwin / gunbit.c_ / gunbit.bin
Text File  |  1995-11-14  |  30KB  |  918 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 = (int)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 (state)
  612.     {
  613.         if (!gGGun.nFiring && 
  614.             (gGGun.nFrameCount==RwGetTextureNumFrames(gGGun.tpTex)-1))
  615.         {
  616.             gGGun.nFrameCount=0;
  617.             gGGun.nFireFlag = 1;
  618.         }
  619.     }
  620.     else
  621.     {
  622.         gGGun.nFrameCount=RwGetTextureNumFrames(gGGun.tpTex)-1;
  623.         gGGun.nFireFlag = 0;
  624.     }
  625.     gGGun.nFiring=state;
  626. }
  627.  
  628. /************************************************************************
  629.  *
  630.  *      Function:       GunSetup()
  631.  *                      
  632.  *      Description:    Setup the gun
  633.  *
  634.  ************************************************************************/
  635. int GunSetup(void)
  636. {
  637.     /* Read the scripts for the gun */
  638.  
  639.     if (!(gGGun.cpGun =   DoRwReadShape("gun.rwx")) ||
  640.         !(gGGun.cpSight = DoRwReadShape("sight.rwx")) ||
  641.     !(gGGun.cpHit =   DoRwReadShape("hit.rwx")))
  642.     {
  643.         /* couldn't read the scripts - fail */
  644.         return FALSE;
  645.     }
  646.  
  647.     /* Find the gun texture and set the current frame to be the last one */
  648.  
  649.     gGGun.tpTex = RwFindNamedTexture("gun");
  650.     gGGun.nFrameCount = RwGetTextureNumFrames(gGGun.tpTex) - 1;
  651.  
  652.     gGGun.nPos     = CREAL(GUN_UP); /* gun starts in the visible position */
  653.     gGGun.nFiring  = FALSE;         /* gun isn't firing */
  654.     gGGun.nEnabled = 1;             /* gun is enabled */
  655.  
  656.     return TRUE;
  657. }
  658.  
  659. /************************************************************************
  660.  *
  661.  *      Function:       GunDestroy()
  662.  *                      
  663.  *      Description:    Destroy the gun
  664.  *
  665.  ************************************************************************/
  666. void GunDestroy(void)
  667. {
  668.     RwDestroyClump(gGGun.cpGun);
  669.     RwDestroyClump(gGGun.cpSight);
  670.     RwDestroyClump(gGGun.cpHit);
  671. }
  672.  
  673. /************************************************************************
  674.  *
  675.  *      Function:       GunUpdate()
  676.  *                      
  677.  *      Description:    Update the gun
  678.  *
  679.  ************************************************************************/
  680. void GunUpdate(void)
  681. {
  682. #ifdef WITH_SOUND
  683.     RwInt32 nRand;
  684. #endif
  685.     Object *opObj;
  686.     RwInt32 nW, nH; 
  687.  
  688.     if (!GunVisible())
  689.         return;
  690.  
  691.     RwGetCameraViewport(cpGCamera, NULL, NULL, &nW, &nH);
  692.  
  693.     /* First see if we are targetting a rat. The sight is in the
  694.        centre of the viewport */
  695.  
  696.     RwPickScene(spGTargetScene, nW/2, nH/2, cpGCamera, &prGPick);
  697.  
  698.     if (gGGun.nFireFlag) 
  699.     {
  700. #ifdef WITH_SOUND
  701.         /* Make the gun firing sound */
  702.         AllSoundsPlaySound("gun");
  703. #endif
  704.  
  705.         gGGun.nFireFlag = 0;    /* only fire once each round */
  706.  
  707.         if (prGPick.type == rwPICKCLUMP) 
  708.         {
  709.             /* Hit a target so destroy it. We identify whether the target is
  710.                a rat or the trophy by the number of polygons on the picked clump
  711.                Each rat only has one polygon in the target scene */
  712.  
  713.             if (RwGetClumpNumPolygons(prGPick.object.clump.clump) == 1)
  714.             {
  715.                 /* We've hit a rat. Identify the rat that has been hit */
  716.  
  717.                 opObj = (Object *) RwGetClumpData(prGPick.object.clump.clump);
  718.  
  719.                 /* Rat hit returns true if the rat has been destroyed, 
  720.                    false otherwise */
  721.  
  722.                 if (RatHit(opObj)) 
  723.                 {
  724.                     /* Explode the rat */
  725. #ifdef WITH_SOUND
  726.                     /* Make the squish sound */
  727.                     AllSoundsPlaySound("squish");
  728. #endif
  729.                     BitExplosionSetup(
  730.                             opObj->vPos.x,
  731.                                 opObj->vPos.y + CREAL(EXPLOSION_HEIGHT),
  732.                             opObj->vPos.z,
  733.                             EXPLOSION_BITS,
  734.                             abGBits.cpExplode);
  735.  
  736.                     /* Destroy the Rat */
  737.                     ObjectDelete(opObj);
  738.                     if (NumRats() == 1)
  739.                     {
  740.                         TrophyEnable();
  741.                     }
  742.                 } 
  743.                 else 
  744.                 {
  745.                     /* Have a little bit of an explosion */
  746.         
  747.                     BitExplosionSetup(
  748.                                 prGPick.object.clump.wcpoint.x,
  749.                                 prGPick.object.clump.wcpoint.y,
  750.                                 prGPick.object.clump.wcpoint.z,
  751.                                 HIT_BITS,
  752.                                 abGBits.cpExplode);
  753.  
  754. #ifdef WITH_SOUND
  755.                     /* Make the ricochet sound */
  756.                     nRand = RwRandom() & 255;
  757.  
  758.                     if (nRand < 80) 
  759.                     {
  760.                         AllSoundsPlaySound("squeak");
  761.                     } 
  762.                     else 
  763.                     {
  764.                         if (nRand < 160) 
  765.                         {
  766.                             AllSoundsPlaySound("ratty");
  767.                         } 
  768.                         else 
  769.                         {
  770.                             AllSoundsPlaySound("ratty2");
  771.                         }          
  772.                     }
  773. #endif
  774.                 }
  775.             } 
  776.             else 
  777.             {
  778.                 TrophyHit();
  779.                 /* must be a trophy */
  780. #ifdef WITH_SOUND
  781.                 /* Make the clang sound */
  782.                 AllSoundsPlaySound("clang");
  783. #endif
  784.                 BitExplosionSetup(
  785.                         prGPick.object.clump.wcpoint.x,
  786.                         prGPick.object.clump.wcpoint.y,
  787.                         prGPick.object.clump.wcpoint.z,
  788.                         TROPHY_BITS,
  789.                         abGBits.cpSpark);
  790.             }    
  791.         } 
  792.         else 
  793.         {
  794.             /* Nothing. See if we will hit a wall */
  795.  
  796.             RwPickScene(spGScene, nW/2, nH/2, cpGCamera, &prGCityPick);
  797.  
  798.             if (prGCityPick.type == rwPICKCLUMP) 
  799.             {
  800.                 /* A wall has been hit !!! */
  801. #ifdef WITH_SOUND
  802.                 /* Make the ricochet sound */
  803.                 AllSoundsPlaySound("ricochet");
  804. #endif
  805.                 /* Wall has been hit */
  806.                 BitExplosionSetup(
  807.                       prGCityPick.object.clump.wcpoint.x,
  808.                       prGCityPick.object.clump.wcpoint.y,
  809.                       prGCityPick.object.clump.wcpoint.z,
  810.                       SPARK_BITS,
  811.                       abGBits.cpSpark);
  812.             }
  813.         }
  814.     }
  815. }
  816.  
  817. /************************************************************************
  818.  *
  819.  *      Function:       GunRender()
  820.  *                      
  821.  *      Description:    Render the gun
  822.  *
  823.  ************************************************************************/
  824. void GunRender(void)
  825. {
  826.     RwV3d vPos;
  827.     RwV3d vAt;
  828.     RwV3d vUp;
  829.                       
  830.     if (gGGun.nPos <= CREAL(GUN_REMOVE)) 
  831.     {
  832.         /* The gun has been removed */
  833.  
  834.         if (gGGun.nEnabled) 
  835.         {
  836.             /* Bring it back */
  837.             gGGun.nPos += CREAL(GUN_SPEED);
  838.         }
  839.     } 
  840.     else 
  841.     {
  842.         /* The gun is on screen */
  843.  
  844.         RwSetTextureFrame(gGGun.tpTex, gGGun.nFrameCount);
  845.  
  846.         if (gGGun.nFrameCount < RwGetTextureNumFrames(gGGun.tpTex) - 1) 
  847.         {
  848.             gGGun.nFrameCount++;
  849.         }
  850.  
  851.         if (!gGGun.nEnabled) 
  852.         {
  853.             gGGun.nPos -= CREAL(GUN_SPEED);
  854.         } 
  855.         else 
  856.         {
  857.             if (gGGun.nPos >= CREAL(GUN_UP)) 
  858.             {
  859.                 gGGun.nPos = CREAL(GUN_UP);
  860.  
  861.                 if ((gGGun.nFrameCount==(RwGetTextureNumFrames(gGGun.tpTex)-1)) &&
  862.                     (gGGun.nFiring))
  863.                 {
  864.                         /* The gun has been fired !!!!!!!!!!!!!!! */
  865.  
  866.                     gGGun.nFrameCount=0;
  867.                     gGGun.nFireFlag = 1;
  868.                 }
  869.             } 
  870.             else 
  871.             {
  872.                 gGGun.nPos+= CREAL(GUN_SPEED);
  873.             }
  874.         }
  875.         /* Render the Sight */
  876.  
  877.         RwGetCameraPosition(cpGCamera, &vPos);
  878.         RwGetCameraLookAt(cpGCamera, &vAt);
  879.  
  880.         RwScaleVector(&vAt, CREAL(GUNSIGHT_POS), &vAt);
  881.         RwAddVector(&vPos, &vAt, &vPos);
  882.  
  883.         RwTranslateMatrix(RwScratchMatrix(), 
  884.                           vPos.x, vPos.y, vPos.z, rwREPLACE);
  885.  
  886.  
  887.         if (prGPick.type == rwPICKCLUMP) 
  888.         {
  889.             /* something has been targetted */
  890.  
  891.             RwTransformClump(gGGun.cpHit, RwScratchMatrix(), rwREPLACE);
  892.             RwRenderClump(gGGun.cpHit);
  893.         } 
  894.         else 
  895.         {
  896.             RwTransformClump(gGGun.cpSight, RwScratchMatrix(), rwREPLACE);
  897.             RwRenderClump(gGGun.cpSight);
  898.         }
  899.  
  900.         /* Render the gun */
  901.  
  902.         RwGetCameraPosition(cpGCamera, &vPos);
  903.         RwGetCameraLookAt(cpGCamera, &vAt);
  904.         RwScaleVector(&vAt, CREAL(GUN_FORWARD), &vAt);
  905.         RwAddVector(&vPos, &vAt, &vPos);
  906.         RwGetCameraLookUp(cpGCamera,&vUp);
  907.  
  908.         RwScaleVector(&vUp, gGGun.nPos, &vUp);
  909.         RwAddVector(&vPos, &vUp, &vPos);
  910.  
  911.         RwTranslateMatrix(RwScratchMatrix(), vPos.x, vPos.y, vPos.z, rwREPLACE);
  912.         RwTransformClump(gGGun.cpGun, RwScratchMatrix(), rwREPLACE);
  913.         RwRenderClump(gGGun.cpGun);
  914.     }
  915. }
  916.  
  917.  
  918.