Import Rogue 5.2 from the Roguelike Restoration Project (r1490)

This commit is contained in:
John "Elwin" Edwards 2009-10-24 16:52:52 +00:00
parent bcc2abe517
commit 9f62c197cc
44 changed files with 16770 additions and 0 deletions

92
rogue4/LICENSE.TXT Normal file
View file

@ -0,0 +1,92 @@
Rogue: Exploring the Dungeons of Doom
Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
===========================================================================
Portions of this software (save/restore game state) are based on the work
of Nicholas J. Kisseberth. Used under license:
Copyright (C) 1999, 2000, 2005 Nicholas J. Kisseberth
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
===========================================================================
Portions of this software (encryption) are based on the work
of David Burren. Used under license:
FreeSec: libcrypt
Copyright (C) 1994 David Burren
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

147
rogue4/Makefile Normal file
View file

@ -0,0 +1,147 @@
#
# Makefile for rogue
# @(#)Makefile 4.13 (Berkeley) 1/23/82
#
# Rogue: Exploring the Dungeons of Doom
# Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
# All rights reserved.
#
# See the file LICENSE.TXT for full copyright and licensing information.
#
DISTNAME=rogue5.2.2
HDRS= rogue.h extern.h
DOBJS= vers.o extern.o armor.o chase.o command.o daemon.o daemons.o \
fight.o init.o io.o list.o main.o misc.o monsters.o move.o \
new_level.o options.o pack.o passages.o potions.o rings.o rip.o \
rooms.o save.o scrolls.o state.o sticks.o things.o weapons.o wizard.o\
xcrypt.o mdport.o
OBJS= $(DOBJS) mach_dep.o
CFILES= vers.c extern.c armor.c chase.c command.c daemon.c daemons.c \
fight.c init.c io.c list.c main.c misc.c monsters.c move.c \
new_level.c options.c pack.c passages.c potions.c rings.c rip.c \
rooms.c save.c scrolls.c state.c sticks.c things.c weapons.c wizard.c \
mach_dep.c xcrypt.c mdport.c
MISC= Makefile LICENSE.TXT rogue.6 rogue.me
CC = gcc
CFLAGS= -O3
CRLIB = -lcurses
RM = rm -f
TAR = tar
SCOREFILE=
SF=-DSCOREFILE=\"rogue52.scr\" -DLOCKFILE=\"rogue52.lck\"
NAMELIST=
NL=
#MACHDEP= -DMAXLOAD=40 -DLOADAV -DCHECKTIME=4
MACHDEP=
.c.o:
@echo $(CC) -c $(CFLAGS) $*.c
@$(CC) -c $(CFLAGS) $*.c -o $*.o
# @cpp -P $(CFLAGS) $*.c | ./xstr -v -c -
# @cc -c $(CFLAGS) x.c
# @mv x.o $*.o
rogue: $(HDRS) $(OBJS) # xs.o
# @rm -f x.c
# $(CC) $(LDFLAGS) xs.o $(OBJS) $(CRLIB)
$(CC) $(LDFLAGS) $(OBJS) $(CRLIB) -o $@
vers.o:
$(CC) -c $(CFLAGS) vers.c
mach_dep.o: mach_dep.c
$(CC) -c $(CFLAGS) $(SF) $(NL) $(MACHDEP) mach_dep.c
xs.o: strings
./xstr
$(CC) -c $(CFLAGS) xs.c
xstr: xstr.c
$(CC) -s -O -o xstr xstr.c
findpw: findpw.c xcrypt.c
$(CC) -s -o findpw findpw.c xcrypt.c
prob: prob.o extern.o xs.o
$(CC) -O -o prob prob.o extern.o xs.o
prob.o: prob.c rogue.h
$(CC) -O -c prob.c
clean:
rm -f $(POBJS) $(OBJS) core a.out p.out rogue strings make.out rogue.tar vgrind.* x.c x.o xs.c xs.o linterrs findpw distmod.o xs.po xstr rogue rogue.exe rogue.tar.gz rogue.cat rogue.doc xstr.exe
dist.src:
make clean
tar cf $(DISTNAME)-src.tar $(CFILES) $(HDRS) $(MISC)
gzip -f $(DISTNAME)-src.tar
debug.irix:
make clean
make CC=cc CFLAGS="-woff 1116 -g -DWIZARD" rogue
dist.irix:
make clean
make CC=cc CFLAGS="-woff 1116 -O3" rogue
tbl rogue.me | nroff -me | colcrt - > rogue.doc
nroff -man rogue.6 | colcrt - > rogue.cat
tar cf $(DISTNAME)-irix.tar rogue LICENSE.TXT rogue.cat rogue.doc
gzip -f $(DISTNAME)-irix.tar
debug.aix:
make clean
make CC=xlc CFLAGS="-qmaxmem=16768 -g -qstrict -DWIZARD" rogue
dist.aix:
make clean
make CC=xlc CFLAGS="-qmaxmem=16768 -O3 -qstrict" rogue
tbl rogue.me | nroff -me | colcrt - > rogue.doc
nroff -man rogue.6 | colcrt - > rogue.cat
tar cf $(DISTNAME)-aix.tar rogue LICENSE.TXT rogue.cat rogue.doc
gzip -f $(DISTNAME)-aix.tar
debug.linux:
make clean
make CFLAGS="-g3 -DWIZARD" rogue
dist.linux:
make clean
make rogue
groff -P-c -t -me -Tascii rogue.me | sed -e 's/.\x08//g' > rogue.doc
groff -man rogue.6 | sed -e 's/.\x08//g' > rogue.cat
tar cf $(DISTNAME)-linux.tar rogue LICENSE.TXT rogue.cat rogue.doc
gzip -f $(DISTNAME)-linux.tar
debug.interix:
make clean
make CFLAGS="-g3 -DWIZARD" rogue
dist.interix:
make clean
make rogue
groff -P-b -P-u -t -me -Tascii rogue.me > rogue.doc
groff -P-b -P-u -man -Tascii rogue.6 > rogue.cat
tar cf $(DISTNAME)-interix.tar rogue LICENSE.TXT rogue.cat rogue.doc
gzip -f $(DISTNAME)-interix.tar
debug.cygwin:
make clean
make CFLAGS="-g3 -DWIZARD" rogue
dist.cygwin:
make clean
make rogue
groff -P-c -t -me -Tascii rogue.me | sed -e 's/.\x08//g' > rogue.doc
groff -P-c -man -Tascii rogue.6 | sed -e 's/.\x08//g' > rogue.cat
tar cf $(DISTNAME)-cygwin.tar rogue.exe LICENSE.TXT rogue.cat rogue.doc
gzip -f $(DISTNAME)-cygwin.tar
debug.djgpp:
make clean
make CFLAGS="-g3 -DWIZARD" LDFLAGS="-L$(DJDIR)/LIB" CRLIB="-lpdcurses" rogue
dist.djgpp:
make clean
make CFLAGS="-O3" LDFLAGS="-L$(DJDIR)/LIB" CRLIB="-lpdcurses" rogue
groff -t -me -Tascii rogue.me | sed -e 's/.\x08//g' > rogue.doc
groff -man -Tascii rogue.6 | sed -e 's/.\x08//g' > rogue.cat
rm -f $(DISTNAME)-djgpp.zip
zip $(DISTNAME)-djgpp.zip rogue.exe LICENSE.TXT rogue.cat rogue.doc

86
rogue4/armor.c Normal file
View file

@ -0,0 +1,86 @@
/*
* This file contains misc functions for dealing with armor
* @(#)armor.c 4.8 (Berkeley) 4/6/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include "rogue.h"
/*
* wear:
* The player wants to wear something, so let him/her put it on.
*/
wear()
{
register THING *obj;
register char *sp;
if (cur_armor != NULL)
{
addmsg("you are already wearing some");
if (!terse)
addmsg(". You'll have to take it off first");
endmsg();
after = FALSE;
return;
}
if ((obj = get_item("wear", ARMOR)) == NULL)
return;
if (obj->o_type != ARMOR)
{
msg("you can't wear that");
return;
}
waste_time();
obj->o_flags |= ISKNOW;
sp = inv_name(obj, TRUE);
cur_armor = obj;
if (!terse)
addmsg("you are now ");
msg("wearing %s", sp);
}
/*
* take_off:
* Get the armor off of the players back
*/
take_off()
{
register THING *obj;
if ((obj = cur_armor) == NULL)
{
after = FALSE;
if (terse)
msg("not wearing armor");
else
msg("you aren't wearing any armor");
return;
}
if (!dropcheck(cur_armor))
return;
cur_armor = NULL;
if (terse)
addmsg("was");
else
addmsg("you used to be ");
msg(" wearing %c) %s", pack_char(obj), inv_name(obj, TRUE));
}
/*
* waste_time:
* Do nothing but let other things happen
*/
waste_time()
{
do_daemons(BEFORE);
do_fuses(BEFORE);
do_daemons(AFTER);
do_fuses(AFTER);
}

424
rogue4/chase.c Normal file
View file

@ -0,0 +1,424 @@
/*
* Code for one creature to chase another
*
* @(#)chase.c 4.25 (Berkeley) 5/5/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include "rogue.h"
#define DRAGONSHOT 5 /* one chance in DRAGONSHOT that a dragon will flame */
coord ch_ret; /* Where chasing takes you */
/*
* runners:
* Make all the running monsters move.
*/
runners()
{
register THING *tp;
register THING *ntp;
for (tp = mlist; tp != NULL; tp = ntp)
{
ntp = next(tp);
if (!on(*tp, ISHELD) && on(*tp, ISRUN))
{
if (!on(*tp, ISSLOW) || tp->t_turn)
if (do_chase(tp) == -1)
continue;
if (on(*tp, ISHASTE))
if (do_chase(tp) == -1)
continue;
tp->t_turn ^= TRUE;
}
}
}
/*
* do_chase:
* Make one thing chase another.
*/
do_chase(th)
register THING *th;
{
register struct room *rer, *ree; /* room of chaser, room of chasee */
register int mindist = 32767, i, dist;
register bool stoprun = FALSE; /* TRUE means we are there */
register char sch;
register bool door;
register THING *obj;
register struct room *oroom;
coord this; /* Temporary destination for chaser */
rer = th->t_room; /* Find room of chaser */
if (on(*th, ISGREED) && rer->r_goldval == 0)
th->t_dest = &hero; /* If gold has been taken, run after hero */
if (th->t_dest == &hero) /* Find room of chasee */
ree = proom;
else
ree = roomin(th->t_dest);
/*
* We don't count doors as inside rooms for this routine
*/
door = (chat(th->t_pos.y, th->t_pos.x) == DOOR);
/*
* If the object of our desire is in a different room,
* and we are not in a corridor, run to the door nearest to
* our goal.
*/
over:
if (rer != ree)
{
for (i = 0; i < rer->r_nexits; i++) /* loop through doors */
{
dist = DISTANCE(th->t_dest->y, th->t_dest->x,
rer->r_exit[i].y, rer->r_exit[i].x);
if (dist < mindist)
{
this = rer->r_exit[i];
mindist = dist;
}
}
if (door)
{
rer = &passages[flat(th->t_pos.y, th->t_pos.x) & F_PNUM];
door = FALSE;
goto over;
}
}
else
{
this = *th->t_dest;
/*
* For dragons check and see if (a) the hero is on a straight
* line from it, and (b) that it is within shooting distance,
* but outside of striking range.
*/
if (th->t_type == 'D' && (th->t_pos.y == hero.y || th->t_pos.x == hero.x
|| abs(th->t_pos.y - hero.y) == abs(th->t_pos.x - hero.x))
&& DISTANCE(th->t_pos.y, th->t_pos.x, hero.y, hero.x) <= BOLT_LENGTH * BOLT_LENGTH
&& !on(*th, ISCANC) && rnd(DRAGONSHOT) == 0)
{
delta.y = sign(hero.y - th->t_pos.y);
delta.x = sign(hero.x - th->t_pos.x);
fire_bolt(&th->t_pos, &delta, "flame");
running = FALSE;
count = quiet = 0;
return 0;
}
}
/*
* This now contains what we want to run to this time
* so we run to it. If we hit it we either want to fight it
* or stop running
*/
if (!chase(th, &this))
{
if (ce(this, hero))
{
return ( attack(th) );
}
else if (ce(this, *th->t_dest))
{
for (obj = lvl_obj; obj != NULL; obj = next(obj))
if (th->t_dest == &obj->o_pos)
{
detach(lvl_obj, obj);
attach(th->t_pack, obj);
chat(obj->o_pos.y, obj->o_pos.x) =
(th->t_room->r_flags & ISGONE) ? PASSAGE : FLOOR;
th->t_dest = find_dest(th);
break;
}
if (th->t_type != 'F')
stoprun = TRUE;
}
}
else if (th->t_type == 'F')
return(0);
mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch);
if (!ce(ch_ret, th->t_pos))
{
sch = mvinch(ch_ret.y, ch_ret.x);
if (sch == FLOOR && (th->t_room->r_flags & ISDARK)
&& DISTANCE(th->t_pos.y, th->t_pos.x, hero.y, hero.x)
&& !on(player, ISBLIND))
th->t_oldch = ' ';
else
th->t_oldch = sch;
oroom = th->t_room;
th->t_room = roomin(&ch_ret);
if (oroom != th->t_room)
th->t_dest = find_dest(th);
moat(th->t_pos.y, th->t_pos.x) = NULL;
moat(ch_ret.y, ch_ret.x) = th;
th->t_pos = ch_ret;
}
if (see_monst(th))
mvaddch(ch_ret.y, ch_ret.x, th->t_disguise);
else if (on(player, SEEMONST))
{
standout();
mvaddch(ch_ret.y, ch_ret.x, th->t_type);
standend();
}
/*
* And stop running if need be
*/
if (stoprun && ce(th->t_pos, *(th->t_dest)))
th->t_flags &= ~ISRUN;
return(0);
}
/*
* see_monst:
* Return TRUE if the hero can see the monster
*/
see_monst(mp)
register THING *mp;
{
if (on(player, ISBLIND))
return FALSE;
if (on(*mp, ISINVIS) && !on(player, CANSEE))
return FALSE;
if (DISTANCE(mp->t_pos.y, mp->t_pos.x, hero.y, hero.x) < LAMPDIST)
return TRUE;
if (mp->t_room != proom)
return FALSE;
return (!(mp->t_room->r_flags & ISDARK));
}
/*
* runto:
* Set a mosnter running after something or stop it from running
* (for when it dies)
*/
runto(runner, spot)
register coord *runner;
coord *spot;
{
register THING *tp;
/*
* If we couldn't find him, something is funny
*/
#ifdef WIZARD
if ((tp = moat(runner->y, runner->x)) == NULL)
msg("couldn't find monster in runto at (%d,%d)", runner->y, runner->x);
#else
tp = moat(runner->y, runner->x);
#endif
/*
* Start the beastie running
*/
if (tp == NULL)
return;
tp->t_flags |= ISRUN;
tp->t_flags &= ~ISHELD;
tp->t_dest = find_dest(tp);
}
/*
* chase:
* Find the spot for the chaser(er) to move closer to the
* chasee(ee). Returns TRUE if we want to keep on chasing later
* FALSE if we reach the goal.
*/
chase(tp, ee)
THING *tp;
coord *ee;
{
register int x, y;
register int dist, thisdist;
register THING *obj;
register coord *er = &tp->t_pos;
register char ch;
register int plcnt = 1;
/*
* If the thing is confused, let it move randomly. Invisible
* Stalkers are slightly confused all of the time, and bats are
* quite confused all the time
*/
if ((on(*tp, ISHUH) && rnd(5) != 0) || (tp->t_type == 'I' && rnd(5) == 0)
|| (tp->t_type == 'B' && rnd(2) == 0))
{
/*
* get a valid random move
*/
ch_ret = *rndmove(tp);
dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x);
/*
* Small chance that it will become un-confused
*/
if (rnd(20) == 0)
tp->t_flags &= ~ISHUH;
}
/*
* Otherwise, find the empty spot next to the chaser that is
* closest to the chasee.
*/
else
{
register int ey, ex;
/*
* This will eventually hold where we move to get closer
* If we can't find an empty spot, we stay where we are.
*/
dist = DISTANCE(er->y, er->x, ee->y, ee->x);
ch_ret = *er;
ey = er->y + 1;
ex = er->x + 1;
for (x = er->x - 1; x <= ex; x++)
for (y = er->y - 1; y <= ey; y++)
{
coord tryp;
tryp.x = x;
tryp.y = y;
if (!diag_ok(er, &tryp))
continue;
ch = winat(y, x);
if (step_ok(ch))
{
/*
* If it is a scroll, it might be a scare monster scroll
* so we need to look it up to see what type it is.
*/
if (ch == SCROLL)
{
for (obj = lvl_obj; obj != NULL; obj = next(obj))
{
if (y == obj->o_pos.y && x == obj->o_pos.x)
break;
}
if (obj != NULL && obj->o_which == S_SCARE)
continue;
}
/*
* It can also be a Mimic, which we shouldn't step on
*/
if ((obj = moat(y, x)) != NULL && obj->t_type == 'M')
continue;
/*
* If we didn't find any scrolls at this place or it
* wasn't a scare scroll, then this place counts
*/
thisdist = DISTANCE(y, x, ee->y, ee->x);
if (thisdist < dist)
{
plcnt = 1;
ch_ret = tryp;
dist = thisdist;
}
else if (thisdist == dist && rnd(++plcnt) == 0)
{
ch_ret = tryp;
dist = thisdist;
}
}
}
}
return (dist != 0 && !ce(ch_ret, hero));
}
/*
* roomin:
* Find what room some coordinates are in. NULL means they aren't
* in any room.
*/
struct room *
roomin(cp)
register coord *cp;
{
register struct room *rp;
register char *fp;
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
if (cp->x < rp->r_pos.x + rp->r_max.x && rp->r_pos.x <= cp->x
&& cp->y < rp->r_pos.y + rp->r_max.y && rp->r_pos.y <= cp->y)
return rp;
fp = &flat(cp->y, cp->x);
if (*fp & F_PASS)
return &passages[*fp & F_PNUM];
msg("in some bizarre place (%d, %d)", unc(*cp));
return NULL;
}
/*
* diag_ok:
* Check to see if the move is legal if it is diagonal
*/
diag_ok(sp, ep)
register coord *sp, *ep;
{
if (ep->x == sp->x || ep->y == sp->y)
return TRUE;
return (step_ok(chat(ep->y, sp->x)) && step_ok(chat(sp->y, ep->x)));
}
/*
* cansee:
* Returns true if the hero can see a certain coordinate.
*/
cansee(y, x)
register int y, x;
{
register struct room *rer;
coord tp;
if (on(player, ISBLIND))
return FALSE;
if (DISTANCE(y, x, hero.y, hero.x) < LAMPDIST)
return TRUE;
/*
* We can only see if the hero in the same room as
* the coordinate and the room is lit or if it is close.
*/
tp.y = y;
tp.x = x;
return ((rer = roomin(&tp)) == proom && !(rer->r_flags & ISDARK));
}
/*
* find_dest:
* find the proper destination for the monster
*/
coord *
find_dest(tp)
register THING *tp;
{
register THING *obj;
register int prob;
register struct room *rp;
if ((prob = monsters[tp->t_type - 'A'].m_carry) <= 0 || tp->t_room == proom
|| see_monst(tp))
return &hero;
rp = tp->t_room;
for (obj = lvl_obj; obj != NULL; obj = next(obj))
{
if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
continue;
if (roomin(&obj->o_pos) == rp && rnd(100) < prob)
{
for (tp = mlist; tp != NULL; tp = next(tp))
if (tp->t_dest == &obj->o_pos)
break;
if (tp == NULL)
return &obj->o_pos;
}
}
return &hero;
}

600
rogue4/command.c Normal file
View file

@ -0,0 +1,600 @@
/*
* Read and execute the user commands
*
* @(#)command.c 4.31 (Berkeley) 4/6/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdlib.h>
#include <curses.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "rogue.h"
char countch, direction, newcount = FALSE;
/*
* command:
* Process the user commands
*/
command()
{
register char ch;
register int ntimes = 1; /* Number of player moves */
char *unctrol();
if (on(player, ISHASTE))
ntimes++;
/*
* Let the daemons start up
*/
do_daemons(BEFORE);
do_fuses(BEFORE);
while (ntimes--)
{
/*
* these are illegal things for the player to be, so if any are
* set, someone's been poking in memeory
*/
if (on(player, ISSLOW|ISCANC|ISGREED|ISINVIS|ISMEAN|ISREGEN))
auto_save(-1);
look(TRUE);
if (!running)
door_stop = FALSE;
status();
lastscore = purse;
move(hero.y, hero.x);
if (!((running || count) && jump))
refresh(); /* Draw screen */
take = 0;
after = TRUE;
/*
* Read command or continue run
*/
#ifdef WIZARD
if (wizard)
noscore = TRUE;
#endif
if (!no_command)
{
if (running) ch = runch;
else if (count) ch = countch;
else
{
ch = readchar();
if (mpos != 0 && !running) /* Erase message if its there */
msg("");
}
}
else
ch = '.';
if (no_command)
{
if (--no_command == 0)
{
player.t_flags |= ISRUN;
msg("you can move again");
}
}
else
{
/*
* check for prefixes
*/
if (isdigit(ch))
{
count = 0;
newcount = TRUE;
while (isdigit(ch))
{
count = count * 10 + (ch - '0');
ch = readchar();
}
countch = ch;
/*
* turn off count for commands which don't make sense
* to repeat
*/
switch (ch) {
case 'h': case 'j': case 'k': case 'l':
case 'y': case 'u': case 'b': case 'n':
case 'H': case 'J': case 'K': case 'L':
case 'Y': case 'U': case 'B': case 'N':
case 'q': case 'r': case 's': case 'f':
case 't': case 'C': case 'I': case '.':
case 'z':
#ifdef WIZARD
case CTRL('D'): case CTRL('U'):
#endif
break;
default:
count = 0;
}
}
switch (ch)
{
case 'f':
if (!on(player, ISBLIND))
{
door_stop = TRUE;
firstmove = TRUE;
}
if (count && !newcount)
ch = direction;
else
ch = readchar();
switch (ch)
{
case 'h': case 'j': case 'k': case 'l':
case 'y': case 'u': case 'b': case 'n':
ch = toupper(ch);
}
direction = ch;
}
newcount = FALSE;
/*
* execute a command
*/
if (count && !running)
count--;
switch (ch)
{
case '!' : shell();
when 'h' : do_move(0, -1);
when 'j' : do_move(1, 0);
when 'k' : do_move(-1, 0);
when 'l' : do_move(0, 1);
when 'y' : do_move(-1, -1);
when 'u' : do_move(-1, 1);
when 'b' : do_move(1, -1);
when 'n' : do_move(1, 1);
when 'H' : do_run('h');
when 'J' : do_run('j');
when 'K' : do_run('k');
when 'L' : do_run('l');
when 'Y' : do_run('y');
when 'U' : do_run('u');
when 'B' : do_run('b');
when 'N' : do_run('n');
when 't':
if (!get_dir())
after = FALSE;
else
missile(delta.y, delta.x);
when 'Q' : after = FALSE; quit(-1);
when 'i' : after = FALSE; inventory(pack, 0);
when 'I' : after = FALSE; picky_inven();
when 'd' : drop();
when 'q' : quaff();
when 'r' : read_scroll();
when 'e' : eat();
when 'w' : wield();
when 'W' : wear();
when 'T' : take_off();
when 'P' : ring_on();
when 'R' : ring_off();
when 'o' : option(); after = FALSE;
when 'c' : call(); after = FALSE;
when '>' : after = FALSE; d_level();
when '<' : after = FALSE; u_level();
when '?' : after = FALSE; help();
when '/' : after = FALSE; identify();
when 's' : search();
when 'z':
if (get_dir())
do_zap();
else
after = FALSE;
when 'D': after = FALSE; discovered();
when CTRL('R') : after = FALSE; msg(huh);
when CTRL('L') :
after = FALSE;
clearok(curscr,TRUE);
wrefresh(curscr);
when 'v' :
after = FALSE;
msg("rogue version %s. (mctesq was here)", release);
when 'S' :
after = FALSE;
if (save_game())
{
move(LINES-1, 0);
clrtoeol();
refresh();
endwin();
exit(0);
}
when '.' : ; /* Rest command */
when ' ' : after = FALSE; /* "Legal" illegal command */
when '^' :
after = FALSE;
if (get_dir()) {
delta.y += hero.y;
delta.x += hero.x;
if (chat(delta.y, delta.x) != TRAP)
msg("no trap there");
else
msg(tr_name(flat(delta.y, delta.x) & F_TMASK));
}
#ifdef WIZARD
when CTRL('P') :
after = FALSE;
if (wizard)
{
wizard = FALSE;
turn_see(TRUE);
msg("not wizard any more");
}
else
{
if (wizard = passwd())
{
noscore = TRUE;
turn_see(FALSE);
msg("you are suddenly as smart as Ken Arnold in dungeon #%d", dnum);
}
else
msg("sorry");
}
#endif
when ESCAPE : /* Escape */
door_stop = FALSE;
count = 0;
after = FALSE;
otherwise :
after = FALSE;
#ifdef WIZARD
if (wizard) switch (ch)
{
case '@' : msg("@ %d,%d", hero.y, hero.x);
when 'C' : create_obj();
when CTRL('I') : inventory(lvl_obj, 0);
when CTRL('W') : whatis(FALSE);
when CTRL('D') : level++; new_level();
when CTRL('U') : if (level > 1) level--; new_level();
when CTRL('F') : show_map();
when CTRL('T') : teleport();
when CTRL('E') : msg("food left: %d", food_left);
when CTRL('A') : msg("%d things in your pack", inpack);
when CTRL('K') : add_pass();
when CTRL('X') : turn_see(on(player, SEEMONST));
when CTRL('N') :
{
register THING *item;
if ((item = get_item("charge", STICK)) != NULL)
item->o_charges = 10000;
}
when CTRL('H') :
{
register int i;
register THING *obj;
for (i = 0; i < 9; i++)
raise_level();
/*
* Give the rogue a sword (+1,+1)
*/
obj = new_item();
obj->o_type = WEAPON;
obj->o_which = TWOSWORD;
init_weapon(obj, SWORD);
obj->o_hplus = 1;
obj->o_dplus = 1;
obj->o_count = 1;
obj->o_group = 0;
add_pack(obj, TRUE);
cur_weapon = obj;
/*
* And his suit of armor
*/
obj = new_item();
obj->o_type = ARMOR;
obj->o_which = PLATE_MAIL;
obj->o_ac = -5;
obj->o_flags |= ISKNOW;
obj->o_count = 1;
obj->o_group = 0;
cur_armor = obj;
add_pack(obj, TRUE);
}
otherwise :
illcom(ch);
}
else
#endif
illcom(ch);
}
/*
* turn off flags if no longer needed
*/
if (!running)
door_stop = FALSE;
}
/*
* If he ran into something to take, let him pick it up.
*/
if (take != 0)
pick_up(take);
if (!running)
door_stop = FALSE;
if (!after)
ntimes++;
}
do_daemons(AFTER);
do_fuses(AFTER);
if (ISRING(LEFT, R_SEARCH))
search();
else if (ISRING(LEFT, R_TELEPORT) && rnd(50) == 0)
teleport();
if (ISRING(RIGHT, R_SEARCH))
search();
else if (ISRING(RIGHT, R_TELEPORT) && rnd(50) == 0)
teleport();
}
/*
* illcom:
* What to do with an illegal command
*/
illcom(ch)
char ch;
{
save_msg = FALSE;
count = 0;
msg("illegal command '%s'", unctrol(ch));
save_msg = TRUE;
}
/*
* search:
* Player gropes about him to find hidden things.
*/
search()
{
register int y, x;
register char *fp;
register int ey, ex;
if (on(player, ISBLIND))
return;
ey = hero.y + 1;
ex = hero.x + 1;
for (y = hero.y - 1; y <= ey; y++)
for (x = hero.x - 1; x <= ex; x++)
{
if (y == hero.y && x == hero.x)
continue;
fp = &flat(y, x);
if (!(*fp & F_REAL))
switch (chat(y, x))
{
case '|':
case '-':
if (rnd(5) != 0)
break;
chat(y, x) = DOOR;
*fp |= F_REAL;
count = running = FALSE;
break;
case FLOOR:
if (rnd(2) != 0)
break;
chat(y, x) = TRAP;
*fp |= F_REAL;
count = running = FALSE;
msg("%s%s", terse ? "" : "you found ", tr_name(*fp & F_TMASK));
break;
}
}
}
/*
* help:
* Give single character help, or the whole mess if he wants it
*/
help()
{
register const struct h_list *strp = helpstr;
register char helpch;
register int cnt;
msg("character you want help for (* for all): ");
helpch = readchar();
mpos = 0;
/*
* If its not a *, print the right help string
* or an error if he typed a funny character.
*/
if (helpch != '*')
{
move(0, 0);
while (strp->h_ch)
{
if (strp->h_ch == helpch)
{
msg("%s%s", unctrol(strp->h_ch), strp->h_desc);
break;
}
strp++;
}
if (strp->h_ch != helpch)
msg("unknown character '%s'", unctrol(helpch));
return;
}
/*
* Here we print help for everything.
* Then wait before we return to command mode
*/
wclear(hw);
cnt = 0;
while (strp->h_ch)
{
mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrol(strp->h_ch));
waddstr(hw, strp->h_desc);
cnt++;
strp++;
}
wmove(hw, LINES-1, 0);
wprintw(hw, "--Press space to continue--");
wrefresh(hw);
w_wait_for(hw,' ');
wmove(stdscr, 0, 0);
wclrtoeol(stdscr);
touchwin(stdscr);
clearok(stdscr, TRUE);
refresh();
}
/*
* identify:
* Tell the player what a certain thing is.
*/
identify()
{
register char ch;
register const char *str;
msg("what do you want identified? ");
ch = readchar();
mpos = 0;
if (ch == ESCAPE)
{
msg("");
return;
}
if (isupper(ch))
str = monsters[ch-'A'].m_name;
else switch (ch)
{
case '|':
case '-':
str = "wall of a room";
when GOLD: str = "gold";
when STAIRS : str = "a staircase";
when DOOR: str = "door";
when FLOOR: str = "room floor";
when PLAYER: str = "you";
when PASSAGE: str = "passage";
when TRAP: str = "trap";
when POTION: str = "potion";
when SCROLL: str = "scroll";
when FOOD: str = "food";
when WEAPON: str = "weapon";
when ' ' : str = "solid rock";
when ARMOR: str = "armor";
when AMULET: str = "the Amulet of Yendor";
when RING: str = "ring";
when STICK: str = "wand or staff";
otherwise: str = "unknown character";
}
msg("'%s': %s", unctrol(ch), str);
}
/*
* d_level:
* He wants to go down a level
*/
d_level()
{
if (chat(hero.y, hero.x) != STAIRS)
msg("I see no way down");
else
{
level++;
new_level();
}
}
/*
* u_level:
* He wants to go up a level
*/
u_level()
{
if (chat(hero.y, hero.x) == STAIRS)
if (amulet)
{
level--;
if (level == 0)
total_winner();
new_level();
msg("you feel a wrenching sensation in your gut");
}
else
msg("your way is magically blocked");
else
msg("I see no way up");
}
/*
* call:
* Allow a user to call a potion, scroll, or ring something
*/
call()
{
register THING *obj;
register char **guess;
const char *elsewise;
register bool *know;
obj = get_item("call", CALLABLE);
/*
* Make certain that it is somethings that we want to wear
*/
if (obj == NULL)
return;
switch (obj->o_type)
{
case RING:
guess = r_guess;
know = r_know;
elsewise = (r_guess[obj->o_which] != NULL ?
r_guess[obj->o_which] : r_stones[obj->o_which]);
when POTION:
guess = p_guess;
know = p_know;
elsewise = (p_guess[obj->o_which] != NULL ?
p_guess[obj->o_which] : p_colors[obj->o_which]);
when SCROLL:
guess = s_guess;
know = s_know;
elsewise = (s_guess[obj->o_which] != NULL ?
s_guess[obj->o_which] : s_names[obj->o_which]);
when STICK:
guess = ws_guess;
know = ws_know;
elsewise = (ws_guess[obj->o_which] != NULL ?
ws_guess[obj->o_which] : ws_made[obj->o_which]);
otherwise:
msg("you can't call that anything");
return;
}
if (know[obj->o_which])
{
msg("that has already been identified");
return;
}
if (!terse)
addmsg("Was ");
msg("called \"%s\"", elsewise);
if (terse)
msg("call it: ");
else
msg("what do you want to call it? ");
if (guess[obj->o_which] != NULL)
free(guess[obj->o_which]);
strcpy(prbuf, elsewise);
if (get_str(prbuf, stdscr) == NORM)
{
guess[obj->o_which] = malloc((unsigned int) strlen(prbuf) + 1);
strcpy(guess[obj->o_which], prbuf);
}
}

186
rogue4/daemon.c Normal file
View file

@ -0,0 +1,186 @@
/*
* Contains functions for dealing with things that happen in the
* future.
*
* @(#)daemon.c 4.4 (Berkeley) 1/12/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include "rogue.h"
#define EMPTY 0
#define DAEMON -1
#define _X_ { EMPTY }
struct delayed_action d_list[MAXDAEMONS] = {
_X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
_X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
};
/*
* d_slot:
* Find an empty slot in the daemon/fuse list
*/
struct delayed_action *
d_slot()
{
register int i;
register struct delayed_action *dev;
for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++)
if (dev->d_type == EMPTY)
return dev;
#ifdef WIZARD
debug("Ran out of fuse slots");
#endif
return NULL;
}
/*
* find_slot:
* Find a particular slot in the table
*/
struct delayed_action *
find_slot(func)
register int (*func)();
{
register int i;
register struct delayed_action *dev;
for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++)
if (dev->d_type != EMPTY && func == dev->d_func)
return dev;
return NULL;
}
/*
* daemon:
* Start a daemon, takes a function.
*/
daemon(func, arg, type)
int (*func)(), arg, type;
{
register struct delayed_action *dev;
dev = d_slot();
dev->d_type = type;
dev->d_func = func;
dev->d_arg = arg;
dev->d_time = DAEMON;
}
/*
* kill_daemon:
* Remove a daemon from the list
*/
kill_daemon(func)
int (*func)();
{
register struct delayed_action *dev;
if ((dev = find_slot(func)) == NULL)
return;
/*
* Take it out of the list
*/
dev->d_type = EMPTY;
}
/*
* do_daemons:
* Run all the daemons that are active with the current flag,
* passing the argument to the function.
*/
do_daemons(flag)
register int flag;
{
register struct delayed_action *dev;
/*
* Loop through the devil list
*/
for (dev = d_list; dev <= &d_list[MAXDAEMONS-1]; dev++)
/*
* Executing each one, giving it the proper arguments
*/
if (dev->d_type == flag && dev->d_time == DAEMON)
(*dev->d_func)(dev->d_arg);
}
/*
* fuse:
* Start a fuse to go off in a certain number of turns
*/
fuse(func, arg, time, type)
int (*func)(), arg, time, type;
{
register struct delayed_action *wire;
wire = d_slot();
wire->d_type = type;
wire->d_func = func;
wire->d_arg = arg;
wire->d_time = time;
}
/*
* lengthen:
* Increase the time until a fuse goes off
*/
lengthen(func, xtime)
int (*func)();
int xtime;
{
register struct delayed_action *wire;
if ((wire = find_slot(func)) == NULL)
return;
wire->d_time += xtime;
}
/*
* extinguish:
* Put out a fuse
*/
extinguish(func)
int (*func)();
{
register struct delayed_action *wire;
if ((wire = find_slot(func)) == NULL)
return;
wire->d_type = EMPTY;
}
/*
* do_fuses:
* Decrement counters and start needed fuses
*/
do_fuses(flag)
register int flag;
{
register struct delayed_action *wire;
/*
* Step though the list
*/
for (wire = d_list; wire <= &d_list[MAXDAEMONS-1]; wire++)
{
/*
* Decrementing counters and starting things we want. We also need
* to remove the fuse from the list once it has gone off.
*/
if (flag == wire->d_type && wire->d_time > 0 && --wire->d_time == 0)
{
wire->d_type = EMPTY;
(*wire->d_func)(wire->d_arg);
}
}
}

174
rogue4/daemons.c Normal file
View file

@ -0,0 +1,174 @@
/*
* All the daemon and fuse functions are in here
*
* @(#)daemons.c 4.10 (Berkeley) 4/6/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include "rogue.h"
int between = 0;
/*
* doctor:
* A healing daemon that restors hit points after rest
*/
doctor()
{
register int lv, ohp;
lv = pstats.s_lvl;
ohp = pstats.s_hpt;
quiet++;
if (lv < 8)
{
if (quiet + (lv << 1) > 20)
pstats.s_hpt++;
}
else
if (quiet >= 3)
pstats.s_hpt += rnd(lv - 7) + 1;
if (ISRING(LEFT, R_REGEN))
pstats.s_hpt++;
if (ISRING(RIGHT, R_REGEN))
pstats.s_hpt++;
if (ohp != pstats.s_hpt)
{
if (pstats.s_hpt > max_hp)
pstats.s_hpt = max_hp;
quiet = 0;
}
}
/*
* Swander:
* Called when it is time to start rolling for wandering monsters
*/
swander()
{
daemon(rollwand, 0, BEFORE);
}
/*
* rollwand:
* Called to roll to see if a wandering monster starts up
*/
rollwand()
{
if (++between >= 4)
{
if (roll(1, 6) == 4)
{
wanderer();
kill_daemon(rollwand);
fuse(swander, 0, WANDERTIME, BEFORE);
}
between = 0;
}
}
/*
* unconfuse:
* Release the poor player from his confusion
*/
unconfuse()
{
player.t_flags &= ~ISHUH;
msg("you feel less confused now");
}
/*
* unsee:
* Turn off the ability to see invisible
*/
unsee()
{
register THING *th;
for (th = mlist; th != NULL; th = next(th))
if (on(*th, ISINVIS) && see_monst(th))
{
move(th->t_pos.y, th->t_pos.x);
addch(th->t_oldch);
}
player.t_flags &= ~CANSEE;
}
/*
* sight:
* He gets his sight back
*/
sight()
{
if (on(player, ISBLIND))
{
extinguish(sight);
player.t_flags &= ~ISBLIND;
if (!(proom->r_flags & ISGONE))
enter_room(&hero);
msg("the veil of darkness lifts");
}
}
/*
* nohaste:
* End the hasting
*/
nohaste()
{
player.t_flags &= ~ISHASTE;
msg("you feel yourself slowing down");
}
/*
* stomach:
* Digest the hero's food
*/
stomach()
{
register int oldfood;
if (food_left <= 0)
{
if (food_left-- < -STARVETIME)
death('s');
/*
* the hero is fainting
*/
if (no_command || rnd(5) != 0)
return;
no_command += rnd(8) + 4;
player.t_flags &= ~ISRUN;
running = FALSE;
count = 0;
hungry_state = 3;
if (!terse)
addmsg("you feel too weak from lack of food. ");
msg("You faint");
}
else
{
oldfood = food_left;
food_left -= ring_eat(LEFT) + ring_eat(RIGHT) + 1 - amulet;
if (food_left < MORETIME && oldfood >= MORETIME)
{
hungry_state = 2;
msg("you are starting to feel weak");
}
else if (food_left < 2 * MORETIME && oldfood >= 2 * MORETIME)
{
hungry_state = 1;
if (!terse)
msg("you are starting to get hungry");
else
msg("getting hungry");
}
}
}

325
rogue4/extern.c Normal file
View file

@ -0,0 +1,325 @@
/*
* global variable initializaton
*
* @(#)extern.c 4.32 (Berkeley) 4/1/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include "rogue.h"
bool after; /* True if we want after daemons */
bool noscore; /* Was a wizard sometime */
bool s_know[MAXSCROLLS]; /* Does he know what a scroll does */
bool p_know[MAXPOTIONS]; /* Does he know what a potion does */
bool r_know[MAXRINGS]; /* Does he know what a ring does */
bool ws_know[MAXSTICKS]; /* Does he know what a stick does */
bool amulet = FALSE; /* He found the amulet */
bool askme = FALSE; /* Ask about unidentified things */
bool door_stop = FALSE; /* Stop running when we pass a door */
bool fight_flush = FALSE; /* True if toilet input */
bool firstmove = FALSE; /* First move after setting door_stop */
bool in_shell = FALSE; /* True if executing a shell */
bool jump = FALSE; /* Show running as series of jumps */
bool passgo = FALSE; /* Follow passages */
bool playing = TRUE; /* True until he quits */
bool running = FALSE; /* True if player is running */
bool save_msg = TRUE; /* Remember last msg */
bool slow_invent = FALSE; /* Inventory one line at a time */
bool terse = FALSE; /* True if we should be short */
#ifdef WIZARD
bool wizard = FALSE; /* True if allows wizard commands */
#endif
char take; /* Thing the rogue is taking */
char prbuf[MAXSTR]; /* Buffer for sprintfs */
char outbuf[BUFSIZ]; /* Output buffer for stdout */
char runch; /* Direction player is running */
char *s_names[MAXSCROLLS]; /* Names of the scrolls */
const char *p_colors[MAXPOTIONS]; /* Colors of the potions */
const char *r_stones[MAXRINGS]; /* Stone settings of the rings */
const char *w_names[MAXWEAPONS + 1] = { /* Names of the various weapons */
"mace",
"long sword",
"short bow",
"arrow",
"dagger",
"two handed sword",
"dart",
"crossbow",
"crossbow bolt",
"spear",
NULL /* fake entry for dragon's breath */
};
const char *a_names[MAXARMORS] = { /* Names of armor types */
"leather armor",
"ring mail",
"studded leather armor",
"scale mail",
"chain mail",
"splint mail",
"banded mail",
"plate mail",
};
const char *ws_made[MAXSTICKS]; /* What sticks are made of */
char *release; /* Release number of rogue */
char whoami[MAXSTR]; /* Name of player */
char fruit[MAXSTR]; /* Favorite fruit */
char huh[MAXSTR]; /* The last message printed */
char *s_guess[MAXSCROLLS]; /* Players guess at what scroll is */
char *p_guess[MAXPOTIONS]; /* Players guess at what potion is */
char *r_guess[MAXRINGS]; /* Players guess at what ring is */
char *ws_guess[MAXSTICKS]; /* Players guess at what wand is */
char *ws_type[MAXSTICKS]; /* Is it a wand or a staff */
char file_name[MAXSTR]; /* Save file name */
char home[MAXSTR]; /* User's home directory */
char _level[MAXLINES*MAXCOLS]; /* Level map */
char _flags[MAXLINES*MAXCOLS]; /* Flags for each space on the map */
int max_level; /* Deepest player has gone */
int ntraps; /* Number of traps on this level */
int dnum; /* Dungeon number */
int level = 1; /* What level rogue is on */
int purse = 0; /* How much gold the rogue has */
int mpos = 0; /* Where cursor is on top line */
int no_move = 0; /* Number of turns held in place */
int no_command = 0; /* Number of turns asleep */
int inpack = 0; /* Number of things in pack */
int total = 0; /* Total dynamic memory bytes */
int lastscore = -1; /* Score before this turn */
int no_food = 0; /* Number of levels without food */
int count = 0; /* Number of times to repeat command */
int fung_hit = 0; /* Number of time fungi has hit */
int quiet = 0; /* Number of quiet turns */
int food_left; /* Amount of food in hero's stomach */
int group = 2; /* Current group number */
int hungry_state = 0; /* How hungry is he */
int fd; /* File descriptor for score file */
int a_chances[MAXARMORS] = { /* Chance for each armor type */
20,
35,
50,
63,
75,
85,
95,
100
};
int a_class[MAXARMORS] = { /* Armor class for each armor type */
8,
7,
7,
6,
5,
4,
4,
3,
};
long seed; /* Random number seed */
coord oldpos; /* Position before last look() call */
coord delta; /* Change indicated to get_dir() */
THING player; /* The rogue */
THING *cur_armor; /* What a well dresssed rogue wears */
THING *cur_weapon; /* Which weapon he is weilding */
THING *cur_ring[2]; /* Which rings are being worn */
THING *lvl_obj = NULL; /* List of objects on this level */
THING *mlist = NULL; /* List of monsters on the level */
THING *_monst[MAXLINES*MAXCOLS]; /* Pointers for monsters at each spot */
WINDOW *hw; /* Used as a scratch window */
#define INIT_STATS { 16, 0, 1, 10, 12, "1d4", 12 }
struct stats max_stats = INIT_STATS; /* The maximum for the player */
struct room *oldrp; /* Roomin(&oldpos) */
struct room rooms[MAXROOMS]; /* One for each room -- A level */
struct room passages[MAXPASS] = /* One for each passage */
{
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }
};
#define ___ 1
#define XX 10
struct monster monsters[26] =
{
/* Name CARRY FLAG str, exp, lvl, amr, hpt, dmg */
{ "giant ant", 0, ISMEAN, { XX, 9, 2, 3, ___, "1d6" } },
{ "bat", 0, 0, { XX, 1, 1, 3, ___, "1d2" } },
{ "centaur", 15, 0, { XX, 15, 4, 4, ___, "1d6/1d6" } },
{ "dragon", 100, ISMEAN, { XX,6800, 10, -1, ___, "1d8/1d8/3d10" } },
{ "floating eye",0, 0, { XX, 5, 1, 9, ___, "0d0" } },
/* NOTE: the damage is %%% so that xstr won't merge this */
/* string with others, since it is written on in the program */
{ "violet fungi",0, ISMEAN, { XX, 80, 8, 3, ___, "%%%d0" } },
{ "gnome", 10, 0, { XX, 7, 1, 5, ___, "1d6" } },
{ "hobgoblin", 0, ISMEAN, { XX, 3, 1, 5, ___, "1d8" } },
{ "invisible stalker",0,ISINVIS,{ XX,120, 8, 3, ___, "4d4" } },
{ "jackal", 0, ISMEAN, { XX, 2, 1, 7, ___, "1d2" } },
{ "kobold", 0, ISMEAN, { XX, 1, 1, 7, ___, "1d4" } },
{ "leprechaun", 0, 0, { XX, 10, 3, 8, ___, "1d1" } },
{ "mimic", 30, 0, { XX,100, 7, 7, ___, "3d4" } },
{ "nymph", 100, 0, { XX, 37, 3, 9, ___, "0d0" } },
{ "orc", 15, ISGREED,{ XX, 5, 1, 6, ___, "1d8" } },
{ "purple worm", 70, 0, { XX,4000, 15, 6, ___, "2d12/2d4" } },
{ "quasit", 30, ISMEAN, { XX, 32, 3, 2, ___, "1d2/1d2/1d4" } },
{ "rust monster",0, ISMEAN, { XX, 20, 5, 2, ___, "0d0/0d0" } },
{ "snake", 0, ISMEAN, { XX, 2, 1, 5, ___, "1d3" } },
{ "troll", 50, ISREGEN|ISMEAN,{ XX, 120, 6, 4, ___, "1d8/1d8/2d6" } },
{ "umber hulk", 40, ISMEAN, { XX,200, 8, 2, ___, "3d4/3d4/2d5" } },
{ "vampire", 20, ISREGEN|ISMEAN,{ XX,350, 8, 1, ___, "1d10" } },
{ "wraith", 0, 0, { XX, 55, 5, 4, ___, "1d6" } },
{ "xorn", 0, ISMEAN, { XX,190, 7, -2, ___, "1d3/1d3/1d3/4d6" } },
{ "yeti", 30, 0, { XX, 50, 4, 6, ___, "1d6/1d6" } },
{ "zombie", 0, ISMEAN, { XX, 6, 2, 8, ___, "1d8" } }
};
#undef ___
#undef XX
struct magic_item things[NUMTHINGS] = {
{ 0, 27 }, /* potion */
{ 0, 30 }, /* scroll */
{ 0, 17 }, /* food */
{ 0, 8 }, /* weapon */
{ 0, 8 }, /* armor */
{ 0, 5 }, /* ring */
{ 0, 5 }, /* stick */
};
struct magic_item s_magic[MAXSCROLLS] = {
{ "monster confusion", 8, 140 },
{ "magic mapping", 5, 150 },
{ "hold monster", 3, 180 },
{ "sleep", 5, 5 },
{ "enchant armor", 8, 160 },
{ "identify", 27, 100 },
{ "scare monster", 4, 200 },
{ "gold detection", 4, 50 },
{ "teleportation", 7, 165 },
{ "enchant weapon", 10, 150 },
{ "create monster", 5, 75 },
{ "remove curse", 8, 105 },
{ "aggravate monsters", 4, 20 },
{ "blank paper", 1, 5 },
{ "genocide", 1, 300 },
};
struct magic_item p_magic[MAXPOTIONS] = {
{ "confusion", 8, 5 },
{ "paralysis", 10, 5 },
{ "poison", 8, 5 },
{ "gain strength", 15, 150 },
{ "see invisible", 2, 100 },
{ "healing", 15, 130 },
{ "monster detection", 6, 130 },
{ "magic detection", 6, 105 },
{ "raise level", 2, 250 },
{ "extra healing", 5, 200 },
{ "haste self", 4, 190 },
{ "restore strength", 14, 130 },
{ "blindness", 4, 5 },
{ "thirst quenching", 1, 5 },
};
struct magic_item r_magic[MAXRINGS] = {
{ "protection", 9, 400 },
{ "add strength", 9, 400 },
{ "sustain strength", 5, 280 },
{ "searching", 10, 420 },
{ "see invisible", 10, 310 },
{ "adornment", 1, 10 },
{ "aggravate monster", 10, 10 },
{ "dexterity", 8, 440 },
{ "increase damage", 8, 400 },
{ "regeneration", 4, 460 },
{ "slow digestion", 9, 240 },
{ "teleportation", 5, 30 },
{ "stealth", 7, 470 },
{ "maintain armor", 5, 380 },
};
struct magic_item ws_magic[MAXSTICKS] = {
{ "light", 12, 250 },
{ "striking", 9, 75 },
{ "lightning", 3, 330 },
{ "fire", 3, 330 },
{ "cold", 3, 330 },
{ "polymorph", 15, 310 },
{ "magic missile", 10, 170 },
{ "haste monster", 9, 5 },
{ "slow monster", 11, 350 },
{ "drain life", 9, 300 },
{ "nothing", 1, 5 },
{ "teleport away", 5, 340 },
{ "teleport to", 5, 50 },
{ "cancellation", 5, 280 },
};
struct h_list helpstr[] = {
'?', " prints help",
'/', " identify object",
'h', " left",
'j', " down",
'k', " up",
'l', " right",
'y', " up & left",
'u', " up & right",
'b', " down & left",
'n', " down & right",
'H', " run left",
'J', " run down",
'K', " run up",
'L', " run right",
'Y', " run up & left",
'U', " run up & right",
'B', " run down & left",
'N', " run down & right",
't', "<dir> throw something",
'f', "<dir> forward until find something",
'z', "<dir> zap a wand in a direction",
'^', "<dir> identify trap type",
's', " search for trap/secret door",
'>', " go down a staircase",
'<', " go up a staircase",
'.', " rest for a while",
'i', " inventory",
'I', " inventory single item",
'q', " quaff potion",
'r', " read paper",
'e', " eat food",
'w', " wield a weapon",
'W', " wear armor",
'T', " take armor off",
'P', " put on ring",
'R', " remove ring",
'd', " drop object",
'c', " call object",
'D', " recall what's been discovered",
'o', " examine/set options",
CTRL('L'), " redraw screen",
CTRL('R'), " repeat last message",
ESCAPE, " cancel command",
'!', " shell escape",
'S', " save game",
'Q', " quit",
0, 0
};

91
rogue4/extern.h Normal file
View file

@ -0,0 +1,91 @@
/*
* Defines for things used in mach_dep.c
*
* @(#)extern.h 4.3 (Berkeley) 4/2/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Don't change the constants, since they are used for sizes in many
* places in the program.
*/
#define MAXSTR 80 /* maximum length of strings */
#define MAXLINES 32 /* maximum number of screen lines used */
#define MAXCOLS 80 /* maximum number of screen columns used */
#define RN (((seed = seed*11109+13849) >> 16) & 0xffff)
/*
* Now all the global variables
*/
extern bool after, amulet, askme, door_stop, fight_flush,
firstmove, in_shell, jump, noscore, p_know[], passgo,
playing, r_know[], running, s_know[], save_msg,
slow_invent, terse, wizard, ws_know[];
extern const char *p_colors[], *r_stones[], *w_names[],
*a_names[], *ws_made[];
extern char _flags[], _level[], file_name[], fruit[],
home[], huh[], outbuf[], *p_guess[],
prbuf[], *r_guess[], *release, runch,
*s_guess[], *s_names[], take, whoami[],
*ws_guess[], *ws_type[];
extern int a_chances[], a_class[], count, dnum, food_left,
fung_hit, fd, group, hungry_state, inpack, lastscore,
level, max_level, mpos, no_command, no_food, no_move,
ntraps, purse, quiet, total;
extern long seed;
extern WINDOW *hw;
/*
* Function types
*/
char *charge_str(), *ctime(), *getenv(), *inv_name(),
*killname(), *nothing(), *num(), *ring_num(),
*tr_name(),
*unctrol(), *vowelstr();
void leave(int), quit(int), tstp(), auto_save(int), endit(int);
int doctor(), nohaste(),
rollwand(), runners(), sight(), stomach(), swander(),
turn_see(), unconfuse(), unsee();
void checkout();
long lseek();
extern coord ch_ret;
extern shint countch;
extern shint direction;
extern shint newcount;
extern int between;
extern int num_checks;
extern char lvl_mons[27];
extern char wand_mons[27];
extern coord nh;
extern bool got_genocide;
#if defined(__GLIBC__) || defined(__INTERIX)
/*
O_BINARY flag not provided in Interix/SFU or some versions of Linux.
It is the same as default behavior so we just zero define it here
to make source code compatible.
*/
#define O_BINARY 0
#endif
extern FILE *md_fdopen(int fd, char *mode);
extern char *md_getusername(int uid);
extern char *md_gethomedir();

738
rogue4/fight.c Normal file
View file

@ -0,0 +1,738 @@
/*
* All the fighting gets done here
*
* @(#)fight.c 4.30 (Berkeley) 4/6/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"
long e_levels[] = {
10L,20L,40L,80L,160L,320L,640L,1280L,2560L,5120L,10240L,20480L,
40920L, 81920L, 163840L, 327680L, 655360L, 1310720L, 2621440L, 0L
};
/*
* fight:
* The player attacks the monster.
*/
fight(mp, mn, weap, thrown)
register coord *mp;
char mn;
register THING *weap;
bool thrown;
{
register THING *tp;
register bool did_hit = TRUE;
register const char *mname;
/*
* Find the monster we want to fight
*/
#ifdef WIZARD
if ((tp = moat(mp->y, mp->x)) == NULL)
debug("Fight what @ %d,%d", mp->y, mp->x);
#else
tp = moat(mp->y, mp->x);
#endif
/*
* Since we are fighting, things are not quiet so no healing takes
* place.
*/
count = quiet = 0;
runto(mp, &hero);
/*
* Let him know it was really a mimic (if it was one).
*/
if (tp->t_type == 'M' && tp->t_disguise != 'M' && !on(player, ISBLIND))
{
tp->t_disguise = 'M';
if (!thrown)
return FALSE;
msg("wait! That's a mimic!");
}
did_hit = FALSE;
if (on(player, ISBLIND))
mname = "it";
else
mname = monsters[mn-'A'].m_name;
if (roll_em(&player, tp, weap, thrown))
{
did_hit = FALSE;
if (thrown)
thunk(weap, mname);
else
hit(NULL, mname);
if (on(player, CANHUH))
{
did_hit = TRUE;
tp->t_flags |= ISHUH;
player.t_flags &= ~CANHUH;
msg("your hands stop glowing red");
}
if (tp->t_stats.s_hpt <= 0)
killed(tp, TRUE);
else if (did_hit && !on(player, ISBLIND))
msg("the %s appears confused", mname);
did_hit = TRUE;
}
else
if (thrown)
bounce(weap, mname);
else
miss(NULL, mname);
return did_hit;
}
/*
* attack:
* The monster attacks the player
*/
attack(mp)
register THING *mp;
{
register const char *mname;
/*
* Since this is an attack, stop running and any healing that was
* going on at the time.
*/
running = FALSE;
count = quiet = 0;
if (mp->t_type == 'M' && !on(player, ISBLIND))
mp->t_disguise = 'M';
if (on(player, ISBLIND))
mname = "it";
else
mname = monsters[mp->t_type-'A'].m_name;
if (roll_em(mp, &player, NULL, FALSE))
{
if (mp->t_type != 'E')
hit(mname, NULL);
if (pstats.s_hpt <= 0)
death(mp->t_type); /* Bye bye life ... */
if (!on(*mp, ISCANC))
switch (mp->t_type)
{
case 'R':
/*
* If a rust monster hits, you lose armor, unless
* that armor is leather or there is a magic ring
*/
if (cur_armor != NULL && cur_armor->o_ac < 9
&& cur_armor->o_which != LEATHER)
if (ISWEARING(R_SUSTARM))
msg("The rust vanishes instantly");
else
{
cur_armor->o_ac++;
if (!terse)
msg("your armor appears to be weaker now. Oh my!");
else
msg("your armor weakens");
}
when 'E':
/*
* The gaze of the floating eye hypnotizes you
*/
if (on(player, ISBLIND))
break;
player.t_flags &= ~ISRUN;
if (!no_command)
{
addmsg("you are transfixed");
if (!terse)
addmsg(" by the gaze of the floating eye");
endmsg();
}
no_command += rnd(2) + 2;
when 'A':
/*
* Ants have poisonous bites
*/
if (!save(VS_POISON))
if (!ISWEARING(R_SUSTSTR))
{
chg_str(-1);
if (!terse)
msg("you feel a sting in your arm and now feel weaker");
else
msg("a sting has weakened you");
}
else
if (!terse)
msg("a sting momentarily weakens you");
else
msg("sting has no effect");
when 'W':
case 'V':
/*
* Wraiths might drain energy levels, and Vampires
* can steal max_hp
*/
if (rnd(100) < (mp->t_type == 'W' ? 15 : 30))
{
register int fewer;
if (mp->t_type == 'W')
{
if (pstats.s_exp == 0)
death('W'); /* All levels gone */
if (--pstats.s_lvl == 0)
{
pstats.s_exp = 0;
pstats.s_lvl = 1;
}
else
pstats.s_exp = e_levels[pstats.s_lvl-1]+1;
fewer = roll(1, 10);
}
else
fewer = roll(1, 5);
pstats.s_hpt -= fewer;
max_hp -= fewer;
if (pstats.s_hpt < 1)
pstats.s_hpt = 1;
if (max_hp < 1)
death(mp->t_type);
msg("you suddenly feel weaker");
}
when 'F':
/*
* Violet fungi stops the poor guy from moving
*/
player.t_flags |= ISHELD;
sprintf(monsters['F'-'A'].m_stats.s_dmg,"%dd1",++fung_hit);
when 'L':
{
/*
* Leperachaun steals some gold
*/
register long lastpurse;
lastpurse = purse;
purse -= GOLDCALC;
if (!save(VS_MAGIC))
purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
if (purse < 0)
purse = 0;
remove_monster(&mp->t_pos, mp, FALSE);
mp = NULL;
if (purse != lastpurse)
msg("your purse feels lighter");
}
when 'N':
{
register THING *obj, *steal;
register int nobj;
/*
* Nymph's steal a magic item, look through the pack
* and pick out one we like.
*/
steal = NULL;
for (nobj = 0, obj = pack; obj != NULL; obj = next(obj))
if (obj != cur_armor && obj != cur_weapon
&& obj != cur_ring[LEFT] && obj != cur_ring[RIGHT]
&& is_magic(obj) && rnd(++nobj) == 0)
steal = obj;
if (steal != NULL)
{
remove_monster(&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE);
mp = NULL;
inpack--;
if (steal->o_count > 1 && steal->o_group == 0)
{
register int oc;
oc = steal->o_count--;
steal->o_count = 1;
msg("she stole %s!", inv_name(steal, TRUE));
steal->o_count = oc;
}
else
{
detach(pack, steal);
msg("she stole %s!", inv_name(steal, TRUE));
discard(steal);
}
}
}
otherwise:
break;
}
}
else if (mp->t_type != 'E')
{
if (mp->t_type == 'F')
{
pstats.s_hpt -= fung_hit;
if (pstats.s_hpt <= 0)
death(mp->t_type); /* Bye bye life ... */
}
miss(mname, NULL);
}
if (fight_flush)
flush_type();
count = 0;
status();
if (mp == NULL)
return(-1);
else
return(0);
}
/*
* swing:
* Returns true if the swing hits
*/
swing(at_lvl, op_arm, wplus)
int at_lvl, op_arm, wplus;
{
register int res = rnd(20);
register int need = (20 - at_lvl) - op_arm;
return (res + wplus >= need);
}
/*
* check_level:
* Check to see if the guy has gone up a level.
*/
check_level()
{
register int i, add, olevel;
for (i = 0; e_levels[i] != 0; i++)
if (e_levels[i] > pstats.s_exp)
break;
i++;
olevel = pstats.s_lvl;
pstats.s_lvl = i;
if (i > olevel)
{
add = roll(i - olevel, 10);
max_hp += add;
if ((pstats.s_hpt += add) > max_hp)
pstats.s_hpt = max_hp;
msg("welcome to level %d", i);
}
}
/*
* roll_em:
* Roll several attacks
*/
roll_em(thatt, thdef, weap, hurl)
THING *thatt, *thdef, *weap;
bool hurl;
{
register struct stats *att, *def;
register char *cp;
register int ndice, nsides, def_arm;
register bool did_hit = FALSE;
register int hplus;
register int dplus;
register int damage;
att = &thatt->t_stats;
def = &thdef->t_stats;
if (weap == NULL)
{
cp = att->s_dmg;
dplus = 0;
hplus = 0;
}
else
{
hplus = (weap == NULL ? 0 : weap->o_hplus);
dplus = (weap == NULL ? 0 : weap->o_dplus);
if (weap == cur_weapon)
{
if (ISRING(LEFT, R_ADDDAM))
dplus += cur_ring[LEFT]->o_ac;
else if (ISRING(LEFT, R_ADDHIT))
hplus += cur_ring[LEFT]->o_ac;
if (ISRING(RIGHT, R_ADDDAM))
dplus += cur_ring[RIGHT]->o_ac;
else if (ISRING(RIGHT, R_ADDHIT))
hplus += cur_ring[RIGHT]->o_ac;
}
if (hurl)
if ((weap->o_flags&ISMISL) && cur_weapon != NULL &&
cur_weapon->o_which == weap->o_launch)
{
cp = weap->o_hurldmg;
hplus += cur_weapon->o_hplus;
dplus += cur_weapon->o_dplus;
}
else
cp = weap->o_hurldmg;
else
{
cp = weap->o_damage;
/*
* Drain a staff of striking
*/
if (weap->o_type == STICK && weap->o_which == WS_HIT
&& --weap->o_charges < 0)
{
strcpy(weap->o_damage,"0d0");
cp = weap->o_damage;
weap->o_hplus = weap->o_dplus = 0;
weap->o_charges = 0;
}
}
}
/*
* If the creature being attacked is not running (alseep or held)
* then the attacker gets a plus four bonus to hit.
*/
if (!on(*thdef, ISRUN))
hplus += 4;
def_arm = def->s_arm;
if (def == &pstats)
{
if (cur_armor != NULL)
def_arm = cur_armor->o_ac;
if (ISRING(LEFT, R_PROTECT))
def_arm -= cur_ring[LEFT]->o_ac;
if (ISRING(RIGHT, R_PROTECT))
def_arm -= cur_ring[RIGHT]->o_ac;
}
for (;;)
{
ndice = atoi(cp);
if ((cp = strchr(cp, 'd')) == NULL)
break;
nsides = atoi(++cp);
if (swing(att->s_lvl, def_arm, hplus + str_plus(att->s_str)))
{
register int proll;
proll = roll(ndice, nsides);
#ifdef WIZARD
if (ndice + nsides > 0 && proll < 1)
debug("Damage for %dd%d came out %d, dplus = %d, add_dam = %d, def_arm = %d", ndice, nsides, proll, dplus, add_dam(att->s_str), def_arm);
#endif
damage = dplus + proll + add_dam(att->s_str);
def->s_hpt -= max(0, damage);
did_hit = TRUE;
}
if ((cp = strchr(cp, '/')) == NULL)
break;
cp++;
}
return did_hit;
}
/*
* prname:
* The print name of a combatant
*/
char *
prname(who, upper)
register char *who;
bool upper;
{
static char tbuf[MAXSTR];
*tbuf = '\0';
if (who == 0)
strcpy(tbuf, "you");
else if (on(player, ISBLIND))
strcpy(tbuf, "it");
else
{
strcpy(tbuf, "the ");
strcat(tbuf, who);
}
if (upper)
*tbuf = toupper(*tbuf);
return tbuf;
}
/*
* hit:
* Print a message to indicate a succesful hit
*/
hit(er, ee)
register char *er, *ee;
{
register char *s = "";
addmsg(prname(er, TRUE));
if (terse)
s = " hit";
else
switch (rnd(4))
{
case 0: s = " scored an excellent hit on ";
when 1: s = " hit ";
when 2: s = (er == 0 ? " have injured " : " has injured ");
when 3: s = (er == 0 ? " swing and hit " : " swings and hits ");
}
addmsg(s);
if (!terse)
addmsg(prname(ee, FALSE));
endmsg();
}
/*
* miss:
* Print a message to indicate a poor swing
*/
miss(er, ee)
register char *er, *ee;
{
register char *s = "";
addmsg(prname(er, TRUE));
switch (terse ? 0 : rnd(4))
{
case 0: s = (er == 0 ? " miss" : " misses");
when 1: s = (er == 0 ? " swing and miss" : " swings and misses");
when 2: s = (er == 0 ? " barely miss" : " barely misses");
when 3: s = (er == 0 ? " don't hit" : " doesn't hit");
}
addmsg(s);
if (!terse)
addmsg(" %s", prname(ee, FALSE));
endmsg();
}
/*
* save_throw:
* See if a creature save against something
*/
save_throw(which, tp)
int which;
THING *tp;
{
register int need;
need = 14 + which - tp->t_stats.s_lvl / 2;
return (roll(1, 20) >= need);
}
/*
* save:
* See if he saves against various nasty things
*/
save(which)
register int which;
{
if (which == VS_MAGIC)
{
if (ISRING(LEFT, R_PROTECT))
which -= cur_ring[LEFT]->o_ac;
if (ISRING(RIGHT, R_PROTECT))
which -= cur_ring[RIGHT]->o_ac;
}
return save_throw(which, &player);
}
/*
* str_plus:
* Compute bonus/penalties for strength on the "to hit" roll
*/
str_plus(str)
register str_t str;
{
if (str == 31)
return 3;
if (str > 20)
return 2;
if (str > 16)
return 1;
if (str > 6)
return 0;
return str - 7;
}
/*
* add_dam:
* Compute additional damage done for exceptionally high or low strength
*/
add_dam(str)
register str_t str;
{
if (str == 31)
return 6;
if (str > 21)
return 5;
if (str == 21)
return 4;
if (str > 18)
return 3;
if (str == 18)
return 2;
if (str > 15)
return 1;
if (str > 6)
return 0;
return str - 7;
}
/*
* raise_level:
* The guy just magically went up a level.
*/
raise_level()
{
pstats.s_exp = e_levels[pstats.s_lvl-1] + 1L;
check_level();
}
/*
* thunk:
* A missile hits a monster
*/
thunk(weap, mname)
register THING *weap;
register const char *mname;
{
if (weap->o_type == WEAPON)
addmsg("the %s hits ", w_names[weap->o_which]);
else
addmsg("you hit ");
if (on(player, ISBLIND))
msg("it");
else
msg("the %s", mname);
}
/*
* bounce:
* A missile misses a monster
*/
bounce(weap, mname)
register THING *weap;
register const char *mname;
{
if (weap->o_type == WEAPON)
addmsg("the %s misses ", w_names[weap->o_which]);
else
addmsg("you missed ");
if (on(player, ISBLIND))
msg("it");
else
msg("the %s", mname);
}
/*
* remove:
* Remove a monster from the screen
*/
remove_monster(mp, tp, waskill)
register coord *mp;
register THING *tp;
bool waskill;
{
register THING *obj, *nexti;
for (obj = tp->t_pack; obj != NULL; obj = nexti)
{
nexti = next(obj);
obj->o_pos = tp->t_pos;
detach(tp->t_pack, obj);
if (waskill)
fall(obj, FALSE);
else
discard(obj);
}
moat(mp->y, mp->x) = NULL;
mvaddch(mp->y, mp->x, tp->t_oldch);
detach(mlist, tp);
discard(tp);
}
/*
* is_magic:
* Returns true if an object radiates magic
*/
is_magic(obj)
register THING *obj;
{
switch (obj->o_type)
{
case ARMOR:
return obj->o_ac != a_class[obj->o_which];
case WEAPON:
return obj->o_hplus != 0 || obj->o_dplus != 0;
case POTION:
case SCROLL:
case STICK:
case RING:
case AMULET:
return TRUE;
}
return FALSE;
}
/*
* killed:
* Called to put a monster to death
*/
killed(tp, pr)
register THING *tp;
bool pr;
{
pstats.s_exp += tp->t_stats.s_exp;
/*
* If the monster was a violet fungi, un-hold him
*/
switch (tp->t_type)
{
case 'F':
player.t_flags &= ~ISHELD;
fung_hit = 0;
strcpy(monsters['F'-'A'].m_stats.s_dmg, "000d0");
when 'L':
{
register THING *gold;
if (fallpos(&tp->t_pos, &tp->t_room->r_gold, TRUE))
{
gold = new_item();
gold->o_type = GOLD;
gold->o_goldval = GOLDCALC;
if (save(VS_MAGIC))
gold->o_goldval += GOLDCALC + GOLDCALC
+ GOLDCALC + GOLDCALC;
attach(tp->t_pack, gold);
}
}
}
/*
* Get rid of the monster.
*/
if (pr)
{
if (!terse)
addmsg("you have ");
addmsg("defeated ");
if (on(player, ISBLIND))
msg("it");
else
{
if (!terse)
addmsg("the ");
msg("%s", monsters[tp->t_type-'A'].m_name);
}
}
remove_monster(&tp->t_pos, tp, TRUE);
/*
* Do adjustments if he went up a level
*/
check_level();
}

23
rogue4/findpw.c Normal file
View file

@ -0,0 +1,23 @@
/*
* print out an encrypted password on the standard output
*
* @(#)findpw.c 1.1 (Berkeley) 12/20/81
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdio.h>
main()
{
char buf[80];
fprintf(stderr, "Password: ");
fgets(buf, 80, stdin);
buf[strlen(buf) - 1] = '\0';
printf("%s\n", xcrypt(buf, "mT"));
}

422
rogue4/init.c Normal file
View file

@ -0,0 +1,422 @@
/*
* global variable initializaton
*
* @(#)init.c 4.16 (Berkeley) 3/30/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "rogue.h"
/*
* init_player:
* Roll up the rogue
*/
init_player()
{
register THING *obj;
pstats = max_stats;
food_left = HUNGERTIME;
/*
* Give the rogue his weaponry. First a mace.
*/
obj = new_item();
obj->o_type = WEAPON;
obj->o_which = MACE;
init_weapon(obj, MACE);
obj->o_hplus = 1;
obj->o_dplus = 1;
obj->o_flags |= ISKNOW;
obj->o_count = 1;
obj->o_group = 0;
add_pack(obj, TRUE);
cur_weapon = obj;
/*
* Now a +1 bow
*/
obj = new_item();
obj->o_type = WEAPON;
obj->o_which = BOW;
init_weapon(obj, BOW);
obj->o_hplus = 1;
obj->o_dplus = 0;
obj->o_count = 1;
obj->o_group = 0;
obj->o_flags |= ISKNOW;
add_pack(obj, TRUE);
/*
* Now some arrows
*/
obj = new_item();
obj->o_type = WEAPON;
obj->o_which = ARROW;
init_weapon(obj, ARROW);
obj->o_count = rnd(15) + 25;
obj->o_hplus = obj->o_dplus = 0;
obj->o_flags |= ISKNOW;
add_pack(obj, TRUE);
/*
* And his suit of armor
*/
obj = new_item();
obj->o_type = ARMOR;
obj->o_which = RING_MAIL;
obj->o_ac = a_class[RING_MAIL] - 1;
obj->o_flags |= ISKNOW;
obj->o_count = 1;
obj->o_group = 0;
cur_armor = obj;
add_pack(obj, TRUE);
/*
* Give him some food too
*/
obj = new_item();
obj->o_type = FOOD;
obj->o_count = 1;
obj->o_which = 0;
obj->o_group = 0;
add_pack(obj, TRUE);
}
/*
* Contains defintions and functions for dealing with things like
* potions and scrolls
*/
const char *rainbow[NCOLORS] = {
"amber",
"aquamarine",
"black",
"blue",
"brown",
"clear",
"crimson",
"cyan",
"ecru",
"gold",
"green",
"grey",
"magenta",
"orange",
"pink",
"plaid",
"purple",
"red",
"silver",
"tan",
"tangerine",
"topaz",
"turquoise",
"vermilion",
"violet",
"white",
"yellow",
};
const char *sylls[NSYLLS] = {
"a", "ab", "ag", "aks", "ala", "an", "ankh","app", "arg", "arze",
"ash", "ban", "bar", "bat", "bek", "bie", "bin", "bit", "bjor",
"blu", "bot", "bu", "byt", "comp","con", "cos", "cre", "dalf",
"dan", "den", "do", "e", "eep", "el", "eng", "er", "ere", "erk",
"esh", "evs", "fa", "fid", "for", "fri", "fu", "gan", "gar",
"glen","gop", "gre", "ha", "he", "hyd", "i", "ing", "ion", "ip",
"ish", "it", "ite", "iv", "jo", "kho", "kli", "klis","la", "lech",
"man", "mar", "me", "mi", "mic", "mik", "mon", "mung","mur",
"nej", "nelg","nep", "ner", "nes", "nes", "nih", "nin", "o", "od",
"ood", "org", "orn", "ox", "oxy", "pay", "pet", "ple", "plu", "po",
"pot", "prok","re", "rea", "rhov","ri", "ro", "rog", "rok", "rol",
"sa", "san", "sat", "see", "sef", "seh", "shu", "ski", "sna",
"sne", "snik","sno", "so", "sol", "sri", "sta", "sun", "ta",
"tab", "tem", "ther","ti", "tox", "trol","tue", "turs","u",
"ulk", "um", "un", "uni", "ur", "val", "viv", "vly", "vom", "wah",
"wed", "werg","wex", "whon","wun", "xo", "y", "yot", "yu",
"zant","zap", "zeb", "zim", "zok", "zon", "zum",
};
const STONE stones[NSTONES] = {
{ "agate", 25},
{ "alexandrite", 40},
{ "amethyst", 50},
{ "carnelian", 40},
{ "diamond", 300},
{ "emerald", 300},
{ "germanium", 225},
{ "granite", 5},
{ "garnet", 50},
{ "jade", 150},
{ "kryptonite", 300},
{ "lapis lazuli", 50},
{ "moonstone", 50},
{ "obsidian", 15},
{ "onyx", 60},
{ "opal", 200},
{ "pearl", 220},
{ "peridot", 63},
{ "ruby", 350},
{ "saphire", 285},
{ "stibotantalite", 200},
{ "tiger eye", 50},
{ "topaz", 60},
{ "turquoise", 70},
{ "taaffeite", 300},
{ "zircon", 80},
};
const char *wood[NWOOD] = {
"avocado wood",
"balsa",
"bamboo",
"banyan",
"birch",
"cedar",
"cherry",
"cinnibar",
"cypress",
"dogwood",
"driftwood",
"ebony",
"elm",
"eucalyptus",
"fall",
"hemlock",
"holly",
"ironwood",
"kukui wood",
"mahogany",
"manzanita",
"maple",
"oaken",
"persimmon wood",
"pecan",
"pine",
"poplar",
"redwood",
"rosewood",
"spruce",
"teak",
"walnut",
"zebrawood",
};
const char *metal[NMETAL] = {
"aluminum",
"beryllium",
"bone",
"brass",
"bronze",
"copper",
"electrum",
"gold",
"iron",
"lead",
"magnesium",
"mercury",
"nickel",
"pewter",
"platinum",
"steel",
"silver",
"silicon",
"tin",
"titanium",
"tungsten",
"zinc",
};
/*
* init_things
* Initialize the probabilities for types of things
*/
init_things()
{
register struct magic_item *mp;
for (mp = &things[1]; mp <= &things[NUMTHINGS-1]; mp++)
mp->mi_prob += (mp-1)->mi_prob;
#ifdef WIZARD
badcheck("things", things, NUMTHINGS);
#endif
}
/*
* init_colors:
* Initialize the potion color scheme for this time
*/
init_colors()
{
register int i, j;
bool used[NCOLORS];
for (i = 0; i < NCOLORS; i++)
used[i] = FALSE;
for (i = 0; i < MAXPOTIONS; i++)
{
do
j = rnd(NCOLORS);
until (!used[j]);
used[j] = TRUE;
p_colors[i] = rainbow[j];
p_know[i] = FALSE;
p_guess[i] = NULL;
if (i > 0)
p_magic[i].mi_prob += p_magic[i-1].mi_prob;
}
#ifdef WIZARD
badcheck("potions", p_magic, MAXPOTIONS);
#endif
}
/*
* init_names:
* Generate the names of the various scrolls
*/
#define MAXNAME 40 /* Max number of characters in a name */
init_names()
{
register int nsyl;
register char *cp;
const char *sp;
register int i, nwords;
for (i = 0; i < MAXSCROLLS; i++)
{
cp = prbuf;
nwords = rnd(4) + 2;
while (nwords--)
{
nsyl = rnd(3) + 1;
while (nsyl--)
{
sp = sylls[rnd((sizeof sylls) / (sizeof (char *)))];
if (&cp[strlen(sp)] > &prbuf[MAXNAME])
break;
while (*sp)
*cp++ = *sp++;
}
*cp++ = ' ';
}
*--cp = '\0';
s_names[i] = (char *) malloc((unsigned) strlen(prbuf)+1);
s_know[i] = FALSE;
s_guess[i] = NULL;
strcpy(s_names[i], prbuf);
if (i > 0)
s_magic[i].mi_prob += s_magic[i-1].mi_prob;
}
#ifdef WIZARD
badcheck("scrolls", s_magic, MAXSCROLLS);
#endif
}
/*
* init_stones:
* Initialize the ring stone setting scheme for this time
*/
init_stones()
{
register int i, j;
bool used[NSTONES];
for (i = 0; i < NSTONES; i++)
used[i] = FALSE;
for (i = 0; i < MAXRINGS; i++)
{
do
j = rnd(NSTONES);
until (!used[j]);
used[j] = TRUE;
r_stones[i] = stones[j].st_name;
r_know[i] = FALSE;
r_guess[i] = NULL;
if (i > 0)
r_magic[i].mi_prob += r_magic[i-1].mi_prob;
r_magic[i].mi_worth += stones[j].st_value;
}
#ifdef WIZARD
badcheck("rings", r_magic, MAXRINGS);
#endif
}
/*
* init_materials:
* Initialize the construction materials for wands and staffs
*/
init_materials()
{
register int i, j;
register const char *str;
bool metused[NMETAL], woodused[NWOOD];
for (i = 0; i < NWOOD; i++)
woodused[i] = FALSE;
for (i = 0; i < NMETAL; i++)
metused[i] = FALSE;
for (i = 0; i < MAXSTICKS; i++)
{
for (;;)
if (rnd(2) == 0)
{
j = rnd(NMETAL);
if (!metused[j])
{
ws_type[i] = "wand";
str = metal[j];
metused[j] = TRUE;
break;
}
}
else
{
j = rnd(NWOOD);
if (!woodused[j])
{
ws_type[i] = "staff";
str = wood[j];
woodused[j] = TRUE;
break;
}
}
ws_made[i] = str;
ws_know[i] = FALSE;
ws_guess[i] = NULL;
if (i > 0)
ws_magic[i].mi_prob += ws_magic[i-1].mi_prob;
}
#ifdef WIZARD
badcheck("sticks", ws_magic, MAXSTICKS);
#endif
}
#ifdef WIZARD
/*
* badcheck:
* Check to see if a series of probabilities sums to 100
*/
badcheck(name, magic, bound)
char *name;
register struct magic_item *magic;
register int bound;
{
register struct magic_item *end;
if (magic[bound - 1].mi_prob == 100)
return;
printf("\nBad percentages for %s:\n", name);
for (end = &magic[bound]; magic < end; magic++)
printf("%3d%% %s\n", magic->mi_prob, magic->mi_name);
printf("[hit RETURN to continue]");
fflush(stdout);
while (getchar() != '\n')
continue;
}
#endif

253
rogue4/io.c Normal file
View file

@ -0,0 +1,253 @@
/*
* Various input/output functions
*
* @(#)io.c 4.13 (Berkeley) 2/25/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"
#include <stdarg.h>
/*
* msg:
* Display a message at the top of the screen.
*/
static char msgbuf[BUFSIZ];
static int newpos = 0;
msg(char *fmt, ...)
{
va_list ap;
/*
* if the string is "", just clear the line
*/
if (*fmt == '\0')
{
move(0, 0);
clrtoeol();
mpos = 0;
return;
}
/*
* otherwise add to the message and flush it out
*/
va_start(ap,fmt);
doadd(fmt, ap);
va_end(ap);
endmsg();
}
/*
* addmsg:
* Add things to the current message
*/
addmsg(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
doadd(fmt, ap);
va_end(ap);
}
/*
* endmsg:
* Display a new msg (giving him a chance to see the previous one
* if it is up there with the --More--)
*/
endmsg()
{
if (save_msg)
{
strncpy(huh, msgbuf, 80);
huh[79] = 0;
}
if (mpos)
{
look(FALSE);
move(0, mpos);
addstr("--More--");
refresh();
wait_for(' ');
}
/*
* All messages should start with uppercase, except ones that
* start with a pack addressing character
*/
if (islower(msgbuf[0]) && msgbuf[1] != ')')
msgbuf[0] = toupper(msgbuf[0]);
mvaddstr(0, 0, msgbuf);
clrtoeol();
mpos = newpos;
newpos = 0;
refresh();
}
/*
* doadd:
* Perform an add onto the message buffer
*/
doadd(char *fmt, va_list ap)
{
vsprintf(&msgbuf[newpos], fmt, ap);
newpos = strlen(msgbuf);
}
/*
* step_ok:
* Returns true if it is ok to step on ch
*/
step_ok(ch)
{
switch (ch)
{
case ' ':
case '|':
case '-':
return FALSE;
default:
return (!isalpha(ch));
}
}
/*
* readchar:
* Flushes stdout so that screen is up to date and then returns
* getchar().
*/
readcharw(win)
WINDOW *win;
{
int ch;
ch = md_readchar(win);
if ((ch == 3) || (ch == 0))
{
quit(0);
return(27);
}
return(ch);
}
readchar()
{
return( readcharw(stdscr) );
}
char *
unctrol(ch)
char ch;
{
return( (char *) unctrl(ch) );
}
/*
* status:
* Display the important stats line. Keep the cursor where it was.
*/
status()
{
register int oy, ox, temp;
static int hpwidth = 0, s_hungry;
static int s_lvl, s_pur = -1, s_hp, s_ac = 0;
static str_t s_str;
static long s_exp = 0;
static char *state_name[] =
{
"", "Hungry", "Weak", "Faint"
};
/*
* If nothing has changed since the last status, don't
* bother.
*/
if (s_hp == pstats.s_hpt && s_exp == pstats.s_exp && s_pur == purse
&& s_ac == (cur_armor != NULL ? cur_armor->o_ac : pstats.s_arm)
&& s_str == pstats.s_str && s_lvl == level && s_hungry == hungry_state)
return;
getyx(stdscr, oy, ox);
if (s_hp != max_hp)
{
temp = s_hp = max_hp;
for (hpwidth = 0; temp; hpwidth++)
temp /= 10;
}
move(LINES - 1, 0);
printw("Level: %d Gold: %-5d Hp: %*d(%*d) Str: %2d(%d) Ac: %-2d Exp: %d/%ld %s",
level, purse, hpwidth, pstats.s_hpt, hpwidth, max_hp, pstats.s_str,
max_stats.s_str,
cur_armor != NULL ? cur_armor->o_ac : pstats.s_arm, pstats.s_lvl,
pstats.s_exp, state_name[hungry_state]);
clrtoeol();
/*
* Save old status
*/
s_lvl = level;
s_pur = purse;
s_hp = pstats.s_hpt;
s_str = pstats.s_str;
s_exp = pstats.s_exp;
s_ac = (cur_armor != NULL ? cur_armor->o_ac : pstats.s_arm);
s_hungry = hungry_state;
move(oy, ox);
}
/*
* wait_for
* Sit around until the guy types the right key
*/
wait_for(ch)
register char ch;
{
w_wait_for(stdscr, ch);
}
w_wait_for(win,ch)
WINDOW *win;
register char ch;
{
register char c;
if (ch == '\n')
while ((c = readcharw(win)) != '\n' && c != '\r')
continue;
else
while (readcharw(win) != ch)
continue;
}
/*
* show_win:
* Function used to display a window and wait before returning
*/
show_win(scr, message)
register WINDOW *scr;
char *message;
{
mvwaddstr(scr, 0, 0, message);
touchwin(scr);
wmove(scr, hero.y, hero.x);
wrefresh(scr);
w_wait_for(scr,' ');
clearok(curscr, TRUE);
touchwin(stdscr);
}

96
rogue4/list.c Normal file
View file

@ -0,0 +1,96 @@
/*
* Functions for dealing with linked lists of goodies
*
* @(#)list.c 4.7 (Berkeley) 12/19/81
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdlib.h>
#include <curses.h>
#include "rogue.h"
/*
* detach:
* Takes an item out of whatever linked list it might be in
*/
_detach(list, item)
register THING **list, *item;
{
if (*list == item)
*list = next(item);
if (prev(item) != NULL) item->l_prev->l_next = next(item);
if (next(item) != NULL) item->l_next->l_prev = prev(item);
item->l_next = NULL;
item->l_prev = NULL;
}
/*
* _attach:
* add an item to the head of a list
*/
_attach(list, item)
register THING **list, *item;
{
if (*list != NULL)
{
item->l_next = *list;
(*list)->l_prev = item;
item->l_prev = NULL;
}
else
{
item->l_next = NULL;
item->l_prev = NULL;
}
*list = item;
}
/*
* _free_list:
* Throw the whole blamed thing away
*/
_free_list(ptr)
register THING **ptr;
{
register THING *item;
while (*ptr != NULL)
{
item = *ptr;
*ptr = next(item);
discard(item);
}
}
/*
* discard:
* Free up an item
*/
discard(item)
register THING *item;
{
total--;
free((char *) item);
}
/*
* new_item
* Get a new item with a specified size
*/
THING *
new_item()
{
register THING *item;
if ((item = calloc(1, sizeof *item)) == NULL)
msg("ran out of memory after %d items", total);
else
total++;
item->l_next = item->l_prev = NULL;
return item;
}

365
rogue4/mach_dep.c Normal file
View file

@ -0,0 +1,365 @@
/*
* Various installation dependent routines
*
* @(#)mach_dep.c 4.23 (Berkeley) 5/19/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* The various tuneable defines are:
*
* SCOREFILE Where/if the score file should live.
* MAXLOAD What (if any) the maximum load average should be
* when people are playing. If defined, then
* LOADAV Should rogue define it's own routine to
* get the load average?
* NAMELIST If so, where does the system namelist hide?
* MAXUSERS What (if any) the maximum user count should be
* when people are playing. If defined, then
* UCOUNT Should rogue define it's own routine to
* count users?
* UTMP If so, where does the user list hide?
* CHECKTIME How often/if rogue should check during the game
* for high load average.
*/
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <curses.h>
#include <time.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "rogue.h"
int num_checks; /* times we've gone over in checkout() */
#ifdef SCOREFILE
#ifdef LOCKFILE
static char *lockfile = LOCKFILE;
#endif
#endif
/*
* init_check:
* Check out too see if it is proper to play the game now
*/
init_check()
{
if (too_much())
{
printf("Sorry, %s, but the system is too loaded now.\n", whoami);
printf("Try again later. Meanwhile, why not enjoy a%s %s?\n",
vowelstr(fruit), fruit);
if (author())
printf("However, since you're a good guy, it's up to you\n");
else
exit(1);
}
}
/*
* open_score:
* Open up the score file for future use, and then
* setuid(getuid()) in case we are running setuid.
*/
open_score()
{
#ifdef SCOREFILE
fd = open(SCOREFILE, O_RDWR | O_CREAT, 0666 );
#else
fd = -1;
#endif
md_normaluser();
}
/*
* setup:
* Get starting setup for all games
*/
setup()
{
void auto_save(), quit(), endit(), tstp();
#ifdef CHECKTIME
int checkout();
#endif
/*
* make sure that large terminals don't overflow the bounds
* of the program
*/
if (LINES > MAXLINES)
LINES = MAXLINES;
if (COLS > MAXCOLS)
COLS = MAXCOLS;
#ifdef SIGHUP
signal(SIGHUP, auto_save);
#endif
#ifndef DUMP
signal(SIGILL, auto_save);
#ifdef SIGTRAP
signal(SIGTRAP, auto_save);
#endif
#ifdef SIGIOT
signal(SIGIOT, auto_save);
#endif
#ifdef SIGEMT
signal(SIGEMT, auto_save);
#endif
signal(SIGFPE, auto_save);
#ifdef SIGBUS
signal(SIGBUS, auto_save);
#endif
signal(SIGSEGV, auto_save);
#ifdef SIGSYS
signal(SIGSYS, auto_save);
#endif
signal(SIGTERM, auto_save);
#endif
signal(SIGINT, quit);
#ifndef DUMP
#ifdef SIGQUIT
signal(SIGQUIT, endit);
#endif
#endif
#ifdef CHECKTIME
signal(SIGALRM, checkout);
alarm(CHECKTIME * 60);
num_checks = 0;
#endif
crmode(); /* Cbreak mode */
noecho(); /* Echo off */
}
/*
* start_score:
* Start the scoring sequence
*/
start_score()
{
#ifdef SIGALRM
signal(SIGALRM, SIG_IGN);
#endif
}
/*
* issymlink:
* See if the file has a symbolic link
*/
issymlink(sp)
char *sp;
{
#ifdef S_IFLNK
struct stat sbuf2;
if (lstat(sp, &sbuf2) < 0)
return FALSE;
else
return ((sbuf2.st_mode & S_IFMT) != S_IFREG);
#else
return FALSE;
#endif
}
/*
* too_much:
* See if the system is being used too much for this game
*/
too_much()
{
#ifdef MAXLOAD
double avec[3];
if (md_getloadavg(avec) == 0)
if (avec[2] > (MAXLOAD / 10.0))
return(1);
#endif
#ifdef MAXUSERS
if (md_ucount() > MAXUSERS)
return(1) ;
#endif
return(0);
}
/*
* author:
* See if a user is an author of the program
*/
author()
{
#ifdef WIZARD
if (wizard)
return TRUE;
#endif
switch (md_getuid())
{
case 0:
return TRUE;
default:
return FALSE;
}
}
/*
* checkout:
* Check each CHECKTIME seconds to see if the load is too high
*/
void
checkout(int s)
{
static char *msgs[] = {
"The load is too high to be playing. Please leave in %0.1f minutes",
"Please save your game. You have %0.1f minutes",
"Last warning. You have %0.1f minutes to leave",
};
int checktime = 0;
#ifdef SIGALRM
signal(SIGALRM, checkout);
#endif
if (too_much())
{
if (author())
{
num_checks = 1;
chmsg("The load is rather high, O exaulted one");
}
else if (num_checks++ == 3)
fatal("Sorry. You took to long. You are dead\n");
#ifdef CHECKTIME
checktime = (CHECKTIME * 60) / num_checks;
#endif
#ifdef SIGALRM
alarm(checktime);
#endif
chmsg(msgs[num_checks - 1], ((double) checktime / 60.0));
}
else
{
if (num_checks)
{
num_checks = 0;
chmsg("The load has dropped back down. You have a reprieve");
}
#ifdef CHECKTIME
#ifdef SIGALRM
alarm(CHECKTIME * 60);
#endif
#endif
}
}
/*
* chmsg:
* checkout()'s version of msg. If we are in the middle of a
* shell, do a printf instead of a msg to avoid the refresh.
*/
chmsg(fmt, arg)
char *fmt;
int arg;
{
if (in_shell)
{
printf(fmt, arg);
putchar('\n');
fflush(stdout);
}
else
msg(fmt, arg);
}
/*
* lock_sc:
* lock the score file. If it takes too long, ask the user if
* they care to wait. Return TRUE if the lock is successful.
*/
lock_sc()
{
#ifdef SCOREFILE
#ifdef LOCKFILE
register int cnt;
static struct stat sbuf;
over:
if (creat(lockfile, 0000) > 0)
return TRUE;
for (cnt = 0; cnt < 5; cnt++)
{
md_sleep(1);
if (creat(lockfile, 0000) > 0)
return TRUE;
}
if (stat(lockfile, &sbuf) < 0)
{
creat(lockfile, 0000);
return TRUE;
}
if (time(NULL) - sbuf.st_mtime > 10)
{
if (md_unlink(lockfile) < 0)
return FALSE;
goto over;
}
else
{
printf("The score file is very busy. Do you want to wait longer\n");
printf("for it to become free so your score can get posted?\n");
printf("If so, type \"y\"\n");
fgets(prbuf, MAXSTR, stdin);
if (prbuf[0] == 'y')
for (;;)
{
if (creat(lockfile, 0000) > 0)
return TRUE;
if (stat(lockfile, &sbuf) < 0)
{
creat(lockfile, 0000);
return TRUE;
}
if (time(NULL) - sbuf.st_mtime > 10)
{
if (md_unlink(lockfile) < 0)
return FALSE;
}
md_sleep(1);
}
else
return FALSE;
}
#endif
#endif
}
/*
* unlock_sc:
* Unlock the score file
*/
unlock_sc()
{
#ifdef SCOREFILE
#ifdef LOCKFILE
md_unlink(lockfile);
#endif
#endif
}
/*
* flush_type:
* Flush typeahead for traps, etc.
*/
flush_type()
{
flushinp();
}

373
rogue4/main.c Normal file
View file

@ -0,0 +1,373 @@
/*
* # #
* # # # # # ## # # #
* #
*
* @(#)main.c 4.26 (Berkeley) 2/4/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*
*/
#include <stdlib.h>
#include <curses.h>
#include <signal.h>
#include <limits.h>
#include <string.h>
#include "rogue.h"
/*
* main:
* The main program, of course
*/
main(argc, argv, envp)
char **argv;
char **envp;
{
register char *env;
int lowtime;
md_init();
#ifndef DUMP
#ifdef SIGQUIT
signal(SIGQUIT, exit);
#endif
signal(SIGILL, exit);
#ifdef SIGTRAP
signal(SIGTRAP, exit);
#endif
#ifdef SIGIOT
signal(SIGIOT, exit);
#endif
#ifdef SIGEMT
signal(SIGEMT, exit);
#endif
signal(SIGFPE, exit);
#ifdef SIGBUS
signal(SIGBUS, exit);
#endif
signal(SIGSEGV, exit);
#ifdef SIGSYS
signal(SIGSYS, exit);
#endif
#endif
#ifdef WIZARD
/*
* Check to see if he is a wizard
*/
if (argc >= 2 && argv[1][0] == '\0')
if (strcmp(PASSWD, xcrypt(md_getpass("Wizard's password: "), "mT")) == 0)
{
wizard = TRUE;
player.t_flags |= SEEMONST;
argv++;
argc--;
}
#endif
/*
* get home and options from environment
*/
strncpy(home, md_gethomedir(), PATH_MAX);
strcpy(file_name, home);
strcat(file_name, "rogue52.sav");
if ((env = getenv("ROGUEOPTS")) != NULL)
parse_opts(env);
if (env == NULL || whoami[0] == '\0')
strucpy(whoami, md_getusername(md_getuid()), strlen(md_getusername(md_getuid())));
if (env == NULL || fruit[0] == '\0')
strcpy(fruit, "slime-mold");
/*
* check for print-score option
*/
open_score();
if (argc == 2 && strcmp(argv[1], "-s") == 0)
{
noscore = TRUE;
score(0, -1);
exit(0);
}
init_check(); /* check for legal startup */
if (argc == 2)
if (!restore(argv[1], envp)) /* Note: restore will never return */
{
endwin();
exit(1);
}
lowtime = (int) time(NULL);
#ifdef WIZARD
noscore = wizard;
#endif
if (getenv("SEED") != NULL)
{
dnum = atoi(getenv("SEED"));
noscore = TRUE;
}
else
dnum = lowtime + getpid();
#ifdef WIZARD
if (wizard)
printf("Hello %s, welcome to dungeon #%d", whoami, dnum);
else
#endif
printf("Hello %s, just a moment while I dig the dungeon...\n\n",whoami);
fflush(stdout);
seed = dnum;
init_player(); /* Set up initial player stats */
init_things(); /* Set up probabilities of things */
init_names(); /* Set up names of scrolls */
init_colors(); /* Set up colors of potions */
init_stones(); /* Set up stone settings of rings */
init_materials(); /* Set up materials of wands */
initscr(); /* Start up cursor package */
if (COLS < 70)
{
printf("\n\nSorry, but your terminal window has too few columns.\n");
printf("Your terminal has %d columns, needs 70.\n",COLS);
endwin();
exit(1);
}
if (LINES < 22)
{
printf("\n\nSorry, but your terminal window has too few lines.\n");
printf("Your terminal has %d lines, needs 22.\n",LINES);
endwin();
exit(1);
}
if ((whoami == NULL) || (*whoami == '\0') || (strcmp(whoami,"dosuser")==0))
{
echo();
mvaddstr(23,2,"Rogue's Name? ");
wgetnstr(stdscr,whoami,MAXSTR);
noecho();
}
if ((whoami == NULL) || (*whoami == '\0'))
strcpy(whoami,"Rodney");
setup();
/*
* Set up windows
*/
hw = newwin(LINES, COLS, 0, 0);
keypad(stdscr,1);
new_level(); /* Draw current level */
/*
* Start up daemons and fuses
*/
daemon(doctor, 0, AFTER);
fuse(swander, 0, WANDERTIME, AFTER);
daemon(stomach, 0, AFTER);
daemon(runners, 0, AFTER);
playit();
}
/*
* endit:
* Exit the program abnormally.
*/
void
endit(int a)
{
fatal("Ok, if you want to exit that badly, I'll have to allow it\n");
}
/*
* fatal:
* Exit the program, printing a message.
*/
fatal(s)
char *s;
{
clear();
move(LINES-2, 0);
printw("%s", s);
refresh();
endwin();
(void) exit(0);
}
/*
* rnd:
* Pick a very random number.
*/
rnd(range)
register int range;
{
return range == 0 ? 0 : abs((int) RN) % range;
}
/*
* roll:
* Roll a number of dice
*/
roll(number, sides)
register int number, sides;
{
register int dtotal = 0;
while (number--)
dtotal += rnd(sides)+1;
return dtotal;
}
/*
* tstp:
* Handle stop and start signals
*/
void
tstp(int a)
{
register int y, x;
register int oy, ox;
getyx(curscr, oy, ox);
mvcur(0, COLS - 1, LINES - 1, 0);
endwin();
clearok(curscr, TRUE);
fflush(stdout);
#ifdef SIGTSTP
signal(SIGTSTP, SIG_DFL);
kill(0, SIGTSTP);
signal(SIGTSTP, tstp);
#endif
crmode();
noecho();
clearok(curscr, TRUE);
wrefresh(curscr);
getyx(curscr, y, x);
mvcur(y, x, oy, ox);
fflush(stdout);
curscr->_cury = oy;
curscr->_curx = ox;
}
/*
* playit:
* The main loop of the program. Loop until the game is over,
* refreshing things and looking at the proper times.
*/
playit()
{
register char *opts;
/*
* set up defaults for slow terminals
*/
if (baudrate() < 1200)
{
terse = TRUE;
jump = TRUE;
}
/*
* parse environment declaration of options
*/
if ((opts = getenv("ROGUEOPTS")) != NULL)
parse_opts(opts);
oldpos = hero;
oldrp = roomin(&hero);
while (playing)
command(); /* Command execution */
endit(0);
}
/*
* quit:
* Have player make certain, then exit.
*/
void
quit(int a)
{
register int oy, ox;
/*
* Reset the signal in case we got here via an interrupt
*/
if (signal(SIGINT, quit) != quit)
mpos = 0;
getyx(curscr, oy, ox);
msg("really quit?");
if (readchar() == 'y')
{
signal(SIGINT, leave);
clear();
mvprintw(LINES - 2, 0, "You quit with %d gold pieces", purse);
move(LINES - 1, 0);
refresh();
score(purse, 1);
exit(0);
}
else
{
move(0, 0);
clrtoeol();
status();
move(oy, ox);
refresh();
mpos = 0;
count = 0;
}
}
/*
* leave:
* Leave quickly, but curteously
*/
void
leave(int sig)
{
/*
if (!_endwin)
{*/
mvcur(0, COLS - 1, LINES - 1, 0);
endwin();
/* } */
putchar('\n');
exit(0);
}
/*
* shell:
* Let him escape for a while
*/
shell()
{
/*
* Set the terminal back to original mode
*/
move(LINES-1, 0);
refresh();
endwin();
putchar('\n');
putchar('\n');
in_shell = TRUE;
after = FALSE;
md_shellescape();
noecho();
crmode();
in_shell = FALSE;
clearok(stdscr, TRUE);
touchwin(stdscr);
}

1309
rogue4/mdport.c Normal file

File diff suppressed because it is too large Load diff

474
rogue4/misc.c Normal file
View file

@ -0,0 +1,474 @@
/*
* All sorts of miscellaneous routines
*
* @(#)misc.c 4.30 (Berkeley) 4/6/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdlib.h>
#include <curses.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"
/*
* tr_name:
* Print the name of a trap
*/
char *
tr_name(type)
char type;
{
switch (type)
{
case T_DOOR:
return terse ? "a trapdoor" : "you found a trapdoor";
case T_BEAR:
return terse ? "a beartrap" : "you found a beartrap";
case T_SLEEP:
return terse ? "a sleeping gas trap":"you found a sleeping gas trap";
case T_ARROW:
return terse ? "an arrow trap" : "you found an arrow trap";
case T_TELEP:
return terse ? "a teleport trap" : "you found a teleport trap";
case T_DART:
return terse ? "a dart trap" : "you found a poison dart trap";
}
msg("wierd trap: %d", type);
return NULL;
}
/*
* look:
* A quick glance all around the player
*/
look(wakeup)
bool wakeup;
{
register int x, y;
register unsigned char ch;
register int index;
register THING *tp;
register struct room *rp;
register int ey, ex;
register int passcount = 0;
register char pfl, *fp, pch;
register int sy, sx, sumhero = 0, diffhero = 0;
register int oldx, oldy;
getyx(stdscr, oldy, oldx);
rp = proom;
if (!ce(oldpos, hero))
{
if ((oldrp->r_flags & (ISGONE|ISDARK)) == ISDARK && !on(player,ISBLIND))
{
ey = oldpos.y + 1;
ex = oldpos.x + 1;
sy = oldpos.y - 1;
for (x = oldpos.x - 1; x <= ex; x++)
for (y = sy; y <= ey; y++)
{
if (y == hero.y && x == hero.x)
continue;
move(y, x);
if (inch() == FLOOR)
addch(' ');
}
}
oldpos = hero;
oldrp = rp;
}
ey = hero.y + 1;
ex = hero.x + 1;
sx = hero.x - 1;
sy = hero.y - 1;
if (door_stop && !firstmove && running)
{
sumhero = hero.y + hero.x;
diffhero = hero.y - hero.x;
}
index = INDEX(hero.y, hero.x);
pfl = _flags[index];
pch = _level[index];
for (y = sy; y <= ey; y++)
if (y > 0 && y < LINES - 1) for (x = sx; x <= ex; x++)
{
if (x <= 0 || x >= COLS)
continue;
if (!on(player, ISBLIND))
{
if (y == hero.y && x == hero.x)
continue;
}
else if (y != hero.y || x != hero.x)
continue;
index = INDEX(y, x);
/*
* THIS REPLICATES THE moat() MACRO. IF MOAT IS CHANGED,
* THIS MUST BE CHANGED ALSO
*/
fp = &_flags[index];
ch = _level[index];
if (pch != DOOR && ch != DOOR)
if ((pfl & F_PASS) != (*fp & F_PASS))
continue;
else if ((*fp & F_PASS) && (*fp & F_PNUM) != (pfl & F_PNUM))
continue;
if ((tp = _monst[index]) != NULL)
if (on(player, SEEMONST) && on(*tp, ISINVIS))
{
if (door_stop && !firstmove)
running = FALSE;
continue;
}
else
{
if (wakeup)
wake_monster(y, x);
if (tp->t_oldch != ' ' ||
(!(rp->r_flags & ISDARK) && !on(player, ISBLIND)))
tp->t_oldch = _level[index];
if (see_monst(tp))
ch = tp->t_disguise;
}
move(y, x);
if (ch != inch())
addch(ch);
if (door_stop && !firstmove && running)
{
switch (runch)
{
case 'h':
if (x == ex)
continue;
when 'j':
if (y == sy)
continue;
when 'k':
if (y == ey)
continue;
when 'l':
if (x == sx)
continue;
when 'y':
if ((y + x) - sumhero >= 1)
continue;
when 'u':
if ((y - x) - diffhero >= 1)
continue;
when 'n':
if ((y + x) - sumhero <= -1)
continue;
when 'b':
if ((y - x) - diffhero <= -1)
continue;
}
switch (ch)
{
case DOOR:
if (x == hero.x || y == hero.y)
running = FALSE;
break;
case PASSAGE:
if (x == hero.x || y == hero.y)
passcount++;
break;
case FLOOR:
case '|':
case '-':
case ' ':
break;
default:
running = FALSE;
break;
}
}
}
if (door_stop && !firstmove && passcount > 1)
running = FALSE;
move(hero.y, hero.x);
addch(PLAYER);
}
/*
* find_obj:
* Find the unclaimed object at y, x
*/
THING *
find_obj(y, x)
register int y, x;
{
register THING *op;
for (op = lvl_obj; op != NULL; op = next(op))
{
if (op->o_pos.y == y && op->o_pos.x == x)
return op;
}
#ifdef WIZARD
sprintf(prbuf, "Non-object %d,%d", y, x);
debug(prbuf);
#endif
return NULL;
}
/*
* eat:
* She wants to eat something, so let her try
*/
eat()
{
register THING *obj;
if ((obj = get_item("eat", FOOD)) == NULL)
return;
if (obj->o_type != FOOD)
{
if (!terse)
msg("ugh, you would get ill if you ate that");
else
msg("that's Inedible!");
return;
}
inpack--;
if (food_left < 0)
food_left = 0;
if ((food_left += HUNGERTIME - 200 + rnd(400)) > STOMACHSIZE)
food_left = STOMACHSIZE;
hungry_state = 0;
if (obj == cur_weapon)
cur_weapon = NULL;
if (obj->o_which == 1)
msg("my, that was a yummy %s", fruit);
else
if (rnd(100) > 70)
{
pstats.s_exp++;
msg("yuk, this food tastes awful");
check_level();
}
else
msg("yum, that tasted good");
if (--obj->o_count < 1)
{
detach(pack, obj);
discard(obj);
}
}
/*
* chg_str:
* Used to modify the playes strength. It keeps track of the
* highest it has been, just in case
*/
chg_str(amt)
register int amt;
{
str_t comp;
if (amt == 0)
return;
add_str(&pstats.s_str, amt);
comp = pstats.s_str;
if (ISRING(LEFT, R_ADDSTR))
add_str(&comp, -cur_ring[LEFT]->o_ac);
if (ISRING(RIGHT, R_ADDSTR))
add_str(&comp, -cur_ring[RIGHT]->o_ac);
if (comp > max_stats.s_str)
max_stats.s_str = comp;
}
/*
* add_str:
* Perform the actual add, checking upper and lower bound limits
*/
add_str(sp, amt)
register str_t *sp;
int amt;
{
if ((*sp += amt) < 3)
*sp = 3;
else if (*sp > 31)
*sp = 31;
}
/*
* add_haste:
* Add a haste to the player
*/
add_haste(potion)
bool potion;
{
if (on(player, ISHASTE))
{
no_command += rnd(8);
player.t_flags &= ~ISRUN;
extinguish(nohaste);
player.t_flags &= ~ISHASTE;
msg("you faint from exhaustion");
return FALSE;
}
else
{
player.t_flags |= ISHASTE;
if (potion)
fuse(nohaste, 0, rnd(4)+4, AFTER);
return TRUE;
}
}
/*
* aggravate:
* Aggravate all the monsters on this level
*/
aggravate()
{
register THING *mi;
for (mi = mlist; mi != NULL; mi = next(mi))
runto(&mi->t_pos, &hero);
}
/*
* vowelstr:
* For printfs: if string starts with a vowel, return "n" for an
* "an".
*/
char *
vowelstr(str)
register char *str;
{
switch (*str)
{
case 'a': case 'A':
case 'e': case 'E':
case 'i': case 'I':
case 'o': case 'O':
case 'u': case 'U':
return "n";
default:
return "";
}
}
/*
* is_current:
* See if the object is one of the currently used items
*/
is_current(obj)
register THING *obj;
{
if (obj == NULL)
return FALSE;
if (obj == cur_armor || obj == cur_weapon || obj == cur_ring[LEFT]
|| obj == cur_ring[RIGHT])
{
if (!terse)
addmsg("That's already ");
msg("in use");
return TRUE;
}
return FALSE;
}
/*
* get_dir:
* Set up the direction co_ordinate for use in varios "prefix"
* commands
*/
get_dir()
{
register char *prompt;
register bool gotit;
if (!terse)
msg(prompt = "which direction? ");
else
prompt = "direction: ";
do
{
gotit = TRUE;
switch (readchar())
{
case 'h': case'H': delta.y = 0; delta.x = -1;
when 'j': case'J': delta.y = 1; delta.x = 0;
when 'k': case'K': delta.y = -1; delta.x = 0;
when 'l': case'L': delta.y = 0; delta.x = 1;
when 'y': case'Y': delta.y = -1; delta.x = -1;
when 'u': case'U': delta.y = -1; delta.x = 1;
when 'b': case'B': delta.y = 1; delta.x = -1;
when 'n': case'N': delta.y = 1; delta.x = 1;
when ESCAPE: return FALSE;
otherwise:
mpos = 0;
msg(prompt);
gotit = FALSE;
}
} until (gotit);
if (on(player, ISHUH) && rnd(5) == 0)
do
{
delta.y = rnd(3) - 1;
delta.x = rnd(3) - 1;
} while (delta.y == 0 && delta.x == 0);
mpos = 0;
return TRUE;
}
/*
* sign:
* Return the sign of the number
*/
sign(nm)
register int nm;
{
if (nm < 0)
return -1;
else
return (nm > 0);
}
/*
* spread:
* Give a spread around a given number (+/- 10%)
*/
spread(nm)
register int nm;
{
return nm - nm / 10 + rnd(nm / 5);
}
/*
* call_it:
* Call an object something after use.
*/
call_it(know, guess)
register bool know;
register char **guess;
{
if (know && *guess)
{
free(*guess);
*guess = NULL;
}
else if (!know && askme && *guess == NULL)
{
msg(terse ? "call it: " : "what do you want to call it? ");
if (get_str(prbuf, stdscr) == NORM)
{
*guess = malloc((unsigned int) strlen(prbuf) + 1);
strcpy(*guess, prbuf);
}
}
}

278
rogue4/monsters.c Normal file
View file

@ -0,0 +1,278 @@
/*
* File with various monster functions in it
*
* @(#)monsters.c 4.24 (Berkeley) 4/6/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <string.h>
#include <ctype.h>
#include "rogue.h"
/*
* List of monsters in rough order of vorpalness
*
* NOTE: This not initialized using strings so that xstr doesn't set up
* the string not to be saved. Otherwise genocide is lost through
* saving a game.
*/
char lvl_mons[] = {
'K', 'J', 'B', 'S', 'H', 'E', 'A', 'O', 'Z', 'G', 'L', 'C', 'R',
'Q', 'N', 'Y', 'T', 'W', 'F', 'I', 'X', 'U', 'M', 'V', 'P', 'D',
'\0'
};
char wand_mons[] = {
'K', 'J', 'B', 'S', 'H', ' ', 'A', 'O', 'Z', 'G', ' ', 'C', 'R',
'Q', ' ', 'Y', 'T', 'W', ' ', 'I', 'X', 'U', ' ', 'V', 'P', ' ',
'\0'
};
/*
* randmonster:
* Pick a monster to show up. The lower the level,
* the meaner the monster.
*/
randmonster(wander)
bool wander;
{
register int d;
register char *mons;
mons = wander ? wand_mons : lvl_mons;
do
{
d = level + (rnd(10) - 5);
if (d < 1)
d = rnd(5) + 1;
if (d > 26)
d = rnd(5) + 22;
} while (mons[--d] == ' ');
return mons[d];
}
/*
* new_monster:
* Pick a new monster and add it to the list
*/
new_monster(tp, type, cp)
register THING *tp;
char type;
register coord *cp;
{
register struct monster *mp;
register int lev_add;
if ((lev_add = level - AMULETLEVEL) < 0)
lev_add = 0;
attach(mlist, tp);
tp->t_type = type;
tp->t_disguise = type;
tp->t_pos = *cp;
tp->t_oldch = mvinch(cp->y, cp->x);
tp->t_room = roomin(cp);
moat(cp->y, cp->x) = tp;
mp = &monsters[tp->t_type-'A'];
tp->t_stats.s_lvl = mp->m_stats.s_lvl + lev_add;
tp->t_stats.s_maxhp = tp->t_stats.s_hpt = roll(tp->t_stats.s_lvl, 8);
tp->t_stats.s_arm = mp->m_stats.s_arm - lev_add;
strncpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg,16);
tp->t_stats.s_str = mp->m_stats.s_str;
tp->t_stats.s_exp = mp->m_stats.s_exp + lev_add * 10 + exp_add(tp);
tp->t_flags = mp->m_flags;
tp->t_turn = TRUE;
tp->t_pack = NULL;
if (ISWEARING(R_AGGR))
runto(cp, &hero);
if (type == 'M')
switch (rnd(level > 25 ? 9 : 8))
{
case 0: tp->t_disguise = GOLD;
when 1: tp->t_disguise = POTION;
when 2: tp->t_disguise = SCROLL;
when 3: tp->t_disguise = STAIRS;
when 4: tp->t_disguise = WEAPON;
when 5: tp->t_disguise = ARMOR;
when 6: tp->t_disguise = RING;
when 7: tp->t_disguise = STICK;
when 8: tp->t_disguise = AMULET;
}
}
/*
* expadd:
* Experience to add for this monster's level/hit points
*/
exp_add(tp)
register THING *tp;
{
register int mod;
if (tp->t_stats.s_lvl == 1)
mod = tp->t_stats.s_maxhp / 8;
else
mod = tp->t_stats.s_maxhp / 6;
if (tp->t_stats.s_lvl > 9)
mod *= 20;
else if (tp->t_stats.s_lvl > 6)
mod *= 4;
return mod;
}
/*
* wanderer:
* Create a new wandering monster and aim it at the player
*/
wanderer()
{
register int i;
register struct room *rp;
register THING *tp;
coord cp = {0,0};
register int cnt = 0;
tp = new_item();
do
{
/* Avoid endless loop when all rooms are filled with monsters
* and the player room is not accessible to the monsters.
*/
if (cnt++ >= 500)
{
discard(tp);
return;
}
i = rnd_room();
if ((rp = &rooms[i]) == proom)
continue;
rnd_pos(rp, &cp);
} until (rp != proom && step_ok(winat(cp.y, cp.x)));
new_monster(tp, randmonster(TRUE), &cp);
runto(&tp->t_pos, &hero);
#ifdef WIZARD
if (wizard)
msg("started a wandering %s", monsters[tp->t_type-'A'].m_name);
#endif
}
/*
* wake_monster:
* What to do when the hero steps next to a monster
*/
THING *
wake_monster(y, x)
int y, x;
{
register THING *tp;
register struct room *rp;
register char ch;
#ifdef WIZARD
if ((tp = moat(y, x)) == NULL)
msg("can't find monster in wake_monster");
#else
tp = moat(y, x);
#endif
ch = tp->t_type;
/*
* Every time he sees mean monster, it might start chasing him
*/
if (!on(*tp, ISRUN) && rnd(3) != 0 && on(*tp, ISMEAN) && !on(*tp, ISHELD)
&& !ISWEARING(R_STEALTH))
{
tp->t_dest = &hero;
tp->t_flags |= ISRUN;
}
if (ch == 'U' && !on(player, ISBLIND) && !on(*tp, ISFOUND)
&& !on(*tp, ISCANC) && on(*tp, ISRUN))
{
rp = proom;
if ((rp != NULL && !(rp->r_flags & ISDARK))
|| DISTANCE(y, x, hero.y, hero.x) < LAMPDIST)
{
tp->t_flags |= ISFOUND;
if (!save(VS_MAGIC))
{
if (on(player, ISHUH))
lengthen(unconfuse, rnd(20) + HUHDURATION);
else
fuse(unconfuse, 0, rnd(20) + HUHDURATION, AFTER);
player.t_flags |= ISHUH;
msg("the umber hulk's gaze has confused you");
}
}
}
/*
* Let greedy ones guard gold
*/
if (on(*tp, ISGREED) && !on(*tp, ISRUN))
{
tp->t_flags |= ISRUN;
if (proom->r_goldval)
tp->t_dest = &proom->r_gold;
else
tp->t_dest = &hero;
}
return tp;
}
/*
* genocide:
* Wipe one monster out of existence (for now...)
*/
genocide()
{
register THING *mp;
register char c;
register int i;
register THING *nmp;
addmsg("which monster");
if (!terse)
addmsg(" do you wish to wipe out");
msg("? ");
while (!isalpha(c = readchar()))
if (c == ESCAPE)
return;
else
{
mpos = 0;
msg("please specifiy a letter between 'A' and 'Z'");
}
mpos = 0;
if (islower(c))
c = toupper(c);
for (mp = mlist; mp; mp = nmp)
{
nmp = next(mp);
if (mp->t_type == c)
remove_monster(&mp->t_pos, mp, FALSE);
}
for (i = 0; i < 26; i++)
if (lvl_mons[i] == c)
{
lvl_mons[i] = ' ';
wand_mons[i] = ' ';
break;
}
if (!terse)
addmsg("there will be ");
msg("no more %ss", monsters[c - 'A'].m_name);
}
/*
* give_pack:
* Give a pack to a monster if it deserves one
*/
give_pack(tp)
register THING *tp;
{
if (rnd(100) < monsters[tp->t_type-'A'].m_carry)
attach(tp->t_pack, new_thing());
}

358
rogue4/move.c Normal file
View file

@ -0,0 +1,358 @@
/*
* Hero movement commands
*
* @(#)move.c 4.24 (Berkeley) 5/12/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <ctype.h>
#include "rogue.h"
/*
* Used to hold the new hero position
*/
coord nh;
/*
* do_run:
* Start the hero running
*/
do_run(ch)
char ch;
{
running = TRUE;
after = FALSE;
runch = ch;
}
/*
* do_move:
* Check to see that a move is legal. If it is handle the
* consequences (fighting, picking up, etc.)
*/
do_move(dy, dx)
int dy, dx;
{
register char ch, fl;
firstmove = FALSE;
if (no_move)
{
no_move--;
msg("you are still stuck in the bear trap");
return;
}
/*
* Do a confused move (maybe)
*/
if (on(player, ISHUH) && rnd(5) != 0)
{
nh = *rndmove(&player);
if (ce(nh, hero))
{
after = FALSE;
running = FALSE;
return;
}
}
else
{
over:
nh.y = hero.y + dy;
nh.x = hero.x + dx;
}
/*
* Check if he tried to move off the screen or make an illegal
* diagonal move, and stop him if he did.
*/
if (nh.x < 0 || nh.x > COLS-1 || nh.y < 1 || nh.y > LINES - 2)
goto hit_bound;
if (!diag_ok(&hero, &nh))
{
after = FALSE;
running = FALSE;
return;
}
if (running && ce(hero, nh))
after = running = FALSE;
fl = flat(nh.y, nh.x);
ch = winat(nh.y, nh.x);
if (!(fl & F_REAL) && ch == FLOOR)
{
chat(nh.y, nh.x) = ch = TRAP;
flat(nh.y, nh.x) |= F_REAL;
}
else
if (on(player, ISHELD) && ch != 'F')
{
msg("you are being held");
return;
}
switch (ch)
{
case ' ':
case '|':
case '-':
hit_bound:
if (passgo && running && (proom->r_flags & ISGONE)
&& !on(player, ISBLIND))
{
register bool b1, b2;
switch (runch)
{
case 'h':
case 'l':
b1 = (((flat(hero.y - 1, hero.x) & F_PASS) || chat(hero.y - 1, hero.x) == DOOR) && hero.y != 1);
b2 = (((flat(hero.y + 1, hero.x) & F_PASS) || chat(hero.y + 1, hero.x) == DOOR) && hero.y != LINES - 2);
if (!(b1 ^ b2))
break;
if (b1)
{
runch = 'k';
dy = -1;
}
else
{
runch = 'j';
dy = 1;
}
dx = 0;
turnref();
goto over;
case 'j':
case 'k':
b1 = (((flat(hero.y, hero.x - 1) & F_PASS) || chat(hero.y, hero.x - 1) == DOOR) && hero.x != 0);
b2 = (((flat(hero.y, hero.x + 1) & F_PASS) || chat(hero.y, hero.x + 1) == DOOR) && hero.x != COLS - 1);
if (!(b1 ^ b2))
break;
if (b1)
{
runch = 'h';
dx = -1;
}
else
{
runch = 'l';
dx = 1;
}
dy = 0;
turnref();
goto over;
}
}
after = running = FALSE;
break;
case DOOR:
running = FALSE;
if (flat(hero.y, hero.x) & F_PASS)
enter_room(&nh);
goto move_stuff;
case TRAP:
ch = be_trapped(&nh);
if (ch == T_DOOR || ch == T_TELEP)
return;
goto move_stuff;
case PASSAGE:
goto move_stuff;
case FLOOR:
if (!(fl & F_REAL))
be_trapped(&hero);
goto move_stuff;
default:
running = FALSE;
if (isupper(ch) || moat(nh.y, nh.x))
fight(&nh, ch, cur_weapon, FALSE);
else
{
running = FALSE;
if (ch != STAIRS)
take = ch;
move_stuff:
mvaddch(hero.y, hero.x, chat(hero.y, hero.x));
if ((fl & F_PASS) && chat(oldpos.y, oldpos.x) == DOOR)
leave_room(&nh);
hero = nh;
}
}
}
/*
* turnref:
* Decide whether to refresh at a passage turning or not
*/
turnref()
{
register int index;
index = INDEX(hero.y, hero.x);
if (!(_flags[index] & F_SEEN))
{
if (jump)
{
leaveok(stdscr, TRUE);
refresh();
leaveok(stdscr, FALSE);
}
_flags[index] |= F_SEEN;
}
}
/*
* door_open:
* Called to illuminate a room. If it is dark, remove anything
* that might move.
*/
door_open(rp)
struct room *rp;
{
register int j, k;
register char ch;
register THING *item;
if (!(rp->r_flags & ISGONE) && !on(player, ISBLIND))
for (j = rp->r_pos.y; j < rp->r_pos.y + rp->r_max.y; j++)
for (k = rp->r_pos.x; k < rp->r_pos.x + rp->r_max.x; k++)
{
ch = winat(j, k);
move(j, k);
if (isupper(ch))
{
item = wake_monster(j, k);
if (item->t_oldch == ' ' && !(rp->r_flags & ISDARK)
&& !on(player, ISBLIND))
item->t_oldch = chat(j, k);
}
}
}
/*
* be_trapped:
* The guy stepped on a trap.... Make him pay.
*/
be_trapped(tc)
register coord *tc;
{
register char tr;
register int index;
count = running = FALSE;
index = INDEX(tc->y, tc->x);
_level[index] = TRAP;
tr = _flags[index] & F_TMASK;
switch (tr)
{
case T_DOOR:
level++;
new_level();
msg("you fell into a trap!");
when T_BEAR:
no_move += BEARTIME;
msg("you are caught in a bear trap");
when T_SLEEP:
no_command += SLEEPTIME;
player.t_flags &= ~ISRUN;
msg("a strange white mist envelops you and you fall asleep");
when T_ARROW:
if (swing(pstats.s_lvl-1, pstats.s_arm, 1))
{
pstats.s_hpt -= roll(1, 6);
if (pstats.s_hpt <= 0)
{
msg("an arrow killed you");
death('a');
}
else
msg("oh no! An arrow shot you");
}
else
{
register THING *arrow;
arrow = new_item();
arrow->o_type = WEAPON;
arrow->o_which = ARROW;
init_weapon(arrow, ARROW);
arrow->o_count = 1;
arrow->o_pos = hero;
arrow->o_hplus = arrow->o_dplus = 0;
fall(arrow, FALSE);
msg("an arrow shoots past you");
}
when T_TELEP:
teleport();
mvaddch(tc->y, tc->x, TRAP); /* since the hero's leaving, look()
won't put it on for us */
when T_DART:
if (swing(pstats.s_lvl+1, pstats.s_arm, 1))
{
pstats.s_hpt -= roll(1, 4);
if (pstats.s_hpt <= 0)
{
msg("a poisoned dart killed you");
death('d');
}
if (!ISWEARING(R_SUSTSTR) && !save(VS_POISON))
chg_str(-1);
msg("a small dart just hit you in the shoulder");
}
else
msg("a small dart whizzes by your ear and vanishes");
}
flush_type();
return tr;
}
/*
* rndmove:
* Move in a random direction if the monster/person is confused
*/
coord *
rndmove(who)
THING *who;
{
register int x, y;
register char ch;
register THING *obj;
static coord ret; /* what we will be returning */
y = ret.y = who->t_pos.y + rnd(3) - 1;
x = ret.x = who->t_pos.x + rnd(3) - 1;
/*
* Now check to see if that's a legal move. If not, don't move.
* (I.e., bump into the wall or whatever)
*/
if (y == who->t_pos.y && x == who->t_pos.x)
return &ret;
if ((y < 0 || y >= LINES - 1) || (x < 0 || x >= COLS))
goto bad;
else if (!diag_ok(&who->t_pos, &ret))
goto bad;
else
{
ch = winat(y, x);
if (!step_ok(ch))
goto bad;
if (ch == SCROLL)
{
for (obj = lvl_obj; obj != NULL; obj = next(obj))
if (y == obj->o_pos.y && x == obj->o_pos.x)
break;
if (obj != NULL && obj->o_which == S_SCARE)
goto bad;
}
}
return &ret;
bad:
ret = who->t_pos;
return &ret;
}

254
rogue4/new_level.c Normal file
View file

@ -0,0 +1,254 @@
/*
* new_level:
* Dig and draw a new level
*
* @(#)new_level.c 4.19 (Berkeley) 1/12/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <time.h>
#include <curses.h>
#include <string.h>
#include "rogue.h"
#define TREAS_ROOM 20 /* one chance in TREAS_ROOM for a treasure room */
#define MAXTREAS 10 /* maximum number of treasures in a treasure room */
#define MINTREAS 2 /* minimum number of treasures in a treasure room */
new_level()
{
register int rm, i;
register THING *tp;
register char *sp;
register THING **mp;
register int index;
coord stairs;
player.t_flags &= ~ISHELD; /* unhold when you go down just in case */
if (level > max_level)
max_level = level;
/*
* Clean things off from last level
*/
clear();
for (sp = _level; sp < &_level[MAXCOLS*MAXLINES]; )
*sp++ = ' ';
for (sp = _flags; sp < &_flags[MAXCOLS*MAXLINES]; )
*sp++ = F_REAL;
for (mp = _monst; mp < &_monst[MAXCOLS*MAXLINES]; )
*mp++ = NULL;
clear();
/*
* Free up the monsters on the last level
*/
for (tp = mlist; tp != NULL; tp = next(tp))
free_list(tp->t_pack);
free_list(mlist);
/*
* Throw away stuff left on the previous level (if anything)
*/
free_list(lvl_obj);
do_rooms(); /* Draw rooms */
do_passages(); /* Draw passages */
no_food++;
put_things(); /* Place objects (if any) */
/*
* Place the staircase down.
*/
i = 0;
do {
rm = rnd_room();
rnd_pos(&rooms[rm], &stairs);
index = INDEX(stairs.y, stairs.x);
if (i++ > 100)
{
i = 0;
srand(getpid() + (int) time((time_t *) NULL));
}
} until (_level[index] == FLOOR);
_level[index] = STAIRS;
/*
* Place the traps
*/
if (rnd(10) < level)
{
ntraps = rnd(level / 4) + 1;
if (ntraps > MAXTRAPS)
ntraps = MAXTRAPS;
i = ntraps;
while (i--)
{
do
{
rm = rnd_room();
rnd_pos(&rooms[rm], &stairs);
index = INDEX(stairs.y, stairs.x);
} until (_level[index] == FLOOR && (_flags[index] & F_REAL));
sp = &_flags[index];
*sp &= ~(F_REAL | F_TMASK);
*sp |= rnd(NTRAPS);
}
}
do
{
rm = rnd_room();
rnd_pos(&rooms[rm], &hero);
index = INDEX(hero.y, hero.x);
} until (_level[index] == FLOOR && (_flags[index] & F_REAL)
&& _monst[index] == NULL);
enter_room(&hero);
move(hero.y, hero.x);
addch(PLAYER);
if (on(player, SEEMONST))
turn_see(FALSE);
}
/*
* rnd_room:
* Pick a room that is really there
*/
rnd_room()
{
register int rm;
do
{
rm = rnd(MAXROOMS);
} while (rooms[rm].r_flags & ISGONE);
return rm;
}
/*
* put_things:
* Put potions and scrolls on this level
*/
put_things()
{
register int i;
register THING *cur;
register int rm;
coord tp;
/*
* Once you have found the amulet, the only way to get new stuff is
* go down into the dungeon.
*/
if (amulet && level < max_level)
return;
/*
* check for treasure rooms, and if so, put it in.
*/
if (rnd(TREAS_ROOM) == 0)
treas_room();
/*
* Do MAXOBJ attempts to put things on a level
*/
for (i = 0; i < MAXOBJ; i++)
if (rnd(100) < 35)
{
/*
* Pick a new object and link it in the list
*/
cur = new_thing();
attach(lvl_obj, cur);
/*
* Put it somewhere
*/
do {
rm = rnd_room();
rnd_pos(&rooms[rm], &tp);
} until (chat(tp.y, tp.x) == FLOOR);
chat(tp.y, tp.x) = cur->o_type;
cur->o_pos = tp;
}
/*
* If he is really deep in the dungeon and he hasn't found the
* amulet yet, put it somewhere on the ground
*/
if (level >= AMULETLEVEL && !amulet)
{
cur = new_item();
attach(lvl_obj, cur);
cur->o_hplus = cur->o_dplus = 0;
strcpy(cur->o_damage,"0d0");
strcpy(cur->o_hurldmg,"0d0");
cur->o_ac = 11;
cur->o_type = AMULET;
/*
* Put it somewhere
*/
do {
rm = rnd_room();
rnd_pos(&rooms[rm], &tp);
} until (winat(tp.y, tp.x) == FLOOR);
chat(tp.y, tp.x) = AMULET;
cur->o_pos = tp;
}
}
/*
* treas_room:
* Add a treasure room
*/
#define MAXTRIES 10 /* max number of tries to put down a monster */
treas_room()
{
register int nm, index;
register THING *tp;
register struct room *rp;
register int spots, num_monst;
coord mp;
rp = &rooms[rnd_room()];
spots = (rp->r_max.y - 2) * (rp->r_max.x - 2) - MINTREAS;
if (spots > (MAXTREAS - MINTREAS))
spots = (MAXTREAS - MINTREAS);
num_monst = nm = rnd(spots) + MINTREAS;
while (nm--)
{
do
{
rnd_pos(rp, &mp);
index = INDEX(mp.y, mp.x);
} until (_level[index] == FLOOR);
tp = new_thing();
tp->o_pos = mp;
attach(lvl_obj, tp);
_level[index] = tp->o_type;
}
/*
* fill up room with monsters from the next level down
*/
if ((nm = rnd(spots) + MINTREAS) < num_monst + 2)
nm = num_monst + 2;
spots = (rp->r_max.y - 2) * (rp->r_max.x - 2);
if (nm > spots)
nm = spots;
level++;
while (nm--)
{
spots = 0;
do
{
rnd_pos(rp, &mp);
index = INDEX(mp.y, mp.x);
spots++;
} until (_monst[index] == NULL || spots > MAXTRIES);
if (_monst[index] == NULL)
{
tp = new_item();
new_monster(tp, randmonster(FALSE), &mp);
tp->t_flags |= ISMEAN; /* no sloughers in THIS room */
give_pack(tp);
}
}
level--;
}

370
rogue4/options.c Normal file
View file

@ -0,0 +1,370 @@
/*
* This file has all the code for the option command. I would rather
* this command were not necessary, but it is the only way to keep the
* wolves off of my back.
*
* @(#)options.c 4.12 (Berkeley) 3/2/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"
#define EQSTR(a, b, c) (strncmp(a, b, c) == 0)
#define NUM_OPTS (sizeof optlist / sizeof (OPTION))
/*
* description of an option and what to do with it
*/
struct optstruct {
char *o_name; /* option name */
char *o_prompt; /* prompt for interactive entry */
int *o_opt; /* pointer to thing to set */
int (*o_putfunc)(); /* function to print value */
int (*o_getfunc)(); /* function to get value interactively */
};
typedef struct optstruct OPTION;
int put_bool(), get_bool(), put_str(), get_str();
OPTION optlist[] = {
{"terse", "Terse output: ",
(int *) &terse, put_bool, get_bool },
{"flush", "Flush typeahead during battle: ",
(int *) &fight_flush, put_bool, get_bool },
{"jump", "Show position only at end of run: ",
(int *) &jump, put_bool, get_bool },
{"step", "Do inventories one line at a time: ",
(int *) &slow_invent, put_bool, get_bool },
{"askme", "Ask me about unidentified things: ",
(int *) &askme, put_bool, get_bool },
{"passgo", "Follow turnings in passageways: ",
(int *) &passgo, put_bool, get_bool },
{"name", "Name: ",
(int *) whoami, put_str, get_str },
{"fruit", "Fruit: ",
(int *) fruit, put_str, get_str },
{"file", "Save file: ",
(int *) file_name, put_str, get_str }
};
/*
* option:
* Print and then set options from the terminal
*/
option()
{
register OPTION *op;
register int retval;
wclear(hw);
/*
* Display current values of options
*/
for (op = optlist; op < &optlist[NUM_OPTS]; op++)
{
waddstr(hw, op->o_prompt);
(*op->o_putfunc)(op->o_opt);
waddch(hw, '\n');
}
/*
* Set values
*/
wmove(hw, 0, 0);
for (op = optlist; op < &optlist[NUM_OPTS]; op++)
{
waddstr(hw, op->o_prompt);
if ((retval = (*op->o_getfunc)(op->o_opt, hw)))
if (retval == QUIT)
break;
else if (op > optlist) { /* MINUS */
wmove(hw, (op - optlist) - 1, 0);
op -= 2;
}
else /* trying to back up beyond the top */
{
putchar('\007');
wmove(hw, 0, 0);
op--;
}
}
/*
* Switch back to original screen
*/
mvwaddstr(hw, LINES-1, 0, "--Press space to continue--");
wrefresh(hw);
wait_for(' ');
clearok(curscr, TRUE);
touchwin(stdscr);
after = FALSE;
}
/*
* put_bool
* Put out a boolean
*/
put_bool(b)
bool *b;
{
waddstr(hw, *b ? "True" : "False");
}
/*
* put_str:
* Put out a string
*/
put_str(str)
char *str;
{
waddstr(hw, str);
}
/*
* get_bool:
* Allow changing a boolean option and print it out
*/
get_bool(bp, win)
bool *bp;
WINDOW *win;
{
register int oy, ox;
register bool op_bad;
op_bad = TRUE;
getyx(win, oy, ox);
waddstr(win, *bp ? "True" : "False");
while (op_bad)
{
wmove(win, oy, ox);
wrefresh(win);
switch (readcharw(win))
{
case 't':
case 'T':
*bp = TRUE;
op_bad = FALSE;
break;
case 'f':
case 'F':
*bp = FALSE;
op_bad = FALSE;
break;
case '\n':
case '\r':
op_bad = FALSE;
break;
case '\033':
case '\007':
return QUIT;
case '-':
return MINUS;
default:
mvwaddstr(win, oy, ox + 10, "(T or F)");
}
}
wmove(win, oy, ox);
waddstr(win, *bp ? "True" : "False");
waddch(win, '\n');
return NORM;
}
/*
* get_str:
* Set a string option
*/
#define MAXINP 50 /* max string to read from terminal or environment */
get_str(opt, win)
register char *opt;
WINDOW *win;
{
register char *sp;
register int c, oy, ox;
char buf[MAXSTR];
getyx(win, oy, ox);
wrefresh(win);
/*
* loop reading in the string, and put it in a temporary buffer
*/
for (sp = buf; (c = readcharw(win)) != '\n' && c != '\r' && c != '\033';
wclrtoeol(win), wrefresh(win))
{
if (c == -1)
continue;
else if (c == md_erasechar()) /* process erase character */
{
if (sp > buf)
{
register int i;
sp--;
for (i = strlen(unctrol(*sp)); i; i--)
waddch(win, '\b');
}
continue;
}
else if (c == md_killchar()) /* process kill character */
{
sp = buf;
wmove(win, oy, ox);
continue;
}
else if (sp == buf)
{
if (c == '-' && win != stdscr)
break;
else if (c == '~')
{
strcpy(buf, home);
waddstr(win, home);
sp += strlen(home);
continue;
}
}
if (sp >= &buf[MAXINP] || !(isprint(c) || c == ' '))
putchar(CTRL('G'));
else
{
*sp++ = c;
waddstr(win, unctrol(c));
}
}
*sp = '\0';
if (sp > buf) /* only change option if something has been typed */
strucpy(opt, buf, strlen(buf));
wmove(win, oy, ox);
waddstr(win, opt);
waddch(win, '\n');
wrefresh(win);
if (win == stdscr)
mpos += sp - buf;
if (c == '-')
return MINUS;
else if (c == '\033' || c == '\007')
return QUIT;
else
return NORM;
}
#ifdef WIZARD
/*
* get_num:
* Get a numeric option
*/
get_num(opt, win)
short *opt;
WINDOW *win;
{
register int i;
char buf[MAXSTR];
if ((i = get_str(buf, win)) == NORM)
*opt = atoi(buf);
return i;
}
#endif
/*
* parse_opts:
* Parse options from string, usually taken from the environment.
* The string is a series of comma seperated values, with booleans
* being stated as "name" (true) or "noname" (false), and strings
* being "name=....", with the string being defined up to a comma
* or the end of the entire option string.
*/
parse_opts(str)
register char *str;
{
register char *sp;
register OPTION *op;
register int len;
while (*str)
{
/*
* Get option name
*/
for (sp = str; isalpha(*sp); sp++)
continue;
len = sp - str;
/*
* Look it up and deal with it
*/
for (op = optlist; op < &optlist[NUM_OPTS]; op++)
if (EQSTR(str, op->o_name, len))
{
if (op->o_putfunc == put_bool) /* if option is a boolean */
*(bool *)op->o_opt = TRUE;
else /* string option */
{
register char *start;
/*
* Skip to start of string value
*/
for (str = sp + 1; *str == '='; str++)
continue;
if (*str == '~')
{
strcpy((char *) op->o_opt, home);
start = (char *) op->o_opt + strlen(home);
while (*++str == '/')
continue;
}
else
start = (char *) op->o_opt;
/*
* Skip to end of string value
*/
for (sp = str + 1; *sp && *sp != ','; sp++)
continue;
strucpy(start, str, sp - str);
}
break;
}
/*
* check for "noname" for booleans
*/
else if (op->o_putfunc == put_bool
&& EQSTR(str, "no", 2) && EQSTR(str + 2, op->o_name, len - 2))
{
*(bool *)op->o_opt = FALSE;
break;
}
/*
* skip to start of next option name
*/
while (*sp && !isalpha(*sp))
sp++;
str = sp;
}
}
/*
* strucpy:
* Copy string using unctrol for things
*/
strucpy(s1, s2, len)
register char *s1, *s2;
register int len;
{
if (len > MAXINP)
len = MAXINP;
while (len--)
{
if (isprint(*s2) || *s2 == ' ')
*s1++ = *s2;
s2++;
}
*s1 = '\0';
}

421
rogue4/pack.c Normal file
View file

@ -0,0 +1,421 @@
/*
* Routines to deal with the pack
*
* @(#)pack.c 4.15 (Berkeley) 4/6/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <ctype.h>
#include "rogue.h"
/*
* update_mdest:
* Called after picking up an object, before discarding it.
* If this was the object of something's desire, that monster will
* get mad and run at the hero
*/
update_mdest(obj)
register THING *obj;
{
register THING *mp;
for (mp = mlist; mp != NULL; mp = next(mp))
if (mp->t_dest == &obj->o_pos)
mp->t_dest = &hero;
}
/*
* add_pack:
* Pick up an object and add it to the pack. If the argument is
* non-null use it as the linked_list pointer instead of gettting
* it off the ground.
*/
add_pack(obj, silent)
register THING *obj;
bool silent;
{
register THING *op, *lp = NULL;
register bool exact, from_floor;
register char floor;
int discarded = 0;
if (obj == NULL)
{
from_floor = TRUE;
if ((obj = find_obj(hero.y, hero.x)) == NULL)
return;
}
else
from_floor = FALSE;
/*
* Link it into the pack. Search the pack for a object of similar type
* if there isn't one, stuff it at the beginning, if there is, look for one
* that is exactly the same and just increment the count if there is.
* it that. Food is always put at the beginning for ease of access, but
* is not ordered so that you can't tell good food from bad. First check
* to see if there is something in thr same group and if there is then
* increment the count.
*/
/* floor = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR; */
if (proom) floor = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
else floor = FLOOR;
if (obj->o_group)
{
for (op = pack; op != NULL; op = next(op))
{
if (op->o_group == obj->o_group)
{
/*
* Put it in the pack and notify the user
*/
op->o_count++;
if (from_floor)
{
detach(lvl_obj, obj);
mvaddch(hero.y, hero.x, floor);
chat(hero.y, hero.x) = floor;
}
update_mdest(obj);
discard(obj);
obj = op;
discarded = 1;
goto picked_up;
}
}
}
/*
* Check if there is room
*/
if (inpack == MAXPACK-1)
{
msg("you can't carry anything else");
return;
}
/*
* Check for and deal with scare monster scrolls
*/
if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
if (obj->o_flags & ISFOUND)
{
detach(lvl_obj, obj);
mvaddch(hero.y, hero.x, floor);
chat(hero.y, hero.x) = floor;
msg("the scroll turns to dust as you pick it up");
return;
}
else
obj->o_flags |= ISFOUND;
inpack++;
if (from_floor)
{
detach(lvl_obj, obj);
mvaddch(hero.y, hero.x, floor);
chat(hero.y, hero.x) = floor;
}
/*
* Search for an object of the same type
*/
exact = FALSE;
for (op = pack; op != NULL; op = next(op))
if (obj->o_type == op->o_type)
break;
if (op == NULL)
{
/*
* Put it at the end of the pack since it is a new type
*/
for (op = pack; op != NULL; op = next(op))
{
if (op->o_type != FOOD)
break;
lp = op;
}
}
else
{
/*
* Search for an object which is exactly the same
*/
while (op->o_type == obj->o_type)
{
if (op->o_which == obj->o_which)
{
exact = TRUE;
break;
}
lp = op;
if ((op = next(op)) == NULL)
break;
}
}
if (op == NULL)
{
/*
* Didn't find an exact match, just stick it here
*/
if (pack == NULL)
pack = obj;
else
{
lp->l_next = obj;
obj->l_prev = lp;
obj->l_next = NULL;
}
}
else
{
/*
* If we found an exact match. If it is a potion, food, or a
* scroll, increase the count, otherwise put it with its clones.
*/
if (exact && ISMULT(obj->o_type))
{
op->o_count++;
update_mdest(obj);
discard(obj);
obj = op;
discarded = 1;
goto picked_up;
}
if ((obj->l_prev = prev(op)) != NULL)
obj->l_prev->l_next = obj;
else
pack = obj;
obj->l_next = op;
op->l_prev = obj;
}
picked_up:
/*
* If this was the object of something's desire, that monster will
* get mad and run at the hero
*/
if (!discarded)
update_mdest(obj);
if (obj->o_type == AMULET)
amulet = TRUE;
/*
* Notify the user
*/
if (!silent)
{
if (!terse)
addmsg("you now have ");
msg("%s (%c)", inv_name(obj, !terse), pack_char(obj));
}
}
/*
* inventory:
* List what is in the pack
*/
inventory(list, type)
THING *list;
int type;
{
register char ch;
register int n_objs;
char inv_temp[MAXSTR];
n_objs = 0;
for (ch = 'a'; list != NULL; ch++, list = next(list))
{
if (type && type != list->o_type && !(type == CALLABLE &&
(list->o_type == SCROLL || list->o_type == POTION ||
list->o_type == RING || list->o_type == STICK)))
continue;
n_objs++;
sprintf(inv_temp, "%c) %%s", ch);
add_line(inv_temp, inv_name(list, FALSE));
}
if (n_objs == 0)
{
if (terse)
msg(type == 0 ? "empty handed" :
"nothing appropriate");
else
msg(type == 0 ? "you are empty handed" :
"you don't have anything appropriate");
return FALSE;
}
end_line();
return TRUE;
}
/*
* pick_up:
* Add something to characters pack.
*/
pick_up(ch)
char ch;
{
register THING *obj, *mp;
switch (ch)
{
case GOLD:
if ((obj = find_obj(hero.y, hero.x)) == NULL)
return;
money(obj->o_goldval);
detach(lvl_obj, obj);
update_mdest(obj);
discard(obj);
proom->r_goldval = 0;
break;
default:
#ifdef WIZARD
debug("Where did you pick a '%s' up???", unctrol(ch));
#endif
case ARMOR:
case POTION:
case FOOD:
case WEAPON:
case SCROLL:
case AMULET:
case RING:
case STICK:
add_pack(NULL, FALSE);
break;
}
}
/*
* picky_inven:
* Allow player to inventory a single item
*/
picky_inven()
{
register THING *obj;
register char ch, mch;
if (pack == NULL)
msg("you aren't carrying anything");
else if (next(pack) == NULL)
msg("a) %s", inv_name(pack, FALSE));
else
{
msg(terse ? "item: " : "which item do you wish to inventory: ");
mpos = 0;
if ((mch = readchar()) == ESCAPE)
{
msg("");
return;
}
for (ch = 'a', obj = pack; obj != NULL; obj = next(obj), ch++)
if (ch == mch)
{
msg("%c) %s",ch,inv_name(obj, FALSE));
return;
}
if (!terse)
msg("'%s' not in pack", unctrol(mch));
msg("range is 'a' to '%c'", --ch);
}
}
/*
* get_item:
* Pick something out of a pack for a purpose
*/
THING *
get_item(purpose, type)
char *purpose;
int type;
{
register THING *obj;
register char ch, och;
if (pack == NULL)
msg("you aren't carrying anything");
else
{
for (;;)
{
if (!terse)
addmsg("which object do you want to ");
addmsg(purpose);
if (terse)
addmsg(" what");
msg("? (* for list): ");
ch = readchar();
mpos = 0;
/*
* Give the poor player a chance to abort the command
*/
if (ch == ESCAPE || ch == CTRL('G'))
{
after = FALSE;
msg("");
return NULL;
}
if (ch == '*')
{
mpos = 0;
if (inventory(pack, type) == 0)
{
after = FALSE;
return NULL;
}
continue;
}
for (obj = pack, och = 'a'; obj != NULL; obj = next(obj), och++)
if (ch == och)
break;
if (obj == NULL)
{
msg("please specify a letter between 'a' and '%c'", och-1);
continue;
}
else
return obj;
}
}
return NULL;
}
/*
* pack_char:
* Return which character would address a pack object
*/
pack_char(obj)
register THING *obj;
{
register THING *item;
register char c;
c = 'a';
for (item = pack; item != NULL; item = next(item))
if (item == obj)
return c;
else
c++;
return '?';
}
/*
* money:
* Add or subtract gold from the pack
*/
money(value)
register int value;
{
register char floor;
floor = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
purse += value;
mvaddch(hero.y, hero.x, floor);
chat(hero.y, hero.x) = floor;
if (value > 0)
{
if (!terse)
addmsg("you found ");
msg("%d gold pieces", value);
}
}

368
rogue4/passages.c Normal file
View file

@ -0,0 +1,368 @@
/*
* Draw the connecting passages
*
* @(#)passages.c 4.8 (Berkeley) 1/27/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include "rogue.h"
/*
* do_passages:
* Draw all the passages on a level.
*/
do_passages()
{
register struct rdes *r1, *r2 = NULL;
register int i, j;
register int roomcount;
static struct rdes
{
bool conn[MAXROOMS]; /* possible to connect to room i? */
bool isconn[MAXROOMS]; /* connection been made to room i? */
bool ingraph; /* this room in graph already? */
} rdes[MAXROOMS] = {
{ { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
};
/*
* reinitialize room graph description
*/
for (r1 = rdes; r1 <= &rdes[MAXROOMS-1]; r1++)
{
for (j = 0; j < MAXROOMS; j++)
r1->isconn[j] = FALSE;
r1->ingraph = FALSE;
}
/*
* starting with one room, connect it to a random adjacent room and
* then pick a new room to start with.
*/
roomcount = 1;
r1 = &rdes[rnd(MAXROOMS)];
r1->ingraph = TRUE;
do
{
/*
* find a room to connect with
*/
j = 0;
for (i = 0; i < MAXROOMS; i++)
if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0)
r2 = &rdes[i];
/*
* if no adjacent rooms are outside the graph, pick a new room
* to look from
*/
if (j == 0)
{
do
r1 = &rdes[rnd(MAXROOMS)];
until (r1->ingraph);
}
/*
* otherwise, connect new room to the graph, and draw a tunnel
* to it
*/
else
{
r2->ingraph = TRUE;
i = r1 - rdes;
j = r2 - rdes;
conn(i, j);
r1->isconn[j] = TRUE;
r2->isconn[i] = TRUE;
roomcount++;
}
} while (roomcount < MAXROOMS);
/*
* attempt to add passages to the graph a random number of times so
* that there isn't always just one unique passage through it.
*/
for (roomcount = rnd(5); roomcount > 0; roomcount--)
{
r1 = &rdes[rnd(MAXROOMS)]; /* a random room to look from */
/*
* find an adjacent room not already connected
*/
j = 0;
for (i = 0; i < MAXROOMS; i++)
if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0)
r2 = &rdes[i];
/*
* if there is one, connect it and look for the next added
* passage
*/
if (j != 0)
{
i = r1 - rdes;
j = r2 - rdes;
conn(i, j);
r1->isconn[j] = TRUE;
r2->isconn[i] = TRUE;
}
}
passnum();
}
/*
* conn:
* Draw a corridor from a room in a certain direction.
*/
conn(r1, r2)
int r1, r2;
{
register struct room *rpf, *rpt = NULL;
register char rmt;
register int distance = 0, turn_spot = 0, turn_distance = 0, index;
register int rm;
register char direc;
coord del = {0,0}, curr, turn_delta = {0,0}, spos = {0,0}, epos = {0,0};
if (r1 < r2)
{
rm = r1;
if (r1 + 1 == r2)
direc = 'r';
else
direc = 'd';
}
else
{
rm = r2;
if (r2 + 1 == r1)
direc = 'r';
else
direc = 'd';
}
rpf = &rooms[rm];
/*
* Set up the movement variables, in two cases:
* first drawing one down.
*/
if (direc == 'd')
{
rmt = rm + 3; /* room # of dest */
rpt = &rooms[rmt]; /* room pointer of dest */
del.x = 0; /* direction of move */
del.y = 1;
spos.x = rpf->r_pos.x; /* start of move */
spos.y = rpf->r_pos.y;
epos.x = rpt->r_pos.x; /* end of move */
epos.y = rpt->r_pos.y;
if (!(rpf->r_flags & ISGONE)) /* if not gone pick door pos */
{
spos.x += rnd(rpf->r_max.x - 2) + 1;
spos.y += rpf->r_max.y - 1;
}
if (!(rpt->r_flags & ISGONE))
epos.x += rnd(rpt->r_max.x - 2) + 1;
distance = abs(spos.y - epos.y) - 1; /* distance to move */
turn_delta.y = 0; /* direction to turn */
turn_delta.x = (spos.x < epos.x ? 1 : -1);
turn_distance = abs(spos.x - epos.x); /* how far to turn */
turn_spot = rnd(distance-1) + 1; /* where turn starts */
}
else if (direc == 'r') /* setup for moving right */
{
rmt = rm + 1;
rpt = &rooms[rmt];
del.x = 1;
del.y = 0;
spos.x = rpf->r_pos.x;
spos.y = rpf->r_pos.y;
epos.x = rpt->r_pos.x;
epos.y = rpt->r_pos.y;
if (!(rpf->r_flags & ISGONE))
{
spos.x += rpf->r_max.x-1;
spos.y += rnd(rpf->r_max.y-2)+1;
}
if (!(rpt->r_flags & ISGONE))
epos.y += rnd(rpt->r_max.y-2)+1;
distance = abs(spos.x - epos.x) - 1;
turn_delta.y = (spos.y < epos.y ? 1 : -1);
turn_delta.x = 0;
turn_distance = abs(spos.y - epos.y);
turn_spot = rnd(distance-1) + 1;
}
#ifdef WIZARD
else
debug("error in connection tables");
#endif
/*
* Draw in the doors on either side of the passage or just put #'s
* if the rooms are gone.
*/
if (!(rpf->r_flags & ISGONE))
door(rpf, &spos);
else
{
index = INDEX(spos.y, spos.x);
_level[index] = PASSAGE;
_flags[index] |= F_PASS;
}
if (!(rpt->r_flags & ISGONE))
door(rpt, &epos);
else
{
index = INDEX(epos.y, epos.x);
_level[index] = PASSAGE;
_flags[index] |= F_PASS;
}
/*
* Get ready to move...
*/
curr.x = spos.x;
curr.y = spos.y;
while (distance)
{
/*
* Move to new position
*/
curr.x += del.x;
curr.y += del.y;
/*
* Check if we are at the turn place, if so do the turn
*/
if (distance == turn_spot)
while (turn_distance--)
{
index = INDEX(curr.y, curr.x);
_level[index] = PASSAGE;
_flags[index] |= F_PASS;
curr.x += turn_delta.x;
curr.y += turn_delta.y;
}
/*
* Continue digging along
*/
index = INDEX(curr.y, curr.x);
_level[index] = PASSAGE;
_flags[index] |= F_PASS;
distance--;
}
curr.x += del.x;
curr.y += del.y;
if (!ce(curr, epos))
msg("warning, connectivity problem on this level");
}
/*
* door:
* Add a door or possibly a secret door. Also enters the door in
* the exits array of the room.
*/
door(rm, cp)
register struct room *rm;
register coord *cp;
{
register int index;
index = INDEX(cp->y, cp->x);
if (rnd(10) + 1 < level && rnd(5) == 0)
{
_level[index] = (cp->y == rm->r_pos.y || cp->y == rm->r_pos.y + rm->r_max.y - 1) ? '-' : '|';
_flags[index] &= ~F_REAL;
}
else
_level[index] = DOOR;
rm->r_exit[rm->r_nexits++] = *cp;
}
#ifdef WIZARD
/*
* add_pass:
* Add the passages to the current window (wizard command)
*/
add_pass()
{
register int y, x, ch;
for (y = 1; y < LINES - 1; y++)
for (x = 0; x < COLS; x++)
if ((ch = chat(y, x)) == DOOR || ch == PASSAGE)
mvaddch(y, x, ch);
}
#endif
/*
* passnum:
* Assign a number to each passageway
*/
static int pnum;
static bool newpnum;
passnum()
{
register struct room *rp;
register int i;
pnum = 0;
newpnum = FALSE;
for (rp = passages; rp < &passages[MAXPASS]; rp++)
rp->r_nexits = 0;
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
for (i = 0; i < rp->r_nexits; i++)
{
newpnum++;
numpass(rp->r_exit[i].y, rp->r_exit[i].x);
}
}
/*
* numpass:
* Number a passageway square and its brethren
*/
numpass(y, x)
register int y, x;
{
register char *fp;
register struct room *rp;
register char ch;
fp = &flat(y, x);
if (*fp & F_PNUM)
return;
if (newpnum)
{
pnum++;
newpnum = FALSE;
}
/*
* check to see if it is a door or secret door, i.e., a new exit,
* or a numerable type of place
*/
if ((ch = chat(y, x)) == DOOR || (!(*fp & F_REAL) && ch != FLOOR))
{
rp = &passages[pnum];
rp->r_exit[rp->r_nexits].y = y;
rp->r_exit[rp->r_nexits++].x = x;
}
else if (!(*fp & F_PASS))
return;
*fp |= pnum;
/*
* recurse on the surrounding places
*/
numpass(y + 1, x);
numpass(y - 1, x);
numpass(y, x + 1);
numpass(y, x - 1);
}

256
rogue4/potions.c Normal file
View file

@ -0,0 +1,256 @@
/*
* Function(s) for dealing with potions
*
* @(#)potions.c 4.24 (Berkeley) 4/6/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include "rogue.h"
/*
* quaff:
* Quaff a potion from the pack
*/
quaff()
{
register THING *obj, *th;
register bool discardit = FALSE;
obj = get_item("quaff", POTION);
/*
* Make certain that it is somethings that we want to drink
*/
if (obj == NULL)
return;
if (obj->o_type != POTION)
{
if (!terse)
msg("yuk! Why would you want to drink that?");
else
msg("that's undrinkable");
return;
}
if (obj == cur_weapon)
cur_weapon = NULL;
/*
* Calculate the effect it has on the poor guy.
*/
switch (obj->o_which)
{
case P_CONFUSE:
p_know[P_CONFUSE] = TRUE;
if (!on(player, ISHUH))
{
if (on(player, ISHUH))
lengthen(unconfuse, rnd(8)+HUHDURATION);
else
fuse(unconfuse, 0, rnd(8)+HUHDURATION, AFTER);
player.t_flags |= ISHUH;
msg("wait, what's going on here. Huh? What? Who?");
}
when P_POISON:
p_know[P_POISON] = TRUE;
if (!ISWEARING(R_SUSTSTR))
{
chg_str(-(rnd(3)+1));
msg("you feel very sick now");
}
else
msg("you feel momentarily sick");
when P_HEALING:
p_know[P_HEALING] = TRUE;
if ((pstats.s_hpt += roll(pstats.s_lvl, 4)) > max_hp)
pstats.s_hpt = ++max_hp;
sight();
msg("you begin to feel better");
when P_STRENGTH:
p_know[P_STRENGTH] = TRUE;
chg_str(1);
msg("you feel stronger, now. What bulging muscles!");
when P_MFIND:
player.t_flags |= SEEMONST;
fuse(turn_see, TRUE, HUHDURATION, AFTER);
if (mlist == NULL)
msg("you have a strange feeling for a moment");
else
p_know[P_MFIND] |= turn_see(FALSE);
when P_TFIND:
/*
* Potion of magic detection. Show the potions and scrolls
*/
if (lvl_obj != NULL)
{
register THING *tp;
register bool show;
show = FALSE;
wclear(hw);
for (tp = lvl_obj; tp != NULL; tp = next(tp))
{
if (is_magic(tp))
{
show = TRUE;
mvwaddch(hw, tp->o_pos.y, tp->o_pos.x, MAGIC);
p_know[P_TFIND] = TRUE;
}
}
for (th = mlist; th != NULL; th = next(th))
{
for (tp = th->t_pack; tp != NULL; tp = next(tp))
{
if (is_magic(tp))
{
show = TRUE;
mvwaddch(hw, th->t_pos.y, th->t_pos.x, MAGIC);
p_know[P_TFIND] = TRUE;
}
}
}
if (show)
{
show_win(hw,
"You sense the presence of magic on this level.--More--");
break;
}
}
msg("you have a strange feeling for a moment, then it passes");
when P_PARALYZE:
p_know[P_PARALYZE] = TRUE;
no_command = HOLDTIME;
player.t_flags &= ~ISRUN;
msg("you can't move");
when P_SEEINVIS:
if (!on(player, CANSEE))
{
fuse(unsee, 0, SEEDURATION, AFTER);
look(FALSE);
invis_on();
}
sight();
msg("this potion tastes like %s juice", fruit);
when P_RAISE:
p_know[P_RAISE] = TRUE;
msg("you suddenly feel much more skillful");
raise_level();
when P_XHEAL:
p_know[P_XHEAL] = TRUE;
if ((pstats.s_hpt += roll(pstats.s_lvl, 8)) > max_hp)
{
if (pstats.s_hpt > max_hp + pstats.s_lvl + 1)
++max_hp;
pstats.s_hpt = ++max_hp;
}
sight();
msg("you begin to feel much better");
when P_HASTE:
p_know[P_HASTE] = TRUE;
if (add_haste(TRUE))
msg("you feel yourself moving much faster");
when P_RESTORE:
if (ISRING(LEFT, R_ADDSTR))
add_str(&pstats.s_str, -cur_ring[LEFT]->o_ac);
if (ISRING(RIGHT, R_ADDSTR))
add_str(&pstats.s_str, -cur_ring[RIGHT]->o_ac);
if (pstats.s_str < max_stats.s_str)
pstats.s_str = max_stats.s_str;
if (ISRING(LEFT, R_ADDSTR))
add_str(&pstats.s_str, cur_ring[LEFT]->o_ac);
if (ISRING(RIGHT, R_ADDSTR))
add_str(&pstats.s_str, cur_ring[RIGHT]->o_ac);
msg("hey, this tastes great. It make you feel warm all over");
when P_BLIND:
p_know[P_BLIND] = TRUE;
if (!on(player, ISBLIND))
{
player.t_flags |= ISBLIND;
fuse(sight, 0, SEEDURATION, AFTER);
look(FALSE);
}
msg("a cloak of darkness falls around you");
when P_NOP:
msg("this potion tastes extremely dull");
otherwise:
msg("what an odd tasting potion!");
return;
}
status();
/*
* Throw the item away
*/
inpack--;
if (obj->o_count > 1)
obj->o_count--;
else
{
detach(pack, obj);
discardit = TRUE;
}
call_it(p_know[obj->o_which], &p_guess[obj->o_which]);
if (discardit)
discard(obj);
}
/*
* invis_on:
* Turn on the ability to see invisible
*/
invis_on()
{
register THING *th;
player.t_flags |= CANSEE;
for (th = mlist; th != NULL; th = next(th))
if (on(*th, ISINVIS) && see_monst(th))
{
move(th->t_pos.y, th->t_pos.x);
addch(th->t_disguise);
}
}
/*
* see_monst:
* Put on or off seeing monsters on this level
*/
turn_see(turn_off)
register bool turn_off;
{
register THING *mp;
register bool can_see, add_new;
add_new = FALSE;
for (mp = mlist; mp != NULL; mp = next(mp))
{
move(mp->t_pos.y, mp->t_pos.x);
can_see = (see_monst(mp) || inch() == (unsigned char)mp->t_type);
if (turn_off)
{
if (!can_see)
addch(mp->t_oldch);
}
else
{
if (!can_see)
standout();
addch(mp->t_type);
if (!can_see)
{
standend();
add_new++;
}
}
}
if (turn_off)
player.t_flags &= ~SEEMONST;
else
player.t_flags |= SEEMONST;
return add_new;
}

96
rogue4/prob.c Normal file
View file

@ -0,0 +1,96 @@
/*
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
# include <curses.h>
# include "rogue.h"
# undef max
# define TRIES 10000
static char *sccsid = "@(#)prob.c 1.3 (Berkeley) 12/17/81";
main(ac, av)
int ac;
char **av;
{
register unsigned int prob, prob2, exp;
register struct monster *mp;
register unsigned int max, min, i;
register unsigned int max2, min2;
printf("%17.17s ----experience--- ----hit points---\n", "");
printf("%17.17s %7s %4s %4s %7s %4s %4s lvl\n", "monster", "avg", "min", "max", "avg", "min", "max", "max hp");
seed = 0;
for (mp = monsters; mp < &monsters[26]; mp++) {
i = TRIES;
prob2 = prob = 0;
min2 = min = 30000;
max2 = max = 0;
while (i--) {
if ((exp = roll(mp->m_stats.s_lvl, 8)) < min2)
min2 = exp;
if (exp > max2)
max2 = exp;
prob2 += exp;
mp->m_stats.s_maxhp = exp;
if ((exp = mp->m_stats.s_exp + exp_add(mp)) < min)
min = exp;
if (exp > max)
max = exp;
prob += exp;
}
printf("%17.17s: %7.2f %4d %4d %7.2f %4d %4d %3d\n", mp->m_name, ((double) prob) / TRIES, min, max, ((double) prob2) / TRIES, min2, max2, mp->m_stats.s_lvl);
fflush(stdout);
}
}
exp_add(mp)
register struct monster *mp;
{
register unsigned int mod;
if (mp->m_stats.s_lvl == 1)
mod = mp->m_stats.s_maxhp / 8;
else
mod = mp->m_stats.s_maxhp / 6;
if (mp->m_stats.s_lvl > 9)
mod *= 20;
else if (mp->m_stats.s_lvl > 6)
mod *= 4;
return mod;
}
/*
* roll:
* roll a number of dice
*/
roll(number, sides)
register unsigned int number, sides;
{
register unsigned int dtotal = 0;
dtotal = number;
while (number--)
dtotal += rnd(sides);
return dtotal;
}
/*
* rnd:
* Pick a very random number.
*/
rnd(range)
register unsigned int range;
{
return RN % range;
}

208
rogue4/rings.c Normal file
View file

@ -0,0 +1,208 @@
/*
* Routines dealing specifically with rings
*
* @(#)rings.c 4.13 (Berkeley) 1/28/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <string.h>
#include "rogue.h"
/*
* ring_on:
* Put a ring on a hand
*/
ring_on()
{
register THING *obj;
register int ring;
obj = get_item("put on", RING);
/*
* Make certain that it is somethings that we want to wear
*/
if (obj == NULL)
return;
if (obj->o_type != RING)
{
if (!terse)
msg("it would be difficult to wrap that around a finger");
else
msg("not a ring");
return;
}
/*
* find out which hand to put it on
*/
if (is_current(obj))
return;
if (cur_ring[LEFT] == NULL && cur_ring[RIGHT] == NULL)
{
if ((ring = gethand()) < 0)
return;
}
else if (cur_ring[LEFT] == NULL)
ring = LEFT;
else if (cur_ring[RIGHT] == NULL)
ring = RIGHT;
else
{
if (!terse)
msg("you already have a ring on each hand");
else
msg("wearing two");
return;
}
cur_ring[ring] = obj;
/*
* Calculate the effect it has on the poor guy.
*/
switch (obj->o_which)
{
case R_ADDSTR:
chg_str(obj->o_ac);
break;
case R_SEEINVIS:
invis_on();
break;
case R_AGGR:
aggravate();
break;
}
if (!terse)
addmsg("you are now wearing ");
msg("%s (%c)", inv_name(obj, TRUE), pack_char(obj));
}
/*
* ring_off:
* Take off a ring
*/
ring_off()
{
register int ring;
register THING *obj;
register char packchar;
if (cur_ring[LEFT] == NULL && cur_ring[RIGHT] == NULL)
{
if (terse)
msg("no rings");
else
msg("you aren't wearing any rings");
return;
}
else if (cur_ring[LEFT] == NULL)
ring = RIGHT;
else if (cur_ring[RIGHT] == NULL)
ring = LEFT;
else
if ((ring = gethand()) < 0)
return;
mpos = 0;
obj = cur_ring[ring];
if (obj == NULL)
{
msg("not wearing such a ring");
return;
}
packchar = pack_char(obj);
if (dropcheck(obj))
msg("was wearing %s(%c)", inv_name(obj, TRUE), packchar);
}
/*
* gethand:
* Which hand is the hero interested in?
*/
gethand()
{
register int c;
for (;;)
{
if (terse)
msg("left or right ring? ");
else
msg("left hand or right hand? ");
if ((c = readchar()) == ESCAPE)
return -1;
mpos = 0;
if (c == 'l' || c == 'L')
return LEFT;
else if (c == 'r' || c == 'R')
return RIGHT;
if (terse)
msg("L or R");
else
msg("please type L or R");
}
}
/*
* ring_eat:
* How much food does this ring use up?
*/
ring_eat(hand)
register int hand;
{
if (cur_ring[hand] == NULL)
return 0;
switch (cur_ring[hand]->o_which)
{
case R_REGEN:
return 2;
case R_SUSTSTR:
case R_SUSTARM:
case R_PROTECT:
case R_ADDSTR:
case R_STEALTH:
return 1;
case R_SEARCH:
case R_ADDHIT:
case R_ADDDAM:
return (rnd(3) == 0);
case R_DIGEST:
return -rnd(2);
case R_SEEINVIS:
return (rnd(5) == 0);
default:
return 0;
}
}
/*
* ring_num:
* Print ring bonuses
*/
char *
ring_num(obj)
register THING *obj;
{
static char buf[5];
if (!(obj->o_flags & ISKNOW))
return "";
switch (obj->o_which)
{
case R_PROTECT:
case R_ADDSTR:
case R_ADDDAM:
case R_ADDHIT:
buf[0] = ' ';
strcpy(&buf[1], num(obj->o_ac, 0, RING));
otherwise:
return "";
}
return buf;
}

433
rogue4/rip.c Normal file
View file

@ -0,0 +1,433 @@
/*
* File for the fun ends
* Death or a total win
*
* @(#)rip.c 4.28 (Berkeley) 4/12/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include "rogue.h"
static char *rip[] = {
" __________",
" / \\",
" / REST \\",
" / IN \\",
" / PEACE \\",
" / \\",
" | |",
" | |",
" | killed by a |",
" | |",
" | 1980 |",
" *| * * * | *",
" ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______",
0
};
/*
* score:
* Figure score and post it.
*/
/* VARARGS2 */
score(amount, flags, monst)
int amount, flags;
char monst;
{
register struct sc_ent *scp;
register int i;
register struct sc_ent *sc2;
register FILE *outf;
register int prflags = 0;
register void (*fp)(int);
register int uid;
char scoreline[MAXSTR + 100];
static struct sc_ent {
char sc_name[MAXSTR];
unsigned int sc_flags;
unsigned int sc_uid;
unsigned short sc_monster;
unsigned short sc_score;
unsigned short sc_level;
} top_ten[10];
static char *reason[] = {
"killed",
"quit",
"A total winner",
};
void endit();
start_score();
if (fd >= 0)
outf = md_fdopen(fd, "wb");
else
return;
for (scp = top_ten; scp <= &top_ten[9]; scp++)
{
scp->sc_score = 0;
for (i = 0; i < MAXSTR; i++)
scp->sc_name[i] = rnd(255);
scp->sc_flags = RN;
scp->sc_level = RN;
scp->sc_monster = RN;
scp->sc_uid = RN;
}
signal(SIGINT, SIG_DFL);
if (flags != -1
#ifdef WIZARD
|| wizard
#endif
)
{
mvaddstr(LINES - 1, 0 , "[Press return to continue]");
refresh();
wgetnstr(stdscr,prbuf,80);
move(LINES - 1, 0);
clrtoeol();
refresh();
endwin();
}
#ifdef WIZARD
if (wizard)
if (strcmp(prbuf, "names") == 0)
prflags = 1;
else if (strcmp(prbuf, "edit") == 0)
prflags = 2;
#endif
for(i=0; i<10; i++)
{
encread((char *) &top_ten[i].sc_name, MAXSTR, fd);
scoreline[0] = '\0';
encread((char *) scoreline, 100, fd);
sscanf(scoreline, "%d %d %hd %hd %hd", &top_ten[i].sc_flags,
&top_ten[i].sc_uid, &top_ten[i].sc_monster, &top_ten[i].sc_score,
&top_ten[i].sc_level);
}
/*
* Insert her in list if need be
*/
sc2 = NULL;
if (!noscore)
{
uid = md_getuid();
for (scp = top_ten; scp <= &top_ten[9]; scp++)
if (amount > scp->sc_score)
break;
#ifdef LIMIT_TOPTEN
else if (flags != 2 && scp->sc_uid == uid && scp->sc_flags != 2)
scp = &top_ten[9] + 1; /* only one score per nowin uid */
#endif
if (scp <= &top_ten[9])
{
#ifdef LIMIT_TOPTEN
if (flags != 2)
for (sc2 = scp; sc2 <= &top_ten[9]; sc2++)
{
if (sc2->sc_uid == uid && sc2->sc_flags != 2)
break;
}
else
#endif
sc2 = &top_ten[9];
while (sc2 > scp)
{
*sc2 = sc2[-1];
sc2--;
}
scp->sc_score = amount;
strncpy(scp->sc_name, whoami, MAXSTR);
scp->sc_flags = flags;
if (flags == 2)
scp->sc_level = max_level;
else
scp->sc_level = level;
scp->sc_monster = monst;
scp->sc_uid = uid;
sc2 = scp;
}
}
/*
* Print the list
*/
printf("Top Ten Rogueists:\nRank\tScore\tName\n");
for (scp = top_ten; scp <= &top_ten[9]; scp++)
{
if (scp->sc_score) {
printf("%d\t%d\t%s: %s on level %d", scp - top_ten + 1,
scp->sc_score, scp->sc_name, reason[scp->sc_flags],
scp->sc_level);
if (scp->sc_flags == 0)
printf(" by %s", killname((char) scp->sc_monster, TRUE));
if (prflags == 1)
{
char *name;
name = md_getusername(scp->sc_uid);
if (name == NULL)
printf(" (%d)", scp->sc_uid);
else
printf(" (%s)", name);
putchar('\n');
}
else if (prflags == 2)
{
fflush(stdout);
fgets(prbuf,80,stdin);
if (prbuf[0] == 'd')
{
for (sc2 = scp; sc2 < &top_ten[9]; sc2++)
*sc2 = *(sc2 + 1);
top_ten[9].sc_score = 0;
for (i = 0; i < MAXSTR; i++)
top_ten[9].sc_name[i] = rnd(255);
top_ten[9].sc_flags = RN;
top_ten[9].sc_level = RN;
top_ten[9].sc_monster = RN;
scp--;
}
}
else
printf(".\n");
}
else
break;
}
fseek(outf, 0L, 0);
/*
* Update the list file
*/
if (sc2 != NULL)
{
if (lock_sc())
{
int i;
fp = signal(SIGINT, SIG_IGN);
for(i=0; i<10; i++)
{
encwrite((char *) &top_ten[i].sc_name, MAXSTR, outf);
sprintf(scoreline," %d %d %hd %hd %hd \n",
top_ten[i].sc_flags, top_ten[i].sc_uid,
top_ten[i].sc_monster, top_ten[i].sc_score,
top_ten[i].sc_level);
encwrite((char *) scoreline, 100, outf);
}
unlock_sc();
signal(SIGINT, fp);
}
}
fclose(outf);
}
/*
* death:
* Do something really fun when he dies
*/
death(monst)
register char monst;
{
register char **dp = rip, *killer;
register struct tm *lt;
time_t date;
char buf[MAXSTR];
struct tm *localtime();
signal(SIGINT, SIG_IGN);
purse -= purse / 10;
signal(SIGINT, leave);
time(&date);
lt = localtime(&date);
clear();
move(8, 0);
while (*dp)
printw("%s\n", *dp++);
mvaddstr(14, 28-((strlen(whoami)+1)/2), whoami);
sprintf(buf, "%d Au", purse);
mvaddstr(15, 28-((strlen(buf)+1)/2), buf);
killer = killname(monst, FALSE);
mvaddstr(17, 28-((strlen(killer)+1)/2), killer);
if (monst == 's')
mvaddch(16, 32, ' ');
else
mvaddstr(16, 33, vowelstr(killer));
sprintf(prbuf, "%2d", 1900+lt->tm_year);
mvaddstr(18, 26, prbuf);
move(LINES-1, 0);
refresh();
score(purse, 0, monst);
exit(0);
}
/*
* total_winner:
* Code for a winner
*/
total_winner()
{
register THING *obj;
register int worth = 0;
register char c;
register int oldpurse;
clear();
standout();
addstr(" \n");
addstr(" @ @ @ @ @ @@@ @ @ \n");
addstr(" @ @ @@ @@ @ @ @ @ \n");
addstr(" @ @ @@@ @ @ @ @ @ @@@ @@@@ @@@ @ @@@ @ \n");
addstr(" @@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ \n");
addstr(" @ @ @ @ @ @ @ @@@@ @ @ @@@@@ @ @ @ \n");
addstr(" @ @ @ @ @ @@ @ @ @ @ @ @ @ @ @ @ \n");
addstr(" @@@ @@@ @@ @ @ @ @@@@ @@@@ @@@ @@@ @@ @ \n");
addstr(" \n");
addstr(" Congratulations, you have made it to the light of day! \n");
standend();
addstr("\nYou have joined the elite ranks of those who have escaped the\n");
addstr("Dungeons of Doom alive. You journey home and sell all your loot at\n");
addstr("a great profit and are admitted to the fighters guild.\n");
mvaddstr(LINES - 1, 0, "--Press space to continue--");
refresh();
wait_for(' ');
clear();
mvaddstr(0, 0, " Worth Item");
oldpurse = purse;
for (c = 'a', obj = pack; obj != NULL; c++, obj = next(obj))
{
switch (obj->o_type)
{
case FOOD:
worth = 2 * obj->o_count;
when WEAPON:
switch (obj->o_which)
{
case MACE: worth = 8;
when SWORD: worth = 15;
when CROSSBOW: worth = 30;
when ARROW: worth = 1;
when DAGGER: worth = 2;
when TWOSWORD: worth = 75;
when DART: worth = 1;
when BOW: worth = 15;
when BOLT: worth = 1;
when SPEAR: worth = 5;
}
worth *= 3 * (obj->o_hplus + obj->o_dplus) + obj->o_count;
obj->o_flags |= ISKNOW;
when ARMOR:
switch (obj->o_which)
{
case LEATHER: worth = 20;
when RING_MAIL: worth = 25;
when STUDDED_LEATHER: worth = 20;
when SCALE_MAIL: worth = 30;
when CHAIN_MAIL: worth = 75;
when SPLINT_MAIL: worth = 80;
when BANDED_MAIL: worth = 90;
when PLATE_MAIL: worth = 150;
}
worth += (9 - obj->o_ac) * 100;
worth += (10 * (a_class[obj->o_which] - obj->o_ac));
obj->o_flags |= ISKNOW;
when SCROLL:
worth = s_magic[obj->o_which].mi_worth;
worth *= obj->o_count;
if (!s_know[obj->o_which])
worth /= 2;
s_know[obj->o_which] = TRUE;
when POTION:
worth = p_magic[obj->o_which].mi_worth;
worth *= obj->o_count;
if (!p_know[obj->o_which])
worth /= 2;
p_know[obj->o_which] = TRUE;
when RING:
worth = r_magic[obj->o_which].mi_worth;
if (obj->o_which == R_ADDSTR || obj->o_which == R_ADDDAM ||
obj->o_which == R_PROTECT || obj->o_which == R_ADDHIT)
if (obj->o_ac > 0)
worth += obj->o_ac * 100;
else
worth = 10;
if (!(obj->o_flags & ISKNOW))
worth /= 2;
obj->o_flags |= ISKNOW;
r_know[obj->o_which] = TRUE;
when STICK:
worth = ws_magic[obj->o_which].mi_worth;
worth += 20 * obj->o_charges;
if (!(obj->o_flags & ISKNOW))
worth /= 2;
obj->o_flags |= ISKNOW;
ws_know[obj->o_which] = TRUE;
when AMULET:
worth = 1000;
}
if (worth < 0)
worth = 0;
mvprintw(c - 'a' + 1, 0, "%c) %5d %s", c, worth, inv_name(obj, FALSE));
purse += worth;
}
mvprintw(c - 'a' + 1, 0," %5d Gold Pieces ", oldpurse);
refresh();
score(purse, 2, 0);
exit(0);
}
/*
* killname:
* Convert a code to a monster name
*/
char *
killname(monst, doart)
register char monst;
bool doart;
{
register const char *sp;
register bool article;
sp = prbuf;
article = TRUE;
switch (monst)
{
case 'a':
sp = "arrow";
when 'b':
sp = "bolt";
when 'd':
sp = "dart";
when 's':
sp = "starvation";
article = FALSE;
otherwise:
if (monst >= 'A' && monst <= 'Z')
sp = monsters[monst-'A'].m_name;
else
{
sp = "God";
article = FALSE;
}
}
if (doart && article)
sprintf(prbuf, "a%s ", vowelstr(sp));
else
prbuf[0] = '\0';
strcat(prbuf, sp);
return prbuf;
}

67
rogue4/rogue.6 Normal file
View file

@ -0,0 +1,67 @@
.TH ROGUE 6 "1 April 1981"
.UC 4
.SH NAME
rogue \- Exploring The Dungeons of Doom
.SH SYNOPSIS
.B rogue
[
.I save_file
]
.SH DESCRIPTION
.PP
.I Rogue
is a computer fantasy game with a new twist. It is crt oriented and the
object of the game is to survive the attacks of various monsters and get
a lot of gold, rather than the puzzle solving orientation of most computer
fantasy games.
.PP
To get started you really only need to know two commands. The command
.B ?
will give you a list of the available commands and the command
.B /
will identify the things you see on the screen.
.PP
To win the game (as opposed to merely playing to beat other people high
scores) you must locate the Amulet of Yendor which is somewhere below
the 20th level of the dungeon and get it out. Nobody has achieved this
yet and if somebody does, they will probably go down in history as a hero
among heros.
.PP
When the game ends, either by your death, when you quit, or if you (by
some miracle) manage to win,
.I rogue
will give you alist of the top-ten scorers. The scoring is based entirely
upon how much gold you get. There is a 10% penalty for getting yourself
killed.
.PP
For more detailed directions, read the document
.I "A Guide to the Dungeons of Doom."
.SH FILES
.DT
.B Score file is searched for in these directories:
.PP
$ROGUEHOME/rogue52.scr
.br
/var/games/roguelike/rogue52.scr
.br
/var/lib/roguelike/rogue52.scr
.br
/var/roguelike/rogue52.scr
.br
/usr/games/lib/rogue52.scr
.br
/games/roguelik/rogue52.scr
.br
rogue52.scr
.PP
.B Default save file
.PP
~/rogue.sav
.SH SEE ALSO
Michael C. Toy,
.I "A guide to the Dungeons of Doom"
.SH BUGS
.PP
Probably infinite. Currently known bugs are: Sometimes you are still hungry
even after you eat food and sometimes you get a monster on the screen in
reverse video which may or may not cause a core dump.

486
rogue4/rogue.h Normal file
View file

@ -0,0 +1,486 @@
/*
* Rogue definitions and variable declarations
*
* @(#)rogue.h 5.2 (Berkeley) 5/10/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
typedef struct {
const char *st_name;
const int st_value;
} STONE;
extern const char *rainbow[];
extern const STONE stones[];
extern const char *sylls[];
extern const char *wood[];
extern const char *metal[];
#define NCOLORS 27
#define NSYLLS 159
#define NSTONES 26
#define NWOOD 33
#define NMETAL 22
/*
* Maximum number of different things
*/
#define MAXDAEMONS 20
#define MAXROOMS 9
#define MAXTHINGS 9
#define MAXOBJ 9
#define MAXPACK 23
#define MAXTRAPS 10
#define AMULETLEVEL 26
#define NUMTHINGS 7 /* number of types of things */
#define MAXPASS 13 /* upper limit on number of passages */
/*
* return values for get functions
*/
#define NORM 0 /* normal exit */
#define QUIT 1 /* quit option setting */
#define MINUS 2 /* back up one option */
/*
* All the fun defines
*/
#define shint char /* short integer (for very small #s) */
#define when break;case
#define otherwise break;default
#define until(expr) while(!(expr))
#define next(ptr) (*ptr).l_next
#define prev(ptr) (*ptr).l_prev
#define winat(y,x) (moat(y,x) != NULL ? moat(y,x)->t_disguise : chat(y,x))
#define DISTANCE(y1, x1, y2, x2) ((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1))
#define ce(a,b) ((a).x == (b).x && (a).y == (b).y)
#define hero player.t_pos
#define pstats player.t_stats
#define pack player.t_pack
#define proom player.t_room
#define max_hp player.t_stats.s_maxhp
#define attach(a,b) _attach(&a,b)
#define detach(a,b) _detach(&a,b)
#define free_list(a) _free_list(&a)
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
#define on(thing,flag) (((thing).t_flags & (flag)) != 0)
#undef CTRL
#define CTRL(ch) (ch & 037)
#define GOLDCALC (rnd(50 + 10 * level) + 2)
#define ISRING(h,r) (cur_ring[h] != NULL && cur_ring[h]->o_which == r)
#define ISWEARING(r) (ISRING(LEFT, r) || ISRING(RIGHT, r))
#define ISMULT(type) (type==POTION || type==SCROLL || type==FOOD || type==GOLD)
#define INDEX(y,x) (((x) << 5) + (y))
#define chat(y,x) (_level[((x) << 5) + (y)])
#define flat(y,x) (_flags[((x) << 5) + (y)])
#define moat(y,x) (_monst[((x) << 5) + (y)])
#define unc(cp) (cp).y, (cp).x
#ifdef WIZARD
#define debug if (wizard) msg
#endif
/*
* Things that appear on the screens
*/
#define PASSAGE '#'
#define DOOR '+'
#define FLOOR '.'
#define PLAYER '@'
#define TRAP '^'
#define STAIRS '%'
#define GOLD '*'
#define POTION '!'
#define SCROLL '?'
#define MAGIC '$'
#define FOOD ':'
#define WEAPON ')'
#define ARMOR ']'
#define AMULET ','
#define RING '='
#define STICK '/'
#define CALLABLE -1
/*
* Various constants
*/
#define PASSWD "mTuZ7WUV9RWkQ"
#define BEARTIME spread(3)
#define SLEEPTIME spread(5)
#define HEALTIME spread(30)
#define HOLDTIME spread(2)
#define WANDERTIME spread(70)
#define BEFORE spread(1)
#define AFTER spread(2)
#define HUHDURATION spread(20)
#define SEEDURATION spread(850)
#define HUNGERTIME spread(1300)
#define MORETIME 150
#define STOMACHSIZE 2000
#define STARVETIME 850
#define ESCAPE 27
#define LEFT 0
#define RIGHT 1
#define BOLT_LENGTH 6
#define LAMPDIST 3
/*
* Save against things
*/
#define VS_POISON 00
#define VS_PARALYZATION 00
#define VS_DEATH 00
#define VS_BREATH 02
#define VS_MAGIC 03
/*
* Various flag bits
*/
/* flags for rooms */
#define ISDARK 0000001 /* room is dark */
#define ISGONE 0000002 /* room is gone (a corridor) */
/* flags for objects */
#define ISCURSED 000001 /* object is cursed */
#define ISKNOW 0000002 /* player knows details about the object */
#define ISMISL 0000004 /* object is a missile type */
#define ISMANY 0000010 /* object comes in groups */
/* flags for creatures */
#define CANHUH 0000001 /* creature can confuse */
#define CANSEE 0000002 /* creature can see invisible creatures */
#define ISBLIND 0000004 /* creature is blind */
#define ISCANC 0000010 /* creature has special qualities cancelled */
#define ISFOUND 0000020 /* creature has been seen (used for objects) */
#define ISGREED 0000040 /* creature runs to protect gold */
#define ISHASTE 0000100 /* creature has been hastened */
#define ISHELD 0000400 /* creature has been held */
#define ISHUH 0001000 /* creature is confused */
#define ISINVIS 0002000 /* creature is invisible */
#define ISMEAN 0004000 /* creature can wake when player enters room */
#define ISREGEN 0010000 /* creature can regenerate */
#define ISRUN 0020000 /* creature is running at the player */
#define SEEMONST 040000 /* hero can detect unseen monsters */
#define ISSLOW 0100000 /* creature has been slowed */
/*
* Flags for level map
*/
#define F_PASS 0x80 /* is a passageway */
#define F_SEEN 0x40 /* have seen this corridor before */
#define F_DROPPED 0x20 /* object was dropped here */
#define F_LOCKED 0x20 /* door is locked */
#define F_REAL 0x10 /* what you see is what you get */
#define F_PNUM 0x0f /* passage number mask */
#define F_TMASK 0x07 /* trap number mask */
/*
* Trap types
*/
#define T_DOOR 00
#define T_ARROW 01
#define T_SLEEP 02
#define T_BEAR 03
#define T_TELEP 04
#define T_DART 05
#define NTRAPS 6
/*
* Potion types
*/
#define P_CONFUSE 0
#define P_PARALYZE 1
#define P_POISON 2
#define P_STRENGTH 3
#define P_SEEINVIS 4
#define P_HEALING 5
#define P_MFIND 6
#define P_TFIND 7
#define P_RAISE 8
#define P_XHEAL 9
#define P_HASTE 10
#define P_RESTORE 11
#define P_BLIND 12
#define P_NOP 13
#define MAXPOTIONS 14
/*
* Scroll types
*/
#define S_CONFUSE 0
#define S_MAP 1
#define S_HOLD 2
#define S_SLEEP 3
#define S_ARMOR 4
#define S_IDENT 5
#define S_SCARE 6
#define S_GFIND 7
#define S_TELEP 8
#define S_ENCH 9
#define S_CREATE 10
#define S_REMOVE 11
#define S_AGGR 12
#define S_NOP 13
#define S_GENOCIDE 14
#define MAXSCROLLS 15
/*
* Weapon types
*/
#define MACE 0
#define SWORD 1
#define BOW 2
#define ARROW 3
#define DAGGER 4
#define TWOSWORD 5
#define DART 6
#define CROSSBOW 7
#define BOLT 8
#define SPEAR 9
#define FLAME 10 /* fake entry for dragon breath (ick) */
#define MAXWEAPONS 10 /* this should equal FLAME */
/*
* Armor types
*/
#define LEATHER 0
#define RING_MAIL 1
#define STUDDED_LEATHER 2
#define SCALE_MAIL 3
#define CHAIN_MAIL 4
#define SPLINT_MAIL 5
#define BANDED_MAIL 6
#define PLATE_MAIL 7
#define MAXARMORS 8
/*
* Ring types
*/
#define R_PROTECT 0
#define R_ADDSTR 1
#define R_SUSTSTR 2
#define R_SEARCH 3
#define R_SEEINVIS 4
#define R_NOP 5
#define R_AGGR 6
#define R_ADDHIT 7
#define R_ADDDAM 8
#define R_REGEN 9
#define R_DIGEST 10
#define R_TELEPORT 11
#define R_STEALTH 12
#define R_SUSTARM 13
#define MAXRINGS 14
/*
* Rod/Wand/Staff types
*/
#define WS_LIGHT 0
#define WS_HIT 1
#define WS_ELECT 2
#define WS_FIRE 3
#define WS_COLD 4
#define WS_POLYMORPH 5
#define WS_MISSILE 6
#define WS_HASTE_M 7
#define WS_SLOW_M 8
#define WS_DRAIN 9
#define WS_NOP 10
#define WS_TELAWAY 11
#define WS_TELTO 12
#define WS_CANCEL 13
#define MAXSTICKS 14
/*
* Now we define the structures and types
*/
/*
* Help list
*/
struct h_list {
char h_ch;
char *h_desc;
};
/*
* Coordinate data type
*/
typedef struct {
shint x;
shint y;
} coord;
/* daemon/fuse data type */
struct delayed_action {
int d_type;
int (*d_func)();
int d_arg;
int d_time;
};
/**/
typedef unsigned int str_t;
/*
* Stuff about magic items
*/
struct magic_item {
const char *mi_name;
shint mi_prob;
short mi_worth;
};
/*
* Room structure
*/
struct room {
coord r_pos; /* Upper left corner */
coord r_max; /* Size of room */
coord r_gold; /* Where the gold is */
int r_goldval; /* How much the gold is worth */
short r_flags; /* Info about the room */
shint r_nexits; /* Number of exits */
coord r_exit[12]; /* Where the exits are */
};
/*
* Structure describing a fighting being
*/
struct stats {
str_t s_str; /* Strength */
long s_exp; /* Experience */
shint s_lvl; /* Level of mastery */
shint s_arm; /* Armor class */
short s_hpt; /* Hit points */
char s_dmg[16]; /* String describing damage done */
shint s_maxhp; /* Max hit points */
};
/*
* Structure for monsters and player
*/
union thing {
struct {
union thing *_l_next, *_l_prev; /* Next pointer in link */
coord _t_pos; /* Position */
bool _t_turn; /* If slowed, is it a turn to move */
unsigned char _t_type; /* What it is */
char _t_disguise; /* What mimic looks like */
char _t_oldch; /* Character that was where it was */
coord *_t_dest; /* Where it is running to */
short _t_flags; /* State word */
struct stats _t_stats; /* Physical description */
struct room *_t_room; /* Current room for thing */
union thing *_t_pack; /* What the thing is carrying */
int _t_reserved;
} _t;
struct {
union thing *_l_next, *_l_prev; /* Next pointer in link */
shint _o_type; /* What kind of object it is */
coord _o_pos; /* Where it lives on the screen */
char *_o_text; /* What it says if you read it */
char _o_launch; /* What you need to launch it */
char _o_damage[8]; /* Damage if used like sword */
char _o_hurldmg[8]; /* Damage if thrown */
shint _o_count; /* Count for plural objects */
shint _o_which; /* Which object of a type it is */
shint _o_hplus; /* Plusses to hit */
shint _o_dplus; /* Plusses to damage */
short _o_ac; /* Armor class */
short _o_flags; /* Information about objects */
shint _o_group; /* Group number for this object */
} _o;
};
typedef union thing THING;
#define l_next _t._l_next
#define l_prev _t._l_prev
#define t_pos _t._t_pos
#define t_turn _t._t_turn
#define t_type _t._t_type
#define t_disguise _t._t_disguise
#define t_oldch _t._t_oldch
#define t_dest _t._t_dest
#define t_flags _t._t_flags
#define t_stats _t._t_stats
#define t_pack _t._t_pack
#define t_room _t._t_room
#define t_reserved _t._t_reserved
#define o_type _o._o_type
#define o_pos _o._o_pos
#define o_text _o._o_text
#define o_launch _o._o_launch
#define o_damage _o._o_damage
#define o_hurldmg _o._o_hurldmg
#define o_count _o._o_count
#define o_which _o._o_which
#define o_hplus _o._o_hplus
#define o_dplus _o._o_dplus
#define o_ac _o._o_ac
#define o_charges o_ac
#define o_goldval o_ac
#define o_flags _o._o_flags
#define o_group _o._o_group
#define o_reserved _o._o_reserved
/*
* Array containing information on all the various types of mosnters
*/
struct monster {
const char *m_name; /* What to call the monster */
const shint m_carry; /* Probability of carrying something */
const short m_flags; /* Things about the monster */
struct stats m_stats; /* Initial stats */
};
/*
* External variables
*/
extern struct delayed_action d_list[20];
extern THING *_monst[], *cur_armor, *cur_ring[], *cur_weapon,
*lvl_obj, *mlist, player;
extern coord delta, oldpos;
extern struct h_list helpstr[];
extern struct room *oldrp, passages[], rooms[];
extern struct stats max_stats;
extern struct monster monsters[];
extern struct magic_item p_magic[], r_magic[], s_magic[],
things[], ws_magic[];
/*
* Function types
*/
coord *find_dest(), *rndmove();
THING *find_mons(), *find_obj(), *get_item(), *new_item(),
*new_thing(), *wake_monster();
struct room *roomin();
#include "extern.h"
#ifndef PATH_MAX
#define PATH_MAX _MAX_PATH
#endif

787
rogue4/rogue.me Normal file
View file

@ -0,0 +1,787 @@
.ds E \s-2<ESCAPE>\s0
.ds R \s-2<RETURN>\s0
.ds U \s-2UNIX\s0
.ie t .ds _ \d\(mi\u
.el .ds _ _
.de Cs
\&\\$3\*(lq\\$1\*(rq\\$2
..
.sp 5
.ce 1000
.ps +4
.vs +4p
.b
A Guide to the Dungeons of Doom
.r
.vs
.ps
.sp 2
.i
Michael C. Toy
Kenneth C. R. C. Arnold
.r
.sp 2
Computer Systems Research Group
Department of Electrical Engineering and Computer Science
University of California
Berkeley, California 94720
.sp 4
.i ABSTRACT
.ce 0
.(b I F
.bi Rogue
is a visual CRT based fantasy game
which runs under the \*U\(dg timesharing system.
.(f
\fR\(dg\*U is a trademark of Bell Laboratories\fP
.)f
This paper describes how to play rogue,
and gives a few hints
for those who might otherwise get lost in the Dungeons of Doom.
.)b
.he '''\fBA Guide to the Dungeons of Doom\fP'
.fo ''- % -''
.bp 1
.sh 1 Introduction
.pp
You have just finished your years as a student at the local fighter's guild.
After much practice and sweat you have finally completed your training
and are ready to embark upon a perilous adventure.
As a test of your skills,
the local guildmasters have sent you into the Dungeons of Doom.
Your task is to return with the Amulet of Yendor.
Your reward for the completion of this task
will be a full membership in the local guild.
In addition,
you are allowed to keep all the loot you bring back from the dungeons.
.pp
In preparation for your journey,
you are given an enchanted mace,
a bow, and a quiver of arrows
taken from a dragon's hoard in the far off Dark Mountains.
You are also outfitted with elf-crafted armor
and given enough food to reach the dungeons.
You say goodbye to family and friends for what may be the last time
and head up the road.
.pp
You set out on your way to the dungeons
and after several days of uneventful travel,
you see the ancient ruins
that mark the entrance to the Dungeons of Doom.
It is late at night,
so you make camp at the entrance
and spend the night sleeping under the open skies.
In the morning you gather your mace,
put on your armor,
eat what is almost your last food,
and enter the dungeons.
.sh 1 "What is going on here?"
.pp
You have just begun a game of rogue.
Your goal is to grab as much treasure as you can,
find the Amulet of Yendor,
and get out of the Dungeons of Doom alive.
On the screen,
a map of where you have been
and what you have seen on the current dungeon level is kept.
As you explore more of the level,
it appears on the screen in front of you.
.pp
Rogue differs from most computer fantasy games in that it is screen oriented.
Commands are all one or two keystrokes\**
.(f
\** As opposed to pseudo English sentences.
.)f
and the results of your commands
are displayed graphically on the screen rather
than being explained in words.
.pp
Another major difference between rogue and other computer fantasy games
is that once you have solved all the puzzles in a standard fantasy game,
it has lost most of its excitement and it ceases to be fun.
Rogue,
on the other hand,
generates a new dungeon every time you play it
and even the author finds it an entertaining and exciting game.
.sh 1 "What do all those things on the screen mean?"
.pp
In order to understand what is going on in rogue
you have to first get some grasp of what rogue is doing with the screen.
The rogue screen is intended
to replace the \*(lqYou can see ...\*(rq descriptions
of standard fantasy games.
Figure 1 is a sample of what a rogue screen might look like.
.(z
.hl
.nf
.TS
center;
ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce.
- - - - - - - - - - - -
| . . . . . . . . . . +
| . . @ . . . . ] . . |
| . . . . B . . . . . |
| . . . . . . . . . . |
- - - - - + - - - - - -
.TE
.ce 1000
Level: 1 Gold: 0 Hp: 12(12) Str: 16(16) Ac: 6 Exp: 1/0
Figure 1
.ce
.hl
.)z
.sh 2 "The bottom line"
.pp
At the bottom line of the screen
are a few pieces of cryptic information
describing your current status.
Here is an explanation of what these things mean:
.ip Level \w'Level\ \ 'u
This number indicates how deep you have gone in the dungeon.
It starts at one and goes up as you go deeper into the dungeon.
.ip Gold \w'Level\ \ 'u
The number of gold pieces you have managed to find
and keep with you so far.
.ip Hp \w'Level\ \ 'u
Your current and maximum hit points.
Hit points indicate how much damage you can take before you die.
The more you get hit in a fight,
the lower they get.
You can regain hit points by resting.
The number in parentheses
is the maximum number your hit points can reach.
.ip Str \w'Level\ \ 'u
Your current strength and maximum ever strength.
This can be any integer less than or equal to 31,
or greater than or equal to three.
The higher the number,
the stronger you are.
The number in the parentheses
is the maximum strength you have attained so far this game.
.ip Ac \w'Level\ \ 'u
Your current armor class.
This number indicates how effective your armor is
in stopping blows from unfriendly creatures.
The lower this number is,
the more effective the armor.
.ip Exp \w'Level\ \ 'u
These two numbers give your current experience level
and experience points.
As you do things,
you gain experience points.
At certain experience point totals,
you gain an experience level.
The more experienced you are,
the better you are able to fight and to withstand magical attacks.
.sh 2 "The top line"
.pp
The top line of the screen is reserved
for printing messages that describe things
that are impossible to represent visually.
If you see a \*(lq--More--\*(rq on the top line,
this means that rogue wants to print another message on the screen,
but it wants to make certain
that you have read the one that is there first.
To read the next message,
just type a space.
.sh 2 "The rest of the screen"
.pp
The rest of the screen is the map of the level
as you have explored it so far.
Each symbol on the screen represents something.
Here is a list of what the various symbols mean:
.ip @
This symbol represents you, the adventurer.
.ip "-\^|"
These symbols represent the walls of rooms.
.ip +
A door to/from a room.
.ip .
The floor of a room.
.ip #
The floor of a passage between rooms.
.ip *
A pile or pot of gold.
.ip )
A weapon of some sort.
.ip ]
A piece of armor.
.ip !
A flask containing a magic potion.
.ip ?
A piece of paper, usually a magic scroll.
.ip =
A ring with magic properties
.ip /
A magical staff or wand
.ip ^
A trap, watch out for these.
.ip %
A staircase to other levels
.ip :
A piece of food.
.ip A-Z
The uppercase letters
represent the various inhabitants of the Dungeons of Doom.
Watch out, they can be nasty and vicious.
.sh 1 Commands
.pp
Commands are given to rogue by typing one or two characters.
Most commands can be preceded by a count to repeat them
(e.g. typing
.Cs 10s
will do ten searches).
Commands for which counts make no sense
have the count ignored.
To cancel a count or a prefix,
type \*E.
The list of commands is rather long,
but it can be read at any time during the game with the
.Cs ?
command.
Here it is for reference,
with a short explanation of each command.
.ip ?
The help command.
Asks for a character to give help on.
If you type a
.Cs * ,
it will list all the commands,
otherwise it will explain what the character you typed does.
.ip /
This is the \*(lqWhat is that on the screen?\*(rq command.
A
.Cs /
followed by any character that you see on the level,
will tell you what that character is.
For instance,
typing
.Cs /@
will tell you that the
.Cs @
symbol represents you, the player.
.ip "h, H"
Move left.
You move one space to the left.
If you use upper case
.Cs h ,
you will continue to move left until you run into something.
This works for all movement commands
(e.g.
.Cs L
means run in direction
.Cs l )
.ip j
Move down.
.ip k
Move up.
.ip l
Move right.
.ip y
Move diagonally up and left.
.ip u
Move diagonally up and right.
.ip b
Move diagonally down and left.
.ip n
Move diagonally down and right.
.ip t
Throw an object.
This is a prefix command.
When followed with a direction
it throws an object in the specified direction.
(e.g. type
.Cs th
to throw
something to the left.)
.ip f
Find prefix.
When followed by a direction
it means to continue moving in the specified direction
until you pass something interesting or run into a wall.
You should experiment with this,
since it is a very useful command,
but very difficult to describe.
.ip z
Zap prefix.
Point a staff or wand in a given direction
and fire it.
Even non-directional staves must be pointed in some direction
to be used.
.ip ^
Identify trap command.
If a trap is on your map
and you can't remember what type it is,
you can get rogue to remind you
by getting next to it and typing
.Cs ^
followed by the direction that would move you on top of it.
.ip s
Search for traps and secret doors.
Examine each space immediately adjacent to you
for the existence of a trap or secret door.
There is a large chance that even if there is something there,
you won't find it,
so you might have to search a while before you find something.
.ip >
Climb down a staircase to the next level.
Not surprisingly, this can only be done if you are standing on staircase.
.ip <
Climb up a staircase to the level above.
This can't be done without the Amulet of Yendor in your posession.
.ip "."
Rest.
This is the \*(lqdo nothing\*(rq command.
This is good for waiting and healing.
.ip i
Inventory.
List what you are carrying in your pack.
.ip I
Selective inventory.
Tells you what a single item in your pack is.
.ip q
Quaff one of the potions you are carrying.
.ip r
Read one of the scrolls in your pack.
.ip e
Eat food from your pack.
.ip w
Wield a weapon.
Take a weapon out of your pack and carry it for use in combat,
replacing the one you are currently using (if any).
.ip W
Wear armor.
You can only wear one suit of armor at a time.
This takes extra time.
.ip T
Take armor off.
You can't remove armor that is cursed.
This takes extra time.
.ip P
Put on a ring.
You can wear only two rings at a time
(one on each hand).
If you aren't wearing any rings,
this command will ask you which hand you want to wear it on,
otherwise, it will place it on the unused hand.
The program assumes that you wield your sword in your right hand.
.ip R
Remove a ring.
If you are only wearing one ring,
this command takes it off.
If you are wearing two,
it will ask you which one you wish to remove,
.ip d
Drop an object.
Take something out of your pack and leave it lying on the floor.
Only one object can occupy each space.
You cannot drop a cursed object at all
if you are wielding or wearing it.
.ip c
Call an object something.
If you have a type of object in your pack
which you wish to remember something about,
you can use the call command to give a name to that type of object.
This is usually used when you figure out what a
potion, scroll, ring, or staff is
after you pick it up.
(See the
.Cs askme
option below.)
.ip D
Print out which things you've discovered something about.
This command will ask you what type of thing you are interested in.
If you type the character for a given type of object
(\fIe.g.\fP
.Cs !
for potion)
it will tell you which kinds of that type of object you've discovered
(\fIi.e.\fP, figured out what they are).
This command works for potions, scrolls, rings, and staves and wands.
.ip o
Examine and set options.
This command is further explained in the section on options.
.ip ^L
Redraws the screen.
Useful if spurious messages or transmission errors
have messed up the display.
.ip ^R
Repeat last message.
Useful when a message disappears before you can read it.
This only repeats the last message
that was not a mistyped command
so that you don't loose anything by accidentally typing
the wrong character instead of ^R.
.ip \*E
Cancel a command, prefix, or count.
.ip !
Escape to a shell for some commands.
.ip Q
Quit.
Leave the game.
.ip S
Save the current game in a file.
It will ask you whether you wish to use the default save file.
.i Caveat :
Rogue won't let you start up a copy of a saved game,
and it removes the save file as soon as you start up a restored game.
This is to prevent people from saving a game just before a dangerous position
and then restarting it if they die.
To restore a saved game,
give the file name as an argument to rogue.
As in
.ti +1i
.nf
% rogue \fIsave\*_file\fP
.ip
To restart from the default save file (see below),
run
.ti +1i
.nf
% rogue \-r
.ip v
Prints the program version number.
.sh 1 Rooms
.pp
Rooms in the dungeons are either lit or dark.
If you walk into a lit room,
the entire room will be drawn on the screen as soon as you enter.
If you walk into a dark room,
it will only be displayed as you explore it.
Upon leaving a room,
all objects inside the room which might move
or be removed
are erased from the screen.
In the darkness you can only see one space
in all directions around you.
A corridor is always dark.
.sh 1 Fighting
.pp
If you see a monster and you wish to fight it,
just attempt to run into it.
Many times a monster you find will mind its own business
unless you attack it.
It is often the case that discretion is the better part of valor.
.sh 1 "Objects you can find"
.pp
When you find something in the dungeon,
it is common to want to pick the object up.
This is accomplished in rogue by walking over the object.
If you are carrying too many things,
the program will tell you and it won't pick up the object,
otherwise it will add it to your pack
and tell you what you just picked up.
.pp
Many of the commands that operate on objects must prompt you
to find out which object you want to use.
If you change your mind and don't want to do that command after all,
just type an \*E and the command will be aborted.
.pp
Some objects, like armor and weapons,
are easily differentiated.
Others, like scrolls and potions,
are given labels which vary according to type.
During a game,
any two of the same kind of object
with the same label
are the same type.
However,
the labels will vary from game to game.
.pp
When you use one of these labeled objects,
if its effect is obvious,
rogue will remember what it is for you.
If it's effect isn't extremely obvious, you can use the
.Cs call
command
(see above)
or the
.Cs askme
option
(see below)
to scribble down something about it
so you will recognize it later.
.sh 2 Weapons
.pp
Some weapons,
like arrows,
come in bunches,
but most come one at a time.
In order to use a weapon,
you must wield it.
To fire an arrow out of a bow,
you must first wield the bow,
then throw the arrow.
You can only wield one weapon at a time,
but you can't change weapons if the one
you are currently wielding is cursed.
.sh 2 Armor
.pp
There are various sorts of armor lying around in the dungeon.
Some of it is enchanted,
some is cursed,
and some is just normal.
Different armor types have different armor classes.
The lower the armor class,
the more protection the armor affords against the blows of monsters.
Here is a list of the various armor types and their normal armor class:
.(b
.TS
center;
l r.
Type Class
=
None 10
Leather armor 8
Studded leather / Ring mail 7
Scale mail 6
Chain mail 5
Banded mail / Splint mail 4
Plate mail 3
.TE
.)b
.lp
If a piece of armor is enchanted,
its armor class will be lower than normal.
If a suit of armor is cursed,
its armor class will be higher,
and you will not be able to remove it.
However, not all armor with a class that is higher than normal is cursed.
.sh 2 Scrolls
.pp
Scrolls come with titles in an unknown tongue.
After you read a scroll,
it disappears from your pack.
.sh 2 Potions
.pp
Potions are labeled by the color of the liquid inside the flask.
They disappear after being quaffed.
.sh 2 "Staves and Wands"
.pp
Staves and wands do the same kinds of things.
Staves are identified by a type of wood;
wands by a type of metal or bone.
They are generally things you want to do to something
over a long distance,
so you must point them at what you wish to affect
to use them.
Some staves are not affected by the direction they are pointed, though.
Staves come with multiple magic charges,
the number being random,
and when they are used up,
the staff is just a piece of wood or metal.
.sh 2 Rings
.pp
Rings are very useful items,
since they are relatively permanent magic,
unlike the usually fleeting effects of potions, scrolls, and staves.
Of course,
the bad rings are also more powerful.
Most rings also cause you to use up food more rapidly,
the rate varying with the type of ring.
Rings are differentiated by their stone settings.
.sh 1 Options
.pp
Due to variations in personal tastes
and conceptions of the way rogue should do things,
there are a set of options you can set
that cause rogue to behave in various different ways.
.sh 2 "Setting the options"
.pp
There are two ways to set the options.
The first is with the
.Cs o
command of rogue;
the second is with the
.Cs ROGUEOPTS
environment variable\**.
.(f
\** On Version 6 systems,
there is no equivalent of the ROGUEOPTS feature.
.br
.)f
.br
.sh 3 "Using the `o' command"
.pp
When you type
.Cs o
in rogue,
it clears the screen
and displays the current settings for all the options.
It then places the cursor by the value of the first option
and waits for you to type.
You can type a \*R
which means to go to the next option,
a
.Cs \-
which means to go to the previous option,
an \*E
which means to return to the game,
or you can give the option a value.
For boolean options this merely involves typing
.Cs t
for true or
.Cs f
for false.
For string options,
type the new value followed by a \*R.
.sh 3 "Using the ROGUEOPTS variable"
.pp
The ROGUEOPTS variable is a string
containing a comma separated list of initial values
for the various options.
Boolean variables can be turned on by listing their name
or turned off by putting a
.Cs no
in front of the name.
Thus to set up an environment variable so that
.b jump
is on,
.b terse
is off,
and the
.b name
is set to \*(lqBlue Meanie\*(rq,
use the command
.nf
.ti +3n
% setenv ROGUEOPTS "jump,noterse,name=Blue Meanie"\**
.fi
.(f
\**
For those of you who use the bourne shell, the commands would be
.in +3
.nf
$ ROGUEOPTS="jump,noterse,name=Blue Meanie"
$ export ROGUEOPTS
.fi
.in +0
.)f
.sh 2 "Option list"
.pp
Here is a list of the options
and an explanation of what each one is for.
The default value for each is enclosed in square brackets.
For character string options,
input over fifty characters will be ignored.
.ip "\fBterse\fP [\fI\^noterse\^\fP]"
Useful for those who are tired of the sometimes lengthy messages of rogue.
This is a useful option for playing on slow terminals,
so this option defaults to
.b terse
if your
are on a slow (1200 baud or under) terminal.
.ip "\fBjump\fP [\fI\^nojump\^\fP]"
If this option is set,
running moves will not be displayed
until you reach the end of the move.
This saves considerable cpu and display time.
This option defaults to
.b jump
if you are using a slow terminal.
.ip "\fBstep\fP [\fI\^nostep\^\fP]"
When
.b step
is set,
lists of things,
like inventories or
.Cs *
responses to
\*(lqWhich item do you wish to \fB. . .\fP? \*(rq questions,
are displayed one item at a time on the top of the screen,
rather than clearing the screen,
displaying the list,
then re-displaying the dungeon level.
.ip "\fBflush\fP [\fI\^noflush\^\fP]"
All typeahead is thrown away after each round of battle.
This is useful for those who type far ahead
and then watch in dismay as a Kobold kills them.
.ip "\fBaskme\fP [\fI\^noaskme\^\fP]"
Upon reading a scroll or quaffing a potion
which does not automatically identify itself upon use,
rogue will ask you what to name it
so you can recognize it if you encounter it again.
.ip "\fBpassgo\fP [\fI\^nopassgo\^\fP]"
Follow turnings in passageways.
If you run in a passage
and you run into stone or a wall,
rogue will see if it can turn to the right or left.
If it can only turn one way,
it will turn that way.
If it can turn either or neither,
it will stop.
This is followed strictly,
which can sometimes lead to slightly confusing occurrences
(which is why it defaults to being off).
The
.Cs f
prefix still works.
.ip "\fBname\fP [account name]"
This is the name of your character.
It is used if you get on the top ten scorer's list.
.ip "\fBfruit\fP [\fI\^slime-mold\^\fP]"
This should hold the name of a fruit that you enjoy eating.
It is basically a whimsey that the program uses in a couple of places.
.ip "\fBfile\fP [\fI\^~/rogue.save\^\fP]"
The default file name for saving the game.
If your phone is hung up by accident,
rogue will automatically save the game in this file.
The file name may contain the special character
.Cs ~
which expands to be your home directory.
.sh 1 Scoring
.pp
Rogue usually maintains a list
of the top ten scoring people on your machine.
Some installations limit each account on the machine
to post only one non-winning score on this list, however
this is no longer considered the default behavior.
If you score higher than someone else on this list,
or better your previous score on the list,
you will be inserted in the proper place
under your current name.
.pp
If you quit the game, you get out with all of your gold intact.
If, however, you get killed in the Dungeons of Doom,
your body is forwarded to your next-of-kin,
along with 90% of your gold;
ten percent of your gold is kept by the Dungeons' wizard as a fee.
This should make you consider whether you want to take one last hit
at that monster and possibly live,
or quit and thus stop with whatever you have.
If you quit, you do get all your gold,
but if you swing and live, you might find more.
.pp
If you just want to see what the current top ten list is,
you can type
.ti +1i
.nf
% rogue \-s
.br
.sh 1 Acknowledgements
.pp
Rogue was originally conceived of by Glenn Wichman and Michael Toy.
Ken Arnold and Michael Toy then smoothed out the user interface,
and added jillions of new features.
We would like to thank
Bob Arnold,
Michelle Busch,
Andy Hatcher,
Kipp Hickman,
Mark Horton,
Daniel Jensen,
Bill Joy,
Joe Kalash,
Steve Maurer,
Marty McNary,
Jan Miller,
and
Scott Nelson
for their ideas and assistance,
and also the teeming multitudes
who graciously ignored work, school, and social life to play rogue
and send us bugs, complaints, suggestions, and just plain flames.
And also Mom.

20
rogue4/rogue52.sln Normal file
View file

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual C++ Express 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rogue52", "rogue52.vcproj", "{8D92C587-9CBA-41FE-BB30-F0A7142AC625}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8D92C587-9CBA-41FE-BB30-F0A7142AC625}.Debug|Win32.ActiveCfg = Debug|Win32
{8D92C587-9CBA-41FE-BB30-F0A7142AC625}.Debug|Win32.Build.0 = Debug|Win32
{8D92C587-9CBA-41FE-BB30-F0A7142AC625}.Release|Win32.ActiveCfg = Release|Win32
{8D92C587-9CBA-41FE-BB30-F0A7142AC625}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

405
rogue4/rogue52.vcproj Normal file
View file

@ -0,0 +1,405 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="rogue52"
ProjectGUID="{8D92C587-9CBA-41FE-BB30-F0A7142AC625}"
RootNamespace="rogue52"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
InlineFunctionExpansion="0"
AdditionalIncludeDirectories="../pdcurses"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;SCOREFILE;ALLSCORES"
StringPooling="true"
MinimalRebuild="true"
ExceptionHandling="0"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
BrowseInformation="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
CompileAs="1"
DisableSpecificWarnings="4033;4716;4013;4131;4244;4201;4431;4127;4706;4100"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib pdcurses.lib advapi32.lib shfolder.lib user32.lib"
OutputFile="$(OutDir)/rogue54.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="../pdcurses"
IgnoreDefaultLibraryNames="LIBC.LIB"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/rogue54.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
OmitFramePointers="true"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/rogue54.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
>
<File
RelativePath="armor.c"
>
</File>
<File
RelativePath="chase.c"
>
</File>
<File
RelativePath="command.c"
>
</File>
<File
RelativePath="daemon.c"
>
</File>
<File
RelativePath="daemons.c"
>
</File>
<File
RelativePath="extern.c"
>
</File>
<File
RelativePath="fight.c"
>
</File>
<File
RelativePath="findpw.c"
>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="init.c"
>
</File>
<File
RelativePath="io.c"
>
</File>
<File
RelativePath="list.c"
>
</File>
<File
RelativePath="mach_dep.c"
>
</File>
<File
RelativePath="main.c"
>
</File>
<File
RelativePath="mdport.c"
>
</File>
<File
RelativePath="misc.c"
>
</File>
<File
RelativePath="monsters.c"
>
</File>
<File
RelativePath="move.c"
>
</File>
<File
RelativePath="new_level.c"
>
</File>
<File
RelativePath="options.c"
>
</File>
<File
RelativePath="pack.c"
>
</File>
<File
RelativePath="passages.c"
>
</File>
<File
RelativePath="potions.c"
>
</File>
<File
RelativePath=".\prob.c"
>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="rings.c"
>
</File>
<File
RelativePath="rip.c"
>
</File>
<File
RelativePath="rooms.c"
>
</File>
<File
RelativePath="save.c"
>
</File>
<File
RelativePath="scrolls.c"
>
</File>
<File
RelativePath="state.c"
>
</File>
<File
RelativePath="sticks.c"
>
</File>
<File
RelativePath="things.c"
>
</File>
<File
RelativePath="vers.c"
>
</File>
<File
RelativePath="weapons.c"
>
</File>
<File
RelativePath="wizard.c"
>
</File>
<File
RelativePath="xcrypt.c"
>
</File>
<File
RelativePath=".\xstr.c"
>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc"
>
<File
RelativePath="extern.h"
>
</File>
<File
RelativePath="rogue.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
>
</Filter>
<File
RelativePath="LICENSE.TXT"
>
</File>
<File
RelativePath="Makefile"
>
</File>
<File
RelativePath="rogue.6"
>
</File>
<File
RelativePath="rogue.me"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

275
rogue4/rooms.c Normal file
View file

@ -0,0 +1,275 @@
/*
* Create the layout for the new level
*
* @(#)rooms.c 4.16 (Berkeley) 1/12/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <ctype.h>
#include <curses.h>
#include "rogue.h"
#define GOLDGRP 1
/*
* do_rooms:
* Create rooms and corridors with a connectivity graph
*/
do_rooms()
{
register int i;
register struct room *rp;
register THING *tp;
register int left_out;
coord top;
coord bsze;
coord mp;
/*
* bsze is the maximum room size
*/
bsze.x = COLS/3;
bsze.y = LINES/3;
/*
* Clear things for a new level
*/
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
rp->r_goldval = rp->r_nexits = rp->r_flags = 0;
/*
* Put the gone rooms, if any, on the level
*/
left_out = rnd(4);
for (i = 0; i < left_out; i++)
rooms[rnd_room()].r_flags |= ISGONE;
/*
* dig and populate all the rooms on the level
*/
for (i = 0, rp = rooms; i < MAXROOMS; rp++, i++)
{
/*
* Find upper left corner of box that this room goes in
*/
top.x = (i%3)*bsze.x + 1;
top.y = i/3*bsze.y;
if (rp->r_flags & ISGONE)
{
/*
* Place a gone room. Make certain that there is a blank line
* for passage drawing.
*/
do
{
rp->r_pos.x = top.x + rnd(bsze.x-2) + 1;
rp->r_pos.y = top.y + rnd(bsze.y-2) + 1;
rp->r_max.x = -COLS;
rp->r_max.x = -LINES;
} until (rp->r_pos.y > 0 && rp->r_pos.y < LINES-1);
continue;
}
if (rnd(10) < level - 1)
rp->r_flags |= ISDARK;
/*
* Find a place and size for a random room
*/
do
{
rp->r_max.x = rnd(bsze.x - 4) + 4;
rp->r_max.y = rnd(bsze.y - 4) + 4;
rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x);
rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y);
} until (rp->r_pos.y != 0);
/*
* Put the gold in
*/
if (rnd(2) == 0 && (!amulet || level >= max_level))
{
register THING *gold;
gold = new_item();
gold->o_goldval = rp->r_goldval = GOLDCALC;
rnd_pos(rp, &rp->r_gold);
gold->o_pos = rp->r_gold;
gold->o_flags = ISMANY;
gold->o_group = GOLDGRP;
gold->o_type = GOLD;
attach(lvl_obj, gold);
}
draw_room(rp);
/*
* Put the monster in
*/
if (rnd(100) < (rp->r_goldval > 0 ? 80 : 25))
{
tp = new_item();
do
{
rnd_pos(rp, &mp);
} until (winat(mp.y, mp.x) == FLOOR);
new_monster(tp, randmonster(FALSE), &mp);
give_pack(tp);
}
}
}
/*
* draw_room:
* Draw a box around a room and lay down the floor
*/
draw_room(rp)
register struct room *rp;
{
register int y, x;
vert(rp, rp->r_pos.x); /* Draw left side */
vert(rp, rp->r_pos.x + rp->r_max.x - 1); /* Draw right side */
horiz(rp, rp->r_pos.y); /* Draw top */
horiz(rp, rp->r_pos.y + rp->r_max.y - 1); /* Draw bottom */
/*
* Put the floor down
*/
for (y = rp->r_pos.y + 1; y < rp->r_pos.y + rp->r_max.y - 1; y++)
/*strrep(&chat(rp->r_pos.y + 1, j), FLOOR, rp->r_max.y - rp->r_pos.y - 2);*/
for (x = rp->r_pos.x + 1; x < rp->r_pos.x + rp->r_max.x - 1; x++)
chat(y, x) = FLOOR;
/*
* Put the gold there
*/
if (rp->r_goldval)
chat(rp->r_gold.y, rp->r_gold.x) = GOLD;
}
/*
* vert:
* Draw a vertical line
*/
vert(rp, startx)
register struct room *rp;
register int startx;
{
register int y;
for (y = rp->r_pos.y + 1; y <= rp->r_max.y + rp->r_pos.y - 1; y++)
chat(y, startx) = '|';
}
/*
* horiz:
* Draw a horizontal line
*/
horiz(rp, starty)
register struct room *rp;
int starty;
{
register int x;
for (x = rp->r_pos.x; x <= rp->r_pos.x + rp->r_max.x - 1; x++)
chat(starty, x) = '-';
}
/*
* rnd_pos:
* Pick a random spot in a room
*/
rnd_pos(rp, cp)
register struct room *rp;
register coord *cp;
{
cp->x = rp->r_pos.x + rnd(rp->r_max.x - 2) + 1;
cp->y = rp->r_pos.y + rnd(rp->r_max.y - 2) + 1;
}
/*
* enter_room:
* Code that is executed whenver you appear in a room
*/
enter_room(cp)
register coord *cp;
{
register struct room *rp;
register int y, x;
register THING *tp;
rp = proom = roomin(cp);
if (rp->r_flags & ISGONE)
{
msg("in a gone room");
return;
}
door_open(rp);
if (!(rp->r_flags & ISDARK) && !on(player, ISBLIND))
for (y = rp->r_pos.y; y < rp->r_max.y + rp->r_pos.y; y++)
{
move(y, rp->r_pos.x);
for (x = rp->r_pos.x; x < rp->r_max.x + rp->r_pos.x; x++)
{
tp = moat(y, x);
if (tp == NULL || !see_monst(tp))
addch(chat(y, x));
else
addch(tp->t_disguise);
}
}
}
/*
* leave_room:
* Code for when we exit a room
*/
leave_room(cp)
register coord *cp;
{
register int y, x;
register struct room *rp;
register char floor;
register char ch;
rp = proom;
proom = &passages[flat(cp->y, cp->x) & F_PNUM];
floor = ((rp->r_flags & ISDARK) && !on(player, ISBLIND)) ? ' ' : FLOOR;
for (y = rp->r_pos.y + 1; y < rp->r_max.y + rp->r_pos.y - 1; y++)
for (x = rp->r_pos.x + 1; x < rp->r_max.x + rp->r_pos.x - 1; x++)
switch (ch = mvinch(y, x))
{
case ' ':
case TRAP:
case STAIRS:
break;
case FLOOR:
if (floor == ' ')
addch(' ');
break;
default:
/*
* to check for monster, we have to strip out
* standout bit
*/
if (isupper(toascii(ch)))
if (on(player, SEEMONST))
{
standout();
addch(ch);
standend();
break;
}
else
{
THING *tp = moat(y, x);
if (tp != NULL)
tp->t_oldch = floor;
#ifdef WIZARD
else
msg("couldn't find monster in leave_room at (%d,%d)", y, x);
#endif
}
addch(floor);
}
door_open(rp);
}

342
rogue4/save.c Normal file
View file

@ -0,0 +1,342 @@
/*
* save and restore routines
*
* @(#)save.c 4.15 (Berkeley) 5/10/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define KERNEL
#include <signal.h>
#undef KERNEL
#include "rogue.h"
typedef struct stat STAT;
extern char version[], encstr[];
extern bool _endwin;
STAT sbuf;
/*
* save_game:
* Implement the "save game" command
*/
save_game()
{
register FILE *savef;
register int c;
char buf[MAXSTR];
/*
* get file name
*/
mpos = 0;
over:
if (file_name[0] != '\0')
{
for (;;)
{
msg("save file (%s)? ", file_name);
c = getchar();
mpos = 0;
if (c == ESCAPE)
{
msg("");
return FALSE;
}
else if (c == 'n' || c == 'N' || c == 'y' || c == 'Y')
break;
else
msg("please answer Y or N");
}
if (c == 'y' || c == 'Y')
{
strcpy(buf, file_name);
goto gotfile;
}
}
do
{
mpos = 0;
msg("file name: ");
buf[0] = '\0';
if (get_str(buf, stdscr) == QUIT)
{
quit:
msg("");
return FALSE;
}
mpos = 0;
gotfile:
/*
* test to see if the file exists
*/
if (stat(buf, &sbuf) >= 0)
{
for (;;)
{
msg("File exists. Do you wish to overwrite it?");
mpos = 0;
if ((c = readchar()) == ESCAPE)
goto quit;
if (c == 'y' || c == 'Y')
break;
else if (c == 'n' || c == 'N')
goto over;
else
msg("Please answer Y or N");
}
msg("file name: %s", buf);
}
strcpy(file_name, buf);
if ((savef = fopen(file_name, "w")) == NULL)
msg(strerror(errno)); /* fake perror() */
} while (savef == NULL);
/*
* write out encrpyted file (after a stat)
* The fwrite is to force allocation of the buffer before the write
*/
save_file(savef);
return TRUE;
}
/*
* auto_save:
* Automatically save a file. This is used if a HUP signal is
* recieved
*/
void
auto_save(int sig)
{
register FILE *savef;
md_ignore_signals();
if (file_name[0] != '\0' && (savef = fopen(file_name, "w")) != NULL)
save_file(savef);
endwin();
exit(1);
}
/*
* save_file:
* Write the saved game on the file
*/
save_file(savef)
register FILE *savef;
{
int slines = LINES;
int scols = COLS;
/*
* close any open score file
*/
close(fd);
move(LINES-1, 0);
refresh();
fstat(md_fileno(savef), &sbuf);
/*
* DO NOT DELETE. This forces stdio to allocate the output buffer
* so that malloc doesn't get confused on restart
*/
fwrite("junk", 1, 5, savef);
fseek(savef, 0L, 0);
encwrite(version,strlen(version)+1,savef);
encwrite(&sbuf.st_ino,sizeof(sbuf.st_ino),savef);
encwrite(&sbuf.st_dev,sizeof(sbuf.st_dev),savef);
encwrite(&sbuf.st_ctime,sizeof(sbuf.st_ctime),savef);
encwrite(&sbuf.st_mtime,sizeof(sbuf.st_mtime),savef);
encwrite(&slines,sizeof(slines),savef);
encwrite(&scols,sizeof(scols),savef);
msg("");
rs_save_file(savef);
fclose(savef);
}
/*
* restore:
* Restore a saved game from a file with elaborate checks for file
* integrity from cheaters
*/
restore(file, envp)
register char *file;
char **envp;
{
register int inf;
register bool syml;
extern char **environ;
char buf[MAXSTR];
STAT sbuf2;
int slines, scols;
if (strcmp(file, "-r") == 0)
file = file_name;
#ifdef SIGTSTP
/*
* If a process can be suspended, this code wouldn't work
*/
signal(SIGTSTP, SIG_IGN);
#endif
if ((inf = open(file, 0)) < 0)
{
perror(file);
return FALSE;
}
fflush(stdout);
encread(buf, strlen(version) + 1, inf);
if (strcmp(buf, version) != 0)
{
printf("Sorry, saved game is out of date.\n");
return FALSE;
}
fstat(inf, &sbuf2);
fflush(stdout);
syml = issymlink(file);
if (
#ifdef WIZARD
!wizard &&
#endif
md_unlink(file) < 0)
{
printf("Cannot unlink file\n");
return FALSE;
}
fflush(stdout);
encread(&sbuf.st_ino,sizeof(sbuf.st_ino), inf);
encread(&sbuf.st_dev,sizeof(sbuf.st_dev), inf);
encread(&sbuf.st_ctime,sizeof(sbuf.st_ctime), inf);
encread(&sbuf.st_mtime,sizeof(sbuf.st_mtime), inf);
encread(&slines,sizeof(slines),inf);
encread(&scols,sizeof(scols),inf);
/*
* we do not close the file so that we will have a hold of the
* inode for as long as possible
*/
initscr();
if (slines > LINES)
{
printf("Sorry, original game was played on a screen with %d lines.\n",slines);
printf("Current screen only has %d lines. Unable to restore game\n",LINES);
return(FALSE);
}
if (scols > COLS)
{
printf("Sorry, original game was played on a screen with %d columns.\n",scols);
printf("Current screen only has %d columns. Unable to restore game\n",COLS);
return(FALSE);
}
hw = newwin(LINES, COLS, 0, 0);
keypad(stdscr,1);
mpos = 0;
mvprintw(0, 0, "%s: %s", file, ctime(&sbuf2.st_mtime));
/*
* defeat multiple restarting from the same place
*/
#ifdef WIZARD
if (!wizard)
#endif
if (sbuf2.st_nlink != 1 || syml)
{
printf("Cannot restore from a linked file\n");
return FALSE;
}
if (rs_restore_file(inf) == FALSE)
{
endwin();
printf("Cannot restore file\n");
return(FALSE);
}
#ifdef SIGTSTP
signal(SIGTSTP, tstp);
#endif
environ = envp;
strcpy(file_name, file);
setup();
clearok(curscr, TRUE);
touchwin(stdscr);
srand(getpid());
msg("file name: %s", file);
status();
playit();
return 0;
}
/*
* encwrite:
* Perform an encrypted write
*/
encwrite(starta, size, outf)
void *starta;
unsigned int size;
register FILE *outf;
{
register char *ep;
register char *start = (char *) starta;
ep = encstr;
while (size--)
{
putc(*start++ ^ *ep++, outf);
if (*ep == '\0')
ep = encstr;
}
}
/*
* encread:
* Perform an encrypted read
*/
encread(starta, size, inf)
register void *starta;
unsigned int size;
register int inf;
{
register char *ep;
register int read_size;
register char *start = (char *) starta;
if ((read_size = read(inf, start, size)) == -1 || read_size == 0)
return read_size;
ep = encstr;
while (size--)
{
*start++ ^= *ep++;
if (*ep == '\0')
ep = encstr;
}
return read_size;
}

269
rogue4/scrolls.c Normal file
View file

@ -0,0 +1,269 @@
/*
* Read a scroll and let it happen
*
* @(#)scrolls.c 4.21 (Berkeley) 4/6/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <ctype.h>
#include "rogue.h"
/*
* read_scroll:
* Read a scroll from the pack and do the appropriate thing
*/
read_scroll()
{
register THING *obj;
register int y, x;
register char ch;
register THING *op;
register int index;
register bool discardit = FALSE;
obj = get_item("read", SCROLL);
if (obj == NULL)
return;
if (obj->o_type != SCROLL)
{
if (!terse)
msg("there is nothing on it to read");
else
msg("nothing to read");
return;
}
msg("as you read the scroll, it vanishes");
/*
* Calculate the effect it has on the poor guy.
*/
if (obj == cur_weapon)
cur_weapon = NULL;
switch (obj->o_which)
{
case S_CONFUSE:
/*
* Scroll of monster confusion. Give him that power.
*/
player.t_flags |= CANHUH;
msg("your hands begin to glow red");
when S_ARMOR:
if (cur_armor != NULL)
{
cur_armor->o_ac--;
cur_armor->o_flags &= ~ISCURSED;
msg("your armor glows faintly for a moment");
}
when S_HOLD:
/*
* Hold monster scroll. Stop all monsters within two spaces
* from chasing after the hero.
*/
for (x = hero.x - 2; x <= hero.x + 2; x++)
if (x >= 0 && x < COLS)
for (y = hero.y - 2; y <= hero.y + 2; y++)
if (y >= 0 && y <= LINES - 1)
if ((op = moat(y, x)) != NULL)
{
op->t_flags &= ~ISRUN;
op->t_flags |= ISHELD;
}
when S_SLEEP:
/*
* Scroll which makes you fall asleep
*/
s_know[S_SLEEP] = TRUE;
no_command += rnd(SLEEPTIME) + 4;
player.t_flags &= ~ISRUN;
msg("you fall asleep");
when S_CREATE:
/*
* Create a monster
* First look in a circle around him, next try his room
* otherwise give up
*/
{
register bool appear = 0;
coord mp;
/*
* Search for an open place
*/
for (y = hero.y - 1; y <= hero.y + 1; y++)
for (x = hero.x - 1; x <= hero.x + 1; x++)
{
/*
* Don't put a monster in top of the player.
*/
if (y == hero.y && x == hero.x)
continue;
/*
* Or anything else nasty
* Also avoid a mimic which is disguised as scroll
*/
if (moat(y, x) == NULL && step_ok(ch = winat(y, x)))
{
if (ch == SCROLL
&& find_obj(y, x)->o_which == S_SCARE)
continue;
if (rnd(++appear) == 0)
{
mp.y = y;
mp.x = x;
}
}
}
if (appear)
{
op = new_item();
new_monster(op, randmonster(FALSE), &mp);
}
else
msg("you hear a faint cry of anguish in the distance");
}
when S_IDENT:
/*
* Identify, let the rogue figure something out
*/
s_know[S_IDENT] = TRUE;
msg("this scroll is an identify scroll");
whatis(TRUE);
when S_MAP:
/*
* Scroll of magic mapping.
*/
s_know[S_MAP] = TRUE;
msg("oh, now this scroll has a map on it");
/*
* Take all the things we want to keep hidden out of the window
*/
for (y = 1; y < LINES - 1; y++)
for (x = 0; x < COLS; x++)
{
index = INDEX(y, x);
switch (ch = _level[index])
{
case '-':
case '|':
if (!(_flags[index] & F_REAL))
{
ch = _level[index] = DOOR;
_flags[index] &= ~F_REAL;
}
case PASSAGE:
_flags[index] |= F_SEEN;
case DOOR:
case STAIRS:
if ((op = moat(y, x)) != NULL)
if (op->t_oldch == ' ')
op->t_oldch = ch;
break;
default:
ch = ' ';
}
if (ch != ' ')
mvaddch(y, x, ch);
}
when S_GFIND:
/*
* Potion of gold detection
*/
ch = FALSE;
wclear(hw);
for (op = lvl_obj; op != NULL; op = next(op))
if (op->o_type == GOLD)
{
ch = TRUE;
mvwaddch(hw, op->o_pos.y, op->o_pos.x, GOLD);
}
if (ch)
{
s_know[S_GFIND] = TRUE;
show_win(hw,
"You begin to feel greedy and you sense gold.--More--");
}
else
msg("you feel a pull downward");
when S_TELEP:
/*
* Scroll of teleportation:
* Make him dissapear and reappear
*/
{
register struct room *cur_room;
cur_room = proom;
teleport();
if (cur_room != proom)
s_know[S_TELEP] = TRUE;
}
when S_ENCH:
if (cur_weapon == NULL || cur_weapon->o_type != WEAPON)
msg("you feel a strange sense of loss");
else
{
cur_weapon->o_flags &= ~ISCURSED;
if (rnd(2) == 0)
cur_weapon->o_hplus++;
else
cur_weapon->o_dplus++;
msg("your %s glows blue for a moment", w_names[cur_weapon->o_which]);
}
when S_SCARE:
/*
* Reading it is a mistake and produces laughter at the
* poor rogue's boo boo.
*/
msg("you hear maniacal laughter in the distance");
when S_REMOVE:
if (cur_armor != NULL)
cur_armor->o_flags &= ~ISCURSED;
if (cur_weapon != NULL)
cur_weapon->o_flags &= ~ISCURSED;
if (cur_ring[LEFT] != NULL)
cur_ring[LEFT]->o_flags &= ~ISCURSED;
if (cur_ring[RIGHT] != NULL)
cur_ring[RIGHT]->o_flags &= ~ISCURSED;
msg("you feel as if somebody is watching over you");
when S_AGGR:
/*
* This scroll aggravates all the monsters on the current
* level and sets them running towards the hero
*/
aggravate();
msg("you hear a high pitched humming noise");
when S_NOP:
msg("this scroll seems to be blank");
when S_GENOCIDE:
s_know[S_GENOCIDE] = TRUE;
msg("you have been granted the boon of genocide");
genocide();
otherwise:
msg("what a puzzling scroll!");
return;
}
look(TRUE); /* put the result of the scroll on the screen */
status();
/*
* Get rid of the thing
*/
inpack--;
if (obj->o_count > 1)
obj->o_count--;
else
{
detach(pack, obj);
discardit = TRUE;
}
call_it(s_know[obj->o_which], &s_guess[obj->o_which]);
if (discardit)
discard(obj);
}

2161
rogue4/state.c Normal file

File diff suppressed because it is too large Load diff

461
rogue4/sticks.c Normal file
View file

@ -0,0 +1,461 @@
/*
* Functions to implement the various sticks one might find
* while wandering around the dungeon.
*
* @(#)sticks.c 4.22 (Berkeley) 5/19/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"
/*
* fix_stick:
* Set up a new stick
*/
fix_stick(cur)
register THING *cur;
{
if (strcmp(ws_type[cur->o_which], "staff") == 0)
strcpy(cur->o_damage,"2d3");
else
strcpy(cur->o_damage,"1d1");
strcpy(cur->o_hurldmg,"1d1");
cur->o_charges = 3 + rnd(5);
switch (cur->o_which)
{
case WS_HIT:
cur->o_hplus = 100;
cur->o_dplus = 3;
strcpy(cur->o_damage,"1d8");
when WS_LIGHT:
cur->o_charges = 10 + rnd(10);
}
}
/*
* do_zap:
* Perform a zap with a wand
*/
do_zap()
{
register THING *obj, *tp;
register int y, x;
register char *name;
if ((obj = get_item("zap with", STICK)) == NULL)
return;
if (obj->o_type != STICK)
{
after = FALSE;
msg("you can't zap with that!");
return;
}
if (obj->o_charges == 0)
{
msg("nothing happens");
return;
}
switch (obj->o_which)
{
case WS_LIGHT:
/*
* Reddy Kilowat wand. Light up the room
*/
ws_know[WS_LIGHT] = TRUE;
if (proom->r_flags & ISGONE)
msg("the corridor glows and then fades");
else
{
proom->r_flags &= ~ISDARK;
/*
* Light the room and put the player back up
*/
enter_room(&hero);
addmsg("the room is lit");
if (!terse)
addmsg(" by a shimmering blue light");
endmsg();
}
when WS_DRAIN:
/*
* Take away 1/2 of hero's hit points, then take it away
* evenly from the monsters in the room (or next to hero
* if he is in a passage)
*/
if (pstats.s_hpt < 2)
{
msg("you are too weak to use it");
return;
}
else
drain();
when WS_POLYMORPH:
case WS_TELAWAY:
case WS_TELTO:
case WS_CANCEL:
{
register char monster, oldch;
register int rm;
y = hero.y;
x = hero.x;
while (step_ok(winat(y, x)))
{
y += delta.y;
x += delta.x;
}
if ((tp = moat(y, x)) != NULL)
{
register char omonst;
omonst = monster = tp->t_type;
if (monster == 'F')
player.t_flags &= ~ISHELD;
if (obj->o_which == WS_POLYMORPH)
{
register THING *pp;
pp = tp->t_pack;
detach(mlist, tp);
if (see_monst(tp))
mvaddch(y, x, chat(y, x));
oldch = tp->t_oldch;
delta.y = y;
delta.x = x;
new_monster(tp, monster = rnd(26) + 'A', &delta);
if (see_monst(tp))
mvaddch(y, x, monster);
tp->t_oldch = oldch;
tp->t_pack = pp;
ws_know[WS_POLYMORPH] |= (monster != omonst);
}
else if (obj->o_which == WS_CANCEL)
{
tp->t_flags |= ISCANC;
tp->t_flags &= ~(ISINVIS|CANHUH);
tp->t_disguise = tp->t_type;
}
else
{
if (isupper(toascii(mvinch(y,x))))
mvaddch(y, x, tp->t_oldch);
if (obj->o_which == WS_TELAWAY)
{
do
{
rm = rnd_room();
rnd_pos(&rooms[rm], &tp->t_pos);
} until (winat(tp->t_pos.y, tp->t_pos.x) == FLOOR);
tp->t_room = roomin(&tp->t_pos);
tp->t_oldch = mvinch(tp->t_pos.y, tp->t_pos.x);
if (see_monst(tp))
mvaddch(tp->t_pos.y, tp->t_pos.x, tp->t_disguise);
else if (on(player, SEEMONST))
{
standout();
mvaddch(tp->t_pos.y, tp->t_pos.x, tp->t_disguise);
standend();
}
}
else
{
tp->t_pos.y = hero.y + delta.y;
tp->t_pos.x = hero.x + delta.x;
if (tp->t_pos.y != y || tp->t_pos.x != x)
tp->t_oldch = mvinch(tp->t_pos.y, tp->t_pos.x);
}
moat(y, x) = NULL;
moat(tp->t_pos.y, tp->t_pos.x) = tp;
if (tp->t_type == 'F')
player.t_flags &= ~ISHELD;
}
tp->t_dest = &hero;
tp->t_flags |= ISRUN;
}
}
when WS_MISSILE:
{
THING bolt;
ws_know[WS_MISSILE] = TRUE;
bolt.o_type = '*';
strcpy(bolt.o_hurldmg,"1d4");
bolt.o_hplus = 100;
bolt.o_dplus = 1;
bolt.o_flags = ISMISL;
if (cur_weapon != NULL)
bolt.o_launch = cur_weapon->o_which;
do_motion(&bolt, delta.y, delta.x);
if ((tp = moat(bolt.o_pos.y, bolt.o_pos.x)) != NULL && !save_throw(VS_MAGIC, tp))
hit_monster(unc(bolt.o_pos), &bolt);
else if (terse)
msg("missle vanishes");
else
msg("the missle vanishes with a puff of smoke");
}
when WS_HIT:
delta.y += hero.y;
delta.x += hero.x;
if ((tp = moat(delta.y, delta.x)) != NULL)
{
if (rnd(20) == 0)
{
strcpy(obj->o_damage,"3d8");
obj->o_dplus = 9;
}
else
{
strcpy(obj->o_damage,"1d8");
obj->o_dplus = 3;
}
fight(&delta, tp->t_type, obj, FALSE);
}
when WS_HASTE_M:
case WS_SLOW_M:
y = hero.y;
x = hero.x;
while (step_ok(winat(y, x)))
{
y += delta.y;
x += delta.x;
}
if ((tp = moat(y, x)) != NULL)
{
if (obj->o_which == WS_HASTE_M)
{
if (on(*tp, ISSLOW))
tp->t_flags &= ~ISSLOW;
else
tp->t_flags |= ISHASTE;
}
else
{
if (on(*tp, ISHASTE))
tp->t_flags &= ~ISHASTE;
else
tp->t_flags |= ISSLOW;
tp->t_turn = TRUE;
}
delta.y = y;
delta.x = x;
runto(&delta, &hero);
}
when WS_ELECT:
case WS_FIRE:
case WS_COLD:
if (obj->o_which == WS_ELECT)
name = "bolt";
else if (obj->o_which == WS_FIRE)
name = "flame";
else
name = "ice";
fire_bolt(&hero, &delta, name);
ws_know[obj->o_which] = TRUE;
when WS_NOP:
otherwise:
msg("what a bizarre schtick!");
}
obj->o_charges--;
}
/*
* drain:
* Do drain hit points from player shtick
*/
drain()
{
register THING *mp;
register int cnt;
register struct room *corp;
register THING **dp;
register bool inpass;
static THING *drainee[40];
/*
* First cnt how many things we need to spread the hit points among
*/
cnt = 0;
if (chat(hero.y, hero.x) == DOOR)
corp = &passages[flat(hero.y, hero.x) & F_PNUM];
else
corp = NULL;
inpass = (proom->r_flags & ISGONE);
dp = drainee;
for (mp = mlist; mp != NULL; mp = next(mp))
if (mp->t_room == proom || mp->t_room == corp ||
(inpass && chat(mp->t_pos.y, mp->t_pos.x) == DOOR &&
&passages[flat(mp->t_pos.y, mp->t_pos.x) & F_PNUM] == proom))
*dp++ = mp;
if ((cnt = dp - drainee) == 0)
{
msg("you have a tingling feeling");
return;
}
*dp = NULL;
pstats.s_hpt /= 2;
cnt = pstats.s_hpt / cnt;
/*
* Now zot all of the monsters
*/
for (dp = drainee; *dp; dp++)
{
mp = *dp;
if ((mp->t_stats.s_hpt -= cnt) <= 0)
killed(mp, see_monst(mp));
else
runto(&mp->t_pos, &hero);
}
}
/*
* fire_bolt:
* Fire a bolt in a given direction from a specific starting place
*/
fire_bolt(start, dir, name)
coord *start, *dir;
char *name;
{
register char dirch, ch;
register THING *tp;
register bool hit_hero, used, changed;
register int i, j;
coord pos;
coord spotpos[BOLT_LENGTH];
THING bolt;
bolt.o_type = WEAPON;
bolt.o_which = FLAME;
strcpy(bolt.o_hurldmg,"6d6");
bolt.o_hplus = 100;
bolt.o_dplus = 0;
bolt.o_flags = 0;
w_names[FLAME] = name;
switch (dir->y + dir->x)
{
case 0: dirch = '/';
when 1: case -1: dirch = (dir->y == 0 ? '-' : '|');
when 2: case -2: dirch = '\\';
}
pos = *start;
hit_hero = (start != &hero);
used = FALSE;
changed = FALSE;
for (i = 0; i < BOLT_LENGTH && !used; i++)
{
pos.y += dir->y;
pos.x += dir->x;
ch = winat(pos.y, pos.x);
spotpos[i] = pos;
switch (ch)
{
case DOOR:
/*
* this code is necessary if the hero is on a door
* and he fires at the wall the door is in, it would
* otherwise loop infinitely
* It is also needed if a dragon flames at the hero.
* If the hero is at a door, the dragon flame would bounce
* and could kill other monsters inadvertly.
*/
if (ce(hero, pos))
goto def;
/* FALLTHROUGH */
case '|':
case '-':
case ' ':
if (!changed)
hit_hero = !hit_hero;
changed = FALSE;
dir->y = -dir->y;
dir->x = -dir->x;
i--;
msg("the %s bounces", name);
break;
default:
def:
if (!hit_hero && (tp = moat(pos.y, pos.x)) != NULL)
{
hit_hero = TRUE;
changed = !changed;
tp->t_oldch = chat(pos.y, pos.x);
if (!save_throw(VS_MAGIC, tp))
{
bolt.o_pos = pos;
used = TRUE;
if (tp->t_type == 'D' && strcmp(name, "flame") == 0)
{
addmsg("the flame bounces");
if (!terse)
msg("off the dragon");
endmsg();
}
else
hit_monster(unc(pos), &bolt);
}
else if (ch != 'M' || tp->t_disguise == 'M')
{
if (start == &hero)
runto(&pos, &hero);
if (terse)
msg("%s misses", name);
else
msg("the %s whizzes past the %s", name, monsters[ch-'A'].m_name);
}
}
else if (hit_hero && ce(pos, hero))
{
hit_hero = FALSE;
changed = !changed;
if (!save(VS_MAGIC))
{
if ((pstats.s_hpt -= roll(6, 6)) <= 0)
if (start == &hero)
death('b');
else
death(moat(start->y, start->x)->t_type);
used = TRUE;
if (terse)
msg("the %s hits", name);
else
msg("you are hit by the %s", name);
}
else
msg("the %s whizzes by you", name);
}
mvaddch(pos.y, pos.x, dirch);
refresh();
}
}
for (j = 0; j < i; j++)
mvaddch(spotpos[j].y, spotpos[j].x, chat(spotpos[j].y, spotpos[j].x));
}
/*
* charge_str:
* Return an appropriate string for a wand charge
*/
char *
charge_str(obj)
register THING *obj;
{
static char buf[20];
if (!(obj->o_flags & ISKNOW))
buf[0] = '\0';
else if (terse)
sprintf(buf, " [%d]", obj->o_charges);
else
sprintf(buf, " [%d charges]", obj->o_charges);
return buf;
}

616
rogue4/things.c Normal file
View file

@ -0,0 +1,616 @@
/*
* Contains functions for dealing with things like potions, scrolls,
* and other items.
*
* @(#)things.c 4.26 (Berkeley) 5/18/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"
bool got_genocide = FALSE;
/*
* inv_name:
* Return the name of something as it would appear in an
* inventory.
*/
char *
inv_name(obj, drop)
register THING *obj;
register bool drop;
{
register char *pb;
pb = prbuf;
switch (obj->o_type)
{
case SCROLL:
if (obj->o_count == 1)
{
strcpy(pb, "A scroll ");
pb = &prbuf[9];
}
else
{
sprintf(pb, "%d scrolls ", obj->o_count);
pb = &prbuf[strlen(prbuf)];
}
if (s_know[obj->o_which])
sprintf(pb, "of %s", s_magic[obj->o_which].mi_name);
else if (s_guess[obj->o_which])
sprintf(pb, "called %s", s_guess[obj->o_which]);
else
sprintf(pb, "titled '%s'", s_names[obj->o_which]);
when POTION:
if (obj->o_count == 1)
{
strcpy(pb, "A potion ");
pb = &prbuf[9];
}
else
{
sprintf(pb, "%d potions ", obj->o_count);
pb = &pb[strlen(prbuf)];
}
if (p_know[obj->o_which])
sprintf(pb, "of %s(%s)", p_magic[obj->o_which].mi_name,
p_colors[obj->o_which]);
else if (p_guess[obj->o_which])
sprintf(pb, "called %s(%s)", p_guess[obj->o_which],
p_colors[obj->o_which]);
else if (obj->o_count == 1)
sprintf(prbuf, "A%s %s potion", vowelstr(p_colors[obj->o_which]),
p_colors[obj->o_which]);
else
sprintf(prbuf, "%d %s potions", obj->o_count,
p_colors[obj->o_which]);
when FOOD:
if (obj->o_which == 1)
if (obj->o_count == 1)
sprintf(pb, "A%s %s", vowelstr(fruit), fruit);
else
sprintf(pb, "%d %ss", obj->o_count, fruit);
else
if (obj->o_count == 1)
strcpy(pb, "Some food");
else
sprintf(pb, "%d rations of food", obj->o_count);
when WEAPON:
if (obj->o_count > 1)
sprintf(pb, "%d ", obj->o_count);
else
sprintf(pb, "A%s ", vowelstr(w_names[obj->o_which]));
pb = &prbuf[strlen(prbuf)];
if (obj->o_flags & ISKNOW)
sprintf(pb, "%s %s", num(obj->o_hplus, obj->o_dplus, WEAPON),
w_names[obj->o_which]);
else
sprintf(pb, "%s", w_names[obj->o_which]);
if (obj->o_count > 1)
strcat(pb, "s");
when ARMOR:
if (obj->o_flags & ISKNOW)
{
sprintf(pb, "%s %s [",
num(a_class[obj->o_which] - obj->o_ac, 0, ARMOR),
a_names[obj->o_which]);
if (!terse)
strcat(pb, "armor class ");
pb = &prbuf[strlen(prbuf)];
sprintf(pb, "%d]", obj->o_ac);
}
else
sprintf(pb, "%s", a_names[obj->o_which]);
when AMULET:
strcpy(pb, "The Amulet of Yendor");
when STICK:
sprintf(pb, "A%s %s ", vowelstr(ws_type[obj->o_which]),
ws_type[obj->o_which]);
pb = &prbuf[strlen(prbuf)];
if (ws_know[obj->o_which])
sprintf(pb, "of %s%s(%s)", ws_magic[obj->o_which].mi_name,
charge_str(obj), ws_made[obj->o_which]);
else if (ws_guess[obj->o_which])
sprintf(pb, "called %s(%s)", ws_guess[obj->o_which],
ws_made[obj->o_which]);
else
sprintf(pb = &prbuf[1], "%s %s %s",
vowelstr(ws_made[obj->o_which]), ws_made[obj->o_which],
ws_type[obj->o_which]);
when RING:
if (r_know[obj->o_which])
sprintf(pb, "A%s ring of %s(%s)", ring_num(obj),
r_magic[obj->o_which].mi_name, r_stones[obj->o_which]);
else if (r_guess[obj->o_which])
sprintf(pb, "A ring called %s(%s)",
r_guess[obj->o_which], r_stones[obj->o_which]);
else
sprintf(pb, "A%s %s ring", vowelstr(r_stones[obj->o_which]),
r_stones[obj->o_which]);
when GOLD:
sprintf(pb, "%d pieces of gold", obj->o_goldval);
#ifdef WIZARD
otherwise:
debug("Picked up something funny %s", unctrol(obj->o_type));
sprintf(pb, "Something bizarre %s", unctrol(obj->o_type));
#endif
}
if (obj == cur_armor)
strcat(pb, " (being worn)");
if (obj == cur_weapon)
strcat(pb, " (weapon in hand)");
if (obj == cur_ring[LEFT])
strcat(pb, " (on left hand)");
else if (obj == cur_ring[RIGHT])
strcat(pb, " (on right hand)");
if (drop && isupper(prbuf[0]))
prbuf[0] = tolower(prbuf[0]);
else if (!drop && islower(*prbuf))
*prbuf = toupper(*prbuf);
return prbuf;
}
/*
* drop:
* Put something down
*/
drop()
{
register char ch;
register THING *nobj, *op;
ch = chat(hero.y, hero.x);
if (ch != FLOOR && ch != PASSAGE)
{
after = FALSE;
msg("there is something there already");
return;
}
if ((op = get_item("drop", 0)) == NULL)
return;
if (!dropcheck(op))
return;
/*
* Take it out of the pack
*/
if (op->o_count >= 2 && op->o_type != WEAPON)
{
op->o_count--;
nobj = new_item();
*nobj = *op;
nobj->o_count = 1;
op = nobj;
if (op->o_group != 0)
inpack++;
}
else
detach(pack, op);
inpack--;
/*
* Link it into the level object list
*/
attach(lvl_obj, op);
chat(hero.y, hero.x) = op->o_type;
flat(hero.y, hero.x) |= F_DROPPED;
op->o_pos = hero;
if (op->o_type == AMULET)
amulet = FALSE;
msg("dropped %s", inv_name(op, TRUE));
}
/*
* dropcheck:
* Do special checks for dropping or unweilding|unwearing|unringing
*/
dropcheck(op)
register THING *op;
{
if (op == NULL)
return TRUE;
if (op != cur_armor && op != cur_weapon
&& op != cur_ring[LEFT] && op != cur_ring[RIGHT])
return TRUE;
if (op->o_flags & ISCURSED)
{
msg("you can't. It appears to be cursed");
return FALSE;
}
if (op == cur_weapon)
cur_weapon = NULL;
else if (op == cur_armor)
{
waste_time();
cur_armor = NULL;
}
else
{
cur_ring[op == cur_ring[LEFT] ? LEFT : RIGHT] = NULL;
switch (op->o_which)
{
case R_ADDSTR:
chg_str(-op->o_ac);
break;
case R_SEEINVIS:
unsee();
extinguish(unsee);
break;
}
}
return TRUE;
}
/*
* new_thing:
* Return a new thing
*/
THING *
new_thing()
{
register THING *cur;
register int j, k;
cur = new_item();
cur->o_hplus = cur->o_dplus = 0;
strcpy(cur->o_damage,"0d0");
strcpy(cur->o_hurldmg,"0d0");
cur->o_ac = 11;
cur->o_count = 1;
cur->o_group = 0;
cur->o_flags = 0;
/*
* Decide what kind of object it will be
* If we haven't had food for a while, let it be food.
*/
switch (no_food > 3 ? 2 : pick_one(things, NUMTHINGS))
{
case 0:
cur->o_type = POTION;
cur->o_which = pick_one(p_magic, MAXPOTIONS);
when 1:
cur->o_type = SCROLL;
cur->o_which = pick_one(s_magic, MAXSCROLLS);
/*
* Only one genocide scroll allowed per game, so if it's
* the second one, then turn it into a identify scroll
*/
if (cur->o_which == S_GENOCIDE)
if (got_genocide)
cur->o_which = S_IDENT;
else
got_genocide = TRUE;
when 2:
no_food = 0;
cur->o_type = FOOD;
if (rnd(10) != 0)
cur->o_which = 0;
else
cur->o_which = 1;
when 3:
cur->o_type = WEAPON;
cur->o_which = rnd(MAXWEAPONS);
init_weapon(cur, cur->o_which);
if ((k = rnd(100)) < 10)
{
cur->o_flags |= ISCURSED;
cur->o_hplus -= rnd(3) + 1;
}
else if (k < 15)
cur->o_hplus += rnd(3) + 1;
when 4:
cur->o_type = ARMOR;
for (j = 0, k = rnd(100); j < MAXARMORS; j++)
if (k < a_chances[j])
break;
#ifdef WIZARD
if (j == MAXARMORS)
{
debug("Picked a bad armor %d", k);
j = 0;
}
#endif
cur->o_which = j;
cur->o_ac = a_class[j];
if ((k = rnd(100)) < 20)
{
cur->o_flags |= ISCURSED;
cur->o_ac += rnd(3) + 1;
}
else if (k < 28)
cur->o_ac -= rnd(3) + 1;
when 5:
cur->o_type = RING;
cur->o_which = pick_one(r_magic, MAXRINGS);
switch (cur->o_which)
{
case R_ADDSTR:
case R_PROTECT:
case R_ADDHIT:
case R_ADDDAM:
if ((cur->o_ac = rnd(3)) == 0)
{
cur->o_ac = -1;
cur->o_flags |= ISCURSED;
}
when R_AGGR:
case R_TELEPORT:
cur->o_flags |= ISCURSED;
}
when 6:
cur->o_type = STICK;
cur->o_which = pick_one(ws_magic, MAXSTICKS);
fix_stick(cur);
#ifdef WIZARD
otherwise:
debug("Picked a bad kind of object");
wait_for(' ');
#endif
}
return cur;
}
/*
* pick_one:
* Pick an item out of a list of nitems possible magic items
*/
pick_one(magic, nitems)
register struct magic_item *magic;
int nitems;
{
register struct magic_item *end;
register int i;
register struct magic_item *start;
start = magic;
for (end = &magic[nitems], i = rnd(100); magic < end; magic++)
if (i < magic->mi_prob)
break;
if (magic == end)
{
#ifdef WIZARD
if (wizard)
{
msg("bad pick_one: %d from %d items", i, nitems);
for (magic = start; magic < end; magic++)
msg("%s: %d%%", magic->mi_name, magic->mi_prob);
}
#endif
magic = start;
}
return magic - start;
}
/*
* discovered:
* list what the player has discovered in this game of a certain type
*/
static int line_cnt = 0;
static bool newpage = FALSE;
static char *lastfmt, *lastarg;
discovered()
{
register char ch;
register bool disc_list;
do {
disc_list = FALSE;
if (!terse)
addmsg("for ");
addmsg("what type");
if (!terse)
addmsg(" of object do you want a list");
msg("? (* for all)");
ch = readchar();
switch (ch)
{
case ESCAPE:
msg("");
return;
case POTION:
case SCROLL:
case RING:
case STICK:
case '*':
disc_list = TRUE;
break;
default:
if (terse)
msg("Not a type");
else
msg("Please type one of %c%c%c%c (ESCAPE to quit)", POTION, SCROLL, RING, STICK);
}
} while (!disc_list);
if (ch == '*')
{
print_disc(POTION);
add_line("");
print_disc(SCROLL);
add_line("");
print_disc(RING);
add_line("");
print_disc(STICK);
end_line();
}
else
{
print_disc(ch);
end_line();
}
}
/*
* print_disc:
* Print what we've discovered of type 'type'
*/
#define MAX(a,b,c,d) (a > b ? (a > c ? (a > d ? a : d) : (c > d ? c : d)) : (b > c ? (b > d ? b : d) : (c > d ? c : d)))
print_disc(type)
char type;
{
register bool *know = NULL;
register char **guess = NULL;
register int i, maxnum = 0, num_found;
static THING obj;
static short order[MAX(MAXSCROLLS, MAXPOTIONS, MAXRINGS, MAXSTICKS)];
switch (type)
{
case SCROLL:
maxnum = MAXSCROLLS;
know = s_know;
guess = s_guess;
break;
case POTION:
maxnum = MAXPOTIONS;
know = p_know;
guess = p_guess;
break;
case RING:
maxnum = MAXRINGS;
know = r_know;
guess = r_guess;
break;
case STICK:
maxnum = MAXSTICKS;
know = ws_know;
guess = ws_guess;
break;
}
set_order(order, maxnum);
obj.o_count = 1;
obj.o_flags = 0;
num_found = 0;
for (i = 0; i < maxnum; i++)
if (know[order[i]] || guess[order[i]])
{
obj.o_type = type;
obj.o_which = order[i];
add_line("%s", inv_name(&obj, FALSE));
num_found++;
}
if (num_found == 0)
add_line(nothing(type));
}
/*
* set_order:
* Set up order for list
*/
set_order(order, numthings)
short *order;
int numthings;
{
register int i, r, t;
for (i = 0; i< numthings; i++)
order[i] = i;
for (i = numthings; i > 0; i--)
{
r = rnd(i);
t = order[i - 1];
order[i - 1] = order[r];
order[r] = t;
}
}
/*
* add_line:
* Add a line to the list of discoveries
*/
/* VARARGS1 */
add_line(fmt, arg)
char *fmt, *arg;
{
if (line_cnt == 0)
{
wclear(hw);
if (slow_invent)
mpos = 0;
}
if (slow_invent)
{
if (*fmt != '\0')
msg(fmt, arg);
line_cnt++;
}
else
{
if (line_cnt >= LINES - 1 || fmt == NULL)
{
mvwaddstr(hw, LINES - 1, 0, "--Press space to continue--");
wrefresh(hw);
w_wait_for(hw,' ');
clearok(curscr, TRUE);
wclear(hw);
touchwin(stdscr);
newpage = TRUE;
line_cnt = 0;
}
if (fmt != NULL && !(line_cnt == 0 && *fmt == '\0'))
{
mvwprintw(hw, line_cnt++, 0, fmt, arg);
lastfmt = fmt;
lastarg = arg;
}
}
}
/*
* end_line:
* End the list of lines
*/
end_line()
{
if (!slow_invent)
if (line_cnt == 1 && !newpage)
{
mpos = 0;
msg(lastfmt, lastarg);
}
else
add_line(NULL);
line_cnt = 0;
newpage = FALSE;
}
/*
* nothing:
* Set up prbuf so that message for "nothing found" is there
*/
char *
nothing(type)
register char type;
{
register char *sp, *tystr = NULL;
if (terse)
sprintf(prbuf, "Nothing");
else
sprintf(prbuf, "Haven't discovered anything");
if (type != '*')
{
sp = &prbuf[strlen(prbuf)];
switch (type)
{
case POTION: tystr = "potion";
when SCROLL: tystr = "scroll";
when RING: tystr = "ring";
when STICK: tystr = "stick";
}
sprintf(sp, " about any %ss", tystr);
}
return prbuf;
}

18
rogue4/vers.c Normal file
View file

@ -0,0 +1,18 @@
/*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Version number. Whenever a new version number is desired, use sccs
* to get vers.c. encstr is declared here to force it to be loaded
* before the version number, and therefore not to be written in saved
* games.
*/
char *release = "5.2";
char encstr[] = "\211g\321_-\251b\324\237;\255\263\214g\"\327\224.,\252|9\265=\357+\343;\311]\341`\251\b\231)\266Y\325\251";
char version[] = "@(#)vers.c 5.2 (Berkeley) 4/11/82";

285
rogue4/weapons.c Normal file
View file

@ -0,0 +1,285 @@
/*
* Functions for dealing with problems brought about by weapons
*
* @(#)weapons.c 4.14 (Berkeley) 4/6/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <curses.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"
#define NONE 100
static struct init_weps {
char *iw_dam; /* Damage when wielded */
char *iw_hrl; /* Damage when thrown */
char iw_launch; /* Launching weapon */
int iw_flags; /* Miscellaneous flags */
} init_dam[MAXWEAPONS] = {
"2d4", "1d3", NONE, 0, /* Mace */
"3d4", "1d2", NONE, 0, /* Long sword */
"1d1", "1d1", NONE, 0, /* Bow */
"1d1", "2d3", BOW, ISMANY|ISMISL, /* Arrow */
"1d6", "1d4", NONE, ISMISL, /* Dagger */
"4d4", "1d2", NONE, 0, /* 2h sword */
"1d1", "1d3", NONE, ISMANY|ISMISL, /* Dart */
"1d1", "1d1", NONE, 0, /* Crossbow */
"1d2", "2d5", CROSSBOW, ISMANY|ISMISL, /* Crossbow bolt */
"2d3", "1d6", NONE, ISMISL, /* Spear */
};
/*
* missile:
* Fire a missile in a given direction
*/
missile(ydelta, xdelta)
int ydelta, xdelta;
{
register THING *obj, *nitem;
/*
* Get which thing we are hurling
*/
if ((obj = get_item("throw", WEAPON)) == NULL)
return;
if (!dropcheck(obj) || is_current(obj))
return;
/*
* Get rid of the thing. If it is a non-multiple item object, or
* if it is the last thing, just drop it. Otherwise, create a new
* item with a count of one.
*/
if (obj->o_count < 2)
{
detach(pack, obj);
inpack--;
}
else
{
obj->o_count--;
if (obj->o_group == 0)
inpack--;
nitem = new_item();
*nitem = *obj;
nitem->o_count = 1;
obj = nitem;
}
do_motion(obj, ydelta, xdelta);
/*
* AHA! Here it has hit something. If it is a wall or a door,
* or if it misses (combat) the monster, put it on the floor
*/
if (moat(obj->o_pos.y, obj->o_pos.x) == NULL
|| !hit_monster(unc(obj->o_pos), obj))
fall(obj, TRUE);
}
/*
* do_motion:
* Do the actual motion on the screen done by an object traveling
* across the room
*/
do_motion(obj, ydelta, xdelta)
register THING *obj;
register int ydelta, xdelta;
{
/*
* Come fly with us ...
*/
obj->o_pos = hero;
for (;;)
{
register int ch;
/*
* Erase the old one
*/
if (!ce(obj->o_pos, hero) && cansee(unc(obj->o_pos)))
mvaddch(obj->o_pos.y, obj->o_pos.x, chat(obj->o_pos.y, obj->o_pos.x));
/*
* Get the new position
*/
obj->o_pos.y += ydelta;
obj->o_pos.x += xdelta;
if (step_ok(ch = winat(obj->o_pos.y, obj->o_pos.x)) && ch != DOOR)
{
/*
* It hasn't hit anything yet, so display it
* If it alright.
*/
if (cansee(unc(obj->o_pos)))
{
mvaddch(obj->o_pos.y, obj->o_pos.x, obj->o_type);
refresh();
}
continue;
}
break;
}
}
/*
* fall:
* Drop an item someplace around here.
*/
fall(obj, pr)
register THING *obj;
register bool pr;
{
static coord fpos;
register int index;
if (fallpos(&obj->o_pos, &fpos, TRUE))
{
index = INDEX(fpos.y, fpos.x);
_level[index] = obj->o_type;
obj->o_pos = fpos;
if (cansee(fpos.y, fpos.x))
{
mvaddch(fpos.y, fpos.x, obj->o_type);
if (_monst[index] != NULL)
_monst[index]->t_oldch = obj->o_type;
}
attach(lvl_obj, obj);
return;
}
if (pr)
msg("the %s vanishes as it hits the ground",
/* BUGFIX: Identification trick */
(obj->o_type==WEAPON) ? w_names[obj->o_which] : inv_name(obj,TRUE));
discard(obj);
}
/*
* init_weapon:
* Set up the initial goodies for a weapon
*/
init_weapon(weap, type)
register THING *weap;
char type;
{
register struct init_weps *iwp;
iwp = &init_dam[type];
strncpy(weap->o_damage, iwp->iw_dam, 8);
strncpy(weap->o_hurldmg, iwp->iw_hrl, 8);
weap->o_launch = iwp->iw_launch;
weap->o_flags = iwp->iw_flags;
if (weap->o_flags & ISMANY)
{
weap->o_count = rnd(8) + 8;
weap->o_group = group++;
}
else
weap->o_count = 1;
}
/*
* hit_monster:
* Does the missile hit the monster?
*/
hit_monster(y, x, obj)
register int y, x;
THING *obj;
{
static coord mp;
mp.y = y;
mp.x = x;
return fight(&mp, moat(y, x)->t_type, obj, TRUE);
}
/*
* num:
* Figure out the plus number for armor/weapons
*/
char *
num(n1, n2, type)
register int n1, n2;
register char type;
{
static char numbuf[10];
sprintf(numbuf, "%s%d", n1 < 0 ? "" : "+", n1);
if (type == WEAPON)
sprintf(&numbuf[strlen(numbuf)], ",%s%d", n2 < 0 ? "" : "+", n2);
return numbuf;
}
/*
* wield:
* Pull out a certain weapon
*/
wield()
{
register THING *obj, *oweapon;
register char *sp;
oweapon = cur_weapon;
if (!dropcheck(cur_weapon))
{
cur_weapon = oweapon;
return;
}
cur_weapon = oweapon;
if ((obj = get_item("wield", WEAPON)) == NULL)
{
bad:
after = FALSE;
return;
}
if (obj->o_type == ARMOR)
{
msg("you can't wield armor");
goto bad;
}
if (is_current(obj))
goto bad;
sp = inv_name(obj, TRUE);
cur_weapon = obj;
if (!terse)
addmsg("you are now ");
msg("wielding %s (%c)", sp, pack_char(obj));
}
/*
* fallpos:
* Pick a random position around the give (y, x) coordinates
*/
fallpos(pos, newpos, pass)
register coord *pos, *newpos;
register bool pass;
{
register int y, x, cnt, ch;
cnt = 0;
for (y = pos->y - 1; y <= pos->y + 1; y++)
for (x = pos->x - 1; x <= pos->x + 1; x++)
{
/*
* check to make certain the spot is empty, if it is,
* put the object there, set it in the level list
* and re-draw the room if he can see it
*/
if (y == hero.y && x == hero.x)
continue;
if (((ch = chat(y, x)) == FLOOR || (pass && ch == PASSAGE))
&& rnd(++cnt) == 0)
{
newpos->y = y;
newpos->x = x;
}
}
return (cnt != 0);
}

238
rogue4/wizard.c Normal file
View file

@ -0,0 +1,238 @@
/*
* Special wizard commands (some of which are also non-wizard commands
* under strange circumstances)
*
* @(#)wizard.c 4.14 (Berkeley) 1/26/82
*/
#include <curses.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"
/*
* whatis:
* What a certin object is
*/
whatis(insist)
bool insist;
{
register THING *obj;
if (pack == NULL)
{
msg("You don't have anything in your pack to identify");
return;
}
for (;;)
if ((obj = get_item("identify", 0)) == NULL && insist)
msg("You must identify something");
else
break;
if (!insist && obj == NULL)
return;
switch (obj->o_type)
{
case SCROLL:
s_know[obj->o_which] = TRUE;
if (s_guess[obj->o_which])
{
free(s_guess[obj->o_which]);
s_guess[obj->o_which] = NULL;
}
when POTION:
p_know[obj->o_which] = TRUE;
if (p_guess[obj->o_which])
{
free(p_guess[obj->o_which]);
p_guess[obj->o_which] = NULL;
}
when STICK:
ws_know[obj->o_which] = TRUE;
obj->o_flags |= ISKNOW;
if (ws_guess[obj->o_which])
{
free(ws_guess[obj->o_which]);
ws_guess[obj->o_which] = NULL;
}
when WEAPON:
case ARMOR:
obj->o_flags |= ISKNOW;
when RING:
r_know[obj->o_which] = TRUE;
obj->o_flags |= ISKNOW;
if (r_guess[obj->o_which])
{
free(r_guess[obj->o_which]);
r_guess[obj->o_which] = NULL;
}
}
msg(inv_name(obj, FALSE));
}
#ifdef WIZARD
/*
* create_obj:
* Wizard command for getting anything he wants
*/
create_obj()
{
register THING *obj;
register char ch, bless;
obj = new_item();
msg("type of item: ");
obj->o_type = readchar();
mpos = 0;
msg("which %c do you want? (0-f)", obj->o_type);
obj->o_which = (isdigit((ch = readchar())) ? ch - '0' : ch - 'a' + 10);
obj->o_group = 0;
obj->o_count = 1;
mpos = 0;
if (obj->o_type == WEAPON || obj->o_type == ARMOR)
{
msg("blessing? (+,-,n)");
bless = readchar();
mpos = 0;
if (bless == '-')
obj->o_flags |= ISCURSED;
if (obj->o_type == WEAPON)
{
init_weapon(obj, obj->o_which);
if (bless == '-')
obj->o_hplus -= rnd(3)+1;
if (bless == '+')
obj->o_hplus += rnd(3)+1;
}
else
{
obj->o_ac = a_class[obj->o_which];
if (bless == '-')
obj->o_ac += rnd(3)+1;
if (bless == '+')
obj->o_ac -= rnd(3)+1;
}
}
else if (obj->o_type == RING)
switch (obj->o_which)
{
case R_PROTECT:
case R_ADDSTR:
case R_ADDHIT:
case R_ADDDAM:
msg("blessing? (+,-,n)");
bless = readchar();
mpos = 0;
if (bless == '-')
obj->o_flags |= ISCURSED;
obj->o_ac = (bless == '-' ? -1 : rnd(2) + 1);
when R_AGGR:
case R_TELEPORT:
obj->o_flags |= ISCURSED;
}
else if (obj->o_type == STICK)
fix_stick(obj);
else if (obj->o_type == GOLD)
{
msg("how much?");
get_num(&obj->o_goldval, stdscr);
}
add_pack(obj, FALSE);
}
#endif
/*
* telport:
* Bamf the hero someplace else
*/
teleport()
{
register int rm;
coord c;
mvaddch(hero.y, hero.x, chat(hero.y, hero.x));
do
{
rm = rnd_room();
rnd_pos(&rooms[rm], &c);
} until (step_ok(winat(c.y, c.x)));
if (&rooms[rm] != proom)
{
leave_room(&hero);
hero = c;
enter_room(&hero);
}
else
{
hero = c;
look(TRUE);
}
mvaddch(hero.y, hero.x, PLAYER);
/*
* turn off ISHELD in case teleportation was done while fighting
* a Fungi
*/
if (on(player, ISHELD)) {
player.t_flags &= ~ISHELD;
fung_hit = 0;
strcpy(monsters['F'-'A'].m_stats.s_dmg, "000d0");
}
no_move = 0;
count = 0;
running = FALSE;
flush_type();
return rm;
}
#ifdef WIZARD
/*
* passwd:
* See if user knows password
*/
passwd()
{
register char *sp, c;
char buf[MAXSTR], *xcrypt();
msg("wizard's Password:");
mpos = 0;
sp = buf;
while ((c = readchar()) != '\n' && c != '\r' && c != ESCAPE)
if (c == md_killchar())
sp = buf;
else if (c == md_erasechar() && sp > buf)
sp--;
else
*sp++ = c;
if (sp == buf)
return FALSE;
*sp = '\0';
return (strcmp(PASSWD, xcrypt(buf, "mT")) == 0);
}
/*
* show_map:
* Print out the map for the wizard
*/
show_map()
{
register int y, x, real;
wclear(hw);
for (y = 1; y < LINES - 1; y++)
for (x = 0; x < COLS; x++)
{
if (!(real = flat(y, x) & F_REAL))
wstandout(hw);
wmove(hw, y, x);
waddch(hw, chat(y, x));
if (!real)
wstandend(hw);
}
show_win(hw, "---More (level map)---");
}
#endif

684
rogue4/xcrypt.c Normal file
View file

@ -0,0 +1,684 @@
/*
* FreeSec: libcrypt
*
* Copyright (C) 1994 David Burren
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name(s) of the author(s) nor the names of other contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
* This is an original implementation of the DES and the crypt(3) interfaces
* by David Burren <davidb@werj.com.au>.
*
* An excellent reference on the underlying algorithm (and related
* algorithms) is:
*
* B. Schneier, Applied Cryptography: protocols, algorithms,
* and source code in C, John Wiley & Sons, 1994.
*
* Note that in that book's description of DES the lookups for the initial,
* pbox, and final permutations are inverted (this has been brought to the
* attention of the author). A list of errata for this book has been
* posted to the sci.crypt newsgroup by the author and is available for FTP.
*
* NOTE:
* This file has a static version of des_setkey() so that crypt.o exports
* only the crypt() interface. This is required to make binaries linked
* against crypt.o exportable or re-exportable from the USA.
*/
#include <sys/types.h>
#include <string.h>
extern unsigned long int md_ntohl(unsigned long int x);
extern unsigned long int md_htonl(unsigned long int x);
#define _PASSWORD_EFMT1 '_'
static unsigned char IP[64] = {
58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
};
static unsigned char inv_key_perm[64];
static unsigned char key_perm[56] = {
57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
};
static unsigned char key_shifts[16] = {
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
static unsigned char inv_comp_perm[56];
static unsigned char comp_perm[48] = {
14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
};
/*
* No E box is used, as it's replaced by some ANDs, shifts, and ORs.
*/
static unsigned char u_sbox[8][64];
static unsigned char sbox[8][64] = {
{
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
},
{
15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
},
{
10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
},
{
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
},
{
2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
},
{
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
},
{
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
},
{
13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
}
};
static unsigned char un_pbox[32];
static unsigned char pbox[32] = {
16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
};
static unsigned int bits32[32] =
{
0x80000000, 0x40000000, 0x20000000, 0x10000000,
0x08000000, 0x04000000, 0x02000000, 0x01000000,
0x00800000, 0x00400000, 0x00200000, 0x00100000,
0x00080000, 0x00040000, 0x00020000, 0x00010000,
0x00008000, 0x00004000, 0x00002000, 0x00001000,
0x00000800, 0x00000400, 0x00000200, 0x00000100,
0x00000080, 0x00000040, 0x00000020, 0x00000010,
0x00000008, 0x00000004, 0x00000002, 0x00000001
};
static unsigned char bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
static unsigned int saltbits;
static int old_salt;
static unsigned int *bits28, *bits24;
static unsigned char init_perm[64], final_perm[64];
static unsigned int en_keysl[16], en_keysr[16];
static unsigned int de_keysl[16], de_keysr[16];
static int des_initialised = 0;
static unsigned char m_sbox[4][4096];
static unsigned int psbox[4][256];
static unsigned int ip_maskl[8][256], ip_maskr[8][256];
static unsigned int fp_maskl[8][256], fp_maskr[8][256];
static unsigned int key_perm_maskl[8][128], key_perm_maskr[8][128];
static unsigned int comp_maskl[8][128], comp_maskr[8][128];
static unsigned int old_rawkey0, old_rawkey1;
static unsigned char ascii64[] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
/* 0000000000111111111122222222223333333333444444444455555555556666 */
/* 0123456789012345678901234567890123456789012345678901234567890123 */
static __inline int
ascii_to_bin(char ch)
{
if (ch > 'z')
return(0);
if (ch >= 'a')
return(ch - 'a' + 38);
if (ch > 'Z')
return(0);
if (ch >= 'A')
return(ch - 'A' + 12);
if (ch > '9')
return(0);
if (ch >= '.')
return(ch - '.');
return(0);
}
static void
des_init()
{
int i, j, b, k, inbit, obit;
unsigned int *p, *il, *ir, *fl, *fr;
old_rawkey0 = old_rawkey1 = 0;
saltbits = 0;
old_salt = 0;
bits24 = (bits28 = bits32 + 4) + 4;
/*
* Invert the S-boxes, reordering the input bits.
*/
for (i = 0; i < 8; i++)
for (j = 0; j < 64; j++) {
b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf);
u_sbox[i][j] = sbox[i][b];
}
/*
* Convert the inverted S-boxes into 4 arrays of 8 bits.
* Each will handle 12 bits of the S-box input.
*/
for (b = 0; b < 4; b++)
for (i = 0; i < 64; i++)
for (j = 0; j < 64; j++)
m_sbox[b][(i << 6) | j] =
(u_sbox[(b << 1)][i] << 4) |
u_sbox[(b << 1) + 1][j];
/*
* Set up the initial & final permutations into a useful form, and
* initialise the inverted key permutation.
*/
for (i = 0; i < 64; i++) {
init_perm[final_perm[i] = IP[i] - 1] = i;
inv_key_perm[i] = 255;
}
/*
* Invert the key permutation and initialise the inverted key
* compression permutation.
*/
for (i = 0; i < 56; i++) {
inv_key_perm[key_perm[i] - 1] = i;
inv_comp_perm[i] = 255;
}
/*
* Invert the key compression permutation.
*/
for (i = 0; i < 48; i++) {
inv_comp_perm[comp_perm[i] - 1] = i;
}
/*
* Set up the OR-mask arrays for the initial and final permutations,
* and for the key initial and compression permutations.
*/
for (k = 0; k < 8; k++) {
for (i = 0; i < 256; i++) {
*(il = &ip_maskl[k][i]) = 0;
*(ir = &ip_maskr[k][i]) = 0;
*(fl = &fp_maskl[k][i]) = 0;
*(fr = &fp_maskr[k][i]) = 0;
for (j = 0; j < 8; j++) {
inbit = 8 * k + j;
if (i & bits8[j]) {
if ((obit = init_perm[inbit]) < 32)
*il |= bits32[obit];
else
*ir |= bits32[obit-32];
if ((obit = final_perm[inbit]) < 32)
*fl |= bits32[obit];
else
*fr |= bits32[obit - 32];
}
}
}
for (i = 0; i < 128; i++) {
*(il = &key_perm_maskl[k][i]) = 0;
*(ir = &key_perm_maskr[k][i]) = 0;
for (j = 0; j < 7; j++) {
inbit = 8 * k + j;
if (i & bits8[j + 1]) {
if ((obit = inv_key_perm[inbit]) == 255)
continue;
if (obit < 28)
*il |= bits28[obit];
else
*ir |= bits28[obit - 28];
}
}
*(il = &comp_maskl[k][i]) = 0;
*(ir = &comp_maskr[k][i]) = 0;
for (j = 0; j < 7; j++) {
inbit = 7 * k + j;
if (i & bits8[j + 1]) {
if ((obit=inv_comp_perm[inbit]) == 255)
continue;
if (obit < 24)
*il |= bits24[obit];
else
*ir |= bits24[obit - 24];
}
}
}
}
/*
* Invert the P-box permutation, and convert into OR-masks for
* handling the output of the S-box arrays setup above.
*/
for (i = 0; i < 32; i++)
un_pbox[pbox[i] - 1] = i;
for (b = 0; b < 4; b++)
for (i = 0; i < 256; i++) {
*(p = &psbox[b][i]) = 0;
for (j = 0; j < 8; j++) {
if (i & bits8[j])
*p |= bits32[un_pbox[8 * b + j]];
}
}
des_initialised = 1;
}
static void
setup_salt(int salt)
{
unsigned int obit, saltbit;
int i;
if (salt == old_salt)
return;
old_salt = salt;
saltbits = 0;
saltbit = 1;
obit = 0x800000;
for (i = 0; i < 24; i++) {
if (salt & saltbit)
saltbits |= obit;
saltbit <<= 1;
obit >>= 1;
}
}
static int
des_setkey(const unsigned char *key)
{
unsigned int k0, k1, rawkey0, rawkey1;
int shifts, round;
if (!des_initialised)
des_init();
rawkey0 = md_ntohl(*(unsigned int *) key);
rawkey1 = md_ntohl(*(unsigned int *) (key + 4));
if ((rawkey0 | rawkey1)
&& rawkey0 == old_rawkey0
&& rawkey1 == old_rawkey1) {
/*
* Already setup for this key.
* This optimisation fails on a zero key (which is weak and
* has bad parity anyway) in order to simplify the starting
* conditions.
*/
return(0);
}
old_rawkey0 = rawkey0;
old_rawkey1 = rawkey1;
/*
* Do key permutation and split into two 28-bit subkeys.
*/
k0 = key_perm_maskl[0][rawkey0 >> 25]
| key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]
| key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]
| key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]
| key_perm_maskl[4][rawkey1 >> 25]
| key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]
| key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]
| key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];
k1 = key_perm_maskr[0][rawkey0 >> 25]
| key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]
| key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]
| key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]
| key_perm_maskr[4][rawkey1 >> 25]
| key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]
| key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]
| key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];
/*
* Rotate subkeys and do compression permutation.
*/
shifts = 0;
for (round = 0; round < 16; round++) {
unsigned int t0, t1;
shifts += key_shifts[round];
t0 = (k0 << shifts) | (k0 >> (28 - shifts));
t1 = (k1 << shifts) | (k1 >> (28 - shifts));
de_keysl[15 - round] =
en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]
| comp_maskl[1][(t0 >> 14) & 0x7f]
| comp_maskl[2][(t0 >> 7) & 0x7f]
| comp_maskl[3][t0 & 0x7f]
| comp_maskl[4][(t1 >> 21) & 0x7f]
| comp_maskl[5][(t1 >> 14) & 0x7f]
| comp_maskl[6][(t1 >> 7) & 0x7f]
| comp_maskl[7][t1 & 0x7f];
de_keysr[15 - round] =
en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f]
| comp_maskr[1][(t0 >> 14) & 0x7f]
| comp_maskr[2][(t0 >> 7) & 0x7f]
| comp_maskr[3][t0 & 0x7f]
| comp_maskr[4][(t1 >> 21) & 0x7f]
| comp_maskr[5][(t1 >> 14) & 0x7f]
| comp_maskr[6][(t1 >> 7) & 0x7f]
| comp_maskr[7][t1 & 0x7f];
}
return(0);
}
static int
do_des(unsigned int l_in, unsigned int r_in, unsigned int *l_out,
unsigned int *r_out, int count)
{
/*
* l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
*/
unsigned int l, r, *kl, *kr, *kl1, *kr1;
unsigned int f = 0, r48l, r48r;
int round;
if (count == 0) {
return(1);
} else if (count > 0) {
/*
* Encrypting
*/
kl1 = en_keysl;
kr1 = en_keysr;
} else {
/*
* Decrypting
*/
count = -count;
kl1 = de_keysl;
kr1 = de_keysr;
}
/*
* Do initial permutation (IP).
*/
l = ip_maskl[0][l_in >> 24]
| ip_maskl[1][(l_in >> 16) & 0xff]
| ip_maskl[2][(l_in >> 8) & 0xff]
| ip_maskl[3][l_in & 0xff]
| ip_maskl[4][r_in >> 24]
| ip_maskl[5][(r_in >> 16) & 0xff]
| ip_maskl[6][(r_in >> 8) & 0xff]
| ip_maskl[7][r_in & 0xff];
r = ip_maskr[0][l_in >> 24]
| ip_maskr[1][(l_in >> 16) & 0xff]
| ip_maskr[2][(l_in >> 8) & 0xff]
| ip_maskr[3][l_in & 0xff]
| ip_maskr[4][r_in >> 24]
| ip_maskr[5][(r_in >> 16) & 0xff]
| ip_maskr[6][(r_in >> 8) & 0xff]
| ip_maskr[7][r_in & 0xff];
while (count--) {
/*
* Do each round.
*/
kl = kl1;
kr = kr1;
round = 16;
while (round--) {
/*
* Expand R to 48 bits (simulate the E-box).
*/
r48l = ((r & 0x00000001) << 23)
| ((r & 0xf8000000) >> 9)
| ((r & 0x1f800000) >> 11)
| ((r & 0x01f80000) >> 13)
| ((r & 0x001f8000) >> 15);
r48r = ((r & 0x0001f800) << 7)
| ((r & 0x00001f80) << 5)
| ((r & 0x000001f8) << 3)
| ((r & 0x0000001f) << 1)
| ((r & 0x80000000) >> 31);
/*
* Do salting for crypt() and friends, and
* XOR with the permuted key.
*/
f = (r48l ^ r48r) & saltbits;
r48l ^= f ^ *kl++;
r48r ^= f ^ *kr++;
/*
* Do sbox lookups (which shrink it back to 32 bits)
* and do the pbox permutation at the same time.
*/
f = psbox[0][m_sbox[0][r48l >> 12]]
| psbox[1][m_sbox[1][r48l & 0xfff]]
| psbox[2][m_sbox[2][r48r >> 12]]
| psbox[3][m_sbox[3][r48r & 0xfff]];
/*
* Now that we've permuted things, complete f().
*/
f ^= l;
l = r;
r = f;
}
r = l;
l = f;
}
/*
* Do final permutation (inverse of IP).
*/
*l_out = fp_maskl[0][l >> 24]
| fp_maskl[1][(l >> 16) & 0xff]
| fp_maskl[2][(l >> 8) & 0xff]
| fp_maskl[3][l & 0xff]
| fp_maskl[4][r >> 24]
| fp_maskl[5][(r >> 16) & 0xff]
| fp_maskl[6][(r >> 8) & 0xff]
| fp_maskl[7][r & 0xff];
*r_out = fp_maskr[0][l >> 24]
| fp_maskr[1][(l >> 16) & 0xff]
| fp_maskr[2][(l >> 8) & 0xff]
| fp_maskr[3][l & 0xff]
| fp_maskr[4][r >> 24]
| fp_maskr[5][(r >> 16) & 0xff]
| fp_maskr[6][(r >> 8) & 0xff]
| fp_maskr[7][r & 0xff];
return(0);
}
static int
des_cipher(const unsigned char *in, unsigned char *out, int salt, int count)
{
unsigned int l_out, r_out, rawl, rawr;
unsigned int x[2];
int retval;
if (!des_initialised)
des_init();
setup_salt(salt);
memcpy(x, in, sizeof x);
rawl = md_ntohl(x[0]);
rawr = md_ntohl(x[1]);
retval = do_des(rawl, rawr, &l_out, &r_out, count);
x[0] = md_htonl(l_out);
x[1] = md_htonl(r_out);
memcpy(out, x, sizeof x);
return(retval);
}
char *
xcrypt(const char *key, const char *setting)
{
int i;
unsigned int count, salt, l, r0, r1, keybuf[2];
unsigned char *p, *q;
static unsigned char output[21];
if (!des_initialised)
des_init();
/*
* Copy the key, shifting each character up by one bit
* and padding with zeros.
*/
q = (unsigned char *) keybuf;
while ((q - (unsigned char *) keybuf) < sizeof(keybuf)) {
if ((*q++ = *key << 1))
key++;
}
if (des_setkey((unsigned char *) keybuf))
return(NULL);
if (*setting == _PASSWORD_EFMT1) {
/*
* "new"-style:
* setting - underscore, 4 bytes of count, 4 bytes of salt
* key - unlimited characters
*/
for (i = 1, count = 0; i < 5; i++)
count |= ascii_to_bin(setting[i]) << (i - 1) * 6;
for (i = 5, salt = 0; i < 9; i++)
salt |= ascii_to_bin(setting[i]) << (i - 5) * 6;
while (*key) {
/*
* Encrypt the key with itself.
*/
if (des_cipher((unsigned char*)keybuf, (unsigned char*)keybuf, 0, 1))
return(NULL);
/*
* And XOR with the next 8 characters of the key.
*/
q = (unsigned char *) keybuf;
while (((q - (unsigned char *) keybuf) < sizeof(keybuf)) &&
*key)
*q++ ^= *key++ << 1;
if (des_setkey((unsigned char *) keybuf))
return(NULL);
}
strncpy((char *)output, setting, 9);
/*
* Double check that we weren't given a short setting.
* If we were, the above code will probably have created
* wierd values for count and salt, but we don't really care.
* Just make sure the output string doesn't have an extra
* NUL in it.
*/
output[9] = '\0';
p = output + strlen((const char *)output);
} else {
/*
* "old"-style:
* setting - 2 bytes of salt
* key - up to 8 characters
*/
count = 25;
salt = (ascii_to_bin(setting[1]) << 6)
| ascii_to_bin(setting[0]);
output[0] = setting[0];
/*
* If the encrypted password that the salt was extracted from
* is only 1 character long, the salt will be corrupted. We
* need to ensure that the output string doesn't have an extra
* NUL in it!
*/
output[1] = setting[1] ? setting[1] : output[0];
p = output + 2;
}
setup_salt(salt);
/*
* Do it.
*/
if (do_des(0, 0, &r0, &r1, count))
return(NULL);
/*
* Now encode the result...
*/
l = (r0 >> 8);
*p++ = ascii64[(l >> 18) & 0x3f];
*p++ = ascii64[(l >> 12) & 0x3f];
*p++ = ascii64[(l >> 6) & 0x3f];
*p++ = ascii64[l & 0x3f];
l = (r0 << 16) | ((r1 >> 16) & 0xffff);
*p++ = ascii64[(l >> 18) & 0x3f];
*p++ = ascii64[(l >> 12) & 0x3f];
*p++ = ascii64[(l >> 6) & 0x3f];
*p++ = ascii64[l & 0x3f];
l = r1 << 2;
*p++ = ascii64[(l >> 12) & 0x3f];
*p++ = ascii64[(l >> 6) & 0x3f];
*p++ = ascii64[l & 0x3f];
*p = 0;
return((char *)output);
}

436
rogue4/xstr.c Normal file
View file

@ -0,0 +1,436 @@
/*
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
static char *sccsid = "@(#)xstr.c 4.1 (Berkeley) 10/1/80";
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <signal.h>
/*
* xstr - extract and hash strings in a C program
*
* Bill Joy UCB
* November, 1978
*/
#define ignore(a) (a)
char *calloc();
off_t tellpt;
off_t hashit();
char *mktemp();
void onintr(int);
char *savestr();
char *strcat();
char *strcpy();
off_t yankstr();
off_t mesgpt;
char *strings = "strings";
int cflg;
int vflg;
int readstd;
main(argc, argv)
int argc;
char *argv[];
{
argc--, argv++;
while (argc > 0 && argv[0][0] == '-') {
register char *cp = &(*argv++)[1];
argc--;
if (*cp == 0) {
readstd++;
continue;
}
do switch (*cp++) {
case 'c':
cflg++;
continue;
case 'v':
vflg++;
continue;
default:
fprintf(stderr, "usage: xstr [ -v ] [ -c ] [ - ] [ name ... ]\n");
} while (*cp);
}
if (signal(SIGINT, SIG_IGN) == SIG_DFL)
signal(SIGINT, onintr);
if (cflg || argc == 0 && !readstd)
inithash();
else
strings = mktemp(savestr("/tmp/xstrXXXXXX"));
while (readstd || argc > 0) {
if (freopen("x.c", "w", stdout) == NULL)
perror("x.c"), exit(1);
if (!readstd && freopen(argv[0], "r", stdin) == NULL)
perror(argv[0]), exit(2);
process("x.c");
if (readstd == 0)
argc--, argv++;
else
readstd = 0;
};
flushsh();
if (cflg == 0)
xsdotc();
if (strings[0] == '/')
ignore(md_unlink(strings));
exit(0);
}
process(name)
char *name;
{
char *cp;
char linebuf[BUFSIZ];
register int c;
register int incomm = 0;
printf("extern char\txstr[];\n");
for (;;) {
if (fgets(linebuf, sizeof linebuf, stdin) == NULL) {
if (ferror(stdin)) {
perror(name);
exit(3);
}
break;
}
if (linebuf[0] == '#') {
if (linebuf[1] == ' ' && isdigit(linebuf[2]))
printf("#line%s", &linebuf[1]);
else
printf("%s", linebuf);
continue;
}
for (cp = linebuf; c = *cp++;) switch (c) {
case '"':
if (incomm)
goto def;
printf("(&xstr[%d])", (int) yankstr(&cp));
break;
case '\'':
if (incomm)
goto def;
putchar(c);
if (*cp)
putchar(*cp++);
break;
case '/':
if (incomm || *cp != '*')
goto def;
incomm = 1;
cp++;
printf("/*");
continue;
case '*':
if (incomm && *cp == '/') {
incomm = 0;
cp++;
printf("*/");
continue;
}
goto def;
def:
default:
putchar(c);
break;
}
}
if (ferror(stdout))
perror("x.c"), onintr(-1);
}
off_t
yankstr(cpp)
register char **cpp;
{
register char *cp = *cpp;
register int c, ch;
char dbuf[BUFSIZ];
register char *dp = dbuf;
register char *tp;
while (c = *cp++) {
switch (c) {
case '"':
cp++;
goto out;
case '\\':
c = *cp++;
if (c == 0)
break;
if (c == '\n')
continue;
for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; ch = *tp++; tp++)
if (c == ch) {
c = *tp;
goto gotc;
}
if (!octdigit(c)) {
*dp++ = '\\';
break;
}
c -= '0';
if (!octdigit(*cp))
break;
c <<= 3, c += *cp++ - '0';
if (!octdigit(*cp))
break;
c <<= 3, c += *cp++ - '0';
break;
}
gotc:
*dp++ = c;
}
out:
*cpp = --cp;
*dp = 0;
return (hashit(dbuf, 1));
}
octdigit(c)
char c;
{
return (isdigit(c) && c != '8' && c != '9');
}
inithash()
{
char buf[BUFSIZ];
register FILE *mesgread = fopen(strings, "r");
if (mesgread == NULL)
return;
for (;;) {
mesgpt = tellpt;
if (fgetNUL(buf, sizeof buf, mesgread) == 0)
break;
hashit(buf, 0);
}
ignore(fclose(mesgread));
}
fgetNUL(obuf, rmdr, file)
char *obuf;
register int rmdr;
FILE *file;
{
register c;
register char *buf = obuf;
while (--rmdr > 0 && (c = xgetc(file)) != 0 && c != EOF)
*buf++ = c;
*buf++ = 0;
return ((feof(file) || ferror(file)) ? 0 : 1);
}
xgetc(file)
FILE *file;
{
tellpt++;
return (getc(file));
}
#define BUCKETS 128
struct hash {
off_t hpt;
char *hstr;
struct hash *hnext;
short hnew;
} bucket[BUCKETS];
off_t
hashit(str, new)
char *str;
int new;
{
int i;
register struct hash *hp, *hp0;
hp = hp0 = &bucket[lastchr(str) & 0177];
while (hp->hnext) {
hp = hp->hnext;
i = istail(str, hp->hstr);
if (i >= 0)
return (hp->hpt + i);
}
hp = (struct hash *) calloc(1, sizeof (*hp));
hp->hpt = mesgpt;
hp->hstr = savestr(str);
mesgpt += strlen(hp->hstr) + 1;
hp->hnext = hp0->hnext;
hp->hnew = new;
hp0->hnext = hp;
return (hp->hpt);
}
flushsh()
{
register int i;
register struct hash *hp;
register FILE *mesgwrit;
register int old = 0, new = 0;
for (i = 0; i < BUCKETS; i++)
for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext)
if (hp->hnew)
new++;
else
old++;
if (new == 0 && old != 0)
return;
mesgwrit = fopen(strings, old ? "a" : "w");
for (i = 0; i < BUCKETS; i++)
for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) {
found(hp->hnew, hp->hpt, hp->hstr);
if (hp->hnew) {
fseek(mesgwrit, hp->hpt, 0);
ignore(fwrite(hp->hstr, strlen(hp->hstr) + 1, 1, mesgwrit));
if (ferror(mesgwrit))
perror(strings), exit(4);
}
}
ignore(fclose(mesgwrit));
}
found(new, off, str)
int new;
off_t off;
char *str;
{
if (vflg == 0)
return;
if (!new)
fprintf(stderr, "found at %d:", (int) off);
else
fprintf(stderr, "new at %d:", (int) off);
prstr(str);
fprintf(stderr, "\n");
}
prstr(cp)
register char *cp;
{
register int c;
while (c = (*cp++ & 0377))
if (c < ' ')
fprintf(stderr, "^%c", c + '`');
else if (c == 0177)
fprintf(stderr, "^?");
else if (c > 0200)
fprintf(stderr, "\\%03o", c);
else
fprintf(stderr, "%c", c);
}
xsdotc()
{
register FILE *strf = fopen(strings, "r");
register FILE *xdotcf;
if (strf == NULL)
perror(strings), exit(5);
xdotcf = fopen("xs.c", "w");
if (xdotcf == NULL)
perror("xs.c"), exit(6);
fprintf(xdotcf, "char\txstr[] = {\n");
for (;;) {
register int i, c;
for (i = 0; i < 20; i++) {
c = getc(strf);
if (ferror(strf)) {
perror(strings);
onintr(-1);
}
if (feof(strf)) {
fprintf(xdotcf, "\n");
goto out;
}
fprintf(xdotcf, "%d,", c);
}
fprintf(xdotcf, "\n");
}
out:
fprintf(xdotcf, "};\n");
ignore(fclose(xdotcf));
ignore(fclose(strf));
}
char *
savestr(cp)
register char *cp;
{
register char *dp = (char *) calloc(1, strlen(cp) + 1);
return (strcpy(dp, cp));
}
Ignore(void *a)
{
a = a;
}
ignorf(a)
void (*a)();
{
a = a;
}
lastchr(cp)
register char *cp;
{
while (cp[0] && cp[1])
cp++;
return (*cp);
}
istail(str, of)
register char *str, *of;
{
register int d = strlen(of) - strlen(str);
if (d < 0 || strcmp(&of[d], str) != 0)
return (-1);
return (d);
}
void
onintr(int sig)
{
ignorf(signal(SIGINT, SIG_IGN));
if (strings[0] == '/')
ignore(md_unlink(strings));
ignore(md_unlink("x.c"));
ignore(md_unlink("xs.c"));
exit(7);
}