Mercurial > hg > early-roguelike
diff arogue7/rip.c @ 125:adfa37e67084
Import Advanced Rogue 7.7 from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Fri, 08 May 2015 15:24:40 -0400 |
parents | |
children | b786053d2f37 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/rip.c Fri May 08 15:24:40 2015 -0400 @@ -0,0 +1,889 @@ +/* + * rip.c - File for the fun ends Death or a total win + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +/* Print flags for scoring */ +#define REALLIFE 1 /* Print out machine and logname */ +#define EDITSCORE 2 /* Edit the current score file */ +#define ADDSCORE 3 /* Add a new score */ + +#define NAMELEN 80 + +/* + * File for the fun ends + * Death or a total win + * + */ + +#include "curses.h" +#ifdef BSD +#include <sys/time.h> +#else +#include <time.h> +#endif +#include <signal.h> +#include <ctype.h> +#include <sys/types.h> +#include <fcntl.h> +#include "mach_dep.h" +#include "network.h" +#include "rogue.h" +#ifdef PC7300 +#include "sys/window.h" +extern struct uwdata wdata, oldwin; +extern char oldtext[WTXTNUM][WTXTLEN]; +#endif + +#ifdef NUMNET +/* Network machines (for mutual score keeping) */ +static struct network Network[NUMNET] = { + { "ihwpt", "/t1/michael/bin/rg" }, +}; +#endif + +/* + * If you change this structure, change the compatibility routines + * scoreout() and scorein() to reflect the change. Also update SCORELEN. + */ +struct sc_ent { + unsigned long sc_score; + char sc_name[NAMELEN]; + char sc_system[SYSLEN]; + char sc_login[LOGLEN]; + short sc_flags; + short sc_level; + short sc_ctype; + short sc_monster; + short sc_quest; +}; +#define SCORELEN \ + (sizeof(unsigned long) + NAMELEN + SYSLEN + LOGLEN + 5*sizeof(short)) + +static char *rip[] = { +" __________", +" / \\", +" / REST \\", +" / IN \\", +" / PEACE \\", +" / \\", +" | |", +" | |", +" | killed by |", +" | |", +" | 1984 |", +" *| * * * | *", +" ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______", + 0 +}; + +char *killname(); + + + + + +void +byebye(sig) +int sig; +{ + if (!isendwin()) { + clear(); + endwin(); + } +#ifdef PC7300 + endhardwin(); +#endif + printf("\n"); + exit(0); +} + + +/* + * death: + * Do something really fun when he dies + */ + +death(monst) +register short monst; +{ + register char **dp = rip, *killer; + register struct tm *lt; + time_t date; + char buf[LINELEN]; + struct tm *localtime(); + + time(&date); + lt = localtime(&date); + clear(); + move(8, 0); + while (*dp) + printw("%s\n", *dp++); + mvaddstr(14, 28-((strlen(whoami)+1)/2), whoami); + sprintf(buf, "%lu Points", pstats.s_exp ); + mvaddstr(15, 28-((strlen(buf)+1)/2), buf); + killer = killname(monst); + mvaddstr(17, 28-((strlen(killer)+1)/2), killer); + mvaddstr(18, 26, (sprintf(prbuf, "%4d", 1900+lt->tm_year), prbuf)); + move(lines-1, 0); + refresh(); + score(pstats.s_exp, KILLED, monst); + endwin(); +#ifdef PC7300 + endhardwin(); +#endif + exit(0); +} + +#ifdef PC7300 +/* + * Restore window characteristics on a hard window terminal (PC7300). + */ +endhardwin() +{ + register int i; + struct utdata labelbuf; + + /* Restore the old window size */ + if (oldwin.uw_width) ioctl(1, WIOCSETD, &oldwin); + + /* Restore the old window text */ + for (i=0; i<WTXTNUM; i++) { + labelbuf.ut_num = i; + strcpy(labelbuf.ut_text, oldtext[i]); + ioctl(1, WIOCSETTEXT, &labelbuf); + } +} +#endif + +char * +killname(monst) +register short monst; +{ + static char mons_name[LINELEN]; + int i; + + if (monst > NUMMONST) return("a strange monster"); + + if (monst >= 0) { + switch (monsters[monst].m_name[0]) { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + sprintf(mons_name, "an %s", monsters[monst].m_name); + break; + default: + sprintf(mons_name, "a %s", monsters[monst].m_name); + } + return(mons_name); + } + for (i = 0; i< DEATHNUM; i++) { + if (deaths[i].reason == monst) + break; + } + if (i >= DEATHNUM) + return ("strange death"); + return (deaths[i].name); +} + + +/* + * score -- figure score and post it. + */ + +/* VARARGS2 */ +score(amount, flags, monst) +unsigned long amount; +short monst; +{ + static struct sc_ent top_ten[NUMSCORE]; + register struct sc_ent *scp; + register int i; + register struct sc_ent *sc2; + register int outfd; + register char *killer; + register int prflags = 0; + register int fd; + short upquest, wintype, uplevel, uptype; /* For network updating */ + char upsystem[SYSLEN], uplogin[LOGLEN]; + char *thissys; /* Holds the name of this system */ + char *compatstr=NULL; /* Holds scores for writing compatible score files */ + char scoreline[100]; +#define REASONLEN 3 + static char *reason[] = { + "killed", + "quit", + "A total winner", + "somehow left", + }; + char *packend; + + signal(SIGINT, byebye); + if (flags != WINNER && flags != SCOREIT && flags != UPDATE) { + if (flags == CHICKEN) + packend = "when you quit"; + else + { + packend = "at your untimely demise"; + mvaddstr(lines - 1, 0, retstr); + refresh(); + getstr(prbuf); + } + showpack(packend); + } + purse = 0; /* Steal all the gold */ + + /* + * Open file and read list + */ + + if ((fd = open(score_file, O_RDWR | O_CREAT, 0666)) < 0) return; + outfd = fd; + +#ifndef SYSTEM + thissys = md_gethostname(); +#else + thissys = SYSTEM; +#endif + + for (scp = top_ten; scp <= &top_ten[NUMSCORE-1]; scp++) + { + scp->sc_score = 0L; + for (i = 0; i < NAMELEN; i++) + scp->sc_name[i] = rnd(255); + scp->sc_quest= RN; + scp->sc_flags = RN; + scp->sc_level = RN; + scp->sc_monster = RN; + scp->sc_ctype = 0; + strncpy(scp->sc_system, thissys, SYSLEN); + scp->sc_login[0] = '\0'; + } + + /* + * If this is a SCOREIT optin (rogue -s), don't call byebye. The + * endwin() call in byebye() will result in a core dump. + */ + if (flags == SCOREIT) signal(SIGINT, SIG_DFL); + else signal(SIGINT, byebye); + + if (flags != SCOREIT && flags != UPDATE) + { + mvaddstr(lines - 1, 0, retstr); + refresh(); + fflush(stdout); + getstr(prbuf); + } + + /* Check for special options */ + if (strcmp(prbuf, "names") == 0) + prflags = REALLIFE; +#ifdef WIZARD + else if (wizard) { + if (strcmp(prbuf, "edit") == 0) prflags = EDITSCORE; + else if (strcmp(prbuf, "add") == 0) { + prflags = ADDSCORE; + waswizard = FALSE; /* We want the new score recorded */ + } + } +#endif + + /* Read the score and convert it to a compatible format */ + for(i = 0; i < NUMSCORE; i++) + { + encread(top_ten[i].sc_name, NAMELEN, fd); + encread(top_ten[i].sc_system, SYSLEN, fd); + encread(top_ten[i].sc_login, LOGLEN, fd); + encread(scoreline, 100, fd); + sscanf(scoreline, " %lu %hd %hd %hd %hd %hd \n", + &top_ten[i].sc_score, &top_ten[i].sc_flags, + &top_ten[i].sc_level, &top_ten[i].sc_ctype, + &top_ten[i].sc_monster, &top_ten[i].sc_quest + ); + } + + /* Get some values if this is an update */ + if (flags == UPDATE) { + unsigned long netread(); + int errcheck, errors = 0; + + upquest = (short) netread(&errcheck, sizeof(short), stdin); + if (errcheck) errors++; + + if (fread(whoami, 1, NAMELEN, stdin) != NAMELEN) errors++; + + wintype = (short) netread(&errcheck, sizeof(short), stdin); + if (errcheck) errors++; + + uplevel = (short) netread(&errcheck, sizeof(short), stdin); + if (errcheck) errors++; + + uptype = (short) netread(&errcheck, sizeof(short), stdin); + if (errcheck) errors++; + + if (fread(upsystem, 1, SYSLEN, stdin) != SYSLEN) + errors++; + if (fread(uplogin, 1, LOGLEN, stdin) != LOGLEN) + errors++; + + if (errors) { + close(outfd); + free(compatstr); + return; + } + } + + /* + * Insert player in list if need be + */ + if (!waswizard) { + char *login; + + if (flags != UPDATE) { + login = md_getusername(); + } + + if (flags == UPDATE) + (void) update(top_ten, amount, upquest, whoami, wintype, + uplevel, monst, uptype, upsystem, uplogin); + else { +#ifdef WIZARD + if (prflags == ADDSCORE) { /* Overlay characteristic by new ones */ + char buffer[LINELEN]; + + clear(); + mvaddstr(1, 0, "Score: "); + mvaddstr(2, 0, "Quest (number): "); + mvaddstr(3, 0, "Name: "); + mvaddstr(4, 0, "System: "); + mvaddstr(5, 0, "Login: "); + mvaddstr(6, 0, "Level: "); + mvaddstr(7, 0, "Char type: "); + mvaddstr(8, 0, "Result: "); + + /* Get the score */ + move(1, 7); + get_str(buffer, stdscr); + amount = atol(buffer); + + /* Get the character's quest -- must be a number */ + move(2, 16); + get_str(buffer, stdscr); + quest_item = atoi(buffer); + + /* Get the character's name */ + move(3, 6); + get_str(buffer, stdscr); + strncpy(whoami, buffer, NAMELEN); + + /* Get the system */ + move(4, 8); + get_str(buffer, stdscr); + strncpy(thissys, buffer, SYSLEN); + + /* Get the login */ + move(5, 7); + get_str(buffer, stdscr); + strncpy(login, buffer, LOGLEN); + + /* Get the level */ + move(6, 7); + get_str(buffer, stdscr); + level = max_level = (short) atoi(buffer); + + /* Get the character type */ + move(7, 11); + get_str(buffer, stdscr); + for (i=0; i<NUM_CHARTYPES; i++) { + if (EQSTR(buffer, char_class[i].name, strlen(buffer))) + break; + } + player.t_ctype = i; + + /* Get the win type */ + move(8, 8); + get_str(buffer, stdscr); + switch (buffer[0]) { + case 'W': + case 'w': + case 'T': + case 't': + flags = WINNER; + break; + + case 'Q': + case 'q': + flags = CHICKEN; + break; + + case 'k': + case 'K': + default: + flags = KILLED; + break; + } + + /* Get the monster if player was killed */ + if (flags == KILLED) { + mvaddstr(9, 0, "Death type: "); + get_str(buffer, stdscr); + if (buffer[0] == 'M' || buffer[0] == 'm') + do { + monst = makemonster(TRUE, "Editing", "choose"); + } while (monst < 0); /* Force a choice */ + else monst = getdeath(); + } + } +#endif + + if (update(top_ten, amount, (short) quest_item, whoami, flags, + (flags == WINNER) ? (short) max_level : (short) level, + monst, player.t_ctype, thissys, login) +#ifdef NUMNET + && fork() == 0 /* Spin off network process */ +#endif + ) { +#ifdef NUMNET + /* Send this update to the other systems in the network */ + int i, j; + char cmd[256]; /* Command for remote execution */ + FILE *rmf, *popen(); /* For input to remote command */ + + for (i=0; i<NUMNET; i++) + if (Network[i].system[0] != '!' && + strcmp(Network[i].system, thissys)) { + sprintf(cmd, NETCOMMAND, + Network[i].system, Network[i].rogue); + + /* Execute the command */ + if ((rmf=popen(cmd, "w")) != NULL) { + unsigned long temp; /* Temporary value */ + + /* Write out the parameters */ + (void) netwrite((unsigned long) amount, + sizeof(unsigned long), rmf); + + (void) netwrite((unsigned long) monst, + sizeof(short), rmf); + + (void) netwrite((unsigned long) quest_item, + sizeof(short), rmf); + + (void) fwrite(whoami, 1, strlen(whoami), rmf); + for (j=strlen(whoami); j<NAMELEN; j++) + putc('\0', rmf); + + (void) netwrite((unsigned long) flags, + sizeof(short), rmf); + + temp = (unsigned long) + (flags==WINNER ? max_level : level); + (void) netwrite(temp, sizeof(short), rmf); + + (void) netwrite((unsigned long) player.t_ctype, + sizeof(short), rmf); + + (void) fwrite(thissys, 1, + strlen(thissys), rmf); + for (j=strlen(thissys); j<SYSLEN; j++) + putc('\0', rmf); + + (void) fwrite(login, 1, strlen(login), rmf); + for (j=strlen(login); j<LOGLEN; j++) + putc('\0', rmf); + + /* Close off the command */ + (void) pclose(rmf); + } + } + _exit(0); /* Exit network process */ +#endif + } + } + } + + /* + * SCOREIT -- rogue -s option. Never started curses if this option. + * UPDATE -- network scoring update. Never started curses if this option. + * EDITSCORE -- want to delete or change a score. + */ +/* if (flags != SCOREIT && flags != UPDATE && prflags != EDITSCORE) + endwin(); */ + + if (flags != UPDATE) { + if (flags != SCOREIT) { + clear(); + refresh(); + endwin(); + } + /* + * Print the list + */ + printf("\nTop %d Adventurers:\nRank Score\tName\n", + NUMSCORE); + for (scp = top_ten; scp <= &top_ten[NUMSCORE-1]; scp++) { + const char *class; + + if (scp->sc_score != 0) { + class = char_class[scp->sc_ctype].name; + + /* Make sure we have an in-bound reason */ + if (scp->sc_flags > REASONLEN) scp->sc_flags = REASONLEN; + + printf("%3d %10lu\t%s (%s)", scp - top_ten + 1, + scp->sc_score, scp->sc_name, class); + + if (prflags == REALLIFE) printf(" [in real life %.*s!%.*s]", + SYSLEN, scp->sc_system, LOGLEN, scp->sc_login); + printf(":\n\t\t%s on level %d", reason[scp->sc_flags], + scp->sc_level); + + switch (scp->sc_flags) { + case KILLED: + printf(" by"); + killer = killname(scp->sc_monster); + printf(" %s", killer); + break; + + case WINNER: + printf(" with the %s", + rel_magic[scp->sc_quest].mi_name); + break; + } + + if (prflags == EDITSCORE) + { + fflush(stdout); + getstr(prbuf); + printf("\n"); + if (prbuf[0] == 'd') { + for (sc2 = scp; sc2 < &top_ten[NUMSCORE-1]; sc2++) + *sc2 = *(sc2 + 1); + top_ten[NUMSCORE-1].sc_score = 0; + for (i = 0; i < NAMELEN; i++) + top_ten[NUMSCORE-1].sc_name[i] = rnd(255); + top_ten[NUMSCORE-1].sc_flags = RN; + top_ten[NUMSCORE-1].sc_level = RN; + top_ten[NUMSCORE-1].sc_monster = RN; + scp--; + } + else if (prbuf[0] == 'e') { + printf("Death type: "); + getstr(prbuf); + if (prbuf[0] == 'M' || prbuf[0] == 'm') + do { + scp->sc_monster = + makemonster(TRUE, "Editing", "choose"); + } while (scp->sc_monster < 0); /* Force a choice */ + else scp->sc_monster = getdeath(); + clear(); + refresh(); + } + } + else printf("\n"); + } + } + if ((flags != SCOREIT) && (flags != UPDATE)) { + printf("\n[Press return to exit]"); + fflush(stdout); + fgets(prbuf,80,stdin); + } +/* if (prflags == EDITSCORE) endwin();*/ /* End editing windowing */ + } + lseek(outfd, 0L, 0); + /* + * Update the list file + */ + + for(i = 0; i < NUMSCORE; i++) + { + memset(scoreline,0,100); + encwrite(top_ten[i].sc_name, NAMELEN, outfd); + encwrite(top_ten[i].sc_system, SYSLEN, outfd); + encwrite(top_ten[i].sc_login, LOGLEN, outfd); + sprintf(scoreline, " %lu %hd %hd %hd %hd %hd \n", + top_ten[i].sc_score, top_ten[i].sc_flags, + top_ten[i].sc_level, top_ten[i].sc_ctype, + top_ten[i].sc_monster, top_ten[i].sc_quest); + encwrite(scoreline,100,outfd); + } + + close(outfd); +} + +/* + * scorein: + * Convert a character string that has been translated from a + * score file by scoreout() back to a score file structure. + */ +scorein(input, scores, num_bytes) +unsigned char *input; +struct sc_ent scores[]; +int num_bytes; /* Number of bytes of input that we want to convert */ +{ + register int i, j; + unsigned long *lptr; + unsigned short *sptr; + unsigned char *cptr; + + /* Convert a maximum of NUMSCORE entries */ + for (i=0; num_bytes > 0 && i < NUMSCORE; num_bytes -= SCORELEN, i++) { + /* The long fields are first -- ordered low to high byte in input */ + lptr = &scores[i].sc_score; + *lptr = ((unsigned long) *input++) & 0x000000ffL; + *lptr |= (((unsigned long) *input++) << 8) & 0x0000ff00L; + *lptr |= (((unsigned long) *input++) << 16) & 0x00ff0000L; + *lptr |= (((unsigned long) *input++) << 24) & 0xff000000L; + + /* The short fields are next -- ordered low to high byte in input */ + sptr = (unsigned short *) &scores[i].sc_flags; + *sptr = ((unsigned short) *input++) & 0xff; + *sptr |= (((unsigned short) *input++) << 8) & 0xff00; + + sptr = (unsigned short *) &scores[i].sc_level; + *sptr = ((unsigned short) *input++) & 0xff; + *sptr |= (((unsigned short) *input++) << 8) & 0xff00; + + sptr = (unsigned short *) &scores[i].sc_ctype; + *sptr = ((unsigned short) *input++) & 0xff; + *sptr |= (((unsigned short) *input++) << 8) & 0xff00; + + sptr = (unsigned short *) &scores[i].sc_monster; + *sptr = ((unsigned short) *input++) & 0xff; + *sptr |= (((unsigned short) *input++) << 8) & 0xff00; + + sptr = (unsigned short *) &scores[i].sc_quest; + *sptr = ((unsigned short) *input++) & 0xff; + *sptr |= (((unsigned short) *input++) << 8) & 0xff00; + + /* Finally comes the char fields -- they're easy */ + cptr = (unsigned char *) scores[i].sc_name;