view urogue/rip.c @ 291:5b6855d5d089

Fix a portability issue with md_hasclreol(). Some games' implementation of md_hasclreol() poked around in ncurses internals, which does not work for some ncurses build configuration. Most games did not actually call md_hasclreol(), so it was removed. There is a standard terminfo function which can retrieve the value of the clr_eol capability, so this was used for rogue5.
author John "Elwin" Edwards
date Wed, 27 Dec 2017 10:26:06 -0500
parents 1bbdd13ec585
children 0250220d8cdd
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, "%ld+%ld", scp->sc_lvl, scp->sc_score);
            printf("%4d %15s %10ld %s:", 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, "%d %d %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);
}