Mercurial > hg > early-roguelike
view rogue5/rip.c @ 110:5f51f7d9805f
arogue5: fix some save/restore-related crashes.
The save/restore code took the pointer intended as an argument for the
doctor() daemon and wrote it to the savefile as an int. I don't know
why it took so long to fail horribly. The problem has been avoided by
replacing the value with &player when restoring. That seems to be the
only argument ever actually used.
The code also writes only four bytes for an unsigned long; if
sizeof(long) == 8, it casts to unsigned int first. It failed to do the
cast when reading back, with the result that four bytes were read and
the other half of the number was effectively uninitialized.
It apparently works now, but the save/restore code ought still to be
regarded as decidedly unfortunate.
author | John "Elwin" Edwards |
---|---|
date | Mon, 06 Jan 2014 15:57:17 -0500 |
parents | 24e6beb9e7aa |
children | ee250e3646fd |
line wrap: on
line source
/* * File for the fun ends * Death or a total win * * @(#)rip.c 4.57 (Berkeley) 02/05/99 * * Rogue: Exploring the Dungeons of Doom * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman * All rights reserved. * * See the file LICENSE.TXT for full copyright and licensing information. */ #include <stdlib.h> #include <string.h> #include <time.h> #include <signal.h> #include <sys/types.h> #include <ctype.h> #include <fcntl.h> #include <curses.h> #include "rogue.h" #include "score.h" static char *rip[] = { " __________\n", " / \\\n", " / REST \\\n", " / IN \\\n", " / PEACE \\\n", " / \\\n", " | |\n", " | |\n", " | killed by a |\n", " | |\n", " | 1980 |\n", " *| * * * | *\n", " ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______\n", 0 }; /* * score: * Figure score and post it. */ /* VARARGS2 */ void score(int amount, int flags, int monst) { SCORE *scp; int i; SCORE *sc2; SCORE *top_ten, *endp; # ifdef MASTER int prflags = 0; # endif void (*fp)(int); uid_t uid; char *reason[] = { "killed", "quit", "A total winner", "killed with Amulet" }; start_score(); if (flags >= 0 #ifdef MASTER || wizard #endif ) { mvaddstr(LINES - 1, 0 , "[Press return to continue]"); refresh(); wgetnstr(stdscr,prbuf,80); endwin(); printf("\n"); resetltchars(); /* * free up space to "guarantee" there is space for the top_ten */ delwin(stdscr); delwin(curscr); if (hw != NULL) delwin(hw); } top_ten = malloc(numscores * sizeof (SCORE)); if (top_ten == NULL) return; endp = &top_ten[numscores]; for (scp = top_ten; scp < endp; scp++) { scp->sc_score = 0; for (i = 0; i < MAXSTR; i++) scp->sc_name[i] = (char) rnd(255); scp->sc_flags = RN; scp->sc_level = RN; scp->sc_monster = RN; scp->sc_uid = RN; } signal(SIGINT, SIG_DFL); #ifdef MASTER if (wizard) if (strcmp(prbuf, "names") == 0) prflags = 1; else if (strcmp(prbuf, "edit") == 0) prflags = 2; #endif rd_score(top_ten); /* * Insert her in list if need be */ sc2 = NULL; if (!noscore) { uid = md_getuid(); for (scp = top_ten; scp < endp; scp++) if (amount > scp->sc_score) break; else if (!allscore && /* only one score per nowin uid */ flags != 2 && scp->sc_uid == uid && scp->sc_flags != 2) scp = endp; if (scp < endp) { if (flags != 2 && !allscore) { for (sc2 = scp; sc2 < endp; sc2++) { if (sc2->sc_uid == uid && sc2->sc_flags != 2) break; } if (sc2 >= endp) sc2 = endp - 1; } else sc2 = endp - 1; while (sc2 > scp) { *sc2 = sc2[-1]; sc2--; } scp->sc_score = amount; strncpy(scp->sc_name, whoami, MAXSTR); scp->sc_flags = flags; if (flags == 2) scp->sc_level = max_level; else scp->sc_level = level; scp->sc_monster = monst; scp->sc_uid = uid; sc2 = scp; } } /* * Print the list */ if (flags != -1) putchar('\n'); printf("Top %s %s:\n", Numname, allscore ? "Scores" : "Rogueists"); printf(" Score Name\n"); for (scp = top_ten; scp < endp; scp++) { if (scp->sc_score) { if (sc2 == scp) md_raw_standout(); printf("%2d %5d %s: %s on level %d", (int) (scp - top_ten + 1), scp->sc_score, scp->sc_name, reason[scp->sc_flags], scp->sc_level); if (scp->sc_flags == 0 || scp->sc_flags == 3) printf(" by %s", killname(scp->sc_monster, TRUE)); #ifdef MASTER if (prflags == 1) { printf(" (%s)", md_getrealname(scp->sc_uid)); } else if (prflags == 2) { fflush(stdout); (void) fgets(prbuf,10,stdin); if (prbuf[0] == 'd') { for (sc2 = scp; sc2 < endp - 1; sc2++) *sc2 = *(sc2 + 1); sc2 = endp - 1; sc2->sc_score = 0; for (i = 0; i < MAXSTR; i++) sc2->sc_name[i] = (char) rnd(255); sc2->sc_flags = RN; sc2->sc_level = RN; sc2->sc_monster = RN; scp--; } } else #endif /* MASTER */ printf("."); if (sc2 == scp) md_raw_standend(); putchar('\n'); } else break; } /* * Update the list file */ if (sc2 != NULL) { if (lock_sc()) { fp = signal(SIGINT, SIG_IGN); wr_score(top_ten); unlock_sc(); signal(SIGINT, fp); } } } void writelog(int amount, int flags, int monst) { #ifdef LOGFILE char logmessage[160], ltemp[80]; if (logfi == NULL) return; #ifdef MASTER if (wizard) { fclose(logfi); return; } #endif sprintf(logmessage, "%d %d %.20s %d ", time(NULL), amount, whoami, pstats.s_lvl); if (flags == 0) /* dead */ { sprintf(ltemp, "killed by %s on level %d\n", killname(monst, TRUE), level); strcat(logmessage, ltemp); } else if (flags == 1) /* quit */ { if (amulet) sprintf(ltemp, "quit on level %d [max %d] with the Amulet\n", level, max_level); else sprintf(ltemp, "quit on level %d\n", level); strcat(logmessage, ltemp); } else if (flags == 2) /* won */ { sprintf(ltemp, "escaped with the Amulet [deepest level: %d]\n", max_level); strcat(logmessage, ltemp); } else if (flags == 3) /* killed with Amulet */ { strcat(logmessage, "killed by "); strcat(logmessage, killname(monst, TRUE)); sprintf(ltemp, " on level %d [max %d] with the Amulet\n", level, max_level); strcat(logmessage, ltemp); } else { fclose(logfi); return; } fprintf(logfi, "%s", logmessage); fclose(logfi); #endif return; } /* * death: * Do something really fun when he dies */ void death(int monst) { char **dp; const char *killer; struct tm *lt; time_t date; signal(SIGINT, SIG_IGN); purse -= purse / 10; signal(SIGINT, leave); clear(); killer = killname(monst, FALSE); if (!tombstone) { mvprintw(LINES - 2, 0, "Killed by "); killer = killname(monst, FALSE); if (monst != 's' && monst != 'h') printw("a%s ", vowelstr(killer)); printw("%s with %d gold", killer, purse); } else { time(&date); lt = localtime(&date); move(8, 0); dp = rip; while (*dp) addstr(*dp++); mvaddstr(17, center(killer), killer); if (monst == 's' || monst == 'h') mvaddch(16, 32, ' '); else mvaddstr(16, 33, vowelstr(killer)); mvaddstr(14, center(whoami), whoami); sprintf(prbuf, "%d Au", purse); move(15, center(prbuf)); addstr(prbuf); sprintf(prbuf, "%4d", 1900+lt->tm_year); mvaddstr(18, 26, prbuf); } move(LINES - 1, 0); refresh(); writelog(purse, amulet ? 3 : 0, monst); score(purse, amulet ? 3 : 0, monst); /* Make sure the output gets through. */ printf("[Press return to exit]\n"); fflush(NULL); getchar(); my_exit(0); } /* * center: * Return the index to center the given string */ int center(const char *str) { return 28 - (((int)strlen(str) + 1) / 2); } /* * total_winner: * Code for a winner */ void total_winner(void) { THING *obj; struct obj_info *op; int worth = 0; int oldpurse; clear(); standout(); addstr(" \n"); addstr(" @ @ @ @ @ @@@ @ @ \n"); addstr(" @ @ @@ @@ @ @ @ @ \n"); addstr(" @ @ @@@ @ @ @ @ @ @@@ @@@@ @@@ @ @@@ @ \n"); addstr(" @@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ \n"); addstr(" @ @ @ @ @ @ @ @@@@ @ @ @@@@@ @ @ @ \n"); addstr(" @ @ @ @ @ @@ @ @ @ @ @ @ @ @ @ @ \n"); addstr(" @@@ @@@ @@ @ @ @ @@@@ @@@@ @@@ @@@ @@ @ \n"); addstr(" \n"); addstr(" Congratulations, you have made it to the light of day! \n"); standend(); addstr("\nYou have joined the elite ranks of those who have escaped the\n"); addstr("Dungeons of Doom alive. You journey home and sell all your loot at\n"); addstr("a great profit and are admitted to the Fighters' Guild.\n"); mvaddstr(LINES - 1, 0, "--Press space to continue--"); refresh(); wait_for(stdscr, ' '); clear(); mvaddstr(0, 0, " Worth Item\n"); oldpurse = purse; for (obj = pack; obj != NULL; obj = next(obj)) { switch (obj->o_type) { case FOOD: worth = 2 * obj->o_count; when WEAPON: worth = weap_info[obj->o_which].oi_worth; worth *= 3 * (obj->o_hplus + obj->o_dplus) + obj->o_count; obj->o_flags |= ISKNOW; when ARMOR: worth = arm_info[obj->o_which].oi_worth; worth += (9 - obj->o_arm) * 100; worth += (10 * (a_class[obj->o_which] - obj->o_arm)); obj->o_flags |= ISKNOW; when SCROLL: worth = scr_info[obj->o_which].oi_worth; worth *= obj->o_count; op = &scr_info[obj->o_which]; if (!op->oi_know) worth /= 2; op->oi_know = TRUE; when POTION: worth = pot_info[obj->o_which].oi_worth; worth *= obj->o_count; op = &pot_info[obj->o_which]; if (!op->oi_know) worth /= 2; op->oi_know = TRUE; when RING: op = &ring_info[obj->o_which]; worth = op->oi_worth; if (obj->o_which == R_ADDSTR || obj->o_which == R_ADDDAM || obj->o_which == R_PROTECT || obj->o_which == R_ADDHIT) { if (obj->o_arm > 0) worth += obj->o_arm * 100; else worth = 10; } if (!(obj->o_flags & ISKNOW)) worth /= 2; obj->o_flags |= ISKNOW; op->oi_know = TRUE; when STICK: op = &ws_info[obj->o_which]; worth = op->oi_worth; worth += 20 * obj->o_charges; if (!(obj->o_flags & ISKNOW)) worth /= 2; obj->o_flags |= ISKNOW; op->oi_know = TRUE; when AMULET: worth = 1000; } if (worth < 0) worth = 0; printw("%c) %5d %s\n", obj->o_packch, worth, inv_name(obj, FALSE)); purse += worth; } printw(" %5d Gold Pieces ", oldpurse); refresh(); writelog(purse, 2, ' '); score(purse, 2, ' '); printf("[Press return to exit]\n"); fflush(NULL); getchar(); my_exit(0); } /* * killname: * Convert a code to a monster name */ const char * killname(int monst, int doart) { struct h_list *hp; const char *sp; int article; struct h_list nlist[] = { {'a', "arrow", TRUE}, {'b', "bolt", TRUE}, {'d', "dart", TRUE}, {'h', "hypothermia", FALSE}, {'s', "starvation", FALSE}, {'\0'} }; if (isupper(monst)) { sp = monsters[monst-'A'].m_name; article = TRUE; } else { sp = "Wally the Wonder Badger"; article = FALSE; for (hp = nlist; hp->h_ch; hp++) if (hp->h_ch == monst) { sp = hp->h_desc; article = hp->h_print; break; } } if (doart && article) sprintf(prbuf, "a%s ", vowelstr(sp)); else prbuf[0] = '\0'; strcat(prbuf, sp); return prbuf; } /* * death_monst: * Return a monster appropriate for a random death. */ int death_monst(void) { int poss[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'h', 'd', 's', ' ' /* This is provided to generate the "Wally the Wonder Badger" message for killer */ }; return poss[rnd(sizeof poss / sizeof (int))]; }