1 /* bzflag
2  * Copyright (c) 1993-2021 Tim Riker
3  *
4  * This package is free software;  you can redistribute it and/or
5  * modify it under the terms of the license found in the file
6  * named COPYING that should have accompanied this file.
7  *
8  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11  */
12 
13 /* interface header */
14 #include "ForceFeedback.h"
15 
16 /* common interface headers */
17 #include "BzfJoystick.h"
18 
19 /* local implementation headers */
20 #include "LocalPlayer.h"
21 #include "playing.h"
22 
23 static BzfJoystick*     getJoystick();
24 static bool      useForceFeedback(const char *type = "Rumble");
25 
26 
getJoystick()27 static BzfJoystick*     getJoystick()
28 {
29     MainWindow *win = getMainWindow();
30     if (win)
31         return win->getJoystick();
32     else
33         return NULL;
34 }
35 
useForceFeedback(const char * type)36 static bool      useForceFeedback(const char *type)
37 {
38     BzfJoystick* js = getJoystick();
39 
40     /* There must be a joystick class, and we need an opened joystick device */
41     if (!js)
42         return false;
43     if (!js->joystick())
44         return false;
45 
46     /* Joystick must be the current input method */
47     if (LocalPlayer::getMyTank()->getInputMethod() != LocalPlayer::Joystick)
48         return false;
49 
50     /* Did the user enable force feedback of this type? */
51     if (BZDB.get("forceFeedback") != type)
52         return false;
53 
54     return true;
55 }
56 
57 namespace ForceFeedback
58 {
59 
death()60 void death()
61 {
62     /* Nice long hard rumble for death */
63     if (useForceFeedback("Rumble"))
64         getJoystick()->ffRumble(1, 0.0f, 1.5f, 1.0f, 0.0f);
65     else if (useForceFeedback("Directional"))
66         getJoystick()->ffDirectionalPeriodic(1, 0.0f, 1.5f, 1.0f, 0.0f, 1.0f, 0.15f, BzfJoystick::FF_SawtoothDown);
67 }
68 
shotFired()69 void shotFired()
70 {
71     /* Tiny little kick for a normal shot being fired */
72     if (useForceFeedback("Rumble"))
73         getJoystick()->ffRumble(1, 0.0f, 0.1f, 0.0f, 1.0f);
74     else if (useForceFeedback("Directional"))
75         getJoystick()->ffDirectionalConstant(1, 0.0f, 0.1f, 0.0f, -1.0f, 0.5f);
76 }
77 
laserFired()78 void laserFired()
79 {
80     /* Funky pulsating rumble for the laser.
81      * (Only tested so far with the Logitech Wingman Cordless Rumblepad,
82      *  some quirks in its driver may mean it's feeling a little different
83      *  than it should)
84      */
85     if (useForceFeedback("Rumble"))
86         getJoystick()->ffRumble(4, 0.01f, 0.02f, 1.0f, 1.0f);
87     else if (useForceFeedback("Directional"))
88         getJoystick()->ffDirectionalPeriodic(4, 0.1f, 0.1f, 0.0f, -1.0f, 0.5f, 0.05f, BzfJoystick::FF_Sine);
89 }
90 
shockwaveFired()91 void shockwaveFired()
92 {
93     /* try to 'match' the shockwave sound */
94     if (useForceFeedback("Rumble"))
95         getJoystick()->ffRumble(1, 0.0f, 0.5f, 0.0f, 1.0f);
96     else if (useForceFeedback("Directional"))
97         getJoystick()->ffDirectionalPeriodic(1, 0.0f, 1.0f, 0.0f, -1.0f, 0.5f, 0.1f, BzfJoystick::FF_Sine);
98 }
99 
100 /* Burrowed, oscillating, etc, tanks get a special resistance force
101  * when moving through solid matter.  We use half-second increments
102  * of force-on time.
103  */
104 static TimeKeeper friction_timer = TimeKeeper::getSunGenesisTime();
solidMatterFriction()105 void solidMatterFriction()
106 {
107     /* There is no way to simulate this with a rumble effect */
108     if (useForceFeedback("Directional"))
109     {
110         if ((TimeKeeper::getCurrent() - friction_timer) >= 0.5f)
111         {
112             getJoystick()->ffDirectionalResistance(0.5f, 1.0f, 0.5f, BzfJoystick::FF_Position);
113             friction_timer = TimeKeeper::getCurrent();
114         }
115     }
116 }
117 }
118 
119 // Local Variables: ***
120 // mode: C++ ***
121 // tab-width: 4 ***
122 // c-basic-offset: 4 ***
123 // indent-tabs-mode: nil ***
124 // End: ***
125 // ex: shiftwidth=4 tabstop=4
126