Add Mac OS X support for networking; better network code
[tennix.git] / input.c
blob9e6ce9684a566f00af31bcc834e7e7e0a4399c1e
2 /**
4 * Tennix! SDL Port
5 * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
22 **/
24 #include <string.h>
26 #include "tennix.h"
27 #include "graphics.h"
28 #include "game.h"
29 #include "input.h"
30 #include "util.h"
32 static InputDevice devices[MAX_INPUT_DEVICES];
33 static int devices_count;
35 #ifdef TENNIX_PYTHON
36 #include "tennixpy.h"
37 #endif
39 void init_input()
41 int n, x;
43 SDL_JoystickEventState(SDL_ENABLE);
45 #ifndef MAEMO
46 /* keyboard presets */
47 devices[devices_count].type = INPUT_TYPE_KEYBOARD;
48 devices[devices_count].up_key = 'w';
49 devices[devices_count].down_key = 's';
50 devices[devices_count].input_keys[INPUT_KEY_HIT]= 'd';
51 devices[devices_count].input_keys[INPUT_KEY_TOPSPIN] = 'e';
52 devices[devices_count].input_keys[INPUT_KEY_SMASH] = 'f';
53 devices[devices_count].icon = GR_INPUT_KEYBOARD_WS;
54 devices[devices_count].exclusive_to_player = 1;
55 strcpy(devices[devices_count].name, "Keyboard (WS/DEF)");
56 devices_count++;
58 /* keyboard presets */
59 devices[devices_count].type = INPUT_TYPE_KEYBOARD;
60 devices[devices_count].up_key = 'o';
61 devices[devices_count].down_key = 'l';
62 devices[devices_count].input_keys[INPUT_KEY_HIT]= 'k';
63 devices[devices_count].input_keys[INPUT_KEY_TOPSPIN] = 'i';
64 devices[devices_count].input_keys[INPUT_KEY_SMASH] = 'j';
65 devices[devices_count].icon = GR_INPUT_KEYBOARD_OL;
66 devices[devices_count].exclusive_to_player = 2;
67 strcpy(devices[devices_count].name, "Keyboard (OL/KIJ)");
68 devices_count++;
69 #endif
71 /* keyboard presets */
72 devices[devices_count].type = INPUT_TYPE_KEYBOARD;
73 devices[devices_count].up_key = SDLK_UP;
74 devices[devices_count].down_key = SDLK_DOWN;
75 devices[devices_count].input_keys[INPUT_KEY_HIT]= SDLK_SPACE;
76 devices[devices_count].input_keys[INPUT_KEY_TOPSPIN] = SDLK_LCTRL;
77 devices[devices_count].input_keys[INPUT_KEY_SMASH] = SDLK_LALT;
78 #ifdef MAEMO
79 devices[devices_count].icon = GR_INPUT_MAEMO_DPAD;
80 strcpy(devices[devices_count].name, "D-Pad");
81 devices[devices_count].input_keys[INPUT_KEY_HIT]= SDLK_RETURN;
82 /* FIXME: No TOPSPIN and SMASH keys on Maemo yet with d-pad */
83 #else
84 devices[devices_count].icon = GR_INPUT_KEYBOARD_ARROWS;
85 strcpy(devices[devices_count].name, "Keyboard (arrows)");
86 #endif
87 devices_count++;
89 /* mouse */
90 devices[devices_count].type = INPUT_TYPE_MOUSE;
91 devices[devices_count].input_keys[INPUT_KEY_HIT]= SDL_BUTTON(1);
92 devices[devices_count].input_keys[INPUT_KEY_TOPSPIN] = SDL_BUTTON(2);
93 devices[devices_count].input_keys[INPUT_KEY_SMASH] = SDL_BUTTON(3);
94 #ifdef MAEMO
95 devices[devices_count].icon = GR_INPUT_TOUCHSCREEN;
96 strcpy(devices[devices_count].name, "Touchscreen");
97 #else
98 devices[devices_count].icon = GR_INPUT_MOUSE;
99 strcpy(devices[devices_count].name, "Mouse");
100 #endif
101 devices_count++;
103 /* network peer */
104 devices[devices_count].type = INPUT_TYPE_NETWORK;
105 devices[devices_count].icon = GR_INPUT_AI; /* FIXME - network icon! */
106 strcpy(devices[devices_count].name, "Network player");
107 devices_count++;
109 /* joysticks */
110 n = SDL_NumJoysticks();
111 for (x=0; x<n && devices_count<MAX_INPUT_DEVICES; x++) {
112 strcpy(devices[devices_count].name, SDL_JoystickName(x));
113 devices[devices_count].type = INPUT_TYPE_JOYSTICK;
114 devices[devices_count].joystick = SDL_JoystickOpen(x);
115 devices[devices_count].x_axis = 0;
116 devices[devices_count].y_axis = 0;
117 devices[devices_count].input_keys[INPUT_KEY_HIT]= 0;
118 devices[devices_count].input_keys[INPUT_KEY_TOPSPIN] = 1;
119 devices[devices_count].input_keys[INPUT_KEY_SMASH] = 2;
120 devices[devices_count].icon = GR_INPUT_GAMEPAD;
121 devices_count++;
124 #ifdef TENNIX_PYTHON
125 /* This will init Python and load all available bots */
126 tennixpy_init();
127 #endif
131 void uninit_input()
133 int i;
134 SDL_JoystickEventState(SDL_IGNORE);
136 for (i=0; i<devices_count; i++) {
137 if (devices[i].type == INPUT_TYPE_JOYSTICK) {
138 SDL_JoystickClose(devices[i].joystick);
139 #ifdef TENNIX_PYTHON
140 } else if (devices[i].type == INPUT_TYPE_AI_PYTHON) {
141 tennixpy_unregister_bot(devices[i].py_bot_class);
142 #endif
146 #ifdef TENNIX_PYTHON
147 tennixpy_uninit();
148 #endif
150 devices_count = 0;
153 Uint8
154 input_pack_axis(float v)
156 static const float min = -1.2;
157 static const float max = 1.2;
158 assert(v >= min && v < max);
159 return (Uint8)((1U<<7) * (v-min) / (max-min));
162 float
163 input_unpack_axis(Uint8 v)
165 static const float min = -1.2;
166 static const float max = 1.2;
167 assert(v < (1U<<7));
168 return v * (max-min) / (1U<<7) + min;
172 InputDevice* find_input_devices(unsigned int* count)
174 *count = devices_count;
175 return devices;
178 void input_device_join_game(InputDevice* device, void* gamestate, int player_id)
180 if (device == NULL) {
181 /* player is a c-style bot with no device attached */
182 return;
184 fprintf(stderr, "Input Device %s joins the game\n", device->name);
185 #ifdef TENNIX_PYTHON
186 if (device->type == INPUT_TYPE_AI_PYTHON) {
187 device->py_bot = tennixpy_create_bot(device->py_bot_class, (GameState*)gamestate, player_id);
189 #endif
192 void input_device_part_game(InputDevice* device)
194 if (device == NULL) {
195 /* player is a c-style bot with no device attached */
196 return;
198 #ifdef TENNIX_PYTHON
199 if (device->type == INPUT_TYPE_AI_PYTHON) {
200 tennixpy_destroy_bot(device->py_bot);
201 device->py_bot = NULL;
203 #endif
204 fprintf(stderr, "Input Device %s leaves the game\n", device->name);
207 const char* input_device_get_name(InputDevice* d)
209 return d->name;
212 float input_device_get_axis(InputDevice* d, unsigned const char axis) {
213 Uint8 *keystate;
214 Uint8 mb;
215 Uint8 net_value;
216 float result = 0.0;
218 SDL_PumpEvents();
220 if (d->type == INPUT_TYPE_KEYBOARD) {
221 keystate = SDL_GetKeyState(NULL);
222 if (axis == INPUT_AXIS_X) {
223 result = 1.0*keystate[d->right_key] + -1.0*keystate[d->left_key];
224 } else {
225 result = 1.0*keystate[d->down_key] + -1.0*keystate[d->up_key];
227 } else if (d->type == INPUT_TYPE_JOYSTICK) {
228 if (axis == INPUT_AXIS_X) {
229 result = JOYSTICK_PERCENTIZE(SDL_JoystickGetAxis(d->joystick, d->x_axis*2));
230 } else {
231 result = JOYSTICK_PERCENTIZE(SDL_JoystickGetAxis(d->joystick, 1+d->y_axis*2));
233 } else if (d->type == INPUT_TYPE_MOUSE) {
234 mb = SDL_GetMouseState(&d->mx, &d->my);
235 if (axis == INPUT_AXIS_X) {
236 /* Not x-movement yet (PLAYER_MOVE_X is not defined!) */
237 /*if (fabsf(d->mx - d->player_x) > PLAYER_MOVE_X) {
238 if (d->mx > d->player_x) {
239 return 1.0;
240 } else if (d->mx < d->player_x) {
241 return -1.0;
244 } else {
245 if (fabsf(d->my - d->player_y) > PLAYER_MOVE_Y) {
246 if (d->my > d->player_y) {
247 result = 1.0;
248 } else if (d->my < d->player_y) {
249 result = -1.0;
253 #ifdef TENNIX_PYTHON
254 } else if (d->type == INPUT_TYPE_AI_PYTHON) {
255 result = tennixpy_bot_get_axis(d->py_bot, axis);
256 #endif
257 } else if (d->type == INPUT_TYPE_NETWORK) {
258 if (axis == INPUT_AXIS_X) {
259 result = input_unpack_axis(d->net.x);
260 } else if (axis == INPUT_AXIS_Y) {
261 result = input_unpack_axis(d->net.y);
263 } else {
264 assert(0/*unimplemented*/);
267 net_value = input_pack_axis(result);
268 if (axis == INPUT_AXIS_X) {
269 d->net.x = net_value;
270 } else if (axis == INPUT_AXIS_Y) {
271 d->net.y = net_value;
274 return result;
277 char input_device_get_key(InputDevice* d, unsigned const char key) {
278 Uint8 mb;
279 char result = 0;
280 SDL_PumpEvents();
282 if (d->type == INPUT_TYPE_KEYBOARD) {
283 result = SDL_GetKeyState(NULL)[d->input_keys[key]];
284 } else if (d->type == INPUT_TYPE_JOYSTICK) {
285 result = SDL_JoystickGetButton(d->joystick, d->input_keys[key]);
286 } else if (d->type == INPUT_TYPE_MOUSE) {
287 mb = SDL_GetMouseState(NULL, NULL);
288 result = (mb & d->input_keys[key]) != 0;
289 #ifdef TENNIX_PYTHON
290 } else if (d->type == INPUT_TYPE_AI_PYTHON) {
291 result = tennixpy_bot_get_key(d->py_bot, key);
292 #endif
293 } else if (d->type == INPUT_TYPE_NETWORK) {
294 result = (d->net.keys & (1<<key));
295 } else {
296 assert(0/*unimplemented*/);
299 /* Update the input device's NetworkInputData struct */
300 if(result) {
301 d->net.keys |= (1<<key);
302 } else {
303 d->net.keys &= ~(1<<key);
306 return result;
310 #ifdef TENNIX_PYTHON
312 void input_add_python_bot(PyObject* bot_class)
314 if (devices_count < MAX_INPUT_DEVICES) {
315 devices[devices_count].type = INPUT_TYPE_AI_PYTHON;
316 devices[devices_count].icon = GR_INPUT_AI;
317 devices[devices_count].py_bot_class = bot_class;
318 tennixpy_get_bot_name(bot_class, devices[devices_count].name, INPUT_DEVICE_NAME_MAX);
319 fprintf(stderr, " %s", devices[devices_count].name);
320 devices_count++;
321 } else {
322 fprintf(stderr, "Warning: Cannot add any more Python bots.\n");
323 /* We carry a ref of bot_class, so give it up here */
324 tennixpy_unregister_bot(bot_class);
328 #endif