view urogue/rip.c @ 310:827441d05b3e

Advanced Rogue family: fix some potential buffer overflows. Some code for determining the score file location assumed that PATH_MAX would be less than 1024, which cannot be guaranteed. Advanced Rogue 5 and 7, and XRogue, have had the buffers for the file name enlarged. UltraRogue never called the functions, so the code has been deleted instead.
author John "Elwin" Edwards
date Mon, 03 May 2021 19:05:37 -0400
parents e52a8a7ad4c5
children
line wrap: on
line source

/*
    rip.c - File for the fun ends Death or a total win
       
    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
    All rights reserved.

    Based on "Advanced Rogue"
    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
    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.
*/

#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include "rogue.h"

static struct sc_ent
{
    int sc_lvl;
    long    sc_score;
    char    sc_name[76];
    long    sc_gold;
    int sc_flags;
    int sc_level;
    int   sc_artifacts;
    int   sc_monster;
} top_ten[10];


static const char *rip[] =
{
    "                       __________",
    "                      /          \\",
    "                     /    REST    \\",
    "                    /      IN      \\",
    "                   /     PEACE      \\",
    "                  /                  \\",
    "                  |                  |",
    "                  |                  |",
    "                  |    killed by     |",
    "                  |                  |",
    "                  |       1993       |",
    "                 *|     *  *  *      | *",
    "       ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______",
    0
};

void writelog(long amount, int lvl, int flags, int monst);

/*
    death()
        Do something really fun when he dies
*/

void
death(int monst)
{
    char **dp = (char **) rip, *killer;
    struct tm   *lt;
    time_t  date;
    char    buf[80];
	int c;

    if (is_wearing(R_RESURRECT) || rnd(wizard ? 3 : 67) == 0)
    {
        int die = TRUE;

        if (resurrect-- == 0)
            msg("You've run out of lives.");
        else if (!save_resurrect(ring_value(R_RESURRECT)))
            msg("Your attempt to return from the grave fails.");
        else
        {
            struct linked_list  *item;
            struct linked_list  *next_item;
            struct object   *obj;
            int rm, flags;
            coord   pos;

            die = FALSE;
            msg("You feel a sudden warmth and then nothingness.");
            teleport();

            if (ring_value(R_RESURRECT) > 1 && rnd(10))
            {
                pstats.s_hpt = 2 * pstats.s_const;
                pstats.s_const = max(pstats.s_const - 1, 3);
            }
            else
            {
                for (item = pack; item != NULL; item = next_item)
                {
                    obj = OBJPTR(item);

                    if (obj->o_flags & ISOWNED || obj->o_flags & ISPROT)
                    {
                        next_item = next(item);
                        continue;
                    }

                    flags = obj->o_flags;
                    obj->o_flags &= ~ISCURSED;
                    dropcheck(obj);
                    obj->o_flags = flags;
                    next_item = next(item);
                    rem_pack(obj);

                    if (obj->o_type == ARTIFACT)
                        has_artifact &= ~(1 << obj->o_which);

                    do
                    {
                        rm = rnd_room();
                        rnd_pos(&rooms[rm], &pos);
                    }
                    while(winat(pos.y, pos.x) != FLOOR);

                    obj->o_pos = pos;
                    add_obj(item, obj->o_pos.y, obj->o_pos.x);
                }

                pstats.s_hpt = pstats.s_const;
                pstats.s_const = max(pstats.s_const - roll(2, 2), 3);
            }

            chg_str(roll(1, 4), TRUE, FALSE);
            pstats.s_lvl = max(pstats.s_lvl, 1);
            no_command += 2 + rnd(4);

            if (on(player, ISHUH))
                lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
            else
                light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);

            turn_on(player, ISHUH);
            light(&hero);
        }

        if (die)
        {
            wmove(cw, mpos, 0);
            waddstr(cw, morestr);
            wrefresh(cw);
            wait_for(' ');
        }
        else
            return;
    }

    time(&date);
    lt = localtime(&date);
    clear();
    wclear(cw);
    move(8, 0);

    while (*dp)
        printw("%s\n", *dp++);

    mvaddstr(14, 28 - ((int)(strlen(whoami) + 1) / 2), whoami);
    sprintf(buf, "%d+%ld Points", pstats.s_lvl, pstats.s_exp);
    mvaddstr(15, 28 - ((int)(strlen(buf) + 1) / 2), buf);
    killer = killname(monst,buf);
    mvaddstr(17, 28 - ((int)(strlen(killer) + 1) / 2), killer);
    mvaddstr(18, 26, (sprintf(prbuf, "%4d", 1900+lt->tm_year), prbuf));
    move(LINES - 1, 0);

    mvaddstr(LINES - 1, 0, retstr);

    while ((c = readcharw(stdscr)) != '\n' && c != '\r')
        continue;
    idenpack();
    wrefresh(cw);
    refresh();

    score(pstats.s_exp, pstats.s_lvl, KILLED, monst);
    byebye();
}

/*
    score()
        figure score and post it.
*/

void
score(long amount, int lvl, int flags, int monst) /*ARGSUSED*/
{
    struct sc_ent   *scp=NULL, *sc2=NULL;
    int i;
    char    *killer;
    char buf[1024];

    static const char *reason[] =
    {
        "killed",
        "quit",
        "a winner",
        "a total winner"
    };

    char    *packend;

    if (flags != SCOREIT)
        writelog(amount, lvl, flags, monst);

    if (flags != WINNER && flags != TOTAL && flags != SCOREIT)
    {
        if (flags == CHICKEN)
            packend = "when you quit";
        else
            packend = "at your untimely demise";

        noecho();
        nl();
        refresh();
        showpack(packend);
    }

    /* Open file and read list */

    if (fd_score == NULL)
    {
        printf("No score file opened\n");
        return;
    }

    for (scp = top_ten; scp < &top_ten[10]; scp++)
    {
        scp->sc_lvl = 0L;
        scp->sc_score = 0L;

        for (i = 0; i < 76; i++)
            scp->sc_name[i] = ucrnd(255);

        scp->sc_gold = 0L;
        scp->sc_flags = rnd(10);
        scp->sc_level = rnd(10);
        scp->sc_monster = srnd(10);
        scp->sc_artifacts = 0;
    }

    if (flags != SCOREIT)
    {
        mvaddstr(LINES - 1, 0, retstr);
        refresh();
        fflush(stdout);
        wait_for('\n');
    }

    fseek(fd_score, 0L, SEEK_SET);
    fread(top_ten, sizeof(top_ten), 1, fd_score);

    /* Insert player in list if need be */

    if (!waswizard)
    {
        for (scp = top_ten; scp < &top_ten[10]; scp++)
        {
            if (lvl > scp->sc_lvl)
                break;

            if (lvl == scp->sc_lvl && amount > scp->sc_score)
                break;
        }

        if (scp < &top_ten[10])
        {
            if (flags == WINNER)
                sc2 = &top_ten[9]; /* LAST WINNER ALWAYS MAKES IT */

            while (sc2 > scp)
            {
                *sc2 = sc2[-1];
                sc2--;
            }
            
			scp->sc_lvl = lvl;
			scp->sc_gold = purse;
            scp->sc_score = amount;
            strcpy(scp->sc_name, whoami);
			strcat(scp->sc_name,", ");
			strcat(scp->sc_name, which_class(player.t_ctype));
            scp->sc_flags = flags;
			
            if (flags == WINNER)
                scp->sc_level = max_level;
            else
                scp->sc_level = level;
				
            scp->sc_monster = monst;
	    scp->sc_artifacts = has_artifact;

            sc2 = scp;
        }
    }

    if (flags != SCOREIT)
    {
        clear();
        refresh();
        endwin();
    }

    /* Print the list */

    printf("\nTop Ten Adventurers:\n%4s %15s %10s %s\n",
	    "Rank", "Score", "Gold", "Name");

    for (scp = top_ten; scp < &top_ten[10]; scp++)
    {
        if (scp->sc_score)
        {
		    char lev[20];
			
			sprintf(lev, "%d+%ld", scp->sc_lvl, scp->sc_score);
            printf("%4d %15s %10ld %s:", (int) (scp - top_ten + 1), 
			       lev,
                   scp->sc_gold,
                   scp->sc_name);

            if (scp->sc_artifacts)
            {
                char  thangs[80];
                int   n;
                int   first = TRUE;

                thangs[0] = '\0';

                for (n = 0; n <= maxartifact; n++)
                {
                    if (scp->sc_artifacts & (1 << n))
                    {
                        if (strlen(thangs))
                            strcat(thangs, ", ");

                        if (first)
                        {
                            strcat(thangs, "retrieved ");
                            first = FALSE;
                        }

                        if (45 - strlen(thangs) < strlen(arts[n].ar_name))
                        {
                            printf("%s\n%32s", thangs," ");
                            thangs[0] = '\0';
                        }
                        strcat(thangs, arts[n].ar_name);
                    }
                }

                if (strlen(thangs))
                    printf("%s,", thangs);

                printf("\n%32s"," ");
            }

            printf("%s on level %d",reason[scp->sc_flags],scp->sc_level);

            if (scp->sc_flags == 0)
            {
                printf(" by \n%32s"," ");
                killer = killname(scp->sc_monster, buf);
                printf(" %s", killer);
            }

            putchar('\n');
        }
    }

    if (sc2 != NULL)
    {
        fseek(fd_score, 0L, SEEK_SET);
        /* Update the list file */
        fwrite(top_ten, sizeof(top_ten), 1, fd_score);
    }

    fclose(fd_score);

    if (flags != SCOREIT) {
        printf("[Press RETURN to exit]\n");
        fflush(stdout);
        getchar();
    }
}

void
writelog(long amount, int lvl, int flags, int monst)
{
    char fate[80];
    if (file_log == NULL)
        return;
    if (flags == KILLED) {
        strcpy(fate, "killed by ");
        killname(monst, fate + 10);
    }
    else if (flags == CHICKEN) {
        strcpy(fate, "quit");
    }
    else if (flags == WINNER || flags == TOTAL) {
        strcpy(fate, "escaped");
    }
    else
        return;
    fprintf(file_log, "%ld %ld %s %d %s %d %d %d %s\n", time(NULL), amount,
		    whoami, lvl, which_class(player.t_ctype), level, max_level,
		    has_artifact, fate);
    fclose(file_log);
    return;
}

void
total_winner(void)
{
    struct linked_list  *item;
    struct object   *obj;
    int worth, oldpurse;
    char    c;
    struct linked_list  *bag = NULL;

    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 \n");
    addstr("escaped the Dungeons of Doom alive.  You journey home \n");
    addstr("and sell all your loot at a great profit.\n");
    addstr("The White Council approves the recommendation of\n");

    if (player.t_ctype == C_FIGHTER)
        addstr("the fighters guild and appoints you Lord Protector\n");
    else if (player.t_ctype == C_ASSASIN)
        addstr("the assassins guild and appoints you Master Murderer\n");
    else if (player.t_ctype == C_NINJA)
        addstr("the ninja guild and appoints you Master of the Wind\n");
    else if (player.t_ctype == C_ILLUSION)
        addstr("the illusionists guild and appoints you Master Wizard\n");
    else if (player.t_ctype == C_MAGICIAN)
        addstr("the magicians guild and appoints you Master Wizard\n");
    else if (player.t_ctype == C_CLERIC)
        addstr("the temple priests and appoints you Master of the Flowers\n");
    else if (player.t_ctype == C_DRUID)
        addstr("the temple priests and appoints you Master of the Flowers\n");
    else if (player.t_ctype == C_RANGER)
        addstr("the rangers guild and appoints you Master Ranger\n");
    else if (player.t_ctype == C_PALADIN)
        addstr("the paladins guild and appoints you Master Paladin\n");
    else if (player.t_ctype == C_THIEF)
    {
        addstr("the thieves guild under protest and appoints you\n");
        addstr("Master of the Highways\n");
    }

    addstr("of the Land Between the Mountains.\n");
    mvaddstr(LINES - 1, 0, spacemsg);
    refresh();
    wait_for(' ');
    clear();
    idenpack();
    oldpurse = purse;
    mvaddstr(0, 0, "   Worth  Item");

    for (c = 'a', item = pack; item != NULL; c++, item = next(item))
    {
        obj = OBJPTR(item);
        worth = get_worth(obj);
        purse += worth;

        if (obj->o_type == ARTIFACT && obj->o_which == TR_PURSE)
            bag = obj->o_bag;

        mvprintw(c - 'a' + 1, 0, "%c) %8d  %s", c,
             worth, inv_name(obj, UPPERCASE));
    }

    if (bag != NULL)
    {
        mvaddstr(LINES - 1, 0, morestr);
        refresh();
        wait_for(' ');
        clear();
        mvprintw(0, 0, "Contents of the Magic Purse of Yendor:\n");

        for (c = 'a', item = bag; item != NULL; c++, item = next(item))
        {
            obj = OBJPTR(item);
            worth = get_worth(obj);
            whatis(item);
            purse += worth;
            mvprintw(c - 'a' + 1, 0, "%c) %8d %s\n", c,
                 worth, inv_name(obj, UPPERCASE));
        }
    }

    mvprintw(c - 'a' + 1, 0, "   %6d  Gold Pieces          ", oldpurse);
    refresh();

    if (has_artifact == 255)
        score(pstats.s_exp, pstats.s_lvl, TOTAL, 0);
    else
        score(pstats.s_exp, pstats.s_lvl, WINNER, 0);

    byebye();
}

char *
killname(int monst, char *buf)
{
    if (buf == NULL)
        return("A bug in UltraRogue #102");

    if (monst >= 0)
    {
        switch (monsters[monst].m_name[0])
        {
            case 'a':
            case 'e':
            case 'i':
            case 'o':
            case 'u':
                sprintf(buf, "an %s", monsters[monst].m_name);
                break;
            default:
                sprintf(buf, "a %s", monsters[monst].m_name);
        }

        return(buf);
    }
    else
        switch(monst)
        {
            case D_ARROW:
                strcpy(buf, "an arrow"); break;
            case D_DART:
                strcpy(buf, "a dart"); break;
            case D_BOLT:
                strcpy(buf, "a bolt"); break;
            case D_POISON:
                strcpy(buf, "poison"); break;
            case D_POTION:
                strcpy(buf, "a cursed potion"); break;
            case D_PETRIFY:
                strcpy(buf, "petrification"); break;
            case D_SUFFOCATION:
                strcpy(buf, "suffocation"); break;
            case D_INFESTATION:
                strcpy(buf, "a parasite"); break;
            case D_DROWN:
                strcpy(buf, "drowning"); break;
            case D_FALL:
                strcpy(buf, "falling"); break;
            case D_FIRE:
                strcpy(buf, "slow boiling in oil"); break;
            case D_SPELLFUMBLE:
                strcpy(buf, "a botched spell"); break;
            case D_DRAINLIFE:
                strcpy(buf, "a drain life spell"); break;
            case D_ARTIFACT:
                strcpy(buf, "an artifact of the gods"); break;
            case D_GODWRATH:
                strcpy(buf, "divine retribution"); break;
            case D_CLUMSY:
                strcpy(buf, "excessive clumsyness"); break;
            default:
                strcpy(buf, "stupidity"); break;
        }

    return(buf);
}

/*
    showpack()
        Display the contents of the hero's pack
*/

void
showpack(char *howso)
{
    char    *iname;
    unsigned int worth;
    int cnt, ch, oldpurse;
    struct linked_list  *item;
    struct object   *obj;
    struct linked_list  *bag = NULL;

    cnt = 1;
    clear();
    mvprintw(0, 0, "Contents of your pack %s:\n", howso);
    ch = 0;
    oldpurse = purse;
    purse = 0;

    for (item = pack; item != NULL; item = next(item))
    {
        obj = OBJPTR(item);
        worth = get_worth(obj);
        whatis(item);
        purse += worth;

        if (obj->o_type == ARTIFACT && obj->o_which == TR_PURSE)
            bag = obj->o_bag;

        iname = inv_name(obj, UPPERCASE);
        mvprintw(cnt, 0, "%d) %s\n", ch, iname);
        ch += 1;

        if (++cnt > LINES - 5 && next(item) != NULL)
        {
            cnt = 1;
            mvaddstr(LINES - 1, 0, morestr);
            refresh();
            wait_for(' ');
            clear();
        }
    }

    if (bag != NULL)
    {
        mvaddstr(LINES - 1, 0, morestr);
        refresh();
        wait_for(' ');
        clear();
        cnt = 1;
        ch = 0;

        mvprintw(0, 0, "Contents of the Magic Purse of Yendor %s:\n", howso);

        for (item = bag; item != NULL; item = next(item))
        {
            obj = OBJPTR(item);
            worth = get_worth(obj);
            whatis(item);
            purse += worth;
            mvprintw(cnt, 0, "%d) %s\n", ch, inv_name(obj, UPPERCASE));
            ch += 1;

            if (++cnt > LINES - 5 && next(item) != NULL)
            {
                cnt = 1;
                mvaddstr(LINES - 1, 0, morestr);
                refresh();
                wait_for(' ');
                clear();
            }
        }
    }

    mvprintw(cnt + 1, 0, "Carrying %d gold pieces", oldpurse);
    mvprintw(cnt + 2, 0, "Carrying objects worth %d gold pieces", purse);
    purse += oldpurse;
    refresh();
}

void
byebye(void)
{
    endwin();
    printf("\n");
    exit(0);
}

/*
    save_resurrect()
        chance of resurrection according to modifed D&D probabilities
*/

int
save_resurrect(int bonus)
{
    int need, adjust;

    adjust = pstats.s_const + bonus - luck;

    if (adjust > 17)
        return(TRUE);
    else if (adjust < 14)
        need = 5 * (adjust + 5);
    else
        need = 90 + 2 * (adjust - 13);

    return(roll(1, 100) < need);
}