Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

443 lines
10 KiB

  1. #include "cbase.h"
  2. #ifdef CLIENT_DLL
  3. #include "tier3/tier3.h"
  4. #include "iviewrender.h"
  5. #include "inputsystem/iinputsystem.h"
  6. #include "vgui/IInputInternal.h"
  7. #include "c_basecombatweapon.h"
  8. #include "c_baseplayer.h"
  9. #include "haptics/ihaptics.h"
  10. #include "hud_macros.h"
  11. #include "iclientvehicle.h"
  12. #include "c_prop_vehicle.h"
  13. #include "prediction.h"
  14. #include "activitylist.h"
  15. #ifdef TERROR
  16. #include "ClientTerrorPlayer.h"
  17. #endif
  18. extern vgui::IInputInternal *g_InputInternal;
  19. #else
  20. #include "usermessages.h"
  21. #endif
  22. #include "haptics/haptic_utils.h"
  23. #include "haptics/haptic_msgs.h"
  24. #ifndef TERROR
  25. #ifndef FCVAR_RELEASE
  26. #define FCVAR_RELEASE 0
  27. #endif
  28. #endif
  29. #ifdef CLIENT_DLL
  30. ConVar hap_HasDevice ( "hap_HasDevice", "0", FCVAR_USERINFO/*|FCVAR_HIDDEN*/, "falcon is connected" );
  31. // damage scale on a title basis. Convar referenced in the haptic dll.
  32. #ifdef PORTAL
  33. #define HAP_DEFAULT_DAMAGE_SCALE_GAME "0.75"
  34. #elif TF_CLIENT_DLL
  35. #define HAP_DEFAULT_DAMAGE_SCALE_GAME "0.3"
  36. #else
  37. #define HAP_DEFAULT_DAMAGE_SCALE_GAME "1.0"
  38. #endif
  39. ConVar hap_damagescale_game("hap_damagescale_game", HAP_DEFAULT_DAMAGE_SCALE_GAME);
  40. #undef HAP_DEFAULT_DAMAGE_SCALE_GAME
  41. #endif
  42. void HapticSendWeaponAnim(CBaseCombatWeapon* weapon, int iActivity)
  43. {
  44. //ignore idle
  45. if(iActivity == ACT_VM_IDLE)
  46. return;
  47. #if defined( CLIENT_DLL )
  48. //if(hap_PrintEvents.GetBool())
  49. // Msg("Client Activity :%s %s %s\n",weapon->GetName(),"Activities",VarArgs("%i",iActivity));
  50. if ( weapon->IsPredicted() )
  51. haptics->ProcessHapticWeaponActivity(weapon->GetName(),iActivity);
  52. #else
  53. if( !weapon->IsPredicted() && weapon->GetOwner() && weapon->GetOwner()->IsPlayer())
  54. {
  55. HapticMsg_SendWeaponAnim( ToBasePlayer(weapon->GetOwner()), iActivity );
  56. }
  57. #endif
  58. }
  59. void HapticSetDrag(CBasePlayer* pPlayer, float drag)
  60. {
  61. #ifdef CLIENT_DLL
  62. haptics->SetDrag(drag);
  63. #else
  64. HapticMsg_SetDrag( pPlayer, drag );
  65. #endif
  66. }
  67. #ifdef CLIENT_DLL
  68. void HapticsHandleMsg_HapSetDrag( float drag )
  69. {
  70. haptics->SetDrag(drag);
  71. }
  72. #endif
  73. void HapticSetConstantForce(CBasePlayer* pPlayer, Vector force)
  74. {
  75. #ifdef CLIENT_DLL
  76. haptics->SetConstantForce(force);
  77. #else
  78. HapticMsg_SetConstantForce( pPlayer, force );
  79. #endif
  80. }
  81. #ifdef CLIENT_DLL
  82. #ifndef HAPTICS_TEST_PREFIX
  83. #define HAPTICS_TEST_PREFIX
  84. #endif
  85. static CSysModule *pFalconModule =0;
  86. void ConnectHaptics(CreateInterfaceFn appFactory)
  87. {
  88. bool success = false;
  89. // NVNT load haptics module
  90. pFalconModule = Sys_LoadModule( HAPTICS_TEST_PREFIX HAPTICS_DLL_NAME );
  91. if(pFalconModule)
  92. {
  93. CreateInterfaceFn factory = Sys_GetFactory( pFalconModule );
  94. if(factory)
  95. {
  96. haptics = reinterpret_cast< IHaptics* >( factory( HAPTICS_INTERFACE_VERSION, NULL ) );
  97. if(haptics &&
  98. haptics->Initialize(engine,
  99. view,
  100. g_InputInternal,
  101. gpGlobals,
  102. appFactory,
  103. g_pVGuiInput->GetIMEWindow(),
  104. filesystem,
  105. enginevgui,
  106. ActivityList_IndexForName,
  107. ActivityList_NameForIndex))
  108. {
  109. success = true;
  110. hap_HasDevice.SetValue(1);
  111. }
  112. }
  113. }
  114. if(!success)
  115. {
  116. Sys_UnloadModule(pFalconModule);
  117. pFalconModule = 0;
  118. haptics = new CHapticsStubbed;
  119. }
  120. if(haptics->HasDevice())
  121. {
  122. Assert( (void*)haptics == inputsystem->GetHapticsInterfaceAddress() );
  123. }
  124. HookHapticMessages();
  125. }
  126. void DisconnectHaptics()
  127. {
  128. haptics->ShutdownHaptics();
  129. if(pFalconModule)
  130. {
  131. Sys_UnloadModule(pFalconModule);
  132. pFalconModule = 0;
  133. }else{
  134. // delete the stub.
  135. delete haptics;
  136. }
  137. haptics = NULL;
  138. }
  139. //Might be able to handle this better...
  140. void HapticsHandleMsg_HapSetConst( Vector const &constant )
  141. {
  142. //Msg("__MsgFunc_HapSetConst: %f %f %f\n",constant.x,constant.y,constant.z);
  143. haptics->SetConstantForce(constant);
  144. //C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer();
  145. }
  146. //Might be able to handle this better...
  147. void HapticsHandleMsg_SPHapWeapEvent( int iActivity )
  148. {
  149. C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer();
  150. C_BaseCombatWeapon* weap = NULL;
  151. if(pPlayer)
  152. weap = pPlayer->GetActiveWeapon();
  153. if(weap)
  154. haptics->ProcessHapticEvent(4,"Weapons",weap->GetName(),"Activities",VarArgs("%i",iActivity));
  155. }
  156. void HapticsHandleMsg_HapPunch( QAngle const &angle )
  157. {
  158. haptics->HapticsPunch(1,angle);
  159. }
  160. #ifdef TERROR
  161. ConVar hap_zombie_damage_scale("hap_zombie_damage_scale", "0.25", FCVAR_RELEASE|FCVAR_NEVER_AS_STRING);
  162. #endif
  163. void HapticsHandleMsg_HapDmg( float pitch, float yaw, float damage, int damageType )
  164. {
  165. if(!haptics->HasDevice())
  166. return;
  167. #ifdef TERROR
  168. C_TerrorPlayer *pPlayer = C_TerrorPlayer::GetLocalTerrorPlayer();
  169. #else
  170. C_BasePlayer *pPlayer = CBasePlayer::GetLocalPlayer();
  171. #endif
  172. if(pPlayer)
  173. {
  174. Vector damageDirection;
  175. damageDirection.x = cos(pitch*M_PI/180.0)*sin(yaw*M_PI/180.0);
  176. damageDirection.y = -sin(pitch*M_PI/180.0);
  177. damageDirection.z = -(cos(pitch*M_PI/180.0)*cos(yaw*M_PI/180.0));
  178. #ifdef TERROR
  179. if(pPlayer->GetTeamNumber()==TEAM_ZOMBIE)
  180. {
  181. damageDirection *= hap_zombie_damage_scale.GetFloat();
  182. }
  183. #endif
  184. haptics->ApplyDamageEffect(damage, damageType, damageDirection);
  185. }
  186. }
  187. ConVar hap_melee_scale("hap_melee_scale", "0.8", FCVAR_RELEASE|FCVAR_NEVER_AS_STRING);
  188. void HapticsHandleMsg_HapMeleeContact()
  189. {
  190. haptics->HapticsPunch(hap_melee_scale.GetFloat(), QAngle(0,0,0));
  191. }
  192. ConVar hap_noclip_avatar_scale("hap_noclip_avatar_scale", "0.10f", FCVAR_RELEASE|FCVAR_NEVER_AS_STRING);
  193. void UpdateAvatarEffect(void)
  194. {
  195. if(!haptics->HasDevice())
  196. return;
  197. Vector vel;
  198. Vector vvel;
  199. Vector evel;
  200. QAngle eye;
  201. C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer();
  202. if(!pPlayer)
  203. return;
  204. eye = pPlayer->GetAbsAngles();
  205. if(pPlayer->IsInAVehicle() && pPlayer->GetVehicle())
  206. {
  207. pPlayer->GetVehicle()->GetVehicleEnt()->EstimateAbsVelocity(vvel);
  208. eye = pPlayer->GetVehicle()->GetVehicleEnt()->EyeAngles();
  209. if(!Q_stristr(pPlayer->GetVehicle()->GetVehicleEnt()->GetClassname(),"choreo"))
  210. {
  211. eye[YAW] += 90;
  212. }
  213. }
  214. else
  215. {
  216. vel = pPlayer->GetAbsVelocity();
  217. }
  218. Vector PlayerVel = pPlayer->GetAbsVelocity();
  219. //Choreo vehicles use player avatar and don't produce their own velocity
  220. if(!pPlayer->GetVehicle() || abs(vvel.Length()) == 0 )
  221. {
  222. vel = PlayerVel;
  223. }
  224. else
  225. vel = vvel;
  226. VectorYawRotate(vel, -90 -eye[YAW], vel );
  227. vel.y = -vel.y;
  228. vel.z = -vel.z;
  229. switch(pPlayer->GetMoveType()) {
  230. case MOVETYPE_NOCLIP:
  231. vel *= hap_noclip_avatar_scale.GetFloat();
  232. break;
  233. default:
  234. break;
  235. }
  236. haptics->UpdateAvatarVelocity(vel);
  237. }
  238. #endif
  239. #ifndef CLIENT_DLL
  240. void HapticsDamage(CBasePlayer* pPlayer, const CTakeDamageInfo &info)
  241. {
  242. #if !defined(TF_DLL) && !defined(CSTRIKE_DLL)
  243. if(!pPlayer->HasHaptics())
  244. return;// do not send to non haptic users.
  245. Vector DamageDirection(0,0,0);
  246. CBaseEntity *eInflictor = info.GetInflictor();
  247. // Pat: nuero toxix crash fix
  248. if(!eInflictor) {
  249. return;
  250. }
  251. // Player Data
  252. Vector playerPosition = pPlayer->GetLocalOrigin();
  253. Vector inflictorPosition = eInflictor->GetLocalOrigin();
  254. Vector posWithDir = playerPosition + (playerPosition - inflictorPosition);
  255. pPlayer->WorldToEntitySpace(posWithDir, &DamageDirection);
  256. QAngle dir(0,0,0);
  257. VectorAngles(DamageDirection, dir);
  258. float yawAngle = dir[YAW];
  259. float pitchAngle = dir[PITCH];
  260. int bitDamageType = info.GetDamageType();
  261. if(bitDamageType & DMG_FALL)
  262. {
  263. pitchAngle = ((float)-90.0); // coming from beneath
  264. }
  265. else if(bitDamageType & DMG_BURN && (bitDamageType & ~DMG_BURN)==0)
  266. {
  267. // just burn, use the z axis here.
  268. pitchAngle = 0.0;
  269. }
  270. #ifdef TERROR
  271. else if(
  272. (bitDamageType & ( DMG_PARALYZE | DMG_NERVEGAS | DMG_POISON | DMG_RADIATION | DMG_DROWNRECOVER | DMG_ACID | DMG_SLOWBURN ) ) &&
  273. (bitDamageType & ~( DMG_PARALYZE | DMG_NERVEGAS | DMG_POISON | DMG_RADIATION | DMG_DROWNRECOVER | DMG_ACID | DMG_SLOWBURN ) )==0 )
  274. {
  275. // it is time based. and should not really do a punch.
  276. return;
  277. }
  278. #endif
  279. float sendDamage = info.GetDamage();
  280. if(sendDamage>0.0f)
  281. {
  282. HapticMsg_HapDmg( pPlayer, pitchAngle, -yawAngle, sendDamage, bitDamageType );
  283. }
  284. #endif
  285. }
  286. void HapticPunch(CBasePlayer* pPlayer, float x, float y, float z)
  287. {
  288. HapticMsg_Punch( pPlayer, x, y, z );
  289. }
  290. void HapticMeleeContact(CBasePlayer* pPlayer)
  291. {
  292. HapticMsg_MeleeContact( pPlayer );
  293. }
  294. #endif // NOT CLIENT_DLL
  295. void HapticProcessSound(const char* soundname, int entIndex)
  296. {
  297. #ifdef CLIENT_DLL
  298. if (prediction->InPrediction() && prediction->IsFirstTimePredicted())
  299. {
  300. bool local = false;
  301. C_BaseEntity *ent = C_BaseEntity::Instance( entIndex );
  302. if(ent)
  303. local = (entIndex == -1 || ent == C_BasePlayer::GetLocalPlayer() || ent == C_BasePlayer::GetLocalPlayer()->GetActiveWeapon());
  304. haptics->ProcessHapticEvent(2,"Sounds",soundname);
  305. }
  306. #endif
  307. }
  308. #ifdef CLIENT_DLL
  309. // NVNT add || defined(OTHER_DEFINITION) if your game uses vehicles.
  310. #if defined( HL2_CLIENT_DLL )
  311. #define HAPTIC_VEHICLE_DEFAULT "1"
  312. #else
  313. #define HAPTIC_VEHICLE_DEFAULT "0"
  314. #endif
  315. // determines weather the vehicles control box option is faded
  316. ConVar hap_ui_vehicles( "hap_ui_vehicles",
  317. HAPTIC_VEHICLE_DEFAULT,
  318. 0
  319. );
  320. #undef HAPTIC_VEHICLE_DEFAULT
  321. void HapticsEnteredVehicle(C_BaseEntity* vehicle, C_BaseCombatCharacter *pPassenger )
  322. {
  323. if(!vehicle)
  324. return;
  325. // NVNT notify haptics system of navigation change.
  326. C_PropVehicleDriveable* drivable = dynamic_cast<C_PropVehicleDriveable*>(vehicle);
  327. bool hasgun = false;
  328. if(drivable)
  329. hasgun = drivable->HasGun();
  330. if(Q_stristr(vehicle->GetClassname(),"airboat"))
  331. {
  332. haptics->ProcessHapticEvent(2,"Movement","airboat");
  333. if(hasgun)
  334. haptics->SetNavigationClass("vehicle_gun");
  335. else
  336. haptics->SetNavigationClass("vehicle_airboat");
  337. }
  338. else if(Q_stristr(vehicle->GetClassname(),"jeepepisodic"))
  339. {
  340. haptics->ProcessHapticEvent(2,"Movement","BaseVehicle");
  341. haptics->SetNavigationClass("vehicle_nogun");
  342. }
  343. else if(Q_stristr(vehicle->GetClassname(),"jeep"))
  344. {
  345. haptics->ProcessHapticEvent(2,"Movement","BaseVehicle");
  346. haptics->SetNavigationClass("vehicle_gun");
  347. }
  348. else if(Q_stristr(vehicle->GetClassname(),"choreo"))
  349. {
  350. haptics->ProcessHapticEvent(2,"Movement","ChoreoVehicle");
  351. haptics->SetNavigationClass("vehicle_gun_nofix");//Give this a bit of aiming
  352. }
  353. else
  354. {
  355. haptics->ProcessHapticEvent(2,"Movement","BaseVehicle");
  356. haptics->SetNavigationClass("vehicle_nogun");
  357. }
  358. Msg("VehicleType:%s:\n",vehicle->GetClassname());
  359. }
  360. void HapticsExitedVehicle(C_BaseEntity* vehicle, C_BaseCombatCharacter *pPassenger )
  361. {
  362. // NVNT notify haptics system of navigation change.
  363. haptics->SetNavigationClass("on_foot");
  364. haptics->ProcessHapticEvent(2,"Movement","BasePlayer");
  365. }
  366. #endif