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 +