home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / cg_event.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  22.1 KB  |  882 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. // cg_event.c -- handle entity events at snapshot or playerstate transitions
  4.  
  5. #include "cg_local.h"
  6.  
  7. //==========================================================================
  8.  
  9. /*
  10. ===================
  11. CG_PlaceString
  12.  
  13. Also called by scoreboard drawing
  14. ===================
  15. */
  16. const char    *CG_PlaceString( int rank ) {
  17.     static char    str[64];
  18.     char    *s, *t;
  19.  
  20.     if ( rank & RANK_TIED_FLAG ) {
  21.         rank &= ~RANK_TIED_FLAG;
  22.         t = "Tied for ";
  23.     } else {
  24.         t = "";
  25.     }
  26.  
  27.     if ( rank == 1 ) {
  28.         s = S_COLOR_BLUE "1st" S_COLOR_WHITE;        // draw in blue
  29.     } else if ( rank == 2 ) {
  30.         s = S_COLOR_RED "2nd" S_COLOR_WHITE;        // draw in red
  31.     } else if ( rank == 3 ) {
  32.         s = S_COLOR_YELLOW "3rd" S_COLOR_WHITE;        // draw in yellow
  33.     } else if ( rank == 11 ) {
  34.         s = "11th";
  35.     } else if ( rank == 12 ) {
  36.         s = "12th";
  37.     } else if ( rank == 13 ) {
  38.         s = "13th";
  39.     } else if ( rank % 10 == 1 ) {
  40.         s = va("%ist", rank);
  41.     } else if ( rank % 10 == 2 ) {
  42.         s = va("%ind", rank);
  43.     } else if ( rank % 10 == 3 ) {
  44.         s = va("%ird", rank);
  45.     } else {
  46.         s = va("%ith", rank);
  47.     }
  48.  
  49.     Com_sprintf( str, sizeof( str ), "%s%s", t, s );
  50.     return str;
  51. }
  52.  
  53. /*
  54. =============
  55. CG_Obituary
  56. =============
  57. */
  58. static void CG_Obituary( entityState_t *ent ) {
  59.     int            mod;
  60.     int            target, attacker;
  61.     char        *message;
  62.     char        *message2;
  63.     const char    *targetInfo;
  64.     const char    *attackerInfo;
  65.     char        targetName[32];
  66.     char        attackerName[32];
  67.     gender_t    gender;
  68.     clientInfo_t    *ci;
  69.  
  70.     target = ent->otherEntityNum;
  71.     attacker = ent->otherEntityNum2;
  72.     mod = ent->eventParm;
  73.  
  74.     if ( target < 0 || target >= MAX_CLIENTS ) {
  75.         CG_Error( "CG_Obituary: target out of range" );
  76.     }
  77.     ci = &cgs.clientinfo[target];
  78.  
  79.     if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
  80.         attacker = ENTITYNUM_WORLD;
  81.         attackerInfo = NULL;
  82.     } else {
  83.         attackerInfo = CG_ConfigString( CS_PLAYERS + attacker );
  84.     }
  85.  
  86.     targetInfo = CG_ConfigString( CS_PLAYERS + target );
  87.     if ( !targetInfo ) {
  88.         return;
  89.     }
  90.     Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2);
  91.     strcat( targetName, S_COLOR_WHITE );
  92.  
  93.     message2 = "";
  94.  
  95.     // check for single client messages
  96.  
  97.     switch( mod ) {
  98.     case MOD_SUICIDE:
  99.         message = "suicides";
  100.         break;
  101.     case MOD_FALLING:
  102.         message = "cratered";
  103.         break;
  104.     case MOD_CRUSH:
  105.         message = "was squished";
  106.         break;
  107.     case MOD_WATER:
  108.         message = "sank like a rock";
  109.         break;
  110.     case MOD_SLIME:
  111.         message = "melted";
  112.         break;
  113.     case MOD_LAVA:
  114.         message = "does a back flip into the lava";
  115.         break;
  116.     case MOD_TARGET_LASER:
  117.         message = "saw the light";
  118.         break;
  119.     case MOD_TRIGGER_HURT:
  120.         message = "was in the wrong place";
  121.         break;
  122.     default:
  123.         message = NULL;
  124.         break;
  125.     }
  126.  
  127.     if (attacker == target) {
  128.         gender = ci->gender;
  129.         switch (mod) {
  130.         case MOD_GRENADE_SPLASH:
  131.             if ( gender == GENDER_FEMALE )
  132.                 message = "tripped on her own grenade";
  133.             else if ( gender == GENDER_NEUTER )
  134.                 message = "tripped on its own grenade";
  135.             else
  136.                 message = "tripped on his own grenade";
  137.             break;
  138.         case MOD_ROCKET_SPLASH:
  139.             if ( gender == GENDER_FEMALE )
  140.                 message = "blew herself up";
  141.             else if ( gender == GENDER_NEUTER )
  142.                 message = "blew itself up";
  143.             else
  144.                 message = "blew himself up";
  145.             break;
  146.         case MOD_PLASMA_SPLASH:
  147.             if ( gender == GENDER_FEMALE )
  148.                 message = "melted herself";
  149.             else if ( gender == GENDER_NEUTER )
  150.                 message = "melted itself";
  151.             else
  152.                 message = "melted himself";
  153.             break;
  154.         case MOD_BFG_SPLASH:
  155.             message = "should have used a smaller gun";
  156.             break;
  157.         default:
  158.             if ( gender == GENDER_FEMALE )
  159.                 message = "killed herself";
  160.             else if ( gender == GENDER_NEUTER )
  161.                 message = "killed itself";
  162.             else
  163.                 message = "killed himself";
  164.             break;
  165.         }
  166.     }
  167.  
  168.     if (message) {
  169.         CG_Printf( "%s %s.\n", targetName, message);
  170.         return;
  171.     }
  172.  
  173.     // check for kill messages from the current clientNum
  174.     if ( attacker == cg.snap->ps.clientNum ) {
  175.         char    *s;
  176.  
  177.         if ( cgs.gametype < GT_TEAM ) {
  178.             s = va("You fragged %s\n%s place with %i", targetName, 
  179.                 CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
  180.                 cg.snap->ps.persistant[PERS_SCORE] );
  181.         } else {
  182.             s = va("You fragged %s", targetName );
  183.         }
  184.         CG_CenterPrint( s, SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH );
  185.  
  186.         // print the text message as well
  187.     }
  188.  
  189.     // check for double client messages
  190.     if ( !attackerInfo ) {
  191.         attacker = ENTITYNUM_WORLD;
  192.         strcpy( attackerName, "noname" );
  193.     } else {
  194.         Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2);
  195.         strcat( attackerName, S_COLOR_WHITE );
  196.         // check for kill messages about the current clientNum
  197.         if ( target == cg.snap->ps.clientNum ) {
  198.             Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
  199.         }
  200.     }
  201.  
  202.     if ( attacker != ENTITYNUM_WORLD ) {
  203.         switch (mod) {
  204.         case MOD_GRAPPLE:
  205.             message = "was caught by";
  206.             break;
  207.         case MOD_GAUNTLET:
  208.             message = "was pummeled by";
  209.             break;
  210.         case MOD_MACHINEGUN:
  211.             message = "was machinegunned by";
  212.             break;
  213.         case MOD_SHOTGUN:
  214.             message = "was gunned down by";
  215.             break;
  216.         case MOD_GRENADE:
  217.             message = "ate";
  218.             message2 = "'s grenade";
  219.             break;
  220.         case MOD_GRENADE_SPLASH:
  221.             message = "was shredded by";
  222.             message2 = "'s shrapnel";
  223.             break;
  224.         case MOD_ROCKET:
  225.             message = "ate";
  226.             message2 = "'s rocket";
  227.             break;
  228.         case MOD_ROCKET_SPLASH:
  229.             message = "almost dodged";
  230.             message2 = "'s rocket";
  231.             break;
  232.         case MOD_PLASMA:
  233.             message = "was melted by";
  234.             message2 = "'s plasmagun";
  235.             break;
  236.         case MOD_PLASMA_SPLASH:
  237.             message = "was melted by";
  238.             message2 = "'s plasmagun";
  239.             break;
  240.         case MOD_RAILGUN:
  241.             message = "was railed by";
  242.             break;
  243.         case MOD_LIGHTNING:
  244.             message = "was electrocuted by";
  245.             break;
  246.         case MOD_BFG:
  247.         case MOD_BFG_SPLASH:
  248.             message = "was blasted by";
  249.             message2 = "'s BFG";
  250.             break;
  251.         case MOD_TELEFRAG:
  252.             message = "tried to invade";
  253.             message2 = "'s personal space";
  254.             break;
  255.         default:
  256.             message = "was killed by";
  257.             break;
  258.         }
  259.  
  260.         if (message) {
  261.             CG_Printf( "%s %s %s%s\n", 
  262.                 targetName, message, attackerName, message2);
  263.             return;
  264.         }
  265.     }
  266.  
  267.     // we don't know what it was
  268.     CG_Printf( "%s died.\n", targetName );
  269. }
  270.  
  271. //==========================================================================
  272.  
  273. /*
  274. ===============
  275. CG_UseItem
  276. ===============
  277. */
  278. static void CG_UseItem( centity_t *cent ) {
  279.     int            itemNum;
  280.     gitem_t        *item;
  281.     entityState_t *es;
  282.  
  283.     es = ¢->currentState;
  284.     
  285.     itemNum = es->event - EV_USE_ITEM0;
  286.     if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {
  287.         itemNum = 0;
  288.     }
  289.  
  290.     // print a message if the local player
  291.     if ( es->number == cg.snap->ps.clientNum ) {
  292.         if ( !itemNum ) {
  293.             CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH );
  294.         } else {
  295.             item = BG_FindItemForHoldable( itemNum );
  296.             CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH );
  297.         }
  298.     }
  299.  
  300.     switch ( itemNum ) {
  301.     default:
  302.     case HI_NONE:
  303.         trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound );
  304.         break;
  305.  
  306.     case HI_TELEPORTER:
  307.         break;
  308.  
  309.     case HI_MEDKIT:
  310.         trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound );
  311.         break;
  312.     }
  313.  
  314. }
  315.  
  316. /*
  317. ================
  318. CG_ItemPickup
  319.  
  320. A new item was picked up this frame
  321. ================
  322. */
  323. static void CG_ItemPickup( int itemNum ) {
  324.     cg.itemPickup = itemNum;
  325.     cg.itemPickupTime = cg.time;
  326.     cg.itemPickupBlendTime = cg.time;
  327.     // see if it should be the grabbed weapon
  328.     if ( bg_itemlist[itemNum].giType == IT_WEAPON ) {
  329.         // select it immediately
  330.         if ( cg_autoswitch.integer && bg_itemlist[itemNum].giTag != WP_MACHINEGUN ) {
  331.             cg.weaponSelectTime = cg.time;
  332.             cg.weaponSelect = bg_itemlist[itemNum].giTag;
  333.         }
  334.     }
  335.  
  336. }
  337.  
  338.  
  339. /*
  340. ================
  341. CG_PainEvent
  342.  
  343. Also called by playerstate transition
  344. ================
  345. */
  346. void CG_PainEvent( centity_t *cent, int health ) {
  347.     char    *snd;
  348.  
  349.     // don't do more than two pain sounds a second
  350.     if ( cg.time - cent->pe.painTime < 500 ) {
  351.         return;
  352.     }
  353.  
  354.     if ( health < 25 ) {
  355.         snd = "*pain25_1.wav";
  356.     } else if ( health < 50 ) {
  357.         snd = "*pain50_1.wav";
  358.     } else if ( health < 75 ) {
  359.         snd = "*pain75_1.wav";
  360.     } else {
  361.         snd = "*pain100_1.wav";
  362.     }
  363.     trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE, 
  364.         CG_CustomSound( cent->currentState.number, snd ) );
  365.  
  366.     // save pain time for programitic twitch animation
  367.     cent->pe.painTime = cg.time;
  368.     cent->pe.painDirection ^= 1;
  369. }
  370.  
  371. /*
  372. ==============
  373. CG_EntityEvent
  374.  
  375. An entity has an event value
  376. also called by CG_CheckPlayerstateEvents
  377. ==============
  378. */
  379. #define    DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
  380. void CG_EntityEvent( centity_t *cent, vec3_t position ) {
  381.     entityState_t    *es;
  382.     int                event;
  383.     vec3_t            dir;
  384.     const char        *s;
  385.     int                clientNum;
  386.     clientInfo_t    *ci;
  387.  
  388.     es = ¢->currentState;
  389.     event = es->event & ~EV_EVENT_BITS;
  390.  
  391.     if ( cg_debugEvents.integer ) {
  392.         CG_Printf( "ent:%3i  event:%3i ", es->number, event );
  393.     }
  394.  
  395.     if ( !event ) {
  396.         DEBUGNAME("ZEROEVENT");
  397.         return;
  398.     }
  399.  
  400.     clientNum = es->clientNum;
  401.     if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
  402.         clientNum = 0;
  403.     }
  404.     ci = &cgs.clientinfo[ clientNum ];
  405.  
  406.     switch ( event ) {
  407.     //
  408.     // movement generated events
  409.     //
  410.     case EV_FOOTSTEP:
  411.         DEBUGNAME("EV_FOOTSTEP");
  412.         if (cg_footsteps.integer) {
  413.             trap_S_StartSound (NULL, es->number, CHAN_BODY, 
  414.                 cgs.media.footsteps[ ci->footsteps ][rand()&3] );
  415.         }
  416.         break;
  417.     case EV_FOOTSTEP_METAL:
  418.         DEBUGNAME("EV_FOOTSTEP_METAL");
  419.         if (cg_footsteps.integer) {
  420.             trap_S_StartSound (NULL, es->number, CHAN_BODY, 
  421.                 cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] );
  422.         }
  423.         break;
  424.     case EV_FOOTSPLASH:
  425.         DEBUGNAME("EV_FOOTSPLASH");
  426.         if (cg_footsteps.integer) {
  427.             trap_S_StartSound (NULL, es->number, CHAN_BODY, 
  428.                 cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
  429.         }
  430.         break;
  431.     case EV_FOOTWADE:
  432.         DEBUGNAME("EV_FOOTWADE");
  433.         if (cg_footsteps.integer) {
  434.             trap_S_StartSound (NULL, es->number, CHAN_BODY, 
  435.                 cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
  436.         }
  437.         break;
  438.     case EV_SWIM:
  439.         DEBUGNAME("EV_SWIM");
  440.         if (cg_footsteps.integer) {
  441.             trap_S_StartSound (NULL, es->number, CHAN_BODY, 
  442.                 cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
  443.         }
  444.         break;
  445.  
  446.  
  447.     case EV_FALL_SHORT:
  448.         DEBUGNAME("EV_FALL_SHORT");
  449.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound );
  450.         if ( clientNum == cg.predictedPlayerState.clientNum ) {
  451.             // smooth landing z changes
  452.             cg.landChange = -8;
  453.             cg.landTime = cg.time;
  454.         }
  455.         break;
  456.     case EV_FALL_MEDIUM:
  457.         DEBUGNAME("EV_FALL_MEDIUM");
  458.         // use normal pain sound trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) );
  459.         if ( clientNum == cg.predictedPlayerState.clientNum ) {
  460.             // smooth landing z changes
  461.             cg.landChange = -16;
  462.             cg.landTime = cg.time;
  463.         }
  464.         break;
  465.     case EV_FALL_FAR:
  466.         DEBUGNAME("EV_FALL_FAR");
  467.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
  468.         cent->pe.painTime = cg.time;    // don't play a pain sound right after this
  469.         if ( clientNum == cg.predictedPlayerState.clientNum ) {
  470.             // smooth landing z changes
  471.             cg.landChange = -24;
  472.             cg.landTime = cg.time;
  473.         }
  474.         break;
  475.  
  476.     case EV_STEP_4:
  477.     case EV_STEP_8:
  478.     case EV_STEP_12:
  479.     case EV_STEP_16:        // smooth out step up transitions
  480.         DEBUGNAME("EV_STEP");
  481.     {
  482.         float    oldStep;
  483.         int        delta;
  484.         int        step;
  485.  
  486.         if ( clientNum != cg.predictedPlayerState.clientNum ) {
  487.             break;
  488.         }
  489.         // if we are interpolating, we don't need to smooth steps
  490.         if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ||
  491.             cg_nopredict.integer || cg_syncronousClients.integer ) {
  492.             break;
  493.         }
  494.         // check for stepping up before a previous step is completed
  495.         delta = cg.time - cg.stepTime;
  496.         if (delta < STEP_TIME) {
  497.             oldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME;
  498.         } else {
  499.             oldStep = 0;
  500.         }
  501.  
  502.         // add this amount
  503.         step = 4 * (event - EV_STEP_4 + 1 );
  504.         cg.stepChange = oldStep + step;
  505.         if ( cg.stepChange > MAX_STEP_CHANGE ) {
  506.             cg.stepChange = MAX_STEP_CHANGE;
  507.         }
  508.         cg.stepTime = cg.time;
  509.         break;
  510.     }
  511.  
  512.     case EV_JUMP_PAD:
  513.         DEBUGNAME("EV_JUMP_PAD");
  514.         // boing sound at origin, jump sound on player
  515.         trap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound );
  516.         trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
  517.         break;
  518.  
  519.     case EV_JUMP:
  520.         DEBUGNAME("EV_JUMP");
  521.         trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
  522.         break;
  523.     case EV_TAUNT:
  524.         DEBUGNAME("EV_TAUNT");
  525.         trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
  526.         break;
  527.     case EV_WATER_TOUCH:
  528.         DEBUGNAME("EV_WATER_TOUCH");
  529.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
  530.         break;
  531.     case EV_WATER_LEAVE:
  532.         DEBUGNAME("EV_WATER_LEAVE");
  533.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
  534.         break;
  535.     case EV_WATER_UNDER:
  536.         DEBUGNAME("EV_WATER_UNDER");
  537.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
  538.         break;
  539.     case EV_WATER_CLEAR:
  540.         DEBUGNAME("EV_WATER_CLEAR");
  541.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
  542.         break;
  543.  
  544.     case EV_ITEM_PICKUP:
  545.         DEBUGNAME("EV_ITEM_PICKUP");
  546.         {
  547.             gitem_t    *item;
  548.             int        index;
  549.  
  550.             index = es->eventParm;        // player predicted
  551.  
  552.             if ( index < 1 || index >= bg_numItems ) {
  553.                 break;
  554.             }
  555.             item = &bg_itemlist[ index ];
  556.  
  557.             // powerups and team items will have a separate global sound, this one
  558.             // will be played at prediction time
  559.             if ( item->giType == IT_POWERUP || item->giType == IT_TEAM) {
  560.                 trap_S_StartSound (NULL, es->number, CHAN_AUTO,    trap_S_RegisterSound( "sound/items/n_health.wav" ) );
  561.             } else {
  562.                 trap_S_StartSound (NULL, es->number, CHAN_AUTO,    trap_S_RegisterSound( item->pickup_sound ) );
  563.             }
  564.  
  565.             // show icon and name on status bar
  566.             if ( es->number == cg.snap->ps.clientNum ) {
  567.                 CG_ItemPickup( index );
  568.             }
  569.         }
  570.         break;
  571.  
  572.     case EV_GLOBAL_ITEM_PICKUP:
  573.         DEBUGNAME("EV_GLOBAL_ITEM_PICKUP");
  574.         {
  575.             gitem_t    *item;
  576.             int        index;
  577.  
  578.             index = es->eventParm;        // player predicted
  579.  
  580.             if ( index < 1 || index >= bg_numItems ) {
  581.                 break;
  582.             }
  583.             item = &bg_itemlist[ index ];
  584.             // powerup pickups are global
  585.             trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound ) );
  586.  
  587.             // show icon and name on status bar
  588.             if ( es->number == cg.snap->ps.clientNum ) {
  589.                 CG_ItemPickup( index );
  590.             }
  591.         }
  592.         break;
  593.  
  594.     //
  595.     // weapon events
  596.     //
  597.     case EV_NOAMMO:
  598.         DEBUGNAME("EV_NOAMMO");
  599. //        trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound );
  600.         if ( es->number == cg.snap->ps.clientNum ) {
  601.             CG_OutOfAmmoChange();
  602.         }
  603.         break;
  604.     case EV_CHANGE_WEAPON:
  605.         DEBUGNAME("EV_CHANGE_WEAPON");
  606.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
  607.         break;
  608.     case EV_FIRE_WEAPON:
  609.         DEBUGNAME("EV_FIRE_WEAPON");
  610.         CG_FireWeapon( cent );
  611.         break;
  612.  
  613.     case EV_USE_ITEM0:
  614.         DEBUGNAME("EV_USE_ITEM0");
  615.         CG_UseItem( cent );
  616.         break;
  617.     case EV_USE_ITEM1:
  618.         DEBUGNAME("EV_USE_ITEM1");
  619.         CG_UseItem( cent );
  620.         break;
  621.     case EV_USE_ITEM2:
  622.         DEBUGNAME("EV_USE_ITEM2");
  623.         CG_UseItem( cent );
  624.         break;
  625.     case EV_USE_ITEM3:
  626.         DEBUGNAME("EV_USE_ITEM3");
  627.         CG_UseItem( cent );
  628.         break;
  629.     case EV_USE_ITEM4:
  630.         DEBUGNAME("EV_USE_ITEM4");
  631.         CG_UseItem( cent );
  632.         break;
  633.     case EV_USE_ITEM5:
  634.         DEBUGNAME("EV_USE_ITEM5");
  635.         CG_UseItem( cent );
  636.         break;
  637.     case EV_USE_ITEM6:
  638.         DEBUGNAME("EV_USE_ITEM6");
  639.         CG_UseItem( cent );
  640.         break;
  641.     case EV_USE_ITEM7:
  642.         DEBUGNAME("EV_USE_ITEM7");
  643.         CG_UseItem( cent );
  644.         break;
  645.     case EV_USE_ITEM8:
  646.         DEBUGNAME("EV_USE_ITEM8");
  647.         CG_UseItem( cent );
  648.         break;
  649.     case EV_USE_ITEM9:
  650.         DEBUGNAME("EV_USE_ITEM9");
  651.         CG_UseItem( cent );
  652.         break;
  653.     case EV_USE_ITEM10:
  654.         DEBUGNAME("EV_USE_ITEM10");
  655.         CG_UseItem( cent );
  656.         break;
  657.     case EV_USE_ITEM11:
  658.         DEBUGNAME("EV_USE_ITEM11");
  659.         CG_UseItem( cent );
  660.         break;
  661.     case EV_USE_ITEM12:
  662.         DEBUGNAME("EV_USE_ITEM12");
  663.         CG_UseItem( cent );
  664.         break;
  665.     case EV_USE_ITEM13:
  666.         DEBUGNAME("EV_USE_ITEM13");
  667.         CG_UseItem( cent );
  668.         break;
  669.     case EV_USE_ITEM14:
  670.         DEBUGNAME("EV_USE_ITEM14");
  671.         CG_UseItem( cent );
  672.         break;
  673.  
  674.     //=================================================================
  675.  
  676.     //
  677.     // other events
  678.     //
  679.     case EV_PLAYER_TELEPORT_IN:
  680.         DEBUGNAME("EV_PLAYER_TELEPORT_IN");
  681.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound );
  682.         CG_SpawnEffect( position);
  683.         break;
  684.  
  685.     case EV_PLAYER_TELEPORT_OUT:
  686.         DEBUGNAME("EV_PLAYER_TELEPORT_OUT");
  687.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound );
  688.         CG_SpawnEffect(  position);
  689.         break;
  690.  
  691.     case EV_ITEM_POP:
  692.         DEBUGNAME("EV_ITEM_POP");
  693.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
  694.         break;
  695.     case EV_ITEM_RESPAWN:
  696.         DEBUGNAME("EV_ITEM_RESPAWN");
  697.         cent->miscTime = cg.time;    // scale up from this
  698.         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
  699.         break;
  700.  
  701.     case EV_GRENADE_BOUNCE:
  702.         DEBUGNAME("EV_GRENADE_BOUNCE");
  703.         if ( rand() & 1 ) {
  704.             trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound("sound/weapons/grenade/hgrenb1a.wav") );
  705.         } else {
  706.             trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound("sound/weapons/grenade/hgrenb2a.wav") );
  707.         }
  708.         break;
  709.  
  710.     //
  711.     // missile impacts
  712.     //
  713.     case EV_MISSILE_HIT:
  714.         DEBUGNAME("EV_MISSILE_HIT");
  715.         ByteToDir( es->eventParm, dir );
  716.         CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum );
  717.         break;
  718.  
  719.     case EV_MISSILE_MISS:
  720.         DEBUGNAME("EV_MISSILE_MISS");
  721.         ByteToDir( es->eventParm, dir );
  722.         CG_MissileHitWall( es->weapon, 0, position, dir );
  723.         break;
  724.  
  725.     case EV_RAILTRAIL:
  726.         DEBUGNAME("EV_RAILTRAIL");
  727.         cent->currentState.weapon = WP_RAILGUN;
  728.         // if the end was on a nomark surface, don't make an explosion
  729.         if ( es->eventParm != 255 ) {
  730.             ByteToDir( es->eventParm, dir );
  731.             CG_MissileHitWall( es->weapon, es->clientNum, position, dir );
  732.         }
  733. #if 1
  734.         CG_RailTrail( ci, es->origin2, es->pos.trBase );
  735. #else
  736.         // the railtrail temp entity will be spawned when this player is added
  737.         VectorCopy( es->pos.trBase, cg_entities[clientNum].pe.railgunImpact );
  738.         cg_entities[clientNum].pe.railgunFlash = qtrue;
  739. #endif
  740.         break;
  741.  
  742.     case EV_BULLET_HIT_WALL:
  743.         DEBUGNAME("EV_BULLET_HIT_WALL");
  744.         ByteToDir( es->eventParm, dir );
  745.         CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
  746.         break;
  747.  
  748.     case EV_BULLET_HIT_FLESH:
  749.         DEBUGNAME("EV_BULLET_HIT_FLESH");
  750.         CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
  751.         break;
  752.  
  753.     case EV_SHOTGUN:
  754.         DEBUGNAME("EV_SHOTGUN");
  755.         CG_ShotgunFire( es );
  756.         break;
  757.  
  758.     case EV_GENERAL_SOUND:
  759.         DEBUGNAME("EV_GENERAL_SOUND");
  760.         if ( cgs.gameSounds[ es->eventParm ] ) {
  761.             trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
  762.         } else {
  763.             s = CG_ConfigString( CS_SOUNDS + es->eventParm );
  764.             trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
  765.         }
  766.         break;
  767.  
  768.     case EV_GLOBAL_SOUND:    // play from the player's head so it never diminishes
  769.         DEBUGNAME("EV_GLOBAL_SOUND");
  770.         if ( cgs.gameSounds[ es->eventParm ] ) {
  771.             trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
  772.         } else {
  773.             s = CG_ConfigString( CS_SOUNDS + es->eventParm );
  774.             trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
  775.         }
  776.         break;
  777.  
  778.     case EV_PAIN:
  779.         // local player sounds are triggered in CG_CheckLocalSounds,
  780.         // so ignore events on the player
  781.         DEBUGNAME("EV_PAIN");
  782.         if ( cent->currentState.number != cg.snap->ps.clientNum ) {
  783.             CG_PainEvent( cent, es->eventParm );
  784.         }
  785.         break;
  786.  
  787.     case EV_DEATH1:
  788.     case EV_DEATH2:
  789.     case EV_DEATH3:
  790.         DEBUGNAME("EV_DEATHx");
  791.         trap_S_StartSound( NULL, es->number, CHAN_VOICE, 
  792.                 CG_CustomSound( es->number, va("*death%i.wav", event - EV_DEATH1 + 1) ) );
  793.         break;
  794.  
  795.  
  796.     case EV_OBITUARY:
  797.         DEBUGNAME("EV_OBITUARY");
  798.         CG_Obituary( es );
  799.         break;
  800.  
  801.     //
  802.     // powerup events
  803.     //
  804.     case EV_POWERUP_QUAD:
  805.         DEBUGNAME("EV_POWERUP_QUAD");
  806.         if ( es->number == cg.snap->ps.clientNum ) {
  807.             cg.powerupActive = PW_QUAD;
  808.             cg.powerupTime = cg.time;
  809.         }
  810.         trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound );
  811.         break;
  812.     case EV_POWERUP_BATTLESUIT:
  813.         DEBUGNAME("EV_POWERUP_BATTLESUIT");
  814.         if ( es->number == cg.snap->ps.clientNum ) {
  815.             cg.powerupActive = PW_BATTLESUIT;
  816.             cg.powerupTime = cg.time;
  817.         }
  818.         trap_S_StartSound (NULL, es->number, CHAN_ITEM, trap_S_RegisterSound("sound/items/protect3.wav") );
  819.         break;
  820.     case EV_POWERUP_REGEN:
  821.         DEBUGNAME("EV_POWERUP_REGEN");
  822.         if ( es->number == cg.snap->ps.clientNum ) {
  823.             cg.powerupActive = PW_REGEN;
  824.             cg.powerupTime = cg.time;
  825.         }
  826.         trap_S_StartSound (NULL, es->number, CHAN_ITEM, trap_S_RegisterSound("sound/items/regen.wav") );
  827.         break;
  828.  
  829.     case EV_GIB_PLAYER:
  830.         DEBUGNAME("EV_GIB_PLAYER");
  831.         trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound );
  832.         CG_GibPlayer( cent->lerpOrigin );
  833.         break;
  834.  
  835.     case EV_DEBUG_LINE:
  836.         DEBUGNAME("EV_DEBUG_LINE");
  837.         CG_Beam( cent );
  838.         break;
  839.  
  840.     default:
  841.         DEBUGNAME("UNKNOWN");
  842.         CG_Error( "Unknown event: %i", event );
  843.         break;
  844.     }
  845.  
  846. }
  847.  
  848.  
  849. /*
  850. ==============
  851. CG_CheckEvents
  852.  
  853. ==============
  854. */
  855. void CG_CheckEvents( centity_t *cent ) {
  856.     // check for event-only entities
  857.     if ( cent->currentState.eType > ET_EVENTS ) {
  858.         if ( cent->previousEvent ) {
  859.             return;    // already fired
  860.         }
  861.         cent->previousEvent = 1;
  862.  
  863.         cent->currentState.event = cent->currentState.eType - ET_EVENTS;
  864.     } else {
  865.         // check for events riding with another entity
  866.         if ( cent->currentState.event == cent->previousEvent ) {
  867.             return;
  868.         }
  869.         cent->previousEvent = cent->currentState.event;
  870.         if ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) {
  871.             return;
  872.         }
  873.     }
  874.  
  875.     // calculate the position at exactly the frame time
  876.     BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );
  877.     CG_SetEntitySoundPosition( cent );
  878.  
  879.     CG_EntityEvent( cent, cent->lerpOrigin );
  880. }
  881.  
  882.