/********************************************************************** * * * sjcursed.c (March 5, 2006): Password generator for Solar * * Jetman: Hunt for the Golden Warpship. * * * * Copyright 2003-2006 David Lawrence Ramsey * * * * Copyright 2006 Joel Yliluoma * * * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public * * License along with this program; if not, write to the Free * * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * * MA 02110-1301, USA. * * * **********************************************************************/ /********************************************************************** * * * This program requires a curses library. You can compile it as * * follows: * * * * cc sjcursed.c -o sjcursed -lcurses * * * **********************************************************************/ /********************************************************************** * * * Password information: * * * * Every password is 12 letters long, each one of which * * corresponds to a 4-bit value. The letters B, D, G, H, K, L, M, * * N, P, Q, R, T, V, W, X, and Z represent the values 0, 1, 2, 3, * * 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, and 15, respectively. * * * * Letter 1: * * 4 bits used to hold the number of lives you have. * * * * Possible range: 0-15. * * * * Letter 2: * * 4 bits used to hold the 1's digit of the amount of cash you * * have. * * * * Possible range: 0-9. * * * * Letter 3: * * 4 bits used to hold the first 4 bits of the number of the * * planet you're on. * * * * Possible range: 0-15. * * * * Letter 4: * * 4 bits used to hold the first checksum value. * * * * Possible range: 0-15. * * * * Letter 5: * * 4 bits used to hold the 100's digit of the amount of cash you * * have. * * * * Possible range: 0-9. * * * * Letter 6: * * 4 bits used to hold the 10's digit of the amount of cash you * * have. * * * * Possible range: 0-9. * * * * Letter 7: * * 4 bits used to hold the 1000's digit of the amount of cash * * you have. * * * * Possible range: 0-9. * * * * Letter 8: * * 4 bits used to hold the 10000's digit of the amount of cash * * you have. * * * * Possible range: 0-9. * * * * Letter 9: * * First 2 bits used to hold the last 2 bits of the number of * * the planet you're on. Last 2 bits used to hold the type of * * mapping device you have. If neither of these is set, you * * have no mapping device. If the first of these is set, you * * have the normal mapping device. If the second of these is * * set, you have the super mapping device. If both of these are * * set, you have both mapping devices, in which case the super * * mapping device overrides the normal mapping device. * * * * Possible range: 0-15. * * * * Letter 10: * * 4 bits used to hold the second checksum value. * * * * Possible range: 0-15. * * * * Letter 11: * * First 2 bits used to hold the type of pod you have. If * * neither of these is set, you have the normal jetpod. If the * * first of these is set, you have the Italian jetpod. If the * * second of these is set, you have the Nippon jetpod. If both * * of these are set, it's invalid. Last two bits used to hold * * the accessories you have. If neither of these is set, you * * don't have shields or boosters. If the first of these is * * set, you have shields but no boosters. If the second of * * these is set, you have boosters but no shields. If both of * * these are set, you have both shields and boosters. * * * * Possible range: 0-11. * * * * Letter 12: * * 4 bits used to hold the 100000's digit of the amount of cash * * you have. * * * * Possible range: 0-9. * * * * Letter range problems: * * * * 1. Having 0 lives makes no sense, so the value of letter 1 * * should only be in the range 1-15. * * 2. There are only 13 planets in the game, so the value of * * letter 3, left-shifted 2 times, plus the value of letter 9, * * right-shifted twice, should only be in the range 0-12. * * * * Letter range inconsistency: * * * * 1. Having both the normal mapping device and the super mapping * * device will make the latter override the former. However, * * having both the Nippon and Italian jetpods will not make the * * latter override the former, but will instead be treated as * * invalid. * * * **********************************************************************/ #include #include #include #include #define INPUT_LEN_MAX 12 #define CHECKSUM_1 3 #define CHECKSUM_2 9 const int input_max[INPUT_LEN_MAX] = {15, 9, 15, -1, 9, 9, 9, 9, 15, -1, 11, 9}; const char letter_set[16] = "BDGHKLMNPQRTVWXZ"; const char *system_names[22] = {"(Zandor)", "(Frobof)", "(Mugrim)", "(Shobas)", "(Xexorm)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)", "(Invalid System)"}; const char *planet_names[64] = {"(Preludon)", "(Mexomorf)", "(Omebru)", "(Corso Qwero)", "(Bokky)", "(Lemonte)", "(Chorlton)", "(Shishkebab)", "(Zlaz Tordus)", "(Shammy Gen)", "(Shankoo)", "(Miplezur)", "(Urownd)", "(Dryn Kup Leez)/(Preludon Warpship Part Area)", "(Mexomorf Warpship Part Area)", "(Omebru Warpship Part Area)", "(Corso Qwero Warpship Part Area)", "(Bokky Warpship Part Area)", "(Lemonte Warpship Part Area)", "(Chorlton Warpship Part Area)", "(Shishkebab Warpship Part Area)", "(Zlaz Tordus Warpship Part Area)", "(Shammy Gen Warpship Part Area)", "(Shankoo Warpship Part Area)", "(Miplezur Warpship Part Area)", "(Urownd Warpship Part Area)", "(Golden Warpship Level, glitchy)", "(Omebru Warp Zone to Bokky, Lemonte, or Chorlton)", "(Lemonte Warp Zone to Zlaz Tordus or Shammy Gen)", "(Preludon Cyberzone)", "(Mexomorf Cyberzone)", "(Omebru Cyberzone)", "(Corso Qwero Cyberzone)", "(Bokky Cyberzone)", "(Lemonte Cyberzone)", "(Chorlton Cyberzone)", "(Shishkebab Cyberzone)", "(Zlaz Tordus Cyberzone)", "(Shammy Gen Cyberzone)", "(Shankoo Cyberzone)", "(Miplezur Cyberzone)", "(Urownd Cyberzone)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)", "(Invalid Level, glitchy)"}; char number_to_letter(int number) { const char *result = letter_set; if (number < 0 || number > 15) return '?'; for (; number > 0; number--, result++) ; return *result; } /* Many thanks to Joel Yliluoma for helping simplify this function. */ void get_checksums(int l1, int l2, int l3, int *checksum1, int l5, int l6, int l7, int l8, int l9, int *checksum2, int l11, int l12) { int nibbles[5], answer, carry; if (checksum1 == NULL || checksum2 == NULL) return; nibbles[0] = (l1 << 4) + l7; nibbles[1] = (l2 << 4) + l8; nibbles[2] = (l3 << 4) + l9; nibbles[3] = (l5 << 4) + l11; nibbles[4] = (l6 << 4) + l12; answer = (nibbles[0] ^ nibbles[1]) + nibbles[2]; carry = (answer > 255); answer = (answer ^ nibbles[3]) + nibbles[4] + carry; *checksum1 = (answer >> 4) & 15; *checksum2 = answer & 15; } int main(void) { int location = 0; int input[INPUT_LEN_MAX] = {4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}; const char *prompt = "Password: "; const int prompt_len = strlen(prompt); bool abort = FALSE, changed = TRUE; WINDOW *title_win, *password_win, *info_win, *help_win; srand((unsigned int)time(NULL)); initscr(); raw(); noecho(); title_win = newwin(2, COLS, 0, 0); password_win = newwin(1, COLS, 2, 0); info_win = newwin(11, COLS, 3, 0); help_win = newwin(9, COLS, 15, 0); keypad(password_win, TRUE); mvwprintw(title_win, 0, 0, "SJCursed: March 5, 2006.\n"); mvwprintw(title_win, 1, 0, " Copyright 2003-2006 David Lawrence Ramsey. Copyright 2006 Joel Yliluoma.\n"); wnoutrefresh(title_win); mvwprintw(help_win, 0, 0, "P: Repaint screen.\n"); mvwprintw(help_win, 1, 0, "8, K, Up: Decrease value.\n"); mvwprintw(help_win, 2, 0, "2, J, Down: Increase value.\n"); mvwprintw(help_win, 3, 0, "4, H, Left: Move to previous value.\n"); mvwprintw(help_win, 4, 0, "6, L, Right: Move to next value.\n"); mvwprintw(help_win, 5, 0, "D: Default password.\n"); mvwprintw(help_win, 6, 0, "R: Random password.\n"); mvwprintw(help_win, 7, 0, "V: Put password in valid range.\n"); mvwprintw(help_win, 8, 0, "Q: Quit.\n"); wnoutrefresh(help_win); while (!abort) { int i; if (changed) { curs_set(0); get_checksums(input[0], input[1], input[2], &input[CHECKSUM_1], input[4], input[5], input[6], input[7], input[8], &input[CHECKSUM_2], input[10], input[11]); mvwprintw(password_win, 0, 0, "%s%c%c%c%c%c%c%c%c%c%c%c%c\n", prompt, number_to_letter(input[0]), number_to_letter(input[1]), number_to_letter(input[2]), number_to_letter(input[3]), number_to_letter(input[4]), number_to_letter(input[5]), number_to_letter(input[6]), number_to_letter(input[7]), number_to_letter(input[8]), number_to_letter(input[9]), number_to_letter(input[10]), number_to_letter(input[11])); wnoutrefresh(password_win); mvwprintw(info_win, 0, 0, "Lives: %2d\n", input[0]); mvwprintw(info_win, 1, 0, "Money: %d%d%d%d%d%d\n", input[11], input[7], input[6], input[4], input[5], input[1]); mvwprintw(info_win, 2, 0, "Planet: %2d %s\n", (input[2] << 2) + (input[8] >> 2) + 1, planet_names[(input[2] << 2) + (input[8] >> 2)]); mvwprintw(info_win, 3, 0, "System: %2d %s\n", (((input[2] << 2) + (input[8] >> 2)) / 3) + 1, system_names[((input[2] << 2) + (input[8] >> 2)) / 3]); mvwprintw(info_win, 4, 0, "Normal mapping device: %3s\n", ((input[8] & 2) != 0) ? "Yes" : "No"); mvwprintw(info_win, 5, 0, "Super mapping device: %3s\n", ((input[8] & 1) != 0) ? "Yes" : "No"); mvwprintw(info_win, 6, 0, "Normal jetpod: %3s\n", ((input[10] >> 2) == 0) ? "Yes" : "No"); mvwprintw(info_win, 7, 0, "Nippon jetpod: %3s\n", ((input[10] >> 2) == 1) ? "Yes" : "No"); mvwprintw(info_win, 8, 0, "Italian jetpod: %3s\n", ((input[10] >> 2) == 2) ? "Yes" : "No"); mvwprintw(info_win, 9, 0, "Shields: %3s\n", ((input[10] & 2) != 0) ? "Yes" : "No"); mvwprintw(info_win, 10, 0, "Boosters: %3s\n", ((input[10] & 1) != 0) ? "Yes" : "No"); wnoutrefresh(info_win); } curs_set(1); wmove(password_win, 0, location + prompt_len); doupdate(); switch (wgetch(password_win)) { case 'P': case 'p': wrefresh(curscr); changed = FALSE; break; case '8': case 'K': case 'k': case KEY_UP: if (input[location] == 0) input[location] = input_max[location]; else input[location]--; changed = TRUE; break; case '2': case 'J': case 'j': case KEY_DOWN: if (input[location] == input_max[location]) input[location] = 0; else input[location]++; changed = TRUE; break; case '4': case 'H': case 'h': case KEY_LEFT: if (location == CHECKSUM_1 + 1 || location == CHECKSUM_2 + 1) location -= 2; else if (location > 0) location--; changed = FALSE; break; case '6': case 'L': case 'l': case KEY_RIGHT: if (location == CHECKSUM_1 - 1 || location == CHECKSUM_2 - 1) location += 2; else if (location < INPUT_LEN_MAX - 1) location++; changed = FALSE; break; case 'D': case 'd': for (i = 0; i < INPUT_LEN_MAX; i++) { if (i == 0) input[i] = 4; else if (i == 6) input[i] = 1; else if (i != CHECKSUM_1 && i != CHECKSUM_2) input[i] = 0; } changed = TRUE; break; case 'R': case 'r': for (i = 0; i < INPUT_LEN_MAX; i++) { if (i != CHECKSUM_1 && i != CHECKSUM_2) input[i] = rand() % input_max[i]; } changed = TRUE; break; case 'V': case 'v': if (input[0] == 0) input[0] = 1; if ((input[2] << 2) + (input[8] >> 2) > 12) { i = ((input[2] << 2) + (input[8] >> 2)) % 13; input[2] = i >> 2; input[8] &= 3; input[8] += (i & 3) << 2; } changed = TRUE; break; case ERR: case 'Q': case 'q': abort = TRUE; break; default: changed = FALSE; } } delwin(title_win); delwin(password_win); delwin(info_win); delwin(help_win); endwin(); return 0; }