#include "cbase.h" #ifdef CLIENT_DLL #include "tier3/tier3.h" #include "iviewrender.h" #include "inputsystem/iinputsystem.h" #include "vgui/IInputInternal.h" #include "c_basecombatweapon.h" #include "c_baseplayer.h" #include "haptics/ihaptics.h" #include "hud_macros.h" #include "iclientvehicle.h" #include "c_prop_vehicle.h" #include "prediction.h" #include "activitylist.h" #ifdef TERROR #include "ClientTerrorPlayer.h" #endif extern vgui::IInputInternal *g_InputInternal; #else #include "usermessages.h" #endif #include "haptics/haptic_utils.h" #include "haptics/haptic_msgs.h" #ifndef TERROR #ifndef FCVAR_RELEASE #define FCVAR_RELEASE 0 #endif #endif #ifdef CLIENT_DLL ConVar hap_HasDevice ( "hap_HasDevice", "0", FCVAR_USERINFO/*|FCVAR_HIDDEN*/, "falcon is connected" ); // damage scale on a title basis. Convar referenced in the haptic dll. #ifdef PORTAL #define HAP_DEFAULT_DAMAGE_SCALE_GAME "0.75" #elif TF_CLIENT_DLL #define HAP_DEFAULT_DAMAGE_SCALE_GAME "0.3" #else #define HAP_DEFAULT_DAMAGE_SCALE_GAME "1.0" #endif ConVar hap_damagescale_game("hap_damagescale_game", HAP_DEFAULT_DAMAGE_SCALE_GAME); #undef HAP_DEFAULT_DAMAGE_SCALE_GAME #endif void HapticSendWeaponAnim(CBaseCombatWeapon* weapon, int iActivity) { //ignore idle if(iActivity == ACT_VM_IDLE) return; #if defined( CLIENT_DLL ) //if(hap_PrintEvents.GetBool()) // Msg("Client Activity :%s %s %s\n",weapon->GetName(),"Activities",VarArgs("%i",iActivity)); if ( weapon->IsPredicted() ) haptics->ProcessHapticWeaponActivity(weapon->GetName(),iActivity); #else if( !weapon->IsPredicted() && weapon->GetOwner() && weapon->GetOwner()->IsPlayer()) { HapticMsg_SendWeaponAnim( ToBasePlayer(weapon->GetOwner()), iActivity ); } #endif } void HapticSetDrag(CBasePlayer* pPlayer, float drag) { #ifdef CLIENT_DLL haptics->SetDrag(drag); #else HapticMsg_SetDrag( pPlayer, drag ); #endif } #ifdef CLIENT_DLL void HapticsHandleMsg_HapSetDrag( float drag ) { haptics->SetDrag(drag); } #endif void HapticSetConstantForce(CBasePlayer* pPlayer, Vector force) { #ifdef CLIENT_DLL haptics->SetConstantForce(force); #else HapticMsg_SetConstantForce( pPlayer, force ); #endif } #ifdef CLIENT_DLL #ifndef HAPTICS_TEST_PREFIX #define HAPTICS_TEST_PREFIX #endif static CSysModule *pFalconModule =0; void ConnectHaptics(CreateInterfaceFn appFactory) { bool success = false; // NVNT load haptics module pFalconModule = Sys_LoadModule( HAPTICS_TEST_PREFIX HAPTICS_DLL_NAME ); if(pFalconModule) { CreateInterfaceFn factory = Sys_GetFactory( pFalconModule ); if(factory) { haptics = reinterpret_cast< IHaptics* >( factory( HAPTICS_INTERFACE_VERSION, NULL ) ); if(haptics && haptics->Initialize(engine, view, g_InputInternal, gpGlobals, appFactory, g_pVGuiInput->GetIMEWindow(), filesystem, enginevgui, ActivityList_IndexForName, ActivityList_NameForIndex)) { success = true; hap_HasDevice.SetValue(1); } } } if(!success) { Sys_UnloadModule(pFalconModule); pFalconModule = 0; haptics = new CHapticsStubbed; } if(haptics->HasDevice()) { Assert( (void*)haptics == inputsystem->GetHapticsInterfaceAddress() ); } HookHapticMessages(); } void DisconnectHaptics() { haptics->ShutdownHaptics(); if(pFalconModule) { Sys_UnloadModule(pFalconModule); pFalconModule = 0; }else{ // delete the stub. delete haptics; } haptics = NULL; } //Might be able to handle this better... void HapticsHandleMsg_HapSetConst( Vector const &constant ) { //Msg("__MsgFunc_HapSetConst: %f %f %f\n",constant.x,constant.y,constant.z); haptics->SetConstantForce(constant); //C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); } //Might be able to handle this better... void HapticsHandleMsg_SPHapWeapEvent( int iActivity ) { C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); C_BaseCombatWeapon* weap = NULL; if(pPlayer) weap = pPlayer->GetActiveWeapon(); if(weap) haptics->ProcessHapticEvent(4,"Weapons",weap->GetName(),"Activities",VarArgs("%i",iActivity)); } void HapticsHandleMsg_HapPunch( QAngle const &angle ) { haptics->HapticsPunch(1,angle); } #ifdef TERROR ConVar hap_zombie_damage_scale("hap_zombie_damage_scale", "0.25", FCVAR_RELEASE|FCVAR_NEVER_AS_STRING); #endif void HapticsHandleMsg_HapDmg( float pitch, float yaw, float damage, int damageType ) { if(!haptics->HasDevice()) return; #ifdef TERROR C_TerrorPlayer *pPlayer = C_TerrorPlayer::GetLocalTerrorPlayer(); #else C_BasePlayer *pPlayer = CBasePlayer::GetLocalPlayer(); #endif if(pPlayer) { Vector damageDirection; damageDirection.x = cos(pitch*M_PI/180.0)*sin(yaw*M_PI/180.0); damageDirection.y = -sin(pitch*M_PI/180.0); damageDirection.z = -(cos(pitch*M_PI/180.0)*cos(yaw*M_PI/180.0)); #ifdef TERROR if(pPlayer->GetTeamNumber()==TEAM_ZOMBIE) { damageDirection *= hap_zombie_damage_scale.GetFloat(); } #endif haptics->ApplyDamageEffect(damage, damageType, damageDirection); } } ConVar hap_melee_scale("hap_melee_scale", "0.8", FCVAR_RELEASE|FCVAR_NEVER_AS_STRING); void HapticsHandleMsg_HapMeleeContact() { haptics->HapticsPunch(hap_melee_scale.GetFloat(), QAngle(0,0,0)); } ConVar hap_noclip_avatar_scale("hap_noclip_avatar_scale", "0.10f", FCVAR_RELEASE|FCVAR_NEVER_AS_STRING); void UpdateAvatarEffect(void) { if(!haptics->HasDevice()) return; Vector vel; Vector vvel; Vector evel; QAngle eye; C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); if(!pPlayer) return; eye = pPlayer->GetAbsAngles(); if(pPlayer->IsInAVehicle() && pPlayer->GetVehicle()) { pPlayer->GetVehicle()->GetVehicleEnt()->EstimateAbsVelocity(vvel); eye = pPlayer->GetVehicle()->GetVehicleEnt()->EyeAngles(); if(!Q_stristr(pPlayer->GetVehicle()->GetVehicleEnt()->GetClassname(),"choreo")) { eye[YAW] += 90; } } else { vel = pPlayer->GetAbsVelocity(); } Vector PlayerVel = pPlayer->GetAbsVelocity(); //Choreo vehicles use player avatar and don't produce their own velocity if(!pPlayer->GetVehicle() || abs(vvel.Length()) == 0 ) { vel = PlayerVel; } else vel = vvel; VectorYawRotate(vel, -90 -eye[YAW], vel ); vel.y = -vel.y; vel.z = -vel.z; switch(pPlayer->GetMoveType()) { case MOVETYPE_NOCLIP: vel *= hap_noclip_avatar_scale.GetFloat(); break; default: break; } haptics->UpdateAvatarVelocity(vel); } #endif #ifndef CLIENT_DLL void HapticsDamage(CBasePlayer* pPlayer, const CTakeDamageInfo &info) { #if !defined(TF_DLL) && !defined(CSTRIKE_DLL) if(!pPlayer->HasHaptics()) return;// do not send to non haptic users. Vector DamageDirection(0,0,0); CBaseEntity *eInflictor = info.GetInflictor(); // Pat: nuero toxix crash fix if(!eInflictor) { return; } // Player Data Vector playerPosition = pPlayer->GetLocalOrigin(); Vector inflictorPosition = eInflictor->GetLocalOrigin(); Vector posWithDir = playerPosition + (playerPosition - inflictorPosition); pPlayer->WorldToEntitySpace(posWithDir, &DamageDirection); QAngle dir(0,0,0); VectorAngles(DamageDirection, dir); float yawAngle = dir[YAW]; float pitchAngle = dir[PITCH]; int bitDamageType = info.GetDamageType(); if(bitDamageType & DMG_FALL) { pitchAngle = ((float)-90.0); // coming from beneath } else if(bitDamageType & DMG_BURN && (bitDamageType & ~DMG_BURN)==0) { // just burn, use the z axis here. pitchAngle = 0.0; } #ifdef TERROR else if( (bitDamageType & ( DMG_PARALYZE | DMG_NERVEGAS | DMG_POISON | DMG_RADIATION | DMG_DROWNRECOVER | DMG_ACID | DMG_SLOWBURN ) ) && (bitDamageType & ~( DMG_PARALYZE | DMG_NERVEGAS | DMG_POISON | DMG_RADIATION | DMG_DROWNRECOVER | DMG_ACID | DMG_SLOWBURN ) )==0 ) { // it is time based. and should not really do a punch. return; } #endif float sendDamage = info.GetDamage(); if(sendDamage>0.0f) { HapticMsg_HapDmg( pPlayer, pitchAngle, -yawAngle, sendDamage, bitDamageType ); } #endif } void HapticPunch(CBasePlayer* pPlayer, float x, float y, float z) { HapticMsg_Punch( pPlayer, x, y, z ); } void HapticMeleeContact(CBasePlayer* pPlayer) { HapticMsg_MeleeContact( pPlayer ); } #endif // NOT CLIENT_DLL void HapticProcessSound(const char* soundname, int entIndex) { #ifdef CLIENT_DLL if (prediction->InPrediction() && prediction->IsFirstTimePredicted()) { bool local = false; C_BaseEntity *ent = C_BaseEntity::Instance( entIndex ); if(ent) local = (entIndex == -1 || ent == C_BasePlayer::GetLocalPlayer() || ent == C_BasePlayer::GetLocalPlayer()->GetActiveWeapon()); haptics->ProcessHapticEvent(2,"Sounds",soundname); } #endif } #ifdef CLIENT_DLL // NVNT add || defined(OTHER_DEFINITION) if your game uses vehicles. #if defined( HL2_CLIENT_DLL ) #define HAPTIC_VEHICLE_DEFAULT "1" #else #define HAPTIC_VEHICLE_DEFAULT "0" #endif // determines weather the vehicles control box option is faded ConVar hap_ui_vehicles( "hap_ui_vehicles", HAPTIC_VEHICLE_DEFAULT, 0 ); #undef HAPTIC_VEHICLE_DEFAULT void HapticsEnteredVehicle(C_BaseEntity* vehicle, C_BaseCombatCharacter *pPassenger ) { if(!vehicle) return; // NVNT notify haptics system of navigation change. C_PropVehicleDriveable* drivable = dynamic_cast(vehicle); bool hasgun = false; if(drivable) hasgun = drivable->HasGun(); if(Q_stristr(vehicle->GetClassname(),"airboat")) { haptics->ProcessHapticEvent(2,"Movement","airboat"); if(hasgun) haptics->SetNavigationClass("vehicle_gun"); else haptics->SetNavigationClass("vehicle_airboat"); } else if(Q_stristr(vehicle->GetClassname(),"jeepepisodic")) { haptics->ProcessHapticEvent(2,"Movement","BaseVehicle"); haptics->SetNavigationClass("vehicle_nogun"); } else if(Q_stristr(vehicle->GetClassname(),"jeep")) { haptics->ProcessHapticEvent(2,"Movement","BaseVehicle"); haptics->SetNavigationClass("vehicle_gun"); } else if(Q_stristr(vehicle->GetClassname(),"choreo")) { haptics->ProcessHapticEvent(2,"Movement","ChoreoVehicle"); haptics->SetNavigationClass("vehicle_gun_nofix");//Give this a bit of aiming } else { haptics->ProcessHapticEvent(2,"Movement","BaseVehicle"); haptics->SetNavigationClass("vehicle_nogun"); } Msg("VehicleType:%s:\n",vehicle->GetClassname()); } void HapticsExitedVehicle(C_BaseEntity* vehicle, C_BaseCombatCharacter *pPassenger ) { // NVNT notify haptics system of navigation change. haptics->SetNavigationClass("on_foot"); haptics->ProcessHapticEvent(2,"Movement","BasePlayer"); } #endif