view urogue/artifact.c @ 296:000b1c5b8d63

UltraRogue: fix inventory collision after save and restore. Inventory letters are based on "identifiers" stored in objects' o_ident field. Identifiers are allocated by get_ident(), which keeps a list of objects that have them, to avoid giving the same identifier to multiple objects. The list is not stored in the savefile, so after restore, get_ident() was not aware of existing identifiers. This resulted in picked-up objects having the same inventory letters as objects restored from the file. The restore code now adds all objects with identifiers to the list.
author John "Elwin" Edwards
date Mon, 15 Jan 2018 20:20:35 -0500
parents c495a4f288c6
children
line wrap: on
line source

/*
    artifact.c  -  functions for dealing with artifacts

    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
    All rights reserved.

    See the file LICENSE.TXT for full copyright and licensing information.
*/

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

/*
    apply()
        apply an artifact
*/

void
apply(void)
{
    struct linked_list  *item;
    struct object   *obj;
    int which;
    int chance;

    if ((item = get_item("activate", ARTIFACT)) == NULL)
        return;

    obj = OBJPTR(item);
    which = obj->o_which;

    if (!(obj->ar_flags & ISACTIVE))
    {
        chance = rnd(100) - 10 * rnd(luck);
        debug("Rolled %d.", chance);
        if (chance < 5)
            do_major();
        else if (chance < 50)
            do_minor(obj);
        else
            obj->ar_flags |= ISACTIVE;
    }

    if (obj->ar_flags & ISACTIVE)
    {
        switch (which)
        {
            case TR_PURSE:    do_bag(obj);
                              break;
            case TR_PHIAL:    do_phial();
                              break;
            case TR_AMULET:   do_amulet();
                              break;
            case TR_PALANTIR: do_palantir();
                              break;
            case TR_CROWN:    do_crown();
                              break;
            case TR_SCEPTRE:  do_sceptre();
                              break;
            case TR_SILMARIL: do_silmaril();
                              break;
            case TR_WAND:     do_wand();
                              break;
            default:          nothing_message(ISCURSED);
                              return;
        }
    }

    if (rnd(pstats.s_lvl) < 6)
        do_minor(obj);

    turn_on(player, POWEREAT);
}

/*
    possessed(int artifact)
        was the hero carrying a particular artifact
*/

int
possessed(int artifact)
{
    return (picked_artifact >> artifact) & 1;
}

/*
    is_carrying(int artifact)
        is the hero carrying a particular artifact
*/

int
is_carrying(int artifact)
{
    return (has_artifact >> artifact) & 1;
}

/*
    make_artifact()
        is it time to make a new artifact?
*/

int
make_artifact(void)
{
    int i;

    mpos = 0;

    debug("Artifact possession and picked flags : %x %x.",
        has_artifact, picked_artifact);

    for(i = 0; i < maxartifact; i++)
    {
       if (!is_carrying(i) && arts[i].ar_level <= level)
           return TRUE;
    }

    return FALSE;
}

/*
    new_artifact(int which, struct object *cur)
        make a specified artifact
*/

struct object *
new_artifact(int which, struct object *cur)
{
    if (which >= maxartifact)
    {
        debug("Bad artifact %d.  Random one created.", which);
        which = rnd(maxartifact);
    }

    if (which < 0)
    {
        for (which = 0; which < maxartifact; which++)
            if (!is_carrying(which) && arts[which].ar_level <= level)
                break;
    }

    debug("Artifact number: %d.", which);

    cur->o_hplus = cur->o_dplus = 0;
    cur->o_damage = cur->o_hurldmg = "0d0";
    cur->o_ac = 11;
    cur->o_mark[0] = '\0';
    cur->o_type = ARTIFACT;
    cur->o_which = which;
    cur->o_weight = arts[which].ar_weight;
    cur->o_flags = 0;
    cur->o_group = 0;
    cur->o_count = 1;
    cur->o_bag = NULL;
    cur->ar_flags = 0;

    return(cur);
}

/*
    do_minor(struct object *tr)
        side effects and minor malevolent effects of artifacts
*/

void
do_minor(struct object *tr)
{
    int which;
    long loss;

    which = rnd(110);

    debug("Rolled %d.", which);

    switch (which)
    {
        case 0:
            seemsg("You develop some acne on your face.");
            break;

        case 1:
            if (on(player, CANSCENT))
            {
                msg("A sudden whiff of BO causes you to faint.");
                no_command = STONETIME;
            }
            else if (off(player, ISUNSMELL))
                msg("You begin to smell funny.");
            break;

        case 2:
            seemsg("A wart grows on the end of your nose.");
            break;

        case 3:
            hearmsg("Your hear strange noises in the distance.");
            break;

        case 4:
            hearmsg("You hear shuffling in the distance.");
            break;

        case 5:
            hearmsg("You hear clanking in the distance.");
            break;

        case 6:
            hearmsg("You hear water dripping onto the floor.");
            break;

        case 7:
            hearmsg("The dungeon goes strangely silent.");
            break;

        case 8:
            msg("You suddenly feel very warm.");
            break;

        case 9:
            msg("You feel very hot.");
            break;

        case 10:
            msg("A blast of heat hits you.");
            break;

        case 11:
            {
                 struct room *rp;

                 if (off(player, ISBLIND))
                    msg("A pillar of flame leaps up beside you.");
                 else
                    msg("You feel something very hot nearby.");

                 if (ntraps + 1 < 2 * MAXTRAPS &&
                     fallpos(hero, &traps[ntraps].tr_pos))
                 {
                    mvaddch(traps[ntraps].tr_pos.y, traps[ntraps].tr_pos.x,
                       FIRETRAP);
                    traps[ntraps].tr_type = FIRETRAP;
                    traps[ntraps].tr_flags = ISFOUND;
                    traps[ntraps].tr_show = FIRETRAP;
                    ntraps++;

                    if ((rp = roomin(hero)) != NULL)
                    {
                        rp->r_flags &= ~ISDARK;
                        light(&hero);
                        mvwaddch(cw, hero.y, hero.x, PLAYER);
                    }
                }
            }
            break;

        case 12:
            msg("You feel a blast of hot air.");
            break;

        case 13:
            msg("You feel very cold.");
            break;

        case 14:
            msg("You break out in a cold sweat.");
            break;

        case 15:
            if (off(player, ISBLIND) && cur_armor == NULL)
                msg("You are covered with frost.");
            else if (off(player, ISBLIND))
                msg("Your armor is covered with frost.");
            else if (cur_armor == NULL)
                msg("Your body feels very cold and you begin to shiver.");
            else
                msg("Your armor feels very cold.  You hear cracking ice.");
            break;

        case 16:
            msg("A cold wind whistles through the dungeon.");
            break;

        case 17:
            {
                int change;

                change = 18 - pstats.s_str;
                chg_str(change, TRUE, FALSE);
                chg_dext(-change, TRUE, FALSE);

                if (change > 0)
                    msg("You feel stronger and clumsier now.");
                else if (change < 0)
                    msg("You feel weaker and more dextrous now.");
                else
                    nothing_message(ISCURSED);
            }
            break;

        case 18:
            msg("You begin to itch all over.");
            break;

        case 19:
            msg("You begin to feel hot and itchy.");
            break;

        case 20:
            msg("You feel a burning itch.");
            chg_dext(-1, FALSE, TRUE);

            if (off(player, HASITCH))
            {
                turn_on(player, HASITCH);
                light_fuse(FUSE_UNITCH, 0, roll(4,6), AFTER);
            }
            else
                lengthen_fuse(FUSE_UNITCH, roll(4,6));
            break;

        case 21:
            if (off(player, ISBLIND))
               msg("Your skin begins to flake and peel.");
            else
               msg("You feel an urge to scratch an itch.");
            break;


        case 22:
            seemsg("Your hair begins to turn grey.");
            break;

        case 23:
            seemsg("Your hair begins to turn white.");
            break;

        case 24:
            seemsg("Some of your hair instantly turns white.");
            break;

        case 25:
            seemsg("You are covered with long white hair.");
            break;

        case 26:
            seemsg("You are covered with long red hair.");
            break;

        case 27:
            msg("You grow a beard.");
            break;

        case 28:
            msg("Your hair falls out.");
            break;

        case 29:
            msg("You feel a burning down below.");
            break;

        case 30:
            msg("Your toes fall off.");
            break;

        case 31:
            msg("You grow some extra toes.");
            break;

        case 32:
            msg("You grow some extra fingers.");
            break;

        case 33:
            msg("You grow an extra thumb.");
            break;

        case 34:
            msg("Your nose falls off.");
            break;

        case 35:
            msg("Your nose gets bigger.");
            break;

        case 36:
            msg("Your nose shrinks.");
            break;

        case 37:
            msg("An eye grows on your forehead.");
            break;

        case 38:
            seemsg("You see beady eyes watching from a distance.");
            break;

        case 39:
            msg("The dungeon rumbles for a moment.");
            break;

        case 40:
            seemsg("A flower grows on the floor next to you.");
            break;

        case 41:
            msg("You are stunned by a psionic blast.");

            if (on(player, ISHUH))
                lengthen_fuse(FUSE_UNCONFUSE, rnd(40) + (HUHDURATION * 3));
            else
            {
                light_fuse(FUSE_UNCONFUSE,0,rnd(40)+(HUHDURATION * 3), AFTER);
                turn_on(player, ISHUH);
            }
            break;

        case 42:
            msg("You are confused by thousands of voices in your head.");

            if (on(player, ISHUH))
                lengthen_fuse(FUSE_UNCONFUSE, rnd(10) + (HUHDURATION * 2));
            else
            {
                light_fuse(FUSE_UNCONFUSE,0,rnd(10)+(HUHDURATION * 2), AFTER);
                turn_on(player, ISHUH);
            }
            break;

        case 43:
            hearmsg("You hear voices in the distance.");
            break;

        case 44:
            msg("You feel a strange pull.");
            teleport();

            if (off(player, ISCLEAR))
            {
                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);
                }
            }
            break;

        case 45:
            msg("You feel less healthy now.");
            pstats.s_const = max(pstats.s_const - 1, 3);
            max_stats.s_const = max(max_stats.s_const - 1, 3);
            break;

        case 46:
            msg("You feel weaker now.");
            chg_str(-1, TRUE, FALSE);
            break;

        case 47:
            msg("You feel less wise now.");
            pstats.s_wisdom = max(pstats.s_wisdom - 1, 3);
            max_stats.s_wisdom = max(max_stats.s_wisdom - 1, 3);
            break;

        case 48:
            msg("You feel less dextrous now.");
            chg_dext(-1, TRUE, FALSE);
            break;

        case 49:
            msg("You feel less intelligent now.");
            pstats.s_intel = max(pstats.s_intel - 1, 3);
            max_stats.s_intel = max(max_stats.s_intel - 1, 3);
            break;

        case 50:
            msg("A trap door opens underneath your feet.");
            mpos = 0;
            level++;
            new_level(NORMLEV,0);

            if (rnd(4) < 2)
            {
                addmsg("You are damaged by the fall");

                if ((pstats.s_hpt -= roll(1, 6)) <= 0)
                {
                    addmsg("!  The fall killed you.");
                    endmsg();
                    death(D_FALL);
                    return;
                }
            }

            addmsg("!");
            endmsg();

            if (off(player, ISCLEAR) && rnd(4) < 3)
            {
                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);
            }
            else
                msg("You feel dizzy for a moment, but it quickly passes.");

            break;

        case 51:
            msg("A maze entrance opens underneath your feet.");
            mpos = 0;
            level++;
            new_level(MAZELEV,0);

            if (rnd(4) < 2)
            {
                addmsg("You are damaged by the fall");

                if ((pstats.s_hpt -= roll(1, 6)) <= 0)
                {
                    addmsg("!  The fall killed you.");
                    endmsg();
                    death(D_FALL);
                    return;
                }
            }
            addmsg("!");
            endmsg();

            if (off(player, ISCLEAR) && rnd(4) < 3)
            {
                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);
            }
            else
                msg("You feel dizzy for a moment, but it quickly passes.");

            break;

        case 52:
            hearmsg("You hear a wailing sound in the distance.");
            aggravate();
            break;

        case 53:
            read_scroll(&player, S_HOLD, ISCURSED);
            break;

        case 54:
            msg("You can't move.");
            no_command = 3 * HOLDTIME;
            break;

        case 55:
            hearmsg("You hear a buzzing sound.");
            aggravate();
            break;

        case 56:
            msg("Your limbs stiffen.");
            no_command = 3 * STONETIME;
            break;

        case 57:
            msg("You feel a rock in your shoe hurting your foot.");
            turn_on(player, STUMBLER);
            break;

        case 58:
            msg("You get a hollow feeling in your stomach.");
            food_left -= 500;
            break;

        case 59:
            msg("Your purse feels lighter.");

            loss  = 50L + ulrnd(purse / 2L);
            purse = (purse > loss) ? purse - loss : 0L;
            break;

        case 60:
            msg("A pixie appears and grabs gold from your purse.");

            loss = 50L + rnd(50);
            purse = (purse > loss) ? purse - loss : 0L;
            break;

        case 61:
            msg("You feel a tingling sensation all over.");
            pstats.s_hpt -= ulrnd(pstats.s_hpt / 3L);
            break;

        case 62:
            msg("You feel a pull downwards.");
            break;

        case 63:
            msg("You feel a strange pull downwards.");
            break;

        case 64:
            msg("You feel a peculiar pull downwards.");
            break;

        case 65:
            msg("You have a strange urge to go down.");
            break;

        case 66:
            msg("You feel a pull upwards.");
            break;

        case 67:
            msg("You feel a strange pull upwards.");
            break;

        case 68:
            msg("You have a strange feeling for a moment.");
            break;

        case 69:
            msg("You float in the air for a moment.");
            break;

        case 70:
            msg("You feel very heavy for a moment.");
            break;

        case 71:
            msg("You feel a strange sense of loss.");
            break;

        case 72:
            msg("You feel the earth spinning underneath your feet.");
            break;

        case 73:
            msg("You feel in touch with a Universal Oneness.");
            break;

        case 74:
            hearmsg("You hear voices in the distance.");
            break;

        case 75:
            msg("A strange feeling of power comes over you.");
            break;

        case 76:
            msg("You feel a strange sense of unease.");
            break;

        case 77:
            msg("You feel Lady Luck is looking the other way.");
            luck++;
            break;

        case 78:
            msg("You feel your pack vibrate for a moment.");
            break;

        case 79:
            msg("You feel someone is watching you.");
            break;

        case 80:
            msg("You feel your hair standing on end.");
            break;

        case 81:
            msg("Wait!  The walls are moving!");
            new_level(NORMLEV,0);
            break;

        case 82:
            msg("Wait!  Walls are appearing out of nowhere!");
            new_level(MAZELEV,0);
            break;

        case 83:
            blue_light(ISCURSED);
            break;

        case 84:
            msg("Your mind goes blank for a moment.");
            wclear(cw);
            light(&hero);
            status(TRUE);
            break;

        case 85:
            if (on(player, ISDEAF))
            {
                msg("You feel your ears burn for a moment.");
                lengthen_fuse(FUSE_HEAR, 2 * PHASEDURATION);
            }
            else
            {
                msg("You are suddenly surrounded by silence.");
                turn_on(player, ISDEAF);
                light_fuse(FUSE_HEAR, 0, 2 * PHASEDURATION, AFTER);
            }
            break;

        case 86:
            {
                apply_to_bag(pack, 0, NULL, baf_curse, NULL);

                if (off(player, ISUNSMELL))
                    msg("You smell a faint trace of burning sulfur.");
            }
            break;

        case 87:
            msg("You have contracted a parasitic infestation.");
            infest_dam++;
            turn_on(player, HASINFEST);
            break;

        case 88:
            msg("You suddenly feel a chill run up and down your spine.");
            turn_on(player, ISFLEE);
            player.t_ischasing = FALSE;
            player.t_chasee = &player;
            break;

        case 89:
            if (cur_weapon != NULL)
                msg("You feel your %s get very hot.",
                    inv_name(cur_weapon, LOWERCASE));
            break;

        case 90:
            if (cur_weapon != NULL)
                msg("Your %s glows white for an instant.",
                    inv_name(cur_weapon, LOWERCASE));
            break;

        case 91:
            if (cur_armor != NULL)
                msg("Your %s gets very hot.", inv_name(cur_armor, LOWERCASE));
            break;

        case 92:
            if (cur_weapon != NULL)
                msg("Your %s suddenly feels very cold.",
                    inv_name(cur_weapon, LOWERCASE));
            break;

        case 93:
            if (cur_armor != NULL)
                msg("Your armor is covered by an oily film.");
            break;

        case 94:
            read_scroll(&player, S_CREATE, ISNORMAL);
            break;

        case 95:
            lower_level(D_POTION);
            break;

        case 96:
            {
                int x, y;

                for (x = -1; x <= 1; x++)
                {
                    for (y = -1; y <= 1; y++)
                    {
                        if (x == 0 && y == 0)
                            continue;

                        delta.x = x;
                        delta.y = y;

                        do_zap(&player, WS_POLYMORPH, rnd(2)
                            ? ISCURSED : ISNORMAL);
                    }
                }
            }
            break;

        case 97:
            {
                int x, y;

                for (x = -1; x <= 1; x++)
                {
                    for (y = -1; y <= 1; y++)
                    {
                        if (x == 0 && y == 0)
                            continue;

                        delta.x = x;
                        delta.y = y;

                        do_zap(&player, WS_INVIS, ISNORMAL);
                    }
                }
            }
            break;

        default:
            tr->ar_flags &= ~ISACTIVE;
            hearmsg("You hear a click coming from %s.",inv_name(tr,LOWERCASE));
            break;

    }
}

/*
    do_major()

        major malevolent effects

        0.  read_scroll(S_SELFTELEPORT, ISCURSED)
        1.  PERMBLIND for twice normal duration
        2.  new_level(THRONE);
        3.  turn_on(player, SUPEREAT);
        4.  lengthen(noslow, 20 + rnd(20));
        5.  lower_level(D_POTION) * roll(1,4)
        6.  change stats
        7.  FIRETRAP
        8.  armor crumbles
        9.  weapon crumbles
       10. weapon crumbles
       11. curse weapon
*/

void
do_major(void)
{
    int which;

    which = rnd(12);

    debug("Rolled %d.", which);

    switch (which)
    {
        case 0:
            read_scroll(&player, S_SELFTELEP, ISCURSED);
            break;

        case 1:
            quaff(&player, P_TRUESEE, ISCURSED);
            quaff(&player, P_TRUESEE, ISCURSED);
            break;

        case 2:
            new_level(THRONE,0);
            break;

        case 3: /* Turn off other body-affecting spells */

            if (on(player, ISREGEN))
            {
                extinguish_fuse(FUSE_UNREGEN);
                turn_off(player, ISREGEN);
                unregen(NULL);
            }

            if (on(player, NOCOLD))