home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume7
/
nethack3
/
part18
< prev
next >
Wrap
Internet Message Format
|
1989-07-31
|
56KB
Path: uunet!zephyr.ens.tek.com!tektronix!tekgen!tekred!saab!billr
From: billr@saab.CNA.TEK.COM (Bill Randle)
Newsgroups: comp.sources.games
Subject: v07i073: NetHack3 - display oriented dungeons & dragons (Ver. 3.0), Part18/38
Message-ID: <4326@tekred.CNA.TEK.COM>
Date: 24 Jul 89 05:05:27 GMT
Sender: nobody@tekred.CNA.TEK.COM
Lines: 2128
Approved: billr@saab.CNA.TEK.COM
Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 7, Issue 73
Archive-name: NetHack3/Part18
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 18 (of 38)."
# Contents: src/artifact.c src/makemon.c src/options.c
# Wrapped by billr@saab on Sun Jul 23 21:33:01 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/artifact.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/artifact.c'\"
else
echo shar: Extracting \"'src/artifact.c'\" \(6525 characters\)
sed "s/^X//" >'src/artifact.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)artifact.c 3.0 88/07/27
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
X
X#ifdef NAMED_ITEMS
X
X#include "artifact.h"
X
X/* the artifacts (currently weapons only) */
Xstatic const struct artifact artilist[] = {
X
X#define NO_ATTK 0, 0, 0, 0
X
X{ LONG_SWORD, "Excalibur", (SPFX_NOGEN | SPFX_SEEK | SPFX_DEFN |
X SPFX_SEARCH), 0,
X { 0, AD_PHYS, 5, 10 }, { 0, AD_DRLI, 0, 0} },
X
X{ KATANA, "Snickersnee", SPFX_RESTR, 0,
X { 0, AD_PHYS, 0, 8 }, NO_ATTK },
X
X/* Ah, never shall I forget the cry,
X * or the shriek that shrieked he,
X * As I gnashed my teeth, and from my sheath
X * I drew my Snickersnee!
X *
X * --Koko, Lord high executioner of Titipu
X * (From Sir W.S. Gilbert's "The Mikado")
X */
X
X{ AXE, "Cleaver", SPFX_RESTR, 0,
X { 0, AD_PHYS, 3, 12 }, NO_ATTK },
X
X/* Special purpose swords - various types */
X
X{ TWO_HANDED_SWORD, "Orcrist", SPFX_DCLAS, S_ORC,
X { 0, AD_PHYS, 5, 0 }, NO_ATTK },
X
X#ifdef TOLKIEN
X{ ELVEN_DAGGER, "Sting", (SPFX_WARN | SPFX_DCLAS), S_ORC,
X { 0, AD_PHYS, 5, 0 }, NO_ATTK },
X#else
X{ DAGGER, "Sting", (SPFX_WARN | SPFX_DCLAS), S_ORC,
X { 0, AD_PHYS, 5, 0 }, NO_ATTK },
X#endif
X
X{ LONG_SWORD, "Frost Brand", (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN), 0,
X { 0, AD_COLD, 5, 0 }, { 0, AD_COLD, 0, 0 } },
X
X{ LONG_SWORD, "Fire Brand", (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN), 0,
X { 0, AD_FIRE, 5, 0 }, { 0, AD_FIRE, 0, 0 } },
X
X/* Stormbringer only has a 2 because it can drain a level, providing 8 more */
X{ BROADSWORD, "Stormbringer", (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN |
X SPFX_DRLI), 0,
X { 0, AD_DRLI, 5, 2 }, { 0, AD_DRLI, 0, 0 } },
X
X{ LONG_SWORD, "Sunsword", (SPFX_RESTR | SPFX_DCLAS), 0, /* undead */
X { 0, AD_PHYS, 5, 0 }, NO_ATTK },
X
X{ BROADSWORD, "Dragonbane", (SPFX_RESTR | SPFX_DCLAS), S_DRAGON,
X { 0, AD_PHYS, 5, 0 }, NO_ATTK },
X
X{ LONG_SWORD, "Demonbane", (SPFX_RESTR | SPFX_DCLAS), 0, /* demons */
X { 0, AD_PHYS, 5, 0 }, NO_ATTK },
X
X{ LONG_SWORD, "Werebane", (SPFX_RESTR | SPFX_DCLAS), 0, /* weres */
X { 0, AD_PHYS, 5, 0 }, NO_ATTK },
X
X{ LONG_SWORD, "Giantslayer", (SPFX_RESTR | SPFX_DCLAS), 0, /* giants */
X { 0, AD_PHYS, 5, 0 }, NO_ATTK },
X
X{ LUCERN_HAMMER, "Ogresmasher", (SPFX_RESTR | SPFX_DCLAS), S_OGRE,
X { 0, AD_PHYS, 5, 0 }, NO_ATTK },
X
X{ LUCERN_HAMMER, "Thunderfist", (SPFX_RESTR | SPFX_ATTK), 0,
X { 0, AD_ELEC, 5, 24 }, NO_ATTK },
X
X{ MORNING_STAR, "Trollsbane", (SPFX_RESTR | SPFX_DCLAS), S_TROLL,
X { 0, AD_PHYS, 5, 0 }, NO_ATTK },
X
X/* ARRAY TERMINATOR */
X{ 0, "", 0, 0, NO_ATTK, NO_ATTK }
X};
X
Xvoid
Xmkartifact(otmp1)
Xstruct obj **otmp1;
X{
X register struct artifact *artif;
X register struct obj *otmp = *otmp1;
X register int n = 0;
X
X for(artif = artilist; artif->otyp; artif++)
X if(otmp->otyp == artif->otyp && !(artif->spfx & SPFX_NOGEN)) n++;
X
X if (n) {
X n = rnd(n);
X for(artif = artilist; artif->otyp && n > 0; ) {
X if(otmp->otyp == artif->otyp && !(artif->spfx & SPFX_NOGEN)) n--;
X if (n>0) artif++;
X }
X
X if(artif->otyp) *otmp1 = oname(otmp, artif->name, 0);
X }
X}
X
Xstatic struct artifact *
Xget_artifact(otmp)
Xstruct obj *otmp;
X{
X register struct artifact *artif;
X
X if(otmp)
X if(strlen(ONAME(otmp)))
X for(artif = artilist; artif->otyp; artif++)
X if(artif->otyp == otmp->otyp &&
X !strcmp(ONAME(otmp), artif->name)) return(artif);
X return((struct artifact *)0);
X}
X
Xboolean
Xis_artifact(otmp)
Xstruct obj *otmp;
X{
X return(get_artifact(otmp) != (struct artifact *)0);
X}
X
Xboolean
Xspec_ability(otmp, abil)
Xstruct obj *otmp;
Xunsigned abil;
X{
X struct artifact *arti = get_artifact(otmp);
X
X return(arti && (arti->spfx & abil));
X}
X
Xint
Xrestr_name(otmp, name) /* returns 1 if name is restricted for otmp->otyp */
Xregister struct obj *otmp;
Xregister char *name;
X{
X register struct artifact *artif;
X
X if(!strlen(name)) return(0);
X
X for(artif = artilist; artif->otyp; artif++)
X if(artif->otyp == otmp->otyp)
X if(artif->spfx & (SPFX_NOGEN | SPFX_RESTR))
X if(!strcmp(artif->name, name)) return(1);
X
X return(0);
X}
X
X# if defined(THEOLOGY) && defined(ALTARS)
Xstruct obj *
Xmk_aligned_artifact(align)
Xint align;
X{
X register struct artifact *artif;
X register struct obj *otmp;
X register int n = 0;
X
X for(artif = artilist; artif->otyp; artif++)
X if(align == artif->align && !(artif->spfx & SPFX_NOGEN)) n++;
X if (n) {
X n = rnd(n);
X for(artif = artilist; artif->otyp && n > 0; ) {
X if(align == artif->align && !(artif->spfx & SPFX_NOGEN))
X n--;
X if (n > 0) artif++;
X }
X if(artif->otyp) {
X otmp = mksobj((int)artif->otyp, FALSE);
X otmp = oname(otmp, artif->name, 0);
X return (otmp);
X }
X }
X return ((struct obj *) 0);
X}
X# endif
X
Xint
Xdefends(adtyp, otmp)
Xregister int adtyp;
Xregister struct obj *otmp;
X{
X register struct artifact *weap;
X
X if(weap = get_artifact(otmp))
X return(weap->defn.adtyp == adtyp);
X return(0);
X}
X
Xstatic int
Xspec_applies(weap, ptr)
Xregister struct artifact *weap;
Xstruct permonst *ptr;
X{
X if(!(weap->spfx & (SPFX_DMONS | SPFX_DCLAS | SPFX_ATTK)))
X return(1);
X
X if(weap->spfx & SPFX_DMONS)
X return((ptr == &mons[weap->mtype]));
X else if(weap->spfx & SPFX_DCLAS) {
X
X if(weap->mtype)
X return((weap->mtype == ptr->mlet));
X else {
X if(!strcmp(weap->name, "Sunsword"))
X return(is_undead(ptr));
X else if(!strcmp(weap->name, "Demonbane"))
X return(is_demon(ptr));
X else if(!strcmp(weap->name, "Werebane"))
X return(is_were(ptr));
X else if(!strcmp(weap->name, "Giantslayer"))
X return(is_giant(ptr));
X else impossible("Weird class specific weapon '%s'",
X weap->name);
X }
X } else if(weap->spfx & SPFX_ATTK) {
X switch(weap->attk.adtyp) {
X case AD_FIRE: return(!resists_fire(ptr));
X case AD_COLD: return(!resists_cold(ptr));
X case AD_ELEC: return(!resists_elec(ptr));
X case AD_DRLI: return(!resists_drli(ptr));
X case AD_STON: return(!resists_ston(ptr));
X default: impossible("Weird special attack for '%s'",
X weap->name);
X }
X }
X return(0);
X}
X
Xint
Xspec_abon(otmp, ptr)
Xstruct obj *otmp;
Xstruct permonst *ptr;
X{
X register struct artifact *weap;
X
X if((weap = get_artifact(otmp)))
X if(spec_applies(weap, ptr))
X return((weap->attk.damn) ? rnd((int)weap->attk.damn) : 0);
X return(0);
X}
X
Xint
Xspec_dbon(otmp, ptr, tmp)
Xregister struct obj *otmp;
Xregister struct permonst *ptr;
Xregister int tmp;
X{
X register struct artifact *weap;
X
X if((weap = get_artifact(otmp)))
X if(spec_applies(weap, ptr))
X return((weap->attk.damd) ? rnd((int)weap->attk.damd) : tmp);
X return(0);
X}
X#endif /* NAMED_ITEMS */
END_OF_FILE
if test 6525 -ne `wc -c <'src/artifact.c'`; then
echo shar: \"'src/artifact.c'\" unpacked with wrong size!
fi
# end of 'src/artifact.c'
fi
if test -f 'src/makemon.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/makemon.c'\"
else
echo shar: Extracting \"'src/makemon.c'\" \(28290 characters\)
sed "s/^X//" >'src/makemon.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)makemon.c 3.0 88/04/11
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
X
Xstruct monst zeromonst;
Xstatic int uncommon P((struct permonst *));
X
Xstatic int monstr[NUMMONS];
X
X#define m_initsgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 3)
X#define m_initlgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 10)
X#define toostrong(monindx, lev) (monstr[monindx] > lev)
X#define tooweak(monindx, lev) (monstr[monindx] < lev)
X
Xstatic void
Xm_initgrp(mtmp, x, y, n) /* make a group just like mtmp */
Xregister struct monst *mtmp;
Xregister int x, y, n;
X{
X coord mm;
X register int cnt = rnd(n);
X struct monst *mon;
X
X mm.x = x;
X mm.y = y;
X while(cnt--) {
X if (peace_minded(mtmp->data)) continue;
X /* Don't create groups of peaceful monsters since they'll get
X * in our way. If the monster has a percentage chance so some
X * are peaceful and some are not, the result will just be a
X * smaller group.
X */
X enexto(&mm, mm.x, mm.y);
X mon = makemon(mtmp->data, mm.x, mm.y);
X mon->mpeaceful = 0;
X set_malign(mon);
X /* Undo the second peace_minded() check in makemon(); if the
X * monster turned out to be peaceful the first time we didn't
X * create it at all; we don't want a second check.
X */
X }
X}
X
Xstatic void
Xm_initthrow(mtmp,otyp,oquan)
Xstruct monst *mtmp;
Xint otyp,oquan;
X{
X register struct obj *otmp;
X
X otmp = mksobj(otyp,FALSE);
X otmp->quan = 2 + rnd(oquan);
X otmp->owt = weight(otmp);
X#ifdef TOLKIEN
X if (otyp == ORCISH_ARROW) otmp->opoisoned = 1;
X#endif
X mpickobj(mtmp, otmp);
X}
X
Xstatic void
Xm_initweap(mtmp)
Xregister struct monst *mtmp;
X{
X register struct permonst *ptr = mtmp->data;
X#ifdef REINCARNATION
X if (dlevel==rogue_level) return;
X#endif
X/*
X * first a few special cases:
X *
X * giants get a boulder to throw sometimes.
X * ettins get clubs
X * kobolds get darts to throw
X * centaurs get some sort of bow & arrows or bolts
X * soldiers get all sorts of things.
X * kops get clubs & cream pies.
X */
X switch (mtmp->data->mlet) {
X case S_GIANT:
X if (rn2(2)) (void)mongets(mtmp, (ptr != &mons[PM_ETTIN]) ?
X BOULDER : CLUB);
X break;
X case S_HUMAN:
X if(is_mercenary(ptr))
X switch(monsndx(ptr)) {
X
X#ifdef ARMY
X case PM_SOLDIER:
X (void) mongets(mtmp, rn2(2) ? SPEAR : SHORT_SWORD);
X break;
X case PM_SERGEANT:
X (void) mongets(mtmp, rn2(2) ? FLAIL : MACE);
X break;
X case PM_LIEUTENANT:
X (void) mongets(mtmp, rn2(2) ? GLAIVE : LONG_SWORD);
X break;
X case PM_CAPTAIN:
X (void) mongets(mtmp, rn2(2) ? LONG_SWORD : SCIMITAR);
X break;
X#endif
X default: if (!rn2(4)) (void) mongets(mtmp, DAGGER);
X if (!rn2(7)) (void) mongets(mtmp, SPEAR);
X break;
X }
X break;
X
X case S_HUMANOID:
X#ifdef TOLKIEN
X if (monsndx(ptr) == PM_HOBBIT) {
X switch (rn2(3)) {
X case 0:
X (void)mongets(mtmp, DAGGER);
X break;
X case 1:
X (void)mongets(mtmp, ELVEN_DAGGER);
X break;
X }
X if (!rn2(10)) (void)mongets(mtmp, ELVEN_MITHRIL_COAT);
X } else if (is_dwarf(ptr)) {
X (void)mongets(mtmp, DWARVISH_CLOAK);
X (void)mongets(mtmp, IRON_SHOES);
X if (!rn2(4)) {
X (void)mongets(mtmp, DWARVISH_SHORT_SWORD);
X (void)mongets(mtmp,
X rn2(3) ? DWARVISH_MATTOCK : AXE);
X (void)mongets(mtmp, DWARVISH_IRON_HELM);
X (void)mongets(mtmp, DWARVISH_ROUNDSHIELD);
X if (!rn2(3))
X (void)mongets(mtmp, DWARVISH_MITHRIL_COAT);
X } else {
X (void)mongets(mtmp, PICK_AXE);
X }
X } else if (is_elf(ptr)) {
X (void)mongets(mtmp,
X rn2(2) ? ELVEN_MITHRIL_COAT : ELVEN_CLOAK);
X if (rn2(2)) (void)mongets(mtmp, ELVEN_LEATHER_HELM);
X if (rn2(3)) (void)mongets(mtmp, ELVEN_DAGGER);
X switch (rn2(3)) {
X case 0:
X if (!rn2(4)) (void)mongets(mtmp, ELVEN_SHIELD);
X (void)mongets(mtmp, ELVEN_SHORT_SWORD);
X (void)mongets(mtmp, ELVEN_BOW);
X m_initthrow(mtmp, ELVEN_ARROW, 12);
X break;
X case 1:
X (void)mongets(mtmp, ELVEN_BROADSWORD);
X if (rn2(2)) (void)mongets(mtmp, ELVEN_SHIELD);
X break;
X case 2:
X (void)mongets(mtmp, ELVEN_SPEAR);
X (void)mongets(mtmp, ELVEN_SHIELD);
X break;
X }
X }
X#else /* TOLKIEN */
X if (is_dwarf(ptr)) {
X (void)mongets(mtmp, IRON_SHOES);
X if (rn2(4) == 0) {
X (void)mongets(mtmp, SHORT_SWORD);
X (void)mongets(mtmp,
X (rn2(3) == 0) ? AXE : TWO_HANDED_SWORD);
X (void)mongets(mtmp, LARGE_SHIELD);
X if (rn2(3) == 0)
X (void)mongets(mtmp, DWARVISH_MITHRIL_COAT);
X } else {
X (void)mongets(mtmp, PICK_AXE);
X }
X } else if (is_elf(ptr)) {
X (void)mongets(mtmp, ELVEN_CLOAK);
X if (rn2(3)) (void)mongets(mtmp, DAGGER);
X switch (rn2(3)) {
X case 0:
X if (!rn2(4)) (void)mongets(mtmp, SMALL_SHIELD);
X (void)mongets(mtmp, SHORT_SWORD);
X (void)mongets(mtmp, BOW);
X m_initthrow(mtmp, ARROW, 12);
X break;
X case 1:
X (void)mongets(mtmp, BROADSWORD);
X if (rn2(2)) (void)mongets(mtmp, SMALL_SHIELD);
X break;
X case 2:
X (void)mongets(mtmp, SPEAR);
X (void)mongets(mtmp, SMALL_SHIELD);
X break;
X }
X }
X#endif /* TOLKIEN */
X break;
X# ifdef KOPS
X case S_KOP: /* create Keystone Kops with cream pies to
X * throw. As suggested by KAA. [MRS]
X */
X if (!rn2(4)) m_initthrow(mtmp, CREAM_PIE, 2);
X if (!rn2(3)) (void)mongets(mtmp, (rn2(2)) ? CLUB : RUBBER_HOSE);
X break;
X#endif
X case S_ORC:
X#ifdef TOLKIEN
X { int mm = monsndx(ptr);
X if(rn2(2)) (void)mongets(mtmp, ORCISH_HELM);
X if (mm == PM_MORDOR_ORC ||
X (mm == PM_ORC_CAPTAIN && rn2(2))) {
X if(rn2(2)) (void)mongets(mtmp, SCIMITAR);
X if(rn2(2)) (void)mongets(mtmp, ORCISH_SHIELD);
X if(rn2(2)) (void)mongets(mtmp, KNIFE);
X if(rn2(2)) (void)mongets(mtmp, ORCISH_CHAIN_MAIL);
X } else if (mm == PM_URUK_HAI || mm == PM_ORC_CAPTAIN) {
X if(rn2(2)) (void)mongets(mtmp, ORCISH_CLOAK);
X if(rn2(2)) (void)mongets(mtmp, ORCISH_SHORT_SWORD);
X if(rn2(2)) (void)mongets(mtmp, IRON_SHOES);
X if(rn2(2)) {
X (void)mongets(mtmp, ORCISH_BOW);
X m_initthrow(mtmp, ORCISH_ARROW, 12);
X }
X if(rn2(2)) (void)mongets(mtmp, URUK_HAI_SHIELD);
X } else if (mm != PM_ORC_SHAMAN) {
X (void)mongets(mtmp, (mm == PM_GOBLIN || rn2(2) == 0) ?
X ORCISH_DAGGER : SCIMITAR);
X }
X }
X#else /* TOLKIEN */
X { int mm = monsndx(ptr);
X if(rn2(2)) (void)mongets(mtmp, ORCISH_HELM);
X if (mm == PM_ORC_CAPTAIN) {
X if(rn2(2)) {
X if(rn2(2)) (void)mongets(mtmp, SCIMITAR);
X if(rn2(2)) (void)mongets(mtmp, SMALL_SHIELD);
X if(rn2(2)) (void)mongets(mtmp, KNIFE);
X if(rn2(2)) (void)mongets(mtmp, CHAIN_MAIL);
X } else {
X if(rn2(2)) (void)mongets(mtmp, SHORT_SWORD);
X if(rn2(2)) (void)mongets(mtmp, IRON_SHOES);
X if(rn2(2)) {
X (void)mongets(mtmp, BOW);
X m_initthrow(mtmp, ARROW, 12);
X }
X if(rn2(2)) (void)mongets(mtmp, SMALL_SHIELD);
X }
X } else if (mm != PM_ORC_SHAMAN) {
X (void)mongets(mtmp, (mm == PM_GOBLIN || rn2(2) == 0) ?
X DAGGER : SCIMITAR);
X }
X }
X#endif /* TOLKIEN */
X break;
X case S_KOBOLD:
X if (!rn2(4)) m_initthrow(mtmp, DART, 12);
X break;
X
X case S_CENTAUR:
X if (rn2(2)) {
X if(ptr == &mons[PM_FOREST_CENTAUR]) {
X (void)mongets(mtmp, BOW);
X m_initthrow(mtmp, ARROW, 12);
X } else {
X (void)mongets(mtmp, CROSSBOW);
X m_initthrow(mtmp, CROSSBOW_BOLT, 12);
X }
X }
X break;
X case S_WRAITH:
X (void)mongets(mtmp, KNIFE);
X (void)mongets(mtmp, LONG_SWORD);
X break;
X case S_DEMON:
X#ifdef HARD
X if (monsndx(ptr) == PM_BALROG) {
X (void)mongets(mtmp, BULLWHIP);
X (void)mongets(mtmp, BROADSWORD);
X break;
X }
X#endif
X /* prevent djinnis and mail daemons from leaving objects when
X * they vanish
X */
X if (!is_demon(ptr)) break;
X /* fall thru */
X/*
X * Now the general case, ~40% chance of getting some type
X * of weapon. TODO: Add more weapons types (use bigmonst());
X */
X default:
X switch(rnd(12)) {
X case 1:
X m_initthrow(mtmp, DART, 12);
X break;
X case 2:
X (void) mongets(mtmp, CROSSBOW);
X m_initthrow(mtmp, CROSSBOW_BOLT, 12);
X break;
X case 3:
X (void) mongets(mtmp, BOW);
X m_initthrow(mtmp, ARROW, 12);
X break;
X case 4:
X m_initthrow(mtmp, DAGGER, 3);
X break;
X case 5:
X (void) mongets(mtmp, AKLYS);
X break;
X default:
X break;
X }
X break;
X }
X}
X
Xstatic void
Xm_initinv(mtmp)
Xregister struct monst *mtmp;
X{
X register int cnt;
X register struct obj *otmp;
X register struct permonst *ptr = mtmp->data;
X#ifdef REINCARNATION
X if (dlevel==rogue_level) return;
X#endif
X/*
X * Soldiers get armour & rations - armour approximates their ac.
X * Nymphs may get mirror or potion of object detection.
X */
X switch(mtmp->data->mlet) {
X
X case S_HUMAN:
X if(is_mercenary(ptr)) {
X register int mac;
X
X if((mac = ptr->ac) < -1)
X mac += 7 + mongets(mtmp, (rn2(5)) ?
X PLATE_MAIL : CRYSTAL_PLATE_MAIL);
X else if(mac < 3)
X mac += 6 + mongets(mtmp, (rn2(3)) ?
X SPLINT_MAIL : BANDED_MAIL);
X else
X mac += 3 + mongets(mtmp, (rn2(3)) ?
X RING_MAIL : STUDDED_LEATHER_ARMOR);
X
X if(mac < 10) {
X mac += 1 + mongets(mtmp, HELMET);
X if(mac < 10) {
X mac += 1 + mongets(mtmp, SMALL_SHIELD);
X if(mac < 10) {
X mac += 1 + mongets(mtmp, ELVEN_CLOAK);
X if(mac < 10)
X mac += 1 +mongets(mtmp, LEATHER_GLOVES);
X }
X }
X }
X
X if(mac != 10) { /* make up the difference */
X otmp = mksobj(RIN_PROTECTION,FALSE);
X otmp->spe = (10 - mac);
X if(otmp->spe < 0) curse(otmp);
X mpickobj(mtmp, otmp);
X }
X#ifdef ARMY
X if(ptr != &mons[PM_GUARD]) {
X if (!rn2(3)) (void) mongets(mtmp, K_RATION);
X if (!rn2(2)) (void) mongets(mtmp, C_RATION);
X }
X#endif
X }
X break;
X
X case S_NYMPH:
X#ifdef MEDUSA
X if(!rn2(2)) (void) mongets(mtmp, MIRROR);
X#endif
X if(!rn2(2)) (void) mongets(mtmp, POT_OBJECT_DETECTION);
X break;
X
X case S_GIANT:
X if(mtmp->data == &mons[PM_MINOTAUR])
X (void) mongets(mtmp, WAN_DIGGING);
X else if (is_giant(mtmp->data)) {
X for(cnt = rn2((int)(mtmp->m_lev / 2)); cnt; cnt--) {
X do
X otmp = mkobj(GEM_SYM,FALSE);
X while (otmp->otyp >= LAST_GEM+5);
X otmp->quan = 2 + rnd(2);
X otmp->owt = weight(otmp);
X mpickobj(mtmp, otmp);
X }
X }
X break;
X#ifdef TOLKIEN
X case S_WRAITH:
X if(mtmp->data == &mons[PM_NAZGUL]) {
X otmp = mksobj(RIN_INVISIBILITY, FALSE);
X curse(otmp);
X mpickobj(mtmp, otmp);
X }
X break;
X#endif
X default:
X break;
X }
X}
X
X/*
X * called with [x,y] = coordinates;
X * [0,0] means anyplace
X * [u.ux,u.uy] means: call mnexto (if !in_mklev)
X *
X * In case we make a monster group, only return the one at [x,y].
X */
Xstruct monst *
Xmakemon(ptr, x, y)
Xregister struct permonst *ptr;
Xregister int x, y;
X{
X register struct monst *mtmp;
X register int ct;
X boolean anything = (!ptr);
X
X /* if caller wants random location, do it here */
X if(x == 0 && y == 0) {
X do {
X x = rn1(COLNO-3,2);
X y = rn2(ROWNO);
X } while(!goodpos(x, y));
X }
X
X /* if a monster already exists at the position, return */
X if(levl[x][y].mmask) return((struct monst *) 0);
X
X if(ptr){
X /* if you are to make a specific monster and it has
X already been genocided, return */
X if(ptr->geno & G_GENOD) return((struct monst *) 0);
X } else {
X /* make a random (common) monster. */
X#ifdef REINCARNATION
X if (!(ptr = (dlevel==rogue_level) ? roguemon() : rndmonst()))
X#else
X if(!(ptr = rndmonst()))
X#endif
X {
X#ifdef DEBUG
X pline("Warning: no monster.");
X#endif
X return((struct monst *) 0); /* no more monsters! */
X }
X }
X /* if it's unique, don't ever make it again */
X if (ptr->geno & G_UNIQ) ptr->geno &= G_GENOD;
X/* gotmon: /* label not referenced */
X mtmp = newmonst(ptr->pxlth);
X *mtmp = zeromonst; /* clear all entries in structure */
X for(ct = 0; ct < ptr->pxlth; ct++)
X ((char *) &(mtmp->mextra[0]))[ct] = 0;
X if(type_is_pname(ptr))
X Strcpy(NAME(mtmp), ptr->mname);
X mtmp->nmon = fmon;
X fmon = mtmp;
X mtmp->m_id = flags.ident++;
X mtmp->data = ptr;
X mtmp->mxlth = ptr->pxlth;
X
X mtmp->m_lev = adj_lev(ptr);
X#ifdef GOLEMS
X if (is_golem(ptr))
X mtmp->mhpmax = mtmp->mhp = golemhp(monsndx(ptr));
X else
X#endif /* GOLEMS */
X if(ptr->mlevel > 49) {
X /* "special" fixed hp monster
X * the hit points are encoded in the mlevel in a somewhat strange
X * way to fit in the 50..127 positive range of a signed character
X * above the 1..49 that indicate "normal" monster levels */
X mtmp->mhpmax = mtmp->mhp = 2*(ptr->mlevel - 6);
X mtmp->m_lev = mtmp->mhp / 4; /* approximation */
X } else if((ptr->mlet == S_DRAGON) && (ptr >= &mons[PM_GREY_DRAGON]))
X mtmp->mhpmax = mtmp->mhp = 80;
X else if(!mtmp->m_lev) mtmp->mhpmax = mtmp->mhp = rnd(4);
X else mtmp->mhpmax = mtmp->mhp = d((int)mtmp->m_lev, 8);
X mtmp->mx = x;
X mtmp->my = y;
X levl[x][y].mmask = 1;
X mtmp->mcansee = 1;
X mtmp->mpeaceful = peace_minded(ptr);
X
X switch(ptr->mlet) {
X case S_MIMIC:
X set_mimic_sym(mtmp);
X break;
X case S_SPIDER:
X case S_SNAKE:
X mtmp->mhide = mtmp->mundetected = 1;
X if(in_mklev)
X if(mtmp->mx && mtmp->my)
X (void) mkobj_at(0, mtmp->mx, mtmp->my);
X break;
X case S_CHAMELEON:
X /* If you're protected with a ring, don't create
X * any shape-changing chameleons -dgk
X */
X if (Protection_from_shape_changers)
X mtmp->cham = 0;
X else {
X mtmp->cham = 1;
X (void) newcham(mtmp, rndmonst());
X }
X break;
X case S_STALKER:
X case S_EEL:
X mtmp->minvis = 1;
X break;
X case S_LEPRECHAUN:
X mtmp->msleep = 1;
X break;
X case S_NYMPH:
X if(rn2(5) && !u.uhave_amulet) mtmp->msleep = 1;
X break;
X case S_UNICORN:
X if ((ptr==&mons[PM_WHITE_UNICORN] &&
X u.ualigntyp == U_LAWFUL) ||
X (ptr==&mons[PM_GREY_UNICORN] &&
X u.ualigntyp == U_NEUTRAL) ||
X (ptr==&mons[PM_BLACK_UNICORN] &&
X u.ualigntyp == U_CHAOTIC))
X mtmp->mpeaceful = 1;
X break;
X }
X if (ptr == &mons[PM_WIZARD_OF_YENDOR]) {
X mtmp->iswiz = 1;
X flags.no_of_wizards++;
X }
X
X if(in_mklev) {
X if(((is_ndemon(ptr)) ||
X (ptr == &mons[PM_WUMPUS]) ||
X#ifdef WORM
X (ptr == &mons[PM_LONG_WORM]) ||
X#endif
X (ptr == &mons[PM_GIANT_EEL])) && rn2(5))
X mtmp->msleep = 1;
X } else {
X if(x == u.ux && y == u.uy && ptr->mlet != S_GHOST) {
X mnexto(mtmp);
X if (ptr->mlet == S_MIMIC) set_mimic_sym(mtmp);
X }
X }
X#ifdef HARD
X if(is_dprince(ptr)) {
X mtmp->mpeaceful = mtmp->minvis = 1;
X# ifdef NAMED_ITEMS
X if(uwep)
X if(!strcmp(ONAME(uwep), "Excalibur"))
X mtmp->mpeaceful = mtmp->mtame = 0;
X# endif
X }
X#endif
X#ifdef WORM
X if(ptr == &mons[PM_LONG_WORM] && getwn(mtmp)) initworm(mtmp);
X#endif
X set_malign(mtmp); /* having finished peaceful changes */
X if(anything) {
X if((ptr->geno & G_SGROUP) && rn2(2))
X m_initsgrp(mtmp, mtmp->mx, mtmp->my);
X else if(ptr->geno & G_LGROUP) {
X if(rn2(3)) m_initlgrp(mtmp, mtmp->mx, mtmp->my);
X else m_initsgrp(mtmp, mtmp->mx, mtmp->my);
X }
X }
X
X if(is_armed(ptr))
X m_initweap(mtmp); /* equip with weapons / armour */
X m_initinv(mtmp); /* add on a few special items */
X
X return(mtmp);
X}
X
Xvoid
Xenexto(cc, xx,yy)
Xcoord *cc;
Xregister xchar xx, yy;
X{
X register xchar x,y;
X coord foo[15], *tfoo;
X int range, i;
X
X tfoo = foo;
X range = 1;
X do { /* full kludge action. */
X for(x = xx-range; x <= xx+range; x++)
X if(goodpos(x, yy-range)) {
X tfoo->x = x;
X (tfoo++)->y = yy-range;
X if(tfoo == &foo[15]) goto foofull;
X }
X for(x = xx-range; x <= xx+range; x++)
X if(goodpos(x,yy+range)) {
X tfoo->x = x;
X (tfoo++)->y = yy+range;
X if(tfoo == &foo[15]) goto foofull;
X }
X for(y = yy+1-range; y < yy+range; y++)
X if(goodpos(xx-range,y)) {
X tfoo->x = xx-range;
X (tfoo++)->y = y;
X if(tfoo == &foo[15]) goto foofull;
X }
X for(y = yy+1-range; y < yy+range; y++)
X if(goodpos(xx+range,y)) {
X tfoo->x = xx+range;
X (tfoo++)->y = y;
X if(tfoo == &foo[15]) goto foofull;
X }
X range++;
X } while(tfoo == foo);
Xfoofull:
X i = rn2(tfoo - foo);
X cc->x = foo[i].x;
X cc->y = foo[i].y;
X return;
X}
X
Xint
Xgoodpos(x, y)
X{
X#ifdef STUPID
X if (x < 1 || x > COLNO-2 || y < 1 || y > ROWNO-2 ||
X levl[x][y].mmask || !ACCESSIBLE(levl[x][y].typ))
X return 0;
X if (IS_DOOR(levl[x][y].typ) &&
X (levl[x][y].doormask & (D_LOCKED | D_CLOSED)))
X return 0;
X return !((x == u.ux && y == u.uy) || sobj_at(BOULDER, x, y));
X#else
X return
X ! (x < 1 || x > COLNO-2 || y < 1 || y > ROWNO-2 ||
X levl[x][y].mmask || !ACCESSIBLE(levl[x][y].typ) ||
X (IS_DOOR(levl[x][y].typ) &&
X (levl[x][y].doormask & (D_LOCKED | D_CLOSED)) )
X || (x == u.ux && y == u.uy)
X || sobj_at(BOULDER, x, y)
X );
X#endif /* STUPID */
X}
X
Xvoid
Xrloc(mtmp)
Xstruct monst *mtmp;
X{
X register int tx, ty;
X
X#ifdef WORM /* do not relocate worms */
X if(mtmp->wormno && mtmp->mx) return;
X#endif
X /* if the wiz teleports away to heal, try the up staircase,
X to block the player's escaping before he's healed */
X if(!mtmp->iswiz || !goodpos(tx = xupstair, ty = yupstair))
X do {
X tx = rn1(COLNO-3,2);
X ty = rn2(ROWNO);
X } while(!goodpos(tx,ty));
X if(mtmp->mx != 0 && mtmp->my != 0)
X levl[mtmp->mx][mtmp->my].mmask = 0;
X mtmp->mx = tx;
X mtmp->my = ty;
X levl[tx][ty].mmask = 1;
X if(u.ustuck == mtmp){
X if(u.uswallow) {
X u.ux = tx;
X u.uy = ty;
X docrt();
X } else u.ustuck = 0;
X }
X pmon(mtmp);
X set_apparxy(mtmp);
X}
X
Xstruct monst *
Xmkmon_at(name, x, y)
Xchar *name;
Xregister int x,y;
X{
X register int ct;
X register struct permonst *ptr;
X
X for(ct = PM_CHAMELEON; ct >= 0; ct--) { /* Chameleon is last monster */
X ptr = &mons[ct];
X if(!strcmp(ptr->mname, name))
X return(makemon(ptr, x, y));
X }
X return((struct monst *)0);
X}
X
Xstatic int
Xcmnum() { /* return the number of "common" monsters */
X
X int i, count;
X
X for(i = count = 0; mons[i].mlet; i++)
X if(!uncommon(&mons[i])) count++;
X
X return(count);
X}
X
Xstatic int
Xuncommon(ptr)
Xstruct permonst *ptr;
X{
X return (ptr->geno & (G_GENOD | G_NOGEN | G_UNIQ)) ||
X (!Inhell ? ptr->geno & G_HELL : ptr->maligntyp > 0);
X}
X
X/* This routine is designed to return an integer value which represents
X * an approximation of monster strength. It uses a similar method of
X * determination as "experience()" to arrive at the strength.
X */
Xstatic int
Xmstrength(ptr)
Xstruct permonst *ptr;
X{
X int i, tmp2, n, tmp = ptr->mlevel;
X
X if(tmp > 49) /* special fixed hp monster */
X tmp = 2*(tmp - 6) / 4;
X
X/* For creation in groups */
X n = (!!(ptr->geno & G_SGROUP));
X n += (!!(ptr->geno & G_LGROUP)) << 1;
X
X/* For higher ac values */
X n += (ptr->ac < 0);
X
X/* For very fast monsters */
X n += (ptr->mmove >= 18);
X
X/* For each attack and "special" attack */
X for(i = 0; i < NATTK; i++) {
X
X tmp2 = ptr->mattk[i].aatyp;
X n += (tmp2 > 0);
X n += (tmp2 == AT_MAGC);
X }
X
X/* For each "special" damage type */
X for(i = 0; i < NATTK; i++) {
X
X tmp2 = ptr->mattk[i].adtyp;
X if((tmp2 == AD_DRLI) || (tmp2 == AD_STON)) n += 2;
X else n += (tmp2 != AD_PHYS);
X n += ((ptr->mattk[i].damd * ptr->mattk[i].damn) > 23);
X }
X
X/* Finally, adjust the monster level 0 <= n <= 24 (approx.) */
X if(n == 0) tmp--;
X else if(n >= 6) tmp += ( n / 2 );
X else tmp += ( n / 3 + 1);
X
X return((tmp >= 0) ? tmp : 0);
X}
X
Xvoid
Xinit_monstr()
X{
X register int ct;
X
X for(ct = 0; mons[ct].mlet; ct++)
X monstr[ct] = mstrength(&(mons[ct]));
X}
X
Xstruct permonst *
Xrndmonst() { /* select a random monster */
X register struct permonst *ptr;
X register int i, ct;
X register int zlevel;
X static int minmlev, maxmlev, accept;
X static long oldmoves = 0L; /* != 1, starting value of moves */
X
X if(oldmoves != moves) { /* must recalculate accept */
X oldmoves = moves;
X zlevel = u.uhave_amulet ? MAXLEVEL : dlevel;
X if(cmnum() <= 0) {
X#ifdef DEBUG
X pline("cmnum() fails!");
X#endif
X return((struct permonst *) 0);
X }
X
X /* determine the level of the weakest monster to make. */
X minmlev = zlevel/6;
X /* determine the level of the strongest monster to make. */
X maxmlev = (zlevel + u.ulevel)>>1;
X/*
X * Find out how many monsters exist in the range we have selected.
X */
X for(accept = ct = 0 ; mons[ct].mlet; ct++) {
X ptr = &(mons[ct]);
X if(uncommon(ptr)) continue;
X if(tooweak(ct, minmlev) || toostrong(ct, maxmlev))
X continue;
X accept += (ptr->geno & G_FREQ);
X }
X }
X
X if(!accept) {
X#ifdef DEBUG
X pline("no accept!");
X#endif
X return((struct permonst *) 0);
X }
X/*
X * Now, select a monster at random.
X */
X ct = rnd(accept);
X for(i = 0; mons[i].mlet && ct > 0; i++) {
X ptr = &(mons[i]);
X if(uncommon(ptr)) continue;
X if(tooweak(i, minmlev) || toostrong(i, maxmlev))
X continue;
X ct -= (ptr->geno & G_FREQ);
X }
X if(ct > 0) {
X#ifdef DEBUG
X pline("no count!");
X#endif
X return((struct permonst *) 0);
X }
X return(ptr);
X}
X
X/* The routine below is used to make one of the multiple types
X * of a given monster class. It will return 0 if no monsters
X * in that class can be made.
X */
X
Xstruct permonst *
Xmkclass(mlet)
Xchar mlet;
X{
X register int first, last, num = 0;
X
X if(!mlet) {
X impossible("mkclass called with null arg!");
X return((struct permonst *) 0);
X }
X/* Assumption #1: monsters of a given class are contiguous in the
X * mons[] array.
X */
X for(first = 0; mons[first].mlet != mlet; first++)
X if(!mons[first].mlet) return((struct permonst *) 0);
X
X for(last = first; mons[last].mlet && mons[last].mlet == mlet; last++)
X if(!(mons[last].geno & (G_GENOD | G_NOGEN | G_UNIQ)))
X num += mons[last].geno & G_FREQ;
X
X if(!num) return((struct permonst *) 0);
X
X/* Assumption #2: monsters of a given class are presented in ascending
X * order of strength.
X */
X for(num = rnd(num); num > 0; first++)
X if(!(mons[first].geno & (G_GENOD | G_NOGEN | G_UNIQ))) { /* consider it */
X /* skew towards lower value monsters at lower exp. levels */
X if(adj_lev(&mons[first]) > (u.ulevel*2)) num--;
X num -= mons[first].geno & G_FREQ;
X }
X first--; /* correct an off-by-one error */
X
X return(&mons[first]);
X}
X
Xint
Xadj_lev(ptr) /* adjust strength of monsters based on dlevel and u.ulevel */
Xregister struct permonst *ptr;
X{
X int tmp, tmp2;
X
X if((tmp = ptr->mlevel) > 49) return(50); /* "special" demons/devils */
X tmp2 = (dlevel - tmp);
X if(tmp2 < 0) tmp--; /* if mlevel > dlevel decrement tmp */
X else tmp += (tmp2 / 5); /* else increment 1 per five diff */
X
X tmp2 = (u.ulevel - ptr->mlevel); /* adjust vs. the player */
X if(tmp2 > 0) tmp += (tmp2 / 4); /* level as well */
X
X tmp2 = 3 * ptr->mlevel/ 2; /* crude upper limit */
X return((tmp > tmp2) ? tmp2 : (tmp > 0 ? tmp : 0)); /* 0 lower limit */
X}
X
Xstruct permonst *
Xgrow_up(mtmp) /* mon mtmp "grows up" to a bigger version. */
Xregister struct monst *mtmp;
X{
X register int newtype;
X register struct permonst *ptr = mtmp->data;
X
X if (ptr->mlevel >= 50 || mtmp->mhpmax <= 8*mtmp->m_lev)
X return ptr;
X newtype = little_to_big(monsndx(ptr));
X if (++mtmp->m_lev >= mons[newtype].mlevel) {
X if (mons[newtype].geno & G_GENOD) {
X pline("As %s grows up into a%s %s, %s dies!",
X mon_nam(mtmp),
X index(vowels,*mons[newtype].mname) ? "n" : "",
X mons[newtype].mname,
X mon_nam(mtmp));
X mondied(mtmp);
X return (struct permonst *)0;
X }
X mtmp->data = &mons[newtype];
X mtmp->m_lev = mons[newtype].mlevel;
X }
X if (mtmp->m_lev > 3*mtmp->data->mlevel / 2)
X mtmp->m_lev = 3*mtmp->data->mlevel / 2;
X return(mtmp->data);
X}
X
Xint
Xmongets(mtmp, otyp)
Xregister struct monst *mtmp;
Xregister int otyp;
X{
X register struct obj *otmp;
X
X if((otmp = (otyp) ? mksobj(otyp,FALSE) : mkobj(otyp,FALSE))) {
X if (mtmp->data->mlet == S_DEMON) {
X /* demons always get cursed objects */
X curse(otmp);
X }
X mpickobj(mtmp, otmp);
X return(otmp->spe);
X } else return(0);
X}
X
X#ifdef REINCARNATION
Xstruct permonst *
Xroguemon()
X{
X/* Make a monster for a Rogue-like level; only capital letters. There are
X * no checks for "too hard" or "too easy", though dragons are specifically
X * ruled out because playtesting showed they made the level too hard.
X * Modified from rndmonst().
X */
X#define isupper(x) ('A'<=(x) && (x)<='Z')
X register struct permonst *ptr;
X register int accept,ct,i;
X
X /* See how many there are. */
X accept = 0;
X for(ct = PM_APE ; isupper(mons[ct].mlet); ct++) {
X if (mons[ct].mlet == S_DRAGON) continue;
X ptr = &(mons[ct]);
X if(uncommon(ptr)) continue;
X accept += (ptr->geno & G_FREQ);
X }
X if(!accept) return((struct permonst *) 0);
X
X /* Now, select one at random. */
X ct = rnd(accept);
X for(i = PM_APE; isupper(mons[i].mlet) && ct > 0; i++) {
X if (mons[i].mlet == S_DRAGON) continue;
X ptr = &(mons[i]);
X if(uncommon(ptr)) continue;
X ct -= (ptr->geno & G_FREQ);
X }
X if(ct > 0) return((struct permonst *) 0);
X return(ptr);
X}
X#endif
X
X#ifdef GOLEMS
Xint
Xgolemhp(type)
Xint type;
X{
X switch(type) {
X case PM_STRAW_GOLEM: return 20;
X case PM_ROPE_GOLEM: return 30;
X case PM_LEATHER_GOLEM: return 40;
X case PM_WOOD_GOLEM: return 50;
X case PM_FLESH_GOLEM: return 40;
X case PM_CLAY_GOLEM: return 50;
X case PM_STONE_GOLEM: return 60;
X case PM_IRON_GOLEM: return 80;
X default: return 0;
X }
X}
X#endif /* GOLEMS */
X
X/*
X * Alignment vs. yours determines monster's attitude to you.
X * ( some "animal" types are co-aligned, but also hungry )
X */
Xboolean
Xpeace_minded(ptr)
Xregister struct permonst *ptr;
X{
X schar mal = ptr->maligntyp, ual = u.ualigntyp;
X
X if (always_peaceful(ptr)) return TRUE;
X if (always_hostile(ptr)) return FALSE;
X
X /* the monster is hostile if its alignment is different from the
X * player's */
X if (sgn(mal) != sgn(ual)) return FALSE;
X
X /* Negative monster hostile to player with Amulet. */
X if (mal < 0 && u.uhave_amulet) return FALSE;
X
X /* Last case: a chance of a co-aligned monster being
X * hostile. This chance is greater if the player has strayed
X * (u.ualign negative) or the monster is not strongly aligned.
X */
X return !!rn2(16 + (u.ualign < -15 ? -15 : u.ualign)) &&
X !!rn2(2 + abs(mal));
X}
X
X/* Set malign to have the proper effect on player alignment if monster is
X * killed. Negative numbers mean it's bad to kill this monster; positive
X * numbers mean it's good. Since there are more hostile monsters than
X * peaceful monsters, the penalty for killing a peaceful monster should be
X * greater than the bonus for killing a hostile monster to maintain balance.
X * Rules:
X * it's bad to kill peaceful monsters, potentially worse to kill always-
X * peaceful monsters
X * it's never bad to kill a hostile monster, although it may not be good
X */
Xvoid
Xset_malign(mtmp)
Xstruct monst *mtmp;
X{
X schar mal = mtmp->data->maligntyp;
X boolean coaligned = (sgn(mal) == sgn(u.ualigntyp));
X
X if (always_peaceful(mtmp->data))
X mtmp->malign = -3*max(5,abs(mal));
X else if (always_hostile(mtmp->data)) {
X if (coaligned)
X mtmp->malign = 0;
X else
X mtmp->malign = max(5,abs(mal));
X } else if (coaligned) {
X if (mtmp->mpeaceful)
X mtmp->malign = -3*max(3,abs(mal));
X else /* renegade */
X mtmp->malign = max(3,abs(mal));
X } else /* not coaligned and therefore hostile */
X mtmp->malign = abs(mal);
X}
X
Xstatic char syms[] = { 0, 0, RING_SYM, WAND_SYM, WEAPON_SYM, FOOD_SYM, GOLD_SYM,
X SCROLL_SYM, POTION_SYM, ARMOR_SYM, AMULET_SYM, TOOL_SYM, ROCK_SYM,
X GEM_SYM,
X#ifdef SPELLS
X SPBOOK_SYM,
X#endif
X S_MIMIC_DEF, S_MIMIC_DEF, S_MIMIC_DEF,
X};
X
Xvoid
Xset_mimic_sym(mtmp) /* KAA */
Xregister struct monst *mtmp;
X{
X int roomno, rt;
X char sym;
X if (!mtmp) return;
X
X syms[0] = UP_SYM;
X syms[1] = DN_SYM;
X
X mtmp->mimic = 1;
X roomno = inroom(mtmp->mx, mtmp->my);
X if (levl[mtmp->mx][mtmp->my].gmask)
X sym = GOLD_SYM;
X else if (levl[mtmp->mx][mtmp->my].omask)
X sym = o_at(mtmp->mx,mtmp->my)->olet;
X else if (IS_DOOR(levl[mtmp->mx][mtmp->my].typ) ||
X IS_WALL(levl[mtmp->mx][mtmp->my].typ))
X sym = DOOR_SYM;
X else if (is_maze_lev)
X sym = rn2(2) ? ROCK_SYM : syms[rn2(sizeof syms)];
X else if (roomno < 0)
X sym = ROCK_SYM;
X else if ((rt = rooms[roomno].rtype) == ZOO || rt == VAULT)
X sym = GOLD_SYM;
X#ifdef ORACLE
X else if (rt == DELPHI)
X sym = rn2(2) ? ROCK_SYM : FOUNTAIN_SYM;
X#endif
X#ifdef ALTARS
X else if (rt == TEMPLE)
X sym = ALTAR_SYM;
X#endif
X /* We won't bother with beehives, morgues, barracks, throne rooms
X * since they shouldn't contain mimics anyway...
X */
X else if (rt >= SHOPBASE) {
X int s_sym = get_shop_item(rt - SHOPBASE);
X
X if (s_sym < 0) sym = objects[-sym].oc_olet;
X else if (sym == RANDOM_SYM)
X sym = syms[rn2(sizeof(syms)-2) + 2];
X else sym = s_sym;
X } else sym = syms[rn2(sizeof syms)];
X mtmp->mappearance = sym;
X}
END_OF_FILE
if test 28290 -ne `wc -c <'src/makemon.c'`; then
echo shar: \"'src/makemon.c'\" unpacked with wrong size!
fi
# end of 'src/makemon.c'
fi
if test -f 'src/options.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/options.c'\"
else
echo shar: Extracting \"'src/options.c'\" \(16326 characters\)
sed "s/^X//" >'src/options.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)options.c 3.0 88/11/09
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
Xstatic boolean set_order;
X
Xstatic void nmcpy();
X
Xvoid
Xinitoptions()
X{
X register char *opts;
X
X flags.time = flags.nonews = flags.notombstone = flags.end_own =
X flags.standout = flags.nonull = flags.ignintr = FALSE;
X flags.no_rest_on_space = flags.invlet_constant = TRUE;
X flags.end_top = 5;
X flags.end_around = 4;
X flags.female = FALSE; /* players are usually male */
X flags.sortpack = TRUE;
X flags.soundok = TRUE;
X flags.verbose = TRUE;
X flags.confirm = TRUE;
X flags.safe_dog = TRUE;
X flags.silent = flags.pickup = TRUE;
X nmcpy(pl_fruit, objects[SLIME_MOLD].oc_name, PL_FSIZ);
X flags.num_pad = FALSE;
X#ifdef MSDOS
X#ifdef DECRAINBOW
X flags.DECRainbow = FALSE;
X#endif
X#ifdef DGK
X flags.IBMBIOS =
X flags.rawio = FALSE;
X#endif
X read_config_file();
X#endif /* MSDOS */
X if(opts = getenv("NETHACKOPTIONS"))
X parseoptions(opts,TRUE);
X (void)fruitadd(pl_fruit);
X objects[SLIME_MOLD].oc_name = "\033";
X /* Put something untypable in there */
X /* We cannot just use NULL because that marks the end of objects */
X}
X
Xstatic void
Xnmcpy(dest, source, maxlen)
X char *dest, *source;
X int maxlen;
X{
X char *cs, *cd;
X int count;
X
X cd = dest;
X cs = source;
X for(count = 1; count < maxlen; count++) {
X if(*cs == ',' || *cs == '\0') break; /*exit on \0 terminator*/
X *cd++ = *cs++;
X }
X *cd = 0;
X}
X
X/*
X * escapes: escape expansion for showsyms. C-style escapes understood include
X * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix
X * for control characters is also understood, and \[mM] followed by any of the
X * previous forms or by a character has the effect of 'meta'-ing the value (so
X * that the alternate character set will be enabled).
X */
Xvoid
Xescapes(cp, tp)
Xchar *cp, *tp;
X{
X while (*cp)
X {
X int cval = 0, meta = 0;
X
X if (*cp == '\\' && index("mM", cp[1])) {
X meta = 1;
X cp += 2;
X }
X if (*cp == '\\' && index("0123456789xXoO", cp[1]))
X {
X char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
X int dcount = 0;
X
X cp++;
X if (*cp == 'x' || *cp == 'X')
X for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
X cval = (cval * 16) + (dp - hex) / 2;
X else if (*cp == 'o' || *cp == 'O')
X for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++)
X cval = (cval * 8) + (*cp - '0');
X else
X for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++)
X cval = (cval * 10) + (*cp - '0');
X }
X else if (*cp == '\\') /* C-style character escapes */
X {
X switch (*++cp)
X {
X case '\\': cval = '\\'; break;
X case 'n': cval = '\n'; break;
X case 't': cval = '\t'; break;
X case 'b': cval = '\b'; break;
X case 'r': cval = '\r'; break;
X default: cval = *cp;
X }
X cp++;
X }
X else if (*cp == '^') /* expand control-character syntax */
X {
X cval = (*++cp & 0x1f);
X cp++;
X }
X else
X cval = *cp++;
X if (meta)
X cval |= 0x80;
X *tp++ = cval;
X }
X *tp = '\0';
X}
X
Xvoid
Xparseoptions(opts, from_env)
Xregister char *opts;
Xboolean from_env;
X{
X register char *op;
X/*
X register char *op2;
X*/
X unsigned num;
X boolean negated;
X
X if(op = index(opts, ',')) {
X *op++ = 0;
X parseoptions(op, from_env);
X }
X/*
X if(op = index(opts, ' ')) {
X op2 = op;
X while(*op++)
X if(*op != ' ') *op2++ = *op;
X }
X*/
X if(!*opts) return;
X negated = FALSE;
X while((*opts == '!') || !strncmp(opts, "no", 2)) {
X if(*opts == '!') opts++; else opts += 2;
X negated = !negated;
X }
X
X#ifndef MSDOS
X if (!strncmp(opts, "standout", 4)) {
X flags.standout = !negated;
X return;
X }
X
X if (!strncmp(opts, "null", 4)) {
X flags.nonull = negated;
X return;
X }
X#endif
X
X if (!strncmp(opts, "ignintr", 3)) {
X flags.ignintr = !negated;
X return;
X }
X
X if (!strncmp(opts, "tombstone", 4)) {
X flags.notombstone = negated;
X return;
X }
X
X#ifdef NEWS
X if (!strncmp(opts, "news", 4)) {
X flags.nonews = negated;
X return;
X }
X#endif
X
X if (!strncmp(opts, "confirm", 4)) {
X flags.confirm = !negated;
X return;
X }
X if (!strncmp(opts, "safe", 4)) {
X flags.safe_dog = !negated;
X return;
X }
X
X if (!strncmp(opts, "silent", 4)) {
X flags.silent = !negated;
X return;
X }
X
X if (!strncmp(opts, "verbose", 4)) {
X flags.verbose = !negated;
X return;
X }
X
X if (!strncmp(opts, "pickup", 4)) {
X flags.pickup = !negated;
X return;
X }
X
X if (!strncmp(opts, "number_pad", 4)) {
X flags.num_pad = !negated;
X return;
X }
X
X#ifdef DGK
X if (!strncmp(opts, "IBM", 3)) {
X flags.IBMBIOS = !negated;
X return;
X }
X
X if (!strncmp(opts, "rawio", 4)) {
X if (from_env)
X flags.rawio = !negated;
X else
X pline("\"rawio\" settable only from %s.", configfile);
X return;
X }
X
X#ifdef DECRAINBOW
X if (!strncmp(opts, "DEC", 3)) {
X flags.DECRainbow = !negated;
X return;
X }
X#endif /* DECRAINBOW */
X#endif
X
X if (!strncmp(opts, "sort", 4)) {
X flags.sortpack = !negated;
X return;
X }
X
X /*
X * the order to list the pack
X */
X if (!strncmp(opts, "packorder", 4)) {
X register char *sp, *tmp;
X int tmpend;
X
X op = index(opts,':');
X if(!op) goto bad;
X op++; /* skip : */
X
X /* Missing characters in new order are filled in at the end
X * from inv_order.
X */
X for (sp = op; *sp; sp++)
X if (!index(inv_order, *sp))
X goto bad; /* bad char in order */
X else if (index(sp + 1, *sp))
X goto bad; /* dup char in order */
X tmp = (char *) alloc((unsigned)(strlen(inv_order)+1));
X Strcpy(tmp, op);
X for (sp = inv_order, tmpend = strlen(tmp); *sp; sp++)
X if (!index(tmp, *sp)) {
X tmp[tmpend++] = *sp;
X tmp[tmpend] = 0;
X }
X Strcpy(inv_order, tmp);
X free((genericptr_t)tmp);
X set_order = TRUE;
X return;
X }
X
X if (!strncmp(opts, "time", 4)) {
X flags.time = !negated;
X flags.botl = 1;
X return;
X }
X
X if (!strncmp(opts, "rest_on_space", 4)) {
X flags.no_rest_on_space = negated;
X return;
X }
X
X if (!strncmp(opts, "fixinv", 3)) {
X flags.invlet_constant = !negated;
X if(!from_env && flags.invlet_constant) reassign ();
X return;
X }
X
X if (!strncmp(opts, "male", 4)) {
X if(!from_env && flags.female != negated)
X pline("That is not anatomically possible.");
X else
X flags.female = negated;
X return;
X }
X if (!strncmp(opts, "female", 3)) {
X if(!from_env && flags.female == negated)
X pline("That is not anatomically possible.");
X else
X flags.female = !negated;
X return;
X }
X
X /* name:string */
X if (!strncmp(opts, "name", 4)) {
X if(!from_env) {
X#ifdef MSDOS
X pline("\"name\" settable only from %s.", configfile);
X#else
X pline("The playername can be set only from NETHACKOPTIONS.");
X#endif
X return;
X }
X op = index(opts,':');
X if(!op) goto bad;
X nmcpy(plname, op+1, sizeof(plname)-1);
X return;
X }
X
X /* graphics:string */
X if (!strncmp(opts, "graphics", 4)) {
X if(!from_env) {
X#ifdef MSDOS
X pline("\"graphics\" settable only from %s.", configfile);
X#else
X pline("The graphics string can be set only from NETHACKOPTIONS.");
X#endif
X return;
X }
X op = index(opts,':');
X if(!op)
X goto bad;
X else
X opts = op + 1;
X escapes(opts, opts);
X#define SETPCHAR(f, n) showsyms.f = (strlen(opts) > n) ? opts[n] : defsyms.f
X SETPCHAR(stone, 0);
X SETPCHAR(vwall, 1);
X SETPCHAR(hwall, 2);
X SETPCHAR(tlcorn, 3);
X SETPCHAR(trcorn, 4);
X SETPCHAR(blcorn, 5);
X SETPCHAR(brcorn, 6);
X SETPCHAR(crwall, 7);
X SETPCHAR(tuwall, 8);
X SETPCHAR(tdwall, 9);
X SETPCHAR(tlwall, 10);
X SETPCHAR(trwall, 11);
X SETPCHAR(vbeam, 12);
X SETPCHAR(hbeam, 13);
X SETPCHAR(lslant, 14);
X SETPCHAR(rslant, 15);
X SETPCHAR(door, 16);
X SETPCHAR(room, 17);
X SETPCHAR(corr, 18);
X SETPCHAR(upstair, 19);
X SETPCHAR(dnstair, 20);
X SETPCHAR(trap, 21);
X SETPCHAR(web, 22);
X SETPCHAR(pool, 23);
X#ifdef FOUNTAINS
X SETPCHAR(fountain, 24);
X#endif
X#ifdef SINKS
X SETPCHAR(sink, 25);
X#endif
X#ifdef THRONES
X SETPCHAR(throne, 26);
X#endif
X#ifdef ALTARS
X SETPCHAR(altar, 27);
X#endif
X#ifdef STRONGHOLD
X SETPCHAR(upladder, 28);
X SETPCHAR(dnladder, 29);
X SETPCHAR(dbvwall, 30);
X SETPCHAR(dbhwall, 31);
X#endif
X#undef SETPCHAR
X return;
X }
X
X /* endgame:5t[op] 5a[round] o[wn] */
X if (!strncmp(opts, "endgame", 3)) {
X op = index(opts,':');
X if(!op) goto bad;
X op++;
X while(*op) {
X num = 1;
X if(digit(*op)) {
X num = atoi(op);
X while(digit(*op)) op++;
X } else
X if(*op == '!') {
X negated = !negated;
X op++;
X }
X switch(*op) {
X case 't':
X flags.end_top = num;
X break;
X case 'a':
X flags.end_around = num;
X break;
X case 'o':
X flags.end_own = !negated;
X break;
X default:
X goto bad;
X }
X while(letter(*++op)) ;
X if(*op == '/') op++;
X }
X return;
X }
X if (!strncmp(opts, "dogname", 3)) {
X if(!from_env) {
X#ifdef MSDOS
X pline("\"dogname\" settable only from %s.", configfile);
X#else
X Your("dog's name can be set only from NETHACKOPTIONS.");
X#endif
X return;
X }
X op = index(opts, ':');
X if (!op) goto bad;
X nmcpy(dogname, ++op, 62);
X return;
X }
X if (!strncmp(opts, "catname", 3)) {
X if(!from_env) {
X#ifdef MSDOS
X pline("\"catname\" settable only from %s.", configfile);
X#else
X Your("cat's name can be set only from NETHACKOPTIONS.");
X#endif
X return;
X }
X op = index(opts, ':');
X if (!op) goto bad;
X nmcpy(catname, ++op, 62);
X return;
X }
X if (!strncmp(opts, "fruit", 2)) {
X op = index(opts, ':');
X if (!op++) goto bad;
X if (!from_env) {
X struct fruit *f;
X int numfruits = 0;
X
X for(f=ffruit; f; f=f->nextf) {
X if (!strcmp(op, f->fname)) goto goodfruit;
X numfruits++;
X }
X if (numfruits >= 100) {
X pline("Doing that so many times isn't very fruitful.");
X return;
X }
X }
Xgoodfruit:
X nmcpy(pl_fruit, op, PL_FSIZ);
X if (!from_env)
X (void)fruitadd(pl_fruit);
X /* If from_env, then initoptions is allowed to do it instead
X * of here (initoptions always has to do it even if there's
X * no fruit option at all. Also, we don't want people
X * setting multiple fruits in their options.)
X */
X return;
X }
Xbad:
X if(!from_env) {
X if(!strncmp(opts, "h", 1) ||
X !strncmp(opts, "?", 1)) {
X option_help();
X return;
X }
X pline("Unknown option: %s. Enter \"O?\" for help.", opts);
X return;
X }
X#ifdef MSDOS
X Printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts);
X#else
X Printf("Bad syntax in NETHACKOPTIONS: %s.", opts);
X (void) puts("Use for example:");
X (void) puts(
X"NETHACKOPTIONS=\"!rest_on_space,notombstone,endgame:own/5 topscorers/4 around me\""
X );
X#endif
X getret();
X}
X
Xint
Xdoset()
X{
X char buf[BUFSZ];
X
X pline("What options do you want to set? ");
X getlin(buf);
X if(!buf[0] || buf[0] == '\033') {
X#ifdef MSDOS
X Strcpy(buf,"OPTIONS=");
X#ifdef DGK
X if (flags.rawio) Strcat(buf,"rawio,");
X if (flags.IBMBIOS) Strcat(buf,"IBM_BIOS,");
X#endif /* DGK */
X#ifdef DECRAINBOW
X if (flags.DECRainbow) Strcat(buf,"DEC_Rainbow,");
X#endif /* DECRAINBOW */
X#else /* MSDOS */
X Strcpy(buf,"NETHACKOPTIONS=");
X if(flags.standout) Strcat(buf,"standout,");
X if(flags.nonull) Strcat(buf,"nonull,");
X#endif /* MSDOS */
X if(flags.ignintr) Strcat(buf,"ignintr,");
X if(flags.num_pad) Strcat(buf,"number_pad,");
X#ifdef NEWS
X if(flags.nonews) Strcat(buf,"nonews,");
X#endif
X if(flags.notombstone) Strcat(buf,"notombstone,");
X Strcat(buf, flags.female ? "female," : "male,");
X if(flags.no_rest_on_space) Strcat(buf,"!rest_on_space,");
X if (flags.invlet_constant) Strcat(buf,"fixinv,");
X if (flags.sortpack) Strcat(buf,"sortpack,");
X if (set_order){
X Strcat(buf, "packorder: ");
X Strcat(buf, inv_order);
X Strcat(buf, ",");
X }
X if (flags.confirm) Strcat(buf,"confirm,");
X if (flags.safe_dog) Strcat(buf,"safe_pet,");
X if (flags.pickup) Strcat(buf,"pickup,");
X if (flags.silent) Strcat(buf,"silent,");
X if (flags.time) Strcat(buf,"time,");
X if (flags.verbose) Strcat(buf,"verbose,");
X Sprintf(eos(buf), "fruit:%s,", pl_fruit);
X if(flags.end_top != 5 || flags.end_around != 4 || flags.end_own){
X Sprintf(eos(buf), "endgame: %u top scores/%u around me",
X flags.end_top, flags.end_around);
X if(flags.end_own) Strcat(buf, "/own scores");
X } else {
X register char *eop = eos(buf);
X if(*--eop == ',') *eop = 0;
X }
X pline(buf);
X } else {
X clrlin();
X parseoptions(buf, FALSE);
X }
X
X return 0;
X}
X
Xint
Xdotogglepickup() {
X flags.pickup = !flags.pickup;
X pline("Pickup: %s.", flags.pickup ? "ON" : "OFF");
X return 0;
X}
X
Xchar packorder[] = {
X AMULET_SYM, WEAPON_SYM, ARMOR_SYM, FOOD_SYM, SCROLL_SYM,
X# ifdef SPELLS
X SPBOOK_SYM,
X# endif
X WAND_SYM, RING_SYM, POTION_SYM, TOOL_SYM, GEM_SYM, BALL_SYM, ROCK_SYM };
X#define Page_line(x) if(page_line(x)) goto quit
X
Xvoid
Xoption_help() {
X char buf[BUFSZ];
X
X set_pager(0);
X Sprintf(buf, " NetHack Options Help:");
X if(page_line("") || page_line(buf) || page_line("")) goto quit;
X
X#ifdef MSDOS
X Sprintf(buf, "To set options use OPTIONS=<options> in %s;", configfile);
X Page_line(buf);
X#else
X Page_line("To set options use `NETHACKOPTIONS=\"<options>\"' in your environment;");
X#endif
X
X Page_line("or press \"O\" while playing, and type your <options> at the prompt.");
X Page_line("In either case, <options> is a list of options separated by commas.");
X Page_line("");
X
X Page_line("Boolean options (which can be negated by prefixing them with '!' or \"no\"):");
X Page_line("confirm, (fe)male, fixinv, pickup, rest_on_space, safe_pet, silent, sortpack,");
X#ifdef MSDOS
X#ifdef NEWS
X Page_line("time, tombstone, verbose, news, number_pad, rawio, and IBM_BIOS");
X#else
X Page_line("time, tombstone, verbose, number_pad, rawio, and IBM_BIOS");
X#endif
X#ifdef DECRAINBOW
X Page_line("and DEC_Rainbow.");
X#endif /* DECRAINBOW */
X#else /* MSDOS */
X#ifdef NEWS
X Page_line("time, tombstone, verbose, news, null, ignintr, and standout.");
X#else
X Page_line("time, tombstone, verbose, null, ignintr, and standout.");
X#endif
X#endif /* MSDOS */
X Page_line("");
X
X Page_line("Compound options:");
X Page_line("`name' - your character's name (e.g., name:Merlin-W),");
X Page_line("`dogname' - the name of your (first) dog (e.g., dogname:Fang),");
X
X Page_line("`packorder' - the inventory order of the items in your pack");
X Sprintf(buf, " (currently, packorder:%s ),", packorder);
X Page_line(buf);
X Page_line("`fruit' - the name of a fruit you enjoy eating,");
X
X Page_line("`endgame' - the parts of the score list you wish to see,");
X
X Page_line("`graphics' - defines the symbols to use in drawing the dungeon map.");
X Page_line("");
X Page_line("Some of the options can be set only before the game is started. You will");
X Page_line("be so informed, if you attempt to set them while in the game.");
X set_pager(1);
X return;
Xquit:
X set_pager(2);
X return;
X}
X
X/* Returns the fid of the fruit type; if that type already exists, it
X * returns the fid of that one; if it does not exist, it adds a new fruit
X * type to the chain and returns the new one.
X */
Xint
Xfruitadd(str)
Xchar *str;
X{
X register int i,j;
X register struct fruit *f;
X struct fruit *lastf;
X int highest_fruit_id = 0;
X char buf[PL_FSIZ];
X boolean user_specified = (str == pl_fruit);
X /* if not user-specified, then it's a fruit name for a fruit on
X * a bones level...
X */
X
X /* Note: every fruit has an id (spe for fruit objects) of at least
X * 1; 0 is an error.
X */
X if (user_specified) {
X /* disallow naming after other foods (since it'd be impossible
X * to tell the difference)
X */
X
X boolean found = FALSE;
X
X for(i = bases[j=letindex(FOOD_SYM)]; i < bases[j+1]; i++) {
X if (!strcmp(objects[i].oc_name, pl_fruit)) {
X found = TRUE;
X break;
X }
X }
X if (found ||
X (!strncmp(buf, "tin of ", 7) && name_to_mon(buf+7) > -1) ||
X !strcmp(buf, "empty tin") ||
X !strcmp(buf, "tin of spinach") ||
X (!strncmp(eos(buf)-6," corpse",6) && name_to_mon(buf) > -1))
X {
X Strcpy(buf, pl_fruit);
X Strcpy(pl_fruit, "candied ");
X nmcpy(pl_fruit+8, buf, PL_FSIZ-8);
X }
X }
X for(f=ffruit; f; f = f->nextf) {
X lastf = f;
X if(f->fid > highest_fruit_id) highest_fruit_id = f->fid;
X if(!strncmp(str, f->fname, PL_FSIZ))
X goto nonew;
X }
X /* if adding another fruit would overflow spe, use a random
X fruit instead... we've got a lot to choose from. */
X if (highest_fruit_id >= 127) return rnd(127);
X highest_fruit_id++;
X f = newfruit();
X if (ffruit) lastf->nextf = f;
X else ffruit = f;
X Strcpy(f->fname, str);
X f->fid = highest_fruit_id;
X f->nextf = 0;
Xnonew:
X if (user_specified) current_fruit = highest_fruit_id;
X return f->fid;
X}
END_OF_FILE
if test 16326 -ne `wc -c <'src/options.c'`; then
echo shar: \"'src/options.c'\" unpacked with wrong size!
fi
# end of 'src/options.c'
fi
echo shar: End of archive 18 \(of 38\).
cp /dev/null ark18isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 38 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0