home *** CD-ROM | disk | FTP | other *** search
/ Micromanía 92 / CDMM92_1.ISO / SOF 2 SDK / sof2sdk-101.msi / _92D6AC311BB48EBA344BBABC89DA6AB0 / _3FDFD4448E4A4397926A3E750B248D3F < prev    next >
Encoding:
Text File  |  2002-06-17  |  32.8 KB  |  1,266 lines

  1. // Copyright (C) 2001-2002 Raven Software
  2. //
  3. // bg_weapons.c - weapon data loading
  4.  
  5. #include "q_shared.h"
  6. #include "bg_public.h"
  7. #include "bg_local.h"
  8. #include "g_local.h"
  9.  
  10. // names as they appear in the SOF2.wpn and inview files
  11. char *bg_weaponNames[WP_NUM_WEAPONS] = 
  12. {
  13.     "No Weapon",                    // WP_NONE,
  14.     "Knife",                        // WP_KNIFE,
  15.     "M1911A1",                        // WP_M1911A1_PISTOL,
  16.     "US SOCOM",                        // WP_US_SOCOM_PISTOL,
  17.     "M590",                            // WP_M590_SHOTGUN,
  18.     "Micro Uzi",                    // WP_MICRO_UZI_SUBMACHINEGUN,
  19.     "M3A1",                            // WP_M3A1_SUBMACHINEGUN,
  20.     "MP5",                            // WP_MP5
  21.     "USAS-12",                        // WP_USAS_12_SHOTGUN,
  22.     "M4",                            // WP_M4_ASSAULT_RIFLE,
  23.     "AK74",                            // WP_AK74_ASSAULT_RIFLE,
  24.     "MSG90A1",                        // WP_MSG90A1_SNIPER_RIFLE,
  25.     "M60",                            // WP_M60_MACHINEGUN,
  26.     "MM1",                            // WP_MM1_GRENADE_LAUNCHER,
  27.     "RPG7",                            // WP_RPG7_LAUNCHER,
  28.     "M84",                            // WP_M84_GRENADE,
  29.     "SMOHG92",                        // WP_SMOHG92_GRENADE,
  30.     "ANM14",                         // WP_ANM14_GRENADE,
  31.     "M15",                            // WP_M15_GRENADE,
  32. };
  33.  
  34. weaponData_t weaponData[WP_NUM_WEAPONS];
  35.  
  36. char *ammoNames[AMMO_MAX] =
  37. {                            
  38.     "Knife",        //    AMMO_KNIFE,
  39.     "0.45 ACP",        //    AMMO_045,
  40.     "5.56mm",         //    AMMO_556,
  41.     "9mm",            //    AMMO_9  ,
  42.     "12 gauge",        //    AMMO_12 ,
  43.     "7.62mm",        //    AMMO_762,
  44.     "40mm grenade",    //    AMMO_40,
  45.     "RPG7",            //  AMMO_RPG7
  46.     "M15",            //    AMMO_M15,
  47.     "M84",            //    AMMO_M84,
  48.     "SMOHG92",        //    AMMO_SMOHG92,
  49.     "ANM14",         //    AMMO_ANM14,
  50.     "7.62mm belt",    //  AMMO_762_BELT,
  51.     "9mm|mp5",        //  AMMO_9_MP5
  52. };
  53.  
  54. ammoData_t ammoData[AMMO_MAX];
  55.  
  56. static const char* BG_GetRealAmmoName ( ammo_t ammoNum )
  57. {
  58.     static char name[64] = "";
  59.     char* or;
  60.  
  61.     or = strchr ( ammoNames[ammoNum], '|' );
  62.     if ( or )
  63.     {
  64.         Q_strncpyz ( name, ammoNames[ammoNum], or - ammoNames[ammoNum] + 1);
  65.     }
  66.     else
  67.     {
  68.         strcpy ( name, ammoNames[ammoNum] );
  69.     }
  70.  
  71.     return name;
  72. }
  73.  
  74. static qboolean BG_ParseAmmoStats(ammo_t ammoNum, void *group)
  75. {
  76.     char        tmpStr[256];
  77.     ammoData_t *ammo;        // ammo
  78.  
  79.     ammo = &ammoData[ammoNum];
  80.     memset(ammo, 0, sizeof(ammoData_t));
  81.  
  82.     ammo->name = (char*)trap_VM_LocalStringAlloc ( BG_GetRealAmmoName ( ammoNum ) );
  83.     Q_strlwr ( ammo->name );
  84.  
  85.     // Get the scale of the gore for this bullet
  86.     trap_GPG_FindPairValue(group, "mp_goreScale||goreScale", "1", tmpStr );
  87.     ammo->goreScale = atof ( tmpStr );
  88.  
  89.     // Max ammo will be filled in by the weapon parsing
  90.  
  91.     return qtrue;
  92. }
  93.  
  94. qboolean BG_InitAmmoStats(void)
  95. {
  96.     void        *GP2, *topGroup;
  97.     int            i;
  98.  
  99.     ammoData[AMMO_NONE].goreScale = 0.0f;
  100.     ammoData[AMMO_NONE].name = "none";
  101.  
  102.     GP2 = trap_GP_ParseFile("ext_data/sof2.ammo", qtrue, qfalse);
  103.     if (!GP2)
  104.     {
  105.         return qfalse;
  106.     }
  107.  
  108.     topGroup = trap_GP_GetBaseParseGroup(GP2);
  109.     for ( i = 0; i < AMMO_MAX; i ++ )
  110.     {
  111.         void*    topSubs;
  112.         const char*    realName;
  113.  
  114.         realName = BG_GetRealAmmoName ( i );
  115.  
  116.         topSubs = trap_GPG_GetSubGroups(topGroup);
  117.         while(topSubs)
  118.         {
  119.             char name[256];
  120.             trap_GPG_GetName(topSubs, name);
  121.             if (Q_stricmp(name, "ammo") != 0)
  122.             {
  123.                 continue;
  124.             }
  125.     
  126.             trap_GPG_FindPairValue(topSubs, "name", "", name);
  127.             if ( !Q_stricmp ( name, realName ) )
  128.             {
  129.                 BG_ParseAmmoStats(i, topSubs );
  130.                 break;
  131.             }
  132.  
  133.             topSubs = trap_GPG_GetNext(topSubs);
  134.         }
  135.  
  136.         if ( !topSubs )
  137.         {
  138.             Com_Printf("BG_InitAmmoStats: Unknown ammo: %s\n", BG_GetRealAmmoName ( i ) );
  139.         }        
  140.     }
  141.  
  142.     trap_GP_Delete(&GP2);
  143.  
  144.     return qtrue;
  145. }
  146.  
  147. static qboolean BG_ParseAttackStats ( int weaponNum, attackData_t* attack, void *attacksub, qboolean pickupsDisabled )
  148. {
  149.     void*    sub;
  150.     char    tmpStr[256];
  151.     int        i;
  152.  
  153.     // No group is success.  This is to allow NULL to be passed 
  154.     if ( NULL == attacksub )
  155.     {
  156.         return qtrue;
  157.     }
  158.  
  159.     // Assign a melee attribute if there is one
  160.     trap_GPG_FindPairValue(attacksub, "mp_melee||melee", "none", tmpStr );
  161.     if ( Q_stricmp ( tmpStr, "none" ) )
  162.     {
  163.         Q_strlwr ( tmpStr );
  164.         attack->melee = trap_VM_LocalStringAlloc ( tmpStr );
  165.     }
  166.  
  167.     trap_GPG_FindPairValue(attacksub, "name", "NONE", attack->name);
  168.     trap_GPG_FindPairValue(attacksub, "hudIcon", "NONE", attack->icon);    
  169.  
  170.     if ( pickupsDisabled )
  171.     {
  172.         trap_GPG_FindPairValue(attacksub, "mp_ammoType_outfitting", "", tmpStr);
  173.         if ( !tmpStr[0] )
  174.         {
  175.             trap_GPG_FindPairValue(attacksub, "mp_ammoType||ammoType", "none", tmpStr);
  176.         }
  177.     }        
  178.     else
  179.     {
  180.         trap_GPG_FindPairValue(attacksub, "mp_ammoType||ammoType", "none", tmpStr);
  181.     }
  182.  
  183.     attack->ammoIndex = AMMO_NONE;
  184.     for (i = 0; i < AMMO_MAX; i++)
  185.     {
  186.         if (0 == Q_stricmp(tmpStr, ammoNames[i]))
  187.         {
  188.             attack->ammoIndex = i;
  189.             break;
  190.         }
  191.     }
  192.  
  193. #ifdef _DEBUG
  194.     if (AMMO_MAX == i)
  195.     {
  196.         Com_Printf("BG_ParseWeaponStats: Unknown ammo: %s\n", tmpStr);
  197.     }
  198. #endif
  199.  
  200.     // Parse the weapon animations
  201.     trap_GPG_FindPairValue( attacksub, "mp_animFire", "TORSO_ATTACK_PISTOL", tmpStr );
  202.     attack->animFire = GetIDForString ( bg_animTable, tmpStr );
  203.     trap_GPG_FindPairValue( attacksub, "mp_animFireZoomed", "", tmpStr );
  204.     attack->animFireZoomed = GetIDForString ( bg_animTable, tmpStr );
  205.  
  206.     trap_GPG_FindPairValue(attacksub, "mp_range||range", "8192", tmpStr);
  207.     attack->rV.range = atoi(tmpStr);
  208.     trap_GPG_FindPairValue(attacksub, "mp_radius||radius", "0", tmpStr);
  209.     attack->splashRadius = atoi(tmpStr);
  210.     trap_GPG_FindPairValue(attacksub, "mp_fireDelay||fireDelay", "0", tmpStr);
  211.     attack->fireDelay = atoi(tmpStr);
  212.     trap_GPG_FindPairValue(attacksub, "mp_clipSize||clipSize", "0", tmpStr);
  213.     attack->clipSize = atoi(tmpStr);
  214.     trap_GPG_FindPairValue(attacksub, "mp_fireAmount||fireAmount", "1", tmpStr);
  215.     attack->fireAmount = atoi(tmpStr);
  216.     trap_GPG_FindPairValue(attacksub, "mp_fireFromClip||fireFromClip", "1", tmpStr);
  217.     attack->fireFromClip = atoi(tmpStr);
  218.     trap_GPG_FindPairValue(attacksub, "mp_damage||damage", "0", tmpStr);
  219.     attack->damage = atoi(tmpStr);
  220.     trap_GPG_FindPairValue(attacksub, "mp_inaccuracy||inaccuracy", "0", tmpStr);
  221.     attack->inaccuracy = (int)(atof(tmpStr)*1000.0f);
  222.     trap_GPG_FindPairValue(attacksub, "mp_maxInaccuracy||maxInaccuracy", "0", tmpStr);
  223.     attack->maxInaccuracy = (int)(atof(tmpStr)*1000.0f);
  224.     trap_GPG_FindPairValue(attacksub, "mp_gore||gore", "YES", tmpStr);
  225.     attack->gore = (Q_stricmp ( tmpStr, "YES" )?qfalse:qtrue);
  226.  
  227.     trap_GPG_FindPairValue(attacksub,"mp_extraClips", "0", tmpStr );
  228.     attack->extraClips = atoi ( tmpStr );
  229.  
  230.     // max ammo is the combination of all guns that share the ammo
  231.     ammoData[attack->ammoIndex].max += attack->clipSize * attack->extraClips;
  232.  
  233.     trap_GPG_FindPairValue(attacksub,"mp_kickAngles||kickAngles", "0 0 0 0 0 0", tmpStr);
  234.     sscanf( tmpStr, "%f %f %f %f %f %f", 
  235.             &attack->minKickAngles[0], 
  236.             &attack->maxKickAngles[0],
  237.             &attack->minKickAngles[1], 
  238.             &attack->maxKickAngles[1],
  239.             &attack->minKickAngles[2], 
  240.             &attack->maxKickAngles[2]  );
  241.     
  242.     if (0 == attack->inaccuracy)
  243.     {
  244.         trap_GPG_FindPairValue(attacksub, "mp_spread||spread", "0", tmpStr);
  245.         attack->inaccuracy = atof(tmpStr);
  246.     }
  247.     trap_GPG_FindPairValue(attacksub, "mp_pellets||pellets", "1", tmpStr);
  248.     attack->pellets = atof(tmpStr);
  249.     attack->mod = (meansOfDeath_t)weaponNum; 
  250.  
  251.     trap_GPG_FindPairValue(attacksub, "mp_lockFlashToBarrel||lockFlashToBarrel", "true", tmpStr);
  252.     if (0 == Q_stricmp(tmpStr, "false"))
  253.     {
  254.         attack->weaponFlags |= UNLOCK_MUZZLEFLASH;
  255.     }
  256.     // load effects, sounds
  257.     trap_GPG_FindPairValue(attacksub, "muzzleFlash", "", attack->muzzleEffect);
  258.     trap_GPG_FindPairValue(attacksub, "3rdPersonMuzzleFlash", "", attack->muzzleEffectInWorld);
  259.     trap_GPG_FindPairValue(attacksub, "EjectBone", "", attack->ejectBone);
  260.     trap_GPG_FindPairValue(attacksub, "ShellCasingEject", "", attack->shellEject);
  261.     trap_GPG_FindPairValue(attacksub, "TracerEffect", "", attack->tracerEffect);
  262.  
  263.     // Some alt attacks have special bones they need their muzzle flashes attached to
  264.     trap_GPG_FindPairValue ( attacksub, "mp_muzzleFlashBone", "", attack->muzzleEffectBone );
  265.  
  266.     sub = trap_GPG_FindSubGroup(attacksub, "fireModes");
  267.     if (sub)
  268.     {        
  269.         int i;
  270.  
  271.         for ( i = 0; i < 5; i ++ )
  272.         {
  273.             trap_GPG_FindPairValue ( sub, va("mp_mode%i||mode%i", i, i ), "", tmpStr );
  274.             if ( !tmpStr[0] )
  275.             {
  276.                 continue;
  277.             }
  278.  
  279.             if (0 == Q_stricmp("single", tmpStr))
  280.                 attack->weaponFlags |= (1<<WP_FIREMODE_SINGLE);
  281.             else if (0 == Q_stricmp("auto", tmpStr))
  282.                 attack->weaponFlags |= (1<<WP_FIREMODE_AUTO);
  283.             else if (0 == Q_stricmp("burst", tmpStr))
  284.                 attack->weaponFlags |= (1<<WP_FIREMODE_BURST);
  285.             else
  286.                 attack->weaponFlags |= (1<<WP_FIREMODE_SINGLE);
  287.         }
  288.     }
  289.     else
  290.     {
  291.         attack->weaponFlags |= (1<<WP_FIREMODE_SINGLE);
  292.     }
  293.  
  294.     sub = trap_GPG_FindSubGroup(attacksub, "projectile");
  295.     if (sub)
  296.     {
  297.         attack->weaponFlags |= PROJECTILE_FIRE;
  298.  
  299.         trap_GPG_FindPairValue(sub, "gravity", "1", tmpStr);
  300.         if (0 < atof(tmpStr))
  301.             attack->weaponFlags |= PROJECTILE_GRAVITY;
  302.  
  303.         trap_GPG_FindPairValue(sub, "detonation", "0", tmpStr);
  304.         if (0 == Q_stricmp(tmpStr,"timer"))
  305.             attack->weaponFlags |= PROJECTILE_TIMED;
  306.  
  307.         trap_GPG_FindPairValue(sub, "mp_bounce||bounce", "0", tmpStr );
  308.         attack->bounceScale = atof ( tmpStr );
  309.  
  310.         switch ( weaponNum )
  311.         {
  312.             case WP_ANM14_GRENADE:
  313.                 // incediary grenade
  314.                 attack->weaponFlags |= PROJECTILE_DAMAGE_AREA;
  315.                 break;
  316.  
  317.             case WP_KNIFE:
  318.                 if ( attack->weaponFlags & PROJECTILE_GRAVITY )
  319.                 {
  320.                     attack->weaponFlags &= ~PROJECTILE_GRAVITY;
  321.                     attack->weaponFlags |= PROJECTILE_LIGHTGRAVITY;
  322.                 }
  323.                 break;
  324.         }
  325.         trap_GPG_FindPairValue(sub, "mp_speed||speed", "0", tmpStr);
  326.         attack->rV.velocity = atoi(tmpStr);
  327.         trap_GPG_FindPairValue(sub, "mp_timer||timer", "10", tmpStr);
  328.         attack->projectileLifetime = (int)(atof(tmpStr) * 1000);
  329.  
  330.         // 'trail' effect
  331.         trap_GPG_FindPairValue(sub, "mp_effect||effect", "", attack->tracerEffect);
  332.         trap_GPG_FindPairValue(sub, "model", "", attack->missileG2Model);
  333.         trap_GPG_FindPairValue(sub, "mp_explosionEffect||explosionEffect", "", attack->explosionEffect);
  334.         trap_GPG_FindPairValue(sub, "mp_explosionSound||explosionSound", "", attack->explosionSound);
  335.     }
  336.  
  337.     return qtrue;
  338. }
  339.  
  340. static qboolean BG_ParseWeaponStats(weapon_t weaponNum, void *group, qboolean pickupsDisabled )
  341. {
  342.     char         tmpStr[256];
  343.     weaponData_t *weapon;
  344.  
  345.     weapon = &weaponData[weaponNum];
  346.     memset(weapon, 0, sizeof(weaponData_t));
  347.  
  348.     weapon->classname = bg_weaponNames[weaponNum];
  349.     trap_GPG_FindPairValue(group, "category", "0", tmpStr);
  350.     weapon->category = atoi(tmpStr);
  351.  
  352.     trap_GPG_FindPairValue(group, "safe", "false", tmpStr);
  353.     weapon->safe = !Q_stricmp(tmpStr, "true");
  354.  
  355.     trap_GPG_FindPairValue(group, "model", "", weapon->worldModel);
  356.  
  357.     trap_GPG_FindPairValue(group, "menuImage", "", weapon->menuImage);
  358.  
  359.     // Grab the animations
  360.     trap_GPG_FindPairValue( group, "mp_animRaise", "TORSO_RAISE", tmpStr );
  361.     weapon->animRaise = GetIDForString ( bg_animTable, tmpStr );
  362.     trap_GPG_FindPairValue( group, "mp_animDrop", "TORSO_DROP", tmpStr );
  363.     weapon->animDrop = GetIDForString ( bg_animTable, tmpStr );
  364.     trap_GPG_FindPairValue( group, "mp_animIdle", "TORSO_IDLE_PISTOL", tmpStr );
  365.     weapon->animIdle = GetIDForString ( bg_animTable, tmpStr );
  366.     trap_GPG_FindPairValue( group, "mp_animIdleZoomed", "", tmpStr );
  367.     weapon->animIdleZoomed = GetIDForString ( bg_animTable, tmpStr );
  368.     trap_GPG_FindPairValue( group, "mp_animReload", "", tmpStr );
  369.     weapon->animReload = GetIDForString ( bg_animTable, tmpStr );
  370.     trap_GPG_FindPairValue( group, "mp_animReloadStart", "", tmpStr );
  371.     weapon->animReloadStart = GetIDForString ( bg_animTable, tmpStr );
  372.     trap_GPG_FindPairValue( group, "mp_animReloadEnd", "", tmpStr );
  373.     weapon->animReloadEnd = GetIDForString ( bg_animTable, tmpStr );
  374.  
  375.     // primary attack
  376.     BG_ParseAttackStats ( weaponNum, &weapon->attack[ATTACK_NORMAL], trap_GPG_FindSubGroup(group, "attack"), pickupsDisabled );
  377.  
  378.     // alternate attack
  379.     BG_ParseAttackStats ( weaponNum, &weapon->attack[ATTACK_ALTERNATE], trap_GPG_FindSubGroup(group, "altattack"), pickupsDisabled );
  380.  
  381.     return qtrue;
  382. }
  383.  
  384. qboolean BG_InitWeaponStats( qboolean pickupsDisabled )
  385. {
  386.     void        *GP2, *topGroup, *topSubs;
  387.     char        name[256];
  388.     int            i;
  389.  
  390.     GP2 = trap_GP_ParseFile("ext_data/sof2.wpn", qtrue, qfalse);
  391.     if (!GP2)
  392.     {
  393.         return qfalse;
  394.     }
  395.  
  396.     topGroup = trap_GP_GetBaseParseGroup(GP2);
  397.     topSubs = trap_GPG_GetSubGroups(topGroup);
  398.     while(topSubs)
  399.     {
  400.         trap_GPG_GetName(topSubs, name);
  401.         if (Q_stricmp(name, "weapon") == 0)
  402.         {
  403.             trap_GPG_FindPairValue(topSubs, "name", "", name);
  404.             for(i=0;i<WP_NUM_WEAPONS;i++)
  405.             {
  406.                 if (Q_stricmp(bg_weaponNames[i], name) == 0)
  407.                 {
  408.                     BG_ParseWeaponStats(i, topSubs, pickupsDisabled );
  409.                     break;
  410.                 }
  411.             }
  412.  
  413. #ifdef _DEBUG
  414.             if (i == WP_NUM_WEAPONS)
  415.             {
  416.                 Com_Printf("BG_InitWeaponStats: Unknown weapon: %s\n", name);
  417.             }
  418. #endif
  419.         }
  420.         topSubs = trap_GPG_GetNext(topSubs);
  421.     }
  422.  
  423.     trap_GP_Delete(&GP2);
  424.  
  425.     return qtrue;
  426. }
  427.  
  428. ////////////////////////////////////////////////////////////////////////////////////
  429.  
  430. TWeaponParseInfo    weaponParseInfo[WP_NUM_WEAPONS];
  431. char                weaponLeftHand[MAX_QPATH];
  432. char                weaponRightHand[MAX_QPATH];
  433.  
  434. static char *BG_BuildSideSurfaceList(void *group, char *pattern, char *sideSurfaces[])
  435. {
  436.     void        *value;
  437.     char        *output, *data;
  438.     char        fieldName[256], fieldValue[256];
  439.     int            length;
  440.     int            i;
  441.     
  442.     output = trap_VM_LocalAlloc(0);
  443.     length = strlen(pattern);
  444.     i=0;
  445.  
  446.     value = trap_GPG_GetPairs(group);
  447.     while((value)&&(i<MAX_SIDE_SURFACES))
  448.     {
  449.         trap_GPV_GetName(value, fieldName);
  450.         if (Q_stricmpn(fieldName, pattern, length) == 0)
  451.         {
  452.             trap_GPV_GetTopValue(value, fieldValue);
  453.             data = trap_VM_LocalAllocUnaligned(strlen(fieldValue)+1);
  454.             strcpy(data, fieldValue);
  455.             sideSurfaces[i]=data;
  456.             i++;
  457.         }
  458.         value = trap_GPV_GetNext(value);
  459.     }
  460.  
  461.     data = trap_VM_LocalAllocUnaligned(1);
  462.     *data = 0;
  463.  
  464.     return output;
  465. }
  466.  
  467. static char *BG_BuildList(void *group, char *pattern)
  468. {
  469.     void        *value;
  470.     char        *output, *data;
  471.     char        fieldName[256], fieldValue[256];
  472.     int            length;
  473.  
  474.     output = trap_VM_LocalAlloc(0);
  475.     length = strlen(pattern);
  476.  
  477.     value = trap_GPG_GetPairs(group);
  478.     while(value)
  479.     {
  480.         trap_GPV_GetName(value, fieldName);
  481.         if (Q_stricmpn(fieldName, pattern, length) == 0)
  482.         {
  483.             trap_GPV_GetTopValue(value, fieldValue);
  484.             data = trap_VM_LocalAllocUnaligned(strlen(fieldValue)+1);
  485.             strcpy(data, fieldValue);
  486.         }
  487.         value = trap_GPV_GetNext(value);
  488.     }
  489.  
  490.     data = trap_VM_LocalAllocUnaligned(1);
  491.     *data = 0;
  492.  
  493.     return output;
  494. }
  495.  
  496. #define        MAX_WEAPON_FILES    10
  497.  
  498. static void *weaponFrames[MAX_WEAPON_FILES];
  499. static void    *frameGroup[MAX_WEAPON_FILES];
  500. static int    numWeaponFiles = 0;
  501. static int    numInitialFiles = 0;
  502.  
  503. static    qboolean BG_OpenWeaponFrames(const char *name)
  504. {
  505.     weaponFrames[numWeaponFiles] = trap_GP_ParseFile((char *)name, qtrue, qfalse);
  506.  
  507.     if (!weaponFrames)
  508.     {
  509.         return qfalse;
  510.     }
  511.  
  512.     frameGroup[numWeaponFiles] = trap_GP_GetBaseParseGroup(weaponFrames[numWeaponFiles]);
  513.     numWeaponFiles++;
  514.  
  515.     return qtrue;
  516. }
  517.  
  518. static TNoteTrack *BG_FindNoteTracks(void *group)
  519. {
  520.     void        *sub;
  521.     char        name[256];
  522.     TNoteTrack    *head, *last, *current, *insert;
  523.  
  524.     head = last = insert = 0;
  525.  
  526.     sub = trap_GPG_GetSubGroups(group);
  527.     while(sub)
  528.     {
  529.         trap_GPG_GetName(sub, name);
  530.         if (Q_stricmp(name, "notetrack") == 0)
  531.         {
  532.             current = (TNoteTrack *)trap_VM_LocalAlloc(sizeof(*current));
  533.             memset(current, 0, sizeof(*current));
  534.  
  535.             // last character is automatically 0 cuz of the memset
  536.             trap_GPG_FindPairValue(sub, "note", "", current->mNote);
  537.             trap_GPG_FindPairValue(sub, "frame", "-1", name);
  538.             current->mFrame = atoi(name);
  539.  
  540.             last=insert=head;
  541.             while(insert)
  542.             {
  543.                 if(current->mFrame<insert->mFrame)
  544.                 {
  545.                     break;
  546.                 }
  547.                 last=insert;
  548.                 insert=insert->mNext;
  549.             }
  550.             if(insert==head)
  551.             {
  552.                 head=current;
  553.             }
  554.             else
  555.             {
  556.                 last->mNext=current;
  557.             }
  558.             current->mNext=insert;
  559.         }
  560.  
  561.         sub = trap_GPG_GetNext(sub);
  562.     }
  563.  
  564.     return head;
  565. }
  566.  
  567. static void BG_FindWeaponFrames(TAnimInfoWeapon *animInfo, int choice)
  568. {
  569.     void    *group;
  570.     int        i;
  571.  
  572.     if (!numWeaponFiles || !animInfo->mAnim[choice])
  573.     {
  574.         animInfo->mNumFrames[choice] = -1;
  575.         return;
  576.     }
  577.  
  578.     for(i=0;i<numWeaponFiles;i++)
  579.     {
  580.         char  temp[256];
  581.  
  582.         group = trap_GPG_GetSubGroups ( frameGroup[i] );
  583.         while ( group )
  584.         {
  585.             char* name;
  586.  
  587.             // Get the name and break it down to just the filename without
  588.             // and extension            
  589.             trap_GPG_GetName ( group, temp );
  590.             name = COM_SkipPath ( temp );
  591.             COM_StripExtension ( name, temp );
  592.  
  593.             if ( Q_stricmp ( temp, animInfo->mAnim[choice] ) == 0 )
  594.             {
  595.                 break;
  596.             }
  597.  
  598.             group = trap_GPG_GetNext ( group );
  599.         }
  600.  
  601.         if (group)
  602.         {
  603.             trap_GPG_FindPairValue(group, "startframe", "0", temp);
  604.             animInfo->mStartFrame[choice] = atoi(temp);
  605.             trap_GPG_FindPairValue(group, "duration", "0", temp);
  606.             animInfo->mNumFrames[choice] = atoi(temp);
  607.             trap_GPG_FindPairValue(group, "fps", "0", temp);
  608.             animInfo->mFPS[choice] = atoi(temp);
  609.             animInfo->mNoteTracks[choice] = BG_FindNoteTracks(group);
  610.             return;
  611.         }
  612.     }
  613.  
  614.     animInfo->mNumFrames[choice] = -1;
  615. }
  616.  
  617. static void BG_CloseWeaponFrames(int upTo)
  618. {
  619.     int        i;
  620.  
  621.     for(i=upTo; i < numWeaponFiles; i++)
  622.     {
  623.         if (weaponFrames[i])
  624.         {
  625.             trap_GP_Delete(&weaponFrames[i]);
  626.         }
  627.     }
  628.  
  629.     numWeaponFiles = upTo;
  630. }
  631.  
  632.  
  633. static qboolean BG_ParseAnimGroup(weapon_t weapon, void *animGroup)
  634. {
  635.     void            *sub;
  636.     char            name[256];
  637.     TAnimWeapon        *anim;
  638.     TAnimInfoWeapon    *info;
  639.     char            value[256];
  640.     int                i;
  641.     char            temp[256];
  642.  
  643.     anim = (TAnimWeapon *)trap_VM_LocalAlloc(sizeof(*anim));
  644.     memset(anim, 0, sizeof(*anim));
  645.  
  646.     anim->mNext = weaponParseInfo[weapon].mAnimList;
  647.     weaponParseInfo[weapon].mAnimList = anim;
  648.  
  649.     trap_GPG_FindPairValue(animGroup, "name", "", anim->mName);
  650.     trap_GPG_FindPairValue(animGroup, "mp_muzzle||muzzle", "", anim->mMuzzle);
  651.  
  652.     sub = trap_GPG_GetSubGroups(animGroup);
  653.     while(sub)
  654.     {
  655.         trap_GPG_GetName(sub, name);
  656.         if (Q_stricmp(name, "info") == 0)
  657.         {
  658.             info = (TAnimInfoWeapon *)trap_VM_LocalAlloc(sizeof(*info));
  659.             memset(info, 0, sizeof(*info));
  660.             
  661.             info->mNext = anim->mInfos;
  662.             anim->mInfos = info;
  663.  
  664.             info->mNumChoices = 0;
  665.             trap_GPG_FindPairValue(sub, "name", "", info->mName);
  666.             trap_GPG_FindPairValue(sub, "type", "", info->mType);
  667.  
  668.             // Cache for later
  669.             if ( !Q_stricmp ( info->mType, "weaponmodel" ) )
  670.             {
  671.                 anim->mWeaponModelInfo = info;
  672.             }
  673.  
  674.             // We first look for a multiplayer specific speed. If we don't
  675.             // find a valid speed, use the single player speed instead.
  676.             trap_GPG_FindPairValue(sub, "mp_speed||speed", "0", temp);
  677.             info->mSpeed = atof(temp);
  678.             if(!info->mSpeed)
  679.             {
  680.                 trap_GPG_FindPairValue(sub, "mp_speed||speed", "1", temp);
  681.                 info->mSpeed = atof(temp);
  682.             }
  683.             trap_GPG_FindPairValue(sub, "lodbias", "0", temp);
  684.             info->mLODBias = atoi(temp);
  685.  
  686.             for(i=0;i<=MAX_WEAPON_ANIM_CHOICES;i++)
  687.             {
  688.                 if (i == 0)
  689.                 {
  690.                     strcpy(temp, "anim||animNoLerp");
  691.                 }
  692.                 else
  693.                 {
  694.                     Com_sprintf(temp, sizeof(temp), "anim%d||animNoLerp%d", i, i);
  695.                 }
  696.                 trap_GPG_FindPairValue(sub, temp, "", value);
  697.                 if (value[0] && info->mNumChoices < MAX_WEAPON_ANIM_CHOICES)
  698.                 {
  699.                     info->mAnim[info->mNumChoices] = (char *)trap_VM_LocalAlloc(strlen(value)+1);
  700.                     strcpy(info->mAnim[info->mNumChoices], value);
  701.  
  702.                     if (i == 0)
  703.                     {
  704.                         strcpy(temp, "transition");
  705.                     }
  706.                     else
  707.                     {
  708.                         Com_sprintf(temp, sizeof(temp), "transition%d", i);
  709.                     }
  710.                     trap_GPG_FindPairValue(sub, temp, "", value);
  711.                     if (value[0])
  712.                     {
  713.                         info->mTransition[info->mNumChoices] = (char *)trap_VM_LocalAlloc(strlen(value)+1);
  714.                         strcpy(info->mTransition[info->mNumChoices], value);
  715.                     }
  716.  
  717.                     if (i == 0)
  718.                     {
  719.                         strcpy(temp, "end");
  720.                     }
  721.                     else
  722.                     {
  723.                         Com_sprintf(temp, sizeof(temp), "end%d", i);
  724.                     }
  725.                     trap_GPG_FindPairValue(sub, temp, "", value);
  726.                     if (value[0])
  727.                     {
  728.                         info->mEnd[info->mNumChoices] = (char *)trap_VM_LocalAlloc(strlen(value)+1);
  729.                         strcpy(info->mEnd[info->mNumChoices], value);
  730.                     }
  731.  
  732.                     info->mNumChoices++;
  733.                 }
  734.             }
  735.         }
  736.  
  737.         sub = trap_GPG_GetNext(sub);
  738.     }
  739.  
  740.     return qtrue;
  741. }
  742.  
  743. static TBoltonWeapon *BG_ParseBolton(void *boltonGroup)
  744. {
  745.     TBoltonWeapon    *bolton;
  746.     void            *sub;
  747.     char            temp[256];
  748.  
  749.     bolton = (TBoltonWeapon *)trap_VM_LocalAlloc(sizeof(*bolton));
  750.     memset(bolton, 0, sizeof(*bolton));
  751.  
  752.     trap_GPG_FindPairValue(boltonGroup, "name", "", bolton->mName);
  753.     trap_GPG_FindPairValue(boltonGroup, "model", "", bolton->mModel);
  754.     trap_GPG_FindPairValue(boltonGroup, "parent", "", bolton->mParent);
  755.     trap_GPG_FindPairValue(boltonGroup, "bolttobone", "", bolton->mBoltToBone);
  756.  
  757.     trap_GPG_FindPairValue(boltonGroup, "frames", "", temp);
  758.     BG_OpenWeaponFrames(temp);
  759.  
  760.     sub = trap_GPG_FindSubGroup(boltonGroup, "rightside");
  761.     if (sub)
  762.     {
  763.          BG_BuildSideSurfaceList(sub, "surface", bolton->mRightSide);
  764.     }
  765.  
  766.     sub = trap_GPG_FindSubGroup(boltonGroup, "joint");
  767.     if (sub)
  768.     {
  769.         trap_GPG_FindPairValue(sub, "bone", "", bolton->mJointBone);
  770.         trap_GPG_FindPairValue(sub, "parentBone", "", bolton->mJointParentBone);
  771.         trap_GPG_FindPairValue(sub, "fwd", "", bolton->mJointForward);
  772.         trap_GPG_FindPairValue(sub, "right", "", bolton->mJointRight);
  773.         trap_GPG_FindPairValue(sub, "up", "", bolton->mJointUp);
  774.     }
  775.  
  776.     return bolton;
  777. }
  778.  
  779. static qboolean BG_ParseWeaponGroup(TWeaponModel *weapon, void *weaponGroup)
  780. {
  781.     void            *sub, *hand;
  782.     char            name[256];
  783.     TOptionalWeapon    *option;
  784.     char            temp[256];
  785.  
  786.     trap_GPG_FindPairValue(weaponGroup, "name", "", weapon->mName);
  787.     trap_GPG_FindPairValue(weaponGroup, "model", "", weapon->mModel);
  788.  
  789.     trap_GPG_FindPairValue(weaponGroup, "frames", "", temp);
  790.     BG_OpenWeaponFrames(temp);
  791.  
  792.     sub = trap_GPG_GetSubGroups(weaponGroup);
  793.     while(sub)
  794.     {
  795.         trap_GPG_GetName(sub, name);
  796.         if (Q_stricmp(name, "buffer") == 0)
  797.         {
  798.             trap_GPG_FindPairValue(sub, "name", "", weapon->mBufferName);
  799.             trap_GPG_FindPairValue(sub, "model", "", weapon->mBufferModel);
  800.             trap_GPG_FindPairValue(sub, "bolttobone", "", weapon->mBufferBoltToBone);
  801.             trap_GPG_FindPairValue(sub, "mp_muzzle||muzzle", "", weapon->mBufferMuzzle);
  802.             trap_GPG_FindPairValue(sub, "mp_altmuzzle", "", weapon->mBufferAltMuzzle);
  803.         }
  804.         else if (Q_stricmp(name, "hands") == 0)
  805.         {
  806.             hand = trap_GPG_FindSubGroup(sub, "left");
  807.             if (hand)
  808.             {
  809.                 trap_GPG_FindPairValue(hand, "bolttobone", "", weapon->mLeftHandsBoltToBone);
  810.             }
  811.             hand = trap_GPG_FindSubGroup(sub, "right");
  812.             if (hand)
  813.             {
  814.                 trap_GPG_FindPairValue(hand, "bolttobone", "", weapon->mRightHandsBoltToBone);
  815.             }
  816.         }
  817.         else if (Q_stricmp(name, "bolton") == 0)
  818.         {
  819.             weapon->mBolton = BG_ParseBolton(sub);
  820.         }
  821.         else if (Q_stricmp(name, "rightside") == 0)
  822.         {
  823.             BG_BuildSideSurfaceList(sub, "surface", weapon->mRightSideSurfaces);
  824.         }
  825.         else if (Q_stricmp(name, "leftside") == 0)
  826.         {
  827.             BG_BuildSideSurfaceList(sub, "surface", weapon->mLeftSideSurfaces);
  828.         }
  829.         else if (Q_stricmp(name, "front") == 0)
  830.         {
  831.             BG_BuildSideSurfaceList(sub, "surface", weapon->mFrontSurfaces);
  832.         }
  833.         else if (Q_stricmp(name, "optionalpart") == 0)
  834.         {
  835.             option = (TOptionalWeapon *)trap_VM_LocalAlloc(sizeof(*option));
  836.             memset(option, 0, sizeof(*option));
  837.             trap_GPG_FindPairValue(sub, "name", "", option->mName);
  838.             trap_GPG_FindPairValue(sub, "muzzle", "", option->mMuzzle);
  839.             BG_BuildSideSurfaceList(sub, "surface", option->mSurfaces);
  840.             option->mNext=weapon->mOptionalList;
  841.             weapon->mOptionalList=option;
  842. /*
  843.             if(weapon->mOptionalList)
  844.             {
  845.                 option->mNext=weapon->mOptionalList;
  846.                 weapon->mOptionalList=option;
  847.             }
  848.             else
  849.             {
  850.                 weapon->mOptionalList=option;
  851.             }        */
  852.         }
  853.         
  854.         sub = trap_GPG_GetNext(sub);
  855.     }
  856.  
  857.     return qtrue;
  858. }
  859.  
  860. static qboolean BG_ParseWeapon(weapon_t weapon, void *group)
  861. {
  862.     void            *sub, *soundName, *surfaceCallbackName;
  863.     void            *soundValue, *surfaceCallbackValue;
  864.     char            onOffVal[256];
  865.     char            name[256];
  866.     int                i, j;
  867.     TAnimWeapon        *anims;
  868.     TAnimInfoWeapon    *infos;
  869.     char            temp[256];
  870.  
  871.     memset(&weaponParseInfo[weapon], 0, sizeof(TWeaponParseInfo));
  872.     weaponParseInfo[weapon].mName = bg_weaponNames[weapon];
  873.     trap_GPG_FindPairValue(group, "foreshorten", "0.0", temp);
  874.     weaponParseInfo[weapon].mForeshorten = atof(temp);
  875.  
  876.     sub = trap_GPG_GetSubGroups(group);
  877.     while(sub)
  878.     {
  879.         trap_GPG_GetName(sub, name);
  880.  
  881.         if (Q_stricmp(name, "viewoffset") == 0)
  882.         {
  883.             trap_GPG_FindPairValue(sub, "forward", "0.0", temp);
  884.             weaponParseInfo[weapon].mViewOffset[0] = atof(temp);
  885.             trap_GPG_FindPairValue(sub, "right", "0.0", temp);
  886.             weaponParseInfo[weapon].mViewOffset[1] = atof(temp);
  887.             trap_GPG_FindPairValue(sub, "up", "0.0", temp);
  888.             weaponParseInfo[weapon].mViewOffset[2] = atof(temp);
  889.         }
  890.         else if (Q_stricmp(name, "sounds") == 0)
  891.         {
  892.             soundName = trap_GPG_GetSubGroups(sub);
  893.             for(i=0;soundName && (i < MAX_WEAPON_SOUNDS);i++)
  894.             {
  895.                 trap_GPG_GetName(soundName, weaponParseInfo[weapon].mSoundNames[i]);
  896.                 soundValue = trap_GPG_GetPairs(soundName);
  897.                 for(j=0;soundValue && (j<MAX_WEAPON_SOUND_SLOTS);j++)
  898.                 {
  899.                     trap_GPV_GetTopValue(soundValue, weaponParseInfo[weapon].mSounds[i][j]);
  900.                     soundValue = trap_GPV_GetNext(soundValue);
  901.                 }
  902.  
  903.                 soundName = trap_GPG_GetNext(soundName);
  904.             }
  905.         }
  906.         else if (Q_stricmp(name, "surfaces") == 0)
  907.         {
  908.             surfaceCallbackName = trap_GPG_GetSubGroups(sub);
  909.             for(i=0;surfaceCallbackName && (i < MAX_SURFACE_CALLBACKS);i++)
  910.             {
  911.                 trap_GPG_GetName(surfaceCallbackName, weaponParseInfo[weapon].mSurfaceCallbacks[i].mName);
  912.                 surfaceCallbackValue = trap_GPG_GetPairs(surfaceCallbackName);
  913.                 for(j=0;surfaceCallbackValue && (j<MAX_CALLBACK_SURFACES);j++)
  914.                 {
  915.                     trap_GPG_GetName(surfaceCallbackValue, weaponParseInfo[weapon].mSurfaceCallbacks[i].mOnOffSurfaces[j].mName);
  916.                     trap_GPV_GetTopValue(surfaceCallbackValue, onOffVal);
  917.                     assert(onOffVal);
  918.                     weaponParseInfo[weapon].mSurfaceCallbacks[i].mOnOffSurfaces[j].mStatus=(!Q_stricmp(onOffVal,"on"))?1:0;
  919.                     surfaceCallbackValue=trap_GPV_GetNext(surfaceCallbackValue);
  920.                 }
  921.                 surfaceCallbackName=trap_GPG_GetNext(surfaceCallbackName);
  922.             }
  923.  
  924.         }
  925.         else if (Q_stricmp(name, "weaponmodel") == 0)
  926.         {
  927.             BG_ParseWeaponGroup(&weaponParseInfo[weapon].mWeaponModel, sub);
  928.         }
  929.         else if (Q_stricmp(name, "anim") == 0)
  930.         {
  931.             BG_ParseAnimGroup(weapon, sub);
  932.         }
  933.  
  934.         sub = trap_GPG_GetNext(sub);
  935.     }
  936.  
  937.     anims = weaponParseInfo[weapon].mAnimList;
  938.     while(anims)
  939.     {
  940.         infos = anims->mInfos;
  941.         while(infos)
  942.         {
  943.             for(i=0;i<infos->mNumChoices;i++)
  944.             {
  945.                 BG_FindWeaponFrames(infos, i);
  946.             }
  947.             infos = infos->mNext;
  948.         }
  949.  
  950.         anims = anims->mNext;
  951.     }
  952.  
  953.     BG_CloseWeaponFrames(numInitialFiles);
  954.  
  955.     return qtrue;
  956. }
  957.  
  958. qboolean BG_ParseInviewFile( qboolean pickupsDisabled )
  959. {
  960.     void        *GP2, *topGroup, *topSubs, *group;
  961.     char        name[256], temp[256];
  962.     int            i;
  963.  
  964.     GP2 = trap_GP_ParseFile("inview/sof2.inview", qtrue, qfalse);
  965.     if (!GP2)
  966.     {
  967.         return qfalse;
  968.     }
  969.  
  970.     weaponLeftHand[0] = 0;
  971.     weaponRightHand[0] = 0;
  972.  
  973.     topGroup = trap_GP_GetBaseParseGroup(GP2);
  974.     topSubs = trap_GPG_GetSubGroups(topGroup);
  975.     while(topSubs)
  976.     {
  977.         trap_GPG_GetName(topSubs, name);
  978.         if (Q_stricmp(name, "hands") == 0)
  979.         {
  980.             group = trap_GPG_FindSubGroup(topSubs, "left");
  981.             if (group)
  982.             {
  983.                 trap_GPG_FindPairValue(group, "model", "", weaponLeftHand);
  984.                 trap_GPG_FindPairValue(group, "frames", "", temp);
  985.                 if (BG_OpenWeaponFrames(temp))
  986.                 {
  987.                     numInitialFiles++;
  988.                 }
  989.             }
  990.             group = trap_GPG_FindSubGroup(topSubs, "right");
  991.             if (group)
  992.             {
  993.                 trap_GPG_FindPairValue(group, "model", "", weaponRightHand);
  994.                 trap_GPG_FindPairValue(group, "frames", "", temp);
  995.                 if (BG_OpenWeaponFrames(temp))
  996.                 {
  997.                     numInitialFiles++;
  998.                 }
  999.             }
  1000.         }
  1001.         else if (Q_stricmp(name, "hud") == 0)
  1002.         {
  1003.         }
  1004.         else if (Q_stricmp(name, "weapon") == 0)
  1005.         {
  1006.             trap_GPG_FindPairValue(topSubs, "name", "", name);
  1007.             for(i=0;i<WP_NUM_WEAPONS;i++)
  1008.             {
  1009.                 if (Q_stricmp(bg_weaponNames[i], name) == 0)
  1010.                 {
  1011.                     BG_ParseWeapon(i, topSubs);
  1012.                     break;
  1013.                 }
  1014.             }
  1015.  
  1016. #ifdef _DEBUG
  1017.             if (i == WP_NUM_WEAPONS)
  1018.             {
  1019.                 Com_Printf("BG_InitWeapons: Unknown weapon: %s\n", name);
  1020.             }
  1021. #endif
  1022.         }
  1023.  
  1024.         topSubs = trap_GPG_GetNext(topSubs);
  1025.     }
  1026.  
  1027.     BG_CloseWeaponFrames(0);
  1028.     trap_GP_Delete(&GP2);
  1029.  
  1030.     BG_InitAmmoStats();
  1031.  
  1032.     return BG_InitWeaponStats( pickupsDisabled );
  1033. }
  1034.  
  1035. TAnimWeapon *BG_GetInviewAnim(int weaponIdx,const char *animKey,int *animIndex)
  1036. {
  1037.     TAnimWeapon            *animWeapon;
  1038.  
  1039.     (*animIndex)=0;
  1040.     animWeapon=weaponParseInfo[weaponIdx].mAnimList;
  1041.     while((animWeapon!=0)&&(Q_stricmp(animWeapon->mName,animKey)))
  1042.     {
  1043.         animWeapon=animWeapon->mNext;
  1044.         (*animIndex)++;
  1045.     }
  1046.     if(!animWeapon)
  1047.     {
  1048.         return(0);
  1049.     }
  1050.     return(animWeapon);
  1051. }
  1052.  
  1053. TAnimWeapon *BG_GetInviewAnimFromIndex(int weaponIdx,int animIndex)
  1054. {
  1055.     TAnimWeapon        *animWeapon;
  1056.     int                i=0;
  1057.  
  1058.     animWeapon=weaponParseInfo[weaponIdx].mAnimList;
  1059.     while((animWeapon!=0)&&(i!=animIndex))
  1060.     {
  1061.         animWeapon=animWeapon->mNext;
  1062.         i++;
  1063.     }
  1064.     if(!animWeapon)
  1065.     {
  1066.         return(0);
  1067.     }
  1068.     return(animWeapon);
  1069. }
  1070.  
  1071. TAnimInfoWeapon *BG_GetInviewModelAnim(int weaponIdx,const char *modelKey,const char *animKey)
  1072. {
  1073.     TAnimWeapon            *animWeapon;
  1074.     TAnimInfoWeapon        *animInfoWeapon;
  1075.     animWeapon=weaponParseInfo[weaponIdx].mAnimList;
  1076.     while((animWeapon!=0)&&(Q_stricmp(animWeapon->mName,animKey)))
  1077.     {
  1078.         animWeapon=animWeapon->mNext;
  1079.     }
  1080.     if(!animWeapon)
  1081.     {
  1082.         return(0);
  1083.     }
  1084.     animInfoWeapon=animWeapon->mInfos;
  1085.     while((animInfoWeapon!=0)&&(Q_stricmp(animInfoWeapon->mType,modelKey)))
  1086.     {
  1087.         animInfoWeapon=animInfoWeapon->mNext;
  1088.     }
  1089.     if(!animInfoWeapon)
  1090.     {
  1091.         return(0);
  1092.     }
  1093.     return(animInfoWeapon);
  1094. }
  1095.  
  1096. /*
  1097. ===============
  1098. BG_WeaponHasAlternateAmmo
  1099.  
  1100. Returns qtrue if the given weapon has ammo for its alternate attack
  1101. ===============
  1102. */
  1103. qboolean BG_WeaponHasAlternateAmmo ( int weapon )
  1104. {
  1105.     // No valid ammo index means no alternate ammo
  1106.     if ( weaponData[weapon].attack[ATTACK_ALTERNATE].ammoIndex == AMMO_NONE )
  1107.     {
  1108.         return qfalse;
  1109.     }
  1110.  
  1111.     // If the alternate attack doesnt deplete ammo then it doesnt use it
  1112.     if ( !weaponData[weapon].attack[ATTACK_ALTERNATE].fireAmount )
  1113.     {
  1114.         return qfalse;
  1115.     }
  1116.  
  1117.     // If the alternate ammo is the same as the primary ammo then
  1118.     // the primary is good enough
  1119.     if ( weaponData[weapon].attack[ATTACK_ALTERNATE].ammoIndex ==
  1120.          weaponData[weapon].attack[ATTACK_NORMAL].ammoIndex )
  1121.     {
  1122.         return qfalse;
  1123.     }
  1124.  
  1125.     // Yup, alternates have ammo
  1126.     return qtrue;
  1127. }
  1128.  
  1129. /*
  1130. ===============
  1131. BG_FindFireMode
  1132.  
  1133. Finds the firemode for the given weapon using the given default
  1134. ===============
  1135. */
  1136. int BG_FindFireMode ( weapon_t weapon, attackType_t attack, int firemode )
  1137. {
  1138.     int i;
  1139.  
  1140.     if ( !weapon )
  1141.     {
  1142.         return WP_FIREMODE_NONE;
  1143.     }
  1144.  
  1145.     for ( i=0; i <= WP_FIREMODE_SINGLE; i++ )
  1146.     {
  1147.         if( firemode >= WP_FIREMODE_MAX )
  1148.         {
  1149.             firemode = WP_FIREMODE_NONE + 1;
  1150.         }
  1151.  
  1152.         if( weaponData[weapon].attack[ATTACK_NORMAL].weaponFlags&(1<<firemode))
  1153.         {
  1154.             break;
  1155.         }
  1156.         else
  1157.         {
  1158.             firemode++;
  1159.         }
  1160.     }
  1161.  
  1162.     assert ( firemode < WP_FIREMODE_MAX );
  1163.     
  1164.     return firemode;
  1165. }
  1166.  
  1167. /*
  1168. ===============
  1169. BG_CalculateBulletEndpoint
  1170.  
  1171. Calculates the end point of a bullet based on the given inaccuracy and range
  1172. ===============
  1173. */
  1174. void BG_CalculateBulletEndpoint ( vec3_t muzzlePoint, vec3_t fireAngs, float inaccuracy, float range, vec3_t end, int *seed )
  1175. {
  1176.     float    fGaussianX = 0;
  1177.     float    fGaussianY = 0;
  1178.     vec3_t    dir;
  1179.     vec3_t  fwd;
  1180.     vec3_t    up;
  1181.     vec3_t    right;
  1182.  
  1183.     AngleVectors ( fireAngs, fwd, right, up );
  1184.  
  1185.     // No inaccuracy so just extend it forward by the range
  1186.     if ( inaccuracy <= 0.0f )
  1187.     {
  1188.         VectorMA (muzzlePoint, range, fwd, end);
  1189.         return;
  1190.     }
  1191.  
  1192.     // Gaussian spread should keep it a bit less random looking
  1193.     while ( 1 )
  1194.     {     
  1195.         float fGaussian;
  1196.         float f1;
  1197.         float f2;
  1198.  
  1199.         f1 = (float)(Q_rand ( seed ) % 15000) / 15000.0f;
  1200.         f2 = (float)(Q_rand ( seed ) % 15000) / 15000.0f;
  1201.         fGaussianX = (f1-0.5f) + (f2-0.5f); 
  1202.  
  1203.         f1 = (float)(Q_rand ( seed ) % 15000) / 15000.0f;
  1204.         f2 = (float)(Q_rand ( seed ) % 15000) / 15000.0f;
  1205.         fGaussianY = (f1-0.5f) + (f2-0.5f); 
  1206.  
  1207.         fGaussian = fGaussianX * fGaussianX + fGaussianY * fGaussianY;
  1208.  
  1209.         if ( fGaussian < 1 )
  1210.         {
  1211.             break;
  1212.         }
  1213.     } 
  1214.  
  1215.     VectorMA ( fwd, 0.05f * inaccuracy * fGaussianX, right, dir );
  1216.     VectorMA ( dir, 0.05f * inaccuracy * fGaussianY, up, dir );
  1217.  
  1218.     VectorMA (muzzlePoint, range, dir, end);
  1219. }
  1220.  
  1221. /*
  1222. ===============
  1223. BG_GetMaxAmmo
  1224.  
  1225. Returns the max ammo a client can hold for the given ammo index
  1226. ===============
  1227. */
  1228. int BG_GetMaxAmmo ( const playerState_t* ps, int ammoIndex )
  1229. {
  1230.     int            ammo;
  1231.     weapon_t    weapon;
  1232.  
  1233.     if ( ammoIndex == AMMO_NONE )
  1234.     {
  1235.         return 0;
  1236.     }
  1237.  
  1238.     for ( ammo = 0, weapon = WP_KNIFE; weapon < WP_NUM_WEAPONS; weapon ++ )
  1239.     {
  1240.         if ( !(ps->stats[STAT_WEAPONS] & (1<<weapon)) )
  1241.         {
  1242.             if ( weapon != ps->stats[STAT_OUTFIT_GRENADE] )
  1243.             {
  1244.                 continue;
  1245.             }
  1246.         }
  1247.  
  1248.         if ( weaponData[weapon].attack[ATTACK_NORMAL].ammoIndex == ammoIndex )
  1249.         {
  1250.             ammo += (weaponData[weapon].attack[ATTACK_NORMAL].extraClips + 1) * weaponData[weapon].attack[ATTACK_NORMAL].clipSize;
  1251.             ammo -= ps->clip[ATTACK_NORMAL][weapon];
  1252.         }
  1253.  
  1254.         if ( BG_WeaponHasAlternateAmmo ( weapon ) )
  1255.         {
  1256.             if ( weaponData[weapon].attack[ATTACK_ALTERNATE].ammoIndex == ammoIndex )
  1257.             {
  1258.                 ammo += (weaponData[weapon].attack[ATTACK_ALTERNATE].extraClips + 1) * weaponData[weapon].attack[ATTACK_ALTERNATE].clipSize;
  1259.                 ammo -= ps->clip[ATTACK_ALTERNATE][weapon];
  1260.             }
  1261.         }
  1262.     }
  1263.  
  1264.     return ammo;
  1265. }
  1266.