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.
499 lines
12 KiB
C
499 lines
12 KiB
C
/*
|
|
* File for the fun ends
|
|
* Death or a total win
|
|
*
|
|
* @(#)rip.c 4.28 (Berkeley) 4/12/82
|
|
*
|
|
* Rogue: Exploring the Dungeons of Doom
|
|
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
|
|
* All rights reserved.
|
|
*
|
|
* See the file LICENSE.TXT for full copyright and licensing information.
|
|
*/
|
|
|
|
#include <curses.h>
|
|
#include <time.h>
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "rogue.h"
|
|
|
|
static char *rip[] = {
|
|
" __________",
|
|
" / \\",
|
|
" / REST \\",
|
|
" / IN \\",
|
|
" / PEACE \\",
|
|
" / \\",
|
|
" | |",
|
|
" | |",
|
|
" | killed by a |",
|
|
" | |",
|
|
" | 1980 |",
|
|
" *| * * * | *",
|
|
" ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______",
|
|
0
|
|
};
|
|
|
|
/*
|
|
* score:
|
|
* Figure score and post it.
|
|
*/
|
|
/* VARARGS2 */
|
|
score(amount, flags, monst)
|
|
int amount, flags;
|
|
char monst;
|
|
{
|
|
register struct sc_ent *scp;
|
|
register int i;
|
|
register struct sc_ent *sc2;
|
|
register FILE *outf;
|
|
register int prflags = 0;
|
|
register void (*fp)(int);
|
|
register int uid;
|
|
char scoreline[MAXSTR + 100];
|
|
|
|
static struct sc_ent {
|
|
char sc_name[MAXSTR];
|
|
unsigned int sc_flags;
|
|
unsigned int sc_uid;
|
|
unsigned short sc_monster;
|
|
unsigned short sc_score;
|
|
unsigned short sc_level;
|
|
} top_ten[10];
|
|
static char *reason[] = {
|
|
"killed",
|
|
"quit",
|
|
"A total winner",
|
|
};
|
|
void endit();
|
|
|
|
start_score();
|
|
|
|
if (fd >= 0)
|
|
outf = md_fdopen(fd, "wb");
|
|
else
|
|
return;
|
|
|
|
for (scp = top_ten; scp <= &top_ten[9]; scp++)
|
|
{
|
|
scp->sc_score = 0;
|
|
for (i = 0; i < MAXSTR; i++)
|
|
scp->sc_name[i] = rnd(255);
|
|
scp->sc_flags = RN;
|
|
scp->sc_level = RN;
|
|
scp->sc_monster = RN;
|
|
scp->sc_uid = RN;
|
|
}
|
|
|
|
signal(SIGINT, SIG_DFL);
|
|
if (flags != -1
|
|
#ifdef WIZARD
|
|
|| wizard
|
|
#endif
|
|
)
|
|
{
|
|
mvaddstr(LINES - 1, 0 , "[Press return to continue]");
|
|
refresh();
|
|
wgetnstr(stdscr,prbuf,80);
|
|
move(LINES - 1, 0);
|
|
clrtoeol();
|
|
refresh();
|
|
endwin();
|
|
}
|
|
#ifdef WIZARD
|
|
if (wizard)
|
|
if (strcmp(prbuf, "names") == 0)
|
|
prflags = 1;
|
|
else if (strcmp(prbuf, "edit") == 0)
|
|
prflags = 2;
|
|
#endif
|
|
for(i=0; i<10; i++)
|
|
{
|
|
encread((char *) &top_ten[i].sc_name, MAXSTR, fd);
|
|
scoreline[0] = '\0';
|
|
encread((char *) scoreline, 100, fd);
|
|
sscanf(scoreline, "%d %d %hd %hd %hd", &top_ten[i].sc_flags,
|
|
&top_ten[i].sc_uid, &top_ten[i].sc_monster, &top_ten[i].sc_score,
|
|
&top_ten[i].sc_level);
|
|
}
|
|
/*
|
|
* Insert her in list if need be
|
|
*/
|
|
sc2 = NULL;
|
|
if (!noscore)
|
|
{
|
|
uid = md_getuid();
|
|
|
|
for (scp = top_ten; scp <= &top_ten[9]; scp++)
|
|
if (amount > scp->sc_score)
|
|
break;
|
|
#ifdef LIMIT_TOPTEN
|
|
else if (flags != 2 && scp->sc_uid == uid && scp->sc_flags != 2)
|
|
scp = &top_ten[9] + 1; /* only one score per nowin uid */
|
|
#endif
|
|
if (scp <= &top_ten[9])
|
|
{
|
|
#ifdef LIMIT_TOPTEN
|
|
if (flags != 2)
|
|
for (sc2 = scp; sc2 <= &top_ten[9]; sc2++)
|
|
{
|
|
if (sc2->sc_uid == uid && sc2->sc_flags != 2)
|
|
break;
|
|
}
|
|
else
|
|
#endif
|
|
sc2 = &top_ten[9];
|
|
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
|
|
*/
|
|
printf("Top Ten Rogueists:\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 %s", killname((char) scp->sc_monster, TRUE));
|
|
if (prflags == 1)
|
|
{
|
|
char *name;
|
|
name = md_getusername(scp->sc_uid);
|
|
|
|
if (name == NULL)
|
|
printf(" (%d)", scp->sc_uid);
|
|
else
|
|
printf(" (%s)", name);
|
|
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 < MAXSTR; 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");
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
fseek(outf, 0L, 0);
|
|
/*
|
|
* Update the list file
|
|
*/
|
|
if (sc2 != NULL)
|
|
{
|
|
if (lock_sc())
|
|
{
|
|
int i;
|
|
|
|
fp = signal(SIGINT, SIG_IGN);
|
|
|
|
for(i=0; i<10; i++)
|
|
{
|
|
encwrite((char *) &top_ten[i].sc_name, MAXSTR, outf);
|
|
sprintf(scoreline," %d %d %hd %hd %hd \n",
|
|
top_ten[i].sc_flags, top_ten[i].sc_uid,
|
|
top_ten[i].sc_monster, top_ten[i].sc_score,
|
|
top_ten[i].sc_level);
|
|
encwrite((char *) scoreline, 100, outf);
|
|
}
|
|
unlock_sc();
|
|
signal(SIGINT, fp);
|
|
}
|
|
}
|
|
fclose(outf);
|
|
}
|
|
|
|
void writelog(int amount, int flags, char monst)
|
|
{
|
|
FILE *logfi;
|
|
char logmessage[220], ltemp[80];
|
|
char *killer;
|
|
if (noscore)
|
|
return;
|
|
#ifdef LOGFILE
|
|
if (lfd >= 0)
|
|
logfi = fdopen(lfd, "a");
|
|
else
|
|
return;
|
|
if (logfi == NULL)
|
|
return;
|
|
/* otherwise writing should work */
|
|
sprintf(logmessage, "%d %d %s %d ", time(NULL), amount, whoami,
|
|
pstats.s_lvl);
|
|
if (flags == 0) /* died */
|
|
{
|
|
strcat(logmessage, "killed by ");
|
|
killer = killname(monst, TRUE);
|
|
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
|
|
{
|
|
fclose(logfi);
|
|
return;
|
|
}
|
|
|
|
/* then write */
|
|
fprintf(logfi, "%s", logmessage);
|
|
fclose(logfi);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* death:
|
|
* Do something really fun when he dies
|
|
*/
|
|
death(monst)
|
|
register char monst;
|
|
{
|
|
register char **dp = rip, *killer;
|
|
register struct tm *lt;
|
|
time_t date;
|
|
char buf[MAXSTR];
|
|
struct tm *localtime();
|
|
|
|
signal(SIGINT, SIG_IGN);
|
|
purse -= purse / 10;
|
|
signal(SIGINT, leave);
|
|
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, "%d Au", purse);
|
|
mvaddstr(15, 28-((strlen(buf)+1)/2), buf);
|
|
killer = killname(monst, FALSE);
|
|
mvaddstr(17, 28-((strlen(killer)+1)/2), killer);
|
|
if (monst == 's')
|
|
mvaddch(16, 32, ' ');
|
|
else
|
|
mvaddstr(16, 33, vowelstr(killer));
|
|
sprintf(prbuf, "%2d", 1900+lt->tm_year);
|
|
mvaddstr(18, 26, prbuf);
|
|
move(LINES-1, 0);
|
|
refresh();
|
|
writelog(purse, 0, monst);
|
|
score(purse, 0, monst);
|
|
/* Make sure the output gets through */
|
|
printf("[Press return to exit]\n");
|
|
fflush(NULL);
|
|
getchar();
|
|
exit(0);
|
|
}
|
|
|
|
/*
|
|
* total_winner:
|
|
* Code for a winner
|
|
*/
|
|
total_winner()
|
|
{
|
|
register THING *obj;
|
|
register int worth = 0;
|
|
register char c;
|
|
register 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(' ');
|
|
clear();
|
|
mvaddstr(0, 0, " Worth Item");
|
|
oldpurse = purse;
|
|
for (c = 'a', obj = pack; obj != NULL; c++, obj = next(obj))
|
|
{
|
|
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 CROSSBOW: worth = 30;
|
|
when ARROW: worth = 1;
|
|
when DAGGER: worth = 2;
|
|
when TWOSWORD: worth = 75;
|
|
when DART: worth = 1;
|
|
when BOW: worth = 15;
|
|
when BOLT: worth = 1;
|
|
when SPEAR: worth = 5;
|
|
}
|
|
worth *= 3 * (obj->o_hplus + obj->o_dplus) + obj->o_count;
|
|
obj->o_flags |= ISKNOW;
|
|
when ARMOR:
|
|
switch (obj->o_which)
|
|
{
|
|
case LEATHER: worth = 20;
|
|
when RING_MAIL: worth = 25;
|
|
when STUDDED_LEATHER: worth = 20;
|
|
when SCALE_MAIL: worth = 30;
|
|
when CHAIN_MAIL: worth = 75;
|
|
when SPLINT_MAIL: worth = 80;
|
|
when BANDED_MAIL: worth = 90;
|
|
when PLATE_MAIL: worth = 150;
|
|
}
|
|
worth += (9 - obj->o_ac) * 100;
|
|
worth += (10 * (a_class[obj->o_which] - obj->o_ac));
|
|
obj->o_flags |= ISKNOW;
|
|
when SCROLL:
|
|
worth = s_magic[obj->o_which].mi_worth;
|
|
worth *= obj->o_count;
|
|
if (!s_know[obj->o_which])
|
|
worth /= 2;
|
|
s_know[obj->o_which] = TRUE;
|
|
when POTION:
|
|
worth = p_magic[obj->o_which].mi_worth;
|
|
worth *= obj->o_count;
|
|
if (!p_know[obj->o_which])
|
|
worth /= 2;
|
|
p_know[obj->o_which] = TRUE;
|
|
when RING:
|
|
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 * 100;
|
|
else
|
|
worth = 10;
|
|
if (!(obj->o_flags & ISKNOW))
|
|
worth /= 2;
|
|
obj->o_flags |= ISKNOW;
|
|
r_know[obj->o_which] = TRUE;
|
|
when STICK:
|
|
worth = ws_magic[obj->o_which].mi_worth;
|
|
worth += 20 * obj->o_charges;
|
|
if (!(obj->o_flags & ISKNOW))
|
|
worth /= 2;
|
|
obj->o_flags |= ISKNOW;
|
|
ws_know[obj->o_which] = TRUE;
|
|
when AMULET:
|
|
worth = 1000;
|
|
}
|
|
if (worth < 0)
|
|
worth = 0;
|
|
mvprintw(c - 'a' + 1, 0, "%c) %5d %s", c, worth, inv_name(obj, FALSE));
|
|
purse += worth;
|
|
}
|
|
mvprintw(c - 'a' + 1, 0," %5d Gold Pieces ", oldpurse);
|
|
refresh();
|
|
writelog(purse, 2, 0);
|
|
score(purse, 2, 0);
|
|
printf("[Press return to exit]\n");
|
|
fflush(NULL);
|
|
getchar();
|
|
exit(0);
|
|
}
|
|
|
|
/*
|
|
* killname:
|
|
* Convert a code to a monster name
|
|
*/
|
|
char *
|
|
killname(monst, doart)
|
|
register char monst;
|
|
bool doart;
|
|
{
|
|
register const char *sp;
|
|
register bool article;
|
|
|
|
sp = prbuf;
|
|
article = TRUE;
|
|
switch (monst)
|
|
{
|
|
case 'a':
|
|
sp = "arrow";
|
|
when 'b':
|
|
sp = "bolt";
|
|
when 'd':
|
|
sp = "dart";
|
|
when 's':
|
|
sp = "starvation";
|
|
article = FALSE;
|
|
otherwise:
|
|
if (monst >= 'A' && monst <= 'Z')
|
|
sp = monsters[monst-'A'].m_name;
|
|
else
|
|
{
|
|
sp = "God";
|
|
article = FALSE;
|
|
}
|
|
}
|
|
if (doart && article)
|
|
sprintf(prbuf, "a%s ", vowelstr(sp));
|
|
else
|
|
prbuf[0] = '\0';
|
|
strcat(prbuf, sp);
|
|
return prbuf;
|
|
}
|