[BACK]Return to monsters.c CVS log [TXT][DIR] Up to [contributed] / early-roguelike / arogue5

Annotation of early-roguelike/arogue5/monsters.c, Revision 1.1.1.1

1.1       rubenllo    1: /*
                      2:  * File with various monster functions in it
                      3:  *
                      4:  * Advanced Rogue
                      5:  * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
                      6:  * All rights reserved.
                      7:  *
                      8:  * Based on "Rogue: Exploring the Dungeons of Doom"
                      9:  * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
                     10:  * All rights reserved.
                     11:  *
                     12:  * See the file LICENSE.TXT for full copyright and licensing information.
                     13:  */
                     14:
                     15: #include "curses.h"
                     16: #include "rogue.h"
                     17: #include <stdlib.h>
                     18: #include <ctype.h>
                     19: #include <string.h>
                     20:
                     21: 
                     22: /*
                     23:  * Check_residue takes care of any effect of the monster
                     24:  */
                     25: void
                     26: check_residue(struct thing *tp)
                     27: {
                     28:     /*
                     29:      * Take care of special abilities
                     30:      */
                     31:     if (on(*tp, DIDHOLD) && (--hold_count == 0)) turn_off(player, ISHELD);
                     32:
                     33:     /* If it has lowered player, give him back a level */
                     34:     if (on(*tp, DIDDRAIN)) raise_level(FALSE);
                     35:
                     36:     /* If frightened of this monster, stop */
                     37:     if (on(player, ISFLEE) &&
                     38:        player.t_dest == &tp->t_pos) turn_off(player, ISFLEE);
                     39:
                     40:     /* If monster was suffocating player, stop it */
                     41:     if (on(*tp, DIDSUFFOCATE)) extinguish(suffocate);
                     42:
                     43:     /* If something with fire, may darken */
                     44:     if (on(*tp, HASFIRE)) {
                     45:        register struct room *rp=roomin(&tp->t_pos);
                     46:        register struct linked_list *fire_item;
                     47:
                     48:        if (rp) {
                     49:            for (fire_item = rp->r_fires; fire_item != NULL;
                     50:                 fire_item = next(fire_item)) {
                     51:                if (THINGPTR(fire_item) == tp) {
                     52:                    detach(rp->r_fires, fire_item);
                     53:                    destroy_item(fire_item);
                     54:                    if (rp->r_fires == NULL) {
                     55:                        rp->r_flags &= ~HASFIRE;
                     56:                        if (cansee(tp->t_pos.y, tp->t_pos.x)) light(&hero);
                     57:                    }
                     58:                    break;
                     59:                }
                     60:            }
                     61:        }
                     62:     }
                     63: }
                     64: 
                     65: /*
                     66:  * Creat_mons creates the specified monster -- any if 0
                     67:  * person: Where to create next to
                     68:  */
                     69:
                     70: bool
                     71: creat_mons(struct thing *person, short monster, bool report)
                     72: {
                     73:     struct linked_list *nitem;
                     74:     register struct thing *tp;
                     75:     struct room *rp;
                     76:     coord *mp;
                     77:
                     78:     if (levtype == POSTLEV)
                     79:        return(FALSE);
                     80:     if ((mp = fallpos(&(person->t_pos), FALSE, 2)) != NULL) {
                     81:        nitem = new_item(sizeof (struct thing));
                     82:        new_monster(nitem,
                     83:                    monster == 0 ? randmonster(FALSE, FALSE)
                     84:                                 : monster,
                     85:                    mp,
                     86:                    TRUE);
                     87:        tp = THINGPTR(nitem);
                     88:        runto(tp, &hero);
                     89:        tp->t_no_move = 1;      /* since it just got here, it is disoriented */
                     90:        carry_obj(tp, monsters[tp->t_index].m_carry/2); /* only half chance */
                     91:        if (on(*tp, HASFIRE)) {
                     92:            rp = roomin(&tp->t_pos);
                     93:            if (rp) {
                     94:                register struct linked_list *fire_item;
                     95:
                     96:                /* Put the new fellow in the room list */
                     97:                fire_item = creat_item();
                     98:                ldata(fire_item) = (char *) tp;
                     99:                attach(rp->r_fires, fire_item);
                    100:
                    101:                rp->r_flags |= HASFIRE;
                    102:            }
                    103:        }
                    104:
                    105:        /*
                    106:         * If we can see this monster, set oldch to ' ' to make light()
                    107:         * think the creature used to be invisible (ie. not seen here)
                    108:         */
                    109:        if (cansee(tp->t_pos.y, tp->t_pos.x)) tp->t_oldch = ' ';
                    110:        return(TRUE);
                    111:     }
                    112:     if (report) msg("You hear a faint cry of anguish in the distance.");
                    113:     return(FALSE);
                    114: }
                    115: 
                    116: /*
                    117:  * Genmonsters:
                    118:  *     Generate at least 'least' monsters for this single room level.
                    119:  *     'Treas' indicates whether this is a "treasure" level.
                    120:  */
                    121:
                    122: void
                    123: genmonsters(int least, bool treas)
                    124: {
                    125:     reg int i;
                    126:     reg struct room *rp = &rooms[0];
                    127:     reg struct linked_list *item;
                    128:     reg struct thing *mp;
                    129:     coord tp;
                    130:
                    131:     for (i = 0; i < level + least; i++) {
                    132:            if (!treas && rnd(100) < 50)        /* put in some little buggers */
                    133:                    continue;
                    134:            /*
                    135:             * Put the monster in
                    136:             */
                    137:            item = new_item(sizeof *mp);
                    138:            mp = THINGPTR(item);
                    139:            do {
                    140:                    rnd_pos(rp, &tp);
                    141:            } until(mvwinch(stdscr, tp.y, tp.x) == FLOOR);
                    142:
                    143:            new_monster(item, randmonster(FALSE, FALSE), &tp, FALSE);
                    144:            /*
                    145:             * See if we want to give it a treasure to carry around.
                    146:             */
                    147:            carry_obj(mp, monsters[mp->t_index].m_carry);
                    148:
                    149:            /* Is it going to give us some light? */
                    150:            if (on(*mp, HASFIRE)) {
                    151:                register struct linked_list *fire_item;
                    152:
                    153:                fire_item = creat_item();
                    154:                ldata(fire_item) = (char *) mp;
                    155:                attach(rp->r_fires, fire_item);
                    156:                rp->r_flags |= HASFIRE;
                    157:            }
                    158:     }
                    159: }
                    160: 
                    161: /*
                    162:  * id_monst returns the index of the monster given its letter
                    163:  */
                    164:
                    165: short
                    166: id_monst(char monster)
                    167: {
                    168:     register short result;
                    169:
                    170:     result = NLEVMONS*vlevel;
                    171:     if (result > NUMMONST) result = NUMMONST;
                    172:
                    173:     for(; result>0; result--)
                    174:        if (monsters[result].m_appear == monster) return(result);
                    175:     for (result=(NLEVMONS*vlevel)+1; result <= NUMMONST; result++)
                    176:        if (monsters[result].m_appear == monster) return(result);
                    177:     return(0);
                    178: }
                    179:
                    180: 
                    181: /*
                    182:  * new_monster:
                    183:  *     Pick a new monster and add it to the list
                    184:  */
                    185:
                    186: void
                    187: new_monster(struct linked_list *item, short type, coord *cp, bool max_monster)
                    188: {
                    189:     register struct thing *tp;
                    190:     register struct monster *mp;
                    191:     register char *ip, *hitp;
                    192:     register int i, min_intel, max_intel;
                    193:     register int num_dice, num_sides=8, num_extra=0;
                    194:
                    195:     attach(mlist, item);
                    196:     tp = THINGPTR(item);
                    197:     tp->t_turn = TRUE;
                    198:     tp->t_pack = NULL;
                    199:     tp->t_index = type;
                    200:     tp->t_wasshot = FALSE;
                    201:     tp->t_type = monsters[type].m_appear;
                    202:     tp->t_ctype = C_MONSTER;
                    203:     tp->t_no_move = 0;
                    204:     tp->t_doorgoal = 0;
                    205:     tp->t_quiet = 0;
                    206:     tp->t_pos = tp->t_oldpos = *cp;
                    207:     tp->t_oldch = CCHAR( mvwinch(cw, cp->y, cp->x) );
                    208:     mvwaddch(mw, cp->y, cp->x, tp->t_type);
                    209:     mp = &monsters[tp->t_index];
                    210:
                    211:     /* Figure out monster's hit points */
                    212:     hitp = mp->m_stats.s_hpt;
                    213:     num_dice = atoi(hitp);
                    214:     if ((hitp = strchr(hitp, 'd')) != NULL) {
                    215:        num_sides = atoi(++hitp);
                    216:        if ((hitp = strchr(hitp, '+')) != NULL)
                    217:            num_extra = atoi(++hitp);
                    218:     }
                    219:
                    220:     tp->t_stats.s_lvl = mp->m_stats.s_lvl;
                    221:     tp->t_stats.s_arm = mp->m_stats.s_arm;
                    222:     strncpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg,sizeof(tp->t_stats.s_dmg));
                    223:     tp->t_stats.s_str = mp->m_stats.s_str;
                    224:     if (vlevel > HARDER) { /* the deeper, the meaner we get */
                    225:         tp->t_stats.s_lvl += (vlevel - HARDER);
                    226:         num_dice += (vlevel - HARDER)/2;
                    227:     }
                    228:     if (max_monster)
                    229:        tp->t_stats.s_hpt = num_dice * num_sides + num_extra;
                    230:     else
                    231:        tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra;
                    232:     tp->t_stats.s_exp = mp->m_stats.s_exp + mp->m_add_exp*tp->t_stats.s_hpt;
                    233:
                    234:     /*
                    235:      * just initailize others values to something reasonable for now
                    236:      * maybe someday will *really* put these in monster table
                    237:      */
                    238:     tp->t_stats.s_wisdom = 8 + rnd(4);
                    239:     tp->t_stats.s_dext = 8 + rnd(4);
                    240:     tp->t_stats.s_const = 8 + rnd(4);
                    241:     tp->t_stats.s_charisma = 8 + rnd(4);
                    242:
                    243:     /* Set the initial flags */
                    244:     for (i=0; i<16; i++) tp->t_flags[i] = 0;
                    245:     for (i=0; i<MAXFLAGS; i++)
                    246:        turn_on(*tp, mp->m_flags[i]);
                    247:
                    248:     /* suprising monsters don't always surprise you */
                    249:     if (!max_monster           && on(*tp, CANSURPRISE) &&
                    250:        off(*tp, ISUNIQUE)      && rnd(100) < 20)
                    251:            turn_off(*tp, CANSURPRISE);
                    252:
                    253:     /* If this monster is unique, gen it */
                    254:     if (on(*tp, ISUNIQUE)) mp->m_normal = FALSE;
                    255:
                    256:     /*
                    257:      * if is it the quartermaster, then compute his level and exp pts
                    258:      * based on the level. This will make it fair when thieves try to
                    259:      * steal and give them reasonable experience if they succeed.
                    260:      */
                    261:     if (on(*tp, CANSELL)) {
                    262:        tp->t_stats.s_exp = vlevel * 100;
                    263:        tp->t_stats.s_lvl = vlevel/2 + 1;
                    264:        attach(tp->t_pack, new_thing(ALL));
                    265:     }
                    266:
                    267:     /* Normally scared monsters have a chance to not be scared */
                    268:     if (on(*tp, ISFLEE) && (rnd(4) == 0)) turn_off(*tp, ISFLEE);
                    269:
                    270:     /* Figure intelligence */
                    271:     min_intel = atoi(mp->m_intel);
                    272:     if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL)
                    273:        tp->t_stats.s_intel = min_intel;
                    274:     else {
                    275:        max_intel = atoi(++ip);
                    276:        if (max_monster)
                    277:            tp->t_stats.s_intel = max_intel;
                    278:        else
                    279:            tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel);
                    280:     }
                    281:     if (vlevel > HARDER)
                    282:         tp->t_stats.s_intel += ((vlevel - HARDER)/2);
                    283:     tp->maxstats = tp->t_stats;
                    284:
                    285:     /* If the monster can shoot, it may have a weapon */
                    286:     if (on(*tp, CANSHOOT) && ((rnd(100) < (22 + vlevel)) || max_monster)) {
                    287:        struct linked_list *item1;
                    288:        register struct object *cur, *cur1;
                    289:
                    290:        item = new_item(sizeof *cur);
                    291:        item1 = new_item(sizeof *cur1);
                    292:        cur = OBJPTR(item);
                    293:        cur1 = OBJPTR(item1);
                    294:        cur->o_hplus = (rnd(4) < 3) ? 0
                    295:                                    : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
                    296:        cur->o_dplus = (rnd(4) < 3) ? 0
                    297:                                    : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
                    298:        cur1->o_hplus = (rnd(4) < 3) ? 0
                    299:                                    : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
                    300:        cur1->o_dplus = (rnd(4) < 3) ? 0
                    301:                                    : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
                    302:        strcpy(cur->o_damage,"0d0");
                    303:         strcpy(cur->o_hurldmg,"0d0");
                    304:        strcpy(cur1->o_damage,"0d0");
                    305:         strcpy(cur1->o_hurldmg,"0d0");
                    306:        cur->o_ac = cur1->o_ac = 11;
                    307:        cur->o_count = cur1->o_count = 1;
                    308:        cur->o_group = cur1->o_group = 0;
                    309:        cur->contents = cur1->contents = NULL;
                    310:        if ((cur->o_hplus <= 0) && (cur->o_dplus <= 0)) cur->o_flags = ISCURSED;
                    311:        if ((cur1->o_hplus <= 0) && (cur1->o_dplus <= 0))
                    312:            cur1->o_flags = ISCURSED;
                    313:        cur->o_flags = cur1->o_flags = 0;
                    314:        cur->o_type = cur1->o_type = WEAPON;
                    315:        cur->o_mark[0] = cur1->o_mark[0] = '\0';
                    316:
                    317:        /* The monster may use a crossbow, sling, or an arrow */
                    318:        i = rnd(100);
                    319:        if (i < 10) {
                    320:            cur->o_which = CROSSBOW;
                    321:            cur1->o_which = BOLT;
                    322:            init_weapon(cur, CROSSBOW);
                    323:            init_weapon(cur1, BOLT);
                    324:        }
                    325:        else if (i < 70) {
                    326:            cur->o_which = BOW;
                    327:            cur1->o_which = ARROW;
                    328:            init_weapon(cur, BOW);
                    329:            init_weapon(cur1, ARROW);
                    330:        }
                    331:        else {
                    332:            cur->o_which = SLING;
                    333:            cur1->o_which = ROCK;
                    334:            init_weapon(cur, SLING);
                    335:            init_weapon(cur1, ROCK);
                    336:        }
                    337:
                    338:        attach(tp->t_pack, item);
                    339:        attach(tp->t_pack, item1);
                    340:     }
                    341:
                    342:
                    343:     if (ISWEARING(R_AGGR))
                    344:        runto(tp, &hero);
                    345:     if (on(*tp, ISDISGUISE))
                    346:     {
                    347:        char mch = 0;
                    348:
                    349:        if (tp->t_pack != NULL)
                    350:            mch = (OBJPTR(tp->t_pack))->o_type;
                    351:        else
                    352:            switch (rnd(10)) {
                    353:                case 0: mch = GOLD;
                    354:                when 1: mch = POTION;
                    355:                when 2: mch = SCROLL;
                    356:                when 3: mch = FOOD;
                    357:                when 4: mch = WEAPON;
                    358:                when 5: mch = ARMOR;
                    359:                when 6: mch = RING;
                    360:                when 7: mch = STICK;
                    361:                when 8: mch = monsters[randmonster(FALSE, FALSE)].m_appear;
                    362:                when 9: mch = MM;
                    363:            }
                    364:        tp->t_disguise = mch;
                    365:     }
                    366: }
                    367: 
                    368: /*
                    369:  * randmonster:
                    370:  *     Pick a monster to show up.  The lower the level,
                    371:  *     the meaner the monster.
                    372:  */
                    373:
                    374: short
                    375: randmonster(bool wander, bool no_unique)
                    376: {
                    377:     register int d, cur_level, range, i;
                    378:
                    379:     /*
                    380:      * Do we want a merchant? Merchant is always in place 'NUMMONST'
                    381:      */
                    382:     if (wander && monsters[NUMMONST].m_wander && rnd(100) < 3) return NUMMONST;
                    383:
                    384:     cur_level = vlevel;
                    385:     range = 4*NLEVMONS;
                    386:     i = 0;
                    387:     do
                    388:     {
                    389:        if (i++ > range*10) { /* just in case all have be genocided */
                    390:            i = 0;
                    391:            if (--cur_level <= 0)
                    392:                fatal("Rogue could not find a monster to make");
                    393:        }
                    394:        d = NLEVMONS*(cur_level - 1) + (rnd(range) - (range - 1 - NLEVMONS));
                    395:        if (d < 1)
                    396:            d = rnd(NLEVMONS) + 1;
                    397:        if (d > NUMMONST - NUMUNIQUE - 1) {
                    398:            if (no_unique)
                    399:                d = rnd(range) + (NUMMONST - NUMUNIQUE - 1) - (range - 1);
                    400:            else if (d > NUMMONST - 1)
                    401:                d = rnd(range+NUMUNIQUE) + (NUMMONST-1) - (range+NUMUNIQUE-1);
                    402:        }
                    403:     }
                    404:     while  (wander ? !monsters[d].m_wander || !monsters[d].m_normal
                    405:                   : !monsters[d].m_normal);
                    406:     return d;
                    407: }
                    408: 
                    409: /* Sell displays a menu of goods from which the player may choose
                    410:  * to purchase something.
                    411:  */
                    412:
                    413: void
                    414: sell(struct thing *tp)
                    415: {
                    416:     register struct linked_list *item;
                    417:     register struct object *obj;
                    418:     register int i, j, min_worth, nitems, goods = 0, chance, which_item;
                    419:     char buffer[LINELEN];
                    420:     struct {
                    421:        int which;
                    422:        int plus1, plus2;
                    423:        int count;
                    424:        int worth;
                    425:        char *name;
                    426:     } selection[10];
                    427:
                    428:     min_worth = 100000;
                    429:     item = find_mons(tp->t_pos.y, tp->t_pos.x); /* Get pointer to monster */
                    430:
                    431:     /* Select the items */
                    432:     nitems = rnd(6) + 5;
                    433:
                    434:     for (i=0; i<nitems; i++) {
                    435:        selection[i].worth = selection[i].plus1
                    436:                           = selection[i].plus2
                    437:                           = selection[i].which
                    438:                           = selection[i].count
                    439:                           = 0;
                    440:     }
                    441:     switch (rnd(9)) {
                    442:        /* Armor */
                    443:        case 0:
                    444:        case 1:
                    445:            goods = ARMOR;
                    446:            for (i=0; i<nitems; i++) {
                    447:                chance = rnd(100);
                    448:                for (j = 0; j < MAXARMORS; j++)
                    449:                    if (chance < armors[j].a_prob)
                    450:                        break;
                    451:                if (j == MAXARMORS) {
                    452:                    debug("Picked a bad armor %d", chance);
                    453:                    j = 0;
                    454:                }
                    455:                selection[i].which = j;
                    456:                selection[i].count = 1;
                    457:                if (rnd(100) < 40) selection[i].plus1 = rnd(5) + 1;
                    458:                else selection[i].plus1 = 0;
                    459:                selection[i].name = armors[j].a_name;
                    460:
                    461:                /* Calculate price */
                    462:                selection[i].worth = armors[j].a_worth;
                    463:                selection[i].worth +=
                    464:                        2 * s_magic[S_ALLENCH].mi_worth * selection[i].plus1;
                    465:                if (min_worth > selection[i].worth)
                    466:                    min_worth = selection[i].worth;
                    467:            }
                    468:            break;
                    469:
                    470:        /* Weapon */
                    471:        case 2:
                    472:        case 3:
                    473:            goods = WEAPON;
                    474:            for (i=0; i<nitems; i++) {
                    475:                selection[i].which = rnd(MAXWEAPONS);
                    476:                selection[i].count = 1;
                    477:                if (rnd(100) < 35) {
                    478:                    selection[i].plus1 = rnd(3);
                    479:                    selection[i].plus2 = rnd(3);
                    480:                }
                    481:                else {
                    482:                    selection[i].plus1 = 0;
                    483:                    selection[i].plus2 = 0;
                    484:                }
                    485:                if (weaps[selection[i].which].w_flags & ISMANY)
                    486:                    selection[i].count = rnd(15) + 5;
                    487:                selection[i].name = weaps[selection[i].which].w_name;
                    488:                /*
                    489:                 * note: use "count" before adding in the enchantment cost
                    490:                 *       of an item. This will keep the price of arrows
                    491:                 *       and such to a reasonable price.
                    492:                 */
                    493:                j = selection[i].plus1 + selection[i].plus2;
                    494:                selection[i].worth = weaps[selection[i].which].w_worth;
                    495:                selection[i].worth *= selection[i].count;
                    496:                selection[i].worth += 2 * s_magic[S_ALLENCH].mi_worth * j;
                    497:                if (min_worth > selection[i].worth)
                    498:                    min_worth = selection[i].worth;
                    499:            }
                    500:            break;
                    501:
                    502:        /* Staff or wand */
                    503:        case 4:
                    504:            goods = STICK;
                    505:            for (i=0; i<nitems; i++) {
                    506:                selection[i].which = pick_one(ws_magic, MAXSTICKS);
                    507:                selection[i].plus1 = rnd(11) + 5;       /* Charges */
                    508:                selection[i].count = 1;
                    509:                selection[i].name = ws_magic[selection[i].which].mi_name;
                    510:                selection[i].worth = ws_magic[selection[i].which].mi_worth;
                    511:                selection[i].worth += 20 * selection[i].plus1;
                    512:                if (min_worth > selection[i].worth)
                    513:                    min_worth = selection[i].worth;
                    514:            }
                    515:            break;
                    516:
                    517:        /* Ring */
                    518:        case 5:
                    519:            goods = RING;
                    520:            for (i=0; i<nitems; i++) {
                    521:                selection[i].which = pick_one(r_magic, MAXRINGS);
                    522:                selection[i].plus1 = rnd(2) + 1;  /* Armor class */
                    523:                selection[i].count = 1;
                    524:                if (rnd(100) < r_magic[selection[i].which].mi_bless + 10)
                    525:                    selection[i].plus1 += rnd(2) + 1;
                    526:                selection[i].name = r_magic[selection[i].which].mi_name;
                    527:                selection[i].worth = r_magic[selection[i].which].mi_worth;
                    528:
                    529:                switch (selection[i].which) {
                    530:                case R_DIGEST:
                    531:                    if (selection[i].plus1 > 2) selection[i].plus1 = 2;
                    532:                    else if (selection[i].plus1 < 1) selection[i].plus1 = 1;
                    533:                /* fall thru here to other cases */
                    534:                case R_ADDSTR:
                    535:                case R_ADDDAM:
                    536:                case R_PROTECT:
                    537:                case R_ADDHIT:
                    538:                case R_ADDINTEL:
                    539:                case R_ADDWISDOM:
                    540:                    if (selection[i].plus1 > 0)
                    541:                        selection[i].worth += selection[i].plus1 * 50;
                    542:                }
                    543:                if(min_worth > selection[i].worth)
                    544:                    min_worth = selection[i].worth;
                    545:            }
                    546:            break;
                    547:
                    548:        /* scroll */
                    549:        case 6:
                    550:            goods = SCROLL;
                    551:            for (i=0; i<nitems; i++) {
                    552:                selection[i].which = pick_one(s_magic, MAXSCROLLS);
                    553:                selection[i].count = 1;
                    554:                selection[i].name = s_magic[selection[i].which].mi_name;
                    555:                selection[i].worth = s_magic[selection[i].which].mi_worth;
                    556:                if (min_worth > selection[i].worth)
                    557:                    min_worth = selection[i].worth;
                    558:            }
                    559:            break;
                    560:
                    561:        /* potions */
                    562:        case 7:
                    563:            goods = POTION;
                    564:            for (i=0; i<nitems; i++) {
                    565:                selection[i].which = pick_one(p_magic, MAXPOTIONS);
                    566:                selection[i].count = 1;
                    567:                selection[i].name = p_magic[selection[i].which].mi_name;
                    568:                selection[i].worth = p_magic[selection[i].which].mi_worth;
                    569:                if (min_worth > selection[i].worth)
                    570:                    min_worth = selection[i].worth;
                    571:            }
                    572:            break;
                    573:
                    574:        /* Miscellaneous magic */
                    575:        case 8:
                    576:            goods = MM;
                    577:            for (i=0; i<nitems; i++) { /* don't sell as many mm as others */
                    578:                selection[i].which = pick_one(m_magic, MAXMM);
                    579:                selection[i].count = 1;
                    580:                selection[i].name = m_magic[selection[i].which].mi_name;
                    581:                selection[i].worth = m_magic[selection[i].which].mi_worth;
                    582:
                    583:                switch (selection[i].which) {
                    584:                case MM_JUG:
                    585:                    switch(rnd(9)) {
                    586:                        case 0: selection[i].plus1 = P_PHASE;
                    587:                        when 1: selection[i].plus1 = P_CLEAR;
                    588:                        when 2: selection[i].plus1 = P_SEEINVIS;
                    589:                        when 3: selection[i].plus1 = P_HEALING;
                    590:                        when 4: selection[i].plus1 = P_MFIND;
                    591:                        when 5: selection[i].plus1 = P_TFIND;
                    592:                        when 6: selection[i].plus1 = P_HASTE;
                    593:                        when 7: selection[i].plus1 = P_RESTORE;
                    594:                        when 8: selection[i].plus1 = P_FLY;
                    595:                    }
                    596:                when MM_OPEN:
                    597:                case MM_HUNGER:
                    598:                case MM_DRUMS:
                    599:                case MM_DISAPPEAR:
                    600:                case MM_CHOKE:
                    601:                case MM_KEOGHTOM:
                    602:                    selection[i].plus1  = 3 + (rnd(3)+1) * 3;
                    603:                    selection[i].worth += selection[i].plus1 * 50;
                    604:                when MM_BRACERS:
                    605:                    selection[i].plus1  = rnd(10)+1;
                    606:                    selection[i].worth += selection[i].plus1 * 75;
                    607:                when MM_DISP:
                    608:                    selection[i].plus1  = 2;
                    609:                when MM_PROTECT:
                    610:                    selection[i].plus1  = rnd(5)+1;
                    611:                    selection[i].worth += selection[i].plus1 * 100;
                    612:                when MM_SKILLS:
                    613:                    selection[i].plus1 = player.t_ctype;
                    614:                otherwise:
                    615:                    break;
                    616:                }
                    617:                if(min_worth > selection[i].worth)
                    618:                    min_worth = selection[i].worth;
                    619:            }
                    620:            break;
                    621:     }
                    622:
                    623:     /* See if player can afford an item */
                    624:     if (min_worth > purse) {
                    625:        msg("The %s eyes your small purse and departs.",
                    626:                        monsters[NUMMONST].m_name);
                    627:        /* Get rid of the monster */
                    628:        killed(item, FALSE, FALSE);
                    629:        return;
                    630:     }
                    631:
                    632:     /* Display the goods */
                    633:     msg("The %s shows you his wares.--More--", monsters[NUMMONST].m_name);
                    634:     wait_for(cw,' ');
                    635:     msg("");
                    636:     clearok(cw, TRUE);
                    637:     touchwin(cw);
                    638:
                    639:     wclear(hw);
                    640:     touchwin(hw);
                    641:     for (i=0; i < nitems; i++) {
                    642:        mvwaddch(hw, i+2, 0, '[');
                    643:        waddch(hw, (char) ((int) 'a' + i));
                    644:        waddstr(hw, "] ");
                    645:        switch (goods) {
                    646:            case ARMOR:
                    647:                waddstr(hw, "Some ");
                    648:            when WEAPON:
                    649:                if (selection[i].count == 1)
                    650:                    waddstr(hw, " A ");
                    651:                else {
                    652:                    sprintf(buffer, "%2d ", selection[i].count);
                    653:                    waddstr(hw, buffer);
                    654:                }
                    655:            when STICK:
                    656:                wprintw(hw, "A %-5s of ", ws_type[selection[i].which]);
                    657:            when RING:
                    658:                waddstr(hw, "A ring of ");
                    659:            when SCROLL:
                    660:                waddstr(hw, "A scroll of ");
                    661:            when POTION:
                    662:                waddstr(hw, "A potion of ");
                    663:        }
                    664:        if (selection[i].count > 1)
                    665:            sprintf(buffer, "%s%s ", selection[i].name, "s");
                    666:        else
                    667:            sprintf(buffer, "%s ", selection[i].name);
                    668:        wprintw(hw, "%-24s", buffer);
                    669:        wprintw(hw, " Price:%5d", selection[i].worth);
                    670:     }
                    671:     sprintf(buffer, "Purse:  %d", purse);
                    672:     mvwaddstr(hw, nitems+3, 0, buffer);
                    673:     mvwaddstr(hw, 0, 0, "How about one of the following goods? ");
                    674:     draw(hw);
                    675:     /* Get rid of the monster */
                    676:     killed(item, FALSE, FALSE);
                    677:
                    678:     which_item = (int) (wgetch(hw) - 'a');
                    679:     while (which_item < 0 || which_item >= nitems) {
                    680:        if (which_item == (int) ESCAPE - (int) 'a') {
                    681:            return;
                    682:        }
                    683:        mvwaddstr(hw, 0, 0, "Please enter one of the listed items. ");
                    684:        draw(hw);
                    685:        which_item = (int) (wgetch(hw) - 'a');
                    686:     }
                    687:
                    688:     if (selection[which_item].worth > purse) {
                    689:        msg("You cannot afford it.");
                    690:        return;
                    691:     }
                    692:
                    693:     purse -= selection[which_item].worth;
                    694:
                    695:     item = spec_item(goods, selection[which_item].which,
                    696:                     selection[which_item].plus1, selection[which_item].plus2);
                    697:
                    698:     obj = OBJPTR(item);
                    699:     if (selection[which_item].count > 1) {
                    700:        obj->o_count = selection[which_item].count;
                    701:        obj->o_group = newgrp();
                    702:     }
                    703:     /* If a stick or ring, let player know the type */
                    704:     switch (goods) {
                    705:        case RING:  r_know[selection[which_item].which] = TRUE;
                    706:        when POTION:p_know[selection[which_item].which] = TRUE;
                    707:        when SCROLL:s_know[selection[which_item].which] = TRUE;
                    708:        when STICK: ws_know[selection[which_item].which] = TRUE;
                    709:        when MM:    m_know[selection[which_item].which] = TRUE;
                    710:
                    711:     }
                    712:
                    713:     if (add_pack(item, FALSE, NULL) == FALSE) {
                    714:
                    715:        obj->o_pos = hero;
                    716:        fall(item, TRUE);
                    717:     }
                    718: }
                    719:
                    720:
                    721: 
                    722: /*
                    723:  * what to do when the hero steps next to a monster
                    724:  */
                    725: struct linked_list *
                    726: wake_monster(int y, int x)
                    727: {
                    728:     register struct thing *tp;
                    729:     register struct linked_list *it;
                    730:     register struct room *trp;
                    731:     register const char *mname;
                    732:     bool nasty;        /* Will the monster "attack"? */
                    733:     char ch;
                    734:
                    735:     if ((it = find_mons(y, x)) == NULL) {
                    736:        msg("Can't find monster in show");
                    737:        return (NULL);
                    738:     }
                    739:     tp = THINGPTR(it);
                    740:     ch = tp->t_type;
                    741:
                    742:     trp = roomin(&tp->t_pos); /* Current room for monster */
                    743:     mname = monsters[tp->t_index].m_name;
                    744:
                    745:     /*
                    746:      * Let greedy ones in a room guard gold
                    747:      * (except in a maze where lots of creatures would all go for the
                    748:      * same piece of gold)
                    749:      */
                    750:     if (on(*tp, ISGREED)       && off(*tp, ISRUN)      &&
                    751:        levtype != MAZELEV      && trp != NULL          &&
                    752:        lvl_obj != NULL) {
                    753:            register struct linked_list *item;
                    754:            register struct object *cur;
                    755:
                    756:            for (item = lvl_obj; item != NULL; item = next(item)) {
                    757:                cur = OBJPTR(item);
                    758:                if ((cur->o_type == GOLD) &&
                    759:                    (roomin(&cur->o_pos) == trp)) {
                    760:                    /* Run to the gold */
                    761:                    tp->t_dest = &cur->o_pos;
                    762:                    turn_on(*tp, ISRUN);
                    763:                    turn_off(*tp, ISDISGUISE);
                    764:
                    765:                    /* Make it worth protecting */
                    766:                    cur->o_count += GOLDCALC + GOLDCALC;
                    767:                    break;
                    768:                }
                    769:            }
                    770:     }
                    771:
                    772:     /*
                    773:      * Every time he sees mean monster, it might start chasing him
                    774:      */
                    775:     if (on(*tp, ISMEAN)                                                        &&
                    776:        off(*tp, ISHELD)                                                &&
                    777:        off(*tp, ISRUN)                                                 &&
                    778:        rnd(100) > 33                                                   &&
                    779:        (!is_stealth(&player) || (on(*tp, ISUNIQUE) && rnd(100) > 95))  &&
                    780:        (off(player, ISINVIS) || on(*tp, CANSEE))                       ||
                    781:        (trp != NULL && (trp->r_flags & ISTREAS))) {
                    782:        tp->t_dest = &hero;
                    783:        turn_on(*tp, ISRUN);
                    784:        turn_off(*tp, ISDISGUISE);
                    785:     }
                    786:
                    787:     /* See if the monster will bother the player */
                    788:     nasty = (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x));
                    789:
                    790:     /*
                    791:      * Let the creature summon if it can.
                    792:      * Also check to see if there is room around the player,
                    793:      * if not then the creature will wait
                    794:      */
                    795:     if (on(*tp, CANSUMMON) && nasty            &&
                    796:        rnd(40) < tp->t_stats.s_lvl             &&
                    797:        fallpos(&hero, FALSE, 2) != NULL) {
                    798:        const char *helpname;
                    799:        int fail;
                    800:        register int which, i;
                    801:
                    802:        turn_off(*tp, CANSUMMON);
                    803:        helpname = monsters[tp->t_index].m_typesum;
                    804:        for (which=1; which<NUMMONST; which++) {
                    805:             if (strcmp(helpname, monsters[which].m_name) == 0)
                    806:                 break;
                    807:        }
                    808:        if (which >= NUMMONST)
                    809:             debug("couldn't find summoned one");
                    810:        if ((off(*tp, ISINVIS)     || on(player, CANSEE)) &&
                    811:            (off(*tp, ISSHADOW)    || on(player, CANSEE)) &&
                    812:            (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) {
                    813:            if (monsters[which].m_normal == FALSE) { /* genocided? */
                    814:                msg("The %s appears dismayed", mname);
                    815:                monsters[tp->t_index].m_numsum = 0;
                    816:            }
                    817:            else {
                    818:                sprintf(outstring,"The %s summons %ss for help", mname, helpname);
                    819:                msg(outstring);
                    820:            }
                    821:        }
                    822:        else {
                    823:            if (monsters[which].m_normal == FALSE) /* genocided? */
                    824:                monsters[tp->t_index].m_numsum = 0;
                    825:            else
                    826:                msg("%ss seem to appear from nowhere!", helpname);
                    827:        }
                    828:        /*
                    829:         * try to make all the creatures around player but remember
                    830:         * if unsuccessful
                    831:         */
                    832:        for (i=0, fail=0; i<monsters[tp->t_index].m_numsum; i++) {
                    833:             if (!creat_mons(&player, which, FALSE))
                    834:                 fail++;        /* remember the failures */
                    835:        }
                    836:        /*
                    837:         * try once again to make the buggers
                    838:         */
                    839:        for (i=0; i<fail; i++)
                    840:             creat_mons(tp, which, FALSE);
                    841:
                    842:        /* Now let the poor fellow see all the trouble */
                    843:        light(&hero);
                    844:     }
                    845:
                    846:     /*
                    847:      * Handle monsters that can gaze and do things while running
                    848:      * Player must be able to see the monster and the monster must
                    849:      * not be asleep
                    850:      */
                    851:     if (nasty && !invisible(tp)) {
                    852:        /*
                    853:         * Confusion
                    854:         */
                    855:        if (on(*tp, CANHUH)                              &&
                    856:           (off(*tp, ISINVIS)     || on(player, CANSEE)) &&
                    857:           (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) {
                    858:            if (!save(VS_MAGIC, &player, 0)) {
                    859:                if (off(player, ISCLEAR)) {
                    860:                    if (find_slot(unconfuse))
                    861:                        lengthen(unconfuse, rnd(20)+HUHDURATION);
                    862:                    else {
                    863:                        fuse(unconfuse, 0, rnd(20)+HUHDURATION, AFTER);
                    864:                        msg("The %s's gaze has confused you.",mname);
                    865:                        turn_on(player, ISHUH);
                    866:                    }
                    867:                }
                    868:                else msg("You feel dizzy for a moment, but it quickly passes.");
                    869:            }
                    870:            else if (rnd(100) < 67)
                    871:                turn_off(*tp, CANHUH); /* Once you save, maybe that's it */
                    872:        }
                    873:
                    874:        /* Sleep */
                    875:        if(on(*tp, CANSNORE) &&
                    876:           no_command == 0 &&
                    877:           !save(VS_PARALYZATION, &player, 0)) {
                    878:            if (ISWEARING(R_ALERT))
                    879:                msg("You feel slightly drowsy for a moment.");
                    880:            else {
                    881:                msg("The %s's gaze puts you to sleep.", mname);
                    882:                no_command += SLEEPTIME;
                    883:                if (rnd(100) < 50) turn_off(*tp, CANSNORE);
                    884:            }
                    885:        }
                    886:
                    887:        /* Fear */
                    888:        if (on(*tp, CANFRIGHTEN)) {
                    889:            turn_off(*tp, CANFRIGHTEN);
                    890:            if (!ISWEARING(R_HEROISM)           &&
                    891:                !save(VS_WAND, &player, 0)      &&
                    892:                !(on(player, ISFLEE) && (player.t_dest == &tp->t_pos))) {
                    893:                    turn_on(player, ISFLEE);
                    894:                    player.t_dest = &tp->t_pos;
                    895:                    msg("The sight of the %s terrifies you.", mname);
                    896:            }
                    897:        }
                    898:
                    899:        /* blinding creatures */
                    900:        if(on(*tp, CANBLIND) &&
                    901:           !find_slot(sight) &&
                    902:           !save(VS_WAND,&player, 0)){
                    903:            msg("The gaze of the %s blinds you", mname);
                    904:            turn_on(player, ISBLIND);
                    905:            fuse(sight, 0, rnd(30)+20, AFTER);
                    906:            light(&hero);
                    907:        }
                    908:
                    909:        /* the sight of the ghost can age you! */
                    910:        if (on(*tp, CANAGE)) {
                    911:            turn_off (*tp, CANAGE);
                    912:            if (!save(VS_MAGIC, &player, 0)) {
                    913:                msg ("The sight of the %s ages you!", mname);
                    914:                pstats.s_const--;
                    915:                max_stats.s_const--;
                    916:                if (pstats.s_const < 0)
                    917:                    death (D_CONSTITUTION);
                    918:            }
                    919:        }
                    920:
                    921:
                    922:        /* Turning to stone */
                    923:        if (on(*tp, LOOKSTONE)) {
                    924:            turn_off(*tp, LOOKSTONE);
                    925:
                    926:            if (on(player, CANINWALL))
                    927:                msg("The gaze of the %s has no effect.", mname);
                    928:            else {
                    929:                if (!save(VS_PETRIFICATION, &player, 0) && rnd(100) < 15) {
                    930:                    pstats.s_hpt = -1;
                    931:                    msg("The gaze of the %s petrifies you.", mname);
                    932:                    msg("You are turned to stone !!! --More--");
                    933:                    wait_for(cw,' ');
                    934:                    death(D_PETRIFY);
                    935:                }
                    936:                else {
                    937:                    msg("The gaze of the %s stiffens your limbs.", mname);
                    938:                    no_command += STONETIME;
                    939:                }
                    940:            }
                    941:        }
                    942:     }
                    943:
                    944:     return it;
                    945: }
                    946: /*
                    947:  * wanderer:
                    948:  *     A wandering monster has awakened and is headed for the player
                    949:  */
                    950:
                    951: void
                    952: wanderer(void)
                    953: {
                    954:     register int i;
                    955:     register struct room *hr = roomin(&hero);
                    956:     register struct linked_list *item;
                    957:     register struct thing *tp;
                    958:     register const long *attr; /* Points to monsters' attributes */
                    959:     int carry; /* Chance of wanderer carrying anything */
                    960:     short rmonst;      /* Our random wanderer */
                    961:     bool canteleport = FALSE,  /* Can the monster teleport? */
                    962:         seehim;        /* Is monster within sight? */
                    963:     coord cp;
                    964:
                    965:     rmonst = randmonster(TRUE, FALSE); /* Choose a random wanderer */
                    966:     attr = &monsters[rmonst].m_flags[0]; /* Start of attributes */
                    967:     for (i=0; i<MAXFLAGS; i++)
                    968:        if (*attr++ == CANTELEPORT) {
                    969:            canteleport = TRUE;
                    970:            break;
                    971:        }
                    972:
                    973:     /* Find a place for it -- avoid the player's room if can't teleport */
                    974:     do {
                    975:        do {
                    976:            i = rnd_room();
                    977:        } until (canteleport || hr != &rooms[i] || levtype == MAZELEV ||
                    978:                 levtype == OUTSIDE || levtype == POSTLEV);
                    979:
                    980:        /* Make sure the monster does not teleport on top of the player */
                    981:        do {
                    982:            rnd_pos(&rooms[i], &cp);
                    983:        } while (hr == &rooms[i] && ce(cp, hero));
                    984:     } until (step_ok(cp.y, cp.x, NOMONST, NULL));
                    985:
                    986:     /* Create a new wandering monster */
                    987:     item = new_item(sizeof *tp);
                    988:     new_monster(item, rmonst, &cp, FALSE);
                    989:     tp = THINGPTR(item);
                    990:     turn_on(*tp, ISRUN);
                    991:     turn_off(*tp, ISDISGUISE);
                    992:     tp->t_dest = &hero;
                    993:     tp->t_pos = cp;    /* Assign the position to the monster */
                    994:     seehim = cansee(tp->t_pos.y, tp->t_pos.x);
                    995:     if (on(*tp, HASFIRE)) {
                    996:        register struct room *rp;
                    997:
                    998:        rp = roomin(&tp->t_pos);
                    999:        if (rp) {
                   1000:            register struct linked_list *fire_item;
                   1001:
                   1002:            fire_item = creat_item();
                   1003:            ldata(fire_item) = (char *) tp;
                   1004:            attach(rp->r_fires, fire_item);
                   1005:
                   1006:            rp->r_flags |= HASFIRE;
                   1007:            if (seehim && next(rp->r_fires) == NULL)
                   1008:                light(&hero);
                   1009:        }
                   1010:     }
                   1011:
                   1012:     /* See if we give the monster anything */
                   1013:     carry = monsters[tp->t_index].m_carry;
                   1014:     if (off(*tp, ISUNIQUE)) carry /= 2;        /* Non-unique has only a half chance */
                   1015:     carry_obj(tp, carry);
                   1016:
                   1017:     /* Alert the player if a monster just teleported in */
                   1018:     if (hr == &rooms[i] && canteleport && seehim && !invisible(tp)) {
                   1019:        msg("A %s just teleported in", monsters[rmonst].m_name);
                   1020:        light(&hero);
                   1021:        running = FALSE;
                   1022:     }
                   1023:
                   1024:     if (wizard)
                   1025:        msg("Started a wandering %s", monsters[tp->t_index].m_name);
                   1026: }

CVSweb