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

Annotation of early-roguelike/xrogue/monsters.c, Revision 1.1

1.1     ! rubenllo    1: /*
        !             2:     monsters.c - File with various monster functions in it
        !             3:
        !             4:     XRogue: Expeditions into the Dungeons of Doom
        !             5:     Copyright (C) 1991 Robert Pietkivitch
        !             6:     All rights reserved.
        !             7:
        !             8:     Based on "Advanced Rogue"
        !             9:     Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
        !            10:     All rights reserved.
        !            11:
        !            12:     Based on "Rogue: Exploring the Dungeons of Doom"
        !            13:     Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
        !            14:     All rights reserved.
        !            15:
        !            16:     See the file LICENSE.TXT for full copyright and licensing information.
        !            17: */
        !            18:
        !            19: #include <curses.h>
        !            20: #include <ctype.h>
        !            21: #include <string.h>
        !            22: #include <stdlib.h>
        !            23: #include "rogue.h"
        !            24:
        !            25: /*
        !            26:  * Check_residue takes care of any effect of the monster
        !            27:  */
        !            28:
        !            29: void
        !            30: check_residue(struct thing *tp)
        !            31: {
        !            32:     /*
        !            33:      * Take care of special abilities
        !            34:      */
        !            35:     if (on(*tp, DIDHOLD) && (--hold_count == 0)) {
        !            36:         turn_off(player, ISHELD);
        !            37:         turn_off(*tp, DIDHOLD);
        !            38:     }
        !            39:
        !            40:     /* If frightened of this monster, stop */
        !            41:     if (on(player, ISFLEE) &&
        !            42:         player.t_dest == &tp->t_pos) turn_off(player, ISFLEE);
        !            43:
        !            44:     /* If monster was suffocating player, stop it */
        !            45:     if (on(*tp, DIDSUFFOCATE)) {
        !            46:         extinguish(suffocate);
        !            47:         turn_off(*tp, DIDSUFFOCATE);
        !            48:     }
        !            49:
        !            50:     /* If something with fire, may darken */
        !            51:     if (on(*tp, HASFIRE)) {
        !            52:         register struct room *rp=roomin(&tp->t_pos);
        !            53:         register struct linked_list *fire_item;
        !            54:
        !            55:         if (rp) {
        !            56:             for (fire_item = rp->r_fires; fire_item != NULL;
        !            57:                  fire_item = next(fire_item)) {
        !            58:                 if (THINGPTR(fire_item) == tp) {
        !            59:                     detach(rp->r_fires, fire_item);
        !            60:                     destroy_item(fire_item);
        !            61:                     if (rp->r_fires == NULL) {
        !            62:                         rp->r_flags &= ~HASFIRE;
        !            63:                         if (cansee(tp->t_pos.y, tp->t_pos.x)) light(&hero);
        !            64:                     }
        !            65:                     break;
        !            66:                 }
        !            67:             }
        !            68:         }
        !            69:     }
        !            70: }
        !            71:
        !            72: /*
        !            73:  * Creat_mons creates the specified monster -- any if 0
        !            74:  * person: where to create next to
        !            75:  */
        !            76:
        !            77: bool
        !            78: creat_mons(struct thing *person, short monster, bool report)
        !            79: {
        !            80:     struct linked_list *nitem;
        !            81:     register struct thing *tp;
        !            82:     struct room *rp;
        !            83:     coord *mp;
        !            84:
        !            85:     if (levtype == POSTLEV)
        !            86:         return(FALSE);
        !            87:     if ((mp = fallpos(&(person->t_pos), FALSE, 2)) != NULL) {
        !            88:         nitem = new_item(sizeof (struct thing));
        !            89:         new_monster(nitem,
        !            90:                     monster == 0 ? randmonster(FALSE, FALSE)
        !            91:                                  : monster,
        !            92:                     mp,
        !            93:                     TRUE);
        !            94:         tp = THINGPTR(nitem);
        !            95:         runto(tp, &hero);
        !            96:         carry_obj(tp, monsters[tp->t_index].m_carry/2); /* only half chance */
        !            97:
        !            98:         /* since it just got here, it is disoriented */
        !            99:         tp->t_no_move = 2 * movement(tp);
        !           100:
        !           101:         if (on(*tp, HASFIRE)) {
        !           102:             rp = roomin(&tp->t_pos);
        !           103:             if (rp) {
        !           104:                 register struct linked_list *fire_item;
        !           105:
        !           106:                 /* Put the new fellow in the room list */
        !           107:                 fire_item = creat_item();
        !           108:                 ldata(fire_item) = (char *) tp;
        !           109:                 attach(rp->r_fires, fire_item);
        !           110:
        !           111:                 rp->r_flags |= HASFIRE;
        !           112:             }
        !           113:         }
        !           114:
        !           115:         /*
        !           116:          * If we can see this monster, set oldch to ' ' to make light()
        !           117:          * think the creature used to be invisible (ie. not seen here)
        !           118:          */
        !           119:         if (cansee(tp->t_pos.y, tp->t_pos.x)) tp->t_oldch = ' ';
        !           120:         return(TRUE);
        !           121:     }
        !           122:     if (report) msg("You hear a faint cry of anguish in the distance.. ");
        !           123:     return(FALSE);
        !           124: }
        !           125:
        !           126: /*
        !           127:  * Genmonsters:
        !           128:  *      Generate at least 'least' monsters for this single room level.
        !           129:  *      'Treas' indicates whether this is a "treasure" level.
        !           130:  */
        !           131:
        !           132: void
        !           133: genmonsters(int least, bool treas)
        !           134: {
        !           135:     reg int i;
        !           136:     reg struct room *rp = &rooms[0];
        !           137:     reg struct linked_list *item;
        !           138:     reg struct thing *mp;
        !           139:     coord tp;
        !           140:
        !           141:     for (i = 0; i < (max(50, level) + least); i++) {
        !           142:             if (!treas && rnd(100) < 65)        /* put in some little buggers */
        !           143:                 continue;
        !           144:
        !           145:             /*
        !           146:              * Put the monster in
        !           147:              */
        !           148:             item = new_item(sizeof *mp);
        !           149:             mp = THINGPTR(item);
        !           150:             do {
        !           151:                     rnd_pos(rp, &tp);
        !           152:             } until(mvwinch(stdscr, tp.y, tp.x) == FLOOR);
        !           153:
        !           154:             new_monster(item, randmonster(FALSE, FALSE), &tp, FALSE);
        !           155:             /*
        !           156:              * See if we want to give it a treasure to carry around.
        !           157:              */
        !           158:             carry_obj(mp, monsters[mp->t_index].m_carry);
        !           159:
        !           160:             /* Calculate a movement rate */
        !           161:             mp->t_no_move = movement(mp);
        !           162:
        !           163:             /* Is it going to give us some light? */
        !           164:             if (on(*mp, HASFIRE)) {
        !           165:                 register struct linked_list *fire_item;
        !           166:
        !           167:                 fire_item = creat_item();
        !           168:                 ldata(fire_item) = (char *) mp;
        !           169:                 attach(rp->r_fires, fire_item);
        !           170:                 rp->r_flags |= HASFIRE;
        !           171:             }
        !           172:     }
        !           173: }
        !           174:
        !           175: /*
        !           176:  * id_monst returns the index of the monster given its letter
        !           177:  */
        !           178:
        !           179: short
        !           180: id_monst(char monster)
        !           181: {
        !           182:     register short result;
        !           183:
        !           184:     if (levtype == OUTSIDE) {
        !           185:         result = NLEVMONS*vlevel + (NUMMONST-NUMDINOS-1);
        !           186:         if (result > NUMMONST) result = NUMMONST;
        !           187:     }
        !           188:     else {
        !           189:         result = NLEVMONS*vlevel;
        !           190:         if (result > NUMMONST-NUMDINOS) result = NUMMONST-NUMDINOS;
        !           191:     }
        !           192:
        !           193:     if (levtype == OUTSIDE) {
        !           194:         for(; result>(NUMMONST-NUMDINOS-1); result--)
        !           195:             if (monsters[result].m_appear == monster) return(result);
        !           196:         for (result=(NLEVMONS*vlevel)+1; result <= NUMMONST-NUMDINOS; result++)
        !           197:             if (monsters[result].m_appear == monster) return(result);
        !           198:     }
        !           199:     else {
        !           200:         for(; result>0; result--)
        !           201:             if (monsters[result].m_appear == monster) return(result);
        !           202:         for (result=(NLEVMONS*vlevel)+1; result <= NUMMONST; result++)
        !           203:             if (monsters[result].m_appear == monster) return(result);
        !           204:     }
        !           205:     return(0);
        !           206: }
        !           207:
        !           208:
        !           209: /*
        !           210:  * new_monster:
        !           211:  *      Pick a new monster and add it to the list
        !           212:  */
        !           213:
        !           214: void
        !           215: new_monster(struct linked_list *item, short type, coord *cp, bool max_monster)
        !           216: {
        !           217:     register struct thing *tp;
        !           218:     register struct monster *mp;
        !           219:     register char *ip, *hitp;
        !           220:     register int i, min_intel, max_intel;
        !           221:     register int num_dice, num_sides=8, num_extra=0;
        !           222:
        !           223:     attach(mlist, item);
        !           224:     tp = THINGPTR(item);
        !           225:     tp->t_pack = NULL;
        !           226:     tp->t_index = type;
        !           227:     tp->t_wasshot = FALSE;
        !           228:     tp->t_type = monsters[type].m_appear;
        !           229:     tp->t_ctype = C_MONSTER;
        !           230:     tp->t_action = A_NIL;
        !           231:     tp->t_doorgoal.x = tp->t_doorgoal.y = -1;
        !           232:     tp->t_quiet = 0;
        !           233:     tp->t_dest = NULL;
        !           234:     tp->t_name = NULL;
        !           235:     tp->t_pos = tp->t_oldpos = *cp;
        !           236:     tp->t_oldch = mvwinch(cw, cp->y, cp->x);
        !           237:     mvwaddch(mw, cp->y, cp->x, tp->t_type);
        !           238:     mp = &monsters[tp->t_index];
        !           239:
        !           240:     /* Figure out monster's hit points */
        !           241:     hitp = mp->m_stats.ms_hpt;
        !           242:     num_dice = atoi(hitp);
        !           243:     if ((hitp = strchr(hitp, 'd')) != NULL) {
        !           244:         num_sides = atoi(++hitp);
        !           245:         if ((hitp = strchr(hitp, '+')) != NULL)
        !           246:             num_extra = atoi(++hitp);
        !           247:     }
        !           248:
        !           249:     tp->t_stats.s_lvladj = 0;
        !           250:     tp->t_stats.s_lvl = mp->m_stats.ms_lvl;
        !           251:     tp->t_stats.s_arm = mp->m_stats.ms_arm;
        !           252:     strcpy(tp->t_stats.s_dmg,mp->m_stats.ms_dmg);
        !           253:     tp->t_stats.s_str = mp->m_stats.ms_str;
        !           254:     tp->t_stats.s_dext = mp->m_stats.ms_dex;
        !           255:     tp->t_movement = mp->m_stats.ms_move;
        !           256:     if (vlevel > HARDER) { /* the deeper, the meaner we get */
        !           257:          tp->t_stats.s_lvl += (vlevel - HARDER);
        !           258:          num_dice += (vlevel - HARDER)/2;
        !           259:          tp->t_stats.s_arm -= (vlevel - HARDER) / 4;
        !           260:     }
        !           261:     if (max_monster)
        !           262:         tp->t_stats.s_hpt = num_dice * num_sides + num_extra;
        !           263:     else
        !           264:         tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra;
        !           265:     tp->t_stats.s_exp = mp->m_stats.ms_exp + mp->m_add_exp*tp->t_stats.s_hpt;
        !           266:
        !           267:     /*
        !           268:      * just initailize others values to something reasonable for now
        !           269:      * maybe someday will *really* put these in monster table
        !           270:      */
        !           271:     tp->t_stats.s_wisdom = 8 + rnd(7);
        !           272:     tp->t_stats.s_const = 8 + rnd(7);
        !           273:     tp->t_stats.s_charisma = 8 + rnd(7);
        !           274:
        !           275:     /* Set the initial flags */
        !           276:     for (i=0; i<16; i++) tp->t_flags[i] = 0;
        !           277:     for (i=0; i<MAXFLAGS; i++)
        !           278:         turn_on(*tp, mp->m_flags[i]);
        !           279:
        !           280:     /*
        !           281:      * these are the base chances that a creatures will do something
        !           282:      * assuming it can. These are(or can be) modified at runtime
        !           283:      * based on what the creature experiences
        !           284:      */
        !           285:     tp->t_breathe = 70;         /* base chance of breathing */
        !           286:     tp->t_artifact = 90;        /* base chance of using artifact */
        !           287:     tp->t_summon = 50;          /* base chance of summoning */
        !           288:     tp->t_cast = 70;            /* base chance of casting a spell */
        !           289:     tp->t_wand = on(*tp, ISUNIQUE) ? 35 : 50;   /* base chance of using wands */
        !           290:
        !           291:     /* suprising monsters don't always surprise you */
        !           292:     if (!max_monster            && on(*tp, CANSURPRISE) &&
        !           293:         off(*tp, ISUNIQUE)      && rnd(100) < 25)
        !           294:             turn_off(*tp, CANSURPRISE);
        !           295:
        !           296:     /* If this monster is unique, gen it */
        !           297:     if (on(*tp, ISUNIQUE)) mp->m_normal = FALSE;
        !           298:
        !           299:     /*
        !           300:      * If it is the quartermaster, then compute his level and exp pts
        !           301:      * based on the level. This will make it fair when thieves try to
        !           302:      * steal and give them reasonable experience if they succeed.
        !           303:      * Then fill his pack with his wares.
        !           304:      */
        !           305:     if (on(*tp, CANSELL)) {
        !           306:         tp->t_stats.s_exp = vlevel * 100;
        !           307:         tp->t_stats.s_lvl = vlevel/2 + 1;
        !           308:         make_sell_pack(tp);
        !           309:     }
        !           310:
        !           311:     /* Normally scared monsters have a chance to not be scared */
        !           312:     if (on(*tp, ISFLEE) && (rnd(4) == 0)) turn_off(*tp, ISFLEE);
        !           313:
        !           314:     /* Figure intelligence */
        !           315:     min_intel = atoi(mp->m_intel);
        !           316:     if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL)
        !           317:         tp->t_stats.s_intel = min_intel;
        !           318:     else {
        !           319:         max_intel = atoi(++ip);
        !           320:         if (max_monster)
        !           321:             tp->t_stats.s_intel = max_intel;
        !           322:         else
        !           323:             tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel);
        !           324:     }
        !           325:     if (vlevel > HARDER)
        !           326:          tp->t_stats.s_intel += ((vlevel - HARDER)/2);
        !           327:     tp->maxstats = tp->t_stats;
        !           328:
        !           329:     /* If the monster can shoot, it may have a weapon */
        !           330:     if (on(*tp, CANSHOOT) && ((rnd(100) < (20 + vlevel)) || max_monster)) {
        !           331:         struct linked_list *item1;
        !           332:         register struct object *cur, *cur1;
        !           333:
        !           334:         item = new_item(sizeof *cur);
        !           335:         item1 = new_item(sizeof *cur1);
        !           336:         cur = OBJPTR(item);
        !           337:         cur1 = OBJPTR(item1);
        !           338:         cur->o_hplus = (rnd(4) < 3) ? 0
        !           339:                                     : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
        !           340:         cur->o_dplus = (rnd(4) < 3) ? 0
        !           341:                                     : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
        !           342:         cur1->o_hplus = (rnd(4) < 3) ? 0
        !           343:                                     : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
        !           344:         cur1->o_dplus = (rnd(4) < 3) ? 0
        !           345:                                     : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
        !           346:         strcpy(cur->o_damage,"0d0");
        !           347:         strcpy(cur->o_hurldmg,"0d0");
        !           348:         strcpy(cur1->o_damage,"0d0");
        !           349:         strcpy(cur1->o_hurldmg,"0d0");
        !           350:         cur->o_ac = cur1->o_ac = 11;
        !           351:         cur->o_count = cur1->o_count = 1;
        !           352:         cur->o_group = cur1->o_group = 0;
        !           353:         cur->contents = cur1->contents = NULL;
        !           354:         if ((cur->o_hplus <= 0) && (cur->o_dplus <= 0)) cur->o_flags = ISCURSED;
        !           355:         if ((cur1->o_hplus <= 0) && (cur1->o_dplus <= 0))
        !           356:             cur1->o_flags = ISCURSED;
        !           357:         cur->o_flags = cur1->o_flags = 0;
        !           358:         cur->o_type = cur1->o_type = WEAPON;
        !           359:         cur->o_mark[0] = cur1->o_mark[0] = '\0';
        !           360:
        !           361:         /* The monster may use a crossbow, sling, or an arrow */
        !           362:         i = rnd(100);
        !           363:         if (i < 35) {
        !           364:             cur->o_which = CROSSBOW;
        !           365:             cur1->o_which = BOLT;
        !           366:             init_weapon(cur, CROSSBOW);
        !           367:             init_weapon(cur1, BOLT);
        !           368:         }
        !           369:         else if (i < 70) {
        !           370:             cur->o_which = BOW;
        !           371:             cur1->o_which = ARROW;
        !           372:             init_weapon(cur, BOW);
        !           373:             init_weapon(cur1, ARROW);
        !           374:         }
        !           375:         else {
        !           376:             cur->o_which = SLING;
        !           377:             cur1->o_which = ROCK;
        !           378:             init_weapon(cur, SLING);
        !           379:             init_weapon(cur1, ROCK);
        !           380:         }
        !           381:
        !           382:         attach(tp->t_pack, item);
        !           383:         attach(tp->t_pack, item1);
        !           384:     }
        !           385:
        !           386:
        !           387:     /* Calculate the initial movement rate */
        !           388:     updpack(TRUE, tp);
        !           389:     tp->t_no_move = movement(tp);
        !           390:
        !           391:     if (ISWEARING(R_AGGR))
        !           392:         runto(tp, &hero);
        !           393:
        !           394:     if (on(*tp, ISDISGUISE))
        !           395:     {
        !           396:         char mch = 0;
        !           397:
        !           398:         if (tp->t_pack != NULL)
        !           399:             mch = (OBJPTR(tp->t_pack))->o_type;
        !           400:         else
        !           401:             switch (rnd(10)) {
        !           402:                 case 0: mch = GOLD;
        !           403:                 when 1: mch = POTION;
        !           404:                 when 2: mch = SCROLL;
        !           405:                 when 3: mch = FOOD;
        !           406:                 when 4: mch = WEAPON;
        !           407:                 when 5: mch = ARMOR;
        !           408:                 when 6: mch = RING;
        !           409:                 when 7: mch = STICK;
        !           410:                 when 8: mch = monsters[randmonster(FALSE, FALSE)].m_appear;
        !           411:                 when 9: mch = MM;
        !           412:             }
        !           413:         tp->t_disguise = mch;
        !           414:     }
        !           415: }
        !           416:
        !           417: /*
        !           418:  * randmonster:
        !           419:  *      Pick a monster to show up.  The lower the level,
        !           420:  *      the meaner the monster.
        !           421:  */
        !           422:
        !           423: short
        !           424: randmonster(bool wander, bool no_unique)
        !           425: {
        !           426:     register int d, cur_level, range, i;
        !           427:
        !           428:     /*
        !           429:      * Do we want a merchant? Merchant is always in place 'NUMMONST'
        !           430:      */
        !           431:     if (wander && monsters[NUMMONST].m_wander && rnd(100) < pstats.s_charisma/3)
        !           432:         return NUMMONST;
        !           433:
        !           434:     cur_level = vlevel;
        !           435:     range = (4*NLEVMONS)+1;  /* range is 0 thru 12 */
        !           436:     i = 0;
        !           437:     do
        !           438:     {
        !           439:         if (i++ > NUMMONST-1) {    /* in case all have be genocided */
        !           440:             i = 0;
        !           441:             if (--cur_level <= 0)
        !           442:                 fatal("rogue: Could not find a monster to make! ");
        !           443:         }
        !           444:         if (levtype == OUTSIDE) {                 /* create DINOSUARS */
        !           445:             d = (cur_level - rnd(range/2)) + (NUMMONST-NUMDINOS-1);
        !           446:             if (d < NUMMONST-NUMDINOS)
        !           447:                 d = (NUMMONST-NUMDINOS) + rnd(range/2);
        !           448:             if (d > NUMMONST-1)
        !           449:                 d = (NUMMONST-NUMDINOS) + rnd(NUMDINOS);
        !           450:         }
        !           451:         else {           /* Create NORMALs and UNIQs here */
        !           452:             d = (NLEVMONS*(cur_level-1) + rnd(range) - (range-NLEVMONS-1));
        !           453:             if (d < 1) d = rnd(6)+1;
        !           454:
        !           455:             if (d > NUMMONST-NUMDINOS-1) {    /* Entire range NORMs + UNIQs */
        !           456:         if (no_unique)   /* Choose from last 12 NORMAL monsters */
        !           457:                     d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) - rnd(NUMUNIQUE/5);
        !           458:         else             /* Choose from entire UNIQ monsters + range */
        !           459:             d = (NUMMONST-NUMDINOS-1) - rnd(NUMUNIQUE+range);
        !           460:             }
        !           461:                      /* Half-way into the UNIQs now */
        !           462:             else if (d > (NUMMONST-NUMDINOS-(NUMUNIQUE/2)-1)) {
        !           463:         if (no_unique)   /* Choose from last 15 NORMAL monsters */
        !           464:                     d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) - rnd(NUMUNIQUE/4);
        !           465:         else             /* Choose from entire UNIQ monsters + range */
        !           466:                     d = (NUMMONST-NUMDINOS-1) - rnd(NUMUNIQUE+range);
        !           467:         }
        !           468:                      /* End NORMALs and begin relic bearing UNIQs */
        !           469:             else if (d > (NUMMONST-NUMDINOS-NUMUNIQUE-1)) {
        !           470:         if (no_unique)   /* Choose from last 20 NORMAL monsters */
        !           471:                     d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) - rnd(NUMUNIQUE/3);
        !           472:         else             /* Choose from first 20 UNIQ monsters */
        !           473:                     d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) + rnd(NUMUNIQUE/3);
        !           474:         }
        !           475:         }
        !           476:     }
        !           477:     while  (wander ? !monsters[d].m_wander || !monsters[d].m_normal
        !           478:                    : !monsters[d].m_normal);
        !           479:     return d;
        !           480: }
        !           481:
        !           482: /* Sell displays a menu of goods from which the player may choose
        !           483:  * to purchase something.
        !           484:  */
        !           485:
        !           486: void
        !           487: sell(struct thing *tp)
        !           488: {
        !           489:     register struct linked_list *item, *seller;
        !           490:     register struct linked_list *sellpack;
        !           491:     register struct object *obj;
        !           492:     register long worth, min_worth;
        !           493:     char buffer[LINELEN];
        !           494:
        !           495:     /*
        !           496:      * Get a linked_list pointer to the seller.  We need this in case
        !           497:      * he disappears so we can set him ISDEAD.
        !           498:      */
        !           499:     seller = find_mons(tp->t_pos.y, tp->t_pos.x);
        !           500:
        !           501:     sellpack = tp->t_pack;
        !           502:     if (sellpack == NULL) {
        !           503:         msg("%s looks puzzled and departs.", prname(monster_name(tp), TRUE));
        !           504:
        !           505:         /* Get rid of the monster */
        !           506:         killed(seller, FALSE, FALSE, FALSE);
        !           507:         return;
        !           508:     }
        !           509:
        !           510:     /* See how much the minimum pack item is worth */
        !           511:     min_worth = 100000;
        !           512:     for (item = sellpack; item != NULL; item = next(item)) {
        !           513:         obj = OBJPTR(item);
        !           514:         obj->o_flags |= ISPOST; /* Force a long description of the item */
        !           515:         worth = get_worth(obj);
        !           516:         if (worth < min_worth) min_worth = worth;
        !           517:     }
        !           518:
        !           519:     /* See if player can afford an item */
        !           520:     if (min_worth > purse) {
        !           521:         msg("%s eyes your small purse and departs.",
        !           522:             prname(monster_name(tp), TRUE));
        !           523:
        !           524:         /* Get rid of the monster */
        !           525:         killed(seller, FALSE, FALSE, FALSE);
        !           526:         return;
        !           527:     }
        !           528:
        !           529:     /* Announce our intentions */
        !           530:     msg("%s opens his pack.  --More--", prname(monster_name(tp), TRUE));
        !           531:     wait_for(' ');
        !           532:
        !           533:     /* Try to sell something */
        !           534:     sprintf(buffer, "You got %ld gold pieces.  Buy", purse);
        !           535:     item = get_item(sellpack, buffer, ALL, TRUE, TRUE);
        !           536:
        !           537:     /* Get rid of the monster */
        !           538:     if (item != NULL) detach(tp->t_pack, item); /* Take it out of the pack */
        !           539:     killed(seller, FALSE, FALSE, FALSE);
        !           540:
        !           541:     if (item == NULL) return;
        !           542:
        !           543:     /* Can he afford the selected item? */
        !           544:     obj = OBJPTR(item);
        !           545:
        !           546:     worth = get_worth(obj);
        !           547:     if (worth > purse) {
        !           548:         msg("You cannot afford it.");
        !           549:         o_discard(item);
        !           550:         return;
        !           551:     }
        !           552:
        !           553:     /* Charge him through the nose */
        !           554:     purse -= worth;
        !           555:
        !           556:     /* If a stick or ring, let player know the type */
        !           557:     switch (obj->o_type) {
        !           558:         case RING:   r_know[obj->o_which]  = TRUE;
        !           559:         when POTION: p_know[obj->o_which]  = TRUE;
        !           560:         when SCROLL: s_know[obj->o_which]  = TRUE;
        !           561:         when STICK:  ws_know[obj->o_which] = TRUE;
        !           562:         when MM:     m_know[obj->o_which]  = TRUE;
        !           563:
        !           564:     }
        !           565:
        !           566:     /* identify it */
        !           567:     whatis (item);
        !           568:
        !           569:     /* Remove the POST flag that we used for get_item() */
        !           570:     obj->o_flags &= ~ISPOST;
        !           571:
        !           572:     if (add_pack(item, FALSE) == FALSE) {
        !           573:         obj->o_pos = hero;
        !           574:         fall(item, TRUE);
        !           575:     }
        !           576: }
        !           577:
        !           578: /*
        !           579:  * what to do when the hero steps next to a monster
        !           580:  */
        !           581:
        !           582: struct linked_list *
        !           583: wake_monster(int y, int x)
        !           584: {
        !           585:     register struct thing *tp;
        !           586:     register struct linked_list *it;
        !           587:     register struct room *trp;
        !           588:     register char *mname;
        !           589:     bool nasty; /* Will the monster "attack"? */
        !           590:
        !           591:     if ((it = find_mons(y, x)) == NULL) {
        !           592:         msg("Wake:  can't find monster in show (%d, %d)", y, x);
        !           593:         return (NULL);
        !           594:     }
        !           595:     tp = THINGPTR(it);
        !           596:     if (on(*tp, ISSTONE)) /* if stoned, don't do anything */
        !           597:         return it;
        !           598:
        !           599:     /*
        !           600:      * For now, if we are a friendly monster, we won't do any of
        !           601:      * our special effects.
        !           602:      */
        !           603:     if (on(*tp, ISFRIENDLY)) return it;
        !           604:
        !           605:     trp = roomin(&tp->t_pos); /* Current room for monster */
        !           606:
        !           607:     /*
        !           608:      * Let greedy ones in a room guard gold
        !           609:      * (except in a maze where lots of creatures would all go for the
        !           610:      * same piece of gold)
        !           611:      */
        !           612:     if (on(*tp, ISGREED) && off(*tp, ISRUN) && levtype != MAZELEV &&
        !           613:     trp != NULL && lvl_obj != NULL) {
        !           614:             register struct linked_list *item;
        !           615:             register struct object *cur;
        !           616:
        !           617:             for (item = lvl_obj; item != NULL; item = next(item)) {
        !           618:                 cur = OBJPTR(item);
        !           619:                 if ((cur->o_type == GOLD) && (roomin(&cur->o_pos) == trp)) {
        !           620:                     /* Run to the gold */
        !           621:                     runto(tp, &cur->o_pos);
        !           622:
        !           623:                     /* Make it worth protecting */
        !           624:                     cur->o_count += GOLDCALC + GOLDCALC;
        !           625:                     break;
        !           626:                 }
        !           627:             }
        !           628:     }
        !           629:
        !           630:     /*
        !           631:      * Every time he sees mean monster, it might start chasing him
        !           632:      */
        !           633:     if (on(*tp, ISMEAN)  &&
        !           634:         off(*tp, ISHELD) &&
        !           635:         off(*tp, ISRUN)  &&
        !           636:         rnd(100) > 35    &&
        !           637:         (!is_stealth(&player) || (on(*tp, ISUNIQUE) && rnd(100) > 35)) &&
        !           638:         (off(player, ISINVIS) || on(*tp, CANSEE)) ||
        !           639:         (trp != NULL && (trp->r_flags & ISTREAS))) {
        !           640:         runto(tp, &hero);
        !           641:     }
        !           642:
        !           643:     /*
        !           644:      * Get the name; we don't want to do it until here because we need to
        !           645:      * know whether the monster is still sleeping or not.
        !           646:      */
        !           647:     mname = monster_name(tp);
        !           648:
        !           649:     /* See if the monster will bother the player */
        !           650:     nasty = (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x));
        !           651:
        !           652:     /*
        !           653:      * if the creature is awake and can see the player and the
        !           654:      * player has the dreaded "eye of vecna" then see if the
        !           655:      * creature is turned to stone
        !           656:      */
        !           657:     if (cur_relic[EYE_VECNA] && nasty && off(*tp, NOSTONE) &&
        !           658:         (off(player, ISINVIS) || on(*tp, CANSEE))) {
        !           659:         turn_on(*tp, NOSTONE);  /* only have to save once */
        !           660:         if (!save(VS_PETRIFICATION, tp, -2)) {
        !           661:                 turn_on(*tp, ISSTONE);
        !           662:                 turn_off(*tp, ISRUN);
        !           663:                 turn_off(*tp, ISINVIS);
        !           664:                 turn_off(*tp, CANSURPRISE);
        !           665:                 turn_off(*tp, ISDISGUISE);
        !           666:                 msg("%s is turned to stone!", prname(mname, TRUE));
        !           667:                 return it;
        !           668:         }
        !           669:     }
        !           670:
        !           671:     /*
        !           672:      * Handle monsters that can gaze and do things while running
        !           673:      * Player must be able to see the monster and the monster must
        !           674:      * not be asleep
        !           675:      */
        !           676:     if (nasty && !invisible(tp)) {
        !           677:         /*
        !           678:          * Confusion
        !           679:          */
        !           680:         if (on(*tp, CANHUH)                              &&
        !           681:            (off(*tp, ISINVIS)     || on(player, CANSEE)) &&
        !           682:            (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) {
        !           683:             if (!save(VS_MAGIC, &player, 0)) {
        !           684:                 if (off(player, ISCLEAR)) {
        !           685:                     if (find_slot(unconfuse))
        !           686:                         lengthen(unconfuse, HUHDURATION);
        !           687:                     else {
        !           688:                         fuse(unconfuse, NULL, HUHDURATION, AFTER);
        !           689:                         msg("%s's gaze has confused you.",prname(mname, TRUE));
        !           690:                         turn_on(player, ISHUH);
        !           691:                     }
        !           692:                 }
        !           693:                 else msg("You feel dizzy for a moment, but it quickly passes.");
        !           694:             }
        !           695:             else if (rnd(100) < 67)
        !           696:                 turn_off(*tp, CANHUH); /* Once you save, maybe that's it */
        !           697:         }
        !           698:
        !           699:         /* Sleep */
        !           700:         if(on(*tp, CANSNORE) &&
        !           701:            player.t_action != A_FREEZE &&
        !           702:            !save(VS_PARALYZATION, &player, 0)) {
        !           703:             if (ISWEARING(R_ALERT))
        !           704:                 msg("You feel drowsy for a moment.. ");
        !           705:             else {
        !           706:                 msg("%s's gaze puts you to sleep! ", prname(mname, TRUE));
        !           707:                 player.t_no_move += movement(&player) * SLEEPTIME;
        !           708:                 player.t_action = A_FREEZE;
        !           709:                 if (rnd(100) < 50) turn_off(*tp, CANSNORE);
        !           710:             }
        !           711:         }
        !           712:
        !           713:         /* Fear */
        !           714:         if (on(*tp, CANFRIGHTEN) && !on(player, ISFLEE)) {
        !           715:             turn_off(*tp, CANFRIGHTEN);
        !           716:             if (!ISWEARING(R_HEROISM) &&
        !           717:                 !save(VS_WAND, &player, -(tp->t_stats.s_lvl/10))) {
        !           718:                     turn_on(player, ISFLEE);
        !           719:                     player.t_dest = &tp->t_pos;
        !           720:                     msg("The sight of %s terrifies you!", prname(mname, FALSE));
        !           721:             }
        !           722:         }
        !           723:
        !           724:         /* blinding creatures */
        !           725:         if(on(*tp, CANBLIND) && !find_slot(sight)) {
        !           726:             turn_off(*tp, CANBLIND);
        !           727:             if (!save(VS_WAND, &player, 0)) {
        !           728:                 msg("The gaze of %s blinds you! ", prname(mname, FALSE));
        !           729:                 turn_on(player, ISBLIND);
        !           730:                 fuse(sight, NULL, rnd(30)+20, AFTER);
        !           731:                 light(&hero);
        !           732:             }
        !           733:         }
        !           734:
        !           735:         /* the sight of the ghost can age you! */
        !           736:         if (on(*tp, CANAGE)) {
        !           737:             turn_off (*tp, CANAGE);
        !           738:             if (!save(VS_MAGIC, &player, 0)) {
        !           739:                 msg ("The sight of %s ages you!", prname(mname, FALSE));
        !           740:                 pstats.s_const--;
        !           741:                 /* max_stats.s_const--; */
        !           742:                 if (pstats.s_const < 1) {
        !           743:             pstats.s_hpt = -1;
        !           744:                     death (D_CONSTITUTION);
        !           745:         }
        !           746:             }
        !           747:         }
        !           748:
        !           749:         /* Turning to stone */
        !           750:         if (on(*tp, LOOKSTONE)) {
        !           751:             turn_off(*tp, LOOKSTONE);
        !           752:
        !           753:             if (on(player, CANINWALL))
        !           754:                 msg("The gaze of %s has no effect.", prname(mname, FALSE));
        !           755:             else {
        !           756:                 if (!save(VS_PETRIFICATION, &player, 0) && rnd(100) < 5) {
        !           757:                     pstats.s_hpt = -1;
        !           758:                     msg("The gaze of %s petrifies you!", prname(mname, FALSE));
        !           759:                     msg("You are turned to stone!!!  --More--");
        !           760:                     wait_for(' ');
        !           761:                     death(D_PETRIFY);
        !           762:                 }
        !           763:                 else {
        !           764:                     msg("The gaze of %s stiffens your limbs.",
        !           765:                         prname(mname, FALSE));
        !           766:                     player.t_no_move += movement(&player) * STONETIME;
        !           767:                     player.t_action = A_FREEZE;
        !           768:                 }
        !           769:             }
        !           770:         }
        !           771:     }
        !           772:
        !           773:     return it;
        !           774: }
        !           775: /*
        !           776:  * wanderer:
        !           777:  *      A wandering monster has awakened and is headed for the player
        !           778:  */
        !           779:
        !           780: void
        !           781: wanderer(void)
        !           782: {
        !           783:     register int i;
        !           784:     register struct room *hr = roomin(&hero);
        !           785:     register struct linked_list *item;
        !           786:     register struct thing *tp;
        !           787:     register long *attr;        /* Points to monsters' attributes */
        !           788:     int carry;  /* Chance of wanderer carrying anything */
        !           789:     short rmonst;       /* Our random wanderer */
        !           790:     bool canteleport = FALSE,   /* Can the monster teleport? */
        !           791:          seehim;        /* Is monster within sight? */
        !           792:     coord cp;
        !           793:
        !           794:     rmonst = randmonster(TRUE, FALSE);  /* Choose a random wanderer */
        !           795:     attr = &monsters[rmonst].m_flags[0]; /* Start of attributes */
        !           796:     for (i=0; i<MAXFLAGS; i++)
        !           797:         if (*attr++ == CANTELEPORT) {
        !           798:             canteleport = TRUE;
        !           799:             break;
        !           800:         }
        !           801:
        !           802:     /* Find a place for it -- avoid the player's room if can't teleport */
        !           803:     do {
        !           804:         do {
        !           805:             i = rnd_room();
        !           806:         } until (canteleport || hr != &rooms[i] || levtype == MAZELEV ||
        !           807:                  levtype == OUTSIDE);
        !           808:
        !           809:         /* Make sure the monster does not teleport on top of the player */
        !           810:         do {
        !           811:             rnd_pos(&rooms[i], &cp);
        !           812:         } while (hr == &rooms[i] && ce(cp, hero));
        !           813:     } until (step_ok(cp.y, cp.x, NOMONST, (struct thing *)NULL));
        !           814:
        !           815:     /* Create a new wandering monster */
        !           816:     item = new_item(sizeof *tp);
        !           817:     new_monster(item, rmonst, &cp, FALSE);
        !           818:     tp = THINGPTR(item);
        !           819:     runto(tp, &hero);
        !           820:     tp->t_pos = cp;     /* Assign the position to the monster */
        !           821:     seehim = cansee(tp->t_pos.y, tp->t_pos.x);
        !           822:     if (on(*tp, HASFIRE)) {
        !           823:         register struct room *rp;
        !           824:
        !           825:         rp = roomin(&tp->t_pos);
        !           826:         if (rp) {
        !           827:             register struct linked_list *fire_item;
        !           828:
        !           829:             fire_item = creat_item();
        !           830:             ldata(fire_item) = (char *) tp;
        !           831:             attach(rp->r_fires, fire_item);
        !           832:
        !           833:             rp->r_flags |= HASFIRE;
        !           834:             if (seehim && next(rp->r_fires) == NULL)
        !           835:                 light(&hero);
        !           836:         }
        !           837:     }
        !           838:
        !           839:     /* See if we give the monster anything */
        !           840:     carry = monsters[tp->t_index].m_carry;
        !           841:     if (off(*tp, ISUNIQUE)) carry /= 2; /* Non-unique has only a half chance */
        !           842:     carry_obj(tp, carry);
        !           843:
        !           844:     /* Calculate its movement rate */
        !           845:     tp->t_no_move = movement(tp);
        !           846:
        !           847:     /* Alert the player if a monster just teleported in */
        !           848:     if (hr == &rooms[i] && canteleport && seehim && !invisible(tp)) {
        !           849:         msg("A %s just teleported in", monster_name(tp));
        !           850:         light(&hero);
        !           851:         running = FALSE;
        !           852:     }
        !           853:
        !           854:     if (wizard)
        !           855:         msg("Started a wandering %s", monster_name(tp));
        !           856: }
        !           857:

CVSweb