From 240117cdf638c185d8469527e583276e546bf666 Mon Sep 17 00:00:00 2001 From: dholland Date: Fri, 6 Aug 2010 09:14:40 +0000 Subject: Rework the game startup so it uses curses nicely. There are now menus and stuff for picking scenarios and ships and all that. --- sail/dr_main.c | 58 +++- sail/extern.h | 29 +- sail/globals.c | 22 +- sail/lo_main.c | 65 ++++- sail/main.c | 63 +++- sail/pl_7.c | 888 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- sail/pl_main.c | 200 +++---------- 7 files changed, 1125 insertions(+), 200 deletions(-) diff --git a/sail/dr_main.c b/sail/dr_main.c index 71c141dd..167c512a 100644 --- a/sail/dr_main.c +++ b/sail/dr_main.c @@ -1,4 +1,4 @@ -/* $NetBSD: dr_main.c,v 1.14 2009/03/14 19:36:42 dholland Exp $ */ +/* $NetBSD: dr_main.c,v 1.15 2010/08/06 09:14:40 dholland Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,17 +34,22 @@ #if 0 static char sccsid[] = "@(#)dr_main.c 8.2 (Berkeley) 4/16/94"; #else -__RCSID("$NetBSD: dr_main.c,v 1.14 2009/03/14 19:36:42 dholland Exp $"); +__RCSID("$NetBSD: dr_main.c,v 1.15 2010/08/06 09:14:40 dholland Exp $"); #endif #endif /* not lint */ #include +#include #include #include #include #include #include "extern.h" #include "driver.h" +#include "player.h" /* XXX for LEAVE_FORK */ +#include "restart.h" + +static int driver_wait_fd = -1; int dr_main(void) @@ -54,23 +59,28 @@ dr_main(void) int nat[NNATION]; int value = 0; + /* + * XXX need a way to print diagnostics back to the player + * process instead of stomping on the curses screen. + */ + signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTSTP, SIG_IGN); if (game < 0 || game >= NSCENE) { - errx(1, "driver: Bad game number %d", game); + errx(1, "\ndriver: Bad game number %d", game); } cc = &scene[game]; ls = SHIP(cc->vessels); if (sync_open() < 0) { - err(1, "driver: syncfile"); + err(1, "\ndriver: syncfile"); } for (n = 0; n < NNATION; n++) nat[n] = 0; foreachship(sp) { if (sp->file == NULL && (sp->file = calloc(1, sizeof (struct File))) == NULL) { - fprintf(stderr, "DRIVER: Out of memory.\n"); + fprintf(stderr, "\nDRIVER: Out of memory.\n"); exit(1); } sp->file->index = sp - SHIP(0); @@ -86,6 +96,12 @@ dr_main(void) windspeed = cc->windspeed; winddir = cc->winddir; people = 0; + + /* report back to the player process that we've started */ + if (driver_wait_fd >= 0) { + close(driver_wait_fd); + } + for (;;) { sleep(7); if (Sync() < 0) { @@ -112,3 +128,35 @@ dr_main(void) sync_close(1); return value; } + +void +startdriver(void) +{ + int fds[2]; + char c; + + if (pipe(fds)) { + warn("pipe"); + leave(LEAVE_FORK); + return; + } + + switch (fork()) { + case 0: + close(fds[0]); + driver_wait_fd = fds[1]; + longjmp(restart, MODE_DRIVER); + /*NOTREACHED*/ + case -1: + warn("fork"); + close(fds[0]); + close(fds[1]); + leave(LEAVE_FORK); + break; + default: + hasdriver++; + close(fds[1]); + read(fds[0], &c, 1); + close(fds[0]); + } +} diff --git a/sail/extern.h b/sail/extern.h index 5492001a..f4509b29 100644 --- a/sail/extern.h +++ b/sail/extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: extern.h,v 1.35 2009/08/12 09:05:08 dholland Exp $ */ +/* $NetBSD: extern.h,v 1.36 2010/08/06 09:14:40 dholland Exp $ */ /* * Copyright (c) 1983, 1993 @@ -43,13 +43,15 @@ extern int mode; #define MODE_LOGGER 3 /* command line flags */ -extern int randomize; /* -x, give first available ship */ -extern int longfmt; /* -l, print score in long format */ -extern int nobells; /* -b, don't ring bell before Signal */ +extern bool randomize; /* -x, give first available ship */ +extern bool longfmt; /* -l, print score in long format */ +extern bool nobells; /* -b, don't ring bell before Signal */ - /* other initial modes */ + /* other initial data */ extern gid_t gid; extern gid_t egid; +#define MAXNAMESIZE 20 +extern char myname[MAXNAMESIZE]; #define dieroll() ((random()) % 6 + 1) #define sqr(a) ((a) * (a)) @@ -103,7 +105,7 @@ extern gid_t egid; #define NLOG 10 struct logs { - char l_name[20]; + char l_name[MAXNAMESIZE]; int l_uid; int l_shipnum; int l_gamenum; @@ -121,7 +123,7 @@ struct snag { short sn_turn; }; -#define NSCENE nscene +#define NSCENE /*nscene*/ 32 #define NSHIP 10 #define NBP 3 @@ -137,7 +139,7 @@ struct snag { struct File { int index; - char captain[20]; /* 0 */ + char captain[MAXNAMESIZE]; /* 0 */ short points; /* 20 */ unsigned char loadL; /* 22 */ unsigned char loadR; /* 24 */ @@ -185,7 +187,7 @@ struct scenario { const char *name; /* 14 */ struct ship ship[NSHIP]; /* 16 */ }; -extern struct scenario scene[]; +extern struct scenario scene[NSCENE]; extern int nscene; struct shipspecs { @@ -234,6 +236,7 @@ extern const char QUAL[9][5]; extern const char MT[9][3]; extern const char *const countryname[]; +extern const char *const shortclassname[]; extern const char *const classname[]; extern const char *const directionname[]; extern const char *const qualname[]; @@ -251,6 +254,7 @@ extern int alive; extern int people; extern int hasdriver; + /* assorted.c */ void table(struct ship *, struct ship *, int, int, int, int); void Cleansnag(struct ship *, struct ship *, int, int); @@ -285,12 +289,14 @@ int mensent(struct ship *, struct ship *, int[3], struct ship **, int *, int); /* dr_main.c */ int dr_main(void); +void startdriver(void); /* game.c */ int maxturns(struct ship *, bool *); int maxmove(struct ship *, int, int); /* lo_main.c */ +void lo_curses(void); int lo_main(void); /* misc.c */ @@ -349,9 +355,12 @@ void upview(void); void downview(void); void leftview(void); void rightview(void); +void startup(void); /* pl_main.c */ -int pl_main(void); +void pl_main_init(void); +void pl_main_uninit(void); +void pl_main(void); /* sync.c */ void fmtship(char *, size_t, const char *, struct ship *); diff --git a/sail/globals.c b/sail/globals.c index 0f34bae1..331e6b64 100644 --- a/sail/globals.c +++ b/sail/globals.c @@ -1,4 +1,4 @@ -/* $NetBSD: globals.c,v 1.15 2009/08/12 09:05:08 dholland Exp $ */ +/* $NetBSD: globals.c,v 1.16 2010/08/06 09:14:40 dholland Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)globals.c 8.2 (Berkeley) 4/28/95"; #else -__RCSID("$NetBSD: globals.c,v 1.15 2009/08/12 09:05:08 dholland Exp $"); +__RCSID("$NetBSD: globals.c,v 1.16 2010/08/06 09:14:40 dholland Exp $"); #endif #endif /* not lint */ @@ -44,7 +44,7 @@ __RCSID("$NetBSD: globals.c,v 1.15 2009/08/12 09:05:08 dholland Exp $"); static struct shipspecs specs[]; -struct scenario scene[] = { +struct scenario scene[NSCENE] = { /* * int winddir; * int windspeed; @@ -526,6 +526,16 @@ const char *const classname[] = { "Brig" }; +const char *const shortclassname[] = { + "Rowboat", + "Ship", + "Ship", + "Frigate", + "Corvette", + "Sloop", + "Brig" +}; + const char *const directionname[] = { "dead ahead", "off the starboard bow", @@ -555,9 +565,9 @@ const char dc[] = { 0, 0, -1, -1, -1, 0, 1, 1, 1 }; int mode; jmp_buf restart; -int randomize; /* -x, give first available ship */ -int longfmt; /* -l, print score in long format */ -int nobells; /* -b, don't ring bell before Signal */ +bool randomize; /* -x, give first available ship */ +bool longfmt; /* -l, print score in long format */ +bool nobells; /* -b, don't ring bell before Signal */ gid_t gid; gid_t egid; diff --git a/sail/lo_main.c b/sail/lo_main.c index 1cd7beb6..48b19280 100644 --- a/sail/lo_main.c +++ b/sail/lo_main.c @@ -1,4 +1,4 @@ -/* $NetBSD: lo_main.c,v 1.18 2010/01/17 22:56:32 wiz Exp $ */ +/* $NetBSD: lo_main.c,v 1.19 2010/08/06 09:14:40 dholland Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)lo_main.c 8.2 (Berkeley) 4/28/95"; #else -__RCSID("$NetBSD: lo_main.c,v 1.18 2010/01/17 22:56:32 wiz Exp $"); +__RCSID("$NetBSD: lo_main.c,v 1.19 2010/08/06 09:14:40 dholland Exp $"); #endif #endif /* not lint */ @@ -45,18 +45,79 @@ __RCSID("$NetBSD: lo_main.c,v 1.18 2010/01/17 22:56:32 wiz Exp $"); */ #include +#include #include #include +#include #include +#include + #include "extern.h" #include "pathnames.h" + static const char *const title[] = { "Admiral", "Commodore", "Captain", "Captain", "Captain", "Captain", "Captain", "Commander", "Commander", "Lieutenant" }; +void +lo_curses(void) +{ + FILE *fp; + char sbuf[32]; + int n = 0, npeople; + int line; + struct passwd *pass; + struct logs log; + struct ship *ship; + + erase(); + + fp = fopen(_PATH_LOGFILE, "r"); + if (fp == NULL) { + mvprintw(5, 10, "%s: %s", _PATH_LOGFILE, strerror(errno)); + mvaddstr(7, 10, "Press any key..."); + getch(); + return; + } + switch (fread(&npeople, sizeof npeople, 1, fp)) { + case 0: + mvprintw(5, 10, "Nobody has sailed yet."); + mvaddstr(7, 10, "Press any key..."); + getch(); + return; + case 1: + break; + default: + mvprintw(5, 10, "%s: %s", _PATH_LOGFILE, strerror(errno)); + mvaddstr(7, 10, "Press any key..."); + getch(); + return; + } + line = 0; + while (fread(&log, sizeof log, 1, fp) == 1 && + log.l_name[0] != '\0' && + line < LINES - 2) { + if (longfmt && (pass = getpwuid(log.l_uid)) != NULL) + snprintf(sbuf, sizeof(sbuf), + "%10.10s (%s)", log.l_name, pass->pw_name); + else + snprintf(sbuf, sizeof(sbuf), + "%20.20s", log.l_name); + ship = &scene[log.l_gamenum].ship[log.l_shipnum]; + mvprintw(line, 0, + "%-10s %21s of the %15s %3d points, %5.2f equiv", + title[n++], sbuf, ship->shipname, log.l_netpoints, + (float) log.l_netpoints / ship->specs->pts); + line++; + } + fclose(fp); + mvprintw(line+1, 0, "%d people have played. Press any key.", npeople); + getch(); +} + int lo_main(void) { diff --git a/sail/main.c b/sail/main.c index 0c9897f1..fdb9d830 100644 --- a/sail/main.c +++ b/sail/main.c @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.25 2009/03/14 23:51:35 dholland Exp $ */ +/* $NetBSD: main.c,v 1.26 2010/08/06 09:14:40 dholland Exp $ */ /* * Copyright (c) 1983, 1993 @@ -39,12 +39,14 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\ #if 0 static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 4/28/95"; #else -__RCSID("$NetBSD: main.c,v 1.25 2009/03/14 23:51:35 dholland Exp $"); +__RCSID("$NetBSD: main.c,v 1.26 2010/08/06 09:14:40 dholland Exp $"); #endif #endif /* not lint */ +#include #include #include +#include #include #include #include @@ -55,12 +57,13 @@ __RCSID("$NetBSD: main.c,v 1.25 2009/03/14 23:51:35 dholland Exp $"); #include "pathnames.h" #include "restart.h" -int -main(int argc, char **argv) +static void +initialize(void) { - char *p; - int a,i; int fd; + const char *name; + struct passwd *pw; + char *s; gid = getgid(); egid = getegid(); @@ -77,6 +80,43 @@ main(int argc, char **argv) srandom((u_long)time(NULL)); + name = getenv("SAILNAME"); + if (name != NULL && *name != '\0') { + strlcpy(myname, name, sizeof(myname)); + } else { + pw = getpwuid(getuid()); + if (pw != NULL) { + strlcpy(myname, pw->pw_gecos, sizeof(myname)); + /* trim to just the realname */ + s = strchr(myname, ','); + if (s != NULL) { + *s = '\0'; + } + /* use just the first name */ + s = strchr(myname, ' '); + if (s != NULL) { + *s = '\0'; + } + /* should really do &-expansion properly */ + if (!strcmp(myname, "&")) { + strlcpy(myname, pw->pw_name, sizeof(myname)); + myname[0] = toupper((unsigned char)myname[0]); + } + } + } + if (*myname == '\0') { + strlcpy(myname, "Anonymous", sizeof(myname)); + } +} + +int +main(int argc, char **argv) +{ + char *p; + int a, i; + + initialize(); + if ((p = strrchr(*argv, '/')) != NULL) p++; else @@ -98,13 +138,13 @@ main(int argc, char **argv) mode = MODE_LOGGER; break; case 'x': - randomize++; + randomize = true; break; case 'l': - longfmt++; + longfmt = true; break; case 'b': - nobells++; + nobells = true; break; default: errx(1, "Usage: %s [-bdlsx] [scenario-number]", p); @@ -123,7 +163,10 @@ main(int argc, char **argv) switch (mode) { case MODE_PLAYER: - return pl_main(); + initscreen(); + startup(); + cleanupscreen(); + return 0; case MODE_DRIVER: return dr_main(); case MODE_LOGGER: diff --git a/sail/pl_7.c b/sail/pl_7.c index 9f2dcd03..63cd5275 100644 --- a/sail/pl_7.c +++ b/sail/pl_7.c @@ -1,4 +1,4 @@ -/* $NetBSD: pl_7.c,v 1.39 2010/08/06 03:10:26 dholland Exp $ */ +/* $NetBSD: pl_7.c,v 1.40 2010/08/06 09:14:40 dholland Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)pl_7.c 8.1 (Berkeley) 5/31/93"; #else -__RCSID("$NetBSD: pl_7.c,v 1.39 2010/08/06 03:10:26 dholland Exp $"); +__RCSID("$NetBSD: pl_7.c,v 1.40 2010/08/06 09:14:40 dholland Exp $"); #endif #endif /* not lint */ @@ -46,6 +46,7 @@ __RCSID("$NetBSD: pl_7.c,v 1.39 2010/08/06 03:10:26 dholland Exp $"); #include #include #include +#include #include "array.h" #include "extern.h" #include "player.h" @@ -84,6 +85,7 @@ static bool obp[3]; static bool dbp[3]; int done_curses; +static bool ingame; int loaded, fired, changed, repaired; int dont_adjust; static int viewrow, viewcol; @@ -151,11 +153,23 @@ initscreen(void) /* * Define esc-x keys */ +#if 0 for (ch = 0; ch < 127; ch++) { - if (ch != '[') { + if (ch != '[' && ch != 'O') { define_esc_key(ch); } } +#else + (void)ch; + (void)define_esc_key; +#endif + + keypad(stdscr, 1); + keypad(view_w, 1); + keypad(slot_w, 1); + keypad(scroll_w, 1); + keypad(stat_w, 1); + keypad(turn_w, 1); done_curses++; } @@ -165,13 +179,140 @@ cleanupscreen(void) { /* alarm already turned off */ if (done_curses) { - wmove(scroll_w, SCROLL_Y - 1, 0); - wclrtoeol(scroll_w); - display_redraw(); + if (ingame) { + wmove(scroll_w, SCROLL_Y - 1, 0); + wclrtoeol(scroll_w); + display_redraw(); + } else { + move(LINES-1, 0); + clrtoeol(); + } endwin(); } } +//////////////////////////////////////////////////////////// +// curses utility functions + +/* + * fill to eol with spaces + * (useful with A_REVERSE since cleartoeol() does not clear to reversed) + */ +static void +filltoeol(void) +{ + int x; + + for (x = getcurx(stdscr); x < COLS; x++) { + addch(' '); + } +} + +/* + * Add a maybe-selected string. + * + * Place strings starting at (Y0, X0); this is string ITEM; CURITEM + * is the selected one; WIDTH is the total width. STR is the string. + */ +static void +mvaddselstr(int y, int x0, int item, int curitem, + size_t width, const char *str) +{ + size_t i, len; + + len = strlen(str); + + move(y, x0); + if (curitem == item) { + attron(A_REVERSE); + } + addstr(str); + if (curitem == item) { + for (i=len; i 0) { + (*posp)--; + } + if (scrollp != NULL) { + if (*posp < *scrollp) { + *scrollp = *posp; + } + } +} + +/* + * Move down by 1, scrolling if needed. MAX is the total number of + * items; VISIBLE is the number that can be visible at once. + */ +static void +down(int *posp, int *scrollp, int max, int visible) +{ + if (max > 0 && *posp < max - 1) { + (*posp)++; + } + if (scrollp != NULL) { + if (*posp > *scrollp + visible - 1) { + *scrollp = *posp - visible + 1; + } + } +} + +/* + * Complain briefly. + */ +static void +oops(int y, int x, const char *fmt, ...) +{ + int oy, ox; + va_list ap; + + oy = getcury(stdscr); + ox = getcurx(stdscr); + move(y, x); + va_start(ap, fmt); + vwprintw(stdscr, fmt, ap); + va_end(ap); + move(oy, ox); + wrefresh(stdscr); + sleep(1); +} + //////////////////////////////////////////////////////////// // scrolling message area @@ -711,3 +852,738 @@ display_adjust_view(void) else if (mf->col > viewcol + (VIEW_X - VIEW_X/8)) viewcol = mf->col - VIEW_X/8; } + +//////////////////////////////////////////////////////////// +// starting game + +static bool shipselected; +static int loadpos; + +static int +nextload(int load) +{ + switch (load) { + case L_ROUND: return L_GRAPE; + case L_GRAPE: return L_CHAIN; + case L_CHAIN: return L_DOUBLE; + case L_DOUBLE: return L_ROUND; + } + return L_ROUND; +} + +static int +loadbychar(int ch) +{ + switch (ch) { + case 'r': return L_ROUND; + case 'g': return L_GRAPE; + case 'c': return L_CHAIN; + case 'd': return L_DOUBLE; + } + return L_ROUND; +} + +static const char * +loadstr(int load) +{ + switch (load) { + case L_ROUND: return "round"; + case L_GRAPE: return "grape"; + case L_CHAIN: return "chain"; + case L_DOUBLE: return "double"; + } + return "???"; +} + +static void +displayshiplist(void) +{ + struct ship *sp; + int which; + + erase(); + + attron(A_BOLD); + mvaddstr(1, 4, cc->name); + attroff(A_BOLD); + + which = 0; + foreachship(sp) { + mvselprintw(which + 3, 4, which, player, 60, + " %2d: %-10s %-15s (%-2d pts) %s", + sp->file->index, + countryname[sp->nationality], + sp->shipname, + sp->specs->pts, + saywhat(sp, 1)); + which++; + } + + if (!shipselected) { + mvaddstr(15, 4, "Choose your ship"); + move(player + 3, 63); + } else { + mvselprintw(15, 4, 0, loadpos, 32, + "Initial left broadside: %s", loadstr(mf->loadL)); + mvselprintw(16, 4, 1, loadpos, 32, + "Initial right broadside: %s", loadstr(mf->loadR)); + mvselprintw(17, 4, 2, loadpos, 32, "Set sail"); + move(loadpos+15, 35); + } + + wrefresh(stdscr); +} + +static int +pickship(void) +{ + struct File *fp; + struct ship *sp; + bool done; + int ch; + + for (;;) { + foreachship(sp) + if (sp->file->captain[0] == 0 && !sp->file->struck + && sp->file->captured == 0) + break; + if (sp >= ls) { + return -1; + } + player = sp - SHIP(0); + if (randomize) { + /* nothing */ + } else { + done = false; + while (!done) { + displayshiplist(); + + ch = getch(); + switch (ch) { + case 12 /*^L*/: + clear(); + break; + case '\r': + case '\n': + done = true; + break; + case 7 /*^G*/: + case 8 /*^H*/: + case 27 /*ESC*/: + case 127 /*^?*/: + beep(); + break; + case 16 /*^P*/: + case KEY_UP: + up(&player, NULL); + break; + case 14 /*^N*/: + case KEY_DOWN: + down(&player, NULL, cc->vessels, + cc->vessels); + break; + default: + beep(); + break; + } + } + } + if (player < 0) + continue; + if (Sync() < 0) + leave(LEAVE_SYNC); + fp = SHIP(player)->file; + if (fp->captain[0] || fp->struck || fp->captured != 0) + oops(16, 4, "That ship is taken."); + else + break; + } + return 0; +} + +static void +pickload(void) +{ + bool done; + int ch; + + mf->loadL = L_ROUND; + mf->loadR = L_ROUND; + + loadpos = 0; + done = false; + while (!done) { + displayshiplist(); + + ch = getch(); + switch (ch) { + case 12 /*^L*/: + clear(); + break; + case 'r': + case 'g': + case 'c': + case 'd': + switch (loadpos) { + case 0: mf->loadL = loadbychar(ch); break; + case 1: mf->loadR = loadbychar(ch); break; + case 2: beep(); break; + } + break; + case '\r': + case '\n': + switch (loadpos) { + case 0: mf->loadL = nextload(mf->loadL); break; + case 1: mf->loadR = nextload(mf->loadR); break; + case 2: done = true; break; + } + break; + case 7 /*^G*/: + case 8 /*^H*/: + case 27 /*ESC*/: + case 127 /*^?*/: + beep(); + break; + case 16 /*^P*/: + case KEY_UP: + up(&loadpos, NULL); + break; + case 14 /*^N*/: + case KEY_DOWN: + down(&loadpos, NULL, 3, 3); + break; + default: + beep(); + break; + } + } + mf->readyR = R_LOADED|R_INITIAL; + mf->readyL = R_LOADED|R_INITIAL; +} + +static void +startgame(void) +{ + + ingame = true; + shipselected = false; + + pl_main_init(); + + hasdriver = sync_exists(game); + if (sync_open() < 0) { + oops(21, 10, "syncfile: %s", strerror(errno)); + pl_main_uninit(); + ingame = false; + return; + } + + if (hasdriver) { + mvaddstr(21, 10, "Synchronizing with the other players..."); + wrefresh(stdscr); + fflush(stdout); + if (Sync() < 0) + leave(LEAVE_SYNC); + } else { + mvaddstr(21, 10, "Starting driver..."); + wrefresh(stdscr); + fflush(stdout); + startdriver(); + } + + if (pickship() < 0) { + oops(21, 10, "All ships taken in that scenario."); + sync_close(0); + people = 0; + pl_main_uninit(); + ingame = false; + return; + } + shipselected = true; + + ms = SHIP(player); + mf = ms->file; + mc = ms->specs; + + pickload(); + + pl_main(); + ingame = false; +} + +//////////////////////////////////////////////////////////// +// scenario picker + +static int pickerpos; +static int pickerscroll; + +static const char * +absdirectionname(int dir) +{ + switch (dir) { + case 1: return "South"; + case 2: return "Southwest"; + case 3: return "West"; + case 4: return "Northwest"; + case 5: return "North"; + case 6: return "Northeast"; + case 7: return "East"; + case 8: return "Southeast"; + } + return "?"; +} + +static const char * +windname(int wind) +{ + switch (wind) { + case 0: return "calm"; + case 1: return "light breeze"; + case 2: return "moderate breeze"; + case 3: return "fresh breeze"; + case 4: return "strong breeze"; + case 5: return "gale"; + case 6: return "full gale"; + case 7: return "hurricane"; + } + return "???"; +} + +static const char * +nationalityname(int nationality) +{ + switch (nationality) { + case N_A: return "a"; + case N_B: return "b"; + case N_S: return "s"; + case N_F: return "f"; + case N_J: return "j"; + case N_D: return "d"; + case N_K: return "k"; + case N_O: return "o"; + } + return "?"; +} + +static void +drawpicker(void) +{ + int y, sc, i; + struct ship *ship; + + erase(); + + mvaddstr(0, 0, "## SHIPS TITLE"); + for (y=1; ynationality), + ship->shipname, + ship->specs->guns, + shortclassname[ship->specs->class], + qualname[ship->specs->qual], + ship->specs->pts); + } + + move(1 + pickerpos - pickerscroll, 55); + wrefresh(stdscr); +} + +static int +pickscenario(int initpos) +{ + int ch; + + pickerpos = initpos; + if (pickerpos < 0) { + pickerpos = 0; + } + + while (1) { + drawpicker(); + ch = getch(); + switch (ch) { + case 12 /*^L*/: + clear(); + break; + case '\r': + case '\n': + return pickerpos; + case 7 /*^G*/: + case 8 /*^H*/: + case 27 /*ESC*/: + case 127 /*^?*/: + return initpos; + case 16 /*^P*/: + case KEY_UP: + up(&pickerpos, &pickerscroll); + break; + case 14 /*^N*/: + case KEY_DOWN: + down(&pickerpos, &pickerscroll, NSCENE, LINES-12); + break; + default: + beep(); + break; + } + } + return pickerpos; +} + +//////////////////////////////////////////////////////////// +// setup menus + +#define MAINITEMS_NUM 5 +#define STARTITEMS_NUM 4 +#define OPTIONSITEMS_NUM 5 + +static int mainpos; +static bool connected; + +static bool joinactive; +static int joinpos; +static int joinscroll; +static int joinable[NSCENE]; +static int numjoinable; + +static bool startactive; +static int startpos; +static int startscenario; + +static bool optionsactive; +static int optionspos; +static char o_myname[MAXNAMESIZE]; +static bool o_randomize; +static bool o_longfmt; +static bool o_nobells; + + +/* + * this and sgetstr() should share code + */ +static void +startup_getstr(int y, int x, char *buf, size_t max) +{ + size_t pos = 0; + int ch; + + for (;;) { + buf[pos] = 0; + move(y, x); + addstr(buf); + clrtoeol(); + wrefresh(stdscr); + fflush(stdout); + + ch = getch(); + switch (ch) { + case '\n': + case '\r': + return; + case '\b': + if (pos > 0) { + /*waddstr(scroll_w, "\b \b");*/ + pos--; + } + break; + default: + if (ch >= ' ' && ch < 0x7f && pos < max - 1) { + buf[pos++] = ch; + } else { + beep(); + } + } + } +} + +static void +changename(void) +{ + mvaddstr(LINES-2, COLS/2, "Enter your name:"); + startup_getstr(LINES-1, COLS/2, o_myname, sizeof(o_myname)); +} + +static void +checkforgames(void) +{ + int i; + int prev; + + if (numjoinable > 0) { + prev = joinable[joinpos]; + } else { + prev = 0; + } + + numjoinable = 0; + for (i = 0; i < NSCENE; i++) { + if (!sync_exists(i)) { + continue; + } + if (i < prev) { + joinpos = numjoinable; + } + joinable[numjoinable++] = i; + } + if (joinpos > numjoinable) { + joinpos = (numjoinable > 0) ? numjoinable - 1 : 0; + } + if (joinscroll > joinpos) { + joinscroll = (joinpos > 0) ? joinpos - 1 : 0; + } +} + +static void +drawstartmenus(void) +{ + const int mainy0 = 8; + const int mainx0 = 12; + + erase(); + + mvaddstr(5, 10, "Wooden Ships & Iron Men"); + + mvaddselstr(mainy0+0, mainx0, 0, mainpos, 17, "Join a game"); + mvaddselstr(mainy0+1, mainx0, 1, mainpos, 17, "Start a game"); + mvaddselstr(mainy0+2, mainx0, 2, mainpos, 17, "Options"); + mvaddselstr(mainy0+3, mainx0, 3, mainpos, 17, "Show high scores"); + mvaddselstr(mainy0+4, mainx0, 4, mainpos, 17, "Quit"); + + mvprintw(15, 10, "Captain %s", myname); + if (connected) { + mvaddstr(16, 10, "Connected via scratch files."); + } else { + mvaddstr(16, 10, "Not connected."); + } + + if (joinactive) { + int y0, leavey = 0, i, sc; + + mvaddstr(0, COLS/2, "## SHIPS TITLE"); + y0 = 1; + for (i = 0; i < numjoinable; i++) { + if (i >= joinscroll && i < joinscroll + LINES-1) { + move(y0 + i - joinscroll, COLS/2); + if (i == joinpos) { + attron(A_REVERSE); + } + sc = joinable[i]; + printw("%-2d %-5d %s", + sc, scene[sc].vessels, scene[sc].name); + if (i == joinpos) { + filltoeol(); + attroff(A_REVERSE); + leavey = y0 + i - joinscroll; + } + } + } + mvaddstr(19, 10, "(Esc to abort)"); + if (numjoinable > 0) { + mvaddstr(18, 10, "Choose a game to join."); + move(leavey, COLS-1); + } else { + mvaddstr(2, COLS/2, "No games."); + mvaddstr(18, 10, "Press return to refresh."); + } + + } else if (startactive) { + const char *name; + + mvaddstr(18, 10, "Start a new game"); + mvaddstr(19, 10, "(Esc to abort)"); + mvaddstr(2, COLS/2, "New game"); + + name = (startscenario < 0) ? + "not selected" : scene[startscenario].name; + + mvselprintw(4, COLS/2, 0, startpos, COLS/2 - 1, + "Scenario: %s", name); + mvaddselstr(5, COLS/2, 1, startpos, COLS/2 - 1, + "Visibility: local"); + mvaddselstr(6, COLS/2, 2, startpos, COLS/2 - 1, + "Password: unset"); + mvaddselstr(7, COLS/2, 3, startpos, COLS/2 - 1, + "Start game"); + move(4+startpos, COLS - 2); + + } else if (optionsactive) { + mvaddstr(18, 10, "Adjust options"); + mvaddstr(19, 10, "(Esc to abort)"); + mvaddstr(2, COLS/2, "Adjust options"); + + mvselprintw(4, COLS/2, 0, optionspos, COLS/2-1, + "Your name: %s", o_myname); + mvselprintw(5, COLS/2, 1, optionspos, COLS/2-1, + "Auto-pick ships: %s", o_randomize ? "ON" : "off"); + mvselprintw(6, COLS/2, 2, optionspos, COLS/2-1, + "Usernames in scores: %s", + o_longfmt ? "ON" : "off"); + mvselprintw(7, COLS/2, 3, optionspos, COLS/2-1, + "Beeping: %s", o_nobells ? "OFF" : "on"); + mvselprintw(8, COLS/2, 4, optionspos, COLS/2-1, + "Apply changes"); + move(4+optionspos, COLS - 2); + + } else { + move(mainy0 + mainpos, mainx0 + 16); + } + + wrefresh(stdscr); + fflush(stdout); +} + +void +startup(void) +{ + int ch; + + connected = false; + mainpos = 0; + + joinactive = false; + joinpos = 0; + joinscroll = 0; + numjoinable = 0; + + startactive = false; + startpos = 0; + startscenario = -1; + + optionsactive = false; + optionspos = 0; + + while (1) { + if (joinactive) { + checkforgames(); + } + drawstartmenus(); + ch = getch(); + switch (ch) { + case 12 /*^L*/: + clear(); + break; + case '\r': + case '\n': + if (joinactive && numjoinable > 0) { + game = joinable[joinpos]; + startgame(); + joinactive = false; + } else if (startactive) { + switch (startpos) { + case 0: + startscenario = pickscenario(startscenario); + startpos = 3; + break; + case 1: + case 2: + oops(21, 10, "That doesn't work yet."); + break; + case 3: + if (startscenario >= 0) { + game = startscenario; + /* can't do this here yet */ + /*startdriver();*/ + startgame(); + startactive = false; + startscenario = -1; + } else { + oops(21, 10, + "Pick a scenario."); + } + break; + } + } else if (optionsactive) { + switch (optionspos) { + case 0: changename(); break; + case 1: o_randomize = !o_randomize; break; + case 2: o_longfmt = !o_longfmt; break; + case 3: o_nobells = !o_nobells; break; + case 4: + strlcpy(myname, o_myname, + sizeof(myname)); + randomize = o_randomize; + longfmt = o_longfmt; + nobells = o_nobells; + optionsactive = false; + break; + } + } else { + switch (mainpos) { + case 0: joinactive = true; break; + case 1: startactive = true; break; + case 2: + strlcpy(o_myname, myname, + sizeof(o_myname)); + o_randomize = randomize; + o_longfmt = longfmt; + o_nobells = nobells; + optionsactive = true; + break; + case 3: lo_curses(); break; + case 4: return; + } + } + break; + case 7 /*^G*/: + case 8 /*^H*/: + case 27 /*ESC*/: + case 127 /*^?*/: + if (joinactive) { + joinactive = false; + } else if (startactive) { + startactive = false; + } else if (optionsactive) { + optionsactive = false; + } else { + /* nothing */ + } + break; + case 16 /*^P*/: + case KEY_UP: + if (joinactive) { + up(&joinpos, &joinscroll); + } else if (startactive) { + up(&startpos, NULL); + } else if (optionsactive) { + up(&optionspos, NULL); + } else { + up(&mainpos, NULL); + } + break; + case 14 /*^N*/: + case KEY_DOWN: + if (joinactive) { + down(&joinpos, &joinscroll, + numjoinable, LINES-1); + } else if (startactive) { + down(&startpos, NULL, + STARTITEMS_NUM, STARTITEMS_NUM); + } else if (optionsactive) { + down(&optionspos, NULL, + OPTIONSITEMS_NUM, OPTIONSITEMS_NUM); + } else { + down(&mainpos, NULL, + MAINITEMS_NUM, MAINITEMS_NUM); + } + break; + default: + beep(); + break; + } + } +} diff --git a/sail/pl_main.c b/sail/pl_main.c index 619a99f1..f13f1f81 100644 --- a/sail/pl_main.c +++ b/sail/pl_main.c @@ -1,4 +1,4 @@ -/* $NetBSD: pl_main.c,v 1.26 2009/03/15 03:33:56 dholland Exp $ */ +/* $NetBSD: pl_main.c,v 1.27 2010/08/06 09:14:40 dholland Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,12 +34,11 @@ #if 0 static char sccsid[] = "@(#)pl_main.c 8.1 (Berkeley) 5/31/93"; #else -__RCSID("$NetBSD: pl_main.c,v 1.26 2009/03/15 03:33:56 dholland Exp $"); +__RCSID("$NetBSD: pl_main.c,v 1.27 2010/08/06 09:14:40 dholland Exp $"); #endif #endif /* not lint */ #include -#include #include #include #include @@ -48,48 +47,18 @@ __RCSID("$NetBSD: pl_main.c,v 1.26 2009/03/15 03:33:56 dholland Exp $"); #include "display.h" #include "extern.h" #include "player.h" -#include "restart.h" -static void initialize(void); +char myname[MAXNAMESIZE]; -/*ARGSUSED*/ -int -pl_main(void) -{ - initialize(); - Msg("Aye aye, Sir"); - play(); - return 0; /* for lint, play() never returns */ -} +static void initialize(void); -static void -initialize(void) +void +pl_main_init(void) { - struct File *fp; - struct ship *sp; - char captain[80]; - char message[60]; - int load; - int n; - char *nameptr; int nat[NNATION]; + int n; + struct ship *sp; - if (game < 0) { - puts("Choose a scenario:\n"); - puts("\n\tNUMBER\tSHIPS\tIN PLAY\tTITLE"); - for (n = 0; n < NSCENE; n++) { - /* ( */ - printf("\t%d):\t%d\t%s\t%s\n", n, scene[n].vessels, - sync_exists(n) ? "YES" : "no", - scene[n].name); - } -reprint: - printf("\nScenario number? "); - fflush(stdout); - scanf("%d", &game); - while (getchar() != '\n' && !feof(stdin)) - ; - } if (game < 0 || game >= NSCENE) { errx(1, "Very funny."); } @@ -114,145 +83,54 @@ reprint: signal(SIGHUP, choke); signal(SIGINT, choke); + signal(SIGCHLD, child); +} - hasdriver = sync_exists(game); - if (sync_open() < 0) { - err(1, "syncfile"); - } +void +pl_main_uninit(void) +{ + struct ship *sp; - if (hasdriver) { - puts("Synchronizing with the other players..."); - fflush(stdout); - if (Sync() < 0) - leave(LEAVE_SYNC); - } - for (;;) { - foreachship(sp) - if (sp->file->captain[0] == 0 && !sp->file->struck - && sp->file->captured == 0) - break; - if (sp >= ls) { - puts("All ships taken in that scenario."); - foreachship(sp) - free(sp->file); - sync_close(0); - people = 0; - goto reprint; - } - if (randomize) { - player = sp - SHIP(0); - } else { - printf("%s\n\n", cc->name); - foreachship(sp) - printf(" %2d: %-10s %-15s (%-2d pts) %s\n", - sp->file->index, - countryname[sp->nationality], - sp->shipname, - sp->specs->pts, - saywhat(sp, 1)); - printf("\nWhich ship (0-%d)? ", cc->vessels-1); - fflush(stdout); - if (scanf("%d", &player) != 1 || player < 0 - || player >= cc->vessels) { - while (getchar() != '\n' && !feof(stdin)) - ; - puts("Say what?"); - player = -1; - } else - while (getchar() != '\n' && !feof(stdin)) - ; - if (feof(stdin)) { - printf("\nExiting...\n"); - leave(LEAVE_QUIT); - } - } - if (player < 0) - continue; - if (Sync() < 0) - leave(LEAVE_SYNC); - fp = SHIP(player)->file; - if (fp->captain[0] || fp->struck || fp->captured != 0) - puts("That ship is taken."); - else - break; + foreachship(sp) { + free(sp->file); + sp->file = NULL; } +} - ms = SHIP(player); - mf = ms->file; - mc = ms->specs; +static void +initialize(void) +{ + char captain[MAXNAMESIZE]; + char message[60]; + + if (game < 0 || game >= NSCENE) { + errx(1, "Very funny."); + } send_begin(ms); if (Sync() < 0) leave(LEAVE_SYNC); - signal(SIGCHLD, child); - if (!hasdriver) - switch (fork()) { - case 0: - longjmp(restart, MODE_DRIVER); - /*NOTREACHED*/ - case -1: - warn("fork"); - leave(LEAVE_FORK); - break; - default: - hasdriver++; - } - +#if 0 printf("Your ship is the %s, a %d gun %s (%s crew).\n", ms->shipname, mc->guns, classname[mc->class], qualname[mc->qual]); - if ((nameptr = getenv("SAILNAME")) && *nameptr) - strlcpy(captain, nameptr, sizeof captain); - else { - printf("Your name, Captain? "); - fflush(stdout); - if (fgets(captain, sizeof captain, stdin) == NULL) - strcpy(captain, "no name"); - else if (*captain == '\0' || *captain == '\n') - strcpy(captain, "no name"); - else - captain[strlen(captain) - 1] = '\0'; - } - send_captain(ms, captain); - for (n = 0; n < 2; n++) { - char buf[10]; +#endif - printf("\nInitial broadside %s (grape, chain, round, double): ", - n ? "right" : "left"); - fflush(stdout); - fgets(buf, sizeof(buf), stdin); - switch (*buf) { - case 'g': - load = L_GRAPE; - break; - case 'c': - load = L_CHAIN; - break; - case 'r': - load = L_ROUND; - break; - case 'd': - load = L_DOUBLE; - break; - default: - load = L_ROUND; - } - if (n) { - mf->loadR = load; - mf->readyR = R_LOADED|R_INITIAL; - } else { - mf->loadL = load; - mf->readyL = R_LOADED|R_INITIAL; - } - } + strlcpy(captain, myname, sizeof(captain)); + send_captain(ms, captain); - printf("\n"); - fflush(stdout); - initscreen(); display_redraw(); snprintf(message, sizeof message, "Captain %s assuming command", captain); send_signal(ms, message); newturn(0); } + +void +pl_main(void) +{ + initialize(); + Msg("Aye aye, Sir"); + play(); +} -- cgit v1.2.3-56-ge451