#ifndef lint static char *sccsid = "@(#)player1.c 1.10 83/07/03"; #endif #include "player.h" #include <sys/types.h> WINDOW *view,*slot; char done_curses = 0; acceptcombat() { int crew[3], men = 0, rangeofshot, target, temp; int n, r, guns[2], load[2], car[2], roll[2]; int ready[2], index, rakehim, sternrake; int shootat[2], hit[2], closest[2], ship; int hhits = 0, ghits = 0, rhits = 0, chits = 0; int buf; struct shipspecs *ptr; struct File *ptr1; ptr = &specs[scene[game].ship[player].shipnum]; ptr1 = scene[game].ship[player].file; crew[0] = ptr->crew1; crew[1] = ptr->crew2; crew[2] = ptr->crew3; ready[0] = ptr1->readyL; ready[1] = ptr1->readyR; load[0] = ptr1->loadL; load[1] = ptr1->loadR; guns[0] = ptr->gunL; guns[1] = ptr->gunR; car[0] = ptr->carL; car[1] = ptr->carR; for (n = 0; n < 3; n++) { if (ptr1->OBP[n].turnsent) men += ptr1->OBP[n].mensent; } for (n = 0; n < 3; n++) { if (ptr1->DBP[n].turnsent) men += ptr1->DBP[n].mensent; } if (men) { crew[0] = men/100 ? 0 : crew[0] != 0; crew[1] = (men%100)/10 ? 0 : crew[1] != 0; crew[2] = men%10 ? 0 : crew[2] != 0; } for (r = 0; r < 2; r++) { if ((guns[r] || car[r]) && crew[2] && load[r] && ready[r] <= 0 && !ptr1->struck && ((closest[r] = closestenemy(player, (r ? 'r' : 'l'), 1)) != 30000)) { switch(load[r]) { case GRAPE: rangeofshot = 1; break; case CHAIN: rangeofshot = 3; break; case DOUBLE: rangeofshot = 1; break; case ROUND: rangeofshot = 10; break; } if ((target = range(player, closest[r])) <= rangeofshot && !scene[game].ship[closest[r]].file->struck && (guns[r] || (car[r] && target < 3))) { Signal("%s (%c%c) within range of %s broadside.", closest[r], (r?"right":"left")); if (load[r] > CHAIN && target < 6) { Signal("Aim for hull or rigging? ", -1, 0); while ((buf = getch()) == EOF); addch(buf); if(buf == 'r') shootat[r] = RIGGING; else if (buf == 'h') shootat[r] = HULL; else { shootat[r] = -1; Signal("'Avast there! Hold your fire.'", -1, 0); } } else { shootat[r] = RIGGING; Signal("Fire? ", -1, 0); while ((buf = getch()) == EOF); addch(buf); if (buf == 'n') { shootat[r] = -1; Signal("Belay that! Hold your fire.", -1, 0); } } if (shootat[r] != -1) { fired = 1; rakehim = gunsbear(player, closest[r]) && !gunsbear(closest[r], player); temp = portside(closest[r], player, 1) - pos[closest[r]].dir + 1; if (temp < 1) temp += 8; if (temp > 8) temp -= 8; sternrake = temp > 4 && temp < 6; if (rakehim && !sternrake) Signal("Raking the %s!", closest[r], 0); else if (rakehim && sternrake) Signal("Stern Rake! %s splintering!", closest[r], 0); index = guns[r]; if (target < 3) index += car[r]; index = (index - 1)/3; index = index > 8 ? 8 : index; if (!rakehim) hit[r] = HDT[index][target-1]; else hit[r] = HDTrake[index][target-1]; if (rakehim && sternrake) hit[r]++; hit[r] += QUAL[index][ptr->qual-1]; for (n=0; n < 3 && ptr1->captured < 0; n++) if (!crew[n]) if (index <= 5) hit[r]--; else hit[r] -= 2; if (ready[r] <= -30000) if (index <= 3) hit[r]++; else hit[r] += 2; if (ptr1->captured > -1) if (index <= 1) hit[r]--; else hit[r] -= 2; hit[r] += AMMO[index][load[r] - 1]; if (((temp = ptr->class) >= 5 || temp == 1) && windspeed == 5) hit[r]--; if (windspeed == 6 && temp == 4) hit[r] -= 2; if (windspeed == 6 && temp <= 3) hit[r]--; if (hit[r] >= 0) { roll[r] = die(); if (load[r] == GRAPE) chits = hit[r]; else { struct Tables *t; hit[r] = hit[r] > 10 ? 10 : hit[r]; t = &(shootat[r] ? RigTable : HullTable)[hit[r]][roll[r]-1]; chits = t->C; rhits = t->R; hhits = t->H; ghits = t->G; if (scene[game].ship[closest[r]].file->FS) rhits *= 2; if (load[r] == CHAIN) { ghits = 0; hhits = 0; } } table(shootat[r], load[r], hit[r], closest[r], player, roll[r]); } scroll = 18; move(scroll++, 0); clearline(); printw("Damage inflicted on the %s:", scene[game].ship[closest[r]].shipname); move(scroll++, 0); clearline(); printw("\t%d HULL, %d GUNS, %d CREW, %d RIGGING", hhits, ghits, chits, rhits); load[r] = 0; if (!r) { ptr1->loadL = 0; ptr1->readyL = 0; } else { ptr1->loadR = 0; ptr1->readyR = 0; } } } else { load[r] = 0; Signal("Unable to fire %s broadside", -1, (r?"right":"left")); } } else Signal("Unable to fire %s broadside", -1, (r?"right":"left")); } } leave(conditions) int conditions; { FILE *fp; int people; float net; char * capn; char message[60]; register int n; struct logs log[10], temp; signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGALRM, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGTSTP, SIG_IGN); if (conditions != -1) { capn = scene[game].ship[player].file->captain; sprintf(message,"Captain %s relinquishing.",capn); Write(FILES + player, 1, 164, message); if (fp = fopen(LOGFILE, "r+")) { net = (float) (scene[game].ship[player].file->points) / specs[scene[game].ship[player].shipnum].pts; (void) fread(&people, sizeof people, 1, fp); n = fread(log, sizeof(struct logs), 10, fp); for (; n < 10; n++) { log[n].fname[0] = 0; log[n].uid = 0; log[n].fshipnum = 0; log[n].fgamenum = 0; log[n].netpoints = -1; } rewind(fp); if(people < 0) { people = 1; (void) fwrite(&people, sizeof people, 1, fp); } else { people++; (void) fwrite(&people, sizeof people, 1, fp); } for (n=0; n < 10; n++) if (net > (float) log[n].netpoints / specs[scene[log[n].fgamenum].ship[log[n].fshipnum].shipnum].pts) { fwrite(log, sizeof(struct logs), n, fp); strcpy(temp.fname, capn); temp.uid = getuid(); temp.fshipnum = player; temp.fgamenum = game; temp.netpoints = scene[game].ship[player].file->points; fwrite(&temp, sizeof(struct logs), 1, fp); fwrite(log + n, sizeof(struct logs), 9 - n, fp); break; } fclose(fp); } Write(FILES + player, 1, 0, " "); Write(SCENARIO, 0, 8, scene[game].people - 1); if (done_curses) { screen(); Signal("It looks like you've had it!", -1, 0); if (conditions == 1) Signal("Your ship was captured.", -1, 0); else if (conditions == 2) Signal("No more enemies.", -1, 0); else if (conditions == 3) Signal("Hurricane! All ships destroyed.", -1, 0); else if (conditions == 4) Signal("The driver died.", -1, 0); move(0, LINES-1); scroll = LINES; clearline(); refresh(); } else { if (conditions == 4) printf("The driver died.\n"); } fclose(syncfile); } if (done_curses) { nocrmode(); echo(); endwin(); } exit(0); } choke() { leave(0); } #include <wait.h> child() { union wait status; int pid; signal(SIGCHLD, SIG_IGN); do { pid = vwait(&status, WNOHANG|WUNTRACED, 0); if (pid < 0 || pid > 0 && !WIFSTOPPED(status)) leave(4); } while (pid != 0); signal(SIGCHLD, child); } grapungrap() { register int n, k, l, number, captured; int buf; for (n=0; n < scene[game].vessels ; n++) { if (n != player && (range(player, n) <= 1 || grapple(player, n))) { if ((captured = scene[game].ship[n].file->captured) < 0) captured = n; Signal("Attempt to grapple or ungrapple %s (%c%c): ", n, 0); while ((buf = getch()) == EOF); addch(buf); if (buf == 'g') { number = die() < 3; if (!number && scene[game].ship[player].nationality == scene[game].ship[captured].nationality) number = 1; if (number) { for (l=0; l < 10 && scene[game].ship[player].file->grapples[l].turnfoul; l++); if (!scene[game].ship[player].file->grapples[l].turnfoul) { Write(FILES + player, 0, 124 + l*4, turn); Write(FILES + player, 0, 124 + l*4 + 2, n); } for (l=0; l < 10 && scene[game].ship[n].file->grapples[l].turnfoul; l++); if (!scene[game].ship[n].file->grapples[l].turnfoul) { Write(FILES + n, 0, 124 + l*4, turn); Write(FILES + n, 0, 124 + l*4 + 2, player); } } if (number) { Signal("Attempt succeeds!", 0, 0); makesignal("grappled with %s (%c%c)", n, player); } else Signal("Attempt fails.", 0, 0); } if (buf == 'u') { for (k=0; k < 10; k++) { if (scene[game].ship[player].file->grapples[k].turnfoul && n == scene[game].ship[player].file->grapples[k].toship) { if (die() < 3 || scene[game].ship[player].nationality == scene[game].ship[captured].nationality) { cleangrapple(player, n, k); Signal("Attempt succeeds!", 0, 0); makesignal("ungrappling with %s (%c%c)", n, player); } else Signal("Attempt fails.", 0, 0); } } } } } } unfoulplayer() { register int n, toship; int buf; for (n=0; n < 10; n++) { if (scene[game].ship[player].file->fouls[n].turnfoul) { Signal("Attempt to unfoul with the %s (%c%c)? ", (toship = scene[game].ship[player].file->fouls[n].toship), 0); while ((buf = getch()) == EOF); addch(buf); if (buf == 'y' && die() < 3) { cleanfoul(player, toship, n); Signal("Attempt succeeds!", 0, 0); makesignal("unfouling %s (%c%c)", toship, player); } else if (buf == 'y') Signal("Attempt fails.", 0, 0); } } } initialize(nodriver, randomize, debug) char randomize, nodriver, debug; { char comm[80], file[25], capn; char message[60]; int load = ROUND, ready = -30000; int people = 0; int pid; register int n; register int k; char *nameptr; srand(pid = getpid()); if (game < 0) { puts("Choose a scenario:\n"); puts("\n\tNUMBER\tSHIPS\tIN PLAY\tTITLE"); for (n=0; n < NUMOFSCENES; n++) { sprintf(file, "/tmp/.sail.%d", n); printf("\t%d):\t%d", n, scene[n].vessels); if (access(file, 0) >= 0) printf("\tYES"); else printf("\tno"); printf("\t%s\n", scene[n].name); } reprint: printf("\nScenario number? "); fflush(stdout); scanf("%d", &game); while (getchar() != '\n'); } if (game < 0 || game >= NUMOFSCENES) { puts("Very funny."); exit(1); } sprintf(file, "/tmp/.sail.%d", game); if (access(file, 0) < 0) { int omask; #ifdef SETUID omask = umask(077); #else omask = umask(011); #endif syncfile = fopen(file, "w+"); umask(omask); } else { syncfile = fopen(file, "r+"); people = 1; } lastsync = 0; for (n=0; n < scene[game].vessels; n++) { nation[scene[game].ship[n].nationality + 1] = n + 1; if ((scene[game].ship[n].file = (struct File *) calloc(1, sizeof(struct File))) == NULL) { puts("OUT OF MEMORY"); exit(0); } scene[game].ship[n].file->captured = -1; } if (!nation[2]) nation[2] = nation[1]; if (!nation[3]) nation[3] = nation[2]; if (people > 0) { puts("Synchronizing with the other players..."); fflush(stdout); sync(); capn = 1; for (n=0; n < scene[game].vessels && capn; n++) { capn = scene[game].ship[n].file->captain[0]; if (scene[game].ship[n].file->struck || scene[game].ship[n].file->captured > -1) capn = 1; } if (!capn) player = n-1; else { puts("All ships taken in that scenario."); for (n=0; n < scene[game].vessels; n++) free(scene[game].ship[n].file); people = 0; for (n=0; n < 5; n++) nation[n] = 0; fclose(syncfile); goto reprint; } } else player = 0; while (randomize) { static char *color[] = { "(American)", "(British)", "(Spanish)", "(French)" }; puts(scene[game].name); putchar('\n'); for (n=0; n < scene[game].vessels; n++) { printf(" %2d: %-10s %-15s (%-2d pts) ", n, color[scene[game].ship[n].nationality], scene[game].ship[n].shipname, specs[scene[game].ship[n].shipnum].pts); if(scene[game].ship[n].file->captain[0]) puts(scene[game].ship[n].file->captain); else if (scene[game].ship[n].file->struck) puts("(struck)"); else if(scene[game].ship[n].file->captured > -1) puts("(captured)"); else puts("(available)"); } putchar('\n'); printf("Which ship do you want (0-%d)? ",scene[game].vessels-1); fflush(stdout); if (scanf("%d",&player) != 1 || player < 0 || player >= scene[game].vessels) { while (getchar() != '\n'); puts("Say what?"); } else { while (getchar() != '\n'); sync(); if (scene[game].ship[player].file->captain[0] || scene[game].ship[player].file->struck || scene[game].ship[player].file->captured > -1) puts("Sorry, that ship is taken."); else break; } } signal(SIGHUP, choke); signal(SIGINT, choke); signal(SIGQUIT, choke); signal(SIGCHLD, child); signal(SIGTSTP, SIG_IGN); Write(FILES + player, 1, 0, "begin"); /* he now exists */ if (people) Write(SCENARIO, 0, 8, scene[game].people + 1); sync(); printf("Your ship is the %s, a %s (%s crew).\n", scene[game].ship[player].shipname, info(player, message), quality(player)); if ((nameptr = (char *) getenv("NAME")) && *nameptr) strcpy(comm,nameptr); else { fputs("Your name, Captain? ", stdout); fflush(stdout); gets(comm); if (!*comm) strcpy(comm, "no name"); } comm[19] = '\0'; for (k=0; k < 2; k++) { printf("\nInitial broadside %s (grape, chain, round, double): ", (k ? "right" : "left")); fflush(stdout); scanf("%s", file); switch(*file) { case 'g': load = GRAPE; break; case 'c': load = CHAIN; break; case 'r': load = ROUND; break; case 'd': load = DOUBLE; break; } if (k) { scene[game].ship[player].file->loadR = load; scene[game].ship[player].file->readyR = ready; } else { scene[game].ship[player].file->loadL = load; scene[game].ship[player].file->readyL = ready; } } Write(FILES + player, 1, 0, comm); if (!people && !nodriver) { char num[10]; sprintf(num, "%d", game); if (!fork()) { if (debug) execl(DEBUGDRIVER, DRIVERNAME, num, 0); else execl(DRIVER, DRIVERNAME, num, 0); perror(DRIVER); kill(pid, SIGKILL); exit(1); } } initscr(); view = newwin(ROWSINVIEW, COLSINVIEW, 2, 1); slot = newwin(ROWSINVIEW, 3, 2, 1+COLSINVIEW); done_curses++; noecho(); crmode(); board(); sprintf(message, "Captain %s assuming command",comm); Write(FILES + player, 1, 164, message); windspeed = scene[game].windspeed; winddir = scene[game].winddir; turn = scene[game].turn; iplotships(); /* new turn */ } /* * Returns the NUMBER of the closest ship */ closestenemy(fromship, side, anyship) int fromship; char side, anyship; { register int n, olddist = 30000, ident, captured; register int dist, eclosest = 30000; if ((ident = scene[game].ship[fromship].file->captured) < 0) ident = fromship; for (n=0; n < scene[game].vessels; n++) { if ((captured = scene[game].ship[n].file->captured) < 0) captured = n; if (n != fromship && pos[n].dir && (scene[game].ship[ident].nationality != scene[game].ship[captured].nationality || anyship)) { if (!side || gunsbear(fromship, n) == side) { dist = range(fromship, n); if (dist < olddist) { eclosest = n; olddist = dist; } } } } if (!side && olddist == 30000) leave(2); return(eclosest); } main(argc, argv) int argc; char ** argv; { register int crew, aheadfirst, ma, n; int ta; char message[60], ch; int uid; char nodrive = 0, randomize = 0, debug = 0; char *badstring(); extern char _sobuf[]; setbuf(stdout, _sobuf); while (*++argv && **argv == '-') switch (*++*argv) { case 'd': nodrive = 1; break; case 'D': debug++; break; case 'x': randomize = 1; break; default: printf("Unknown flag '%s'\n",*argv); break; } if (*argv) game = atoi(*argv); else game = -1; initialize(nodrive, randomize, debug); Signal("Aye aye, Sir", 0, 0); for(;;) { move(scroll++,0); clearline(); addch('~'); move(--scroll,0); refresh(); ch = getch(); switch(ch) { case 'm': crew = specs[scene[game].ship[player].shipnum].crew3; if (crew && !grappled(player) && !fouled(player) && windspeed) { ta = maxturns(player); aheadfirst = ta & 0100000; ma = maxmove(player, pos[player].dir, 0); ta &= 077777; acceptmove(ma, ta, aheadfirst); } else Signal("Unable to move", 0, 0); break; case 's': acceptsignal(); break; case 'g': grapungrap(); break; case 'u': unfoulplayer(); break; case 'v': version(); break; case 'b': boarding(); break; case 'f': acceptcombat(); break; case 'l': loadplayer(); break; case 'c': changesail(); break; case 'r': repair(); break; case 'B': Signal("'Hands to stations!'", 0, 0); unboard(player, player, 1); /* cancel DBP's */ unboard(player, player, 0); /* cancel offense */ break; case '\f': signal(SIGALRM, SIG_IGN); viewrow = pos[player].row - ROWSINVIEW / 2; viewcol = pos[player].col - COLSINVIEW / 2; board(); plotships(); /* don't create new turn */ break; case 'L': scene[game].ship[player].file->loadL = 0; scene[game].ship[player].file->loadR = 0; scene[game].ship[player].file->readyL = 0; scene[game].ship[player].file->readyR = 0; Signal("Broadsides unloaded", 0, 0); break; case 'q': Signal("Type 'Q' to quit", 0, 0); break; case 'Q': leave(0); break; case 'I': for (n = 0; n < scene[game].vessels; n++) eyeball(player, n); break; case 'i': n = closestenemy(player, 0, 1); eyeball(player, n); break; } signalflags(); lost(); } } char *saywhat(n) int n; { if(scene[game].ship[n].file->captain[0]) return(scene[game].ship[n].file->captain); else if (scene[game].ship[n].file->struck) return("(struck)"); else if(scene[game].ship[n].file->captured > -1) return("(captured)"); else return("(computer)"); } eyeball(player, n) int player, n; { char message[80]; register i; if (scene[game].ship[n].shipdir) { sprintf(message, "%d, %s", range(player, n), saywhat(n)); Signal("Sail ho! (range %s)", -1, message); switch(scene[game].ship[n].nationality) { case 0: strcpy(message, "American "); break; case 1: strcpy(message, "British "); break; case 2: strcpy(message, "Spanish "); break; case 3: strcpy(message, "French "); break; default: strcpy(message, "Gremlin "); break; } switch(specs[scene[game].ship[n].shipnum].class) { case 1: case 2: strcat(message, "Ship of the Line "); break; case 3: case 4: strcat(message, "Frigate "); break; case 5: case 6: strcat(message, "Sloop "); break; } switch(portside(player, n, 1) - pos[player].dir) { case -7: case 1: strcat(message, "off the starboard bow."); break; case -6: case 2: strcat(message, "off the starboard beam."); break; case -5: case 3: strcat(message, "off the starboard quarter."); break; case -4: case 4: strcat(message, "dead astern."); break; case -3: case 5: strcat(message, "off the port quarter."); break; case -2: case 6: strcat(message, "off the port beam."); break; case -1: case 7: strcat(message, "off the port bow."); break; case 0: strcat(message, "dead ahead."); break; } Signal(message, 0, 0); } }