Mercurial > hg > early-roguelike
view arogue7/rip.c @ 227:696277507a2e
Rogue V4, V5: disable a cheat granting permanent monster detection.
In these two games, a potion of monster detection turns on the player's
SEEMONST flag. A fuse is set to call turn_see() to turn the flag back
off. But the save and restore functions do not recognize turn_see() and
fail to set the fuse up again.
When restoring, Rogue V4 merely sets the fuse's function to NULL and
leaves it burning. When it goes off, a segfault results. Rogue V5
clears all the fuse's fields, and the player retains the ability to see
all monsters on the level.
The save and restore code can now handle the fuse. The function used is
a new wrapper, turn_see_off(), which should lead to less problems with
daemons being multiple incompatible types.
Also, Rogue V4 and Super-Rogue now properly clear unrecognized daemon
and fuse slots when restoring a saved game.
| author | John "Elwin" Edwards |
|---|---|
| date | Sat, 05 Mar 2016 12:10:20 -0500 |
| parents | f9ef86cf22b2 |
| children | d3968e9cb98d |
line wrap: on
line source
/* * 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 <string.h> #include <stdlib.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 extern int scorefd; extern FILE *logfile; #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(short monst); void showpack(char *howso); int update(struct sc_ent top_ten[], unsigned long amount, short quest, char *whoami, short flags, short level, short monst, short ctype, char *system, char *login); void byebye(int sig) { if (!isendwin()) { clear(); endwin(); } #ifdef PC7300 endhardwin(); #endif printf("\n"); exit(0); } /* * death: * Do something really fun when he dies */ void death(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(); writelog(pstats.s_exp, KILLED, monst); score(pstats.s_exp, KILLED, monst); endwin(); #ifdef PC7300 endhardwin(); #endif exit(0); } #ifdef PC7300 /* * Restore window characteristics on a hard window terminal (PC7300). */ void endhardwin(void) { 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(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); } /* Writes an entry in the log file */ void writelog(unsigned long amount, int flags, short monst) { char had_quest = '0'; char fate[LINELEN]; struct linked_list *item; struct object *obj; #ifdef LOGFILE if (waswizard) return; if (logfile == NULL) return; /* Check for quest item */ for (item = pack; item != NULL; item = next(item)) { obj = OBJPTR(item); if (obj->o_type == RELIC && obj->o_which == quest_item) had_quest = '1'; } /* Describe what happened */ if (flags == KILLED) { snprintf(fate, LINELEN, "killed by %s", killname(monst)); } else if (flags == CHICKEN) { strcpy(fate, "quit"); } else if (flags == WINNER) { strcpy(fate, "escaped"); } else return; /* Write */ fprintf(logfile, "%d %d %s %d %s %d %d %d %c %s\n", time(NULL), amount, whoami, pstats.s_lvl, char_class[char_type].name, level, max_level, quest_item, had_quest, fate); fclose(logfile); #endif return; } /* * score -- figure score and post it. */ /* VARARGS2 */ void score(unsigned long amount, int flags, 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 = scorefd) < 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: ");
