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