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.
515 lines
12 KiB
C
515 lines
12 KiB
C
/*
|
|
* 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[220], ltemp[80];
|
|
|
|
if (logfi == NULL)
|
|
return;
|
|
#ifdef MASTER
|
|
if (wizard)
|
|
{
|
|
fclose(logfi);
|
|
return;
|
|
}
|
|
#endif
|
|
sprintf(logmessage, "%d %d %.80s %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))];
|
|
}
|