home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
games
/
volume16
/
nethack31
/
part87
< prev
next >
Wrap
Internet Message Format
|
1993-02-06
|
59KB
Path: uunet!news.tek.com!master!saab!billr
From: billr@saab.CNA.TEK.COM (Bill Randle)
Newsgroups: comp.sources.games
Subject: v16i095: nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part87/108
Message-ID: <4458@master.CNA.TEK.COM>
Date: 5 Feb 93 19:22:05 GMT
Sender: news@master.CNA.TEK.COM
Lines: 1783
Approved: billr@saab.CNA.TEK.COM
Xref: uunet comp.sources.games:1646
Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
Posting-number: Volume 16, Issue 95
Archive-name: nethack31/Part87
Supersedes: nethack3p9: Volume 10, Issue 46-102
Environment: Amiga, Atari, Mac, MS-DOS, OS2, Unix, VMS, X11
#! /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 87 (of 108)."
# Contents: dat/Wizard.des src/quest.c sys/vms/vmsmail.c
# sys/vms/vmstty.c
# Wrapped by billr@saab on Wed Jan 27 16:09:21 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'dat/Wizard.des' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dat/Wizard.des'\"
else
echo shar: Extracting \"'dat/Wizard.des'\" \(14707 characters\)
sed "s/^X//" >'dat/Wizard.des' <<'END_OF_FILE'
X# SCCS Id: @(#)Wizard.des 3.1 92/07/11
X# Copyright (c) 1992 by David Cohrs
X# NetHack may be freely redistributed. See license for details.
X#
X# The "start" level for the quest.
X#
X# Here you meet your (besieged) class leader, the Wizard of Balance
X# and receive your quest assignment.
X#
XMAZE: "W-start",' '
XFLAGS: noteleport,hardfloor
XGEOMETRY:center,center
XMAP
X............................................................................
X.....................C....CC.C........................C.....................
X..........CCC.....................CCC.......................................
X........CC........-----------.......C.C...C...C....C........................
X.......C.....---------------------...C..C..C..C.............................
X......C..C...------....\....------....C.....C...............................
X........C...||....|.........|....||.........................................
X.......C....||....|.........+....||.........................................
X.......C...||---+--.........|....|||........................................
X......C....||...............|--S--||........................................
X...........||--+--|++----|---|..|.SS..........C......C......................
X........C..||.....|..|...|...|--|.||..CC..C.....C..........C................
X.......C...||.....|..|.--|.|.|....||.................C..C...................
X.....C......||....|..|.....|.|.--||..C..C..........C...........}}}..........
X......C.C...||....|..-----.|.....||...C.C.C..............C....}}}}}}........
X.........C...------........|------....C..C.....C..CC.C......}}}}}}}}}}}.....
X.........CC..---------------------...C.C..C.....CCCCC.C.......}}}}}}}}......
X.........C........-----------..........C.C.......CCC.........}}}}}}}}}......
X..........C.C.........................C............C...........}}}}}........
X......................CCC.C.................................................
XENDMAP
X# Random Monsters
XRANDOM_MONSTERS: 'B', 'i'
X# Dungeon Description
XREGION:(00,00,75,19),lit,"ordinary"
XREGION:(35,00,49,03),unlit,"ordinary"
XREGION:(43,12,49,16),unlit,"ordinary"
XREGION:(19,11,33,15),unlit,"ordinary",unfilled,true
XREGION:(30,10,31,10),unlit,"ordinary"
X# Stairs
XSTAIR:(30,10),down
X# Portal arrival point
XBRANCH:(63,06,63,06),(0,0,0,0)
X# Doors
XDOOR:closed,(31,09)
XDOOR:closed,(16,08)
XDOOR:closed,(28,07)
XDOOR:locked,(34,10)
XDOOR:locked,(35,10)
XDOOR:closed,(15,10)
XDOOR:locked,(19,10)
XDOOR:locked,(20,10)
X# Wizard of Balance
XMONSTER:'@',"Wizard of Balance",(23,05)
X# The treasure of Wizard of Balance
XOBJECT:'(',"chest",(24,05)
X# apprentice guards for the audience chamber
XMONSTER:'@',"apprentice",(30,07)
XMONSTER:'@',"apprentice",(24,06)
XMONSTER:'@',"apprentice",(15,06)
XMONSTER:'@',"apprentice",(15,12)
XMONSTER:'@',"apprentice",(26,11)
XMONSTER:'@',"apprentice",(27,11)
XMONSTER:'@',"apprentice",(19,09)
XMONSTER:'@',"apprentice",(20,09)
X# Eels in the pond
XMONSTER:';',"giant eel",(62,14)
XMONSTER:';',"giant eel",(69,15)
XMONSTER:';',"giant eel",(67,17)
X# Non diggable walls
XNON_DIGGABLE:(00,00,75,19)
X# Random traps
XTRAP:random,random
XTRAP:random,random
XTRAP:random,random
XTRAP:random,random
XTRAP:random,random
XTRAP:random,random
X# Monsters on siege duty.
XMONSTER: 'B',random,(60,09),hostile
XMONSTER: 'W',random,(60,10),hostile
XMONSTER: 'B',random,(60,11),hostile
XMONSTER: 'B',random,(60,12),hostile
XMONSTER: 'i',random,(60,13),hostile
XMONSTER: 'B',random,(61,10),hostile
XMONSTER: 'B',random,(61,11),hostile
XMONSTER: 'B',random,(61,12),hostile
XMONSTER: 'B',random,(35,03),hostile
XMONSTER: 'i',random,(35,17),hostile
XMONSTER: 'B',random,(36,17),hostile
XMONSTER: 'B',random,(34,16),hostile
XMONSTER: 'i',random,(34,17),hostile
XMONSTER: 'W',random,(67,02),hostile
XMONSTER: 'B',random,(10,19),hostile
X
X#
X# The "locate" level for the quest.
X#
X# Here you have to find the Entrance to the Tower of Darkness to go
X# further towards your assigned quest.
X#
X
XMAZE: "W-locate",' '
XFLAGS: hardfloor
XGEOMETRY:center,center
XMAP
X............. .......................................................
X.............. .............}}}}}}}.}}}}}}}}}}}}}}}}}}}.}}}}}}}.......
X.............. ..............}.................................}.......
X.............. ..............}.---------S---------------------.}.......
X............... .........C....}.|.............................|.}.......
X............... ..........C....}.|.---------------------------.|.}.......
X............... .........CCC.....|.|.........................|.|.........
X................ ....C....CCC...}.|.|.---S-------------------.|.|.}.......
X.......C..C..... .....C....CCC...}.|.|.|......+.......+......|.|.|.}.......
X.............C..CC.....C....CCC...}.|.|.|......|-------|......|.|.|.}.......
X................ ....C....CCC...}.|.|.|......|.......S......|.|.|.}.......
X......C..C..... ....C....CCC...}.|.|.|......|-------|......|.|.|.}.......
X............C.. ...C....CCC...}.|.|.|......+.......+......|.|.|.}.......
X........C...... ....C....CCC...}.|.|.-----------------------.|.|.}.......
X....C......C... ........CCC.....|.|.........................|.|.........
X......C..C.... .........C....}.|.--------------------S------.|.}.......
X.............. .........C....}.|.............................|.}.......
X............. ..............}.-------------------------------.}.......
X............. .............}.................................}.......
X............. .............}}}}}}}.}}}}}}}}}}}}}}}}}}}.}}}}}}}.......
X............. .......................................................
XENDMAP
X# Random Monsters
XRANDOM_MONSTERS: 'B', 'X'
X# Dungeon Description
XREGION:(00,00,75,20),lit,"ordinary"
XREGION:(37,04,65,16),unlit,"ordinary"
XREGION:(41,08,46,12),lit,"ordinary"
XREGION:(56,08,61,12),lit,"ordinary"
XREGION:(48,08,54,08),unlit,"ordinary"
XREGION:(48,12,54,12),unlit,"ordinary"
XREGION:(48,10,54,10),unlit,"ordinary"
X
X# Doors
XDOOR:locked,(45,03)
XDOOR:locked,(43,07)
XDOOR:locked,(58,15)
XDOOR:locked,(55,10)
XDOOR:locked,(55,08)
XDOOR:locked,(55,12)
XDOOR:locked,(47,08)
XDOOR:locked,(47,12)
X# Stairs
XSTAIR:(03,17),up
XSTAIR:(48,10),down
X# Non diggable walls
XNON_DIGGABLE:(00,00,75,20)
X# Objects
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
X# Random traps
XTRAP:"spiked pit",(24,02)
XTRAP:"spiked pit",(07,10)
XTRAP:"spiked pit",(23,05)
XTRAP:"spiked pit",(26,19)
XTRAP:"spiked pit",(72,02)
XTRAP:"spiked pit",(72,12)
XTRAP:"falling rock",(45,16)
XTRAP:"falling rock",(65,13)
XTRAP:"falling rock",(55,06)
XTRAP:"falling rock",(39,11)
XTRAP:"falling rock",(57,09)
XTRAP:"magic",random
XTRAP:"statue",random
XTRAP:"statue",random
XTRAP:"polymorph",random
XTRAP:"anti magic",(53,10)
XTRAP:"sleep gas",random
XTRAP:"sleep gas",random
XTRAP:"dart",random
XTRAP:"dart",random
XTRAP:"dart",random
X# Random monsters.
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'i',random,random,hostile
X
X#
X# The "goal" level for the quest.
X#
X# Here you meet the Dark One, your nemesis monster. You have to
X# defeat the Dark One in combat to gain the artifact you have
X# been assigned to retrieve.
X#
X
XMAZE: "W-goal", ' '
XGEOMETRY:center,center
XMAP
X
X
X
X ------------- -------------
X |...........| |...........|
X -------|...........-------------------...........|
X |......S...........|..|..|..|..|..|..|...........|
X |......|...........|..|..|..|..|..|..|...........|
X |......|...........--+--+--+--+--+--+-...........|
X --S----|...........S.................+...........|
X |......|...........--+--+--+--+--+--+-...........|
X |......|...........|..|..|..|..|..|..|...........|
X |......|...........|..|..|..|..|..|..|...........|
X -------|...........-------------------...........|
X |...........| |...........|
X ------------- -------------
X
X
X
X
XENDMAP
X# Random Monsters
XRANDOM_MONSTERS: 'B', 'X'
X# Dungeon Description
XREGION:(13,10,18,12),unlit,"temple"
XREGION:(13,06,18,08),lit,"ordinary"
XREGION:(20,04,30,14),unlit,"ordinary"
XREGION:(32,06,33,07),unlit,"ordinary"
XREGION:(35,06,36,07),unlit,"ordinary"
XREGION:(38,06,39,07),unlit,"ordinary"
XREGION:(41,06,42,07),unlit,"ordinary"
XREGION:(44,06,45,07),unlit,"ordinary"
XREGION:(47,06,48,07),unlit,"ordinary"
XREGION:(32,09,48,09),unlit,"ordinary"
XREGION:(32,11,33,12),unlit,"ordinary"
XREGION:(35,11,36,12),unlit,"ordinary"
XREGION:(38,11,39,12),unlit,"ordinary"
XREGION:(41,11,42,12),unlit,"ordinary"
XREGION:(44,11,45,12),unlit,"ordinary"
XREGION:(47,11,48,12),unlit,"ordinary"
XREGION:(50,04,60,14),lit,"ordinary"
X# Doors
XDOOR:locked,(19,06)
XDOOR:locked,(14,09)
XDOOR:locked,(31,09)
XDOOR:locked,(33,08)
XDOOR:locked,(36,08)
XDOOR:locked,(39,08)
XDOOR:locked,(42,08)
XDOOR:locked,(45,08)
XDOOR:locked,(48,08)
XDOOR:locked,(33,10)
XDOOR:locked,(36,10)
XDOOR:locked,(39,10)
XDOOR:locked,(42,10)
XDOOR:locked,(45,10)
XDOOR:locked,(48,10)
XDOOR:locked,(49,09)
X# Stairs
XSTAIR:(55,05),up
X# Non diggable walls
XNON_DIGGABLE:(00,00,75,19)
X# The altar of Anhur. This is not a shrine.
XALTAR:(16,11),chaos,altar
X# Objects
XOBJECT:'"',"amulet of ESP",(16,11),blessed,0,"The Eye of the Aethiopica"
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
XOBJECT:random,random,random
X# Random traps
XTRAP:random,random
XTRAP:random,random
XTRAP:random,random
XTRAP:random,random
XTRAP:random,random
XTRAP:random,random
X# Random monsters.
XMONSTER:'@',"Dark One",(16,11)
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'B',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'i',random,random,hostile
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'B',"vampire bat",random
XMONSTER:'i',random,random,hostile
X# Captive Monsters in the dungeon
XMONSTER:'@',"rogue",(35,06),peaceful,"Pug"
XMONSTER:'Y',"owlbear",(47,06),peaceful,asleep
XMONSTER:'@',"wizard",(32,11),peaceful,asleep,"Newt"
XMONSTER:'@',"Grey-elf",(44,11),peaceful
XMONSTER:'H',"hill giant",(47,11),peaceful,asleep
XMONSTER:'G',"gnomish wizard",(38,06),peaceful
X
X#
X# The "fill" levels for the quest.
X#
X# These levels are used to fill out any levels not occupied by specific
X# levels as defined above. "filla" is the upper filler, between the
X# start and locate levels, and "fillb" the lower between the locate
X# and goal levels.
X#
X
XLEVEL: "W-filla"
X# Random Monsters
XRANDOM_MONSTERS: 'B', 'X'
X#
XROOM: "ordinary" , random, random, random, random
XSTAIR: random, up
XOBJECT: random,random,random
XMONSTER: 'i', random, random, hostile
X
XROOM: "ordinary" , random, random, random, random
XOBJECT: random, random, random
XOBJECT: random,random,random
XMONSTER: 'i', random, random, hostile
X
XROOM: "ordinary" , random, random, random, random
XOBJECT: random, random, random
XTRAP: random, random
XOBJECT: random,random,random
XMONSTER: 'B', "vampire bat", random
XMONSTER: 'B', "vampire bat", random
X
XROOM: "ordinary" , random, random, random, random
XSTAIR: random, down
XOBJECT: random, random, random
XTRAP: random, random
XMONSTER: 'i', random, random, hostile
XMONSTER: 'B', "vampire bat", random
X
XROOM: "ordinary" , random, random, random, random
XOBJECT: random, random, random
XOBJECT: random, random, random
XTRAP: random, random
XMONSTER: 'i', random, random, hostile
X
XROOM: "ordinary" , random, random, random, random
XOBJECT: random, random, random
XTRAP: random, random
XMONSTER: 'B', "vampire bat", random
X
XRANDOM_CORRIDORS
X
XLEVEL: "W-fillb"
X# Random Monsters
XRANDOM_MONSTERS: 'B', 'X'
X#
XROOM: "ordinary" , random, random, random, random
XSTAIR: random, up
XOBJECT: random,random,random
XMONSTER: 'X', random, random, hostile
X
XROOM: "ordinary" , random, random, random, random
XOBJECT: random, random, random
XOBJECT: random,random,random
XMONSTER: 'i', random, random, hostile
X
XROOM: "ordinary" , random, random, random, random
XOBJECT: random, random, random
XTRAP: random, random
XOBJECT: random,random,random
XMONSTER: 'X', random, random, hostile
X
XROOM: "ordinary" , random, random, random, random
XSTAIR: random, down
XOBJECT: random, random, random
XTRAP: random, random
XMONSTER: 'i', random, random, hostile
XMONSTER: 'B', "vampire bat", random
X
XROOM: "ordinary" , random, random, random, random
XOBJECT: random, random, random
XOBJECT: random, random, random
XTRAP: random, random
XMONSTER: 'i', random, random, hostile
X
XROOM: "ordinary" , random, random, random, random
XOBJECT: random, random, random
XTRAP: random, random
XMONSTER: 'B', "vampire bat", random
X
XRANDOM_CORRIDORS
END_OF_FILE
if test 14707 -ne `wc -c <'dat/Wizard.des'`; then
echo shar: \"'dat/Wizard.des'\" unpacked with wrong size!
fi
# end of 'dat/Wizard.des'
fi
if test -f 'src/quest.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/quest.c'\"
else
echo shar: Extracting \"'src/quest.c'\" \(8083 characters\)
sed "s/^X//" >'src/quest.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)quest.c 3.1 92/11/13 */
X/* Copyright 1991, M. Stephenson */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
X
X#ifdef MULDGN
X/* quest dungeon branch routines. */
X
X#include "quest.h"
X#include "qtext.h"
X
X#define Not_firsttime (on_level(&u.uz0, &u.uz))
X#define Qstat(x) (quest_status.x)
X
Xstatic void NDECL(on_start);
Xstatic void NDECL(on_locate);
Xstatic void NDECL(on_goal);
Xstatic boolean NDECL(not_capable);
Xstatic boolean NDECL(not_pure);
Xstatic void FDECL(expulsion, (BOOLEAN_P));
Xstatic void NDECL(chat_with_leader);
Xstatic void NDECL(chat_with_nemesis);
Xstatic void NDECL(chat_with_guardian);
X
Xstatic void
Xon_start() {
X if(!Qstat(first_start)) {
X qt_pager(QT_FIRSTTIME);
X Qstat(first_start) = TRUE;
X } else if((u.uz0.dnum != u.uz.dnum) || (u.uz0.dlevel < u.uz.dlevel)) {
X if(Qstat(not_ready) <= 2) qt_pager(QT_NEXTTIME);
X else qt_pager(QT_OTHERTIME);
X }
X}
X
Xstatic void
Xon_locate() {
X if(!Qstat(first_locate)) {
X qt_pager(QT_FIRSTLOCATE);
X Qstat(first_locate) = TRUE;
X } else if(u.uz0.dlevel < u.uz.dlevel)
X qt_pager(QT_NEXTLOCATE);
X}
X
Xstatic void
Xon_goal() {
X if(!Qstat(made_goal)) {
X qt_pager(QT_FIRSTGOAL);
X Qstat(made_goal) = 1;
X } else {
X qt_pager(QT_NEXTGOAL);
X if(Qstat(made_goal) < 7) Qstat(made_goal)++;
X }
X}
X
Xvoid
Xquest_init() {
X/*
X * Special setup modifications here:
X *
X * Unfortunately, this is going to have to be done on each level,
X * on start-up, and on entry, since you lose the permonst mods
X * across a save/restore :-)
X *
X * 1 - The Rogue Leader is the Tourist Nemesis.
X * 1 - Elves can have one of two different leaders, work it out here.
X * 2 - Priests start with a random alignment - convert the leader and
X * guardians here.
X */
X#ifdef TOURIST
X if(pl_character[0] == 'T' && Is_nemesis(&u.uz)) {
X register struct monst *mtmp;
X mons[PM_MASTER_OF_THIEVES].msound = MS_NEMESIS;
X mons[PM_MASTER_OF_THIEVES].mflags2 &= ~(M2_PEACEFUL);
X mons[PM_MASTER_OF_THIEVES].mflags2 |= (M2_NASTY|M2_STALK|M2_HOSTILE);
X mons[PM_MASTER_OF_THIEVES].mflags3 = M3_WANTSARTI | M3_WAITFORU;
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) /* find the leader... */
X if(mtmp->data->msound == MS_NEMESIS) {
X set_malign(mtmp); /* changed M2_PEACEFUL */
X break;
X }
X } else
X#endif
X if(pl_character[0] == 'E' && flags.female && Is_qstart(&u.uz)) {
X register struct monst *mtmp;
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) /* find the leader... */
X if(mtmp->data->msound == MS_LEADER) {
X mtmp->data = &mons[PM_ELWING]; /* sex-change */
X break;
X }
X } else if(pl_character[0] == 'P' && Is_qstart(&u.uz)) {
X
X register struct monst *mtmp;
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) /* find leader & guards */
X if(mtmp->data->msound == MS_LEADER ||
X mtmp->data->msound == MS_GUARDIAN) {
X /* use game-start alignment for reference */
X mtmp->data->maligntyp = u.ualignbase[1]*3;
X mtmp->mpeaceful = TRUE;
X set_malign(mtmp); /* mpeaceful may have changed */
X }
X }
X}
X
Xvoid
Xonquest() {
X
X if(Not_firsttime) return;
X if(!Is_special(&u.uz)) return;
X
X if(Is_qstart(&u.uz)) on_start();
X else if(Is_qlocate(&u.uz) && u.uz.dlevel > u.uz0.dlevel) on_locate();
X else if(Is_nemesis(&u.uz)) on_goal();
X return;
X}
X
Xvoid
Xnemdead() {
X if(!Qstat(killed_nemesis)) {
X Qstat(killed_nemesis) = TRUE;
X qt_pager(QT_KILLEDNEM);
X }
X}
X
Xvoid
Xartitouch() {
X if(!Qstat(touched_artifact)) {
X Qstat(touched_artifact) = TRUE;
X qt_pager(QT_GOTIT);
X exercise(A_WIS, TRUE);
X }
X}
X
X/* external hook for do.c (level change check) */
Xboolean
Xok_to_quest() {
X
X return(Qstat(got_quest));
X}
X
Xstatic boolean
Xnot_capable() {
X return(u.ulevel < MIN_QUEST_LEVEL);
X}
X
X/* TODO: This one needs tuning. */
Xstatic boolean
Xnot_pure() {
X#ifdef WIZARD
X if(wizard && (u.ualign.record < MIN_QUEST_ALIGN)) {
X
X You("are currently %d and require %d.",
X u.ualign.record, MIN_QUEST_ALIGN);
X if(yn_function("adjust?", NULL, 'y') == 'y')
X u.ualign.record = MIN_QUEST_ALIGN;
X }
X#endif
X return(u.ualign.record < MIN_QUEST_ALIGN);
X}
X
X/*
X * Expell the player to the stairs on the parent of the quest dungeon.
X *
X * This assumes that the hero is currently _in_ the quest dungeon and that
X * there is a single branch to and from it.
X */
Xstatic void
Xexpulsion(seal)
Xboolean seal;
X{
X branch *br;
X d_level *dest;
X
X br = dungeon_branch("The Quest");
X dest = (br->end1.dnum == u.uz.dnum) ? &br->end2 : &br->end1;
X assign_level(&u.utolev, dest);
X u.utotype = 1; /* portal */
X if (seal) { /* remove the portal to the quest - sealing it off */
X u.utotype |= 0200;
X u.uevent.qexpelled = 1;
X }
X}
X
Xstatic void
Xchat_with_leader()
X{
X/* Rule 0: Cheater checks. */
X if(u.uhave.questart && !Qstat(met_nemesis))
X Qstat(cheater) = TRUE;
X
X/* It is possible for you to get the amulet without completing
X * the quest. If so, try to induce the player to quest.
X */
X if(Qstat(got_thanks)) {
X/* Rule 1: You've gone back with/whithout the amulet. */
X if(u.uhave.amulet) qt_pager(QT_HASAMULET);
X
X/* Rule 2: You've gone back before going for the amulet. */
X else qt_pager(QT_POSTHANKS);
X }
X
X/* Rule 3: You've got the artifact and are back to return it. */
X else if(u.uhave.questart) {
X if(u.uhave.amulet) qt_pager(QT_HASAMULET);
X else qt_pager(QT_OFFEREDIT);
X Qstat(got_thanks) = TRUE;
X u.uevent.qcompleted = 1; /* you did it! */
X
X/* Rule 4: You haven't got the artifact yet. */
X } else if(Qstat(got_quest)) qt_pager(rn1(10, QT_ENCOURAGE));
X
X/* Rule 5: You aren't yet acceptable - or are you? */
X else {
X if(!Qstat(met_leader)) {
X qt_pager(QT_FIRSTLEADER);
X Qstat(met_leader) = TRUE;
X Qstat(not_ready) = 0;
X } else qt_pager(QT_NEXTLEADER);
X
X if(not_capable()) {
X qt_pager(QT_BADLEVEL);
X exercise(A_WIS, TRUE);
X expulsion(FALSE);
X } else if(not_pure()) {
X qt_pager(QT_BADALIGN);
X if(Qstat(not_ready) == MAX_QUEST_TRIES) {
X qt_pager(QT_LASTLEADER);
X expulsion(TRUE);
X } else {
X Qstat(not_ready)++;
X exercise(A_WIS, TRUE);
X expulsion(FALSE);
X }
X } else { /* You are worthy! */
X qt_pager(QT_ASSIGNQUEST);
X exercise(A_WIS, TRUE);
X Qstat(got_quest) = TRUE;
X }
X }
X}
X
Xvoid
Xleader_speaks(mtmp)
X
X register struct monst *mtmp;
X{
X /* maybe you attacked leader? */
X if(!mtmp->mpeaceful) {
X Qstat(pissed_off) = TRUE;
X mtmp->data->mflags3 = 0; /* end the inaction */
X }
X
X if(Qstat(pissed_off)) {
X qt_pager(QT_LASTLEADER);
X expulsion(TRUE);
X } else chat_with_leader();
X
X}
X
Xstatic void
Xchat_with_nemesis()
X{
X/* The nemesis will do most of the talking, but... */
X qt_pager(rn1(10, QT_DISCOURAGE));
X if(!Qstat(met_nemesis)) Qstat(met_nemesis++);
X}
X
Xvoid
Xnemesis_speaks()
X{
X if(!Qstat(in_battle)) {
X if(u.uhave.questart) qt_pager(QT_NEMWANTSIT);
X else if(!Qstat(made_goal)) qt_pager(QT_FIRSTNEMESIS);
X else if(Qstat(made_goal) < 3) qt_pager(QT_NEXTNEMESIS);
X else if(Qstat(made_goal) < 7) qt_pager(QT_OTHERNEMESIS);
X else if(!rn2(5)) qt_pager(rn1(10, QT_DISCOURAGE));
X if(Qstat(made_goal) < 7) Qstat(made_goal)++;
X Qstat(met_nemesis) = TRUE;
X } else /* he will spit out random maledictions */
X if(!rn2(5)) qt_pager(rn1(10, QT_DISCOURAGE));
X}
X
Xstatic void
Xchat_with_guardian()
X{
X/* These guys/gals really don't have much to say... */
X qt_pager(rn1(5, QT_GUARDTALK));
X}
X
Xvoid
Xquest_chat(mtmp)
X
X register struct monst *mtmp;
X{
X
X switch(mtmp->data->msound) {
X case MS_LEADER: chat_with_leader(); break;
X case MS_NEMESIS: chat_with_nemesis(); break;
X case MS_GUARDIAN: chat_with_guardian(); break;
X default: impossible("quest_chat: Unknown quest character %s.",
X mon_nam(mtmp));
X }
X}
X
Xvoid
Xquest_talk(mtmp)
X
X register struct monst *mtmp;
X{
X switch(mtmp->data->msound) {
X case MS_LEADER: leader_speaks(mtmp); break;
X case MS_NEMESIS: nemesis_speaks(); break;
X default: break;
X }
X}
X
Xvoid
Xquest_stat_check(mtmp)
X
X struct monst *mtmp;
X{
X if(mtmp->data->msound == MS_NEMESIS)
X Qstat(in_battle) =
X (mtmp->mcanmove && !mtmp->msleep && monnear(mtmp, u.ux, u.uy));
X}
X
X#endif /* MULDGN */
X
X/*quest.c*/
END_OF_FILE
if test 8083 -ne `wc -c <'src/quest.c'`; then
echo shar: \"'src/quest.c'\" unpacked with wrong size!
fi
# end of 'src/quest.c'
fi
if test -f 'sys/vms/vmsmail.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'sys/vms/vmsmail.c'\"
else
echo shar: Extracting \"'sys/vms/vmsmail.c'\" \(16224 characters\)
sed "s/^X//" >'sys/vms/vmsmail.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)vmsmail.c 3.1 92/12/16 */
X/* Copyright (c) Robert Patrick Rankin, 1991. */
X/* NetHack may be freely redistributed. See license for details. */
X
X#define EXTERN_H /* don't need all those prototypes */
X#include "config.h"
X
X#ifdef MAIL
X#include "winprocs.h"
X#include "mail.h"
X#include <ctype.h>
X#include <descrip.h>
X#include <errno.h>
X# ifndef __GNUC__
X#include <msgdef.h>
X# else
X# define MSG$_TRMHANGUP 6
X# define MSG$_TRMBRDCST 83
X# endif /*__GNUC__*/
X#include <signal.h>
X/* #include <string.h> */
X# define vms_ok(sts) ((sts)&1)
X
Xstatic struct mail_info *FDECL(parse_brdcst, (char *));
Xstatic void FDECL(filter_brdcst, (char *));
Xstatic void NDECL(flush_broadcasts);
Xstatic void FDECL(broadcast_ast, (int));
Xextern char *strcpy(), *strcat(), *strrchr(), *strstri(), *eos();
Xextern int strspn(), strncmpi();
X#ifndef __DECC
Xextern int VDECL(sscanf, (const char *,const char *,...));
X#endif
Xextern unsigned long
X SMG$CREATE_PASTEBOARD(),
X SMG$GET_BROADCAST_MESSAGE(),
X SMG$SET_BROADCAST_TRAPPING(),
X SMG$DISABLE_BROADCAST_TRAPPING();
X
Xextern volatile int broadcasts; /* defining declaration in mail.c */
X
Xstatic long pasteboard_id = 0; /* SMG's magic cookie */
X
X/*
X * Mail (et al) overview:
X *
X * When a broadcast is asynchronously captured, a volatile counter
X * ('broadcasts') is incremented. Each player turn, ckmailstatus() polls
X * the counter and calls parse_next_broadcast() if it's positive; this
X * returns some display text, object name, and response command, which is
X * passed to newmail(). Routine newmail() generates a mail-daemon monster
X * who approaches the character, "speaks" the display text, and delivers
X * a scroll of mail pre-named to the object name; the response command is
X * initially appended to the name, so that the object is tagged with both
X * of them; a NUL is inserted to terminate the ordinary name and hide the
X * command. (If the player renames such a scroll, the hidden command will
X * be lost; who cares?) Unrecognized broadcasts result in the mail-daemon
X * arriving and announcing the display text, but no scroll being created.
X * If SHELL is undefined, then all broadcasts are treated as 'other'; since
X * no subproceses are allowed, there'd be no way to respond to the scroll.
X *
X * When a scroll of mail is read by the character, readmail() extracts
X * the hidden command string and uses it for the default when prompting the
X * player for a system command to spawn. The player may enter any command
X * he or she chooses, or just <return> to accept the default or <escape> to
X * avoid executing any command. If the command is "SPAWN", a regular shell
X * escape to DCL is performed; otherwise, the indicated single command is
X * spawned. Either way, NetHack resumes play when the subprocess terminates
X * or explicitly reattaches to its parent.
X *
X * Broadcast parsing:
X *
X * The following broadcast messages are [attempted to be] recognized:
X * text fragment name for scroll default command
X * New mail VMSmail MAIL
X * New ALL-IN-1 MAIL A1mail A1M
X * Software Tools mail STmail MSG [+folder]
X * MM mail MMmail MM
X * WPmail: New mail WPmail OFFICE/MAIL
X * **M400 mail M400mail M400
X * " mail", ^"mail " unknown mail SPAWN
X * " phoning" Phone call PHONE ANSWER
X * talk-daemon...by...foo Talk request TALK[/OLD] foo@bar
X * (node)user - Bitnet noise XYZZY user@node
X * Anything else results in just the message text being passed along, no
X * scroll of mail so consequently no command to execute when scroll read.
X * The user can set up ``$ XYZZY :== SEND'' prior to invoking NetHack if
X * vanilla JNET responses to Bitnet messages are prefered.
X *
X * Static return buffers are used because only one broadcast gets
X * processed at a time, and the essential information in each one is
X * either displayed and discarded or copied into a scroll-of-mail object.
X *
X * The test driver code below can be used to check out potential new
X * entries without rebuilding NetHack itself. CC/DEFINE="TEST_DRIVER"
X * Link it with hacklib.obj or nethack.olb/incl=hacklib (not nethack/lib).
X */
X
Xstatic struct mail_info msg; /* parse_*()'s return buffer */
Xstatic char nam_cmd_buf[63], /* maximum onamelth, size of ONAME(object) */
X txt_buf[255+1]; /* same size as used for message buf[] */
X
X/* try to decipher and categorize broadcast message text
X*/
Xstatic struct mail_info *
Xparse_brdcst(buf) /* called by parse_next_broadcast() */
Xchar *buf; /* input: filtered broadcast text */
X{
X int typ;
X char *txt, *nam, *cmd;
X# ifdef SHELL /* only parse if spawned commands are enabled */
X register char *p, *q;
X boolean is_jnet_send;
X char cmd_buf[127+1], user[127+1], node[127+1], sentinel;
X
X /* Check these first; otherwise, their arbitrary text would enable
X easy spoofing of some other message patterns. Unfortunately,
X any home-grown broadcast delivery program poses a similar risk. */
X if (!strncmpi(buf, "reply received", 14)) goto other;
X is_jnet_send = (sscanf(buf, "(%[^)])%s -%c", node, user, &sentinel) == 3);
X if (is_jnet_send) goto jnet_send;
X
X /* scan the text more or less by brute force */
X if ((q = strstri(buf, " mail")) != 0 || /* all known mail broadcasts */
X !strncmpi(q = buf, "mail ", 5)) { /* unexpected alternative */
X typ = MSG_MAIL;
X p = strstri(q, " from");
X txt = p ? strcat(strcpy(txt_buf, "Mail for you"), p) : (char *) 0;
X
X if (!strncmpi(buf, "new mail", 8)) {
X/*
XNew mail [on node FOO] from [SPAM::]BAR [\"personal_name\"] [\(HH:MM:SS\)]
X*/
X nam = "VMSmail"; /* assume VMSmail */
X cmd = "MAIL";
X if (txt && (p = strrchr(txt, '(')) > txt && /* discard time */
X (--p, strspn(p, "0123456789( :.)") == strlen(p))) *p = '\0';
X } else if (!strncmpi(buf, "new all-in-1", 12)) {
X int i;
X/*
XNew ALL-IN-1 MAIL message [on node FOO] from Personal Name \(BAR@SPAM\) [\(DD-MMM-YYYY HH:MM:SS\)]
X*/
X nam = "A1mail";
X cmd = "A1M";
X if (txt && (p = strrchr(txt, '(')) > txt && /* discard date+time */
X sscanf(p-1," (%*d-%*[^-]-%*d %*d:%*d:%d) %c",&i,&sentinel) == 1)
X *--p = '\0';
X } else if (!strncmpi(buf, "software tools", 14)) {
X/*
XSoftware Tools mail has arrived on FOO from \'BAR\' [in SPAM]
X*/
X nam = "STmail";
X cmd = "MSG";
X if (txt && (p = strstri(p, " in ")) != 0) /* specific folder */
X cmd = strcat(strcpy(cmd_buf, "MSG +"), p + 4);
X } else if (q - 2 >= buf && !strncmpi(q - 2, "mm", 2)) {
X/*
X{MultiNet\ |PMDF\/}MM mail has arrived on FOO from BAR\n
X[Subject: subject_text] (PMDF only)
X*/
X nam = "MMmail"; /* MultiNet's version of MM */
X cmd = "MM"; /*{ perhaps "MM READ"? }*/
X } else if (!strncmpi(buf, "wpmail:", 7)) {
X/*
XWPmail: New mail from BAR. subject_text
X*/
X nam = "WPmail"; /* WordPerfect [sic] Office */
X cmd = "OFFICE/MAIL";
X } else if (!strncmpi(buf, "**m400 mail", 7)) {
X/*
X**M400 mail waiting**
X*/
X nam = "M400mail"; /* Messenger 400 [not seen] */
X cmd = "M400";
X } else {
X /* not recognized, but presumed to be mail */
X nam = "unknown mail";
X cmd = "SPAWN"; /* generic escape back to DCL */
X txt = (char *) 0; /* don't rely on "from" info here */
X }
X
X if (!txt) txt = strcat(strcpy(txt_buf, "Mail for you: "), buf);
X /*
X : end of mail recognition; now check for call-type interruptions...
X */
X } else if ((q = strstri(buf, " phoning")) != 0) {
X/*
XBAR is phoning you [on FOO] \(HH:MM:SS\)
X*/
X typ = MSG_CALL;
X nam = "Phone call";
X cmd = "PHONE ANSWER";
X if (!strncmpi(q + 8, " you", 4)) q += (8 + 4), *q = '\0';
X txt = strcat(strcpy(txt_buf, "Do you hear ringing? "), buf);
X } else if ((q = strstri(buf, " talk-daemon")) != 0 ||
X (q = strstri(buf, " talk_daemon")) != 0) {
X/*
XMessage from TALK-DAEMON@FOO at HH:MM:SS\n
XConnection request by BAR@SPAM\n
X\[Respond with: TALK[/OLD] BAR@SPAM\]
X*/
X typ = MSG_CALL;
X nam = "Talk request"; /* MultiNet's TALK and/or TALK/OLD */
X cmd = "TALK";
X if ((p = strstri(q, " by ")) != 0) {
X txt = strcat(strcpy(txt_buf, "Talk request from"), p + 3);
X if ((p = strstri(p, "respond with")) != 0) {
X if (*(p-1) == '[') *(p-1) = '\0'; else *p = '\0'; /* terminate */
X p += (sizeof "respond with" - sizeof "");
X if (*p == ':') p++;
X if (*p == ' ') p++;
X cmd = strcpy(cmd_buf, p); /* "TALK[/OLD] bar@spam" */
X p = eos(cmd);
X if (*--p == ']') *p = '\0';
X }
X } else
X txt = strcat(strcpy(txt_buf, "Pardon the interruption: "), buf);
X } else if (is_jnet_send) { /* sscanf(,"(%[^)])%s -%c",,,)==3 */
Xjnet_send:
X/*
X\(SPAM\)BAR - arbitrary_message_text (from BAR@SPAM)
X*/
X typ = MSG_CALL;
X nam = "Bitnet noise"; /* RSCS/NJE message received via JNET */
X Sprintf(cmd = cmd_buf, "XYZZY %s@%s", user, node);
X /*{ perhaps just vanilla SEND instead of XYZZY? }*/
X Sprintf(txt = txt_buf, "Message from %s@%s:%s", user, node,
X &buf[1+strlen(node)+1+strlen(user)+2-1]); /* "(node)user -" */
X /*
X : end of call recognition; anything else is none-of-the-above...
X */
X } else {
Xother:
X# endif /* SHELL */
X/* arbitrary broadcast: batch job completed, system shutdown imminent, &c */
X typ = MSG_OTHER;
X nam = (char *) 0; /*"captured broadcast message"*/
X cmd = (char *) 0;
X txt = strcat(strcpy(txt_buf, "Message for you: "), buf);
X# ifdef SHELL
X }
X /* Daemon in newmail() will append period when the text is displayed */
X if ((p = eos(txt)) > txt && *--p == '.') *p = '\0';
X
X /* newmail() and readmail() assume that nam and cmd are concatenated */
X if (nam) { /* object name to attach to scroll of mail */
X nam = strcpy(nam_cmd_buf, nam);
X if (cmd) { /* append command to name; readmail() requires it */
X int len = sizeof nam_cmd_buf - sizeof "" - (strlen(nam) + 1);
X cmd_buf[len] = '\0'; /* possibly truncate */
X (void) strcat(nam, " ");
X cmd = strcpy(eos(nam), cmd);
X }
X }
X# endif /* SHELL */
X msg.message_typ = typ; /* simple index */
X msg.display_txt = txt; /* text for daemon to pline() */
X msg.object_nam = nam; /* 'name' for mail scroll */
X msg.response_cmd = cmd; /* command to spawn when scroll read */
X return &msg;
X}
X
X/* filter out non-printable characters and redundant noise
X*/
Xstatic void
Xfilter_brdcst(buf) /* called by parse_next_broadcast() */
Xregister char *buf; /* in: original text; out: filtered text */
X{
X register char c, *p, *buf_p;
X
X /* filter the text; restrict consecutive spaces or dots to just two */
X for (p = buf_p = buf; *buf_p; buf_p++) {
X c = *buf_p & '\177';
X if (c == ' ' || c == '\t' || c == '\n')
X if (p == buf || /* ignore leading whitespace */
X (p >= buf+2 && *(p-1) == ' ' && *(p-2) == ' ')) continue;
X else c = ' ';
X else if (c == '.' || c < ' ' || c == '\177')
X if (p == buf || /* skip leading beeps & such */
X (p >= buf+2 && *(p-1) == '.' && *(p-2) == '.')) continue;
X else c = '.';
X else if (c == '%' && /* trim %%% OPCOM verbosity %%% */
X p >= buf+2 && *(p-1) == '%' && *(p-2) == '%') continue;
X *p++ = c;
X }
X *p = '\0'; /* terminate, then strip trailing junk */
X while (p > buf && (*--p == ' ' || *p == '.')) *p = '\0';
X return;
X}
X
X/* fetch the text of a captured broadcast, then mangle and decipher it
X*/
Xstruct mail_info *
Xparse_next_broadcast() /* called by ckmailstatus(mail.c) */
X{
X short length, msg_type;
X $DESCRIPTOR(message, ""); /* string descriptor for buf[] */
X struct mail_info *result = 0;
X /* messages could actually be longer; let long ones be truncated */
X char buf[255+1];
X
X message.dsc$a_pointer = buf, message.dsc$w_length = sizeof buf - 1;
X msg_type = length = 0;
X SMG$GET_BROADCAST_MESSAGE(&pasteboard_id, &message, &length, &msg_type);
X if (msg_type == MSG$_TRMBRDCST) {
X buf[length] = '\0';
X filter_brdcst(buf); /* mask non-printable characters */
X result = parse_brdcst(buf); /* do the real work */
X } else if (msg_type == MSG$_TRMHANGUP) {
X (void) gsignal(SIGHUP);
X }
X return result;
X}
X
X/* spit out any pending broadcast messages whenever we leave
X*/
Xstatic void
Xflush_broadcasts() /* called from disable_broadcast_trapping() */
X{
X if (broadcasts > 0) {
X short len, typ;
X $DESCRIPTOR(msg, "");
X char buf[512+1];
X
X msg.dsc$a_pointer = buf, msg.dsc$w_length = sizeof buf - 1;
X raw_print(""); /* print at least one line for wait_synch() */
X do {
X typ = len = 0;
X SMG$GET_BROADCAST_MESSAGE(&pasteboard_id, &msg, &len, &typ);
X if (typ == MSG$_TRMBRDCST) buf[len] = '\0', raw_print(buf);
X } while (--broadcasts);
X wait_synch(); /* prompt with "Hit return to continue: " */
X }
X}
X
X/* AST routine called when the terminal's associated mailbox receives a message
X*/
Xstatic void
Xbroadcast_ast(dummy) /* called asynchronously by terminal driver */
Xint dummy; /* not used */
X{
X broadcasts++;
X}
X
X/* initialize the broadcast manipulation code; SMG makes this easy
X*/
Xunsigned long init_broadcast_trapping() /* called by setftty() [once only] */
X{
X unsigned long sts, preserve_screen_flag = 1;
X
X /* we need a pasteboard to pass to the broadcast setup/teardown routines */
X sts = SMG$CREATE_PASTEBOARD(&pasteboard_id, 0, 0, 0, &preserve_screen_flag);
X if (!vms_ok(sts)) {
X errno = EVMSERR, vaxc$errno = sts;
X raw_print("");
X perror("?can't create SMG pasteboard for broadcast trapping");
X wait_synch();
X broadcasts = -1; /* flag that trapping is currently broken */
X }
X return sts;
X}
X
X/* set up the terminal driver to deliver $brkthru data to a mailbox device
X*/
Xunsigned long enable_broadcast_trapping() /* called by setftty() */
X{
X unsigned long sts = 1;
X
X if (broadcasts >= 0) { /* (-1 => no pasteboard, so don't even try) */
X /* register callback routine to be triggered when broadcasts arrive */
X /* Note side effect: also intercepts hangup notification. */
X /* Another note: TMPMBX privilege is required. */
X sts = SMG$SET_BROADCAST_TRAPPING(&pasteboard_id, broadcast_ast, 0);
X if (!vms_ok(sts)) {
X errno = EVMSERR, vaxc$errno = sts;
X raw_print("");
X perror("?can't enable broadcast trapping");
X wait_synch();
X }
X }
X return sts;
X}
X
X/* return to 'normal'; $brkthru data goes straight to the terminal
X*/
Xunsigned long disable_broadcast_trapping() /* called by settty() */
X{
X unsigned long sts = 1;
X
X if (broadcasts >= 0) {
X /* disable trapping; releases associated MBX so that SPAWN can work */
X sts = SMG$DISABLE_BROADCAST_TRAPPING(&pasteboard_id);
X if (!vms_ok(sts)) errno = EVMSERR, vaxc$errno = sts;
X flush_broadcasts(); /* don't hold on to any buffered ones */
X }
X return sts;
X}
X#else /* MAIL */
X /* simple stubs for non-mail configuration */
Xunsigned long init_broadcast_trapping() { return 1; }
Xunsigned long enable_broadcast_trapping() { return 1; }
Xunsigned long disable_broadcast_trapping() { return 1; }
X#endif /* MAIL */
X
X/*----------------------------------------------------------------------*/
X
X#ifdef TEST_DRIVER
X /* (Take parse_next_broadcast for a spin. :-) */
X
Xvolatile int broadcasts = 0;
X
Xvoid newmail(foo)
Xstruct mail_info *foo;
X{
X# define STRING(s) ((s) ? (s) : "<null>")
X printf("\n\
X message type = %d\n\
X display text = \"%s\"\n\
X object name = \"%.*s\"\n\
X response cmd = \"%s\"\n\
X", foo->message_typ, STRING(foo->display_txt),
X (foo->object_nam && foo->response_cmd) ?
X (foo->response_cmd - foo->object_nam - 1) :
X strlen(STRING(foo->object_nam)),
X STRING(foo->object_nam), STRING(foo->response_cmd));
X# undef STRING
X}
X
Xvoid ckmailstatus()
X{
X struct mail_info *brdcst, *parse_next_broadcast();
X
X while (broadcasts > 0) { /* process all trapped broadcasts [until] */
X broadcasts--;
X if ((brdcst = parse_next_broadcast()) != 0) {
X newmail(brdcst);
X break; /* only handle one real message at a time */
X } else
X printf("\n--< non-broadcast encountered >--\n");
X }
X}
X
Xint main()
X{
X char dummy[BUFSIZ];
X
X init_broadcast_trapping();
X enable_broadcast_trapping();
X for (;;) {
X ckmailstatus();
X printf("> "), fflush(stdout); /* issue a prompt */
X if (!gets(dummy)) break; /* wait for a response */
X }
X disable_broadcast_trapping();
X return 1;
X}
X
Xvoid panic(s) char *s; { raw_print(s); exit(1); }
X
Xvoid raw_print(s) char *s; { puts(s); fflush(stdout); }
X
Xvoid wait_synch() { char dummy[BUFSIZ];
X printf("\nPress <return> to continue: "); fflush(stdout); (void) gets(dummy);
X}
X#endif /* TEST_DRIVER */
X
X/*vmsmail.c*/
END_OF_FILE
if test 16224 -ne `wc -c <'sys/vms/vmsmail.c'`; then
echo shar: \"'sys/vms/vmsmail.c'\" unpacked with wrong size!
fi
# end of 'sys/vms/vmsmail.c'
fi
if test -f 'sys/vms/vmstty.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'sys/vms/vmstty.c'\"
else
echo shar: Extracting \"'sys/vms/vmstty.c'\" \(14490 characters\)
sed "s/^X//" >'sys/vms/vmstty.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)vmstty.c 3.1 92/11/24 */
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X/* tty.c - (VMS) version */
X
X#define NEED_VARARGS
X#include "hack.h"
X#include "wintty.h"
X#include "termcap.h"
X
X#include <descrip.h>
X#include <iodef.h>
X#ifndef __GNUC__
X#include <smgdef.h>
X#include <ttdef.h>
X#include <tt2def.h>
X#else /* values needed from missing include files */
X# define SMG$K_TRM_UP 274
X# define SMG$K_TRM_DOWN 275
X# define SMG$K_TRM_LEFT 276
X# define SMG$K_TRM_RIGHT 277
X# define TT$M_MECHTAB 0x00000100 /* hardware tab support */
X# define TT$M_MECHFORM 0x00080000 /* hardware form-feed support */
X# define TT$M_NOBRDCST 0x00020000 /* disable broadcast messages, but */
X# define TT2$M_BRDCSTMBX 0x00000010 /* catch them in associated mailbox */
X#endif /* __GNUC__ */
X#ifdef USE_QIO_INPUT
X#include <ssdef.h>
X#endif
X#include <errno.h>
X#include <signal.h>
X
Xunsigned long LIB$DISABLE_CTRL(), LIB$ENABLE_CTRL();
Xunsigned long SYS$ASSIGN(), SYS$DASSGN(), SYS$QIOW();
X#ifndef USE_QIO_INPUT
Xunsigned long SMG$CREATE_VIRTUAL_KEYBOARD(), SMG$DELETE_VIRTUAL_KEYBOARD(),
X SMG$READ_KEYSTROKE(), SMG$CANCEL_INPUT();
X#else
Xstatic short FDECL(parse_function_key, (int));
X#endif
Xstatic void NDECL(setctty);
Xstatic void NDECL(resettty);
X
X#define vms_ok(sts) ((sts)&1)
X#define META(c) ((c)|0x80) /* 8th bit */
X#define CTRL(c) ((c)&0x1F)
X#define CMASK(c) (1<<CTRL(c))
X#define LIB$M_CLI_CTRLT CMASK('T') /* 0x00100000 */
X#define LIB$M_CLI_CTRLY CMASK('Y') /* 0x02000000 */
X#define ESC '\033'
X#define CSI META(ESC) /* '\233' */
X#define SS3 META(CTRL('O')) /* '\217' */
X
Xextern short ospeed;
Xchar erase_char, intr_char, kill_char;
Xstatic boolean settty_needed = FALSE, bombing = FALSE;
Xstatic unsigned long kb = 0;
X#ifdef USE_QIO_INPUT
Xstatic char inputbuf[15+1], *inp = 0;
Xstatic int inc = 0;
X#endif
X
X#define QIO_FUNC IO$_TTYREADALL|IO$M_NOECHO|IO$M_TRMNOECHO
X#ifdef MAIL
X#define TT_SPECIAL_HANDLING (TT$M_MECHTAB|TT$M_MECHFORM|TT$M_NOBRDCST)
X#define TT2_SPECIAL_HANDLING (TT2$M_BRDCSTMBX)
X#else
X#define TT_SPECIAL_HANDLING (TT$M_MECHTAB|TT$M_MECHFORM)
X#define TT2_SPECIAL_HANDLING (0)
X#endif
X#define Uword unsigned short
X#define Ubyte unsigned char
Xstruct _rd_iosb { /* i/o status block for read */
X Uword status, trm_offset;
X Uword terminator, trm_siz;
X};
Xstruct _wr_iosb { /* i/o status block for write */
X Uword status, byte_cnt;
X unsigned : 32;
X};
Xstruct _sm_iosb { /* i/o status block for sense-mode qio */
X Uword status;
X Ubyte xmt_speed, rcv_speed;
X Ubyte cr_fill, lf_fill, parity;
X unsigned : 8;
X};
Xstruct _sm_bufr { /* sense-mode characteristics buffer */
X Ubyte class, type; /* class==DC$_TERM, type==(various) */
X Uword buf_siz; /* aka page width */
X#define page_width buf_siz /* number of columns */
X unsigned tt_char : 24; /* primary characteristics */
X unsigned page_length : 8; /* number of lines */
X unsigned tt2_char : 32; /* secondary characteristics */
X};
Xstatic struct {
X struct _sm_iosb io;
X struct _sm_bufr sm;
X} sg = {{0},{0}};
Xstatic unsigned short tt_chan = 0;
Xstatic unsigned long tt_char_restore = 0, tt_char_active = 0,
X tt2_char_restore = 0, tt2_char_active = 0;
Xstatic unsigned long ctrl_mask = 0;
X
Xint
Xvms_getchar()
X{
X short key;
X
X#ifdef USE_QIO_INPUT
X struct _rd_iosb iosb;
X unsigned long sts;
X unsigned char kb_buf;
X
X if (inc > 0) {
X /* we have buffered character(s) from previous read */
X kb_buf = *inp++;
X --inc;
X sts = SS$_NORMAL;
X } else {
X sts = SYS$QIOW(0, tt_chan, QIO_FUNC, &iosb, (void(*)())0, 0,
X &kb_buf, sizeof kb_buf, 0, 0, 0, 0);
X }
X if (vms_ok(sts)) {
X if (kb_buf == CTRL('C')) {
X if (intr_char) gsignal(SIGINT);
X key = (short)kb_buf;
X } else if (kb_buf == '\r') { /* <return> */
X key = (short)'\n';
X } else if (kb_buf == ESC || kb_buf == CSI || kb_buf == SS3) {
X switch(parse_function_key((int)kb_buf)) {
X case SMG$K_TRM_UP: key = flags.num_pad ? '8' : 'k'; break;
X case SMG$K_TRM_DOWN: key = flags.num_pad ? '2' : 'j'; break;
X case SMG$K_TRM_LEFT: key = flags.num_pad ? '4' : 'h'; break;
X case SMG$K_TRM_RIGHT: key = flags.num_pad ? '6' : 'l'; break;
X default: key = ESC; break;
X }
X } else {
X key = (short)kb_buf;
X }
X } else if (sts == SS$_HANGUP || iosb.status == SS$_HANGUP) {
X gsignal(SIGHUP);
X key = ESC;
X } else /*(this should never happen)*/
X key = getchar();
X
X#else /*!USE_QIO_INPUT*/
X static volatile int recurse = 0; /* SMG is not AST re-entrant! */
X
X if (recurse++ == 0 && kb != 0) {
X SMG$READ_KEYSTROKE(&kb, &key);
X switch (key) {
X case SMG$K_TRM_UP: flags.num_pad ? '8' : key = 'k'; break;
X case SMG$K_TRM_DOWN: flags.num_pad ? '2' : key = 'j'; break;
X case SMG$K_TRM_LEFT: flags.num_pad ? '4' : key = 'h'; break;
X case SMG$K_TRM_RIGHT: flags.num_pad ? '6' : key = 'l'; break;
X case '\r': key = '\n'; break;
X default: if (key > 255) key = ESC;
X break;
X }
X } else {
X /* abnormal input--either SMG didn't initialize properly or
X vms_getchar() has been called recursively (via SIGINT handler).
X */
X if (kb != 0) /* must have been a recursive call */
X SMG$CANCEL_INPUT(&kb); /* from an interrupt handler */
X key = getchar();
X }
X --recurse;
X#endif /* USE_QIO_INPUT */
X
X return (int)key;
X}
X
X#ifdef USE_QIO_INPUT
X /*
X * We've just gotten an <escape> character. Do a timed read to
X * get any other characters, then try to parse them as an escape
X * sequence. This isn't perfect, since there's no guarantee
X * that a full escape sequence will be available, or even if one
X * is, it might actually by regular input from a fast typist or
X * a stalled input connection. {For packetized environments,
X * cross plural(body_part(FINGER)) and hope for best. :-}
X *
X * This is needed to preserve compatability with SMG interface
X * for two reasons:
X * 1) retain support for arrow keys, and
X * 2) treat other VTxxx function keys as <esc> for aborting
X * various NetHack prompts.
X * The second reason is compelling; otherwise remaining chars of
X * an escape sequence get treated as inappropriate user commands.
X *
X * SMG code values for these key sequences fall in the range of
X * 256 thru 3xx. The assignments are not particularly intuitive.
X */
X/*=
X -- Summary of VTxxx-style keyboards and transmitted escape sequences. --
XKeypad codes are prefixed by 7 bit (\033 O) or 8 bit SS3:
X keypad: PF1 PF2 PF3 PF4 codes: P Q R S
X 7 8 9 - w x y m
X 4 5 6 . t u v n
X 1 2 3 :en-: q r s : :
X ...0... , :ter: ...p... l :M:
XArrows are prefixed by either SS3 or CSI (either 7 or 8 bit), depending on
Xwhether the terminal is in application or numeric mode (ditto for PF keys):
X arrows: <up> <dwn> <lft> <rgt> A B D C
XAdditional function keys (vk201/vk401) generate CSI nn ~ (nn is 1 or 2 digits):
X vk201 keys: F6 F7 F8 F9 F10 F11 F12 F13 F14 Help Do F17 F18 F19 F20
X 'nn' digits: 17 18 19 20 21 23 24 25 26 28 29 31 32 33 34
X alternate: ^C ^[ ^H ^J (when in VT100 mode)
X edit keypad: <fnd> <ins> <rmv> digits: 1 2 3
X <sel> <prv> <nxt> 4 5 6
XVT52 mode: arrows and PF keys send ESCx where x is in A-D or P-S.
X=*/
X
Xstatic const char *arrow_or_PF = "ABCDPQRS", /* suffix char */
X *smg_keypad_codes = "PQRSpqrstuvwxyMmlnABDC";
X /* PF1..PF4,KP0..KP9,enter,dash,comma,dot,up-arrow,down,left,right */
X /* Ultimate return value is (index into smg_keypad_codes[] + 256). */
X
Xstatic short
Xparse_function_key(c)
Xregister int c;
X{
X struct _rd_iosb iosb;
X unsigned long sts;
X char seq_buf[15+1]; /* plenty room for escape sequence + slop */
X short result = ESC; /* translate to <escape> by default */
X
X /*
X * Read whatever we can from type-ahead buffer (1 second timeout).
X * If the user typed an actual <escape> to deliberately abort
X * something, he or she should be able to tolerate the necessary
X * restriction of a negligible pause before typing anything else.
X * We might already have [at least some of] an escape sequence from a
X * previous read, particularly if user holds down the arrow keys...
X */
X if (inc > 0) strncpy(seq_buf, inp, inc);
X if (inc < sizeof seq_buf - 1) {
X sts = SYS$QIOW(0, tt_chan, QIO_FUNC|IO$M_TIMED, &iosb, (void(*)())0, 0,
X seq_buf + inc, sizeof seq_buf - 1 - inc, 1, 0, 0, 0);
X if (vms_ok(sts)) sts = iosb.status;
X } else
X sts = SS$_NORMAL;
X if (vms_ok(sts) || sts == SS$_TIMEOUT) {
X register int cnt = iosb.trm_offset + iosb.trm_siz + inc;
X register char *p = seq_buf;
X if (c == ESC) /* check for 7-bit vt100/ANSI, or vt52 */
X if (*p == '[' || *p == 'O') c = META(CTRL(*p++)), cnt--;
X else if (strchr(arrow_or_PF, *p)) c = SS3; /*CSI*/
X if (cnt > 0 && (c == SS3 || (c == CSI && strchr(arrow_or_PF, *p)))) {
X register char *q = strchr(smg_keypad_codes, *p);
X if (q) result = 256 + (q - smg_keypad_codes);
X p++, --cnt; /* one more char consumed */
X } else if (cnt > 1 && c == CSI) {
X static short /* "CSI nn ~" -> F_keys[nn] */
X F_keys[35] = { ESC, /*(filler)*/
X 311, 312, 313, 314, 315, 316, /* E1-E6 */
X ESC, ESC, ESC, ESC, /*(more filler)*/
X 281, 282, 283, 284, 285, ESC, /* F1-F5 */
X 286, 287, 288, 289, 290, ESC, /* F6-F10*/
X 291, 292, 293, 294, ESC, /*F11-F14*/
X 295, 296, ESC, /*<help>,<do>, aka F15,F16*/
X 297, 298, 299, 300 /*F17-F20*/
X }; /* note: there are several missing nn in CSI nn ~ values */
X int nn; char *q;
X *(p + cnt) = '\0'; /* terminate string */
X q = strchr(p, '~');
X if (q && sscanf(p, "%d~", &nn) == 1) {
X if (nn > 0 && nn < SIZE(F_keys)) result = F_keys[nn];
X cnt -= (++q - p);
X p = q;
X }
X }
X if (cnt > 0) strncpy((inp = inputbuf), p, (inc = cnt));
X else inc = 0, inp = 0;
X }
X return result;
X}
X#endif /* USE_QIO_INPUT */
X
Xstatic void
Xsetctty()
X{
X struct _sm_iosb iosb;
X unsigned long status;
X
X status = SYS$QIOW(0, tt_chan, IO$_SETMODE, &iosb, (void(*)())0, 0,
X &sg.sm, sizeof sg.sm, 0, 0, 0, 0);
X if (vms_ok(status)) status = iosb.status;
X if (!vms_ok(status)) {
X raw_print("");
X errno = EVMSERR, vaxc$errno = status;
X perror("NetHack(setctty: setmode)");
X wait_synch();
X }
X}
X
Xstatic void
Xresettty(){ /* atexit() routine */
X if (settty_needed) {
X bombing = TRUE; /* don't clear screen; preserve traceback info */
X settty((char *)NULL);
X }
X (void) SYS$DASSGN(tt_chan), tt_chan = 0;
X}
X
X/*
X * Get initial state of terminal, set ospeed (for termcap routines)
X * and switch off tab expansion if necessary.
X * Called by init_nhwindows() and resume_nhwindows() in wintty.c
X * (for initial startup and for returning from '!' or ^Z).
X */
Xvoid
Xgettty()
X{
X static $DESCRIPTOR(tty_dsc, "TT:");
X int err = 0;
X unsigned long status, zero = 0;
X
X if (tt_chan == 0) { /* do this stuff once only */
X flags.cbreak = OFF, flags.echo = ON; /* until setup is complete */
X status = SYS$ASSIGN(&tty_dsc, &tt_chan, 0, 0);
X if (!vms_ok(status)) {
X raw_print(""), err++;
X errno = EVMSERR, vaxc$errno = status;
X perror("NetHack(gettty: $assign)");
X }
X atexit(resettty); /* register an exit handler to reset things */
X }
X status = SYS$QIOW(0, tt_chan, IO$_SENSEMODE, &sg.io, (void(*)())0, 0,
X &sg.sm, sizeof sg.sm, 0, 0, 0, 0);
X if (vms_ok(status)) status = sg.io.status;
X if (!vms_ok(status)) {
X raw_print(""), err++;
X errno = EVMSERR, vaxc$errno = status;
X perror("NetHack(gettty: sensemode)");
X }
X ospeed = sg.io.xmt_speed;
X erase_char = '\177'; /* <rubout>, aka <delete> */
X kill_char = CTRL('U');
X intr_char = CTRL('C');
X (void) LIB$ENABLE_CTRL(&zero, &ctrl_mask);
X /* Use the systems's values for lines and columns if it has any idea. */
X if (sg.sm.page_length)
X LI = sg.sm.page_length;
X if (sg.sm.page_width)
X CO = sg.sm.page_width;
X /* Determine whether TTDRIVER is doing tab and/or form-feed expansion;
X if so, we want to suppress that but also restore it at final exit. */
X if ((sg.sm.tt_char & TT_SPECIAL_HANDLING) != TT_SPECIAL_HANDLING
X && (sg.sm.tt2_char & TT2_SPECIAL_HANDLING) != TT2_SPECIAL_HANDLING) {
X tt_char_restore = sg.sm.tt_char;
X tt_char_active = sg.sm.tt_char |= TT_SPECIAL_HANDLING;
X tt2_char_restore = sg.sm.tt2_char;
X tt2_char_active = sg.sm.tt2_char |= TT2_SPECIAL_HANDLING;
X#if 0 /*[ defer until setftty() ]*/
X setctty();
X#endif
X } else /* no need to take any action */
X tt_char_restore = tt_char_active = 0,
X tt2_char_restore = tt2_char_active = 0;
X if (err) wait_synch();
X}
X
X/* reset terminal to original state */
Xvoid
Xsettty(s)
Xconst char *s;
X{
X if (!bombing) {
X end_screen();
X if (s) raw_print(s);
X }
X disable_broadcast_trapping();
X#if 0 /* let SMG's exit handler do the cleanup (as per doc) */
X/* #ifndef USE_QIO_INPUT */
X if (kb) SMG$DELETE_VIRTUAL_KEYBOARD(&kb), kb = 0;
X#endif /* 0 (!USE_QIO_INPUT) */
X if (ctrl_mask)
X (void) LIB$ENABLE_CTRL(&ctrl_mask, 0);
X flags.echo = ON;
X flags.cbreak = OFF;
X if (tt_char_restore != 0 || tt2_char_restore != 0) {
X sg.sm.tt_char = tt_char_restore;
X sg.sm.tt2_char = tt2_char_restore;
X setctty();
X }
X settty_needed = FALSE;
X}
X
X/* same as settty, with no clearing of the screen */
Xvoid
Xshuttty(s)
Xconst char *s;
X{
X if(s) raw_print(s);
X bombing = TRUE;
X settty(s);
X bombing = FALSE;
X}
X
Xvoid
Xsetftty()
X{
X unsigned long mask = LIB$M_CLI_CTRLT | LIB$M_CLI_CTRLY;
X
X (void) LIB$DISABLE_CTRL(&mask, 0);
X if (kb == 0) { /* do this stuff once only */
X#ifdef USE_QIO_INPUT
X kb = tt_chan;
X#else /*!USE_QIO_INPUT*/
X SMG$CREATE_VIRTUAL_KEYBOARD(&kb);
X#endif /*USE_QIO_INPUT*/
X init_broadcast_trapping();
X }
X enable_broadcast_trapping(); /* no-op if !defined(MAIL) */
X flags.cbreak = (kb != 0) ? ON : OFF;
X flags.echo = (kb != 0) ? OFF : ON;
X /* disable tab & form-feed expansion */
X if (tt_char_active != 0 || tt2_char_active != 0) {
X sg.sm.tt_char = tt_char_active;
X sg.sm.tt2_char = tt2_char_active;
X setctty();
X }
X start_screen();
X settty_needed = TRUE;
X}
X
Xvoid
Xintron() /* enable kbd interupts if enabled when game started */
X{
X intr_char = CTRL('C');
X}
X
Xvoid
Xintroff() /* disable kbd interrupts if required*/
X{
X intr_char = 0;
X}
X
X
X/* fatal error */
X/*VARARGS1*/
Xvoid
Xerror VA_DECL(const char *,s)
X VA_START(s);
X VA_INIT(s, const char *);
X if(settty_needed)
X settty(NULL);
X Vprintf(s,VA_ARGS);
X (void) putchar('\n');
X VA_END();
X exit(1);
X}
END_OF_FILE
if test 14490 -ne `wc -c <'sys/vms/vmstty.c'`; then
echo shar: \"'sys/vms/vmstty.c'\" unpacked with wrong size!
fi
# end of 'sys/vms/vmstty.c'
fi
echo shar: End of archive 87 \(of 108\).
cp /dev/null ark87isdone
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 39 40 \
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
101 102 103 104 105 106 107 108 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 108 archives.
echo "Now execute 'rebuild.sh'"
rm -f ark10[0-8]isdone 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