Mercurial > hg > index.fcgi > lj > lj046
diff src/pcjoy.c @ 0:c84446dfb3f5
initial add
author | paulo@localhost |
---|---|
date | Fri, 13 Mar 2009 00:39:12 -0700 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/pcjoy.c Fri Mar 13 00:39:12 2009 -0700 1.3 @@ -0,0 +1,503 @@ 1.4 +/* PC joystick code 1.5 + 1.6 +Copyright (C) 2006 Damian Yerrick <tepples+lj@spamcop.net> 1.7 + 1.8 +This work is free software; you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation; either version 2 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with this program; if not, write to the Free Software 1.20 +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1.21 + 1.22 +Original game concept and design by Alexey Pajitnov. 1.23 +The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg, 1.24 +or The Tetris Company LLC. 1.25 + 1.26 +*/ 1.27 + 1.28 +#include "pcjoy.h" 1.29 +#include <allegro.h> 1.30 +#include <string.h> 1.31 +#include "ljpath.h" 1.32 + 1.33 +extern const FONT *aver32, *aver16; 1.34 +extern int bgColor, fgColor, hiliteColor; 1.35 + 1.36 +static volatile int lastScancodePressed = -1; 1.37 +static void (*oldKeyListener)(int scancode); 1.38 +volatile int wantsClose = 0; 1.39 +void ezPlaySample(const char *filename, int vol); 1.40 + 1.41 +static void ljpcKeyListener(int scancode) { 1.42 + if (!(scancode & 0x80)) { 1.43 + lastScancodePressed = scancode; 1.44 + } 1.45 + if (oldKeyListener) { 1.46 + oldKeyListener(scancode); 1.47 + } 1.48 +} END_OF_FUNCTION(ljpcKeyListener); 1.49 + 1.50 + 1.51 +/** 1.52 + * Presses the escape key when the user clicks the close box. 1.53 + */ 1.54 +static void setWantsClose() { 1.55 + wantsClose = 1; 1.56 +} 1.57 + 1.58 +static int withJoystick = 0; 1.59 + 1.60 +#define N_VKEYS 14 1.61 +#define N_PLAYERS 2 1.62 + 1.63 +static const char keysFileName[] = "lj-keys.043"; 1.64 + 1.65 +static const struct pkeyMapping defaultKeymappings[N_PLAYERS][N_VKEYS] = { 1.66 + { 1.67 + // [0]: player 1 1.68 + {-1, -1, KEY_UP}, 1.69 + {-1, -1, KEY_DOWN}, 1.70 + {-1, -1, KEY_LEFT}, 1.71 + {-1, -1, KEY_RIGHT}, 1.72 + {-1, -1, KEY_Z}, 1.73 + {-1, -1, KEY_X}, 1.74 + {-1, -1, KEY_S}, 1.75 + {-1, -1, KEY_SPACE}, 1.76 + {-1, -1, KEY_C}, 1.77 + {-1, -1, KEY_W}, 1.78 + {-1, -1, KEY_Q}, 1.79 + {-1, -1, KEY_E}, 1.80 + {-1, -1, KEY_ENTER}, 1.81 + {-1, -1, KEY_D} 1.82 + }, 1.83 + { 1.84 + // [1]: player 2 1.85 + {-1, -1, KEY_UP}, 1.86 + {-1, -1, KEY_DOWN}, 1.87 + {-1, -1, KEY_LEFT}, 1.88 + {-1, -1, KEY_RIGHT}, 1.89 + {-1, -1, KEY_Z}, 1.90 + {-1, -1, KEY_X}, 1.91 + {-1, -1, KEY_S}, 1.92 + {-1, -1, KEY_SPACE}, 1.93 + {-1, -1, KEY_C}, 1.94 + {-1, -1, KEY_W}, 1.95 + {-1, -1, KEY_Q}, 1.96 + {-1, -1, KEY_E}, 1.97 + {-1, -1, KEY_ENTER}, 1.98 + {-1, -1, KEY_D} 1.99 + } 1.100 +}; 1.101 + 1.102 +static struct pkeyMapping keymappings[N_PLAYERS][N_VKEYS]; 1.103 + 1.104 +void getPkeyName(char *dst, int j, int s, int a) { 1.105 + if (j < 0) { 1.106 + if (a >= 0 && a < KEY_MAX) { 1.107 + usprintf(dst, "Key %d (%s)", a, scancode_to_name(a)); 1.108 + } else { 1.109 + usprintf(dst, "Key %d (???"")", a); 1.110 + } 1.111 + } else if (s < 0) { 1.112 + usprintf(dst, 1.113 + "Joy %d button %s", 1.114 + j, 1.115 + joy[j].button[a].name); 1.116 + } else if (a < 0) { 1.117 + usprintf(dst, 1.118 + "Joy %d stick %s axis %s -", 1.119 + j, 1.120 + joy[j].stick[s].name, 1.121 + joy[j].stick[s].axis[~a].name); 1.122 + } else { 1.123 + usprintf(dst, 1.124 + "Joy %d stick %s axis %s +", 1.125 + j, 1.126 + joy[j].stick[s].name, 1.127 + joy[j].stick[s].axis[a].name); 1.128 + } 1.129 +} 1.130 + 1.131 +static int getPkeyState(int j, int s, int a) { 1.132 + int k; 1.133 + if (j < 0) { 1.134 + k = key[a]; 1.135 + } else if (s < 0) { 1.136 + k = joy[j].button[a].b; 1.137 + } else if (a < 0) { 1.138 + k = joy[j].stick[s].axis[~a].d1; 1.139 + } else { 1.140 + k = joy[j].stick[s].axis[a].d2; 1.141 + } 1.142 + return k; 1.143 +} 1.144 + 1.145 +const char *const vkeyNames[] = { 1.146 + "Hard Drop (Up)", 1.147 + "Soft Drop (Down)", 1.148 + "Left", 1.149 + "Right", 1.150 + "Rotate Left", 1.151 + "Rotate Right", 1.152 + "Hold", 1.153 + "Item (unused)", 1.154 + "Alt. Rotate Left", 1.155 + "Rotate Left Twice", 1.156 + "Far Left", 1.157 + "Far Right", 1.158 + "Alt. Firm Drop", 1.159 + "Alt. Hold", 1.160 + "Macro G", 1.161 + "Macro H" 1.162 +}; 1.163 + 1.164 +static int getVkeyState(int player, int vkey) { 1.165 + int j = keymappings[player][vkey].joy; 1.166 + int s = keymappings[player][vkey].stick; 1.167 + int a = keymappings[player][vkey].axis; 1.168 + 1.169 + return getPkeyState(j, s, a); 1.170 +} 1.171 + 1.172 +LJBits readPad(unsigned int player) { 1.173 + int keys = 0; 1.174 + poll_joystick(); 1.175 + 1.176 + for (int i = 0; 1.177 + i < N_VKEYS; 1.178 + ++i) { 1.179 + if (getVkeyState(player, i)) { 1.180 + keys |= 1 << i; 1.181 + } 1.182 + } 1.183 + return keys; 1.184 +} 1.185 + 1.186 +LJBits menuReadPad(void) { 1.187 + if (key[KEY_ENTER]) { 1.188 + return VKEY_ROTR | VKEY_START; 1.189 + } else if (key[KEY_ESC]) { 1.190 + return VKEY_ROTL; 1.191 + } else if (key[KEY_UP]) { 1.192 + return VKEY_UP; 1.193 + } else if (key[KEY_DOWN]) { 1.194 + return VKEY_DOWN; 1.195 + } else if (key[KEY_LEFT]) { 1.196 + return VKEY_LEFT; 1.197 + } else if (key[KEY_RIGHT]) { 1.198 + return VKEY_RIGHT; 1.199 + } else { 1.200 + return readPad(0) | readPad(1); 1.201 + } 1.202 +} 1.203 + 1.204 +// These contain the states of ALL buttons on ALL 1.205 +// joysticks 1.206 +static LJBits lastConfigButtons[8]; 1.207 +static LJBits lastConfigStickAxis[8]; 1.208 + 1.209 +static int newButton(int *outJ, int *outS, int *outA) { 1.210 + poll_joystick(); 1.211 + int found = 0; 1.212 + 1.213 + if (lastScancodePressed >= 0) { 1.214 + *outJ = -1; 1.215 + *outS = -1; 1.216 + *outA = lastScancodePressed; 1.217 + lastScancodePressed = -1; 1.218 + return 1; 1.219 + } 1.220 + 1.221 + for (int j = 0; 1.222 + j < num_joysticks; 1.223 + ++j) { 1.224 + LJBits cur = 0; 1.225 + 1.226 + for (int b = 0; b < joy[j].num_buttons; ++b) { 1.227 + if (joy[j].button[b].b) { 1.228 + if (!(lastConfigButtons[j] & (1 << b)) && !found) { 1.229 + *outJ = j; 1.230 + *outS = -1; 1.231 + *outA = b; 1.232 + found = 1; 1.233 + } 1.234 + cur |= 1 << b; 1.235 + } 1.236 + } 1.237 + lastConfigButtons[j] = cur; 1.238 + } 1.239 + if (found) { 1.240 + return 1; 1.241 + } 1.242 + 1.243 + for (int j = 0; 1.244 + j < num_joysticks; 1.245 + ++j) { 1.246 + LJBits cur = 0; 1.247 + LJBits mask = 1; 1.248 + 1.249 + for (int s = 0; s < joy[j].num_sticks; ++s) { 1.250 + for (int a = 0; a < joy[j].stick[s].num_axis; ++a) { 1.251 + if (joy[j].stick[s].axis[a].d1) { 1.252 + if (!(lastConfigStickAxis[j] & mask) && !found) { 1.253 + *outJ = j; 1.254 + *outS = s; 1.255 + *outA = ~a; 1.256 + found = 1; 1.257 + } 1.258 + cur |= mask; 1.259 + } 1.260 + mask <<= 1; 1.261 + if (joy[j].stick[s].axis[a].d2) { 1.262 + if (!(lastConfigStickAxis[j] & mask) && !found) { 1.263 + *outJ = j; 1.264 + *outS = s; 1.265 + *outA = a; 1.266 + found = 1; 1.267 + } 1.268 + cur |= mask; 1.269 + } 1.270 + mask <<= 1; 1.271 + } 1.272 + } 1.273 + lastConfigStickAxis[j] = cur; 1.274 + } 1.275 + return found; 1.276 +} 1.277 + 1.278 +static void clearNewButton(void) { 1.279 + int j, s, a; 1.280 + while (newButton(&j, &s, &a)); 1.281 +} 1.282 + 1.283 +void loadKeys(const char *filename) { 1.284 + FILE *fp = ljfopen(filename, "rb"); 1.285 + 1.286 + memcpy(keymappings, defaultKeymappings, sizeof(keymappings)); 1.287 + if (fp) { 1.288 + for (unsigned int player = 0; player < 2; ++player) { 1.289 + for (unsigned int vkey = 0; 1.290 + vkey < N_VKEYS; 1.291 + ++vkey) { 1.292 + int j = fgetc(fp); 1.293 + int s = fgetc(fp); 1.294 + int a = fgetc(fp); 1.295 + 1.296 + if (a == EOF) { 1.297 + break; 1.298 + } 1.299 + keymappings[player][vkey].joy = j; 1.300 + keymappings[player][vkey].stick = s; 1.301 + keymappings[player][vkey].axis = a; 1.302 + } 1.303 + } 1.304 + fclose(fp); 1.305 + } 1.306 +} 1.307 + 1.308 +void saveKeys(const char *filename) { 1.309 + FILE *fp = ljfopen(filename, "wb"); 1.310 + 1.311 + if (fp) { 1.312 + for (unsigned int player = 0; player < 2; ++player) { 1.313 + for (unsigned int vkey = 0; 1.314 + vkey < N_VKEYS && !feof(fp); 1.315 + ++vkey) { 1.316 + fputc(keymappings[player][vkey].joy, fp); 1.317 + fputc(keymappings[player][vkey].stick, fp); 1.318 + fputc(keymappings[player][vkey].axis, fp); 1.319 + } 1.320 + } 1.321 + fclose(fp); 1.322 + } 1.323 +} 1.324 + 1.325 +#define VKEY_ROWHT 24 1.326 +#define VKEY_TOP 120 1.327 + 1.328 +void drawVkeyRow(int vkey, int hilite) { 1.329 + char name[256]; 1.330 + int y = VKEY_TOP + vkey * VKEY_ROWHT; 1.331 + 1.332 + rectfill(screen, 1.333 + 16, y, 719, y + VKEY_ROWHT - 1, 1.334 + hilite ? hiliteColor : bgColor); 1.335 + textout_ex(screen, aver16, vkeyNames[vkey], 24, y + 4, fgColor, -1); 1.336 + for (int player = 0; player < N_PLAYERS; ++player) { 1.337 + if (player + 1 == hilite) { 1.338 + rect(screen, 1.339 + 240 + 240 * player, y, 1.340 + 479 + 240 * player, y + VKEY_ROWHT - 1, 1.341 + fgColor); 1.342 + } 1.343 + getPkeyName(name, 1.344 + keymappings[player][vkey].joy, 1.345 + keymappings[player][vkey].stick, 1.346 + keymappings[player][vkey].axis); 1.347 + textout_ex(screen, aver16, name, 240 + 240 * player, y + 4, fgColor, -1); 1.348 + } 1.349 +} 1.350 + 1.351 +/** 1.352 + * Waits for a key or button press. If any key but Esc is pressed, 1.353 + * reassigns the vkey. Otherwise, does nothing. 1.354 + * @param vkey the index of the vkey to reassign 1.355 + * @return 0 if key not changed; nonzero if key was changed 1.356 + */ 1.357 +static int changeKey(int player, int vkey) { 1.358 + int changed = 0; 1.359 + int phase = 0; 1.360 + 1.361 + clearNewButton(); 1.362 + while (!changed) { 1.363 + int j, s, a; 1.364 + 1.365 + if (phase == 5) { 1.366 + drawVkeyRow(vkey, 0); 1.367 + } else if (phase == 0) { 1.368 + drawVkeyRow(vkey, player + 1); 1.369 + phase = 15; 1.370 + } 1.371 + --phase; 1.372 + 1.373 + if (keypressed()) { 1.374 + int scancode; 1.375 + ureadkey(&scancode); 1.376 + if (scancode == KEY_ESC) { 1.377 + changed = -1; 1.378 + } 1.379 + } 1.380 + if (vkey < N_VKEYS && newButton(&j, &s, &a)) { 1.381 + if (j >= 0 || s > 0 || a != KEY_ESC) { 1.382 + keymappings[player][vkey].joy = j; 1.383 + keymappings[player][vkey].stick = s; 1.384 + keymappings[player][vkey].axis = a; 1.385 + ezPlaySample("nextS_wav", 128); 1.386 + changed = 1; 1.387 + } else { 1.388 + changed = -1; 1.389 + } 1.390 + } 1.391 + if (wantsClose) { 1.392 + changed = -1; 1.393 + } 1.394 + 1.395 + rest(30); 1.396 + } 1.397 + 1.398 + // Draw new vkey value 1.399 + drawVkeyRow(vkey, 0); 1.400 + return changed > 0; 1.401 +} 1.402 + 1.403 +void configureKeys(void) { 1.404 + clear_to_color(screen, bgColor); 1.405 + textout_ex(screen, aver32, "LOCKJAW > Game Keys", 16, 32, fgColor, -1); 1.406 + textout_ex(screen, aver16, 1.407 + "Use arrow keys to select a key. To reassign the selected key, press Enter", 1.408 + 40, 80, fgColor, -1); 1.409 + textout_ex(screen, aver16, 1.410 + "and then the key you want to use. When done, press Esc.", 1.411 + 40, 96, fgColor, -1); 1.412 + 1.413 + // Draw each vkey's name 1.414 + for (int vkey = 0; vkey < N_VKEYS; ++vkey) { 1.415 + drawVkeyRow(vkey, 0); 1.416 + } 1.417 + 1.418 + clearNewButton(); 1.419 + int vkey = 0; 1.420 + int player = 0; 1.421 + 1.422 + drawVkeyRow(vkey, player + 1); 1.423 + 1.424 + while (vkey >= 0 && !wantsClose) { 1.425 + int scancode = 0; 1.426 + 1.427 + rest(30); 1.428 + if (keypressed()) { 1.429 + ureadkey(&scancode); 1.430 + } 1.431 + 1.432 + switch (scancode) { 1.433 + 1.434 + case KEY_RIGHT: 1.435 + if (player < N_PLAYERS - 1) { 1.436 + ezPlaySample("shift_wav", 128); 1.437 + drawVkeyRow(vkey, 0); 1.438 + ++player; 1.439 + drawVkeyRow(vkey, player + 1); 1.440 + } 1.441 + break; 1.442 + 1.443 + case KEY_LEFT: 1.444 + if (player > 0) { 1.445 + ezPlaySample("shift_wav", 128); 1.446 + drawVkeyRow(vkey, 0); 1.447 + --player; 1.448 + drawVkeyRow(vkey, player + 1); 1.449 + } 1.450 + break; 1.451 + 1.452 + case KEY_UP: 1.453 + if (vkey > 0) { 1.454 + ezPlaySample("shift_wav", 128); 1.455 + drawVkeyRow(vkey, 0); 1.456 + --vkey; 1.457 + drawVkeyRow(vkey, player + 1); 1.458 + } 1.459 + break; 1.460 + case KEY_DOWN: 1.461 + if (vkey < N_VKEYS - 1) { 1.462 + ezPlaySample("shift_wav", 128); 1.463 + drawVkeyRow(vkey, 0); 1.464 + ++vkey; 1.465 + drawVkeyRow(vkey, player + 1); 1.466 + } 1.467 + break; 1.468 + case KEY_ENTER: 1.469 + ezPlaySample("rotate_wav", 96); 1.470 + while (vkey < N_VKEYS && changeKey(player, vkey)) { 1.471 + rest(150); 1.472 + ++vkey; 1.473 + } 1.474 + if (vkey >= N_VKEYS) { 1.475 + ezPlaySample("land_wav", 128); 1.476 + vkey = N_VKEYS - 1; 1.477 + } else { 1.478 + ezPlaySample("nextO_wav", 128); 1.479 + } 1.480 + drawVkeyRow(vkey, player + 1); 1.481 + break; 1.482 + case KEY_ESC: 1.483 + vkey = -1; 1.484 + break; 1.485 + } 1.486 + } 1.487 + saveKeys(keysFileName); 1.488 + ezPlaySample("line_wav", 128); 1.489 +} 1.490 + 1.491 + 1.492 +void initKeys(void) { 1.493 + LOCK_FUNCTION(ljpcKeyListener); 1.494 + LOCK_VARIABLE(lastScancodePressed); 1.495 + LOCK_VARIABLE(oldKeyListener); 1.496 + LOCK_FUNCTION(setWantsClose); 1.497 + LOCK_VARIABLE(wantsClose); 1.498 + 1.499 + oldKeyListener = keyboard_lowlevel_callback; 1.500 + keyboard_lowlevel_callback = ljpcKeyListener; 1.501 + withJoystick = !install_joystick(JOY_TYPE_AUTODETECT); 1.502 + loadKeys(keysFileName); 1.503 + set_close_button_callback(setWantsClose); 1.504 +} 1.505 + 1.506 +