This is makemon.c in view mode; [Download] [Up]
/* SCCS Id: @(#)makemon.c 3.0 89/11/22 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef REINCARNATION # include <ctype.h> #endif VSTATIC struct monst zeromonst; static int FDECL(uncommon, (struct permonst *)); OSTATIC void FDECL(m_initgrp,(struct monst *,int,int,int)); static void FDECL(m_initthrow,(struct monst *,int,int)); OSTATIC void FDECL(m_initweap,(struct monst *)); static void FDECL(m_initinv,(struct monst *)); static void FDECL(rloc_to,(struct monst *,int,int)); static int FDECL(mstrength,(struct permonst *)); extern int monstr[]; #ifdef OVLB int monstr[NUMMONS]; #endif /* OVLB */ #define m_initsgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 3) #define m_initlgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 10) #define toostrong(monindx, lev) (monstr[monindx] > lev) #define tooweak(monindx, lev) (monstr[monindx] < lev) #ifdef OVLB XSTATIC void m_initgrp(mtmp, x, y, n) /* make a group just like mtmp */ register struct monst *mtmp; register int x, y, n; { coord mm; register int cnt = rnd(n); struct monst *mon; /* * Temporary kludge to cut down on swarming at lower character levels * till we can get this game a little more balanced. [mrs] */ cnt /= (u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1; if(!cnt) cnt++; mm.x = x; mm.y = y; while(cnt--) { if (peace_minded(mtmp->data)) continue; /* Don't create groups of peaceful monsters since they'll get * in our way. If the monster has a percentage chance so some * are peaceful and some are not, the result will just be a * smaller group. */ enexto(&mm, mm.x, mm.y, mtmp->data); mon = makemon(mtmp->data, mm.x, mm.y); mon->mpeaceful = 0; set_malign(mon); /* Undo the second peace_minded() check in makemon(); if the * monster turned out to be peaceful the first time we didn't * create it at all; we don't want a second check. */ } } static void m_initthrow(mtmp,otyp,oquan) struct monst *mtmp; int otyp,oquan; { register struct obj *otmp; otmp = mksobj(otyp,FALSE); otmp->quan = 2 + rnd(oquan); otmp->owt = weight(otmp); #ifdef TOLKIEN if (otyp == ORCISH_ARROW) otmp->opoisoned = 1; #endif mpickobj(mtmp, otmp); } XSTATIC void m_initweap(mtmp) register struct monst *mtmp; { register struct permonst *ptr = mtmp->data; register int mm = monsndx(ptr); #ifdef REINCARNATION if (dlevel==rogue_level) return; #endif /* * first a few special cases: * * giants get a boulder to throw sometimes. * ettins get clubs * kobolds get darts to throw * centaurs get some sort of bow & arrows or bolts * soldiers get all sorts of things. * kops get clubs & cream pies. */ switch (mtmp->data->mlet) { case S_GIANT: if (rn2(2)) (void)mongets(mtmp, (ptr != &mons[PM_ETTIN]) ? BOULDER : CLUB); break; case S_HUMAN: if(is_mercenary(ptr)) switch (mm) { #ifdef ARMY case PM_SOLDIER: (void) mongets(mtmp, rn2(2) ? SPEAR : SHORT_SWORD); break; case PM_SERGEANT: (void) mongets(mtmp, rn2(2) ? FLAIL : MACE); break; case PM_LIEUTENANT: (void) mongets(mtmp, rn2(2) ? GLAIVE : LONG_SWORD); break; case PM_CAPTAIN: (void) mongets(mtmp, rn2(2) ? LONG_SWORD : SCIMITAR); break; #endif default: if (!rn2(4)) (void) mongets(mtmp, DAGGER); if (!rn2(7)) (void) mongets(mtmp, SPEAR); break; } break; case S_HUMANOID: #ifdef TOLKIEN if (mm == PM_HOBBIT) { switch (rn2(3)) { case 0: (void)mongets(mtmp, DAGGER); break; case 1: (void)mongets(mtmp, ELVEN_DAGGER); break; case 2: (void)mongets(mtmp, SLING); break; } if (!rn2(10)) (void)mongets(mtmp, ELVEN_MITHRIL_COAT); } else if (is_dwarf(ptr)) { (void)mongets(mtmp, DWARVISH_CLOAK); (void)mongets(mtmp, IRON_SHOES); if (!rn2(4)) { (void)mongets(mtmp, DWARVISH_SHORT_SWORD); /* note: you can't use a mattock with a shield */ if (rn2(2)) (void)mongets(mtmp, DWARVISH_MATTOCK); else { (void)mongets(mtmp, AXE); (void)mongets(mtmp, DWARVISH_ROUNDSHIELD); } (void)mongets(mtmp, DWARVISH_IRON_HELM); if (!rn2(3)) (void)mongets(mtmp, DWARVISH_MITHRIL_COAT); } else { (void)mongets(mtmp, PICK_AXE); } } else if (is_elf(ptr)) { (void)mongets(mtmp, rn2(2) ? ELVEN_MITHRIL_COAT : ELVEN_CLOAK); if (rn2(2)) (void)mongets(mtmp, ELVEN_LEATHER_HELM); if (rn2(3)) (void)mongets(mtmp, ELVEN_DAGGER); switch (rn2(3)) { case 0: if (!rn2(4)) (void)mongets(mtmp, ELVEN_SHIELD); (void)mongets(mtmp, ELVEN_SHORT_SWORD); (void)mongets(mtmp, ELVEN_BOW); m_initthrow(mtmp, ELVEN_ARROW, 12); break; case 1: (void)mongets(mtmp, ELVEN_BROADSWORD); if (rn2(2)) (void)mongets(mtmp, ELVEN_SHIELD); break; case 2: (void)mongets(mtmp, ELVEN_SPEAR); (void)mongets(mtmp, ELVEN_SHIELD); break; } } #else /* TOLKIEN */ if (is_dwarf(ptr)) { (void)mongets(mtmp, IRON_SHOES); if (rn2(4) == 0) { (void)mongets(mtmp, SHORT_SWORD); (void)mongets(mtmp, (rn2(3) == 0) ? AXE : TWO_HANDED_SWORD); (void)mongets(mtmp, LARGE_SHIELD); if (rn2(3) == 0) (void)mongets(mtmp, DWARVISH_MITHRIL_COAT); } else { (void)mongets(mtmp, PICK_AXE); } } else if (is_elf(ptr)) { (void)mongets(mtmp, ELVEN_CLOAK); if (rn2(3)) (void)mongets(mtmp, DAGGER); switch (rn2(3)) { case 0: if (!rn2(4)) (void)mongets(mtmp, SMALL_SHIELD); (void)mongets(mtmp, SHORT_SWORD); (void)mongets(mtmp, BOW); m_initthrow(mtmp, ARROW, 12); break; case 1: (void)mongets(mtmp, BROADSWORD); if (rn2(2)) (void)mongets(mtmp, SMALL_SHIELD); break; case 2: (void)mongets(mtmp, SPEAR); (void)mongets(mtmp, SMALL_SHIELD); break; } } #endif /* TOLKIEN */ break; # ifdef KOPS case S_KOP: /* create Keystone Kops with cream pies to * throw. As suggested by KAA. [MRS] */ if (!rn2(4)) m_initthrow(mtmp, CREAM_PIE, 2); if (!rn2(3)) (void)mongets(mtmp, (rn2(2)) ? CLUB : RUBBER_HOSE); break; #endif case S_ORC: if(rn2(2)) (void)mongets(mtmp, ORCISH_HELM); #ifdef TOLKIEN switch (mm != PM_ORC_CAPTAIN ? mm : rn2(2) ? PM_MORDOR_ORC : PM_URUK_HAI) { case PM_MORDOR_ORC: if(rn2(2)) (void)mongets(mtmp, SCIMITAR); if(rn2(2)) (void)mongets(mtmp, ORCISH_SHIELD); if(rn2(2)) (void)mongets(mtmp, KNIFE); if(rn2(2)) (void)mongets(mtmp, ORCISH_CHAIN_MAIL); break; case PM_URUK_HAI: if(rn2(2)) (void)mongets(mtmp, ORCISH_CLOAK); if(rn2(2)) (void)mongets(mtmp, ORCISH_SHORT_SWORD); if(rn2(2)) (void)mongets(mtmp, IRON_SHOES); if(rn2(2)) { (void)mongets(mtmp, ORCISH_BOW); m_initthrow(mtmp, ORCISH_ARROW, 12); } if(rn2(2)) (void)mongets(mtmp, URUK_HAI_SHIELD); break; default: if (mm != PM_ORC_SHAMAN) (void)mongets(mtmp, (mm == PM_GOBLIN || rn2(2) == 0) ? ORCISH_DAGGER : SCIMITAR); #else /* TOLKIEN */ switch (mm) { case PM_ORC_CAPTAIN: if(rn2(2)) { if(rn2(2)) (void)mongets(mtmp, SCIMITAR); if(rn2(2)) (void)mongets(mtmp, SMALL_SHIELD); if(rn2(2)) (void)mongets(mtmp, KNIFE); if(rn2(2)) (void)mongets(mtmp, CHAIN_MAIL); } else { if(rn2(2)) (void)mongets(mtmp, SHORT_SWORD); if(rn2(2)) (void)mongets(mtmp, IRON_SHOES); if(rn2(2)) { (void)mongets(mtmp, BOW); m_initthrow(mtmp, ARROW, 12); } if(rn2(2)) (void)mongets(mtmp, SMALL_SHIELD); } default: if (mm != PM_ORC_SHAMAN) (void)mongets(mtmp, (mm == PM_GOBLIN || rn2(2) == 0) ? DAGGER : SCIMITAR); #endif /* TOLKIEN */ } break; case S_KOBOLD: if (!rn2(4)) m_initthrow(mtmp, DART, 12); break; case S_CENTAUR: if (rn2(2)) { if(ptr == &mons[PM_FOREST_CENTAUR]) { (void)mongets(mtmp, BOW); m_initthrow(mtmp, ARROW, 12); } else { (void)mongets(mtmp, CROSSBOW); m_initthrow(mtmp, CROSSBOW_BOLT, 12); } } break; case S_WRAITH: (void)mongets(mtmp, KNIFE); (void)mongets(mtmp, LONG_SWORD); break; case S_DEMON: #ifdef INFERNO switch (mm) { case PM_BALROG: (void)mongets(mtmp, BULLWHIP); (void)mongets(mtmp, BROADSWORD); break; case PM_ORCUS: (void)mongets(mtmp, WAN_DEATH); /* the Wand of Orcus */ break; case PM_HORNED_DEVIL: (void)mongets(mtmp, rn2(4) ? TRIDENT : BULLWHIP); break; case PM_ICE_DEVIL: if (!rn2(4)) (void)mongets(mtmp, SPEAR); break; case PM_ASMODEUS: (void)mongets(mtmp, WAN_COLD); break; case PM_DISPATER: (void)mongets(mtmp, WAN_STRIKING); break; case PM_YEENOGHU: (void)mongets(mtmp, FLAIL); break; } #endif /* prevent djinnis and mail daemons from leaving objects when * they vanish */ if (!is_demon(ptr)) break; /* fall thru */ /* * Now the general case, ~40% chance of getting some type * of weapon. TODO: Add more weapons types (use bigmonst()); */ default: switch(rnd(12)) { case 1: m_initthrow(mtmp, DART, 12); break; case 2: (void) mongets(mtmp, CROSSBOW); m_initthrow(mtmp, CROSSBOW_BOLT, 12); break; case 3: (void) mongets(mtmp, BOW); m_initthrow(mtmp, ARROW, 12); break; case 4: m_initthrow(mtmp, DAGGER, 3); break; case 5: (void) mongets(mtmp, AKLYS); break; default: break; } break; } } #endif /* OVLB */ #ifdef OVL1 static void m_initinv(mtmp) register struct monst *mtmp; { register int cnt; register struct obj *otmp; register struct permonst *ptr = mtmp->data; #ifdef REINCARNATION if (dlevel==rogue_level) return; #endif /* * Soldiers get armour & rations - armour approximates their ac. * Nymphs may get mirror or potion of object detection. */ switch(mtmp->data->mlet) { case S_HUMAN: if(is_mercenary(ptr)) { register int mac; if((mac = ptr->ac) < -1) mac += 7 + mongets(mtmp, (rn2(5)) ? PLATE_MAIL : CRYSTAL_PLATE_MAIL); else if(mac < 3) mac += 6 + mongets(mtmp, (rn2(3)) ? SPLINT_MAIL : BANDED_MAIL); else mac += 3 + mongets(mtmp, (rn2(3)) ? RING_MAIL : STUDDED_LEATHER_ARMOR); if(mac < 10) { mac += 1 + mongets(mtmp, HELMET); if(mac < 10) { mac += 1 + mongets(mtmp, SMALL_SHIELD); if(mac < 10) { mac += 1 + mongets(mtmp, ELVEN_CLOAK); if(mac < 10) mac += 1 +mongets(mtmp, LEATHER_GLOVES); } } } if(mac != 10) { /* make up the difference */ otmp = mksobj(RIN_PROTECTION,FALSE); otmp->spe = (10 - mac); if(otmp->spe < 0) curse(otmp); mpickobj(mtmp, otmp); } #ifdef ARMY if(ptr != &mons[PM_GUARD]) { if (!rn2(3)) (void) mongets(mtmp, K_RATION); if (!rn2(2)) (void) mongets(mtmp, C_RATION); } #endif } else if (ptr == &mons[PM_SHOPKEEPER]) { (void) mongets(mtmp,SKELETON_KEY); } break; case S_NYMPH: #ifdef MEDUSA if(!rn2(2)) (void) mongets(mtmp, MIRROR); #endif if(!rn2(2)) (void) mongets(mtmp, POT_OBJECT_DETECTION); break; case S_GIANT: if(mtmp->data == &mons[PM_MINOTAUR]) (void) mongets(mtmp, WAN_DIGGING); else if (is_giant(mtmp->data)) { for(cnt = rn2((int)(mtmp->m_lev / 2)); cnt; cnt--) { do otmp = mkobj(GEM_SYM,FALSE); while (otmp->otyp >= LAST_GEM+6); otmp->quan = 2 + rnd(2); otmp->owt = weight(otmp); mpickobj(mtmp, otmp); } } break; #ifdef TOLKIEN case S_WRAITH: if(mtmp->data == &mons[PM_NAZGUL]) { otmp = mksobj(RIN_INVISIBILITY, FALSE); curse(otmp); mpickobj(mtmp, otmp); } break; #endif default: break; } } /* * called with [x,y] = coordinates; * [0,0] means anyplace * [u.ux,u.uy] means: call mnexto (if !in_mklev) * * In case we make a monster group, only return the one at [x,y]. */ struct monst * makemon(ptr, x, y) register struct permonst *ptr; register int x, y; { register struct monst *mtmp; register int ct; boolean anything = (!ptr); /* if caller wants random location, do it here */ if(x == 0 && y == 0) { int uroom; int tryct = 0; /* careful with bigrooms */ #ifdef __GNULINT__ uroom = 0; /* supress used before set warning */ #endif if(!in_mklev) uroom = inroom(u.ux, u.uy); do { x = rn1(COLNO-3,2); y = rn2(ROWNO); } while(!goodpos(x, y, ptr) || (!in_mklev && tryct++ < 50 && inroom(x, y) == uroom)); } /* if a monster already exists at the position, return */ if(MON_AT(x, y)) return((struct monst *) 0); if(ptr){ /* if you are to make a specific monster and it has already been genocided, return */ if(ptr->geno & G_GENOD) return((struct monst *) 0); } else { /* make a random (common) monster. */ if(!(ptr = rndmonst())) { #ifdef DEBUG pline("Warning: no monster."); #endif return((struct monst *) 0); /* no more monsters! */ } } /* if it's unique, don't ever make it again */ if (ptr->geno & G_UNIQ) ptr->geno &= G_GENOD; /* gotmon: /* label not referenced */ mtmp = newmonst(ptr->pxlth); *mtmp = zeromonst; /* clear all entries in structure */ for(ct = 0; ct < ptr->pxlth; ct++) ((char *) &(mtmp->mextra[0]))[ct] = 0; mtmp->nmon = fmon; fmon = mtmp; mtmp->m_id = flags.ident++; mtmp->data = ptr; mtmp->mxlth = ptr->pxlth; mtmp->m_lev = adj_lev(ptr); #ifdef GOLEMS if (is_golem(ptr)) mtmp->mhpmax = mtmp->mhp = golemhp(monsndx(ptr)); else #endif /* GOLEMS */ if(ptr->mlevel > 49) { /* "special" fixed hp monster * the hit points are encoded in the mlevel in a somewhat strange * way to fit in the 50..127 positive range of a signed character * above the 1..49 that indicate "normal" monster levels */ mtmp->mhpmax = mtmp->mhp = 2*(ptr->mlevel - 6); mtmp->m_lev = mtmp->mhp / 4; /* approximation */ } else if((ptr->mlet == S_DRAGON) && (ptr >= &mons[PM_GRAY_DRAGON])) mtmp->mhpmax = mtmp->mhp = 80; else if(!mtmp->m_lev) mtmp->mhpmax = mtmp->mhp = rnd(4); else mtmp->mhpmax = mtmp->mhp = d((int)mtmp->m_lev, 8); place_monster(mtmp, x, y); mtmp->mcansee = mtmp->mcanmove = 1; mtmp->mpeaceful = peace_minded(ptr); switch(ptr->mlet) { case S_MIMIC: set_mimic_sym(mtmp); break; case S_SPIDER: case S_SNAKE: mtmp->mhide = 1; if(in_mklev) if(x && y) (void) mkobj_at(0, x, y); if(OBJ_AT(x, y) || levl[x][y].gmask) mtmp->mundetected = 1; break; case S_STALKER: case S_EEL: mtmp->minvis = 1; break; case S_LEPRECHAUN: mtmp->msleep = 1; break; case S_JABBERWOCK: case S_NYMPH: if(rn2(5) && !u.uhave_amulet) mtmp->msleep = 1; break; case S_UNICORN: if ((ptr==&mons[PM_WHITE_UNICORN] && u.ualigntyp == U_LAWFUL) || (ptr==&mons[PM_GRAY_UNICORN] && u.ualigntyp == U_NEUTRAL) || (ptr==&mons[PM_BLACK_UNICORN] && u.ualigntyp == U_CHAOTIC)) mtmp->mpeaceful = 1; break; } if (ptr == &mons[PM_CHAMELEON]) { /* If you're protected with a ring, don't create * any shape-changing chameleons -dgk */ if (Protection_from_shape_changers) mtmp->cham = 0; else { mtmp->cham = 1; (void) newcham(mtmp, rndmonst()); } } else if (ptr == &mons[PM_WIZARD_OF_YENDOR]) { mtmp->iswiz = 1; flags.no_of_wizards++; } else if (ptr == &mons[PM_QUANTUM_MECHANIC]) mtmp = qname(mtmp); if(in_mklev) { if(((is_ndemon(ptr)) || (ptr == &mons[PM_WUMPUS]) || #ifdef WORM (ptr == &mons[PM_LONG_WORM]) || #endif (ptr == &mons[PM_GIANT_EEL])) && rn2(5)) mtmp->msleep = 1; } else { if(x == u.ux && y == u.uy) { mnexto(mtmp); if (ptr->mlet == S_MIMIC) { set_mimic_sym(mtmp); unpmon(mtmp); pmon(mtmp); } } } #ifdef INFERNO if(is_dprince(ptr)) { mtmp->mpeaceful = mtmp->minvis = 1; # ifdef NAMED_ITEMS if(uwep) if(!strcmp(ONAME(uwep), "Excalibur")) mtmp->mpeaceful = mtmp->mtame = 0; # endif } #endif #ifdef WORM if(ptr == &mons[PM_LONG_WORM] && getwn(mtmp)) initworm(mtmp); #endif set_malign(mtmp); /* having finished peaceful changes */ if(anything) { if((ptr->geno & G_SGROUP) && rn2(2)) m_initsgrp(mtmp, mtmp->mx, mtmp->my); else if(ptr->geno & G_LGROUP) { if(rn2(3)) m_initlgrp(mtmp, mtmp->mx, mtmp->my); else m_initsgrp(mtmp, mtmp->mx, mtmp->my); } } if(is_armed(ptr)) m_initweap(mtmp); /* equip with weapons / armour */ m_initinv(mtmp); /* add on a few special items */ return(mtmp); } void enexto(cc, xx, yy, mdat) coord *cc; register xchar xx, yy; struct permonst *mdat; { register xchar x,y; coord foo[15], *tfoo; int range, i; tfoo = foo; range = 1; do { /* full kludge action. */ for(x = xx-range; x <= xx+range; x++) if(goodpos(x, yy-range, mdat)) { tfoo->x = x; (tfoo++)->y = yy-range; if(tfoo == &foo[15]) goto foofull; } for(x = xx-range; x <= xx+range; x++) if(goodpos(x, yy+range, mdat)) { tfoo->x = x; (tfoo++)->y = yy+range; if(tfoo == &foo[15]) goto foofull; } for(y = yy+1-range; y < yy+range; y++) if(goodpos(xx-range, y, mdat)) { tfoo->x = xx-range; (tfoo++)->y = y; if(tfoo == &foo[15]) goto foofull; } for(y = yy+1-range; y < yy+range; y++) if(goodpos(xx+range, y, mdat)) { tfoo->x = xx+range; (tfoo++)->y = y; if(tfoo == &foo[15]) goto foofull; } range++; } while(tfoo == foo); foofull: i = rn2((int)(tfoo - foo)); cc->x = foo[i].x; cc->y = foo[i].y; return; } int goodpos(x, y, mdat) int x,y; struct permonst *mdat; { if (x < 1 || x > COLNO-2 || y < 1 || y > ROWNO-2 || MON_AT(x, y)) return 0; if (x == u.ux && y == u.uy) return 0; if (mdat) { if (IS_POOL(levl[x][y].typ)) if (mdat == &playermon && HLevitation) return 1; else return (is_flyer(mdat) || is_swimmer(mdat)); if (passes_walls(mdat)) return 1; } if (!ACCESSIBLE(levl[x][y].typ)) return 0; if (closed_door(x, y) && (!mdat || !amorphous(mdat))) return 0; if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat))) return 0; return 1; } #endif /* OVL1 */ #ifdef OVLB static void rloc_to(mtmp, x, y) struct monst *mtmp; register int x,y; { #ifdef WORM /* do not relocate worms */ if(mtmp->wormno && mtmp->mx) return; #endif if(mtmp->mx != 0 && mtmp->my != 0) remove_monster(mtmp->mx, mtmp->my); place_monster(mtmp, x, y); if(u.ustuck == mtmp){ if(u.uswallow) { u.ux = x; u.uy = y; docrt(); } else u.ustuck = 0; } pmon(mtmp); set_apparxy(mtmp); } void rloc(mtmp) struct monst *mtmp; { register int x, y; /* if the wiz teleports away to heal, try the up staircase, to block the player's escaping before he's healed */ if(!mtmp->iswiz || !goodpos(x = xupstair, y = yupstair, mtmp->data)) do { x = rn1(COLNO-3,2); y = rn2(ROWNO); } while(!goodpos(x,y,mtmp->data)); rloc_to(mtmp, x, y); } void vloc(mtmp) struct monst *mtmp; { register struct mkroom *croom; register int x, y; for(croom = &rooms[0]; croom->hx >= 0; croom++) if(croom->rtype == VAULT) { x = rn2(2) ? croom->lx : croom->hx; y = rn2(2) ? croom->ly : croom->hy; if(goodpos(x, y, mtmp->data)) { rloc_to(mtmp, x, y); return; } } rloc(mtmp); } #endif /* OVLB */ #ifdef OVL0 static int cmnum() { /* return the number of "common" monsters */ int i, count; for(i = count = 0; mons[i].mlet; i++) if(!uncommon(&mons[i])) count++; return(count); } static int uncommon(ptr) struct permonst *ptr; { return (ptr->geno & (G_GENOD | G_NOGEN | G_UNIQ)) || (!Inhell ? ptr->geno & G_HELL : ptr->maligntyp > 0); } #endif /* OVL0 */ #ifdef OVL1 /* This routine is designed to return an integer value which represents * an approximation of monster strength. It uses a similar method of * determination as "experience()" to arrive at the strength. */ static int mstrength(ptr) struct permonst *ptr; { int i, tmp2, n, tmp = ptr->mlevel; if(tmp > 49) /* special fixed hp monster */ tmp = 2*(tmp - 6) / 4; /* For creation in groups */ n = (!!(ptr->geno & G_SGROUP)); n += (!!(ptr->geno & G_LGROUP)) << 1; /* For ranged attacks */ if (ranged_attk(ptr)) n++; /* For higher ac values */ n += (ptr->ac < 0); /* For very fast monsters */ n += (ptr->mmove >= 18); /* For each attack and "special" attack */ for(i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].aatyp; n += (tmp2 > 0); n += (tmp2 == AT_MAGC); n += (tmp2 == AT_WEAP && strongmonst(ptr)); } /* For each "special" damage type */ for(i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].adtyp; if((tmp2 == AD_DRLI) || (tmp2 == AD_STON) #ifdef POLYSELF || (tmp2 == AD_WERE) #endif ) n += 2; else if (ptr != &mons[PM_GRID_BUG]) n += (tmp2 != AD_PHYS); n += ((ptr->mattk[i].damd * ptr->mattk[i].damn) > 23); } /* Leprechauns are special cases. They have many hit dice so they can hit and are hard to kill, but they don't really do much damage. */ if (ptr == &mons[PM_LEPRECHAUN]) n -= 2; /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */ if(n == 0) tmp--; else if(n >= 6) tmp += ( n / 2 ); else tmp += ( n / 3 + 1); return((tmp >= 0) ? tmp : 0); } void init_monstr() { register int ct; for(ct = 0; mons[ct].mlet; ct++) monstr[ct] = mstrength(&(mons[ct])); } #endif /* OVL1 */ #ifdef OVL0 struct permonst * rndmonst() /* select a random monster */ { register struct permonst *ptr; register int i, ct; register int zlevel; static int minmlev, maxmlev, accept; static long oldmoves = 0L; /* != 1, starting value of moves */ #ifdef REINCARNATION static boolean upper; upper = (dlevel == rogue_level); #endif #ifdef __GNULINT__ ptr = (struct permonst *)0; /* suppress "used uninitialized" warning */ #endif if(oldmoves != moves) { /* must recalculate accept */ oldmoves = moves; zlevel = u.uhave_amulet ? MAXLEVEL : dlevel; if(cmnum() <= 0) { #ifdef DEBUG pline("cmnum() fails!"); #endif return((struct permonst *) 0); } /* determine the level of the weakest monster to make. */ minmlev = zlevel/6; /* determine the level of the strongest monster to make. */ maxmlev = (zlevel + u.ulevel)>>1; /* * Find out how many monsters exist in the range we have selected. */ accept = 0; #ifdef REINCARNATION for(ct = (upper ? PM_APE : 0); upper ? isupper(mons[ct].mlet) : mons[ct].mlet; ct++) { #else for(ct = 0 ; mons[ct].mlet; ct++) { #endif ptr = &(mons[ct]); if(uncommon(ptr)) continue; if(tooweak(ct, minmlev) || toostrong(ct, maxmlev)) continue; accept += (ptr->geno & G_FREQ); } } if(!accept) { #ifdef DEBUG pline("no accept!"); #endif return((struct permonst *) 0); } /* * Now, select a monster at random. */ ct = rnd(accept); #ifdef REINCARNATION for(i = (upper ? PM_APE : 0); (upper ? isupper(mons[i].mlet) : mons[i].mlet) && ct > 0; i++) { #else for(i = 0; mons[i].mlet && ct > 0; i++) { #endif ptr = &(mons[i]); if(uncommon(ptr)) continue; if(tooweak(i, minmlev) || toostrong(i, maxmlev)) continue; ct -= (ptr->geno & G_FREQ); } if(ct > 0) { #ifdef DEBUG pline("no count!"); #endif return((struct permonst *) 0); } return(ptr); } #endif /* OVL0 */ #ifdef OVL1 /* The routine below is used to make one of the multiple types * of a given monster class. It will return 0 if no monsters * in that class can be made. */ struct permonst * mkclass(mlet) char mlet; { register int first, last, num = 0; if(!mlet) { impossible("mkclass called with null arg!"); return((struct permonst *) 0); } /* Assumption #1: monsters of a given class are contiguous in the * mons[] array. */ for(first = 0; mons[first].mlet != mlet; first++) if(!mons[first].mlet) return((struct permonst *) 0); for(last = first; mons[last].mlet && mons[last].mlet == mlet; last++) if(!(mons[last].geno & (G_GENOD | G_NOGEN | G_UNIQ))) num += mons[last].geno & G_FREQ; if(!num) return((struct permonst *) 0); /* Assumption #2: monsters of a given class are presented in ascending * order of strength. */ for(num = rnd(num); num > 0; first++) if(!(mons[first].geno & (G_GENOD | G_NOGEN | G_UNIQ))) { /* consider it */ /* skew towards lower value monsters at lower exp. levels */ if(adj_lev(&mons[first]) > (u.ulevel*2)) num--; num -= mons[first].geno & G_FREQ; } first--; /* correct an off-by-one error */ return(&mons[first]); } int adj_lev(ptr) /* adjust strength of monsters based on dlevel and u.ulevel */ register struct permonst *ptr; { int tmp, tmp2; if((tmp = ptr->mlevel) > 49) return(50); /* "special" demons/devils */ tmp2 = (dlevel - tmp); if(tmp2 < 0) tmp--; /* if mlevel > dlevel decrement tmp */ else tmp += (tmp2 / 5); /* else increment 1 per five diff */ tmp2 = (u.ulevel - ptr->mlevel); /* adjust vs. the player */ if(tmp2 > 0) tmp += (tmp2 / 4); /* level as well */ tmp2 = 3 * ptr->mlevel/ 2; /* crude upper limit */ return((tmp > tmp2) ? tmp2 : (tmp > 0 ? tmp : 0)); /* 0 lower limit */ } #endif /* OVL1 */ #ifdef OVLB struct permonst * grow_up(mtmp) /* mon mtmp "grows up" to a bigger version. */ register struct monst *mtmp; { register int newtype; register struct permonst *ptr = mtmp->data; if (ptr->mlevel >= 50 || mtmp->mhpmax <= 8*mtmp->m_lev) return ptr; newtype = little_to_big(monsndx(ptr)); if (++mtmp->m_lev >= mons[newtype].mlevel) { if (mons[newtype].geno & G_GENOD) { pline("As %s grows up into %s, %s dies!", mon_nam(mtmp), an(mons[newtype].mname), mon_nam(mtmp)); mondied(mtmp); return (struct permonst *)0; } mtmp->data = &mons[newtype]; mtmp->m_lev = mons[newtype].mlevel; } if (mtmp->m_lev > 3*mtmp->data->mlevel / 2) mtmp->m_lev = 3*mtmp->data->mlevel / 2; return(mtmp->data); } #endif /* OVLB */ #ifdef OVL1 int mongets(mtmp, otyp) register struct monst *mtmp; register int otyp; { register struct obj *otmp; if((otmp = (otyp) ? mksobj(otyp,FALSE) : mkobj(otyp,FALSE))) { if (mtmp->data->mlet == S_DEMON) { /* demons always get cursed objects */ curse(otmp); } mpickobj(mtmp, otmp); return(otmp->spe); } else return(0); } #endif /* OVL1 */ #ifdef OVLB #ifdef GOLEMS int golemhp(type) int type; { switch(type) { case PM_STRAW_GOLEM: return 20; case PM_ROPE_GOLEM: return 30; case PM_LEATHER_GOLEM: return 40; case PM_WOOD_GOLEM: return 50; case PM_FLESH_GOLEM: return 40; case PM_CLAY_GOLEM: return 50; case PM_STONE_GOLEM: return 60; case PM_IRON_GOLEM: return 80; default: return 0; } } #endif /* GOLEMS */ #endif /* OVLB */ #ifdef OVL1 /* * Alignment vs. yours determines monster's attitude to you. * ( some "animal" types are co-aligned, but also hungry ) */ boolean peace_minded(ptr) register struct permonst *ptr; { schar mal = ptr->maligntyp, ual = u.ualigntyp; if (always_peaceful(ptr)) return TRUE; if (always_hostile(ptr)) return FALSE; /* the monster is hostile if its alignment is different from the * player's */ if (sgn(mal) != sgn(ual)) return FALSE; /* Negative monster hostile to player with Amulet. */ if (mal < 0 && u.uhave_amulet) return FALSE; /* Last case: a chance of a co-aligned monster being * hostile. This chance is greater if the player has strayed * (u.ualign negative) or the monster is not strongly aligned. */ return !!rn2(16 + (u.ualign < -15 ? -15 : u.ualign)) && !!rn2(2 + abs(mal)); } /* Set malign to have the proper effect on player alignment if monster is * killed. Negative numbers mean it's bad to kill this monster; positive * numbers mean it's good. Since there are more hostile monsters than * peaceful monsters, the penalty for killing a peaceful monster should be * greater than the bonus for killing a hostile monster to maintain balance. * Rules: * it's bad to kill peaceful monsters, potentially worse to kill always- * peaceful monsters * it's never bad to kill a hostile monster, although it may not be good */ void set_malign(mtmp) struct monst *mtmp; { schar mal = mtmp->data->maligntyp; boolean coaligned = (sgn(mal) == sgn(u.ualigntyp)); if (always_peaceful(mtmp->data)) mtmp->malign = -3*max(5,abs(mal)); else if (always_hostile(mtmp->data)) { if (coaligned) mtmp->malign = 0; else mtmp->malign = max(5,abs(mal)); } else if (coaligned) { if (mtmp->mpeaceful) mtmp->malign = -3*max(3,abs(mal)); else /* renegade */ mtmp->malign = max(3,abs(mal)); } else /* not coaligned and therefore hostile */ mtmp->malign = abs(mal); } #endif /* OVL1 */ #ifdef OVLB static char syms[] = { 0, 1, RING_SYM, WAND_SYM, WEAPON_SYM, FOOD_SYM, GOLD_SYM, SCROLL_SYM, POTION_SYM, ARMOR_SYM, AMULET_SYM, TOOL_SYM, ROCK_SYM, GEM_SYM, #ifdef SPELLS SPBOOK_SYM, #endif S_MIMIC_DEF, S_MIMIC_DEF, S_MIMIC_DEF, }; void set_mimic_sym(mtmp) /* KAA, modified by ERS */ register struct monst *mtmp; { int roomno, rt; unsigned appear, ap_type; int s_sym; struct obj *otmp; int mx, my; if (!mtmp) return; mx = mtmp->mx; my = mtmp->my; mtmp->mimic = 1; roomno = inroom(mx, my); if (levl[mx][my].gmask) { ap_type = M_AP_GOLD; if (g_at(mx, my)->amount <= 32767) appear = g_at(mx, my)->amount; else appear = 32000 + rnd(767); } else if (OBJ_AT(mx, my)) { ap_type = M_AP_OBJECT; appear = level.objects[mx][my]->otyp; } else if (IS_DOOR(levl[mx][my].typ) || IS_WALL(levl[mx][my].typ) || levl[mx][my].typ == SDOOR || levl[mx][my].typ == SCORR) { ap_type = M_AP_FURNITURE; appear = S_cdoor; } else if (is_maze_lev && rn2(2)) { ap_type = M_AP_OBJECT; appear = STATUE; } else if (roomno < 0) { ap_type = M_AP_OBJECT; appear = BOULDER; } else if ((rt = rooms[roomno].rtype) == ZOO || rt == VAULT) { ap_type = M_AP_GOLD; appear = rn2(100)+10; /* number of gold pieces in pile */ } #ifdef ORACLE else if (rt == DELPHI) { if (rn2(2)) { ap_type = M_AP_OBJECT; appear = STATUE; } else { ap_type = M_AP_FURNITURE; appear = S_fountain; } } #endif #ifdef ALTARS else if (rt == TEMPLE) { ap_type = M_AP_FURNITURE; appear = S_altar; } #endif /* We won't bother with beehives, morgues, barracks, throne rooms * since they shouldn't contain too many mimics anyway... */ else if (rt >= SHOPBASE) { s_sym = get_shop_item(rt - SHOPBASE); if (s_sym < 0) { ap_type = M_AP_OBJECT; appear = -s_sym; } else { if (s_sym == RANDOM_SYM) s_sym = syms[rn2(sizeof(syms)-2) + 2]; goto assign_sym; } } else { s_sym = syms[rn2(sizeof syms)]; assign_sym: if (s_sym < 2) { ap_type = M_AP_FURNITURE; appear = s_sym ? S_upstair : S_dnstair; } else if (s_sym == GOLD_SYM) { ap_type = M_AP_GOLD; appear = rn2(100)+100; } else { ap_type = M_AP_OBJECT; if (s_sym == S_MIMIC_DEF) appear = STRANGE_OBJECT; else { otmp = mkobj( (char) s_sym, FALSE ); appear = otmp->otyp; free((genericptr_t) otmp); } } } mtmp->m_ap_type = ap_type; mtmp->mappearance = appear; } #endif /* OVLB */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.