Beispiel #1
0
/*
 * OEXTRA note: Passing mtmp causes mtraits to be saved
 * even if ptr passed as well, but ptr is always used for
 * the corpse type (corpsenm). That allows the corpse type
 * to be different from the original monster,
 *	i.e.  vampire -> human corpse
 * yet still allow restoration of the original monster upon
 * resurrection.
 */
struct obj *
mkcorpstat(int objtype, struct monst *mtmp, struct permonst *ptr, int x, int y, boolean init)
            	/* CORPSE or STATUE */
                   
                     
         
             
{
    register struct obj *otmp;

    if (objtype != CORPSE && objtype != STATUE)
        warning("making corpstat type %d", objtype);
    if (x == 0 && y == 0) {		/* special case - random placement */
        otmp = mksobj(objtype, init, FALSE);
        if (otmp) rloco(otmp);
    } else
        otmp = mksobj_at(objtype, x, y, init, FALSE);
    if (otmp) {
        if (mtmp) {
            struct obj *otmp2;

            if (!ptr) ptr = mtmp->data;
            /* save_mtraits frees original data pointed to by otmp */
            otmp2 = save_mtraits(otmp, mtmp);
            if (otmp2) otmp = otmp2;
        }
        /* use the corpse or statue produced by mksobj() as-is
           unless `ptr' is non-null */
        if (ptr) {
            int old_corpsenm = otmp->corpsenm;

            otmp->corpsenm = monsndx(ptr);
            otmp->owt = weight(otmp);
            if (otmp->otyp == CORPSE &&
                    (special_corpse(old_corpsenm) ||
                     special_corpse(otmp->corpsenm))) {
                obj_stop_timers(otmp);
                start_corpse_timeout(otmp);
            }
        }
    }
    return(otmp);
}
Beispiel #2
0
/*
 * Get a random player name and class from the high score list,
 * and attach them to an object (for statues or morgue corpses).
 */
struct obj *
tt_oname(struct obj *otmp)
{
    int rank, fd;
    struct toptenentry *toptenlist, *tt;

    if (!otmp)
        return NULL;

    fd = open_datafile(RECORD, O_RDONLY, SCOREPREFIX);
    toptenlist = read_topten(fd, 100);  /* load the top 100 scores */
    close(fd);

    /* try to find a valid entry, reducing the value range for rank each time */
    rank = rn2(100);
    while (!validentry(toptenlist[rank]) && rank)
        rank = rn2(rank);

    tt = &toptenlist[rank];

    if (!validentry(toptenlist[rank]))
        otmp = NULL;    /* the topten list is empty */
    else {
        /* reset timer in case corpse started out as lizard or troll */
        if (otmp->otyp == CORPSE)
            obj_stop_timers(otmp);
        otmp->corpsenm = classmon(tt->plrole, (tt->plgend[0] == 'F'));
        otmp->owt = weight(otmp);
        otmp = oname(otmp, tt->name);
        if (otmp->otyp == CORPSE)
            start_corpse_timeout(otmp);
    }

    free(toptenlist);
    return otmp;
}
Beispiel #3
0
struct obj *
mksobj(int otyp, boolean init, boolean artif)
{
    int mndx, tryct;
    struct obj *otmp;
    char let = objects[otyp].oc_class;

    otmp = newobj(0);
    *otmp = zeroobj;
    otmp->age = monstermoves;
    otmp->o_id = flags.ident++;
    if (!otmp->o_id) otmp->o_id = flags.ident++;	/* ident overflowed */
    otmp->quan = 1L;
    otmp->oclass = let;
    otmp->otyp = otyp;
    otmp->where = OBJ_FREE;
    otmp->dknown = index(dknowns, let) ? 0 : 1;
    if (otmp->otyp == AMULET_OF_YENDOR)
        otmp->orecursive = FALSE;
    if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD) ||
            otmp->otyp == SHIELD_OF_REFLECTION)
        otmp->dknown = 0;
    if (!objects[otmp->otyp].oc_uses_known)
        otmp->known = 1;
    if (is_rustprone(otmp) || is_corrodeable(otmp) || is_flammable(otmp))
        otmp->rknown = 1;
#ifdef INVISIBLE_OBJECTS
    otmp->oinvis = !rn2(1250);
#endif
    if (init) switch (let) {
        case WEAPON_CLASS:
            otmp->quan = is_multigen(otmp) ? (long) rn1(6,6) : 1L;
            if(!rn2(11)) {
                otmp->spe = rne(3);
                otmp->blessed = rn2(2);
            } else if(!rn2(10)) {
                curse(otmp);
                otmp->spe = -rne(3);
            } else	blessorcurse(otmp, 10);
            if (is_poisonable(otmp) && !rn2(100))
                otmp->opoisoned = 1;

            if (artif && !rn2(20))
                otmp = mk_artifact(otmp, (aligntyp)A_NONE);
            break;
        case FOOD_CLASS:
            otmp->odrained = 0;
            otmp->oeaten = 0;
            switch(otmp->otyp) {
            case CORPSE:
                /* possibly overridden by mkcorpstat() */
                tryct = 50;
                do otmp->corpsenm = undead_to_corpse(rndmonnum());
                while ((mvitals[otmp->corpsenm].mvflags & G_NOCORPSE) && (--tryct > 0));
                if (tryct == 0) {
                    /* perhaps rndmonnum() only wants to make G_NOCORPSE monsters on
                       this level; let's create an adventurer's corpse instead, then */
                    otmp->corpsenm = PM_HUMAN;
                }
                /* timer set below */
                break;
            case EGG:
                otmp->corpsenm = NON_PM;	/* generic egg */
                if (!rn2(3)) for (tryct = 200; tryct > 0; --tryct) {
                        mndx = can_be_hatched(rndmonnum());
                        if (mndx != NON_PM && !dead_species(mndx, TRUE)) {
                            otmp->corpsenm = mndx;		/* typed egg */
                            attach_egg_hatch_timeout(otmp);
                            break;
                        }
                    }
                break;
            case TIN:
                otmp->corpsenm = NON_PM;	/* empty (so far) */
                if (!rn2(6))
                    otmp->spe = 1;		/* spinach */
                else for (tryct = 200; tryct > 0; --tryct) {
                        mndx = undead_to_corpse(rndmonnum());
                        if (mons[mndx].cnutrit &&
                                !(mvitals[mndx].mvflags & G_NOCORPSE)) {
                            otmp->corpsenm = mndx;
                            break;
                        }
                    }
                blessorcurse(otmp, 10);
                break;
            case SLIME_MOLD:
                otmp->spe = current_fruit;
                break;
            case KELP_FROND:
                otmp->quan = (long) rnd(2);
                break;
            }
            if (otmp->otyp == CORPSE || otmp->otyp == MEAT_RING ||
                    otmp->otyp == KELP_FROND) break;
            /* fall into next case */

        case GEM_CLASS:
            if (otmp->otyp == LOADSTONE) curse(otmp);
            else if (otmp->otyp == ROCK) otmp->quan = (long) rn1(6,6);
            else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2L;
            else otmp->quan = 1L;
            break;
        case TOOL_CLASS:
            switch(otmp->otyp) {
            case TALLOW_CANDLE:
            case WAX_CANDLE:
                otmp->spe = 1;
                otmp->age = 20L * /* 400 or 200 */
                            (long)objects[otmp->otyp].oc_cost;
                otmp->lamplit = 0;
                otmp->quan = 1L +
                             (long)(rn2(2) ? rn2(7) : 0);
                blessorcurse(otmp, 5);
                break;
            case BRASS_LANTERN:
            case OIL_LAMP:
                otmp->spe = 1;
                otmp->age = (long) rn1(500,1000);
                otmp->lamplit = 0;
                blessorcurse(otmp, 5);
                break;
            case MAGIC_LAMP:
                otmp->spe = 1;
                otmp->lamplit = 0;
                blessorcurse(otmp, 2);
                break;
            case IRON_SAFE:
                otmp->olocked = 1;
            case CHEST:
            case LARGE_BOX:
                if (otmp->otyp != IRON_SAFE) {
                    otmp->olocked = !!(rn2(5));  /* clumsy tweak */
                }
                otmp->otrapped = !(rn2(10));
            case ICE_BOX:
            case SACK:
            case OILSKIN_SACK:
            case BAG_OF_HOLDING:
                mkbox_cnts(otmp);
                break;
#ifdef TOURIST
            case EXPENSIVE_CAMERA:
#endif
            case TINNING_KIT:
            case MAGIC_MARKER:
                otmp->spe = rn1(60,20);
                break;
            case CAN_OF_GREASE:
                otmp->spe = rnd(25);
                blessorcurse(otmp, 10);
                break;
            case CRYSTAL_BALL:
                otmp->spe = rnd(5);
                blessorcurse(otmp, 2);
                break;
            case HORN_OF_PLENTY:
            case BAG_OF_TRICKS:
                otmp->spe = rnd(20);
                break;
            case FIGURINE:	{
                int tryct2 = 0;
                do
                    otmp->corpsenm = rndmonnum();
                while(is_human(&mons[otmp->corpsenm])
                        && tryct2++ < 30);
                blessorcurse(otmp, 4);
                break;
            }
            case BELL_OF_OPENING:
                otmp->spe = 3;
                break;
            case MAGIC_FLUTE:
            case MAGIC_HARP:
            case FROST_HORN:
            case FIRE_HORN:
            case DRUM_OF_EARTHQUAKE:
                otmp->spe = rn1(5,4);
                break;
            }
            break;
        case AMULET_CLASS:
            if (otmp->otyp == AMULET_OF_YENDOR) flags.made_amulet = TRUE;
            if(rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION ||
                           otmp->otyp == AMULET_OF_CHANGE ||
                           otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) {
                curse(otmp);
            } else	blessorcurse(otmp, 10);
        case VENOM_CLASS:
        case CHAIN_CLASS:
        case BALL_CLASS:
            break;
        case POTION_CLASS:
            if (otmp->otyp == POT_OIL)
                otmp->age = MAX_OIL_IN_FLASK;	/* amount of oil */
            /* fall through */
        case SCROLL_CLASS:
#ifdef MAIL
            if (otmp->otyp != SCR_MAIL)
#endif
                blessorcurse(otmp, 4);
            break;
        case SPBOOK_CLASS:
            blessorcurse(otmp, 17);
            break;
        case ARMOR_CLASS:
            if(rn2(10) && (otmp->otyp == FUMBLE_BOOTS ||
                           otmp->otyp == LEVITATION_BOOTS ||
                           otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT ||
                           otmp->otyp == GAUNTLETS_OF_FUMBLING ||
                           otmp->otyp == TINFOIL_HAT ||
                           !rn2(11))) {
                curse(otmp);
                otmp->spe = -rne(3);
            } else if(!rn2(10)) {
                otmp->blessed = rn2(2);
                otmp->spe = rne(3);
            } else	blessorcurse(otmp, 10);
            if (artif && !rn2(40))
                otmp = mk_artifact(otmp, (aligntyp)A_NONE);
            /* simulate lacquered armor for samurai */
            if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL &&
                    (moves <= 1 || In_quest(&u.uz))) {
#ifdef UNIXPC
                /* optimizer bitfield bug */
                otmp->oerodeproof = 1;
                otmp->rknown = 1;
#else
                otmp->oerodeproof = otmp->rknown = 1;
#endif
            }
            break;
        case WAND_CLASS:
            if (otmp->otyp == WAN_WISHING) {
                otmp->spe = (rnf(2,3) ? 1 : rnf(1,2) ? 0 : 2);
                otmp->recharged = 1;
            } else {
                otmp->spe = rn1(5,
                                (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4);
                otmp->recharged = 0; /* used to control recharging */
            }
            blessorcurse(otmp, 17);
            break;
        case RING_CLASS:
            if(objects[otmp->otyp].oc_charged) {
                blessorcurse(otmp, 3);
                if(rn2(10)) {
                    if(rn2(10) && bcsign(otmp))
                        otmp->spe = bcsign(otmp) * rne(3);
                    else otmp->spe = rn2(2) ? rne(3) : -rne(3);
                }
                /* make useless +0 rings much less common */
                if (otmp->spe == 0) otmp->spe = rn2(4) - rn2(3);
                /* negative rings are usually cursed */
                if (otmp->spe < 0 && rn2(5)) curse(otmp);
            } else if(rn2(10) && (otmp->otyp == RIN_TELEPORTATION ||
                                  otmp->otyp == RIN_POLYMORPH ||
                                  otmp->otyp == RIN_AGGRAVATE_MONSTER ||
                                  otmp->otyp == RIN_HUNGER || !rn2(9))) {
                curse(otmp);
            }
            break;
        case ROCK_CLASS:
            switch (otmp->otyp) {
            case STATUE:
                /* possibly overridden by mkcorpstat() */
                otmp->corpsenm = rndmonnum();
                if (!verysmall(&mons[otmp->corpsenm]) &&
                        rn2(level_difficulty()/2 + 10) > 10)
                    (void) add_to_container(otmp,
                                            mkobj(SPBOOK_CLASS,FALSE));
            }
            break;
        case COIN_CLASS:
            break;	/* do nothing */
        default:
            warning("impossible mkobj %d, sym '%c'.", otmp->otyp,
                    objects[otmp->otyp].oc_class);
            return (struct obj *)0;
        }

    /* Some things must get done (timers) even if init = 0 */
    switch (otmp->otyp) {
    case CORPSE:
        start_corpse_timeout(otmp);
        break;
    }

    /* unique objects may have an associated artifact entry */
    if (objects[otyp].oc_unique && !otmp->oartifact)
        otmp = mk_artifact(otmp, (aligntyp)A_NONE);
    otmp->owt = weight(otmp);
    return(otmp);
}
Beispiel #4
0
/* Called every turn during chest-forcing. The caller must set
   u.utracked[tos_lock] to the chest in question. */
static int
forcelock(void)
{
    struct monst *shkp;
    boolean costly;

    struct obj *otmp;
    struct obj *box = u.utracked[tos_lock];

    if (!obj_with_u(box))
        return reset_pick();

    if (!uwep_can_force()) /* prints the messages; ensures uwep != NULL */
        return reset_pick();

    if (u.uoccupation_progress[tos_lock]++ >= 50 ||
         nohands(youmonst.data)) {
        pline(msgc_failrandom, "You give up your attempt to force the lock.");
        if (!nohands(youmonst.data))
            exercise(is_blade(uwep) ? A_DEX : A_STR, TRUE);
        return reset_pick();
    }

    if (is_blade(uwep)) {
        if (rn2(1000 - (int)uwep->spe) > (992 - greatest_erosion(uwep) * 10) &&
            !uwep->cursed && !obj_resists(uwep, 0, 99)) {
            /* for a +0 weapon, probability that it survives an unsuccessful
               attempt to force the lock is (.992)^50 = .67 */
            pline(msgc_substitute, "%sour %s broke!",
                  (uwep->quan > 1L) ? "One of y" : "Y", xname(uwep));
            useup(uwep);
            pline_implied(msgc_failcurse,
                          "You can't exactly force that lock now.");
            exercise(A_DEX, TRUE);
            return reset_pick();
        }
    } else      /* blunt */
        wake_nearby(FALSE);  /* due to hammering on the container */

    if (rn2(100) >= objects[uwep->otyp].oc_wldam * 2)
        return 1;       /* still busy */

    pline(msgc_actionok, "You succeed in forcing the lock.");
    box->olocked = 0;
    box->obroken = 1;
    costly = (*u.ushops && costly_spot(youmonst.mx, youmonst.my));
    shkp = costly ? shop_keeper(level, *u.ushops) : 0;
    if (!is_blade(uwep) && !rn2(3)) {
        long loss = 0L;

        pline(msgc_substitute, "In fact, you've totally destroyed %s.",
              the(xname(box)));

        /* Put the contents on ground at the hero's feet. */
        while ((otmp = box->cobj) != 0) {
            obj_extract_self(otmp);
            if (!rn2(3) || otmp->oclass == POTION_CLASS) {
                chest_shatter_msg(otmp);
                if (costly)
                    loss +=
                        stolen_value(otmp, youmonst.mx, youmonst.my,
                                     (boolean) shkp->mpeaceful, TRUE);
                if (otmp->quan == 1L) {
                    obfree(otmp, NULL);
                    continue;
                }
                useup(otmp);
            }
            if (box->otyp == ICE_BOX && otmp->otyp == CORPSE) {
                otmp->age = moves - otmp->age;  /* actual age */
                start_corpse_timeout(otmp);
            }
            place_object(otmp, level, youmonst.mx, youmonst.my);
            stackobj(otmp);
        }

        if (costly)
            loss +=
                stolen_value(box, youmonst.mx, youmonst.my, (boolean) shkp->mpeaceful,
                             TRUE);
        if (loss)
            pline(msgc_unpaid, "You owe %ld %s for objects destroyed.",
                  loss, currency(loss));
        delobj(box);
    } else {
        if (costly) {
            struct obj *cobjbak = box->cobj;

            box->cobj = (struct obj *)0;
            verbalize(msgc_unpaid, "You damage it, you bought it!");
            bill_dummy_object(box);
            box->cobj = cobjbak;
        }
    }
    exercise(is_blade(uwep) ? A_DEX : A_STR, TRUE);

    return reset_pick();
}