1: #include "mille.h" 2: #ifndef unctrl 3: #include "unctrl.h" 4: #endif 5: 6: # ifdef attron 7: # include <term.h> 8: # define _tty cur_term->Nttyb 9: # endif attron 10: 11: /* 12: * @(#)move.c 1.2 (Berkeley) 3/28/83 13: */ 14: 15: #undef CTRL 16: #define CTRL(c) (c - 'A' + 1) 17: 18: char *Movenames[] = { 19: "M_DISCARD", "M_DRAW", "M_PLAY", "M_ORDER" 20: }; 21: 22: domove() 23: { 24: reg PLAY *pp; 25: reg int i, j; 26: reg bool goodplay; 27: 28: pp = &Player[Play]; 29: if (Play == PLAYER) 30: getmove(); 31: else 32: calcmove(); 33: Next = FALSE; 34: goodplay = TRUE; 35: switch (Movetype) { 36: case M_DISCARD: 37: if (haspicked(pp)) { 38: if (pp->hand[Card_no] == C_INIT) 39: if (Card_no == 6) 40: Finished = TRUE; 41: else 42: error("no card there"); 43: else { 44: if (issafety(pp->hand[Card_no])) { 45: error("discard a safety?"); 46: goodplay = FALSE; 47: break; 48: } 49: Discard = pp->hand[Card_no]; 50: pp->hand[Card_no] = C_INIT; 51: Next = TRUE; 52: if (Play == PLAYER) 53: account(Discard); 54: } 55: } 56: else 57: error("must pick first"); 58: break; 59: case M_PLAY: 60: goodplay = playcard(pp); 61: break; 62: case M_DRAW: 63: Card_no = 0; 64: if (Topcard <= Deck) 65: error("no more cards"); 66: else if (haspicked(pp)) 67: error("already picked"); 68: else { 69: pp->hand[0] = *--Topcard; 70: if (Debug) 71: fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]); 72: acc: 73: if (Play == COMP) { 74: account(*Topcard); 75: if (issafety(*Topcard)) 76: pp->safety[*Topcard-S_CONV] = S_IN_HAND; 77: } 78: if (pp->hand[1] == C_INIT && Topcard > Deck) { 79: Card_no = 1; 80: pp->hand[1] = *--Topcard; 81: if (Debug) 82: fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]); 83: goto acc; 84: } 85: pp->new_battle = FALSE; 86: pp->new_speed = FALSE; 87: } 88: break; 89: 90: case M_ORDER: 91: break; 92: } 93: /* 94: * move blank card to top by one of two methods. If the 95: * computer's hand was sorted, the randomness for picking 96: * between equally valued cards would be lost 97: */ 98: if (Order && Movetype != M_DRAW && goodplay && pp == &Player[PLAYER]) 99: sort(pp->hand); 100: else 101: for (i = 1; i < HAND_SZ; i++) 102: if (pp->hand[i] == C_INIT) { 103: for (j = 0; pp->hand[j] == C_INIT; j++) 104: if (j >= HAND_SZ) { 105: j = 0; 106: break; 107: } 108: pp->hand[i] = pp->hand[j]; 109: pp->hand[j] = C_INIT; 110: } 111: if (Topcard <= Deck) 112: check_go(); 113: if (Next) 114: nextplay(); 115: } 116: 117: /* 118: * Check and see if either side can go. If they cannot, 119: * the game is over 120: */ 121: check_go() { 122: 123: reg CARD card; 124: reg PLAY *pp, *op; 125: reg int i; 126: 127: for (pp = Player; pp < &Player[2]; pp++) { 128: op = (pp == &Player[COMP] ? &Player[PLAYER] : &Player[COMP]); 129: for (i = 0; i < HAND_SZ; i++) { 130: card = pp->hand[i]; 131: if (issafety(card) || canplay(pp, op, card)) { 132: if (Debug) { 133: fprintf(outf, "CHECK_GO: can play %s (%d), ", C_name[card], card); 134: fprintf(outf, "issafety(card) = %d, ", issafety(card)); 135: fprintf(outf, "canplay(pp, op, card) = %d\n", canplay(pp, op, card)); 136: } 137: return; 138: } 139: else if (Debug) 140: fprintf(outf, "CHECK_GO: cannot play %s\n", 141: C_name[card]); 142: } 143: } 144: Finished = TRUE; 145: } 146: 147: playcard(pp) 148: reg PLAY *pp; 149: { 150: reg int v; 151: reg CARD card; 152: 153: /* 154: * check and see if player has picked 155: */ 156: switch (pp->hand[Card_no]) { 157: default: 158: if (!haspicked(pp)) 159: mustpick: 160: return error("must pick first"); 161: case C_GAS_SAFE: case C_SPARE_SAFE: 162: case C_DRIVE_SAFE: case C_RIGHT_WAY: 163: break; 164: } 165: 166: card = pp->hand[Card_no]; 167: if (Debug) 168: fprintf(outf, "PLAYCARD: Card = %s\n", C_name[card]); 169: Next = FALSE; 170: switch (card) { 171: case C_200: 172: if (pp->nummiles[C_200] == 2) 173: return error("only two 200's per hand"); 174: case C_100: case C_75: 175: if (pp->speed == C_LIMIT) 176: return error("limit of 50"); 177: case C_50: 178: if (pp->mileage + Value[card] > End) 179: return error("puts you over %d", End); 180: case C_25: 181: if (!pp->can_go) 182: return error("cannot move now"); 183: pp->nummiles[card]++; 184: v = Value[card]; 185: pp->total += v; 186: pp->hand_tot += v; 187: if ((pp->mileage += v) == End) 188: check_ext(FALSE); 189: break; 190: 191: case C_GAS: case C_SPARE: case C_REPAIRS: 192: if (pp->battle != opposite(card)) 193: return error("can't play \"%s\"", C_name[card]); 194: pp->battle = card; 195: if (pp->safety[S_RIGHT_WAY] == S_PLAYED) 196: pp->can_go = TRUE; 197: break; 198: 199: case C_GO: 200: if (pp->battle != C_INIT && pp->battle != C_STOP 201: && !isrepair(pp->battle)) 202: return error("cannot play \"Go\" on a \"%s\"", 203: C_name[pp->battle]); 204: pp->battle = C_GO; 205: pp->can_go = TRUE; 206: break; 207: 208: case C_END_LIMIT: 209: if (pp->speed != C_LIMIT) 210: return error("not limited"); 211: pp->speed = C_END_LIMIT; 212: break; 213: 214: case C_EMPTY: case C_FLAT: case C_CRASH: 215: case C_STOP: 216: pp = &Player[other(Play)]; 217: if (!pp->can_go) 218: return error("opponent cannot go"); 219: else if (pp->safety[safety(card) - S_CONV] == S_PLAYED) 220: protected: 221: return error("opponent is protected"); 222: pp->battle = card; 223: pp->new_battle = TRUE; 224: pp->can_go = FALSE; 225: pp = &Player[Play]; 226: break; 227: 228: case C_LIMIT: 229: pp = &Player[other(Play)]; 230: if (pp->speed == C_LIMIT) 231: return error("opponent has limit"); 232: if (pp->safety[S_RIGHT_WAY] == S_PLAYED) 233: goto protected; 234: pp->speed = C_LIMIT; 235: pp->new_speed = TRUE; 236: pp = &Player[Play]; 237: break; 238: 239: case C_GAS_SAFE: case C_SPARE_SAFE: 240: case C_DRIVE_SAFE: case C_RIGHT_WAY: 241: if (pp->battle == opposite(card) 242: || (card == C_RIGHT_WAY && pp->speed == C_LIMIT)) { 243: if (!(card == C_RIGHT_WAY && !isrepair(pp->battle))) { 244: pp->battle = C_GO; 245: pp->can_go = TRUE; 246: } 247: if (card == C_RIGHT_WAY && pp->speed == C_LIMIT) 248: pp->speed = C_INIT; 249: if (pp->new_battle 250: || (pp->new_speed && card == C_RIGHT_WAY)) { 251: pp->coups[card - S_CONV] = TRUE; 252: pp->total += SC_COUP; 253: pp->hand_tot += SC_COUP; 254: pp->coupscore += SC_COUP; 255: } 256: } 257: /* 258: * if not coup, must pick first 259: */ 260: else if (pp->hand[0] == C_INIT && Topcard > Deck) 261: goto mustpick; 262: pp->safety[card - S_CONV] = S_PLAYED; 263: pp->total += SC_SAFETY; 264: pp->hand_tot += SC_SAFETY; 265: if ((pp->safescore += SC_SAFETY) == NUM_SAFE * SC_SAFETY) { 266: pp->total += SC_ALL_SAFE; 267: pp->hand_tot += SC_ALL_SAFE; 268: } 269: if (card == C_RIGHT_WAY) { 270: if (pp->speed == C_LIMIT) 271: pp->speed = C_INIT; 272: if (pp->battle == C_STOP || pp->battle == C_INIT) { 273: pp->can_go = TRUE; 274: pp->battle = C_INIT; 275: } 276: if (!pp->can_go && isrepair(pp->battle)) 277: pp->can_go = TRUE; 278: } 279: Next = -1; 280: break; 281: 282: case C_INIT: 283: error("no card there"); 284: Next = -1; 285: break; 286: } 287: if (pp == &Player[PLAYER]) 288: account(card); 289: pp->hand[Card_no] = C_INIT; 290: Next = (Next == -1 ? FALSE : TRUE); 291: return TRUE; 292: } 293: 294: getmove() 295: { 296: reg char c, *sp; 297: static char moveprompt[] = ">>:Move:"; 298: #ifdef EXTRAP 299: static bool last_ex = FALSE; /* set if last command was E */ 300: 301: if (last_ex) { 302: undoex(); 303: prboard(); 304: last_ex = FALSE; 305: } 306: #endif 307: for (;;) { 308: prompt(MOVEPROMPT); 309: leaveok(Board, FALSE); 310: refresh(); 311: while ((c = readch()) == killchar() || c == erasechar()) 312: continue; 313: if (islower(c)) 314: c = toupper(c); 315: if (isprint(c) && !isspace(c)) { 316: addch(c); 317: refresh(); 318: } 319: switch (c) { 320: case 'P': /* Pick */ 321: Movetype = M_DRAW; 322: goto ret; 323: case 'U': /* Use Card */ 324: case 'D': /* Discard Card */ 325: if ((Card_no = getcard()) < 0) 326: break; 327: Movetype = (c == 'U' ? M_PLAY : M_DISCARD); 328: goto ret; 329: case 'O': /* Order */ 330: Order = !Order; 331: if (Window == W_SMALL) { 332: if (!Order) 333: mvwaddstr(Score, 12, 21, 334: "o: order hand"); 335: else 336: mvwaddstr(Score, 12, 21, 337: "o: stop ordering"); 338: wclrtoeol(Score); 339: } 340: Movetype = M_ORDER; 341: goto ret; 342: case 'Q': /* Quit */ 343: rub(); /* Same as a rubout */ 344: break; 345: case 'W': /* Window toggle */ 346: Window = nextwin(Window); 347: newscore(); 348: prscore(TRUE); 349: wrefresh(Score); 350: break; 351: case 'R': /* Redraw screen */ 352: case CTRL('L'): 353: wrefresh(curscr); 354: break; 355: case 'S': /* Save game */ 356: On_exit = FALSE; 357: save(); 358: break; 359: case 'E': /* Extrapolate */ 360: #ifdef EXTRAP 361: if (last_ex) 362: break; 363: Finished = TRUE; 364: if (Window != W_FULL) 365: newscore(); 366: prscore(FALSE); 367: wrefresh(Score); 368: last_ex = TRUE; 369: Finished = FALSE; 370: #else 371: error("%c: command not implemented", c); 372: #endif 373: break; 374: case '\r': /* Ignore RETURNs and */ 375: case '\n': /* Line Feeds */ 376: case ' ': /* Spaces */ 377: case '\0': /* and nulls */ 378: break; 379: case 'Z': /* Debug code */ 380: if (geteuid() == ARNOLD) { 381: if (!Debug && outf == NULL) { 382: char buf[40]; 383: over: 384: prompt(FILEPROMPT); 385: leaveok(Board, FALSE); 386: refresh(); 387: sp = buf; 388: while ((*sp = readch()) != '\n') { 389: if (*sp == killchar()) 390: goto over; 391: else if (*sp == erasechar()) { 392: if (--sp < buf) 393: sp = buf; 394: else { 395: addch('\b'); 396: if (*sp < ' ') 397: addch('\b'); 398: clrtoeol(); 399: } 400: } 401: else 402: addstr(unctrl(*sp++)); 403: refresh(); 404: } 405: *sp = '\0'; 406: leaveok(Board, TRUE); 407: if ((outf = fopen(buf, "w")) == NULL) 408: perror(buf); 409: setbuf(outf, NULL); 410: } 411: Debug = !Debug; 412: break; 413: } 414: /* FALLTHROUGH */ 415: default: 416: error("unknown command: %s", unctrl(c)); 417: break; 418: } 419: } 420: ret: 421: leaveok(Board, TRUE); 422: } 423: /* 424: * return whether or not the player has picked 425: */ 426: haspicked(pp) 427: reg PLAY *pp; { 428: 429: reg int card; 430: 431: if (Topcard <= Deck) 432: return TRUE; 433: switch (pp->hand[Card_no]) { 434: case C_GAS_SAFE: case C_SPARE_SAFE: 435: case C_DRIVE_SAFE: case C_RIGHT_WAY: 436: card = 1; 437: break; 438: default: 439: card = 0; 440: break; 441: } 442: return (pp->hand[card] != C_INIT); 443: } 444: 445: account(card) 446: reg CARD card; { 447: 448: reg CARD oppos; 449: 450: if (card == C_INIT) 451: return; 452: ++Numseen[card]; 453: if (Play == COMP) 454: switch (card) { 455: case C_GAS_SAFE: 456: case C_SPARE_SAFE: 457: case C_DRIVE_SAFE: 458: oppos = opposite(card); 459: Numgos += Numcards[oppos] - Numseen[oppos]; 460: break; 461: case C_CRASH: 462: case C_FLAT: 463: case C_EMPTY: 464: case C_STOP: 465: Numgos++; 466: break; 467: } 468: } 469: 470: prompt(promptno) 471: int promptno; 472: { 473: static char *names[] = { 474: ">>:Move:", 475: "Really?", 476: "Another hand?", 477: "Another game?", 478: "Save game?", 479: "Same file?", 480: "file:", 481: "Extension?", 482: "Overwrite file?", 483: }; 484: static int last_prompt = -1; 485: 486: if (promptno == last_prompt) 487: move(MOVE_Y, MOVE_X + strlen(names[promptno]) + 1); 488: else { 489: move(MOVE_Y, MOVE_X); 490: if (promptno == MOVEPROMPT) 491: standout(); 492: addstr(names[promptno]); 493: if (promptno == MOVEPROMPT) 494: standend(); 495: addch(' '); 496: last_prompt = promptno; 497: } 498: clrtoeol(); 499: } 500: 501: sort(hand) 502: reg CARD *hand; 503: { 504: reg CARD *cp, *tp; 505: reg CARD temp; 506: 507: cp = hand; 508: hand += HAND_SZ; 509: for ( ; cp < &hand[-1]; cp++) 510: for (tp = cp + 1; tp < hand; tp++) 511: if (*cp > *tp) { 512: temp = *cp; 513: *cp = *tp; 514: *tp = temp; 515: } 516: }