added optional button to restart game (door, panel and touch variants)
[rocksndiamonds.git] / src / libgame / joystick.c
1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // joystick.c
10 // ============================================================================
11
12 #if defined(PLATFORM_FREEBSD)
13 #include <machine/joystick.h>
14 #endif
15
16 #include "joystick.h"
17 #include "misc.h"
18
19
20 // ============================================================================
21 // platform independent joystick functions
22 // ============================================================================
23
24 int getJoystickNrFromDeviceName(char *device_name)
25 {
26   char c;
27   int joystick_nr = 0;
28
29   if (device_name == NULL || device_name[0] == '\0')
30     return 0;
31
32   c = device_name[strlen(device_name) - 1];
33
34   if (c >= '0' && c <= '9')
35     joystick_nr = (int)(c - '0');
36
37   if (joystick_nr < 0 || joystick_nr >= MAX_PLAYERS)
38     joystick_nr = 0;
39
40   return joystick_nr;
41 }
42
43 char *getDeviceNameFromJoystickNr(int joystick_nr)
44 {
45   static char *joystick_device_name[MAX_PLAYERS] =
46   {
47     DEV_JOYSTICK_0,
48     DEV_JOYSTICK_1,
49     DEV_JOYSTICK_2,
50     DEV_JOYSTICK_3
51   };
52
53   return (joystick_nr >= 0 && joystick_nr <= 3 ?
54           joystick_device_name[joystick_nr] : "");
55 }
56
57 char *getFormattedJoystickName(const char *name_raw)
58 {
59   static char name[MAX_JOYSTICK_NAME_LEN + 1];
60   boolean name_skip_space = TRUE;
61   int i, j;
62
63   if (name_raw == NULL)
64     name_raw = "(unknown joystick)";
65
66   // copy joystick name, cutting leading and multiple spaces
67   for (i = 0, j = 0; i < strlen(name_raw) && i < MAX_JOYSTICK_NAME_LEN; i++)
68   {
69     if (name_raw[i] != ' ')
70     {
71       name[j++] = name_raw[i];
72       name_skip_space = FALSE;
73     }
74     else if (!name_skip_space)
75     {
76       name[j++] = name_raw[i];
77       name_skip_space = TRUE;
78     }
79   }
80
81   // cut trailing space
82   if (j > 0 && name[j - 1] == ' ')
83     j--;
84
85   name[j] = '\0';
86
87   return name;
88 }
89
90 static int JoystickPositionPercent(int center, int border, int actual)
91 {
92   int range, position;
93   int percent;
94
95   if (border < center && actual > center)
96     return 0;
97   if (border > center && actual < center)
98     return 0;
99
100   range = ABS(border - center);
101   position = ABS(actual - center);
102
103   percent = (int)(position * 100 / range);
104
105   if (percent > 100)
106     percent = 100;
107
108   return percent;
109 }
110
111 int JoystickExt(int player_nr, boolean use_as_joystick_nr)
112 {
113   int joystick_nr = joystick.nr[player_nr];
114   int js_x, js_y;
115   boolean js_b1, js_b2;
116   int left, right, up, down;
117   int result = JOY_NO_ACTION;
118
119   if (use_as_joystick_nr)
120     joystick_nr = player_nr;
121
122   if (joystick.status != JOYSTICK_ACTIVATED)
123     return JOY_NO_ACTION;
124
125   if (joystick_nr < 0)
126     return JOY_NO_ACTION;
127
128   if (!ReadJoystick(joystick_nr, &js_x, &js_y, &js_b1, &js_b2))
129   {
130     Warn("cannot read joystick device '%s'",
131          setup.input[player_nr].joy.device_name);
132
133     joystick.status = JOYSTICK_NOT_AVAILABLE;
134
135     return JOY_NO_ACTION;
136   }
137
138   left  = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle,
139                                   setup.input[player_nr].joy.xleft,  js_x);
140   right = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle,
141                                   setup.input[player_nr].joy.xright, js_x);
142   up    = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle,
143                                   setup.input[player_nr].joy.yupper, js_y);
144   down  = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle,
145                                   setup.input[player_nr].joy.ylower, js_y);
146
147   if (left > JOYSTICK_PERCENT)
148     result |= JOY_LEFT;
149   else if (right > JOYSTICK_PERCENT)
150     result |= JOY_RIGHT;
151   if (up > JOYSTICK_PERCENT)
152     result |= JOY_UP;
153   else if (down > JOYSTICK_PERCENT)
154     result |= JOY_DOWN;
155
156   if (js_b1)
157     result |= JOY_BUTTON_1;
158   if (js_b2)
159     result |= JOY_BUTTON_2;
160
161   return result;
162 }
163
164 int Joystick(int player_nr)
165 {
166   return JoystickExt(player_nr, FALSE);
167 }
168
169 static int JoystickButtonExt(int player_nr, boolean use_as_joystick_nr)
170 {
171   static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 };
172   int joy_button = (JoystickExt(player_nr, use_as_joystick_nr) & JOY_BUTTON);
173   int result;
174
175   if (joy_button)
176   {
177     if (last_joy_button[player_nr])
178       result = JOY_BUTTON_PRESSED;
179     else
180       result = JOY_BUTTON_NEW_PRESSED;
181   }
182   else
183   {
184     if (last_joy_button[player_nr])
185       result = JOY_BUTTON_NEW_RELEASED;
186     else
187       result = JOY_BUTTON_NOT_PRESSED;
188   }
189
190   last_joy_button[player_nr] = joy_button;
191   return result;
192 }
193
194 int JoystickButton(int player_nr)
195 {
196   return JoystickButtonExt(player_nr, FALSE);
197 }
198
199 int AnyJoystick(void)
200 {
201   int i;
202   int result = 0;
203
204   for (i = 0; i < MAX_PLAYERS; i++)
205     result |= JoystickExt(i, TRUE);
206
207   return result;
208 }
209
210 int AnyJoystickButton(void)
211 {
212   int i;
213   int result = JOY_BUTTON_NOT_PRESSED;
214
215   for (i = 0; i < MAX_PLAYERS; i++)
216   {
217     result = JoystickButtonExt(i, TRUE);
218     if (result != JOY_BUTTON_NOT_PRESSED)
219       break;
220   }
221
222   return result;
223 }