The player name is stored in whoami[], which is length 80 in most games (1024 in rogue5). Only the first 10 chars were used to create file_name, because that buffer is the same length. Increasing the size of file_name to 256 permits using all of whoami. The name is also no longer truncated to 20 chars when writing the log. All games should now be able to handle 79-character names without collisions. Anything more would break save compatibility.
495 lines
12 KiB
C
495 lines
12 KiB
C
/*
|
|
* File for the fun ends
|
|
* Death or a total win
|
|
*
|
|
* @(#)rip.c 3.13 (Berkeley) 6/16/81
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <signal.h>
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include "curses.h"
|
|
#include "machdep.h"
|
|
#include "rogue.h"
|
|
|
|
static char *rip[] = {
|
|
" __________",
|
|
" / \\",
|
|
" / REST \\",
|
|
" / IN \\",
|
|
" / PEACE \\",
|
|
" / \\",
|
|
" | |",
|
|
" | |",
|
|
" | killed by a |",
|
|
" | |",
|
|
" | 1980 |",
|
|
" *| * * * | *",
|
|
" ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______",
|
|
0
|
|
};
|
|
|
|
char *killname();
|
|
|
|
/*
|
|
* death:
|
|
* Do something really fun when he dies
|
|
*/
|
|
|
|
void
|
|
death(int monst)
|
|
{
|
|
char **dp = rip, *killer;
|
|
struct tm *lt;
|
|
time_t date;
|
|
char buf[80];
|
|
|
|
/* Don't autosave dead games. It would be a good idea to autosave a
|
|
game that is between death and scoreboard write, but the restore
|
|
code can't handle that case yet. */
|
|
md_onsignal_default();
|
|
|
|
time(&date);
|
|
lt = localtime(&date);
|
|
clear();
|
|
move(8, 0);
|
|
while (*dp)
|
|
printw("%s\n", *dp++);
|
|
mvaddstr(14, 28-(((int)strlen(whoami)+1)/2), whoami);
|
|
purse -= purse/10;
|
|
sprintf(buf, "%d Au", purse);
|
|
mvaddstr(15, 28-(((int)strlen(buf)+1)/2), buf);
|
|
killer = killname(monst);
|
|
mvaddstr(17, 28-(((int)strlen(killer)+1)/2), killer);
|
|
mvaddstr(16, 33, vowelstr(killer));
|
|
sprintf(prbuf, "%4d", 1900+lt->tm_year);
|
|
mvaddstr(18, 26, prbuf);
|
|
move(LINES-1, 0);
|
|
draw(stdscr);
|
|
writelog(purse, 0, monst);
|
|
score(purse, 0, monst);
|
|
/* Make sure all the output gets through ssh and
|
|
anything else that might be in the way. */
|
|
printf("[Press return to exit]\n");
|
|
fflush(NULL);
|
|
getchar();
|
|
exit(0);
|
|
}
|
|
|
|
/*
|
|
* score -- figure score and post it.
|
|
*/
|
|
|
|
void
|
|
open_score(void)
|
|
{
|
|
#ifdef SCOREFILE
|
|
char *scorefile = SCOREFILE;
|
|
|
|
if (scoreboard != NULL) {
|
|
rewind(scoreboard);
|
|
return;
|
|
}
|
|
|
|
scoreboard = fopen(scorefile, "r+");
|
|
|
|
if ((scoreboard == NULL) && (errno == ENOENT))
|
|
{
|
|
scoreboard = fopen(scorefile, "w+");
|
|
md_chmod(scorefile,0664);
|
|
}
|
|
|
|
if (scoreboard == NULL) {
|
|
fprintf(stderr, "Could not open %s for writing: %s\n", scorefile, strerror(errno));
|
|
fflush(stderr);
|
|
}
|
|
#else
|
|
scoreboard = NULL;
|
|
#endif
|
|
}
|
|
|
|
/* Same thing, but for the log file. Maybe combine them eventually. */
|
|
void open_log(void)
|
|
{
|
|
#ifdef LOGFILE
|
|
logfi = fopen(LOGFILE, "a");
|
|
|
|
if (logfi == NULL)
|
|
{
|
|
fprintf(stderr, "Could not open %s for appending: %s\n", LOGFILE, strerror(errno));
|
|
fflush(stderr);
|
|
}
|
|
#else
|
|
logfi == NULL;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/* VARARGS2 */
|
|
void
|
|
score(int amount, int flags, int monst)
|
|
{
|
|
static struct sc_ent {
|
|
int sc_score;
|
|
char sc_name[80];
|
|
int sc_flags;
|
|
int sc_level;
|
|
char sc_login[8];
|
|
int sc_monster;
|
|
} top_ten[10];
|
|
struct sc_ent *scp;
|
|
int i;
|
|
struct sc_ent *sc2;
|
|
FILE *outf;
|
|
char *killer;
|
|
int prflags = 0;
|
|
static char *reason[] = {
|
|
"killed",
|
|
"quit",
|
|
"A total winner",
|
|
};
|
|
char scoreline[100];
|
|
int rogue_ver = 0, scorefile_ver = 0;
|
|
|
|
/*
|
|
* Open file and read list
|
|
*/
|
|
|
|
if (scoreboard == NULL)
|
|
return;
|
|
|
|
outf = scoreboard;
|
|
|
|
for (scp = top_ten; scp <= &top_ten[9]; scp++)
|
|
{
|
|
scp->sc_score = 0;
|
|
for (i = 0; i < 80; i++)
|
|
scp->sc_name[i] = rnd(255);
|
|
scp->sc_flags = RN;
|
|
scp->sc_level = RN;
|
|
scp->sc_monster = RN;
|
|
scp->sc_login[0] = '\0';
|
|
}
|
|
|
|
signal(SIGINT, SIG_DFL);
|
|
if ((flags != -1) && (flags != 1))
|
|
{
|
|
mvaddstr(LINES-1, 0, "[Press return to continue]");
|
|
draw(stdscr);
|
|
prbuf[0] = 0;
|
|
get_str(prbuf, stdscr);
|
|
endwin();
|
|
}
|
|
if (wizard)
|
|
if (strcmp(prbuf, "names") == 0)
|
|
prflags = 1;
|
|
else if (strcmp(prbuf, "edit") == 0)
|
|
prflags = 2;
|
|
|
|
md_lockfile(outf);
|
|
|
|
encread(scoreline, 100, outf);
|
|
(void) sscanf(scoreline, "R%d %d\n", &rogue_ver, &scorefile_ver);
|
|
|
|
if ((rogue_ver == 36) && (scorefile_ver == 2))
|
|
for(i = 0; i < 10; i++)
|
|
{
|
|
encread(&top_ten[i].sc_name, 80, outf);
|
|
encread(&top_ten[i].sc_login, 8, outf);
|
|
encread(scoreline, 100, outf);
|
|
(void) sscanf(scoreline, " %d %d %d %d \n",
|
|
&top_ten[i].sc_score, &top_ten[i].sc_flags,
|
|
&top_ten[i].sc_level, &top_ten[i].sc_monster);
|
|
}
|
|
|
|
/*
|
|
* Insert her in list if need be
|
|
*/
|
|
if (!waswizard)
|
|
{
|
|
for (scp = top_ten; scp <= &top_ten[9]; scp++)
|
|
if (amount > scp->sc_score)
|
|
break;
|
|
if (scp <= &top_ten[9])
|
|
{
|
|
for (sc2 = &top_ten[9]; sc2 > scp; sc2--)
|
|
*sc2 = *(sc2-1);
|
|
scp->sc_score = amount;
|
|
strcpy(scp->sc_name, whoami);
|
|
scp->sc_flags = flags;
|
|
if (flags == 2)
|
|
scp->sc_level = max_level;
|
|
else
|
|
scp->sc_level = level;
|
|
scp->sc_monster = monst;
|
|
strncpy(scp->sc_login, md_getusername(), 8);
|
|
}
|
|
}
|
|
/*
|
|
* Print the list
|
|
*/
|
|
if (flags != -1)
|
|
printf("\n\n\n");
|
|
printf("Top Ten Adventurers:\nRank\tScore\tName\n");
|
|
for (scp = top_ten; scp <= &top_ten[9]; scp++) {
|
|
if (scp->sc_score) {
|
|
printf("%d\t%d\t%s: %s on level %d", scp - top_ten + 1,
|
|
scp->sc_score, scp->sc_name, reason[scp->sc_flags],
|
|
scp->sc_level);
|
|
if (scp->sc_flags == 0) {
|
|
printf(" by a");
|
|
killer = killname(scp->sc_monster);
|
|
if (*killer == 'a' || *killer == 'e' || *killer == 'i' ||
|
|
*killer == 'o' || *killer == 'u')
|
|
putchar('n');
|
|
printf(" %s", killer);
|
|
}
|
|
if (prflags == 1)
|
|
{
|
|
printf(" (%s)", scp->sc_login);
|
|
putchar('\n');
|
|
}
|
|
else if (prflags == 2)
|
|
{
|
|
fflush(stdout);
|
|
fgets(prbuf,80,stdin);
|
|
if (prbuf[0] == 'd')
|
|
{
|
|
for (sc2 = scp; sc2 < &top_ten[9]; sc2++)
|
|
*sc2 = *(sc2 + 1);
|
|
top_ten[9].sc_score = 0;
|
|
for (i = 0; i < 80; i++)
|
|
top_ten[9].sc_name[i] = rnd(255);
|
|
top_ten[9].sc_flags = RN;
|
|
top_ten[9].sc_level = RN;
|
|
top_ten[9].sc_monster = RN;
|
|
scp--;
|
|
}
|
|
}
|
|
else
|
|
printf(".\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Update the list file
|
|
*/
|
|
|
|
rewind(outf);
|
|
|
|
strcpy(scoreline, "R36 2\n");
|
|
encwrite(scoreline, 100, outf);
|
|
|
|
for(i = 0; i < 10; i++)
|
|
{
|
|
encwrite(&top_ten[i].sc_name, 80, outf);
|
|
encwrite(&top_ten[i].sc_login, 8, outf);
|
|
sprintf(scoreline, " %d %d %d %d \n",
|
|
top_ten[i].sc_score, top_ten[i].sc_flags,
|
|
top_ten[i].sc_level, top_ten[i].sc_monster);
|
|
encwrite(scoreline, 100, outf);
|
|
}
|
|
|
|
md_unlockfile(outf);
|
|
|
|
fclose(outf);
|
|
}
|
|
|
|
void writelog(int amount, int flags, int monst)
|
|
{
|
|
char logmessage[220], ltemp[80];
|
|
char *killer;
|
|
|
|
if (waswizard)
|
|
return;
|
|
#ifdef LOGFILE
|
|
sprintf(logmessage, "%d %d %s %d ", time(NULL), amount, whoami,
|
|
pstats.s_lvl);
|
|
if (flags == 0) /* died */
|
|
{
|
|
strcat(logmessage, "killed by a");
|
|
killer = killname(monst);
|
|
if (*killer == 'a' || *killer == 'e' || *killer == 'i' ||
|
|
*killer == 'o' || *killer == 'u')
|
|
strcat(logmessage, "n ");
|
|
else
|
|
strcat(logmessage, " ");
|
|
strcat(logmessage, killer);
|
|
if (amulet)
|
|
sprintf(ltemp, " on level %d [max %d] with the Amulet\n",
|
|
level, max_level);
|
|
else
|
|
sprintf(ltemp, " on level %d\n", 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
|
|
return;
|
|
|
|
if (logfi == NULL)
|
|
return;
|
|
/* and write it */
|
|
md_lockfile(logfi);
|
|
fprintf(logfi, "%s", logmessage);
|
|
md_unlockfile(logfi);
|
|
fclose(logfi);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
void
|
|
total_winner()
|
|
{
|
|
struct linked_list *item;
|
|
struct object *obj;
|
|
int worth = 0;
|
|
int c;
|
|
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");
|
|
oldpurse = purse;
|
|
for (c = 'a', item = pack; item != NULL; c++, item = next(item))
|
|
{
|
|
obj = (struct object *) ldata(item);
|
|
switch (obj->o_type)
|
|
{
|
|
case FOOD:
|
|
worth = 2 * obj->o_count;
|
|
when WEAPON:
|
|
switch (obj->o_which)
|
|
{
|
|
case MACE: worth = 8;
|
|
when SWORD: worth = 15;
|
|
when BOW: worth = 75;
|
|
when ARROW: worth = 1;
|
|
when DAGGER: worth = 2;
|
|
when ROCK: worth = 1;
|
|
when TWOSWORD: worth = 30;
|
|
when SLING: worth = 1;
|
|
when DART: worth = 1;
|
|
when CROSSBOW: worth = 15;
|
|
when BOLT: worth = 1;
|
|
when SPEAR: worth = 2;
|
|
otherwise: worth = 0;
|
|
}
|
|
worth *= (1 + (10 * obj->o_hplus + 10 * obj->o_dplus));
|
|
worth *= obj->o_count;
|
|
obj->o_flags |= ISKNOW;
|
|
when ARMOR:
|
|
switch (obj->o_which)
|
|
{
|
|
case LEATHER: worth = 5;
|
|
when RING_MAIL: worth = 30;
|
|
when STUDDED_LEATHER: worth = 15;
|
|
when SCALE_MAIL: worth = 3;
|
|
when CHAIN_MAIL: worth = 75;
|
|
when SPLINT_MAIL: worth = 80;
|
|
when BANDED_MAIL: worth = 90;
|
|
when PLATE_MAIL: worth = 400;
|
|
otherwise: worth = 0;
|
|
}
|
|
if (obj->o_which >= MAXARMORS)
|
|
break;
|
|
worth *= (1 + (10 * (a_class[obj->o_which] - obj->o_ac)));
|
|
obj->o_flags |= ISKNOW;
|
|
when SCROLL:
|
|
s_know[obj->o_which] = TRUE;
|
|
worth = s_magic[obj->o_which].mi_worth;
|
|
worth *= obj->o_count;
|
|
when POTION:
|
|
p_know[obj->o_which] = TRUE;
|
|
worth = p_magic[obj->o_which].mi_worth;
|
|
worth *= obj->o_count;
|
|
when RING:
|
|
obj->o_flags |= ISKNOW;
|
|
r_know[obj->o_which] = TRUE;
|
|
worth = r_magic[obj->o_which].mi_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_ac > 0)
|
|
worth += obj->o_ac * 20;
|
|
else
|
|
worth = 50;
|
|
when STICK:
|
|
obj->o_flags |= ISKNOW;
|
|
ws_know[obj->o_which] = TRUE;
|
|
worth = ws_magic[obj->o_which].mi_worth;
|
|
worth += 20 * obj->o_charges;
|
|
when AMULET:
|
|
worth = 1000;
|
|
}
|
|
mvprintw(c - 'a' + 1, 0, "%c) %5d %s", c, worth, inv_name(obj, FALSE));
|
|
purse += worth;
|
|
}
|
|
mvprintw(c - 'a' + 1, 0," %5d Gold Peices ", oldpurse);
|
|
refresh();
|
|
writelog(purse, 2, 0);
|
|
score(purse, 2, 0);
|
|
printf("[Press return to exit]\n");
|
|
fflush(NULL);
|
|
getchar();
|
|
exit(0);
|
|
}
|
|
|
|
char *
|
|
killname(int monst)
|
|
{
|
|
if (isupper(monst))
|
|
return monsters[monst-'A'].m_name;
|
|
else
|
|
switch (monst)
|
|
{
|
|
case 'a':
|
|
return "arrow";
|
|
case 'd':
|
|
return "dart";
|
|
case 'b':
|
|
return "bolt";
|
|
}
|
|
return("");
|
|
}
|