Mercurial > hg > early-roguelike
view arogue5/monsters.c @ 162:600873555ec0
Don't swap signal handlers in md_shellescape().
md_shellescape() sets SIGINT and SIGQUIT to be ignored, storing the
previous handlers, and restores them after the shell exits. But it
mixed up the two handlers.
Since the signals were usually handled by the same function, this fix
doesn't have much effect, but anything that makes signal code less
confusing is a good thing.
author | John "Elwin" Edwards |
---|---|
date | Mon, 08 Jun 2015 10:01:25 -0400 |
parents | 0ed67132cf10 |
children | 56e748983fa8 |
line wrap: on
line source
/* * File with various monster functions in it * * Advanced Rogue * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T * All rights reserved. * * Based on "Rogue: Exploring the Dungeons of Doom" * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman * All rights reserved. * * See the file LICENSE.TXT for full copyright and licensing information. */ #include "curses.h" #include "rogue.h" #include <ctype.h> #include <string.h> /* * Check_residue takes care of any effect of the monster */ check_residue(tp) register struct thing *tp; { /* * Take care of special abilities */ if (on(*tp, DIDHOLD) && (--hold_count == 0)) turn_off(player, ISHELD); /* If it has lowered player, give him back a level */ if (on(*tp, DIDDRAIN)) raise_level(FALSE); /* If frightened of this monster, stop */ if (on(player, ISFLEE) && player.t_dest == &tp->t_pos) turn_off(player, ISFLEE); /* If monster was suffocating player, stop it */ if (on(*tp, DIDSUFFOCATE)) extinguish(suffocate); /* If something with fire, may darken */ if (on(*tp, HASFIRE)) { register struct room *rp=roomin(&tp->t_pos); register struct linked_list *fire_item; if (rp) { for (fire_item = rp->r_fires; fire_item != NULL; fire_item = next(fire_item)) { if (THINGPTR(fire_item) == tp) { detach(rp->r_fires, fire_item); destroy_item(fire_item); if (rp->r_fires == NULL) { rp->r_flags &= ~HASFIRE; if (cansee(tp->t_pos.y, tp->t_pos.x)) light(&hero); } break; } } } } } /* * Creat_mons creates the specified monster -- any if 0 */ bool creat_mons(person, monster, report) struct thing *person; /* Where to create next to */ short monster; bool report; { struct linked_list *nitem; register struct thing *tp; struct room *rp; coord *mp; if (levtype == POSTLEV) return(FALSE); if ((mp = fallpos(&(person->t_pos), FALSE, 2)) != NULL) { nitem = new_item(sizeof (struct thing)); new_monster(nitem, monster == 0 ? randmonster(FALSE, FALSE) : monster, mp, TRUE); tp = THINGPTR(nitem); runto(tp, &hero); tp->t_no_move = 1; /* since it just got here, it is disoriented */ carry_obj(tp, monsters[tp->t_index].m_carry/2); /* only half chance */ if (on(*tp, HASFIRE)) { rp = roomin(&tp->t_pos); if (rp) { register struct linked_list *fire_item; /* Put the new fellow in the room list */ fire_item = creat_item(); ldata(fire_item) = (char *) tp; attach(rp->r_fires, fire_item); rp->r_flags |= HASFIRE; } } /* * If we can see this monster, set oldch to ' ' to make light() * think the creature used to be invisible (ie. not seen here) */ if (cansee(tp->t_pos.y, tp->t_pos.x)) tp->t_oldch = ' '; return(TRUE); } if (report) msg("You hear a faint cry of anguish in the distance."); return(FALSE); } /* * Genmonsters: * Generate at least 'least' monsters for this single room level. * 'Treas' indicates whether this is a "treasure" level. */ void genmonsters(least, treas) register int least; bool treas; { reg int i; reg struct room *rp = &rooms[0]; reg struct linked_list *item; reg struct thing *mp; coord tp; for (i = 0; i < level + least; i++) { if (!treas && rnd(100) < 50) /* put in some little buggers */ continue; /* * Put the monster in */ item = new_item(sizeof *mp); mp = THINGPTR(item); do { rnd_pos(rp, &tp); } until(mvwinch(stdscr, tp.y, tp.x) == FLOOR); new_monster(item, randmonster(FALSE, FALSE), &tp, FALSE); /* * See if we want to give it a treasure to carry around. */ carry_obj(mp, monsters[mp->t_index].m_carry); /* Is it going to give us some light? */ if (on(*mp, HASFIRE)) { register struct linked_list *fire_item; fire_item = creat_item(); ldata(fire_item) = (char *) mp; attach(rp->r_fires, fire_item); rp->r_flags |= HASFIRE; } } } /* * id_monst returns the index of the monster given its letter */ short id_monst(monster) register char monster; { register short result; result = NLEVMONS*vlevel; if (result > NUMMONST) result = NUMMONST; for(; result>0; result--) if (monsters[result].m_appear == monster) return(result); for (result=(NLEVMONS*vlevel)+1; result <= NUMMONST; result++) if (monsters[result].m_appear == monster) return(result); return(0); } /* * new_monster: * Pick a new monster and add it to the list */ new_monster(item, type, cp, max_monster) struct linked_list *item; short type; register coord *cp; bool max_monster; { register struct thing *tp; register struct monster *mp; register char *ip, *hitp; register int i, min_intel, max_intel; register int num_dice, num_sides=8, num_extra=0; attach(mlist, item); tp = THINGPTR(item); tp->t_turn = TRUE; tp->t_pack = NULL; tp->t_index = type; tp->t_wasshot = FALSE; tp->t_type = monsters[type].m_appear; tp->t_ctype = C_MONSTER; tp->t_no_move = 0; tp->t_doorgoal = 0; tp->t_quiet = 0; tp->t_pos = tp->t_oldpos = *cp; tp->t_oldch = CCHAR( mvwinch(cw, cp->y, cp->x) ); mvwaddch(mw, cp->y, cp->x, tp->t_type); mp = &monsters[tp->t_index]; /* Figure out monster's hit points */ hitp = mp->m_stats.s_hpt; num_dice = atoi(hitp); if ((hitp = strchr(hitp, 'd')) != NULL) { num_sides = atoi(++hitp); if ((hitp = strchr(hitp, '+')) != NULL) num_extra = atoi(++hitp); } tp->t_stats.s_lvl = mp->m_stats.s_lvl; tp->t_stats.s_arm = mp->m_stats.s_arm; strncpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg,sizeof(tp->t_stats.s_dmg)); tp->t_stats.s_str = mp->m_stats.s_str; if (vlevel > HARDER) { /* the deeper, the meaner we get */ tp->t_stats.s_lvl += (vlevel - HARDER); num_dice += (vlevel - HARDER)/2; } if (max_monster) tp->t_stats.s_hpt = num_dice * num_sides + num_extra; else tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra; tp->t_stats.s_exp = mp->m_stats.s_exp + mp->m_add_exp*tp->t_stats.s_hpt; /* * just initailize others values to something reasonable for now * maybe someday will *really* put these in monster table */ tp->t_stats.s_wisdom = 8 + rnd(4); tp->t_stats.s_dext = 8 + rnd(4); tp->t_stats.s_const = 8 + rnd(4); tp->t_stats.s_charisma = 8 + rnd(4); /* Set the initial flags */ for (i=0; i<16; i++) tp->t_flags[i] = 0; for (i=0; i<MAXFLAGS; i++) turn_on(*tp, mp->m_flags[i]); /* suprising monsters don't always surprise you */ if (!max_monster && on(*tp, CANSURPRISE) && off(*tp, ISUNIQUE) && rnd(100) < 20) turn_off(*tp, CANSURPRISE); /* If this monster is unique, gen it */ if (on(*tp, ISUNIQUE)) mp->m_normal = FALSE; /* * if is it the quartermaster, then compute his level and exp pts * based on the level. This will make it fair when thieves try to * steal and give them reasonable experience if they succeed. */ if (on(*tp, CANSELL)) { tp->t_stats.s_exp = vlevel * 100; tp->t_stats.s_lvl = vlevel/2 + 1; attach(tp->t_pack, new_thing(ALL)); } /* Normally scared monsters have a chance to not be scared */ if (on(*tp, ISFLEE) && (rnd(4) == 0)) turn_off(*tp, ISFLEE); /* Figure intelligence */ min_intel = atoi(mp->m_intel); if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL) tp->t_stats.s_intel = min_intel; else { max_intel = atoi(++ip); if (max_monster) tp->t_stats.s_intel = max_intel; else tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel); } if (vlevel > HARDER) tp->t_stats.s_intel += ((vlevel - HARDER)/2); tp->maxstats = tp->t_stats; /* If the monster can shoot, it may have a weapon */ if (on(*tp, CANSHOOT) && ((rnd(100) < (22 + vlevel)) || max_monster)) { struct linked_list *item1; register struct object *cur, *cur1; item = new_item(sizeof *cur); item1 = new_item(sizeof *cur1); cur = OBJPTR(item); cur1 = OBJPTR(item1); cur->o_hplus = (rnd(4) < 3) ? 0 : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1); cur->o_dplus = (rnd(4) < 3) ? 0 : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1); cur1->o_hplus = (rnd(4) < 3) ? 0 : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1); cur1->o_dplus = (rnd(4) < 3) ? 0 : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1); strcpy(cur->o_damage,"0d0"); strcpy(cur->o_hurldmg,"0d0"); strcpy(cur1->o_damage,"0d0"); strcpy(cur1->o_hurldmg,"0d0"); cur->o_ac = cur1->o_ac = 11; cur->o_count = cur1->o_count = 1; cur->o_group = cur1->o_group = 0; cur->contents = cur1->contents = NULL; if ((cur->o_hplus <= 0) && (cur->o_dplus <= 0)) cur->o_flags = ISCURSED; if ((cur1->o_hplus <= 0) && (cur1->o_dplus <= 0)) cur1->o_flags = ISCURSED; cur->o_flags = cur1->o_flags = 0; cur->o_type = cur1->o_type = WEAPON; cur->o_mark[0] = cur1->o_mark[0] = '\0'; /* The monster may use a crossbow, sling, or an arrow */ i = rnd(100); if (i < 10) { cur->o_which = CROSSBOW; cur1->o_which = BOLT; init_weapon(cur, CROSSBOW); init_weapon(cur1, BOLT); } else if (i < 70) { cur->o_which = BOW; cur1->o_which = ARROW; init_weapon(cur, BOW); init_weapon(cur1, ARROW); } else { cur->o_which = SLING; cur1->o_which = ROCK; init_weapon(cur, SLING); init_weapon(cur1, ROCK); } attach(tp->t_pack, item); attach(tp->t_pack, item1); } if (ISWEARING(R_AGGR)) runto(tp, &hero); if (on(*tp, ISDISGUISE)) { char mch = 0; if (tp->t_pack != NULL) mch = (OBJPTR(tp->t_pack))->o_type; else switch (rnd(10)) { case 0: mch = GOLD; when 1: mch = POTION; when 2: mch = SCROLL; when 3: mch = FOOD; when 4: mch = WEAPON; when 5: mch = ARMOR; when 6: mch = RING; when 7: mch = STICK; when 8: mch = monsters[randmonster(FALSE, FALSE)].m_appear; when 9: mch = MM; } tp->t_disguise = mch; } } /* * randmonster: * Pick a monster to show up. The lower the level, * the meaner the monster. */ short randmonster(wander, no_unique) register bool wander, no_unique; { register int d, cur_level, range, i; /* * Do we want a merchant? Merchant is always in place 'NUMMONST' */ if (wander && monsters[NUMMONST].m_wander && rnd(100) < 3) return NUMMONST; cur_level = vlevel; range = 4*NLEVMONS; i = 0; do { if (i++ > range*10) { /* just in case all have be genocided */ i = 0; if (--cur_level <= 0) fatal("Rogue could not find a monster to make"); } d = NLEVMONS*(cur_level - 1) + (rnd(range) - (range - 1 - NLEVMONS)); if (d < 1) d = rnd(NLEVMONS) + 1; if (d > NUMMONST - NUMUNIQUE - 1) { if (no_unique) d = rnd(range) + (NUMMONST - NUMUNIQUE - 1) - (range - 1); else if (d > NUMMONST - 1) d = rnd(range+NUMUNIQUE) + (NUMMONST-1) - (range+NUMUNIQUE-1); } } while (wander ? !monsters[d].m_wander || !monsters[d].m_normal : !monsters[d].m_normal); return d; } /* Sell displays a menu of goods from which the player may choose * to purchase something. */ sell(tp) register struct thing *tp; { register struct linked_list *item; register struct object *obj; register int i, j, min_worth, nitems, goods = 0, chance, which_item; char buffer[LINELEN]; struct { int which; int plus1, plus2; int count; int worth; char *name; } selection[10]; min_worth = 100000; item = find_mons(tp->t_pos.y, tp->t_pos.x); /* Get pointer to monster */ /* Select the items */ nitems = rnd(6) + 5; for (i=0; i<nitems; i++) { selection[i].worth = selection[i].plus1 = selection[i].plus2 = selection[i].which = selection[i].count = 0; } switch (rnd(9)) { /* Armor */ case 0: case 1: goods = ARMOR; for (i=0; i<nitems; i++) { chance = rnd(100); for (j = 0; j < MAXARMORS; j++) if (chance < armors[j].a_prob) break; if (j == MAXARMORS) { debug("Picked a bad armor %d", chance); j = 0; } selection[i].which = j; selection[i].count = 1; if (rnd(100) < 40) selection[i].plus1 = rnd(5) + 1; else selection[i].plus1 = 0; selection[i].name = armors[j].a_name; /* Calculate price */ selection[i].worth = armors[j].a_worth; selection[i].worth += 2 * s_magic[S_ALLENCH].mi_worth * selection[i].plus1; if (min_worth > selection[i].worth) min_worth = selection[i].worth; } break; /* Weapon */ case 2: case 3: goods = WEAPON; for (i=0; i<nitems; i++) { selection[i].which = rnd(MAXWEAPONS); selection[i].count = 1; if (rnd(100) < 35) { selection[i].plus1 = rnd(3); selection[i].plus2 = rnd(3); } else { selection[i].plus1 = 0; selection[i].plus2 = 0; } if (weaps[selection[i].which].w_flags & ISMANY) selection[i].count = rnd(15) + 5; selection[i].name = weaps[selection[i].which].w_name; /* * note: use "count" before adding in the enchantment cost * of an item. This will keep the price of arrows * and such to a reasonable price. */ j = selection[i].plus1 + selection[i].plus2; selection[i].worth = weaps[selection[i].which].w_worth; selection[i].worth *= selection[i].count; selection[i].worth += 2 * s_magic[S_ALLENCH].mi_worth * j; if (min_worth > selection[i].worth) min_worth = selection[i].worth; } break; /* Staff or wand */ case 4: goods = STICK; for (i=0; i<nitems; i++) { selection[i].which = pick_one(ws_magic, MAXSTICKS); selection[i].plus1 = rnd(11) + 5; /* Charges */ selection[i].count = 1; selection[i].name = ws_magic[selection[i].which].mi_name; selection[i].worth = ws_magic[selection[i].which].mi_worth; selection[i].worth += 20 * selection[i].plus1; if (min_worth > selection[i].worth) min_worth = selection[i].worth; } break; /* Ring */ case 5: goods = RING; for (i=0; i<nitems; i++) { selection[i].which = pick_one(r_magic, MAXRINGS); selection[i].plus1 = rnd(2) + 1; /* Armor class */ selection[i].count = 1; if (rnd(100) < r_magic[selection[i].which].mi_bless + 10) selection[i].plus1 += rnd(2) + 1; selection[i].name = r_magic[selection[i].which].mi_name; selection[i].worth = r_magic[selection[i].which].mi_worth; switch (selection[i].which) { case R_DIGEST: if (selection[i].plus1 > 2) selection[i].plus1 = 2; else if (selection[i].plus1 < 1) selection[i].plus1 = 1; /* fall thru here to other cases */ case R_ADDSTR: case R_ADDDAM: case R_PROTECT: case R_ADDHIT: case R_ADDINTEL: case R_ADDWISDOM: if (selection[i].plus1 > 0) selection[i].worth += selection[i].plus1 * 50; } if(min_worth > selection[i].worth) min_worth = selection[i].worth; } break; /* scroll */ case 6: goods = SCROLL; for (i=0; i<nitems; i++) { selection[i].which = pick_one(s_magic, MAXSCROLLS); selection[i].count = 1; selection[i].name = s_magic[selection[i].which].mi_name; selection[i].worth = s_magic[selection[i].which].mi_worth; if (min_worth > selection[i].worth) min_worth = selection[i].worth; } break; /* potions */ case 7: goods = POTION; for (i=0; i<nitems; i++) { selection[i].which = pick_one(p_magic, MAXPOTIONS); selection[i].count = 1; selection[i].name = p_magic[selection[i].which].mi_name; selection[i].worth = p_magic[selection[i].which].mi_worth; if (min_worth > selection[i].worth) min_worth = selection[i].worth; } break; /* Miscellaneous magic */ case 8: goods = MM; for (i=0; i<nitems; i++) { /* don't sell as many mm as others */ selection[i].which = pick_one(m_magic, MAXMM); selection[i].count = 1; selection[i].name = m_magic[selection[i].which].mi_name; selection[i].worth = m_magic[selection[i].which].mi_worth; switch (selection[i].which) { case MM_JUG: switch(rnd(9)) { case 0: selection[i].plus1 = P_PHASE; when 1: selection[i].plus1 = P_CLEAR; when 2: selection[i].plus1 = P_SEEINVIS; when 3: selection[i].plus1 = P_HEALING; when 4: selection[i].plus1 = P_MFIND; when 5: selection[i].plus1 = P_TFIND; when 6: selection[i].plus1 = P_HASTE; when 7: selection[i].plus1 = P_RESTORE; when 8: selection[i].plus1 = P_FLY; } when MM_OPEN: case MM_HUNGER: case MM_DRUMS: case MM_DISAPPEAR: case MM_CHOKE: case MM_KEOGHTOM: selection[i].plus1 = 3 + (rnd(3)+1) * 3; selection[i].worth += selection[i].plus1 * 50; when MM_BRACERS: selection[i].plus1 = rnd(10)+1; selection[i].worth += selection[i].plus1 * 75; when MM_DISP: selection[i].plus1 = 2; when MM_PROTECT: selection[i].plus1 = rnd(5)+1; selection[i].worth += selection[i].plus1 * 100; when MM_SKILLS: selection[i].plus1 = player.t_ctype; otherwise: break; } if(min_worth > selection[i].worth) min_worth = selection[i].worth; } break; } /* See if player can afford an item */ if (min_worth > purse) { msg("The %s eyes your small purse and departs.", monsters[NUMMONST].m_name); /* Get rid of the monster */ killed(item, FALSE, FALSE); return; } /* Display the goods */ msg("The %s shows you his wares.--More--", monsters[NUMMONST].m_name); wait_for(cw,' '); msg(""); clearok(cw, TRUE); touchwin(cw); wclear(hw); touchwin(hw); for (i=0; i < nitems; i++) { mvwaddch(hw, i+2, 0, '['); waddch(hw, (char) ((int) 'a' + i)); waddstr(hw, "] "); switch (goods) { case ARMOR: waddstr(hw, "Some "); when WEAPON: if (selection[i].count == 1) waddstr(hw, " A "); else { sprintf(buffer, "%2d ", selection[i].count); waddstr(hw, buffer); } when STICK: wprintw(hw, "A %-5s of ", ws_type[selection[i].which]); when RING: waddstr(hw, "A ring of "); when SCROLL: waddstr(hw, "A scroll of "); when POTION: waddstr(hw, "A potion of "); } if (selection[i].count > 1) sprintf(buffer, "%s%s ", selection[i].name, "s"); else sprintf(buffer, "%s ", selection[i].name); wprintw(hw, "%-24s", buffer); wprintw(hw, " Price:%5d", selection[i].worth); } sprintf(buffer, "Purse: %d", purse); mvwaddstr(hw, nitems+3, 0, buffer); mvwaddstr(hw, 0, 0, "How about one of the following goods? "); draw(hw); /* Get rid of the monster */ killed(item, FALSE, FALSE); which_item = (int) (wgetch(hw) - 'a'); while (which_item < 0 || which_item >= nitems) { if (which_item == (int) ESCAPE - (int) 'a') { return; } mvwaddstr(hw, 0, 0, "Please enter one of the listed items. "); draw(hw); which_item = (int) (wgetch(hw) - 'a'); } if (selection[which_item].worth > purse) { msg("You cannot afford it."); return; } purse -= selection[which_item].worth; item = spec_item(goods, selection[which_item].which, selection[which_item].plus1, selection[which_item].plus2); obj = OBJPTR(item); if (selection[which_item].count > 1) { obj->o_count = selection[which_item].count; obj->o_group = newgrp(); } /* If a stick or ring, let player know the type */ switch (goods) { case RING: r_know[selection[which_item].which] = TRUE; when POTION:p_know[selection[which_item].which] = TRUE; when SCROLL:s_know[selection[which_item].which] = TRUE; when STICK: ws_know[selection[which_item].which] = TRUE; when MM: m_know[selection[which_item].which] = TRUE; } if (add_pack(item, FALSE, NULL) == FALSE) { obj->o_pos = hero; fall(item, TRUE); } } /* * what to do when the hero steps next to a monster */ struct linked_list * wake_monster(y, x) int y, x; { register struct thing *tp; register struct linked_list *it; register struct room *trp; register const char *mname; bool nasty; /* Will the monster "attack"? */ char ch; if ((it = find_mons(y, x)) == NULL) { msg("Can't find monster in show"); return (NULL); } tp = THINGPTR(it); ch = tp->t_type; trp = roomin(&tp->t_pos); /* Current room for monster */ mname = monsters[tp->t_index].m_name; /* * Let greedy ones in a room guard gold * (except in a maze where lots of creatures would all go for the * same piece of gold) */ if (on(*tp, ISGREED) && off(*tp, ISRUN) && levtype != MAZELEV && trp != NULL && lvl_obj != NULL) { register struct linked_list *item; register struct object *cur; for (item = lvl_obj; item != NULL; item = next(item)) { cur = OBJPTR(item); if ((cur->o_type == GOLD) && (roomin(&cur->o_pos) == trp)) { /* Run to the gold */ tp->t_dest = &cur->o_pos; turn_on(*tp, ISRUN); turn_off(*tp, ISDISGUISE); /* Make it worth protecting */ cur->o_count += GOLDCALC + GOLDCALC; break; } } } /* * Every time he sees mean monster, it might start chasing him */ if (on(*tp, ISMEAN) && off(*tp, ISHELD) && off(*tp, ISRUN) && rnd(100) > 33 && (!is_stealth(&player) || (on(*tp, ISUNIQUE) && rnd(100) > 95)) && (off(player, ISINVIS) || on(*tp, CANSEE)) || (trp != NULL && (trp->r_flags & ISTREAS))) { tp->t_dest = &hero; turn_on(*tp, ISRUN); turn_off(*tp, ISDISGUISE); } /* See if the monster will bother the player */ nasty = (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x)); /* * Let the creature summon if it can. * Also check to see if there is room around the player, * if not then the creature will wait */ if (on(*tp, CANSUMMON) && nasty && rnd(40) < tp->t_stats.s_lvl && fallpos(&hero, FALSE, 2) != NULL) { const char *helpname; int fail; register int which, i; turn_off(*tp, CANSUMMON); helpname = monsters[tp->t_index].m_typesum; for (which=1; which<NUMMONST; which++) { if (strcmp(helpname, monsters[which].m_name) == 0) break; } if (which >= NUMMONST) debug("couldn't find summoned one"); if ((off(*tp, ISINVIS) || on(player, CANSEE)) && (off(*tp, ISSHADOW) || on(player, CANSEE)) && (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) { if (monsters[which].m_normal == FALSE) { /* genocided? */ msg("The %s appears dismayed", mname); monsters[tp->t_index].m_numsum = 0; } else { sprintf(outstring,"The %s summons %ss for help", mname, helpname); msg(outstring); } } else { if (monsters[which].m_normal == FALSE) /* genocided? */ monsters[tp->t_index].m_numsum = 0; else msg("%ss seem to appear from nowhere!", helpname); } /* * try to make all the creatures around player but remember * if unsuccessful */ for (i=0, fail=0; i<monsters[tp->t_index].m_numsum; i++) { if (!creat_mons(&player, which, FALSE)) fail++; /* remember the failures */ } /* * try once again to make the buggers */ for (i=0; i<fail; i++) creat_mons(tp, which, FALSE); /* Now let the poor fellow see all the trouble */