home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2006 March / Gamestar_82_2006-03_dvd.iso / DVDStar / Editace / quake4_sdkv10.exe / source / game / Player.cpp < prev    next >
C/C++ Source or Header  |  2005-11-14  |  346KB  |  13,035 lines

  1. // RAVEN BEGIN
  2. // bdube: note that this file is no longer merged with Doom3 updates
  3. //
  4. // MERGE_DATE 09/30/2004
  5.  
  6. #include "../idlib/precompiled.h"
  7. #pragma hdrstop
  8.  
  9. #include "Game_local.h"
  10.  
  11. #include "ai/AI.h"
  12. #include "ai/AI_Manager.h"
  13. #include "Weapon.h"
  14. #include "Projectile.h"
  15. #include "vehicle/Vehicle.h"
  16. #include "client/ClientModel.h"
  17. #include "ai/AAS_tactical.h"
  18. #include "Healing_Station.h"
  19. #include "ai/AI_Medic.h"
  20.  
  21. // RAVEN BEGIN
  22. // nrausch: support for turning the weapon change ui on and off
  23. #ifdef _XENON
  24. #include "../ui/Window.h"
  25.  
  26. // nrausch: support for direct button input
  27. #include "../sys/xenon/xen_input.h"
  28. #endif
  29. // RAVEN END
  30.  
  31. idCVar net_predictionErrorDecay( "net_predictionErrorDecay", "112", CVAR_FLOAT | CVAR_GAME | CVAR_NOCHEAT, "time in milliseconds it takes to fade away prediction errors", 0.0f, 200.0f );
  32. idCVar net_showPredictionError( "net_showPredictionError", "-1", CVAR_INTEGER | CVAR_GAME | CVAR_NOCHEAT, "show prediction errors for the given client", -1, MAX_CLIENTS );
  33.  
  34. /*
  35. ===============================================================================
  36.  
  37.     Player control.
  38.     This object handles all player movement and world interaction.
  39.  
  40. ===============================================================================
  41. */
  42.  
  43. #ifdef _XENON
  44. bool g_ObjectiveSystemOpen = false;
  45. #endif
  46.  
  47. // distance between ladder rungs (actually is half that distance, but this sounds better)
  48. const int LADDER_RUNG_DISTANCE = 32;
  49.  
  50. // amount of health per dose from the health station
  51. const int HEALTH_PER_DOSE = 10;
  52.  
  53. // time before a weapon dropped to the floor disappears
  54. const int WEAPON_DROP_TIME = 20 * 1000;
  55.  
  56. // time before a next or prev weapon switch happens
  57. const int    WEAPON_SWITCH_DELAY        = 150;
  58.  
  59. const float    PLAYER_ITEM_DROP_SPEED    = 100.0f;
  60.  
  61. // how many units to raise spectator above default view height so it's in the head of someone
  62. const int SPECTATE_RAISE = 25;
  63.  
  64. const int    HEALTH_PULSE        = 1000;            // Regen rate and heal leak rate (for health > 100)
  65. const int    ARMOR_PULSE            = 1000;            // armor ticking down due to being higher than maxarmor
  66. const int    AMMO_REGEN_PULSE    = 1000;            // ammo regen in Arena CTF
  67. const int    POWERUP_BLINKS        = 5;            // Number of times the powerup wear off sound plays
  68. const int    POWERUP_BLINK_TIME    = 1000;            // Time between powerup wear off sounds
  69. const float MIN_BOB_SPEED        = 5.0f;            // minimum speed to bob and play run/walk animations at
  70. const int    MAX_RESPAWN_TIME    = 10000;
  71. const int    RAGDOLL_DEATH_TIME    = 3000;
  72. const int    STEPUP_TIME            = 200;
  73. const int    MAX_INVENTORY_ITEMS = 20;
  74.  
  75. const int    ARENA_POWERUP_MASK = ( 1 << POWERUP_AMMOREGEN ) | ( 1 << POWERUP_GUARD ) | ( 1 << POWERUP_DOUBLER ) | ( 1 << POWERUP_SCOUT );
  76.  
  77. //const idEventDef EV_Player_HideDatabaseEntry ( "<hidedatabaseentry>", NULL );
  78. const idEventDef EV_Player_ZoomIn ( "<zoomin>" );
  79. const idEventDef EV_Player_ZoomOut ( "<zoomout>" );
  80.  
  81. const idEventDef EV_Player_GetButtons( "getButtons", NULL, 'd' );
  82. const idEventDef EV_Player_GetMove( "getMove", NULL, 'v' );
  83. const idEventDef EV_Player_GetViewAngles( "getViewAngles", NULL, 'v' );
  84. const idEventDef EV_Player_SetViewAngles( "setViewAngles", "v" );
  85. const idEventDef EV_Player_StopFxFov( "stopFxFov" );
  86. const idEventDef EV_Player_EnableWeapon( "enableWeapon" );
  87. const idEventDef EV_Player_DisableWeapon( "disableWeapon" );
  88. const idEventDef EV_Player_GetCurrentWeapon( "getCurrentWeapon", NULL, 's' );
  89. const idEventDef EV_Player_GetPreviousWeapon( "getPreviousWeapon", NULL, 's' );
  90. const idEventDef EV_Player_SelectWeapon( "selectWeapon", "s" );
  91. const idEventDef EV_Player_GetWeaponEntity( "getWeaponEntity", NULL, 'e' );
  92. const idEventDef EV_Player_ExitTeleporter( "exitTeleporter" );
  93. const idEventDef EV_Player_HideTip( "hideTip" );
  94. const idEventDef EV_Player_LevelTrigger( "levelTrigger" );
  95. const idEventDef EV_SpectatorTouch( "spectatorTouch", "et" );
  96. const idEventDef EV_Player_GetViewPos("getViewPos", NULL, 'v');
  97. const idEventDef EV_Player_FinishHearingLoss ( "<finishHearingLoss>", "f" );
  98. const idEventDef EV_Player_GetAmmoData( "getAmmoData", "s", 'v');
  99. const idEventDef EV_Player_RefillAmmo( "refillAmmo" );
  100. const idEventDef EV_Player_SetExtraProjPassEntity( "setExtraProjPassEntity", "E" );
  101. const idEventDef EV_Player_SetArmor( "setArmor", "f" );
  102. const idEventDef EV_Player_DamageEffect( "damageEffect", "sE" );
  103. const idEventDef EV_Player_AllowFallDamage( "allowFallDamage", "d" );
  104.  
  105. // mekberg: allow enabling/disabling of objectives
  106. const idEventDef EV_Player_EnableObjectives( "enableObjectives" );
  107. const idEventDef EV_Player_DisableObjectives( "disableObjectives" );
  108.  
  109. // mekberg: don't suppress showing of new objectives anymore
  110. const idEventDef EV_Player_AllowNewObjectives( "<allownewobjectives>" );
  111.  
  112. // RAVEN END
  113.  
  114. CLASS_DECLARATION( idActor, idPlayer )
  115. //    EVENT( EV_Player_HideDatabaseEntry,        idPlayer::Event_HideDatabaseEntry )
  116.     EVENT( EV_Player_ZoomIn,                idPlayer::Event_ZoomIn )
  117.     EVENT( EV_Player_ZoomOut,                idPlayer::Event_ZoomOut )
  118.     EVENT( EV_Player_GetButtons,            idPlayer::Event_GetButtons )
  119.     EVENT( EV_Player_GetMove,                idPlayer::Event_GetMove )
  120.     EVENT( EV_Player_GetViewAngles,            idPlayer::Event_GetViewAngles )
  121.     EVENT( EV_Player_SetViewAngles,            idPlayer::Event_SetViewAngles )
  122.     EVENT( EV_Player_StopFxFov,                idPlayer::Event_StopFxFov )
  123.     EVENT( EV_Player_EnableWeapon,            idPlayer::Event_EnableWeapon )
  124.     EVENT( EV_Player_DisableWeapon,            idPlayer::Event_DisableWeapon )
  125.     EVENT( EV_Player_GetCurrentWeapon,        idPlayer::Event_GetCurrentWeapon )
  126.     EVENT( EV_Player_GetPreviousWeapon,        idPlayer::Event_GetPreviousWeapon )
  127.     EVENT( EV_Player_SelectWeapon,            idPlayer::Event_SelectWeapon )
  128.     EVENT( EV_Player_GetWeaponEntity,        idPlayer::Event_GetWeaponEntity )
  129.     EVENT( EV_Player_ExitTeleporter,        idPlayer::Event_ExitTeleporter )
  130.     EVENT( EV_Player_HideTip,                idPlayer::Event_HideTip )
  131.     EVENT( EV_Player_LevelTrigger,            idPlayer::Event_LevelTrigger )
  132.     EVENT( EV_Player_GetViewPos,            idPlayer::Event_GetViewPos )
  133.     EVENT( EV_Player_FinishHearingLoss,        idPlayer::Event_FinishHearingLoss )
  134.     EVENT( EV_Player_GetAmmoData,            idPlayer::Event_GetAmmoData )
  135.     EVENT( EV_Player_RefillAmmo,            idPlayer::Event_RefillAmmo )
  136.     EVENT( EV_Player_AllowFallDamage,        idPlayer::Event_AllowFallDamage )
  137.  
  138.  
  139. // mekberg: allow enabling/disabling of objectives
  140.     EVENT ( EV_Player_EnableObjectives,        idPlayer::Event_EnableObjectives )
  141.     EVENT ( EV_Player_DisableObjectives,    idPlayer::Event_DisableObjectives )
  142.  
  143. // mekberg: don't suppress showing of new objectives anymore
  144.     EVENT ( EV_Player_AllowNewObjectives,    idPlayer::Event_AllowNewObjectives )
  145. // RAVEN END
  146.     
  147.     EVENT( AI_EnableTarget,                    idPlayer::Event_EnableTarget )
  148.     EVENT( AI_DisableTarget,                idPlayer::Event_DisableTarget )
  149.  
  150.     EVENT( EV_ApplyImpulse,                    idPlayer::Event_ApplyImpulse )
  151.  
  152. // RAVEN BEGIN
  153. // mekberg: sethealth on player.
  154.     EVENT( AI_SetHealth,                    idPlayer::Event_SetHealth )
  155. //MCG: setArmor
  156.     EVENT( EV_Player_SetArmor,                idPlayer::Event_SetArmor )
  157. // RAVEN END;
  158.     EVENT( EV_Player_SetExtraProjPassEntity,idPlayer::Event_SetExtraProjPassEntity )
  159. //MCG: direct damage
  160.     EVENT( EV_Player_DamageEffect,            idPlayer::Event_DamageEffect )
  161. END_CLASS
  162.  
  163. // RAVEN BEGIN
  164. // asalmon: Xenon weapon combo system
  165. #ifdef _XENON
  166. nextWeaponCombo_t weaponComboChart[12] = {
  167.     // up, down, left, right
  168.     {1,3,2,4},     // 0: empty slot (select none)
  169.     {10,0,6,5},
  170.     {6,7,11,0},
  171.     {0,3,7,8},
  172.     {5,8,0,9},
  173.     {5,4,1,5},
  174.     {6,2,6,1},
  175.     {2,7,7,3},
  176.     {4,8,3,8},
  177.     {9,9,4,9},
  178.     {10,1,10,10},
  179.     {11,11,11,2} 
  180. };
  181. #endif
  182. // RAVEN END
  183.  
  184. const idVec4 marineHitscanTint( 0.69f, 1.0f, 0.4f, 1.0f );
  185. const idVec4 stroggHitscanTint( 1.0f, 0.5f, 0.0f, 1.0f );
  186. const idVec4 defaultHitscanTint( 0.4f, 1.0f, 0.4f, 1.0f );
  187.  
  188. /*
  189. ==============
  190. idInventory::Clear
  191. ==============
  192. */
  193. void idInventory::Clear( void ) {
  194.     maxHealth        = 0;
  195.     weapons            = 0;
  196.     powerups        = 0;
  197.     armor            = 0;
  198.     maxarmor        = 0;
  199.     secretAreasDiscovered = 0;
  200.  
  201.     memset( ammo, 0, sizeof( ammo ) );
  202.  
  203.     ClearPowerUps();
  204.  
  205.     memset ( weaponMods, 0, sizeof(weaponMods) );
  206.  
  207.     // set to -1 so that the gun knows to have a full clip the first time we get it and at the start of the level
  208.     memset( clip, -1, sizeof( clip ) );
  209.     
  210.     items.DeleteContents( true );
  211.     pdas.Clear();
  212.     videos.Clear();
  213.  
  214.     levelTriggers.Clear();
  215.  
  216.     nextItemPickup = 0;
  217.     nextItemNum = 1;
  218.     onePickupTime = 0;
  219.     objectiveNames.Clear();
  220.  
  221.      ammoPredictTime = 0;
  222.      lastGiveTime = 0;
  223.  
  224.     memset(    ammoRegenStep, -1, sizeof( int ) * MAX_WEAPONS );
  225.     memset( ammoIndices, -1, sizeof( int ) * MAX_WEAPONS );
  226.     memset( startingAmmo, -1, sizeof( int ) * MAX_WEAPONS );
  227.     memset( ammoRegenTime, -1, sizeof( int ) * MAX_WEAPONS );
  228. }
  229.  
  230. /*
  231. ==============
  232. idInventory::GivePowerUp
  233. ==============
  234. */
  235. void idInventory::GivePowerUp( idPlayer *player, int powerup, int msec ) {
  236.     powerups |= 1 << powerup;
  237.     powerupEndTime[ powerup ] = msec == -1 ? -1 : (gameLocal.time + msec);
  238. }
  239.  
  240. /*
  241. ==============
  242. idInventory::ClearPowerUps
  243. ==============
  244. */
  245. void idInventory::ClearPowerUps( void ) {
  246.     int i;
  247.     for ( i = 0; i < POWERUP_MAX; i++ ) {
  248.         powerupEndTime[ i ] = 0;
  249.     }
  250.     powerups = 0;
  251. }
  252.  
  253. /*
  254. ==============
  255. idInventory::GetPersistantData
  256. ==============
  257. */
  258. void idInventory::GetPersistantData( idDict &dict ) {
  259.     int        i;
  260.     int        num;
  261.     idDict    *item;
  262.     idStr    key;
  263.     const idKeyValue *kv;
  264.     const char *name;
  265.  
  266.     // armor
  267.     dict.SetInt( "armor", armor );
  268.  
  269.     // ammo
  270.     for( i = 0; i < MAX_AMMOTYPES; i++ ) {
  271.         name = rvWeapon::GetAmmoNameForIndex( i );
  272.         if ( name ) {
  273.             dict.SetInt( name, ammo[ i ] );
  274.         }
  275.     }
  276.  
  277.     // items
  278.     num = 0;
  279.     for( i = 0; i < items.Num(); i++ ) {
  280.         item = items[ i ];
  281.  
  282.         // copy all keys with "inv_"
  283.         kv = item->MatchPrefix( "inv_" );
  284.         if ( kv ) {
  285.             while( kv ) {
  286.                 sprintf( key, "item_%i %s", num, kv->GetKey().c_str() );
  287.                 dict.Set( key, kv->GetValue() );
  288.                 kv = item->MatchPrefix( "inv_", kv );
  289.             }
  290.             num++;
  291.         }
  292.     }
  293.     dict.SetInt( "items", num );
  294.  
  295.     // weapons
  296.     dict.SetInt( "weapon_bits", weapons );
  297.  
  298.     // weapon mods
  299.     for ( i = 0; i < MAX_WEAPONS; i++ ) {
  300.         dict.SetInt( va( "weapon_mods_%i", i ), weaponMods[ i ] );
  301.     }
  302.  
  303.     dict.SetInt( "levelTriggers", levelTriggers.Num() );
  304.     for ( i = 0; i < levelTriggers.Num(); i++ ) {
  305.         sprintf( key, "levelTrigger_Level_%i", i );
  306.         dict.Set( key, levelTriggers[i].levelName );
  307.         sprintf( key, "levelTrigger_Trigger_%i", i );
  308.         dict.Set( key, levelTriggers[i].triggerName );
  309.     }
  310. }
  311.  
  312. /*
  313. ==============
  314. idInventory::RestoreInventory
  315. ==============
  316. */
  317. void idInventory::RestoreInventory( idPlayer *owner, const idDict &dict ) {
  318.     int            i;
  319.     int            num;
  320.     idDict        *item;
  321.     idStr        key;
  322.     idStr        itemname;
  323.     const idKeyValue *kv;
  324.     const char    *name;
  325.  
  326.     Clear();
  327.  
  328.     // health/armor
  329.     maxHealth        = dict.GetInt( "maxhealth", "100" );
  330.     armor            = dict.GetInt( "armor", "50" );
  331.     maxarmor        = dict.GetInt( "maxarmor", "100" );
  332.  
  333.     // ammo
  334.     for( i = 0; i < MAX_AMMOTYPES; i++ ) {
  335.         name = rvWeapon::GetAmmoNameForIndex ( i );
  336.         if ( name ) {
  337.             ammo[ i ] = dict.GetInt( name );
  338.         }
  339.     }
  340.  
  341.     // items
  342.     num = dict.GetInt( "items" );
  343.     items.SetNum( num );
  344.     for( i = 0; i < num; i++ ) {
  345.         item = new idDict();
  346.         items[ i ] = item;
  347.         sprintf( itemname, "item_%i ", i );
  348.         kv = dict.MatchPrefix( itemname );
  349.         while( kv ) {
  350.             key = kv->GetKey();
  351.             key.Strip( itemname );
  352.             item->Set( key, kv->GetValue() );
  353.             kv = dict.MatchPrefix( itemname, kv );
  354.         }
  355.     }
  356.  
  357.     // weapons are stored as a number for persistant data, but as strings in the entityDef
  358.     weapons    = dict.GetInt( "weapon_bits", "0" );
  359.  
  360. // RAVEN BEGIN
  361. // mekberg: removed nightmare weapon check.
  362.     Give( owner, dict, "weapon", dict.GetString( "weapon" ), NULL, false );
  363. // RAVEN END
  364.  
  365.     // weapon mods
  366.     for ( i = 0; i < MAX_WEAPONS; i++ ) {
  367.         weaponMods[ i ] = dict.GetInt( va( "weapon_mods_%i", i ) );
  368.     }
  369.     // forcefully invalidate the weapon
  370.     owner->GiveWeaponMods( 0 );
  371.  
  372.     num = dict.GetInt( "levelTriggers" );
  373.     for ( i = 0; i < num; i++ ) {
  374.         sprintf( itemname, "levelTrigger_Level_%i", i );
  375.         idLevelTriggerInfo lti;
  376.         lti.levelName = dict.GetString( itemname );
  377.         sprintf( itemname, "levelTrigger_Trigger_%i", i );
  378.         lti.triggerName = dict.GetString( itemname );
  379.         levelTriggers.Append( lti );
  380.     }
  381.  
  382. }
  383.  
  384. /*
  385. ==============
  386. idInventory::Save
  387. ==============
  388. */
  389. void idInventory::Save( idSaveGame *savefile ) const {
  390.     int i;
  391.  
  392.     savefile->WriteInt( maxHealth );
  393.     savefile->WriteInt( weapons );
  394.     savefile->WriteInt( powerups );
  395.     savefile->WriteInt( armor );
  396.     savefile->WriteInt( maxarmor );
  397.  
  398.     for( i = 0; i < MAX_AMMO; i++ ) {
  399.         savefile->WriteInt( ammo[ i ] );
  400.     }
  401.  
  402.     for( i = 0; i < MAX_WEAPONS; i++ ) {
  403.         savefile->WriteInt( clip[ i ] );
  404.         savefile->WriteInt( weaponMods[i] );
  405.     }
  406.  
  407.     for( i = 0; i < POWERUP_MAX; i++ ) {
  408.         savefile->WriteInt( powerupEndTime[ i ] );
  409.     }
  410.  
  411.     savefile->WriteInt( ammoPredictTime );
  412.      savefile->WriteInt( lastGiveTime );
  413.  
  414.     // Save Items
  415.     savefile->WriteInt( items.Num() );
  416.     for( i = 0; i < items.Num(); i++ ) {
  417.         savefile->WriteDict( items[ i ] );
  418.     }
  419.  
  420.     // TOSAVE: idStrList                pdas;
  421.     // TOSAVE: idStrList                pdaSecurity;
  422.     // TOSAVE: idStrList                videos;
  423.  
  424.     // Save level triggers
  425.     savefile->WriteInt( levelTriggers.Num() );
  426.     for ( i = 0; i < levelTriggers.Num(); i++ ) {
  427.         savefile->WriteString( levelTriggers[i].levelName );
  428.         savefile->WriteString( levelTriggers[i].triggerName );
  429.     }
  430.  
  431.     savefile->WriteInt( nextItemPickup );
  432.     savefile->WriteInt( nextItemNum );
  433.     savefile->WriteInt( onePickupTime );
  434.  
  435.     // Save pick up item names
  436.     savefile->WriteInt( pickupItemNames.Num() );
  437.     for( i = 0; i < pickupItemNames.Num(); i++ ) {
  438.         savefile->WriteString( pickupItemNames[ i ].name );
  439.         savefile->WriteString( pickupItemNames[ i ].icon );
  440.     }
  441.  
  442.     // Save objectives
  443.     savefile->WriteInt( objectiveNames.Num() );
  444.     for( i = 0; i < objectiveNames.Num(); i++ ) {
  445.         savefile->WriteString( objectiveNames[i].screenshot );
  446.         savefile->WriteString( objectiveNames[i].text );
  447.         savefile->WriteString( objectiveNames[i].title );
  448.     }
  449. /*
  450.     // Save database
  451.     savefile->WriteInt ( database.Num() );
  452.     for ( i = 0; i < database.Num(); i ++ ) {
  453.         savefile->WriteString ( database[i].title );
  454.         savefile->WriteString ( database[i].text );
  455.         savefile->WriteString ( database[i].image );
  456.         savefile->WriteString ( database[i].filter );
  457.     }
  458. */
  459.     savefile->WriteInt( secretAreasDiscovered );
  460.  
  461.     savefile->WriteSyncId();
  462. }
  463.  
  464. /*
  465. ==============
  466. idInventory::Restore
  467. ==============
  468. */
  469. void idInventory::Restore( idRestoreGame *savefile ) {
  470.     int i, num;
  471.  
  472.     savefile->ReadInt( maxHealth );
  473.     savefile->ReadInt( weapons );
  474.     savefile->ReadInt( powerups );
  475.     savefile->ReadInt( armor );
  476.     savefile->ReadInt( maxarmor );
  477.  
  478.     for( i = 0; i < MAX_AMMO; i++ ) {
  479.         savefile->ReadInt( ammo[ i ] );
  480.     }
  481.  
  482.     for( i = 0; i < MAX_WEAPONS; i++ ) {
  483.         savefile->ReadInt( clip[ i ] );
  484.         savefile->ReadInt( weaponMods[i] );
  485.     }
  486.  
  487.     for( i = 0; i < POWERUP_MAX; i++ ) {
  488.         savefile->ReadInt( powerupEndTime[ i ] );
  489.     }
  490.  
  491.     savefile->ReadInt( ammoPredictTime );
  492.      savefile->ReadInt( lastGiveTime );
  493.  
  494.     // Load Items
  495.     savefile->ReadInt( num );
  496.     for( i = 0; i < num; i++ ) {
  497.         idDict *itemdict = new idDict;
  498.  
  499.         savefile->ReadDict( itemdict );
  500.         items.Append( itemdict );
  501.     }
  502.  
  503.     // TORESTORE: idStrList                pdas;
  504.     // TORESTORE: idStrList                pdaSecurity;
  505.     // TORESTORE: idStrList                videos;
  506.  
  507.     // Load level triggers
  508.     savefile->ReadInt( num );
  509.     for ( i = 0; i < num; i++ ) {
  510.         idLevelTriggerInfo lti;
  511.         savefile->ReadString( lti.levelName );
  512.         savefile->ReadString( lti.triggerName );
  513.         levelTriggers.Append( lti );
  514.     }
  515.  
  516.     savefile->ReadInt( nextItemPickup );
  517.     savefile->ReadInt( nextItemNum );
  518.     savefile->ReadInt( onePickupTime );
  519.     
  520.     // Load pickup items
  521.     savefile->ReadInt( num );
  522.     for ( i = 0; i < num; i++ ) {
  523.         idItemInfo itemInfo;
  524.         savefile->ReadString( itemInfo.name );
  525.         savefile->ReadString( itemInfo.icon );
  526.         pickupItemNames.Append( itemInfo );
  527.     }
  528.  
  529.     // Load objectives
  530.     savefile->ReadInt( num );
  531.     for( i = 0; i < num; i++ ) {
  532.         idObjectiveInfo obj;
  533.         savefile->ReadString( obj.screenshot );
  534.         savefile->ReadString( obj.text );
  535.         savefile->ReadString( obj.title );
  536.         objectiveNames.Append( obj );
  537.     }
  538. /*
  539.     // Load database
  540.     savefile->ReadInt ( num );
  541.     for ( i = 0; i < num; i++ ) {
  542.         rvDatabaseEntry entry;
  543.         savefile->ReadString ( entry.title );
  544.         savefile->ReadString ( entry.text );
  545.         savefile->ReadString ( entry.image );
  546.         savefile->ReadString ( entry.filter );
  547.         database.Append ( entry );
  548.     }
  549. */
  550.     savefile->ReadInt( secretAreasDiscovered );
  551.  
  552.     savefile->ReadSyncId( "idInventory::Restore" );
  553. }
  554.  
  555. /*
  556. ==============
  557. idInventory::AmmoIndexForAmmoClass
  558. ==============
  559. */
  560. int idInventory::AmmoIndexForAmmoClass( const char *ammo_classname ) const {
  561.     return rvWeapon::GetAmmoIndexForName( ammo_classname );
  562. }
  563.  
  564. /*
  565. ==============
  566. idInventory::MaxAmmoForAmmoClass
  567. ==============
  568. */
  569. int idInventory::MaxAmmoForAmmoClass( idPlayer *owner, const char *ammo_classname ) const {
  570.     return owner->spawnArgs.GetInt( va( "max_%s", ammo_classname ), "0" );
  571. }
  572.  
  573. /*
  574. ==============
  575. idInventory::AmmoIndexForWeaponClass
  576. ==============
  577. */
  578. int idInventory::AmmoIndexForWeaponClass( const char *weapon_classname, int *ammoRequired ) {
  579.     const idDeclEntityDef *decl = gameLocal.FindEntityDef( weapon_classname, false );
  580.     if ( !decl ) {
  581.         gameLocal.Error( "Unknown weapon in decl '%s'", weapon_classname );
  582.     }
  583.     if ( ammoRequired ) {
  584.         *ammoRequired = decl->dict.GetInt( "ammoRequired" );
  585.     }
  586.     return AmmoIndexForAmmoClass( decl->dict.GetString( "ammoType" ) );
  587. }
  588.  
  589. /*
  590. ==============
  591. idInventory::AmmoClassForWeaponClass
  592. ==============
  593. */
  594. const char * idInventory::AmmoClassForWeaponClass( const char *weapon_classname ) {
  595.     const idDeclEntityDef *decl = gameLocal.FindEntityDef( weapon_classname, false );
  596.     if ( !decl ) {
  597.         gameLocal.Error( "Unknown weapon in decl '%s'", weapon_classname );
  598.     }
  599.  
  600.     return decl->dict.GetString( "ammoType" );
  601. }
  602.  
  603. // RAVEN BEGIN
  604. // mekberg: if the player can pick up ammo at this time
  605. /*
  606. ==============
  607. idInventory::DetermineAmmoAvailability
  608. ==============
  609. */
  610. bool idInventory::DetermineAmmoAvailability( idPlayer* owner, const char *ammoName, int ammoIndex, int ammoAmount, int ammoMax ) {
  611.     const idDeclEntityDef *weaponDecl = NULL;
  612.     const idDict*    weaponDict    = NULL;
  613.     const char*        mod            = NULL;
  614.     const idDict*    modDict        = NULL;
  615.     int                weaponIndex    = -1;
  616.     int                clipSize    = 0;    
  617.     int                modClipSize    = 0;    
  618.     int                difference    = 0;
  619.     idStr            realAmmoName( ammoName );
  620.  
  621.     // Early out
  622.     if ( ammo[ ammoIndex ] == ammoMax ) {
  623.         return false;
  624.     }
  625.  
  626.     // Make sure the clip info is updated.
  627.     if ( owner->weapon ) {
  628.         clip[ owner->GetCurrentWeapon( ) ] = owner->weapon->AmmoInClip( );
  629.     }
  630.  
  631.      if ( !idStr::Icmpn( ammoName, "start_ammo_", 11 ) ) {
  632.         realAmmoName.StripLeading( "start_" );
  633.     }
  634.     
  635.     // Find the entityDef for the weapon that uses this ammo.
  636.     for ( int i = 0; i < MAX_WEAPONS; i++ ) {
  637.  
  638.         if ( ! ( weapons & ( 1 << i ) ) ) {
  639.             continue;
  640.         }
  641.  
  642.         weaponDecl = owner->GetWeaponDef( i );
  643.  
  644.         if ( !weaponDecl ) {
  645.             continue;
  646.         }
  647.  
  648.         if ( !idStr::Icmp ( weaponDecl->dict.GetString( "ammoType" ), realAmmoName.c_str() ) ) {
  649.             weaponDict = &( weaponDecl->dict );
  650.             weaponIndex = i;
  651.             break;
  652.         }
  653.     }
  654.  
  655.     // If we didn't find one.
  656.     if ( weaponIndex == -1 ) {
  657.         // If we are picking up ammo and we aren't currently full.
  658.         if ( ammoAmount && ammo[ ammoIndex ] != ammoMax ) {
  659.             ammo[ ammoIndex ] += ammoAmount;
  660.             if ( ammo[ ammoIndex ] > ammoMax ) {
  661.                 ammo[ ammoIndex ] = ammoMax;
  662.             }
  663.             return true;
  664.         }        
  665.         return false;
  666.     }
  667.  
  668.     clipSize = weaponDict->GetInt( "clipSize", "0" );
  669.  
  670.     // Find the weaponmods for this weapon and see if we have any clipsize mods.
  671.     for ( int m = 0; m < MAX_WEAPONMODS; m ++ ) {        
  672.         if ( ! ( weaponMods[ weaponIndex ] & ( 1 << m ) ) ) {
  673.             continue;
  674.         }
  675.  
  676.         mod = weaponDict->GetString ( va ( "def_mod%d" , m + 1 ) );
  677.         if ( !mod || !*mod ) {
  678.             break;
  679.         }
  680.  
  681.         modDict = gameLocal.FindEntityDefDict ( mod, false );
  682.         modClipSize = modDict->GetInt( "clipSize", "0" );
  683.  
  684.         if ( modClipSize > clipSize ) {
  685.             clipSize = modClipSize;
  686.         }                    
  687.     }
  688.     
  689.     // Don't bother with these checks if we don't have a clipsize
  690.     if ( clipSize ) {
  691.         difference = ( ammoMax - clipSize ) - ( ammo[ ammoIndex ] - clip[ weaponIndex ] );
  692.  
  693.         if (  difference  ) {
  694.             if ( ammoAmount  > difference ) {            
  695.                 ammo[ ammoIndex ] += difference;
  696.             } else {
  697.                 ammo[ ammoIndex ] += ammoAmount;
  698.             }
  699.             return true;
  700.         } else {
  701.             return false;
  702.         }
  703.     } else if ( ( ammo[ ammoIndex ] + ammoAmount ) > ammoMax ) {
  704.         ammo[ ammoIndex ] = ammoMax;
  705.     } else {
  706.         ammo[ ammoIndex ] += ammoAmount;
  707.     }    
  708.     return true;
  709. }
  710. // RAVEN END
  711.  
  712.  
  713. /*
  714. ==============
  715. idInventory::AmmoIndexForWeaponIndex
  716. ==============
  717. */
  718. int    idInventory::AmmoIndexForWeaponIndex( int weaponIndex ) {
  719.     if( ammoIndices[ weaponIndex ] == -1 ) {
  720.         const idDict* playerDict = gameLocal.FindEntityDefDict( "player_marine", false );
  721.         if( !playerDict ) {
  722.             gameLocal.Error( "idInventory::AmmoIndexForWeaponIndex() - Can't find player def\n" );
  723.             return -1;
  724.         }
  725.  
  726.         ammoIndices[ weaponIndex ] = AmmoIndexForWeaponClass( playerDict->GetString( va( "def_weapon%d", weaponIndex ) ) );
  727.     }
  728.  
  729.     return ammoIndices[ weaponIndex ];
  730. }
  731.  
  732. /*
  733. ==============
  734. idInventory::StartingAmmoForWeaponIndex
  735. ==============
  736. */
  737. int idInventory::StartingAmmoForWeaponIndex( int weaponIndex ) {
  738.     if( startingAmmo[ weaponIndex ] == -1 ) {
  739.         const idDict* playerDict = gameLocal.FindEntityDefDict( "player_marine", false );
  740.         if( !playerDict ) {
  741.             gameLocal.Error( "idInventory::StartingAmmoForWeaponIndex() - Can't find player def\n" );
  742.             return -1;
  743.         }
  744.  
  745.         const idDict* weaponDict = gameLocal.FindEntityDefDict( playerDict->GetString( va( "def_weapon%d", weaponIndex ) ), false );
  746.         if( !weaponDict ) {
  747.             gameLocal.Warning( "idInventory::StartingAmmoForWeaponIndex() - Unknown weapon '%d'\n", weaponIndex );
  748.             return -1;
  749.         }
  750.  
  751.         const idKeyValue* kv = weaponDict->MatchPrefix( "inv_start_ammo" );
  752.         if( kv == NULL ) {
  753.             startingAmmo[ weaponIndex ] = 1;
  754.         } else {
  755.             startingAmmo[ weaponIndex ] = atoi( kv->GetValue() );
  756.             kv = weaponDict->MatchPrefix( "inv_start_ammo", kv );
  757.             if( kv != NULL ) {
  758.                 gameLocal.Error( "idInventory::StartingAmmoForWeaponIndex() - Weapon dict for player's def_weapon%d has multiple inv_start_ammo entries\n", weaponIndex );
  759.                 return -1;
  760.             }
  761.         }
  762.     }
  763.  
  764.     return startingAmmo[ weaponIndex ];
  765. }
  766.  
  767. /*
  768. ==============
  769. idInventory::AmmoRegenStepForWeaponIndex
  770. ==============
  771. */
  772. int    idInventory::AmmoRegenStepForWeaponIndex( int weaponIndex ) {
  773.     if( ammoRegenStep[ weaponIndex ] == -1 ) {
  774.         const idDict* playerDict = gameLocal.FindEntityDefDict( "player_marine", false );
  775.         if( !playerDict ) {
  776.             gameLocal.Error( "idInventory::AmmoRegenStepForWeaponIndex() - Can't find player def\n" );
  777.             return -1;
  778.         }
  779.  
  780.         const idDict* weaponDict = gameLocal.FindEntityDefDict( playerDict->GetString( va( "def_weapon%d", weaponIndex ) ), false );
  781.         if( !weaponDict ) {
  782.             gameLocal.Warning( "idInventory::AmmoRegenStepForWeaponIndex() - Unknown weapon '%d'\n", weaponIndex );
  783.             return -1;
  784.         }
  785.  
  786.         ammoRegenStep[ weaponIndex ] = weaponDict->GetInt( "ammoRegenStep", "1" );
  787.     }
  788.  
  789.     return ammoRegenStep[ weaponIndex ];
  790. }
  791.  
  792. /*
  793. ==============
  794. idInventory::AmmoRegenTimeForAmmoIndex
  795. ==============
  796. */
  797. int    idInventory::AmmoRegenTimeForWeaponIndex( int weaponIndex ) {
  798.     if ( ammoRegenTime[ weaponIndex ] == -1 ) {
  799.         const idDict* playerDict = gameLocal.FindEntityDefDict( "player_marine", false );
  800.         if( !playerDict ) {
  801.             gameLocal.Error( "idInventory::AmmoRegenTimeForWeaponIndex() - Can't find player def\n" );
  802.             return -1;
  803.         }
  804.  
  805.         const idDict* weaponDict = gameLocal.FindEntityDefDict( playerDict->GetString( va( "def_weapon%d", weaponIndex ) ), false );
  806.         if( !weaponDict ) {
  807.             gameLocal.Warning( "idInventory::AmmoRegenTimeForWeaponIndex() - Unknown weapon '%d'\n", weaponIndex );
  808.             return -1;
  809.         }
  810.  
  811.         ammoRegenTime[ weaponIndex ] = weaponDict->GetInt( "ammoRegenTime", "1" );
  812.     }
  813.  
  814.     return ammoRegenTime[ weaponIndex ];
  815. }
  816.  
  817.  
  818. /*
  819. ==============
  820. idInventory::Give
  821. ==============
  822. */
  823. bool idInventory::Give( idPlayer *owner, const idDict &spawnArgs, const char *statname, const char *value, int *idealWeapon, bool updateHud, bool dropped ) {
  824.     int                        i;
  825.     const char                *pos;
  826.     const char                *end;
  827.     int                        len;
  828.     idStr                    weaponString;
  829.     int                        max;
  830.     int                        amount;
  831.  
  832.     if ( !idStr::Icmpn( statname, "ammo_", 5 ) ) {
  833.         i = AmmoIndexForAmmoClass( statname );
  834.         max = MaxAmmoForAmmoClass( owner, statname );
  835.         amount = atoi( value );
  836.  
  837. // RAVEN BEGIN
  838. // mekberg: check max ammo vs clipsize when picking up ammo
  839.         if ( !gameLocal.IsMultiplayer ( ) ) {
  840.             return DetermineAmmoAvailability ( owner, statname, i, amount, max );    
  841.         } else if ( ammo[ i ] >= max ) {
  842.             return false;
  843.         }
  844.  
  845.         if ( amount ) {            
  846.             ammo[ i ] += amount;
  847.             if ( ( max > 0 ) && ( ammo[ i ] > max ) ) {
  848.                 ammo[ i ] = max;
  849.             }
  850.         }
  851. // RAVEN END
  852.     } else if ( !idStr::Icmpn( statname, "start_ammo_", 11 ) ) {
  853.         // starting ammo gives only if current ammo is below it
  854.         idStr ammoname( statname );
  855.         ammoname.StripLeading( "start_" );
  856.         i = AmmoIndexForAmmoClass( ammoname.c_str() );
  857.         max = MaxAmmoForAmmoClass( owner, ammoname.c_str() );
  858.         amount = atoi( value );
  859.  
  860. // RAVEN BEGIN
  861. // mekberg: check max ammo vs clipsize when picking up ammo
  862.         if ( !gameLocal.IsMultiplayer ( ) ) {
  863.             return DetermineAmmoAvailability ( owner, statname, i, amount, max );
  864.         } else if ( amount ) {    
  865.             if ( ammo[ i ] >= amount ) {
  866.                 amount = 1;
  867.             } else {
  868.                 amount = amount - ammo[ i ];
  869.             }
  870.         }
  871.  
  872.         if ( amount ) {            
  873.             ammo[ i ] += amount;
  874.             if ( ( max > 0 ) && ( ammo[ i ] > max ) ) {
  875.                 ammo[ i ] = max;
  876.             }
  877.         }
  878. // RAVEN END
  879.     } else if ( !idStr::Icmp( statname, "armor" ) ) {
  880.         if ( armor >= maxarmor * 2 ) {
  881.             return false;
  882.         }
  883.     } else     if ( !idStr::Icmp( statname, "health" ) ) {
  884.         if ( owner->health >= maxHealth ) {
  885.             return false;
  886.         }
  887.     } else if ( idStr::FindText( statname, "inclip_" ) == 0 ) {
  888.         i = owner->SlotForWeapon ( statname + 7 );
  889.         if ( i != -1 ) {
  890.             // set, don't add. not going over the clip size limit.
  891.             clip[ i ] = atoi( value );
  892.         }
  893.     } else if ( !idStr::Icmp( statname, "quad" ) ) {
  894.         GivePowerUp( owner, POWERUP_QUADDAMAGE, SEC2MS( atof( value ) ) );
  895.     } else if ( !idStr::Icmp( statname, "regen" ) ) {
  896.         GivePowerUp( owner, POWERUP_REGENERATION, SEC2MS( atof( value ) ) );
  897.     } else if ( !idStr::Icmp( statname, "haste" ) ) {
  898.         GivePowerUp( owner, POWERUP_HASTE, SEC2MS( atof( value ) ) );
  899.     } else if( !idStr::Icmp( statname, "ammoregen" ) ) {
  900.         GivePowerUp( owner, POWERUP_AMMOREGEN, -1 );
  901.     } else if ( !idStr::Icmp( statname, "weapon" ) ) {
  902.         bool tookWeapon = false;
  903.          for( pos = value; pos != NULL; pos = end ) {
  904.             end = strchr( pos, ',' );
  905.             if ( end ) {
  906.                 len = end - pos;
  907.                 end++;
  908.             } else {
  909.                 len = strlen( pos );
  910.             }
  911.  
  912.             idStr weaponName( pos, 0, len );
  913.  
  914.             // find the number of the matching weapon names
  915.             i = owner->SlotForWeapon ( weaponName );
  916. // RAVEN BEGIN
  917. // mekberg: check for not found weapons
  918.             if ( i == -1 ) {
  919.                 gameLocal.Warning( "Unknown weapon '%s'", weaponName.c_str() );
  920.                 return false;
  921.             }
  922. // RAVEN END
  923.  
  924.              if ( gameLocal.isMultiplayer 
  925.                 && ( weapons & ( 1 << i ) ) ) {
  926.                 //already have this weapon
  927.                 if ( !dropped ) {
  928.                     //a placed weapon item
  929.                     if ( gameLocal.serverInfo.GetBool( "si_weaponStay" ) ) {
  930.                         //don't pick up weapons at all if you already have them...
  931.                         continue;
  932.                     }
  933.                 }
  934.                 // don't pickup "no ammo" weapon types twice
  935.                  // not for singleplayer.. there is only one case in the game where you can get a no ammo
  936.                  // weapon when you might already have it, in that case it is more consistent to pick it up
  937.                 // cache the media for this weapon
  938.                 const idDict* dict;
  939.                 dict = &owner->GetWeaponDef ( i )->dict;
  940.                 if ( dict && !dict->GetInt( "ammoRequired" ) ) {
  941.                     continue;
  942.                 }
  943.             }
  944.  
  945.              if ( !gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) || ( weaponName == "weapon_fists" ) ) {
  946.                  if ( ( weapons & ( 1 << i ) ) == 0 || gameLocal.isMultiplayer ) {
  947.                      if ( owner->GetUserInfo()->GetBool( "ui_autoSwitch" ) && idealWeapon ) {
  948.                          assert( !gameLocal.isClient );
  949.                          *idealWeapon = i;
  950.                      } 
  951.                      if ( owner->hud && updateHud && lastGiveTime + 1000 < gameLocal.time ) {
  952.                          owner->hud->SetStateInt( "newWeapon", i );
  953.                          owner->hud->HandleNamedEvent( "newWeapon" );
  954.                          lastGiveTime = gameLocal.time;
  955.                      }
  956.                      weapons |= ( 1 << i );
  957.                      tookWeapon = true;
  958.                  }
  959.               }
  960.         }
  961.         return tookWeapon;
  962.     } else if ( !idStr::Icmp( statname, "item" ) || !idStr::Icmp( statname, "icon" ) || !idStr::Icmp( statname, "name" ) ) {
  963.         // ignore these as they're handled elsewhere
  964.         return false;
  965.     } else {
  966.         // unknown item
  967.         gameLocal.Warning( "Unknown stat '%s' added to player's inventory", statname );
  968.         return false;
  969.     }
  970.  
  971.     return true;
  972. }
  973.  
  974. /*
  975. ===============
  976. idInventoy::Drop
  977. ===============
  978. */
  979. void idInventory::Drop( const idDict &spawnArgs, const char *weapon_classname, int weapon_index ) {
  980.     // remove the weapon bit
  981.     // also remove the ammo associated with the weapon as we pushed it in the item
  982.     assert( weapon_index != -1 || weapon_classname );
  983.     if ( weapon_index == -1 ) {
  984.         for( weapon_index = 0; weapon_index < MAX_WEAPONS; weapon_index++ ) {
  985.             if ( !idStr::Icmp( weapon_classname, spawnArgs.GetString( va( "def_weapon%d", weapon_index ) ) ) ) {
  986.                 break;
  987.             }
  988.         }
  989.  
  990.         if ( weapon_index >= MAX_WEAPONS ) {
  991.             gameLocal.Error( "Unknown weapon '%s'", weapon_classname );
  992.         }
  993.     } else if ( !weapon_classname ) {
  994.         weapon_classname = spawnArgs.GetString( va( "def_weapon%d", weapon_index ) );
  995.     }
  996.     weapons &= ( 0xffffffff ^ ( 1 << weapon_index ) );
  997.     int ammo_i = AmmoIndexForWeaponClass( weapon_classname, NULL );
  998.     if ( ammo_i ) {
  999.         clip[ weapon_index ] = -1;
  1000.         ammo[ ammo_i ] = 0;
  1001.     }
  1002.  
  1003.     weaponMods[weapon_index] = 0;
  1004. }
  1005.  
  1006. /*
  1007. ===============
  1008. idInventory::HasAmmo
  1009. ===============
  1010. */
  1011. int idInventory::HasAmmo( int index, int amount ) {
  1012.     if ( ( index == 0 ) || !amount ) {
  1013.         // always allow weapons that don't use ammo to fire
  1014.         return -1;
  1015.     }
  1016.  
  1017.     // check if we have infinite ammo
  1018.     if ( ammo[ index ] < 0 ) {
  1019.         return -1;
  1020.     }
  1021.  
  1022.     // return how many shots we can fire
  1023.     return ammo[ index ] / amount;
  1024. }
  1025.  
  1026. /*
  1027. ===============
  1028. idInventory::HasAmmo
  1029. ===============
  1030. */
  1031. int idInventory::HasAmmo( const char *weapon_classname ) {
  1032.     int ammoRequired;
  1033.     int index;
  1034.     index = AmmoIndexForWeaponClass( weapon_classname, &ammoRequired );
  1035.     return HasAmmo( index, ammoRequired );
  1036. }
  1037.  
  1038. /*
  1039. ===============
  1040. idInventory::UseAmmo
  1041. ===============
  1042. */
  1043. bool idInventory::UseAmmo( int index, int amount ) {
  1044.     if ( !HasAmmo( index, amount ) ) {
  1045.         return false;
  1046.     }
  1047.  
  1048.     // take an ammo away if not infinite
  1049.     if ( ammo[ index ] >= 0 ) {
  1050.         ammo[ index ] -= amount;
  1051.          ammoPredictTime = gameLocal.time; // mp client: we predict this. mark time so we're not confused by snapshots
  1052.     }
  1053.  
  1054.     return true;
  1055. }
  1056.  
  1057. /*
  1058. ==============
  1059. idPlayer::idPlayer
  1060. ==============
  1061. */
  1062. idPlayer::idPlayer() {
  1063.     memset( &usercmd, 0, sizeof( usercmd ) );
  1064.  
  1065.     doInitWeapon            = false;
  1066.     noclip                    = false;
  1067.     godmode                    = false;
  1068.     undying                    = g_forceUndying.GetBool() ? !gameLocal.isMultiplayer : false;
  1069.  
  1070.     spawnAnglesSet            = false;
  1071.     spawnAngles                = ang_zero;
  1072.     viewAngles                = ang_zero;
  1073.     deltaViewAngles            = ang_zero;
  1074.     cmdAngles                = ang_zero;
  1075.  
  1076.     demoViewAngleTime        = 0;
  1077.     demoViewAngles            = ang_zero;
  1078.  
  1079. // RAVEN BEGIN
  1080. // mwhitlock: Xenon texture streaming.
  1081. #if defined(_XENON)
  1082.     streamingPrecache        = false;
  1083. #endif
  1084. // RAVEN END
  1085.  
  1086.     oldButtons                = 0;
  1087.     buttonMask                = 0;
  1088.     oldFlags                = 0;
  1089.  
  1090.     lastHitTime                = 0;
  1091.      lastSndHitTime            = 0;
  1092.     lastSavingThrowTime        = 0;
  1093.  
  1094.     weapon                    = NULL;
  1095.  
  1096.     hud                        = NULL;
  1097.     mphud                    = NULL;
  1098.     objectiveSystem            = NULL;
  1099.     objectiveSystemOpen        = false;
  1100.     showNewObjectives        = false;
  1101. #ifdef _XENON
  1102.     g_ObjectiveSystemOpen    = false;
  1103. #endif
  1104.     objectiveButtonReleased = false;
  1105.     cinematicHud            = NULL;
  1106.  
  1107.     overlayHud                = NULL;
  1108.     overlayHudTime            = 0;
  1109.  
  1110.     lastDmgTime                = 0;
  1111.     deathClearContentsTime    = 0;
  1112.     nextHealthPulse            = 0;
  1113.  
  1114.     scoreBoardOpen            = false;
  1115.     forceScoreBoard            = false;
  1116.     forceScoreBoardTime        = 0;
  1117.     forceRespawn            = false;
  1118.     spectating                = false;
  1119.     spectator                = 0;
  1120.     forcedReady                = false;
  1121.     wantSpectate            = false;
  1122.  
  1123.     lastHitToggle            = false;
  1124.     lastArmorHit            = false;
  1125.  
  1126.     minRespawnTime            = 0;
  1127.     maxRespawnTime            = 0;
  1128.  
  1129.     firstPersonViewOrigin    = vec3_zero;
  1130.     firstPersonViewAxis        = mat3_identity;
  1131.  
  1132.     hipJoint                = INVALID_JOINT;
  1133.     chestJoint                = INVALID_JOINT;
  1134.      headJoint                = INVALID_JOINT;
  1135.  
  1136.     bobFoot                    = 0;
  1137.     bobFrac                    = 0.0f;
  1138.     bobfracsin                = 0.0f;
  1139.     bobCycle                = 0;
  1140.     xyspeed                    = 0.0f;
  1141.     stepUpTime                = 0;
  1142.     stepUpDelta                = 0.0f;
  1143.     idealLegsYaw            = 0.0f;
  1144.     legsYaw                    = 0.0f;
  1145.      legsForward                = true;
  1146.     oldViewYaw                = 0.0f;
  1147.     viewBobAngles            = ang_zero;
  1148.     viewBob                    = vec3_zero;
  1149.     landChange                = 0;
  1150.     landTime                = 0;
  1151.  
  1152.     currentWeapon            = -1;
  1153.     idealWeapon                = -1;
  1154.     previousWeapon            = -1;
  1155.     weaponSwitchTime        =  0;
  1156.     weaponEnabled            = true;
  1157.      showWeaponViewModel        = true;
  1158.     oldInventoryWeapons        = 0;
  1159.  
  1160. // RAVEN BEGIN
  1161. // mekberg: allow disabling of objectives during non-cinematic time periods
  1162.     objectivesEnabled = true;
  1163. // RAVEN END
  1164.  
  1165.     skin                    = NULL;
  1166.     weaponViewSkin            = NULL;
  1167.     headSkin                = NULL;
  1168.     powerUpSkin                = NULL;
  1169.  
  1170.     numProjectilesFired        = 0;
  1171.     numProjectileHits        = 0;
  1172.  
  1173.     airless                    = false;
  1174.     airTics                    = 0;
  1175.     lastAirDamage            = 0;
  1176.  
  1177.     gibDeath                = false;
  1178.     gibsLaunched            = false;
  1179.     gibDir                    = vec3_zero;
  1180.  
  1181.     centerView.Init( 0, 0, 0, 0 );
  1182.     fxFov                    = false;
  1183.  
  1184.     influenceFov            = 0;
  1185.     influenceActive            = 0;
  1186.     influenceRadius            = 0.0f;
  1187.     influenceEntity            = NULL;
  1188.     influenceMaterial        = NULL;
  1189.      influenceSkin            = NULL;
  1190.  
  1191.     privateCameraView        = NULL;
  1192.  
  1193.     memset( loggedViewAngles, 0, sizeof( loggedViewAngles ) );
  1194.     memset( loggedAccel, 0, sizeof( loggedAccel ) );
  1195.     currentLoggedAccel    = 0;
  1196.  
  1197.     focusTime                = 0;
  1198.     focusUI                    = NULL;
  1199.     focusEnt                = NULL;
  1200.     focusType                = FOCUS_NONE;
  1201.     focusBrackets            = NULL;
  1202.     focusBracketsTime        = 0;
  1203.  
  1204.     talkingNPC                = NULL;
  1205.  
  1206.     cursor                    = NULL;
  1207.      talkCursor                = 0;
  1208.     
  1209.     oldMouseX                = 0;
  1210.     oldMouseY                = 0;
  1211.  
  1212.     lastDamageDef            = 0;
  1213.     lastDamageDir            = vec3_zero;
  1214.     lastDamageLocation        = 0;
  1215.  
  1216.     predictedFrame            = 0;
  1217.     predictedOrigin            = vec3_zero;
  1218.     predictedAngles            = ang_zero;
  1219.     predictedUpdated        = false;
  1220.     predictionOriginError    = vec3_zero;
  1221.     predictionAnglesError    = ang_zero;
  1222.     predictionErrorTime        = 0;
  1223.  
  1224.     fl.networkSync            = true;
  1225.  
  1226.     latchedTeam                = -1;
  1227.      doingDeathSkin            = false;
  1228.      weaponGone                = false;
  1229.      useInitialSpawns        = false;
  1230.     lastSpectateTeleport    = 0;
  1231.     hiddenWeapon            = false;
  1232.     tipUp                    = false;
  1233.     objectiveUp                = false;
  1234.      teleportEntity            = NULL;
  1235.     teleportKiller            = -1;
  1236.     lastKiller                = NULL;
  1237.  
  1238.      respawning                = false;
  1239.      ready                    = false;
  1240.      leader                    = false;
  1241.      lastSpectateChange        = 0;
  1242.     lastArenaChange            = 0;
  1243.      lastTeleFX                = -9999;
  1244.  
  1245.      weaponCatchup            = false;
  1246.      lastSnapshotSequence    = 0;
  1247.  
  1248.      aimClientNum            = -1;
  1249.  
  1250.      spawnedTime                = 0;
  1251.  
  1252.      isTelefragged            = false;
  1253.     isLagged                = false;
  1254.      isChatting                = false;
  1255.  
  1256.     intentDir.Zero();
  1257.     aasSensor = rvAASTacticalSensor::CREATE_SENSOR(this);
  1258.  
  1259.     zoomFov.Init ( 0, 0, DefaultFov(), DefaultFov() );
  1260.     zoomed                    = false;
  1261.     
  1262.     memset ( cachedWeaponDefs, 0, sizeof(cachedWeaponDefs) );
  1263.     memset ( cachedPowerupDefs, 0, sizeof(cachedPowerupDefs) );
  1264.  
  1265.     lastImpulsePlayer = NULL;
  1266.     lastImpulseTime = gameLocal.time;
  1267.  
  1268.     weaponChangeIconsUp = false;
  1269.  
  1270.     reloadModel = false;
  1271.     modelDict = NULL;
  1272.  
  1273.     disableHud = false;
  1274.  
  1275.     mutedPlayers = 0;
  1276.     friendPlayers = 0;
  1277.     connectTime = 0;
  1278.     rank = -1;
  1279.     arena = 0;
  1280.  
  1281.     memset( nextAmmoRegenPulse, 0, sizeof( int ) * MAX_AMMO );
  1282.  
  1283.     spectator = 0;
  1284.  
  1285.     quadOverlay = NULL;
  1286.     hasteOverlay = NULL;
  1287.     regenerationOverlay = NULL;
  1288.     invisibilityOverlay = NULL;
  1289.     powerUpOverlay = NULL;
  1290.  
  1291.     tourneyStatus = PTS_UNKNOWN;
  1292.     
  1293.     vsMsgState = false;
  1294.  
  1295.     deathSkinTime = 0;
  1296.  
  1297.     jumpDuringHitch = false;
  1298. }
  1299. /*
  1300. ==============
  1301. idPlayer::SetShowHud
  1302. ==============
  1303. */
  1304. void idPlayer::SetShowHud( bool showHud )    {
  1305.     disableHud = !showHud;
  1306. }
  1307.  
  1308. /*
  1309. ==============
  1310. idPlayer::SetShowHud
  1311. ==============
  1312. */
  1313. bool idPlayer::GetShowHud( void )    {
  1314.     return !disableHud;
  1315. }
  1316.  
  1317. /*
  1318. ==============
  1319. idPlayer::SetWeapon
  1320. ==============
  1321. */
  1322. void idPlayer::SetWeapon( int weaponIndex ) {
  1323.     if ( weapon && weaponIndex == currentWeapon ) {
  1324.         return;
  1325.     }
  1326.     
  1327.     // Clear the weapon entity
  1328.     delete weapon;
  1329.     weapon = NULL;
  1330.  
  1331.     previousWeapon    = currentWeapon;
  1332.     currentWeapon    = weaponIndex;
  1333.     weaponGone        = false;        
  1334.  
  1335.     if ( weaponIndex < 0 ) {
  1336.         weaponGone = true;
  1337.         return;
  1338.     }
  1339.     
  1340.     animPrefix = spawnArgs.GetString( va( "def_weapon%d", currentWeapon ) );
  1341.  
  1342.     idTypeInfo*    typeInfo;
  1343.     weaponDef = GetWeaponDef( currentWeapon );
  1344.     if ( !weaponDef ) {
  1345.         gameLocal.Error( "Weapon definition not found for weapon %d", currentWeapon ) ;
  1346.     }
  1347.     typeInfo = idClass::GetClass( weaponDef->dict.GetString( "weaponclass", "rvWeapon" ) );
  1348.     if ( !typeInfo || !typeInfo->IsType( rvWeapon::GetClassType() ) ) {
  1349.         gameLocal.Error( "Invalid weapon class '%s' specified for weapon '%s'", animPrefix.c_str(), weaponDef->dict.GetString ( "weaponclass", "rvWeapon" ) );
  1350.     }
  1351.     weapon = static_cast<rvWeapon*>( typeInfo->CreateInstance() );
  1352.     weapon->Init( this, weaponDef, currentWeapon, isStrogg );
  1353.     weapon->CallSpawn( );
  1354.  
  1355.     // Reset the zoom fov on weapon change
  1356.     if ( zoomed ) {
  1357.         zoomFov.Init ( gameLocal.time, 100, CalcFov(true), DefaultFov() );
  1358.         zoomed = false;
  1359.     }                
  1360.  
  1361.     UpdateHudWeapon();
  1362.  
  1363.     // Remove the "weapon_" from the anim prefect for the player world anims
  1364.     animPrefix.Strip( "weapon_" );
  1365.     
  1366.     // Make sure weapon is hidden
  1367.     if ( !weaponEnabled ) {
  1368.         Event_DisableWeapon( );
  1369.     }
  1370. }
  1371.  
  1372. /*
  1373. ==============
  1374. idPlayer::SetupWeaponEntity
  1375. ==============
  1376. */
  1377. void idPlayer::SetupWeaponEntity( void ) {
  1378.     int w;
  1379.     const char* weap;
  1380.     
  1381.     // don't setup weapons for spectators
  1382.     if ( gameLocal.isClient || (weaponViewModel && weaponWorldModel) || spectating ) {
  1383.         return;
  1384.     }
  1385.     
  1386.     if ( !weaponViewModel ) {
  1387.         // setup the view model
  1388. // RAVEN BEGIN
  1389. // jnewquist: Use accessor for static class type 
  1390.         weaponViewModel = static_cast<rvViewWeapon*>( gameLocal.SpawnEntityType( rvViewWeapon::GetClassType(), NULL ) );
  1391.         weaponViewModel->SetName( va("%s_weapon", name.c_str() ) );
  1392.         weaponViewModel->SetInstance( instance );
  1393.     }
  1394.     
  1395.             
  1396.     if ( !weaponWorldModel ) {
  1397.         // setup the world model
  1398.         weaponWorldModel = static_cast<idAnimatedEntity*>( gameLocal.SpawnEntityType( idAnimatedEntity::GetClassType(), NULL ) );
  1399. // RAVEN END
  1400.         weaponWorldModel->fl.networkSync = true;
  1401.         weaponWorldModel->SetName ( va("%s_weapon_world", name.c_str() ) );
  1402.         weaponWorldModel->SetInstance( instance );
  1403.     }
  1404.     
  1405.     currentWeapon = -1;
  1406.  
  1407.     weaponWorldModel->fl.persistAcrossInstances = true;
  1408.     weaponViewModel->fl.persistAcrossInstances = true;
  1409.  
  1410.      for( w = 0; w < MAX_WEAPONS; w++ ) {
  1411.          weap = spawnArgs.GetString( va( "def_weapon%d", w ) );
  1412.          if ( weap && *weap ) {
  1413.              rvWeapon::CacheWeapon( weap );
  1414.          }
  1415.      }
  1416. }
  1417.  
  1418. /*
  1419. ==============
  1420. idPlayer::Init
  1421. ==============
  1422. */
  1423. void idPlayer::Init( void ) {
  1424.     const char            *value;
  1425.  
  1426.     noclip                    = false;
  1427.     godmode                    = false;
  1428.     godmodeDamage            = 0;
  1429.     undying                    = g_forceUndying.GetBool() ? !gameLocal.isMultiplayer : false;
  1430.  
  1431.     oldButtons                = 0;
  1432.     oldFlags                = 0;
  1433.  
  1434.     currentWeapon            = -1;
  1435.     idealWeapon                = -1;
  1436.     previousWeapon            = -1;
  1437.     weaponSwitchTime        = 0;
  1438.     weaponEnabled            = true;
  1439.      showWeaponViewModel        = GetUserInfo()->GetBool( "ui_showGun" );
  1440.     oldInventoryWeapons        = 0;
  1441.  
  1442.     lastDmgTime                = 0;
  1443.     
  1444.     bobCycle                = 0;
  1445.     bobFrac                    = 0.0f;
  1446.     landChange                = 0;
  1447.     landTime                = 0;
  1448.     zoomFov.Init( 0, 0, 0, 0 );
  1449.     centerView.Init( 0, 0, 0, 0 );
  1450.     fxFov                    = false;
  1451.  
  1452.     influenceFov            = 0;
  1453.     influenceActive            = 0;
  1454.     influenceRadius            = 0.0f;
  1455.     influenceEntity            = NULL;
  1456.     influenceMaterial        = NULL;
  1457.      influenceSkin            = NULL;
  1458.  
  1459.     currentLoggedAccel        = 0;
  1460.  
  1461.     focusTime                = 0;
  1462.     focusUI                    = NULL;
  1463.     focusEnt                = NULL;
  1464.     focusType                = FOCUS_NONE;
  1465.     focusBrackets            = NULL;
  1466.     focusBracketsTime        = 0;
  1467.     
  1468.     talkingNPC                = NULL;
  1469.      talkCursor                = 0;
  1470.  
  1471.     lightningEffects        = 0;
  1472.     lightningNextTime        = 0;
  1473.  
  1474.     modelName                = idStr();
  1475.  
  1476.     // Remove any hearing loss that may be set up from the last map
  1477.     soundSystem->FadeSoundClasses( SOUNDWORLD_GAME, 0, 0.0f, 0 );
  1478.     
  1479.     // remove any damage effects
  1480.     playerView.ClearEffects();
  1481.  
  1482.     // damage values
  1483.     fl.takedamage            = true;
  1484.     ClearPain();
  1485.  
  1486.     // restore persistent data
  1487.     RestorePersistantInfo();
  1488.  
  1489.     bobCycle    = 0;
  1490.  
  1491.     SetupWeaponEntity( );
  1492.     currentWeapon = -1;
  1493.     previousWeapon = -1;
  1494.     
  1495.     flashlightOn      = false;
  1496.  
  1497.     idealLegsYaw = 0.0f;
  1498.     legsYaw = 0.0f;
  1499.     legsForward = true;
  1500.     oldViewYaw = 0.0f;
  1501.  
  1502. // RAVEN BEGIN
  1503. // abahr: need to init this
  1504.     vehicleCameraDist = 0.0f;
  1505.  
  1506. // mekberg: moved into function.
  1507.     SetPMCVars( );    
  1508. // RAVEN END
  1509.  
  1510.     // air always initialized to maximum too
  1511.     airTics = pm_airTics.GetFloat();
  1512.     airless = false;
  1513.  
  1514.     gibDeath = false;
  1515.     gibsLaunched = false;
  1516.     gibDir.Zero();
  1517.  
  1518. // RAVEN BEGIN
  1519. // abahr: changed to GetCurrentGravity
  1520.     // set the gravity
  1521.     physicsObj.SetGravity( gameLocal.GetCurrentGravity(this) );
  1522. // RAVEN END
  1523.  
  1524.     // start out standing
  1525.     SetEyeHeight( pm_normalviewheight.GetFloat() );
  1526.  
  1527.     stepUpTime = 0;
  1528.     stepUpDelta = 0.0f;
  1529.     viewBobAngles.Zero();
  1530.     viewBob.Zero();
  1531.  
  1532.     if( gameLocal.isMultiplayer && gameLocal.IsTeamGame() ) {
  1533.         value = spawnArgs.GetString( va( "model_%s", team ? "strogg" : "marine" ), NULL );
  1534.     }
  1535.     else {
  1536.         value = spawnArgs.GetString( "model" );
  1537.     }
  1538.  
  1539.     if( gameLocal.isMultiplayer ) {
  1540.         UpdateModelSetup( true );
  1541.     } else {
  1542.         if ( value && ( *value != 0 ) ) {
  1543.             SetModel( value );
  1544.         }
  1545.         // check head
  1546.         if( idStr::Icmp( head ? head->spawnArgs.GetString( "classname", "" ) : "", spawnArgs.GetString( "def_head", "" ) ) ) {
  1547.             SetupHead();
  1548.         }
  1549.     }
  1550.  
  1551.     if ( cursor ) {
  1552.          cursor->SetStateInt( "talkcursor", 0 );
  1553.         cursor->HandleNamedEvent( "showCrossCombat" );
  1554.     }
  1555.  
  1556.     if ( !gameLocal.isMultiplayer ) {
  1557.         if ( g_testDeath.GetBool() && skin ) {
  1558.             SetSkin( skin );
  1559.             renderEntity.shaderParms[6] = 0.0f;
  1560.         } else if ( spawnArgs.GetString( "spawn_skin", NULL, &value ) ) {
  1561.             skin = declManager->FindSkin( value );
  1562.             SetSkin( skin );
  1563.             renderEntity.shaderParms[6] = 0.0f;
  1564.         }
  1565.     } else {
  1566.         SetSkin( skin );
  1567.         if( head ) {
  1568.             head->SetSkin( headSkin );
  1569.             if( head->GetModelDefHandle() > 0) {
  1570.                 gameRenderWorld->RemoveDecals(     head->GetModelDefHandle() );
  1571.             }
  1572.         }
  1573.  
  1574.         if( weaponViewModel ) {
  1575.             weaponViewModel->SetSkin( weaponViewSkin );
  1576.         }
  1577.     }
  1578.  
  1579.      value = spawnArgs.GetString( "joint_hips", "" );
  1580.      hipJoint = animator.GetJointHandle( value );
  1581.      if ( hipJoint == INVALID_JOINT ) {
  1582.          gameLocal.Error( "Joint '%s' not found for 'joint_hips' on '%s'", value, name.c_str() );
  1583.      }
  1584.  
  1585.      value = spawnArgs.GetString( "joint_chest", "" );
  1586.      chestJoint = animator.GetJointHandle( value );
  1587.      if ( chestJoint == INVALID_JOINT ) {
  1588.          gameLocal.Error( "Joint '%s' not found for 'joint_chest' on '%s'", value, name.c_str() );
  1589.      }
  1590.  
  1591.      value = spawnArgs.GetString( "joint_head", "" );
  1592.      headJoint = animator.GetJointHandle( value );
  1593.      if ( headJoint == INVALID_JOINT ) {
  1594.          gameLocal.Error( "Joint '%s' not found for 'joint_head' on '%s'", value, name.c_str() );
  1595.      }
  1596.  
  1597.     // initialize the script variables
  1598.     memset ( &pfl, 0, sizeof( pfl ) );
  1599.     pfl.onGround = true;
  1600.     pfl.noFallingDamage = false;
  1601.  
  1602.     // Start in idle
  1603.     SetAnimState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
  1604.     SetAnimState( ANIMCHANNEL_LEGS, "Legs_Idle", 0 );
  1605.     
  1606.     forceScoreBoard        = false;
  1607.     forceScoreBoardTime = 0;
  1608.     forcedReady            = false;
  1609.  
  1610.     privateCameraView    = NULL;
  1611.  
  1612.     lastSpectateChange    = 0;
  1613.     lastArenaChange        = 0;
  1614.      lastTeleFX            = -9999;
  1615.  
  1616.     hiddenWeapon        = false;
  1617.     tipUp                = false;
  1618.     objectiveUp            = false;
  1619.      teleportEntity        = NULL;
  1620.     lastKiller            = NULL;
  1621.     teleportKiller        = -1;
  1622.      leader                = false;
  1623.  
  1624.      SetPrivateCameraView( NULL );
  1625.  
  1626.      lastSnapshotSequence    = 0;
  1627.  
  1628.     isStrogg = spawnArgs.GetBool ( "strogg", "0" );
  1629.  
  1630.      aimClientNum        = -1;
  1631.     if( mphud ) {
  1632.         mphud->HandleNamedEvent( "aim_fade" );
  1633.     }
  1634.  
  1635.      isChatting = false;
  1636.  
  1637.     SetInitialHud();
  1638.  
  1639.     emote = PE_NONE;
  1640.  
  1641.     powerupEffectTime   = 0;
  1642.     powerupEffect        = NULL;
  1643.     powerupEffectType    = 0;
  1644.     hasteEffect            = NULL;
  1645.     flagEffect            = NULL;
  1646.         
  1647.     quadOverlay            = declManager->FindMaterial( spawnArgs.GetString( "mtr_quaddamage_overlay" ), false );
  1648.     hasteOverlay        = declManager->FindMaterial( spawnArgs.GetString( "mtr_haste_overlay" ), false );
  1649.     regenerationOverlay = declManager->FindMaterial( spawnArgs.GetString( "mtr_regeneration_overlay" ), false );
  1650.     invisibilityOverlay = declManager->FindMaterial( spawnArgs.GetString( "mtr_invisibility_overlay" ), false );
  1651.     powerUpOverlay        = NULL;
  1652.  
  1653.     if( gameLocal.isMultiplayer && entityNumber == gameLocal.localClientNum ) {
  1654.         if( (gameLocal.mpGame.GetGameState()->GetMPGameState() != WARMUP) && gameLocal.mpGame.GetGameState()->GetMPGameState() != SUDDENDEATH ){
  1655.             if( gameLocal.gameType != GAME_TOURNEY || ((rvTourneyGameState*)(gameLocal.mpGame.GetGameState()))->GetArena( arena ).GetState() != AS_WARMUP && ((rvTourneyGameState*)(gameLocal.mpGame.GetGameState()))->GetArena( arena ).GetState() != AS_SUDDEN_DEATH )  {
  1656.                 // don't clear notices while in warmup modes or sudden death
  1657.                 GUIMainNotice( "" );
  1658.                 GUIFragNotice( "" );
  1659.             }
  1660.         }
  1661.  
  1662.         if ( (gameLocal.mpGame.GetGameState()->GetMPGameState() == WARMUP) && vsMsgState ) {
  1663.             GUIMainNotice( "" );
  1664.             GUIFragNotice( "" );
  1665.         }
  1666.     }
  1667.     
  1668.     deathSkinTime        = 0;
  1669.     deathStateHitch        = false;
  1670. // mwhitlock: Xenon texture streaming.
  1671. #if defined(_XENON)
  1672.     // Force precaching.
  1673.     streamingPrecache=true;
  1674. #endif
  1675.  
  1676.     jumpDuringHitch = false;
  1677. }
  1678.  
  1679. /*
  1680. ===============
  1681. idPlayer::GetCursorGUI
  1682. ===============
  1683. */
  1684. idUserInterface* idPlayer::GetCursorGUI( void ) {
  1685.     idStr temp;
  1686.  
  1687.     assert( !gameLocal.isMultiplayer || gameLocal.localClientNum == entityNumber );
  1688.     if ( cursor ) {
  1689.         return cursor;
  1690.     }
  1691.     if ( spawnArgs.GetString( "cursor", "", temp ) ) {
  1692.         cursor = uiManager->FindGui( temp, true, gameLocal.isMultiplayer, gameLocal.isMultiplayer );
  1693.     }
  1694.     return cursor;
  1695. }
  1696.  
  1697. /*
  1698. ==============
  1699. idPlayer::Spawn
  1700.  
  1701. Prepare any resources used by the player.
  1702. ==============
  1703. */
  1704. void idPlayer::Spawn( void ) {
  1705.     idStr        temp;
  1706.     idBounds    bounds;
  1707.  
  1708.     if ( entityNumber >= MAX_CLIENTS ) {
  1709.         gameLocal.Error( "entityNum > MAX_CLIENTS for player.  Player may only be spawned with a client." );
  1710.     }
  1711.  
  1712.     // allow thinking during cinematics
  1713.     cinematic = true;
  1714.  
  1715.     if ( gameLocal.isMultiplayer ) {
  1716.         // always start in spectating state waiting to be spawned in
  1717.         // do this before SetClipModel to get the right bounding box
  1718.         spectating = true;
  1719.     }
  1720.  
  1721.     // set our collision model
  1722.     physicsObj.SetSelf( this );
  1723.     SetClipModel( );
  1724.     physicsObj.SetMass( spawnArgs.GetFloat( "mass", "100" ) );
  1725.     physicsObj.SetContents( CONTENTS_BODY | (use_combat_bbox?CONTENTS_SOLID:0) );
  1726.     physicsObj.SetClipMask( MASK_PLAYERSOLID );
  1727.     SetPhysics( &physicsObj );
  1728.     InitAASLocation();
  1729.     
  1730.     skin = renderEntity.customSkin;
  1731.  
  1732.     // only the local player needs guis
  1733.      if ( !gameLocal.isMultiplayer || entityNumber == gameLocal.localClientNum ) {
  1734.         
  1735.         // load HUD
  1736.         hud = NULL;
  1737.         mphud = NULL;
  1738.          
  1739.         overlayHud = NULL;
  1740.         overlayHudTime = 0;
  1741.         
  1742.         objectiveSystem = NULL;
  1743.  
  1744.         if ( spawnArgs.GetString( "hud", "", temp ) ) {
  1745.             hud = uiManager->FindGui( temp, true, false, true );
  1746.         } else {
  1747.             gameLocal.Warning( "idPlayer::Spawn() - No hud for player." );
  1748.         }
  1749.  
  1750.         if ( gameLocal.isMultiplayer && spawnArgs.GetString( "mphud", "", temp ) ) {
  1751.               mphud = uiManager->FindGui( temp, true, false, true );
  1752.         } else if ( gameLocal.isMultiplayer ) {
  1753.             gameLocal.Warning( "idPlayer::Spawn() - No MP hud overlay while in MP.");
  1754.         }
  1755.  
  1756.         if ( hud ) {
  1757.             hud->Activate( true, gameLocal.time );
  1758.         }
  1759.  
  1760.         if ( mphud ) {
  1761.             mphud->Activate( true, gameLocal.time );
  1762.         }
  1763.  
  1764.         // load cursor
  1765.         GetCursorGUI();
  1766.         /*
  1767.         if ( spawnArgs.GetString( "cursor", "", temp ) ) {
  1768.             cursor = uiManager->FindGui( temp, true, gameLocal.isMultiplayer, gameLocal.isMultiplayer );
  1769.         }
  1770.         */
  1771.         if ( cursor ) {
  1772.             cursor->Activate( true, gameLocal.time );
  1773.         }
  1774.         
  1775.         // Load 
  1776.  
  1777.         if ( spawnArgs.GetString ( "cinematicHud", "", temp ) ) {
  1778.             cinematicHud = uiManager->FindGui( temp, true, false, true );
  1779.         }
  1780.  
  1781.         if ( !gameLocal.isMultiplayer ) {
  1782.             objectiveSystem = uiManager->FindGui( spawnArgs.GetString( "wristcomm", "guis/wristcomm.gui" ), true, false, true );
  1783.             objectiveSystemOpen = false;
  1784. #ifdef _XENON
  1785.             g_ObjectiveSystemOpen = objectiveSystemOpen;
  1786. #endif
  1787.         }
  1788.  
  1789.         // clear votes
  1790.         // if we want to display current votes that were started before a player was connected
  1791.         // but are still being voted on, this should check the current vote and update the gui appropriately
  1792.         gameLocal.mpGame.ClearVote( entityNumber );
  1793.     }
  1794.  
  1795.     SetLastHitTime( 0, false );
  1796.  
  1797.     // load the armor sound feedback
  1798.     declManager->FindSound( "player_sounds_hitArmor" );
  1799.  
  1800.     animator.RemoveOriginOffset( true );
  1801.  
  1802.     // initialize user info related settings
  1803.     // on server, we wait for the userinfo broadcast, as this controls when the player is initially spawned in game
  1804.     // ocassionally, a race condition may mark a client in-game before he is spawned, if this is the case, parse the userinfo here
  1805.     if ( (gameLocal.isClient || entityNumber == gameLocal.localClientNum) || (gameLocal.isServer && gameLocal.mpGame.IsInGame( entityNumber ) ) ) {
  1806.         UserInfoChanged();
  1807.     }
  1808.  
  1809.     // create combat collision hull for exact collision detection
  1810.     SetCombatModel();
  1811.  
  1812.     // init the damage effects
  1813.     playerView.SetPlayerEntity( this );
  1814.  
  1815.     // supress model in non-player views, but allow it in mirrors and remote views
  1816.     renderEntity.suppressSurfaceInViewID = entityNumber+1;
  1817.  
  1818.     // don't project shadow on self or weapon
  1819.     renderEntity.noSelfShadow = true;
  1820.  
  1821.     idAFAttachment *headEnt = head.GetEntity();
  1822.     if ( headEnt ) {
  1823.         headEnt->GetRenderEntity()->suppressSurfaceInViewID = entityNumber+1;
  1824.         headEnt->GetRenderEntity()->noSelfShadow = true;
  1825.     }
  1826.  
  1827.     if ( gameLocal.isMultiplayer ) {
  1828.         Init();
  1829.          Hide();    // properly hidden if starting as a spectator
  1830.  
  1831.         // Normally idPlayer::Move() gets called to set the contents to 0, but we don't call
  1832.         // move on players not in our snap, so we need to set it manually here.
  1833.         bool inOtherInstance = gameLocal.isClient && gameLocal.GetLocalPlayer() && gameLocal.GetLocalPlayer()->GetInstance() != instance;
  1834.         if( inOtherInstance ) {
  1835.             physicsObj.SetContents( 0 );
  1836.             physicsObj.SetMovementType( PM_SPECTATOR );
  1837.             physicsObj.SetClipMask( MASK_DEADSOLID );
  1838.         }
  1839.  
  1840.         if ( !gameLocal.isClient ) {
  1841.             // set yourself ready to spawn. idMultiplayerGame will decide when/if appropriate and call SpawnFromSpawnSpot
  1842.             SetupWeaponEntity( );
  1843.             SpawnFromSpawnSpot( );
  1844.             spectator = entityNumber;
  1845.             forceRespawn = true;
  1846.             assert( spectating );
  1847.         }
  1848.     } else {
  1849.          SetupWeaponEntity( );
  1850.         SpawnFromSpawnSpot( );
  1851.     }
  1852.  
  1853.     // trigger playtesting item gives, if we didn't get here from a previous level
  1854.     // the devmap key will be set on the first devmap, but cleared on any level
  1855.     // transitions
  1856.     if ( !gameLocal.isMultiplayer && gameLocal.serverInfo.FindKey( "devmap" ) ) {
  1857.         // fire a trigger with the name "devmap"
  1858.         idEntity *ent = gameLocal.FindEntity( "devmap" );
  1859.         if ( ent ) {
  1860.             ent->ActivateTargets( this );
  1861.         }
  1862.     }
  1863.     
  1864.     if ( gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) ) {
  1865.         hiddenWeapon = true;
  1866.         if ( weapon ) {
  1867.             weapon->LowerWeapon();
  1868.         }
  1869. // RAVEN BEGIN
  1870. // mekberg: set to blaster now and disable the weapon.
  1871.         idealWeapon = SlotForWeapon ( "weapon_blaster" ); 
  1872.         Event_DisableWeapon( );
  1873. // RAVEN END
  1874.     } else {
  1875.         hiddenWeapon = false;
  1876.     }
  1877.     
  1878.     if ( hud ) {
  1879.         UpdateHudWeapon( );
  1880.         hud->StateChanged( gameLocal.time );
  1881.     }
  1882.  
  1883.     tipUp = false;
  1884.     objectiveUp = false;
  1885.  
  1886.     aiManager.AddTeammate ( this );
  1887.  
  1888.     if ( inventory.levelTriggers.Num() ) {
  1889.         PostEventMS( &EV_Player_LevelTrigger, 0 );
  1890.     }
  1891.  
  1892.     // ddynerman: defaults for these values are the single player fall deltas
  1893.     fatalFallDelta = spawnArgs.GetFloat("fatal_fall_delta", "65");
  1894.     hardFallDelta = spawnArgs.GetFloat("hard_fall_delta", "45");
  1895.     softFallDelta = spawnArgs.GetFloat("soft_fall_delta", "30");
  1896.     noFallDelta = spawnArgs.GetFloat("no_fall_delta", "7");
  1897.  
  1898.     // precache decls
  1899.     declManager->FindType( DECL_ENTITYDEF, "damage_fatalfall", false, false );
  1900.     declManager->FindType( DECL_ENTITYDEF, "damage_hardfall", false, false );
  1901.     declManager->FindType( DECL_ENTITYDEF, "damage_softfall", false, false );
  1902.     declManager->FindType( DECL_ENTITYDEF, "damage_noair", false, false );
  1903.     declManager->FindType( DECL_ENTITYDEF, "damage_suicide", false, false );
  1904.     declManager->FindType( DECL_ENTITYDEF, "damage_telefrag", false, false );
  1905.  
  1906.     gibSkin = declManager->FindSkin( spawnArgs.GetString( "skin_gibskin" ) );
  1907.  
  1908.     // Skil levels
  1909.     dynamicProtectionScale = 1.0f;
  1910.     if ( !gameLocal.isMultiplayer ) {
  1911.         if ( g_skill.GetInteger() < 2 ) {
  1912.             if ( health < 25 ) {
  1913.                 health = 25;
  1914.             }
  1915.         } else {
  1916.             //g_armorProtection.SetFloat( ( g_skill.GetInteger() < 2 ) ? 0.4f : 0.2f );
  1917.         }
  1918.     }
  1919.     
  1920.     // Powerup joints?
  1921.     if ( spawnArgs.GetString ( "powerup_effect_joints", "", temp ) ) {
  1922.         animator.GetJointList ( temp, powerupEffectJoints );
  1923.     }
  1924.  
  1925.     // RAVEN BEGIN
  1926.     // mekberg: allow disabling of objectives during non-cinematic time periods
  1927.     objectivesEnabled = true;
  1928.  
  1929.     // mekberg: new objectives are suppressed until this event is processed
  1930.     PostEventMS( &EV_Player_AllowNewObjectives, 5000 );
  1931.     tourneyStatus = PTS_UNKNOWN;
  1932.  
  1933.     predictionOriginError    = vec3_zero;
  1934.     predictionAnglesError    = ang_zero;
  1935.  
  1936.     // zero out view angles when we spawn ourselves in MP - the server will send down
  1937.     // the correct ones (only zero if our input is still zero'd)
  1938.     if( gameLocal.isClient && gameLocal.localClientNum == entityNumber && usercmd.angles[ 0 ] == 0 && usercmd.angles[ 1 ] == 0 && usercmd.angles[ 2 ] == 0 ) {
  1939.         deltaViewAngles = ang_zero;
  1940.     }
  1941. }
  1942.  
  1943. /*
  1944. ==============
  1945. idPlayer::~idPlayer()
  1946.  
  1947. Release any resources used by the player.
  1948. ==============
  1949. */
  1950. idPlayer::~idPlayer() {
  1951.     if( gameLocal.mpGame.GetGameState() ) {
  1952.         gameLocal.mpGame.GetGameState()->ClientDisconnect( this );
  1953.     }
  1954.  
  1955.     delete weaponViewModel;
  1956.     delete weaponWorldModel;
  1957.     delete weapon;
  1958.     delete aasSensor;
  1959.     
  1960.     SetPhysics( NULL );
  1961. }
  1962.  
  1963. /*
  1964. ===========
  1965. idPlayer::Save
  1966. ===========
  1967. */
  1968. void idPlayer::Save( idSaveGame *savefile ) const {
  1969.     int i;
  1970.  
  1971.     savefile->WriteUsercmd( usercmd );
  1972.  
  1973.     playerView.Save( savefile );
  1974.  
  1975.     savefile->WriteBool( noclip );
  1976.     savefile->WriteBool( godmode );
  1977.     savefile->WriteInt ( godmodeDamage );    
  1978.     savefile->WriteBool( undying );
  1979.  
  1980.     // don't save spawnAnglesSet, since we'll have to reset them after loading the savegame
  1981.     savefile->WriteAngles( spawnAngles );
  1982.     savefile->WriteAngles( viewAngles );
  1983.     savefile->WriteAngles( cmdAngles );
  1984.  
  1985.     // TOSAVE: bool streamingPrecache; ??? do we save on Xenon?
  1986.  
  1987.     savefile->WriteInt( buttonMask );
  1988.     savefile->WriteInt( oldButtons );
  1989.      savefile->WriteInt( oldFlags );
  1990.  
  1991.     savefile->WriteInt( lastHitTime );
  1992.      savefile->WriteInt( lastSndHitTime );
  1993.     savefile->WriteInt( lastSavingThrowTime );
  1994.  
  1995.     // idBoolFields don't need to be saved, just re-linked in Restore
  1996.     savefile->Write( &pfl, sizeof( pfl ) );
  1997.  
  1998.     inventory.Save( savefile );
  1999.     
  2000.     //weapon->Save( savefile );                                // Don't save this
  2001.  
  2002.     weaponViewModel.Save( savefile );
  2003.     weaponWorldModel.Save ( savefile );
  2004.     // weaponDef restore = weaponDef = GetWeaponDef ( currentWeapon );
  2005.  
  2006.      savefile->WriteUserInterface( hud, false );
  2007. //    savefile->WriteUserInterface( mphud, false );            // Don't save MP stuff
  2008.      savefile->WriteUserInterface( objectiveSystem, false );
  2009.     savefile->WriteUserInterface( cinematicHud, false );
  2010.     savefile->WriteBool( objectiveSystemOpen );
  2011.     savefile->WriteBool( disableHud );
  2012.  
  2013.     savefile->WriteInt( lastDmgTime );
  2014.     savefile->WriteInt( deathClearContentsTime );
  2015.      savefile->WriteBool( doingDeathSkin );
  2016.      savefile->WriteInt( nextHealthPulse );
  2017.      savefile->WriteInt( nextArmorPulse );
  2018.      savefile->WriteBool( hiddenWeapon );
  2019.  
  2020. //    savefile->WriteInt( spectator );                        // Don't save MP stuff
  2021.  
  2022. //    savefile->WriteBool( scoreBoardOpen );                    // Don't save MP stuff
  2023. //    savefile->WriteBool( tourneyBracketsOpen );                // Don't save MP stuff
  2024. //    savefile->WriteBool( forceScoreBoard );                    // Don't save MP stuff
  2025. //    savefile->WriteBool( forceRespawn );                    // Don't save MP stuff
  2026.  
  2027. //    savefile->WriteBool( spectating );                        // Don't save MP stuff
  2028. //    savefile->WriteBool( lastHitToggle );                    // Don't save MP stuff
  2029. //    savefile->WriteBool( forcedReady );                        // Don't save MP stuff
  2030. //    savefile->WriteBool( wantSpectate );                    // Don't save MP stuff
  2031.  
  2032. //     savefile->WriteBool( weaponGone );                        // Don't save MP stuff
  2033. //     savefile->WriteBool( useInitialSpawns );                // Don't save MP stuff
  2034. //     savefile->WriteBool( isLagged );                        // Don't save MP stuff
  2035. //     savefile->WriteBool( isChatting );                        // Don't save MP stuff
  2036.  
  2037. //     savefile->WriteInt( lastSpectateTeleport );                // Don't save MP stuff
  2038. //     savefile->WriteInt( latchedTeam );                        // Don't save MP stuff
  2039. //     savefile->WriteInt( spawnedTime );                        // Don't save MP stuff
  2040.  
  2041. //    teleportEntity.Save( savefile );                        // Don't save MP stuff
  2042. //     savefile->WriteInt( teleportKiller );                    // Don't save MP stuff
  2043.  
  2044.     savefile->WriteInt( minRespawnTime );
  2045.     savefile->WriteInt( maxRespawnTime );
  2046.  
  2047.     savefile->WriteVec3( firstPersonViewOrigin );
  2048.     savefile->WriteMat3( firstPersonViewAxis );
  2049.  
  2050.     // don't bother saving dragEntity or aasSensor since it's a dev tool
  2051.     savefile->WriteVec3( intentDir );
  2052.  
  2053.     // TOSAVE: xbox only - idActor* bestEnemy;
  2054.  
  2055.     savefile->WriteFloat ( vehicleCameraDist );
  2056.  
  2057.     savefile->WriteJoint( hipJoint );
  2058.     savefile->WriteJoint( chestJoint );
  2059.      savefile->WriteJoint( headJoint );
  2060.  
  2061.     savefile->WriteStaticObject( physicsObj );
  2062.  
  2063.      savefile->WriteInt( aasLocation.Num() );
  2064.      for( i = 0; i < aasLocation.Num(); i++ ) {
  2065.          savefile->WriteInt( aasLocation[ i ].areaNum );
  2066.          savefile->WriteVec3( aasLocation[ i ].pos );
  2067.      }
  2068.  
  2069.     savefile->WriteString( modelName );    // cnicholson: Added unsaved var
  2070.     // TOSAVE: const idDict*            modelDict
  2071.     
  2072.     savefile->WriteInt( bobFoot );
  2073.     savefile->WriteFloat( bobFrac );
  2074.     savefile->WriteFloat( bobfracsin );
  2075.     savefile->WriteInt( bobCycle );
  2076.     savefile->WriteFloat( xyspeed );
  2077.     savefile->WriteInt( stepUpTime );
  2078.     savefile->WriteFloat( stepUpDelta );
  2079.     savefile->WriteFloat( idealLegsYaw );
  2080.     savefile->WriteFloat( legsYaw );
  2081.      savefile->WriteBool( legsForward );
  2082.     savefile->WriteFloat( oldViewYaw );
  2083.     savefile->WriteAngles( viewBobAngles );
  2084.     savefile->WriteVec3( viewBob );
  2085.     savefile->WriteInt( landChange );
  2086.     savefile->WriteInt( landTime );
  2087.  
  2088.     savefile->WriteFloat( fatalFallDelta );
  2089.     savefile->WriteFloat( hardFallDelta );
  2090.     savefile->WriteFloat( softFallDelta );
  2091.     savefile->WriteFloat( noFallDelta );
  2092.  
  2093.     savefile->WriteInt( currentWeapon );
  2094.     savefile->WriteInt( idealWeapon );
  2095.     savefile->WriteInt( previousWeapon );
  2096.      savefile->WriteInt( weaponSwitchTime );
  2097.     savefile->WriteBool( weaponEnabled );
  2098.  
  2099.     savefile->WriteBool ( flashlightOn);
  2100.     savefile->WriteBool ( zoomed );
  2101.  
  2102.     savefile->WriteBool( reloadModel );
  2103.  
  2104.     savefile->WriteSkin( skin );
  2105.     savefile->WriteSkin( powerUpSkin );
  2106.     savefile->WriteSkin( gibSkin );
  2107.  
  2108.     savefile->WriteInt( numProjectilesFired );
  2109.     savefile->WriteInt( numProjectileHits );
  2110.  
  2111.      savefile->WriteBool( airless );
  2112.     savefile->WriteInt( airTics );
  2113.     savefile->WriteInt( lastAirDamage );
  2114.  
  2115.     savefile->WriteBool( gibDeath );
  2116.     savefile->WriteBool( gibsLaunched );
  2117.     savefile->WriteVec3( gibDir );
  2118.  
  2119.     savefile->WriteBool( isStrogg );
  2120.  
  2121.     savefile->WriteInterpolate( zoomFov );
  2122.     savefile->WriteInterpolate( centerView );
  2123.      savefile->WriteBool( fxFov );
  2124.  
  2125.     savefile->WriteFloat( influenceFov );
  2126.     savefile->WriteInt( influenceActive );
  2127.     savefile->WriteObject( influenceEntity );
  2128.     savefile->WriteMaterial( influenceMaterial );
  2129.     savefile->WriteFloat( influenceRadius );
  2130.      savefile->WriteSkin( influenceSkin );
  2131.  
  2132.     savefile->WriteObject( privateCameraView );
  2133.  
  2134.     for( i = 0; i < NUM_LOGGED_VIEW_ANGLES; i++ ) {
  2135.         savefile->WriteAngles( loggedViewAngles[ i ] );
  2136.     }
  2137.     for( i = 0; i < NUM_LOGGED_ACCELS; i++ ) {
  2138.         savefile->WriteInt( loggedAccel[ i ].time );
  2139.         savefile->WriteVec3( loggedAccel[ i ].dir );
  2140.     }
  2141.     savefile->WriteInt( currentLoggedAccel );
  2142.  
  2143.     savefile->WriteUserInterface( focusUI, false );
  2144.     savefile->WriteInt( focusTime );
  2145.     savefile->WriteInt ( focusType );
  2146.     focusEnt.Save ( savefile );
  2147.     savefile->WriteUserInterface( focusBrackets, false );
  2148.     savefile->WriteInt( focusBracketsTime );
  2149.  
  2150.      talkingNPC.Save( savefile );
  2151.  
  2152.     extraProjPassEntity.Save( savefile );
  2153.  
  2154.     savefile->WriteInt( talkCursor );
  2155.     savefile->WriteUserInterface( cursor, false );
  2156.  
  2157.     savefile->WriteUserInterface( overlayHud, false );
  2158.     savefile->WriteInt ( overlayHudTime );
  2159.  
  2160.     savefile->WriteBool( targetFriendly );
  2161.  
  2162.     savefile->WriteInt( oldMouseX );
  2163.     savefile->WriteInt( oldMouseY );
  2164.  
  2165.      savefile->WriteBool( tipUp );
  2166.      savefile->WriteBool( objectiveUp );
  2167.  
  2168.     savefile->WriteFloat( dynamicProtectionScale );
  2169.     savefile->WriteInt( lastDamageDef );
  2170.     savefile->WriteVec3( lastDamageDir );
  2171.     savefile->WriteInt( lastDamageLocation );
  2172.  
  2173.     savefile->WriteInt( predictedFrame );
  2174.     savefile->WriteVec3( predictedOrigin );
  2175.     savefile->WriteAngles( predictedAngles );
  2176.     savefile->WriteBool( predictedUpdated );
  2177.     savefile->WriteVec3( predictionOriginError );
  2178.     savefile->WriteAngles( predictionAnglesError );
  2179.     savefile->WriteInt( predictionErrorTime );
  2180.  
  2181. //    savefile->WriteBool( ready );                    // Don't save MP stuff
  2182. //     savefile->WriteBool( respawning );                // Don't save MP stuff
  2183. //     savefile->WriteBool( leader );                    // Don't save MP stuff
  2184. //     savefile->WriteBool( weaponCatchup );            // Don't save MP stuff
  2185. //    savefile->WriteBool( isTelefragged );            // Don't save MP stuff
  2186.  
  2187. //    savefile->WriteInt( lastSpectateChange );        // Don't save MP stuff
  2188. //     savefile->WriteInt( lastTeleFX );                // Don't save MP stuff
  2189. //    savefile->WriteInt( lastSnapshotSequence );        // Don't save MP stuff
  2190.  
  2191. //    savefile->WriteInt( aimClientNum );                // Don't save MP stuff
  2192.  
  2193. //    lastImpulsePlayer->Save( savefile );            // Don't save MP stuff
  2194.  
  2195. //    savefile->WriteInt( arena );                    // Don't save MP stuff
  2196.  
  2197. //    savefile->WriteInt( connectTime );                // Don't save MP stuff
  2198. //    savefile->WriteInt( mutedPlayers );                // Don't save MP stuff
  2199. //    savefile->WriteInt( friendPlayers );            // Don't save MP stuff
  2200.  
  2201. //    savefile->WriteInt( rank );                        // Don't save MP stuff
  2202.  
  2203.     savefile->WriteInt( lastImpulseTime );
  2204.     bossEnemy.Save( savefile );                        // cnicholson: Added unsaved var
  2205.  
  2206.     // TOSAVE: const idDeclEntityDef*    cachedWeaponDefs [ MAX_WEAPONS ];    // cnicholson: Save these?
  2207.     // TOSAVE: const idDeclEntityDef*    cachedPowerupDefs [ POWERUP_MAX ];
  2208.  
  2209.     savefile->WriteBool( weaponChangeIconsUp );        // cnicholson: Added unsaved var
  2210.  
  2211.     // mekberg: added
  2212.     savefile->WriteBool( showNewObjectives );
  2213.     savefile->WriteBool( objectivesEnabled );
  2214.     
  2215. #ifdef _XENON
  2216.     BYTE *data = (BYTE *)session->GetAutoSaveBuffer();
  2217.     unsigned int size = *(session->GetAutoSaveBufferSize());
  2218.         
  2219.     savefile->WriteInt( (int)size );
  2220.     savefile->Write( data, (int)size );
  2221. #endif
  2222.  
  2223.     // TOSAVE: const idDeclEntityDef*    cachedWeaponDefs [ MAX_WEAPONS ];    // cnicholson: Save these?
  2224.     // TOSAVE: const idDeclEntityDef*    cachedPowerupDefs [ POWERUP_MAX ];
  2225.  
  2226.      if ( hud ) {
  2227.         hud->SetStateString( "message", common->GetLocalizedString( "#str_102916" ) );
  2228.         hud->HandleNamedEvent( "Message" );
  2229.      }
  2230. }
  2231.  
  2232. /*
  2233. ===========
  2234. idPlayer::Restore
  2235. ===========
  2236. */
  2237. void idPlayer::Restore( idRestoreGame *savefile ) {
  2238.     int      i;
  2239.     int   num;
  2240.  
  2241.     savefile->ReadUsercmd( usercmd );
  2242.  
  2243.     playerView.Restore( savefile );
  2244.  
  2245.     savefile->ReadBool( noclip );
  2246.     savefile->ReadBool( godmode );
  2247.     savefile->ReadInt ( godmodeDamage );    
  2248.     savefile->ReadBool( undying );
  2249.  
  2250.     savefile->ReadAngles( spawnAngles );
  2251.     savefile->ReadAngles( viewAngles );
  2252.     savefile->ReadAngles( cmdAngles );
  2253.  
  2254.      memset( usercmd.angles, 0, sizeof( usercmd.angles ) );
  2255.     SetViewAngles( viewAngles );
  2256.     spawnAnglesSet = true;
  2257.  
  2258.     savefile->ReadInt( buttonMask );
  2259.      savefile->ReadInt( oldButtons );
  2260.      savefile->ReadInt( oldFlags );
  2261.  
  2262.      usercmd.flags = 0;
  2263.      oldFlags = 0;
  2264.  
  2265.     savefile->ReadInt( lastHitTime );
  2266.      savefile->ReadInt( lastSndHitTime );
  2267.     savefile->ReadInt( lastSavingThrowTime );
  2268.  
  2269.     savefile->Read( &pfl, sizeof( pfl ) );
  2270.  
  2271.     inventory.Restore( savefile );
  2272.  
  2273.     assert( !weapon );
  2274.  
  2275.     weaponViewModel.Restore( savefile );    
  2276.     weaponWorldModel.Restore( savefile );    
  2277.  
  2278.      savefile->ReadUserInterface( hud, &spawnArgs );    
  2279.     assert( !mphud );                                    // Don't save MP stuff
  2280.     savefile->ReadUserInterface( objectiveSystem, &spawnArgs );
  2281.     savefile->ReadUserInterface( cinematicHud, &spawnArgs );
  2282.     savefile->ReadBool( objectiveSystemOpen );
  2283.  
  2284. #ifdef _XENON
  2285.     g_ObjectiveSystemOpen = objectiveSystemOpen;
  2286. #endif
  2287.  
  2288.     objectiveButtonReleased = false;
  2289.     savefile->ReadBool( disableHud );                    // cnicholson: Added unrestored var
  2290.  
  2291.     savefile->ReadInt( lastDmgTime );
  2292.     savefile->ReadInt( deathClearContentsTime );
  2293.      savefile->ReadBool( doingDeathSkin );
  2294.      savefile->ReadInt( nextHealthPulse );
  2295.      savefile->ReadInt( nextArmorPulse );
  2296.      savefile->ReadBool( hiddenWeapon );
  2297.  
  2298.     assert( !spectator );                                // Don't save MP stuff
  2299.  
  2300.     assert( !scoreBoardOpen );                            // Don't save MP stuff
  2301.     assert( !forceScoreBoard );                            // Don't save MP stuff
  2302.     assert( !forceRespawn );                            // Don't save MP stuff
  2303.  
  2304.     assert( !spectating );                                // Don't save MP stuff
  2305.     assert( !lastHitToggle );                            // Don't save MP stuff
  2306.     assert( !forcedReady );                                // Don't save MP stuff
  2307.     assert( !wantSpectate );                            // Don't save MP stuff
  2308.  
  2309.      assert( !weaponGone );                                // Don't save MP stuff
  2310.      assert( !useInitialSpawns );                        // Don't save MP stuff
  2311.      assert( !isLagged );                                // Don't save MP stuff
  2312.      assert( !isChatting );                                // Don't save MP stuff
  2313.  
  2314.     assert( !lastSpectateTeleport );                    // Don't save MP stuff
  2315.      assert( latchedTeam == -1 );                        // Don't save MP stuff
  2316.      assert( !spawnedTime );                                // Don't save MP stuff
  2317.  
  2318.     assert( !teleportEntity );                            // Don't save MP stuff
  2319.      assert( teleportKiller == -1 );                        // Don't save MP stuff
  2320.  
  2321.     savefile->ReadInt( minRespawnTime );
  2322.     savefile->ReadInt( maxRespawnTime );
  2323.  
  2324.     savefile->ReadVec3( firstPersonViewOrigin );
  2325.     savefile->ReadMat3( firstPersonViewAxis );
  2326.  
  2327.     // don't bother restoring dragEntity since it's a dev tool
  2328.      dragEntity.Clear();
  2329.     savefile->ReadVec3( intentDir );
  2330.  
  2331.     // TORESTORE: xbox only - idActor* bestEnemy;
  2332.  
  2333.     savefile->ReadFloat ( vehicleCameraDist );
  2334.  
  2335.     savefile->ReadJoint( hipJoint );
  2336.     savefile->ReadJoint( chestJoint );
  2337.      savefile->ReadJoint( headJoint );
  2338.  
  2339.     savefile->ReadStaticObject( physicsObj );
  2340.      RestorePhysics( &physicsObj );
  2341.  
  2342.      savefile->ReadInt( num );
  2343.      aasLocation.SetGranularity( 1 );
  2344.      aasLocation.SetNum( num );
  2345.      for( i = 0; i < num; i++ ) {
  2346.          savefile->ReadInt( aasLocation[ i ].areaNum );
  2347.          savefile->ReadVec3( aasLocation[ i ].pos );
  2348.      }
  2349.  
  2350.     savefile->ReadString( modelName );    // cnicholson: Added unrestored var
  2351.     // TORESTORE: const idDict*            modelDict
  2352.  
  2353.     savefile->ReadInt( bobFoot );
  2354.     savefile->ReadFloat( bobFrac );
  2355.     savefile->ReadFloat( bobfracsin );
  2356.     savefile->ReadInt( bobCycle );
  2357.     savefile->ReadFloat( xyspeed );
  2358.     savefile->ReadInt( stepUpTime );
  2359.     savefile->ReadFloat( stepUpDelta );
  2360.     savefile->ReadFloat( idealLegsYaw );
  2361.     savefile->ReadFloat( legsYaw );
  2362.      savefile->ReadBool( legsForward );
  2363.     savefile->ReadFloat( oldViewYaw );
  2364.     savefile->ReadAngles( viewBobAngles );
  2365.     savefile->ReadVec3( viewBob );
  2366.     savefile->ReadInt( landChange );
  2367.     savefile->ReadInt( landTime );
  2368.  
  2369.     savefile->ReadFloat( fatalFallDelta );
  2370.     savefile->ReadFloat( hardFallDelta );
  2371.     savefile->ReadFloat( softFallDelta );
  2372.     savefile->ReadFloat( noFallDelta );
  2373.  
  2374.     savefile->ReadInt( currentWeapon );
  2375.     savefile->ReadInt( idealWeapon );
  2376.     savefile->ReadInt( previousWeapon );
  2377.      savefile->ReadInt( weaponSwitchTime );
  2378.     savefile->ReadBool( weaponEnabled );
  2379.  
  2380.     savefile->ReadBool ( flashlightOn );
  2381.     savefile->ReadBool ( zoomed );
  2382.  
  2383.     savefile->ReadBool ( reloadModel );
  2384.  
  2385.     savefile->ReadSkin( skin );
  2386.     savefile->ReadSkin( powerUpSkin );
  2387.     savefile->ReadSkin( gibSkin );
  2388.  
  2389.     savefile->ReadInt( numProjectilesFired );
  2390.     savefile->ReadInt( numProjectileHits );
  2391.  
  2392.      savefile->ReadBool( airless );
  2393.     savefile->ReadInt( airTics );
  2394.     savefile->ReadInt( lastAirDamage );
  2395.  
  2396.     savefile->ReadBool( gibDeath );
  2397.     savefile->ReadBool( gibsLaunched );
  2398.     savefile->ReadVec3( gibDir );
  2399.  
  2400.     savefile->ReadBool( isStrogg );
  2401.  
  2402.     savefile->ReadInterpolate( zoomFov );
  2403.     savefile->ReadInterpolate( centerView );
  2404.     savefile->ReadBool( fxFov );
  2405.  
  2406.     savefile->ReadFloat( influenceFov );
  2407.     savefile->ReadInt( influenceActive );
  2408.     savefile->ReadObject( reinterpret_cast<idClass *&>( influenceEntity ) );
  2409.     savefile->ReadMaterial( influenceMaterial );
  2410.     savefile->ReadFloat( influenceRadius );
  2411.     savefile->ReadSkin( influenceSkin );
  2412.  
  2413.     savefile->ReadObject( reinterpret_cast<idClass *&>( privateCameraView ) );
  2414.  
  2415.     for( i = 0; i < NUM_LOGGED_VIEW_ANGLES; i++ ) {
  2416.         savefile->ReadAngles( loggedViewAngles[ i ] );
  2417.     }
  2418.     for( i = 0; i < NUM_LOGGED_ACCELS; i++ ) {
  2419.         savefile->ReadInt( loggedAccel[ i ].time );
  2420.         savefile->ReadVec3( loggedAccel[ i ].dir );
  2421.     }
  2422.     savefile->ReadInt( currentLoggedAccel );
  2423.  
  2424.     savefile->ReadUserInterface( focusUI, &spawnArgs ),
  2425.     savefile->ReadInt( focusTime );
  2426.     savefile->ReadInt( (int&)focusType );
  2427.     focusEnt.Restore ( savefile );
  2428.     savefile->ReadUserInterface( focusBrackets, &spawnArgs );
  2429.     savefile->ReadInt( focusBracketsTime );
  2430.     
  2431.     talkingNPC.Restore( savefile );
  2432.  
  2433.     extraProjPassEntity.Restore( savefile );
  2434.  
  2435.     savefile->ReadInt( talkCursor );
  2436.      savefile->ReadUserInterface( cursor, &spawnArgs );
  2437.  
  2438.     savefile->ReadUserInterface( overlayHud, &spawnArgs );        // cnicholson: Added unrestored var
  2439.     savefile->ReadInt ( overlayHudTime );            // cnicholson: Added unrestored var
  2440.  
  2441.     savefile->ReadBool( targetFriendly );
  2442.  
  2443.     savefile->ReadInt( oldMouseX );
  2444.     savefile->ReadInt( oldMouseY );
  2445.  
  2446.      savefile->ReadBool( tipUp );
  2447.      savefile->ReadBool( objectiveUp );
  2448.  
  2449.     savefile->ReadFloat( dynamicProtectionScale );    // cnicholson: Added unrestored var
  2450.     savefile->ReadInt( lastDamageDef );
  2451.     savefile->ReadVec3( lastDamageDir );
  2452.     savefile->ReadInt( lastDamageLocation );
  2453.  
  2454.     savefile->ReadInt( predictedFrame );
  2455.     savefile->ReadVec3( predictedOrigin );
  2456.     savefile->ReadAngles( predictedAngles );
  2457.     savefile->ReadBool( predictedUpdated );
  2458.     savefile->ReadVec3( predictionOriginError );
  2459.     savefile->ReadAngles( predictionAnglesError );
  2460.     savefile->ReadInt( predictionErrorTime );
  2461.  
  2462.     assert( !ready );                                // Don't save MP stuff
  2463.      assert( !respawning );                            // Don't save MP stuff
  2464.      assert( !leader );                                // Don't save MP stuff
  2465.      assert( !weaponCatchup );                        // Don't save MP stuff
  2466.     assert( !isTelefragged );                        // Don't save MP stuff
  2467.  
  2468.     assert( !lastSpectateChange );                    // Don't save MP stuff
  2469.      assert( lastTeleFX == -9999 );                    // Don't save MP stuff
  2470.      assert( !lastSnapshotSequence );                // Don't save MP stuff
  2471.  
  2472.      assert( aimClientNum == -1 );                    // Don't save MP stuff
  2473.  
  2474.     assert( !lastImpulsePlayer );                    // Don't save MP stuff
  2475.  
  2476.     assert( !arena );                                // Don't save MP stuff
  2477.  
  2478.     assert( !connectTime );                            // Don't save MP stuff
  2479.     assert( !mutedPlayers );                        // Don't save MP stuff
  2480.     assert( !friendPlayers );                        // Don't save MP stuff
  2481.  
  2482.     assert( rank == -1 );                            // Don't save MP stuff
  2483.  
  2484.     savefile->ReadInt( lastImpulseTime );
  2485.     bossEnemy.Restore( savefile );                    // cnicholson: Added unrestored var
  2486.  
  2487.     // TORESTORE: const idDeclEntityDef*    cachedWeaponDefs [ MAX_WEAPONS ];    // cnicholson: Save these?
  2488.     // TORESTORE: const idDeclEntityDef*    cachedPowerupDefs [ POWERUP_MAX ];
  2489.  
  2490.     savefile->ReadBool( weaponChangeIconsUp );        // cnicholson: Added unrestored var
  2491.  
  2492. // mekberg: added
  2493.     savefile->ReadBool( showNewObjectives );
  2494.     savefile->ReadBool( objectivesEnabled );
  2495.  
  2496. #ifdef _XENON
  2497.     int s = 0;
  2498.     savefile->ReadInt( s );
  2499.     *(session->GetAutoSaveBufferSize()) = s;
  2500.     
  2501.     savefile->Read( session->GetAutoSaveBuffer(), s );
  2502. #endif
  2503.  
  2504.  
  2505.     // set the pm_ cvars
  2506.     const idKeyValue    *kv;
  2507.     kv = spawnArgs.MatchPrefix( "pm_", NULL );
  2508.     while( kv ) {
  2509.         cvarSystem->SetCVarString( kv->GetKey(), kv->GetValue() );
  2510.         kv = spawnArgs.MatchPrefix( "pm_", kv );
  2511.     }
  2512.  
  2513.     // Loading a game on easy mode ensures you alwasy have 20% health when you load
  2514.     i = spawnArgs.GetInt ( va("minRestoreHealth%d", g_skill.GetInteger ( ) ) );
  2515.     if ( health < i ) {
  2516.         health = i;
  2517.     }
  2518.  
  2519.     //if there's hearing loss, make sure we post a finishing event
  2520.     if( pfl.hearingLoss )    {
  2521.         Event_FinishHearingLoss( 3.0f );
  2522.     } else {
  2523.         Event_FinishHearingLoss( 0.05f );
  2524.     }
  2525.     // create combat collision hull for exact collision detection
  2526.     SetCombatModel();    
  2527.  
  2528. // RAVEN BEGIN
  2529. // mekberg: Grab from user info.
  2530.      showWeaponViewModel = GetUserInfo()->GetBool( "ui_showGun" );
  2531.  
  2532.     // precache decls
  2533.     declManager->FindType( DECL_ENTITYDEF, "damage_fatalfall", false, false );
  2534.     declManager->FindType( DECL_ENTITYDEF, "damage_hardfall", false, false );
  2535.     declManager->FindType( DECL_ENTITYDEF, "damage_softfall", false, false );
  2536.     declManager->FindType( DECL_ENTITYDEF, "damage_noair", false, false );
  2537.     declManager->FindType( DECL_ENTITYDEF, "damage_suicide", false, false );
  2538.     declManager->FindType( DECL_ENTITYDEF, "damage_telefrag", false, false );
  2539. // RAVEN END
  2540.  
  2541. // mwhitlock: Xenon texture streaming.
  2542. #if defined(_XENON)
  2543.     // Force precaching.
  2544.     streamingPrecache=true;
  2545. #endif
  2546. }
  2547.  
  2548. /*
  2549. ===============
  2550. idPlayer::PrepareForRestart
  2551. ================
  2552. */
  2553. void idPlayer::PrepareForRestart( void ) {
  2554.     ClearPowerUps();
  2555.     Spectate( true );
  2556.     forceRespawn = true;
  2557.     
  2558.     // we will be restarting program, clear the client entities from program-related things first
  2559.     ShutdownThreads();
  2560.  
  2561.     // the sound world is going to be cleared, don't keep references to emitters
  2562.     FreeSoundEmitter( false );
  2563. }
  2564.  
  2565. /*
  2566. ===============
  2567. idPlayer::Restart
  2568. ================
  2569. */
  2570. void idPlayer::Restart( void ) {
  2571.     idActor::Restart();
  2572.  
  2573.     // client needs to setup the animation script object again
  2574.     if ( gameLocal.isClient ) {
  2575.         // clear the existing model to force a reload
  2576.         Init();
  2577.     } else {
  2578.         // choose a random spot and prepare the point of view in case player is left spectating
  2579.         assert( spectating );
  2580.         SpawnFromSpawnSpot();
  2581.     }
  2582.  
  2583.     lastKiller = NULL;
  2584.     useInitialSpawns = true;
  2585. }
  2586.  
  2587. /*
  2588. ===============
  2589. idPlayer::ServerSpectate
  2590. ================
  2591. */
  2592. void idPlayer::ServerSpectate( bool spectate ) {
  2593.     assert( !gameLocal.isClient );
  2594.  
  2595.     if ( spectating != spectate ) {
  2596.         // if we select spectating on the client 
  2597.         // mekberg: drop and clear powerups from the player.
  2598.         DropPowerups ( );    
  2599.         ClearPowerUps ( );
  2600.          Spectate( spectate );
  2601.         gameLocal.mpGame.GetGameState()->Spectate( this );
  2602.            if ( spectate ) {
  2603.               SetSpectateOrigin( );
  2604.          } 
  2605.     }
  2606.     if ( !spectate ) {
  2607.         SpawnFromSpawnSpot( );
  2608.     }
  2609. }
  2610.  
  2611. /*
  2612. ===========
  2613. idPlayer::SelectSpawnPoint
  2614.  
  2615. Find a spawn point marked, otherwise use normal spawn selection.
  2616. ============
  2617. */
  2618. bool idPlayer::SelectSpawnPoint( idVec3 &origin, idAngles &angles ) {
  2619.     idEntity *spot;
  2620.     idStr skin;
  2621.  
  2622.     spot = gameLocal.SelectSpawnPoint( this );
  2623.  
  2624.     // no spot, try again next frame
  2625.     if( !spot ) {
  2626.         forceRespawn = true;
  2627.         return false;
  2628.     }
  2629.     //HACK: begin "show spawn point" hack for RJ
  2630.     /*if( !spot->spawnArgs.GetInt("text") )    {
  2631.         gameLocal.Warning("texting up spawn point '%s'", GetName());
  2632.         idDict        args;
  2633.         idEntity*    textEntity;
  2634.         idVec3        newOrigin;
  2635.  
  2636.         newOrigin = spot->GetPhysics()->GetOrigin();
  2637.         newOrigin.z += 64;
  2638.  
  2639.         args.SetVector ( "origin", newOrigin );
  2640.         args.Set ( "text", spot->GetName() );
  2641.         args.SetBool ( "playerOriented", 1 );
  2642.         args.SetBool ( "force", 1 );
  2643.         args.Set ( "target", spot->GetName() );
  2644.         args.Set ( "classname", "text" );
  2645.  
  2646.         gameLocal.SpawnEntityDef ( args, &textEntity );
  2647.  
  2648.         //mark the spawn point so it doesn't do this again
  2649.         spawnArgs.SetInt("text", 1);
  2650.  
  2651.     }*/
  2652.  
  2653.  
  2654.     // set the player skin from the spawn location
  2655.     if ( spot->spawnArgs.GetString( "skin", NULL, skin ) ) {
  2656.         spawnArgs.Set( "spawn_skin", skin );
  2657.     }
  2658.  
  2659.     if ( spot->spawnArgs.GetString( "spawn_model", NULL ) ) {
  2660.         spawnArgs.Set( "model", spot->spawnArgs.GetString( "spawn_model", NULL ) );
  2661.     }
  2662.  
  2663.     if ( spot->spawnArgs.GetString( "def_head", NULL ) ) {
  2664.         spawnArgs.Set( "def_head", spot->spawnArgs.GetString( "def_head", NULL ) );
  2665.     }
  2666.  
  2667.     // activate the spawn locations targets
  2668.     spot->PostEventMS( &EV_ActivateTargets, 0, this );
  2669.  
  2670.     origin = spot->GetPhysics()->GetOrigin();
  2671.     origin[2] += 4.0f + CM_BOX_EPSILON;        // move up to make sure the player is at least an epsilon above the floor
  2672.     angles = spot->GetPhysics()->GetAxis().ToAngles();
  2673.  
  2674.     return true;
  2675. }
  2676.  
  2677. /*
  2678. ===========
  2679. idPlayer::SpawnFromSpawnSpot
  2680.  
  2681. Chooses a spawn location and spawns the player
  2682. ============
  2683. */
  2684. void idPlayer::SpawnFromSpawnSpot( void ) {
  2685.     idVec3        spawn_origin;
  2686.     idAngles    spawn_angles;
  2687.     
  2688.     if( !SelectSpawnPoint( spawn_origin, spawn_angles ) ) {
  2689.         forceRespawn = true;
  2690.         return;
  2691.     }
  2692.     SpawnToPoint( spawn_origin, spawn_angles );
  2693. }
  2694.  
  2695. /*
  2696. ===========
  2697. idPlayer::SpawnToPoint
  2698.  
  2699. Called every time a client is placed fresh in the world:
  2700. after the first ClientBegin, and after each respawn
  2701. Initializes all non-persistant parts of playerState
  2702.  
  2703. when called here with spectating set to true, just place yourself and init
  2704. ============
  2705. */
  2706. void idPlayer::SpawnToPoint( const idVec3 &spawn_origin, const idAngles &spawn_angles ) {
  2707.     idVec3 spec_origin;
  2708.  
  2709.     assert( !gameLocal.isClient );
  2710.  
  2711.     respawning = true;
  2712.  
  2713.     Init();
  2714.  
  2715.     // Force players to use bounding boxes when in multiplayer
  2716.     if ( gameLocal.isMultiplayer ) {
  2717.         use_combat_bbox = true;
  2718.  
  2719.         // Make sure the combat model is unlinked
  2720.         if ( combatModel ) {
  2721.             combatModel->Unlink ( );
  2722.         }
  2723.     }
  2724.  
  2725.     // Any health over max health will tick down
  2726.     if ( health > inventory.maxHealth ) {
  2727.         nextHealthPulse = gameLocal.time + HEALTH_PULSE;
  2728.     }
  2729.     
  2730.     if ( inventory.armor > inventory.maxarmor ) {
  2731.         nextArmorPulse = gameLocal.time + ARMOR_PULSE;
  2732.     }        
  2733.  
  2734.     fl.noknockback = false;
  2735.     // stop any ragdolls being used
  2736.     StopRagdoll();
  2737.     // set back the player physics
  2738.     SetPhysics( &physicsObj );
  2739.     physicsObj.SetClipModelAxis();
  2740.     physicsObj.EnableClip();
  2741.     if ( !spectating ) {
  2742.         SetCombatContents( true );
  2743.     }
  2744.  
  2745.     physicsObj.SetLinearVelocity( vec3_origin );
  2746.  
  2747.     // setup our initial view
  2748.     if ( !spectating ) {
  2749.         SetOrigin( spawn_origin );
  2750. // RAVEN BEGIN
  2751. // abahr: taking into account gravity
  2752.         SetAxis( spawn_angles.ToMat3() );
  2753. // RAVEN END
  2754.     } else {
  2755.         spec_origin = spawn_origin;
  2756.         spec_origin[ 2 ] += pm_normalheight.GetFloat();
  2757.         spec_origin[ 2 ] += SPECTATE_RAISE;
  2758.         SetOrigin( spec_origin );
  2759.     }
  2760.  
  2761.     // if this is the first spawn of the map, we don't have a usercmd yet,
  2762.     // so the delta angles won't be correct.  This will be fixed on the first think.
  2763.     viewAngles = ang_zero;
  2764.     SetDeltaViewAngles( ang_zero );
  2765.     SetViewAngles( spawn_angles );
  2766.     spawnAngles = spawn_angles;
  2767.     spawnAnglesSet = false;
  2768.  
  2769.      legsForward = true;
  2770.     legsYaw = 0.0f;
  2771.     idealLegsYaw = 0.0f;
  2772.     oldViewYaw = viewAngles.yaw;
  2773.  
  2774.     if ( spectating ) {
  2775.         Hide();
  2776.     } else {
  2777.         Show();
  2778.     }
  2779.  
  2780.     if ( gameLocal.isMultiplayer ) {
  2781.         if ( !spectating ) {
  2782.              // we may be called twice in a row in some situations. avoid a double fx and 'fly to the roof'
  2783.              if ( lastTeleFX < gameLocal.time - 1000 ) {
  2784.                 // currentThinkingEntity not set here (called out of Run())
  2785.                 idEntity* thinker = gameLocal.currentThinkingEntity;
  2786.                 gameLocal.currentThinkingEntity = this;
  2787.                 gameLocal.PlayEffect ( spawnArgs, "fx_spawn", renderEntity.origin, idVec3(0,0,1).ToMat3(), false, vec3_origin, true );
  2788.                 lastTeleFX = gameLocal.time;
  2789.                 gameLocal.currentThinkingEntity = thinker;
  2790.              }
  2791.  
  2792.             // if we have a strogg model, set the strogg flag here
  2793.             isStrogg = false;
  2794.             if( modelDict ) {
  2795.                 const idKeyValue *kv = modelDict->FindKey( "team" );
  2796.                 if( kv ) {
  2797.                     isStrogg = !kv->GetValue().Icmp( "strogg" );
  2798.                 }
  2799.             }
  2800.         }
  2801.         pfl.teleport = true;
  2802.     } else {
  2803.         pfl.teleport = false;
  2804.     }
  2805.  
  2806.     // kill anything at the new position
  2807.     if ( !spectating ) {
  2808.         physicsObj.SetClipMask( MASK_PLAYERSOLID ); // the clip mask is usually maintained in Move(), but KillBox requires it
  2809. // RAVEN BEGIN
  2810. // abahr: this is killing the tram car when spawning in.  Ooooops!
  2811.         if( gameLocal.isMultiplayer ) {
  2812.             gameLocal.KillBox( this );
  2813.         }
  2814. // RAVEN END
  2815.     }
  2816.  
  2817.     // don't allow full run speed for a bit
  2818.     physicsObj.SetKnockBack( 100 );
  2819.  
  2820.     // set our respawn time and buttons so that if we're killed we don't respawn immediately
  2821.     minRespawnTime = gameLocal.time;
  2822.     maxRespawnTime = gameLocal.time;
  2823.     if ( !spectating ) {
  2824.         forceRespawn = false;
  2825.     }
  2826.  
  2827.     privateCameraView = NULL;
  2828.  
  2829.     BecomeActive( TH_THINK );
  2830.  
  2831.     // run a client frame to drop exactly to the floor,
  2832.     // initialize animations and other things
  2833.     Think();
  2834.  
  2835.      respawning            = false;
  2836.      isTelefragged        = false;
  2837.      isLagged            = false;
  2838.      isChatting            = false;
  2839.  
  2840.     lastImpulsePlayer = NULL;
  2841.     lastImpulseTime = 0;
  2842. }
  2843.  
  2844. /*
  2845. ===============
  2846. idPlayer::SavePersistantInfo
  2847.  
  2848. Saves any inventory and player stats when changing levels.
  2849. ===============
  2850. */
  2851. void idPlayer::SavePersistantInfo( void ) {
  2852.     idDict &playerInfo = gameLocal.persistentPlayerInfo[entityNumber];
  2853.  
  2854.     playerInfo.Clear();
  2855.     inventory.GetPersistantData( playerInfo );
  2856.     playerInfo.SetInt( "health", health );
  2857.     playerInfo.SetInt( "current_weapon", currentWeapon );
  2858. }
  2859.  
  2860. /*
  2861. ===============
  2862. idPlayer::RestorePersistantInfo
  2863.  
  2864. Restores any inventory and player stats when changing levels.
  2865. ===============
  2866. */
  2867. void idPlayer::RestorePersistantInfo( void ) {
  2868.      if ( gameLocal.isMultiplayer ) {
  2869.          gameLocal.persistentPlayerInfo[entityNumber].Clear();
  2870.      }
  2871.  
  2872.     spawnArgs.Copy( gameLocal.persistentPlayerInfo[entityNumber] );
  2873.  
  2874.     inventory.RestoreInventory( this, spawnArgs );
  2875.      health = spawnArgs.GetInt( "health", "100" );
  2876.      if ( !gameLocal.isClient ) {
  2877.          idealWeapon = spawnArgs.GetInt( "current_weapon", "0" );
  2878. #ifdef _XENON
  2879.          // nrausch: needs to happen in order to restore the current weapon after an autosave
  2880.          if ( !gameLocal.isMultiplayer ) {
  2881.              SetWeapon( idealWeapon );
  2882.          }
  2883. #endif
  2884.      }
  2885. }
  2886.  
  2887. /*
  2888. ================
  2889. idPlayer::GetUserInfo
  2890. ================
  2891. */
  2892. idDict *idPlayer::GetUserInfo( void ) {
  2893.     return &gameLocal.userInfo[ entityNumber ];
  2894. }
  2895.  
  2896. /*
  2897. ==============
  2898. idPlayer::UpdateModelSetup
  2899. Updates the player's model setup.  Model setups are read from the player def, and contain
  2900. information about the player's model, the player's head model, a skin, and a team for the
  2901. composite model.
  2902. ==============
  2903. */
  2904. void idPlayer::UpdateModelSetup( bool forceReload ) {
  2905.     const idDict* dict;
  2906.     const char* uiKeyName = NULL;
  2907.     const char* defaultModel = NULL;
  2908.     const char* newModelName = NULL;
  2909.  
  2910.     if( !gameLocal.isMultiplayer || spectating ) {
  2911.         return;
  2912.     }
  2913.  
  2914.     if( gameLocal.IsTeamGame() ) {
  2915.         uiKeyName = va( "ui_model_%s", idMultiplayerGame::teamNames[ team ] );
  2916.         newModelName = GetUserInfo()->GetString( uiKeyName );
  2917.         defaultModel = spawnArgs.GetString( va( "def_default_model_%s", idMultiplayerGame::teamNames[ team ] ), NULL );
  2918.     } else {
  2919.         uiKeyName = "ui_model";
  2920.         newModelName = GetUserInfo()->GetString( uiKeyName );
  2921.         defaultModel = spawnArgs.GetString( "def_default_model" );
  2922.     }
  2923.  
  2924.     if( !idStr::Icmp( newModelName, "" ) ) {
  2925.         newModelName = defaultModel;
  2926.     }
  2927.  
  2928.     // model hasn't changed
  2929.     if( !modelName.Icmp( newModelName ) && !forceReload ) {
  2930.         return;
  2931.     }
  2932.  
  2933.     dict = gameLocal.FindEntityDefDict ( newModelName, false );
  2934.  
  2935.     // validate that the model they've selected is OK for this team game
  2936.     if( gameLocal.IsTeamGame() && dict ) {
  2937.         if( idStr::Icmp( dict->GetString( "team", "" ), idMultiplayerGame::teamNames[ team ] ) ) {
  2938.             gameLocal.Warning( "idPlayer::UpdateModelSetup() - Player %d (%s) wants model %s which is restricted to team %s (Player team: %s)\n", entityNumber, GetUserInfo()->GetString( "ui_name" ), GetUserInfo()->GetString( va( "ui_model_%s", idMultiplayerGame::teamNames[ team ] ), "" ), dict->GetString( "team" ), idMultiplayerGame::teamNames[ team ] );
  2939.             cvarSystem->SetCVarBool( uiKeyName, "" );
  2940.             dict = NULL;
  2941.         }
  2942.     } 
  2943.  
  2944.     // check to see if the user-specified ui_model/ui_model_strogg/ui_model_marine is valid
  2945.     if( !dict ) {
  2946.         newModelName = defaultModel;
  2947.  
  2948.         dict = gameLocal.FindEntityDefDict ( newModelName, false );
  2949.         if( !dict ) {
  2950.             gameLocal.Error( "idPlayer::UpdateModelSetup() - Can't find default model (%s)\n", defaultModel );
  2951.         } else {
  2952.             // If it's not valid, set the cvar to the default model
  2953.             GetUserInfo()->Set( uiKeyName, defaultModel );
  2954.             if( entityNumber == gameLocal.localClientNum ) {
  2955.                 cvarSystem->SetCVarString( uiKeyName, defaultModel );
  2956.             }
  2957.             cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "updateUI %d\n", entityNumber ) );
  2958.         }
  2959.     }
  2960.     
  2961.     modelName = newModelName;
  2962.     modelDict = dict;
  2963.  
  2964.     SetAnimState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
  2965.     SetAnimState( ANIMCHANNEL_LEGS, "Legs_Idle", 0 );
  2966.     UpdateState();
  2967.  
  2968.     reloadModel = true;
  2969. }
  2970.  
  2971. /*
  2972. ==============
  2973. idPlayer::BalanceTeam
  2974. ==============
  2975. */
  2976. // RAVEN BEGIN
  2977. // shouchard:  BalanceTDM->BalanceTeam (now used for CTF as well as TDM)
  2978. bool idPlayer::BalanceTeam( void ) {
  2979. // RAVEN END
  2980.     int            i, balanceTeam, teamCount[2];
  2981.     idEntity    *ent;
  2982.  
  2983.     teamCount[ 0 ] = teamCount[ 1 ] = 0;
  2984.     for( i = 0; i < gameLocal.numClients; i++ ) {
  2985.         ent = gameLocal.entities[ i ];
  2986.         if ( ent && ent->IsType( idPlayer::Type ) && gameLocal.mpGame.IsInGame( i ) ) {
  2987.             teamCount[ static_cast< idPlayer * >( ent )->team ]++;
  2988.         }
  2989.     }
  2990.     balanceTeam = -1;
  2991.     if ( teamCount[ 0 ] < teamCount[ 1 ] ) {
  2992.         balanceTeam = 0;
  2993.     } else if ( teamCount[ 0 ] > teamCount[ 1 ] ) {
  2994.         balanceTeam = 1;
  2995.     }
  2996.  
  2997. // RAVEN BEGIN
  2998. // shouchard:  avoid switching teams in degenerate cases
  2999.     if ( balanceTeam != -1 && team != balanceTeam && teamCount[ balanceTeam ]+1 != teamCount[ !balanceTeam ] ) {
  3000. // RAVEN END
  3001.         common->DPrintf( "team balance: forcing player %d to %s team\n", entityNumber, balanceTeam ? "strogg" : "marine" );
  3002.         team = balanceTeam;
  3003.         GetUserInfo()->Set( "ui_team", team ? "Strogg" : "Marine" );
  3004.         cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "updateUI %d\n", entityNumber ) );
  3005.         return true;
  3006.     }
  3007.     return false;
  3008. }
  3009.  
  3010. void HSVtoRGB( float &r, float &g, float &b, float h, float s, float v ) {
  3011.     int i;
  3012.     float f, p, q, t;
  3013.  
  3014.     h = idMath::ClampFloat( 0.0f, 360.0f, h );
  3015.     s = idMath::ClampFloat( 0.0f, 1.0f, s );
  3016.     v = idMath::ClampFloat( 0.75f, 1.0f, v );
  3017.  
  3018.     if( s == 0 ) {
  3019.         // achromatic (grey)
  3020.         r = g = b = v;
  3021.         return;
  3022.     }
  3023.  
  3024.     h /= 60;            // sector 0 to 5
  3025.     i = floor( h );
  3026.     f = h - i;            // factorial part of h
  3027.     p = v * ( 1 - s );
  3028.     q = v * ( 1 - s * f );
  3029.     t = v * ( 1 - s * ( 1 - f ) );
  3030.  
  3031.     switch( i ) {
  3032.         case 0:
  3033.             r = v;
  3034.             g = t;
  3035.             b = p;
  3036.             break;
  3037.  
  3038.         case 1:
  3039.             r = q;
  3040.             g = v;
  3041.             b = p;
  3042.             break;
  3043.  
  3044.         case 2:
  3045.             r = p;
  3046.             g = v;
  3047.             b = t;
  3048.             break;
  3049.             
  3050.         case 3:
  3051.             r = p;
  3052.             g = q;
  3053.             b = v;
  3054.             break;
  3055.  
  3056.         case 4:
  3057.             r = t;
  3058.             g = p;
  3059.             b = v;
  3060.             break;
  3061.  
  3062.         default:        // case 5:
  3063.             r = v;
  3064.             g = p;
  3065.             b = q;
  3066.             break;
  3067.     }
  3068. }
  3069.  
  3070. /*
  3071. ==============
  3072. idPlayer::UserInfoChanged
  3073. ==============
  3074. */
  3075. bool idPlayer::UserInfoChanged( void ) {
  3076.      idDict    *userInfo;
  3077.      bool    modifiedInfo;
  3078.      bool    spec;
  3079.      bool    newready;
  3080.  
  3081.      userInfo = GetUserInfo();
  3082.      showWeaponViewModel = userInfo->GetBool( "ui_showGun" );
  3083.  
  3084.     if ( !gameLocal.isMultiplayer ) {
  3085.         return false;
  3086.     }
  3087.  
  3088.      modifiedInfo = false;
  3089.  
  3090.      spec = ( idStr::Icmp( userInfo->GetString( "ui_spectate" ), "Spectate" ) == 0 );
  3091.     if ( gameLocal.serverInfo.GetBool( "si_spectators" ) ) {
  3092.          // never let spectators go back to game while sudden death is on
  3093.          if ( gameLocal.mpGame.GetGameState()->GetMPGameState() == SUDDENDEATH && !spec && wantSpectate == true ) {
  3094.              userInfo->Set( "ui_spectate", "Spectate" );
  3095.              modifiedInfo |= true;
  3096.          } else {
  3097.              if ( spec != wantSpectate && !spec ) {
  3098.                  // returning from spectate, set forceRespawn so we don't get stuck in spectate forever
  3099.                  forceRespawn = true;
  3100.              }
  3101.              wantSpectate = spec;
  3102.            }
  3103.     } else {
  3104.          if ( spec ) {
  3105.              userInfo->Set( "ui_spectate", "Play" );
  3106.              modifiedInfo |= true;
  3107.          } else if ( spectating ) {  
  3108.              // allow player to leaving spectator mode if they were in it when it was disallowed
  3109.              forceRespawn = true;
  3110.          }
  3111.         wantSpectate = false;
  3112.     }
  3113.  
  3114.     if ( gameLocal.serverInfo.GetBool( "si_useReady" ) ) {
  3115.         newready = ( idStr::Icmp( userInfo->GetString( "ui_ready" ), "Ready" ) == 0 );
  3116.         if ( ready != newready && gameLocal.mpGame.GetGameState()->GetMPGameState() == WARMUP && !wantSpectate ) {
  3117.              gameLocal.mpGame.AddChatLine( common->GetLocalizedString( "#str_107180" ), userInfo->GetString( "ui_name" ), newready ? common->GetLocalizedString( "#str_104300" ) : common->GetLocalizedString( "#str_104301" ) );
  3118.         }
  3119.         ready = newready;
  3120.     }
  3121.     
  3122.     team = ( idStr::Icmp( userInfo->GetString( "ui_team" ), "Strogg" ) == 0 );
  3123.     if( hud && gameLocal.IsTeamGame() ) {
  3124.         hud->HandleNamedEvent( (team ? "setTeam_strogg" : "setTeam_marine") );
  3125.     } else if( hud ) {
  3126.         hud->HandleNamedEvent( "setTeam_marine" );
  3127.     }
  3128.  
  3129.     if ( gameLocal.IsTeamGame() ) {
  3130.         if ( team != latchedTeam ) {
  3131.             if( gameLocal.isServer ) {    
  3132.                 gameLocal.mpGame.SwitchToTeam( entityNumber, latchedTeam, team );
  3133.             }
  3134.  
  3135.             SetInitialHud();
  3136.             if( mphud ) {
  3137.                 mphud->SetStateInt( "playerteam", team );
  3138.                 mphud->HandleNamedEvent( "TeamChange" );
  3139.             }
  3140.         } 
  3141.         latchedTeam = team;
  3142.     }
  3143.  
  3144. // RAVEN BEGIN
  3145. // server maintains TDM balance
  3146. // shouchard:  balance teams extended to CTF
  3147.     if ( !gameLocal.isClient && gameLocal.serverInfo.GetBool( "si_autoBalance" ) && gameLocal.IsTeamGame() ) {
  3148.         bool teamsBalanced = BalanceTeam();
  3149.          modifiedInfo |= teamsBalanced;
  3150.         // hack to make sure listen server clients do the right thing
  3151.         if ( teamsBalanced ) {
  3152.             team = ( idStr::Icmp( userInfo->GetString( "ui_team" ), "Strogg" ) == 0 );
  3153.             gameLocal.mpGame.SwitchToTeam( entityNumber, !team, team );
  3154.             latchedTeam = team;
  3155.             if ( hud ) {
  3156.                 hud->HandleNamedEvent( (team ? "setTeam_strogg" : "setTeam_marine") );
  3157.             }
  3158.             if ( mphud ) {
  3159.                 mphud->SetStateInt( "playerteam", team );
  3160.                 mphud->HandleNamedEvent( "TeamChange" );
  3161.             }
  3162.         }
  3163. // RAVEN END
  3164.     }
  3165.  
  3166.     UpdateModelSetup();
  3167.  
  3168.     if( (gameLocal.isServer && gameLocal.mpGame.IsInGame( entityNumber )) || (gameLocal.isClient && gameLocal.localClientNum == entityNumber) ) {
  3169.          isChatting = userInfo->GetBool( "ui_chat", "0" );
  3170.          if ( isChatting && pfl.dead ) {
  3171.              // if dead, always force chat icon off.
  3172.              isChatting = false;
  3173.              userInfo->SetBool( "ui_chat", false );
  3174.              modifiedInfo |= true;
  3175.         }
  3176.     }
  3177.  
  3178.     // grab hitscan tint
  3179.     hitscanTint = userInfo->GetVec4( "ui_hitscanTint", "81 1 1 1" );
  3180.     HSVtoRGB( hitscanTint.x, hitscanTint.y, hitscanTint.z, hitscanTint.x, hitscanTint.y, hitscanTint.z );
  3181.     // force alpha to 1
  3182.     hitscanTint.w = 1.0f;
  3183.  
  3184.     return modifiedInfo;
  3185. }
  3186.    
  3187.  
  3188. /*
  3189. ===============
  3190. idPlayer::UpdateHudAmmo
  3191. ===============
  3192. */
  3193. void idPlayer::UpdateHudAmmo( idUserInterface *_hud ) {
  3194.     int inclip;
  3195.     int ammoamount;
  3196.  
  3197.     assert( weapon );
  3198.     assert( _hud );
  3199.  
  3200.     inclip        = weapon->AmmoInClip();
  3201.     ammoamount    = weapon->AmmoAvailable();
  3202.  
  3203.     if ( ammoamount < 0 ) {
  3204.         // show infinite ammo
  3205.         _hud->SetStateString( "player_ammo", "-1" );
  3206.         _hud->SetStateString( "player_totalammo", "-1" );
  3207.         _hud->SetStateFloat ( "player_ammopct", 1.0f );
  3208.     } else if ( weapon->ClipSize ( ) && !gameLocal.isMultiplayer ) {
  3209.         _hud->SetStateInt ( "player_clip_size", weapon->ClipSize() );
  3210.         _hud->SetStateFloat ( "player_ammopct", (float)inclip / (float)weapon->ClipSize ( ) );
  3211.         if ( weapon->ClipSize ( )==1) {
  3212.             _hud->SetStateInt ( "player_totalammo", ammoamount );
  3213.         }
  3214.         else {
  3215.             _hud->SetStateInt ( "player_totalammo", ammoamount - inclip );
  3216.         }
  3217.         _hud->SetStateInt ( "player_ammo", inclip );
  3218.     } else {
  3219.         _hud->SetStateFloat ( "player_ammopct", (float)ammoamount / (float)weapon->maxAmmo );
  3220.         _hud->SetStateInt ( "player_totalammo", ammoamount );
  3221.         _hud->SetStateInt ( "player_ammo", -1 );
  3222.     } 
  3223.  
  3224.     _hud->SetStateBool( "player_ammo_empty", ( ammoamount == 0 ) );
  3225. }
  3226.  
  3227. /*
  3228. ===============
  3229. idPlayer::UpdateHudStats
  3230. ===============
  3231. */
  3232. void idPlayer::UpdateHudStats( idUserInterface *_hud ) {
  3233.     int temp;
  3234.     
  3235.     assert ( _hud );
  3236.  
  3237.     temp = _hud->State().GetInt ( "player_health", "-1" );
  3238.     if ( temp != health ) {        
  3239.         _hud->SetStateInt   ( "player_healthDelta", temp == -1 ? 0 : (temp - health) );
  3240.         _hud->SetStateInt    ( "player_health", health < -100 ? -100 : health );
  3241.         _hud->SetStateFloat    ( "player_healthpct", idMath::ClampFloat ( 0.0f, 1.0f, (float)health / (float)inventory.maxHealth ) );
  3242.         _hud->HandleNamedEvent ( "updateHealth" );
  3243.     }
  3244.         
  3245.     temp = _hud->State().GetInt ( "player_armor", "-1" );
  3246.     if ( temp != inventory.armor ) {
  3247.         _hud->SetStateInt ( "player_armorDelta", temp == -1 ? 0 : (temp - inventory.armor) );
  3248.         _hud->SetStateInt ( "player_armor", inventory.armor );
  3249.         _hud->SetStateFloat    ( "player_armorpct", idMath::ClampFloat ( 0.0f, 1.0f, (float)inventory.armor / (float)inventory.maxarmor ) );
  3250.         _hud->HandleNamedEvent ( "updateArmor" );
  3251.     }
  3252.     
  3253.     // Boss bar
  3254.     if ( _hud->State().GetInt ( "boss_health", "-1" ) != (bossEnemy ? bossEnemy->health : -1) ) {
  3255.         if ( !bossEnemy || bossEnemy->health <= 0 ) {
  3256.             bossEnemy = NULL;
  3257.             _hud->SetStateInt ( "boss_health", -1 );
  3258.             _hud->HandleNamedEvent ( "hideBossBar" );            
  3259.              _hud->HandleNamedEvent ( "hideBossShieldBar" ); // grrr, for boss buddy..but maybe other bosses will have shields?
  3260.         } else {            
  3261.             _hud->SetStateInt ( "boss_health", bossEnemy->health );
  3262.             _hud->HandleNamedEvent ( "updateBossBar" );
  3263.         }
  3264.     }
  3265.         
  3266.     // god mode information
  3267.     _hud->SetStateString( "player_god", va( "%i", (godmode && g_showGodDamage.GetBool()) ) );
  3268.     _hud->SetStateString( "player_god_damage", va( "%i", godmodeDamage ) );
  3269.  
  3270.     // Update the hit direction
  3271.     idVec3 localDir;
  3272.     viewAxis.ProjectVector( lastDamageDir, localDir );
  3273.     _hud->SetStateFloat( "hitdir", localDir.ToAngles()[YAW] + 180.0f );
  3274.  
  3275.     //_hud->HandleNamedEvent( "updateArmorHealthAir" );
  3276.  
  3277.     if ( weapon ) {
  3278.         UpdateHudAmmo( _hud );
  3279.     }
  3280.     
  3281.     _hud->StateChanged( gameLocal.time );
  3282. }
  3283.  
  3284. /*
  3285. ===============
  3286. idPlayer::UpdateHudWeapon
  3287. ===============
  3288. */
  3289. void idPlayer::UpdateHudWeapon( int displayWeapon ) {
  3290.     
  3291.     if ( (displayWeapon < -1) || (displayWeapon >= MAX_WEAPONS) ) {
  3292.         common->DPrintf( "displayweapon was out of range" );
  3293.         return;
  3294.     }
  3295.     
  3296.     int index = 0;
  3297.     int idealIndex = 0;
  3298.     idUserInterface * hud = idPlayer::hud;
  3299.     idUserInterface * mphud = idPlayer::mphud;
  3300.     idUserInterface * cursor = idPlayer::cursor;
  3301.  
  3302.      // if updating the hud of a followed client
  3303.      if ( gameLocal.localClientNum >= 0 && gameLocal.entities[ gameLocal.localClientNum ] ) {
  3304.          idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ gameLocal.localClientNum ] );
  3305.          if ( p->spectating && p->spectator == entityNumber ) {
  3306.              assert( p->hud && p->mphud );
  3307.             hud = p->hud;
  3308.             mphud = p->mphud;
  3309.             cursor = p->GetCursorGUI();
  3310.          }
  3311.      }
  3312.  
  3313.     if ( !hud || !weapon ) {
  3314.         return;
  3315.     }
  3316.  
  3317.     for ( int i = 0; i < MAX_WEAPONS; i++ ) {
  3318.         const char *weapnum = va( "weapon%d", i );
  3319.         int weapstate = 0;
  3320.         if ( inventory.weapons & ( 1 << i ) && spawnArgs.GetBool( va( "weapon%d_cycle", i ) ) ) {
  3321.             hud->SetStateBool ( weapnum, true );
  3322.             const char *weap = spawnArgs.GetString( va( "def_weapon%d", i ) );
  3323.             if ( weap && *weap ) {
  3324.                 weapstate++;
  3325.  
  3326.                 if ( idealWeapon == i ) {
  3327.                     idealIndex = index;
  3328.                 }
  3329.  
  3330.                 hud->SetStateInt    ( va("weapon%d_index", i ), index++ );
  3331.                 hud->SetStateString ( va("weapon%d_icon", i ), GetWeaponDef ( i )->dict.GetString ( "inv_icon" ) );
  3332.                 hud->SetStateInt    ( va("weapon%d_ammo", i ), inventory.ammo[inventory.AmmoIndexForWeaponClass ( weap ) ] );                
  3333.             }
  3334.         } else {
  3335.             hud->SetStateBool( weapnum, false );
  3336.         }                
  3337.     }
  3338.  
  3339.     hud->SetStateInt( "weaponcount", index );
  3340.     hud->SetStateString( "weapicon", weapon->GetIcon() );    
  3341.     hud->SetStateString( "ammoIcon", weapon->spawnArgs.GetString ( "inv_icon" ) );
  3342.      hud->SetStateInt( "player_weapon", currentWeapon );
  3343.     hud->SetStateInt( "player_lastweapon", previousWeapon );
  3344.     hud->SetStateInt( "player_idealweapon", ((displayWeapon!=-1)?displayWeapon:idealWeapon) );
  3345.     hud->SetStateInt( "player_idealIndex", idealIndex );
  3346.  
  3347.     // Weapon name for weapon selection
  3348.     const idDeclEntityDef* w = GetWeaponDef( ( displayWeapon != -1 ) ? displayWeapon:idealWeapon );
  3349.     if ( w ) {
  3350.         idStr langToken = w->dict.GetString( "inv_name" );
  3351.         hud->SetStateString( "weaponname", common->GetLocalizedString( langToken ) );
  3352.     }
  3353.  
  3354.     UpdateHudAmmo( hud );
  3355.              
  3356.      if ( cursor ) {
  3357.          weapon->UpdateCrosshairGUI( cursor );
  3358.  
  3359.         // mekberg: force a redraw so ON_INIT gets called and doesn't stomp all over
  3360.         //            the color values we set in weaponChange.
  3361.         cursor->Redraw( gameLocal.time );
  3362.         cursor->HandleNamedEvent( "weaponChange" );
  3363.     }
  3364.  
  3365.     hud->HandleNamedEvent( "weaponChange" );
  3366.     hud->StateChanged( gameLocal.time );             
  3367.     weaponChangeIconsUp = true;
  3368. }
  3369.  
  3370. /*
  3371. ===============
  3372. idPlayer::StartRadioChatter
  3373. ===============
  3374. */
  3375. void idPlayer::StartRadioChatter ( void ) {
  3376.     if ( hud ) {
  3377.         hud->HandleNamedEvent( "radioChatterUp" );
  3378.     }
  3379.     if ( vehicleController.IsDriving ( ) ) {
  3380.         vehicleController.StartRadioChatter ( );
  3381.     }
  3382. }
  3383.  
  3384. /*
  3385. ===============
  3386. idPlayer::StopRadioChatter
  3387. ===============
  3388. */
  3389. void idPlayer::StopRadioChatter ( void ) {
  3390.     if ( hud ) {
  3391.         hud->HandleNamedEvent( "radioChatterDown" );
  3392.     }
  3393.     if ( vehicleController.IsDriving( ) ) {
  3394.         vehicleController.StopRadioChatter( );
  3395.     }
  3396. }
  3397.  
  3398. /*
  3399. ===============
  3400. idPlayer::DrawShadow
  3401. ===============
  3402. */
  3403. void idPlayer::DrawShadow( renderEntity_t *headRenderEnt ) {
  3404.     if ( gameLocal.isMultiplayer && g_skipPlayerShadowsMP.GetBool() ) {
  3405.         // Disable all player shadows for the local client
  3406.         renderEntity.suppressShadowInViewID    = gameLocal.localClientNum+1;
  3407.          if ( headRenderEnt ) {
  3408.              headRenderEnt->suppressShadowInViewID = gameLocal.localClientNum+1;
  3409.            }
  3410.     } else if ( gameLocal.isMultiplayer || g_showPlayerShadow.GetBool() || pm_thirdPerson.GetBool() ) {
  3411.         // Show all player shadows
  3412.         renderEntity.suppressShadowInViewID    = 0;
  3413.          if ( headRenderEnt ) {
  3414.             headRenderEnt->suppressShadowInViewID = 0;
  3415.         }
  3416.     } else {
  3417.         // Only show player shadows for other clients
  3418.         renderEntity.suppressShadowInViewID    = entityNumber+1;
  3419.          if ( headRenderEnt ) {
  3420.              headRenderEnt->suppressShadowInViewID = entityNumber+1;
  3421.            }
  3422.     }
  3423. }
  3424.  
  3425. /*
  3426. ===============
  3427. idPlayer::DrawHUD
  3428. ===============
  3429. */
  3430. void idPlayer::DrawHUD( idUserInterface *_hud ) {
  3431.     idUserInterface * cursor = idPlayer::cursor;
  3432.  
  3433.      // if updating the hud of a followed client
  3434.      if ( gameLocal.localClientNum >= 0 && gameLocal.entities[ gameLocal.localClientNum ] ) {
  3435.          idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ gameLocal.localClientNum ] );
  3436.          if ( p->spectating && p->spectator == entityNumber ) {
  3437.             cursor = p->GetCursorGUI();
  3438.             if ( cursor ) {
  3439.                 cursor->HandleNamedEvent( "showCrossCombat" );
  3440.             }
  3441.          }
  3442.      }
  3443.  
  3444.     if ( disableHud || influenceActive != INFLUENCE_NONE || privateCameraView || !_hud || !g_showHud.GetBool() ) {
  3445.         return;
  3446.     }
  3447.  
  3448.     if ( objectiveSystemOpen ) {
  3449.         if ( !GuiActive() ) {
  3450.             // showing weapon zoom gui when objectives are open because that's the way I'z told to make it werkz
  3451.             if ( weapon && weapon->GetZoomGui( ) && zoomed ) {
  3452.                 weapon->GetZoomGui( )->Redraw( gameLocal.time );
  3453.             }
  3454.         }
  3455.         return;
  3456.     }
  3457.  
  3458.     if ( gameLocal.isMultiplayer ) {
  3459.         _hud->SetStateBool( "mp", true );
  3460.     } else {
  3461.         _hud->SetStateBool( "mp", false );
  3462.     }
  3463.  
  3464.     // Draw the cinematic hud when in a cinematic
  3465.     if ( gameLocal.GetCamera( ) ) {
  3466.         if ( cinematicHud && !(gameLocal.editors & EDITOR_MODVIEW) ) {
  3467.             cinematicHud->Redraw( gameLocal.time );
  3468.         }
  3469.         return;
  3470.     }
  3471.     
  3472.     // Let the vehicle draw the hud instead
  3473.     if ( vehicleController.IsDriving( ) ) {
  3474.         if ( !gameDebug.IsHudActive( DBGHUD_ANY ) ) {
  3475.             if ( cursor && health > 0 ) {            
  3476.                 // mekberg: adjustable crosshair size.
  3477.                 int crossSize = cvarSystem->GetCVarInteger( "g_crosshairSize" );
  3478.                 crossSize = crossSize - crossSize % 8;
  3479.                 cvarSystem->SetCVarInteger( "g_crosshairSize", crossSize );
  3480.                 cursor->SetStateInt( "g_crosshairSize", crossSize );
  3481.  
  3482.                 vehicleController.UpdateCursorGUI( cursor );
  3483.                 cursor->Redraw( gameLocal.time );
  3484.             }
  3485.             vehicleController.DrawHUD( );
  3486.         }
  3487.         _hud = GetHud();
  3488.         // Boss bar
  3489.         if ( _hud && _hud->State().GetInt( "boss_health", "-1" ) != (bossEnemy ? bossEnemy->health : -1) ) {
  3490.             if ( !bossEnemy || bossEnemy->health <= 0 ) {
  3491.                 bossEnemy = NULL;
  3492.                 _hud->SetStateInt( "boss_health", -1 );
  3493.                 _hud->HandleNamedEvent( "hideBossBar" );            
  3494.                  _hud->HandleNamedEvent( "hideBossShieldBar" ); // grrr, for boss buddy..but maybe other bosses will have shields?
  3495.             } else {            
  3496.                 _hud->SetStateInt( "boss_health", bossEnemy->health );
  3497.                 _hud->HandleNamedEvent( "updateBossBar" );
  3498.             }
  3499.         }
  3500.         return;
  3501.     }
  3502.     
  3503.     // FIXME: this is temp to allow the sound meter to show up in the hud
  3504.     // it should be commented out before shipping but the code can remain
  3505.     // for mod developers to enable for the same functionality
  3506.     _hud->SetStateInt( "s_debug", cvarSystem->GetCVarInteger( "s_showLevelMeter" ) );
  3507.  
  3508.     // don't draw main hud in spectator (only mphud)
  3509.     if ( !spectating && !gameDebug.IsHudActive( DBGHUD_ANY ) ) {
  3510.         // weapon targeting crosshair
  3511.         if ( !GuiActive() ) {
  3512.             if ( weapon && weapon->GetZoomGui( ) && zoomed ) {
  3513.                 weapon->GetZoomGui( )->Redraw( gameLocal.time );
  3514.             }
  3515. // RAVEN BEGIN
  3516. // mekberg: removed check for weapon->ShowCrosshair.
  3517. //            we want to show the crosshair regardless for NPC tags
  3518.             if ( cursor && health > 0 ) {        
  3519.                 // Pass the current weapon to the cursor gui for custom crosshairs
  3520. // mekberg: adjustable crosshair size.
  3521.                 int crossSize = cvarSystem->GetCVarInteger( "g_crosshairSize" );
  3522.                 crossSize = crossSize - crossSize % 8;
  3523.                 cvarSystem->SetCVarInteger( "g_crosshairSize", crossSize );
  3524.                 cursor->SetStateInt( "g_crosshairSize", crossSize );
  3525. // RAVEN END
  3526.                 cursor->Redraw( gameLocal.time );
  3527.             }
  3528.         }    
  3529.  
  3530.         UpdateHudStats( _hud );
  3531.  
  3532.         if ( focusBrackets ) {
  3533.             // If 2d_calc is still true then the gui didnt render so we can abandon it
  3534.             if ( focusBrackets->State().GetBool( "2d_calc" ) ) {
  3535.                 focusBrackets->SetStateBool( "2d_calc", false );
  3536.                 focusBrackets = NULL;
  3537.                 focusBracketsTime = 0;
  3538.                 _hud->HandleNamedEvent( "hideBrackets" );
  3539.             } else {
  3540.                 _hud->SetStateString( "bracket_left", focusBrackets->State().GetString( "2d_min_x" ) );
  3541.                 _hud->SetStateString( "bracket_top", focusBrackets->State().GetString( "2d_min_y" ) );
  3542.                 _hud->SetStateFloat( "bracket_width", focusBrackets->State().GetFloat( "2d_max_x" ) - focusBrackets->State().GetFloat( "2d_min_x" ) );
  3543.                 _hud->SetStateFloat( "bracket_height", focusBrackets->State().GetFloat( "2d_max_y" ) - focusBrackets->State().GetFloat( "2d_min_y" ) );
  3544.                 // TODO: Find a way to get bracket text from gui to hud
  3545.             }
  3546.         }        
  3547.          _hud->Redraw( gameLocal.realClientTime );
  3548.     }
  3549.  
  3550.     if ( gameLocal.isMultiplayer ) {
  3551.         idUserInterface* _mphud = mphud;
  3552.         // if we're spectating someone else, use our local hud
  3553.         if ( gameLocal.GetLocalPlayer() != this ) {
  3554.             _mphud = gameLocal.GetLocalPlayer()->mphud;
  3555.         }
  3556.         if ( _mphud ) {
  3557.             gameLocal.mpGame.UpdateHud( _mphud );
  3558.             _mphud->Redraw( gameLocal.time );
  3559.         }
  3560.         
  3561.         if ( overlayHud && overlayHudTime > gameLocal.time && overlayHudTime != 0 ) {
  3562.             overlayHud->Redraw( gameLocal.time );
  3563.         } else {
  3564.             overlayHud = NULL;
  3565.             overlayHudTime = 0;
  3566.         }
  3567.     }
  3568. }
  3569.  
  3570. /*
  3571. ===============
  3572. idPlayer::EnterCinematic
  3573. ===============
  3574. */
  3575. void idPlayer::EnterCinematic( void ) {
  3576.     Hide();
  3577.  
  3578. // RAVEN BEGIN
  3579. // jnewquist: Cinematics are letterboxed, this auto-fixes on widescreens
  3580.     g_fixedHorizFOV.SetBool(true);
  3581. // RAVEN END
  3582.  
  3583.        if ( hud ) {
  3584.            hud->HandleNamedEvent( "radioChatterDown" );
  3585.        }
  3586.        
  3587.        cinematicHud = NULL;
  3588.        
  3589.     // See if camera has custom cinematic gui
  3590.        if ( gameLocal.GetCamera ( ) ) {
  3591.            const char* guiCinematic;
  3592.            guiCinematic = gameLocal.GetCamera()->spawnArgs.GetString ( "guiCinematic", "" );
  3593.            if ( *guiCinematic ) {
  3594.             cinematicHud = uiManager->FindGui( guiCinematic, true, false, true );           
  3595.         }
  3596.     }
  3597.  
  3598.     // Load default cinematic gui?
  3599.     if ( !cinematicHud ) {    
  3600.         const char* temp;
  3601.         if ( spawnArgs.GetString ( "cinematicHud", "", &temp ) ) {
  3602.             cinematicHud = uiManager->FindGui( temp, true, false, true );
  3603.         }
  3604.     }
  3605.     
  3606.        // Have the cinematic hud start
  3607.        if ( cinematicHud ) {    
  3608.            cinematicHud->Activate ( true, gameLocal.time );
  3609.            cinematicHud->HandleNamedEvent ( "cinematicStart" );
  3610. // RAVEN BEGIN
  3611. // jnewquist: Option to adjust vertical fov instead of horizontal for non 4:3 modes
  3612.         if ( cvarSystem->GetCVarInteger( "r_aspectRatio" ) != 0 ) {
  3613.             cinematicHud->HandleNamedEvent ( "hideLetterbox" );
  3614.         }
  3615. // RAVEN END
  3616.        }
  3617.        
  3618.        physicsObj.SetLinearVelocity( vec3_origin );
  3619.        
  3620.      if ( weaponEnabled && weapon ) {
  3621.         //this preSave kills all effects and sounds that we don't need lingering around.
  3622.            weapon->PreSave();
  3623.         weapon->EnterCinematic();
  3624.        }
  3625.  
  3626.     // Reset state flags   
  3627.     memset ( &pfl, 0, sizeof(pfl) );
  3628.     pfl.onGround = true;
  3629.     pfl.dead     = (health <= 0);
  3630. }
  3631.    
  3632. /*
  3633. ===============
  3634. idPlayer::ExitCinematic
  3635. ===============
  3636. */
  3637. void idPlayer::ExitCinematic( void ) {
  3638.       Show();
  3639.    
  3640. // RAVEN BEGIN
  3641. // jnewquist: Cinematics are letterboxed, this auto-fixes on widescreens
  3642.     g_fixedHorizFOV.SetBool(false);
  3643. // RAVEN END
  3644.  
  3645.      if ( weaponEnabled && weapon ) {
  3646.         //and this will restore them!
  3647.         weapon->PostSave();
  3648.            weapon->ExitCinematic();
  3649.        }
  3650.    
  3651.        SetAnimState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
  3652.     SetAnimState( ANIMCHANNEL_LEGS, "Legs_Idle", 0 );
  3653.  
  3654.        UpdateState();
  3655. }
  3656.  
  3657. /*
  3658. ===============
  3659. idPlayer::SkipCinematic
  3660. ===============
  3661. */
  3662. bool idPlayer::SkipCinematic( void ) {
  3663.     StartSound( "snd_skipcinematic", SND_CHANNEL_ANY, 0, false, NULL );
  3664.     return gameLocal.SkipCinematic();
  3665. }
  3666.    
  3667. /*
  3668. =====================
  3669. idPlayer::UpdateConditions
  3670. =====================
  3671. */
  3672. void idPlayer::UpdateConditions( void ) {
  3673.     idVec3    velocity;
  3674.     float    fallspeed;
  3675.     float    forwardspeed;
  3676.     float    sidespeed;
  3677.  
  3678.     // minus the push velocity to avoid playing the walking animation and sounds when riding a mover
  3679.     velocity = physicsObj.GetLinearVelocity() - physicsObj.GetPushedLinearVelocity();
  3680.     fallspeed = velocity * physicsObj.GetGravityNormal();
  3681.  
  3682.      if ( influenceActive ) {
  3683.          pfl.forward        = false;
  3684.          pfl.backward    = false;
  3685.          pfl.strafeLeft    = false;
  3686.          pfl.strafeRight    = false;
  3687.     } else if ( gameLocal.time - lastDmgTime < 500 ) {
  3688.         forwardspeed    = velocity * viewAxis[ 0 ];
  3689.         sidespeed        = velocity * viewAxis[ 1 ];
  3690.         pfl.forward        = pfl.onGround && ( forwardspeed > 20.01f );
  3691.         pfl.backward    = pfl.onGround && ( forwardspeed < -20.01f );
  3692.         pfl.strafeLeft    = pfl.onGround && ( sidespeed > 20.01f );
  3693.         pfl.strafeRight    = pfl.onGround && ( sidespeed < -20.01f );
  3694.      } else if ( xyspeed > MIN_BOB_SPEED ) {
  3695.         pfl.forward        = pfl.onGround && ( usercmd.forwardmove > 0 );
  3696.         pfl.backward    = pfl.onGround && ( usercmd.forwardmove < 0 );
  3697.         pfl.strafeLeft    = pfl.onGround && ( usercmd.rightmove < 0 );
  3698.         pfl.strafeRight    = pfl.onGround && ( usercmd.rightmove > 0 );
  3699.      } else {
  3700.          pfl.forward        = false;
  3701.          pfl.backward    = false;
  3702.          pfl.strafeLeft    = false;
  3703.          pfl.strafeRight    = false;
  3704.        }
  3705.  
  3706.     pfl.run        = 1;
  3707.      pfl.dead    = ( health <= 0 );
  3708. }
  3709.  
  3710. /*
  3711. ==================
  3712. idPlayer::WeaponFireFeedback
  3713.  
  3714. Called when a weapon fires, generates head twitches, etc
  3715. ==================
  3716. */
  3717. void idPlayer::WeaponFireFeedback( const idDict *weaponDef ) {
  3718.     // force a blink
  3719.     blink_time = 0;
  3720.  
  3721.     // play the fire animation
  3722.     pfl.weaponFired = true;
  3723.  
  3724.     // Bias the intent direction more heavily due to firing
  3725.     BiasIntentDir( viewAxis[0]*100.0f, 1.0f );
  3726.  
  3727.     // update view feedback
  3728.     playerView.WeaponFireFeedback( weaponDef );
  3729. }
  3730.  
  3731. /*
  3732. ===============
  3733. idPlayer::StopFiring
  3734. ===============
  3735. */
  3736. void idPlayer::StopFiring( void ) {
  3737.     pfl.attackHeld    = false;
  3738.     pfl.weaponFired = false;
  3739.     pfl.reload        = false;
  3740.     if ( weapon ) {
  3741.         weapon->EndAttack();
  3742.     }
  3743. }
  3744.  
  3745. /*
  3746. ===============
  3747. idPlayer::FireWeapon
  3748. ===============
  3749. */
  3750. void idPlayer::FireWeapon( void ) {
  3751.     idMat3 axis;
  3752.     idVec3 muzzle;
  3753.  
  3754.     if ( privateCameraView ) {
  3755.         return;
  3756.     }
  3757.  
  3758.     if ( g_editEntityMode.GetInteger() ) {
  3759.         GetViewPos( muzzle, axis );
  3760.         gameLocal.editEntities->SelectEntity( muzzle, axis[0], this );    
  3761.         return;
  3762.     }
  3763.  
  3764.     if ( !hiddenWeapon && weapon->IsReady() ) {
  3765.         if ( weapon->AmmoInClip() || weapon->AmmoAvailable() ) {
  3766.             pfl.attackHeld = true;
  3767.             weapon->BeginAttack();
  3768.         } else {
  3769.             pfl.attackHeld = false;
  3770.             pfl.weaponFired = false;
  3771.             StopFiring();
  3772.             NextBestWeapon();
  3773.         }
  3774.     }
  3775.     // If reloading when fire is hit cancel the reload
  3776.     else if ( weapon->IsReloading ( ) ) {
  3777.         weapon->CancelReload ( );
  3778.     }
  3779. /* twhitaker: removed this at the request of Matt Vainio.
  3780.     if ( !gameLocal.isMultiplayer ) {
  3781.         if ( hud && tipUp ) {
  3782.             HideTip();
  3783.         }
  3784.         // may want to track with with a bool as well
  3785.         // keep from looking up named events so often
  3786.         if ( objectiveSystem && objectiveUp ) {
  3787.             HideObjective();
  3788.         }
  3789.     }
  3790. */
  3791.     if( hud && weaponChangeIconsUp ) {
  3792.         hud->HandleNamedEvent( "weaponFire" );
  3793.         // nrausch: objectiveSystem does not necessarily exist (in mp it doesn't)
  3794.         if ( objectiveSystem ) {
  3795.             objectiveSystem->HandleNamedEvent( "weaponFire" );
  3796.         }
  3797.         weaponChangeIconsUp = false;
  3798.     }
  3799. }
  3800.  
  3801. /*
  3802. ===============
  3803. idPlayer::CacheWeapons
  3804. ===============
  3805. */
  3806. void idPlayer::CacheWeapons( void ) {
  3807.     idStr    weap;
  3808.     int        w;
  3809.  
  3810.     // check if we have any weapons
  3811.     if ( !inventory.weapons ) {
  3812.         return;
  3813.     }
  3814.     
  3815.     for( w = 0; w < MAX_WEAPONS; w++ ) {
  3816.         if ( inventory.weapons & ( 1 << w ) ) {
  3817.             if ( !GetWeaponDef ( w ) ) {
  3818.                 inventory.weapons &= ~( 1 << w );
  3819.             } else {
  3820.                 rvWeapon::CacheWeapon( spawnArgs.GetString( va( "def_weapon%d", w ) ) );
  3821.             }        
  3822.         }
  3823.     }
  3824. }
  3825.  
  3826. /*
  3827. ===============
  3828. idPlayer::Give
  3829. ===============
  3830. */
  3831. bool idPlayer::Give( const char *statname, const char *value, bool dropped ) {
  3832.     int amount;
  3833.  
  3834.     if ( pfl.dead ) {
  3835.         return false;
  3836.     }
  3837.  
  3838.     if ( IsInVehicle ( ) ) {
  3839.         vehicleController.Give ( statname, value );
  3840.     }
  3841.  
  3842.     int boundaryHealth = inventory.maxHealth;
  3843.     int boundaryArmor = inventory.maxarmor;
  3844.     if( PowerUpActive( POWERUP_GUARD ) ) {
  3845.         boundaryHealth = inventory.maxHealth / 2;
  3846.         boundaryArmor = inventory.maxarmor / 2;
  3847.     }
  3848.     if( PowerUpActive( POWERUP_SCOUT ) ) {
  3849.         boundaryArmor = 0;
  3850.     }
  3851.     if ( gameLocal.isMultiplayer ) {
  3852.         //In MP, you can get twice your max from pickups
  3853.         boundaryArmor *= 2;
  3854.     }
  3855.  
  3856.     if ( !idStr::Icmp( statname, "health" ) ) {
  3857.         if ( health >= boundaryHealth ) {
  3858.             return false;
  3859.         }
  3860.          amount = atoi( value );
  3861.          if ( amount ) {
  3862.              health += amount;
  3863.              if ( health > boundaryHealth ) {
  3864.                  health = boundaryHealth;
  3865.              }
  3866.         }
  3867.     } else if ( !idStr::Icmp( statname, "bonushealth" ) ) {
  3868.         // allow health over max health
  3869.         if ( health >= boundaryHealth * 2 ) {
  3870.             return false;
  3871.         }
  3872.         amount = atoi( value );
  3873.          if ( amount ) {
  3874.              health += amount;
  3875.              if ( health > boundaryHealth * 2 ) {
  3876.                  health = boundaryHealth * 2;
  3877.              }
  3878.         }
  3879.         nextHealthPulse = gameLocal.time + HEALTH_PULSE;
  3880.     } else if ( !idStr::Icmp( statname, "armor" ) ) {
  3881.         if ( inventory.armor >= boundaryArmor ) {
  3882.             return false;
  3883.         }
  3884.         amount = atoi( value );
  3885.  
  3886.         inventory.armor += amount;
  3887.         if ( inventory.armor > boundaryArmor ) {
  3888.              inventory.armor = boundaryArmor;
  3889.         }
  3890.         nextArmorPulse = gameLocal.time + ARMOR_PULSE;
  3891.     } else if ( !idStr::Icmp( statname, "air" ) ) {
  3892.         if ( airTics >= pm_airTics.GetInteger() ) {
  3893.             return false;
  3894.         }
  3895.         airTics += atoi( value ) / 100.0 * pm_airTics.GetInteger();
  3896.         if ( airTics > pm_airTics.GetInteger() ) {
  3897.             airTics = pm_airTics.GetInteger();
  3898.         }
  3899.     } else if ( !idStr::Icmp ( statname, "weaponmod" ) ) {
  3900.         if( !idStr::Icmp( value, "all" ) ) {
  3901.             for( int i = 0; i < MAX_WEAPONS; i++ ) {
  3902.                 if ( inventory.weapons & ( 1 << i ) ) {
  3903.                     GiveWeaponMods( i, 0xFFFFFFFF );
  3904.                 }
  3905.             }
  3906.         } else {
  3907.             const char* pos = value;
  3908.  
  3909.             while( pos != NULL ) {
  3910.                 const char* end = strchr( pos, ',' );
  3911.                 int            len;
  3912.                 if ( end ) {
  3913.                     len = end - pos;
  3914.                     end++;
  3915.                 } else {
  3916.                     len = strlen( pos );
  3917.                 }
  3918.  
  3919.                 idStr weaponMod ( pos, 0, len );
  3920.                 GiveWeaponMod ( weaponMod );
  3921.  
  3922.                 pos = end;
  3923.             }
  3924.         }
  3925.     } else {
  3926.          return inventory.Give( this, spawnArgs, statname, value, &idealWeapon, true, dropped );
  3927.     }
  3928.     return true;
  3929. }
  3930.  
  3931. /*
  3932. ===============
  3933. idPlayer::GiveItem
  3934.  
  3935. Returns false if the item shouldn't be picked up
  3936. ===============
  3937. */
  3938. bool idPlayer::GiveItem( idItem *item ) {
  3939.     int                    i;
  3940.     const idKeyValue    *arg;
  3941.     idDict                attr;
  3942.     bool                gave;
  3943.  
  3944.     if ( gameLocal.isMultiplayer && spectating ) {
  3945.         return false;
  3946.     }
  3947.  
  3948.     item->GetAttributes( attr );
  3949.  
  3950.     if( gameLocal.isServer || !gameLocal.isMultiplayer ) {
  3951.         gave = false;
  3952.         bool dropped = false;
  3953.         bool skipWeaponKey = false;
  3954.         bool skipRestOfKeys = false;
  3955.         if ( gameLocal.IsMultiplayer() ) {
  3956.             dropped = item->spawnArgs.GetBool( "dropped" );
  3957.             if ( item->spawnArgs.FindKey( "weaponclass" ) ) {
  3958.                 //this is really fucking lame, but
  3959.                 //this is the only way we know we're trying
  3960.                 //to pick up a weapon before we blindly start
  3961.                 //processesing the attribute arguments in
  3962.                 //whatever order they're in below.  We need
  3963.                 //to not process any at all if we're not allowed
  3964.                 //to pick up the weapon in the first place!
  3965.                 arg = attr.FindKey( "weapon" );
  3966.                 if ( arg ) {
  3967.                     skipWeaponKey = true;
  3968.                     if ( Give( arg->GetKey(), arg->GetValue(), dropped ) ) {
  3969.                         gave = true;
  3970.                     } else if ( !dropped//not a dropped weapon
  3971.                         && gameLocal.serverInfo.GetBool( "si_weaponStay" ) ) {
  3972.                         //if failed to give weapon, don't give anything else with the weapon
  3973.                         skipRestOfKeys = true;
  3974.                     }
  3975.                 }
  3976.             }
  3977.         }
  3978.         if ( !skipRestOfKeys ) {
  3979.             for( i = 0; i < attr.GetNumKeyVals(); i++ ) {
  3980.                 arg = attr.GetKeyVal( i );
  3981.                 if ( skipWeaponKey && arg->GetKey() == "weapon" ) {
  3982.                     //already processed this above
  3983.                     continue;
  3984.                 }
  3985.                 if ( Give( arg->GetKey(), arg->GetValue(), dropped ) ) {
  3986.                     gave = true;
  3987.                 }
  3988.             }
  3989.         }
  3990.  
  3991.         // hack - powerups call into this code to let them give stuff based on inv_ keywords
  3992.         // for powerups that don't have any ammo/etc to give to the player, we still want to
  3993.         // display the inv_name on the hud
  3994.         // since idItemPowerup::GiveToPlayer() handles whether or not a player gets a powerup,
  3995.         // we can override gave here for powerups
  3996.         if ( !gave && !item->IsType( idItemPowerup::GetClassType() ) ) {
  3997.             return false;
  3998.         }
  3999.     } else {
  4000.         gave = true;
  4001.     }
  4002.  
  4003.     arg = item->spawnArgs.MatchPrefix( "inv_ammo_", NULL );
  4004.     if ( arg && hud ) {
  4005.         hud->HandleNamedEvent( "ammoPulse" );
  4006.     }
  4007.     arg = item->spawnArgs.MatchPrefix( "inv_health", NULL );
  4008.     if ( arg && hud ) {
  4009.         hud->HandleNamedEvent( "healthPulse" );
  4010.     }
  4011.     arg = item->spawnArgs.MatchPrefix( "inv_weapon", NULL );
  4012.     if ( arg && hud ) {
  4013.         // We need to update the weapon hud manually, but not
  4014.         // the armor/ammo/health because they are updated every
  4015.         // frame no matter what
  4016.         if ( gameLocal.isMultiplayer ) {
  4017.             UpdateHudWeapon( );
  4018.         } else {
  4019.             //so weapon mods highlight the correct weapon when received
  4020.             int weapon = SlotForWeapon ( arg->GetValue() );
  4021.             UpdateHudWeapon( weapon );
  4022.         }
  4023.         hud->HandleNamedEvent( "weaponPulse" );
  4024.     }
  4025.     arg = item->spawnArgs.MatchPrefix( "inv_armor", NULL );
  4026.     if ( arg && hud ) {
  4027.         hud->HandleNamedEvent( "armorPulse" );
  4028.     }
  4029.     
  4030. //    GiveDatabaseEntry ( &item->spawnArgs );
  4031.     
  4032.     // Show the item pickup on the hud
  4033.     if ( hud ) {
  4034.         idStr langToken = item->spawnArgs.GetString( "inv_name" );
  4035.         hud->SetStateString ( "itemtext", common->GetLocalizedString( langToken ) );
  4036.         hud->SetStateString ( "itemicon", item->spawnArgs.GetString( "inv_icon" ) );
  4037.         hud->HandleNamedEvent ( "itemPickup" );
  4038.     }
  4039.  
  4040.     return gave;
  4041. }
  4042.  
  4043. /*
  4044. ===============
  4045. idPlayer::PowerUpModifier
  4046. ===============
  4047. */
  4048. float idPlayer::PowerUpModifier( int type ) {
  4049.     float mod = 1.0f;
  4050.  
  4051.     if ( PowerUpActive( POWERUP_QUADDAMAGE ) ) {
  4052.         switch( type ) {
  4053.             case PMOD_PROJECTILE_DAMAGE: {
  4054.                 mod *= 3.0f;
  4055.                 break;
  4056.             }
  4057.             case PMOD_MELEE_DAMAGE: {
  4058.                 mod *= 3.0f;
  4059.                 break;
  4060.             }
  4061.             case PMOD_PROJECTILE_DEATHPUSH: {
  4062.                 mod *= 2.0f;
  4063.                 break;
  4064.             }
  4065.         }
  4066.     }
  4067.  
  4068.     if ( PowerUpActive( POWERUP_HASTE ) ) {
  4069.         switch ( type ) {
  4070.             case PMOD_SPEED:    
  4071.                 mod *= 1.3f;
  4072.                 break;
  4073.  
  4074.             case PMOD_FIRERATE:
  4075.                 mod *= 0.7f;
  4076.                 break;
  4077.         }
  4078.     }
  4079.  
  4080.     // Arena CTF powerups
  4081.     if( PowerUpActive( POWERUP_AMMOREGEN ) ) {
  4082.         switch( type ) {
  4083.             case PMOD_FIRERATE: {
  4084.                 mod *= 0.7f;
  4085.                 break;
  4086.             }
  4087.         }
  4088.     }
  4089.  
  4090.     if( PowerUpActive( POWERUP_DOUBLER ) ) {
  4091.         switch( type ) {
  4092.             case PMOD_PROJECTILE_DAMAGE: {
  4093.                 mod *= 2.0f;
  4094.                 break;
  4095.             }
  4096.             case PMOD_MELEE_DAMAGE: {
  4097.                 mod *= 2.0f;
  4098.                 break;
  4099.             }
  4100.         }
  4101.     }
  4102.  
  4103.     if( PowerUpActive( POWERUP_SCOUT ) ) {
  4104.         switch( type ) {
  4105.             case PMOD_FIRERATE: {
  4106.                 mod *= (2.0f / 3.0f);
  4107.                 break;
  4108.             }
  4109.             case PMOD_SPEED: {    
  4110.                 mod *= 1.5f;
  4111.                 break;
  4112.             }
  4113.         }
  4114.     }
  4115.  
  4116.     return mod;
  4117. }
  4118.  
  4119. /*
  4120. ===============
  4121. idPlayer::PowerUpActive
  4122. ===============
  4123. */
  4124. bool idPlayer::PowerUpActive( int powerup ) const {
  4125.     return ( inventory.powerups & ( 1 << powerup ) ) != 0;
  4126. }
  4127.  
  4128. /*
  4129. ===============
  4130. idPlayer::StartPowerUpEffect
  4131. ===============
  4132. */
  4133. void idPlayer::StartPowerUpEffect( int powerup ) {
  4134.  
  4135.     switch( powerup ) {
  4136.         case POWERUP_CTF_MARINEFLAG: {
  4137.             AddClientModel ( "mp_ctf_flag_pole" );
  4138.             AddClientModel ( "mp_ctf_marine_flag_world" );
  4139.             flagEffect = PlayEffect( "fx_ctf_marine_flag_world", animator.GetJointHandle( spawnArgs.GetString( "flagEffectJoint" ) ), spawnArgs.GetVector( "flagEffectOrigin" ), physicsObj.GetAxis(), true );
  4140.             break;
  4141.         }
  4142.  
  4143.         case POWERUP_CTF_STROGGFLAG: {
  4144.             AddClientModel ( "mp_ctf_flag_pole" );
  4145.             AddClientModel ( "mp_ctf_strogg_flag_world" );
  4146.             flagEffect = PlayEffect( "fx_ctf_strogg_flag_world", animator.GetJointHandle( spawnArgs.GetString( "flagEffectJoint" ) ), spawnArgs.GetVector( "flagEffectOrigin" ), physicsObj.GetAxis(), true );
  4147.             break;
  4148.         }
  4149.  
  4150.         case POWERUP_CTF_ONEFLAG: {
  4151.             AddClientModel ( "mp_ctf_one_flag" );
  4152.             break;
  4153.         }
  4154.  
  4155.         case POWERUP_QUADDAMAGE: {
  4156.             powerUpOverlay = quadOverlay;
  4157.  
  4158.             StopEffect ( "fx_regeneration" );
  4159.             PlayEffect ( "fx_quaddamage", animator.GetJointHandle( "chest" ), true );            
  4160.             StartSound ( "snd_quaddamage_idle", SND_CHANNEL_POWERUP_IDLE, 0, false, NULL );
  4161.  
  4162.             // Spawn quad effect
  4163.             powerupEffect = gameLocal.GetEffect ( spawnArgs, "fx_quaddamage_crawl" );
  4164.             powerupEffectTime = gameLocal.time;
  4165.             powerupEffectType = POWERUP_QUADDAMAGE;
  4166.  
  4167.             break;
  4168.         }
  4169.  
  4170.         case POWERUP_REGENERATION: {
  4171.             powerUpOverlay = regenerationOverlay;
  4172.  
  4173.             StopEffect ( "fx_quaddamage" );
  4174.             PlayEffect ( "fx_regeneration", animator.GetJointHandle( "chest" ), true );
  4175.  
  4176.             // Spawn quad effect
  4177.             powerupEffect = gameLocal.GetEffect ( spawnArgs, "fx_regeneration" );            
  4178.             powerupEffectTime = gameLocal.time;
  4179.             powerupEffectType = POWERUP_REGENERATION;
  4180.  
  4181.             break;
  4182.         }
  4183.  
  4184.         case POWERUP_HASTE: {
  4185.             powerUpOverlay = hasteOverlay;
  4186.  
  4187.             hasteEffect = PlayEffect ( "fx_haste", GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), true );
  4188.             break;
  4189.         }
  4190.         
  4191.         case POWERUP_INVISIBILITY: {
  4192.             powerUpOverlay = invisibilityOverlay;
  4193.  
  4194.             powerUpSkin = declManager->FindSkin( spawnArgs.GetString( "skin_invisibility" ), false );
  4195.             break;
  4196.         }
  4197.  
  4198.         case POWERUP_GUARD: {
  4199.             PlayEffect ( "fx_guard", physicsObj.GetOrigin(), physicsObj.GetAxis(), true );
  4200.             break;
  4201.         }
  4202.         
  4203.         case POWERUP_SCOUT: {
  4204.             PlayEffect ( "fx_scout", physicsObj.GetOrigin(), physicsObj.GetAxis(), true );
  4205.             break;
  4206.         }
  4207.         
  4208.         case POWERUP_AMMOREGEN: {
  4209.             PlayEffect ( "fx_ammoregen", physicsObj.GetOrigin(), physicsObj.GetAxis(), true );
  4210.             break;
  4211.         }
  4212.         
  4213.         case POWERUP_DOUBLER: {
  4214.             PlayEffect ( "fx_doubler", physicsObj.GetOrigin(), physicsObj.GetAxis(), true );
  4215.             break;
  4216.         }
  4217.     }
  4218. }
  4219.  
  4220. /*
  4221. ===============
  4222. idPlayer::StopPowerUpEffect
  4223. ===============
  4224. */
  4225. void idPlayer::StopPowerUpEffect( int powerup ) {
  4226.     //if the player doesn't have quad, regen, haste or invisibility remaining on him, remove the power up overlay.
  4227.     if( !( 
  4228.         (inventory.powerups & ( 1 << POWERUP_QUADDAMAGE ) ) || 
  4229.         (inventory.powerups & ( 1 << POWERUP_REGENERATION ) ) || 
  4230.         (inventory.powerups & ( 1 << POWERUP_HASTE ) ) || 
  4231.         (inventory.powerups & ( 1 << POWERUP_INVISIBILITY ) ) 
  4232.         ) )    {
  4233.  
  4234.             powerUpOverlay = NULL;
  4235.             StopSound( SND_CHANNEL_POWERUP_IDLE, false );
  4236.         }
  4237.  
  4238.  
  4239.     switch( powerup ) {
  4240.         case POWERUP_QUADDAMAGE: {
  4241.             powerupEffect = NULL;
  4242.             powerupEffectTime = 0;
  4243.             powerupEffectType = 0;
  4244.  
  4245.             StopEffect( "fx_quaddamage" );
  4246.             break;
  4247.         }
  4248.         case POWERUP_REGENERATION: {
  4249.             powerupEffect = NULL;
  4250.             powerupEffectTime = 0;
  4251.             powerupEffectType = 0;
  4252.  
  4253.             StopEffect( "fx_regeneration" );
  4254.             break;
  4255.         }
  4256.         case POWERUP_HASTE: {
  4257.             StopEffect( "fx_haste" );
  4258.             break;
  4259.         }
  4260.         case POWERUP_INVISIBILITY: {
  4261.             powerUpSkin = NULL;
  4262.             break;
  4263.         }
  4264.         case POWERUP_CTF_STROGGFLAG: {
  4265.             RemoveClientModel ( "mp_ctf_flag_pole" );
  4266.             RemoveClientModel ( "mp_ctf_strogg_flag_world" );
  4267.             StopEffect( "fx_ctf_strogg_flag_world" );
  4268.             break;
  4269.         }
  4270.         case POWERUP_CTF_MARINEFLAG: {
  4271.             RemoveClientModel ( "mp_ctf_flag_pole" );
  4272.             RemoveClientModel ( "mp_ctf_marine_flag_world" );
  4273.             StopEffect( "fx_ctf_marine_flag_world" );
  4274.             break;
  4275.         }
  4276.         case POWERUP_CTF_ONEFLAG: {
  4277.             RemoveClientModel ( "mp_ctf_one_flag" );
  4278.             break;
  4279.         }
  4280.         case POWERUP_SCOUT: {
  4281.             StopEffect( "fx_scout" );
  4282.             break;
  4283.         }
  4284.         case POWERUP_GUARD: {
  4285.             StopEffect( "fx_guard" );
  4286.             break;
  4287.         }
  4288.         case POWERUP_DOUBLER: {
  4289.             StopEffect( "fx_doubler" );
  4290.             break;
  4291.         }
  4292.         case POWERUP_AMMOREGEN: {
  4293.             StopEffect( "fx_ammoregen" );
  4294.             break;
  4295.         }
  4296.     }
  4297. }
  4298.  
  4299. /*
  4300. ===============
  4301. idPlayer::GivePowerUp
  4302. passiveEffectsOnly - GivePowerup() is used to restore effects on stale players coming
  4303. back into snapshot.  We don't want to announce powerups in this case 
  4304. (just re-start effects)
  4305. ===============
  4306. */
  4307. bool idPlayer::GivePowerUp( int powerup, int time ) {
  4308.     if ( powerup < 0 || powerup >= POWERUP_MAX ) {
  4309.         gameLocal.Warning( "Player given power up %i\n which is out of range", powerup );
  4310.         return false;
  4311.     }
  4312.  
  4313.     if ( gameLocal.isServer ) {
  4314.         idBitMsg    msg;
  4315.         byte        msgBuf[MAX_EVENT_PARAM_SIZE];
  4316.  
  4317.         msg.Init( msgBuf, sizeof( msgBuf ) );
  4318.         msg.WriteShort( powerup );
  4319.         msg.WriteBits( 1, 1 );
  4320.         ServerSendEvent ( EVENT_POWERUP, &msg, false, -1 );
  4321.     }
  4322.  
  4323.     inventory.GivePowerUp( this, powerup, time );
  4324.  
  4325.     // only start client effects in the same instance
  4326.     bool playClientEffects = ( gameLocal.GetLocalPlayer() && gameLocal.GetLocalPlayer()->GetInstance() == instance );
  4327.  
  4328.     switch( powerup ) {
  4329.         case POWERUP_CTF_MARINEFLAG: {
  4330.             // shouchard:  added notice for picking up the flag
  4331.             if ( playClientEffects && this == gameLocal.GetLocalPlayer() ) {
  4332.                 if ( mphud ) {
  4333.                     mphud->SetStateString( "main_notice_text", common->GetLocalizedString( "#str_104419" ) );
  4334.                     mphud->HandleNamedEvent( "main_notice" );
  4335.                 }
  4336.             }
  4337.             break;
  4338.         }
  4339.  
  4340.         case POWERUP_CTF_STROGGFLAG: {
  4341.             // shouchard:  added notice for picking up the flag
  4342.             if ( playClientEffects && this == gameLocal.GetLocalPlayer() ) {
  4343.                 if ( mphud ) {
  4344.                     mphud->SetStateString( "main_notice_text", common->GetLocalizedString( "#str_104419" ) );
  4345.                     mphud->HandleNamedEvent( "main_notice" );
  4346.                 }
  4347.             }
  4348.             break;
  4349.         }
  4350.  
  4351.         case POWERUP_CTF_ONEFLAG: {
  4352.             // shouchard:  added notice for picking up the flag
  4353.             if ( playClientEffects && this == gameLocal.GetLocalPlayer() ) {
  4354.                 if ( mphud ) {
  4355.                     mphud->SetStateString( "main_notice_text", common->GetLocalizedString( "#str_104419" ) );
  4356.                     mphud->HandleNamedEvent( "main_notice" );
  4357.                 }
  4358.             }
  4359.             break;
  4360.         }
  4361.         
  4362.         case POWERUP_QUADDAMAGE: {                
  4363.             gameLocal.mpGame.ScheduleAnnouncerSound( AS_GENERAL_QUAD_DAMAGE, gameLocal.time, gameLocal.gameType == GAME_TOURNEY ? GetArena( ) : -1 );
  4364.             break;
  4365.         }
  4366.  
  4367.         case POWERUP_REGENERATION: {
  4368.             nextHealthPulse = gameLocal.time + HEALTH_PULSE;
  4369.  
  4370.             gameLocal.mpGame.ScheduleAnnouncerSound( AS_GENERAL_REGENERATION, gameLocal.time, gameLocal.gameType == GAME_TOURNEY ? GetArena( ) : -1 );
  4371.             break;
  4372.         }
  4373.         case POWERUP_HASTE: {
  4374.             gameLocal.mpGame.ScheduleAnnouncerSound( AS_GENERAL_HASTE, gameLocal.time, gameLocal.gameType == GAME_TOURNEY ? GetArena( ) : -1 );
  4375.             break;
  4376.         }
  4377.         case POWERUP_INVISIBILITY: {
  4378.             gameLocal.mpGame.ScheduleAnnouncerSound( AS_GENERAL_INVISIBILITY, gameLocal.time, gameLocal.gameType == GAME_TOURNEY ? GetArena( ) : -1 );
  4379.             break;
  4380.         }
  4381.         case POWERUP_GUARD: {
  4382.             nextHealthPulse = gameLocal.time + HEALTH_PULSE;
  4383.             inventory.maxHealth = 200;
  4384.             inventory.maxarmor = 200;
  4385.  
  4386.             break;
  4387.         }
  4388.         case POWERUP_SCOUT: {
  4389.             inventory.armor = 0;
  4390.  
  4391.             break;
  4392.         }
  4393.         case POWERUP_AMMOREGEN: {
  4394.             //noop
  4395.             break;
  4396.         }
  4397.         case POWERUP_DOUBLER: {
  4398.             //noop
  4399.             break;
  4400.         }
  4401.     }
  4402.  
  4403.     // only start effects if in our instances and snapshot
  4404.     if( playClientEffects && !fl.networkStale ) {
  4405.         StartPowerUpEffect( powerup );
  4406.     }
  4407.  
  4408.     return true;
  4409. }
  4410.  
  4411. /*
  4412. ==============
  4413. idPlayer::ClearPowerup
  4414. ==============
  4415. */
  4416. void idPlayer::ClearPowerup( int i ) {
  4417.     if ( gameLocal.isServer ) {
  4418.         idBitMsg    msg;
  4419.         byte        msgBuf[MAX_EVENT_PARAM_SIZE];
  4420.  
  4421.         msg.Init( msgBuf, sizeof( msgBuf ) );
  4422.         msg.WriteShort( i );
  4423.         msg.WriteBits( 0, 1 );
  4424.         ServerSendEvent( EVENT_POWERUP, &msg, false, -1 );
  4425.     }
  4426.  
  4427.      inventory.powerups &= ~( 1 << i );
  4428.     inventory.powerupEndTime[ i ] = 0;
  4429.  
  4430.     //if the player doesn't have quad, regen, haste or invisibility remaining on him, remove the power up overlay.
  4431.     if( !( 
  4432.             (inventory.powerups & ( 1 << POWERUP_QUADDAMAGE ) ) || 
  4433.             (inventory.powerups & ( 1 << POWERUP_REGENERATION ) ) || 
  4434.             (inventory.powerups & ( 1 << POWERUP_HASTE ) ) || 
  4435.             (inventory.powerups & ( 1 << POWERUP_INVISIBILITY ) ) 
  4436.         ) )    {
  4437.  
  4438.         powerUpOverlay = NULL;
  4439.         StopSound( SND_CHANNEL_POWERUP_IDLE, false );
  4440.     }
  4441.     
  4442.     StopPowerUpEffect( i );
  4443. }
  4444.  
  4445. /*
  4446. ==============
  4447. idPlayer::GetArenaPowerupString
  4448. ==============
  4449. */
  4450. const char* idPlayer::GetArenaPowerupString ( void ) {
  4451.     if ( PowerUpActive( POWERUP_SCOUT ) ) {
  4452.         return "^isct";
  4453.     } else if ( PowerUpActive( POWERUP_GUARD ) ) {
  4454.         return "^igrd";
  4455.     } else if ( PowerUpActive( POWERUP_DOUBLER ) ) {
  4456.         return "^idbl";
  4457.     } else if ( PowerUpActive( POWERUP_AMMOREGEN ) ) {
  4458.         return "^irgn";
  4459.     } else {
  4460.         return "";
  4461.     }
  4462. }
  4463.  
  4464. /*
  4465. ==============
  4466. idPlayer::UpdatePowerUps
  4467. ==============
  4468. */
  4469. void idPlayer::UpdatePowerUps( void ) {
  4470.     int i;
  4471.     int index;
  4472.     int wearoff;
  4473.  
  4474.     wearoff = -1;
  4475.     if( hud ) {
  4476.         hud->HandleNamedEvent( "clearPowerups" );
  4477.     }
  4478.  
  4479.     for ( i = 0, index = 0; i < POWERUP_MAX; i++ ) {
  4480.         // Do we have this powerup?
  4481.         if ( !(inventory.powerups & ( 1 << i ) ) ) {
  4482.             continue;
  4483.         }
  4484.             
  4485.         if ( inventory.powerupEndTime[i] > gameLocal.time || inventory.powerupEndTime[i] == -1 ) {
  4486.             // If there is still time remaining on the powerup then update the hud        
  4487.             if ( hud ) {
  4488.                 // Play the wearoff sound for the powerup that is closest to wearing off
  4489.                 if ( ( wearoff == -1 || inventory.powerupEndTime[i] < inventory.powerupEndTime[wearoff] ) && inventory.powerupEndTime[i] != -1 ) {
  4490.                     wearoff = i;
  4491.                 }
  4492.  
  4493.                 // for flags, set the powerup_flag_* variables, which give us a special pulsing flag display
  4494.                 if( i == POWERUP_CTF_MARINEFLAG || i == POWERUP_CTF_STROGGFLAG || i == POWERUP_CTF_ONEFLAG ) {
  4495.                     hud->SetStateInt( "powerup_flag_visible", 1 );
  4496.                 } else {
  4497.                     hud->SetStateString ( va("powerup%d_icon", index ), GetPowerupDef(i)->dict.GetString ( "inv_icon" ) );
  4498.                     hud->SetStateString ( va("powerup%d_time", index ), inventory.powerupEndTime[i] == -1 ? "" : va( "%d" , (int)MS2SEC(inventory.powerupEndTime[i] - gameLocal.time) + 1 ) );
  4499.                     hud->SetStateInt ( va( "powerup%d_visible", index ), 1 );
  4500.                     index++;
  4501.                 }
  4502.             }
  4503.  
  4504.             continue;
  4505.         } else if( inventory.powerupEndTime[ i ] != -1 && gameLocal.isServer ) {
  4506.             // Powerup time has run out so take it away from the player
  4507.             ClearPowerup( i );
  4508.         }
  4509.     }
  4510.  
  4511.     // PLay wear off sound?
  4512.     if ( gameLocal.isNewFrame && wearoff != -1 ) {
  4513.         if ( (inventory.powerupEndTime[wearoff] - gameLocal.time) < POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
  4514.             if ( (inventory.powerupEndTime[wearoff] - gameLocal.time) / POWERUP_BLINK_TIME != ( inventory.powerupEndTime[wearoff] - gameLocal.previousTime ) / POWERUP_BLINK_TIME ) {
  4515.                 StartSound ( "snd_powerup_wearoff", SND_CHANNEL_POWERUP, 0, false, NULL );
  4516.             }
  4517.         }
  4518.     }
  4519.  
  4520.     // Reneration regnerates faster when less than maxHealth and can regenerate up to maxHealth * 2
  4521.     if ( gameLocal.time > nextHealthPulse ) {
  4522.         if ( PowerUpActive ( POWERUP_REGENERATION ) || PowerUpActive ( POWERUP_GUARD ) ) {
  4523.             int healthBoundary = inventory.maxHealth; // health will regen faster under this value, slower above
  4524.             int healthTic = 15;
  4525.  
  4526.             if( PowerUpActive ( POWERUP_GUARD ) ) {
  4527.                 // guard max health == 200, so set the boundary back to 100
  4528.                 healthBoundary = inventory.maxHealth / 2;
  4529.                 if( PowerUpActive (POWERUP_REGENERATION) ) {
  4530.                     healthTic = 30;
  4531.                 }
  4532.             }
  4533.  
  4534.             if ( health < healthBoundary ) {
  4535.                 // only actually give health on the server
  4536.                 if( gameLocal.isServer ) {
  4537.                     health += healthTic;
  4538.                     if ( health > (healthBoundary * 1.1f) ) {
  4539.                         health = healthBoundary * 1.1f;
  4540.                     }
  4541.                 }
  4542.                 StartSound ( "snd_powerup_regen", SND_CHANNEL_POWERUP, 0, false, NULL );
  4543.                 nextHealthPulse = gameLocal.time + HEALTH_PULSE;
  4544.             } else if ( health < (healthBoundary * 2) ) {
  4545.                 if( gameLocal.isServer ) {
  4546.                     health += healthTic / 3;
  4547.                     if ( health > (healthBoundary * 2) ) {
  4548.                         health = healthBoundary * 2;
  4549.                     }
  4550.                 }
  4551.                 StartSound ( "snd_powerup_regen", SND_CHANNEL_POWERUP, 0, false, NULL );
  4552.                 nextHealthPulse = gameLocal.time + HEALTH_PULSE;
  4553.             }    
  4554.         // Health above max technically isnt a powerup but functions as one so handle it here
  4555.         } else if ( health > inventory.maxHealth && gameLocal.isServer ) { 
  4556.             nextHealthPulse = gameLocal.time + HEALTH_PULSE;
  4557.             health--;
  4558.         }
  4559.     }
  4560.  
  4561.     // Regenerate ammo
  4562.     if( gameLocal.isServer && PowerUpActive( POWERUP_AMMOREGEN ) ) {
  4563.         for( int i = 0; i < MAX_WEAPONS; i++ ) {
  4564.             if( inventory.weapons & ( 1 << i ) ) {
  4565.                 int ammoIndex    = inventory.AmmoIndexForWeaponIndex( i );
  4566.                 int max            = inventory.StartingAmmoForWeaponIndex( i );
  4567.  
  4568.                 // only regen ammo if lower than starting
  4569.                 if( gameLocal.time > nextAmmoRegenPulse[ ammoIndex ] && inventory.ammo[ ammoIndex ] < max ) {
  4570.                     int step        = inventory.AmmoRegenStepForWeaponIndex( i );
  4571.                     int time        = inventory.AmmoRegenTimeForWeaponIndex( i );
  4572.  
  4573.                     if( inventory.ammo[ ammoIndex ] < max ) {
  4574.                         inventory.ammo[ ammoIndex ] += step;
  4575.                     }
  4576.                     if( inventory.ammo[ ammoIndex ] >= max ) {
  4577.                         inventory.ammo[ ammoIndex ] = max;
  4578.                     }
  4579.  
  4580.                     nextAmmoRegenPulse[ ammoIndex ] = gameLocal.time + time;
  4581.                 }    
  4582.             }
  4583.         }
  4584.     }
  4585.  
  4586.     // Tick armor down if greater than max armor
  4587.     if ( !gameLocal.isClient && gameLocal.time > nextArmorPulse ) {
  4588.         if ( inventory.armor > inventory.maxarmor ) { 
  4589.             nextArmorPulse += ARMOR_PULSE;
  4590.             inventory.armor--;
  4591.         }        
  4592.     }
  4593.         
  4594.     // Assign the powerup skin as long as we are alive
  4595.      if ( health > 0 ) {
  4596.          if ( powerUpSkin ) {
  4597.              renderEntity.customSkin = powerUpSkin;
  4598.             if( head ) {
  4599.                 head->SetSkin( powerUpSkin );
  4600.             }
  4601.  
  4602.             if( weaponWorldModel ) {
  4603.                 weaponWorldModel->SetSkin( powerUpSkin );
  4604.             }
  4605.  
  4606.             if( weaponViewModel ) {
  4607.                 weaponViewModel->SetSkin( powerUpSkin );
  4608.             }
  4609.          } else {
  4610.              renderEntity.customSkin = skin;
  4611.  
  4612.             if( head ) {
  4613.                 head->SetSkin( headSkin );
  4614.             }
  4615.  
  4616.             if( weaponViewModel ) {
  4617.                 weaponViewModel->SetSkin( weaponViewSkin );
  4618.             }
  4619.          }
  4620.  
  4621.         if( weaponViewModel ) {
  4622.             weaponViewModel->SetOverlayShader( powerUpOverlay );
  4623.         }
  4624.  
  4625.         if( head ) {
  4626.             head->GetRenderEntity()->overlayShader = powerUpOverlay;
  4627.         }
  4628.  
  4629.         if( weaponWorldModel ) {
  4630.             weaponWorldModel->GetRenderEntity()->overlayShader = powerUpOverlay;
  4631.         }
  4632.  
  4633.         renderEntity.overlayShader = powerUpOverlay;
  4634.     } else {
  4635.         renderEntity.overlayShader = NULL;
  4636.         powerUpOverlay = NULL;
  4637.  
  4638.         if( head ) {
  4639.             head->GetRenderEntity()->overlayShader = NULL;
  4640.         }
  4641.  
  4642.         if ( renderEntity.customSkin != gibSkin ) {
  4643.             if ( influenceSkin ) {
  4644.                 renderEntity.customSkin = influenceSkin;
  4645.             } else {
  4646.                 renderEntity.customSkin = skin;
  4647.             }
  4648.         }
  4649.     }
  4650.  
  4651.     // Spawn quad effect
  4652.     if( PowerUpActive ( powerupEffectType ) && powerupEffect && gameLocal.time >= powerupEffectTime  ) {
  4653.         rvClientCrawlEffect* effect = new rvClientCrawlEffect( powerupEffect, this, 100, &powerupEffectJoints );
  4654.         effect->Play ( gameLocal.time, false );                    
  4655.         effect->GetRenderEffect()->suppressSurfaceInViewID = entityNumber+1;
  4656.         powerupEffectTime = gameLocal.time + 400;
  4657.     }
  4658.     
  4659.     // Attenuate haste effect
  4660.     if ( hasteEffect ) {
  4661.         hasteEffect->Attenuate ( idMath::ClampFloat ( 0.0f, 1.0f, physicsObj.GetLinearVelocity().LengthSqr() / Square(100.0f) ) );
  4662.     }
  4663.  
  4664.     if ( flagEffect ) {
  4665.         flagEffect->Attenuate ( idMath::ClampFloat ( 0.0f, 1.0f, physicsObj.GetLinearVelocity().LengthSqr() / Square(100.0f) ) );
  4666.     }
  4667. }
  4668.  
  4669. /*
  4670. ===============
  4671. idPlayer::ClearPowerUps
  4672. ===============
  4673. */
  4674. void idPlayer::ClearPowerUps( void ) {
  4675.     int i;
  4676.      for ( i = 0; i < POWERUP_MAX; i++ ) {
  4677.          if ( PowerUpActive( i ) ) {
  4678.                ClearPowerup( i );
  4679.            }
  4680.        }
  4681.  
  4682.     inventory.ClearPowerUps();
  4683. }
  4684.  
  4685. /*
  4686. ===============
  4687. idPlayer::GiveWeaponMods
  4688. ===============
  4689. */
  4690. bool idPlayer::GiveWeaponMods ( int mods ) {
  4691.     inventory.weaponMods[currentWeapon] |= mods;
  4692.     currentWeapon = -1;
  4693.     
  4694.     return true;
  4695. }
  4696.  
  4697. /*
  4698. ===============
  4699. idPlayer::GiveWeaponMods
  4700. ===============
  4701. */
  4702. bool idPlayer::GiveWeaponMods ( int weapon, int mods ) {
  4703.     inventory.weaponMods[weapon] |= mods;
  4704.     currentWeapon = -1;
  4705.  
  4706.     return true;
  4707. }
  4708.  
  4709. /*
  4710. ==============
  4711. idPlayer::GiveWeaponMod
  4712. ==============
  4713. */
  4714. void idPlayer::GiveWeaponMod ( const char* weaponmod ) {
  4715.     const idDict* modDict;
  4716.     const idDict* weaponDict;
  4717.     const char*      weaponClass;
  4718.     int              m;
  4719.     int              weaponIndex;
  4720.  
  4721.     // Grab the weapon mod dictionary
  4722.     modDict = gameLocal.FindEntityDefDict ( weaponmod, false );
  4723.     if ( !modDict ) {
  4724.         gameLocal.Warning ( "Invalid weapon modification def specified '%s'", weaponmod );
  4725.         return;
  4726.     }
  4727.         
  4728.     // Get the weapon it modifies
  4729.     weaponClass = modDict->GetString ( "weapon" );
  4730.     weaponDict  = gameLocal.FindEntityDefDict ( weaponClass, false );
  4731.     if ( !weaponDict ) {
  4732.         gameLocal.Warning ( "Invalid weapon classname '%s' specified on weapon modification '%s'", weaponClass, weaponmod );
  4733.         return;
  4734.     }
  4735.     
  4736.     weaponIndex = SlotForWeapon ( weaponClass );
  4737.  
  4738.     // Find the index of the weapon mod
  4739.     for ( m = 0; m < MAX_WEAPONMODS; m ++ ) {        
  4740.         const char* mod;
  4741.         mod = weaponDict->GetString ( va("def_mod%d",m+1) );
  4742.         if ( !mod || !*mod ) {
  4743.             break;
  4744.         }
  4745.  
  4746.         if ( !idStr::Icmp ( weaponmod, mod ) ) {
  4747.             if ( !(inventory.weaponMods[weaponIndex] & (1<<m)) ) {
  4748.                 inventory.weaponMods[weaponIndex] |= (1<<m);
  4749.                 // If the players current weapon is the modified one then we need
  4750.                 // to force the weapon to switch so the mods dont just appear on it
  4751.                 if ( currentWeapon == weaponIndex ) {
  4752.                     currentWeapon = -1;
  4753.                 }
  4754.             }
  4755.             return;
  4756.         }
  4757.     }
  4758. }
  4759.  
  4760. /*
  4761. ===============
  4762. idPlayer::GiveInventoryItem
  4763. ===============
  4764. */
  4765. bool idPlayer::GiveInventoryItem( idDict *item ) {
  4766.     if ( gameLocal.isMultiplayer && spectating ) {
  4767.         return false;
  4768.     }
  4769.  
  4770. // RAVEN BEGIN
  4771. // mwhitlock: Dynamic memory consolidation
  4772.     RV_PUSH_HEAP_MEM(this);
  4773. // RAVEN END
  4774.     inventory.items.Append( new idDict( *item ) );
  4775. // RAVEN BEGIN
  4776. // mwhitlock: Dynamic memory consolidation
  4777.     RV_POP_HEAP();
  4778. // RAVEN END
  4779.  
  4780.     if ( hud ) {
  4781.         const char *itemName = common->GetLocalizedString( item->GetString( "inv_name" ) );
  4782.         hud->SetStateString ( "itemtext", itemName );
  4783.         hud->SetStateString ( "itemicon", item->GetString( "inv_icon" ) );
  4784.         hud->HandleNamedEvent ( "itemPickup" );
  4785.     }
  4786.     
  4787.     return true;
  4788. }
  4789.  
  4790. /*
  4791. ==============
  4792. idPlayer::UpdateObjectiveInfo
  4793. ==============
  4794.  */
  4795. void idPlayer::UpdateObjectiveInfo( void ) {
  4796.     if ( objectiveSystem == NULL ) {
  4797.         return;
  4798.     }
  4799.     objectiveSystem->SetStateString( "objective1", "" );
  4800.     objectiveSystem->SetStateString( "objective2", "" );
  4801.     objectiveSystem->SetStateString( "objective3", "" );
  4802.  
  4803. // RAVEN BEGIN
  4804. // mekberg: swap objective positions to allow for stack-like appearance.
  4805.     int objectiveCount = inventory.objectiveNames.Num();
  4806.     for ( int i = 0; i < inventory.objectiveNames.Num(); i++, objectiveCount-- ) {
  4807.         objectiveSystem->SetStateString( va( "objective%i", objectiveCount ), "1" );
  4808.         objectiveSystem->SetStateString( va( "objectivetitle%i", objectiveCount ), inventory.objectiveNames[i].title.c_str() );
  4809.         objectiveSystem->SetStateString( va( "objectivetext%i", objectiveCount), inventory.objectiveNames[i].text.c_str() );
  4810.         objectiveSystem->SetStateInt( va( "objectiveLength%i", objectiveCount), inventory.objectiveNames[i].text.Length() );
  4811.         objectiveSystem->SetStateString( va( "objectiveshot%i", objectiveCount), inventory.objectiveNames[i].screenshot.c_str() );
  4812.     }
  4813.     objectiveSystem->SetStateBool( "noObjective", !objectiveCount );
  4814. // RAVEN END
  4815.  
  4816.     objectiveSystem->StateChanged( gameLocal.time );
  4817. }
  4818.  
  4819. /*
  4820. ===============
  4821. idPlayer::GiveObjective
  4822. ===============
  4823. */
  4824. void idPlayer::GiveObjective( const char *title, const char *text, const char *screenshot ) {
  4825.     idObjectiveInfo info;
  4826. // RAVEN BEGIN
  4827.     info.title = common->GetLocalizedString( title );
  4828.     info.text = common->GetLocalizedString( text );
  4829. // RAVEN END
  4830.     info.screenshot = screenshot;
  4831.     inventory.objectiveNames.Append( info );
  4832.     if ( showNewObjectives ) {
  4833.         ShowObjective( "newObjective" );
  4834.     }
  4835.     if ( objectiveSystem ) {
  4836.         if ( objectiveSystemOpen ) {
  4837.             objectiveSystemOpen = false;
  4838.             ToggleObjectives ( );
  4839. #ifdef _XENON
  4840.             g_ObjectiveSystemOpen = objectiveSystemOpen;
  4841. #endif
  4842.         }
  4843.     }
  4844. }
  4845.  
  4846. /*
  4847. ===============
  4848. idPlayer::CompleteObjective
  4849. ===============
  4850. */
  4851. void idPlayer::CompleteObjective( const char *title ) {
  4852. // RAVEN BEGIN
  4853.     title = common->GetLocalizedString( title );
  4854. // RAVEN END
  4855.     int c = inventory.objectiveNames.Num();
  4856.     for ( int i = 0;  i < c; i++ ) {
  4857.         if ( idStr::Icmp(inventory.objectiveNames[i].title, title) == 0 ) {
  4858.             inventory.objectiveNames.RemoveIndex( i );
  4859.             break;
  4860.         }
  4861.     }
  4862.     ShowObjective( "newObjectiveComplete" );
  4863.  
  4864.     if ( objectiveSystem ) {
  4865.         objectiveSystem->HandleNamedEvent( "newObjectiveComplete" );
  4866.     }
  4867.  
  4868.     if ( objectiveSystemOpen ) {
  4869.         objectiveSystemOpen = false;
  4870.         ToggleObjectives ( );
  4871. #ifdef _XENON
  4872.         g_ObjectiveSystemOpen = objectiveSystemOpen;
  4873. #endif
  4874.     }
  4875. }
  4876.  
  4877. /*
  4878. ===============
  4879. idPlayer::FailObjective
  4880. ===============
  4881. */
  4882. void idPlayer::FailObjective ( const char* title ) {
  4883. // RAVEN BEGIN
  4884.     title = common->GetLocalizedString( title );
  4885.  
  4886. // mekberg: prevent save games if objective failed.
  4887.     gameLocal.sessionCommand = "objectiveFailed";
  4888. // RAVEN END
  4889.     HideObjective ( );
  4890.     if ( objectiveSystem ) {
  4891.         objectiveSystem->HandleNamedEvent( "objectiveFailed" );
  4892.     }
  4893.     if( IsInVehicle() )    {
  4894.          vehicleController.GetVehicle()->EjectAllDrivers();
  4895.     }
  4896.     playerView.Fade( colorBlack, 12000 );
  4897.     fl.takedamage = true;
  4898.     pfl.objectiveFailed = true;
  4899.     minRespawnTime = gameLocal.time + RAGDOLL_DEATH_TIME;
  4900.     maxRespawnTime = minRespawnTime + MAX_RESPAWN_TIME;
  4901. }
  4902.  
  4903. // RAVEN BEGIN
  4904. // twhitaker: no more database system
  4905. /*
  4906. ===============
  4907. idPlayer::UpdateDatabaseInfo
  4908. ===============
  4909. */
  4910. /*
  4911. void idPlayer::UpdateDatabaseInfo( void ) {
  4912.     int        i;
  4913.     int        index;
  4914.     int        selected;
  4915.     idStr    filter;
  4916.  
  4917.     if ( !objectiveSystem ) {
  4918.         return;
  4919.     }
  4920.  
  4921.     // Determine which item is selected
  4922.     if ( -1 == ( selected = objectiveSystem->State().GetInt( "listDB_sel", "-1" ) ) ) {
  4923.         selected = 0;
  4924.         objectiveSystem->SetStateInt( "listDB_sel", selected );
  4925.     }
  4926.  
  4927.     objectiveSystem->State().GetString ( "dbFilter", "", filter );
  4928.  
  4929.     objectiveSystem->SetStateString ( "dbEntryTitle", "" );
  4930.     objectiveSystem->SetStateString ( "dbEntryText",  "" );
  4931.     objectiveSystem->SetStateString ( "dbEntryImage",  "" );
  4932.  
  4933.     // Fill the database list
  4934.     for ( i = 0, index = 0; i < inventory.database.Num(); i ++ ) {
  4935.         // Check to see if there is a filter and if it matches or not
  4936.         if ( filter.Length() && filter.Icmp ( inventory.database[i].filter ) ) {
  4937.             continue;
  4938.         }
  4939.  
  4940.         // currently selected item?
  4941.         if ( selected == index ) {
  4942.             objectiveSystem->SetStateString ( "dbEntryTitle", inventory.database[i].title );
  4943.             objectiveSystem->SetStateString ( "dbEntryText",  inventory.database[i].text );
  4944.             objectiveSystem->SetStateString ( "dbEntryImage",  inventory.database[i].image );
  4945.         }
  4946.  
  4947.         objectiveSystem->SetStateString( va( "listDB_item_%d", index++ ), inventory.database[i].title );
  4948.     }
  4949.  
  4950.     // Clear any old items from the gui
  4951.     for ( ; index < inventory.database.Num(); index ++ ) {
  4952.         objectiveSystem->SetStateString ( va( "listDB_item_%d", index ), "" );
  4953.     }
  4954.         
  4955.     objectiveSystem->StateChanged( gameLocal.time );
  4956. }
  4957. */
  4958. // RAVEN END
  4959.  
  4960. // RAVEN BEGIN
  4961. // twhitaker: no more database system
  4962. /*
  4963. ===============
  4964. idPlayer::GiveDatabaseEntry
  4965. ===============
  4966. */
  4967. /*void idPlayer::GiveDatabaseEntry ( const idDict* dict, bool hudPopup ) {
  4968.     int i;
  4969.  
  4970.     if ( gameLocal.isMultiplayer || spectating ) {
  4971.         return;
  4972.     }
  4973.  
  4974.     // Initialize the new databse entry from the given dictionary
  4975.     rvDatabaseEntry dbEntry;
  4976.     dict->GetString ( "dbTitle", "", dbEntry.title );
  4977.     dict->GetString ( "dbText", "", dbEntry.text );
  4978.     dict->GetString ( "dbImage", "", dbEntry.image );
  4979.     dict->GetString ( "dbFilter", "", dbEntry.filter );
  4980.     
  4981.     if ( !dbEntry.title.Length() ) { 
  4982.         return;
  4983.     }
  4984.     
  4985.     // Make sure the database item isnt already in the list
  4986.     for ( i = inventory.database.Num() - 1; i >= 0; i -- ) {
  4987.         if ( inventory.database[i].title.Icmp ( dbEntry.title ) == 0 ) {
  4988.             return;
  4989.         }
  4990.     }
  4991.     
  4992.     // Add the databse entry
  4993.     inventory.database.Append ( dbEntry );
  4994.  
  4995.     // Let the hud know about the new database entry
  4996.     if ( hud && hudPopup && g_showHudPopups.GetBool ( ) ) {
  4997.         hud->SetStateString( "dbEntry", "1" );
  4998.         hud->SetStateString( "dbEntryTitle", dbEntry.title );
  4999.         hud->SetStateString( "dbEntryText", dbEntry.text );
  5000.         hud->SetStateString( "dbEntryImage", dbEntry.image );
  5001.         hud->HandleNamedEvent( "newDatabaseEntry" );
  5002.         
  5003.         PostEventMS( &EV_Player_HideDatabaseEntry, 2000 );
  5004.     }
  5005.     
  5006.     // Indicators to have the gui switch to the newly added database item.
  5007.     objectiveSystem->HandleNamedEvent ( va("newDatabaseEntry%s", dbEntry.filter.c_str() ) );
  5008. }
  5009. */
  5010. // RAVEN END
  5011.  
  5012. /*
  5013. ===============
  5014. idPlayer::FindInventoryItem
  5015. ===============
  5016. */
  5017. idDict *idPlayer::FindInventoryItem( const char *name ) {
  5018.     for ( int i = 0; i < inventory.items.Num(); i++ ) {
  5019.         const char *iname = inventory.items[i]->GetString( "inv_name" );
  5020.         if ( iname && *iname ) {
  5021.             if ( idStr::Icmp( name, iname ) == 0 ) {
  5022.                 return inventory.items[i];
  5023.             }
  5024.         }
  5025.     }
  5026.     return NULL;
  5027. }
  5028.  
  5029. /*
  5030. ===============
  5031. idPlayer::RemoveInventoryItem
  5032. ===============
  5033. */
  5034. void idPlayer::RemoveInventoryItem( const char *name ) {
  5035.     idDict *item = FindInventoryItem(name);
  5036.     if ( item ) {
  5037.         RemoveInventoryItem( item );
  5038.     }
  5039. }
  5040.  
  5041. /*
  5042. ===============
  5043. idPlayer::RemoveInventoryItem
  5044. ===============
  5045. */
  5046. void idPlayer::RemoveInventoryItem( idDict *item ) {
  5047.     inventory.items.Remove( item );
  5048.     delete item;
  5049. }
  5050.  
  5051. /*
  5052. ===============
  5053. idPlayer::GiveItem
  5054. ===============
  5055. */
  5056. void idPlayer::GiveItem( const char *itemname ) {
  5057.     idDict args;
  5058.  
  5059.     args.Set( "classname", itemname );
  5060.     args.Set( "owner", name.c_str() );
  5061.     gameLocal.SpawnEntityDef( args );
  5062. }
  5063.  
  5064. /*
  5065. ==================
  5066. idPlayer::SlotForWeapon
  5067. ==================
  5068. */
  5069. int idPlayer::SlotForWeapon( const char *weaponName ) {
  5070.     int i;
  5071.  
  5072.     for( i = 0; i < MAX_WEAPONS; i++ ) {
  5073.         const char *weap = spawnArgs.GetString( va( "def_weapon%d", i ) );
  5074.         if ( !idStr::Cmp( weap, weaponName ) ) {
  5075.             return i;
  5076.         }
  5077.     }
  5078.  
  5079.     // not found
  5080.     return -1;
  5081. }
  5082.  
  5083. /*
  5084. ===============
  5085. idPlayer::Reload
  5086. ===============
  5087. */
  5088. void idPlayer::Reload( void ) {
  5089.      if ( gameLocal.isClient || spectating || gameLocal.inCinematic || influenceActive || !weapon ) {
  5090.          return;
  5091.      }
  5092.  
  5093.     weapon->Reload();
  5094. }
  5095.  
  5096. #ifdef _XENON
  5097. /*
  5098. ===============
  5099. idPlayer::ScheduleWeaponSwitch
  5100. ===============
  5101. */
  5102. void idPlayer::ScheduleWeaponSwitch(int weapon)
  5103. {
  5104.     CancelEvents(&EV_Player_SelectWeapon);
  5105.     hud->SetStateInt("player_selectedWeapon", weapon-1);
  5106.     hud->HandleNamedEvent( "weaponSelect" );
  5107.     
  5108.     // nrausch: support for turning the weapon change ui on and off
  5109.     idWindow *win = FindWindowByName( "p_weapswitch", hud->GetDesktop() );
  5110.     if ( win ) {
  5111.         win->SetVisible( false );
  5112.     }
  5113.  
  5114.     if ( weapon > 0 ) {
  5115.         const char *weap = spawnArgs.GetString( va( "def_weapon%d", weapon-1 ) );
  5116.         PostEventSec(&EV_Player_SelectWeapon, 0.25f, weap);
  5117.     }
  5118. }
  5119. #endif
  5120.  
  5121. /*
  5122. ===============
  5123. idPlayer::ShowCrosshair
  5124. ===============
  5125. */
  5126. void idPlayer::ShowCrosshair( void ) {
  5127.     if ( !weaponEnabled ) {
  5128.         return;
  5129.     }
  5130.  
  5131.     if ( cursor ) {
  5132.         cursor->HandleNamedEvent( "showCrossCombat" );
  5133.     }
  5134.     UpdateHudWeapon();
  5135. }
  5136.  
  5137. /*
  5138. ===============
  5139. idPlayer::HideCrosshair
  5140. ===============
  5141. */
  5142. void idPlayer::HideCrosshair( void ) {
  5143.     if ( cursor ) {
  5144.         cursor->HandleNamedEvent( "crossHide" );
  5145.     }
  5146. }
  5147.  
  5148. /*
  5149. ===============
  5150. idPlayer::LastWeapon
  5151. ===============
  5152. */
  5153. void idPlayer::LastWeapon( void ) {
  5154.     // Dont bother if previousWeapon is invalid or the player is spectating
  5155.     if ( spectating || previousWeapon < 0 )    {
  5156.         return;
  5157.     }
  5158.     
  5159.     // Do we have the weapon still?
  5160.     if ( !(inventory.weapons & ( 1 << previousWeapon ) ) ) {
  5161.         return;
  5162.     }
  5163.     
  5164.     idealWeapon = previousWeapon;
  5165. }
  5166.  
  5167. /*
  5168. ===============
  5169. idPlayer::NextBestWeapon
  5170. ===============
  5171. */
  5172. void idPlayer::NextBestWeapon( void ) {
  5173.     const char *weap;
  5174.     int w = MAX_WEAPONS;
  5175.  
  5176.      if ( gameLocal.isClient || !weaponEnabled ) {
  5177.          return;
  5178.      }
  5179.  
  5180.      while ( w > 0 ) {
  5181.         w--;
  5182.         weap = spawnArgs.GetString( va( "def_weapon%d", w ) );
  5183.          if ( !weap[ 0 ] || ( ( inventory.weapons & ( 1 << w ) ) == 0 ) || ( !inventory.HasAmmo( weap ) ) ) {
  5184.             continue;
  5185.         }
  5186.         if ( !spawnArgs.GetBool( va( "weapon%d_best", w ) ) ) {
  5187.             continue;
  5188.         }
  5189.         break;
  5190.     }
  5191.     idealWeapon = w;
  5192.     weaponSwitchTime = gameLocal.time + WEAPON_SWITCH_DELAY;
  5193.     UpdateHudWeapon();
  5194. }
  5195.  
  5196. /*
  5197. ===============
  5198. idPlayer::NextWeapon
  5199. ===============
  5200. */
  5201. void idPlayer::NextWeapon( void ) {
  5202.     const char *weap;
  5203.     int w;
  5204.  
  5205.      if ( !weaponEnabled || spectating || hiddenWeapon || gameLocal.inCinematic || gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) || health < 0 ) {
  5206.          return;
  5207.      }
  5208.  
  5209. // RAVEN BEGIN
  5210. // nrausch: support for turning the weapon change ui on and off
  5211.  
  5212.     // check if we have any weapons
  5213.     if ( !inventory.weapons ) {
  5214.         return;
  5215.     }
  5216.  
  5217. #ifdef _XENON
  5218.  
  5219.     w = idealWeapon;
  5220.     while( 1 ) {
  5221.         w++;
  5222.         if ( w >= MAX_WEAPONS ) {
  5223.             w = 0;
  5224.         } 
  5225.          weap = spawnArgs.GetString( va( "def_weapon%d", w ) );
  5226.         if ( !spawnArgs.GetBool( va( "weapon%d_cycle", w ) ) ) {
  5227.             continue;
  5228.         }
  5229.         if ( !weap[ 0 ] ) {
  5230.             continue;
  5231.         }
  5232.         if ( ( inventory.weapons & ( 1 << w ) ) == 0 ) {
  5233.             continue;
  5234.         }
  5235.         if ( inventory.HasAmmo( weap ) ) {
  5236.             break;
  5237.         }
  5238.     }
  5239.  
  5240.     if ( ( w != currentWeapon ) && ( w != idealWeapon ) ) {
  5241.         
  5242.         if ( entityNumber == gameLocal.localClientNum ) {
  5243.             idWindow *win = FindWindowByName( "p_weapswitch", hud->GetDesktop() );
  5244.             if ( win ) {
  5245.                 win->SetVisible( true );
  5246.             }
  5247.         }
  5248.          
  5249.      if ( gameLocal.isClient ) {
  5250.         return;
  5251.     }
  5252.  
  5253.         idealWeapon = w;
  5254.         weaponSwitchTime = gameLocal.time + WEAPON_SWITCH_DELAY;
  5255.         UpdateHudWeapon();
  5256.     }
  5257.  
  5258. #else
  5259.  
  5260.      if ( gameLocal.isClient ) {
  5261.         return;
  5262.     }
  5263.     
  5264.     w = idealWeapon;
  5265.     while( 1 ) {
  5266.         w++;
  5267.         if ( w >= MAX_WEAPONS ) {
  5268.             w = 0;
  5269.         } 
  5270.          weap = spawnArgs.GetString( va( "def_weapon%d", w ) );
  5271.         if ( !spawnArgs.GetBool( va( "weapon%d_cycle", w ) ) ) {
  5272.             continue;
  5273.         }
  5274.         if ( !weap[ 0 ] ) {
  5275.             continue;
  5276.         }
  5277.         if ( ( inventory.weapons & ( 1 << w ) ) == 0 ) {
  5278.             continue;
  5279.         }
  5280.         if ( inventory.HasAmmo( weap ) ) {
  5281.             break;
  5282.         }
  5283.     }
  5284.  
  5285.     if ( ( w != currentWeapon ) && ( w != idealWeapon ) ) {
  5286.         idealWeapon = w;
  5287.         weaponSwitchTime = gameLocal.time + WEAPON_SWITCH_DELAY;
  5288.         UpdateHudWeapon();
  5289.     }
  5290.  
  5291. #endif
  5292. // RAVEN END
  5293. }
  5294.  
  5295. /*
  5296. ===============
  5297. idPlayer::PrevWeapon
  5298. ===============
  5299. */
  5300. void idPlayer::PrevWeapon( void ) {
  5301.     const char *weap;
  5302.     int w;
  5303.  
  5304.      if ( !weaponEnabled || spectating || hiddenWeapon || gameLocal.inCinematic || gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) || health < 0 ) {
  5305.          return;
  5306.      }
  5307.  
  5308. // RAVEN BEGIN
  5309. // nrausch: support for turning the weapon change ui on and off
  5310.  
  5311.     // check if we have any weapons
  5312.     if ( !inventory.weapons ) {
  5313.         return;
  5314.     }
  5315.  
  5316. #ifdef _XENON
  5317.     
  5318.     w = idealWeapon;
  5319.     while( 1 ) {
  5320.         w--;
  5321.         if ( w < 0 ) {
  5322.             w = MAX_WEAPONS - 1;
  5323.         }
  5324.          weap = spawnArgs.GetString( va( "def_weapon%d", w ) );
  5325.         if ( !spawnArgs.GetBool( va( "weapon%d_cycle", w ) ) ) {
  5326.             continue;
  5327.         }
  5328.         if ( !weap[ 0 ] ) {
  5329.             continue;
  5330.         }
  5331.         if ( ( inventory.weapons & ( 1 << w ) ) == 0 ) {
  5332.             continue;
  5333.         }
  5334.         if ( inventory.HasAmmo( weap ) ) {
  5335.             break;
  5336.         }
  5337.     }
  5338.  
  5339.     if ( ( w != currentWeapon ) && ( w != idealWeapon ) ) {
  5340.         if ( entityNumber == gameLocal.localClientNum ) {
  5341.             idWindow *win = FindWindowByName( "p_weapswitch", hud->GetDesktop() );
  5342.             if ( win ) {
  5343.                 win->SetVisible( true );
  5344.             }
  5345.          
  5346.      if ( gameLocal.isClient ) {
  5347.         return;
  5348.     }
  5349.  
  5350.             idealWeapon = w;
  5351.             weaponSwitchTime = gameLocal.time + WEAPON_SWITCH_DELAY;
  5352.             UpdateHudWeapon();
  5353.         }
  5354.     }
  5355.  
  5356. #else
  5357.  
  5358.      if ( gameLocal.isClient ) {
  5359.         return;
  5360.     }
  5361.  
  5362.     w = idealWeapon;
  5363.     while( 1 ) {
  5364.         w--;
  5365.         if ( w < 0 ) {
  5366.             w = MAX_WEAPONS - 1;
  5367.         }
  5368.          weap = spawnArgs.GetString( va( "def_weapon%d", w ) );
  5369.         if ( !spawnArgs.GetBool( va( "weapon%d_cycle", w ) ) ) {
  5370.             continue;
  5371.         }
  5372.         if ( !weap[ 0 ] ) {
  5373.             continue;
  5374.         }
  5375.         if ( ( inventory.weapons & ( 1 << w ) ) == 0 ) {
  5376.             continue;
  5377.         }
  5378.         if ( inventory.HasAmmo( weap ) ) {
  5379.             break;
  5380.         }
  5381.     }
  5382.  
  5383.     if ( ( w != currentWeapon ) && ( w != idealWeapon ) ) {
  5384.         idealWeapon = w;
  5385.         weaponSwitchTime = gameLocal.time + WEAPON_SWITCH_DELAY;
  5386.         UpdateHudWeapon();
  5387.     }
  5388. #endif
  5389. // RAVEN END
  5390. }
  5391.  
  5392. /*
  5393. ===============
  5394. idPlayer::SelectWeapon
  5395. ===============
  5396. */
  5397. void idPlayer::SelectWeapon( const char *weapon_name ) {
  5398.     Event_SelectWeapon( weapon_name );
  5399. }
  5400.  
  5401. /*
  5402. ===============
  5403. idPlayer::SelectWeapon
  5404. ===============
  5405. */
  5406. void idPlayer::SelectWeapon( int num, bool force ) {
  5407.     const char *weap;
  5408.  
  5409.      if ( !weaponEnabled || spectating || gameLocal.inCinematic || health < 0 ) {
  5410.         return;
  5411.     }
  5412.  
  5413.     if ( ( num < 0 ) || ( num >= MAX_WEAPONS ) ) {
  5414.         return;
  5415.     }
  5416.  
  5417.      if ( gameLocal.isClient ) {
  5418.          return;
  5419.      }
  5420.  
  5421.      weap = spawnArgs.GetString( va( "def_weapon%d", num ) );
  5422.     if ( !weap[ 0 ] ) {
  5423.         gameLocal.Warning( "Invalid weapon def_weapon%d\n", num );
  5424.         return;
  5425.     }
  5426.  
  5427.     // cycle in-between weapons
  5428.     // if a weapon_def has a "def_weapon_swap" keyvalue pointing to another 
  5429.     // weapon, hitting that impulse twice will cycle to the target swap. 
  5430.     if( num == currentWeapon ) {
  5431.         const idDict* weapDict = gameLocal.FindEntityDefDict( weap, false );
  5432.  
  5433.         if( weapDict == NULL ) {
  5434.             gameLocal.Warning( "Invalid weapon entity %s\n", weap );
  5435.             return;
  5436.         }
  5437.  
  5438. // RAVEN BEGIN
  5439. // nrausch: we have no need for weapon swapping on the xenon, and it gets in the way of the quick weapon select ui
  5440. #ifndef _XENON
  5441.         const char* destWeapon = weapDict->GetString( "def_weapon_swap", NULL );
  5442.  
  5443.         if( destWeapon != NULL ) {
  5444.             int swapNum = SlotForWeapon( destWeapon );
  5445.             if( swapNum == -1 ) {
  5446.                 gameLocal.Warning( "Swap weapon for %s (%s) is invalid", weap, destWeapon );
  5447.             } else {
  5448.                 num = swapNum;
  5449.             }
  5450.         } 
  5451. #endif
  5452. // RAVEN END
  5453.     } 
  5454.  
  5455.     if ( force || ( inventory.weapons & ( 1 << num ) ) ) {
  5456.          if ( !inventory.HasAmmo( weap ) && !spawnArgs.GetBool( va( "weapon%d_allowempty", num ) ) ) {
  5457.              return;
  5458.          }
  5459.         if ( ( previousWeapon >= 0 ) && ( idealWeapon == num ) && ( spawnArgs.GetBool( va( "weapon%d_toggle", num ) ) ) ) {
  5460.              weap = spawnArgs.GetString( va( "def_weapon%d", previousWeapon ) );
  5461.              if ( !inventory.HasAmmo( weap ) && !spawnArgs.GetBool( va( "weapon%d_allowempty", previousWeapon ) ) ) {
  5462.                  return;
  5463.              }
  5464.             idealWeapon = previousWeapon;
  5465. /* NO PDA yet
  5466.         } else if ( ( weapon_pda >= 0 ) && ( num == weapon_pda ) && ( inventory.pdas.Num() == 0 ) ) {
  5467.             ShowTip( spawnArgs.GetString( "text_infoTitle" ), spawnArgs.GetString( "text_noPDA" ), true );
  5468.             return;
  5469. */
  5470.         } else {
  5471.             idealWeapon = num;
  5472.         }
  5473.         UpdateHudWeapon();
  5474.     }
  5475. }
  5476.  
  5477. /*
  5478. =================
  5479. idPlayer::DropItem
  5480. =================
  5481. */
  5482. idEntity* idPlayer::DropItem ( const char* itemClass, const idDict& customArgs, const idVec3& velocity ) const {
  5483.     idDict        args;
  5484.     idEntity*    ent;
  5485.     args.Set( "classname", itemClass );
  5486.     args.Set( "origin", GetPhysics()->GetAbsBounds().GetCenter().ToString ( ) );
  5487.     args.Set( "dropped", "1" );
  5488.     args.SetFloat ( "angle", 360.0f * gameLocal.random.RandomFloat ( ) );
  5489.     args.Copy ( customArgs );
  5490.     gameLocal.SpawnEntityDef ( args, &ent );
  5491.     if ( !ent ) {
  5492.         return NULL;
  5493.     }
  5494.     
  5495.     // If a velocity was given then just use that, otherwise randomly throw it around
  5496.     if ( velocity != vec3_origin ) {
  5497.         ent->GetPhysics()->SetLinearVelocity ( velocity );
  5498.     } else {
  5499.         idVec3 vel;
  5500.         float  ang;
  5501.         ang = idMath::TWO_PI * gameLocal.random.RandomFloat();
  5502.         vel[0] = PLAYER_ITEM_DROP_SPEED * idMath::Cos ( ang );
  5503.         vel[1] = PLAYER_ITEM_DROP_SPEED * idMath::Sin ( ang );
  5504.         vel[2] = PLAYER_ITEM_DROP_SPEED * 2;
  5505.         ent->GetPhysics()->SetLinearVelocity ( vel );
  5506.     }
  5507.     return ent;
  5508. }
  5509.  
  5510. /*
  5511. =================
  5512. idPlayer::DropPowerups
  5513. =================
  5514. */
  5515. void idPlayer::DropPowerups ( void ) {
  5516.     int            i;
  5517.     idEntity*    item;
  5518.  
  5519.     assert( !gameLocal.isClient );
  5520.  
  5521.     for ( i = 0; i < POWERUP_MAX; i++ ) {
  5522.         if ( !(inventory.powerups & ( 1 << i )) ) {
  5523.             continue;
  5524.         }        
  5525.         
  5526.         const idDeclEntityDef* def;
  5527.         def = GetPowerupDef ( i );
  5528.         if ( !def ) {
  5529.             continue;
  5530.         }
  5531.  
  5532.         if( def->dict.GetBool( "nodrop" ) ) {
  5533.             continue;
  5534.         }
  5535.  
  5536.         idDict args;        
  5537.         args.SetFloat ( "time", inventory.powerupEndTime[i] == -1 ? -1 : MS2SEC(inventory.powerupEndTime[i]-gameLocal.time) );            
  5538.         item = DropItem ( def->dict.GetString ( "classname" ), args );
  5539.         if ( !item ) {
  5540.             gameLocal.Warning ( "Player %d failed to drop powerup '%s'", entityNumber, def->dict.GetString ( "classname" ) );
  5541.             return;
  5542.         }    
  5543.     }    
  5544. }
  5545.  
  5546. /*
  5547. =================
  5548. idPlayer::ResetFlag
  5549. =================
  5550. */
  5551. idEntity* idPlayer::ResetFlag ( const char* itemClass, const idDict& customArgs ) const {
  5552.     idDict        args;
  5553.     idEntity*    ent;
  5554.     args.Set( "classname", itemClass );
  5555.     args.Set( "origin", GetPhysics()->GetAbsBounds().GetCenter().ToString ( ) );
  5556.     args.Set( "dropped", "1" );
  5557.     args.Set( "reset", "1" );
  5558.     args.Copy ( customArgs );
  5559.     gameLocal.SpawnEntityDef ( args, &ent );
  5560.     if ( !ent ) {
  5561.         return NULL;
  5562.     }
  5563.     
  5564.     return ent;
  5565. }
  5566.  
  5567. /*
  5568. =================
  5569. idPlayer::RespawnFlags
  5570. =================
  5571. */
  5572. void idPlayer::RespawnFlags ( void ) {
  5573.     int            i;
  5574.     idEntity*    item;
  5575.  
  5576.     assert( !gameLocal.isClient );
  5577.  
  5578.     for ( i = POWERUP_CTF_MARINEFLAG; i < POWERUP_CTF_ONEFLAG; i++ ) {
  5579.         if ( !(inventory.powerups & ( 1 << i )) ) {
  5580.             continue;
  5581.         }        
  5582.         
  5583.         const idDeclEntityDef* def;
  5584.         def = GetPowerupDef ( i );
  5585.         if ( !def ) {
  5586.             continue;
  5587.         }
  5588.  
  5589.         idDict args;        
  5590.         args.SetFloat ( "time", inventory.powerupEndTime[i] == -1 ? -1 : MS2SEC(inventory.powerupEndTime[i]-gameLocal.time) );            
  5591.         item = ResetFlag ( def->dict.GetString ( "classname" ), args );
  5592.         if ( !item ) {
  5593.             gameLocal.Warning ( "Player %d failed to drop powerup '%s'", entityNumber, def->dict.GetString ( "classname" ) );
  5594.             return;
  5595.         }    
  5596.     }    
  5597. }
  5598.  
  5599. /*
  5600. =================
  5601. DropWeapon
  5602. =================
  5603. */
  5604. void idPlayer::DropWeapon( void ) {
  5605.     idEntity*    item;
  5606.     idDict        args;
  5607.     const char*    itemClass;
  5608.  
  5609.     assert( !gameLocal.isClient );
  5610.  
  5611.     if( !gameLocal.isMultiplayer ) {
  5612.         return;
  5613.     }
  5614.  
  5615.      if ( spectating || weaponGone || !weapon ) {
  5616.         return;
  5617.     }
  5618.  
  5619.     // Make sure the weapon is droppable    
  5620.     itemClass = weapon->spawnArgs.GetString ( "def_dropItem" );
  5621.     if ( !itemClass || !*itemClass ) {
  5622.         return;
  5623.     }
  5624.         
  5625.     // If still alive then the weapon is being thrown so start it a bit in front of the player
  5626.     
  5627.     // copy over the instance
  5628.     args.SetInt( "instance", GetInstance() );
  5629.  
  5630.     if ( health > 0 ) {        
  5631.         idVec3 forward;
  5632.         idVec3 up;
  5633.         viewAngles.ToVectors( &forward, NULL, &up );
  5634.         args.SetBool( "triggerFirst", true );
  5635.         item = DropItem ( itemClass, args, 250.0f*forward + 150.0f*up );
  5636.     } else {
  5637.         item = DropItem ( itemClass, args );
  5638.     }
  5639.     
  5640.     // Drop the weapon
  5641.     if ( !item ) {
  5642.         gameLocal.Warning ( "Player %d failed to drop weapon '%s'", entityNumber, weapon->spawnArgs.GetString ( "def_dropItem" ) );
  5643.         return;
  5644.     }
  5645.  
  5646.     // Since this weapon was dropped, replace any starting ammo values with real ammo values
  5647.     const idKeyValue* keyval = item->spawnArgs.MatchPrefix( "inv_start_ammo_" );
  5648.     idDict newArgs;
  5649.     while( keyval ) {
  5650.         newArgs.Set( va( "inv_ammo_%s", keyval->GetKey().Right( keyval->GetKey().Length() - 15 ).c_str() ), keyval->GetValue().c_str() );
  5651.         item->spawnArgs.Set( keyval->GetKey(), "" );
  5652.         keyval = item->spawnArgs.MatchPrefix( "inv_start_ammo_", keyval );
  5653.     }
  5654.  
  5655.     item->spawnArgs.SetDefaults( &newArgs );
  5656.  
  5657.     // Set the appropriate mods on the dropped item
  5658.     int        i;
  5659.     int        mods;
  5660.     idStr    out;
  5661.     mods = weapon->GetMods ( );
  5662.     for ( i = 0; i < MAX_WEAPONMODS; i ++ ) {
  5663.         if ( mods & (1<<i) ) {
  5664.             if ( out.Length() ) {
  5665.                 out += ",";
  5666.             }
  5667.             out += weapon->spawnArgs.GetString ( va("def_mod%d", i+1) );
  5668.         }
  5669.     } 
  5670.     if ( out.Length() ) {    
  5671.         item->spawnArgs.Set ( "inv_weaponmod", out );
  5672.     }
  5673.  
  5674.     // Make sure the weapon removes itself over time.
  5675.     item->PostEventMS ( &EV_Remove, WEAPON_DROP_TIME );
  5676.  
  5677.     // Delay aquire since the weapon is being thrown
  5678.     if ( health > 0 ) {        
  5679.         item->PostEventMS ( &EV_Activate, 500, item );
  5680.         inventory.Drop( spawnArgs, item->spawnArgs.GetString( "inv_weapon" ), -1 );
  5681.         NextWeapon();
  5682.     }
  5683. }
  5684.  
  5685. /*
  5686. ===============
  5687. idPlayer::ActiveGui
  5688. ===============
  5689. */
  5690. idUserInterface *idPlayer::ActiveGui( void ) {
  5691. #ifdef _XENON
  5692.     if ( objectiveSystemOpen ) {
  5693.         return 0;
  5694.     }
  5695. #endif
  5696.     return focusUI;
  5697. }
  5698.  
  5699. /*
  5700. ===============
  5701. idPlayer::Weapon_Combat
  5702. ===============
  5703. */
  5704. void idPlayer::Weapon_Combat( void ) {
  5705.     
  5706.      if ( influenceActive || !weaponEnabled || gameLocal.inCinematic || privateCameraView 
  5707. #ifdef _XENON
  5708.          || objectiveSystemOpen 
  5709. #endif
  5710.          ) {
  5711. #ifdef _XENON
  5712.         if ( objectiveSystemOpen && pfl.attackHeld ) {
  5713.              pfl.attackHeld = false;
  5714.              weapon->EndAttack();
  5715.         }
  5716. #endif
  5717.         return;
  5718.     }
  5719.  
  5720.     if ( weapon ) {
  5721.         weapon->RaiseWeapon();
  5722.  
  5723.          if ( weapon->IsReloading() ) {
  5724.              if ( !pfl.reload ) {
  5725.                  pfl.reload = true;
  5726.                  SetAnimState ( ANIMCHANNEL_TORSO, "Torso_Reload", 4 );
  5727.                  UpdateState();
  5728.             }
  5729.          } else {
  5730.              pfl.reload = false;
  5731.          }
  5732.     }
  5733.  
  5734.     if ( idealWeapon != currentWeapon ) {
  5735.          if ( !weapon || weaponCatchup ) {
  5736.              assert( gameLocal.isClient );
  5737.                weaponGone = false;
  5738.                SetWeapon ( idealWeapon );
  5739.  
  5740.             weapon->NetCatchup();
  5741.             
  5742.             SetAnimState ( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
  5743.             SetAnimState ( ANIMCHANNEL_LEGS, "Legs_Idle", 0 );
  5744.             UpdateState();
  5745.         } else {
  5746.              if ( weapon->IsReady() || weapon->IsReloading() ) {
  5747.                  weapon->PutAway();
  5748. // RAVEN BEGIN
  5749. // mwhitlock: Xenon texture streaming
  5750. #if defined(_XENON)
  5751.                 // Caching resource data for next weapon will go here!
  5752. #endif
  5753. // RAVEN END
  5754.              }
  5755.  
  5756.              if ( weapon->IsHolstered() && weaponViewModel ) {
  5757.                 assert( idealWeapon >= 0 );
  5758.                 assert( idealWeapon < MAX_WEAPONS );
  5759.  
  5760.                 SetWeapon ( idealWeapon );
  5761.  
  5762.                 weapon->Raise();
  5763.             }
  5764.         }
  5765.     } else {
  5766.         weaponGone = false;
  5767.          if ( weapon->IsHolstered() ) {
  5768.              if ( !weapon->AmmoAvailable() ) {
  5769.                  // weapons can switch automatically if they have no more ammo
  5770.                  NextBestWeapon();
  5771.              } else {
  5772.                  weapon->Raise();
  5773.  
  5774.                 SetAnimState ( ANIMCHANNEL_TORSO, "Torso_RaiseWeapon", 3 );
  5775.                }
  5776.            }
  5777.     } 
  5778.  
  5779.     weaponCatchup = false;
  5780.  
  5781.     // check for attack
  5782.     pfl.weaponFired = false;
  5783.      if ( !influenceActive ) {
  5784.          if ( ( usercmd.buttons & BUTTON_ATTACK ) && !weaponGone ) {
  5785.              FireWeapon();
  5786.          } else if ( oldButtons & BUTTON_ATTACK ) {
  5787.              pfl.attackHeld = false;
  5788.              weapon->EndAttack();
  5789.          }
  5790.      }
  5791.  
  5792.     if ( gameLocal.isMultiplayer && spectating ) {
  5793.         UpdateHudWeapon();
  5794.     }
  5795.  
  5796.     // update our ammo clip in our inventory
  5797.     if ( gameLocal.GetLocalPlayer() == this && ( currentWeapon >= 0 ) && ( currentWeapon < MAX_WEAPONS ) ) {
  5798.         inventory.clip[ currentWeapon ] = weapon->AmmoInClip();
  5799.          if ( hud && ( currentWeapon == idealWeapon ) ) {
  5800.              UpdateHudAmmo( hud );
  5801.         }
  5802.     }
  5803. }
  5804.  
  5805. /*
  5806. ===============
  5807. idPlayer::Weapon_Vehicle
  5808. ===============
  5809. */
  5810. void idPlayer::Weapon_Vehicle( void ) {
  5811.     StopFiring();
  5812.     weapon->LowerWeapon();
  5813.  
  5814.     if ( ( usercmd.buttons & BUTTON_ATTACK ) && !( oldButtons & BUTTON_ATTACK ) ) {
  5815.         ProcessEvent ( &AI_EnterVehicle, focusEnt.GetEntity() );
  5816.         
  5817.         ClearFocus ( );
  5818.     }
  5819. }
  5820.  
  5821. /*
  5822. ===============
  5823. idPlayer::Weapon_Usable
  5824. ===============
  5825. */
  5826. void idPlayer::Weapon_Usable( void ) {
  5827.     StopFiring();
  5828.     weapon->LowerWeapon();
  5829.  
  5830.     if ( ( usercmd.buttons & BUTTON_ATTACK ) && !( oldButtons & BUTTON_ATTACK ) ) {
  5831.         focusEnt->ProcessEvent ( &EV_Activate, this  );
  5832.  
  5833.         ClearFocus ( );
  5834.     }
  5835. }
  5836.  
  5837. /*
  5838. ===============
  5839. idPlayer::Weapon_NPC
  5840. ===============
  5841. */
  5842. void idPlayer::Weapon_NPC( void ) {
  5843.     if ( idealWeapon != currentWeapon ) {
  5844.         Weapon_Combat();
  5845.     }
  5846.     //UGH: hack! So blaster doesn't discharge when pointed at NPC...
  5847.     if ( currentWeapon != SlotForWeapon ( "weapon_blaster" ) ) {
  5848.         StopFiring();
  5849.         //weapon->LowerWeapon();
  5850.     }
  5851.  
  5852.     if ( !focusEnt || focusEnt->health <= 0 ) {
  5853.         ClearFocus ( );
  5854.         return;
  5855.     }
  5856.  
  5857.     if ( talkCursor && ( usercmd.buttons & BUTTON_ATTACK ) && !( oldButtons & BUTTON_ATTACK ) ) {
  5858.         buttonMask |= BUTTON_ATTACK;
  5859.         if ( !talkingNPC ) {
  5860.             idAI *focusAI = static_cast<idAI*>(focusEnt.GetEntity());
  5861.             if ( focusAI ) {
  5862.                 focusAI->TalkTo( this );
  5863.                 talkingNPC = focusAI;
  5864.             }
  5865.         }
  5866.     } else if ( currentWeapon == SlotForWeapon ( "weapon_blaster" ) ) {
  5867.         Weapon_Combat();
  5868.     }
  5869. }
  5870.  
  5871.  
  5872. /*
  5873. ===============
  5874. idPlayer::LowerWeapon
  5875. ===============
  5876. */
  5877. void idPlayer::LowerWeapon( void ) {
  5878.     if ( weapon && !weapon->IsHidden() ) {
  5879.         weapon->LowerWeapon();
  5880.     }
  5881. }
  5882.  
  5883. /*
  5884. ===============
  5885. idPlayer::RaiseWeapon
  5886. ===============
  5887. */
  5888. void idPlayer::RaiseWeapon( void ) {
  5889.     if ( weapon && weapon->IsHidden() ) {
  5890.         weapon->RaiseWeapon();
  5891.     }
  5892. }
  5893.  
  5894. /*
  5895. ===============
  5896. idPlayer::WeaponLoweringCallback
  5897. ===============
  5898. */
  5899. void idPlayer::WeaponLoweringCallback( void ) {
  5900.     SetAnimState ( ANIMCHANNEL_TORSO, "Torso_LowerWeapon", 3 );
  5901.     UpdateState();
  5902. }
  5903.  
  5904. /*
  5905. ===============
  5906. idPlayer::WeaponRisingCallback
  5907. ===============
  5908. */
  5909. void idPlayer::WeaponRisingCallback( void ) {
  5910.     SetAnimState ( ANIMCHANNEL_TORSO, "Torso_RaiseWeapon", 2 );
  5911.     UpdateState();
  5912. }
  5913.  
  5914. /*
  5915. ===============
  5916. idPlayer::Weapon_GUI
  5917. ===============
  5918. */
  5919. void idPlayer::Weapon_GUI( void ) {
  5920.  
  5921.     if ( !objectiveSystemOpen ) {
  5922.         if ( idealWeapon != currentWeapon ) {
  5923.             Weapon_Combat();
  5924.         }
  5925.         StopFiring();
  5926.         weapon->LowerWeapon();
  5927.     }
  5928.  
  5929.     // disable click prediction for the GUIs. handy to check the state sync does the right thing
  5930.     if ( gameLocal.isClient && !net_clientPredictGUI.GetBool() ) {
  5931.         return;
  5932.     }
  5933.  
  5934.     if ( ( oldButtons ^ usercmd.buttons ) & BUTTON_ATTACK ) {
  5935.         sysEvent_t ev;
  5936.          const char *command = NULL;
  5937.         bool updateVisuals = false;
  5938.  
  5939.         idUserInterface *ui = ActiveGui();
  5940.         if ( ui ) {
  5941. // RAVEN END
  5942. // jnewquist: FIXME - which one should be used?
  5943. #ifndef _XENON
  5944.              ev = sys->GenerateMouseButtonEvent( 1, ( usercmd.buttons & BUTTON_ATTACK ) != 0 );
  5945. #else
  5946.              ev = sys->GenerateMouseButtonEvent( 1, true );
  5947. #endif
  5948.  // RAVEN END
  5949.             command = ui->HandleEvent( &ev, gameLocal.time, &updateVisuals );
  5950.             if ( updateVisuals && focusEnt && ui == focusUI ) {
  5951.                 focusEnt->UpdateVisuals();
  5952.             }
  5953.         }
  5954.         if ( gameLocal.isClient ) {
  5955.             // we predict enough, but don't want to execute commands
  5956.             return;
  5957.         }
  5958.         if ( focusEnt ) {
  5959.             HandleGuiCommands( focusEnt, command );
  5960.         } else {
  5961.             HandleGuiCommands( this, command );
  5962.         }
  5963.     }
  5964. }
  5965.  
  5966. /*
  5967. ===============
  5968. idPlayer::UpdateWeapon
  5969. ===============
  5970. */
  5971. void idPlayer::UpdateWeapon( void ) {
  5972.     if ( health <= 0 ) {
  5973.         return;
  5974.     }
  5975.  
  5976.     assert( !spectating );
  5977.  
  5978.     // clients need to wait till the weapon and it's world model entity
  5979.     // are present and synchronized ( weapon.worldModel idEntityPtr to idAnimatedEntity )
  5980.     if ( gameLocal.isClient && (!weaponViewModel || !weaponWorldModel) ) {
  5981.         return;
  5982.     }
  5983.  
  5984.     // always make sure the weapon is correctly setup before accessing it
  5985.     if ( !weapon ) {
  5986.         if ( idealWeapon != -1 ) {
  5987.             SetWeapon( idealWeapon );
  5988.             weaponCatchup = false;
  5989.             assert( weapon );
  5990.         } else {
  5991.             return;
  5992.         }
  5993.     }
  5994.     
  5995.     if ( !weapon ) {
  5996.         common->Warning( "ATTN PROGRAMMIGN MENZ: WEAPON IS NULL IN %s\n", __FUNCTION__ );
  5997.         return;
  5998.     }
  5999.     
  6000.     if ( hiddenWeapon && tipUp && usercmd.buttons & BUTTON_ATTACK ) {
  6001.         HideTip();
  6002.     }
  6003.  
  6004.     // Make sure the weapon is in a settled state before preventing thinking due
  6005.     // to drag entity.  This way things like hitting reload, zoom, etc, wont crash
  6006.     if ( g_dragEntity.GetInteger() ) {
  6007.         StopFiring();
  6008.         if ( weapon ) {
  6009.              weapon->LowerWeapon();
  6010.          }
  6011.          dragEntity.Update( this );
  6012.         return;
  6013.     } else if ( focusType == FOCUS_CHARACTER) {
  6014.         Weapon_NPC();
  6015.     } else if ( focusType == FOCUS_VEHICLE ) {
  6016.         Weapon_Vehicle();
  6017.     } else if ( focusType == FOCUS_USABLE || focusType == FOCUS_USABLE_VEHICLE ) {
  6018.         Weapon_Usable();
  6019.     } else if ( ActiveGui() ) {
  6020.         Weapon_GUI();
  6021.     } else if ( !hiddenWeapon ) { /* no pda yet || ( ( weapon_pda >= 0 ) && ( idealWeapon == weapon_pda ) ) ) { */
  6022.         Weapon_Combat();
  6023.     }    
  6024.  
  6025.     // Range finder for debugging
  6026.     if ( g_showRange.GetBool ( ) ) {
  6027.         idVec3    start;
  6028.         idVec3    end;
  6029.         trace_t    tr;
  6030.         
  6031.         start = GetEyePosition();
  6032.         end = start + viewAngles.ToForward() * 50000.0f;
  6033.         gameLocal.TracePoint( this, tr, start, end, MASK_SHOT_BOUNDINGBOX, this );
  6034.  
  6035.         idVec3 forward;
  6036.         idVec3 right;
  6037.         idVec3 up;        
  6038.         viewAngles.ToVectors ( &forward, &right, &up );
  6039.         gameRenderWorld->DrawText( va( "%d qu", ( int )( tr.endpos - start ).Length() ), start + forward * 100.0f + right * 25.0f, .2f, colorCyan, viewAxis );
  6040.         gameRenderWorld->DrawText( va( "%d m", ( int )( tr.endpos - start ).Length() ), start + forward * 100.0f + right * 25.0f - up * 6.0f, .2f, colorCyan, viewAxis );
  6041.         gameRenderWorld->DrawText( va( "%d 2d", ( int )DistanceTo2d( tr.endpos ) ), start + forward * 100.0f + right * 25.0f - up * 12.0f, .2f, colorCyan, viewAxis );
  6042.     }
  6043.  
  6044.      if ( hiddenWeapon ) {
  6045.          weapon->LowerWeapon();
  6046.      }
  6047.  
  6048.     // update weapon state, particles, dlights, etc
  6049.     weaponViewModel->PresentWeapon( showWeaponViewModel );
  6050. }
  6051.  
  6052. /*
  6053. ===============
  6054. idPlayer::SpectateFreeFly
  6055. ===============
  6056. */
  6057. void idPlayer::SpectateFreeFly( bool force ) {
  6058.     idPlayer    *player;
  6059.     idVec3        newOrig;
  6060.     idVec3        spawn_origin;
  6061.     idAngles    spawn_angles;
  6062.  
  6063.     player = gameLocal.GetClientByNum( spectator );
  6064.     if ( force || gameLocal.time > lastSpectateChange ) {
  6065.         spectator = entityNumber;
  6066.         if ( player && player != this && !player->spectating && !player->IsInTeleport() ) {
  6067.             newOrig = player->GetPhysics()->GetOrigin();
  6068.             if ( player->physicsObj.IsCrouching() ) {
  6069.                 newOrig[ 2 ] += pm_crouchviewheight.GetFloat();
  6070.             } else {
  6071.                 newOrig[ 2 ] += pm_normalviewheight.GetFloat();
  6072.             }
  6073.             newOrig[ 2 ] += SPECTATE_RAISE;
  6074.             idBounds b = idBounds( vec3_origin ).Expand( pm_spectatebbox.GetFloat() * 0.5f );
  6075.             idVec3 start = player->GetPhysics()->GetOrigin();
  6076.             start[2] += pm_spectatebbox.GetFloat() * 0.5f;
  6077.             trace_t t;
  6078.             // assuming spectate bbox is inside stand or crouch box
  6079. // RAVEN BEGIN
  6080. // ddynerman: multiple clip worlds
  6081.             gameLocal.TraceBounds( player, t, start, newOrig, b, MASK_PLAYERSOLID, player );
  6082. // RAVEN END
  6083.             newOrig.Lerp( start, newOrig, t.fraction );
  6084.             SetOrigin( newOrig );
  6085.             idAngles angle = player->viewAngles;
  6086.             angle[ 2 ] = 0;
  6087.             SetViewAngles( angle );
  6088.         } else {    
  6089.             if( !SelectSpawnPoint( spawn_origin, spawn_angles ) ) {
  6090.                 return;
  6091.             }
  6092.             spawn_origin[ 2 ] += pm_normalviewheight.GetFloat();
  6093.             spawn_origin[ 2 ] += SPECTATE_RAISE;
  6094.             SetOrigin( spawn_origin );
  6095.             SetViewAngles( spawn_angles );
  6096.         }
  6097.         lastSpectateChange = gameLocal.time + 500;
  6098.     }
  6099. }
  6100.  
  6101. /*
  6102. ===============
  6103. idPlayer::SpectateCycle
  6104. ===============
  6105. */
  6106. void idPlayer::SpectateCycle( void ) {
  6107.     idPlayer *player;
  6108.  
  6109.     if ( gameLocal.time > lastSpectateChange ) {
  6110.         int latchedSpectator = spectator;
  6111.         spectator = gameLocal.GetNextClientNum( spectator );
  6112.         player = gameLocal.GetClientByNum( spectator );
  6113.         assert( player ); // never call here when the current spectator is wrong
  6114.         // ignore other spectators
  6115.         while ( latchedSpectator != spectator && player->spectating ) {
  6116.             spectator = gameLocal.GetNextClientNum( spectator );
  6117.             player = gameLocal.GetClientByNum( spectator );
  6118.         }
  6119.         lastSpectateChange = gameLocal.time + 500;
  6120.  
  6121.         if ( player ) {
  6122.             UpdateHudWeapon( player->currentWeapon );
  6123.         }
  6124.     }
  6125. }
  6126.  
  6127. /*
  6128. ===============
  6129. idPlayer::UpdateSpectating
  6130. ===============
  6131. */
  6132. void idPlayer::UpdateSpectating( void ) {
  6133.     assert( spectating );
  6134.     assert( !gameLocal.isClient );
  6135.     assert( IsHidden() );
  6136.     idPlayer *player;
  6137.     if ( !gameLocal.isMultiplayer ) {
  6138.         return;
  6139.     }
  6140.     player = gameLocal.GetClientByNum( spectator );
  6141.     if ( !player || ( player->spectating && player != this ) ) {
  6142.         SpectateFreeFly( true );        
  6143.     } else if ( usercmd.upmove > 0 && player && player != this ) {
  6144.         // following someone and hit jump? release.
  6145.         SpectateFreeFly( false );
  6146.     } else if ( usercmd.buttons & BUTTON_ATTACK && gameLocal.gameType != GAME_TOURNEY ) {
  6147.         // tourney mode uses seperate cycling
  6148.         SpectateCycle();
  6149.     }
  6150. }
  6151.  
  6152. /*
  6153. ===============
  6154. idPlayer::HandleSingleGuiCommand
  6155. ===============
  6156. */
  6157. bool idPlayer::HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ) {
  6158.     idToken token;
  6159.  
  6160.     if ( !src->ReadToken( &token ) ) {
  6161.         return false;
  6162.     }
  6163.  
  6164.     if ( token == ";" ) {
  6165.         return false;
  6166.     }
  6167.  
  6168.     if ( token.Icmp( "addhealth" ) == 0 ) {
  6169.         if ( entityGui && health < 100 ) {
  6170.             int _health = entityGui->spawnArgs.GetInt( "gui_parm1" );
  6171.             int amt = ( _health >= HEALTH_PER_DOSE ) ? HEALTH_PER_DOSE : _health;
  6172.             _health -= amt;
  6173.             entityGui->spawnArgs.SetInt( "gui_parm1", _health );
  6174.             if ( entityGui->GetRenderEntity() && entityGui->GetRenderEntity()->gui[ 0 ] ) {
  6175.                 entityGui->GetRenderEntity()->gui[ 0 ]->SetStateInt( "gui_parm1", _health );
  6176.             }
  6177.             health += amt;
  6178.             if ( health > 100 ) {
  6179.                 health = 100;
  6180.             }
  6181.         }
  6182.         return true;
  6183.     }
  6184.  
  6185.     if ( token.Icmp( "ready" ) == 0 ) {
  6186.         PerformImpulse( IMPULSE_17 );
  6187.         return true;
  6188.     }
  6189.  
  6190. // RAVEN BEGIN
  6191. // twhitaker: no more database system
  6192. /*    if ( token.Icmp( "updateDB" ) == 0 ) {
  6193.         UpdateDatabaseInfo();
  6194.         return true;
  6195.     }
  6196.     
  6197.     if ( token.Icmp ( "filterDB" ) == 0 ) {
  6198.         if ( !src->ReadToken( &token ) ) {
  6199.             return false;
  6200.         }
  6201.  
  6202.         if ( objectiveSystem ) {
  6203.             objectiveSystem->SetStateString ( "dbFilter", token );
  6204.             UpdateDatabaseInfo ( );
  6205.         }
  6206.     }
  6207. */
  6208. // RAVEN END
  6209.  
  6210.     if ( token.Icmp( "heal" ) == 0 && 
  6211.         entityGui->IsType( rvHealingStation::GetClassType() ) &&
  6212.         src->ReadToken( &token ) )
  6213.     {
  6214.         rvHealingStation * station = static_cast< rvHealingStation * >( entityGui );
  6215.  
  6216.         if ( token.Icmp( "begin" ) == 0 ) {
  6217.             station->BeginHealing( this );
  6218.         } else if ( token.Icmp( "end" ) == 0 ) {
  6219.             station->EndHealing( );
  6220.         } else {
  6221.             return false;
  6222.         }
  6223.         return true;
  6224.     }
  6225.  
  6226.     src->UnreadToken( &token );
  6227.     return false;
  6228. }
  6229.  
  6230. /*
  6231. ==============
  6232. idPlayer::Collide
  6233. ==============
  6234. */
  6235. bool idPlayer::Collide( const trace_t &collision, const idVec3 &velocity ) {
  6236.     idEntity *other;
  6237.  
  6238.     if ( gameLocal.isClient ) {
  6239.         return false;
  6240.     }
  6241.  
  6242.     other = gameLocal.entities[ collision.c.entityNum ];
  6243.     if ( other ) {
  6244.         other->Signal( SIG_TOUCH );
  6245.         if ( !spectating ) {
  6246.             if ( other->RespondsTo( EV_Touch ) ) {
  6247.                 other->ProcessEvent( &EV_Touch, this, &collision );
  6248.             }
  6249.         } else {
  6250.             if ( other->RespondsTo( EV_SpectatorTouch ) ) {
  6251.                 other->ProcessEvent( &EV_SpectatorTouch, this, &collision );
  6252.             }
  6253.         }
  6254.     }
  6255.     return false;
  6256. }
  6257.  
  6258. /*
  6259. ================
  6260. idPlayer::UpdateLocation
  6261.  
  6262. Searches nearby locations 
  6263. ================
  6264. */
  6265.  void idPlayer::UpdateLocation( void ) {
  6266.        if ( hud ) {
  6267.          idLocationEntity *locationEntity = gameLocal.LocationForPoint( GetEyePosition() );
  6268.          if ( locationEntity ) {
  6269.              hud->SetStateString( "location", locationEntity->GetLocation() );
  6270.          } else {
  6271. // RAVEN BEGIN
  6272. // rjohnson: temp fix until id corrects slow downs created from constant string lookup
  6273. //             hud->SetStateString( "location", common->GetLocalizedString( "#str_102911" ) );
  6274.              hud->SetStateString( "location", "Unidentified" );
  6275. // RAVEN END
  6276.          }
  6277.        }
  6278. }
  6279.  
  6280. /*
  6281. ================
  6282. idPlayer::UpdateFocus
  6283.  
  6284. Searches nearby entities for interactive guis, possibly making one of them
  6285. the focus and sending it a mouse move event
  6286. ================
  6287. */
  6288. void idPlayer::UpdateFocus( void ) {
  6289.     
  6290.     // These only need to be updated at the last tic
  6291.     if ( !gameLocal.isLastPredictFrame ) {
  6292.         return;
  6293.     }
  6294.     
  6295.     idClipModel*        clipModelList[ MAX_GENTITIES ];
  6296.     idClipModel*        clip;
  6297.     int                    listedClipModels;
  6298.     idEntity*            ent;
  6299.     idUserInterface*    oldBrackets;
  6300.     int                    oldTalkCursor;
  6301.     int                    i;
  6302.     int                    j;
  6303.     idVec3                start;
  6304.     idVec3                end;
  6305.     trace_t                trace;
  6306.     guiPoint_t            pt;
  6307.  
  6308. // RAVEN BEGIN
  6309.     // mekberg: removed check to see if attack was held.
  6310. // RAVEN END
  6311.  
  6312.     // No focus during cinimatics
  6313.     if ( gameLocal.inCinematic ) {
  6314.         return;
  6315.     }
  6316.  
  6317.     // Focus has a limited time, make sure it hasnt expired
  6318.     if ( focusTime && gameLocal.time > focusTime ) {
  6319.         ClearFocus ( );
  6320.     }
  6321.  
  6322.      if ( spectating ) {
  6323.          return;
  6324.       }
  6325.  
  6326.     if ( g_perfTest_noPlayerFocus.GetBool() ) {
  6327.         return;
  6328.     }
  6329.  
  6330.     // Kill the focus brackets when their time has elapsed
  6331.     oldBrackets = focusBrackets;    
  6332.     if ( focusBracketsTime && gameLocal.time > focusBracketsTime ) {
  6333.         focusBrackets = NULL;
  6334.     }
  6335.  
  6336.     oldTalkCursor = talkCursor;
  6337.     talkCursor = 0;
  6338.     start = GetEyePosition();
  6339.     end = start + viewAngles.ToForward() * 768.0f;
  6340.  
  6341. #ifdef _XENON
  6342.  
  6343.         if ( gameLocal.isMultiplayer && (gameLocal.isMultiplayer && entityNumber == gameLocal.localClientNum) ) {
  6344.  
  6345.             bestEnemy = NULL;
  6346.             idEntity *ent = NULL;
  6347.             idActor *actor = NULL;
  6348.             bool inside;
  6349.             bool showDebug = cvarSystem->GetCVarBool("pm_showAimAssist");
  6350.             float bDist = cvarSystem->GetCVarInteger("pm_AimAssistDistance");
  6351.             float dist;
  6352.             idFrustum aimArea;
  6353.             float dNear, dFar, size;
  6354.             renderView_t *rv = GetRenderView();
  6355.             float fovY, fovX;
  6356.             // field of view
  6357.              gameLocal.CalcFov( CalcFov( true ), fovX, fovY );
  6358.             
  6359.         
  6360.             dNear = cvarSystem->GetCVarFloat( "r_znear" );
  6361.             dFar = cvarSystem->GetCVarInteger("pm_AimAssistDistance");
  6362.             size = dFar * idMath::Tan( DEG2RAD( fovY * 0.5f ) ) * cvarSystem->GetCVarInteger("pm_AimAssistFOV")/100.0;
  6363.             aimArea.SetOrigin( GetEyePosition() );
  6364.             aimArea.SetAxis( viewAngles.ToMat3() );
  6365.             aimArea.SetSize( dNear, dFar, size, size );
  6366.         
  6367.  
  6368.             if(showDebug){
  6369.                 gameRenderWorld->DebugFrustum(colorRed, aimArea, false, 20);
  6370.             }
  6371.  
  6372.                     
  6373.             if ( gameLocal.isMultiplayer){
  6374.  
  6375.                 idLinkList<idEntity> *entities = &gameLocal.snapshotEntities;
  6376.                 if(gameLocal.isServer)
  6377.                 {
  6378.                     entities = &gameLocal.spawnedEntities;
  6379.                 }
  6380.                 ent = entities->Next();
  6381.                 while( ent != NULL) {
  6382.  
  6383.                     if(idStr::Icmp(ent->GetClassname(),"idPlayer"))
  6384.                     {
  6385.                         if(gameLocal.isServer)
  6386.                         {
  6387.                             ent = ent->spawnNode.Next();
  6388.                         }
  6389.                         else
  6390.                         {
  6391.                             ent = ent->snapshotNode.Next();
  6392.                         }
  6393.                         continue;
  6394.                     }
  6395.  
  6396.                     if(!idStr::Icmp(name.c_str(),ent->name.c_str()))
  6397.                     {
  6398.                         if(gameLocal.isServer)
  6399.                         {
  6400.                             ent = ent->spawnNode.Next();
  6401.                         }
  6402.                         else
  6403.                         {
  6404.                             ent = ent->snapshotNode.Next();
  6405.                         }
  6406.                         continue;
  6407.                     }
  6408.  
  6409.                     const idBounds &bounds = ent->GetPhysics()->GetAbsBounds();
  6410.                     if(showDebug)
  6411.                     {
  6412.                         gameRenderWorld->DebugBounds(colorGreen, bounds, vec3_origin, 20);
  6413.                     }
  6414.                     inside = aimArea.IntersectsBounds(bounds);
  6415.                     if ( inside ) {
  6416.                         dist = bounds.ShortestDistance(GetEyePosition());
  6417.                         if(bDist > dist)
  6418.                         {
  6419.                             bDist = dist;
  6420.                             bestEnemy = (idActor *)ent;
  6421.                         }
  6422.                     }
  6423.  
  6424.                     if(gameLocal.isServer)
  6425.                     {
  6426.                         ent = ent->spawnNode.Next();
  6427.                     }
  6428.                     else
  6429.                     {
  6430.                         ent = ent->snapshotNode.Next();
  6431.                     }
  6432.                 
  6433.                 }
  6434.             }
  6435.             
  6436.             if ( bestEnemy ) {
  6437.                 if ( cursor ) {
  6438.                     cursor->HandleNamedEvent ( "weaponHit" );
  6439.                 }
  6440.  
  6441.                 int slow = cvarSystem->GetCVarInteger("pm_AimAssistSlow");
  6442.                 usercmdGen->SetSlowJoystick(slow);
  6443.             } else {
  6444.                 usercmdGen->SetSlowJoystick(100);
  6445.             }
  6446.  
  6447.             return;
  6448.         }
  6449.  
  6450. #endif
  6451.  
  6452.      // player identification -> names to the hud
  6453.      if ( gameLocal.isMultiplayer && entityNumber == gameLocal.localClientNum ) {
  6454.          idVec3 end = start + viewAngles.ToForward() * 768.0f;
  6455.         gameLocal.TracePoint( this, trace, start, end, MASK_SHOT_BOUNDINGBOX, this );
  6456.         // no aim text if player is invisible
  6457.          if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum < MAX_CLIENTS ) && ( !((idPlayer*)gameLocal.entities[ trace.c.entityNum ])->PowerUpActive( POWERUP_INVISIBILITY ) ) ) {
  6458.             if( trace.c.entityNum != aimClientNum ) {
  6459.                 if( mphud ) {        
  6460.                     mphud->SetStateString( "aim_text", va( "%s\n%s", gameLocal.userInfo[ trace.c.entityNum ].GetString( "ui_name" ), gameLocal.userInfo[ trace.c.entityNum ].GetString( "ui_clan" ) ) );
  6461.                     if( gameLocal.IsTeamGame() ) {
  6462.                         idPlayer* p = static_cast<idPlayer*>(gameLocal.entities[ trace.c.entityNum ]);
  6463.                         mphud->SetStateInt( "aim_player_team", p->team );
  6464.     
  6465.                         // when looking at a friendly, color the crosshair
  6466.                         if( cursor ) {
  6467.                             if( p->team == team ) {
  6468.                                 cursor->HandleNamedEvent( "targetFriendly" );
  6469.                             } else {
  6470.                                 cursor->HandleNamedEvent( "clearTarget" );
  6471.                             }
  6472.                         }
  6473.                     }
  6474.  
  6475.                     mphud->HandleNamedEvent( "aim_text" );
  6476.                     aimClientNum = trace.c.entityNum;
  6477.                 }    
  6478.             }
  6479.         } else {
  6480.             if( mphud && aimClientNum != -1 ) {
  6481.                 mphud->HandleNamedEvent( "aim_fade" );
  6482.                 aimClientNum = -1;
  6483.             }
  6484.             if( cursor ) {
  6485.                 cursor->HandleNamedEvent( "clearTarget" );
  6486.             }
  6487.         }
  6488.      }
  6489.  
  6490.     idBounds bounds( start );
  6491.     bounds.AddPoint( end );
  6492.     
  6493.     listedClipModels = gameLocal.ClipModelsTouchingBounds( this, bounds, -1, clipModelList, MAX_GENTITIES );
  6494.  
  6495.     // Do autoaim
  6496.     
  6497.     
  6498. //RAVEN BEGIN
  6499. //asalmon: auto-aim for Xenon, finds a best enemy and changes the crosshairs.
  6500. #ifdef _XBOX
  6501.     
  6502.         bool doAimAssist = cvarSystem->GetCVarBool("pm_AimAssist");
  6503.         
  6504.         bestEnemy = NULL;
  6505.         bool showDebug = cvarSystem->GetCVarBool("pm_showAimAssist");
  6506.         float bDist = cvarSystem->GetCVarInteger("pm_AimAssistDistance");
  6507.         float dist;
  6508.         idFrustum aimArea;
  6509.         float dNear, dFar, size;
  6510.         renderView_t *rv = GetRenderView();
  6511.         float fovY, fovX;
  6512.         
  6513.         if ( doAimAssist ) {
  6514.         
  6515.             // field of view
  6516.              gameLocal.CalcFov( CalcFov( true ), fovX, fovY );
  6517.         
  6518.             dNear = cvarSystem->GetCVarFloat( "r_znear" );
  6519.             dFar = bDist;
  6520.             size = dFar * idMath::Tan( DEG2RAD( fovY * 0.5f ) ) * cvarSystem->GetCVarInteger("pm_AimAssistFOV")/100.0;
  6521.             aimArea.SetOrigin( GetEyePosition() );
  6522.             aimArea.SetAxis( viewAngles.ToMat3() );
  6523.             aimArea.SetSize( dNear, dFar, size, size );
  6524.     
  6525.             if ( showDebug ) {
  6526.                 gameRenderWorld->DebugFrustum( colorRed, aimArea, false, 20 );
  6527.             }
  6528.         }
  6529.  
  6530. #endif
  6531. //RAVEN END
  6532.     
  6533.     
  6534.     // no pretense at sorting here, just assume that there will only be one active
  6535.     // gui within range along the trace
  6536.     bool wasTargetFriendly = targetFriendly;
  6537.     targetFriendly = false;
  6538.     for ( i = 0; i < listedClipModels; i++ ) {
  6539.         clip = clipModelList[ i ];
  6540.         ent = clip->GetEntity();
  6541.  
  6542.         if ( ent->IsHidden() ) {
  6543.             continue;
  6544.         }
  6545.  
  6546.         float focusLength = (ent->GetPhysics()->GetOrigin() - start).LengthFast() - ent->GetPhysics()->GetBounds().GetRadius();
  6547.         // derp, does MP want to do this?
  6548.         //    basically what was happening was that heads, which are an idAFAttachment, were being used for the focusLength
  6549.         //    calculations, but that generates a different focus length than the body would (when you scan the crosshair back 
  6550.         //    and forth between the head and body).  This ends up looking like a bug when you are right at the threshold where
  6551.         //    the body will display the name and rank, but doesn't when you pitch up to aim at the head.  Hence, using the body
  6552.         //    for this special case.
  6553.         if ( !gameLocal.isMultiplayer && ent->IsType( idAFAttachment::GetClassType() )) {
  6554.             idEntity *body = static_cast<idAFAttachment *>( ent )->GetBody();
  6555.             if ( body && body->IsType( idAI::GetClassType()) )     {
  6556.                 focusLength = (body->GetPhysics()->GetOrigin() - start).LengthFast() - body->GetPhysics()->GetBounds().GetRadius();
  6557.             }
  6558.         }
  6559.         
  6560.         bool isAI = ent->IsType( idAI::GetClassType() );
  6561.         bool isFriendly = false;
  6562.         
  6563.         if ( isAI ) {
  6564.             isFriendly = (static_cast<idAI *>( ent )->team == team);
  6565.         }
  6566.         
  6567.         //change crosshair color if over a friendly
  6568.         if ( !gameLocal.isMultiplayer 
  6569.             && focusType == FOCUS_NONE 
  6570.             && !g_crosshairCharInfoFar.GetBool() ) {
  6571.             if ( focusLength < 512 ) {
  6572.                 bool newTargetFriendly = false;
  6573.                 if ( isAI && isFriendly ) {
  6574.                     newTargetFriendly = true;
  6575.                 } else if ( ent->IsType( idAFAttachment::GetClassType() ) ) {
  6576.                     idEntity *body = static_cast<idAFAttachment *>( ent )->GetBody();
  6577.                     if ( body && body->IsType( idAI::GetClassType() ) && ( static_cast<idAI *>( body )->team == team ) ) {
  6578.                         newTargetFriendly = true;
  6579.                     }
  6580.                 }
  6581.                 if ( newTargetFriendly ) {
  6582.                     gameLocal.TracePoint( this, trace, start, end, MASK_SHOT_RENDERMODEL, this );
  6583.                     if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum == ent->entityNumber ) ) {
  6584.                         targetFriendly = true;
  6585.                         if( cursor && !wasTargetFriendly ) {
  6586.                             cursor->HandleNamedEvent( "showCrossBuddy" );
  6587.                         }
  6588.                     }
  6589.                 }
  6590.             }
  6591.         }
  6592.  
  6593. // RAVEN BEGIN
  6594.  
  6595. #ifdef _XENON
  6596.         if ( doAimAssist ) {
  6597.             if ( isAI && !isFriendly ) {
  6598.                 
  6599.                 if ( idStr::Icmp( name.c_str(),ent->name.c_str() ) != 0 ) {
  6600.                 
  6601.                     const idBounds &bounds = ent->GetPhysics()->GetAbsBounds();
  6602.                     //if ( showDebug ) {
  6603.                         //gameRenderWorld->DebugBounds(colorGreen, bounds, vec3_origin, 20);
  6604.                     //}
  6605.                     bool inside = aimArea.IntersectsBounds(bounds);
  6606.                     
  6607.                     if ( inside ) {
  6608.                         dist = bounds.ShortestDistance(GetEyePosition());
  6609.                         if ( bDist > dist ) {
  6610.                             bDist = dist;
  6611.                             bestEnemy = (idActor *)ent;
  6612.                         }
  6613.                     }                    
  6614.                 }
  6615.             }
  6616.         }
  6617. #endif
  6618.  
  6619. // mekberg: allowFocus removed
  6620.         if ( focusLength < (g_crosshairCharInfoFar.GetBool()?256.0f:80.0f) ) {
  6621. // RAVEN END
  6622.             if ( ent->IsType( idAFAttachment::GetClassType() ) ) {
  6623.                 idEntity *body = static_cast<idAFAttachment *>( ent )->GetBody();
  6624.                 if ( body && body->IsType( idAI::GetClassType() ) && ( static_cast<idAI *>( body )->GetTalkState() >= TALK_OK ) ) {
  6625.                     gameLocal.TracePoint( this, trace, start, end, MASK_SHOT_RENDERMODEL, this );
  6626.                     if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum == ent->entityNumber ) ) {
  6627.                         SetFocus ( FOCUS_CHARACTER, FOCUS_TIME, body, NULL );
  6628.                         if ( focusLength < 80.0f ) {
  6629.                             talkCursor = 1;
  6630.                         }
  6631.                         break;
  6632.                     }
  6633.                 }
  6634.                 continue;
  6635.             }
  6636.  
  6637.             if ( isAI ) {
  6638.                  if ( static_cast<idAI *>( ent )->GetTalkState() >= TALK_OK ) {
  6639.                     gameLocal.TracePoint( this, trace, start, end, MASK_SHOT_RENDERMODEL, this );
  6640.                     if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum == ent->entityNumber ) ) {
  6641.                         SetFocus ( FOCUS_CHARACTER, FOCUS_TIME, ent, NULL );
  6642.                         if ( focusLength < 80.0f ) {
  6643.                             talkCursor = 1;
  6644.                         }
  6645.                         break;
  6646.                     }
  6647.                 }
  6648.                 continue;
  6649.             }
  6650.         }
  6651.  
  6652.         if ( focusLength < 80.0f ) {
  6653.             if ( ent->IsType( rvVehicle::GetClassType() ) ) {
  6654.                 rvVehicle* vehicle = static_cast<rvVehicle*>(ent);
  6655.                 gameLocal.TracePoint( this, trace, start, end, MASK_SHOT_BOUNDINGBOX, this );
  6656.                 if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum == ent->entityNumber ) && ((end - start).Length() * trace.fraction < vehicle->FocusLength()) ) {
  6657.                     //jshepard: locked or unusable vehicles
  6658.                     if ( !vehicle->IsLocked() && vehicle->HasOpenPositions() ) {
  6659.                         SetFocus ( FOCUS_VEHICLE, FOCUS_TIME, ent, NULL );
  6660.                     } else {
  6661.                         SetFocus ( FOCUS_LOCKED_VEHICLE, FOCUS_TIME, ent, NULL );
  6662.                     }
  6663.                     break;
  6664.                 }
  6665.             } 
  6666.  
  6667.             //jshepard: unusable vehicle
  6668.             if( ent->spawnArgs.GetBool( "unusableVehicle", "0" ) ) {
  6669.                 gameLocal.TracePoint( this, trace, start, end, MASK_ALL, this );
  6670.                 if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum == ent->entityNumber ) ) {
  6671.                     SetFocus ( FOCUS_LOCKED_VEHICLE, FOCUS_TIME, ent, NULL );
  6672.                     break;
  6673.                 }
  6674.             }
  6675.             // Usable entities are last
  6676.             if ( ent->fl.usable ) {
  6677.             //jshepard: fake vehicles
  6678.                 gameLocal.TracePoint( this, trace, start, end, MASK_ALL, this );
  6679.                 if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum == ent->entityNumber ) ) {
  6680.                     if( ent->spawnArgs.GetBool("crosshair_vehicle"))    {
  6681.                         SetFocus ( FOCUS_USABLE_VEHICLE, FOCUS_TIME, ent, NULL );
  6682.                     }    else    {
  6683.                         SetFocus ( FOCUS_USABLE, FOCUS_TIME, ent, NULL );
  6684.                     }
  6685.                     break;
  6686.                 }
  6687.             }
  6688.         }
  6689.  
  6690.         if ( !ent->GetRenderEntity() || !ent->GetRenderEntity()->gui[ 0 ] || !ent->GetRenderEntity()->gui[ 0 ]->IsInteractive() ) {
  6691.             continue;
  6692.         }
  6693.  
  6694.         if ( ent->spawnArgs.GetBool( "inv_item" ) ) {
  6695.             // don't allow guis on pickup items focus
  6696.             continue;
  6697.         }
  6698.  
  6699.         pt = gameRenderWorld->GuiTrace( ent->GetModelDefHandle(), start, end );
  6700.         if ( pt.x != -1 ) {
  6701.             idUserInterface*    ui = NULL;            
  6702.             renderEntity_t*        focusGUIrenderEntity;
  6703.             
  6704.             focusGUIrenderEntity = ent->GetRenderEntity();
  6705.             if ( !focusGUIrenderEntity ) {
  6706.                 continue;
  6707.             }
  6708.  
  6709.             if ( pt.guiId >= 1 && pt.guiId <= MAX_RENDERENTITY_GUI ) {
  6710.                 ui = focusGUIrenderEntity->gui[ pt.guiId-1 ];
  6711.             }
  6712.             
  6713.             if ( ui == NULL || !ui->IsInteractive ( ) ) {
  6714.                 continue;
  6715.             }
  6716.  
  6717.             // All focused guis get brackets
  6718.             focusBrackets = ui;
  6719.  
  6720.             // Any GUI that is too far away will just get bracket focus so the player can still shoot 
  6721.             // but still see which guis are interractive
  6722.             if ( focusLength > 300.0f ) {
  6723.                 ClearFocus ( );
  6724.                 break;
  6725.             } else if ( focusLength > 80.0f ) {
  6726.                 ClearFocus ( );
  6727.                 focusType = FOCUS_BRACKETS;
  6728.                 break;
  6729.             }
  6730.  
  6731.             // If this is the first time this gui was activated then set up some things
  6732.             if ( focusEnt != ent ) {
  6733.                 const idKeyValue* kv;
  6734.                 
  6735.                 // new activation
  6736.                 // going to see if we have anything in inventory a gui might be interested in
  6737.                 // need to enumerate inventory items
  6738.                 ui->SetStateInt( "inv_count", inventory.items.Num() );
  6739.                 for ( j = 0; j < inventory.items.Num(); j++ ) {
  6740.                     idDict *item = inventory.items[ j ];
  6741.                     const char *iname = item->GetString( "inv_name" );
  6742.                     iname = common->GetLocalizedString( iname );
  6743.  
  6744.                     const char *iicon = item->GetString( "inv_icon" );
  6745.                     const char *itext = item->GetString( "inv_text" );
  6746.  
  6747.                     ui->SetStateString( va( "inv_name_%i", j), iname );
  6748.                     ui->SetStateString( va( "inv_icon_%i", j), iicon );
  6749.                     ui->SetStateString( va( "inv_text_%i", j), itext );
  6750.                     kv = item->MatchPrefix("inv_id", NULL);
  6751.                     if ( kv ) {
  6752.                         ui->SetStateString( va( "inv_id_%i", j ), kv->GetValue() );
  6753.                     }
  6754.                     ui->SetStateInt( iname, 1 );
  6755.                 }
  6756.  
  6757.                 for( j = 0; j < inventory.pdaSecurity.Num(); j++ ) {
  6758.                     const char *p = inventory.pdaSecurity[ j ];
  6759.  
  6760.                     if ( p && *p ) {
  6761.                         ui->SetStateInt( p, 1 );
  6762.                     }
  6763.                 }
  6764.  
  6765.                 ui->SetStateString( "player_health", va("%i", health ) );
  6766.                 ui->SetStateString( "player_armor", va( "%i%%", inventory.armor ) );
  6767.  
  6768.                 kv = ent->spawnArgs.MatchPrefix( "gui_", NULL );
  6769.                 while ( kv ) {
  6770.                     ui->SetStateString( kv->GetKey(), common->GetLocalizedString( kv->GetValue() ) );
  6771.                     kv = ent->spawnArgs.MatchPrefix( "gui_", kv );
  6772.                 }
  6773.             }
  6774.  
  6775.             // clamp the mouse to the corner
  6776.             const char*    command;
  6777.             sysEvent_t    ev;
  6778.              ev = sys->GenerateMouseMoveEvent( -2000, -2000 );
  6779.             command = ui->HandleEvent( &ev, gameLocal.time );
  6780.               HandleGuiCommands( ent, command );
  6781.  
  6782.             // move to an absolute position
  6783.              ev = sys->GenerateMouseMoveEvent( pt.x * SCREEN_WIDTH, pt.y * SCREEN_HEIGHT );
  6784.             command = ui->HandleEvent( &ev, gameLocal.time );
  6785.              HandleGuiCommands( ent, command );
  6786.             
  6787.             SetFocus ( FOCUS_GUI, FOCUS_GUI_TIME, ent, ui );
  6788.             break;
  6789.         }
  6790.     }
  6791.  
  6792. #ifdef _XENON
  6793.     if ( bestEnemy && doAimAssist ) {
  6794.         
  6795.         if ( cursor ) {
  6796.             cursor->HandleNamedEvent ( "weaponHit" );
  6797.         }
  6798.  
  6799.         int slow = cvarSystem->GetCVarInteger( "pm_AimAssistSlow" );
  6800.         usercmdGen->SetSlowJoystick( slow );
  6801.     
  6802.     } else {
  6803.         usercmdGen->SetSlowJoystick(100);
  6804.     }
  6805. #endif
  6806.  
  6807.     if ( wasTargetFriendly && !targetFriendly && focusType == FOCUS_NONE ) {
  6808.         if ( cursor ) {
  6809.             cursor->HandleNamedEvent ( WeaponIsEnabled() ? "showCrossCombat" : "crossHide" );
  6810.         }
  6811.     }
  6812.  
  6813.     // Update the focus brackets within the hud
  6814.     if ( focusBrackets && hud ) {
  6815.         if (focusType == FOCUS_BRACKETS || focusType == FOCUS_GUI ) {
  6816.             if ( !oldBrackets || focusBracketsTime ) {
  6817.                 
  6818. #ifdef _XENON
  6819.                 int nodpad = 0;
  6820.                 if ( focusUI ) {
  6821.                     nodpad = focusUI->GetStateInt( "nodpad", "0" );
  6822.                 }
  6823.                 hud->SetStateInt( "GUIIsNotUsingDPad", nodpad );
  6824. #endif
  6825.  
  6826.                 hud->HandleNamedEvent ( "showBrackets" );            
  6827.             }
  6828.             focusBracketsTime = 0;
  6829.         } else {
  6830.             if ( focusBracketsTime == 0 ) {
  6831.                 hud->HandleNamedEvent ( "fadeBrackets" );
  6832.                 focusBracketsTime = gameLocal.time + 2000;
  6833.             }
  6834.         }
  6835.         focusBrackets->SetStateBool ( "2d_calc", true );
  6836.     }    
  6837.  
  6838.      if ( cursor && ( oldTalkCursor != talkCursor ) ) {
  6839.          cursor->SetStateInt( "talkcursor", talkCursor );
  6840.      }
  6841.  
  6842. }
  6843.  
  6844. /*
  6845. ================
  6846. idPlayer::ClearFocus
  6847. ================
  6848. */
  6849. void idPlayer::ClearFocus ( void ) {
  6850.     SetFocus ( FOCUS_NONE, 0, NULL, NULL );
  6851. }
  6852.  
  6853. void idPlayer::UpdateFocusCharacter( idEntity* newEnt ) {
  6854.     if ( !cursor ) {
  6855.         return;
  6856.     }
  6857.     // Handle character interaction
  6858.     cursor->SetStateString( "npc", common->GetLocalizedString(newEnt->spawnArgs.GetString( "npc_name", "Joe" )) );
  6859.     cursor->SetStateString( "npcdesc", common->GetLocalizedString(newEnt->spawnArgs.GetString( "npc_description", "" )) );
  6860.     if ( newEnt->IsType( rvAIMedic::GetClassType() ) ) {
  6861.         if ( ((rvAIMedic*)newEnt)->isTech ) {
  6862.             cursor->SetStateInt( "npc_medictech", 2 );
  6863.         } else {
  6864.             cursor->SetStateInt( "npc_medictech", 1 );
  6865.         }
  6866.     } else {
  6867.         cursor->SetStateInt( "npc_medictech", 0 );
  6868.     }
  6869. }
  6870. /*
  6871. ================
  6872. idPlayer::SetFocus
  6873. ================
  6874. */
  6875. void idPlayer::SetFocus ( playerFocus_t newType, int _focusTime, idEntity* newEnt, idUserInterface* newUI ) {
  6876.     const char* command;
  6877.  
  6878.     // Handle transitions from one user interface to another or to none
  6879.     if ( newUI != focusUI ) {
  6880.         if ( focusUI ) {        
  6881.             command = focusUI->Activate( false, gameLocal.time );
  6882.             HandleGuiCommands( focusEnt, command );
  6883.             StartSound( "snd_guiexit", SND_CHANNEL_ANY, 0, false, NULL );
  6884.         }            
  6885.         if ( newUI ) {
  6886.             command = newUI->Activate( true, gameLocal.time );
  6887.             HandleGuiCommands( newEnt, command );
  6888.             StartSound( "snd_guienter", SND_CHANNEL_ANY, 0, false, NULL );
  6889.  
  6890.             // Hide the weapon when a gui is being used
  6891.             /*
  6892.             if ( weapon ) {
  6893.                 weapon->Hide();                
  6894.             }
  6895.             */
  6896.         }/*
  6897.          else if ( weapon ) {
  6898.             // Show the weapon since it was hidden when a gui first got focus
  6899.             weapon->Show();
  6900.         }        
  6901.         */
  6902.     }
  6903.  
  6904.     //jshepard: the medic/tech crosshair won't update unless handleNamedEvent is called. I moved this outside
  6905.     //of the switch below because the focus type is the same when moving directly from marine to marine, but the
  6906.     //medic/tech status may change.
  6907.     if ( newType == FOCUS_CHARACTER ) {
  6908.         if ( newEnt != focusEnt ) {
  6909.             UpdateFocusCharacter( newEnt );
  6910.             cursor->HandleNamedEvent ( "showCrossTalk" );
  6911.         }
  6912.     }
  6913.     // Show the appropriate cursor for the current focus type
  6914.     if ( cursor && ( focusType != newType ) ) {
  6915.         switch ( newType ) {
  6916.             case FOCUS_VEHICLE:
  6917.             case FOCUS_USABLE_VEHICLE:
  6918.                 cursor->HandleNamedEvent ( "showCrossVehicle" );
  6919.                 break;
  6920.             case FOCUS_LOCKED_VEHICLE:
  6921.                 cursor->HandleNamedEvent ( "showCrossVehicleLocked" );
  6922.                 break;
  6923.             case FOCUS_USABLE:
  6924.                 cursor->HandleNamedEvent ( "showCrossUsable" );
  6925.                 break;
  6926.             case FOCUS_GUI:
  6927.                 cursor->HandleNamedEvent ( "showCrossGui" );
  6928.                 break;
  6929.             case FOCUS_CHARACTER:
  6930.                 if ( newEnt != focusEnt ) {
  6931.                     UpdateFocusCharacter( newEnt );
  6932.                 }
  6933.                 cursor->HandleNamedEvent ( "showCrossTalk" );
  6934.                 break;
  6935.             default:
  6936.                 // Make sure the weapon is shown in the default state
  6937. // RAVEN BEGIN
  6938. // abahr: don't do this if weapons are disabled
  6939.                 cursor->HandleNamedEvent ( WeaponIsEnabled() ? "showCrossCombat" : "crossHide" );
  6940. // RAVEN END
  6941.                 break;
  6942.         }
  6943.     }
  6944.  
  6945.  
  6946.     focusType = newType;
  6947.     focusEnt  = newEnt;
  6948.     focusUI      = newUI;
  6949.     
  6950.     if ( focusType == FOCUS_NONE ) {
  6951.         focusTime = 0;
  6952.     } else {
  6953.         focusTime = gameLocal.time + _focusTime;
  6954.     }
  6955. }
  6956.  
  6957. /*
  6958. =================
  6959. idPlayer::CrashLand
  6960.  
  6961. Check for hard landings that generate sound events
  6962. =================
  6963. */
  6964. void idPlayer::CrashLand( const idVec3 &oldOrigin, const idVec3 &oldVelocity ) {
  6965.     idVec3        origin, velocity;
  6966.     idVec3        gravityVector, gravityNormal;
  6967.     float        delta;
  6968.     float        dist;
  6969.     float        vel, acc;
  6970.     float        t;
  6971.     float        a, b, c, den;
  6972.     waterLevel_t waterLevel;
  6973.      bool        noDamage;
  6974.  
  6975.     pfl.softLanding = false;
  6976.     pfl.hardLanding = false;
  6977.  
  6978.     // if the player is not on the ground
  6979.     if ( !physicsObj.HasGroundContacts() ) {
  6980.         return;
  6981.     }
  6982.  
  6983.     gravityNormal = physicsObj.GetGravityNormal();
  6984.  
  6985.     // if the player wasn't going down
  6986.     if ( ( oldVelocity * -gravityNormal ) >= 0.0f ) {
  6987.         return;
  6988.     }
  6989.  
  6990.     waterLevel = physicsObj.GetWaterLevel();
  6991.  
  6992.     // never take falling damage if completely underwater
  6993.     if ( waterLevel == WATERLEVEL_HEAD ) {
  6994.         return;
  6995.     }
  6996.  
  6997.     // no falling damage if touching a nodamage surface
  6998.      noDamage = false;
  6999.     for ( int i = 0; i < physicsObj.GetNumContacts(); i++ ) {
  7000.         const contactInfo_t &contact = physicsObj.GetContact( i );
  7001.         if ( contact.material->GetSurfaceFlags() & SURF_NODAMAGE ) {
  7002.              noDamage = true;
  7003.              break;
  7004.         }
  7005.     }
  7006.  
  7007.     //jshepard: no falling damage if falling damage is disabled
  7008.     if( pfl.noFallingDamage )    {
  7009.         return;
  7010.     }
  7011.  
  7012.     origin = GetPhysics()->GetOrigin();
  7013.     gravityVector = physicsObj.GetGravity();
  7014.  
  7015.     // calculate the exact velocity on landing
  7016.     dist = ( origin - oldOrigin ) * -gravityNormal;
  7017.     vel = oldVelocity * -gravityNormal;
  7018.     acc = -gravityVector.Length();
  7019.  
  7020.     a = acc / 2.0f;
  7021.     b = vel;
  7022.     c = -dist;
  7023.  
  7024.     den = b * b - 4.0f * a * c;
  7025.     if ( den < 0 ) {
  7026.         return;
  7027.     }
  7028.     t = ( -b - idMath::Sqrt( den ) ) / ( 2.0f * a );
  7029.  
  7030.     delta = vel + t * acc;
  7031.     delta = delta * delta * 0.0001;
  7032.  
  7033.     // reduce falling damage if there is standing water
  7034.     if ( waterLevel == WATERLEVEL_WAIST ) {
  7035.         delta *= 0.25f;
  7036.     }
  7037.     if ( waterLevel == WATERLEVEL_FEET ) {
  7038.         delta *= 0.5f;
  7039.     }
  7040.  
  7041.     if ( delta < 1.0f ) {
  7042.         return;
  7043.     }
  7044.  
  7045.     // ddynerman: moved height delta selection to player def
  7046.     if ( delta > fatalFallDelta && fatalFallDelta > 0.0f ) {
  7047.         pfl.hardLanding = true;
  7048.         landChange = -32;
  7049.         landTime = gameLocal.time;
  7050.          if ( !noDamage ) {
  7051.              pain_debounce_time = gameLocal.time + pain_delay + 1;  // ignore pain since we'll play our landing anim
  7052.              Damage( NULL, NULL, idVec3( 0, 0, -1 ), "damage_fatalfall", 1.0f, 0 );
  7053.          }
  7054.     } else if ( delta > hardFallDelta && hardFallDelta > 0.0f ) {
  7055.         pfl.hardLanding = true;
  7056.         landChange    = -24;
  7057.         landTime    = gameLocal.time;
  7058.          if ( !noDamage ) {
  7059.              pain_debounce_time = gameLocal.time + pain_delay + 1;  // ignore pain since we'll play our landing anim
  7060.              Damage( NULL, NULL, idVec3( 0, 0, -1 ), "damage_hardfall", 1.0f, 0 );
  7061.          }
  7062.     } else if ( delta > softFallDelta && softFallDelta > 0.0f ) {
  7063.         pfl.softLanding = true;
  7064.          landChange    = -16;
  7065.          landTime    = gameLocal.time;
  7066.          if ( !noDamage ) {
  7067.              pain_debounce_time = gameLocal.time + pain_delay + 1;  // ignore pain since we'll play our landing anim
  7068.              Damage( NULL, NULL, idVec3( 0, 0, -1 ), "damage_softfall", 1.0f, 0 );
  7069.         }
  7070.     } else if ( delta > noFallDelta && noFallDelta > 0.0f ) {
  7071.         pfl.softLanding = true;
  7072.         landChange    = -8;
  7073.         landTime    = gameLocal.time;
  7074.     }
  7075.  
  7076.     // ddynerman: sometimes the actual landing animation is pre-empted by another animation (i.e. sliding, moving forward)
  7077.     // so we play the landing sound here instead of relying on the anim
  7078.     if( pfl.hardLanding ) {
  7079.         StartSound ( "snd_land_hard", SND_CHANNEL_ANY, 0, false, NULL );        
  7080.         StartSound ( "snd_land_hard_pain", SND_CHANNEL_ANY, 0, false, NULL );    
  7081.     } else if ( pfl.softLanding ) {
  7082.         // todo - 2 different landing sounds for variety?
  7083.         StartSound ( "snd_land_soft", SND_CHANNEL_ANY, 0, false, NULL );                 
  7084.     }
  7085. }
  7086.  
  7087. /*
  7088. ===============
  7089. idPlayer::BobCycle
  7090. ===============
  7091. */
  7092. void idPlayer::BobCycle( const idVec3 &pushVelocity ) {
  7093.     float        bobmove;
  7094.     int            old, deltaTime;
  7095.     idVec3        vel, gravityDir, velocity;
  7096.     idMat3        viewaxis;
  7097.     float        bob;
  7098.     float        delta;
  7099.     float        speed;
  7100.     float        f;
  7101.  
  7102.  
  7103.     //
  7104.     // calculate speed and cycle to be used for
  7105.     // all cyclic walking effects
  7106.     //
  7107.     velocity = physicsObj.GetLinearVelocity() - pushVelocity;
  7108.  
  7109.     if ( noclip ) {
  7110.         velocity.Zero ( );
  7111.     }
  7112.    
  7113.     gravityDir = physicsObj.GetGravityNormal();
  7114.     vel = velocity - ( velocity * gravityDir ) * gravityDir;
  7115.     xyspeed = vel.LengthFast();
  7116.     
  7117.     if ( !physicsObj.HasGroundContacts() || influenceActive == INFLUENCE_LEVEL2 || ( gameLocal.isMultiplayer && spectating ) ) {
  7118.         // airborne
  7119.         bobCycle = 0;
  7120.         bobFoot = 0;
  7121.         bobfracsin = 0;
  7122.      } else if ( ( !usercmd.forwardmove && !usercmd.rightmove ) || ( xyspeed <= MIN_BOB_SPEED ) ) {
  7123.          // start at beginning of cycle again
  7124.          bobCycle = 0;
  7125.          bobFoot = 0;
  7126.          bobfracsin = 0;
  7127.     } else {
  7128.         if ( physicsObj.IsCrouching() ) {
  7129.             bobmove = pm_crouchbob.GetFloat();
  7130.             // ducked characters never play footsteps
  7131.         } else {
  7132.             // vary the bobbing based on the speed of the player
  7133.             bobmove = pm_walkbob.GetFloat() * ( 1.0f - bobFrac ) + pm_runbob.GetFloat() * bobFrac;
  7134.         }
  7135.  
  7136.         // check for footstep / splash sounds
  7137.         old = bobCycle;
  7138.         bobCycle = (int)( old + bobmove * gameLocal.GetMSec() ) & 255;
  7139.         bobFoot = ( bobCycle & 128 ) >> 7;
  7140.         bobfracsin = idMath::Fabs( idMath::Sin( ( bobCycle & 127 ) / 127.0 * idMath::PI ) );
  7141.     }
  7142.  
  7143.     // calculate angles for view bobbing
  7144.     viewBobAngles.Zero();
  7145.  
  7146.     // no view bob at all in MP while zoomed in
  7147.     if( gameLocal.isMultiplayer && IsZoomed() ) {
  7148.         bobCycle = 0;
  7149.         bobFoot = 0;
  7150.         bobfracsin = 0;    
  7151.         return;
  7152.     }
  7153.  
  7154.     viewaxis = viewAngles.ToMat3() * physicsObj.GetGravityAxis();
  7155.  
  7156.     // add angles based on velocity
  7157.     delta = velocity * viewaxis[0];
  7158.     viewBobAngles.pitch += delta * pm_runpitch.GetFloat();
  7159.     
  7160.     delta = velocity * viewaxis[1];
  7161.     viewBobAngles.roll -= delta * pm_runroll.GetFloat();
  7162.  
  7163.     // add angles based on bob
  7164.     // make sure the bob is visible even at low speeds
  7165.     speed = xyspeed > 200 ? xyspeed : 200;
  7166.  
  7167.     delta = bobfracsin * pm_bobpitch.GetFloat() * speed;
  7168.     if ( physicsObj.IsCrouching() ) {
  7169.         delta *= 3;        // crouching
  7170.     }
  7171.     viewBobAngles.pitch += delta;
  7172.     delta = bobfracsin * pm_bobroll.GetFloat() * speed;
  7173.     if ( physicsObj.IsCrouching() ) {
  7174.         delta *= 3;        // crouching accentuates roll
  7175.     }
  7176.     if ( bobFoot & 1 ) {
  7177.         delta = -delta;
  7178.     }
  7179.     viewBobAngles.roll += delta;
  7180.  
  7181.     // calculate position for view bobbing
  7182.     viewBob.Zero();
  7183.  
  7184.     if ( physicsObj.HasSteppedUp() ) {
  7185.  
  7186.         // check for stepping up before a previous step is completed
  7187.         deltaTime = gameLocal.time - stepUpTime;
  7188.         if ( deltaTime < STEPUP_TIME ) {
  7189.             stepUpDelta = stepUpDelta * ( STEPUP_TIME - deltaTime ) / STEPUP_TIME + physicsObj.GetStepUp();
  7190.         } else {
  7191.             stepUpDelta = physicsObj.GetStepUp();
  7192.         }
  7193.         if ( stepUpDelta > 2.0f * pm_stepsize.GetFloat() ) {
  7194.             stepUpDelta = 2.0f * pm_stepsize.GetFloat();
  7195.         }
  7196.         stepUpTime = gameLocal.time;
  7197.     }
  7198.  
  7199.     idVec3 gravity = physicsObj.GetGravityNormal();
  7200.  
  7201.     // if the player stepped up recently
  7202.     deltaTime = gameLocal.time - stepUpTime;
  7203.     if ( deltaTime < STEPUP_TIME ) {
  7204.         viewBob += gravity * ( stepUpDelta * ( STEPUP_TIME - deltaTime ) / STEPUP_TIME );
  7205.     }
  7206.  
  7207.     // add bob height after any movement smoothing
  7208.     bob = bobfracsin * xyspeed * pm_bobup.GetFloat();
  7209.     if ( bob > 6 ) {
  7210.         bob = 6;
  7211.     }
  7212. // RAVEN BEGIN
  7213. // abahr: added gravity
  7214.     viewBob += bob * -gravityDir;
  7215. // RAVEN END
  7216.  
  7217.     // add fall height
  7218.     delta = gameLocal.time - landTime;
  7219.     if ( delta < LAND_DEFLECT_TIME ) {
  7220.         f = delta / LAND_DEFLECT_TIME;
  7221.         viewBob -= gravity * ( landChange * f );
  7222.     } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
  7223.         delta -= LAND_DEFLECT_TIME;
  7224.         f = 1.0 - ( delta / LAND_RETURN_TIME );
  7225.         viewBob -= gravity * ( landChange * f );
  7226.     }    
  7227. }
  7228.  
  7229. /*
  7230. ================
  7231. idPlayer::UpdateDeltaViewAngles
  7232. ================
  7233. */
  7234. void idPlayer::UpdateDeltaViewAngles( const idAngles &angles ) {
  7235.     // set the delta angle
  7236.     idAngles delta;
  7237.     for( int i = 0; i < 3; i++ ) {
  7238.         delta[ i ] = angles[ i ] - SHORT2ANGLE( usercmd.angles[ i ] );
  7239.     }
  7240.     SetDeltaViewAngles( delta );
  7241. }
  7242.  
  7243. /*
  7244. ================
  7245. idPlayer::SetViewAngles
  7246. ================
  7247. */
  7248. void idPlayer::SetViewAngles( const idAngles &angles ) {
  7249.     UpdateDeltaViewAngles(angles);
  7250.     viewAngles = angles;
  7251. }
  7252.  
  7253. /*
  7254. ================
  7255. idPlayer::UpdateViewAngles
  7256. ================
  7257. */
  7258. void idPlayer::UpdateViewAngles( void ) {
  7259.     int i;
  7260.     idAngles delta;
  7261.  
  7262.     if ( !noclip && ( gameLocal.inCinematic || privateCameraView || gameLocal.GetCamera() || influenceActive == INFLUENCE_LEVEL2 ) ) {
  7263.         // no view changes at all, but we still want to update the deltas or else when
  7264.         // we get out of this mode, our view will snap to a kind of random angle
  7265.         UpdateDeltaViewAngles( viewAngles );
  7266.         return;
  7267.     }
  7268.  
  7269.     // if dead
  7270.     if ( health <= 0 ) {
  7271.         if ( pm_thirdPersonDeath.GetBool() ) {
  7272.             viewAngles.roll = 0.0f;
  7273.             viewAngles.pitch = 30.0f;
  7274.         } else {
  7275.             viewAngles.roll = 40.0f;
  7276.             viewAngles.pitch = -15.0f;
  7277.         }
  7278.         return;
  7279.     }
  7280.  
  7281.     // circularly clamp the angles with deltas
  7282.     // circularly clamp the angles with deltas
  7283. //    if( gameLocal.localClientNum == entityNumber ) {
  7284. //        gameLocal.Printf( "BEFORE VIEWANGLES: %s\n", viewAngles.ToString() );
  7285. //        gameLocal.Printf( "\tUSERCMD: <%d, %d, %d>\n", usercmd.angles[ 0 ], usercmd.angles[ 1 ], usercmd.angles[ 2 ] );
  7286. //        gameLocal.Printf( "\tDELTAVIEW: %s\n", deltaViewAngles.ToString() );
  7287. //    }
  7288.     for ( i = 0; i < 3; i++ ) {
  7289.         cmdAngles[i] = SHORT2ANGLE( usercmd.angles[i] );
  7290.         if ( influenceActive == INFLUENCE_LEVEL3 ) {
  7291.             viewAngles[i] += idMath::ClampFloat( -1.0f, 1.0f, idMath::AngleDelta( idMath::AngleNormalize180( SHORT2ANGLE( usercmd.angles[i]) + deltaViewAngles[i] ) , viewAngles[i] ) );
  7292.         } else {
  7293.             viewAngles[i] = idMath::AngleNormalize180( SHORT2ANGLE( usercmd.angles[i] ) + deltaViewAngles[i] );
  7294.         }
  7295.     }
  7296.     if ( !centerView.IsDone( gameLocal.time ) ) {
  7297.         viewAngles.pitch = centerView.GetCurrentValue( gameLocal.time );
  7298.     }
  7299. //    if( gameLocal.localClientNum == entityNumber ) {
  7300. //        gameLocal.Printf( "AFTER VIEWANGLES: %s\n", viewAngles.ToString() );
  7301. //    }
  7302.  
  7303.     // RAVEN BEGIN
  7304. #ifdef _XENON    
  7305.     //nrausch: experimental post-rocket jumping autocentering
  7306.     if ( gameLocal.isMultiplayer ) {
  7307.         
  7308.         if ( pm_RocketJumpAutocenter.GetBool() ) {
  7309.         
  7310.             rocketJumpEnd = gameLocal.time;
  7311.             if ( rocketJumpEnd - rocketJumpStart < 100 ) {
  7312.         
  7313.                 int p, y, r, f;
  7314.                 usercmdGen->GetInputs( p, y, r, f );
  7315.             
  7316.                 if ( ((p == 0) && (y == 0) && ((r != 0) || (f != 0))) ) {
  7317.                     // Autocenter
  7318.                     viewAngles.pitch*=0.85f;
  7319.                     rocketJumpStart = gameLocal.time;
  7320.                 }
  7321.             } else {
  7322.                 rocketJumpStart = 0;
  7323.             }
  7324.         }
  7325.     }
  7326. #endif
  7327.     // RAVEN END
  7328.  
  7329.     // clamp the pitch
  7330.     if ( noclip ) {
  7331.         if ( viewAngles.pitch > 89.0f ) {
  7332.             // don't let the player look down more than 89 degrees while noclipping
  7333.             viewAngles.pitch = 89.0f;
  7334.         } else if ( viewAngles.pitch < -89.0f ) {
  7335.             // don't let the player look up more than 89 degrees while noclipping
  7336.             viewAngles.pitch = -89.0f;
  7337.         }
  7338.     } else {
  7339.         if ( viewAngles.pitch > pm_maxviewpitch.GetFloat() ) {
  7340.             // don't let the player look down enough to see the shadow of his (non-existant) feet
  7341.             viewAngles.pitch = pm_maxviewpitch.GetFloat();
  7342.         } else if ( viewAngles.pitch < pm_minviewpitch.GetFloat() ) {
  7343.             // don't let the player look up more than 89 degrees
  7344.             viewAngles.pitch = pm_minviewpitch.GetFloat();
  7345.         }
  7346.     }
  7347.  
  7348.     UpdateDeltaViewAngles( viewAngles );
  7349.  
  7350.     // orient the model towards the direction we're looking
  7351.     SetAngles( idAngles( 0, viewAngles.yaw, 0 ) );
  7352.  
  7353.     // save in the log for analyzing weapon angle offsets
  7354.     loggedViewAngles[ gameLocal.framenum & (NUM_LOGGED_VIEW_ANGLES-1) ] = viewAngles;
  7355. }
  7356.  
  7357. /*
  7358. ==============
  7359. idPlayer::UpdateAir
  7360. ==============
  7361. */
  7362. void idPlayer::UpdateAir( void ) {
  7363.     
  7364.     if ( health <= 0 ) {
  7365.         return;
  7366.     }
  7367.  
  7368.     // see if the player is connected to the info_vacuum
  7369.     bool    newAirless = false;
  7370.  
  7371.     if ( gameLocal.vacuumAreaNum != -1 ) {
  7372.         int    num = GetNumPVSAreas();
  7373.         if ( num > 0 ) {
  7374.             int        areaNum;
  7375.  
  7376.             // if the player box spans multiple areas, get the area from the origin point instead,
  7377.             // otherwise a rotating player box may poke into an outside area
  7378.             if ( num == 1 ) {
  7379.                 const int    *pvsAreas = GetPVSAreas();
  7380.                 areaNum = pvsAreas[0];
  7381.             } else {
  7382.                 areaNum = gameRenderWorld->PointInArea( this->GetPhysics()->GetOrigin() );
  7383.             }
  7384.             newAirless = gameRenderWorld->AreasAreConnected( gameLocal.vacuumAreaNum, areaNum, PS_BLOCK_AIR );
  7385.         }
  7386.     }
  7387.  
  7388.     if ( newAirless ) {
  7389.         if ( !airless ) {
  7390.              StartSound( "snd_decompress", SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
  7391.              StartSound( "snd_noAir", SND_CHANNEL_BODY2, 0, false, NULL );
  7392.             if ( hud ) {
  7393.                 hud->HandleNamedEvent( "noAir" );
  7394.             }
  7395.         }
  7396.         airTics--;
  7397.         if ( airTics < 0 ) {
  7398.             airTics = 0;
  7399.             // check for damage
  7400.             const idDict *damageDef = gameLocal.FindEntityDefDict( "damage_noair", false );
  7401.             int dmgTiming = 1000 * ((damageDef) ? damageDef->GetFloat( "delay", "3.0" ) : 3.0f );
  7402.             if ( gameLocal.time > lastAirDamage + dmgTiming ) {
  7403.                 Damage( NULL, NULL, vec3_origin, "damage_noair", 1.0f, 0 );
  7404.                 lastAirDamage = gameLocal.time;
  7405.             }
  7406.         }
  7407.         
  7408.     } else {
  7409.         if ( airless ) {
  7410.              StartSound( "snd_recompress", SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
  7411.              StopSound( SND_CHANNEL_BODY2, false );
  7412.             if ( hud ) {
  7413.                 hud->HandleNamedEvent( "Air" );
  7414.             }
  7415.         }
  7416.         airTics+=2;    // regain twice as fast as lose
  7417.         if ( airTics > pm_airTics.GetInteger() ) {
  7418.             airTics = pm_airTics.GetInteger();
  7419.         }
  7420.     }
  7421.  
  7422.     airless = newAirless;
  7423.  
  7424.     if ( hud ) {
  7425.         hud->SetStateInt( "player_air", 100 * airTics / pm_airTics.GetInteger() );
  7426.     }
  7427. }
  7428.  
  7429. // RAVEN BEGIN
  7430. // abahr
  7431. /*
  7432. ==============
  7433. idPlayer::UpdateGravity
  7434. ==============
  7435. */
  7436. void idPlayer::UpdateGravity( void ) {
  7437.     GetPhysics()->SetGravity( gameLocal.GetCurrentGravity(this) );
  7438. }
  7439. // RAVEN END
  7440.  
  7441. /*
  7442. ==============
  7443. idPlayer::ToggleObjectives
  7444. ==============
  7445. */
  7446. void idPlayer::ToggleObjectives ( void ) {
  7447. // RAVEN BEGIN
  7448. // mekberg: allow disabling of objectives.
  7449.     if ( objectiveSystem == NULL || !objectivesEnabled ) {
  7450.         return;
  7451.     }
  7452. // RAVEN END
  7453.  
  7454.     if ( !objectiveSystemOpen ) {
  7455.         int j, c = inventory.items.Num();
  7456.         objectiveSystem->SetStateInt( "inv_count", c );
  7457.         for ( j = 0; j < c; j++ ) {
  7458.             idDict *item = inventory.items[j];
  7459.             if ( !item->GetBool( "inv_pda" ) ) {
  7460.                 const char *iname = item->GetString( "inv_name" );
  7461.                 iname = common->GetLocalizedString( iname );
  7462.  
  7463.                 const char *iicon = item->GetString( "inv_icon" );
  7464.                 const char *itext = item->GetString( "inv_text" );
  7465.                 objectiveSystem->SetStateString( va( "inv_name_%i", j ), iname );
  7466.                 objectiveSystem->SetStateString( va( "inv_icon_%i", j ), iicon );
  7467.                 objectiveSystem->SetStateString( va( "inv_text_%i", j ), itext );
  7468.                 const idKeyValue *kv = item->MatchPrefix( "inv_id", NULL );
  7469.                 if ( kv ) {
  7470.                     objectiveSystem->SetStateString( va( "inv_id_%i", j ), kv->GetValue() );
  7471.                 }
  7472.             }
  7473.         }
  7474.  
  7475.         for ( j = 0; j < MAX_WEAPONS; j++ ) {
  7476.             const char *weapnum = va( "def_weapon%d", j );
  7477.             int weapstate = 0;
  7478.             if ( inventory.weapons & ( 1 << j ) ) {
  7479.                 const char *weap = spawnArgs.GetString( weapnum );
  7480.                 if ( weap && *weap ) {
  7481.                     weapstate++;
  7482.                 }
  7483.             }
  7484.             objectiveSystem->SetStateInt( weapnum, weapstate );
  7485.         }
  7486.  
  7487.         UpdateObjectiveInfo();
  7488.         objectiveSystem->Activate( true, gameLocal.time );
  7489.         objectiveSystem->HandleNamedEvent( "wristcommShow" );
  7490.     } else {
  7491.         objectiveSystem->Activate( false, gameLocal.time );
  7492.         objectiveSystem->HandleNamedEvent( "wristcommHide" );
  7493.     }
  7494.     objectiveSystemOpen ^= 1;
  7495. }
  7496.  
  7497. /*
  7498. ==============
  7499. idPlayer::ToggleScoreboard
  7500. ==============
  7501. */
  7502. void idPlayer::ToggleScoreboard( void ) {
  7503.     scoreBoardOpen ^= 1;
  7504. }
  7505.  
  7506. /*
  7507. ==============
  7508. idPlayer::Spectate
  7509. ==============
  7510. */
  7511. void idPlayer::Spectate( bool spectate, bool force ) {
  7512.      idBitMsg    msg;
  7513.      byte        msgBuf[MAX_EVENT_PARAM_SIZE];
  7514.  
  7515.      // track invisible player bug
  7516.      // all hiding and showing should be performed through Spectate calls
  7517.      // except for the private camera view, which is used for teleports
  7518.     // ok for players in other instances to be hidden
  7519.     assert( force || ( teleportEntity.GetEntity() != NULL ) || ( IsHidden() == spectating ) || ( IsHidden() && gameLocal.GetLocalPlayer() && gameLocal.GetLocalPlayer()->GetInstance() != instance ) );
  7520.  
  7521.     if ( spectating == spectate && !force ) {
  7522.         return;
  7523.     }
  7524.  
  7525.     bool inOtherInstance = gameLocal.isClient && gameLocal.GetLocalPlayer() && gameLocal.GetLocalPlayer()->GetInstance() != instance;
  7526.  
  7527.     spectating = spectate;
  7528.  
  7529.     // don't do any smoothing with this snapshot
  7530.     predictedFrame = gameLocal.framenum;
  7531.  
  7532.      if ( gameLocal.isServer ) {
  7533.          msg.Init( msgBuf, sizeof( msgBuf ) );
  7534.          msg.WriteBits( spectating, 1 );
  7535.          ServerSendEvent( EVENT_SPECTATE, &msg, false, -1 );
  7536.      }
  7537.  
  7538.     // on the client, we'll get spectate messages about clients in other instances - always assume they are spectating
  7539.     if ( spectating || inOtherInstance ) {
  7540.         // join the spectators
  7541.         if ( !gameLocal.isClient && head.GetEntity() ) {
  7542.              head.GetEntity()->PostEventMS( &EV_Remove, 0 );
  7543.             // if we spawn another head this frame, don't collide with the old head        
  7544.             head->SetName( va( "%s_old_spec_head_%d", name.c_str(), head->entityNumber ) );
  7545.             head = NULL;
  7546.         }
  7547.         ClearPowerUps();
  7548.         spectator = this->entityNumber;
  7549.         Init();
  7550.         StopRagdoll();
  7551.         SetPhysics( &physicsObj );
  7552.         common->DPrintf( "idPlayer::Spectate() - Disabling clip for %d '%s' - spectate: %d force: %d\n", entityNumber, GetUserInfo()->GetString( "ui_name" ), spectate, force );
  7553.         physicsObj.DisableClip();
  7554.         Hide();
  7555.         Event_DisableWeapon();
  7556.  
  7557.         // remove the weapon
  7558.         delete weapon;
  7559.         weapon = NULL;
  7560.         if ( !gameLocal.isClient ) {
  7561.             delete weaponViewModel;
  7562.             weaponViewModel = NULL;
  7563.             delete weaponWorldModel;
  7564.             weaponWorldModel = NULL;
  7565.         }
  7566.     } else {
  7567.         // put everything back together again
  7568.         UpdateModelSetup( true );
  7569.         currentWeapon = -1;    // to make sure the def will be loaded if necessary
  7570.         Show();
  7571.         Event_EnableWeapon();
  7572.     }
  7573.  
  7574.     SetClipModel( inOtherInstance );
  7575.  
  7576.     if ( inOtherInstance ) {
  7577.         // Normally idPlayer::Move() gets called to set the contents to 0, but we don't call
  7578.         // move on players not in our snap, so we need to set it manually here.
  7579.         physicsObj.SetContents( 0 );
  7580.         physicsObj.SetMovementType( PM_SPECTATOR );
  7581.         physicsObj.SetClipMask( MASK_DEADSOLID );
  7582.     }
  7583. }
  7584.  
  7585. /*
  7586. ==============
  7587. idPlayer::SetClipModel
  7588. ==============
  7589. */
  7590. void idPlayer::SetClipModel( bool forceSpectatorBBox ) {
  7591.     idBounds bounds;
  7592.  
  7593.     common->DPrintf( "idPlayer::SetClipModel() - Called on %d '%s' forceSpectatorBBox = %d spectate = %d instance = %d local instance = %d\n", entityNumber, GetUserInfo()->GetString( "ui_name" ), forceSpectatorBBox, spectating, instance, gameLocal.GetLocalPlayer() ? gameLocal.GetLocalPlayer()->GetInstance() : -1 );
  7594.     if ( spectating || forceSpectatorBBox ) {
  7595.          bounds = idBounds( vec3_origin ).Expand( pm_spectatebbox.GetFloat() * 0.5f );
  7596.     } else {
  7597.         bounds[0].Set( -pm_bboxwidth.GetFloat() * 0.5f, -pm_bboxwidth.GetFloat() * 0.5f, 0 );
  7598.         bounds[1].Set( pm_bboxwidth.GetFloat() * 0.5f, pm_bboxwidth.GetFloat() * 0.5f, pm_normalheight.GetFloat() );
  7599.     }
  7600.     // the origin of the clip model needs to be set before calling SetClipModel
  7601.     // otherwise our physics object's current origin value gets reset to 0
  7602.     idClipModel *newClip;
  7603. // RAVEN BEGIN
  7604. // mwhitlock: Dynamic memory consolidation
  7605.     RV_PUSH_HEAP_MEM_AUTO(p0,this);
  7606. // RAVEN END
  7607.  
  7608.     if ( pm_usecylinder.GetBool() ) {
  7609.         newClip = new idClipModel( idTraceModel( bounds, 8 ), declManager->FindMaterial( "textures/flesh_boundingbox" ) );
  7610.         newClip->Translate( physicsObj.PlayerGetOrigin() );
  7611.         physicsObj.SetClipModel( newClip, 1.0f );
  7612.     } else {
  7613.         newClip = new idClipModel( idTraceModel( bounds ), declManager->FindMaterial( "textures/flesh_boundingbox" ) );
  7614.         newClip->Translate( physicsObj.PlayerGetOrigin() );
  7615.         physicsObj.SetClipModel( newClip, 1.0f );
  7616.     }
  7617. }
  7618.  
  7619. /*
  7620. ==============
  7621. idPlayer::EnterVehicle
  7622. ==============
  7623. */
  7624. bool idPlayer::EnterVehicle( idEntity* vehicle ) {
  7625.     if ( !idActor::EnterVehicle ( vehicle ) ) {
  7626.         return false;
  7627.     }
  7628.     
  7629. // RAVEN BEGIN
  7630. // jshepard: safety first
  7631.     if( weapon)    {
  7632.           weapon->Hide();
  7633.     }
  7634.  
  7635. // abahr:
  7636.     //HideCrosshair();
  7637. // RAVEN END
  7638.       
  7639.       return true;
  7640. }
  7641.  
  7642. /*
  7643. ==============
  7644. idPlayer::ExitVehicle
  7645. ==============
  7646. */
  7647. bool idPlayer::ExitVehicle ( bool force ) {
  7648.     if ( !idActor::ExitVehicle ( force ) ) {
  7649.         return false;
  7650.     }
  7651.     
  7652.     SetViewAngles( viewAxis[0].ToAngles() );
  7653.  
  7654. // RAVEN BEGIN
  7655. // jshepard: had this crash on me more than once :(
  7656.     if(weapon)    {
  7657.         weapon->Show();
  7658.     }
  7659. // abahr: Would like to call something more specific
  7660.     ShowCrosshair();
  7661. // RAVEN END
  7662.     
  7663.     return true;
  7664. }
  7665.  
  7666. /*
  7667. ==============
  7668. idPlayer::PerformImpulse
  7669. ==============
  7670. */
  7671. void idPlayer::PerformImpulse( int impulse ) {
  7672.  
  7673. //RAVEN BEGIN
  7674. // nrausch: Don't send xenon dpad impulses over the network
  7675. #ifdef _XENON
  7676.     
  7677.     if ( objectiveSystemOpen ) {
  7678.         return;
  7679.     }
  7680.     
  7681.     if ( gameLocal.isClient && (impulse < IMPULSE_70) ) {
  7682. #else
  7683.     if ( gameLocal.isClient ) {
  7684. #endif
  7685. //RAVEN END
  7686.         idBitMsg    msg;
  7687.         byte        msgBuf[MAX_EVENT_PARAM_SIZE];
  7688.  
  7689.          assert( entityNumber == gameLocal.localClientNum );
  7690.         msg.Init( msgBuf, sizeof( msgBuf ) );
  7691.         msg.BeginWriting();
  7692.         msg.WriteBits( impulse, 6 );
  7693.         ClientSendEvent( EVENT_IMPULSE, &msg );
  7694.     }
  7695.  
  7696.     if ( impulse >= IMPULSE_0 && impulse <= IMPULSE_12 ) {
  7697.         SelectWeapon( impulse, false );
  7698.         return;
  7699.     }
  7700.  
  7701. //RAVEN BEGIN
  7702. //asalmon: D-pad events for in game guis on Xenon
  7703. #ifdef _XBOX
  7704.     sysEvent_t ev;
  7705.     ev.evType = SE_KEY;
  7706.     ev.evValue2 = 1;
  7707.     ev.evPtrLength = 0;
  7708.     ev.evPtr = NULL;
  7709.  
  7710.     const char *command = NULL;
  7711.     idUserInterface *ui = ActiveGui();
  7712.     bool updateVisuals = false;
  7713. #endif
  7714. //RAVEN END
  7715.  
  7716.     switch( impulse ) {
  7717.         case IMPULSE_13: {
  7718.             Reload();
  7719.             break;
  7720.         }
  7721.         case IMPULSE_14: {
  7722.             NextWeapon();
  7723.  
  7724.             if( gameLocal.isServer && spectating && gameLocal.gameType == GAME_TOURNEY ) {    
  7725.                 ((rvTourneyGameState*)gameLocal.mpGame.GetGameState())->SpectateCycleNext( this );
  7726.             }
  7727.             break;
  7728.         }
  7729.         case IMPULSE_15: {
  7730.             PrevWeapon();
  7731.             if( gameLocal.isServer && spectating && gameLocal.gameType == GAME_TOURNEY ) {    
  7732.                 ((rvTourneyGameState*)gameLocal.mpGame.GetGameState())->SpectateCyclePrev( this );
  7733.             }
  7734.             break;
  7735.         }
  7736.         case IMPULSE_17: {
  7737.              if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) {
  7738.                  gameLocal.mpGame.ToggleReady( );
  7739.             }
  7740.             break;
  7741.         }
  7742.         case IMPULSE_18: {
  7743.             centerView.Init(gameLocal.time, 200, viewAngles.pitch, 0);
  7744.             break;
  7745.         }
  7746.         case IMPULSE_19: {
  7747. /*        
  7748.             // when we're not in single player, IMPULSE_19 is used for showScores
  7749.             // otherwise it does IMPULSE_12 (PDA)
  7750.             if ( !gameLocal.isMultiplayer ) {
  7751.                 if ( !objectiveSystemOpen ) {
  7752.                     if ( weapon ) {
  7753.                         weapon->Hide ();
  7754.                     }
  7755.                 }
  7756.                 ToggleMap();
  7757.             }
  7758. */
  7759.             break;
  7760.         }
  7761.         case IMPULSE_20: {
  7762.              if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) {
  7763.                  gameLocal.mpGame.ToggleTeam( );
  7764.             }
  7765.             break;
  7766.         }
  7767.         case IMPULSE_21: {
  7768.             if( gameLocal.isServer && gameLocal.gameType == GAME_TOURNEY ) {
  7769.                 // only allow a client to join the waiting arena if they are not currently assigned to an arena
  7770.  
  7771.                 // removed waiting arena functionality for now
  7772.                 /*rvTourneyArena& arena = ((rvTourneyGameState*)gameLocal.mpGame.GetGameState())->GetArena( GetArena() );
  7773.  
  7774.                 if( this != arena.GetPlayers()[ 0 ] && this != arena.GetPlayers()[ 1 ] ) {
  7775.                     if( instance == MAX_ARENAS && !spectating ) {
  7776.                         ServerSpectate( true );
  7777.                         JoinInstance( ((rvTourneyGameState*)gameLocal.mpGame.GetGameState())->GetNextActiveArena( 0 ) );
  7778.                     } else if( spectating ) {
  7779.                         JoinInstance( MAX_ARENAS );
  7780.                         ServerSpectate( false );
  7781.                     }
  7782.                 }*/
  7783.             }
  7784.             break;
  7785.         }
  7786.         case IMPULSE_22: {
  7787.              if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) {
  7788.                  gameLocal.mpGame.ToggleSpectate( );
  7789.                }
  7790.                break;
  7791.            }
  7792.                 
  7793.         case IMPULSE_28: {
  7794.              if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) {
  7795.                  gameLocal.mpGame.CastVote( gameLocal.localClientNum, true );
  7796.                }
  7797.                break;
  7798.            }
  7799.            case IMPULSE_29: {
  7800.              if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) {
  7801.                 gameLocal.mpGame.CastVote( gameLocal.localClientNum, false );
  7802.                }
  7803.                break;
  7804.            }
  7805.         case IMPULSE_40: {
  7806.             idFuncRadioChatter::RepeatLast();
  7807.             break;
  7808.         }
  7809.         case IMPULSE_50: {
  7810.             ToggleFlashlight ( );
  7811.             break;
  7812.         }
  7813.  
  7814.          case IMPULSE_51: {
  7815.              LastWeapon();
  7816.              break;
  7817.          }
  7818.  
  7819. //RAVEN BEGIN
  7820. //asalmon: Xbox weapon switching combos and in game gui event routing.
  7821. #ifdef _XBOX
  7822.  
  7823.         case IMPULSE_70: {    //weapon switch up
  7824.             if ( !ActiveGui() ) {
  7825.                 int last = hud->State().GetInt( "player_selectedWeapon", "-1" ) + 1;
  7826.                 ScheduleWeaponSwitch( weaponComboChart[last].up );
  7827.             } else {
  7828.                 ev.evValue = K_JOY_DPAD_UP;
  7829.             }
  7830.             break;
  7831.         }
  7832.  
  7833.          case IMPULSE_71: {    //weapon switch down
  7834.             if ( !ActiveGui() ) {
  7835.                 int last = hud->State().GetInt( "player_selectedWeapon", "-1" ) + 1;
  7836.                 ScheduleWeaponSwitch( weaponComboChart[last].down );
  7837.             } else {
  7838.                 ev.evValue = K_JOY_DPAD_DOWN;
  7839.             }
  7840.              break;
  7841.          }
  7842.  
  7843.         case IMPULSE_72: {    //weapon switch right
  7844.             if ( !ActiveGui() ) {
  7845.                 int last = hud->State().GetInt( "player_selectedWeapon", "-1" ) + 1;
  7846.                 ScheduleWeaponSwitch( weaponComboChart[last].right );
  7847.                 break;
  7848.             } else {
  7849.                 ev.evValue = K_JOY_DPAD_RIGHT;
  7850.             }
  7851.             break;
  7852.         }
  7853.  
  7854.          case IMPULSE_73: {    //weapon switch left
  7855.             if ( !ActiveGui() ) {
  7856.                 int last = hud->State().GetInt( "player_selectedWeapon", "-1" ) + 1;
  7857.                 ScheduleWeaponSwitch( weaponComboChart[last].left );
  7858.                  break;
  7859.             } else {
  7860.                 ev.evValue = K_JOY_DPAD_LEFT;
  7861.             }
  7862.             break;
  7863.          }
  7864.         
  7865. #endif
  7866. //RAVEN END
  7867.  
  7868.  
  7869.  
  7870.  
  7871.     } 
  7872.  
  7873. //RAVEN BEGIN
  7874. //asalmon: route d-pad input to the active gui.
  7875. #ifdef _XBOX
  7876.     if (ui && ev.evValue != 0 && !objectiveSystemOpen ) {
  7877.         command = ui->HandleEvent( &ev, gameLocal.time, &updateVisuals );
  7878.         if ( updateVisuals && focusEnt && ui == focusUI ) {
  7879.             focusEnt->UpdateVisuals();
  7880.         }
  7881.  
  7882.         if ( gameLocal.isClient ) {
  7883.             // we predict enough, but don't want to execute commands
  7884.             return;
  7885.         } 
  7886.         if ( focusEnt ) {
  7887.             HandleGuiCommands( focusEnt, command );
  7888.         } else {
  7889.             HandleGuiCommands( this, command );
  7890.         }
  7891.     }
  7892. #endif
  7893. //RAVEN END
  7894. }
  7895.    
  7896. /*
  7897. ==============
  7898. idPlayer::HandleESC
  7899. ==============
  7900. */
  7901. bool idPlayer::HandleESC( void ) {
  7902.     if ( gameLocal.inCinematic ) {
  7903.         return SkipCinematic();
  7904.     }
  7905.     return false;
  7906. }
  7907.  
  7908. /*
  7909. ==============
  7910. idPlayer::HandleObjectiveInput
  7911. ==============
  7912. */
  7913. void idPlayer::HandleObjectiveInput() {
  7914. #ifdef _XENON
  7915.     if ( !objectiveButtonReleased ) {
  7916.         if ( ( usercmd.buttons &    BUTTON_SCORES ) == 0 ) {
  7917.             objectiveButtonReleased = true;
  7918.         }
  7919.     } else {
  7920.         if ( ( usercmd.buttons & BUTTON_SCORES ) != 0 ) {
  7921.             ToggleObjectives ( );
  7922.             g_ObjectiveSystemOpen = objectiveSystemOpen;
  7923.             objectiveButtonReleased = false;
  7924.         }
  7925.     }
  7926. #else
  7927.     if ( ( usercmd.buttons & BUTTON_SCORES ) != 0 && !objectiveSystemOpen && !gameLocal.inCinematic ) {
  7928.         ToggleObjectives ( );
  7929.     } else if ( ( usercmd.buttons & BUTTON_SCORES ) == 0 && objectiveSystemOpen ) {
  7930.         ToggleObjectives ( );
  7931.     } else if ( objectiveSystemOpen && gameLocal.inCinematic ) {
  7932.         ToggleObjectives ( );
  7933.     }
  7934. #endif
  7935. }
  7936.  
  7937. /*
  7938. ==============
  7939. idPlayer::EvaluateControls
  7940. ==============
  7941. */
  7942. void idPlayer::EvaluateControls( void ) {
  7943.     // check for respawning
  7944.     if ( pfl.dead || pfl.objectiveFailed ) {
  7945.         if ( ( gameLocal.time > minRespawnTime ) && ( usercmd.buttons & BUTTON_ATTACK ) ) {
  7946.             forceRespawn = true;
  7947.         } else if ( gameLocal.time > maxRespawnTime ) {
  7948.             forceRespawn = true;
  7949.         }
  7950.     }
  7951.  
  7952.     // in MP, idMultiplayerGame decides spawns
  7953.     if ( forceRespawn && !gameLocal.isMultiplayer && !g_testDeath.GetBool() ) {
  7954.         // in single player, we let the session handle restarting the level or loading a game
  7955.         gameLocal.sessionCommand = "died";
  7956.     }
  7957.  
  7958.     if ( ( usercmd.flags & UCF_IMPULSE_SEQUENCE ) != ( oldFlags & UCF_IMPULSE_SEQUENCE ) )  {
  7959.         PerformImpulse( usercmd.impulse );
  7960.     }
  7961.  
  7962.     if( forceScoreBoard && forceScoreBoardTime && gameLocal.time > forceScoreBoardTime ) {
  7963.         forceScoreBoardTime = 0;
  7964.         forceScoreBoard = false;
  7965.     }
  7966.     scoreBoardOpen        = ( ( usercmd.buttons & BUTTON_SCORES ) != 0 || forceScoreBoard );
  7967.  
  7968.     oldFlags = usercmd.flags;
  7969.  
  7970.     AdjustSpeed();
  7971.  
  7972.     // update the viewangles
  7973.     UpdateViewAngles();
  7974. }
  7975.  
  7976. /*
  7977. ==============
  7978. idPlayer::AdjustSpeed
  7979. ==============
  7980. */
  7981. void idPlayer::AdjustSpeed( void ) {
  7982.     float speed;
  7983.  
  7984.     if ( spectating ) {
  7985.         speed = pm_spectatespeed.GetFloat();
  7986.         bobFrac = 0.0f;
  7987.     } else if ( noclip ) {
  7988.         speed = pm_noclipspeed.GetFloat();
  7989.         bobFrac = 0.0f;
  7990.      } else if ( !physicsObj.OnLadder() && ( usercmd.buttons & BUTTON_RUN ) && ( usercmd.forwardmove || usercmd.rightmove ) && ( usercmd.upmove >= 0 ) ) {
  7991.         bobFrac = 1.0f;
  7992.         speed = pm_speed.GetFloat();
  7993.     } else {
  7994.         speed = pm_walkspeed.GetFloat();
  7995.         bobFrac = 0.0f;
  7996.     }
  7997.  
  7998.     speed *= PowerUpModifier(PMOD_SPEED);
  7999.  
  8000.     if ( influenceActive == INFLUENCE_LEVEL3 ) {
  8001.         speed *= 0.33f;
  8002.     }
  8003.  
  8004.     physicsObj.SetSpeed( speed, pm_crouchspeed.GetFloat() );
  8005. }
  8006.  
  8007. /*
  8008. ==============
  8009. idPlayer::AdjustBodyAngles
  8010. ==============
  8011. */
  8012. void idPlayer::AdjustBodyAngles( void ) {
  8013.     idMat3        lookAxis;
  8014.     idMat3        legsAxis;
  8015.     bool        blend;
  8016.     float        diff;
  8017.     float        frac;
  8018.     float        upBlend;
  8019.     float        forwardBlend;
  8020.     float        downBlend;
  8021.  
  8022.     if ( health < 0 ) {
  8023.         return;
  8024.     }
  8025.  
  8026.     blend = true;
  8027.  
  8028.     if ( !physicsObj.HasGroundContacts() ) {
  8029.         idealLegsYaw = 0.0f;
  8030.         legsForward = true;
  8031.     } else if ( usercmd.forwardmove < 0 ) {
  8032.         idealLegsYaw = idMath::AngleNormalize180( idVec3( -usercmd.forwardmove, usercmd.rightmove, 0.0f ).ToYaw() );
  8033.         legsForward = false;
  8034.     } else if ( usercmd.forwardmove > 0 ) {
  8035.         idealLegsYaw = idMath::AngleNormalize180( idVec3( usercmd.forwardmove, -usercmd.rightmove, 0.0f ).ToYaw() );
  8036.         legsForward = true;
  8037.     } else if ( ( usercmd.rightmove != 0 ) && physicsObj.IsCrouching() ) {
  8038.         if ( !legsForward ) {
  8039.             idealLegsYaw = idMath::AngleNormalize180( idVec3( idMath::Abs( usercmd.rightmove ), usercmd.rightmove, 0.0f ).ToYaw() );
  8040.         } else {
  8041.             idealLegsYaw = idMath::AngleNormalize180( idVec3( idMath::Abs( usercmd.rightmove ), -usercmd.rightmove, 0.0f ).ToYaw() );
  8042.         }
  8043.     } else if ( usercmd.rightmove != 0 ) {
  8044.         idealLegsYaw = 0.0f;
  8045.         legsForward = true;
  8046.     } else {
  8047.         legsForward = true;
  8048.         diff = idMath::Fabs( idealLegsYaw - legsYaw );
  8049.         idealLegsYaw = idealLegsYaw - idMath::AngleNormalize180( viewAngles.yaw - oldViewYaw );
  8050.         if ( diff < 0.1f ) {
  8051.             legsYaw = idealLegsYaw;
  8052.             blend = false;
  8053.         }
  8054.     }
  8055.  
  8056.     if ( !physicsObj.IsCrouching() ) {
  8057.         legsForward = true;
  8058.     }
  8059.  
  8060.     oldViewYaw = viewAngles.yaw;
  8061.  
  8062.     pfl.turnLeft = false;
  8063.     pfl.turnRight = false;
  8064.     if ( idealLegsYaw < -45.0f ) {
  8065.         idealLegsYaw = 0;
  8066.         pfl.turnRight = true;
  8067.         blend = true;
  8068.     } else if ( idealLegsYaw > 45.0f ) {
  8069.         idealLegsYaw = 0;
  8070.         pfl.turnLeft = true;
  8071.         blend = true;
  8072.     }
  8073.  
  8074.     if ( blend ) {
  8075.         legsYaw = legsYaw * 0.9f + idealLegsYaw * 0.1f;
  8076.     }
  8077.     legsAxis = idAngles( 0.0f, legsYaw, 0.0f ).ToMat3();
  8078.     animator.SetJointAxis( hipJoint, JOINTMOD_WORLD, legsAxis );
  8079.  
  8080.     // calculate the blending between down, straight, and up
  8081.     frac = viewAngles.pitch / 90.0f;
  8082.     if ( frac > 0.0f ) {
  8083.         downBlend        = frac;
  8084.         forwardBlend    = 1.0f - frac;
  8085.         upBlend            = 0.0f;
  8086.     } else {
  8087.         downBlend        = 0.0f;
  8088.         forwardBlend    = 1.0f + frac;
  8089.         upBlend            = -frac;
  8090.     }
  8091.  
  8092.     animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 0, downBlend );
  8093.     animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 1, forwardBlend );
  8094.     animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 2, upBlend );
  8095.  
  8096.     animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 0, downBlend );
  8097.     animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 1, forwardBlend );
  8098.     animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 2, upBlend );
  8099.  
  8100. }
  8101.  
  8102. /*
  8103. ==============
  8104. idPlayer::InitAASLocation
  8105. ==============
  8106. */
  8107. void idPlayer::InitAASLocation( void ) {
  8108.     int        i;
  8109.     int        num;
  8110.     idVec3    size;
  8111.     idBounds bounds;
  8112.     idAAS    *aas;
  8113.     idVec3    origin;
  8114.  
  8115.     GetFloorPos( 64.0f, origin );
  8116.  
  8117.     num = gameLocal.NumAAS();
  8118.     aasLocation.SetGranularity( 1 );
  8119.     aasLocation.SetNum( num );    
  8120.     for( i = 0; i < aasLocation.Num(); i++ ) {
  8121.         aasLocation[ i ].areaNum = 0;
  8122.         aasLocation[ i ].pos = origin;
  8123.         aas = gameLocal.GetAAS( i );
  8124.         if ( aas && aas->GetSettings() ) {
  8125.             size = aas->GetSettings()->boundingBoxes[0][1];
  8126.             bounds[0] = -size;
  8127.             size.z = 32.0f;
  8128.             bounds[1] = size;
  8129.  
  8130.             aasLocation[ i ].areaNum = aas->PointReachableAreaNum( origin, bounds, AREA_REACHABLE_WALK );
  8131.         }
  8132.     }
  8133. }
  8134.  
  8135. /*
  8136. ==============
  8137. idPlayer::SetAASLocation
  8138. ==============
  8139. */
  8140. void idPlayer::SetAASLocation( void ) {
  8141.     int        i;
  8142.     int        areaNum;
  8143.     idVec3    size;
  8144.     idBounds bounds;
  8145.     idAAS    *aas;
  8146.     idVec3    origin;
  8147.  
  8148.     if ( !GetFloorPos( 64.0f, origin ) ) {
  8149.         return;
  8150.     }
  8151.     
  8152.     for( i = 0; i < aasLocation.Num(); i++ ) {
  8153.         aas = gameLocal.GetAAS( i );
  8154.         if ( !aas ) {
  8155.             continue;
  8156.         }
  8157.  
  8158.         size = aas->GetSettings()->boundingBoxes[0][1];
  8159.         bounds[0] = -size;
  8160.         size.z = 32.0f;
  8161.         bounds[1] = size;
  8162.  
  8163.         areaNum = aas->PointReachableAreaNum( origin, bounds, AREA_REACHABLE_WALK );
  8164.         if ( areaNum ) {
  8165.             aasLocation[ i ].pos = origin;
  8166.             aasLocation[ i ].areaNum = areaNum;
  8167.         }
  8168.     }
  8169. }
  8170.  
  8171. /*
  8172. ==============
  8173. idPlayer::GetAASLocation
  8174. ==============
  8175. */
  8176. void idPlayer::GetAASLocation( idAAS *aas, idVec3 &pos, int &areaNum ) const {
  8177.     int i;
  8178.  
  8179.     if ( aas != NULL ) {
  8180.         for( i = 0; i < aasLocation.Num(); i++ ) {
  8181.             if ( aas == gameLocal.GetAAS( i ) ) {
  8182.                 areaNum = aasLocation[ i ].areaNum;
  8183.                 pos = aasLocation[ i ].pos;
  8184.                 return;
  8185.             }
  8186.         }
  8187.     }
  8188.  
  8189.     areaNum = 0;
  8190.     pos = physicsObj.GetOrigin();
  8191. }
  8192.  
  8193. /*
  8194. ==============
  8195. idPlayer::Move
  8196. ==============
  8197. */
  8198. void idPlayer::Move( void ) {
  8199.     float newEyeOffset;
  8200.     idVec3 oldOrigin;
  8201.     idVec3 oldVelocity;
  8202.     idVec3 pushVelocity;
  8203.  
  8204.     // save old origin and velocity for crashlanding
  8205.     oldOrigin = physicsObj.GetOrigin();
  8206.     oldVelocity = physicsObj.GetLinearVelocity();
  8207.     pushVelocity = physicsObj.GetPushedLinearVelocity();
  8208.  
  8209.     // set physics variables
  8210.     physicsObj.SetMaxStepHeight( pm_stepsize.GetFloat() );
  8211.     physicsObj.SetMaxJumpHeight( pm_jumpheight.GetFloat() );
  8212.  
  8213.     if ( noclip ) {
  8214.         physicsObj.SetContents( 0 );
  8215.         physicsObj.SetMovementType( PM_NOCLIP );
  8216.     } else if ( spectating || ( gameLocal.isClient && gameLocal.GetLocalPlayer() && gameLocal.GetLocalPlayer()->GetInstance() != instance ) ) {
  8217.         physicsObj.SetContents( 0 );
  8218.         physicsObj.SetMovementType( PM_SPECTATOR );
  8219.     } else if ( health <= 0 ) {
  8220.         physicsObj.SetContents( CONTENTS_CORPSE | CONTENTS_MONSTERCLIP );
  8221.         physicsObj.SetMovementType( PM_DEAD );
  8222.      } else if ( gameLocal.inCinematic || pfl.objectiveFailed || gameLocal.GetCamera() || privateCameraView || ( influenceActive == INFLUENCE_LEVEL2 ) ) {
  8223.         physicsObj.SetContents( CONTENTS_BODY | (use_combat_bbox?CONTENTS_SOLID:0) );
  8224.         physicsObj.SetMovementType( PM_FREEZE );
  8225.     } else {
  8226.         physicsObj.SetContents( CONTENTS_BODY | (use_combat_bbox?CONTENTS_SOLID:0) );
  8227.         physicsObj.SetMovementType( PM_NORMAL );
  8228.     }
  8229.  
  8230.     if ( spectating || ( gameLocal.isClient && gameLocal.GetLocalPlayer() && gameLocal.GetLocalPlayer()->GetInstance() != instance ) ) {
  8231.         physicsObj.SetClipMask( MASK_DEADSOLID );
  8232.     } else if ( health <= 0 ) {
  8233.         physicsObj.SetClipMask( MASK_DEADSOLID );
  8234.     } else {
  8235.         physicsObj.SetClipMask( MASK_PLAYERSOLID );
  8236.     }
  8237.  
  8238.     physicsObj.SetDebugLevel( g_debugMove.GetBool() );
  8239.     physicsObj.SetPlayerInput( usercmd, viewAngles );
  8240.  
  8241.     // FIXME: physics gets disabled somehow
  8242.     BecomeActive( TH_PHYSICS );
  8243.     
  8244.     // If the player is dead then only run physics on new
  8245.     // frames since articulated figures are not synchronized over the network
  8246.     if ( health <= 0 ) {
  8247.         if ( gameLocal.isNewFrame ) {
  8248.             DeathPush();
  8249.             RunPhysics();
  8250.         }
  8251.     } else { 
  8252.         RunPhysics();
  8253.     }
  8254.  
  8255.      // update our last valid AAS location for the AI
  8256.     if( !gameLocal.isMultiplayer ) {
  8257.         SetAASLocation(); 
  8258.     }
  8259.  
  8260.     if ( spectating ) {
  8261.         newEyeOffset = 0.0f;
  8262.     } else if ( health <= 0 ) {
  8263.         newEyeOffset = pm_deadviewheight.GetFloat();
  8264.     } else if ( physicsObj.IsCrouching() ) {
  8265.         newEyeOffset = pm_crouchviewheight.GetFloat();
  8266.     } else if ( IsInVehicle ( ) ) {
  8267.         newEyeOffset = 0.0f;
  8268.     } else {
  8269.         newEyeOffset = pm_normalviewheight.GetFloat();
  8270.     }
  8271.  
  8272.     if ( EyeHeight() != newEyeOffset ) {
  8273.         if ( spectating ) {
  8274.             SetEyeHeight( newEyeOffset );
  8275.         } else {
  8276.             // smooth out duck height changes
  8277.             SetEyeHeight( EyeHeight() * pm_crouchrate.GetFloat() + newEyeOffset * ( 1.0f - pm_crouchrate.GetFloat() ) );
  8278.         }
  8279.     }
  8280.  
  8281.     if ( noclip || gameLocal.inCinematic || ( influenceActive == INFLUENCE_LEVEL2 ) ) {
  8282.         pfl.crouch        = false;
  8283.          pfl.onGround    = ( influenceActive == INFLUENCE_LEVEL2 );
  8284.         pfl.onLadder    = false;
  8285.         pfl.jump        = false;
  8286.     } else {
  8287.         pfl.crouch    = physicsObj.IsCrouching();
  8288.         pfl.onGround    = physicsObj.HasGroundContacts();
  8289.         pfl.onLadder    = physicsObj.OnLadder();
  8290.         pfl.jump        = physicsObj.HasJumped();
  8291.  
  8292.          // check if we're standing on top of a monster and give a push if we are
  8293.          idEntity *groundEnt = physicsObj.GetGroundEntity();
  8294. // RAVEN BEGIN
  8295. // jnewquist: Use accessor for static class type 
  8296.          if ( groundEnt && groundEnt->IsType( idAI::GetClassType() ) ) {
  8297. // RAVEN END
  8298.              idVec3 vel = physicsObj.GetLinearVelocity();
  8299.              if ( vel.ToVec2().LengthSqr() < 0.1f ) {
  8300.                  vel.ToVec2() = physicsObj.GetOrigin().ToVec2() - groundEnt->GetPhysics()->GetAbsBounds().GetCenter().ToVec2();
  8301.                  vel.ToVec2().NormalizeFast();
  8302.                  vel.ToVec2() *= pm_speed.GetFloat();
  8303.              } else {
  8304.                  // give em a push in the direction they're going
  8305.                  vel *= 1.1f;
  8306.              }
  8307.              physicsObj.SetLinearVelocity( vel );
  8308.          }
  8309.     }
  8310.  
  8311.     if ( pfl.jump ) {
  8312.         loggedAccel_t    *acc = &loggedAccel[currentLoggedAccel&(NUM_LOGGED_ACCELS-1)];
  8313.         currentLoggedAccel++;
  8314.         acc->time = gameLocal.time;
  8315.         acc->dir[2] = 200;
  8316.         acc->dir[0] = acc->dir[1] = 0;
  8317.     }
  8318.  
  8319.     if ( pfl.onLadder ) {
  8320.         int old_rung = oldOrigin.z / LADDER_RUNG_DISTANCE;
  8321.          int new_rung = physicsObj.GetOrigin().z / LADDER_RUNG_DISTANCE;
  8322.  
  8323.         if ( old_rung != new_rung ) {
  8324.              StartSound( "snd_stepladder", SND_CHANNEL_ANY, 0, false, NULL );
  8325.         }
  8326.     }
  8327.  
  8328.     UpdateIntentDir( );
  8329.  
  8330.     BobCycle( pushVelocity );
  8331.  
  8332. // RAVEN BEGIN
  8333. // abahr: don't crashland while no clipping.
  8334.     if( !noclip ) {
  8335.         CrashLand( oldOrigin, oldVelocity );
  8336.     }
  8337. // RAVEN END
  8338. }
  8339.  
  8340. /*
  8341. ==================
  8342. idPlayer::BiasIntentDir
  8343.  
  8344. Called when a weapon fires, generates head twitches, etc
  8345. ==================
  8346. */
  8347. void idPlayer::BiasIntentDir( idVec3 newIntentDir, float prevBias ) {
  8348.     if ( !newIntentDir.Compare( vec3_origin ) )    {
  8349.         if ( intentDir.Compare( vec3_origin ) )    {
  8350.             //initialize it
  8351.             intentDir = newIntentDir;
  8352.         } else {
  8353.             intentDir = ((intentDir*prevBias)+newIntentDir)/(prevBias+1.0f);
  8354.             float iDirLen = idMath::ClampFloat(0.0f,1024.0f,intentDir.Normalize());
  8355.             intentDir *= iDirLen;
  8356.         }
  8357.     }
  8358. }
  8359.  
  8360. /*
  8361. ==============
  8362. idPlayer::UpdateIntentDir
  8363. ==============
  8364. */
  8365. void idPlayer::UpdateIntentDir ( void ) {
  8366.     idVec3 newIntentDir;
  8367.     idVec3 viewDir = viewAxis[0];
  8368.     viewDir.z = 0;
  8369.     viewDir.Normalize();
  8370.     float prevBias = 199.0f;
  8371.     if ( intentDir.Compare( vec3_origin ) ) {
  8372.         newIntentDir = viewDir*50.0f;
  8373.     } else {
  8374.         newIntentDir = viewDir*intentDir.Length();
  8375.         if ( flashlightOn ) {
  8376.             //bias them more heavily to looking where I'm looking
  8377.             prevBias = 19.0f;
  8378.         }
  8379.     }
  8380.     if ( pfl.onGround )    {
  8381.         idVec3 moveDir = physicsObj.GetLinearVelocity();
  8382.         if ( moveDir.x || moveDir.y ) {
  8383.             // moving, too
  8384.             moveDir.z = 0;
  8385.             newIntentDir = moveDir;
  8386.             prevBias = 39.0f;
  8387.         }
  8388.     }
  8389.     BiasIntentDir( newIntentDir, prevBias );
  8390.     if ( ai_debugSquad.GetBool() ) {
  8391.         idVec4 color = colorCyan;
  8392.         if ( pfl.weaponFired ) {
  8393.             color = colorRed;
  8394.         }
  8395.         gameRenderWorld->DebugArrow( color, GetPhysics()->GetOrigin(), GetPhysics()->GetOrigin() + intentDir*4.0f, 8, 0 );
  8396.     }
  8397. }
  8398.  
  8399. /*
  8400. ==============
  8401. idPlayer::UpdateHud
  8402. ==============
  8403. */
  8404. void idPlayer::UpdateHud( void ) {
  8405.     if ( !hud ) {
  8406.         return;
  8407.     }
  8408.  
  8409.     if ( entityNumber != gameLocal.localClientNum ) {
  8410.         return;
  8411.     }
  8412.  
  8413.     // FIXME: this is here for level ammo balancing to see pct of hits 
  8414.     hud->SetStateInt( "g_showProjectilePct", g_showProjectilePct.GetInteger() );
  8415.     if ( numProjectilesFired ) {
  8416.         hud->SetStateString( "projectilepct", va( "Hit %% %.1f", ( (float) numProjectileHits / numProjectilesFired ) * 100 ) );
  8417.     } else {
  8418.         hud->SetStateString( "projectilepct", "Hit % 0.0" );
  8419.     }
  8420.  
  8421.      if ( isLagged && gameLocal.isMultiplayer && gameLocal.localClientNum == entityNumber ) {
  8422.          hud->SetStateString( "hudLag", "1" );
  8423.      } else {
  8424.          hud->SetStateString( "hudLag", "0" );
  8425.      }
  8426. }
  8427.  
  8428. /*
  8429. ==============
  8430. idPlayer::UpdateDeathSkin
  8431. ==============
  8432. */
  8433. void idPlayer::UpdateDeathSkin( bool state_hitch ) {
  8434.     if ( !( gameLocal.isMultiplayer || g_testDeath.GetBool() ) ) {
  8435.         return;
  8436.     }
  8437.      if ( health <= 0 ) {
  8438.          if ( !doingDeathSkin && !deathSkinTime ) {
  8439.             deathSkinTime = gameLocal.time + 3000;
  8440.             deathStateHitch = state_hitch;
  8441.         }
  8442.  
  8443.         // wait a bit before switching off the content
  8444.         if ( deathClearContentsTime && gameLocal.time > deathClearContentsTime ) {
  8445.             SetCombatContents( false );
  8446.             deathClearContentsTime = 0;
  8447.         }
  8448.     } else {
  8449.         renderEntity.noShadow = false;
  8450.         renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = 0.0f;
  8451.         if( head ) {
  8452.             head.GetEntity()->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = 0.0f;
  8453.         }
  8454.         UpdateVisuals();
  8455.          doingDeathSkin = false;
  8456.         deathClearContentsTime = 0;
  8457.     }
  8458. }
  8459.  
  8460. /*
  8461. ===============
  8462. idPlayer::LoadDeferredModel
  8463. ===============
  8464. */
  8465. void idPlayer::LoadDeferredModel( void ) {
  8466.     if( !modelDict ) {
  8467.         gameLocal.Warning( "idPlayer::ClientPredictionThink() - reloadModel without vaid modelDict\n" );
  8468.         return;
  8469.     } 
  8470.  
  8471.     if( weapon ) {
  8472.         weapon->NetCatchup();
  8473.     }
  8474.  
  8475.     if( !idStr::Icmp( modelDict->GetString( "skin" ), "" ) ) {
  8476.         skin = NULL;
  8477.     } else {
  8478.         skin = declManager->FindSkin( modelDict->GetString( "skin" ), false );
  8479.     }
  8480.  
  8481.  
  8482.     SetModel( modelDict->GetString( "model" ) );
  8483.  
  8484.     if( !idStr::Icmp( modelDict->GetString( "def_head" ), "" ) ) {
  8485.         if( head ) {
  8486.             head->PostEventMS( &EV_Remove, 0 );
  8487.             head = NULL;
  8488.         }
  8489.     } else {
  8490.         SetupHead( modelDict->GetString( "def_head" ), modelDict->GetVector( "head_offset" ) );
  8491.     }
  8492.  
  8493.     if( powerUpSkin != NULL ) {
  8494.         SetSkin( powerUpSkin );
  8495.         if( head ) {
  8496.             head->SetSkin( powerUpSkin );
  8497.         }
  8498.     } else {
  8499.         SetSkin( skin );
  8500.         if( head ) {
  8501.             head->SetSkin( headSkin );
  8502.         }
  8503.     }
  8504. }
  8505.  
  8506. /*
  8507. ==============
  8508. idPlayer::Think
  8509.  
  8510. Called every tic for each player
  8511. ==============
  8512. */
  8513. void idPlayer::Think( void ) {
  8514.     renderEntity_t *headRenderEnt;
  8515.  
  8516.     if ( talkingNPC ) {
  8517.         if ( !talkingNPC.IsValid() ) {
  8518.             talkingNPC = NULL;
  8519.         } else {
  8520.             idAI *talkingNPCAI = (idAI*)(talkingNPC.GetEntity());
  8521.             if ( !talkingNPCAI ) {
  8522.                 //wtf?
  8523.                 talkingNPC = NULL;
  8524.             } else if ( talkingNPCAI->talkTarget != this || !talkingNPCAI->IsSpeaking() || DistanceTo( talkingNPCAI ) > 256.0f ) {
  8525.                 //forget about them, okay to talk to someone else now
  8526.                 talkingNPC = NULL;
  8527.             }
  8528.         }
  8529.     }
  8530.  
  8531.     if ( !gameLocal.usercmds ) {
  8532.         return;
  8533.     }
  8534.  
  8535.      // Dont do any thinking if we are in modview
  8536.     if ( gameLocal.editors & EDITOR_MODVIEW || gameEdit->PlayPlayback() ) {
  8537.         // calculate the exact bobbed view position, which is used to
  8538.         // position the view weapon, among other things
  8539.         CalculateFirstPersonView();
  8540.  
  8541.         // this may use firstPersonView, or a thirdPerson / camera view
  8542.         CalculateRenderView();
  8543.  
  8544.         FreeModelDef();
  8545.         
  8546.         if ( weapon ) {
  8547.             weapon->GetWorldModel()->FreeModelDef();
  8548.         }
  8549.  
  8550.          if ( head.GetEntity() ) {
  8551.             head->FreeModelDef();
  8552.         }
  8553.  
  8554.         return;
  8555.     }
  8556.  
  8557.     if( reloadModel ) {
  8558.         LoadDeferredModel(); 
  8559.         reloadModel = false;
  8560.     }
  8561.  
  8562.     gameEdit->RecordPlayback( usercmd, this );
  8563.  
  8564.     // latch button actions
  8565.     oldButtons = usercmd.buttons;
  8566.  
  8567.     // grab out usercmd
  8568.     usercmd_t oldCmd = usercmd;
  8569.     usercmd = gameLocal.usercmds[ entityNumber ];
  8570.     buttonMask &= usercmd.buttons;
  8571.     usercmd.buttons &= ~buttonMask;
  8572.  
  8573.     HandleObjectiveInput();
  8574.     if ( objectiveSystemOpen ) {
  8575.         HandleCheats();
  8576.     } else {
  8577.         ClearCheatState();
  8578.     }
  8579.  
  8580.     aasSensor->Update();
  8581.  
  8582.     if ( gameLocal.inCinematic && gameLocal.skipCinematic ) {
  8583.         // we need to let the camera think inside of this routine
  8584.         CalculateRenderView();
  8585.         return;
  8586.     }
  8587.  
  8588.      // clear the ik before we do anything else so the skeleton doesn't get updated twice
  8589.      walkIK.ClearJointMods();
  8590.  
  8591.     // if this is the very first frame of the map, set the delta view angles
  8592.     // based on the usercmd angles
  8593.     if ( !spawnAnglesSet && ( gameLocal.GameState() != GAMESTATE_STARTUP ) ) {
  8594.         spawnAnglesSet = true;
  8595.         SetViewAngles( spawnAngles );
  8596.         oldFlags = usercmd.flags;
  8597.     }
  8598.  
  8599.     if ( gameLocal.inCinematic || influenceActive 
  8600. #ifdef _XENON
  8601.         || objectiveSystemOpen 
  8602. #endif
  8603.         ) {
  8604.         usercmd.forwardmove = 0;
  8605.         usercmd.rightmove = 0;
  8606.         usercmd.upmove = 0;
  8607.     }
  8608.  
  8609.     
  8610.     // zooming
  8611.     bool zoom = (usercmd.buttons & BUTTON_ZOOM) && CanZoom();
  8612.     if ( zoom != zoomed ) {
  8613.         if ( zoom ) {
  8614.             ProcessEvent ( &EV_Player_ZoomIn );
  8615.         } else {
  8616.             ProcessEvent ( &EV_Player_ZoomOut );
  8617.         }
  8618.     }
  8619.  
  8620.     if ( IsInVehicle ( ) ) {    
  8621.         vehicleController.SetInput ( usercmd, viewAngles );
  8622.                 
  8623.         // calculate the exact bobbed view position, which is used to
  8624.         // position the view weapon, among other things
  8625.         CalculateFirstPersonView();
  8626.  
  8627.         // this may use firstPersonView, or a thirdPeoson / camera view
  8628.         CalculateRenderView();
  8629.  
  8630.         thinkFlags |= TH_PHYSICS;
  8631.         RunPhysics();
  8632.  
  8633.         if ( health > 0 ) {
  8634.             TouchTriggers();
  8635.         }
  8636.  
  8637.         UpdateLocation();
  8638.         
  8639.         if ( !fl.hidden ) {
  8640.             UpdateAnimation();
  8641.             Present();
  8642.             LinkCombat();
  8643.         } else {
  8644.             UpdateModel ( );
  8645.         }
  8646.  
  8647.         // I don't want to have to add this but if you are in a locked vehicle and you fail your objective, you won't be 
  8648.         //    ejected from the vehicle (and I don't think we'd want that even though we do have the option of forcing it..)
  8649.         //    and since you are still in the vehicle, EvaluateControls (which covers the logic below for player usercmds)
  8650.         //    will never get called.
  8651.         if ( pfl.objectiveFailed ) 
  8652.         {
  8653.             if ( (    gameLocal.time > minRespawnTime && (usercmd.buttons & BUTTON_ATTACK)) ||
  8654.                     gameLocal.time > maxRespawnTime )
  8655.             {
  8656.                 gameLocal.sessionCommand = "died";
  8657.             }
  8658.         }
  8659.  
  8660.         return;
  8661.     }
  8662.  
  8663.     // log movement changes for weapon bobbing effects
  8664.     if ( usercmd.forwardmove != oldCmd.forwardmove ) {
  8665.         loggedAccel_t    *acc = &loggedAccel[currentLoggedAccel&(NUM_LOGGED_ACCELS-1)];
  8666.         currentLoggedAccel++;
  8667.         acc->time = gameLocal.time;
  8668.         acc->dir[0] = usercmd.forwardmove - oldCmd.forwardmove;
  8669.         acc->dir[1] = acc->dir[2] = 0;
  8670.     }
  8671.  
  8672.     if ( usercmd.rightmove != oldCmd.rightmove ) {
  8673.         loggedAccel_t    *acc = &loggedAccel[currentLoggedAccel&(NUM_LOGGED_ACCELS-1)];
  8674.         currentLoggedAccel++;
  8675.         acc->time = gameLocal.time;
  8676.         acc->dir[1] = usercmd.rightmove - oldCmd.rightmove;
  8677.         acc->dir[0] = acc->dir[2] = 0;
  8678.     }
  8679.  
  8680.     // freelook centering
  8681.     if ( ( usercmd.buttons ^ oldCmd.buttons ) & BUTTON_MLOOK ) {
  8682.         centerView.Init( gameLocal.time, 200, viewAngles.pitch, 0 );
  8683.     }
  8684.  
  8685.     // if we have an active gui, we will unrotate the view angles as
  8686.     // we turn the mouse movements into gui events
  8687.     idUserInterface *gui = ActiveGui();
  8688.     if ( gui && gui != focusUI ) {
  8689.         RouteGuiMouse( gui );
  8690.     }
  8691.  
  8692.     // set the push velocity on the weapon before running the physics
  8693.     if ( weapon ) {
  8694.         weapon->SetPushVelocity( physicsObj.GetPushedLinearVelocity() );
  8695.     }
  8696.  
  8697.     EvaluateControls();
  8698.  
  8699.  
  8700. // RAVEN BEGIN
  8701. // abahr
  8702.     if( !noclip && !spectating ) {
  8703.         UpdateGravity();
  8704.     }
  8705. // RAVEN END
  8706.  
  8707.     Move();
  8708.  
  8709.     if ( !g_stopTime.GetBool() ) {
  8710.          if ( !noclip && !spectating && ( health > 0 ) && !IsHidden() ) {
  8711.              TouchTriggers();
  8712.          }
  8713.  
  8714.         // not done on clients for various reasons. don't do it on server and save the sound channel for other things
  8715.         if ( !gameLocal.isMultiplayer ) {
  8716.             if ( g_useDynamicProtection.GetBool() && dynamicProtectionScale < 1.0f && gameLocal.time - lastDmgTime > 500 ) {
  8717.                 if ( dynamicProtectionScale < 1.0f ) {
  8718.                     dynamicProtectionScale += 0.05f;
  8719.                 }
  8720.                 if ( dynamicProtectionScale > 1.0f ) {
  8721.                     dynamicProtectionScale = 1.0f;
  8722.                 }
  8723.             }
  8724.         }
  8725.  
  8726.          // update GUIs, Items, and character interactions
  8727.         UpdateFocus();
  8728.          
  8729.          UpdateLocation();
  8730.  
  8731.          // update player script
  8732.          UpdateState(); 
  8733.  
  8734.         // service animations
  8735.         if ( !spectating && !af.IsActive() ) {
  8736.             UpdateConditions();
  8737.             UpdateAnimState();
  8738.             CheckBlink();
  8739.         }
  8740.  
  8741.         // clear out our pain flag so we can tell if we recieve any damage between now and the next time we think
  8742.         pfl.pain = false;
  8743.     }
  8744.  
  8745.     if ( !af.IsActive() ) {
  8746.         AdjustBodyAngles();
  8747.     }
  8748.  
  8749.     // calculate the exact bobbed view position, which is used to
  8750.     // position the view weapon, among other things
  8751.     CalculateFirstPersonView();
  8752.  
  8753.     // this may use firstPersonView, or a thirdPeroson / camera view
  8754.     CalculateRenderView();
  8755.  
  8756.     if ( spectating ) {
  8757.         UpdateSpectating();
  8758.     } else if ( health > 0 && !gameLocal.inCinematic ) {
  8759.         UpdateWeapon();
  8760.     }
  8761.  
  8762.     UpdateAir();
  8763.     
  8764.     UpdateHud();
  8765.  
  8766.     UpdatePowerUps();
  8767.  
  8768.     UpdateDeathSkin( false );
  8769.  
  8770.     UpdateDeathShader( deathStateHitch );
  8771.  
  8772.      if ( head.GetEntity() ) {
  8773.          headRenderEnt = head.GetEntity()->GetRenderEntity();
  8774.      } else {
  8775.          headRenderEnt = NULL;
  8776.      }
  8777.  
  8778.      if ( headRenderEnt ) {
  8779.         if ( powerUpSkin ) {
  8780.             headRenderEnt->customSkin = powerUpSkin;
  8781.         } else if ( influenceSkin ) {
  8782.              headRenderEnt->customSkin = influenceSkin;
  8783.          } else {
  8784.              headRenderEnt->customSkin = headSkin;
  8785.          }
  8786.          headRenderEnt->suppressSurfaceInViewID = entityNumber + 1;
  8787.      }
  8788.  
  8789.     // always show your own shadow
  8790.     if( entityNumber == gameLocal.localClientNum ) {
  8791.         renderEntity.suppressLOD = 1;
  8792.         if( headRenderEnt ) {
  8793.             headRenderEnt->suppressLOD = 1;
  8794.         }
  8795.     } else {
  8796.         renderEntity.suppressLOD = 0;
  8797.         if( headRenderEnt ) {
  8798.             headRenderEnt->suppressLOD = 0;
  8799.         }
  8800.     }
  8801.  
  8802.     DrawShadow( headRenderEnt );
  8803.  
  8804.     // never cast shadows from our first-person muzzle flashes
  8805.     // FIXME: get first person flashlight into this 
  8806.     renderEntity.suppressShadowInLightID = rvWeapon::WPLIGHT_MUZZLEFLASH * 100 + entityNumber;
  8807.      if ( headRenderEnt ) {
  8808.          headRenderEnt->suppressShadowInLightID = rvWeapon::WPLIGHT_MUZZLEFLASH * 100 + entityNumber;
  8809.        }
  8810.  
  8811.      if ( !g_stopTime.GetBool() ) {
  8812.         UpdateAnimation();
  8813.  
  8814.         Present();
  8815.  
  8816.         LinkCombat();
  8817.     }
  8818.  
  8819.      if ( !( thinkFlags & TH_THINK ) ) {
  8820.         common->DPrintf( "player %d not thinking?\n", entityNumber );
  8821.     }
  8822.  
  8823.     if ( g_showEnemies.GetBool() ) {
  8824.         idActor *ent;
  8825.         int num = 0;
  8826.         for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
  8827.             common->DPrintf( "enemy (%d)'%s'\n", ent->entityNumber, ent->name.c_str() );
  8828.             gameRenderWorld->DebugBounds( colorRed, ent->GetPhysics()->GetBounds().Expand( 2 ), ent->GetPhysics()->GetOrigin() );
  8829.             num++;
  8830.         }
  8831.         common->DPrintf( "%d: enemies\n", num );
  8832.     }
  8833. }
  8834.  
  8835. /*
  8836. =================
  8837. idPlayer::RouteGuiMouse
  8838. =================
  8839. */
  8840. void idPlayer::RouteGuiMouse( idUserInterface *gui ) {
  8841.      sysEvent_t ev;
  8842.      const char *command;
  8843.  
  8844.     if ( usercmd.mx != oldMouseX || usercmd.my != oldMouseY ) {
  8845.          ev = sys->GenerateMouseMoveEvent( usercmd.mx - oldMouseX, usercmd.my - oldMouseY );
  8846.          command = gui->HandleEvent( &ev, gameLocal.time );
  8847.         oldMouseX = usercmd.mx;
  8848.         oldMouseY = usercmd.my;
  8849.     }
  8850. }
  8851.  
  8852. bool idPlayer::CanZoom( void  )
  8853. {
  8854.     if ( vehicleController.IsDriving() ) {
  8855.         rvVehicle * vehicle                = vehicleController.GetVehicle();
  8856.         rvVehiclePosition * position    = vehicle ? vehicle->GetPosition( vehicleController.GetPosition() ) : 0;
  8857.         rvVehicleWeapon * weapon        = position ? position->GetActiveWeapon() : 0;
  8858.  
  8859.         return weapon && weapon->CanZoom();
  8860.     }
  8861.  
  8862.     return weapon && weapon->CanZoom() && !weapon->IsReloading ( );
  8863. }
  8864.  
  8865. /*
  8866. ==================
  8867. idPlayer::LookAtKiller
  8868. ==================
  8869. */
  8870. void idPlayer::LookAtKiller( idEntity *inflictor, idEntity *attacker ) {
  8871.     idVec3 dir;
  8872.     
  8873.     if ( attacker && attacker != this ) {
  8874.         dir = attacker->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  8875.     } else if ( inflictor && inflictor != this ) {
  8876.         dir = inflictor->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  8877.     } else {
  8878.         dir = viewAxis[ 0 ];
  8879.     }
  8880.  
  8881.     idAngles ang( 0, dir.ToYaw(), 0 );
  8882.     SetViewAngles( ang );
  8883. }
  8884.  
  8885. /*
  8886. ==============
  8887. idPlayer::Kill
  8888. ==============
  8889. */
  8890. void idPlayer::Kill( bool delayRespawn, bool nodamage ) {
  8891.     if ( spectating ) {
  8892.         SpectateFreeFly( false );
  8893.     } else if ( health > 0 ) {
  8894.         godmode = false;
  8895.         if ( !g_forceUndying.GetBool() ) {
  8896.             undying = false;
  8897.         }
  8898.         if ( nodamage ) {
  8899.             ServerSpectate( true );
  8900.             forceRespawn = true;
  8901.         } else {
  8902.             Damage( this, this, vec3_origin, "damage_suicide", 1.0f, INVALID_JOINT );
  8903.             if ( delayRespawn ) {
  8904.                 forceRespawn = false;
  8905.                 int delay = spawnArgs.GetFloat( "respawn_delay" );
  8906.                 minRespawnTime = gameLocal.time + SEC2MS( delay );
  8907.                 maxRespawnTime = minRespawnTime + MAX_RESPAWN_TIME;
  8908.              }
  8909.          }
  8910.     }
  8911. }
  8912.  
  8913. /*
  8914. ==================
  8915. idPlayer::Killed
  8916. ==================
  8917. */
  8918. void idPlayer::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  8919.     float delay;
  8920.  
  8921.     assert( !gameLocal.isClient );
  8922.  
  8923.     // stop taking knockback once dead
  8924.     fl.noknockback = true;
  8925.     if ( health < -999 ) {
  8926.         health = -999;
  8927.     }
  8928.  
  8929. // RAVEN BEGIN
  8930. // rjohnson: keep this off for better performance
  8931. #if 0
  8932.     // Turn off bounding boxes when the player dies
  8933.     if ( gameLocal.isMultiplayer ) {
  8934.         use_combat_bbox = false;
  8935.     }
  8936. #endif
  8937. // RAVEN END
  8938.  
  8939.     if ( pfl.dead ) {
  8940.         pfl.pain = true;
  8941.         return;
  8942.     }
  8943.  
  8944.     bool noDrop = false;
  8945.     if ( inflictor 
  8946.         && inflictor->IsType( idTrigger_Hurt::GetClassType() ) 
  8947.         && inflictor->spawnArgs.GetBool( "nodrop" ) ) {
  8948.         //don't drop weapon or items here, flag auto-returns.
  8949.         noDrop = true;
  8950.     }
  8951.  
  8952.     if ( !g_testDeath.GetBool() && !gameLocal.isMultiplayer ) {
  8953.         playerView.Fade( colorBlack, 12000 );
  8954.     }
  8955.  
  8956.     pfl.dead = true;
  8957.     SetAnimState( ANIMCHANNEL_LEGS, "Legs_Dead", 4 );
  8958.     SetAnimState( ANIMCHANNEL_TORSO, "Torso_Dead", 4 );
  8959.  
  8960.     animator.ClearAllJoints();
  8961.  
  8962.     if ( StartRagdoll() ) {
  8963.         pm_modelView.SetInteger( 0 );
  8964.         minRespawnTime = gameLocal.time + RAGDOLL_DEATH_TIME;
  8965.         maxRespawnTime = minRespawnTime + MAX_RESPAWN_TIME;
  8966.     } else {
  8967.         // don't allow respawn until the death anim is done
  8968.         // g_forcerespawn may force spawning at some later time
  8969.         delay = spawnArgs.GetFloat( "respawn_delay" );
  8970.         minRespawnTime = gameLocal.time + SEC2MS( delay );
  8971.         maxRespawnTime = minRespawnTime + MAX_RESPAWN_TIME;
  8972.     }
  8973.  
  8974.     physicsObj.SetMovementType( PM_DEAD );
  8975.      StartSound( "snd_death", SND_CHANNEL_VOICE, 0, false, NULL );
  8976.      StopSound( SND_CHANNEL_BODY2, false );
  8977.  
  8978.     fl.takedamage = true;        // can still be gibbed
  8979.  
  8980.     if (weapon) {                    // cnicholson: Fix for crash if player dies while in vehicle
  8981.         weapon->OwnerDied();        // get rid of weapon
  8982.         if ( !noDrop ) {
  8983.             DropWeapon( );                // drop the weapon as an item 
  8984.         }
  8985.         delete weapon;
  8986.     }
  8987.  
  8988.     weapon = NULL;
  8989.     currentWeapon = -1;
  8990.  
  8991.     if ( !g_testDeath.GetBool() ) {
  8992.         LookAtKiller( inflictor, attacker );
  8993.     }
  8994.  
  8995.     if ( gameLocal.isMultiplayer || g_testDeath.GetBool() ) {
  8996.         idPlayer *killer = NULL;
  8997.         int methodOfDeath = MAX_WEAPONS;
  8998.         
  8999.         if ( attacker->IsType( idPlayer::Type ) ) {
  9000.             killer = static_cast<idPlayer*>(attacker);
  9001.  
  9002.             lastKiller = killer;
  9003.              if ( gameLocal.IsTeamGame() && killer->team == team ) {
  9004.                 // don't worry about team killers
  9005.                  lastKiller = NULL;
  9006.              }
  9007.             if ( killer == this ) {
  9008.                 // don't worry about yourself
  9009.                 lastKiller = NULL;
  9010.             }
  9011.  
  9012.             if ( health < -20 || killer->PowerUpActive( POWERUP_QUADDAMAGE ) ) {
  9013.                 gibDeath = true;
  9014.                 gibDir = dir;
  9015.                 gibsLaunched = false;
  9016.                 if( gameLocal.isMultiplayer && gameLocal.isListenServer && gameLocal.GetLocalPlayer() && gameLocal.GetLocalPlayer()->GetInstance() == instance ) {
  9017.                     ClientGib( dir );
  9018.                 }
  9019.             }
  9020.  
  9021. // RAVEN BEGIN
  9022. // jnewquist: Use accessor for static class type 
  9023.             if ( inflictor->IsType( idProjectile::GetClassType() ) ) {
  9024. // RAVEN END
  9025.                 methodOfDeath = static_cast<idProjectile*>(inflictor)->methodOfDeath;
  9026.             } else if ( inflictor->IsType( idPlayer::Type ) ) {
  9027.                 // hitscan weapon
  9028.                 methodOfDeath = static_cast<idPlayer*>(inflictor)->GetCurrentWeapon();
  9029.             }
  9030.  
  9031.             if( methodOfDeath == -1 ) {
  9032.                 methodOfDeath = MAX_WEAPONS + isTelefragged;
  9033.             }
  9034.  
  9035. // RAVEN BEGIN
  9036. // jnewquist: Use accessor for static class type 
  9037.         } else if ( attacker->IsType( idWorldspawn::GetClassType() ) ) {
  9038. // RAVEN END
  9039.             if( lastImpulseTime > gameLocal.time && lastImpulsePlayer ) {
  9040.                 killer = lastImpulsePlayer;
  9041.             }
  9042.         }
  9043.  
  9044.         gameLocal.mpGame.PlayerDeath( this, killer, methodOfDeath );
  9045.     } else {
  9046.         physicsObj.SetContents( CONTENTS_CORPSE | CONTENTS_MONSTERCLIP );
  9047.     }
  9048.  
  9049.     if ( gameLocal.isMultiplayer && gameLocal.IsFlagGameType() ) {
  9050.         if ( PowerUpActive ( POWERUP_CTF_MARINEFLAG ) ) {
  9051.             RemoveClientModel ( "mp_ctf_flag_pole" );
  9052.             RemoveClientModel ( "mp_ctf_marine_flag_world" );
  9053.             StopEffect( "fx_ctf_marine_flag_world" );
  9054.         } else if ( PowerUpActive ( POWERUP_CTF_STROGGFLAG ) ) { 
  9055.             RemoveClientModel ( "mp_ctf_flag_pole" );
  9056.             RemoveClientModel ( "mp_ctf_strogg_flag_world" );
  9057.             StopEffect( "fx_ctf_strogg_flag_world" );
  9058.         } else if ( PowerUpActive( POWERUP_CTF_ONEFLAG ) ) {
  9059.             RemoveClientModel ( "mp_ctf_one_flag" );
  9060.         }
  9061.  
  9062.         if( PowerUpActive( POWERUP_CTF_STROGGFLAG ) || PowerUpActive( POWERUP_CTF_MARINEFLAG ) || PowerUpActive( POWERUP_CTF_ONEFLAG ) ) {
  9063.             statManager->FlagDropped( this, attacker );
  9064.         }
  9065.     }
  9066.  
  9067.     if ( noDrop ) {
  9068.         RespawnFlags();
  9069.     } else {
  9070.         DropPowerups ( );    
  9071.     }
  9072.  
  9073.     ClearPowerUps();
  9074.  
  9075.     UpdateVisuals();
  9076.  
  9077.     // AI sometimes needs to respond to having killed someone.
  9078.     // Note: Would it be better to make this a virtual funciton of... something?
  9079.     aiManager.RemoveTeammate ( this );
  9080.     
  9081.     isChatting = false;
  9082. }
  9083.  
  9084. /*
  9085. =================
  9086. CalcDamagePoints
  9087.  
  9088. Calculates how many health and armor points will be inflicted, but
  9089. doesn't actually do anything with them.  This is used to tell when an attack
  9090. would have killed the player, possibly allowing a "saving throw"
  9091. =================
  9092. */
  9093. void idPlayer::CalcDamagePoints( idEntity *inflictor, idEntity *attacker, const idDict *damageDef,
  9094.                                const float damageScale, const int location, int *health, int *armor ) {
  9095.     int        damage;
  9096.     int        armorSave;
  9097.     float    pDmgScale;
  9098.  
  9099.     damageDef->GetInt( "damage", "20", damage );
  9100.     damage = GetDamageForLocation( damage, location );
  9101.  
  9102.     // optional different damage in team games
  9103.     if( gameLocal.isMultiplayer && gameLocal.IsTeamGame() && damageDef->GetInt( "damage_team" ) ) {
  9104.         damage = damageDef->GetInt( "damage_team" );
  9105.     }
  9106.  
  9107.     idPlayer *player = attacker->IsType( idPlayer::Type ) ? static_cast<idPlayer*>(attacker) : NULL;
  9108.     if ( !gameLocal.isMultiplayer ) {
  9109.         if ( inflictor != gameLocal.world ) {
  9110.             switch ( g_skill.GetInteger() ) {
  9111.                 case 0: 
  9112.                     damage = ceil(0.80f*(float)damage);
  9113.                     break;
  9114.                 case 2:
  9115.                     damage *= 1.7f;
  9116.                     break;
  9117.                 case 3:
  9118.                      damage *= 3.5f;
  9119.                     break;
  9120.                 default:
  9121.                     damage *= 1.1f;
  9122.                     break;
  9123.             }    
  9124.         }
  9125.     }
  9126.  
  9127.     damage = ceil(damageScale*(float)damage);
  9128.  
  9129.     pDmgScale = damageDef->GetFloat( "playerScale", "1" );
  9130.     damage = ceil(pDmgScale*(float)damage);
  9131.  
  9132.     // check for completely getting out of the damage
  9133.     if ( !damageDef->GetBool( "noGod" ) ) {
  9134.         // check for godmode
  9135.         if ( godmode ) {
  9136.             godmodeDamage += damage;
  9137.             damage = 0;
  9138.         }
  9139.     }
  9140.  
  9141.     // save some from armor
  9142.     if ( !damageDef->GetBool( "noArmor" ) ) {
  9143.         float armor_protection;
  9144.  
  9145.          armor_protection = ( gameLocal.isMultiplayer ) ? g_armorProtectionMP.GetFloat() : g_armorProtection.GetFloat();
  9146.         armorSave = ceil( damage * armor_protection );
  9147.         if ( armorSave >= inventory.armor ) {
  9148.             armorSave = inventory.armor;
  9149.         }
  9150.  
  9151.          if ( !damage ) {
  9152.              armorSave = 0;
  9153.          } else if ( armorSave >= damage ) {
  9154.              armorSave = damage - 1;
  9155.              damage = 1;
  9156.          } else {
  9157.              damage -= armorSave;
  9158.          }
  9159.     } else {
  9160.         armorSave = 0;
  9161.     }
  9162.  
  9163.      // check for team damage
  9164.      if ( gameLocal.IsTeamGame()
  9165.          && !gameLocal.serverInfo.GetBool( "si_teamDamage" )
  9166.          && !damageDef->GetBool( "noTeam" )
  9167.          && player
  9168.          && player != this        // you get self damage no matter what
  9169.          && player->team == team ) {
  9170.              damage = 0;
  9171.      }
  9172.  
  9173.     *health = damage;
  9174.     *armor = armorSave;
  9175. }
  9176.  
  9177. //#define INSTA_TEST
  9178.  
  9179. /*
  9180. ============
  9181. Damage
  9182.  
  9183. this        entity that is being damaged
  9184. inflictor    entity that is causing the damage
  9185. attacker    entity that caused the inflictor to damage targ
  9186.     example: this=monster, inflictor=rocket, attacker=player
  9187.  
  9188. dir            direction of the attack for knockback in global space
  9189.  
  9190. damageDef    an idDict with all the options for damage effects
  9191.  
  9192. inflictor, attacker, dir, and point can be NULL for environmental effects
  9193. ============
  9194. */
  9195. void idPlayer::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir,
  9196.                        const char *damageDefName, const float damageScale, int location ) {
  9197.      idVec3        kick;
  9198.      int            damage;
  9199.      int            armorSave;
  9200.      int            knockback;
  9201.      idVec3        damage_from;
  9202.      float        attackerPushScale;
  9203.  
  9204.     // RAVEN BEGIN
  9205.     // twhitaker: difficulty levels
  9206.     float modifiedDamageScale = damageScale;
  9207.     
  9208.     if ( !gameLocal.isMultiplayer ) {
  9209.         if ( inflictor != gameLocal.world ) {
  9210.             modifiedDamageScale *= ( 1.0f + gameLocal.GetDifficultyModifier() );
  9211.         }
  9212.     }
  9213.     // RAVEN END
  9214.  
  9215.     if ( forwardDamageEnt.IsValid() ) {
  9216.         forwardDamageEnt->Damage( inflictor, attacker, dir, damageDefName, modifiedDamageScale, location );
  9217.         return;
  9218.     }
  9219.  
  9220.     // damage is only processed on server
  9221.     if ( gameLocal.isClient ) {
  9222.         return;
  9223.     }
  9224.     
  9225.      if ( !fl.takedamage || noclip || spectating || gameLocal.inCinematic ) {
  9226.         // If in vehicle let it know that something is trying to hurt the invisible player
  9227.         if ( IsInVehicle ( ) ) {
  9228.             const idDict *damageDict = gameLocal.FindEntityDefDict( damageDefName, false );
  9229.             if ( !damageDict ) {
  9230.                 gameLocal.Warning( "Unknown damageDef '%s'", damageDefName );
  9231.                 return;
  9232.             }
  9233.             
  9234.             // If the damage def is marked as a hazard then issue a warning to the vehicle 
  9235.             if ( damageDict->GetBool ( "hazard", "0" ) ) {
  9236.                 vehicleController.GetVehicle()->IssueHazardWarning ( );
  9237.             }
  9238.         }
  9239.         return;
  9240.     }
  9241.  
  9242.     if ( !inflictor ) {
  9243.         inflictor = gameLocal.world;
  9244.     }
  9245.     if ( !attacker ) {
  9246.         attacker = gameLocal.world;
  9247.     }
  9248.  
  9249.     // MCG: player doesn't take friendly fire damage, except from self!
  9250.     if ( !gameLocal.isMultiplayer && attacker != this ) {
  9251.         if ( attacker->IsType ( idActor::GetClassType() ) && static_cast<idActor*>(attacker)->team == team ) {
  9252.             return;
  9253.         }
  9254.     }
  9255.  
  9256.     const idDeclEntityDef *damageDef = gameLocal.FindEntityDef( damageDefName, false );
  9257.     if ( !damageDef ) {
  9258.         gameLocal.Warning( "Unknown damageDef '%s'", damageDefName );
  9259.         return;
  9260.     }
  9261.  
  9262.      if ( damageDef->dict.GetBool( "ignore_player" ) ) {
  9263.          return;
  9264.      }
  9265.  
  9266.     if ( damageDef->dict.GetBool( "lightning_damage_effect" ) )
  9267.     {
  9268.         lightningEffects = 0;
  9269.         lightningNextTime = gameLocal.GetTime();
  9270.     }
  9271.  
  9272.     // We pass in damageScale, because this function calculates a modified damageScale 
  9273.     // based on g_skill, and we don't want to compensate for skill level twice.
  9274.     CalcDamagePoints( inflictor, attacker, &damageDef->dict, damageScale, location, &damage, &armorSave );
  9275.  
  9276. #ifdef INSTA_TEST
  9277.     if ( gameLocal.isMultiplayer ) {
  9278.         if ( attacker && attacker->IsType( idPlayer::GetClassType() ) && attacker != this ) {
  9279.             damage = 100;
  9280.         }
  9281.     }
  9282. #endif
  9283.  
  9284.     //
  9285.     // determine knockback
  9286.     //
  9287.     damageDef->dict.GetInt( "knockback", "0", knockback );
  9288.     if( gameLocal.isMultiplayer && gameLocal.IsTeamGame() ) {
  9289.         damageDef->dict.GetInt( "knockback_team", va( "%d", knockback ), knockback );
  9290.     }
  9291.  
  9292.     knockback *= damageScale;
  9293.  
  9294.     if ( knockback != 0 && !fl.noknockback ) {
  9295.         if ( !gameLocal.isMultiplayer && attacker == this ) {
  9296.             //In SP, no knockback from your own stuff
  9297.             knockback = 0;
  9298.         } else {
  9299.             if ( attacker != this ) {
  9300.                 attackerPushScale = 1.0f;    
  9301.             } else {
  9302.                 // since default attackerDamageScale is 0.5, default attackerPushScale should be 2
  9303.                 damageDef->dict.GetFloat( "attackerPushScale", "2", attackerPushScale );
  9304.             }
  9305.         
  9306.    
  9307. // RAVEN BEGIN   
  9308. #ifdef _XENON
  9309.             if ( gameLocal.isMultiplayer ) {
  9310.                 if ( (attacker == this)/* && (GetCurrentWeapon() == 6)*/ ) {
  9311.                     rocketJumpStart = gameLocal.time;
  9312.                 }
  9313.             }
  9314. #endif
  9315. // RAVEN END
  9316.             kick = dir;
  9317.  
  9318.             kick.Normalize();
  9319.              kick *= g_knockback.GetFloat() * knockback * attackerPushScale / 200.0f;
  9320.             
  9321.             physicsObj.SetLinearVelocity( physicsObj.GetLinearVelocity() + kick );
  9322.  
  9323.             // set the timer so that the player can't cancel out the movement immediately
  9324.              physicsObj.SetKnockBack( idMath::ClampInt( 50, 200, knockback * 2 ) );
  9325.         }
  9326.     }
  9327.     
  9328.     if ( damageDef->dict.GetBool( "burn" ) ) {
  9329.         StartSound( "snd_burn", SND_CHANNEL_BODY3, 0, false, NULL );
  9330.     } else if ( damageDef->dict.GetBool( "no_air" ) ) {
  9331.         if ( !armorSave && health > 0 ) {
  9332.             StartSound( "snd_airGasp", SND_CHANNEL_ITEM, 0, false, NULL );
  9333.         }
  9334.     }
  9335.  
  9336.     // give feedback on the player view and audibly when armor is helping
  9337.     inventory.armor -= armorSave;
  9338.  
  9339.     if ( g_debugDamage.GetInteger() ) {
  9340.         gameLocal.Printf( "client:%i health:%i damage:%i armor:%i\n", 
  9341.             entityNumber, health, damage, armorSave );
  9342.     }
  9343.  
  9344.     // move the world direction vector to local coordinates
  9345.     ClientDamageEffects ( damageDef->dict, dir, damage );
  9346.  
  9347.      // inform the attacker that they hit someone
  9348.      attacker->DamageFeedback( this, inflictor, damage );
  9349.     
  9350. //RAVEN BEGIN
  9351. //asalmon: Xenon needs stats in singleplayer
  9352. #ifndef _XENON
  9353.     if( gameLocal.isMultiplayer )
  9354. #endif 
  9355.     {
  9356. //RAVEN END
  9357.         idEntity* attacker = NULL;
  9358.  
  9359. // RAVEN BEGIN
  9360. // jnewquist: Use accessor for static class type 
  9361.         int methodOfDeath = -1;
  9362.         if ( inflictor->IsType( idProjectile::GetClassType() ) ) {
  9363. // RAVEN END
  9364.             methodOfDeath = static_cast<idProjectile*>(inflictor)->methodOfDeath;
  9365.             attacker = static_cast<idProjectile*>(inflictor)->GetOwner();
  9366.         } else if ( inflictor->IsType( idPlayer::Type ) ) {
  9367.             // hitscan weapon
  9368.             methodOfDeath = static_cast<idPlayer*>(inflictor)->GetCurrentWeapon();
  9369.             attacker = inflictor;
  9370.         }
  9371.  
  9372.         statManager->Damage( attacker, this, methodOfDeath, damage );
  9373.     }
  9374.         
  9375. // RAVEN BEGIN
  9376. // MCG - added damage over time
  9377.     if ( !inDamageEvent ) {
  9378.         if ( damageDef->dict.GetFloat( "dot_duration" ) ) {
  9379.             int endTime;
  9380.             if ( damageDef->dict.GetFloat( "dot_duration" ) == -1 ) {
  9381.                 endTime = -1;
  9382.             } else {
  9383.                 endTime = gameLocal.GetTime() + SEC2MS(damageDef->dict.GetFloat( "dot_duration" ));
  9384.             }
  9385.             int interval = SEC2MS(damageDef->dict.GetFloat( "dot_interval", "0" ));
  9386.             if ( endTime == -1 || gameLocal.GetTime() + interval <= endTime ) {//post it again
  9387.                 PostEventMS( &EV_DamageOverTime, interval, endTime, interval, inflictor, attacker, dir, damageDefName, damageScale, location );
  9388.             }
  9389.             if ( damageDef->dict.GetString( "fx_dot", NULL ) ) {
  9390.                 ProcessEvent( &EV_DamageOverTimeEffect, endTime, interval, damageDefName );
  9391.             }
  9392.             if ( damageDef->dict.GetString( "snd_dot_start", NULL ) ) {
  9393.                 StartSound ( "snd_dot_start", SND_CHANNEL_ANY, 0, false, NULL );
  9394.             }
  9395.         }
  9396.     }
  9397. // RAVEN END
  9398.  
  9399.     // do the damage
  9400.     if ( damage > 0 ) {
  9401.         if ( !gameLocal.isMultiplayer ) {
  9402.             if ( g_useDynamicProtection.GetBool() && g_skill.GetInteger() < 2 ) {
  9403.                 if ( gameLocal.time > lastDmgTime + 500 && dynamicProtectionScale > 0.25f ) {
  9404.                     dynamicProtectionScale -= 0.05f;
  9405.                 }
  9406.             }
  9407.  
  9408.             if ( dynamicProtectionScale > 0.0f ) {
  9409.                 damage *= dynamicProtectionScale;
  9410.             }
  9411.         }
  9412.  
  9413.         if ( damage < 1 ) {
  9414.             damage = 1;
  9415.         }
  9416.  
  9417.         int oldHealth = health;
  9418.         health -= damage;
  9419.  
  9420.         GAMELOG_ADD ( va("player%d_damage_taken", entityNumber ), damage );
  9421.         GAMELOG_ADD ( va("player%d_damage_%s", entityNumber, damageDefName), damage );
  9422.  
  9423.         // Check undying mode
  9424.         if ( !damageDef->dict.GetBool( "noGod" ) ) {
  9425.             if ( undying ) {
  9426.                 if ( health < 1 ) {
  9427.                     health = 1;
  9428.                 }
  9429.             }
  9430.         }
  9431.  
  9432.         if ( health <= 0 ) {
  9433.  
  9434.             if ( health < -999 ) {
  9435.                 health = -999;
  9436.             }
  9437.  
  9438.              isTelefragged = damageDef->dict.GetBool( "telefrag" );
  9439.  
  9440.              lastDmgTime = gameLocal.time;
  9441.  
  9442.             Killed( inflictor, attacker, damage, dir, location );
  9443.  
  9444.             if ( oldHealth > 0 ) {    
  9445.                 float pushScale = 1.0f;
  9446.                 if ( inflictor && inflictor->IsType ( idPlayer::Type ) ) {
  9447.                     pushScale = static_cast<idPlayer*>(inflictor)->PowerUpModifier ( PMOD_PROJECTILE_DEATHPUSH );
  9448.                 }
  9449.                 InitDeathPush ( dir, location, &damageDef->dict, pushScale );
  9450.             }            
  9451.         } else {
  9452.             // force a blink
  9453.             blink_time = 0;
  9454.  
  9455.             // let the anim script know we took damage
  9456.              pfl.pain = Pain( inflictor, attacker, damage, dir, location );
  9457.             if ( !g_testDeath.GetBool() ) {
  9458.                 lastDmgTime = gameLocal.time;
  9459.             }
  9460.         }
  9461.     } else {
  9462.          // don't accumulate impulses
  9463.         if ( af.IsLoaded() ) {
  9464.             // clear impacts
  9465.             af.Rest();
  9466.  
  9467.             // physics is turned off by calling af.Rest()
  9468.             BecomeActive( TH_PHYSICS );
  9469.         }
  9470.     }
  9471.  
  9472.     lastDamageDir = dir;
  9473.       lastDamageDir.Normalize();
  9474.     lastDamageDef = damageDef->Index();
  9475.     lastDamageLocation = location;
  9476. }
  9477.  
  9478. /*
  9479. =====================
  9480. idPlayer::AddDamageEffect
  9481. =====================
  9482. */
  9483. void idPlayer::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName, idEntity* inflictor ) {
  9484.     if( gameLocal.isMultiplayer ) {
  9485.         if( ! cvarSystem->GetCVarBool("si_teamDamage") && inflictor && inflictor->IsType( idPlayer::GetClassType() ) && gameLocal.IsTeamGame() && ((idPlayer*)inflictor)->team == team ) {
  9486.             return;
  9487.         }
  9488.     }
  9489.     
  9490.     idActor::AddDamageEffect ( collision, velocity, damageDefName, inflictor );
  9491. }
  9492.  
  9493. /*
  9494. ===========
  9495. idPlayer::Teleport
  9496. ============
  9497. */
  9498. void idPlayer::Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ) {
  9499.      idVec3 org;
  9500.  
  9501.      if ( weapon ) {
  9502.          weapon->LowerWeapon();
  9503.      }
  9504.  
  9505.     SetOrigin( origin + idVec3( 0, 0, CM_CLIP_EPSILON ) );
  9506.      if ( !gameLocal.isMultiplayer && GetFloorPos( 16.0f, org ) ) {
  9507.          SetOrigin( org );
  9508.      }
  9509.  
  9510.      // clear the ik heights so model doesn't appear in the wrong place
  9511.      walkIK.EnableAll();
  9512.  
  9513.     GetPhysics()->SetLinearVelocity( vec3_origin );
  9514.     SetViewAngles( angles );
  9515.  
  9516.     legsYaw = 0.0f;
  9517.     idealLegsYaw = 0.0f;
  9518.     oldViewYaw = viewAngles.yaw;
  9519.  
  9520.      if ( gameLocal.isMultiplayer ) {
  9521.          playerView.Flash( colorWhite, 140 );
  9522.      }
  9523.  
  9524.     // don't do any smoothing with this snapshot
  9525.     predictedFrame = gameLocal.framenum;
  9526.  
  9527.     UpdateVisuals();
  9528.  
  9529.      teleportEntity = destination;
  9530.  
  9531.     if ( !gameLocal.isClient && !noclip ) {
  9532.          if ( gameLocal.isMultiplayer ) {
  9533.              // kill anything at the new position or mark for kill depending on immediate or delayed teleport
  9534.              gameLocal.KillBox( this, destination != NULL );
  9535.          } else {
  9536.              // kill anything at the new position
  9537.              gameLocal.KillBox( this, true );
  9538.          }
  9539.     }
  9540. }
  9541.  
  9542. /*
  9543. ====================
  9544. idPlayer::SetPrivateCameraView
  9545. ====================
  9546. */
  9547. void idPlayer::SetPrivateCameraView( idCamera *camView ) {
  9548.     privateCameraView = camView;
  9549.     if ( camView ) {
  9550.         StopFiring();
  9551.         Hide();
  9552.     } else {
  9553.         if ( !spectating ) {
  9554.             Show();
  9555.         }
  9556.     }
  9557. }
  9558.  
  9559. /*
  9560. ====================
  9561. idPlayer::DefaultFov
  9562.  
  9563. Returns the base FOV
  9564. ====================
  9565. */
  9566. float idPlayer::DefaultFov( void ) const {
  9567.     float fov;
  9568.  
  9569.     fov = g_fov.GetFloat();
  9570.     if ( gameLocal.isMultiplayer ) {
  9571.         if ( fov < 90.0f ) {
  9572.             return 90.0f;
  9573.         } else if ( fov > 110.0f ) {
  9574.             return 110.0f;
  9575.         }
  9576.     }
  9577.  
  9578.     return fov;
  9579. }
  9580.  
  9581. /*
  9582. ====================
  9583. idPlayer::CalcFov
  9584.  
  9585. Fixed fov at intermissions, otherwise account for fov variable and zooms.
  9586. ====================
  9587. */
  9588. float idPlayer::CalcFov( bool honorZoom ) {
  9589.     float fov;
  9590.  
  9591.     if ( fxFov ) {
  9592.         return DefaultFov() + 10.0f + idMath::Cos( ( gameLocal.time + 2000 ) * 0.01 ) * 10.0f;
  9593.     }
  9594.  
  9595.     if ( influenceFov ) {
  9596.         return influenceFov;
  9597.     }
  9598.  
  9599.     if ( vehicleController.IsDriving() ) {
  9600.         rvVehicle * vehicle                = vehicleController.GetVehicle();
  9601.         rvVehiclePosition * position    = vehicle ? vehicle->GetPosition( vehicleController.GetPosition() ) : 0;
  9602.         rvVehicleWeapon * weapon        = position ? position->GetActiveWeapon() : 0;
  9603.  
  9604.         if ( zoomFov.IsDone( gameLocal.time ) ) {
  9605.              fov = ( honorZoom && zoomed && weapon ) ? weapon->GetZoomFov() : DefaultFov();
  9606.         } else {
  9607.             fov = zoomFov.GetCurrentValue( gameLocal.time );
  9608.         }
  9609.     } else {
  9610.         if ( zoomFov.IsDone( gameLocal.time ) ) {
  9611.              fov = ( honorZoom && zoomed && weapon ) ? weapon->GetZoomFov() : DefaultFov();
  9612.         } else {
  9613.             fov = zoomFov.GetCurrentValue( gameLocal.time );
  9614.         }
  9615.     }
  9616.  
  9617.     // bound normal viewsize
  9618.     if ( fov < 1 ) {
  9619.         fov = 1;
  9620.     } else if ( fov > 179 ) {
  9621.         fov = 179;
  9622.     }
  9623.  
  9624.     return fov;
  9625. }
  9626.  
  9627. /*
  9628. ==============
  9629. idPlayer::GunTurningOffset
  9630.  
  9631. generate a rotational offset for the gun based on the view angle
  9632. history in loggedViewAngles
  9633. ==============
  9634. */
  9635. idAngles idPlayer::GunTurningOffset( void ) {
  9636.     idAngles    a;
  9637.  
  9638.     a.Zero();
  9639.  
  9640.     if ( gameLocal.framenum < NUM_LOGGED_VIEW_ANGLES ) {
  9641.         return a;
  9642.     }
  9643.  
  9644.     idAngles current = loggedViewAngles[ gameLocal.framenum & (NUM_LOGGED_VIEW_ANGLES-1) ];
  9645.  
  9646.     idAngles    av, base;
  9647.     int weaponAngleOffsetAverages;
  9648.     float weaponAngleOffsetScale, weaponAngleOffsetMax;
  9649.  
  9650.     weapon->GetAngleOffsets( &weaponAngleOffsetAverages, &weaponAngleOffsetScale, &weaponAngleOffsetMax );
  9651.  
  9652.     av = current;
  9653.  
  9654.     // calcualte this so the wrap arounds work properly
  9655.     for ( int j = 1 ; j < weaponAngleOffsetAverages ; j++ ) {
  9656.         idAngles a2 = loggedViewAngles[ ( gameLocal.framenum - j ) & (NUM_LOGGED_VIEW_ANGLES-1) ];
  9657.  
  9658.         idAngles delta = a2 - current;
  9659.  
  9660.         if ( delta[1] > 180 ) {
  9661.             delta[1] -= 360;
  9662.         } else if ( delta[1] < -180 ) {
  9663.             delta[1] += 360;
  9664.         }
  9665.  
  9666.         av += delta * ( 1.0f / weaponAngleOffsetAverages );
  9667.     }
  9668.  
  9669.     a = ( av - current ) * weaponAngleOffsetScale;
  9670.  
  9671.     for ( int i = 0 ; i < 3 ; i++ ) {
  9672.         if ( a[i] < -weaponAngleOffsetMax ) {
  9673.             a[i] = -weaponAngleOffsetMax;
  9674.         } else if ( a[i] > weaponAngleOffsetMax ) {
  9675.             a[i] = weaponAngleOffsetMax;
  9676.         }
  9677.     }
  9678.  
  9679.     return a;
  9680. }
  9681.  
  9682. /*
  9683. ==============
  9684. idPlayer::GunAcceleratingOffset
  9685.  
  9686. generate a positional offset for the gun based on the movement
  9687. history in loggedAccelerations
  9688. ==============
  9689. */
  9690. idVec3    idPlayer::GunAcceleratingOffset( void ) {
  9691.     idVec3    ofs;
  9692.     float    weaponOffsetTime;
  9693.     float    weaponOffsetScale;
  9694.  
  9695.     ofs.Zero();
  9696.  
  9697.     weapon->GetTimeOffsets( &weaponOffsetTime, &weaponOffsetScale );
  9698.  
  9699.     int stop = currentLoggedAccel - NUM_LOGGED_ACCELS;
  9700.     if ( stop < 0 ) {
  9701.         stop = 0;
  9702.     }
  9703.     for ( int i = currentLoggedAccel-1 ; i > stop ; i-- ) {
  9704.         loggedAccel_t    *acc = &loggedAccel[i&(NUM_LOGGED_ACCELS-1)];
  9705.  
  9706.         float    f;
  9707.         float    t = gameLocal.time - acc->time;
  9708.         if ( t >= weaponOffsetTime ) {
  9709.             break;    // remainder are too old to care about
  9710.         }
  9711.  
  9712.         f = t / weaponOffsetTime;
  9713.         f = ( idMath::Cos( f * 2.0f * idMath::PI ) - 1.0f ) * 0.5f;
  9714.         ofs += f * weaponOffsetScale * acc->dir;
  9715.     }
  9716.  
  9717.     return ofs;
  9718. }
  9719.  
  9720. /*
  9721. ==============
  9722. idPlayer::CalculateViewWeaponPos
  9723.  
  9724. Calculate the bobbing position of the view weapon
  9725. ==============
  9726. */
  9727. void idPlayer::CalculateViewWeaponPos( idVec3 &origin, idMat3 &axis ) {
  9728.     float        scale;
  9729.     float        fracsin;
  9730.     idAngles    angles;
  9731.     int            delta;
  9732.  
  9733.     // CalculateRenderView must have been called first
  9734.     const idVec3 &viewOrigin = firstPersonViewOrigin;
  9735.     const idMat3 &viewAxis = firstPersonViewAxis;
  9736.  
  9737.     // these cvars are just for hand tweaking before moving a value to the weapon def
  9738.     idVec3    gunpos( g_gun_x.GetFloat(), g_gun_y.GetFloat(), g_gun_z.GetFloat() );
  9739.     gunpos += weapon->GetViewModelOffset ( );
  9740.  
  9741.     // as the player changes direction, the gun will take a small lag
  9742.     idVec3    gunOfs = GunAcceleratingOffset();
  9743.     origin = viewOrigin + ( gunpos + gunOfs ) * viewAxis;
  9744.  
  9745.     // on odd legs, invert some angles
  9746.     if ( noclip || 1 ) {
  9747.         scale = 0;
  9748.     } else if ( bobCycle & 128 ) {
  9749.         scale = -xyspeed;
  9750.     } else {
  9751.         scale = xyspeed;
  9752.     }
  9753.  
  9754.     // gun angles from bobbing
  9755.     angles.roll        = scale * bobfracsin * 0.005f + g_gun_roll.GetFloat();
  9756.     angles.yaw        = scale * bobfracsin * 0.01f + g_gun_yaw.GetFloat();
  9757.     angles.pitch    = xyspeed * bobfracsin * 0.005f + g_gun_pitch.GetFloat();
  9758.     
  9759.     angles += weapon->GetViewModelAngles();
  9760.  
  9761.     // gun angles from turning
  9762.      if ( gameLocal.isMultiplayer ) {
  9763.          idAngles offset = GunTurningOffset();
  9764.          offset *= g_mpWeaponAngleScale.GetFloat();
  9765.          angles += offset;
  9766.      } else {
  9767.          angles += GunTurningOffset();
  9768.      }   
  9769.  
  9770.     idVec3 gravity = physicsObj.GetGravityNormal();
  9771.  
  9772. // RAVEN BEGIN
  9773. // abahr: when looking down, really large deflections cause back of weapons to show
  9774.     float landChangeFrac = idMath::Lerp( 0.25f, 0.05f, viewAngles.ToForward() * gravity);
  9775. // RAVEN ABAHR
  9776.  
  9777.     // drop the weapon when landing after a jump / fall
  9778.     delta = gameLocal.time - landTime;
  9779.     if ( delta < LAND_DEFLECT_TIME ) {
  9780. // RAVEN BEGIN
  9781. // abahr: changed to use landChangeFrac
  9782.         origin -= gravity * ( landChange*landChangeFrac * delta / LAND_DEFLECT_TIME );
  9783.     } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
  9784.         origin -= gravity * ( landChange*landChangeFrac * (LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME );
  9785. // RAVEN END
  9786.     }
  9787.  
  9788.     // speed sensitive idle drift
  9789.     if ( !noclip ) {
  9790.         scale = xyspeed * 0.5f + 40.0f;
  9791.         fracsin = scale * idMath::Sin( MS2SEC( gameLocal.time ) ) * 0.01f;
  9792.         angles.roll        += fracsin;
  9793.         angles.yaw        += fracsin;
  9794.         angles.pitch    += fracsin;
  9795.     }
  9796.  
  9797.     axis = angles.ToMat3() * viewAxis;
  9798. }
  9799.  
  9800. /*
  9801. ===============
  9802. idPlayer::OffsetThirdPersonVehicleView
  9803. ===============
  9804. */
  9805. // RAVEN BEGIN
  9806. // jnewquist: option to avoid clipping against world
  9807. void idPlayer::OffsetThirdPersonVehicleView( bool clip ) {
  9808. // RAVEN END
  9809.     idVec3            view;
  9810.     idVec3            focusAngles;
  9811.     trace_t            trace;
  9812.     idVec3            focusPoint;
  9813.     float            focusDist;
  9814.     idVec3            origin;
  9815.     idAngles        angles, angles2;
  9816.     idEntity*        vehicle;
  9817.  
  9818.     assert ( IsInVehicle ( ) );
  9819.     
  9820.     vehicle = vehicleController.GetVehicle();
  9821.  
  9822.     origin = vehicle->GetRenderEntity()->origin;
  9823.     angles = vehicle->GetRenderEntity()->axis.ToAngles();
  9824.     
  9825.     angles.yaw += pm_thirdPersonAngle.GetFloat();
  9826.     angles.pitch += 25.0f;
  9827.  
  9828. //    angles.pitch += viewAngles.pitch;
  9829. //    angles.yaw += viewAngles.yaw;
  9830.  
  9831.     focusPoint = origin + angles.ToForward() * THIRD_PERSON_FOCUS_DISTANCE;
  9832.     view = origin;
  9833. // RAVEN BEGIN
  9834. // abahr: taking into account gravity
  9835.     view += physicsObj.GetGravityAxis()[2] * 8.0f;
  9836. // RAVEN END
  9837.  
  9838.     renderView->viewaxis = angles.ToMat3() * physicsObj.GetGravityAxis();
  9839.  
  9840.     float speed = vehicle->GetPhysics()->GetLinearVelocity() * 
  9841.                   vehicle->GetPhysics()->GetAxis()[0];
  9842.  
  9843.     speed = idMath::Fabs( speed );
  9844.     speed *= pm_vehicleCameraSpeedScale.GetFloat();
  9845.     if( speed > pm_vehicleCameraScaleMax.GetFloat() ) 
  9846.     {
  9847.         speed = pm_vehicleCameraScaleMax.GetFloat();
  9848.     }
  9849.  
  9850.     vehicleCameraDist += ( MS2SEC( gameLocal.GetMSec() ) * ( ( pm_vehicleCameraMinDist.GetFloat() + speed ) - vehicleCameraDist ) );
  9851.  
  9852.     view -= vehicleCameraDist * renderView->viewaxis[ 0 ];
  9853.  
  9854. // RAVEN BEGIN
  9855. // jnewquist: option to avoid clipping against world
  9856.      if ( clip ) {
  9857.         // trace a ray from the origin to the viewpoint to make sure the view isn't
  9858.         // in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything
  9859.         const idVec3 clip_mins( -4.0f, -4.0f, -4.0f );
  9860.         const idVec3 clip_maxs( 4.0f, 4.0f, 4.0f );
  9861.         const idBounds clip_bounds( clip_mins, clip_maxs );
  9862.         idClipModel clipBounds( clip_bounds );// We clip when using a tram gun in the tram car
  9863. // ddynerman: multiple clip worlds
  9864.         gameLocal.Translation( this, trace, origin, view, &clipBounds, vehicle->GetPhysics()->GetAxis(), MASK_SOLID, vehicle, vehicle->GetBindMaster() ); 
  9865.         if ( trace.fraction != 1.0 ) 
  9866.         {
  9867.             view = trace.endpos;
  9868. // abahr: taking into account gravity
  9869.             view += physicsObj.GetGravityAxis()[2] * ( 1.0f - trace.fraction ) * 32;
  9870.  
  9871.             // try another trace to this position, because a tunnel may have the ceiling
  9872.             // close enough that this is poking out
  9873. // ddynerman: multiple clip worlds
  9874.             gameLocal.Translation( this, trace, origin, view, &clipBounds, vehicle->GetPhysics()->GetAxis(), MASK_SOLID, vehicle, vehicle->GetBindMaster() ); 
  9875.             view = trace.endpos;
  9876.         }
  9877.     }
  9878. // RAVEN END
  9879.  
  9880.     // select pitch to look at focus point from vieword
  9881.     focusPoint -= view;
  9882.     focusDist = idMath::Sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
  9883.     if ( focusDist < 1 ) 
  9884.     {
  9885.         focusDist = 1;    // should never happen
  9886.     }
  9887.  
  9888.     angles.pitch = - RAD2DEG( idMath::ATan( focusPoint.z, focusDist ) );
  9889.  
  9890.     renderView->vieworg = view;
  9891.     renderView->viewaxis = angles.ToMat3() * physicsObj.GetGravityAxis();
  9892.     renderView->viewID = 0;
  9893. }
  9894.  
  9895. /*
  9896. ===============
  9897. idPlayer::OffsetThirdPersonView
  9898. ===============
  9899. */
  9900. void idPlayer::OffsetThirdPersonView( float angle, float range, float height, bool clip ) {
  9901.     idVec3            view;
  9902.     idVec3            focusAngles;
  9903.     trace_t            trace;
  9904.     idVec3            focusPoint;
  9905.     float            focusDist;
  9906.     float            forwardScale, sideScale;
  9907.     idVec3            origin;
  9908.     idAngles        angles;
  9909.     idMat3            axis;
  9910.     idBounds        bounds;
  9911.  
  9912.     angles = viewAngles;
  9913.     GetViewPos( origin, axis );
  9914.  
  9915.     if ( angle ) {
  9916.         angles.pitch = 0.0f;
  9917.     }
  9918.  
  9919.     if ( angles.pitch > 45.0f ) {
  9920.         angles.pitch = 45.0f;        // don't go too far overhead
  9921.     }
  9922.  
  9923.     focusPoint = origin + angles.ToForward() * THIRD_PERSON_FOCUS_DISTANCE;
  9924.     focusPoint.z += height;
  9925.     view = origin;
  9926. // RAVEN BEGIN
  9927. // abahr: taking into account gravity
  9928.     view += physicsObj.GetGravityAxis()[2] * (8.0f + height);
  9929. // RAVEN END
  9930.  
  9931.     angles.pitch *= 0.5f;
  9932.     renderView->viewaxis = angles.ToMat3() * physicsObj.GetGravityAxis();
  9933.  
  9934.     idMath::SinCos( DEG2RAD( angle ), sideScale, forwardScale );
  9935.     view -= range * forwardScale * renderView->viewaxis[ 0 ];
  9936.     view += range * sideScale * renderView->viewaxis[ 1 ];
  9937.  
  9938.      if ( clip ) {
  9939.          // trace a ray from the origin to the viewpoint to make sure the view isn't
  9940.          // in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything
  9941.          bounds = idBounds( idVec3( -4, -4, -4 ), idVec3( 4, 4, 4 ) );
  9942. // RAVEN BEGIN
  9943. // ddynerman: multiple clip worlds
  9944.         gameLocal.TraceBounds( this, trace, origin, view, bounds, MASK_SOLID, this );
  9945. // RAVEN END
  9946.          if ( trace.fraction != 1.0f ) {
  9947.              view = trace.endpos;
  9948. // RAVEN BEGIN
  9949. // abahr: taking into account gravity
  9950.              view += physicsObj.GetGravityAxis()[2] * ( 1.0f - trace.fraction ) * 32.0f;
  9951. // RAVEN END
  9952.    
  9953.              // try another trace to this position, because a tunnel may have the ceiling
  9954.              // close enough that this is poking out
  9955. // RAVEN BEGIN
  9956. // ddynerman: multiple clip worlds
  9957.             gameLocal.TraceBounds( this, trace, origin, view, bounds, MASK_SOLID, this );
  9958. // RAVEN END
  9959.              view = trace.endpos;
  9960.          }
  9961.        }
  9962.    
  9963.  
  9964.     // select pitch to look at focus point from vieword
  9965.     focusPoint -= view;
  9966.     focusDist = idMath::Sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
  9967.     if ( focusDist < 1.0f ) {
  9968.         focusDist = 1.0f;    // should never happen
  9969.     }
  9970.  
  9971.     angles.pitch = - RAD2DEG( idMath::ATan( focusPoint.z, focusDist ) );
  9972.     angles.yaw -= angle;
  9973.  
  9974.     renderView->vieworg = view;
  9975.     renderView->viewaxis = angles.ToMat3() * physicsObj.GetGravityAxis();
  9976.     renderView->viewID = 0;
  9977. }
  9978.  
  9979. /*
  9980. ===============
  9981. idPlayer::GetEyePosition
  9982. ===============
  9983. */
  9984. idVec3 idPlayer::GetEyePosition( void ) const {
  9985.     idVec3 org;
  9986.  
  9987.     if ( WantSmoothing() ) {
  9988.         org = predictedOrigin;
  9989.     } else {
  9990.         org = GetPhysics()->GetOrigin();
  9991.     }
  9992.  
  9993.     return org + ( GetPhysics()->GetGravityNormal() * -eyeOffset.z );
  9994. }
  9995.  
  9996. /*
  9997. ===============
  9998. idPlayer::GetViewPos
  9999. ===============
  10000. */
  10001. void idPlayer::GetViewPos( idVec3 &origin, idMat3 &axis ) const {
  10002.     idAngles angles;
  10003.  
  10004.     // if dead, fix the angle and don't add any kick
  10005.     if ( health <= 0 ) {
  10006.         angles.yaw = viewAngles.yaw;
  10007.         angles.roll = 40;
  10008.         angles.pitch = -15;
  10009.         axis = angles.ToMat3();
  10010.         origin = GetEyePosition();
  10011.     } else if ( IsInVehicle ( ) ) {    
  10012.         vehicleController.GetEyePosition ( origin, axis );
  10013.  
  10014.           idVec3        shakeOffset;
  10015.           idAngles    shakeAngleOffset;
  10016.            idBounds    relBounds(idVec3(0, 0, 0), idVec3(0, 0, 0));
  10017.           playerView.ShakeOffsets( shakeOffset, shakeAngleOffset, relBounds );
  10018.  
  10019.           origin += shakeOffset;
  10020.           axis = (shakeAngleOffset + playerView.AngleOffset()).ToMat3() * axis;
  10021.     } else {
  10022.           idVec3        shakeOffset;
  10023.           idAngles    shakeAngleOffset;
  10024.            idBounds    relBounds(idVec3(0, 0, 0), idVec3(0, 0, 0));
  10025.  
  10026.           playerView.ShakeOffsets( shakeOffset, shakeAngleOffset, relBounds );
  10027.           origin = GetEyePosition() + viewBob + shakeOffset;          
  10028.         angles = viewAngles + viewBobAngles + shakeAngleOffset + playerView.AngleOffset();
  10029.  
  10030.         axis = angles.ToMat3() * physicsObj.GetGravityAxis();
  10031.  
  10032.         // adjust the origin based on the camera nodal distance (eye distance from neck)
  10033.         origin += physicsObj.GetGravityNormal() * g_viewNodalZ.GetFloat();
  10034.         origin += axis[0] * g_viewNodalX.GetFloat() + axis[2] * g_viewNodalZ.GetFloat();
  10035.     }
  10036. }
  10037.  
  10038. /*
  10039. ===============
  10040. idPlayer::CalculateFirstPersonView
  10041. ===============
  10042. */
  10043. void idPlayer::CalculateFirstPersonView( void ) {
  10044.     if ( ( pm_modelView.GetInteger() == 1 ) || ( ( pm_modelView.GetInteger() == 2 ) && ( health <= 0 ) ) ) {
  10045.         //    Displays the view from the point of view of the "camera" joint in the player model
  10046.  
  10047.         idMat3 axis;
  10048.         idVec3 origin;
  10049.         idAngles ang;
  10050.  
  10051.         ang = viewBobAngles + playerView.AngleOffset();
  10052.         ang.yaw += viewAxis[ 0 ].ToYaw();
  10053.         
  10054.         jointHandle_t joint = animator.GetJointHandle( "camera" );
  10055.         animator.GetJointTransform( joint, gameLocal.time, origin, axis );
  10056.         firstPersonViewOrigin = ( origin + modelOffset ) * ( viewAxis * physicsObj.GetGravityAxis() ) + physicsObj.GetOrigin() + viewBob;
  10057.         firstPersonViewAxis = axis * ang.ToMat3() * physicsObj.GetGravityAxis();
  10058.     } else {
  10059.         // offset for local bobbing and kicks
  10060.         GetViewPos( firstPersonViewOrigin, firstPersonViewAxis );
  10061.     }
  10062. }
  10063.  
  10064. /*
  10065. ==================
  10066. idPlayer::GetRenderView
  10067.  
  10068. Returns the renderView that was calculated for this tic
  10069. ==================
  10070. */
  10071. renderView_t *idPlayer::GetRenderView( void ) {
  10072.     return renderView;
  10073. }
  10074.  
  10075. /*
  10076. ==================
  10077. idPlayer::SmoothenRenderView
  10078.  
  10079. various situations where the view angles need smoothing:
  10080.  
  10081. demo replay:
  10082.   On a slow client with low fps multiple game frames are run in quick succession
  10083.   inbetween rendered frames. As a result the usercmds are not recorded at fixed
  10084.   time intervals but in small bursts. This routine interpolates the view angles
  10085.   based on the real time at which the usercmds were recorded to make a demo
  10086.   recorded on a slow client play back smoothly on a fast client.
  10087.  
  10088. spectate follow?
  10089. ==================
  10090. */
  10091. void idPlayer::SmoothenRenderView( bool firstPerson ) {
  10092.     int d1, d2;
  10093.     idAngles angles, anglesDelta, newAngles;
  10094.  
  10095.     if ( gameLocal.GetDemoState() == DEMO_PLAYING ) {
  10096.  
  10097.         d1 = usercmd.gameTime - demoViewAngleTime;
  10098.         if ( d1 < 0 ) {
  10099.             return;
  10100.         }
  10101.         d2 = usercmd.realTime - demoViewAngleTime;
  10102.         if ( d2 <= 0 ) {
  10103.             return;
  10104.         }
  10105.         if ( d1 >= d2 ) {
  10106.             return;
  10107.         }
  10108.  
  10109.         angles = renderView->viewaxis.ToAngles();
  10110.  
  10111.         anglesDelta = angles - demoViewAngles;
  10112.         anglesDelta.Normalize180();
  10113.         newAngles = demoViewAngles + ( (float) d1 / d2 ) * anglesDelta;
  10114.         renderView->viewaxis = newAngles.ToMat3();
  10115.  
  10116.         if ( usercmd.gameTime + gameLocal.msec > usercmd.realTime ) {
  10117.             demoViewAngleTime = usercmd.realTime;
  10118.             demoViewAngles = angles;
  10119.         }
  10120.  
  10121.         if ( firstPerson ) {
  10122.             // make sure the view weapon moves smoothly
  10123.             firstPersonViewAxis = renderView->viewaxis;
  10124.         }
  10125.     }
  10126. }
  10127.  
  10128. /*
  10129. ==================
  10130. idPlayer::CalculateRenderView
  10131.  
  10132. create the renderView for the current tic
  10133. ==================
  10134. */
  10135. void idPlayer::CalculateRenderView( void ) {
  10136.     int i;
  10137.     float range;
  10138.  
  10139.     if ( !renderView ) {
  10140. // RAVEN BEGIN
  10141. // mwhitlock: Dynamic memory consolidation
  10142.         RV_PUSH_HEAP_MEM_AUTO(p0,this);
  10143. // RAVEN END
  10144.         renderView = new renderView_t;
  10145.     }
  10146.     memset( renderView, 0, sizeof( *renderView ) );
  10147.  
  10148.     // copy global shader parms
  10149.     for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
  10150.         renderView->shaderParms[ i ] = gameLocal.globalShaderParms[ i ];
  10151.     }
  10152.     renderView->globalMaterial = gameLocal.GetGlobalMaterial();
  10153.     renderView->time = gameLocal.time;
  10154.  
  10155.     // calculate size of 3D view
  10156.     renderView->x = 0;
  10157.     renderView->y = 0;
  10158.     renderView->width = SCREEN_WIDTH;
  10159.     renderView->height = SCREEN_HEIGHT;
  10160.     renderView->viewID = 0;
  10161.  
  10162.     // check if we should be drawing from a camera's POV
  10163.     if ( !noclip && (gameLocal.GetCamera() || privateCameraView) ) {
  10164.         // get origin, axis, and fov
  10165.         if ( privateCameraView ) {
  10166.             privateCameraView->GetViewParms( renderView );
  10167.         } else {
  10168.             gameLocal.GetCamera()->GetViewParms( renderView );
  10169.         }
  10170.     } else {
  10171.         bool cameraIsSet = false;
  10172.  
  10173.         // First try out any camera views that can possibly fail.
  10174.         if( !cameraIsSet ){
  10175.             if ( g_stopTime.GetBool() ) {
  10176.                  renderView->vieworg = firstPersonViewOrigin;
  10177.                  renderView->viewaxis = firstPersonViewAxis;
  10178.                 SmoothenRenderView( true );
  10179.  
  10180.                  if ( !pm_thirdPerson.GetBool() ) {
  10181.                      // set the viewID to the clientNum + 1, so we can suppress the right player bodies and
  10182.                      // allow the right player view weapons
  10183.                      renderView->viewID = entityNumber + 1;
  10184.                  }
  10185.             } else if ( pm_thirdPerson.GetBool() && IsInVehicle ( ) ) {
  10186. // RAVEN BEGIN
  10187. // jnewquist: option to avoid clipping against world
  10188.                 OffsetThirdPersonVehicleView( pm_thirdPersonClip.GetBool() );
  10189. // RAVEN END
  10190.                 SmoothenRenderView( false );
  10191.             } else if ( pm_thirdPerson.GetBool() ) {
  10192.                 OffsetThirdPersonView( pm_thirdPersonAngle.GetFloat(), pm_thirdPersonRange.GetFloat(), pm_thirdPersonHeight.GetFloat(), pm_thirdPersonClip.GetBool() );
  10193.                 SmoothenRenderView( false );
  10194.             } else if ( pm_thirdPersonDeath.GetBool() ) {
  10195.                 range = gameLocal.time < minRespawnTime ? ( gameLocal.time + RAGDOLL_DEATH_TIME - minRespawnTime ) * ( 120.0f / RAGDOLL_DEATH_TIME ) : 120.0f;
  10196.                  OffsetThirdPersonView( 0.0f, 20.0f + range, 0.0f, false );
  10197.                 SmoothenRenderView( false );
  10198.             } else {
  10199.                 renderView->vieworg = firstPersonViewOrigin;
  10200.                 renderView->viewaxis = firstPersonViewAxis;
  10201.                 SmoothenRenderView( true );
  10202.                 // set the viewID to the clientNum + 1, so we can suppress the right player bodies and
  10203.                 // allow the right player view weapons
  10204.                 renderView->viewID = entityNumber + 1;
  10205.             }
  10206.         }
  10207.         
  10208.         // field of view
  10209.          gameLocal.CalcFov( CalcFov( true ), renderView->fov_x, renderView->fov_y );
  10210.  
  10211.     }
  10212.  
  10213.     if ( renderView->fov_y == 0 ) {
  10214.         common->Error( "renderView->fov_y == 0" );
  10215.     }
  10216.  
  10217.     if ( g_showviewpos.GetBool() ) {
  10218.         gameLocal.Printf( "%s : %s\n", renderView->vieworg.ToString(), renderView->viewaxis.ToAngles().ToString() );
  10219.     }
  10220. }
  10221.  
  10222. /*
  10223. ==================
  10224. idPlayer::Event_EnableTarget
  10225. ==================
  10226. */
  10227. void idPlayer::Event_EnableTarget ( void ) {
  10228.     fl.notarget = false;
  10229. }
  10230.  
  10231. /*
  10232. ==================
  10233. idPlayer::Event_DisableTarget
  10234. ==================
  10235. */
  10236. void idPlayer::Event_DisableTarget ( void ) {
  10237.     fl.notarget = true;
  10238. }
  10239.  
  10240. /*
  10241. ==================
  10242. idPlayer::Event_GetViewPos
  10243. ==================
  10244. */
  10245. void idPlayer::Event_GetViewPos( void ) {
  10246.     idVec3        viewOrigin;
  10247.     idMat3        viewAxis;
  10248.  
  10249.     GetViewPos(viewOrigin, viewAxis);
  10250.     idThread::ReturnVector( viewOrigin );
  10251. }
  10252.  
  10253. /*
  10254. ==================
  10255. idPlayer::Event_FinishHearingLoss
  10256. ==================
  10257. */
  10258. void idPlayer::Event_FinishHearingLoss ( float fadeTime ) {
  10259.     if ( fadeTime <= 0.0f ) {
  10260.         StopSound ( SND_CHANNEL_DEMONIC, false );
  10261.         pfl.hearingLoss = false;
  10262.     } else {
  10263.         soundSystem->FadeSoundClasses( SOUNDWORLD_GAME, 0, 0.0f, fadeTime );
  10264.         PostEventSec ( &EV_Player_FinishHearingLoss, fadeTime, 0.0f );
  10265.     }
  10266. }
  10267.  
  10268. // RAVEN BEGIN
  10269. // twhitaker: added the event
  10270. /*
  10271. =============
  10272. idPlayer::Event_ApplyImpulse
  10273. =============
  10274. */
  10275. void idPlayer::Event_ApplyImpulse ( idEntity* ent, idVec3 &point, idVec3 &impulse ) {
  10276.     GetPhysics()->ApplyImpulse( 0, point, impulse );
  10277. }
  10278.  
  10279. // mekberg: added Event_EnableObjectives
  10280. /*
  10281. =============
  10282. idPlayer::Event_EnableObjectives
  10283. =============
  10284. */
  10285. void idPlayer::Event_EnableObjectives ( void ) {
  10286.     objectivesEnabled = true;
  10287. }
  10288.  
  10289. // mekberg: added Event_DisableObjectives
  10290. /*
  10291. =============
  10292. idPlayer::Event_DisableObjectives
  10293. =============
  10294. */
  10295. void idPlayer::Event_DisableObjectives ( void ) {
  10296.     // if it's open, it should be closed
  10297.     if (objectiveSystemOpen ) {
  10298.         ToggleObjectives();
  10299.     }
  10300.     objectivesEnabled = false;
  10301. }
  10302.  
  10303. // mekberg: added Event_AllowNewObjectives
  10304. void idPlayer::Event_AllowNewObjectives ( void ) {
  10305.     showNewObjectives = true;
  10306. }
  10307.  
  10308. // mekberg: added sethealth
  10309. /*
  10310. =============
  10311. idPlayer::Event_SetHealth
  10312. =============
  10313. */
  10314. void idPlayer::Event_SetHealth( float newHealth ) {
  10315.     health = idMath::ClampInt( 1 , inventory.maxHealth, newHealth );
  10316. }
  10317. /*
  10318. =============
  10319. idPlayer::Event_SetArmor
  10320. =============
  10321. */
  10322. void idPlayer::Event_SetArmor( float newArmor ) {
  10323.     inventory.armor = idMath::ClampInt( 0 , inventory.maxarmor, newArmor );
  10324. }
  10325.  
  10326. /*
  10327. =============
  10328. idPlayer::Event_SetExtraProjPassEntity
  10329. =============
  10330. */
  10331. void idPlayer::Event_SetExtraProjPassEntity( idEntity* _extraProjPassEntity ) {
  10332.     extraProjPassEntity = _extraProjPassEntity;
  10333. }
  10334. // RAVEN END
  10335.  
  10336. /*
  10337. =============
  10338. idPlayer::AddProjectilesFired
  10339. =============
  10340. */
  10341. void idPlayer::AddProjectilesFired( int count ) {
  10342.     numProjectilesFired += count;
  10343. }
  10344.  
  10345. /*
  10346. =============
  10347. idPlayer::AddProjectileHites
  10348. =============
  10349. */
  10350. void idPlayer::AddProjectileHits( int count ) {
  10351.     numProjectileHits += count;
  10352. }
  10353.  
  10354. /*
  10355. =============
  10356. idPlayer::SetLastHitTime
  10357. =============
  10358. */
  10359. void idPlayer::SetLastHitTime( int time, bool armorHit ) {
  10360.      if ( !time ) {
  10361.          // level start and inits
  10362.          return;
  10363.      }
  10364.  
  10365.     // if updating the hud of a followed client
  10366.     idUserInterface *cursor        = idPlayer::cursor;
  10367.     bool            spectated    = false;
  10368.     if ( gameLocal.localClientNum >= 0 && gameLocal.entities[ gameLocal.localClientNum ] ) {
  10369.         idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ gameLocal.localClientNum ] );
  10370.         if ( p->spectating && p->spectator == entityNumber ) {
  10371.             cursor = p->GetCursorGUI();
  10372.             spectated = true;
  10373.         }
  10374.     }
  10375.  
  10376.     if ( lastHitTime != time ) {
  10377.         if ( cursor ) {
  10378.             cursor->HandleNamedEvent( "weaponHit" );
  10379.         }
  10380.         if ( gameLocal.isMultiplayer ) {            
  10381.             // spectated so we get sounds for a client we're following
  10382.             // localClientNum check so listen server plays only for local player
  10383.             if ( spectated || gameLocal.localClientNum == entityNumber ) {
  10384.                 const char* sound;
  10385.  
  10386.                 if ( armorHit ) {
  10387.                     if ( spawnArgs.GetString ( "snd_armorHit", "", &sound ) ) {
  10388.                         soundSystem->PlayShaderDirectly( SOUNDWORLD_GAME, sound );
  10389.                     }
  10390.                 } else {
  10391.                     if ( spawnArgs.GetString ( "snd_weaponHit", "", &sound ) ) {
  10392.                         soundSystem->PlayShaderDirectly( SOUNDWORLD_GAME, sound );
  10393.                     }
  10394.                 }
  10395.             }
  10396.         
  10397.             if ( aimClientNum != -1 ) {
  10398.                 if ( mphud ) {
  10399.                     mphud->HandleNamedEvent( "aim_hit" );
  10400.                 }
  10401.             }
  10402.  
  10403.         }
  10404.         lastArmorHit = armorHit;
  10405.         lastHitToggle ^= 1;
  10406.     }
  10407. }
  10408.  
  10409. /*
  10410. =============
  10411. idPlayer::SetInfluenceLevel
  10412. =============
  10413. */
  10414. void idPlayer::SetInfluenceLevel( int level ) {
  10415.     if ( level != influenceActive ) {
  10416.         if ( level ) {
  10417.             for ( idEntity *ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  10418. // RAVEN BEGIN
  10419. // jnewquist: Use accessor for static class type 
  10420.                 if ( ent->IsType( idProjectile::GetClassType() ) ) {
  10421. // RAVEN END
  10422.                     // remove all projectiles
  10423.                     ent->PostEventMS( &EV_Remove, 0 );
  10424.                 }
  10425.             }
  10426.             if ( weaponEnabled && weapon ) {
  10427.                 weapon->EnterCinematic();
  10428.             }
  10429.         } else {
  10430.             physicsObj.SetLinearVelocity( vec3_origin );
  10431.             if ( weaponEnabled && weapon ) {
  10432.                 weapon->ExitCinematic();
  10433.             }
  10434.         }
  10435.         influenceActive = level;
  10436.     }
  10437. }
  10438.  
  10439. /*
  10440. =============
  10441. idPlayer::SetInfluenceView
  10442. =============
  10443. */
  10444. void idPlayer::SetInfluenceView( const char *mtr, const char *skinname, float radius, idEntity *ent ) {
  10445.     influenceMaterial = NULL;
  10446.     influenceEntity = NULL;
  10447.     influenceSkin = NULL;
  10448.     if ( mtr && *mtr ) {
  10449.         influenceMaterial = declManager->FindMaterial( mtr );
  10450.     }
  10451.     if ( skinname && *skinname ) {
  10452.         influenceSkin = declManager->FindSkin( skinname );
  10453.         if ( head.GetEntity() ) {
  10454.             head.GetEntity()->GetRenderEntity()->shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  10455.         }
  10456.         UpdateVisuals();
  10457.     }
  10458.     influenceRadius = radius;
  10459.     if ( radius > 0.0f ) {
  10460.         influenceEntity = ent;
  10461.     }
  10462. }
  10463.  
  10464. /*
  10465. =============
  10466. idPlayer::SetInfluenceFov
  10467. =============
  10468. */
  10469. void idPlayer::SetInfluenceFov( float fov ) {
  10470.     influenceFov = fov;
  10471. }
  10472.  
  10473. /*
  10474. ================
  10475. idPlayer::OnLadder
  10476. ================
  10477. */
  10478. bool idPlayer::OnLadder( void ) const {
  10479.     return physicsObj.OnLadder();
  10480. }
  10481.  
  10482. /*
  10483. ==================
  10484. idPlayer::Event_GetButtons
  10485. ==================
  10486. */
  10487. void idPlayer::Event_GetButtons( void ) {
  10488.     idThread::ReturnInt( usercmd.buttons );
  10489. }
  10490.  
  10491. /*
  10492. ==================
  10493. idPlayer::Event_GetMove
  10494. ==================
  10495. */
  10496. void idPlayer::Event_GetMove( void ) {
  10497.     idVec3 move( usercmd.forwardmove, usercmd.rightmove, usercmd.upmove );
  10498.     idThread::ReturnVector( move );
  10499. }
  10500.  
  10501. /*
  10502. ================
  10503. idPlayer::Event_GetViewAngles
  10504. ================
  10505. */
  10506. void idPlayer::Event_GetViewAngles( void ) {
  10507.     idThread::ReturnVector( idVec3( viewAngles[0], viewAngles[1], viewAngles[2] ) );
  10508. }
  10509.  
  10510. /*
  10511. ================
  10512. idPlayer::Event_SetViewAngles
  10513. ================
  10514. */
  10515. void idPlayer::Event_SetViewAngles( const idVec3 & vec ) {
  10516.     idAngles ang;
  10517.     ang.Set( vec.z, vec.y, vec.x );
  10518.     SetViewAngles( ang );
  10519. }
  10520.  
  10521. /*
  10522. ==================
  10523. idPlayer::Event_StopFxFov
  10524. ==================
  10525. */
  10526. void idPlayer::Event_StopFxFov( void ) {
  10527.     fxFov = false;
  10528. }
  10529.  
  10530. /*
  10531. ==================
  10532. idPlayer::StartFxFov 
  10533. ==================
  10534. */
  10535. void idPlayer::StartFxFov( float duration ) { 
  10536.     fxFov = true;
  10537.     PostEventSec( &EV_Player_StopFxFov, duration );
  10538. }
  10539.  
  10540. /*
  10541. ==================
  10542. idPlayer::Event_EnableWeapon 
  10543. ==================
  10544. */
  10545. void idPlayer::Event_EnableWeapon( void ) {
  10546.     gameLocal.world->spawnArgs.SetBool( "no_Weapons", 0 );
  10547.     Give( "weapon", spawnArgs.GetString( va( "def_weapon%d", 0 ) ) );
  10548.      hiddenWeapon = false;
  10549.     weaponEnabled = true;
  10550.     if ( weapon ) {
  10551.          weapon->ExitCinematic();
  10552.     }
  10553.     ShowCrosshair();
  10554. }
  10555.  
  10556. /*
  10557. ==================
  10558. idPlayer::Event_DisableWeapon
  10559. ==================
  10560. */
  10561. void idPlayer::Event_DisableWeapon( void ) {
  10562.      hiddenWeapon = true;
  10563.     weaponEnabled = false;
  10564.        if ( weapon ) {
  10565.         weapon->EnterCinematic();
  10566.        }
  10567.     HideCrosshair();
  10568. }
  10569.  
  10570. /*
  10571. ==================
  10572. idPlayer::Event_GetCurrentWeapon
  10573. ==================
  10574. */
  10575. void idPlayer::Event_GetCurrentWeapon( void ) {
  10576.     if ( currentWeapon >= 0 ) {
  10577.         idThread::ReturnString( spawnArgs.GetString( va( "def_weapon%d", currentWeapon ) ) );
  10578.     } else {
  10579.         idThread::ReturnString( "" );
  10580.     }
  10581. }
  10582.  
  10583. /*
  10584. ==================
  10585. idPlayer::Event_GetPreviousWeapon
  10586. ==================
  10587. */
  10588. void idPlayer::Event_GetPreviousWeapon( void ) {
  10589.     if ( previousWeapon >= 0 ) {
  10590.         int pw = ( gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) ) ? 0 : previousWeapon;
  10591.         idThread::ReturnString( spawnArgs.GetString( va( "def_weapon%d", pw) ) );
  10592.     } else {
  10593.         idThread::ReturnString( "def_weapon0" );
  10594.     }
  10595. }
  10596.  
  10597. /*
  10598. ==================
  10599. idPlayer::Event_SelectWeapon
  10600. ==================
  10601. */
  10602. void idPlayer::Event_SelectWeapon( const char *weaponName ) {
  10603.     int i;
  10604.     int weaponNum;
  10605.  
  10606.     if ( gameLocal.isClient ) {
  10607. // RAVEN BEGIN
  10608. // nrausch: we need to support a select weapon event in multiplayer to make the quick select ui work
  10609. #ifdef _XENON
  10610.         int impulse = 0;
  10611.     
  10612.         // Because of the spawnargs stuff, we can't really change this...
  10613.         // so drill through each possible weapon name and figure out the correct impulse
  10614.         if ( idStr::Icmp( weaponName, "weapon_blaster" ) == 0 )
  10615.         {
  10616.             impulse = 0;
  10617.         }
  10618.         else if ( idStr::Icmp( weaponName, "weapon_machinegun" ) == 0 )
  10619.         {
  10620.             impulse = 1;
  10621.         }
  10622.         else if ( idStr::Icmp( weaponName, "weapon_shotgun" ) == 0 )
  10623.         {
  10624.             impulse = 2;
  10625.         }
  10626.         else if ( idStr::Icmp( weaponName, "weapon_nailgun" ) == 0 )
  10627.         {
  10628.             impulse = 5;
  10629.         }
  10630.         else if ( idStr::Icmp( weaponName, "weapon_hyperblaster" ) == 0 )
  10631.         {
  10632.             impulse = 3;
  10633.         }
  10634.         else if ( idStr::Icmp( weaponName, "weapon_rocketlauncher" ) == 0 )
  10635.         {
  10636.             impulse = 6;
  10637.         }    
  10638.         else if ( idStr::Icmp( weaponName, "weapon_lightninggun" ) == 0 )
  10639.         {
  10640.             impulse = 8;
  10641.         }
  10642.         else if ( idStr::Icmp( weaponName, "weapon_grenadelauncher" ) == 0 )
  10643.         {
  10644.             impulse = 4;
  10645.         }
  10646.         else if ( idStr::Icmp( weaponName, "weapon_railgun" ) == 0 )
  10647.         {
  10648.             impulse = 7;
  10649.         }    
  10650.         else if ( idStr::Icmp( weaponName, "weapon_gauntlet" ) == 0 )
  10651.         {
  10652.             impulse = 0;
  10653.         }    
  10654.         else if ( idStr::Icmp( weaponName, "weapon_dmg" ) == 0 )
  10655.         {
  10656.             impulse = 9;
  10657.         }    
  10658.         
  10659.         if ( impulse > 0 && impulse != 10 ) {
  10660.             const char *weap = spawnArgs.GetString( va( "def_weapon%d", impulse ) );
  10661.             if ( !inventory.HasAmmo( weap ) ) {
  10662.                 return;
  10663.             }
  10664.         }
  10665.  
  10666.         usercmdGen->StuffImpulse( impulse );
  10667. #else
  10668.          gameLocal.Warning( "Cannot switch weapons from script in multiplayer" );
  10669. #endif
  10670. // RAVEN END
  10671.          return;
  10672.      }
  10673.  
  10674.     weaponNum = -1;
  10675.     for( i = 0; i < MAX_WEAPONS; i++ ) {
  10676.         if ( inventory.weapons & ( 1 << i ) ) {
  10677.             const char *weap = spawnArgs.GetString( va( "def_weapon%d", i ) );
  10678.             if ( !idStr::Cmp( weap, weaponName ) ) {
  10679.  
  10680.                 if ( !inventory.HasAmmo( weap ) ) {
  10681.                     return;
  10682.                 }
  10683.                 weaponNum = i;
  10684.                 break;
  10685.             }
  10686.         }
  10687.     }
  10688.  
  10689.     if ( weaponNum < 0 ) {
  10690.         gameLocal.Warning( "%s is not carrying weapon '%s'", name.c_str(), weaponName );
  10691.         return;
  10692.     }
  10693.  
  10694.     hiddenWeapon = false;
  10695.     idealWeapon = weaponNum;
  10696.  
  10697.      UpdateHudWeapon();
  10698. }
  10699. /*
  10700. ==================
  10701. idPlayer::Event_GetAmmoData
  10702. ==================
  10703. */
  10704. void idPlayer::Event_GetAmmoData( const char *ammoClass ) {
  10705.  
  10706.     idVec3    weaponAmmo;
  10707.  
  10708.     //ammo vector is this: current ammo count, max ammo count, and %
  10709.     weaponAmmo.x = inventory.ammo[ inventory.AmmoIndexForAmmoClass( ammoClass) ];
  10710.     weaponAmmo.y = inventory.MaxAmmoForAmmoClass( this, ammoClass );
  10711.  
  10712.     if( weaponAmmo.y == 0)
  10713.         weaponAmmo.z = 0;
  10714.     else
  10715.         weaponAmmo.z = (float)(weaponAmmo.x / weaponAmmo.y);
  10716.  
  10717.     idThread::ReturnVector( weaponAmmo);
  10718. }
  10719.  
  10720. /*
  10721. ==================
  10722. idPlayer::Event_RefillAmmo
  10723. ==================
  10724. */
  10725. void idPlayer::Event_RefillAmmo( void ) {
  10726.     int a;
  10727.     for ( int i = 0; i < MAX_WEAPONS; i++ ) {
  10728.         if ( inventory.weapons & ( 1 << i ) ) {
  10729.             const char *weap = spawnArgs.GetString( va( "def_weapon%d", i ) );
  10730.             if ( weap && *weap ) {
  10731.                 a = inventory.AmmoIndexForWeaponIndex( i );
  10732.                 inventory.ammo[ a ] = inventory.MaxAmmoForAmmoClass( this, rvWeapon::GetAmmoNameForIndex( a ) );
  10733.             }
  10734.         }
  10735.     }
  10736. }
  10737.  
  10738. /*
  10739. ==================
  10740. idPlayer::Event_AllowFallDamage
  10741. ==================
  10742. */
  10743. void idPlayer::Event_AllowFallDamage( int toggle ) {
  10744.     if( toggle )    {
  10745.         pfl.noFallingDamage = false;
  10746.     } else {
  10747.         pfl.noFallingDamage = true;
  10748.     }
  10749.  
  10750. }
  10751. /*
  10752. ==================
  10753. idPlayer::Event_GetWeaponEntity
  10754. ==================
  10755. */
  10756. void idPlayer::Event_GetWeaponEntity( void ) {
  10757.     idThread::ReturnEntity( weaponViewModel );
  10758. }
  10759.  
  10760. /*
  10761. ==================
  10762. idPlayer::Event_HideDatabaseEntry
  10763. ==================
  10764. */
  10765. void idPlayer::Event_HideDatabaseEntry ( void ) {
  10766.     if ( hud ) {
  10767.         hud->HandleNamedEvent( "closeDatabaseEntry" );
  10768.     }
  10769. }
  10770.  
  10771. /*
  10772. ==================
  10773. idPlayer::Event_ZoomIn
  10774. ==================
  10775. */
  10776. void idPlayer::Event_ZoomIn ( void ) {
  10777.     float currentFov;
  10778.     float t;
  10779.     
  10780.     if ( zoomed ) {
  10781.         return;
  10782.     }
  10783.     
  10784.     if ( vehicleController.IsDriving() ) {
  10785.         rvVehicle * vehicle                = vehicleController.GetVehicle();
  10786.         rvVehiclePosition * position    = vehicle ? vehicle->GetPosition( vehicleController.GetPosition() ) : 0;
  10787.         rvVehicleWeapon * weapon        = position ? position->GetActiveWeapon() : 0;
  10788.  
  10789.         if( !weapon ) {
  10790.             // this should only happen in fringe cases - zooming in while dead, etc
  10791.             zoomFov.Init( gameLocal.time, 0, DefaultFov(), DefaultFov() );
  10792.             zoomed = false;
  10793.             return;
  10794.         }
  10795.  
  10796.         currentFov = CalcFov ( true );
  10797.         t  = currentFov - weapon->GetZoomFov();
  10798.         t /= (DefaultFov() - weapon->GetZoomFov());
  10799.         t *= weapon->GetZoomTime();
  10800.  
  10801.         zoomFov.Init( gameLocal.time, SEC2MS(t), currentFov, weapon->GetZoomFov() );
  10802.                 
  10803.         zoomed = true;
  10804.         if ( weapon->GetZoomGui() )    {
  10805.             weapon->GetZoomGui()->HandleNamedEvent ( "zoomIn" );
  10806.             weaponViewModel->StartSound ( "snd_zoomin", SND_CHANNEL_ANY, 0, false, NULL );
  10807.         }
  10808.     } else if ( weapon ) {
  10809.         currentFov = CalcFov ( true );
  10810.         t  = currentFov - weapon->GetZoomFov();
  10811.         t /= (DefaultFov() - weapon->GetZoomFov());
  10812.         t *= weapon->GetZoomTime();
  10813.  
  10814.         zoomFov.Init( gameLocal.time, SEC2MS(t), currentFov, weapon->GetZoomFov() );
  10815.                 
  10816.         zoomed = true;
  10817.         if ( weapon->GetZoomGui() )    {
  10818.             weapon->GetZoomGui()->HandleNamedEvent ( "zoomIn" );
  10819.             weaponViewModel->StartSound ( "snd_zoomin", SND_CHANNEL_ANY, 0, false, NULL );
  10820.         }
  10821.     }
  10822. }
  10823.  
  10824. /*
  10825. ==================
  10826. idPlayer::Event_ZoomOut
  10827. ==================
  10828. */
  10829. void idPlayer::Event_ZoomOut ( void ) {
  10830.     float t;
  10831.     float currentFov;
  10832.  
  10833.     if ( !zoomed ) {
  10834.         return;
  10835.     }
  10836.     
  10837.     if ( vehicleController.IsDriving() ) {
  10838.         rvVehicle * vehicle                = vehicleController.GetVehicle();
  10839.         rvVehiclePosition * position    = vehicle ? vehicle->GetPosition( vehicleController.GetPosition() ) : 0;
  10840.         rvVehicleWeapon * weapon        = position ? position->GetActiveWeapon() : 0;
  10841.  
  10842.         if( !weapon ) {
  10843.             // this should only happen in fringe cases - zooming out while dead, etc
  10844.             zoomFov.Init( gameLocal.time, 0, DefaultFov(), DefaultFov() );
  10845.             zoomed = false;
  10846.             return;
  10847.         }
  10848.  
  10849.         currentFov = CalcFov ( true );
  10850.         t  = currentFov - weapon->GetZoomFov();
  10851.         t /= (DefaultFov() - weapon->GetZoomFov());
  10852.         t  = (1.0f - t) * weapon->GetZoomTime();
  10853.  
  10854.         zoomFov.Init( gameLocal.time, SEC2MS(t), currentFov, DefaultFov() );
  10855.         zoomed = false;
  10856.         if ( weapon->GetZoomGui() )    {
  10857.             weaponViewModel->StartSound ( "snd_zoomout", SND_CHANNEL_ANY, 0, false, NULL );
  10858.         }
  10859.     } else {
  10860.         if( !weapon ) {
  10861.             // this should only happen in fringe cases - zooming out while dead, etc
  10862.             zoomFov.Init( gameLocal.time, 0, DefaultFov(), DefaultFov() );
  10863.             zoomed = false;
  10864.             return;
  10865.         }
  10866.  
  10867.         currentFov = CalcFov ( true );
  10868.         t  = currentFov - weapon->GetZoomFov();
  10869.         t /= (DefaultFov() - weapon->GetZoomFov());
  10870.         t  = (1.0f - t) * weapon->GetZoomTime();
  10871.  
  10872.         zoomFov.Init( gameLocal.time, SEC2MS(t), currentFov, DefaultFov() );
  10873.         zoomed = false;
  10874.         if ( weapon->GetZoomGui() )    {
  10875.             weaponViewModel->StartSound ( "snd_zoomout", SND_CHANNEL_ANY, 0, false, NULL );
  10876.         }
  10877.     }
  10878. }
  10879.  
  10880. /*
  10881. ==================
  10882. idPlayer::TeleportDeath
  10883. ==================
  10884. */
  10885. void idPlayer::TeleportDeath( int killer ) {
  10886.     teleportKiller = killer;
  10887. }
  10888.  
  10889. /*
  10890. ==================
  10891. idPlayer::Event_ExitTeleporter
  10892. ==================
  10893. */
  10894. void idPlayer::Event_ExitTeleporter( void ) {
  10895.     idEntity    *exitEnt;
  10896.     float        pushVel;
  10897.  
  10898.     // verify and setup
  10899.      exitEnt = teleportEntity;
  10900.      if ( !exitEnt ) {
  10901.         common->DPrintf( "Event_ExitTeleporter player %d while not being teleported\n", entityNumber );
  10902.         return;
  10903.     }
  10904.  
  10905.     pushVel = exitEnt->spawnArgs.GetFloat( "push", "300" );
  10906.  
  10907.      if ( gameLocal.isServer ) {
  10908.          ServerSendInstanceEvent( EVENT_EXIT_TELEPORTER, NULL, false, -1 );
  10909.        }
  10910.  
  10911.     SetPrivateCameraView( NULL );
  10912.     // setup origin and push according to the exit target
  10913.     SetOrigin( exitEnt->GetPhysics()->GetOrigin() + idVec3( 0, 0, CM_CLIP_EPSILON ) );
  10914.     SetViewAngles( exitEnt->GetPhysics()->GetAxis().ToAngles() );
  10915.     physicsObj.SetLinearVelocity( exitEnt->GetPhysics()->GetAxis()[ 0 ] * pushVel );
  10916.     physicsObj.ClearPushedVelocity( );
  10917.     // teleport fx
  10918.     playerView.Flash( colorWhite, 120 );
  10919.  
  10920.      // clear the ik heights so model doesn't appear in the wrong place
  10921.      walkIK.EnableAll();
  10922.  
  10923.     UpdateVisuals();
  10924.  
  10925.     gameLocal.PlayEffect ( spawnArgs, "fx_teleport", GetPhysics()->GetOrigin(), idVec3(0,0,1).ToMat3(), false, vec3_origin );
  10926.  
  10927.     StartSound( "snd_teleport_exit", SND_CHANNEL_ANY, 0, false, NULL );
  10928.  
  10929.     if ( teleportKiller != -1 ) {
  10930.         // we got killed while being teleported
  10931.         Damage( gameLocal.entities[ teleportKiller ], gameLocal.entities[ teleportKiller ], vec3_origin, "damage_telefrag", 1.0f, INVALID_JOINT );
  10932.         teleportKiller = -1;
  10933.     } else {
  10934.         // kill anything that would have waited at teleport exit
  10935.         gameLocal.KillBox( this );
  10936.     }
  10937.      teleportEntity = NULL;
  10938. }
  10939.  
  10940. /*
  10941. ===============
  10942. idPlayer::Event_DamageOverTimeEffect
  10943. ===============
  10944. */
  10945. void idPlayer::Event_DamageOverTimeEffect( int endTime, int interval, const char *damageDefName ) {
  10946.     const idDeclEntityDef *damageDef = gameLocal.FindEntityDef( damageDefName, false );
  10947.     if ( damageDef ) {
  10948.         rvClientCrawlEffect* effect;
  10949.  
  10950.         // mwhitlock: Dynamic memory consolidation
  10951.         RV_PUSH_SYS_HEAP_ID(RV_HEAP_ID_MULTIPLE_FRAME);
  10952.         effect = new rvClientCrawlEffect( gameLocal.GetEffect ( damageDef->dict, "fx_dot" ), GetWeaponViewModel(), interval );
  10953.         RV_POP_HEAP();
  10954.  
  10955.         effect->Play ( gameLocal.time, false );
  10956.         if ( endTime == -1 || gameLocal.GetTime() + interval <= endTime ) {
  10957.             //post it again
  10958.             PostEventMS( &EV_DamageOverTimeEffect, interval, endTime, interval, damageDefName );
  10959.         }
  10960.     }
  10961. }
  10962.  
  10963. /*
  10964. ===============
  10965. idPlayer::LocalClientPredictionThink
  10966. ===============
  10967. */
  10968. void idPlayer::LocalClientPredictionThink( void ) {
  10969.     renderEntity_t *headRenderEnt;
  10970.  
  10971. #if 0
  10972. // rjohnson: disabled because of too many string look ups
  10973.  
  10974. // RAVEN BEGIN
  10975. // shouchard:  profiling
  10976.     // probably the worst way to get the number of players evar
  10977.     if ( cvarSystem->GetCVarBool( "net_debugFrameTime" ) ) {
  10978.         int value = cvarSystem->GetCVarInteger( "net_debugPlayerCount" );
  10979.         value++;
  10980.         cvarSystem->SetCVarInteger( "net_debugPlayerCount", value );
  10981.     }
  10982. // RAVEN END
  10983. #endif
  10984.  
  10985.     oldFlags = usercmd.flags;
  10986.     oldButtons = usercmd.buttons;
  10987.  
  10988.     usercmd = gameLocal.usercmds[ entityNumber ];
  10989.  
  10990.     buttonMask &= usercmd.buttons;
  10991.     usercmd.buttons &= ~buttonMask;
  10992.  
  10993.     if ( idealWeapon != currentWeapon ) {
  10994.         usercmd.buttons &= ~BUTTON_ATTACK;        
  10995.     }
  10996.  
  10997.      // clear the ik before we do anything else so the skeleton doesn't get updated twice
  10998.      walkIK.ClearJointMods();
  10999.  
  11000.     if ( gameLocal.isNewFrame ) {
  11001.         if ( ( usercmd.flags & UCF_IMPULSE_SEQUENCE ) != ( oldFlags & UCF_IMPULSE_SEQUENCE ) ) {
  11002.             PerformImpulse( usercmd.impulse );
  11003.         }
  11004.     }
  11005.  
  11006.     if( forceScoreBoard && forceScoreBoardTime && gameLocal.time > forceScoreBoardTime ) {
  11007.         forceScoreBoardTime = 0;
  11008.         forceScoreBoard = false;
  11009.     }
  11010.     scoreBoardOpen = ( ( usercmd.buttons & BUTTON_SCORES ) != 0 || forceScoreBoard );
  11011.  
  11012.     // zooming
  11013.     bool zoom = (usercmd.buttons & BUTTON_ZOOM) && CanZoom();
  11014.     if ( zoom != zoomed ) {
  11015.         if ( zoom ) {
  11016.             ProcessEvent( &EV_Player_ZoomIn );
  11017.         } else {
  11018.             ProcessEvent( &EV_Player_ZoomOut );
  11019.         }
  11020.     }
  11021.  
  11022.     if ( IsInVehicle( ) ) {    
  11023.         vehicleController.SetInput( usercmd, viewAngles );
  11024.                 
  11025.         // calculate the exact bobbed view position, which is used to
  11026.         // position the view weapon, among other things
  11027.         CalculateFirstPersonView();
  11028.  
  11029.         // this may use firstPersonView, or a thirdPeoson / camera view
  11030.         CalculateRenderView();
  11031.  
  11032.         UpdateLocation();
  11033.  
  11034.         if ( !fl.hidden ) {
  11035.             UpdateAnimation();
  11036.             Present();
  11037.         }            
  11038.         
  11039.         return;
  11040.     }
  11041.  
  11042.     AdjustSpeed();
  11043.  
  11044.     UpdateViewAngles();
  11045.  
  11046. /*
  11047. // RAVEN BEGIN
  11048. // abahr
  11049.     if( !noclip && !spectating ) {
  11050.         UpdateGravity();
  11051.     }
  11052. // RAVEN END
  11053. */
  11054.  
  11055.      if ( !isLagged ) {
  11056.          // don't allow client to move when lagged
  11057.         predictedUpdated = false;
  11058.          Move();
  11059.      }
  11060.  
  11061.     // update GUIs, Items, and character interactions
  11062.     UpdateFocus();
  11063.  
  11064.     // service animations
  11065.      if ( !spectating && !af.IsActive() ) {
  11066.         UpdateConditions();
  11067.         UpdateAnimState();
  11068.         CheckBlink();
  11069.     }
  11070.  
  11071.     // clear out our pain flag so we can tell if we recieve any damage between now and the next time we think
  11072.     pfl.pain = false;
  11073.  
  11074.     if ( !af.IsActive() ) {
  11075.         AdjustBodyAngles();
  11076.     }
  11077.  
  11078.     // calculate the exact bobbed view position, which is used to
  11079.     // position the view weapon, among other things
  11080.     CalculateFirstPersonView();
  11081.  
  11082.     // this may use firstPersonView, or a thirdPerson / camera view
  11083.     CalculateRenderView();
  11084.  
  11085.      if ( !gameLocal.inCinematic && weaponViewModel && ( health > 0 ) && !( gameLocal.isMultiplayer && spectating ) ) {
  11086.         UpdateWeapon();
  11087.     }
  11088.  
  11089.     UpdateHud();
  11090.  
  11091.      if ( gameLocal.isNewFrame ) {
  11092.          UpdatePowerUps();
  11093.      }
  11094.  
  11095.      UpdateDeathSkin( false );
  11096.  
  11097.     UpdateDeathShader( deathStateHitch );
  11098.  
  11099.      if ( head.GetEntity() ) {
  11100.          headRenderEnt = head.GetEntity()->GetRenderEntity();
  11101.      } else {
  11102.          headRenderEnt = NULL;
  11103.      }
  11104.  
  11105.      if ( headRenderEnt ) {
  11106.         // in MP, powerup skin overrides influence     
  11107.         if ( powerUpSkin ) {
  11108.             headRenderEnt->customSkin = powerUpSkin;
  11109.         } else if ( influenceSkin ) {
  11110.             headRenderEnt->customSkin = influenceSkin;
  11111.         } else {
  11112.             headRenderEnt->customSkin = headSkin;
  11113.         }
  11114.      }
  11115.  
  11116.     // always show your own shadow
  11117.     renderEntity.suppressLOD = 1;
  11118.     if ( headRenderEnt ) {
  11119.         headRenderEnt->suppressLOD = 1;
  11120.     }
  11121.  
  11122.     DrawShadow( headRenderEnt );
  11123.  
  11124.     // never cast shadows from our first-person muzzle flashes
  11125.     // FIXME: flashlight too
  11126.     renderEntity.suppressShadowInLightID = rvWeapon::WPLIGHT_MUZZLEFLASH * 100 + entityNumber;
  11127.      if ( headRenderEnt ) {
  11128.          headRenderEnt->suppressShadowInLightID = renderEntity.suppressShadowInLightID;
  11129.        }
  11130.  
  11131.      if ( !gameLocal.inCinematic ) {
  11132.          UpdateAnimation();
  11133.      }
  11134.  
  11135.     Present();
  11136.  
  11137.      LinkCombat();
  11138. }
  11139.  
  11140. /*
  11141. ===============
  11142. idPlayer::NonLocalClientPredictionThink
  11143. ===============
  11144. */
  11145. #define LIMITED_PREDICTION        1
  11146.  
  11147. void idPlayer::NonLocalClientPredictionThink( void ) {
  11148.     renderEntity_t *headRenderEnt;
  11149.  
  11150. #if 0
  11151. // rjohnson: disabled because of too many string look ups
  11152.  
  11153. // RAVEN BEGIN
  11154. // shouchard:  profiling
  11155.     // probably the worst way to get the number of players evar
  11156.     if ( cvarSystem->GetCVarBool( "net_debugFrameTime" ) ) {
  11157.         int value = cvarSystem->GetCVarInteger( "net_debugPlayerCount" );
  11158.         value++;
  11159.         cvarSystem->SetCVarInteger( "net_debugPlayerCount", value );
  11160.     }
  11161. // RAVEN END
  11162. #endif
  11163.  
  11164.     oldFlags = usercmd.flags;
  11165.     oldButtons = usercmd.buttons;
  11166.  
  11167.     usercmd = gameLocal.usercmds[ entityNumber ];
  11168.  
  11169.     buttonMask &= usercmd.buttons;
  11170.     usercmd.buttons &= ~buttonMask;
  11171.  
  11172.     //jshepard: added this to make sure clients can see other clients and the host switching weapons
  11173.     if ( idealWeapon != currentWeapon )    {
  11174.         usercmd.buttons &= ~BUTTON_ATTACK;        
  11175.     }
  11176.  
  11177.      // clear the ik before we do anything else so the skeleton doesn't get updated twice
  11178.      walkIK.ClearJointMods();
  11179.  
  11180.     if ( gameLocal.isNewFrame ) {
  11181.         if ( ( usercmd.flags & UCF_IMPULSE_SEQUENCE ) != ( oldFlags & UCF_IMPULSE_SEQUENCE ) ) {
  11182.             PerformImpulse( usercmd.impulse );
  11183.         }
  11184.     }
  11185.  
  11186.     if ( forceScoreBoard && forceScoreBoardTime && gameLocal.time > forceScoreBoardTime ) {
  11187.         forceScoreBoardTime = 0;
  11188.         forceScoreBoard = false;
  11189.     }
  11190.     scoreBoardOpen = ( ( usercmd.buttons & BUTTON_SCORES ) != 0 || forceScoreBoard );
  11191.  
  11192.     // zooming
  11193.     bool zoom = (usercmd.buttons & BUTTON_ZOOM) && CanZoom();
  11194.     if ( zoom != zoomed ) {
  11195.         if ( zoom ) {
  11196.             ProcessEvent( &EV_Player_ZoomIn );
  11197.         } else {
  11198.             ProcessEvent( &EV_Player_ZoomOut );
  11199.         }
  11200.     }
  11201.  
  11202. #if !LIMITED_PREDICTION
  11203.     if ( IsInVehicle ( ) ) {    
  11204.         vehicleController.SetInput ( usercmd, viewAngles );
  11205.  
  11206.         // calculate the exact bobbed view position, which is used to
  11207.         // position the view weapon, among other things
  11208.         CalculateFirstPersonView();
  11209.  
  11210.         // this may use firstPersonView, or a thirdPeoson / camera view
  11211.         CalculateRenderView();
  11212.  
  11213.         UpdateLocation();
  11214.  
  11215.         if ( !fl.hidden ) {
  11216.             UpdateAnimation();
  11217.             Present();
  11218.         }            
  11219.         
  11220.         return;
  11221.     }
  11222. #endif
  11223.  
  11224.     AdjustSpeed();
  11225.  
  11226.     UpdateViewAngles();
  11227.  
  11228. /*
  11229. // RAVEN BEGIN
  11230. // abahr
  11231.     if( !noclip && !spectating ) {
  11232.         UpdateGravity();
  11233.     }
  11234. // RAVEN END
  11235. */
  11236.     if( gameLocal.isLastPredictFrame && jumpDuringHitch ) {
  11237.         StartSound( "snd_jump", (s_channelType)FC_SOUND, 0, false, NULL );
  11238.         jumpDuringHitch = false;
  11239.     }
  11240.  
  11241.     if ( !isLagged ) {
  11242.          // don't allow client to move when lagged
  11243.         predictedUpdated = false;
  11244.         // NOTE: only running on new frames causes prediction errors even when the input does not change!
  11245.         if ( gameLocal.isNewFrame ) {
  11246.              Move();
  11247.         } else {
  11248.             PredictionErrorDecay();
  11249.         }
  11250.      }
  11251.  
  11252. #if defined( _XENON ) || !LIMITED_PREDICTION
  11253.     // update GUIs, Items, and character interactions
  11254.     UpdateFocus();
  11255. #endif
  11256.  
  11257.     // service animations
  11258.      if ( !spectating && !af.IsActive() ) {
  11259.         UpdateConditions();
  11260.         UpdateAnimState();
  11261.         CheckBlink();
  11262.     }
  11263.  
  11264.     // clear out our pain flag so we can tell if we recieve any damage between now and the next time we think
  11265.     pfl.pain = false;
  11266.  
  11267.     if ( !af.IsActive() ) {
  11268.         AdjustBodyAngles();
  11269.     }
  11270.  
  11271.     // calculate the exact bobbed view position, which is used to
  11272.     // position the view weapon, among other things
  11273.     CalculateFirstPersonView();
  11274.  
  11275.      if ( !gameLocal.inCinematic && weaponViewModel && ( health > 0 ) && !( gameLocal.isMultiplayer && spectating ) ) {
  11276.         UpdateWeapon();
  11277.     }
  11278.  
  11279.     if ( gameLocal.isLastPredictFrame ) {
  11280.         // this may use firstPersonView, or a thirdPerson / camera view
  11281.         CalculateRenderView();
  11282.  
  11283.         UpdateHud();
  11284.          UpdatePowerUps();
  11285.      }
  11286.  
  11287. //#if !LIMITED_PREDICTION
  11288.      UpdateDeathSkin( false );
  11289.  
  11290.     UpdateDeathShader( deathStateHitch );
  11291. //#endif
  11292.  
  11293.      if ( head.GetEntity() ) {
  11294.          headRenderEnt = head.GetEntity()->GetRenderEntity();
  11295.      } else {
  11296.          headRenderEnt = NULL;
  11297.      }
  11298.  
  11299.     if ( headRenderEnt ) {
  11300.         // in MP, powerup skin overrides influence     
  11301.         if ( powerUpSkin ) {
  11302.             headRenderEnt->customSkin = powerUpSkin;
  11303.         } else if ( influenceSkin ) {
  11304.              headRenderEnt->customSkin = influenceSkin;
  11305.          } else {
  11306.              headRenderEnt->customSkin = headSkin;
  11307.          }
  11308.      }
  11309.  
  11310.     // always show your own shadow
  11311.     renderEntity.suppressLOD = 1;
  11312.     if ( headRenderEnt ) {
  11313.         headRenderEnt->suppressLOD = 1;
  11314.     }
  11315.  
  11316.     DrawShadow( headRenderEnt );
  11317.  
  11318.     // never cast shadows from our first-person muzzle flashes
  11319.     // FIXME: flashlight too
  11320.     renderEntity.suppressShadowInLightID = rvWeapon::WPLIGHT_MUZZLEFLASH * 100 + entityNumber;
  11321.      if ( headRenderEnt ) {
  11322.          headRenderEnt->suppressShadowInLightID = renderEntity.suppressShadowInLightID;
  11323.        }
  11324.  
  11325.      if ( !gameLocal.inCinematic ) {
  11326.          UpdateAnimation();
  11327.      }
  11328.  
  11329.     Present();
  11330.  
  11331.      LinkCombat();
  11332. }
  11333.  
  11334. /*
  11335. ================
  11336. idPlayer::ClientPredictionThink
  11337. ================
  11338. */
  11339. void idPlayer::ClientPredictionThink( void ) {
  11340.     
  11341.     if ( doInitWeapon ) {
  11342.         InitWeapon();
  11343.     }
  11344.     
  11345.     // common code for both the local & non local clients
  11346.     if ( reloadModel ) {
  11347.         LoadDeferredModel();
  11348.         reloadModel = false;
  11349.     }
  11350.  
  11351.     if ( entityNumber == gameLocal.localClientNum ) {
  11352.         LocalClientPredictionThink();
  11353.         return;
  11354.     }
  11355.  
  11356.     assert( gameLocal.localClientNum >= 0 );
  11357.     idPlayer *p = gameLocal.GetClientByNum( gameLocal.localClientNum );
  11358.     if ( p && p->spectating && p->spectator == entityNumber ) {
  11359.         LocalClientPredictionThink();
  11360.         return;
  11361.     }
  11362.  
  11363.     NonLocalClientPredictionThink();
  11364. }
  11365.  
  11366. /*
  11367. ================
  11368. idPlayer::GetMasterPosition
  11369. ================
  11370. */
  11371. bool idPlayer::GetMasterPosition( idVec3 &masterOrigin, idMat3 &masterAxis ) const {
  11372.     if( !IsInVehicle() ) {
  11373.         return idActor::GetMasterPosition( masterOrigin, masterAxis );    
  11374.     }
  11375.     
  11376.     vehicleController.GetDriverPosition( masterOrigin, masterAxis );
  11377.     return true;
  11378. }
  11379.  
  11380. /*
  11381. ===============
  11382. idPlayer::PredictionErrorDecay
  11383. ===============
  11384. */
  11385. void idPlayer::PredictionErrorDecay( void ) {
  11386.     if ( predictedUpdated ) {
  11387.         return;
  11388.     }
  11389.  
  11390.     if ( net_predictionErrorDecay.GetFloat() <= 0.0f ) {
  11391.         idMat3 renderAxis = viewAxis * GetPhysics()->GetAxis();
  11392.         idVec3 renderOrigin = GetPhysics()->GetOrigin() + modelOffset * renderAxis;
  11393.         predictedOrigin = renderOrigin;
  11394.         return;
  11395.     }
  11396.  
  11397.     if ( gameLocal.framenum >= predictedFrame ) {
  11398.         idMat3 renderAxis = viewAxis * GetPhysics()->GetAxis();
  11399.         idVec3 renderOrigin = GetPhysics()->GetOrigin() + modelOffset * renderAxis;
  11400.  
  11401.         if ( gameLocal.framenum == predictedFrame ) {
  11402.  
  11403.             predictionOriginError = predictedOrigin - renderOrigin;
  11404.             predictionAnglesError = predictedAngles - viewAngles;
  11405.             predictionAnglesError.Normalize180();
  11406.             predictionErrorTime = gameLocal.time;
  11407.  
  11408.             if ( net_showPredictionError.GetInteger() == entityNumber ) {
  11409.                 renderSystem->DebugGraph( predictionOriginError.Length(), 0.0f, 100.0f, colorGreen );
  11410.                 renderSystem->DebugGraph( predictionAnglesError.Length(), 0.0f, 180.0f, colorBlue );
  11411.             }
  11412.         }
  11413.  
  11414.         int t = gameLocal.time - predictionErrorTime;
  11415.         float f = ( net_predictionErrorDecay.GetFloat() - t ) / net_predictionErrorDecay.GetFloat();
  11416.         if ( f > 0.0f && f < 1.0f ) {
  11417.             predictedOrigin = renderOrigin + f * predictionOriginError;
  11418.             predictedAngles = viewAngles + f * predictionAnglesError;
  11419.             predictedAngles.Normalize180();
  11420.         } else {
  11421.             predictedOrigin = renderOrigin;
  11422.             predictedAngles = viewAngles;
  11423.         }
  11424.  
  11425.         predictedFrame = gameLocal.framenum;
  11426.  
  11427.     }
  11428.  
  11429.     viewAngles = predictedAngles;
  11430.     // adjust them now so they are right for the bound objects ( head and weapon )
  11431.     AdjustBodyAngles();
  11432.  
  11433.     predictedUpdated = true;
  11434. }
  11435.  
  11436. /*
  11437. ===============
  11438. idPlayer::WantSmoothing
  11439. ===============
  11440. */
  11441. bool idPlayer::WantSmoothing( void ) const {
  11442.     if ( !gameLocal.isClient ) {
  11443.         return false;
  11444.     }
  11445.     if ( net_predictionErrorDecay.GetFloat() <= 0.0f ) {
  11446.         return false;
  11447.     }
  11448.     // always on for self
  11449. /*
  11450.     if ( entityNumber == gameLocal.localClientNum ) {
  11451.         return false;
  11452.     }
  11453. */
  11454.     return true;
  11455. }
  11456.  
  11457. /*
  11458. ================
  11459. idPlayer::GetPhysicsToVisualTransform
  11460. ================
  11461. */
  11462. bool idPlayer::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
  11463.     if ( af.IsActive() ) {
  11464.         af.GetPhysicsToVisualTransform( origin, axis );
  11465.         return true;
  11466.     }
  11467.  
  11468.     if ( vehicleController.IsDriving() ) {
  11469.         vehicleController.GetDriverPosition( origin, axis );
  11470.         origin.Zero();
  11471.         return true;
  11472.     }
  11473.  
  11474.     PredictionErrorDecay();
  11475.  
  11476.     // smoothen the rendered origin and angles of other clients
  11477.     if ( gameLocal.framenum >= predictedFrame && WantSmoothing() ) {
  11478.  
  11479.         axis = idAngles( 0.0f, predictedAngles.yaw, 0.0f ).ToMat3();
  11480.         origin = ( predictedOrigin - GetPhysics()->GetOrigin() ) * axis.Transpose();
  11481.  
  11482.     } else {
  11483.  
  11484.         axis = viewAxis;
  11485.         origin = modelOffset;
  11486.  
  11487.     }
  11488.  
  11489.     return true;
  11490. }
  11491.  
  11492. /*
  11493. ================
  11494. idPlayer::GetPhysicsToSoundTransform
  11495. ================
  11496. */
  11497. bool idPlayer::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
  11498.     idCamera *camera;
  11499.  
  11500.     if ( privateCameraView ) {
  11501.         camera = privateCameraView;
  11502.     } else {
  11503.         camera = gameLocal.GetCamera();
  11504.     }
  11505.  
  11506.     if ( camera ) {
  11507.         renderView_t view;
  11508.  
  11509.         memset( &view, 0, sizeof( view ) );
  11510.         camera->GetViewParms( &view );
  11511.         origin = view.vieworg;
  11512.         axis = view.viewaxis;
  11513.         return true;
  11514.     } else {
  11515.         return idActor::GetPhysicsToSoundTransform( origin, axis );
  11516.     }
  11517. }
  11518.  
  11519. /*
  11520. ================
  11521. idPlayer::WriteToSnapshot
  11522. ================
  11523. */
  11524. void idPlayer::WriteToSnapshot( idBitMsgDelta &msg ) const {
  11525.     physicsObj.WriteToSnapshot( msg );
  11526.     WriteBindToSnapshot( msg );
  11527.     msg.WriteDeltaFloat( 0.0f, deltaViewAngles[0] );
  11528.     msg.WriteDeltaFloat( 0.0f, deltaViewAngles[1] );
  11529.     msg.WriteDeltaFloat( 0.0f, deltaViewAngles[2] );
  11530.     msg.WriteShort( health );
  11531.      msg.WriteBits( lastDamageDef, gameLocal.entityDefBits );
  11532.     msg.WriteDir( lastDamageDir, 9 );
  11533.     msg.WriteShort( lastDamageLocation );
  11534.     msg.WriteBits( idealWeapon, idMath::BitsForInteger( MAX_WEAPONS ) );
  11535.     msg.WriteBits( inventory.weapons, MAX_WEAPONS );
  11536.     msg.WriteBits( weaponViewModel.GetSpawnId(), 32 );
  11537.     msg.WriteBits( weaponWorldModel.GetSpawnId(), 32 );
  11538.     msg.WriteBits( head.GetSpawnId(), 32 );
  11539.     msg.WriteBits( spectator, idMath::BitsForInteger( MAX_CLIENTS ) );
  11540.     msg.WriteBits( lastHitToggle, 1 );
  11541.     msg.WriteBits( lastArmorHit, 1 );
  11542.      msg.WriteBits( weaponGone, 1 );
  11543.      msg.WriteBits( isLagged, 1 );
  11544.      msg.WriteBits( isChatting, 1 );
  11545.     msg.WriteLong( connectTime );
  11546.     msg.WriteByte( lastKiller ? lastKiller->entityNumber : 255 );
  11547.      
  11548.     //     vehicleController.WriteToSnapshot( msg );
  11549.      
  11550.      if ( weapon ) {
  11551.          msg.WriteBits( 1, 1 );
  11552.          weapon->WriteToSnapshot( msg );
  11553.      } else {
  11554.          msg.WriteBits( 0, 1 );
  11555.      }
  11556. }
  11557.  
  11558. /*
  11559. ================
  11560. idPlayer::ReadFromSnapshot
  11561. ================
  11562. */
  11563. void idPlayer::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  11564.      int        i, oldHealth, newIdealWeapon, weaponSpawnId, weaponWorldSpawnId, headSpawnId;
  11565.      bool    newHitToggle, stateHitch, newHitArmor;
  11566.     int        lastKillerEntity;
  11567.  
  11568.      if ( snapshotSequence - lastSnapshotSequence > 1 ) {
  11569.          stateHitch = true;
  11570.      } else {
  11571.          stateHitch = false;
  11572.      }
  11573.      lastSnapshotSequence = snapshotSequence;
  11574.  
  11575.     oldHealth = health;
  11576.  
  11577.     physicsObj.ReadFromSnapshot( msg );
  11578.     ReadBindFromSnapshot( msg );
  11579. ///    if( gameLocal.localClientNum == entityNumber ) {
  11580. //        gameLocal.Printf( "BEFORE delta view: %s\n", deltaViewAngles.ToString() );
  11581. //    }
  11582.     deltaViewAngles[0] = msg.ReadDeltaFloat( 0.0f );
  11583.     deltaViewAngles[1] = msg.ReadDeltaFloat( 0.0f );
  11584.     deltaViewAngles[2] = msg.ReadDeltaFloat( 0.0f );
  11585. //    if( gameLocal.localClientNum == entityNumber ) {
  11586. //        gameLocal.Printf( "AFTER delta view: %s\n", deltaViewAngles.ToString() );
  11587. //    }
  11588.     health = msg.ReadShort();
  11589.      lastDamageDef = msg.ReadBits( gameLocal.entityDefBits );
  11590.     lastDamageDir = msg.ReadDir( 9 );
  11591.     lastDamageLocation = msg.ReadShort();
  11592.     newIdealWeapon = msg.ReadBits( idMath::BitsForInteger( MAX_WEAPONS ) );
  11593.     inventory.weapons = msg.ReadBits( MAX_WEAPONS );
  11594.      weaponSpawnId = msg.ReadBits( 32 );
  11595.      weaponWorldSpawnId = msg.ReadBits( 32 );
  11596.     headSpawnId = msg.ReadBits( 32 );
  11597.     int latchedSpectator = spectator;
  11598.     spectator = msg.ReadBits( idMath::BitsForInteger( MAX_CLIENTS ) );
  11599.     if ( spectating && latchedSpectator != spectator && this == gameLocal.GetLocalPlayer() ) {
  11600.         // don't do any smoothing with this snapshot
  11601.         predictedFrame = gameLocal.framenum;
  11602.         // this is where the client updates their spectated player
  11603.         if ( gameLocal.gameType == GAME_TOURNEY ) {
  11604.             rvTourneyArena& arena = ((rvTourneyGameState*)gameLocal.mpGame.GetGameState())->GetArena( GetArena() );
  11605.  
  11606.             if( arena.GetPlayers()[ 0 ] == NULL || arena.GetPlayers()[ 1 ] == NULL || (spectator != arena.GetPlayers()[ 0 ]->entityNumber && spectator != arena.GetPlayers()[ 1 ]->entityNumber) ) {
  11607.                 gameLocal.mpGame.tourneyGUI.ArenaSelect( GetArena(), TGH_BRACKET );
  11608.             } else if( spectator == arena.GetPlayers()[ 0 ]->entityNumber ) {
  11609.                 gameLocal.mpGame.tourneyGUI.ArenaSelect( GetArena(), TGH_PLAYER_ONE );
  11610.             } else if( spectator == arena.GetPlayers()[ 1 ]->entityNumber ) {
  11611.                 gameLocal.mpGame.tourneyGUI.ArenaSelect( GetArena(), TGH_PLAYER_TWO );
  11612.             }
  11613.  
  11614.             gameLocal.mpGame.tourneyGUI.UpdateScores();
  11615.         }
  11616.  
  11617.         if ( gameLocal.entities[ spectator ] ) {
  11618.             idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ spectator ] );
  11619.             p->UpdateHudWeapon( p->currentWeapon );
  11620.         }
  11621.     }
  11622.      newHitToggle = msg.ReadBits( 1 ) != 0;
  11623.     newHitArmor = msg.ReadBits( 1 ) != 0;
  11624.      weaponGone = msg.ReadBits( 1 ) != 0;
  11625.      isLagged = msg.ReadBits( 1 ) != 0;
  11626.      isChatting = msg.ReadBits( 1 ) != 0;
  11627.     connectTime = msg.ReadLong();
  11628.     lastKillerEntity = msg.ReadByte();
  11629.     if( lastKillerEntity >= 0 && lastKillerEntity < MAX_CLIENTS)    {
  11630.         lastKiller = static_cast<idPlayer *>(gameLocal.entities[ lastKillerEntity ]);
  11631.     } else {
  11632.         lastKiller = NULL;
  11633.     }
  11634.     
  11635.     if ( idealWeapon != newIdealWeapon ) {
  11636.         if ( stateHitch ) {
  11637.             weaponCatchup = true;
  11638.         }
  11639.         idealWeapon = newIdealWeapon;
  11640.         StopFiring();
  11641.         UpdateHudWeapon();
  11642.         usercmd.buttons &= (~BUTTON_ATTACK);        
  11643.     }
  11644.  
  11645.     // Attach the world and view entities  
  11646.     weaponWorldModel.SetSpawnId( weaponWorldSpawnId );
  11647.     if ( weaponViewModel.SetSpawnId( weaponSpawnId ) ) {
  11648.         currentWeapon = -1;
  11649.         SetWeapon( idealWeapon );
  11650.     }
  11651.  
  11652.     // rjohnson: instance persistance information
  11653.     if ( weaponWorldModel.IsValid() ) {
  11654.         weaponWorldModel->fl.persistAcrossInstances = true;
  11655.         weaponWorldModel->SetInstance( GetInstance() );
  11656.     }
  11657.     if ( weaponViewModel.IsValid() ) {
  11658.         weaponViewModel->fl.persistAcrossInstances = true;
  11659.         weaponViewModel->SetInstance( GetInstance() );
  11660.     }
  11661.  
  11662.     // If we have a weapon then update it from the snapshot, otherwise
  11663.     // we just skip whatever it would have read if it were there
  11664.     if ( msg.ReadBits( 1 ) ) {
  11665.         if ( weapon ) {
  11666.             weapon->ReadFromSnapshot( msg );
  11667.         } else {
  11668.             rvWeapon::SkipFromSnapshot( msg );
  11669.         }
  11670.     }
  11671.  
  11672.      // no msg reading below this
  11673.     
  11674.     // if not a local client assume the client has all ammo types
  11675.     if ( entityNumber != gameLocal.localClientNum ) {
  11676.         for( i = 0; i < MAX_AMMO; i++ ) {
  11677.             inventory.ammo[ i ] = 999;
  11678.         }
  11679.     }
  11680.  
  11681.     if ( oldHealth > 0 && health <= 0 ) {
  11682.          if ( stateHitch ) {
  11683.              // so we just hide and don't show a death skin
  11684.              UpdateDeathSkin( true );
  11685.          }
  11686.         // die
  11687.         pfl.dead = true;
  11688.         ClearPowerUps();
  11689.         SetAnimState( ANIMCHANNEL_LEGS, "Legs_Dead", 4 );
  11690.         SetAnimState( ANIMCHANNEL_TORSO, "Torso_Dead", 4 );
  11691.         animator.ClearAllJoints();
  11692.         StartRagdoll();
  11693.         physicsObj.SetMovementType( PM_DEAD );
  11694.          if ( !stateHitch ) {
  11695.              StartSound( "snd_death", SND_CHANNEL_VOICE, 0, false, NULL );
  11696.          }
  11697.         
  11698.         const idDeclEntityDef* def = static_cast<const idDeclEntityDef*>(declManager->DeclByIndex ( DECL_ENTITYDEF, lastDamageDef ));
  11699.         if ( def ) {        
  11700.             // TODO: get attackers push scale?
  11701.             InitDeathPush ( lastDamageDir, lastDamageLocation, &def->dict, 1.0f );
  11702.         }
  11703.  
  11704.         //gib them here
  11705.         if ( health < -20 || ( lastKiller && lastKiller->PowerUpActive( POWERUP_QUADDAMAGE )) )    {    
  11706.             ClientGib( lastDamageDir );
  11707.         }        
  11708.  
  11709.         if ( weapon ) {
  11710.             weapon->OwnerDied();
  11711.  
  11712.             // Get rid of the weapon now
  11713.             delete weapon;
  11714.             weapon = NULL;
  11715.             currentWeapon = -1;            
  11716.         }
  11717.     } else if ( oldHealth <= 0 && health > 0 ) {
  11718.          // respawn
  11719.         common->DPrintf( "idPlayer::ReadFromSnapshot() - Player respawn detected for %d '%s' - re-enabling clip\n", entityNumber, GetUserInfo()->GetString( "ui_name" ) );
  11720.  
  11721.         // this is the first time we've seen the player since we heard he died - he may have picked up
  11722.         // some powerups since he actually spawned in, so restore those
  11723.         int latchPowerup = inventory.powerups;
  11724.         Init();
  11725.         inventory.powerups = latchPowerup;
  11726.         StopRagdoll();
  11727.         SetPhysics( &physicsObj );
  11728.         physicsObj.EnableClip();
  11729.         SetCombatContents( true );
  11730.     } else if ( oldHealth - health > 2 && health > 0 ) {
  11731.          if ( stateHitch ) {
  11732.             lastDmgTime = gameLocal.time;
  11733.            } else {
  11734.              // damage feedback
  11735.              const idDeclEntityDef *def = static_cast<const idDeclEntityDef *>( declManager->DeclByIndex( DECL_ENTITYDEF, lastDamageDef, false ) );
  11736.              if ( def ) {
  11737.                  ClientDamageEffects ( def->dict, lastDamageDir, oldHealth - health );
  11738.                  pfl.pain = Pain( NULL, NULL, oldHealth - health, lastDamageDir, lastDamageLocation );
  11739.                  lastDmgTime = gameLocal.time;
  11740.              } else {
  11741.                  common->Warning( "NET: no damage def for damage feedback '%d'\n", lastDamageDef );
  11742.              }
  11743.         }
  11744.     }
  11745.  
  11746.      if ( lastHitToggle != newHitToggle ) {
  11747.         SetLastHitTime( gameLocal.realClientTime, newHitArmor );
  11748.     }
  11749.     
  11750.     if ( msg.HasChanged() ) {
  11751.         UpdateVisuals();
  11752.     }
  11753.  
  11754.     if ( (head == NULL || headSpawnId != head.GetSpawnId()) && headSpawnId > 0 ) {
  11755.         head.SetSpawnId( headSpawnId );
  11756.         SetupHead();
  11757.     }
  11758. }
  11759.  
  11760. /*
  11761. ================
  11762. idPlayer::WritePlayerStateToSnapshot
  11763. ================
  11764. */
  11765. void idPlayer::WritePlayerStateToSnapshot( idBitMsgDelta &msg ) const {
  11766.     int i;
  11767.  
  11768.     msg.WriteDeltaByte( 0, bobCycle );
  11769.     msg.WriteDeltaLong( 0, stepUpTime );
  11770.     msg.WriteDeltaFloat( 0.0f, stepUpDelta );
  11771.  
  11772.     msg.WriteShort( inventory.weapons );
  11773.     msg.WriteByte( inventory.armor );
  11774.     msg.WriteShort( inventory.powerups );
  11775.  
  11776.     for( i = 0; i < MAX_AMMO; i++ ) {
  11777.         msg.WriteBits( inventory.ammo[i], ASYNC_PLAYER_INV_AMMO_BITS );
  11778.     }
  11779.  
  11780.     for( i = 0; i < POWERUP_MAX; i ++ ) {
  11781.         msg.WriteLong( inventory.powerupEndTime[ i ] );
  11782.     }
  11783. }
  11784.  
  11785. /*
  11786. ================
  11787. idPlayer::ReadPlayerStateFromSnapshot
  11788. ================
  11789. */
  11790. void idPlayer::ReadPlayerStateFromSnapshot( const idBitMsgDelta &msg ) {
  11791.     int i, ammo;
  11792.  
  11793.     bobCycle = msg.ReadDeltaByte( 0 );
  11794.     stepUpTime = msg.ReadDeltaLong( 0 );
  11795.     stepUpDelta = msg.ReadDeltaFloat( 0.0f );
  11796.  
  11797.     inventory.weapons = msg.ReadShort();
  11798.     inventory.armor = msg.ReadByte();
  11799.     inventory.powerups = msg.ReadShort();
  11800.  
  11801.     for( i = 0; i < MAX_AMMO; i++ ) {
  11802.          ammo = msg.ReadBits( ASYNC_PLAYER_INV_AMMO_BITS );
  11803.          if ( gameLocal.time >= inventory.ammoPredictTime ) {
  11804.              inventory.ammo[ i ] = ammo;
  11805.          }
  11806.     }
  11807.  
  11808.     for( i = 0; i < POWERUP_MAX; i ++ ) {
  11809.         inventory.powerupEndTime[ i ] = msg.ReadLong();
  11810.     }
  11811.  
  11812.     if ( gameLocal.IsMultiplayer() ) {
  11813.         if ( (inventory.weapons&~oldInventoryWeapons)  ) {
  11814.             //added a weapon from inventory, bring up bar
  11815.             UpdateHudWeapon();
  11816.         }
  11817.         oldInventoryWeapons = inventory.weapons;
  11818.     }
  11819. }
  11820.  
  11821. /*
  11822. ================
  11823. idPlayer::ServerReceiveEvent
  11824. ================
  11825. */
  11826. bool idPlayer::ServerReceiveEvent( int event, int time, const idBitMsg &msg ) {
  11827.  
  11828.     if ( idEntity::ServerReceiveEvent( event, time, msg ) ) {
  11829.         return true;
  11830.     }
  11831.  
  11832.     // client->server events
  11833.     switch( event ) {
  11834.         case EVENT_IMPULSE: {
  11835.             PerformImpulse( msg.ReadBits( 6 ) );
  11836.             return true;
  11837.         }
  11838.         case EVENT_EMOTE: {
  11839.             // forward the emote on to all clients except the one that sent it to us
  11840.             ServerSendInstanceEvent( EVENT_EMOTE, &msg, false, entityNumber );
  11841.  
  11842.             // Set the emote locally
  11843.             SetEmote( (playerEmote_t)msg.ReadByte() );
  11844.             
  11845.             return true;
  11846.         }
  11847.         default: {
  11848.             return false;
  11849.         }
  11850.     }
  11851. }
  11852.  
  11853. /*
  11854. ================
  11855. idPlayer::ClientReceiveEvent
  11856. ================
  11857. */
  11858. bool idPlayer::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  11859.      int powerup;
  11860.     bool start;
  11861.  
  11862.     switch ( event ) {
  11863.         case EVENT_EXIT_TELEPORTER:
  11864.             Event_ExitTeleporter();
  11865.             return true;
  11866.          case EVENT_ABORT_TELEPORTER:
  11867.              SetPrivateCameraView( NULL );
  11868.              return true;
  11869.          case EVENT_POWERUP: {
  11870.              powerup = msg.ReadShort();
  11871.              start = msg.ReadBits( 1 ) != 0;
  11872.              if ( start ) {
  11873.                  GivePowerUp( powerup, 0 );
  11874.              } else {
  11875.                  ClearPowerup( powerup );
  11876.              }    
  11877.  
  11878.              return true;
  11879.          }
  11880.          case EVENT_SPECTATE: {
  11881.              bool spectate = ( msg.ReadBits( 1 ) != 0 );
  11882.             // force to spectator if we got this event about a client in a different
  11883.             // instance
  11884.              Spectate( spectate );
  11885.  
  11886.             // spectate might re-link clip for stale players, so re-call ClientStale if we're stale
  11887.             if( fl.networkStale ) {
  11888.                 ClientStale();    
  11889.             }
  11890.                return true;
  11891.          }
  11892.          case EVENT_ADD_DAMAGE_EFFECT: {
  11893.              if ( spectating ) {
  11894.                  // if we're spectating, ignore
  11895.                  // happens if the event and the spectate change are written on the server during the same frame (fraglimit)
  11896.                  return true;
  11897.              }
  11898.              return idActor::ClientReceiveEvent( event, time, msg );
  11899.          }
  11900.         case EVENT_EMOTE: {
  11901.             // Set the emote locally
  11902.             SetEmote( (playerEmote_t)msg.ReadByte() );
  11903.  
  11904.             return true;
  11905.         }
  11906.          default: {
  11907.             return idActor::ClientReceiveEvent( event, time, msg );
  11908.         }
  11909.     }
  11910. //unreachable
  11911. //    return false;
  11912. }
  11913.  
  11914. /*
  11915. ================
  11916. idPlayer::Hide
  11917. ================
  11918. */
  11919. void idPlayer::Hide( void ) {
  11920.     idActor::Hide();
  11921.     
  11922.     if ( weapon ) {
  11923.         weapon->HideWorldModel( );
  11924.     }
  11925. }
  11926.  
  11927. /*
  11928. ================
  11929. idPlayer::Show
  11930. ================
  11931. */
  11932. void idPlayer::Show( void ) {
  11933.     idActor::Show();
  11934.  
  11935.     if ( weapon ) {
  11936.         weapon->ShowWorldModel( );
  11937.     }
  11938. }
  11939.  
  11940. /*
  11941. ===============
  11942. idPlayer::ShowTip
  11943. ===============
  11944. */
  11945. void idPlayer::ShowTip( const char *title, const char *tip, bool autoHide ) {
  11946.     if ( tipUp ) {
  11947.         return;
  11948.     }
  11949.     hud->SetStateString( "tip", tip );
  11950.     hud->SetStateString( "tiptitle", title );
  11951.     hud->HandleNamedEvent( "tipWindowUp" ); 
  11952.     if ( autoHide ) {
  11953.         PostEventSec( &EV_Player_HideTip, 5.0f );
  11954.     }
  11955.     tipUp = true;
  11956. }
  11957.  
  11958. /*
  11959. ===============
  11960. idPlayer::HideTip
  11961. ===============
  11962. */
  11963. void idPlayer::HideTip( void ) {
  11964.     hud->HandleNamedEvent( "tipWindowDown" ); 
  11965.     tipUp = false;
  11966. }
  11967.  
  11968. /*
  11969. ===============
  11970. idPlayer::Event_HideTip
  11971. ===============
  11972. */
  11973. void idPlayer::Event_HideTip( void ) {
  11974.     HideTip();
  11975. }
  11976.  
  11977. /*
  11978. ===============
  11979. idPlayer::ShowObjective
  11980. ===============
  11981. */
  11982. void idPlayer::ShowObjective( const char *obj ) {
  11983.     objectiveSystem->HandleNamedEvent( obj );
  11984.     objectiveUp = true;
  11985. }
  11986.  
  11987.  
  11988. /*
  11989. ===============
  11990. idPlayer::HideObjective
  11991. ===============
  11992. */
  11993. void idPlayer::HideObjective( void ) {
  11994.     objectiveSystem->HandleNamedEvent( "closeObjective" );
  11995.     objectiveUp = false;
  11996. }
  11997.  
  11998. /*
  11999. ===============
  12000. idPlayer::SetSpectateOrigin
  12001. ===============
  12002. */
  12003. void idPlayer::SetSpectateOrigin( void ) {
  12004.     idVec3 neworig;
  12005.  
  12006.     neworig = GetPhysics()->GetOrigin();
  12007.     neworig[ 2 ] += EyeHeight();
  12008.     neworig[ 2 ] += 25;
  12009.     SetOrigin( neworig );
  12010. }
  12011.  
  12012. /*
  12013. ===============
  12014. idPlayer::RemoveWeapon
  12015. ===============
  12016. */
  12017. void idPlayer::RemoveWeapon( const char *weap ) {
  12018.     if ( weap && *weap ) {
  12019.         inventory.Drop( spawnArgs, spawnArgs.GetString( weap ), -1 );
  12020.     }
  12021. }
  12022.  
  12023. /*
  12024. ===============
  12025. idPlayer::CanShowWeaponViewmodel
  12026. ===============
  12027. */
  12028. bool idPlayer::CanShowWeaponViewmodel( void ) const {
  12029.      return showWeaponViewModel;
  12030. }
  12031.  
  12032. /*
  12033. ===============
  12034. idPlayer::SetLevelTrigger
  12035. ===============
  12036. */
  12037. void idPlayer::SetLevelTrigger( const char *levelName, const char *triggerName ) {
  12038.     if ( levelName && *levelName && triggerName && *triggerName ) {
  12039.         idLevelTriggerInfo lti;
  12040.         lti.levelName = levelName;
  12041.         lti.triggerName = triggerName;
  12042.         inventory.levelTriggers.Append( lti );
  12043.     }
  12044. }
  12045.  
  12046.  
  12047. /*
  12048. ===============
  12049. idPlayer::Event_LevelTrigger
  12050. ===============
  12051. */
  12052. void idPlayer::Event_LevelTrigger( void ) {
  12053.     idStr mapName = gameLocal.GetMapName();
  12054.     mapName.StripPath();
  12055.     mapName.StripFileExtension();
  12056.     for ( int i = inventory.levelTriggers.Num() - 1; i >= 0; i-- ) {
  12057.         if ( idStr::Icmp( mapName, inventory.levelTriggers[i].levelName) == 0 ){
  12058.             idEntity *ent = gameLocal.FindEntity( inventory.levelTriggers[i].triggerName );
  12059.             if ( ent ) {
  12060.                 ent->PostEventMS( &EV_Activate, 1, this );
  12061.             }
  12062.         }
  12063.     }
  12064. }
  12065.  
  12066. /*
  12067. ================
  12068. idPlayer::ToggleFlashlight
  12069. ================
  12070. */
  12071. void idPlayer::ToggleFlashlight ( void ) {
  12072.     // Dead people can use flashlights
  12073. // RAVEN BEGIN
  12074. // mekberg: check to see if the weapon is enabled.
  12075.     if ( health <= 0 || !weaponEnabled ) {
  12076.         return;
  12077.     }
  12078. // RAVEN END
  12079.  
  12080.     int flashlightWeapon = currentWeapon;
  12081.     if ( !spawnArgs.GetBool( va( "weapon%d_flashlight", flashlightWeapon ) ) ) {
  12082.         // TODO: find the first flashlight weapon that has ammo starting at the bottom
  12083.         for( flashlightWeapon = MAX_WEAPONS - 1; flashlightWeapon >= 0; flashlightWeapon-- ) {
  12084.             if ( inventory.weapons & ( 1 << flashlightWeapon ) ) {
  12085.                 const char *weap = spawnArgs.GetString( va( "def_weapon%d", flashlightWeapon ) );
  12086.                 int            ammo = inventory.ammo[inventory.AmmoIndexForWeaponClass ( weap ) ];
  12087.  
  12088.                 if ( !ammo ) {
  12089.                     continue;
  12090.                 }
  12091.  
  12092.                 if ( spawnArgs.GetBool ( va ( "weapon%d_flashlight", flashlightWeapon ) ) ) {
  12093.                     break;
  12094.                 }
  12095.             }
  12096.         }
  12097.         
  12098.         // Couldnt find flashlight
  12099.         if ( flashlightWeapon < 0 ) {
  12100.             return;
  12101.         }
  12102.     }
  12103.  
  12104.     // If the current weapon isnt the flashlight then always force the flashlight on
  12105.     if ( flashlightWeapon != idealWeapon ) {
  12106.         flashlightOn = true;
  12107.         idealWeapon = flashlightWeapon;
  12108.     // Inform the weapon to toggle the flashlight, this will eventually cause the players
  12109.     // Flashlight method to be called 
  12110.     } else if ( weapon ) {
  12111.         weapon->Flashlight ( );
  12112.     }
  12113. }
  12114.  
  12115. /*
  12116. ================
  12117. idPlayer::Flashlight
  12118. ================
  12119. */
  12120. void idPlayer::Flashlight ( bool on ) {
  12121.     flashlightOn = on;    
  12122. }
  12123.  
  12124. /*
  12125. ================
  12126. idPlayer::DamageFeedback
  12127. ================
  12128. */
  12129. void idPlayer::DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage ) {
  12130.     
  12131.     //rvTramCars weren't built on the idActor inheritance hierarchy but need to be treated like one when shot.
  12132.     //TODO: Maybe add a key to entity flags that will allow them to be shot as actors even if they aren't actors?
  12133.     if( !victim || ( !victim->IsType( idActor::GetClassType() ) && !victim->IsType( rvTramCar::GetClassType() ) ) || victim->health <= 0 ) {
  12134.         return;
  12135.     }
  12136.  
  12137.     bool armorHit = false;
  12138.  
  12139.     if( gameLocal.isMultiplayer && victim->IsType( idPlayer::GetClassType() ) ) {
  12140.         if( this == victim ) {
  12141.             // no feedback for self hits
  12142.             return;
  12143.         }
  12144.         if( gameLocal.IsTeamGame() && ((idPlayer*)victim)->team == team ) {
  12145.             // no feedback for team hits
  12146.             return;
  12147.         }
  12148.         if( ((idPlayer*)victim)->inventory.armor > 0 ) {
  12149.             armorHit = true;
  12150.         }
  12151.     } 
  12152.  
  12153.     SetLastHitTime( gameLocal.time, armorHit );
  12154. }
  12155.  
  12156. /*
  12157. ==============
  12158. idPlayer::GetWeaponDef
  12159. ==============
  12160. */
  12161. const idDeclEntityDef* idPlayer::GetWeaponDef ( int weaponIndex ) {
  12162.     if ( cachedWeaponDefs[weaponIndex] ) {
  12163.         return cachedWeaponDefs[weaponIndex];
  12164.     }
  12165.  
  12166.     idStr weapon;
  12167.     weapon = spawnArgs.GetString ( va("def_weapon%d", weaponIndex ) );
  12168.     if ( !weapon.Length() ) {
  12169.         return NULL;
  12170.     }
  12171.         
  12172.     cachedWeaponDefs[weaponIndex] = gameLocal.FindEntityDef ( weapon, false );
  12173.     if ( !cachedWeaponDefs[weaponIndex] ) {
  12174.         gameLocal.Error( "Could not find weapon definition '%s'", weapon.c_str() );
  12175.     }    
  12176.     
  12177.     return cachedWeaponDefs[weaponIndex];
  12178. }
  12179.  
  12180. /*
  12181. ==============
  12182. idPlayer::GetPowerupDef
  12183.  
  12184. Returns the powerup dictionary for the given powerup index.  The dictionary is cached to ensure a
  12185. speedy retrieval after the first call.
  12186. ==============
  12187. */
  12188. const idDeclEntityDef* idPlayer::GetPowerupDef ( int powerupIndex ) {
  12189.     const idDict* types;
  12190.     int              i;
  12191.     int              num;
  12192.     
  12193.     if ( cachedPowerupDefs[powerupIndex] ) {
  12194.         return cachedPowerupDefs[powerupIndex];
  12195.     }
  12196.     
  12197.     types = gameLocal.FindEntityDefDict( "powerup_types", false );
  12198.     if ( !types ) {
  12199.         gameLocal.Error( "Could not find entity definition for 'powerup_types'" );
  12200.     }
  12201.     
  12202.     num = types->GetNumKeyVals();
  12203.     for( i = 0; i < num; i++ ) {
  12204.         const idKeyValue* kv;
  12205.         kv = types->GetKeyVal( i );
  12206.         if ( atoi(kv->GetValue()) == powerupIndex ) {
  12207.             cachedPowerupDefs[powerupIndex] = gameLocal.FindEntityDef ( kv->GetKey(), false );
  12208.             if ( !cachedPowerupDefs[powerupIndex] ) {
  12209.                 gameLocal.Error( "Could not find powerup definition '%s'", kv->GetKey().c_str() );
  12210.             }
  12211.             return cachedPowerupDefs[powerupIndex];
  12212.         }
  12213.     }    
  12214.     
  12215.     gameLocal.Error( "Could not find powerup definition '%d'", powerupIndex );
  12216.     
  12217.     return NULL;
  12218. }
  12219.  
  12220. /*
  12221. ==============
  12222. idPlayer::discoverSecretArea
  12223.  
  12224. Announces a secret area and increases the secret area tally
  12225. ==============
  12226. */
  12227. void idPlayer::DiscoverSecretArea(const char* _description)    {
  12228.  
  12229.     //increment the secret area tally
  12230.     inventory.secretAreasDiscovered++;
  12231.  
  12232. /*    // FIXME: For now, this is how we can indicate secret areas. We can come up
  12233.     // with a different method later, although keeping it as part of the database
  12234.     // GUI would be less disruptive to the game atmosphere.
  12235.     
  12236.     if ( hud && g_showHudPopups.GetBool ( ) ) {
  12237.         hud->SetStateString( "dbEntry", "1" );
  12238.         hud->SetStateString( "dbEntryTitle", "Secret Area Discovered" );
  12239.         hud->SetStateString( "dbEntryText", _description );
  12240. //        hud->SetStateString( "dbEntryImage", dbEntry.image );
  12241.         hud->HandleNamedEvent( "newDatabaseEntry" );
  12242.  
  12243. //        PostEventMS( &EV_Player_HideDatabaseEntry, 2000 );
  12244.     }
  12245. */
  12246. }
  12247.  
  12248. /*
  12249. ==============
  12250. idPlayer::StartBossBattle
  12251.  
  12252. Starts a boss battle with the given entity.  During a boss battle the health of the boss 
  12253. will be displayed on the HUD
  12254. ==============
  12255. */
  12256. void idPlayer::StartBossBattle ( idEntity* enemy ) {
  12257.     bossEnemy = enemy;
  12258.     idUserInterface *hud_ = GetHud();
  12259.     if ( hud_ ) {
  12260.         hud_->SetStateInt ( "boss_maxhealth", enemy->health );
  12261.         hud_->HandleNamedEvent ( "showBossBar" );
  12262.     }
  12263. }
  12264.  
  12265. /*
  12266. =====================
  12267. idPlayer::SetInitialHud
  12268. =====================
  12269. */
  12270. void idPlayer::SetInitialHud ( void ) {
  12271.     if ( !mphud || !gameLocal.isMultiplayer || gameLocal.GetLocalPlayer() != this ) {
  12272.         return;
  12273.     }
  12274.  
  12275.     mphud->SetStateInt( "gametype", gameLocal.gameType );
  12276.     mphud->HandleNamedEvent( "InitHud" );
  12277.     
  12278.     if( gameLocal.IsFlagGameType() ) {
  12279.         mphud->SetStateFloat( "ap", gameLocal.mpGame.assaultPoints.Num() );
  12280.  
  12281.         for( int i = 0; i < TEAM_MAX; i++ ) {
  12282.             mphud->SetStateInt( "team", i );
  12283.             if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( i ) == FS_DROPPED ) {
  12284.                 mphud->HandleNamedEvent( "flagDrop" );
  12285.             } else if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( i ) == FS_TAKEN ) {
  12286.                 mphud->HandleNamedEvent( "flagTaken" );    
  12287.             } else if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( i ) == FS_TAKEN_MARINE ) {
  12288.                 mphud->SetStateInt( "team", TEAM_MARINE );
  12289.                 mphud->HandleNamedEvent( "flagTaken" );    
  12290.             } else if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( i ) == FS_TAKEN_STROGG ) {
  12291.                 mphud->SetStateInt( "team", TEAM_STROGG );
  12292.                 mphud->HandleNamedEvent( "flagTaken" );    
  12293.             } else if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( i ) == FS_AT_BASE ) {
  12294.                 mphud->SetStateInt( "team", i );
  12295.                 mphud->HandleNamedEvent( "flagReturn" );
  12296.             }
  12297.         }
  12298.  
  12299.         for( int i = 0; i < gameLocal.mpGame.assaultPoints.Num(); i++ ) {
  12300.             mphud->SetStateFloat( "apindex", i );
  12301.             //mphud->SetStateInt( "apteam", ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetAPOwner( i ) );
  12302.             mphud->StateChanged( gameLocal.time );
  12303.             mphud->HandleNamedEvent( "APCaptured" );
  12304.         }
  12305.     }
  12306.  
  12307.     mphud->StateChanged ( gameLocal.time );
  12308. }
  12309.  
  12310. void idPlayer::RemoveClientModel ( const char *entityDefName ) {
  12311.     rvClientEntity* cent;
  12312.     rvClientEntity*    next;
  12313.     
  12314.     for( cent = clientEntities.Next(); cent != NULL; cent = next ) {
  12315.         next = cent->bindNode.Next();
  12316.  
  12317. // RAVEN BEGIN
  12318. // jnewquist: Use accessor for static class type 
  12319.         if ( cent->IsType ( rvClientModel::GetClassType() ) ) {
  12320. // RAVEN END
  12321.             if ( !idStr::Icmp ( ( static_cast<rvClientModel*> ( cent ) )->GetClassname(), entityDefName ) ) {
  12322.                 cent->Unbind ( );
  12323.                 delete cent;
  12324.             }
  12325.         }
  12326.     }        
  12327. }
  12328.  
  12329. rvClientEntityPtr<rvClientModel> idPlayer::AddClientModel ( const char* entityDefName, const char* shaderName ) {
  12330.     rvClientEntityPtr<rvClientModel> ptr;
  12331.     ptr = NULL;
  12332.     
  12333.     if ( entityDefName == NULL ) {
  12334.         return ptr;
  12335.     }
  12336.     
  12337.     const idDict* entityDef = gameLocal.FindEntityDefDict ( entityDefName, false );
  12338.     
  12339.     if ( entityDef == NULL ) {
  12340.         return ptr;
  12341.     }
  12342.  
  12343.     // mwhitlock: Dynamic memory consolidation
  12344.     RV_PUSH_HEAP_MEM(this);
  12345.  
  12346.     rvClientModel *newModel = new rvClientModel();
  12347.  
  12348.     // mwhitlock: Dynamic memory consolidation
  12349.     RV_POP_HEAP();
  12350.  
  12351.     newModel->Spawn ( entityDef );    
  12352.     idMat3 rotation;
  12353.     rotation = entityDef->GetAngles( "angles" ).ToMat3();
  12354.     newModel->SetAxis( rotation );
  12355.     newModel->SetOrigin( entityDef->GetVector( "origin" ) * rotation );
  12356.     newModel->Bind ( this, animator.GetJointHandle( entityDef->GetString ( "joint" ) ) );
  12357.  
  12358.     newModel->SetCustomShader ( shaderName );
  12359.     newModel->GetRenderEntity()->suppressSurfaceInViewID = entityNumber + 1;
  12360.     newModel->GetRenderEntity()->noSelfShadow = true;
  12361.     newModel->GetRenderEntity()->noShadow = true;
  12362.  
  12363.     ptr = newModel;
  12364.  
  12365.     return ptr;
  12366. }
  12367.  
  12368. void idPlayer::RemoveClientModels ( void ) {
  12369.     rvClientEntity* cent;
  12370.     rvClientEntity*    next;
  12371.     
  12372.     for( cent = clientEntities.Next(); cent != NULL; cent = next ) {
  12373.         next = cent->bindNode.Next();
  12374.  
  12375. // RAVEN BEGIN
  12376. // jnewquist: Use accessor for static class type 
  12377.         if ( cent->IsType ( rvClientModel::GetClassType() ) ) {
  12378. // RAVEN END
  12379.             cent->Unbind ( );
  12380.             delete cent;
  12381.         }
  12382.     }    
  12383. }
  12384.  
  12385. /*
  12386. =====================
  12387. idPlayer::ClientGib()
  12388. ddynerman: Spawns client side gibs around this player
  12389. =====================
  12390. */
  12391. void idPlayer::ClientGib( const idVec3& dir ) {
  12392.     
  12393.     if( !spawnArgs.GetBool( "gib" )    )    {
  12394.         return;
  12395.     }
  12396.  
  12397.     int i;
  12398.     idVec3 entityCenter, velocity;
  12399.     idList<rvClientMoveable *> list;
  12400.  
  12401.         
  12402.     // hide the player
  12403.     SetSkin( gibSkin );
  12404.  
  12405.     //and the head
  12406.     if ( head.GetEntity() ) {
  12407.         head.GetEntity()->Hide();
  12408.     }
  12409.  
  12410.     // blow out the gibs in the given direction away from the center of the entity
  12411.     
  12412.  
  12413.     // spawn gib client models
  12414.     rvClientMoveable::SpawnClientMoveables( this, "clientgib", &list );
  12415.  
  12416.     entityCenter = GetPhysics()->GetAbsBounds().GetCenter();
  12417.     for ( i = 0; i < list.Num(); i++ ) {
  12418.         list[i]->GetPhysics()->SetContents( CONTENTS_CORPSE );
  12419.         list[i]->GetPhysics()->SetClipMask( CONTENTS_SOLID );
  12420.         velocity = list[i]->GetPhysics()->GetAbsBounds().GetCenter() - entityCenter;
  12421.         velocity.NormalizeFast();
  12422.         velocity += ( i & 1 ) ? dir : -dir;
  12423.         
  12424.         list[i]->GetPhysics()->ApplyImpulse( 0, list[i]->GetPhysics()->GetOrigin(), velocity * ( 25000.0f + ( gameLocal.random.RandomFloat() * 50000.0f)) );
  12425. //        list[i]->GetPhysics()->SetLinearVelocity( velocity * ( 25.0f + ( gameLocal.random.RandomFloat() * 300.0f)));
  12426.         list[i]->GetPhysics()->SetAngularVelocity( velocity * ( -250.0f + ( gameLocal.random.RandomFloat() * 500.0f)));
  12427.  
  12428.         list[i]->GetRenderEntity()->noShadow = true;
  12429.         list[i]->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
  12430.         list[i]->PostEventMS( &CL_FadeOut, SEC2MS( 4.0f ), SEC2MS( 2.0f ) );
  12431.     }
  12432.     
  12433.  
  12434.     //play gib fx
  12435.     gameLocal.PlayEffect ( spawnArgs, "fx_gib", GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
  12436.  
  12437.     // gibs are PVS agnostic.  If we gib a player outside of our PVS, set the oldHealth
  12438.     // to below 0 so when this player re-appears in our snap we respawn him
  12439.     if( gameLocal.isClient && gameLocal.GetLocalPlayer() && health > 0 ) { 
  12440.         health = -100;
  12441.     }
  12442. }
  12443.  
  12444. /*
  12445. =====================
  12446. idPlayer::CanDamage
  12447. =====================
  12448. */
  12449. bool idPlayer::CanDamage( const idVec3 &origin, idVec3 &damagePoint, idEntity *ignoreEnt ) {
  12450.     if( gameLocal.isMultiplayer && health <= 0 ) {
  12451.         return false;
  12452.     }
  12453.  
  12454.     return idActor::CanDamage( origin, damagePoint, ignoreEnt );
  12455. }
  12456.  
  12457. /*
  12458. =====================
  12459. idPlayer::ClientDamageEffects
  12460.  
  12461. =====================
  12462. */
  12463. void idPlayer::ClientDamageEffects ( const idDict& damageDef, const idVec3& dir, int damage ) {
  12464.     idVec3 from;
  12465.     idVec3 localDir;
  12466.     float  fadeDB;
  12467.  
  12468.     // Only necessary on clients
  12469.     if ( gameLocal.isMultiplayer && !gameLocal.isClient && !gameLocal.isListenServer ) {
  12470.         return;
  12471.     }
  12472.     
  12473.     from = dir;
  12474.     from.Normalize();
  12475.     viewAxis.ProjectVector( from, localDir );
  12476.     
  12477.     // Visual effects
  12478.      if ( health > 0 && damage ) {    
  12479. // RAVEN BEGIN
  12480. // jnewquist: Controller rumble
  12481.         playerView.DamageImpulse( localDir, &damageDef, damage );
  12482. // RAVEN END
  12483.         
  12484.         // Let the hud know about the hit
  12485.         if ( hud ) {
  12486.             hud->SetStateFloat ( "hitdir", localDir.ToAngles()[YAW] + 180.0f );
  12487.             hud->HandleNamedEvent ( "playerHit" );
  12488.         }
  12489.      }
  12490.  
  12491.     // Sound effects    
  12492.     if ( damageDef.GetFloat ( "hl_volumeDB", "-40", fadeDB ) ) {
  12493.         float fadeTime;
  12494.         
  12495.         fadeTime = 0.0f;
  12496.         if ( !pfl.hearingLoss ) {
  12497.             const char* fade;
  12498.  
  12499.             fadeTime = damageDef.GetFloat ( "hl_fadeOutTime", ".25" );
  12500.             soundSystem->FadeSoundClasses( SOUNDWORLD_GAME, 0, fadeDB, fadeTime );
  12501.         
  12502.             pfl.hearingLoss = true;
  12503.  
  12504.             // sound overlayed?        
  12505.             if ( damageDef.GetString ( "snd_hl", "", &fade ) && *fade ) {            
  12506.                 StartSoundShader ( declManager->FindSound ( fade ), SND_CHANNEL_DEMONIC, 0, false, NULL );
  12507.             }
  12508.         }
  12509.         
  12510.         fadeTime += damageDef.GetFloat ( "hl_time", "1" );
  12511.  
  12512.         CancelEvents ( &EV_Player_FinishHearingLoss );
  12513.         PostEventSec ( &EV_Player_FinishHearingLoss, fadeTime, damageDef.GetFloat ( "hl_fadeInTime", ".25" ) );
  12514.     }
  12515. }
  12516.  
  12517. /*
  12518. =====================
  12519. idPlayer::GetDebugInfo
  12520. =====================
  12521. */
  12522. void idPlayer::GetDebugInfo ( debugInfoProc_t proc, void* userData ) {
  12523.     idActor::GetDebugInfo ( proc, userData );
  12524.     proc ( "idPlayer", "inventory.armor",        va("%d", inventory.armor ), userData );
  12525.     proc ( "idPlayer", "inventory.weapons",        va("%d", inventory.weapons ), userData );
  12526.     proc ( "idPlayer", "inventory.powerups",    va("%d", inventory.powerups ), userData );
  12527. }
  12528.  
  12529.  
  12530.  
  12531. // RAVEN END
  12532.  
  12533. /*
  12534. =====================
  12535. idPlayer::ApplyImpulse
  12536. =====================
  12537. */
  12538. void idPlayer::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash ) {
  12539.     if( !ent)    {
  12540.         gameLocal.Warning( "idPlayer::ApplyImpulse called with null entity as instigator.");
  12541.         return;
  12542.     }
  12543.  
  12544.     lastImpulsePlayer = NULL;
  12545.     lastImpulseTime = gameLocal.time + 1000;
  12546.  
  12547.     if( ent->IsType( idPlayer::Type ) && ent != this ) {
  12548.         lastImpulsePlayer = static_cast<idPlayer*>(ent);
  12549. // RAVEN BEGIN
  12550. // jnewquist: Use accessor for static class type 
  12551.     } else if( ent->IsType( idProjectile::GetClassType() ) ) {
  12552. // RAVEN END
  12553.         idEntity* owner = static_cast<idProjectile*>(ent)->GetOwner();
  12554.         if( owner && owner->IsType( idPlayer::Type ) && owner != this ) {
  12555.             lastImpulsePlayer = static_cast<idPlayer*>(owner);
  12556.         }
  12557.     }
  12558.  
  12559.     idAFEntity_Base::ApplyImpulse( ent, id, point, impulse, splash );
  12560. }
  12561.  
  12562. /*
  12563. =====================
  12564. idPlayer::SetupHead
  12565. =====================
  12566. */
  12567. void idPlayer::SetupHead( const char* headModel, idVec3 headOffset ) {
  12568.     idActor::SetupHead( headModel, headOffset );
  12569.  
  12570.     if ( head ) {
  12571.         head->fl.persistAcrossInstances = true;
  12572.     }
  12573. }
  12574.  
  12575. /*
  12576. =====================
  12577. idPlayer::GUIMainNotice
  12578. =====================
  12579. */
  12580. void idPlayer::GUIMainNotice( const char* message, bool persist ) {
  12581.     if( !gameLocal.isMultiplayer || !mphud ) {
  12582.         return;
  12583.     }
  12584.     
  12585.     mphud->SetStateString( "main_notice_text", message );
  12586.     mphud->SetStateBool( "main_notice_persist", persist );
  12587.     mphud->StateChanged( gameLocal.time );
  12588.     mphud->HandleNamedEvent( "main_notice" );
  12589. }
  12590.  
  12591. /*
  12592. =====================
  12593. idPlayer::GUIFragNotice
  12594. =====================
  12595. */
  12596. void idPlayer::GUIFragNotice( const char* message, bool persist ) {
  12597.     if( !gameLocal.isMultiplayer || !mphud ) {
  12598.         return;
  12599.     }
  12600.  
  12601.     mphud->SetStateString( "frag_notice_text", message );
  12602.     mphud->SetStateBool( "frag_notice_persist", persist );
  12603.     mphud->StateChanged( gameLocal.time );
  12604.     mphud->HandleNamedEvent( "frag_notice" );
  12605. }
  12606.  
  12607. /*
  12608. =====================
  12609. idPlayer::SetHudOverlay
  12610. =====================
  12611. */
  12612. void idPlayer::SetHudOverlay( idUserInterface* overlay, int duration ) {
  12613.     overlayHud = overlay;
  12614.     overlayHudTime = gameLocal.time + duration;
  12615. }
  12616.  
  12617. // RAVEN BEGIN
  12618. // mekberg: wrap saveMessages
  12619. /*
  12620. =====================
  12621. idPlayer::SaveMessage
  12622. =====================
  12623. */
  12624. void idPlayer::SaveMessage( void ) {
  12625.     if ( GetHud( ) ) {
  12626.         GetHud()->HandleNamedEvent( "saveMessage" );
  12627.     }
  12628.  
  12629.     if ( objectiveSystem ) {
  12630.         objectiveSystem->HandleNamedEvent( "saveMessage" );
  12631.     }
  12632. }
  12633.  
  12634. // mekberg: set pm_ cvars
  12635. /*
  12636. =====================
  12637. idPlayer::SetPMCVars
  12638. =====================
  12639. */
  12640. void idPlayer::SetPMCVars( void ) {
  12641.     const idKeyValue    *kv;
  12642.  
  12643.      if ( !gameLocal.isMultiplayer || gameLocal.isServer ) {
  12644.          kv = spawnArgs.MatchPrefix( "pm_", NULL );
  12645.          while( kv ) {
  12646.              cvarSystem->SetCVarString( kv->GetKey(), kv->GetValue() );
  12647.              kv = spawnArgs.MatchPrefix( "pm_", kv );
  12648.          }
  12649.     }
  12650. }
  12651. // RAVEN END
  12652.  
  12653. /*
  12654. =====================
  12655. idPlayer::GetSpawnClassname
  12656. =====================
  12657. */
  12658. const char* idPlayer::GetSpawnClassname ( void ) {
  12659.     idEntity*    world;
  12660.     const char*    entityFilter;
  12661.     
  12662.     // Test player def
  12663.     if ( *g_testPlayer.GetString() ) {
  12664.         return g_testPlayer.GetString ( );
  12665.     }
  12666.  
  12667.     // Multiplayer
  12668.     if ( gameLocal.isMultiplayer ) {
  12669.         return "player_marine_mp";
  12670.     }
  12671.     
  12672.     // See if the world spawn specifies a player
  12673.     world = gameLocal.entities[ENTITYNUM_WORLD];
  12674.     assert( world );
  12675.     
  12676.     gameLocal.serverInfo.GetString( "si_entityFilter", "", &entityFilter );
  12677.     if ( entityFilter && *entityFilter ) {
  12678.         return world->spawnArgs.GetString( va("player_%s", entityFilter ), world->spawnArgs.GetString( "player", "player_marine" ) );
  12679.     }
  12680.     
  12681.     return world->spawnArgs.GetString( "player", "player_marine" );
  12682. }
  12683.  
  12684. /*
  12685. ===============
  12686. idPlayer::SetInstance
  12687. ===============
  12688. */
  12689. void idPlayer::SetInstance( int newInstance ) {
  12690.     common->DPrintf( "idPlayer::SetInstance() - Setting instance for '%s' to %d\n", name.c_str(), newInstance );
  12691.     idEntity::SetInstance( newInstance );
  12692.  
  12693.     if( head.GetEntity() ) {
  12694.         head.GetEntity()->SetInstance( newInstance );
  12695.     }
  12696.  
  12697.     if( weapon ) {
  12698.         if( weapon->GetViewModel() ) {
  12699.             weapon->GetViewModel()->SetInstance( newInstance );
  12700.         }
  12701.  
  12702.         if( weapon->GetWorldModel() ) {
  12703.             weapon->GetWorldModel()->SetInstance( newInstance );
  12704.         }
  12705.     }
  12706.  
  12707.     if( weaponWorldModel ) {
  12708.         weaponWorldModel->SetInstance( newInstance );
  12709.     }
  12710.     
  12711.     if( weaponViewModel ) {
  12712.         weaponViewModel->SetInstance( newInstance );
  12713.     }
  12714. }
  12715.  
  12716. /*
  12717. ===============
  12718. idPlayer::JoinInstance
  12719. ===============
  12720. */
  12721. void idPlayer::JoinInstance( int newInstance ) {
  12722.     assert( gameLocal.isServer );
  12723.     if( instance == newInstance ) {
  12724.         return;
  12725.     }
  12726.  
  12727.     if( newInstance < 0 || newInstance >= MAX_ARENAS ) {
  12728.         gameLocal.Warning( "idPlayer::JoinInstance() - Invalid instance %d specified\n", newInstance );
  12729.     }
  12730.  
  12731.     if( gameLocal.GetNumInstances() <= newInstance || gameLocal.GetInstance( newInstance ) == NULL ) {
  12732.         // don't populate instance until player gets linked into the right one    
  12733.         gameLocal.AddInstance( newInstance );
  12734.  
  12735.         if( this == gameLocal.GetLocalPlayer() ) {
  12736.             // ensure InstanceLeave() gets called on newly spawned entities before
  12737.             // InstanceJoin() gets called.
  12738.             gameLocal.mpGame.ServerSetInstance( instance );
  12739.         }
  12740.     }
  12741.  
  12742.     SetArena( newInstance );
  12743.     SetInstance( newInstance );
  12744.  
  12745.     gameLocal.GetInstance( newInstance )->JoinInstance( this );
  12746. }
  12747.  
  12748. /*
  12749. ===============
  12750. idPlayer::SetEmote
  12751. ===============
  12752. */
  12753. void idPlayer::SetEmote( playerEmote_t newEmote ) {
  12754.     emote = newEmote;
  12755.  
  12756.     // if we're the ones generating the emote, pass it along
  12757.     if( gameLocal.localClientNum == entityNumber ) {
  12758.         idBitMsg    msg;
  12759.         byte        msgBuf[MAX_EVENT_PARAM_SIZE];
  12760.  
  12761.         assert( entityNumber == gameLocal.localClientNum );
  12762.         msg.Init( msgBuf, sizeof( msgBuf ) );
  12763.         msg.BeginWriting();
  12764.         msg.WriteByte( emote );
  12765.         if( gameLocal.isServer ) {
  12766.             ServerSendInstanceEvent( EVENT_EMOTE, &msg, false, -1 );
  12767.         } else {
  12768.             ClientSendEvent( EVENT_EMOTE, &msg );
  12769.         }
  12770.     }
  12771. }
  12772.  
  12773. /*
  12774. ===============
  12775. idPlayer::GetGroundElevator
  12776. ===============
  12777. */
  12778. idEntity* idPlayer::GetGroundElevator( idEntity* testElevator ) const {
  12779.     idEntity* groundEnt = GetGroundEntity();
  12780.     if ( !groundEnt ) {
  12781.         return NULL;
  12782.     }
  12783.     while ( groundEnt->GetBindMaster() ) {
  12784.         groundEnt = groundEnt->GetBindMaster();
  12785.     }
  12786.  
  12787.     if ( !groundEnt->IsType( idElevator::GetClassType() ) ) {
  12788.         return NULL;
  12789.     }
  12790.     //NOTE: for player, don't care if all the way on, or not
  12791.     return groundEnt;
  12792. }
  12793.  
  12794. /*
  12795. ===================
  12796. idPlayer::IsCrouching
  12797. ===================
  12798. */
  12799. bool idPlayer::IsCrouching( void ) const {
  12800.     return physicsObj.IsCrouching();
  12801. }
  12802.  
  12803. /*
  12804. ===============
  12805. idPlayer::SetArena
  12806. ===============
  12807. */
  12808. void idPlayer::SetArena( int newArena ) {
  12809.     if( arena == newArena ) {
  12810.         return;
  12811.     }
  12812.  
  12813.     arena = newArena;
  12814.     if( gameLocal.GetLocalPlayer() == this && gameLocal.gameType == GAME_TOURNEY ) {
  12815.         if( arena >= 0 && arena <= MAX_ARENAS ) {
  12816.             if( arena < MAX_ARENAS ) {
  12817. // RAVEN BEGIN
  12818. // rhummer: localized these strings.
  12819.                 GUIMainNotice( va( common->GetLocalizedString( "#str_107270" ), newArena + 1 ) );
  12820.             } else {
  12821.                 GUIMainNotice( common->GetLocalizedString( "#str_107271" ) );
  12822.             }
  12823. // RAVEN END
  12824.             
  12825.             if( gameLocal.GetLocalPlayer() ) {
  12826.                 gameLocal.mpGame.tourneyGUI.ArenaSelect( newArena, TGH_BRACKET );
  12827.             }
  12828.             gameLocal.mpGame.ScheduleAnnouncerSound( (announcerSound_t)(AS_TOURNEY_JOIN_ARENA_ONE + arena), gameLocal.time );
  12829.         } 
  12830.     }
  12831. }
  12832.  
  12833. /*
  12834. ===============
  12835. idPlayer::Event_DamageEffect
  12836. ===============
  12837. */
  12838. void idPlayer::Event_DamageEffect( const char *damageDefName, idEntity* _damageFromEnt )
  12839.     const idDeclEntityDef *damageDef = gameLocal.FindEntityDef( damageDefName, false );
  12840.     if ( damageDef )
  12841.     {
  12842.         idVec3 dir = (_damageFromEnt!=NULL)?(GetEyePosition()-_damageFromEnt->GetEyePosition()):viewAxis[2];
  12843.         dir.Normalize();
  12844.         int        damage = 1;
  12845.         ClientDamageEffects( damageDef->dict, dir, damage );
  12846.         if ( !g_testDeath.GetBool() ) {
  12847.             lastDmgTime = gameLocal.time;
  12848.         }
  12849.         lastDamageDir = dir;
  12850.           lastDamageDir.Normalize();
  12851.         lastDamageDef = damageDef->Index();
  12852.         lastDamageLocation = 0;
  12853.     }
  12854. }
  12855.  
  12856. /*
  12857. ===============
  12858. idPlayer::UpdateDeathShader
  12859. ===============
  12860. */
  12861. void idPlayer::UpdateDeathShader ( bool state_hitch ) {
  12862.     if ( !doingDeathSkin && gameLocal.time > deathSkinTime && deathSkinTime ) {
  12863.         deathSkinTime = 0;
  12864.  
  12865.         deathClearContentsTime = spawnArgs.GetInt( "deathSkinTime" );
  12866.         doingDeathSkin = true;
  12867.         if ( state_hitch ) {
  12868.             renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f - 2.0f;
  12869.             if( head ) {
  12870.                 head.GetEntity()->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f - 2.0f;
  12871.             }
  12872.         } else {
  12873.             renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
  12874.             if( head ) {
  12875.                 head.GetEntity()->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
  12876.             }
  12877.         }
  12878.         renderEntity.noShadow = true;
  12879.         UpdateVisuals();
  12880.     }
  12881. }
  12882.  
  12883. /*
  12884. ===============
  12885. idPlayer::Event_InitWeapon
  12886. ===============
  12887. */
  12888. void idPlayer::InitWeapon( void ) {
  12889.     doInitWeapon = false;
  12890.     currentWeapon = -1;
  12891.     SetWeapon( idealWeapon );
  12892. }
  12893.  
  12894. /*
  12895. ===============
  12896. idPlayer::GetHitscanTint
  12897. ===============
  12898. */
  12899. const idVec4& idPlayer::GetHitscanTint( void ) {
  12900.     if( gameLocal.IsTeamGame() ) {
  12901.         if( gameLocal.serverInfo.GetInt( "si_allowHitscanTint" ) >= 2 ) {
  12902.             if( team == TEAM_MARINE ) {
  12903.                 return marineHitscanTint;
  12904.             } else if( team == TEAM_STROGG ) {
  12905.                 return stroggHitscanTint;
  12906.             } else {
  12907.                 gameLocal.Error( "idPlayer::GetHitscanTint() - Unknown team '%d' on player %d '%s'\n", team, entityNumber, GetUserInfo()->GetString( "ui_name" ) );
  12908.             }
  12909.         } else {
  12910.             return defaultHitscanTint;
  12911.         }
  12912.     }
  12913.     
  12914.     if( gameLocal.serverInfo.GetInt( "si_allowHitscanTint" ) >= 1 ) {
  12915.         return hitscanTint;    
  12916.     } 
  12917.  
  12918.     return defaultHitscanTint;
  12919. }
  12920.  
  12921. /*
  12922. ===============
  12923. idPlayer::IsReady
  12924. ===============
  12925. */
  12926. bool idPlayer::IsReady( void ) {
  12927.     return !gameLocal.serverInfo.GetBool( "si_useReady" ) || ready || forcedReady;
  12928. }
  12929.  
  12930. /*
  12931. ===============
  12932. idPlayer::ForceScoreboard
  12933. ===============
  12934. */
  12935. void idPlayer::ForceScoreboard( bool force, int time ) {
  12936.     forceScoreBoard = force;
  12937.     forceScoreBoardTime = time;
  12938. }
  12939.  
  12940. /*
  12941. ===============
  12942. idPlayer::GetTextTourneyStatus
  12943. ===============
  12944. */
  12945. const char* idPlayer::GetTextTourneyStatus( void ) {
  12946.     if( tourneyStatus == PTS_ADVANCED ) {
  12947.         return common->GetLocalizedString( "#str_107740" );
  12948.     } else if( tourneyStatus == PTS_ELIMINATED ) {
  12949.         return common->GetLocalizedString( "#str_107729" );
  12950.     } else if( tourneyStatus == PTS_PLAYING ) {
  12951.         return common->GetLocalizedString( "#str_107728" );
  12952.     } else if( tourneyStatus == PTS_UNKNOWN ) {
  12953.         return common->GetLocalizedString( "#str_107739" );
  12954.     }
  12955.     return "UNKNOWN TOURNEY STATUS";
  12956. }
  12957.  
  12958. /*
  12959. ===============
  12960. idPlayer::ClientInstanceJoin
  12961. Players know about all other players, even in other instances
  12962. We need to hide/show them on the client as we switch to/from instances
  12963. ===============
  12964. */
  12965. void idPlayer::ClientInstanceJoin( void ) {
  12966.     assert( gameLocal.isClient );
  12967.  
  12968.     common->DPrintf( "idPlayer::ClientInstanceJoin() - client %d ('%s') is being shown\n", entityNumber, GetUserInfo()->GetString( "ui_name" ) );
  12969.  
  12970.     // restore client
  12971.     Spectate( spectating, true );
  12972. }
  12973.  
  12974. /*
  12975. ===============
  12976. idPlayer::ClientInstanceLeave
  12977. Players know about all other players, even in other instances
  12978. We need to hide/show them on the client as we switch to/from instances
  12979. ===============
  12980. */
  12981. void idPlayer::ClientInstanceLeave( void ) {
  12982.     assert( gameLocal.isClient );
  12983.     common->DPrintf( "idPlayer::ClientInstanceLeave() - client %d ('%s') is being hidden\n", entityNumber, GetUserInfo()->GetString( "ui_name" ) );
  12984.  
  12985.     // force client to spectate
  12986.     Spectate( spectating, true );
  12987. }
  12988.  
  12989. /*
  12990. ===============
  12991. idPlayer::ClientStale
  12992. ===============
  12993. */
  12994. bool idPlayer::ClientStale( void ) {
  12995.     idEntity::ClientStale();
  12996.     
  12997.     // remove all powerup effects
  12998.     for( int i = 0; i < POWERUP_MAX; i++ ) {
  12999.         if( inventory.powerups & ( 1 << i ) ) {
  13000.             StopPowerUpEffect( i );
  13001.         }
  13002.     }
  13003.  
  13004.     // never delete client
  13005.     return false;
  13006. }
  13007.  
  13008. /*
  13009. ===============
  13010. idPlayer::ClientUnstale
  13011. ===============
  13012. */
  13013. void idPlayer::ClientUnstale( void ) {
  13014.     idEntity::ClientUnstale();
  13015.     
  13016.     // force render ent to position
  13017.     renderEntity.axis = physicsObj.GetAxis();
  13018.     renderEntity.origin = physicsObj.GetOrigin();
  13019.  
  13020.     // don't do any smoothing with this snapshot
  13021.     predictedFrame = gameLocal.framenum;
  13022.     // the powerup effects ( rvClientEntity ) will do some bindings, which in turn will call GetPosition
  13023.     // which uses the predictedOrigin .. which won't be updated till we Think() so just don't leave the predictedOrigin to the old position
  13024.     predictedOrigin = renderEntity.origin;
  13025.  
  13026.     // restart powerup effects on clients that are coming back into our snapshot
  13027.     int i;
  13028.     for ( i = 0; i < POWERUP_MAX; i++ ) {
  13029.         if ( inventory.powerups & (1 << i) ) {
  13030.             StartPowerUpEffect( i );
  13031.         }
  13032.     }
  13033. }
  13034.