changed number of eater arrays from 8 to 4 for pre-V6 EM engine levels
[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 //                  http://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 #define TRANSLATE_JOYSYMBOL_TO_JOYNAME  0
25 #define TRANSLATE_JOYNAME_TO_JOYSYMBOL  1
26
27 static void translate_joyname(int *joysymbol, char **name, int mode)
28 {
29   static struct
30   {
31     int joysymbol;
32     char *name;
33   } translate_joy[] =
34   {
35     { JOY_LEFT,         "joystick_left" },
36     { JOY_RIGHT,        "joystick_right" },
37     { JOY_UP,           "joystick_up" },
38     { JOY_DOWN,         "joystick_down" },
39     { JOY_BUTTON_1,     "joystick_button_1" },
40     { JOY_BUTTON_2,     "joystick_button_2" },
41   };
42
43   int i;
44
45   if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME)
46   {
47     *name = "[undefined]";
48
49     for (i = 0; i < 6; i++)
50     {
51       if (*joysymbol == translate_joy[i].joysymbol)
52       {
53         *name = translate_joy[i].name;
54         break;
55       }
56     }
57   }
58   else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL)
59   {
60     *joysymbol = 0;
61
62     for (i = 0; i < 6; i++)
63     {
64       if (strEqual(*name, translate_joy[i].name))
65       {
66         *joysymbol = translate_joy[i].joysymbol;
67         break;
68       }
69     }
70   }
71 }
72
73 char *getJoyNameFromJoySymbol(int joysymbol)
74 {
75   char *name;
76
77   translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME);
78   return name;
79 }
80
81 int getJoySymbolFromJoyName(char *name)
82 {
83   int joysymbol;
84
85   translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL);
86   return joysymbol;
87 }
88
89 int getJoystickNrFromDeviceName(char *device_name)
90 {
91   char c;
92   int joystick_nr = 0;
93
94   if (device_name == NULL || device_name[0] == '\0')
95     return 0;
96
97   c = device_name[strlen(device_name) - 1];
98
99   if (c >= '0' && c <= '9')
100     joystick_nr = (int)(c - '0');
101
102   if (joystick_nr < 0 || joystick_nr >= MAX_PLAYERS)
103     joystick_nr = 0;
104
105   return joystick_nr;
106 }
107
108 char *getDeviceNameFromJoystickNr(int joystick_nr)
109 {
110   static char *joystick_device_name[MAX_PLAYERS] =
111   {
112     DEV_JOYSTICK_0,
113     DEV_JOYSTICK_1,
114     DEV_JOYSTICK_2,
115     DEV_JOYSTICK_3
116   };
117
118   return (joystick_nr >= 0 && joystick_nr <= 3 ?
119           joystick_device_name[joystick_nr] : "");
120 }
121
122 char *getFormattedJoystickName(const char *name_raw)
123 {
124   static char name[MAX_JOYSTICK_NAME_LEN + 1];
125   boolean name_skip_space = TRUE;
126   int i, j;
127
128   if (name_raw == NULL)
129     name_raw = "(unknown joystick)";
130
131   // copy joystick name, cutting leading and multiple spaces
132   for (i = 0, j = 0; i < strlen(name_raw) && i < MAX_JOYSTICK_NAME_LEN; i++)
133   {
134     if (name_raw[i] != ' ')
135     {
136       name[j++] = name_raw[i];
137       name_skip_space = FALSE;
138     }
139     else if (!name_skip_space)
140     {
141       name[j++] = name_raw[i];
142       name_skip_space = TRUE;
143     }
144   }
145
146   // cut trailing space
147   if (j > 0 && name[j - 1] == ' ')
148     j--;
149
150   name[j] = '\0';
151
152   return name;
153 }
154
155 static int JoystickPositionPercent(int center, int border, int actual)
156 {
157   int range, position;
158   int percent;
159
160   if (border < center && actual > center)
161     return 0;
162   if (border > center && actual < center)
163     return 0;
164
165   range = ABS(border - center);
166   position = ABS(actual - center);
167
168   percent = (int)(position * 100 / range);
169
170   if (percent > 100)
171     percent = 100;
172
173   return percent;
174 }
175
176 void CheckJoystickData(void)
177 {
178   int i;
179   int distance = 100;
180
181   for (i = 0; i < MAX_PLAYERS; i++)
182   {
183     if (setup.input[i].joy.xleft >= setup.input[i].joy.xmiddle)
184       setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance;
185     if (setup.input[i].joy.xright <= setup.input[i].joy.xmiddle)
186       setup.input[i].joy.xright = setup.input[i].joy.xmiddle + distance;
187
188     if (setup.input[i].joy.yupper >= setup.input[i].joy.ymiddle)
189       setup.input[i].joy.yupper = setup.input[i].joy.ymiddle - distance;
190     if (setup.input[i].joy.ylower <= setup.input[i].joy.ymiddle)
191       setup.input[i].joy.ylower = setup.input[i].joy.ymiddle + distance;
192   }
193 }
194
195 int JoystickExt(int player_nr, boolean use_as_joystick_nr)
196 {
197   int joystick_nr = joystick.nr[player_nr];
198   int js_x, js_y;
199   boolean js_b1, js_b2;
200   int left, right, up, down;
201   int result = JOY_NO_ACTION;
202
203   if (use_as_joystick_nr)
204     joystick_nr = player_nr;
205
206   if (joystick.status != JOYSTICK_ACTIVATED)
207     return JOY_NO_ACTION;
208
209   if (joystick_nr < 0)
210     return JOY_NO_ACTION;
211
212   if (!ReadJoystick(joystick_nr, &js_x, &js_y, &js_b1, &js_b2))
213   {
214     Error(ERR_WARN, "cannot read joystick device '%s'",
215           setup.input[player_nr].joy.device_name);
216
217     joystick.status = JOYSTICK_NOT_AVAILABLE;
218     return JOY_NO_ACTION;
219   }
220
221   left  = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle,
222                                   setup.input[player_nr].joy.xleft,  js_x);
223   right = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle,
224                                   setup.input[player_nr].joy.xright, js_x);
225   up    = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle,
226                                   setup.input[player_nr].joy.yupper, js_y);
227   down  = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle,
228                                   setup.input[player_nr].joy.ylower, js_y);
229
230   if (left > JOYSTICK_PERCENT)
231     result |= JOY_LEFT;
232   else if (right > JOYSTICK_PERCENT)
233     result |= JOY_RIGHT;
234   if (up > JOYSTICK_PERCENT)
235     result |= JOY_UP;
236   else if (down > JOYSTICK_PERCENT)
237     result |= JOY_DOWN;
238
239   if (js_b1)
240     result |= JOY_BUTTON_1;
241   if (js_b2)
242     result |= JOY_BUTTON_2;
243
244   return result;
245 }
246
247 int Joystick(int player_nr)
248 {
249   return JoystickExt(player_nr, FALSE);
250 }
251
252 static int JoystickButtonExt(int player_nr, boolean use_as_joystick_nr)
253 {
254   static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 };
255   int joy_button = (JoystickExt(player_nr, use_as_joystick_nr) & JOY_BUTTON);
256   int result;
257
258   if (joy_button)
259   {
260     if (last_joy_button[player_nr])
261       result = JOY_BUTTON_PRESSED;
262     else
263       result = JOY_BUTTON_NEW_PRESSED;
264   }
265   else
266   {
267     if (last_joy_button[player_nr])
268       result = JOY_BUTTON_NEW_RELEASED;
269     else
270       result = JOY_BUTTON_NOT_PRESSED;
271   }
272
273   last_joy_button[player_nr] = joy_button;
274   return result;
275 }
276
277 int JoystickButton(int player_nr)
278 {
279   return JoystickButtonExt(player_nr, FALSE);
280 }
281
282 int AnyJoystick(void)
283 {
284   int i;
285   int result = 0;
286
287   for (i = 0; i < MAX_PLAYERS; i++)
288     result |= JoystickExt(i, TRUE);
289
290   return result;
291 }
292
293 int AnyJoystickButton(void)
294 {
295   int i;
296   int result = JOY_BUTTON_NOT_PRESSED;
297
298   for (i = 0; i < MAX_PLAYERS; i++)
299   {
300     result = JoystickButtonExt(i, TRUE);
301     if (result != JOY_BUTTON_NOT_PRESSED)
302       break;
303   }
304
305   return result;
306 }
307
308 void DeactivateJoystick(void)
309 {
310   /* Temporarily deactivate joystick. This is needed for calibration
311      screens, where the player has to select a joystick device that
312      should be calibrated. If there is a totally uncalibrated joystick
313      active, it may be impossible (due to messed up input from joystick)
314      to select the joystick device to calibrate even when trying to use
315      the mouse or keyboard to select the device. */
316
317   if (joystick.status & JOYSTICK_AVAILABLE)
318     joystick.status &= ~JOYSTICK_ACTIVE;
319 }
320
321 void ActivateJoystick(void)
322 {
323   // reactivate temporarily deactivated joystick
324
325   if (joystick.status & JOYSTICK_AVAILABLE)
326     joystick.status |= JOYSTICK_ACTIVE;
327 }