Import Advanced Rogue 7.7 from the Roguelike Restoration Project (r1490)

This commit is contained in:
John "Elwin" Edwards 2015-05-08 15:24:40 -04:00
parent 6af92da76a
commit cf121ade21
51 changed files with 37593 additions and 0 deletions

179
arogue7/LICENSE.TXT Normal file
View file

@ -0,0 +1,179 @@
Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
Portions Copyright (C) 1984 Robert D. Kindelberger
Portions Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
Portions Copyright (C) 2005 Nicholas J. Kisseberth
Portions Copyright (C) 1994 David Burren
All rights reserved.
===========================================================================
Advanced Rogue
Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
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.
4. The name "Advanced Rogue" and "ARogue" must not be used to endorse or
promote products derived from this software without prior written
permission.
5. Products derived from this software may not be called "Advanced Rogue" or
"ARogue", nor may "Advanced Rogue" or "ARogue appear in their name,
without 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 are based on the work of Robert D. Kindelberger.
Used under license:
Super-Rogue
Copyright (C) 1984 Robert D. Kindelberger
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.
4. The name "Super-Rogue" must not be used to endorse or promote products
derived from this software without prior written permission.
5. Products derived from this software may not be called "Super-Rogue",
nor may "Super-Rogue" appear in their name, without 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 are based on the work of Michael Toy, Ken Arnold
and Glenn Wichman. Used under license:
Rogue: Exploring the Dungeons of Doom
Copyright (C) 1980, 1981 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 (state.c, mdport.c) are based on the work
of Nicholas J. Kisseberth. Used under license:
Copyright (C) 2005 Nicholas J. Kisseberth
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 (xcrypt.c) 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.

193
arogue7/Makefile Normal file
View file

@ -0,0 +1,193 @@
#
# Makefile for rogue
#
# Advanced Rogue
# Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
# All rights reserved.
#
# Based on "Rogue: Exploring the Dungeons of Doom"
# Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
# All rights reserved.
#
# See the file LICENSE.TXT for full copyright and licensing information.
#
#
# Makefile for rogue
#
DISTNAME=arogue7.7.1
PROGRAM=arogue77
O=o
HDRS= rogue.h mach_dep.h network.h
OBJS1 = vers.$(O) actions.$(O) chase.$(O) command.$(O) daemon.$(O) \
daemons.$(O) eat.$(O) effects.$(O) encumb.$(O) fight.$(O) init.$(O) \
io.$(O) list.$(O) main.$(O) maze.$(O) mdport.$(O) misc.$(O) \
monsters.$(O)
OBJS2 = move.$(O) new_level.$(O) options.$(O) outside.$(O) pack.$(O) \
passages.$(O) player.$(O) potions.$(O) rings.$(O) rip.$(O) rogue.$(O) \
rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) things.$(O) \
trader.$(O) util.$(O) weapons.$(O) wear.$(O) wizard.$(O) xcrypt.$(O)
OBJS = $(OBJS1) $(OBJS2)
CFILES= vers.c actions.c chase.c command.c daemon.c \
daemons.c eat.c effects.c encumb.c fight.c init.c \
io.c list.c main.c maze.c mdport.c misc.c monsters.c \
move.c new_level.c options.c outside.c pack.c \
passages.c player.c potions.c rings.c rip.c rogue.c \
rooms.c save.c scrolls.c state.c sticks.c things.c \
trader.c util.c weapons.c wear.c wizard.c xcrypt.c
MISC_C=
DOCSRC= aguide.mm
DOCS = $(PROGRAM).doc $(PROGRAM).html
MISC = Makefile $(MISC_C) LICENSE.TXT $(PROGRAM).sln $(PROGRAM).vcproj $(DOCS)\
$(DOCSRC)
CC = gcc
ROPTS =
COPTS = -O3
CFLAGS= $(COPTS) $(ROPTS)
LIBS = -lcurses
RM = rm -f
.SUFFIXES: .obj
.c.obj:
$(CC) $(CFLAGS) /c $*.c
$(PROGRAM): $(HDRS) $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
clean:
$(RM) $(OBJS1)
$(RM) $(OBJS2)
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe $(PROGRAM).lck
$(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip
dist.src:
make clean
tar cf $(DISTNAME)-src.tar $(CFILES) $(HDRS) $(MISC)
gzip -f $(DISTNAME)-src.tar
doc.nroff:
tbl aguide.mm | nroff -mm | colcrt - > arogue77.doc
doc.groff:
groff -P-c -t -mm -Tascii aguide.mm | sed -e 's/.\x08//g' > arogue77.doc
groff -t -mm -Thtml aguide.mm > arogue77.ht
dist.irix:
make clean
make CC=cc COPTS="-woff 1116 -O3" $(PROGRAM)
tar cf $(DISTNAME)-irix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-irix.tar
dist.aix:
make clean
make CC=xlc COPTS="-qmaxmem=16768 -O3 -qstrict" $(PROGRAM)
tar cf $(DISTNAME)-aix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-aix.tar
dist.linux:
make clean
make $(PROGRAM)
tar cf $(DISTNAME)-linux.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-linux.tar
dist.interix:
@$(MAKE) clean
@$(MAKE) COPTS="-ansi" $(PROGRAM)
tar cf $(DISTNAME)-interix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-interix.tar
dist.cygwin:
@$(MAKE) --no-print-directory clean
@$(MAKE) --no-print-directory $(PROGRAM)
tar cf $(DISTNAME)-cygwin.tar $(PROGRAM).exe LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-cygwin.tar
#
# Use MINGW32-MAKE to build this target
#
dist.mingw32:
@$(MAKE) --no-print-directory RM="cmd /c del" clean
@$(MAKE) --no-print-directory LIBS="-lpdcurses" $(PROGRAM)
cmd /c del $(DISTNAME)-mingw32.zip
zip $(DISTNAME)-mingw32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)
dist.msys:
@$(MAKE) --no-print-directory clean
@$(MAKE) --no-print-directory LIBS="-lcurses" $(PROGRAM)
tar cf $(DISTNAME)-msys.tar $(PROGRAM).exe LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-msys.tar
dist.djgpp:
@$(MAKE) --no-print-directory clean
@$(MAKE) --no-print-directory LDFLAGS="-L$(DJDIR)/LIB" \
LIBS="-lpdcurses" $(PROGRAM)
rm -f $(DISTNAME)-djgpp.zip
zip $(DISTNAME)-djgpp.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)
#
# Use NMAKE to build this targer
#
dist.win32:
@$(MAKE) /NOLOGO O="obj" RM="-del" clean
@$(MAKE) /NOLOGO O="obj" CC="CL" \
LIBS="..\pdcurses\pdcurses.lib shfolder.lib user32.lib Advapi32.lib" \
COPTS="-nologo -I..\pdcurses \
-Ox -wd4033 -wd4716" $(PROGRAM)
-del $(DISTNAME)-win32.zip
zip $(DISTNAME)-win32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)
actions.o: rogue.h
chase.o: rogue.h
command.o: rogue.h
command.o: mach_dep.h
daemon.o: rogue.h
daemons.o: rogue.h
eat.o: rogue.h
edit.o: mach_dep.h
edit.o: rogue.h
effects.o: rogue.h
encumb.o: rogue.h
fight.o: rogue.h
init.o: rogue.h
init.o: mach_dep.h
io.o: rogue.h
list.o: rogue.h
main.o: mach_dep.h
main.o: network.h
main.o: rogue.h
maze.o: rogue.h
misc.o: rogue.h
monsters.o: rogue.h
move.o: rogue.h
new_level.o: rogue.h
options.o: rogue.h
outside.o: rogue.h
pack.o: rogue.h
passages.o: rogue.h
player.o: rogue.h
potions.o: rogue.h
rings.o: rogue.h
rip.o: mach_dep.h
rip.o: network.h
rip.o: rogue.h
rogue.o: rogue.h
rooms.o: rogue.h
save.o: rogue.h
save.o: mach_dep.h
scrolls.o: rogue.h
sticks.o: rogue.h
things.o: rogue.h
trader.o: rogue.h
util.o: rogue.h
weapons.o: rogue.h
wear.o: rogue.h
wizard.o: rogue.h

982
arogue7/actions.c Normal file
View file

@ -0,0 +1,982 @@
/*
* actions.c - functions for dealing with monster actions
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <ctype.h>
#include <limits.h>
#include "curses.h"
#include "rogue.h"
#define MAXINT INT_MAX
#define MININT INT_MIN
/*
* Did we disrupt a spell?
*/
dsrpt_monster(tp, always, see_him)
register struct thing *tp;
bool always, see_him;
{
switch (tp->t_action) {
case A_SUMMON:
case A_MISSILE:
case A_SLOW:
tp->t_action = A_NIL; /* Just make the old fellow start over again */
tp->t_no_move = movement(tp);
tp->t_using = NULL;/* Just to be on the safe side */
turn_on(*tp, WASDISRUPTED);
if (see_him)
msg("%s's spell has been disrupted.",prname(monster_name(tp),TRUE));
/*
* maybe choose something else to do next time since player
* is disrupting us
*/
tp->t_summon *= 2;
tp->t_cast /= 2;
return;
}
/* We may want to disrupt other actions, too */
if (always) {
tp->t_action = A_NIL; /* Just make the old fellow start over again */
tp->t_no_move = movement(tp);
tp->t_using = NULL;/* Just to be on the safe side */
}
}
dsrpt_player()
{
int which, action;
struct linked_list *item;
struct object *obj;
action = player.t_action;
which = player.t_selection;
switch (action) {
case C_CAST: /* Did we disrupt a spell? */
case C_PRAY:
case C_CHANT:
{
msg("Your %s was disrupted!", action == C_CAST ? "spell" : "prayer");
/* Charge him anyway */
if (action == C_CAST)
spell_power += magic_spells[which].s_cost;
else if (action == C_PRAY)
pray_time += cleric_spells[which].s_cost;
else if (action == C_CHANT)
chant_time += druid_spells[which].s_cost;
}
when C_COUNT: /* counting of gold? */
{
if (purse > 0) {
msg("Your gold goes flying everywhere!");
do {
item = spec_item(GOLD, NULL, NULL, NULL);
obj = OBJPTR(item);
obj->o_count = min(purse, rnd(10)+1);
purse -= obj->o_count;
obj->o_pos = hero;
fall(item, FALSE);
} while (purse > 0 && rnd(10) != 1);
}
}
when C_EAT:
msg("You gag on your food for a moment.");
del_pack(player.t_using);
when A_PICKUP:
msg("You drop what you are picking up!");
when C_SEARCH: /* searching for traps and secret doors... */
msg("Oww....You decide to stop searching.");
count = 0; /* don't search again */
when C_SETTRAP:
msg("Oww....You can't get a trap set.");
when A_NIL:
default:
return;
}
player.t_no_move = movement(&player); /* disoriented for a while */
player.t_action = A_NIL;
player.t_selection = 0;
player.t_using = NULL;
}
/*
* m_act:
* If the critter isn't doing anything, choose an action for it.
* Otherwise, let it perform its chosen action.
*/
m_act(tp)
register struct thing *tp;
{
struct object *obj;
bool flee; /* Are we scared? */
/* What are we planning to do? */
switch (tp->t_action) {
default:
/* An unknown action! */
msg("Unknown monster action (%d)", tp->t_action);
/* Fall through */
case A_NIL:
/* If the monster is fairly intelligent and about to die, it
* may turn tail and run. But if we are a FRIENDLY creature
* in the hero's service, don't run.
*/
if (off(*tp, ISFLEE) &&
tp->t_stats.s_hpt < tp->maxstats.s_hpt &&
tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/6) &&
(off(*tp, ISFRIENDLY) || tp->t_dest != &hero) &&
rnd(25) < tp->t_stats.s_intel) {
turn_on(*tp, ISFLEE);
/* It is okay to turn tail */
tp->t_oldpos = tp->t_pos;
}
/* Should the monster run away? */
flee = on(*tp, ISFLEE) ||
((tp->t_dest == &hero) && on(player, ISINWALL) &&
off(*tp, CANINWALL));
m_select(tp, flee); /* Select an action */
return;
when A_ATTACK:
/*
* We're trying to attack the player or monster at t_newpos
* if the prey moved, do nothing
*/
obj = tp->t_using ? OBJPTR(tp->t_using) : NULL;
if (ce(tp->t_newpos, hero)) {
attack(tp, obj, FALSE);
}
else if (mvwinch(mw, tp->t_newpos.y, tp->t_newpos.x) &&
step_ok(tp->t_newpos.y, tp->t_newpos.x, FIGHTOK, tp)) {
skirmish(tp, &tp->t_newpos, obj, FALSE);
}
when A_SELL:
/* Is the player still next to us? */
if (ce(tp->t_newpos, hero)) sell(tp);
/* The darned player moved away */
else if (off(player, ISBLIND) &&
cansee(unc(tp->t_pos)) &&
(off(*tp, ISINVIS) || on(player, CANSEE)) &&
(off(*tp, ISSHADOW) || on(player, CANSEE)) &&
(off(*tp, CANSURPRISE) || ISWEARING(R_ALERT)))
msg("%s grunts with frustration",prname(monster_name(tp),TRUE));
when A_MOVE:
/* Let's try to move */
do_chase(tp);
/* If t_no_move > 0, we found that we have to fight! */
if (tp->t_no_move > 0) return;
when A_BREATHE:
/* Breathe on the critter */
m_breathe(tp);
when A_SLOW:
/* make him move slower */
add_slow();
turn_off(*tp, CANSLOW);
when A_MISSILE:
/* Start up a magic missile spell */
m_spell(tp);
when A_SONIC:
/* Let out a sonic blast! */
m_sonic(tp);
when A_THROW:
/* We're throwing something (like an arrow) */
missile(tp->t_newpos.y, tp->t_newpos.x, tp->t_using, tp);
when A_SUMMON:
/* We're summoning help */
m_summon(tp);
when A_USERELIC:
/* Use our relic */
m_use_relic(tp);
when A_USEWAND:
/* use the wand we have */
m_use_wand(tp);
}
/* No action now */
tp->t_action = A_NIL;
tp->t_using = NULL;
}
/*
* m_breathe:
* Breathe in the chosen direction.
*/
m_breathe(tp)
register struct thing *tp;
{
register int damage;
register char *breath;
damage = tp->t_stats.s_hpt;
turn_off(*tp, CANSURPRISE);
/* Will it breathe at random */
if (on(*tp, CANBRANDOM)) {
/* Turn off random breath */
turn_off(*tp, CANBRANDOM);
/* Select type of breath */
switch (rnd(10)) {
case 0: breath = "acid";
turn_on(*tp, NOACID);
when 1: breath = "flame";
turn_on(*tp, NOFIRE);
when 2: breath = "lightning bolt";
turn_on(*tp, NOBOLT);
when 3: breath = "chlorine gas";
turn_on(*tp, NOGAS);
when 4: breath = "ice";
turn_on(*tp, NOCOLD);
when 5: breath = "nerve gas";
turn_on(*tp, NOPARALYZE);
when 6: breath = "sleeping gas";
turn_on(*tp, NOSLEEP);
when 7: breath = "slow gas";
turn_on(*tp, NOSLOW);
when 8: breath = "confusion gas";
turn_on(*tp, ISCLEAR);
when 9: breath = "fear gas";
turn_on(*tp, NOFEAR);
}
}
/* Or can it breathe acid? */
else if (on(*tp, CANBACID)) {
turn_off(*tp, CANBACID);
breath = "acid";
}
/* Or can it breathe fire */
else if (on(*tp, CANBFIRE)) {
turn_off(*tp, CANBFIRE);
breath = "flame";
}
/* Or can it breathe electricity? */
else if (on(*tp, CANBBOLT)) {
turn_off(*tp, CANBBOLT);
breath = "lightning bolt";
}
/* Or can it breathe gas? */
else if (on(*tp, CANBGAS)) {
turn_off(*tp, CANBGAS);
breath = "chlorine gas";
}
/* Or can it breathe ice? */
else if (on(*tp, CANBICE)) {
turn_off(*tp, CANBICE);
breath = "ice";
}
else if (on(*tp, CANBPGAS)) {
turn_off(*tp, CANBPGAS);
breath = "nerve gas";
}
/* can it breathe sleeping gas */
else if (on(*tp, CANBSGAS)) {
turn_off(*tp, CANBSGAS);
breath = "sleeping gas";
}
/* can it breathe slow gas */
else if (on(*tp, CANBSLGAS)) {
turn_off(*tp, CANBSLGAS);
breath = "slow gas";
}
/* can it breathe confusion gas */
else if (on(*tp, CANBCGAS)) {
turn_off(*tp, CANBCGAS);
breath = "confusion gas";
}
/* can it breathe fear gas */
else {
turn_off(*tp, CANBFGAS);
breath = "fear gas";
}
/* Now breathe -- sets "monst_dead" if it kills someone */
shoot_bolt(tp, tp->t_pos, tp->t_newpos, FALSE,
tp->t_index, breath, damage);
running = FALSE;
if (fight_flush) md_flushinp();
}
/*
* m_select:
* Select an action for the monster.
*/
m_select(th, flee)
register struct thing *th;
register bool flee; /* True if running away or player is inaccessible in wall */
{
register struct room *rer, *ree; /* room of chaser, room of chasee */
int dist = MININT;
int mindist = MAXINT, maxdist = MININT;
bool rundoor; /* TRUE means run to a door */
char sch;
coord *last_door=0, /* Door we just came from */
this; /* Temporary destination for chaser */
rer = roomin(&th->t_pos); /* Find room of chaser */
ree = roomin(th->t_dest); /* Find room of chasee */
/* First see if we want to use an ability or weapon */
if (m_use_it(th, flee, rer, ree)) return;
/*
* We don't count monsters on doors as inside rooms here because when
* a monster is in a room and the player is not in that room, the
* monster looks for the best door out. If we counted doors as part
* of the room, the monster would already be on the best door out;
* so he would never move.
*/
if ((sch = CCHAR( mvwinch(stdscr, th->t_pos.y, th->t_pos.x) )) == DOOR ||
sch == SECRETDOOR || sch == PASSAGE) {
rer = NULL;
}
this = *th->t_dest;
/*
* If we are in a room heading for the player and the player is not
* in the room with us, we run to the "best" door.
* If we are in a room fleeing from the player, then we run to the
* "best" door if he IS in the same room.
*
* Note: We don't bother with doors in mazes or if we can walk
* through walls.
*/
if (rer != NULL && levtype != MAZELEV && off(*th, CANINWALL)) {
if (flee) rundoor = (rer == ree);
else rundoor = (rer != ree);
}
else rundoor = FALSE;
if (rundoor) {
register struct linked_list *exitptr; /* For looping through exits */
coord *exit, /* A particular door */
*entrance; /* Place just inside doorway */
int exity, exitx; /* Door's coordinates */
char dch='\0'; /* Door character */
if (th->t_doorgoal)
dch = CCHAR( mvwinch(stdscr, th->t_doorgoal->y, th->t_doorgoal->x) );
/* Do we have a valid goal? */
if ((dch == PASSAGE || dch == DOOR) && /* A real door */
(!flee || !ce(*th->t_doorgoal, *th->t_dest))) { /* Prey should not
* be at door if
* we are running
* away
*/
/* Make sure the player is not in the doorway, either */
entrance = doorway(rer, th->t_doorgoal);
if (!flee || entrance == NULL || !ce(*entrance, *th->t_dest)) {
this = *th->t_doorgoal;
dist = 0; /* Indicate that we have our door */
}
}
/* Go through all the doors */
else for (exitptr = rer->r_exit; exitptr; exitptr = next(exitptr)) {
exit = DOORPTR(exitptr);
exity = exit->y;
exitx = exit->x;
/* Make sure it is a real door */
dch = CCHAR( mvwinch(stdscr, exity, exitx) );
if (dch == PASSAGE || dch == DOOR) {
/* Don't count a door if we are fleeing from someone and
* he is standing on it. Also, don't count it if he is
* standing in the doorway.
*/
if (flee) {
if (ce(*exit, *th->t_dest)) continue;
entrance = doorway(rer, exit);
if (entrance != NULL && ce(*entrance, *th->t_dest))
continue;
}
/* Were we just on this door? */
if (ce(*exit, th->t_oldpos)) last_door = exit;
else {
dist = DISTANCE(th->t_dest->y, th->t_dest->x, exity, exitx);
/* If fleeing, we want to maximize distance from door to
* what we flee, and minimize distance from door to us.
*/
if (flee)
dist -= DISTANCE(th->t_pos.y, th->t_pos.x, exity, exitx);
/* Maximize distance if fleeing, otherwise minimize it */
if ((flee && (dist > maxdist)) ||
(!flee && (dist < mindist))) {
th->t_doorgoal = exit; /* Use this door */
this = *exit;
mindist = maxdist = dist;
}
}
}
}
/* Could we not find a door? */
if (dist == MININT) {
/* If we were on a door, go ahead and use it */
if (last_door) {
th->t_doorgoal = last_door;
this = th->t_oldpos;
dist = 0; /* Indicate that we found a door */
}
else th->t_doorgoal = NULL; /* No more door goal */
}
/* Indicate that we do not want to flee from the door */
if (dist != MININT) flee = FALSE;
}
else th->t_doorgoal = 0; /* Not going to any door */
/* Now select someplace to go and start the action */
chase(th, &this, rer, ree, flee);
}
/*
* m_sonic:
* The monster is sounding a sonic blast.
*/
m_sonic(tp)
register struct thing *tp;
{
register int damage;
static struct object blast =
{
MISSILE, {0, 0}, "", 0, "", "150" , NULL, 0, 0, 0, 0
};
turn_off(*tp, CANSONIC);
turn_off(*tp, CANSURPRISE);
do_motion(&blast, tp->t_newpos.y, tp->t_newpos.x, tp);
damage = 150;
if (save(VS_BREATH, &player, -3))
damage /= 2;
msg ("%s's sonic blast hits you", prname(monster_name(tp), TRUE));
if ((pstats.s_hpt -= damage) <= 0)
death(tp->t_index);
running = FALSE;
if (fight_flush) md_flushinp();
dsrpt_player();
}
/*
* m_spell:
* The monster casts a spell. Currently this is limited to
* magic missile.
*/
m_spell(tp)
register struct thing *tp;
{
static struct object missile =
{
MISSILE, {0, 0}, "", 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1
};
sprintf(missile.o_hurldmg, "%dd4", tp->t_stats.s_lvl);
do_motion(&missile, tp->t_newpos.y, tp->t_newpos.x, tp);
hit_monster(unc(missile.o_pos), &missile, tp);
turn_off(*tp, CANMISSILE);
turn_off(*tp, CANSURPRISE);
running = FALSE;
if (fight_flush) md_flushinp();
}
/*
* m_summon:
* Summon aid.
*/
m_summon(tp)
register struct thing *tp;
{
register char *helpname, *mname;
int fail, numsum;
register int which, i;
/* Let's make sure our prey is still here */
if (!cansee(unc(tp->t_pos)) || fallpos(&hero, FALSE, 2) == NULL) return;
/*
* Non-uniques can only summon once. Uniques get fewer
* creatures with each successive summoning. Also, the
* probability of summoning goes down
*/
if (off(*tp, ISUNIQUE))
turn_off(*tp, CANSUMMON);
turn_off(*tp, CANSURPRISE);
mname = monster_name(tp);
helpname = monsters[tp->t_index].m_typesum;
which = findmindex(helpname);
if ((off(*tp, ISINVIS) || on(player, CANSEE)) &&
(off(*tp, ISSHADOW) || on(player, CANSEE)) &&
(off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) {
if (monsters[which].m_normal == FALSE) { /* genocided? */
msg("%s appears dismayed", prname(mname, TRUE));
monsters[tp->t_index].m_numsum = 0;
}
else {
msg("%s summons %ss for help", prname(mname, TRUE), helpname);
}
}
else {
if (monsters[which].m_normal == FALSE) /* genocided? */
monsters[tp->t_index].m_numsum = 0;
else {
msg("%ss seem to appear from nowhere!", helpname);
}
}
numsum = monsters[tp->t_index].m_numsum;
if (numsum && on(*tp, ISUNIQUE)) { /* UNIQUEs summon less each time */
monsters[tp->t_index].m_numsum--;
tp->t_summon *= 2; /* cut probability in half */
}
/*
* try to make all the creatures around player but remember
* if unsuccessful
*/
for (i=0, fail=0; i<numsum; i++) {
if (!creat_mons(&player, which, FALSE))
fail++; /* remember the failures */
}
/*
* try once again to make the buggers
*/
for (i=0; i<fail; i++)
creat_mons(tp, which, FALSE);
/* Now let the poor fellow see all the trouble */
light(&hero);
turn_on(*tp, HASSUMMONED);
}
/*
* m_use_it:
* See if the monster (tp) has anything useful it can do
* (ie. an ability or a weapon) other than just move.
*/
bool
m_use_it(tp, flee, rer, ree)
register struct thing *tp;
bool flee;
register struct room *rer, *ree;
{
int dist;
register coord *ee = tp->t_dest, *er = &tp->t_pos;
coord *shoot_dir;
struct linked_list *weapon;
struct thing *prey;
bool dest_player; /* Are we after the player? */
/*
* If we are fleeing, there's a chance, depending on our
* intelligence, that we'll just run in terror.
*/
if (flee && rnd(25) >= tp->t_stats.s_intel) return(FALSE);
/*
* Make sure that we have a living destination, and record whether
* it is the player.
*/
if (ee != NULL) {
if (ce(*ee, hero)) {
dest_player = TRUE;
prey = &player;
}
else {
struct linked_list *item;
dest_player = FALSE;
/* What is the monster we're chasing? */
item = find_mons(ee->y, ee->x);
if (item != NULL) prey = THINGPTR(item);
else return(FALSE);
}
}
else return(FALSE);
/*
* If we are friendly to the hero, we don't do anything.
*/
if (on(*tp, ISFRIENDLY) && dest_player) return(FALSE);
/*
* Also, for now, if our prey is in a wall, we won't do
* anything. The prey must be in the same room as we are OR
* we must have a straight shot at him. Note that
* shoot_dir must get set before rer is checked so
* that we get a valid value.
*/
if (on(*prey, ISINWALL) ||
((shoot_dir = can_shoot(er, ee)) == NULL &&
(rer == NULL || rer != ree)))
return(FALSE);
/*
* If we can't see the prey then forget it
*/
if (on(*prey, ISINVIS) && off(*tp, CANSEE))
return(FALSE);
/* How far are we from our prey? */
dist = DISTANCE(er->y, er->x, ee->y, ee->x);
/*
* Shall we summon aid so we don't have to get our hands dirty?
* For now, we will only summon aid against the player.
* We'll wait until he's within 2 dots of a missile length.
*/
if (on(*tp, CANSUMMON) && dest_player &&
dist < (BOLT_LENGTH+2)*(BOLT_LENGTH+2) &&
rnd(tp->t_summon) < tp->t_stats.s_lvl &&
monsters[tp->t_index].m_numsum > 0 &&
fallpos(&hero, FALSE, 2) != NULL) {
tp->t_action = A_SUMMON; /* We're going to summon help */
tp->t_no_move = movement(tp); /* It takes time! */
return(TRUE);
}
/*
* If the creature can cast a slow spell and if the prey is within
* 2 dots of a missile fire, then see whether we will cast it.
* if next to player, lessen chance because we don't like being
* disrupted
*/
if (on(*tp, CANSLOW) && dest_player &&
dist < (BOLT_LENGTH+5)*(BOLT_LENGTH+5) &&
rnd(100) < (dist > 3 ? tp->t_cast : tp->t_cast/2)) {
tp->t_action = A_SLOW; /* We're going to slow him */
tp->t_no_move = 3 * movement(tp); /* Takes time! */
debug("casting slow spell!");
return(TRUE);
}
/*
* If we have a special magic item, we might use it. We will restrict
* this options to uniques with relics and creatures with wands for now.
* Also check for the quartermaster. Don't want him shooting wands....
*/
if ((on(*tp, ISUNIQUE) || on(*tp, CARRYSTICK)) &&
off(*tp, CANSELL) && dest_player &&
m_use_pack(tp, er, ee, dist, shoot_dir)) {
return(TRUE);
}
/* From now on, we must have a direct shot at the prey */
if (shoot_dir == NULL) return(FALSE);
/* We may use a sonic blast if we can, only on the player */
if (on(*tp, CANSONIC) &&
dest_player &&
(dist < BOLT_LENGTH*2) &&
(rnd(100) < tp->t_breathe)) {
tp->t_newpos = *shoot_dir; /* Save the direction */
tp->t_action = A_SONIC; /* We're going to sonic blast */
tp->t_no_move = 2 * movement(tp); /* Takes 2 movement periods */
}
/* If we can breathe, we may do so */
else if (on(*tp, CANBREATHE) &&
(dist < BOLT_LENGTH*BOLT_LENGTH) &&
(rnd(100) < tp->t_breathe)) {
tp->t_newpos = *shoot_dir; /* Save the direction */
tp->t_action = A_BREATHE; /* We're going to breathe */
tp->t_no_move = movement(tp); /* It takes 1 movement period */
}
/*
* We may shoot missiles if we can
* if next to player, lessen chance so we don't get disrupted as often
*/
else if (on(*tp,CANMISSILE) &&
rnd(100) < (dist > 3 ? tp->t_cast : tp->t_cast/2)){
tp->t_newpos = *shoot_dir; /* Save the direction */
tp->t_action = A_MISSILE; /* We're going to shoot MM's */
tp->t_no_move = 3 * movement(tp); /* Takes time! */
}
/*
* If we can shoot or throw something, we might do so.
* If next to player, then forget it
*/
else if ((on(*tp,CANSHOOT) || on(*tp,CARRYWEAPON) ||
on(*tp,CARRYDAGGER) || on(*tp, CARRYAXE)) &&
dist > 3 &&
off(*tp, CANSELL) &&
(weapon = get_hurl(tp))) {
tp->t_newpos = *shoot_dir; /* Save the direction */
tp->t_action = A_THROW; /* We're going to throw something */
tp->t_using = weapon; /* Save our weapon */
tp->t_no_move = 2 * movement(tp); /* Takes 2 movement periods */
}
/* We couldn't find anything to do */
else return(FALSE);
return(TRUE);
}
/*
* runners:
* Make all the awake monsters try to do something.
*/
runners(segments)
int segments; /* Number of segments since last called */
{
register struct linked_list *item;
register struct thing *tp;
register min_time = 20; /* Minimum time until a monster can act */
/*
* loop thru the list of running (wandering) monsters and see what
* each one will do this time.
*
* Note: the special case that one of this buggers kills another.
* if this happens than we have to see if the monster killed
* himself or someone else. In case its himself we have to get next
* one immediately. If it wasn't we have to get next one at very
* end in case he killed the next one.
*/
for (item = mlist; item != NULL; item = next(item)) {
tp = THINGPTR(item);
turn_on(*tp, ISREADY);
}
for (;;) {
for (item = mlist; item != NULL; item = next(item)) {
tp = THINGPTR(item);
if (on(*tp, ISREADY))
break;
}
if (item == NULL)
break;
turn_off(*tp, ISREADY);
/* If we are not awake, just skip us */
if (off(*tp, ISRUN) && off(*tp, ISHELD)) continue;
/* See if it's our turn */
tp->t_no_move -= segments;
if (tp->t_no_move > 0) {
if (tp->t_no_move < min_time) min_time = tp->t_no_move;
continue;
}
/* If we were frozen, we're moving now */
if (tp->t_action == A_FREEZE) tp->t_action = A_NIL;
if (on(*tp, ISHELD)) {
/* Make sure the action and using are nil */
tp->t_action = A_NIL;
tp->t_using = NULL;
/* Can we break free? */
if (rnd(tp->t_stats.s_lvl) > 11) {
turn_off(*tp, ISHELD);
runto(tp, &hero);
if (cansee(tp->t_pos.y, tp->t_pos.x))
msg("%s breaks free from the hold spell",
prname(monster_name(tp), TRUE));
}
/* Too bad -- try again later */
else tp->t_no_move = movement(tp);
}
/* Heal the creature if it's not in the middle of some action */
if (tp->t_action == A_NIL) doctor(tp);
while (off(*tp,ISELSEWHERE) &&
off(*tp,ISDEAD) &&
tp->t_no_move <= 0 && off(*tp, ISHELD) && on(*tp, ISRUN)) {
/* Let's act (or choose an action if t_action = A_NIL) */
m_act(tp);
}
if (off(*tp,ISELSEWHERE) && off(*tp,ISDEAD)) {
if (tp->t_no_move < min_time) min_time = tp->t_no_move;
if (tp->t_quiet < 0) tp->t_quiet = 0;
}
}
return(min_time);
}
/*
* See if a monster has some magic it can use. Return TRUE if so.
* Only care about relics and wands for now.
*/
bool
m_use_pack(monster, monst_pos, defend_pos, dist, shoot_dir)
register struct thing *monster;
register coord *monst_pos, *defend_pos;
register int dist;
register coord *shoot_dir;
{
register struct object *obj;
register struct linked_list *pitem, *relic, *stick;
register int units = -1;
relic = stick = NULL;
for (pitem=monster->t_pack; pitem; pitem=next(pitem)) {
obj = OBJPTR(pitem);
if (obj->o_flags & ISCURSED) continue;
if (obj->o_type == RELIC) {
switch (obj->o_which) {
case MING_STAFF:
if (shoot_dir != NULL) {
units = 2; /* Use 2 time units */
relic = pitem;
}
when EMORI_CLOAK:
if (obj->o_charges != 0 &&
shoot_dir != NULL) {
units = 2; /* Use 2 time units */
relic = pitem;
}
when ASMO_ROD:
/* The bolt must be able to reach the defendant */
if (shoot_dir != NULL &&
dist < BOLT_LENGTH * BOLT_LENGTH) {
units = 2; /* Use 2 time units */
relic = pitem;
}
when BRIAN_MANDOLIN:
/* The defendant must be the player and within 4 spaces */
if (ce(*defend_pos, hero) &&
dist < 25 &&
player.t_action != A_FREEZE) {
units = 4;
relic = pitem;
}
when GERYON_HORN:
/* The defendant must be the player and within 5 spaces */
if (ce(*defend_pos, hero) &&
dist < 25 &&
(off(player,ISFLEE)|| player.t_dest!=&monster->t_pos)) {
units = 3;
relic = pitem;
}
}
}
if (obj->o_type == STICK) {
if (obj->o_charges < 1) continue;
switch(obj->o_which) {
case WS_ELECT:
case WS_FIRE:
case WS_COLD:
/* The bolt must be able to reach the defendant */
if (shoot_dir != NULL &&
dist < BOLT_LENGTH * BOLT_LENGTH) {
units = 3;
stick = pitem;
}
when WS_MISSILE:
case WS_SLOW_M:
case WS_CONFMON:
case WS_PARALYZE:
case WS_MDEG:
case WS_FEAR:
if (shoot_dir != NULL) {
units = 3;
stick = pitem;
}
otherwise:
break;
}
}
}
/* use relics in preference to all others */
if (relic) debug("chance to use relic = %d%%", monster->t_artifact);
if (stick) debug("chance to use stick = %d%%", monster->t_wand);
if (relic && rnd(100) < monster->t_artifact) {
monster->t_action = A_USERELIC;
pitem = relic;
}
else if (stick && rnd(100) < monster->t_wand) {
/*
* see if the monster will use the wand
*/
pitem = stick;
monster->t_action = A_USEWAND;
}
else {
return(FALSE);
}
monster->t_no_move = units * movement(monster);
monster->t_using = pitem;
monster->t_newpos = *shoot_dir;
return(TRUE);
}

799
arogue7/aguide.mm Normal file
View file

@ -0,0 +1,799 @@
.\"
.\" aguide.mm
.\"
.\" Advanced Rogue
.\" Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
.\" All rights reserved.
.\"
.\" Based on "Rogue: Exploring the Dungeons of Doom"
.\" Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
.\" All rights reserved.
.\"
.\" See the file LICENSE.TXT for full copyright and licensing information.
.\"
.tr ~
.nr Pt 1
.ds HF 3 2 2 2 2 2 2
.TL
The Dungeons of Doom
.AF Toolchest
.AU " "
.AS 1
.P
Rogue was introduced at the University of California at Berkeley as a
screen-oriented fantasy game.
The game had 26 types of monsters that the player could meet while
exploring a dungeon generated by the computer.
Scrolls, potions, rings, wands, staves, armor, and weapons helped the
player to battle these monsters and to gain gold, the basis for scoring.
.P
The version of Rogue described in this guide has been expanded to include
over 110 monsters with many new capabilities.
Many of the monsters are intelligent, and they, like the player, must avoid
traps and decide when it is better to fight or to run.
The player chooses a character class at the beginning of the game which
defines the player's abilities.
Experience, rather than gold, decides the player's score.
.AE
.MT 4
.H 1 INTRODUCTION
Rogue is a screen-oriented fantasy game set in the ever-changing
\fIDungeons of Doom\fR.
The game comes complete with monsters, spells, weapons, armor, potions,
and other magical items.
The dungeon's geography changes with every game, and although many magical
items have certain identifiable properties, such as turning the player
invisible, the physical manifestation of the magic changes each game.
A red potion, for example, will cause the same reaction throughout
a given game, but it may be a completely different potion in a new game.
.P
Entering the dungeon with only a little food, armor, and a weapon, the player
must develop a good strategy of when
to fight, when to run, and how to best use any magical items found
in the dungeon.
To make things interesting, the player has a quest to return one of
several unique artifacts, rumored to lie deep in the dungeon's bowels.
Returning with this artifact brings great glory and the title of
\fIComplete Winner\fR.
But even after finding the artifact, the player may wish to continue
further to match wits with an \fIarch-devil\fR, \fIdemon prince\fR, or even a
\fIdeity\fR found far down in the dungeon.
Defeating such a creature will gain the player many experience points,
the basis for scoring in Rogue.
.P
It is very difficult to return from the \fIDungeons of Doom\fR.
Few people ever make it out alive.
Should this unlikely event occur, the player would be proclaimed a
complete winner and handsomely rewarded for any booty removed from the
dungeon.
.H 1 "CHARACTER CLASSES"
Before placing the player in the dungeon, the game requests the player
to select what type of character they would like to be:~ a fighter, a magic user, a cleric,
a druid, a thief, a paladin, a ranger, a monk, or an assassin.
.H 2 "The Fighter"
A fighter is very strong and will have a high strength rating.
This great strength gives a fighter the best odds of
winning a battle with a monster.
At high experience levels the \fIfighter\fR also gets to attack
multiple times in a single turn.
This obviously further increases his chances at winning battles.
Intrinsic to the fighter class is a robustness which results in
1 to 12 extra hit points for every new experience
level.
.H 2 "The Magician"
A Magician is able to "cast" spells.
The number and variety of spells increases as
the magician gains experience and intelligence.
Magic users are not as hearty as fighters;
they receive 1 to 6 extra hit
points for every new experience level.
.H 2 "The Cleric"
A cleric is able to "pray" to his god for help.
The number and variety of prayers which the gods are willing to grant to
a cleric increase as the cleric gains experience and wisdom.
.P
Because of their religious nature, clerics can also affect the "undead"
beings, like \fIzombies\fR and \fIghouls\fR, which became monsters after they
died.
If an "undead" creature is next to a cleric, the cleric may try
to turn it and cause it to flee.
If the cleric is sufficiently powerful relative to the monster,
the cleric will destroy it.
This ability increases as the character gains experience levels.
.P
Clerics can gain from 1 to 8 extra hit points on
reaching a new experience level.
.H 2 "The Druid"
The druid is a cleric of sorts but worships nature rather than a god.
The druid is able to "chant" and thereby recieve certain types
of spells. Most of the chants are targeted more towards the
elements and nature.
.P
Druids gain from 1 to 8 hit points when they gain an experience level.
.H 2 "The Thief"
A thief is exceptionally dextrous and has a good chance to
set a trap or rob a monster.
.P
By their nature, thieves can automatically detect all the gold on the
current level of the dungeon.
They are also good at detecting hidden traps.
Because thieves slink along, they are not as likely as other characters
to wake sleeping monsters.
If a \fIthief\fR manages to sneak up on a creature without waking it, he
will get a chance to \fIbackstab\fR the monster. When this is done,
the damage done by the \fIthief\fR greatly increases based on his experience
level.
.P
Thieves gain from 1 to 6 extra hit points from a new experience level.
.H 2 "The Paladin"
The paladin is a type of holy warrior. Somewhat of a cross between a
fighter and a cleric. He is able to pray and turn undead as a cleric,
(but to a lesser degree) but fights as a fighter. He is on the side of
all that is good and righteous. Therefore he would never attack a
creature that would not attack him first. If he does kill a non-violent
creature inadvertantly he will feel "uneasy" and his god may retaliate
by making him a mere fighter.
.P
Paladins gain 1 to 10 hit points per experience level.
.H 2 "The Ranger"
The ranger is somewhat of a cross between a druid and a fighter. He
too is on the side of righteousness and good. Therefore, the same
same restrictions apply to his as they do to a paladin. The ranger
can "chant" and "cast" but to a lesser degree than the druid and
magician.
.P
Rangers gain 1 to 8 hit points per experience level.
.H 2 "The Monk"
The Monk is a martial arts expert. He wears no armor but has
an effective armor class based on his ability to dodge attacks.
He does not need a weapon in combat for his hands and feet are
a formidable weapon. His ability to dodge and use his hands
as weapons increases as he gains in level.
.P
Monks gain 1 to 6 hit points per experience level.
.H 2 "The Assassin"
The assassin is a person trained in the art of killing people
by surprise. He has most of the abilities of the thief except
the "backstab". Instead, the assassin has the chance to kill
an opponent outright with one strike. He is also a ruthless
character and trained in the use of poison. He can recognize
poison on sight and can coat his weapon with it thereby making
his next attack an exceptionally lethal one.
.P
Assassins gain 1 to 6 hit points per experience level.
.H 1 "ATTRIBUTES"
.H 2 "Intelligence"
Intelligence is the primary attribute associated with casting
spells. With higher intelligence comes the knowledge of more
spells, the ability to cast more spells, and faster recovery
of spells that have been cast.
.H 2 "Strength"
This is, of course, the measure of a character's physical strength.
With higher strength a character can carry more, cause more damage
when striking, have a better chance to strike an opponent, and
move about more quickly when carrying a load.
.H 2 "Wisdom"
Wisdom is the primary attribute associated with Praying
to a god. With higher wisdom comes the knowledge of more
prayers, the ability to pray more often, and faster recovery
of prayer ability.
.H 2 "Dexterity"
Dexterity is a measure of a character's agility. With higher dexterity
a character is harder to hit, can hit a opponent more easily, and
can move about more quickly when carrying a load.
.H 2 Constitution
Every character has a constitution rating.
A character with an exceptionally good constitution will gain more than
the normal amount of hit points associated with the character's class
when the character reaches a new experience level. Exceptional constitution
also provides better protection versus poison-based attacks and diseases.
.H 2 "Charisma"
Charisma is a measure of a characters looks and general likeableness.
It effects transactions when trying to purchase things.
.H 2 "Experience Levels"
Characters gain experience for killing monsters, stealing from monsters,
and turning monsters.
Each character class has a set of thresholds associated with it.
When a character reaches a threshold, the character attains the next
experience level.
This new level brings extra hit points and a greater chance of success
in performing the abilities associated with the character's class.
For example, magicians receive new spells, and clerics receive new prayers.
.P
.H 2 "Allocating Attributes"
The player starts with 72 "attribute points" to create a character and
can distribute them in any manner among the six attributes described
above.
When prompting the player for each attribute, the game displays the
minimum and maximum allowable values for that attribute.
The player can type a backspace (control-H) to go back and change
a value; typing an escape (ESC) sets the remaining attributes to
the maximum value possible given the remaining attribute points.
.H 1 "THE SCREEN"
During the normal course of play, the screen consists of three separate
sections:~ the top line of the terminal, the bottom two lines of the
terminal, and the remaining middle lines.
The top line reports actions which occur during the game, the middle
section depicts the dungeon, and the bottom lines describe the player's
current condition.
.H 2 "The Top Line"
Whenever anything happens to the player, such as finding a scroll or
hitting or being hit by a monster, a short report of the occurrence
appears on the top line of the screen.
When such reports occur quickly, one right after another,
the game displays the notice followed by the prompt '\(emMore\(em.'~
After reading this notice, the player can press a space to display
the next message.
At such a point, the game ignores all commands until the player presses
a space.
.H 2 "The Dungeon Section"
The large middle section of the screen displays the player's surroundings using
the following symbols:
.tr ~~
.VL 10
.LI |
A wall of a room.
.LI -
A wall of a room.
.LI *
A pile of gold.
.LI %
A way to the next level.
.LI +
A doorway.
.LI .
The floor in a room.
.LI @
The player.
.LI _
The player, when invisible.
.LI #
The floor in a passageway.
.LI !
A flask containing a potion.
.LI ?
A sealed scroll.
.LI :
Some food.
.LI )
A weapon.
.LI \
Solid rock (denoted by a space).
.LI ]
Some armor.
.LI ;
A miscellaneous magic item
.LI ,
An artifact
.LI =
A ring.
.LI /
A wand or a staff.
.LI ^
The entrance to a trading post
.LI >
A trapdoor leading to the next level
.LI {
An arrow trap
.LI $
A sleeping gas trap
.LI }
A beartrap
.LI ~
A trap that teleports you somewhere else
.LI \`
A poison dart trap
.LI \fR"\fR
A shimmering magic pool
.LI \'
An entrance to a maze
.LI $
Any magical item. (During magic detection)
.LI >
A blessed magical item. (During magic detection)
.LI <
A cursed magical item. (During magic detection)
.LI A\ letter
A monster.
Note that a given letter may signify multiple monsters,
depending on the level of the dungeon.
The player can always identify a current monster by using
the identify command ('\fB/\fR').
.LE
.tr ~
.H 2 "The Status Section"
The bottom two lines of the screen describe the player's current status.
The first line gives the player's characteristics:
.BL
.LI
Intelligence (\fBInt\fR)
.LI
Strength (\fBStr\fR)
.LI
Wisdom (\fBWis\fR)
.LI
Dexterity (\fBDxt\fR)
.LI
Constitution (\fBConst\fR)
.LI
Charisma (\fBChar\fR)
.LI
Encumberance (\fBCarry\fR)
.LE
.P
Intelligence, strength, wisdom, dexterity, charisma, and constitution have a
normal maximum of 25, but can be higher when augmented by a ring.
Encumberance is a measurement of how much the player can carry versus
how much he is currently carrying. The more you carry relative to your
maximum causes you to use more food.
.P
The second status line provides the following information:
.BL
.LI
The current level (\fBLvl\fR) in the dungeon. This number increases as the
player goes further down.
.LI
The player's current number of hit points (\fBHp\fR), followed in parentheses
by the player's current maximum number of hit points.
Hit points express the player's health.
As a player heals by resting, the player's current hit points gradually
increase until reaching the current maximum.
This maximum increases each time a player attains a new experience level.
If the player's current hit points reach 0, the player dies.
.LI
The player's armor class (\fBAc\fR).
This number describes the amount of protection provided by the armor, cloaks,
and/or rings currently worn by the player.
It is also affected by high or low dexterity.
Wearing no armor is equivalent to an armor class of 10.
The protection level increases as the armor class decreases.
.LI
The player's current experience level (\fBExp\fR) followed by the player's
experience points.
The player can gain experience points by killing monsters, successfully
stealing from monsters, and turning monsters.
When a player gains enough experience points to surpass a threshold that
depends on the player's character type, the player reaches a new
experience level.
A new experience level brings extra hit points and possibly added
abilities, such as a new spell for a magician or a new prayer for
a cleric.
.LI
A description of the player's character.
This description depends on the player's character type and experience
level.
.LE
.H 1 COMMANDS
A player can invoke most Rogue commands by typing a single character.
Some commands, however, require a direction, in which case the player
types the command character followed by a directional command.
Many commands can be prefaced by a number, indicating how many times
the command should be executed.
.P
When the player invokes a command referring to an item in the player's
pack (such as reading a scroll), the game prompts for the item.
The player should then type the letter associated with the item, as
displayed by the \fBinventory\fR command.
Typing a '*' at this point produces a list of the eligible items.
.P
Rogue understands the following commands:~
.VL 4
.LI ?
Preceding a command by a '\fB?\fR' produces a brief explanation of the command.
The command '\fB?*\fR' gives an explanation of all the commands.
.LI /
Preceding a symbol by a '\fB/\fR' identifies the symbol.
.LI =
Clarify.
After typing an '\fB=\fR' sign, the player can use the movement keys to
position the cursor anywhere on the current level.
As long as the player can normally see the selected position, Rogue will
identify whatever is at that space.
Examples include a \fIsleeping giant rat\fR, a \fIblue potion\fR, and a \fIfood
ration\fR.
.LI h
Move one position to the left.
.LI j
Move one position down.
.LI k
Move one position up.
.LI l
Move one position to the right.
.LI y
Move one position to the top left.
.LI u
Move one position to the top right.
.LI b
Move one position to the bottom left.
.LI n
Move one position to the bottom right.
.LI H
Run to the left until reaching something interesting.
.LI J
Run down until reaching something interesting.
.LI K
Run up until reaching something interesting.
.LI L
Run to the right until reaching something interesting.
.LI Y
Run to the top left until reaching something interesting.
.LI U
Run to the top right until reaching something interesting.
.LI B
Run to the bottom left until reaching something interesting.
.LI N
Run to the bottom right until reaching something interesting.
.LI t
This command prompts for an object from the players pack.
The player then \fBt\fRhrows the object in the specified direction.
.LI f
When this command precedes a directional command, the player moves
in the specified direction until passing something interesting.
.LI z
This command prompts for a wand or staff from the player's pack and
\fBz\fRaps it in the specified direction.
.LI >
Go down to the next level.
.LI <
Go up to the next level.
.LI s
\fBS\fRearch for a secret door or a trap in the circle surrounding the player.
.LI .
This command (a dot) causes the player to rest a turn.
.LI i
Display an \fBi\fRnventory of the player's pack.
.LI I
This command prompts for an item from the player's pack and displays
the \fBi\fRnventory information for that item.
.LI q
\fBQ\fRuaff a potion from the player's pack.
.LI r
\fBR\fRead a scroll from the player's pack.
.LI e
\fBE\fRat some food from the player's pack.
.LI w
\fBW\fRield a weapon from the player's pack.
.LI W
\fBW\fRear some armor, ring, or miscellaneous magic item from the player's pack.
The player can wear a maximum of eight rings.
.LI T
\fBT\fRake off whatever the player is wearing.
.LI ^U
\fBU\fRse a magic item in the player's pack.
.LI d
\fBD\fRrop an item from the player's pack.
.LI P
\fBP\fRick up the items currently under the player.
.LI ^N
When the player types this command, Rogue prompts for a monster or an item
from the player's pack and a one-line \fBn\fRame.
For monsters, the player can use the movement keys to position the cursor
over the desired monster, and Rogue will use the given \fBn\fRame to refer
to that monster.
For items, Rogue gives all similar items (such as all the blue potions)
the specified \fBn\fRame.
.LI m
When the player types this command, Rogue prompts for an item from the
player's pack and a one-line name.
Rogue then \fBm\fRarks the specified item with the given name.
.LI o
Typing this command causes Rogue to display all the settable \fBo\fRptions.
The player can then merely examine the options or change any or all of them.
.LI C
This command, restricted to magicians and rangers
produces a listing of the current supply of spells.
The player can select one of the displayed spells and, if the player's
energy level is sufficiently high, \fBC\fRast it.
The more complicated the spell, the more energy it takes.
.LI c
This command, restricted to druids and rangers
produces a listing of the current supply of chants.
The player can select one of the displayed chants and, if the player's
energy level is sufficiently high, \fBc\fRhant it.
The more complicated the spell, the more energy it takes.
.LI p
This command, restricted to clerics and paladins,
produces a listing of the character's known \fBp\fRrayers.
The player can then offer one of these prayers to the character's deity.
Deities are not known for favoring characters which continually pray
to them, and they are most likely to answer the least "ambitious" prayers.
.LI a
This command is restricted to clerics and paladins
must be followed by a directional command.
If there is an "undead" monster standing next to the player in the
specified direction, there is a chance the player will \fBa\fRffect the
monster by causing it to flee or possibly even destroying it.
.LI *
Count the gold in the player's pack.
.LI ^
This command sets a trap and is limited to thieves and assassins.
If the character is successful, Rogue prompts the player for a type of trap
and sets it where the player is standing.
.LI G
This command is restricted to thieves and assassins.
It causes Rogue to display all the gold on the current level.
.LI D
\fBD\fRip something into a magic pool.
.LI ^T
This command is restricted to thieves and assassins.
It must be followed by a directional command.
If there is a monster standing next to the player in the specified direction,
the player tries to \fBs\fRteal an item from the monster's pack.
If the player is successful, the monster does not notice anything, but if
the player is unsuccessful, there is a chance the monster will wake up.
.LI ^L
Redraw the screen.
.LI ^R
\fBR\fRepeat the last message that was displayed on the top line of the screen.
.LI ^[
Typing an escape will usually cause Rogue to cancel the current command.
.LI v
Print the current Rogue \fBv\fRersion number.
.LI !
Escape to the shell.
.LI S
Quit and \fBs\fRave the game for resumption at a later time.
.LI Q
\fBQ\fRuit without saving the game.
.LE
.H 1 "IMPLICIT COMMANDS"
There is no "attack" command.
If a player wishes to attack a monster, the player simply tries to
move onto the spot where the monster is standing.
The game then assumes that the player wishes to attack the monster
with whatever weapon the player is wielding.
.P
When the player moves onto an item, the game automatically places the
object into the player's pack.
If there is no room left in the pack, the game announces that fact and
leaves the item on the floor.
.H 1 TIME
All actions except for purely bookkeeping commands, such as taking an
inventory, take time.
The amount of time varies with the command.
Swinging a weapon, for example, takes more time than simply moving;
so a monster could move several spaces in the time it takes the player
to make one attack.
The time it takes to swing a weapon also varies based on the bulk of the
weapon, and the time it takes to simply move a space varies with the type
of armor worn.
Movement is always faster when flying.
.P
Since actions take time, some of them can be disrupted.
If the player is casting a spell, for example, and gets hit before finishing
it, the spell is lost.
Similarly, the player might choke if hit while trying to eat.
Of course, the same rule applies when the player hits a monster.
.P
Magical hasting (or slowing) will decrease (or increase) the time it takes
to perform an action.
.H 1 LIGHT
Some rooms in the dungeon possess a natural light source.
In other rooms and in corridors the player can see only those things
within a one space radius from the player.
These dark rooms can be lit with magical light or by a \fIfire beetle\fR.
.H 1 "WEAPONS AND ARMOR"
The player can wield exactly one weapon at a time.
When the player attacks a monster, the amount of damage depends on the
particular weapon the player is wielding.
To fire a projectile weapon, such as a crossbow or a short bow, the player
should wield the bow and "throw" the bolt or arrow at the monster.
.P
A weapon may be cursed or blessed, affecting the likelihood of hitting a
monster with the weapon and the damage the weapon will inflict on the monster.
If the player has identified a weapon, the "to hit" and "to damage" bonuses
appear in that order before the weapon's name in an inventory listing.
A positive bonus indicates a blessed weapon, and a negative bonus usually
indicates a cursed weapon.
The player cannot release a cursed weapon.
.P
Without any armor the player has an armor class of 10.
The lower the player's armor class, the harder it is for a monster to hit
the player, so
wearing armor can improve the player's armor class.
A cursed suit of armor, however, offers poor protection and may sometimes be
worse than no armor at all.
.P
After the player has identified a suit of armor, the protection bonus appears
before the armor's name in an inventory listing.
If the bonus is positive the armor is blessed, and if it is negative, the
armor is usually cursed.
The player cannot remove a cursed suit of armor.
.P
Some monsters can corrode armor when they hit it.
If such a monster hits the player when the player is wearing metal armor,
the armor loses some of its protection value, but the corrosion does not
curse the armor.
This corrosive property can also apply to weapons when the player hits
such a monster.
.H 1 "POTIONS AND SCROLLS"
The player can frequently find potions and scrolls in the dungeon.
In any given dungeon, the player can distinguish among the different types
of potions by a potion's color and among the different types of scrolls
by a scroll's name.
Quaffing a potion or reading a scroll usually causes some magical occurrence.
Most potions and scrolls may be cursed or blessed.
.H 1 RINGS
The player can wear a maximum of eight rings, and
they have a magical effect on the player as long as they are worn.
Some rings also speed up the player's metabolism, making the player require
food more often.
Many rings can be cursed or blessed, and the player cannot remove a
cursed ring.
The player can distinguish among different types of rings by a ring's jewel.
.H 1 "WANDS AND STAVES"
Wands and staves affect the player's environment.
The player can zap a wand or staff at something and perhaps shoot a bolt
of lightning at it or teleport it away.
All wands or staves of the same type are constructed with the same type of wood.
Some wands and staves may be cursed or blessed.
.H 1 FOOD
The player must be careful not to run out of food since moving through the
dungeon fighting monsters consumes a lot of energy.
Starving results in the player's fainting for increasingly longer periods
of time, during which any nearby monster can attack the player freely.
.P
Food comes in the form of standard rations and as a variety of berries.
Some berries have side effects in addition to satisfying one's hunger.
.H 1 GOLD
Gold has one use in a dungeon:~ buying things.
One can buy things in two ways, either in a \fItrading post\fR or from a
\fIquartermaster\fR.
A trading post is a place that sometimes occurs "between levels" of the
dungeon and can be entered by stepping on the entrance.
A quartermaster is a person who will sometimes appear and
will try to sell the player some of his wares.
These wares are never cursed and frequently blessed, though blessed goods
cost more than normal goods.
If the player chooses to buy one of the quartermaster's items, the
quartermaster trades the item for the specified amount of gold and
disappears.
Attacking a quartermaster causes him to vanish without offering
a trade.
.P
The player starts the game in a trading post with a class-dependent allotment
of gold.
Although there are restrictions on the use of some items (eg. only fighters,
paladins, and rangers can wield two-handed swords), the market will happily
sell the player anything that he can afford.
.H 1 "MISCELLANEOUS MAGIC ITEMS"
Miscellaneous items such as a pair of boots or a book may be found within the
dungeon.
These items can usually be used to the player's advantage (assuming they are
not cursed).
Some of these items can be worn, such as a cloak, while others are to be used,
such as a book.
.H 1 "ARTIFACTS"
Some monsters down in the depths of the dungeon carry unique artifacts.
The game begins as a quest to retrieve one of these items.
Each artifact appears only on its owner's person.
These items also can usually be used to the player's advantage. However,
care must be taken when handling them for they are intelligent and will
reject mishandling or abuse. These items consume food and merely carrying
them will result in increased food use.
.H 1 TRAPS
A variety of traps, including trap doors, bear traps, and sleeping traps, are
hidden in the dungeon.
They remain hidden until sprung by a monster or the player.
A sprung trap continues to function, but since it is visible, an intelligent
monster is not likely to tread on it.
.H 1 "THE MONSTERS"
Each monster except for the merchant \fIquartermaster\fR appears in
a limited range of dungeon levels.
All monsters of the same type share the same abilities;
all \fIgiant rats\fR, for example, can give the player a disease, and
all \fIjackalweres\fR can put the player to sleep.
Monsters of the same type can vary, however, such that one \fIkobold\fR
may be much more difficult to kill than another one.
In general, the more difficult it is to kill a monster, the more
experience points the monster is worth.
.P
Most monsters attack by biting and clawing, but some monsters carry
weapons, including such projectile weapons as short bows and crossbows,
and some monsters have breath weapons.
Some monsters even use magical items, such as wands.
Monsters with distance weapons or magic can attack the player from across a room
or down a corridor.
.P
Some monsters are more intelligent than others, and the more intelligent
a monster, the more likely that the monster will run away if it is about
to die.
A fleeing monster will not attack the player unless cornered.
.P
It is sometimes possible to enlist a monster's aid.
Reading a \fIcharm monster\fR scroll, for example, or singing a \fIcharm
monster\fR chant can make a monster believe the player is its friend.
A charmed monster will fight hostile monsters for the player as long as they are
not of its race.
.P
As the player moves down in the dungeon, the monsters get more powerful.
Deep down in the dungeon there exist some one-of-a-kind monsters.
These monsters are greatly feared.
However, once a "unique monster" is killed, the player will not find
another in the current dungeon.
.H 1 OPTIONS
Rogue has several options which may be set by the player:~
.VL 7
.LI \fBterse\fR
Setting this Boolean option results in shorter messages appearing on
the top line of the screen.
.LI \fBjump\fR
Setting this Boolean option results in waiting until the player has
finished running to draw the player's path.
Otherwise the game always displays the path one step at a time.
.LI \fBstep\fR
Setting this Boolean option results in most listings, such as an inventory,
appearing one item at a time on the top line of the screen.
When this option is not set, the game clears the screen, displays the
list, and then redraws the dungeon.
.LI \fBflush\fR
Setting this Boolean option results in flushing all typeahead (pending) commands
when the player encounters a monster.
.LI \fBaskme\fR
Setting this Boolean option results in the game prompting the player for a
name upon encountering a new type of scroll, potion, ring, staff, or wand.
.LI \fBpickup\fR
This option specifys whether items should be picked up automatically as the
rogue steps over them.
In the non-automatic mode, the player may still pick up items via the
pickup (P) command.
The option defaults to true.
.LI \fBname\fR
This string is the player's name and defaults to the player's account name.
.LI \fBfile\fR
This string, which defaults to rogue.save, specifies the file to use for
saving the game.
.LI \fBscore\fR
This string identifies the top-twenty score file to use for the game.
.LI \fBclass\fR
This option specifies the character class of the rogue.
It can be set only in the ROGUEOPTS environment variable.
.LI \fBquested~item\fR
.br
This option is set by the game at the start and cannot be reset by the player.
It is merely listed to remind the player of his quest.
.LE
.P
The player can set options at the beginning of a game via the ROGUEOPTS
environment variable.
Naming a Boolean option sets it, and preceding the Boolean option name by
"no" clears it.
The syntax "stringoption=name" sets a string option to "name."~
So setting ROGUEOPTS to
"terse, jump, nostep, flush, askme, name=Ivan~the~Terrible"
would set the \fIterse, jump, flush\fR, and \fIaskme\fR Boolean options,
clear the \fIstep\fR Boolean option, set the player's
\fIname\fR to "Ivan the Terrible," and use the defaults for
the \fIsave file\fR and the \fIscore file\fR.
.P
The player may change an option at any time during the game
via the \fBoption\fR command, which results in a listing of
the current options.
Typing a new value changes the option, a RETURN moves to the
next option, a '-' moves to the previous option, and an ESCAPE
returns the player to the dungeon.
.H 1 SCORING
The player receives experience points for stealing items from
monsters, turning monsters (a clerical ability), and killing
monsters.
When the player gets killed, the player's score equals the player's
experience points.
A player who quits gets a score equal to the player's experience
points and gold.
If the player makes it back up out of the dungeon, the player's
score equals the player's experience points plus the gold the
player carried and the gold received from selling the player's
possessions.
.P
Rogue maintains a list of the top twenty scores to date, together
with the name of the player obtaining the score, the level where
the player finished, and the manner in which the player ended the
game.
As an installation option, the game may record only one entry per
character type and login;
this restriction encourages a greater number of different players
in the scorechart.
.H 1 ACKNOWLEDGEMENTS
This version of Rogue is based on a version developed at the
University of California.

1122
arogue7/arogue77.doc Normal file

File diff suppressed because it is too large Load diff

1328
arogue7/arogue77.html Normal file

File diff suppressed because it is too large Load diff

21
arogue7/arogue77.sln Normal file
View file

@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 7.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "arogue77", "arogue77.vcproj", "{D95CFDAC-E66E-47D3-87B7-F76149F6A51D}"
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
ConfigName.0 = Debug
ConfigName.1 = Release
EndGlobalSection
GlobalSection(ProjectDependencies) = postSolution
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{D95CFDAC-E66E-47D3-87B7-F76149F6A51D}.Debug.ActiveCfg = Debug|Win32
{D95CFDAC-E66E-47D3-87B7-F76149F6A51D}.Debug.Build.0 = Debug|Win32
{D95CFDAC-E66E-47D3-87B7-F76149F6A51D}.Release.ActiveCfg = Release|Win32
{D95CFDAC-E66E-47D3-87B7-F76149F6A51D}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

270
arogue7/arogue77.vcproj Normal file
View file

@ -0,0 +1,270 @@
<?xml version="1.0" encoding = "Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.00"
Name="arogue77"
ProjectGUID="{D95CFDAC-E66E-47D3-87B7-F76149F6A51D}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../pdcurses"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DUMP"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"
DisableSpecificWarnings="4013;4033;4716"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="shfolder.lib pdcurses.lib"
OutputFile="$(OutDir)/arogue77.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="../pdcurses"
IgnoreAllDefaultLibraries="FALSE"
IgnoreDefaultLibraryNames="LIBC.LIB"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/arogue77.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
OmitFramePointers="TRUE"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/arogue77.exe"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
</Configuration>
</Configurations>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
<File
RelativePath="actions.c">
</File>
<File
RelativePath="chase.c">
</File>
<File
RelativePath="command.c">
</File>
<File
RelativePath="daemon.c">
</File>
<File
RelativePath="daemons.c">
</File>
<File
RelativePath="eat.c">
</File>
<File
RelativePath="effects.c">
</File>
<File
RelativePath="encumb.c">
</File>
<File
RelativePath="fight.c">
</File>
<File
RelativePath="init.c">
</File>
<File
RelativePath="io.c">
</File>
<File
RelativePath="list.c">
</File>
<File
RelativePath="main.c">
</File>
<File
RelativePath="maze.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="outside.c">
</File>
<File
RelativePath="pack.c">
</File>
<File
RelativePath="passages.c">
</File>
<File
RelativePath="player.c">
</File>
<File
RelativePath="potions.c">
</File>
<File
RelativePath="rings.c">
</File>
<File
RelativePath="rip.c">
</File>
<File
RelativePath="rogue.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="trader.c">
</File>
<File
RelativePath="util.c">
</File>
<File
RelativePath="vers.c">
</File>
<File
RelativePath="weapons.c">
</File>
<File
RelativePath="wear.c">
</File>
<File
RelativePath="wizard.c">
</File>
<File
RelativePath="xcrypt.c">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc">
<File
RelativePath="mach_dep.h">
</File>
<File
RelativePath="network.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="aguide.mm">
</File>
<File
RelativePath="arogue77.doc">
</File>
<File
RelativePath="arogue77.html">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

928
arogue7/chase.c Normal file
View file

@ -0,0 +1,928 @@
/*
* chase.c - Code for one object to chase another
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Code for one object to chase another
*
*/
#include <ctype.h>
#include <limits.h>
#include "curses.h"
#include "rogue.h"
#define MAXINT INT_MAX
#define MININT INT_MIN
/*
* Canblink checks if the monster can teleport (blink). If so, it will
* try to blink the monster next to the player.
*/
bool
can_blink(tp)
register struct thing *tp;
{
register int y, x, index=9;
coord tryp; /* To hold the coordinates for use in diag_ok */
bool spots[9], found_one=FALSE;
/*
* First, can the monster even blink? And if so, there is only a 50%
* chance that it will do so. And it won't blink if it is running or
* held.
*/
if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) ||
on(*tp, ISFLEE) ||
tp->t_action == A_FREEZE ||
(rnd(12) < 6)) return(FALSE);
/* Initialize the spots as illegal */
do {
spots[--index] = FALSE;
} while (index > 0);
/* Find a suitable spot next to the player */
for (y=hero.y-1; y<hero.y+2; y++)
for (x=hero.x-1; x<hero.x+2; x++, index++) {
/* Make sure x coordinate is in range and that we are
* not at the player's position
*/
if (x<0 || x >= cols || index == 4) continue;
/* Is it OK to move there? */
if (step_ok(y, x, NOMONST, tp) &&
(!isatrap(mvwinch(cw, y, x)) ||
rnd(10) >= tp->t_stats.s_intel ||
on(*tp, ISFLY))) {
/* OK, we can go here. But don't go there if
* monster can't get at player from there
*/
tryp.y = y;
tryp.x = x;
if (diag_ok(&tryp, &hero, tp)) {
spots[index] = TRUE;
found_one = TRUE;
}
}
}
/* If we found one, go to it */
if (found_one) {
char rch; /* What's really where the creatures moves to */
/* Find a legal spot */
while (spots[index=rnd(9)] == FALSE) continue;
/* Get the coordinates */
y = hero.y + (index/3) - 1;
x = hero.x + (index % 3) - 1;
/* Move the monster from the old space */
mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
/* Move it to the new space */
tp->t_oldch = CCHAR( mvwinch(cw, y, x) );
/* Display the creature if our hero can see it */
if (cansee(y, x) &&
off(*tp, ISINWALL) &&
!invisible(tp))
mvwaddch(cw, y, x, tp->t_type);
/* Fix the monster window */
mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Clear old position */
mvwaddch(mw, y, x, tp->t_type);
/* Record the new position */
tp->t_pos.y = y;
tp->t_pos.x = x;
/* If the monster is on a trap, trap it */
rch = CCHAR( mvinch(y, x) );
if (isatrap(rch)) {
if (cansee(y, x)) tp->t_oldch = rch;
be_trapped(tp, &(tp->t_pos));
}
}
return(found_one);
}
/*
* Can_shoot determines if the monster (er) has a direct line of shot
* at the prey (ee). If so, it returns the direction in which to shoot.
*/
coord *
can_shoot(er, ee)
register coord *er, *ee;
{
static coord shoot_dir;
/*
* They must be in the same room or very close (at door)
*/
if (roomin(er) != roomin(ee) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1)
return(NULL);
/* Do we have a straight shot? */
if (!straight_shot(er->y, er->x, ee->y, ee->x, &shoot_dir)) return(NULL);
else return(&shoot_dir);
}
/*
* chase:
* Find the spot for the chaser(er) to move closer to the
* chasee(ee). Rer is the room of the chaser, and ree is the
* room of the creature being chased (chasee).
*/
chase(tp, ee, rer, ree, flee)
register struct thing *tp;
register coord *ee;
register struct room *rer, *ree;
bool flee; /* True if destination (ee) is player and monster is running away
* or the player is in a wall and the monster can't get to it
*/
{
int dist, thisdist, monst_dist = MAXINT;
register coord *er = &tp->t_pos;
struct thing *prey; /* What we are chasing */
coord ch_ret; /* Where chasing takes you */
char ch, mch;
bool next_player = FALSE;
/*
* set the distance from the chas(er) to the chas(ee) here and then
* we won't have to reset it unless the chas(er) moves (instead of shoots)
*/
dist = DISTANCE(er->y, er->x, ee->y, ee->x);
/*
* See if our destination is a monster or player. If so, make "prey" point
* to it.
*/
if (ce(hero, *ee)) prey = &player; /* Is it the player? */
else if (tp->t_dest && ce(*(tp->t_dest), *ee)) { /* Is it a monster? */
struct linked_list *item;
/* What is the monster we're chasing? */
item = find_mons(ee->y, ee->x);
if (item != NULL) prey = THINGPTR(item);
else prey = NULL;
}
else prey = NULL;
/* We will use at least one movement period */
tp->t_no_move = movement(tp);
if (on(*tp, ISFLY)) /* If the creature is flying, speed it up */
tp->t_no_move /= 2;
/*
* If the thing is confused or it can't see the player,
* let it move randomly.
*/
if ((on(*tp, ISHUH) && rnd(10) < 8) ||
(prey && on(*prey, ISINVIS) && off(*tp, CANSEE))) { /* invisible prey */
/*
* get a valid random move
*/
tp->t_newpos = *rndmove(tp);
dist = DISTANCE(tp->t_newpos.y, tp->t_newpos.x, ee->y, ee->x);
}
/*
* Otherwise, find the empty spot next to the chaser that is
* closest to the chasee.
*/
else {
register int ey, ex, x, y;
int dist_to_old = MININT; /* Dist from goal to old position */
/*
* This will eventually hold where we move to get closer
* If we can't find an empty spot, we stay where we are.
*/
dist = flee ? 0 : MAXINT;
ch_ret = *er;
/* Are we at our goal already? */
if (!flee && ce(ch_ret, *ee)) {
turn_off(*tp, ISRUN); /* So stop running! */
return;
}
ey = er->y + 1;
ex = er->x + 1;
/* Check all possible moves */
for (x = er->x - 1; x <= ex; x++) {
if (x < 0 || x >= cols) /* Don't try off the board */
continue;
for (y = er->y - 1; y <= ey; y++) {
coord tryp;
if ((y < 1) || (y >= lines - 2)) /* Don't try off the board */
continue;
/* Don't try the player if not going after the player */
if ((flee || !ce(hero, *ee) || on(*tp, ISFRIENDLY)) &&
x == hero.x && y == hero.y) {
next_player = TRUE;
continue;
}
tryp.x = x;
tryp.y = y;
/* Is there a monster on this spot closer to our goal?
* Don't look in our spot or where we were.
*/
if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
isalpha(mch = CCHAR( mvwinch(mw, y, x) ) )) {
int test_dist;
test_dist = DISTANCE(y, x, ee->y, ee->x);
if (test_dist <= 25 && /* Let's be fairly close */
test_dist < monst_dist) {
/* Could we really move there? */
mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */
if (diag_ok(er, &tryp, tp)) monst_dist = test_dist;
mvwaddch(mw, y, x, mch); /* Restore monster */
}
}
/* Can we move onto the spot? */
if (!diag_ok(er, &tryp, tp)) continue;
ch = CCHAR( mvwinch(cw, y, x) ); /* Screen character */
/*
* Stepping on player is NOT okay if we are fleeing.
* If we are friendly to the player and there is a monster
* in the way that is not of our race, it is okay to move
* there.
*/
if (step_ok(y, x, FIGHTOK, tp) &&
(off(*tp, ISFLEE) || ch != PLAYER))
{
/*
* If it is a trap, an intelligent monster may not
* step on it (unless our hero is on top!)
*/
if ((isatrap(ch)) &&
(rnd(10) < tp->t_stats.s_intel) &&
(!on(*tp, ISFLY)) &&
(y != hero.y || x != hero.x))
continue;
/*
* OK -- this place counts
*/
thisdist = DISTANCE(y, x, ee->y, ee->x);
/* Adjust distance if we are being shot at */
if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
prey != NULL) {
/* Move out of line of sight */
if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) {
if (flee) thisdist -= SHOTPENALTY;
else thisdist += SHOTPENALTY;
}
/* But do we want to leave the room? */
else if (rer && rer == ree && ch == DOOR)
thisdist += DOORPENALTY;
}
/* Don't move to the last position if we can help it
* (unless out prey just moved there)
*/
if (ce(tryp, tp->t_oldpos) && (flee || !ce(tryp, hero)))
dist_to_old = thisdist;
else if ((flee && (thisdist > dist)) ||
(!flee && (thisdist < dist)))
{
ch_ret = tryp;
dist = thisdist;
}
}
}
}
/* If we aren't trying to get the player, but he is in our way,
* hit him (unless we have been turned or are friendly). next_player
* being TRUE -> we are next to the player but don't want to hit him.
*
* If we are friendly to the player, following him, and standing next
* to him, we will try to help him out in battle.
*/
if (next_player && off(*tp, WASTURNED)) {
if (off(*tp, ISFRIENDLY) &&
((flee && ce(ch_ret, *er)) ||
(!flee && DISTANCE(er->y, er->x, ee->y, ee->x) < dist)) &&
step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) {
/* Okay to hit player */
debug("Switching to hero.");
tp->t_newpos = hero;
tp->t_action = A_MOVE;
return;
}
else if (on(*tp, ISFRIENDLY) && !flee && ce(*ee, hero)) {
/*
* Look all around the player. If there is a fightable
* creature next to both of us, hit it. Otherwise, if
* there is a fightable creature next to the player, try
* to move next to it.
*/
dist = MAXINT;
for (x = hero.x - 1; x <= hero.x + 1; x++) {
if (x < 0 || x >= cols) /* Don't try off the board */
continue;
for (y = hero.y - 1; y <= hero.y + 1; y++) {
if ((y < 1) || (y >= lines - 2)) /* Stay on the board */
continue;
/* Is there a fightable monster here? */
if (isalpha(mvwinch(mw, y, x)) &&
step_ok(y, x, FIGHTOK, tp) &&
off(*tp, ISSTONE)) {
thisdist = DISTANCE(er->y, er->x, y, x);
if (thisdist < dist) {
dist = thisdist;
ch_ret.y = y;
ch_ret.x = x;
}
}
}
}
/* Are we next to a bad guy? */
if (dist <= 2) { /* Get him! */
tp->t_newpos = ch_ret;
tp->t_action = A_MOVE;
}
/* Try to move to the bad guy */
else if (dist < MAXINT)
chase(tp, &ch_ret,
roomin(&tp->t_pos), roomin(&ch_ret), FALSE);
else tp->t_action = A_NIL;
return;
}
}
/*
* If we have decided that we can move onto a monster (we are
* friendly to the player, go to it.
*/
if (!ce(ch_ret, *er) && isalpha(mvwinch(mw, ch_ret.y, ch_ret.x))) {
debug("Attack monster");
tp->t_newpos = ch_ret;
tp->t_action = A_MOVE;
return;
}
/* If we can't get closer to the player (if that's our goal)
* because other monsters are in the way, just stay put
*/
if (!flee && ce(hero, *ee) && monst_dist < MAXINT &&
DISTANCE(er->y, er->x, hero.y, hero.x) < dist) {
tp->t_action = A_NIL; /* do nothing for awhile */
return;
}
/* Do we want to go back to the last position? */
else if (dist_to_old != MININT && /* It is possible to move back */
((flee && dist == 0) || /* No other possible moves */
(!flee && dist == MAXINT))) {
/* Do we move back or just stay put (default)? */
dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */
if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos;
}
/* Record the new destination */
tp->t_newpos = ch_ret;
}
/*
* Do we want to fight or move? If our selected destination (ch_ret)
* is our hero, then we want to fight. Otherwise, we want to move.
*/
if (ce(tp->t_newpos, hero)) {
/* Fight! (or sell) */
if (on(*tp, CANSELL)) {
tp->t_action = A_SELL;
tp->t_no_move += movement(tp); /* takes a little time to sell */
}
else {
tp->t_action = A_ATTACK;
/*
* Try to find a weapon to wield. Wield_weap will return a
* projector if weapon is a projectile (eg. bow for arrow).
* If weapon is NULL (the case here), it will try to find
* a suitable weapon.
*
* Add in rest of time. Fight is
* movement() + weap_move() + FIGHTBASE
*/
tp->t_using = wield_weap(NULL, tp);
if (tp->t_using == NULL)
tp->t_no_move += weap_move(tp, NULL);
else
tp->t_no_move += weap_move(tp, OBJPTR(tp->t_using));
if (on(*tp, ISHASTE))
tp->t_no_move += FIGHTBASE/2;
else if (on(*tp, ISSLOW))
tp->t_no_move += FIGHTBASE*2;
else
tp->t_no_move += FIGHTBASE;
}
}
else {
/* Move */
tp->t_action = A_MOVE;
/*
* Check if the creature is not next to the player. If it
* is not and has held or suffocated the player, then stop it!
* Note that this code should more appropriately appear in
* the area that actually moves the monster, but for now it
* is okay here because the player can't move while held or
* suffocating.
*/
if (dist > 2) {
if (on(*tp, DIDHOLD)) {
turn_off(*tp, DIDHOLD);
turn_on(*tp, CANHOLD);
if (--hold_count == 0)
turn_off(player, ISHELD);
}
/* If monster was suffocating, stop it */
if (on(*tp, DIDSUFFOCATE)) {
turn_off(*tp, DIDSUFFOCATE);
turn_on(*tp, CANSUFFOCATE);
extinguish(suffocate);
msg("You can breathe again.....Whew!");
}
}
}
}
/*
* do_chase:
* Make one thing chase another.
*/
do_chase(th)
register struct thing *th;
{
register struct room *orig_rer, /* Original room of chaser */
*new_room; /* new room of monster */
char floor, rch, sch;
coord old_pos, /* Old position of monster */
ch_ret; /* Where we want to go */
if (on(*th, NOMOVE)) return;
ch_ret = th->t_newpos; /* Record our desired new position */
/*
* Make sure we have an open spot (no other monster's gotten in our way,
* someone didn't just drop a scare monster there, our prey didn't just
* get there, etc.)
*/
if (!step_ok(th->t_newpos.y, th->t_newpos.x, FIGHTOK, th)) {
/*
* Most monsters get upset now. Guardians are all friends,
* and we don't want to see 50 messages in a row!
*/
if (th->t_stats.s_intel > 4 &&
off(*th, ISUNDEAD) &&
off(*th, ISGUARDIAN) &&
off(*th, AREMANY) &&
off(*th, ISHUH) &&
off(player, ISBLIND) &&
cansee(unc(th->t_pos)) &&
!invisible(th))
msg("%s motions angrily.", prname(monster_name(th), TRUE));
return;
}
else if (ce(th->t_newpos, hero) || /* Player just got in our way */
isalpha(mvwinch(mw, th->t_newpos.y, th->t_newpos.x))) {
bool fightplayer = ce(th->t_newpos, hero);
/* If we were turned or are friendly, we just have to sit here! */
if (fightplayer && (on(*th, WASTURNED) || on(*th, ISFRIENDLY))) return;
/* Do we want to sell something? */
if (fightplayer && on(*th, CANSELL)) {
th->t_action = A_SELL;
th->t_no_move += movement(th); /* takes a little time to sell */
return;
}
/* Let's hit him */
th->t_action = A_ATTACK;
/*
* Try to find a weapon to wield. Wield_weap will return a
* projector if weapon is a projectile (eg. bow for arrow).
* If weapon is NULL (the case here), it will try to find
* a suitable weapon.
*/
th->t_using = wield_weap(NULL, th);
/*
* add in rest of time
*/
if (th->t_using == NULL)
th->t_no_move += weap_move(th, NULL);
else
th->t_no_move += weap_move(th, OBJPTR(th->t_using));
if (on(*th, ISHASTE))
th->t_no_move += FIGHTBASE/2;
else if (on(*th, ISSLOW))
th->t_no_move += FIGHTBASE*2;
else
th->t_no_move += FIGHTBASE;
return;
}
/*
* Blank out the old position and record the new position --
* the blanking must be done first in case the positions are the same.
*/
mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type);
/* Get new and old rooms of monster */
new_room = roomin(&ch_ret);
orig_rer = roomin(&th->t_pos);
/* Store the critter's old position and update the current one */
old_pos = th->t_pos;
th->t_pos = ch_ret;
floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR;
/* If we have a scavenger, it can pick something up */
if (off(*th, ISGUARDIAN)) {
register struct linked_list *n_item, *o_item;
register int item_count = 0;
bool want_something = FALSE;
while ((n_item = find_obj(ch_ret.y, ch_ret.x)) != NULL) {
register struct object *n_obj, *o_obj;
bool wants_it;
/* Does this monster want anything? */
if (want_something == FALSE) {
if (on(*th, ISSCAVENGE) || on(*th, CARRYFOOD) ||
on(*th, CARRYGOLD) || on(*th, CARRYSCROLL) ||
on(*th, CARRYPOTION) || on(*th, CARRYRING) ||
on(*th, CARRYSTICK) || on(*th, CARRYMISC) ||
on(*th, CARRYWEAPON) || on(*th, CARRYARMOR) ||
on(*th, CARRYDAGGER)) {
want_something = TRUE;
/*
* Blank the area. We have to do it only before the
* first item in case an item gets dropped in same
* place. We don't want to blank it out after it get
* dropped.
*/
mvaddch(ch_ret.y, ch_ret.x, floor);
/* Were we specifically after something here? */
if (ce(*th->t_dest, ch_ret)) {
/* If we're mean, we go after the hero */
if (on(*th, ISMEAN)) runto(th, &hero);
/* Otherwise just go back to sleep */
else {
turn_off(*th, ISRUN);
th->t_dest = NULL;
}
}
}
else break;
}
item_count++; /* Count the number of items */
/*
* see if he's got one of this group already
*/
o_item = NULL;
n_obj = OBJPTR(n_item);
detach(lvl_obj, n_item);
/* See if he wants it */
if (n_obj->o_type == SCROLL && n_obj->o_which == S_SCARE &&
th->t_stats.s_intel < 16)
wants_it = FALSE; /* Most monsters don't want a scare monster */
else if (on(*th, ISSCAVENGE)) wants_it = TRUE;
else {
wants_it = FALSE; /* Default case */
switch (n_obj->o_type) {
case FOOD: if(on(*th, CARRYFOOD)) wants_it = TRUE;
when GOLD: if(on(*th, CARRYGOLD)) wants_it = TRUE;
when SCROLL:if(on(*th, CARRYSCROLL)) wants_it = TRUE;
when POTION:if(on(*th, CARRYPOTION)) wants_it = TRUE;
when RING: if(on(*th, CARRYRING)) wants_it = TRUE;
when STICK: if(on(*th, CARRYSTICK)) wants_it = TRUE;
when MM: if(on(*th, CARRYMISC)) wants_it = TRUE;
when ARMOR: if(on(*th, CARRYARMOR)) wants_it = TRUE;
when WEAPON:if(on(*th, CARRYWEAPON) ||
(on(*th,CARRYDAGGER)&&n_obj->o_which==DAGGER))
wants_it = TRUE;
}
}
/*
* The quartermaster doesn't sell cursed stuff so he won't
* pick it up
*/
if (on(*th, CANSELL) && (n_obj->o_flags & ISCURSED))
wants_it = FALSE;
/* If he doesn't want it, throw it away */
if (wants_it == FALSE) {
fall(n_item, FALSE);
continue;
}
/* Otherwise, let's pick it up */
if (n_obj->o_group) {
for(o_item = th->t_pack; o_item != NULL; o_item = next(o_item)){
o_obj = OBJPTR(o_item);
if (o_obj->o_group == n_obj->o_group) {
o_obj->o_count += n_obj->o_count;
o_discard(n_item);
break;
}
}
}
if (o_item == NULL) { /* didn't find it */
attach(th->t_pack, n_item);
}
}
/* If there was anything here, we may have to update the screen */
if (item_count) {
if (cansee(ch_ret.y, ch_ret.x))
mvwaddch(cw, ch_ret.y, ch_ret.x, mvinch(ch_ret.y, ch_ret.x));
updpack(TRUE, th); /* Update the monster's encumberance, too */
}
}
rch = CCHAR( mvwinch(stdscr, old_pos.y, old_pos.x) );
if (th->t_oldch == floor && rch != floor && !isatrap(rch))
mvwaddch(cw, old_pos.y, old_pos.x, rch);
else
mvwaddch(cw, old_pos.y, old_pos.x, th->t_oldch);
sch = CCHAR( mvwinch(cw, ch_ret.y, ch_ret.x) ); /* What player sees */
rch = CCHAR( mvwinch(stdscr, ch_ret.y, ch_ret.x) ); /* What's really there */
/* If we have a tunneling monster, it may be making a tunnel */
if (on(*th, CANTUNNEL) &&
(rch == SECRETDOOR || rch == WALL || rch == '|' || rch == '-')) {
char nch; /* The new look to the tunnel */
if (rch == WALL) nch = PASSAGE;
else if (levtype == MAZELEV) nch = FLOOR;
else nch = DOOR;
addch(nch);
if (cansee(ch_ret.y, ch_ret.x)) sch = nch; /* Can player see this? */
/* Does this make a new exit? */
if (rch == '|' || rch == '-') {
struct linked_list *newroom;
coord *exit;
newroom = new_item(sizeof(coord));
exit = DOORPTR(newroom);
*exit = ch_ret;
attach(new_room->r_exit, newroom);
}
}
/* Mark if the monster is inside a wall */
if (isrock(mvinch(ch_ret.y, ch_ret.x))) turn_on(*th, ISINWALL);
else turn_off(*th, ISINWALL);
/* If the monster can illuminate rooms, check for a change */
if (on(*th, HASFIRE)) {
register struct linked_list *fire_item;
/* Is monster entering a room? */
if (orig_rer != new_room && new_room != NULL) {
fire_item = creat_item(); /* Get an item-only structure */
ldata(fire_item) = (char *) th;
attach(new_room->r_fires, fire_item);
new_room->r_flags |= HASFIRE;
if (cansee(ch_ret.y, ch_ret.x) && next(new_room->r_fires) == NULL)
light(&hero);
}
/* Is monster leaving a room? */
if (orig_rer != new_room && orig_rer != NULL) {
/* Find the bugger in the list and delete him */
for (fire_item = orig_rer->r_fires; fire_item != NULL;
fire_item = next(fire_item)) {
if (THINGPTR(fire_item) == th) { /* Found him! */
detach(orig_rer->r_fires, fire_item);
destroy_item(fire_item);
if (orig_rer->r_fires == NULL) {
orig_rer->r_flags &= ~HASFIRE;
if (cansee(old_pos.y, old_pos.x))
light(&old_pos);
}
break;
}
}
}
}
/* If monster is entering player's room and player can see it,
* stop the player's running.
*/
if (new_room != orig_rer && new_room != NULL &&
new_room == roomin(th->t_dest) && cansee(unc(ch_ret)) &&
(off(*th, ISINVIS) || on(player, CANSEE)) &&
(off(*th, ISSHADOW) || on(player, CANSEE)) &&
(off(*th, CANSURPRISE) || ISWEARING(R_ALERT))) {
running = FALSE;
if (fight_flush) md_flushinp();
}
th->t_oldch = sch;
/* Let's display those creatures that we can see. */
if (cansee(unc(ch_ret)) &&
off(*th, ISINWALL) &&
!invisible(th))
mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type);
/* Record monster's last position (if new one is different) */
if (!ce(ch_ret, old_pos)) th->t_oldpos = old_pos;
/* If the monster is on a trap, trap it */
sch = CCHAR( mvinch(ch_ret.y, ch_ret.x) );
if (isatrap(sch)) {
if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch;
be_trapped(th, &ch_ret);
}
}
/*
* Get_hurl returns the weapon that the monster will "throw" if he has one
*/
struct linked_list *
get_hurl(tp)
register struct thing *tp;
{
struct linked_list *arrow=NULL, *bolt=NULL, *rock=NULL,
*spear = NULL, *dagger=NULL, *dart=NULL, *aklad=NULL;
register struct linked_list *pitem;
register struct object *obj;
bool bow=FALSE, crossbow=FALSE, sling=FALSE;
for (pitem=tp->t_pack; pitem; pitem=next(pitem)) {
obj = OBJPTR(pitem);
if (obj->o_type == WEAPON)
switch (obj->o_which) {
case BOW: bow = TRUE;
when CROSSBOW: crossbow = TRUE;
when SLING: sling = TRUE;
when ROCK: rock = pitem;
when ARROW: arrow = pitem;
when BOLT: bolt = pitem;
when SPEAR: spear = pitem;
when DAGGER:
/* Don't throw the dagger if it's our last one */
if (obj->o_count > 1) dagger = pitem;
when DART: dart = pitem;
}
else if (obj->o_type == RELIC &&
obj->o_which == AXE_AKLAD)
aklad = pitem;
}
/* Do we have that all-powerful Aklad Axe? */
if (aklad) return(aklad);
/* Use crossbow bolt if possible */
if (crossbow && bolt) return(bolt);
if (bow && arrow) return(arrow);
if (spear) return(spear);
if (dagger) return(dagger);
if (sling && rock) return(rock);
if (dart) return(dart);
return(NULL);
}
/*
* runto:
* Set a monster running after something
*/
runto(runner, spot)
register struct thing *runner;
coord *spot;
{
if (on(*runner, ISSTONE))
return;
/* If we are chasing a new creature, forget about thrown weapons */
if (runner->t_dest && !ce(*runner->t_dest, *spot)) runner->t_wasshot=FALSE;
/*
* Start the beastie running
*/
runner->t_dest = spot;
turn_on(*runner, ISRUN);
turn_off(*runner, ISDISGUISE);
}
/*
* straight_shot:
* See if there is a straight line of sight between the two
* given coordinates. If shooting is not NULL, it is a pointer
* to a structure which should be filled with the direction
* to shoot (if there is a line of sight). If shooting, monsters
* get in the way. Otherwise, they do not.
*/
bool
straight_shot(ery, erx, eey, eex, shooting)
register int ery, erx, eey, eex;
register coord *shooting;
{
register int dy, dx; /* Deltas */
char ch;
/* Does the monster have a straight shot at prey */
if ((ery != eey) && (erx != eex) &&
(abs(ery - eey) != abs(erx - eex))) return(FALSE);
/* Get the direction to shoot */
if (eey > ery) dy = 1;
else if (eey == ery) dy = 0;
else dy = -1;
if (eex > erx) dx = 1;
else if (eex == erx) dx = 0;
else dx = -1;
/* Make sure we have free area all the way to the player */
ery += dy;
erx += dx;
while ((ery != eey) || (erx != eex)) {
switch (ch = CCHAR( winat(ery, erx) )) {
case '|':
case '-':
case WALL:
case DOOR:
case SECRETDOOR:
case FOREST:
return(FALSE);
default:
if (shooting && isalpha(ch)) return(FALSE);
}
ery += dy;
erx += dx;
}
if (shooting) { /* If we are shooting -- put in the directions */
shooting->y = dy;
shooting->x = dx;
}
return(TRUE);
}

1220
arogue7/command.c Normal file

File diff suppressed because it is too large Load diff

252
arogue7/daemon.c Normal file
View file

@ -0,0 +1,252 @@
/*
* daemon.c - functions for dealing with things that happen in the future.
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Contains functions for dealing with things that happen in the
* future.
*
*/
#include "curses.h"
#include "rogue.h"
#define EMPTY 0
#define DAEMON -1
#define MAXDAEMONS 10
#define MAXFUSES 20
#define _X_ { EMPTY }
struct delayed_action d_list[MAXDAEMONS] = {
_X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_
};
struct delayed_action f_list[MAXFUSES] = {
_X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
_X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_
};
int demoncnt = 0; /* number of active daemons */
int fusecnt = 0;
/*
* d_slot:
* Find an empty slot in the daemon list
*/
struct delayed_action *
d_slot()
{
reg int i;
reg struct delayed_action *dev;
for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++)
if (dev->d_type == EMPTY)
return dev;
return NULL;
}
/*
* f_slot:
* Find an empty slot in the fuses list
*/
struct delayed_action *
f_slot()
{
reg int i;
reg struct delayed_action *dev;
for (i = 0, dev = f_list; i < MAXFUSES; i++, dev++)
if (dev->d_type == EMPTY)
return dev;
return NULL;
}
/*
* find_slot:
* Find a particular slot in the table
*/
struct delayed_action *
find_slot(func)
reg int (*func)();
{
reg int i;
reg struct delayed_action *dev;
for (i = 0, dev = f_list; i < MAXFUSES; 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)
reg int arg, type, (*func)();
{
reg struct delayed_action *dev;
dev = d_slot();
if (dev != NULL) {
dev->d_type = type;
dev->d_func = func;
dev->d_.arg = arg;
dev->d_time = DAEMON;
demoncnt += 1; /* update count */
}
}
/*
* kill_daemon:
* Remove a daemon from the list
*/
kill_daemon(func)
reg int (*func)();
{
reg struct delayed_action *dev;
reg int i;
for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++) {
if (dev->d_type != EMPTY && func == dev->d_func)
break;
}
if (i >= MAXDAEMONS) return; /* if not found, forget it */
/*
* Take it out of the list
*/
dev->d_type = EMPTY;
dev->d_.arg = 0;
dev->d_func = NULL;
dev->d_time = 0;
demoncnt -= 1; /* update count */
}
/*
* do_daemons:
* Run all the daemons that are active with the current flag,
* passing the argument to the function.
*/
do_daemons(flag)
reg int flag;
{
reg 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)
reg int (*func)(), arg, time, type;
{
reg struct delayed_action *wire;
wire = f_slot();
if (wire != NULL) {
wire->d_type = type;
wire->d_func = func;
wire->d_.arg = arg;
wire->d_time = time;
fusecnt += 1; /* update count */
}
}
/*
* lengthen:
* Increase the time until a fuse goes off
*/
lengthen(func, xtime)
reg int (*func)(), xtime;
{
reg struct delayed_action *wire;
if ((wire = find_slot(func)) == NULL)
return;
wire->d_time += xtime;
}
/*
* extinguish:
* Put out a fuse
*/
extinguish(func)
reg int (*func)();
{
reg struct delayed_action *wire;
if ((wire = find_slot(func)) == NULL)
return;
wire->d_type = EMPTY;
wire->d_func = NULL;
wire->d_.arg = 0;
wire->d_time = 0;
fusecnt -= 1;
}
/*
* do_fuses:
* Decrement counters and start needed fuses
*/
do_fuses(flag)
reg int flag;
{
reg struct delayed_action *wire;
/*
* Step though the list
*/
for (wire = f_list; wire <= &f_list[MAXFUSES-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;
if (wire->d_func != NULL)
(*wire->d_func)(wire->d_.arg);
fusecnt -= 1;
}
}
}
/*
* activity:
* Show wizard number of demaons and memory blocks used
*/
activity()
{
msg("Daemons = %d : Fuses = %d : Memory Items = %d : Memory Used = %d",
demoncnt,fusecnt,total,md_memused(0));
}

663
arogue7/daemons.c Normal file
View file

@ -0,0 +1,663 @@
/*
* daemon.c - All the daemon and fuse functions are in here
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* All the daemon and fuse functions are in here
*
*/
#include "curses.h"
#include "rogue.h"
/*
* doctor:
* A healing daemon that restors hit points after rest
*/
doctor(tp)
register struct thing *tp;
{
register int ohp;
register int limit, new_points;
register struct stats *curp; /* current stats pointer */
register struct stats *maxp; /* max stats pointer */
curp = &(tp->t_stats);
maxp = &(tp->maxstats);
if (curp->s_hpt == maxp->s_hpt) {
tp->t_quiet = 0;
return;
}
tp->t_quiet++;
switch (tp->t_ctype) {
case C_MAGICIAN:
limit = 8 - curp->s_lvl;
new_points = curp->s_lvl - 3;
when C_THIEF:
case C_ASSASIN:
case C_MONK:
limit = 8 - curp->s_lvl;
new_points = curp->s_lvl - 2;
when C_CLERIC:
case C_DRUID:
limit = 8 - curp->s_lvl;
new_points = curp->s_lvl - 3;
when C_FIGHTER:
case C_RANGER:
case C_PALADIN:
limit = 16 - curp->s_lvl*2;
new_points = curp->s_lvl - 5;
when C_MONSTER:
limit = 16 - curp->s_lvl;
new_points = curp->s_lvl - 6;
otherwise:
debug("what a strange character you are!");
return;
}
ohp = curp->s_hpt;
if (off(*tp, HASDISEASE) && off(*tp, DOROT)) {
if (curp->s_lvl < 8) {
if (tp->t_quiet > limit) {
curp->s_hpt++;
tp->t_quiet = 0;
}
}
else {
if (tp->t_quiet >= 3) {
curp->s_hpt += rnd(new_points)+1;
tp->t_quiet = 0;
}
}
}
if (tp == &player) {
if (ISRING(LEFT_1, R_REGEN)) curp->s_hpt++;
if (ISRING(LEFT_2, R_REGEN)) curp->s_hpt++;
if (ISRING(LEFT_3, R_REGEN)) curp->s_hpt++;
if (ISRING(LEFT_4, R_REGEN)) curp->s_hpt++;
if (ISRING(RIGHT_1, R_REGEN)) curp->s_hpt++;
if (ISRING(RIGHT_2, R_REGEN)) curp->s_hpt++;
if (ISRING(RIGHT_3, R_REGEN)) curp->s_hpt++;
if (ISRING(RIGHT_4, R_REGEN)) curp->s_hpt++;
}
if (on(*tp, ISREGEN))
curp->s_hpt += curp->s_lvl/10 + 1;
if (ohp != curp->s_hpt) {
if (curp->s_hpt >= maxp->s_hpt) {
curp->s_hpt = maxp->s_hpt;
if (off(*tp, WASTURNED) && on(*tp, ISFLEE) && tp != &player) {
turn_off(*tp, ISFLEE);
tp->t_oldpos = tp->t_pos; /* Start our trek over */
}
}
}
}
/*
* 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
*/
int between = 0;
rollwand()
{
if (++between >= 4)
{
/* Theives may not awaken a monster */
if ((roll(1, 6) == 4) &&
((player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) ||
(rnd(30) >= dex_compute()))) {
if (levtype != POSTLEV)
wanderer();
kill_daemon(rollwand);
fuse(swander, 0, WANDERTIME, BEFORE);
}
between = 0;
}
}
/*
* this function is a daemon called each turn when the character is a thief
*/
trap_look()
{
if (rnd(100) < (2*dex_compute() + 5*pstats.s_lvl))
search(TRUE, FALSE);
}
/*
* unconfuse:
* Release the poor player from his confusion
*/
unconfuse()
{
turn_off(player, ISHUH);
msg("You feel less confused now");
}
/*
* unsee:
* He lost his see invisible power
*/
unsee()
{
if (!ISWEARING(R_SEEINVIS)) {
turn_off(player, CANSEE);
msg("The tingling feeling leaves your eyes");
}
}
/*
* unstink:
* Remove to-hit handicap from player
*/
unstink()
{
turn_off(player, HASSTINK);
}
/*
* unclrhead:
* Player is no longer immune to confusion
*/
unclrhead()
{
turn_off(player, ISCLEAR);
msg("The blue aura about your head fades away.");
}
/*
* unphase:
* Player can no longer walk through walls
*/
unphase()
{
turn_off(player, CANINWALL);
msg("Your dizzy feeling leaves you.");
if (!step_ok(hero.y, hero.x, NOMONST, &player)) death(D_PETRIFY);
}
/*
* land:
* Player can no longer fly
*/
land()
{
turn_off(player, ISFLY);
msg("You regain your normal weight");
running = FALSE;
}
/*
* sight:
* He gets his sight back
*/
sight()
{
if (on(player, ISBLIND))
{
extinguish(sight);
turn_off(player, ISBLIND);
light(&hero);
msg("The veil of darkness lifts");
}
}
/*
* res_strength:
* Restore player's strength
*/
void
res_strength(howmuch)
int howmuch;
{
/* If lost_str is non-zero, restore that amount of strength,
* else all of it
*/
if (lost_str) {
chg_str(lost_str);
lost_str = 0;
}
/* Now, add in the restoral, but no greater than maximum strength */
if (howmuch > 0)
pstats.s_str =
min(pstats.s_str + howmuch, max_stats.s_str + ring_value(R_ADDSTR));
updpack(TRUE, &player);
}
/*
* nohaste:
* End the hasting
*/
nohaste()
{
turn_off(player, ISHASTE);
msg("You feel yourself slowing down.");
}
/*
* noslow:
* End the slowing
*/
noslow()
{
turn_off(player, ISSLOW);
msg("You feel yourself speeding up.");
}
/*
* suffocate:
* If this gets called, the player has suffocated
*/
suffocate()
{
death(D_SUFFOCATION);
}
/*
* digest the hero's food
*/
stomach()
{
register int oldfood, old_hunger, food_use, i;
/*
* avoid problems of fainting while eating by just not saying it
* takes food to eat food
*/
if (player.t_action == C_EAT)
return;
old_hunger = hungry_state;
if (food_left <= 0)
{
/*
* the hero is fainting
*/
if (player.t_action == A_FREEZE)
return;
if (rnd(100) > 20)
return;
if (hungry_state == F_FAINT && rnd(20) == 7) /*must have fainted once*/
death(D_STARVATION);
player.t_action = A_FREEZE;
player.t_no_move = movement(&player) * (rnd(8) + 4);
if (!terse)
addmsg("You feel too weak from lack of food. ");
msg("You faint");
running = FALSE;
if (fight_flush) md_flushinp();
count = 0;
hungry_state = F_FAINT;
}
else
{
oldfood = food_left;
food_use = 0;
for (i=0; i<MAXRELIC; i++) { /* each relic eats an additional food */
if (cur_relic[i])
food_use++;
}
food_use += (ring_eat(LEFT_1) + ring_eat(LEFT_2) +
ring_eat(LEFT_3) + ring_eat(LEFT_4) +
ring_eat(RIGHT_1) + ring_eat(RIGHT_2) +
ring_eat(RIGHT_3) + ring_eat(RIGHT_4) +
foodlev);
if (food_use < 1)
food_use = 1;
food_left -= food_use;
if (food_left < MORETIME && oldfood >= MORETIME) {
msg("You are starting to feel weak");
running = FALSE;
if (fight_flush) md_flushinp();
count = 0;
hungry_state = F_WEAK;
}
else if (food_left < 2 * MORETIME && oldfood >= 2 * MORETIME)
{
msg(terse ? "Getting hungry" : "You are starting to get hungry");
running = FALSE;
hungry_state = F_HUNGRY;
}
else if(food_left<STOMACHSIZE-MORETIME && oldfood>=STOMACHSIZE-MORETIME)
{
hungry_state = F_OKAY;
}
}
if (old_hunger != hungry_state) {
updpack(TRUE, &player);
status(TRUE);
}
wghtchk();
}
/*
* daemon for curing the diseased
*/
cure_disease()
{
turn_off(player, HASDISEASE);
if (off (player, HASINFEST))
msg(terse ? "You feel yourself improving"
: "You begin to feel yourself improving again");
}
/*
* appear:
* Become visible again
*/
appear()
{
turn_off(player, ISINVIS);
PLAYER = VPLAYER;
msg("The tingling feeling leaves your body");
light(&hero);
}
/*
* dust_appear:
* dust of disappearance wears off
*/
dust_appear()
{
turn_off(player, ISINVIS);
PLAYER = VPLAYER;
msg("You become visible again");
light(&hero);
}
/*
* unchoke:
* the effects of "dust of choking and sneezing" wear off
*/
unchoke()
{
if (!find_slot(unconfuse))
turn_off(player, ISHUH);
if (!find_slot(sight))
turn_off(player, ISBLIND);
light(&hero);
msg("Your throat and eyes return to normal");
}
/*
* make some potion for the guy in the Alchemy jug
*/
alchemy(obj)
register struct object *obj;
{
register struct object *tobj;
register struct linked_list *item;
/*
* verify that the object pointer we have still points to an alchemy
* jug (hopefully the right one!) because the hero could have thrown
* it away
*/
for (item = pack; item != NULL; item = next(item)) {
tobj = OBJPTR(item);
if (tobj == obj &&
tobj->o_type == MM &&
tobj->o_which== MM_JUG &&
tobj->o_ac == JUG_EMPTY )
break;
}
if (item == NULL) { /* not in the pack, check the level */
for (item = lvl_obj; item != NULL; item = next(item)) {
tobj = OBJPTR(item);
if (tobj == obj &&
tobj->o_type == MM &&
tobj->o_which== MM_JUG &&
tobj->o_ac == JUG_EMPTY )
break;
}
}
if (item == NULL) /* can't find it.....too bad */
return;
switch(rnd(11)) {
case 0: tobj->o_ac = P_PHASE;
when 1: tobj->o_ac = P_CLEAR;
when 2: tobj->o_ac = P_SEEINVIS;
when 3: tobj->o_ac = P_HEALING;
when 4: tobj->o_ac = P_MFIND;
when 5: tobj->o_ac = P_TFIND;
when 6: tobj->o_ac = P_HASTE;
when 7: tobj->o_ac = P_RESTORE;
when 8: tobj->o_ac = P_FLY;
when 9: tobj->o_ac = P_SKILL;
when 10:tobj->o_ac = P_FFIND;
}
}
/*
* otto's irresistable dance wears off
*/
undance()
{
turn_off(player, ISDANCE);
msg ("Your feet take a break.....whew!");
}
/*
* if he has our favorite necklace of strangulation then take damage every turn
*/
strangle()
{
if ((pstats.s_hpt -= 6) <= 0) death(D_STRANGLE);
}
/*
* if he has on the gauntlets of fumbling he might drop his weapon each turn
*/
fumble()
{
register struct linked_list *item;
if (cur_weapon!=NULL &&
!(cur_weapon->o_flags & ISCURSED) &&
cur_weapon->o_type != RELIC &&
rnd(100)<3) {
for (item = pack; item != NULL; item = next(item)) {
if (OBJPTR(item) == cur_weapon)
break;
}
if (item != NULL) {
switch(mvwinch(stdscr, hero.y, hero.x)) {
case PASSAGE:
case SCROLL:
case POTION:
case WEAPON:
case FLOOR:
case STICK:
case ARMOR:
case POOL:
case RELIC:
case GOLD:
case FOOD:
case RING:
case MM:
drop(item);
running = FALSE;
break;
default:
break;
}
}
}
}
/*
* this is called each turn the hero has the ring of searching on
*/
ring_search()
{
search(FALSE, FALSE);
}
/*
* this is called each turn the hero has the ring of teleportation on
*/
ring_teleport()
{
if (rnd(100) < 2) teleport();
}
/*
* this is called to charge up the quill of Nagrom
*/
quill_charge()
{
register struct object *tobj;
register struct linked_list *item;
/*
* find the Quill of Nagrom in the hero's pack. It should still be there
* because it can't be dropped. If its not then don't do anything.
*/
for (item = pack; item != NULL; item = next(item)) {
tobj = OBJPTR(item);
if (tobj->o_type == RELIC && tobj->o_which == QUILL_NAGROM)
break;
}
if (item == NULL)
return;
if (tobj->o_charges < QUILLCHARGES)
tobj->o_charges++;
fuse (quill_charge, 0, player.t_ctype == C_MAGICIAN ? 4 : 8, AFTER);
}
/*
* take the skills away gained (or lost) by the potion of skills
*/
unskill()
{
if (pstats.s_lvladj != 0) {
pstats.s_lvl -= pstats.s_lvladj;
pstats.s_lvladj = 0;
msg("You feel your normal skill level return.");
status(TRUE);
}
}
/*
* charge up the cloak of Emori
*/
cloak_charge(obj)
register struct object *obj;
{
if (obj->o_charges < 1)
obj->o_charges = 1;
}
/*
* nofire:
* He lost his fire resistance
*/
nofire()
{
if (!ISWEARING(R_FIRE)) {
turn_off(player, NOFIRE);
msg("Your feeling of fire resistance leaves you");
}
}
/*
* nocold:
* He lost his cold resistance
*/
nocold()
{
if (!ISWEARING(R_WARMTH)) {
turn_off(player, NOCOLD);
msg("Your feeling of warmth leaves you");
}
}
/*
* nobolt:
* He lost his protection from lightning
*/
nobolt()
{
turn_off(player, NOBOLT);
msg("Your skin looses its bluish tint");
}
/*
* eat_gold:
* an artifact eats gold
*/
eat_gold(obj)
register struct object *obj;
{
if (purse == 1)
msg("%s demand you find more gold", inv_name(obj, FALSE));
if (purse == 0) {
if (--pstats.s_hpt <= 0)
death(D_RELIC);
}
else
purse--;
}
/*
* give the hero back some spell points
*/
spell_recovery()
{
int time;
time = SPELLTIME - max(17-pstats.s_intel, 0);
time = max(time, 5);
if (spell_power > 0) spell_power--;
fuse(spell_recovery, NULL, time, AFTER);
}
/*
* give the hero back some prayer points
*/
prayer_recovery()
{
int time;
time = SPELLTIME - max(17-pstats.s_wisdom, 0);
time = max(time, 5);
if (pray_time > 0) pray_time--;
fuse(prayer_recovery, NULL, time, AFTER);
}
/*
* give the hero back some chant points
*/
chant_recovery()
{
int time;
time = SPELLTIME - max(17-pstats.s_wisdom, 0);
time = max(time, 5);
if (chant_time > 0) chant_time--;
fuse(chant_recovery, NULL, time, AFTER);
}

130
arogue7/eat.c Normal file
View file

@ -0,0 +1,130 @@
/*
* eat.c - Functions for dealing with digestion
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "curses.h"
#include "rogue.h"
/*
* eat:
* He wants to eat something, so let him try
*/
eat()
{
register struct linked_list *item;
int which;
unsigned long temp;
if (player.t_action != C_EAT) {
if ((item = get_item(pack, "eat", FOOD, FALSE, FALSE)) == NULL)
return;
player.t_using = item; /* Remember what it is */
player.t_action = C_EAT; /* We are eating */
which = (OBJPTR(item))->o_which;
player.t_no_move = max(foods[which].mi_food/100, 1) * movement(&player);
return;
}
/* We have waited our time, let's eat the food */
item = player.t_using;
player.t_using = NULL;
player.t_action = A_NIL;
which = (OBJPTR(item))->o_which;
if ((food_left += foods[which].mi_food) > STOMACHSIZE)
food_left = STOMACHSIZE;
del_pack(item);
if (hungry_state == F_SATIATED && food_left == STOMACHSIZE && rnd(4) == 1) {
pstats.s_hpt = 0;
msg ("You choke on all that food and die! -- More --");
wait_for(' ');
death(D_FOOD_CHOKE);
}
if (food_left >= STOMACHSIZE-MORETIME) {
hungry_state = F_SATIATED;
msg ("You have trouble getting all that food down.");
msg ("Your stomach feels like its about to burst!");
}
else {
hungry_state = F_OKAY;
switch (rnd(3)) {
case 0: msg("My, that was a yummy %s", foods[which].mi_name);
when 1: msg("Mmmm, that was a tasty %s", foods[which].mi_name);
when 2: msg("Wow, that was a scrumptious %s", foods[which].mi_name);
}
}
updpack(TRUE, &player);
switch(which) {
case E_WHORTLEBERRY:
add_abil[A_INTELLIGENCE](1);
when E_SWEETSOP:
add_abil[A_DEXTERITY](1);
when E_SOURSOP:
add_abil[A_STRENGTH](1);
when E_SAPODILLA:
add_abil[A_WISDOM](1);
when E_RAMBUTAN:
add_abil[A_CONSTITUTION](1);
when E_PEACH:
add_abil[A_CHARISMA](1);
when E_STRAWBERRY:
temp = pstats.s_exp/100;
pstats.s_exp += temp;
if (temp > 0)
msg("You feel slightly more experienced now");
check_level();
when E_PITANGA:
max_stats.s_hpt++;
pstats.s_hpt++;
if (terse)
msg("You feel a bit tougher now");
else
msg("You feel a bit tougher now. Go get 'em!");
when E_HAGBERRY:
pstats.s_arm--;
msg("Your skin feels more resilient now");
when E_DEWBERRY:
if (chant_time > 0) {
chant_time -= 50;
if (chant_time < 0)
chant_time = 0;
msg("You feel you have more chant ability");
}
if (pray_time > 0) {
pray_time -= 50;
if (pray_time < 0)
pray_time = 0;
msg("You feel you have more prayer ability");
}
if (spell_power > 0) {
spell_power -= 50;
if (spell_power < 0)
spell_power = 0;
msg("You feel you have more spell casting ability");
}
otherwise: /* all the foods don't have to do something */
break;
}
}

699
arogue7/effects.c Normal file
View file

@ -0,0 +1,699 @@
/*
* effects.c - functions for dealing with appllying effects to monsters
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "curses.h"
#include "rogue.h"
/*
* effect:
* Check for effects of one thing hitting another thing. Return
* the reason code if the defender is killed. Otherwise return 0.
*/
effect(att, def, weap, thrown, see_att, see_def)
register struct thing *att, *def;
struct object *weap;
bool thrown;
register bool see_att, see_def;
{
register bool att_player, def_player;
char attname[LINELEN+1], defname[LINELEN+1];
/* See if the attacker or defender is the player */
att_player = (att == &player);
def_player = (def == &player);
/*
* If the player could see the attacker or defender, they can't
* surprise anymore (don't bother checking if they could).
*/
if (see_att) turn_off(*att, CANSURPRISE);
if (see_def) turn_off(*def, CANSURPRISE);
/* What are the attacker and defender names? */
if (att_player) strcpy(attname, "you");
else {
if (see_att) strcpy(attname, monster_name(att));
else strcpy(attname, "something");
}
if (def_player) strcpy(defname, "you");
else {
if (see_def) strcpy(defname, monster_name(def));
else strcpy(defname, "something");
}
/*
* See what happens to the attacker first. We can skip this
* whole section, however, if the defender is the player.
* Nothing happens (yet) to anyone just for hitting the player.
*/
if (!def_player) {
if (!thrown) { /* Some things require a direct hit. */
/*
* If the attacker hits a rusting monster, The weapon
* may be damaged
*/
if (on(*def, CANRUST) && weap &&
weap->o_type != RELIC && (weap->o_flags & ISMETAL) &&
!(weap->o_flags & ISPROT)) {
if ((weap->o_hplus < 1 && weap->o_dplus < 1) ||
roll(1,20) < weap->o_hplus+weap->o_dplus+10) {
if (rnd(100) < 50) weap->o_hplus--;
else weap->o_dplus--;
if (att_player)
msg(terse ? "Your %s weakens!"
: "Your %s appears to be weaker now!",
weaps[weap->o_which].w_name);
}
}
}
/* If the attacker hit something that shrieks, wake the dungeon */
if (on(*def, CANSHRIEK)) {
turn_off(*def, CANSHRIEK);
if (see_def)
msg("%s emits a piercing shriek.", prname(defname, TRUE));
else msg("You hear a piercing shriek.");
aggravate(TRUE, TRUE);
}
/*
* does the creature explode when hit?
*/
if (on(*def, CANEXPLODE)) {
if (see_def) msg("%s explodes!", prname(defname, TRUE));
else msg("You hear a tremendous explosion!");
explode(def);
if (pstats.s_hpt <= 0)
death(def->t_index);
}
}
/*
* Now let's see what happens to the defender. Start out with
* the things that everyone can do. Then exit if the attacker
* is the player.
*/
if (!thrown) {
/*
* Can the player confuse?
*/
if (on(*att, CANHUH) && att_player) {
msg("Your hands stop glowing red.");
if (off(*def, ISCLEAR) &&
(off(*def, ISUNIQUE) || !save(VS_MAGIC, def, 0))) {
if (see_def) msg("%s appears confused.", prname(defname, TRUE));
turn_on(*def, ISHUH);
}
turn_off(*att, CANHUH);
}
/* Return now if the attacker is the player. */
if (att_player) return(0);
/*
* Some monsters may take half your hit points
*/
if (on(*att, CANSUCK) && !save(VS_MAGIC, def, 0)) {
if (def->t_stats.s_hpt == 1) return(att->t_index); /* Killed! */
else {
def->t_stats.s_hpt /= 2;
if (def_player)
msg("You feel your life force being drawn from you.");
}
}
/*
* If a hugging monster hits, it may SQUEEEEEEEZE.
*/
if (on(*att, CANHUG)) {
if (roll(1,20) >= 18 || roll(1,20) >= 18) {
if (def_player)
msg("%s squeezes you against itself.",
prname(attname, TRUE));
else if (see_att)
msg("%s squeezes hard.", prname(attname, TRUE));
if ((def->t_stats.s_hpt -= roll(2,8)) <= 0)
return(att->t_index);
}
}
/*
* Some monsters have poisonous bites.
*/
if (on(*att, CANPOISON) && !save(VS_POISON, def, 0)) {
if (def_player) {
if (ISWEARING(R_SUSABILITY))
msg(terse ? "Sting has no effect"
: "A sting momentarily weakens you");
else {
chg_str(-1);
msg(terse ? "A sting has weakened you" :
"You feel a sting in your arm and now feel weaker");
}
}
else {
/* Subtract a strength point and see if it kills it */
if (--def->t_stats.s_str <= 0) return(D_STRENGTH);
}
}
/*
* Turning to stone:
*/
if (on(*att, TOUCHSTONE)) {
if (def_player) turn_off(*att, TOUCHSTONE);
if (on(*def, CANINWALL)) {
if (def_player)
msg("%s's touch has no effect.", prname(attname, TRUE));
}
else {
if (!save(VS_PETRIFICATION, def, 0) && rnd(100) < 10) {
if (def_player) {
msg("Your body begins to solidify.");
msg("You are turned to stone !!! --More--");
wait_for(' ');
return(D_PETRIFY);
}
else {
/* The monster got stoned! */
turn_on(*def, ISSTONE);
turn_off(*def, ISRUN);
turn_off(*def, ISINVIS);
turn_off(*def, ISDISGUISE);
if (see_def)
msg("%s turns to stone.", prname(defname, TRUE));
else if (cansee(unc(def->t_pos)))
msg("A new statue appears!");
}
}
else if (def->t_action != A_FREEZE) {
if (def_player)
msg("%s's touch stiffens your limbs.",
prname(attname, TRUE));
else if (see_def)
msg("%s appears to freeze.", prname(defname, TRUE));
def->t_no_move += movement(def) * STONETIME;
def->t_action = A_FREEZE;
}
}
}
/*
* Wraiths might drain energy levels
*/
if ((on(*att, CANDRAIN) || on(*att, DOUBLEDRAIN)) &&
!save(VS_POISON, def, 3-(att->t_stats.s_lvl/5))) {
if (def_player) {
lower_level(att->t_index);
if (on(*att, DOUBLEDRAIN)) lower_level(att->t_index);
turn_on(*att, DIDDRAIN);
}
else {
def->t_stats.s_hpt -= roll(1, 8);
def->t_stats.s_lvl--;
if (on(*att, DOUBLEDRAIN)) {
def->t_stats.s_hpt -= roll(1, 8);
def->t_stats.s_lvl--;
}
if (see_def)
msg("%s appears less skillfull.", prname(defname, TRUE));
/* Did it kill it? */
if (def->t_stats.s_hpt <= 0 ||
def->t_stats.s_lvl <= 0)
return(att->t_index);
}
}
/*
* Paralyzation:
*/
if (on(*att, CANPARALYZE) && def->t_action != A_FREEZE) {
if (def_player) turn_off(*att, CANPARALYZE);
if (!save(VS_PARALYZATION, def, 0)) {
if (on(*def, CANINWALL)) {
if (def_player)
msg("%s's touch has no effect.", prname(attname, TRUE));
}
else {
if (def_player)
msg("%s's touch paralyzes you.", prname(attname, TRUE));
else if (see_def)
msg("%s appears to freeze.", prname(defname, TRUE));
def->t_no_move += movement(def) * FREEZETIME;
def->t_action = A_FREEZE;
}
}
}
/*
* Painful wounds make the defendant faint
*/
if (on(*att, CANPAIN) && def->t_action != A_FREEZE) {
if (def_player) turn_off(*att, CANPAIN);
if (!ISWEARING(R_ALERT) && !save(VS_POISON, def, 0)) {
if (def_player)
msg("You faint from the painful wound");
else if (see_def)
msg("%s appears to faint.", prname(defname, TRUE));
def->t_no_move += movement(def) * PAINTIME;
def->t_action = A_FREEZE;
}
}
/*
* Some things currently affect only the player. Let's make
* a check here so we don't have to check for each thing.
*/
if (def_player) {
/*
* Stinking monsters make the defender weaker (to hit). For now
* this will only affect the player. We may later add the HASSTINK
* effect to monsters, too.
*/
if (on(*att, CANSTINK)) {
turn_off(*att, CANSTINK);
if (!save(VS_POISON, def, 0)) {
msg("The stench of %s sickens you.",
prname(attname, FALSE));
if (on(player, HASSTINK)) lengthen(unstink, STINKTIME);
else {
turn_on(player, HASSTINK);
fuse(unstink, 0, STINKTIME, AFTER);
}
}
}
/*
* Chilling monster reduces strength each time. This only
* affects the player for now because of its temporary nature.
*/
if (on(*att, CANCHILL)) {
if (!ISWEARING(R_SUSABILITY) && !save(VS_POISON, def, 0)) {
msg("You cringe at %s's chilling touch.",
prname(attname, FALSE));
chg_str(-1);
if (lost_str++ == 0)
fuse(res_strength, 0, CHILLTIME, AFTER);
else lengthen(res_strength, CHILLTIME);
}
}
/*
* Itching monsters reduce dexterity (temporarily). This only
* affects the player for now because of its temporary nature.
*/
if (on(*att, CANITCH) && !save(VS_POISON, def, 0)) {
msg("The claws of %s scratch you.", prname(attname, FALSE));
if (ISWEARING(R_SUSABILITY)) {
msg("The scratch has no effect");
}
else {
add_abil[A_DEXTERITY](-1);
}
}
/*
* If a disease-carrying monster hits, there is a chance the
* defender will catch the disease. This only applies to the
* player for now because of the temporary nature.
*/
if (on(*att, CANDISEASE) &&
(rnd(def->t_stats.s_const) < att->t_stats.s_lvl) &&
off(*def, HASDISEASE)) {
if (ISWEARING(R_HEALTH) ||
player.t_ctype == C_PALADIN ||
player.t_ctype == C_MONK) {
msg("The wound heals quickly.");
}
else {
turn_on(*def, HASDISEASE);
fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER);
msg(terse ? "You have been diseased."
: "You have contracted a disease!");
}
}
/*
* If a rusting monster hits, you lose armor. This only applies to
* the player because monsters don't wear armor (for now).
*/
if (on(*att, CANRUST)) {
if (cur_armor != NULL &&
cur_armor->o_which != LEATHER &&
cur_armor->o_which != STUDDED_LEATHER &&
cur_armor->o_which != PADDED_ARMOR &&
!(cur_armor->o_flags & ISPROT) &&
cur_armor->o_ac < def->t_stats.s_arm+1) {
msg(terse ? "Your armor weakens"
: "Your armor appears to be weaker now. Oh my!");
cur_armor->o_ac++;
}
if (cur_misc[WEAR_BRACERS] != NULL &&
cur_misc[WEAR_BRACERS]->o_ac > 0 &&
!(cur_misc[WEAR_BRACERS]->o_flags & ISPROT)) {
cur_misc[WEAR_BRACERS]->o_ac--;
if (cur_misc[WEAR_BRACERS]->o_ac == 0) {
register struct linked_list *item;
for (item=pack; item!=NULL; item=next(item)) {
if (OBJPTR(item) == cur_misc[WEAR_BRACERS]) {
detach(pack, item);
o_discard(item);
break;
}
}
msg ("Your bracers crumble and fall off!");
cur_misc[WEAR_BRACERS] = NULL;
inpack--;
}
else {
msg("Your bracers weaken!");
}
}
}
/*
* If can dissolve and hero has leather type armor. This
* also only applies to the player for now because of the
* armor.
*/
if (on(*att, CANDISSOLVE) && cur_armor != NULL &&
(cur_armor->o_which == LEATHER ||
cur_armor->o_which == STUDDED_LEATHER ||
cur_armor->o_which == PADDED_ARMOR) &&
!(cur_armor->o_flags & ISPROT) &&
cur_armor->o_ac < def->t_stats.s_arm+1) {
msg(terse ? "Your armor dissolves"
: "Your armor appears to dissolve. Oh my!");
cur_armor->o_ac++;
}
/*
* If an infesting monster hits you, you get a parasite or rot.
* This will only affect the player until we figure out how to
* make it affect monsters.
*/
if (on(*att, CANINFEST) &&
rnd(def->t_stats.s_const) < att->t_stats.s_lvl) {
if (ISWEARING(R_HEALTH) ||
player.t_ctype == C_PALADIN ||
player.t_ctype == C_MONK) {
msg("The wound heals quickly.");
}
else {
turn_off(*att, CANINFEST);
msg(terse ? "You have been infested."
: "You have contracted a parasitic infestation!");
infest_dam++;
turn_on(*def, HASINFEST);
}
}
/*
* Does it take wisdom away? This currently affects only
* the player because of its temporary nature.
*/
if (on(*att, TAKEWISDOM) &&
!save(VS_MAGIC, def, 0) &&
!ISWEARING(R_SUSABILITY)) {
add_abil[A_WISDOM](-1);
}
/*
* Does it take intelligence away? This currently affects
* only the player because of its temporary nature.
*/
if (on(*att, TAKEINTEL) &&
!save(VS_MAGIC, &player, 0) &&
!ISWEARING(R_SUSABILITY)) {
add_abil[A_INTELLIGENCE](-1);
}
/*
* Cause fear by touching. This currently affects only
* the player until we figure out how we want it to
* affect monsters.
*/
if (on(*att, TOUCHFEAR)) {
turn_off(*att, TOUCHFEAR);
if (!ISWEARING(R_HEROISM) &&
!save(VS_WAND, def, 0) &&
!(on(*def, ISFLEE) && (def->t_dest == &att->t_pos))) {
turn_on(*def, ISFLEE);
def->t_dest = &att->t_pos;
msg("%s's touch terrifies you.", prname(attname, TRUE));
/* It is okay to turn tail */
if (!def_player) def->t_oldpos = def->t_pos;
}
}
/*
* Make the hero dance (as in otto's irresistable dance)
* This should be fairly easy to do to monsters, but
* we'll restrict it to players until we decide what to
* do about the temporary nature.
*/
if (on(*att, CANDANCE) &&
!on(*def, ISDANCE) &&
def->t_action != A_FREEZE &&
!save(VS_MAGIC, def, -4)) {
turn_off(*att, CANDANCE);
turn_on(*def, ISDANCE);
msg("You begin to dance uncontrollably!");
fuse(undance, 0, roll(2,4), AFTER);
}
/*
* Suffocating our hero. Monsters don't get suffocated.
* That's too hard for now.
*/
if (on(*att, CANSUFFOCATE) &&
!ISWEARING(R_FREEDOM) &&
rnd(100) < 25 &&
(find_slot(suffocate) == 0)) {
turn_on(*att, DIDSUFFOCATE);
msg("%s is beginning to suffocate you.", prname(attname, TRUE));
fuse(suffocate, 0, roll(9,3), AFTER);
}
/*
* some creatures stops the poor guy from moving.
* How can we do this to a monster?
*/
if (on(*att,CANHOLD) && off(*att,DIDHOLD) && !ISWEARING(R_FREEDOM)){
turn_on(*def, ISHELD);
turn_on(*att, DIDHOLD);
hold_count++;
}
/*
* Sucker will suck blood and run. This
* should be easy to have happen to a monster,
* but we have to decide how to handle the fleeing.
*/
if (on(*att, CANDRAW)) {
turn_off(*att, CANDRAW);
turn_on(*att, ISFLEE);
msg("%s sates itself with your blood.", prname(attname, TRUE));
if ((def->t_stats.s_hpt -= 12) <= 0) return(att->t_index);
/* It is okay to turn tail */
att->t_oldpos = att->t_pos;
}
/*
* Bad smell will force a reduction in strength.
* This will happen only to the player because of
* the temporary nature.
*/
if (on(*att, CANSMELL)) {
turn_off(*att, CANSMELL);
if (save(VS_MAGIC, def, 0) || ISWEARING(R_SUSABILITY))
msg("You smell an unpleasant odor.");
else {
int odor_str = -(rnd(6)+1);
msg("You are overcome by a foul odor.");
if (lost_str == 0) {
chg_str(odor_str);
fuse(res_strength, 0, SMELLTIME, AFTER);
lost_str -= odor_str;
}
else lengthen(res_strength, SMELLTIME);
}
}
/*
* The monsters touch slows the defendant down.
*/
if (on(*att, TOUCHSLOW)) {
turn_off(*att, TOUCHSLOW);
if (!save(VS_PARALYZATION, def, 0))
add_slow();
}
/*
* Rotting only affects the player.
*/
if (on(*att, CANROT)) {
if (!ISWEARING(R_HEALTH) &&
player.t_ctype != C_PALADIN &&
player.t_ctype != C_MONK &&
!save(VS_POISON, def, 0) &&
off(*def, DOROT)) {
turn_on(*def, DOROT);
msg("You feel your skin starting to rot away!");
}
}
/*
* Monsters should be able to steal gold from anyone,
* but until this is rewritten, they will only steal
* from the player (tough break).
*/
if (on(*att, STEALGOLD)) {
/*
* steal some gold
*/
register long lastpurse;
register struct linked_list *item;
register struct object *obj;
lastpurse = purse;
purse -= GOLDCALC + GOLDCALC;
if (!save(VS_MAGIC, def, att->t_stats.s_lvl/10)) {
if (on(*att, ISUNIQUE))
purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
}
if (purse < 0)
purse = 0;
if (purse != lastpurse) {
msg("Your purse feels lighter");
/* Give the gold to the thief */
for (item=att->t_pack; item != NULL; item=next(item)) {
obj = OBJPTR(item);
if (obj->o_type == GOLD) {
obj->o_count += lastpurse - purse;
break;
}
}
/* Did we do it? */
if (item == NULL) { /* Then make some */
item = new_item(sizeof *obj);
obj = OBJPTR(item);
obj->o_type = GOLD;
obj->o_count = lastpurse - purse;
obj->o_hplus = obj->o_dplus = 0;
strncpy(obj->o_damage, "0d0", sizeof(obj->o_damage));
strncpy(obj->o_hurldmg, "0d0", sizeof(obj->o_hurldmg));
obj->o_ac = 11;
obj->contents = NULL;
obj->o_group = 0;
obj->o_flags = 0;
obj->o_mark[0] = '\0';
obj->o_pos = att->t_pos;
attach(att->t_pack, item);
}
}
turn_on(*att, ISFLEE);
turn_on(*att, ISINVIS);
/* It is okay to turn tail */
att->t_oldpos = att->t_pos;
}
}
/*
* Stealing happens last since the monster disappears
* after the act.
*/
if (on(*att, STEALMAGIC)) {
register struct linked_list *list, *steal;
register struct object *obj;
register int nobj;
/*
* steal a magic item, look through the pack
* and pick out one we like.
*/
steal = NULL;
for (nobj = 0, list = def->t_pack; list != NULL; list = next(list))
{
obj = OBJPTR(list);
if (!is_current(obj) &&
list != def->t_using &&
obj->o_type != RELIC &&
is_magic(obj) &&
rnd(++nobj) == 0)
steal = list;
}
if (steal != NULL)
{
register struct object *obj;
struct linked_list *item;
obj = OBJPTR(steal);
if (on(*att, ISUNIQUE))
monsters[att->t_index].m_normal = TRUE;
item = find_mons(att->t_pos.y, att->t_pos.x);
killed(item, FALSE, FALSE, FALSE); /* Remove the attacker */
if (obj->o_count > 1 && obj->o_group == 0) {
register int oc;
oc = --(obj->o_count);
obj->o_count = 1;
if (def_player)
msg("%s stole %s!", prname(attname, TRUE),
inv_name(obj, TRUE));
obj->o_count = oc;
}
else {
if (def_player) {
msg("%s stole %s!", prname(attname, TRUE),
inv_name(obj, TRUE));
/* If this is a relic, clear its holding field */
if (obj->o_type == RELIC)
cur_relic[obj->o_which] = 0;
inpack--;
}
detach(def->t_pack, steal);
o_discard(steal);
}
updpack(FALSE, def);
}
}
}
/* Didn't kill the defender */
return(0);
}

207
arogue7/encumb.c Normal file
View file

@ -0,0 +1,207 @@
/*
* encumb.c - Stuff to do with encumberence
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Stuff to do with encumberence
*
*/
#include "curses.h"
#include "rogue.h"
/*
* updpack:
* Update his pack weight and adjust fooduse accordingly
*/
updpack(getmax, tp)
int getmax;
struct thing *tp;
{
reg int topcarry, curcarry;
if (getmax)
tp->t_stats.s_carry = totalenc(tp); /* get total encumb */
curcarry = packweight(tp); /* get pack weight */
/* Only update food use for the player (for now) */
if (tp == &player) {
topcarry = tp->t_stats.s_carry / 5; /* 20% of total carry */
if(curcarry > 4 * topcarry) {
if(rnd(100) < 80)
foodlev = 3; /* > 80% of pack */
} else if(curcarry > 3 * topcarry) {
if(rnd(100) < 60)
foodlev = 2; /* > 60% of pack */
} else
foodlev = 1; /* <= 60% of pack */
}
tp->t_stats.s_pack = curcarry; /* update pack weight */
}
/*
* packweight:
* Get the total weight of the hero's pack
*/
packweight(tp)
register struct thing *tp;
{
reg struct object *obj;
reg struct linked_list *pc;
reg int weight;
weight = 0;
for (pc = tp->t_pack ; pc != NULL ; pc = next(pc)) {
obj = OBJPTR(pc);
weight += itemweight(obj);
}
if (weight < 0) /* in case of amulet */
weight = 0;
/* If this is the player, is he wearing a ring of carrying? */
if (tp == &player && ISWEARING(R_CARRY)) {
register int temp, i;
temp = 0;
for (i=0; i<NUM_FINGERS; i++) {
if (cur_ring[i]->o_which == R_CARRY) {
if (cur_ring[i]->o_flags & ISCURSED) temp--;
else temp++;
}
}
weight -= (temp * weight) / 4;
}
return(weight);
}
/*
* itemweight:
* Get the weight of an object
*/
itemweight(wh)
reg struct object *wh;
{
reg int weight;
reg int ac;
weight = wh->o_weight; /* get base weight */
switch(wh->o_type) {
case ARMOR:
/*
* subtract 10% for each enchantment
* this will add weight for negative items
*/
ac = armors[wh->o_which].a_class - wh->o_ac;
weight = ((weight*10) - (weight*ac)) / 10;
if (weight < 0) weight = 0;
when WEAPON:
if ((wh->o_hplus + wh->o_dplus) > 0)
weight /= 2;
}
if(wh->o_flags & ISCURSED)
weight += weight / 5; /* 20% more for cursed */
weight *= wh->o_count;
return(weight);
}
/*
* playenc:
* Get hero's carrying ability above norm
*/
playenc(tp)
register struct thing *tp;
{
register int strength;
if (tp == &player) strength = str_compute();
else strength = tp->t_stats.s_str;
return ((strength-8)*50);
}
/*
* totalenc:
* Get total weight that the hero can carry
*/
totalenc(tp)
register struct thing *tp;
{
reg int wtotal;
wtotal = NORMENCB + playenc(tp);
if (tp == &player) switch(hungry_state) {
case F_SATIATED:
case F_OKAY:
case F_HUNGRY: ; /* no change */
when F_WEAK: wtotal -= wtotal / 10; /* 10% off weak */
when F_FAINT: wtotal /= 2; /* 50% off faint */
}
return(wtotal);
}
/*
* whgtchk:
* See if the hero can carry his pack
*/
wghtchk()
{
reg int dropchk, err = TRUE;
reg char ch;
int wghtchk();
inwhgt = TRUE;
if (pstats.s_pack > pstats.s_carry) {
ch = CCHAR( mvwinch(stdscr, hero.y, hero.x) );
if((ch != FLOOR && ch != PASSAGE)) {
extinguish(wghtchk);
fuse(wghtchk,TRUE,1,AFTER);
inwhgt = FALSE;
return;
}
extinguish(wghtchk);
msg("Your pack is too heavy for you");
do {
dropchk = drop(NULL);
if(dropchk == 0) {
mpos = 0;
msg("You must drop something");
}
if(dropchk == TRUE)
err = FALSE;
} while(err);
}
inwhgt = FALSE;
}
/*
* hitweight:
* Gets the fighting ability according to current weight
* This returns a +1 hit for light pack weight
* 0 hit for medium pack weight
* -1 hit for heavy pack weight
*/
hitweight()
{
return(2 - foodlev);
}

1495
arogue7/fight.c Normal file

File diff suppressed because it is too large Load diff

624
arogue7/init.c Normal file
View file

@ -0,0 +1,624 @@
/*
* init.c - global variable initializaton
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* global variable initializaton
*
*/
#include "curses.h"
#include <ctype.h>
#include "rogue.h"
#include "mach_dep.h"
/*
* If there is any news, put it in a character string and assign it to
* rogue_news. Otherwise, assign NULL to rogue_news.
*/
static char *rogue_news = "You no longer fall into trading posts. They are \
now entered like going down the stairs.";
char *rainbow[] = {
"amber", "aquamarine", "beige",
"black", "blue", "brown",
"clear", "crimson", "ecru",
"gold", "green", "grey",
"indigo", "khaki", "lavender",
"magenta", "orange", "pink",
"plaid", "purple", "red",
"silver", "saffron", "scarlet",
"tan", "tangerine", "topaz",
"turquoise", "vermilion", "violet",
"white", "yellow",
};
#define NCOLORS (sizeof rainbow / sizeof(char *))
int cNCOLORS = NCOLORS;
static char *sylls[] = {
"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", "net", "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",
};
char *stones[] = {
"agate", "alexandrite", "amethyst",
"azurite", "bloodstone", "cairngorm",
"carnelian", "chalcedony", "chrysoberyl",
"chrysolite", "chrysoprase", "citrine",
"coral", "diamond", "emerald",
"garnet", "heliotrope", "hematite",
"hyacinth", "jacinth", "jade",
"jargoon", "jasper", "kryptonite",
"lapus lazuli", "malachite", "mocca stone",
"moonstone", "obsidian", "olivine",
"onyx", "opal", "pearl",
"peridot", "quartz", "rhodochrosite",
"rhodolite", "ruby", "sapphire",
"sardonyx", "serpintine", "spinel",
"tiger eye", "topaz", "tourmaline",
"turquoise", "zircon",
};
#define NSTONES (sizeof stones / sizeof(char *))
int cNSTONES = NSTONES;
char *wood[] = {
"avocado wood", "balsa", "banyan", "birch",
"cedar", "cherry", "cinnibar", "dogwood",
"driftwood", "ebony", "eucalyptus", "hemlock",
"ironwood", "mahogany", "manzanita", "maple",
"oak", "pine", "redwood", "rosewood",
"teak", "walnut", "zebra wood", "persimmon wood",
};
#define NWOOD (sizeof wood / sizeof(char *))
int cNWOOD = NWOOD;
char *metal[] = {
"aluminium", "bone", "brass", "bronze",
"copper", "chromium", "iron", "lead",
"magnesium", "pewter", "platinum", "silver",
"steel", "tin", "titanium", "zinc",
};
#define NMETAL (sizeof metal / sizeof(char *))
int cNMETAL = NMETAL;
#define MAX3(a,b,c) (a > b ? (a > c ? a : c) : (b > c ? b : c))
static bool used[MAX3(NCOLORS, NSTONES, NWOOD)];
/*
* make sure all the percentages specified in the tables add up to the
* right amounts
*/
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 == 1000)
return;
printf("\nBad percentages for %s:\n", name);
for (end = &magic[bound] ; magic < end ; magic++)
printf("%4d%% %s\n", magic->mi_prob, magic->mi_name);
printf(retstr);
fflush(stdout);
while (getchar() != '\n')
continue;
}
/*
* init_colors:
* Initialize the potion color scheme for this time
*/
init_colors()
{
register int i, j;
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;
}
badcheck("potions", p_magic, MAXPOTIONS);
}
/*
* do any initialization for food
*/
init_foods()
{
register int i;
for (i=0; i < MAXFOODS; i++) {
if (i > 0)
foods[i].mi_prob += foods[i-1].mi_prob;
}
badcheck("foods", foods, MAXFOODS);
}
/*
* init_materials:
* Initialize the construction materials for wands and staffs
*/
init_materials()
{
register int i, j;
register char *str;
static bool metused[NMETAL];
for (i = 0; i < NWOOD; i++)
used[i] = FALSE;
for (i = 0; i < NMETAL; i++)
metused[i] = FALSE;
for (i = 0 ; i < MAXSTICKS ; i++)
{
for (;;)
if (rnd(100) > 50)
{
j = rnd(NMETAL);
if (!metused[j])
{
ws_type[i] = "wand";
str = metal[j];
metused[j] = TRUE;
break;
}
}
else
{
j = rnd(NWOOD);
if (!used[j])
{
ws_type[i] = "staff";
str = wood[j];
used[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;
}
badcheck("sticks", ws_magic, MAXSTICKS);
}
/*
* do any initialization for miscellaneous magic
*/
init_misc()
{
register int i;
for (i=0; i < MAXMM; i++) {
m_know[i] = FALSE;
m_guess[i] = NULL;
if (i > 0)
m_magic[i].mi_prob += m_magic[i-1].mi_prob;
}
badcheck("miscellaneous magic", m_magic, MAXMM);
}
/*
* init_names:
* Generate the names of the various scrolls
*/
init_names()
{
register int nsyl;
register char *cp, *sp;
register int i, nwords;
for (i = 0 ; i < MAXSCROLLS ; i++)
{
cp = prbuf;
nwords = rnd(cols/20) + 1 + (cols > 40 ? 1 : 0);
while(nwords--)
{
nsyl = rnd(3)+1;
while(nsyl--)
{
sp = sylls[rnd((sizeof sylls) / (sizeof (char *)))];
while(*sp)
*cp++ = *sp++;
}
*cp++ = ' ';
}
*--cp = '\0';
s_names[i] = (char *) new(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;
}
badcheck("scrolls", s_magic, MAXSCROLLS);
}
/*
* init_player:
* roll up the rogue
*/
init_player()
{
int stat_total, round, minimum, maximum, ch, i, j;
short do_escape, *our_stats[NUMABILITIES-1];
struct linked_list *weap_item, *armor_item;
struct object *obj;
weap_item = armor_item = NULL;
if (char_type == -1) {
/* See what type character will be */
wclear(hw);
touchwin(hw);
wmove(hw,2,0);
for(i=1; i<=NUM_CHARTYPES-1; i++) {
wprintw(hw,"[%d] %s\n",i,char_class[i-1].name);
}
mvwaddstr(hw, 0, 0, "What character class do you desire? ");
draw(hw);
char_type = (wgetch(hw) - '0');
while (char_type < 1 || char_type > NUM_CHARTYPES-1) {
wmove(hw,0,0);
wprintw(hw,"Please enter a character type between 1 and %d: ",
NUM_CHARTYPES-1);
draw(hw);
char_type = (wgetch(hw) - '0');
}
char_type--;
}
player.t_ctype = char_type;
player.t_quiet = 0;
pack = NULL;
/* Select the gold */
purse = 2700;
switch (player.t_ctype) {
case C_FIGHTER:
purse += 1800;
when C_THIEF:
case C_ASSASIN:
purse += 600;
}
#ifdef WIZARD
/*
* allow me to describe a super character
*/
if (wizard && strcmp(getenv("SUPER"),"YES") == 0) {
pstats.s_str = 25;
pstats.s_intel = 25;
pstats.s_wisdom = 25;
pstats.s_dext = 25;
pstats.s_const = 25;
pstats.s_charisma = 25;
pstats.s_exp = 10000000L;
pstats.s_lvladj = 0;
pstats.s_lvl = 1;
pstats.s_hpt = 500;
pstats.s_carry = totalenc(&player);
strncpy(pstats.s_dmg, "3d4", sizeof(pstats.s_dmg));
check_level();
mpos = 0;
if (player.t_ctype == C_FIGHTER ||
player.t_ctype == C_RANGER ||
player.t_ctype == C_PALADIN)
weap_item = spec_item(WEAPON, TWOSWORD, 5, 5);
else
weap_item = spec_item(WEAPON, SWORD, 5, 5);
obj = OBJPTR(weap_item);
obj->o_flags |= ISKNOW;
add_pack(weap_item, TRUE, NULL);
cur_weapon = obj;
if (player.t_ctype != C_MONK) {
j = PLATE_ARMOR;
if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASIN)
j = STUDDED_LEATHER;
armor_item = spec_item(ARMOR, j, 10, 0);
obj = OBJPTR(armor_item);
obj->o_flags |= (ISKNOW | ISPROT);
obj->o_weight = armors[j].a_wght;
add_pack(armor_item, TRUE, NULL);
cur_armor = obj;
}
purse += 10000;
}
else
#endif
{
switch(player.t_ctype) {
case C_MAGICIAN:round = A_INTELLIGENCE;
when C_FIGHTER: round = A_STRENGTH;
when C_RANGER: round = A_STRENGTH;
when C_PALADIN: round = A_STRENGTH;
when C_CLERIC: round = A_WISDOM;
when C_DRUID: round = A_WISDOM;
when C_THIEF: round = A_DEXTERITY;
when C_ASSASIN: round = A_DEXTERITY;
when C_MONK: round = A_DEXTERITY;
}
do {
wclear(hw);
/* If there is any news, display it */
if (rogue_news) {
register int i;
/* Print a separator line */
wmove(hw, 12, 0);
for (i=0; i<cols; i++) waddch(hw, '-');
/* Print the news */
mvwaddstr(hw, 14, 0, rogue_news);
}
stat_total = MAXSTATS;
do_escape = FALSE; /* No escape seen yet */
/* Initialize abilities */
pstats.s_intel = 0;
pstats.s_str = 0;
pstats.s_wisdom = 0;
pstats.s_dext = 0;
pstats.s_const = 0;
pstats.s_charisma = 0;
/* Initialize pointer into abilities */
our_stats[A_INTELLIGENCE] = &pstats.s_intel;
our_stats[A_STRENGTH] = &pstats.s_str;
our_stats[A_WISDOM] = &pstats.s_wisdom;
our_stats[A_DEXTERITY] = &pstats.s_dext;
our_stats[A_CONSTITUTION] = &pstats.s_const;
/* Let player distribute attributes */
for (i=0; i<NUMABILITIES-1; i++) {
wmove(hw, 2, 0);
wprintw(hw, "You are creating a %s with %2d attribute points.",
char_class[player.t_ctype].name, stat_total);
/*
* Player must have a minimum of 7 in any attribute and 11 in
* the player's primary attribute.
*/
minimum = (round == i ? 11 : 7);
/* Subtract out remaining minimums */
maximum = stat_total - (7 * (NUMABILITIES-1 - i));
/* Subtract out remainder of profession minimum (11 - 7) */
if (round > i) maximum -= 4;
/* Maximum can't be greater than 18 */
if (maximum > 18) maximum = 18;
wmove(hw, 4, 0);
wprintw(hw,
"Minimum: %2d; Maximum: %2d (%s corrects previous entry)",
minimum, maximum, unctrl('\b'));
wmove(hw, 6, 0);
wprintw(hw, " Int: %-2d", pstats.s_intel);
wprintw(hw, " Str: %-2d", pstats.s_str);
wprintw(hw, " Wis: %-2d", pstats.s_wisdom);
wprintw(hw, " Dex: %-2d", pstats.s_dext);
wprintw(hw, " Con: %-2d", pstats.s_const);
wprintw(hw, " Cha: %-2d", pstats.s_charisma);
wclrtoeol(hw);
wmove(hw, 6, 11*i + 9);
if (do_escape == FALSE) draw(hw);
/* Get player's input */
if (do_escape || maximum == minimum) {
*our_stats[i] = maximum;
stat_total -= maximum;
}
else for (;;) {
ch = wgetch(hw);
if (ch == '\b') { /* Backspace */
if (i == 0) continue; /* Can't move back */
else {
stat_total += *our_stats[i-1];
*our_stats[i] = 0;
*our_stats[i-1] = 0;
i -= 2; /* Back out */
break;
}
}
if (ch == '\033') { /* Escape */
/*
* Escape will result in using all maximums for
* remaining abilities.
*/
do_escape = TRUE;
*our_stats[i] = maximum;
stat_total -= maximum;
break;
}
/* Do we have a legal digit? */
if (ch >= '0' && ch <= '9') {
ch -= '0'; /* Convert it to a number */
*our_stats[i] = 10 * *our_stats[i] + ch;
/* Is the number in range? */
if (*our_stats[i] >= minimum &&
*our_stats[i] <= maximum) {
stat_total -= *our_stats[i];
break;
}
/*
* If it's too small, get more - 1x is the only
* allowable case.
*/
if (*our_stats[i] < minimum && *our_stats[i] == 1) {
/* Print the player's one */
waddch(hw, '1');
draw(hw);
continue;
}
}
/* Error condition */
putchar('\007');
*our_stats[i] = 0;
i--; /* Rewind */
break;
}
}
/* Discard extra points over 18 */
if (stat_total > 18) stat_total = 18;
/* Charisma gets what's left */
pstats.s_charisma = stat_total;
/* Intialize constants */
pstats.s_lvl = 1;
pstats.s_lvladj = 0;
pstats.s_exp = 0L;
strncpy(pstats.s_dmg, "1d4", sizeof(pstats.s_dmg));
pstats.s_carry = totalenc(&player);
/* Get the hit points. */
pstats.s_hpt = 12 + const_bonus(); /* Base plus bonus */
/* Add in the component that varies according to class */
pstats.s_hpt += char_class[player.t_ctype].hit_pts;
/* Display the character */
wmove(hw, 2, 0);
wprintw(hw,"You are creating a %s.",
char_class[player.t_ctype].name);
wclrtoeol(hw);
/* Get rid of max/min line */
wmove(hw, 4, 0);
wclrtoeol(hw);
wmove(hw, 6, 0);
wprintw(hw, " Int: %2d", pstats.s_intel);
wprintw(hw, " Str: %2d", pstats.s_str);
wprintw(hw, " Wis: %2d", pstats.s_wisdom);
wprintw(hw, " Dex: %2d", pstats.s_dext);
wprintw(hw, " Con: %2d", pstats.s_const);
wprintw(hw, " Cha: %2d", pstats.s_charisma);
wclrtoeol(hw);
wmove(hw, 8, 0);
wprintw(hw, " Hp: %2d", pstats.s_hpt);
wclrtoeol(hw);
wmove(hw, 10, 0);
wprintw(hw, " Gold: %d", purse);
mvwaddstr(hw, 0, 0, "Is this character okay? ");
draw(hw);
} while(wgetch(hw) != 'y');
}
pstats.s_arm = 10;
max_stats = pstats;
/* Set up the initial movement rate */
player.t_action = A_NIL;
player.t_movement = 6;
player.t_no_move = 0;
player.t_using = NULL;
}
/*
* init_stones:
* Initialize the ring stone setting scheme for this time
*/
init_stones()
{
register int i, j;
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];
r_know[i] = FALSE;
r_guess[i] = NULL;
if (i > 0)
r_magic[i].mi_prob += r_magic[i-1].mi_prob;
}
badcheck("rings", r_magic, MAXRINGS);
}
/*
* init_things
* Initialize the probabilities for types of things
*/
init_things()
{
register struct magic_item *mp;
for (mp = &things[1] ; mp < &things[NUMTHINGS] ; mp++)
mp->mi_prob += (mp-1)->mi_prob;
badcheck("things", things, NUMTHINGS);
}

539
arogue7/io.c Normal file
View file

@ -0,0 +1,539 @@
/*
* io.c - Various input/output functions
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Various input/output functions
*/
#include "curses.h"
#include <stdarg.h>
#include <ctype.h>
#include "rogue.h"
/*
* msg:
* Display a message at the top of the screen.
*/
static char msgbuf[BUFSIZ];
static int newpos = 0;
/*VARARGS1*/
msg(char *fmt, ...)
{
va_list ap;
/*
* if the string is "", just clear the line
*/
if (*fmt == '\0')
{
overwrite(cw,msgw);
wmove(msgw, 0, 0);
clearok(msgw, FALSE);
draw(msgw);
mpos = 0;
return;
}
/*
* otherwise add to the message and flush it out
*/
va_start(ap,fmt);
doadd(fmt, ap);
va_end(ap);
endmsg();
}
/*
* add things to the current message
*/
addmsg(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
doadd(fmt, ap);
va_end(ap);
}
/*
* Display a new msg (giving him a chance to see the previous one if it
* is up there with the --More--)
*/
endmsg()
{
/* Needed to track where we are for 5.0 (PC) curses */
register int x, y;
strcpy(huh, msgbuf);
if (mpos) {
/*
* If this message will fit on the line (plus space for --More--
* then just add it (only during combat).
*/
if (player.t_quiet < 0 && mpos + newpos + strlen(morestr) + 2 < cols) {
wmove(msgw, 0, mpos + 2);
newpos += mpos + 2;
}
else {
wmove(msgw, 0, mpos);
waddstr(msgw, morestr);
draw(cw);
draw(msgw);
wait_for(' ');
overwrite(cw,msgw);
wmove(msgw, 0, 0);
touchwin(cw);
}
}
else {
overwrite(cw,msgw);
wmove(msgw, 0, 0);
}
waddstr(msgw, msgbuf);
getyx(msgw, y, x);
mpos = newpos;
newpos = 0;
wmove(msgw, y, x);
draw(cw);
clearok(msgw, FALSE);
draw(msgw);
}
doadd(char *fmt, va_list ap)
{
/*
* Do the printf into buf
*/
vsprintf(&msgbuf[newpos], fmt, ap);
newpos = strlen(msgbuf);
}
/*
* step_ok:
* returns true if it is ok for type to step on ch
* flgptr will be NULL if we don't know what the monster is yet!
*/
step_ok(y, x, can_on_monst, flgptr)
register int y, x, can_on_monst;
register struct thing *flgptr;
{
/* can_on_monst = MONSTOK if all we care about are physical obstacles */
register struct linked_list *item;
register struct thing *tp;
char ch;
/* What is here? Don't check monster window if MONSTOK is set */
if (can_on_monst == MONSTOK) ch = CCHAR( mvinch(y, x) );
else ch = CCHAR( winat(y, x) );
if (can_on_monst == FIGHTOK && isalpha(ch) &&
(item = find_mons(y, x)) != NULL) {
tp = THINGPTR(item); /* What monster is here? */
/* We can hit it if we're after it */
if (flgptr->t_dest == &tp->t_pos) return TRUE;
/*
* Otherwise, if we're friendly we'll hit it unless it is also
* friendly or is our race.
*/
if (off(*flgptr, ISFRIENDLY) ||
on(*tp, ISFRIENDLY) ||
flgptr->t_index == tp->t_index) return FALSE;
else return TRUE;
}
else switch (ch)
{
case ' ':
case '|':
case '-':
case SECRETDOOR:
if (flgptr && on(*flgptr, CANINWALL)) return(TRUE);
return FALSE;
when SCROLL:
if (can_on_monst == MONSTOK) return(TRUE); /* Not a real obstacle */
/*
* 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 (flgptr && flgptr->t_ctype == C_MONSTER) {
item = find_obj(y, x);
if (item != NULL &&
(OBJPTR(item))->o_which==S_SCARE &&
(flgptr == NULL || flgptr->t_stats.s_intel < 16))
return(FALSE); /* All but smart ones are scared */
}
return(TRUE);
otherwise:
return (!isalpha(ch));
}
return(FALSE);
}
/*
* shoot_ok:
* returns true if it is ok for type to shoot over ch
*/
shoot_ok(ch)
{
switch (ch)
{
case ' ':
case '|':
case '-':
case SECRETDOOR:
case FOREST:
return FALSE;
default:
return (!isalpha(ch));
}
}
/*
* readchar:
* flushes stdout so that screen is up to date and then returns
* getchar.
*/
readchar()
{
int ch;
ch = md_readchar(cw);
if ((ch == 3) || (ch == 0))
{
quit(0);
return(27);
}
return(ch);
}
/*
* status:
* Display the important stats line. Keep the cursor where it was.
*/
status(display)
bool display; /* is TRUE, display unconditionally */
{
register struct stats *stat_ptr, *max_ptr;
register int oy, ox, temp;
register char *pb;
static char buf[LINELEN];
static int hpwidth = 0, s_hungry = -1;
static int s_lvl = -1, s_hp = -1, s_str, maxs_str,
s_ac = 0;
static short s_intel, s_dext, s_wisdom, s_const, s_charisma;
static short maxs_intel, maxs_dext, maxs_wisdom, maxs_const, maxs_charisma;
static unsigned long s_exp = 0;
static int s_carry, s_pack;
bool first_line=FALSE;
stat_ptr = &pstats;
max_ptr = &max_stats;
/*
* If nothing has changed in the first line, then skip it
*/
if (!display &&
s_lvl == level &&
s_intel == stat_ptr->s_intel &&
s_wisdom == stat_ptr->s_wisdom &&
s_dext == dex_compute() &&
s_const == stat_ptr->s_const &&
s_charisma == stat_ptr->s_charisma &&
s_str == str_compute() &&
s_hungry == hungry_state &&
maxs_intel == max_ptr->s_intel &&
maxs_wisdom == max_ptr->s_wisdom &&
maxs_dext == max_ptr->s_dext &&
maxs_const == max_ptr->s_const &&
maxs_charisma == max_ptr->s_charisma &&
maxs_str == max_ptr->s_str ) goto line_two;
/* Display the first line */
first_line = TRUE;
getyx(cw, oy, ox);
sprintf(buf, "Int:%d(%d) Str:%d", stat_ptr->s_intel,
max_ptr->s_intel, str_compute());
/* Maximum strength */
pb = &buf[strlen(buf)];
sprintf(pb, "(%d)", max_ptr->s_str);
pb = &buf[strlen(buf)];
sprintf(pb, " Wis:%d(%d) Dxt:%d(%d) Con:%d(%d) Cha:%d(%d)",
stat_ptr->s_wisdom,max_ptr->s_wisdom,dex_compute(),max_ptr->s_dext,
stat_ptr->s_const,max_ptr->s_const,stat_ptr->s_charisma,
max_ptr->s_charisma);
/* Update first line status */
s_intel = stat_ptr->s_intel;
s_wisdom = stat_ptr->s_wisdom;
s_dext = dex_compute();
s_const = stat_ptr->s_const;
s_charisma = stat_ptr->s_charisma;
s_str = str_compute();
maxs_intel = max_ptr->s_intel;
maxs_wisdom = max_ptr->s_wisdom;
maxs_dext = max_ptr->s_dext;
maxs_const = max_ptr->s_const;
maxs_charisma = max_ptr->s_charisma;
maxs_str = max_ptr->s_str;
/* Print the line */
mvwaddstr(cw, lines - 2, 0, buf);
switch (hungry_state)
{
case F_SATIATED:
waddstr(cw, " Satiated");
when F_OKAY: ;
when F_HUNGRY:
waddstr(cw, " Hungry");
when F_WEAK:
waddstr(cw, " Weak");
when F_FAINT:
waddstr(cw, " Fainting");
}
wclrtoeol(cw);
s_hungry = hungry_state;
/*
* If nothing has changed since the last status, don't
* bother.
*/
line_two:
if (!display &&
s_lvl == level &&
s_hp == stat_ptr->s_hpt &&
s_ac == ac_compute(FALSE) - dext_prot(s_dext) &&
s_pack == stat_ptr->s_pack &&
s_carry == stat_ptr->s_carry &&
s_exp == stat_ptr->s_exp ) return;
if (!first_line) getyx(cw, oy, ox);
if (s_hp != max_ptr->s_hpt)
{
temp = s_hp = max_ptr->s_hpt;
for (hpwidth = 0; temp; hpwidth++)
temp /= 10;
}
sprintf(buf, "Lvl:%d Hp:%*d(%*d) Ac:%d Carry:%d(%d) Exp:%d/%lu %s",
level, hpwidth, stat_ptr->s_hpt, hpwidth, max_ptr->s_hpt,
ac_compute(FALSE) - dext_prot(s_dext),stat_ptr->s_pack/10,
stat_ptr->s_carry/10, stat_ptr->s_lvl, stat_ptr->s_exp,
cnames[player.t_ctype][min(stat_ptr->s_lvl-1, NUM_CNAMES-1)]);
/*
* Save old status
*/
s_lvl = level;
s_hp = stat_ptr->s_hpt;
s_ac = ac_compute(FALSE) - dext_prot(s_dext);
s_pack = stat_ptr->s_pack;
s_carry = stat_ptr->s_carry;
s_exp = stat_ptr->s_exp;
mvwaddstr(cw, lines - 1, 0, buf);
wclrtoeol(cw);
wmove(cw, oy, ox);
}
/*
* wait_for
* Sit around until the guy types the right key
*/
wait_for(ch)
register char ch;
{
register char c;
if (ch == '\n')
while ((c = wgetch(msgw)) != '\n' && c != '\r')
continue;
else
while (wgetch(msgw) != ch)
continue;
}
/*
* over_win:
* Given a current window, a new window, and the max y and x of the
* new window, paint the new window on top of the old window without
* destroying any of the old window. Current window and new window
* are assumed to have lines lines and cols columns (max y and max x
* pertain only the the useful information to be displayed.
* If redraw is non-zero, we wait for the character "redraw" to be
* typed and then redraw the starting screen.
*/
over_win(oldwin, newin, maxy, maxx, cursory, cursorx, redraw)
WINDOW *oldwin, *newin;
int maxy, maxx, cursory, cursorx;
char redraw;
{
static char blanks[LINELEN+1];
register int line, i;
WINDOW *ow; /* Overlay window */
/* Create a blanking line */
for (i=0; i<maxx && i<cols && i<LINELEN; i++) blanks[i] = ' ';
blanks[i] = '\0';
/* Create the window we will display */
ow = newwin(lines, cols, 0, 0);
/* Blank out the area we want to use */
if (oldwin == cw) {
msg("");
line = 1;
}
else line = 0;
overwrite(oldwin, ow); /* Get a copy of the old window */
/* Do the remaining blanking */
for (; line < maxy; line++) mvwaddstr(ow, line, 0, blanks);
overlay(newin, ow); /* Overlay our new window */
/* Move the cursor to the specified location */
wmove(ow, cursory, cursorx);
clearok(ow, FALSE); /* Draw inventory without clearing */
draw(ow);
if (redraw) {
wait_for(redraw);
clearok(oldwin, FALSE); /* Setup to redraw current screen */
touchwin(oldwin); /* clearing first */
draw(oldwin);
}
delwin(ow);
}
/*
* 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);
draw(scr);
wait_for(' ');
clearok(cw, TRUE);
touchwin(cw);
}
/*
* dbotline:
* Displays message on bottom line and waits for a space to return
*/
dbotline(scr,message)
WINDOW *scr;
char *message;
{
mvwaddstr(scr,lines-1,0,message);
draw(scr);
wait_for(' ');
}
/*
* restscr:
* Restores the screen to the terminal
*/
restscr(scr)
WINDOW *scr;
{
clearok(scr,TRUE);
touchwin(scr);
}
/*
* netread:
* Read a byte, short, or long machine independently
* Always returns the value as an unsigned long.
*/
unsigned long
netread(error, size, stream)
int *error;
int size;
FILE *stream;
{
unsigned long result = 0L, /* What we read in */
partial; /* Partial value */
int nextc, /* The next byte */
i; /* To index through the result a byte at a time */
/* Be sure we have a right sized chunk */
if (size < 1 || size > 4) {
*error = 1;
return(0L);
}
for (i=0; i<size; i++) {
nextc = getc(stream);
if (nextc == EOF) {
*error = 1;
return(0L);
}
else {
partial = (unsigned long) (nextc & 0xff);
partial <<= 8*i;
result |= partial;
}
}
*error = 0;
return(result);
}
/*
* netwrite:
* Write out a byte, short, or long machine independently.
*/
netwrite(value, size, stream)
unsigned long value; /* What to write */
int size; /* How much to write out */
FILE *stream; /* Where to write it */
{
int i; /* Goes through value one byte at a time */
char outc; /* The next character to be written */
/* Be sure we have a right sized chunk */
if (size < 1 || size > 4) return(0);
for (i=0; i<size; i++) {
outc = (char) ((value >> (8 * i)) & 0xff);
putc(outc, stream);
}
return(size);
}

226
arogue7/list.c Normal file
View file

@ -0,0 +1,226 @@
/*
* list.c - Functions for dealing with linked lists of goodies
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Functions for dealing with linked lists of goodies
*
*/
#include "curses.h"
#include <stdlib.h>
#include "rogue.h"
/*
* detach:
* Takes an item out of whatever linked list it might be in
*/
_detach(list, item)
register struct linked_list **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 struct linked_list **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;
}
/*
* o_free_list:
* Throw the whole object list away
*/
_o_free_list(ptr)
register struct linked_list **ptr;
{
register struct linked_list *item;
while (*ptr != NULL)
{
item = *ptr;
*ptr = next(item);
o_discard(item);
}
}
/*
* o_discard:
* free up an item and its object(and maybe contents)
*/
o_discard(item)
register struct linked_list *item;
{
register struct object *obj;
obj = OBJPTR(item);
if (obj->contents != NULL)
o_free_list(obj->contents);
total -= 2;
FREE(obj);
FREE(item);
}
/*
* r_free_list:
* Throw the whole list of room exits away
*/
_r_free_list(ptr)
register struct linked_list **ptr;
{
register struct linked_list *item;
while (*ptr != NULL)
{
item = *ptr;
*ptr = next(item);
r_discard(item);
}
}
/*
* r_discard:
* free up an item and its room
*/
r_discard(item)
register struct linked_list *item;
{
total -= 2;
FREE(DOORPTR(item));
FREE(item);
}
/*
* t_free_list:
* Throw the whole thing list away
*/
_t_free_list(ptr)
register struct linked_list **ptr;
{
register struct linked_list *item;
while (*ptr != NULL)
{
item = *ptr;
*ptr = next(item);
t_discard(item);
}
}
/*
* t_discard:
* free up an item and its thing
*/
t_discard(item)
register struct linked_list *item;
{
register struct thing *tp;
total -= 2;
tp = THINGPTR(item);
if (tp->t_name != NULL) FREE(tp->t_name);
FREE(tp);
FREE(item);
}
/*
* destroy_item:
* get rid of an item structure -- don't worry about contents
*/
destroy_item(item)
register struct linked_list *item;
{
total--;
FREE(item);
}
/*
* new_item
* get a new item with a specified size
*/
struct linked_list *
new_item(size)
int size;
{
register struct linked_list *item;
if ((item = (struct linked_list *) new(sizeof *item)) == NULL)
msg("Ran out of memory for header after %d items", total);
if ((item->l_data = new(size)) == NULL)
msg("Ran out of memory for data after %d items", total);
item->l_next = item->l_prev = NULL;
return item;
}
/*
* creat_item:
* Create just an item structure -- don't make any contents
*/
struct linked_list *
creat_item()
{
register struct linked_list *item;
if ((item = (struct linked_list *) new(sizeof *item)) == NULL)
msg("Ran out of memory for header after %d items", total);
item->l_next = item->l_prev = NULL;
return item;
}
char *
new(size)
int size;
{
register char *space = ALLOC(size);
static char errbuf[LINELEN];
if (space == NULL) {
sprintf(errbuf,"Rogue ran out of memory (used = %d, wanted = %d).",
md_memused(), size);
fatal(errbuf);
}
total++;
return space;
}

84
arogue7/mach_dep.h Normal file
View file

@ -0,0 +1,84 @@
/*
* mach_dep.h - machine dependicies
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* define that the wizard commands exist
*/
#define WIZARD 0
/*
* define if you want to limit scores to one per class per userid
*/
#undef LIMITSCORE /* 1 */
/*
* define that rogue should "nice()" itself
*/
#undef NICE /* 1 */
#ifdef NICE
#define FUDGE_TIME 70 /* fudge factor allowed in time for saved game*/
#else
#define FUDGE_TIME 50 /* fudge factor allowed in time for saved game*/
#endif
#undef DUMP /* 1 */ /* dump core rather than catch the signal */
#undef NOCHECKACCESS /* 1 */ /* If set, then don't check time on save file */
/*
* where scorefile should live
*/
#ifndef SCOREFILE
#define SCOREFILE "/usr/games/lib/rogue_roll"
#endif
/*
* Variables for checking to make sure the system isn't too loaded
* for people to play
*/
#if u370
# define MAXUSERS 40 /* max number of users for this game */
# define MAXPROCESSES 140 /* number processes including system */
/* processes but not including gettys*/
#endif
#if uts
# define MAXUSERS 45 /* max number of users for this game */
# define MAXPROCESSES 150 /* number processes including system */
/* processes but not including gettys*/
#endif
#if vax
# define MAXUSERS 17 /* max number of users for this game */
# define MAXPROCESSES 85 /* number processes including system */
/* processes but not including gettys*/
#endif
#if u3b
# define MAXUSERS 14 /* max number of users for this game */
# define MAXPROCESSES 75 /* number processes including system */
/* processes but not including gettys*/
#endif
#undef MAXUSERS
#undef MAXPROCESSES
#undef CHECKTIME /* 15 *//* number of minutes between load checks */
/* if not defined checks are only on startup */
#define UTMP "/etc/utmp" /* where utmp file lives */
/*
* define the current author user id of the program for "special handling"
*/
#ifndef AUTHOR
#define AUTHOR 0
#endif

725
arogue7/main.c Normal file
View file

@ -0,0 +1,725 @@
/*
* main.c - setup code
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "curses.h"
#include <signal.h>
#ifdef BSD
#include <sys/time.h>
#else
#include <time.h>
#endif
#include "mach_dep.h"
#include "network.h"
#include "rogue.h"
#ifdef PC7300
#include "sys/window.h"
#include <ctype.h>
extern struct uwdata wdata, oldwin;
extern char oldtext[WTXTNUM][WTXTLEN];
#endif
main(argc, argv, envp)
char **argv;
char **envp;
{
register char *env;
int lowtime;
time_t now;
#ifdef PC7300
int hardwindow; /* Do we have a hardware window? */
#endif
md_init();
/*
* get home and options from environment
*/
strncpy(home, md_gethomedir(), LINELEN);
/* Get default save file */
strcpy(file_name, home);
strcat(file_name, "arogue77.sav");
/* Get default score file */
strcpy(score_file, md_getroguedir());
if (*score_file)
strcat(score_file,"/");
strcat(score_file,"arogue77.scr");
if ((env = getenv("ROGUEOPTS")) != NULL)
parse_opts(env);
if (whoami[0] == '\0')
strucpy(whoami, md_getusername(), strlen(md_getusername()));
/*
* check for print-score option
*/
if (argc == 2 && strcmp(argv[1], "-s") == 0)
{
waswizard = TRUE;
score(0, SCOREIT, 0);
exit(0);
}
#ifdef NUMNET
/*
* Check for a network update
*/
if (argc == 2 && strcmp(argv[1], "-u") == 0) {
unsigned long netread();
int errcheck, errors = 0;
unsigned long amount;
short monster;
/* Read in the amount and monster values to pass to score */
amount = netread(&errcheck, sizeof(unsigned long), stdin);
if (errcheck) errors++;
monster = (short) netread(&errcheck, sizeof(short), stdin);
if (errcheck) errors++;
/* Now do the update if there were no errors */
if (errors) exit(1);
else {
score(amount, UPDATE, monster);
exit(0);
}
}
#endif
#ifdef WIZARD
/*
* Check to see if he is a wizard
*/
if (argc >= 2 && argv[1][0] == '\0')
if (strcmp(PASSWD, md_crypt(md_getpass("Wizard's password: "), "mT")) == 0)
{
wizard = TRUE;
argv++;
argc--;
}
#endif
if (!wizard && !author() && !holiday()) {
printf("Sorry, %s, but you can't play during working hours.\n", whoami);
printf("Try again later.\n");
exit(1);
}
if (!wizard && !author() && too_much()) {
printf("Sorry, %s, but the system is too loaded now.\n", whoami);
printf("Try again later.\n");
exit(1);
}
#if NICE
if (!wizard)
nice(19); /* nice the max amount */
#endif
if (argc == 2)
if (!restore(argv[1], envp)) /* Note: restore will never return */
exit(1);
lowtime = (int) time(&now);
dnum = (wizard && getenv("SEED") != NULL ?
atoi(getenv("SEED")) :
lowtime + getpid());
if (wizard)
printf("Hello %s, welcome to dungeon #%d", whoami, dnum);
else
printf("Hello %s, just a moment while I dig the dungeon...", whoami);
fflush(stdout);
seed = dnum;
md_srand(seed);
#ifdef PC7300
/* Store static window parameters */
hardwindow = ioctl(0, WIOCGETD, &wdata);
if (hardwindow >= 0) { /* We have a hardware window */
extern char **environ;
/* Make sure our window is the right size */
oldwin = wdata;
if ((wdata.uw_height / wdata.uw_vs) < 23 ||
(wdata.uw_width / wdata.uw_hs) < 75) {
wdata.uw_width = 80 * wdata.uw_hs;
wdata.uw_height = 24 * wdata.uw_vs;
wdata.uw_x = 0;
wdata.uw_y = wdata.uw_vs;
wdata.uw_uflags = NBORDER;
/* Make the change */
if (ioctl(1, WIOCSETD, &wdata) >= 0 && environ) {
char **eptr, *tptr, *nptr, *newenv, *lptr = 0, *cptr = 0;
int i, nlines = -1, ncols = -1, nlindig = 0, ncoldig = 0;
struct utdata labelbuf;
/* Save and change window-associated text */
for (i=0; i<WTXTNUM; i++) {
labelbuf.ut_num = i;
ioctl(1, WIOCGETTEXT, &labelbuf);
strncpy(oldtext[i], labelbuf.ut_text, WTXTLEN - 1);
if (*labelbuf.ut_text) {
*labelbuf.ut_text = '\0';
ioctl(1, WIOCSETTEXT, &labelbuf);
}
}
labelbuf.ut_num = WTXTLABEL;
strcpy(labelbuf.ut_text, "Advanced Rogue");
ioctl(1, WIOCSETTEXT, &labelbuf);
/* We have to change the TERMCAP entry */
eptr = environ;
while (*eptr) {
if (strncmp(*eptr, "TERMCAP=", 8) == 0) break;
else eptr++;
}
/* We found a TERMCAP entry */
if (*eptr) {
/* Search for li# and co# */
tptr = *eptr;
while (*tptr) {
switch (*tptr) {
case 'l':
if (nlines == -1 &&
strncmp(tptr, "li#", 3) == 0) {
tptr += 3;
lptr = tptr;
lines = atoi(tptr);
while (isdigit(*tptr)) {
nlindig++;;
tptr++;
}
}
else tptr++;
break;
case 'c':
if (ncols == -1 &&
strncmp(tptr, "co#", 3) == 0) {
tptr += 3;
cptr = tptr;
cols = atoi(tptr);
while (isdigit(*tptr)) {
ncoldig++;
tptr++;
}
}
else tptr++;
break;
default:
tptr++;
}
}
/* Change the entry */
if (ncoldig != 2 || nlindig != 2) {
int length;
/* Add in difference in num lengths plus NULL */
length = strlen(*eptr) - ncoldig - nlindig + 5;
if (ncoldig == 0) length += 4; /* For :co# */
if (nlindig == 0) length += 4; /* For :li# */
newenv = malloc(length);
tptr = *eptr;
nptr = newenv;
if (nlindig == 0 || ncoldig == 0) {
/* Copy up to the first : */
while (*tptr && *tptr != ':') *nptr++ = *tptr++;
/* Do we have to add a field? */
if (nlindig == 0) {
strcpy(nptr, ":li#24");
nptr += 6;
}
if (ncoldig == 0) {
strcpy(nptr, ":co#80");
nptr += 6;
}
}
while (*tptr) {
if (tptr == lptr) {
strcpy(nptr, "24");
nptr += 2;
tptr += nlindig;
}
else if (tptr == cptr) {
strcpy(nptr, "80");
nptr += 2;
tptr += ncoldig;
}
else *nptr++ = *tptr++;
}
*nptr = '\0';
/* Replace the old one */
free(*eptr);
*eptr = newenv;
}
else {
/* Just overwrite the old numbers */
*lptr++ = '2';
*lptr = '4';
*cptr++ = '8';
*cptr = '0';
}
}
}
}
}
#endif
init_things(); /* Set up probabilities of things */
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 */
init_names(); /* Set up names of scrolls */
init_misc(); /* Set up miscellaneous magic */
init_foods(); /* set up the food table */
cols = COLS;
lines = LINES;
if (cols > 85) cols = 85;
if (lines > 24) lines = 24;
if (lines < 23 || cols < 75) { /* give player a break if larger font used */
printf("\nERROR: screen size too small for rogue\n");
byebye(0);
}
/*
* Now that we have cols and lines, we can update our window
* structure for non-hardware windows.
*/
#ifdef PC7300
if (hardwindow < 0) {
wdata.uw_x = 0;
wdata.uw_y = 0;
wdata.uw_width = COLS;
wdata.uw_height = LINES;
wdata.uw_uflags = 0;
wdata.uw_hs = 1;
wdata.uw_vs = 1;
wdata.uw_baseline = 0;
}
#endif
setup();
/*
* Set up windows
*/
cw = newwin(lines, cols, 0, 0);
mw = newwin(lines, cols, 0, 0);
hw = newwin(lines, cols, 0, 0);
msgw = newwin(4, cols, 0, 0);
keypad(cw,TRUE);
keypad(msgw,TRUE);
init_player(); /* Roll up the rogue */
waswizard = wizard;
#ifdef WIZARD
/* A super wizard doesn't have to get equipped */
if (wizard && strcmp(getenv("SUPER"),"YES") == 0) {
level = 1;
new_level(NORMLEV);
}
else
#endif
new_level(STARTLEV); /* Draw current level */
/*
* Start up daemons and fuses
*/
daemon(doctor, &player, AFTER);
fuse(swander, 0, WANDERTIME, AFTER);
if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_RANGER)
fuse(spell_recovery, 0, SPELLTIME, AFTER);
if (player.t_ctype == C_DRUID || player.t_ctype == C_RANGER)
fuse(chant_recovery, 0, SPELLTIME, AFTER);
if (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN)
fuse(prayer_recovery, 0, SPELLTIME, AFTER);
daemon(stomach, 0, AFTER);
if (player.t_ctype == C_THIEF ||
player.t_ctype == C_ASSASIN ||
player.t_ctype == C_MONK)
daemon(trap_look, 0, AFTER);
/* Does this character have any special knowledge? */
switch (player.t_ctype) {
case C_ASSASIN:
/* Assassins automatically recognize poison */
p_know[P_POISON] = TRUE;
}
/* Choose a quest item */
quest_item = rnd(MAXRELIC);
draw(cw);
msg("You have been quested to retrieve the %s....",
rel_magic[quest_item].mi_name);
mpos = 0;
playit();
}
/*
* endit:
* Exit the program abnormally.
*/
void
endit(sig)
int sig;
{
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);
draw(stdscr);
endwin();
#ifdef PC7300
endhardwin();
#endif
printf("\n"); /* So the curser doesn't stop at the end of the line */
exit(0);
}
/*
* rnd:
* Pick a very random number.
*/
rnd(range)
register int range;
{
return(range <= 0 ? 0 : md_rand() % 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;
}
# ifdef SIGTSTP
/*
* handle stop and start signals
*/
void
tstp(sig)
int sig;
{
mvcur(0, cols - 1, lines - 1, 0);
endwin();
fflush(stdout);
kill(0, SIGTSTP);
signal(SIGTSTP, tstp);
raw();
noecho();
keypad(cw,1);
keypad(msgw,1);
clearok(curscr, TRUE);
touchwin(cw);
draw(cw);
md_flushinp();
}
# endif
setup()
{
#ifdef CHECKTIME
int checkout();
if (!author()) {
signal(SIGALRM, checkout);
alarm(CHECKTIME * 60);
}
#endif
/*
#ifndef DUMP
signal(SIGILL, bugkill);
#ifdef SIGTRAP
signal(SIGTRAP, bugkill);
#endif
#ifdef SIGIOT
signal(SIGIOT, bugkill);
#endif
#ifdef SIGEMT
signal(SIGEMT, bugkill);
#endif
signal(SIGFPE, bugkill);
#ifdef SIGBUS
signal(SIGBUS, bugkill);
#endif
signal(SIGSEGV, bugkill);
#ifdef SIGSYS
signal(SIGSYS, bugkill);
#endif
#ifdef SIGPIPE
signal(SIGPIPE, bugkill);
#endif
#endif
*/
#ifdef SIGTSTP
signal(SIGTSTP, tstp);
#endif
#ifdef SIGHUP
signal(SIGHUP, auto_save);
#endif
signal(SIGTERM, auto_save);
signal(SIGINT, quit);
#ifdef SIGQUIT
signal(SIGQUIT, endit);
#endif
raw(); /* Cbreak mode */
noecho(); /* Echo off */
}
/*
* 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;
/*
* parse environment declaration of options
*/
if ((opts = getenv("ROGUEOPTS")) != NULL)
parse_opts(opts);
player.t_oldpos = hero;
oldrp = roomin(&hero);
after = TRUE;
command(); /* Command execution */
endit(0);
}
/*
* see if the system is being used too much for this game
*/
too_much()
{
#if MAXPROCESSES
if (loadav() > MAXPROCESSES)
return(TRUE);
#endif
#if MAXUSERS
if (ucount() > MAXUSERS)
return(TRUE);
#endif
return(FALSE);
}
/*
* author:
* See if a user is an author of the program
*/
author()
{
switch (md_getuid()) {
#if AUTHOR
case AUTHOR:
#endif
case 0: /* always OK for root to play */
return TRUE;
default:
return FALSE;
}
}
#if CHECKTIME
static int num_checks = 0; /* times we've gone over in checkout() */
checkout()
{
static char *msgs[] = {
"The system is too loaded for games. Please leave in %d minutes",
"Please save your game. You have %d minutes",
"This is your last chance. You had better leave in %d minutes",
};
int checktime;
signal(SIGALRM, checkout);
if (!holiday() && !author()) {
msg("Game time is over. Your game is being saved.\n\n");
auto_save(); /* NO RETURN */
}
if (too_much()) {
if (num_checks >= 3)
fatal("You didn't listen, so now you are DEAD !!\n");
checktime = CHECKTIME / (num_checks + 1);
chmsg(msgs[num_checks++], checktime);
alarm(checktime * 60);
}
else {
if (num_checks) {
chmsg("The load has dropped. You have a reprieve.");
num_checks = 0;
}
alarm(CHECKTIME * 60);
}
}
/*
* 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);
}
#endif
#ifdef MAXPROCESSES
#include <fcntl.h>
loadav()
{
char *sarcmd = "sar -v | cut -c17-20 | tail -2";
char *gettycmd = "grep getty /etc/inittab | wc -l";
char sysbuffer[BUFSIZ];
char tempfile[50];
char inbuf[BUFSIZ];
int fd, nprocess, ngetty;
sprintf(tempfile, "/tmp/rg%d", getpid());
sprintf(sysbuffer, "%s > %s", sarcmd, tempfile);
if (system(sysbuffer) != 0) {
debug ("system() call failed");
return (MAXPROCESSES - 1);
}
if ((fd = open(tempfile, O_RDONLY)) == -1) {
debug ("open() call failed");
return (MAXPROCESSES - 1);
}
if (read(fd, inbuf, BUFSIZ) == -1) {
debug ("read() call failed");
return (MAXPROCESSES - 1);
}
close(fd);
sscanf(inbuf, "%d", &nprocess);
sprintf(sysbuffer, "%s > %s", gettycmd, tempfile);
if (system(sysbuffer) != 0) {
debug ("system() call failed");
return (MAXPROCESSES - 1);
}
if ((fd = open(tempfile, O_RDONLY)) == -1) {
debug ("open() call failed");
return (MAXPROCESSES - 1);
}
if (read(fd, inbuf, BUFSIZ) == -1) {
debug ("read() call failed");
return (MAXPROCESSES - 1);
}
close(fd);
sscanf(inbuf, "%d", &ngetty);
unlink(tempfile);
return(nprocess - ngetty);
}
#endif
#ifdef MAXUSERS
/*
* ucount:
* Count the number of people on the system
*/
#include <sys/types.h>
#include <utmp.h>
struct utmp buf;
ucount()
{
reg struct utmp *up;
reg FILE *utmp;
reg int count;
if ((utmp = fopen(UTMP, "r")) == NULL)
return 0;
up = &buf;
count = 0;
while (fread(up, 1, sizeof (*up), utmp) > 0)
#ifdef BSD
if (buf.ut_line[0] == 't') /* On a tty */
#else
if (buf.ut_type == USER_PROCESS)
#endif
count++;
fclose(utmp);
return count;
}
#endif
/*
* holiday:
* Returns TRUE when it is a good time to play rogue
*/
holiday()
{
#ifdef CHECKTIME
long now;
struct tm *localtime();
reg struct tm *ntime;
time(&now); /* get the current time */
ntime = localtime(&now);
if(ntime->tm_wday == 0 || ntime->tm_wday == 6)
return TRUE; /* OK on Sat & Sun */
if(ntime->tm_hour < 8 || ntime->tm_hour >= 18)
return TRUE; /* OK before 8AM & after 6PM */
if(ntime->tm_yday <= 7 || ntime->tm_yday >= 350)
return TRUE; /* OK during Christmas */
return FALSE; /* All other times are bad */
#else
return TRUE;
#endif
}

368
arogue7/maze.c Normal file
View file

@ -0,0 +1,368 @@
/*
* maze.c - functions for dealing with mazes
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "curses.h"
#include <stdlib.h>
#include "rogue.h"
struct cell {
char y_pos;
char x_pos;
};
struct bordercells {
char num_pos; /* number of frontier cells next to you */
struct cell conn[4]; /* the y,x position of above cell */
} border_cells;
static char *frontier,
*bits;
static int maze_lines,
maze_cols;
char *moffset(),
*foffset();
/*
* crankout:
* Does actual drawing of maze to window
*/
crankout()
{
reg int x, y;
for (y = 0; y < lines - 3; y++) {
move(y + 1, 0);
for (x = 0; x < cols - 1; x++) {
if (*moffset(y, x)) { /* here is a wall */
if(y==0 || y==lines-4) /* top or bottom line */
addch('-');
else if(x==0 || x==cols-2) /* left | right side */
addch('|');
else if (y % 2 == 0 && x % 2 == 0) {
if(*moffset(y, x-1) || *moffset(y, x+1))
addch('-');
else
addch('|');
}
else if (y % 2 == 0)
addch('-');
else
addch('|');
}
else
addch(FLOOR);
}
}
}
/*
* domaze:
* Draw the maze on this level.
*/
do_maze()
{
reg int least;
reg struct room *rp;
reg struct linked_list *item;
reg struct object *obj;
int cnt;
bool treas;
coord tp;
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) {
rp->r_flags = ISGONE; /* kill all rooms */
rp->r_fires = NULL; /* no fires */
}
rp = &rooms[0]; /* point to only room */
rp->r_flags = ISDARK; /* mazes always dark */
rp->r_pos.x = 0; /* room fills whole screen */
rp->r_pos.y = 1;
rp->r_max.x = cols - 1;
rp->r_max.y = lines - 3;
draw_maze(); /* put maze into window */
/*
* add some gold to make it worth looking for
*/
item = spec_item(GOLD, NULL, NULL, NULL);
obj = OBJPTR(item);
obj->o_count *= (rnd(5) + 5); /* add in one large hunk */
attach(lvl_obj, item);
cnt = 0;
do {
rnd_pos(rp, &tp);
} until (mvinch(tp.y, tp.x) == FLOOR || cnt++ > 5000);
mvaddch(tp.y, tp.x, GOLD);
obj->o_pos = tp;
/*
* add in some food to make sure he has enough
*/
item = spec_item(FOOD, NULL, NULL, NULL);
obj = OBJPTR(item);
attach(lvl_obj, item);
do {
rnd_pos(rp, &tp);
} until (mvinch(tp.y, tp.x) == FLOOR || cnt++ > 5000);
mvaddch(tp.y, tp.x, FOOD);
obj->o_pos = tp;
if (rnd(100) < 40) { /* treasure type maze */
treas = TRUE;
least = 10;
debug("treasure maze");
}
else { /* normal maze level */
least = 5;
treas = FALSE;
}
genmonsters(least, treas);
}
/*
* draw_maze:
* Generate and draw the maze on the screen
*/
draw_maze()
{
reg int i, j, more;
reg char *ptr;
maze_lines = (lines - 3) / 2;
maze_cols = (cols - 1) / 2;
bits = ALLOC((lines - 3) * (cols - 1));
frontier = ALLOC(maze_lines * maze_cols);
ptr = frontier;
while (ptr < (frontier + (maze_lines * maze_cols)))
*ptr++ = TRUE;
for (i = 0; i < lines - 3; i++) {
for (j = 0; j < cols - 1; j++) {
if (i % 2 == 1 && j % 2 == 1)
*moffset(i, j) = FALSE; /* floor */
else
*moffset(i, j) = TRUE; /* wall */
}
}
for (i = 0; i < maze_lines; i++) {
for (j = 0; j < maze_cols; j++) {
do
more = findcells(i,j);
while(more != 0);
}
}
crankout();
FREE(frontier);
FREE(bits);
}
/*
* findcells:
* Figure out cells to open up
*/
findcells(y,x)
reg int x, y;
{
reg int rtpos, i;
*foffset(y, x) = FALSE;
border_cells.num_pos = 0;
if (y < maze_lines - 1) { /* look below */
if (*foffset(y + 1, x)) {
border_cells.conn[border_cells.num_pos].y_pos = y + 1;
border_cells.conn[border_cells.num_pos].x_pos = x;
border_cells.num_pos += 1;
}
}
if (y > 0) { /* look above */
if (*foffset(y - 1, x)) {
border_cells.conn[border_cells.num_pos].y_pos = y - 1;
border_cells.conn[border_cells.num_pos].x_pos = x;
border_cells.num_pos += 1;
}
}
if (x < maze_cols - 1) { /* look right */
if (*foffset(y, x + 1)) {
border_cells.conn[border_cells.num_pos].y_pos = y;
border_cells.conn[border_cells.num_pos].x_pos = x + 1;
border_cells.num_pos += 1;
}
}
if (x > 0) { /* look left */
if (*foffset(y, x - 1)) {
border_cells.conn[border_cells.num_pos].y_pos = y;
border_cells.conn[border_cells.num_pos].x_pos = x - 1;
border_cells.num_pos += 1;
}
}
if (border_cells.num_pos == 0) /* no neighbors available */
return 0;
else {
i = rnd(border_cells.num_pos);
rtpos = border_cells.num_pos - 1;
rmwall(border_cells.conn[i].y_pos, border_cells.conn[i].x_pos, y, x);
return rtpos;
}
}
/*
* foffset:
* Calculate memory address for frontier
*/
char *
foffset(y, x)
int y, x;
{
return (frontier + (y * maze_cols) + x);
}
/*
* Maze_view:
* Returns true if the player can see the specified location within
* the confines of a maze (within one column or row)
*/
bool
maze_view(y, x)
int y, x;
{
register int start, goal, delta, ycheck, xcheck, absy, absx, see_radius;
register bool row;
/* Get the absolute value of y and x differences */
absy = hero.y - y;
absx = hero.x - x;
if (absy < 0) absy = -absy;
if (absx < 0) absx = -absx;
/* If we are standing in a wall, we can see a bit more */
switch (winat(hero.y, hero.x)) {
case '|':
case '-':
case WALL:
case SECRETDOOR:
case DOOR:
see_radius = 2;
otherwise:
see_radius = 1;
}
/* Must be within one or two rows or columns */
if (absy > see_radius && absx > see_radius) return(FALSE);
if (absx > see_radius) { /* Go along row */
start = hero.x;
goal = x;
ycheck = hero.y;
row = TRUE;
}
else { /* Go along column */
start = hero.y;
goal = y;
xcheck = hero.x;
row = FALSE;
}
if (start <= goal) delta = 1;
else delta = -1;
/* Start one past where we are standing */
if (start != goal) start += delta;
/* If we are in a wall, we want to look in the area outside the wall */
if (see_radius > 1) {
if (row) {
/* See if above us it okay first */
switch (winat(ycheck, start)) {
case '|':
case '-':
case WALL:
case DOOR:
case SECRETDOOR:
/* No good, try one up */
if (y > hero.y) ycheck++;
else ycheck--;
otherwise:
see_radius = 1; /* Just look straight over the row */
}
}
else {
/* See if above us it okay first */
switch (winat(start, xcheck)) {
case '|':
case '-':
case WALL:
case DOOR:
case SECRETDOOR:
/* No good, try one over */
if (x > hero.x) xcheck++;
else xcheck--;
otherwise:
see_radius = 1; /* Just look straight up the column */
}
}
}
/* Check boundary again */
if (absy > see_radius && absx > see_radius) return(FALSE);
while (start != goal) {
if (row) xcheck = start;
else ycheck = start;
switch (winat(ycheck, xcheck)) {
case '|':
case '-':
case WALL:
case DOOR:
case SECRETDOOR:
return(FALSE);
}
start += delta;
}
return(TRUE);
}
/*
* moffset:
* Calculate memory address for bits
*/
char *
moffset(y, x)
int y, x;
{
return (bits + (y * (cols - 1)) + x);
}
/*
* rmwall:
* Removes appropriate walls from the maze
*/
rmwall(newy, newx, oldy, oldx)
int newy, newx, oldy, oldx;
{
reg int xdif,ydif;
xdif = newx - oldx;
ydif = newy - oldy;
*moffset((oldy * 2) + ydif + 1, (oldx * 2) + xdif + 1) = FALSE;
findcells(newy, newx);
}

1195
arogue7/mdport.c Normal file

File diff suppressed because it is too large Load diff

1202
arogue7/misc.c Normal file

File diff suppressed because it is too large Load diff

827
arogue7/monsters.c Normal file
View file

@ -0,0 +1,827 @@
/*
* monsters.c - File with various monster functions in it
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* File with various monster functions in it
*
*/
#include "curses.h"
#include "rogue.h"
#include <ctype.h>
/*
* Check_residue takes care of any effect of the monster
*/
check_residue(tp)
register struct thing *tp;
{
/*
* Take care of special abilities
*/
if (on(*tp, DIDHOLD) && (--hold_count == 0)) {
turn_off(player, ISHELD);
turn_off(*tp, DIDHOLD);
}
/* If frightened of this monster, stop */
if (on(player, ISFLEE) &&
player.t_dest == &tp->t_pos) turn_off(player, ISFLEE);
/* If monster was suffocating player, stop it */
if (on(*tp, DIDSUFFOCATE)) {
extinguish(suffocate);
turn_off(*tp, DIDSUFFOCATE);
}
/* If something with fire, may darken */
if (on(*tp, HASFIRE)) {
register struct room *rp=roomin(&tp->t_pos);
register struct linked_list *fire_item;
if (rp) {
for (fire_item = rp->r_fires; fire_item != NULL;
fire_item = next(fire_item)) {
if (THINGPTR(fire_item) == tp) {
detach(rp->r_fires, fire_item);
destroy_item(fire_item);
if (rp->r_fires == NULL) {
rp->r_flags &= ~HASFIRE;
if (cansee(tp->t_pos.y, tp->t_pos.x)) light(&hero);
}
break;
}
}
}
}
}
/*
* Creat_mons creates the specified monster -- any if 0
*/
bool
creat_mons(person, monster, report)
struct thing *person; /* Where to create next to */
short monster;
bool report;
{
struct linked_list *nitem;
register struct thing *tp;
struct room *rp;
coord *mp;
if (levtype == POSTLEV)
return(FALSE);
if ((mp = fallpos(&(person->t_pos), FALSE, 2)) != NULL) {
nitem = new_item(sizeof (struct thing));
new_monster(nitem,
monster == 0 ? randmonster(FALSE, FALSE)
: monster,
mp,
TRUE);
tp = THINGPTR(nitem);
runto(tp, &hero);
carry_obj(tp, monsters[tp->t_index].m_carry/2); /* only half chance */
/* since it just got here, it is disoriented */
tp->t_no_move = 2 * movement(tp);
if (on(*tp, HASFIRE)) {
rp = roomin(&tp->t_pos);
if (rp) {
register struct linked_list *fire_item;
/* Put the new fellow in the room list */
fire_item = creat_item();
ldata(fire_item) = (char *) tp;
attach(rp->r_fires, fire_item);
rp->r_flags |= HASFIRE;
}
}
/*
* If we can see this monster, set oldch to ' ' to make light()
* think the creature used to be invisible (ie. not seen here)
*/
if (cansee(tp->t_pos.y, tp->t_pos.x)) tp->t_oldch = ' ';
return(TRUE);
}
if (report) msg("You hear a faint cry of anguish in the distance.");
return(FALSE);
}
/*
* Genmonsters:
* Generate at least 'least' monsters for this single room level.
* 'Treas' indicates whether this is a "treasure" level.
*/
void
genmonsters(least, treas)
register int least;
bool treas;
{
reg int i;
reg struct room *rp = &rooms[0];
reg struct linked_list *item;
reg struct thing *mp;
coord tp;
for (i = 0; i < level + least; i++) {
if (!treas && rnd(100) < 50) /* put in some little buggers */
continue;
/*
* Put the monster in
*/
item = new_item(sizeof *mp);
mp = THINGPTR(item);
do {
rnd_pos(rp, &tp);
} until(mvwinch(stdscr, tp.y, tp.x) == FLOOR);
new_monster(item, randmonster(FALSE, FALSE), &tp, FALSE);
/*
* See if we want to give it a treasure to carry around.
*/
carry_obj(mp, monsters[mp->t_index].m_carry);
/* Calculate a movement rate */
mp->t_no_move = movement(mp);
/* Is it going to give us some light? */
if (on(*mp, HASFIRE)) {
register struct linked_list *fire_item;
fire_item = creat_item();
ldata(fire_item) = (char *) mp;
attach(rp->r_fires, fire_item);
rp->r_flags |= HASFIRE;
}
}
}
/*
* id_monst returns the index of the monster given its letter
*/
short
id_monst(monster)
register char monster;
{
register short result;
result = NLEVMONS*vlevel;
if (result > NUMMONST) result = NUMMONST;
for(; result>0; result--)
if (monsters[result].m_appear == monster) return(result);
for (result=(NLEVMONS*vlevel)+1; result <= NUMMONST; result++)
if (monsters[result].m_appear == monster) return(result);
return(0);
}
/*
* new_monster:
* Pick a new monster and add it to the list
*/
new_monster(item, type, cp, max_monster)
struct linked_list *item;
short type;
coord *cp;
bool max_monster;
{
register struct thing *tp;
register struct monster *mp;
register char *ip, *hitp;
register int i, min_intel, max_intel;
register int num_dice, num_sides=8, num_extra=0;
char *strchr();
attach(mlist, item);
tp = THINGPTR(item);
tp->t_pack = NULL;
tp->t_index = type;
tp->t_wasshot = FALSE;
tp->t_type = monsters[type].m_appear;
tp->t_ctype = C_MONSTER;
tp->t_action = A_NIL;
tp->t_doorgoal = 0;
tp->t_quiet = 0;
tp->t_dest = NULL;
tp->t_name = NULL;
tp->t_pos = tp->t_oldpos = *cp;
tp->t_oldch = CCHAR( mvwinch(cw, cp->y, cp->x) );
mvwaddch(mw, cp->y, cp->x, tp->t_type);
mp = &monsters[tp->t_index];
/* Figure out monster's hit points */
hitp = mp->m_stats.s_hpt;
num_dice = atoi(hitp);
if ((hitp = strchr(hitp, 'd')) != NULL) {
num_sides = atoi(++hitp);
if ((hitp = strchr(hitp, '+')) != NULL)
num_extra = atoi(++hitp);
}
tp->t_stats.s_lvladj = 0;
tp->t_stats.s_lvl = mp->m_stats.s_lvl;
tp->t_stats.s_arm = mp->m_stats.s_arm;
strncpy(tp->t_stats.s_dmg, mp->m_stats.s_dmg, sizeof(tp->t_stats.s_dmg));
tp->t_stats.s_str = mp->m_stats.s_str;
tp->t_stats.s_dext = mp->m_stats.s_dex;
tp->t_movement = mp->m_stats.s_move;
if (vlevel > HARDER) { /* the deeper, the meaner we get */
tp->t_stats.s_lvl += (vlevel - HARDER);
num_dice += (vlevel - HARDER)/2;
tp->t_stats.s_arm -= (vlevel - HARDER) / 4;
}
if (max_monster)
tp->t_stats.s_hpt = num_dice * num_sides + num_extra;
else
tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra;
tp->t_stats.s_exp = mp->m_stats.s_exp + mp->m_add_exp*tp->t_stats.s_hpt;
/*
* just initailize others values to something reasonable for now
* maybe someday will *really* put these in monster table
*/
tp->t_stats.s_wisdom = 8 + rnd(4);
tp->t_stats.s_const = 8 + rnd(4);
tp->t_stats.s_charisma = 8 + rnd(4);
/* Set the initial flags */
for (i=0; i<16; i++) tp->t_flags[i] = 0;
for (i=0; i<MAXFLAGS; i++)
turn_on(*tp, mp->m_flags[i]);
/*
* these are the base chances that a creatures will do something
* assuming it can. These are(or can be) modified at runtime
* based on what the creature experiences
*/
tp->t_breathe = 75; /* base chance of breathing */
tp->t_artifact = 90; /* base chance of using artifact */
tp->t_summon = 40; /* base chance of summoning */
tp->t_cast = 75; /* base chance of casting a spell */
tp->t_wand = on(*tp, ISUNIQUE) ? 35 : 50; /* base chance of using wands */
/* suprising monsters don't always surprise you */
if (!max_monster && on(*tp, CANSURPRISE) &&
off(*tp, ISUNIQUE) && rnd(100) < 20)
turn_off(*tp, CANSURPRISE);
/* If this monster is unique, gen it */
if (on(*tp, ISUNIQUE)) mp->m_normal = FALSE;
/*
* If it is the quartermaster, then compute his level and exp pts
* based on the level. This will make it fair when thieves try to
* steal and give them reasonable experience if they succeed.
* Then fill his pack with his wares.
*/
if (on(*tp, CANSELL)) {
tp->t_stats.s_exp = vlevel * 100;
tp->t_stats.s_lvl = vlevel/2 + 1;
make_sell_pack(tp);
}
/* Normally scared monsters have a chance to not be scared */
if (on(*tp, ISFLEE) && (rnd(4) == 0)) turn_off(*tp, ISFLEE);
/* Figure intelligence */
min_intel = atoi(mp->m_intel);
if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL)
tp->t_stats.s_intel = min_intel;
else {
max_intel = atoi(++ip);
if (max_monster)
tp->t_stats.s_intel = max_intel;
else
tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel);
}
if (vlevel > HARDER)
tp->t_stats.s_intel += ((vlevel - HARDER)/2);
tp->maxstats = tp->t_stats;
/* If the monster can shoot, it may have a weapon */
if (on(*tp, CANSHOOT) && ((rnd(100) < (22 + vlevel)) || max_monster)) {
struct linked_list *item1;
register struct object *cur, *cur1;
item = new_item(sizeof *cur);
item1 = new_item(sizeof *cur1);
cur = OBJPTR(item);
cur1 = OBJPTR(item1);
cur->o_hplus = (rnd(4) < 3) ? 0
: (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
cur->o_dplus = (rnd(4) < 3) ? 0
: (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
cur1->o_hplus = (rnd(4) < 3) ? 0
: (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
cur1->o_dplus = (rnd(4) < 3) ? 0
: (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
strncpy(cur->o_damage, "0d0", sizeof(cur->o_damage));
strncpy(cur->o_hurldmg, "0d0", sizeof(cur->o_hurldmg));
strncpy(cur1->o_damage, "0d0", sizeof(cur1->o_damage));
strncpy(cur1->o_hurldmg, "0d0", sizeof(cur1->o_hurldmg));
cur->o_ac = cur1->o_ac = 11;
cur->o_count = cur1->o_count = 1;
cur->o_group = cur1->o_group = 0;
cur->contents = cur1->contents = NULL;
if ((cur->o_hplus <= 0) && (cur->o_dplus <= 0)) cur->o_flags = ISCURSED;
if ((cur1->o_hplus <= 0) && (cur1->o_dplus <= 0))
cur1->o_flags = ISCURSED;
cur->o_flags = cur1->o_flags = 0;
cur->o_type = cur1->o_type = WEAPON;
cur->o_mark[0] = cur1->o_mark[0] = '\0';
/* The monster may use a crossbow, sling, or an arrow */
i = rnd(100);
if (i < 10) {
cur->o_which = CROSSBOW;
cur1->o_which = BOLT;
init_weapon(cur, CROSSBOW);
init_weapon(cur1, BOLT);
}
else if (i < 70) {
cur->o_which = BOW;
cur1->o_which = ARROW;
init_weapon(cur, BOW);
init_weapon(cur1, ARROW);
}
else {
cur->o_which = SLING;
cur1->o_which = ROCK;
init_weapon(cur, SLING);
init_weapon(cur1, ROCK);
}
attach(tp->t_pack, item);
attach(tp->t_pack, item1);
}
/* Calculate the initial movement rate */
updpack(TRUE, tp);
tp->t_no_move = movement(tp);
if (ISWEARING(R_AGGR))
runto(tp, &hero);
if (on(*tp, ISDISGUISE))
{
char mch;
if (tp->t_pack != NULL)
mch = (OBJPTR(tp->t_pack))->o_type;
else
switch (rnd(10)) {
case 0: mch = GOLD;
when 1: mch = POTION;
when 2: mch = SCROLL;
when 3: mch = FOOD;
when 4: mch = WEAPON;
when 5: mch = ARMOR;
when 6: mch = RING;
when 7: mch = STICK;
when 8: mch = monsters[randmonster(FALSE, FALSE)].m_appear;
when 9: mch = MM;
}
tp->t_disguise = mch;
}
}
/*
* randmonster:
* Pick a monster to show up. The lower the level,
* the meaner the monster.
*/
short
randmonster(wander, no_unique)
register bool wander, no_unique;
{
register int d, cur_level, range, i;
/*
* Do we want a merchant? Merchant is always in place 'NUMMONST'
*/
if (wander && monsters[NUMMONST].m_wander && rnd(100) < pstats.s_charisma/4)
return NUMMONST;
cur_level = vlevel;
range = 4*NLEVMONS;
i = 0;
do
{
if (i++ > range*10) { /* just in case all have be genocided */
i = 0;
if (--cur_level <= 0)
fatal("Rogue could not find a monster to make");
}
d = NLEVMONS*(cur_level - 1) + (rnd(range) - (range - 1 - NLEVMONS));
if (d < 1)
d = rnd(NLEVMONS) + 1;
if (d > NUMMONST - NUMUNIQUE - 1) {
if (no_unique)
d = rnd(range) + (NUMMONST - NUMUNIQUE - 1) - (range - 1);
else if (d > NUMMONST - 1)
d = rnd(range+NUMUNIQUE) + (NUMMONST-1) - (range+NUMUNIQUE-1);
}
}
while (wander ? !monsters[d].m_wander || !monsters[d].m_normal
: !monsters[d].m_normal);
return d;
}
/* Sell displays a menu of goods from which the player may choose
* to purchase something.
*/
sell(tp)
register struct thing *tp;
{
register struct linked_list *item, *seller;
register struct linked_list *sellpack;
register struct object *obj;
register int worth, min_worth;
char buffer[LINELEN];
/*
* Get a linked_list pointer to the seller. We need this in case
* he disappears so we can set monst_dead.
*/
seller = find_mons(tp->t_pos.y, tp->t_pos.x);
sellpack = tp->t_pack;
if (sellpack == NULL) {
msg("%s looks puzzled and departs.", prname(monster_name(tp), TRUE));
/* Get rid of the monster */
killed(seller, FALSE, FALSE, FALSE);
return;
}
/* See how much the minimum pack item is worth */
min_worth = 100000;
for (item = sellpack; item != NULL; item = next(item)) {
obj = OBJPTR(item);
obj->o_flags |= ISPOST; /* Force a long description of the item */
worth = get_worth(obj);
if (worth < min_worth) min_worth = worth;
}
/* See if player can afford an item */
if (min_worth > purse) {
msg("%s eyes your small purse and departs.",
prname(monster_name(tp), TRUE));
/* Get rid of the monster */
killed(seller, FALSE, FALSE, FALSE);
return;
}
/* Announce our intentions */
msg("%s opens his pack.--More--", prname(monster_name(tp), TRUE));
wait_for(' ');
/* Try to sell something */
sprintf(buffer, "You got %d gold pieces. Buy", purse);
item = get_item(sellpack, buffer, ALL, TRUE, TRUE);
/* Get rid of the monster */
if (item != NULL) detach(tp->t_pack, item); /* Take it out of the pack */
killed(seller, FALSE, FALSE, FALSE);
if (item == NULL) return;
/* Can he afford the selected item? */
obj = OBJPTR(item);
worth = get_worth(obj);
if (worth > purse) {
msg("You cannot afford it.");
o_discard(item);
return;
}
/* Charge him through the nose */
purse -= worth;
/* If a stick or ring, let player know the type */
switch (obj->o_type) {
case RING: r_know[obj->o_which] = TRUE;
when POTION:p_know[obj->o_which] = TRUE;
when SCROLL:s_know[obj->o_which] = TRUE;
when STICK: ws_know[obj->o_which] = TRUE;
when MM: m_know[obj->o_which] = TRUE;
}
/* Remove the POST flag that we used for get_item() */
obj->o_flags &= ~ISPOST;
if (add_pack(item, FALSE, NULL) == FALSE) {
obj->o_pos = hero;
fall(item, TRUE);
}
}
/*
* what to do when the hero steps next to a monster
*/
struct linked_list *
wake_monster(y, x)
int y, x;
{
register struct thing *tp;
register struct linked_list *it;
register struct room *trp;
register char *mname;
bool nasty; /* Will the monster "attack"? */
if ((it = find_mons(y, x)) == NULL) {
msg("Wake: can't find monster in show (%d, %d)", y, x);
return (NULL);
}
tp = THINGPTR(it);
if (on(*tp, ISSTONE)) /* if stoned, don't do anything */
return it;
/*
* For now, if we are a friendly monster, we won't do any of
* our special effects.
*/
if (on(*tp, ISFRIENDLY)) return it;
trp = roomin(&tp->t_pos); /* Current room for monster */
/*
* Let greedy ones in a room guard gold
* (except in a maze where lots of creatures would all go for the
* same piece of gold)
*/
if (on(*tp, ISGREED) && off(*tp, ISRUN) &&
levtype != MAZELEV && trp != NULL &&
lvl_obj != NULL) {
register struct linked_list *item;
register struct object *cur;
for (item = lvl_obj; item != NULL; item = next(item)) {
cur = OBJPTR(item);
if ((cur->o_type == GOLD) && (roomin(&cur->o_pos) == trp)) {
/* Run to the gold */
runto(tp, &cur->o_pos);
/* Make it worth protecting */
cur->o_count += GOLDCALC + GOLDCALC;
break;
}
}
}
/*
* Every time he sees mean monster, it might start chasing him
*/
if (on(*tp, ISMEAN) &&
off(*tp, ISHELD) &&
off(*tp, ISRUN) &&
rnd(100) > 33 &&
(!is_stealth(&player) || (on(*tp, ISUNIQUE) && rnd(100) > 50)) &&
(off(player, ISINVIS) || on(*tp, CANSEE)) ||
(trp != NULL && (trp->r_flags & ISTREAS))) {
runto(tp, &hero);
}
/*
* Get the name; we don't want to do it until here because we need to
* know whether the monster is still sleeping or not.
*/
mname = monster_name(tp);
/* See if the monster will bother the player */
nasty = (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x));
/*
* if the creature is awake and can see the player and the
* player has the dreaded "eye of vecna" then see if the
* creature is turned to stone
*/
if (cur_relic[EYE_VECNA] && nasty && off(*tp, NOSTONE) &&
(off(player, ISINVIS) || on(*tp, CANSEE))) {
turn_on(*tp, NOSTONE); /* only have to save once */
if (!save(VS_PETRIFICATION, tp, -2)) {
turn_on(*tp, ISSTONE);
turn_off(*tp, ISRUN);
turn_off(*tp, ISINVIS);
turn_off(*tp, CANSURPRISE);
turn_off(*tp, ISDISGUISE);
msg("%s is turned to stone!", prname(mname, TRUE));
return it;
}
}
/*
* Handle monsters that can gaze and do things while running
* Player must be able to see the monster and the monster must
* not be asleep
*/
if (nasty && !invisible(tp)) {
/*
* Confusion
*/
if (on(*tp, CANHUH) &&
(off(*tp, ISINVIS) || on(player, CANSEE)) &&
(off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) {
if (!save(VS_MAGIC, &player, 0)) {
if (off(player, ISCLEAR)) {
if (find_slot(unconfuse))
lengthen(unconfuse, HUHDURATION);
else {
fuse(unconfuse, 0, HUHDURATION, AFTER);
msg("%s's gaze has confused you.",prname(mname, TRUE));
turn_on(player, ISHUH);
}
}
else msg("You feel dizzy for a moment, but it quickly passes.");
}
else if (rnd(100) < 67)
turn_off(*tp, CANHUH); /* Once you save, maybe that's it */
}
/* Sleep */
if(on(*tp, CANSNORE) &&
player.t_action != A_FREEZE &&
!save(VS_PARALYZATION, &player, 0)) {
if (ISWEARING(R_ALERT))
msg("You feel slightly drowsy for a moment.");
else {
msg("%s's gaze puts you to sleep.", prname(mname, TRUE));
player.t_no_move += movement(&player) * SLEEPTIME;
player.t_action = A_FREEZE;
if (rnd(100) < 50) turn_off(*tp, CANSNORE);
}
}
/* Fear */
if (on(*tp, CANFRIGHTEN) && !on(player, ISFLEE)) {
turn_off(*tp, CANFRIGHTEN);
if (!ISWEARING(R_HEROISM) &&
!save(VS_WAND, &player, -(tp->t_stats.s_lvl/10))) {
turn_on(player, ISFLEE);
player.t_dest = &tp->t_pos;
msg("The sight of %s terrifies you.", prname(mname, FALSE));
}
}
/* blinding creatures */
if(on(*tp, CANBLIND) && !find_slot(sight)) {
turn_off(*tp, CANBLIND);
if (!save(VS_WAND, &player, 0)) {
msg("The gaze of %s blinds you", prname(mname, FALSE));
turn_on(player, ISBLIND);
fuse(sight, 0, rnd(30)+20, AFTER);
light(&hero);
}
}
/* the sight of the ghost can age you! */
if (on(*tp, CANAGE)) {
turn_off (*tp, CANAGE);
if (!save(VS_MAGIC, &player, 0)) {
msg ("The sight of %s ages you!", prname(mname, FALSE));
pstats.s_const--;
max_stats.s_const--;
if (pstats.s_const < 0)
death (D_CONSTITUTION);
}
}
/* Turning to stone */
if (on(*tp, LOOKSTONE)) {
turn_off(*tp, LOOKSTONE);
if (on(player, CANINWALL))
msg("The gaze of %s has no effect.", prname(mname, FALSE));
else {
if (!save(VS_PETRIFICATION, &player, 0) && rnd(100) < 5) {
pstats.s_hpt = -1;
msg("The gaze of %s petrifies you.", prname(mname, FALSE));
msg("You are turned to stone !!! --More--");
wait_for(' ');
death(D_PETRIFY);
}
else {
msg("The gaze of %s stiffens your limbs.",
prname(mname, FALSE));
player.t_no_move += movement(&player) * STONETIME;
player.t_action = A_FREEZE;
}
}
}
}
return it;
}
/*
* wanderer:
* A wandering monster has awakened and is headed for the player
*/
wanderer()
{
register int i;
register struct room *hr = roomin(&hero);
register struct linked_list *item;
register struct thing *tp;
register long *attr; /* Points to monsters' attributes */
int carry; /* Chance of wanderer carrying anything */
short rmonst; /* Our random wanderer */
bool canteleport = FALSE, /* Can the monster teleport? */
seehim; /* Is monster within sight? */
coord cp;
rmonst = randmonster(TRUE, FALSE); /* Choose a random wanderer */
attr = &monsters[rmonst].m_flags[0]; /* Start of attributes */
for (i=0; i<MAXFLAGS; i++)
if (*attr++ == CANTELEPORT) {
canteleport = TRUE;
break;
}
/* Find a place for it -- avoid the player's room if can't teleport */
do {
do {
i = rnd_room();
} until (canteleport || hr != &rooms[i] || levtype == MAZELEV ||
levtype == OUTSIDE || levtype == POSTLEV);
/* Make sure the monster does not teleport on top of the player */
do {
rnd_pos(&rooms[i], &cp);
} while (hr == &rooms[i] && ce(cp, hero));
} until (step_ok(cp.y, cp.x, NOMONST, NULL));
/* Create a new wandering monster */
item = new_item(sizeof *tp);
new_monster(item, rmonst, &cp, FALSE);
tp = THINGPTR(item);
runto(tp, &hero);
tp->t_pos = cp; /* Assign the position to the monster */
seehim = cansee(tp->t_pos.y, tp->t_pos.x);
if (on(*tp, HASFIRE)) {
register struct room *rp;
rp = roomin(&tp->t_pos);
if (rp) {
register struct linked_list *fire_item;
fire_item = creat_item();
ldata(fire_item) = (char *) tp;
attach(rp->r_fires, fire_item);
rp->r_flags |= HASFIRE;
if (seehim && next(rp->r_fires) == NULL)
light(&hero);
}
}
/* See if we give the monster anything */
carry = monsters[tp->t_index].m_carry;
if (off(*tp, ISUNIQUE)) carry /= 2; /* Non-unique has only a half chance */
carry_obj(tp, carry);
/* Calculate its movement rate */
tp->t_no_move = movement(tp);
/* Alert the player if a monster just teleported in */
if (hr == &rooms[i] && canteleport && seehim && !invisible(tp)) {
msg("A %s just teleported in", monster_name(tp));
light(&hero);
running = FALSE;
}
if (wizard)
msg("Started a wandering %s", monster_name(tp));
}

1874
arogue7/move.c Normal file

File diff suppressed because it is too large Load diff

36
arogue7/network.h Normal file
View file

@ -0,0 +1,36 @@
/*
* network.h - networking setup
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Note that networking is set up for machines that can communicate
* via some system such as uucp. The mechanism listed here uses
* uux and assumes that the target machine allows access to the
* game via the uux command. NETCOMMAND must be defined if networking
* is desired.
*/
/* #define NETCOMMAND "uux - -n '%s!%s -u' >/dev/null 2>&1" */
/* Networking information -- should not vary among networking machines */
#define SYSLEN 9
#define LOGLEN 8
#undef NUMNET /* 1 */
struct network {
char *system;
char *rogue;
};
extern struct network Network[];
/* This system's name -- should not be defined if uname() is available */
#undef SYSTEM /* "ihesa" */

628
arogue7/new_level.c Normal file
View file

@ -0,0 +1,628 @@
/*
* new_level.c - Dig and draw a new level
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "curses.h"
#include "rogue.h"
#define TERRASAVE 3
/*
* new_level:
* Dig and draw a new level
*
*/
new_level(ltype)
LEVTYPE ltype; /* designates type of level to create */
{
register int rm, i, cnt;
register char ch;
register struct linked_list *item;
register struct thing *tp;
register struct object *obj;
int waslit = 0; /* Was the previous outside level lit? */
int starty, startx, deltay, deltax;
bool fresh=TRUE, vert, top;
struct room *rp;
struct linked_list *nitem, *savmonst=NULL, *savitems=NULL;
coord stairs;
if (wizard) {
msg("Turns: %d", turns); /* Number of turns for last level */
mpos = 0;
}
/* Start player off right */
turn_off(player, ISHELD);
turn_off(player, ISFLEE);
extinguish(suffocate);
hold_count = 0;
trap_tries = 0;
/* Are we just entering a dungeon? If so, how big is it? */
if (ltype != OUTSIDE && nfloors < 0) nfloors = HARDER+10 + rnd(11);
if (level > max_level)
max_level = level;
/* Are we starting a new outside level? */
if (ltype == OUTSIDE) {
register int i, j;
/* Save some information prior to clearing the screen */
if (level == -1 || mvinch(hero.y, hero.x) == '-') vert = TRUE;
else vert = FALSE;
if (level == -1) {
fresh = TRUE;
starty = 2;
startx = 1;
deltay = deltax = 1;
level = 0; /* Restore the level */
}
else { /* Copy several lines of the terrain to the other end */
char cch; /* Copy character */
/* Was the area dark (not magically lit)? */
if (!(rooms[0].r_flags & ISDARK)) waslit = 1;
fresh = FALSE;
if ((vert && hero.y == 1) || (!vert && hero.x == 0)) top = TRUE;
else top = FALSE;
for (i=0; i<TERRASAVE; i++) {
if (vert)
for (j=1; j<cols-1; j++) {
if (top) {
cch = CCHAR( mvinch(i+2, j) );
mvaddch(lines-6+i, j, cch);
}
else {
cch = CCHAR( mvinch(lines-4-i, j) );
mvaddch(4-i, j, cch);
}
}
else
for (j=2; j<lines-3; j++) {
if (top) {
cch = CCHAR( mvinch(j, i+1) );
mvaddch(j, cols-4+i, cch);
}
else {
cch = CCHAR( mvinch(j, cols-2-i) );
mvaddch(j, 3-i, cch);
}
}
}
if (vert) {
startx = deltax = 1;
if (top) {
starty = lines-4-TERRASAVE;
deltay = -1;
}
else {
starty = TERRASAVE + 2;
deltay = 1;
}
}
else {
starty = 2;
deltay = 1;
if (top) {
startx = cols-2-TERRASAVE;
deltax = -1;
}
else {
deltax = 1;
startx = TERRASAVE + 1;
}
}
/* Check if any monsters should be saved */
for (item = mlist; item != NULL; item = nitem) {
nitem = next(item);
tp = THINGPTR(item);
if (vert) {
if (top) {
if (tp->t_pos.y < TERRASAVE + 2)
tp->t_pos.y += lines - 5 - TERRASAVE;
else continue;
}
else {
if (tp->t_pos.y > lines - 4 - TERRASAVE)
tp->t_pos.y += 5 + TERRASAVE - lines;
else continue;
}
}
else {
if (top) {
if (tp->t_pos.x < TERRASAVE + 1)
tp->t_pos.x += cols - 2 - TERRASAVE;
else continue;
}
else {
if (tp->t_pos.x > cols - 2 - TERRASAVE)
tp->t_pos.x += 2 + TERRASAVE - cols;
else continue;
}
}
/*
* If the monster is busy chasing another monster, don't save
* it
*/
if (tp->t_dest && tp->t_dest != &hero) continue;
detach(mlist, item);
attach(savmonst, item);
}
/* Check if any treasure should be saved */
for (item = lvl_obj; item != NULL; item = nitem) {
nitem = next(item);
obj = OBJPTR(item);
if (vert) {
if (top) {
if (obj->o_pos.y < TERRASAVE + 2)
obj->o_pos.y += lines - 5 - TERRASAVE;
else continue;
}
else {
if (obj->o_pos.y > lines - 4 - TERRASAVE)
obj->o_pos.y += 5 + TERRASAVE - lines;
else continue;
}
}
else {
if (top) {
if (obj->o_pos.x < TERRASAVE + 1)
obj->o_pos.x += cols - 2 - TERRASAVE;
else continue;
}
else {
if (obj->o_pos.x > cols - 2 - TERRASAVE)
obj->o_pos.x += 2 + TERRASAVE - cols;
else continue;
}
}
detach(lvl_obj, item);
attach(savitems, item);
}
}
}
wclear(cw);
wclear(mw);
if (fresh) clear();
/*
* check to see if he missed a UNIQUE, If he did then put it back
* in the monster table for next time
*/
for (item = mlist; item != NULL; item = next(item)) {
tp = THINGPTR(item);
if (on(*tp, ISUNIQUE))
monsters[tp->t_index].m_normal = TRUE;
}
/*
* Free up the monsters on the last level
*/
t_free_list(monst_dead);
t_free_list(mlist);
o_free_list(lvl_obj); /* Free up previous objects (if any) */
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
r_free_list(rp->r_exit); /* Free up the exit lists */
levtype = ltype;
foods_this_level = 0; /* food for hero this level */
if (ltype == POSTLEV || ltype == STARTLEV) {
if (ltype == POSTLEV) do_post(FALSE); /* Trading post */
else do_post(TRUE); /* Equippage */
levtype = ltype = POSTLEV;
}
else if (ltype == MAZELEV) {
do_maze();
no_food++;
put_things(ltype); /* Place objects (if any) */
}
else if (ltype == OUTSIDE) {
init_terrain();
do_terrain(starty, startx, deltay, deltax, (bool) (fresh || !vert));
no_food++;
put_things(ltype);
/* Should we magically light this area? */
if (waslit) rooms[0].r_flags &= ~ISDARK;
}
else {
do_rooms(); /* Draw rooms */
do_passages(); /* Draw passages */
no_food++;
put_things(ltype); /* Place objects (if any) */
}
/*
* Place the staircase down. Only a small chance for an outside stairway.
*/
if (ltype != OUTSIDE || roll(1, 4) == 4) {
cnt = 0;
do {
rm = rnd_room();
rnd_pos(&rooms[rm], &stairs);
} until (mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 5000);
addch(STAIRS);
}
/*
* maybe add a trading post
*/
if (level > 5 && rnd(11) == 7 && ltype == NORMLEV) {
cnt = 0;
do {
rm = rnd_room();
if (rooms[rm].r_flags & ISTREAS)
continue;
rnd_pos(&rooms[rm], &stairs);
} until (winat(stairs.y, stairs.x) == FLOOR || cnt++ > 5000);
addch(POST);
}
if (ltype != POSTLEV) { /* Add monsters that fell through */
nitem = tlist;
while (nitem != NULL) {
item = nitem;
nitem = next(item); /* because detach and attach mess up ptrs */
tp = THINGPTR(item);
cnt = 0;
do {
rm = rnd_room();
rnd_pos(&rooms[rm], &tp->t_pos);
} until (cnt++ > 5000 || winat(tp->t_pos.y, tp->t_pos.x) == FLOOR);
mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type);
tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) );
/*
* If it has a fire, mark it
*/
if (on(*tp, HASFIRE)) {
register struct linked_list *fire_item;
fire_item = creat_item();
ldata(fire_item) = (char *) tp;
attach(rooms[rm].r_fires, fire_item);
rooms[rm].r_flags |= HASFIRE;
}
turn_off(*tp,ISELSEWHERE);
detach(tlist, item);
attach(mlist, item);
}
}
/* Restore any saved monsters */
for (item = savmonst; item != NULL; item = nitem) {
nitem = next(item);
tp = THINGPTR(item);
mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type);
tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) );
/*
* If it has a fire, mark it
*/
if (on(*tp, HASFIRE)) {
register struct linked_list *fire_item;
fire_item = creat_item();
ldata(fire_item) = (char *) tp;
attach(rooms[rm].r_fires, fire_item);
rooms[rm].r_flags |= HASFIRE;
}
detach(savmonst, item);
attach(mlist, item);
}
/* Restore any saved objects */
for(item = savitems; item != NULL; item = nitem) {
nitem = next(item);
obj = OBJPTR(item);
mvaddch(obj->o_pos.y, obj->o_pos.x, obj->o_type);
detach(savitems, item);
attach(lvl_obj, item);
}
/*
* Place the traps (except for trading post)
*/
ntraps = 0; /* No traps yet */
if (levtype == NORMLEV) {
if (rnd(10) < vlevel) {
ntraps = rnd(vlevel/4)+1;
if (ntraps > MAXTRAPS)
ntraps = MAXTRAPS;
i = ntraps;
while (i--)
{
cnt = 0;
do {
rm = rnd_room();
if (rooms[rm].r_flags & ISTREAS)
continue;
rnd_pos(&rooms[rm], &stairs);
} until (winat(stairs.y, stairs.x) == FLOOR || cnt++ > 5000);
traps[i].tr_flags = 0;
/* If we are at the bottom, we can't set a trap door */
if (level >= nfloors) ch = (char) rnd(7) + 1;
else ch = (char) rnd(8);
switch((int) ch) {
case 0: ch = TRAPDOOR;
when 1: ch = BEARTRAP;
when 2: ch = SLEEPTRAP;
when 3: ch = ARROWTRAP;
when 4: ch = TELTRAP;
when 5: ch = DARTTRAP;
when 6: ch = POOL;
traps[i].tr_flags = ISFOUND;
when 7: ch = MAZETRAP;
}
addch(ch);
traps[i].tr_type = ch;
traps[i].tr_show = FLOOR;
traps[i].tr_pos = stairs;
}
}
}
if (fresh) { /* A whole new picture */
/*
* try to find a room for the hero. The objective here is to:
*
* --> don't put him in a treasure room
* --> don't put him on an object
* --> try not to put him next to the stairs
*/
cnt = 5000;
do {
rm = rnd_room();
if (rooms[rm].r_flags & ISTREAS)
continue;
rnd_pos(&rooms[rm], &hero);
} until( cnt-- == 0 ||
(winat(hero.y, hero.x) == FLOOR &&
DISTANCE(hero.y, hero.x, stairs.y, stairs.x) > cnt/10));
}
else { /* We're extending into an adjacent outside plane */
rm = 0;
if (vert) {
if (hero.y == 1) hero.y = lines - 3 - TERRASAVE; /* Top to bottom */
else hero.y = TERRASAVE + 1; /* Bottom to top */
}
else {
if (hero.x == 0) hero.x = cols - 1 - TERRASAVE; /* Right to left */
else hero.x = TERRASAVE; /* Left to right */
}
}
oldrp = &rooms[rm]; /* Set the current room */
player.t_oldpos = player.t_pos; /* Set the current position */
if (ISWEARING(R_AGGR) ||
(cur_misc[WEAR_JEWEL] != NULL &&
cur_misc[WEAR_JEWEL]->o_which == MM_JEWEL))
aggravate(TRUE, TRUE);
/*
* If player is moving up or above his deepest point, wake up any
* non-uniques
*/
else if (level < cur_max) aggravate(FALSE, FALSE);
light(&hero);
wmove(cw, hero.y, hero.x);
waddch(cw, PLAYER);
if (level > cur_max)
cur_max = level;
status(TRUE);
/* Do we sense any food on this level? */
if (cur_relic[SURTUR_RING]) quaff(P_FFIND, NULL, NULL, FALSE);
}
/*
* Pick a room that is really there
*/
rnd_room()
{
register int rm;
if (levtype != NORMLEV)
rm = 0;
else do
{
rm = rnd(MAXROOMS);
} while (rooms[rm].r_flags & ISGONE);
return rm;
}
/*
* put_things:
* put potions and scrolls on this level
*/
put_things(ltype)
LEVTYPE ltype; /* designates type of level to create */
{
register int i, rm, cnt;
register struct object *cur;
register struct linked_list *item, *nextitem, *exitptr;
int length, width;
coord tp, *exit;
/*
* The only way to get new stuff is to go down into the dungeon.
*/
if (level <= cur_max)
return;
/*
* There is a chance that there is a treasure room on this level
*/
if (ltype != MAZELEV && rnd(HARDER) < level - 10) {
register j;
register struct room *rp;
/* Count the number of free spaces */
i = 0; /* 0 tries */
do {
rp = &rooms[rnd_room()];
width = rp->r_max.y - 2;
length = rp->r_max.x - 2;
} until ((width*length >= MAXTREAS) || (i++ > MAXROOMS*4));
/* Mark the room as a treasure room */
rp->r_flags |= ISTREAS;
/* Make all the doors secret doors */
for (exitptr = rp->r_exit; exitptr; exitptr = next(exitptr)) {
exit = DOORPTR(exitptr);
move(exit->y, exit->x);
addch(SECRETDOOR);
}
/*
* check to see if there are any monsters in room already
*/
for (item = mlist; item != NULL; item = nextitem) {
register struct thing *tp;
tp = THINGPTR(item);
nextitem = next(item);
if (rp == roomin(&tp->t_pos)) {
/*
* Don't let nice creatures be generated in a treasure
* room.
*/
if ((player.t_ctype==C_PALADIN || player.t_ctype==C_RANGER) &&
off(*tp, ISMEAN)) {
int index;
if (on(*tp, ISUNIQUE)) index = tp->t_index;
else index = -1;
/* Get rid of the monster */
killed(item, FALSE, FALSE, FALSE);
/* Restore uniques back in the table */
if (index != -1) monsters[index].m_normal = TRUE;
continue;
}
turn_on(*tp, ISMEAN);
turn_on(*tp, ISGUARDIAN);
}
}
/* Put in the monsters and treasures */
for (j=1; j<rp->r_max.y-1; j++)
for (i=1; i<rp->r_max.x-1; i++) {
coord trp;
trp.y = rp->r_pos.y+j;
trp.x = rp->r_pos.x+i;
/* Monsters */
if ((rnd(100) < (MAXTREAS*100)/(width*length)) &&
(mvwinch(mw, rp->r_pos.y+j, rp->r_pos.x+i) == ' ')) {
register struct thing *tp;
/*
* Put it there and leave it asleep. Wake the monsters
* when the player enters the room. Hopefully, all bases
* are covered as far as the ways to get in. This way
* cpu time is not wasted on the awake monsters that
* can't get to the player anyway.
* try not to put any UNIQUEs in a treasure room.
* note that they may have put put in already by the
* non-treasure room code.
* also, try not to put ISMEAN monsters in a treasure
* room as these are supposed to be non-hostile until
* attacked. It also makes life simpler for the ranger
* and paladin.
*/
while (TRUE) {
item = new_item(sizeof *tp); /* Make a monster */
tp = THINGPTR(item);
new_monster(item,randmonster(FALSE, TRUE),&trp,TRUE);
if (on(*tp, HASFIRE)) {
register struct linked_list *fire_item;
fire_item = creat_item();
ldata(fire_item) = (char *) tp;
attach(rp->r_fires, fire_item);
rp->r_flags |= HASFIRE;
}
/*
* only picky for these classes
*/
if (player.t_ctype!=C_RANGER&&player.t_ctype!=C_PALADIN)
break;
if (on(*tp, ISMEAN))
break;
killed (item, FALSE, FALSE, FALSE);
}
if (on(*tp, ISUNIQUE)) { /* just in case */
carry_obj(tp, monsters[tp->t_index].m_carry);
tp->t_no_move = movement(tp);
}
turn_on(*tp, ISGUARDIAN);
}
/* Treasures */
if ((rnd(100) < (MAXTREAS*100)/(width*length)) &&
(mvinch(rp->r_pos.y+j, rp->r_pos.x+i) == FLOOR)) {
item = new_thing(ALL, TRUE);
attach(lvl_obj, item);
cur = OBJPTR(item);
mvaddch(trp.y, trp.x, cur->o_type);
cur->o_pos = trp;
}
}
}
/*
* Do MAXOBJ attempts to put things on a level
* put more things in a maze to entice player to navigate them
*/
for (i = 0; i < MAXOBJ; i++)
if (ltype == MAZELEV || rnd(100) < 45) {
/*
* Pick a new object and link it in the list
*/
item = new_thing(ALL, TRUE);
attach(lvl_obj, item);
cur = OBJPTR(item);
/*
* Put it somewhere
*/
cnt = 0;
do {
rm = rnd_room();
rnd_pos(&rooms[rm], &tp);
} until (winat(tp.y, tp.x) == FLOOR || cnt++ > 500);
mvaddch(tp.y, tp.x, cur->o_type);
cur->o_pos = tp;
}
}

464
arogue7/options.c Normal file
View file

@ -0,0 +1,464 @@
/*
* options.c - This file has all the code for the option command
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* 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.
*
*/
#include "curses.h"
#include <ctype.h>
#include "rogue.h"
#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(),
put_abil(),
get_abil(),
get_quest(),
put_quest();
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 },
{"pickup", "Pick things up automatically: ",
(int *) &auto_pickup, put_bool, get_bool },
{"overlay", "Overlay menu: ",
(int *) &menu_overlay, put_bool, get_bool },
{"name", "Name: ",
(int *) whoami, put_str, get_str },
{"file", "Save file: ",
(int *) file_name, put_str, get_str },
{"score", "Score file: ",
(int *) score_file, put_str, get_str },
{"class", "Character class: ",
(int *)&char_type, put_abil, get_abil },
{"quest", "Quest item: ",
(int *) &quest_item, put_quest, get_quest }
};
/*
* The ability field is read-only
*/
get_abil(abil, win)
int *abil;
WINDOW *win;
{
register int oy, ox;
getyx(win, oy, ox);
put_abil(abil, win);
get_ro(win, oy, ox);
}
/*
* The quest field is read-only
*/
get_quest(quest, win)
int *quest;
WINDOW *win;
{
register int oy, ox;
getyx(win, oy, ox);
waddstr(win, rel_magic[*quest].mi_name);
get_ro(win, oy, ox);
}
/*
* get_ro:
* "Get" a read-only value.
*/
get_ro(win, oy, ox)
WINDOW *win;
register int oy, ox;
{
register int ny, nx;
register bool op_bad;
op_bad = TRUE;
getyx(win, ny, nx);
while(op_bad)
{
wmove(win, oy, ox);
draw(win);
switch (wgetch(win))
{
case '\n':
case '\r':
op_bad = FALSE;
break;
case '\033':
case '\007':
return QUIT;
case '-':
return MINUS;
default:
mvwaddstr(win, ny, nx + 5, "(no change allowed)");
}
}
wmove(win, ny, nx + 5);
wclrtoeol(win);
wmove(win, ny, nx);
waddch(win, '\n');
return NORM;
}
/*
* 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);
draw(win);
switch (wgetch(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);
wclrtoeol(win);
waddstr(win, *bp ? "True" : "False");
waddch(win, '\n');
return NORM;
}
/*
* set a string option
*/
get_str(opt, win)
register char *opt;
WINDOW *win;
{
register char *sp;
register int c, oy, ox;
char buf[LINELEN];
draw(win);
getyx(win, oy, ox);
/*
* loop reading in the string, and put it in a temporary buffer
*/
for (sp = buf;
(c = wgetch(win)) != '\n' &&
c != '\r' &&
c != '\033' &&
c != '\007' &&
sp < &buf[LINELEN-1];
wclrtoeol(win), draw(win))
{
if (c == -1)
continue;
else if (c == md_erasechar()) /* process erase character */
{
if (sp > buf)
{
register int i;
sp--;
for (i = strlen(unctrl(*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 == hw) /* To move back a line in hw */
break;
else if (c == '~')
{
strcpy(buf, home);
waddstr(win, home);
sp += strlen(home);
continue;
}
*sp++ = c;
waddstr(win, unctrl(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');
draw(win);
if (win == msgw)
mpos += (int)(sp - buf);
if (c == '-')
return MINUS;
else if (c == '\033' || c == '\007')
return QUIT;
else
return NORM;
}
/*
* print and then set options from the terminal
*/
option()
{
register OPTION *op;
register int retval;
wclear(hw);
touchwin(hw);
/*
* Display current values of options
*/
for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)
{
waddstr(hw, op->o_prompt);
(*op->o_putfunc)(op->o_opt, hw);
waddch(hw, '\n');
}
/*
* Set values
*/
wmove(hw, 0, 0);
for (op = optlist; op <= &optlist[NUM_OPTS-1]; 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, (int)(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, spacemsg);
draw(hw);
wait_for(' ');
clearok(cw, TRUE);
touchwin(cw);
after = FALSE;
}
/*
* 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 = (int)(sp - str);
/*
* Look it up and deal with it
*/
for (op = optlist; op <= &optlist[NUM_OPTS-1]; 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;
char value[LINELEN];
/*
* Skip to start of string value
*/
for (str = sp + 1; *str == '='; str++)
continue;
if (*str == '~')
{
strcpy((char *) value, home);
start = (char *) value + strlen(home);
while (*++str == '/')
continue;
}
else
start = (char *) value;
/*
* Skip to end of string value
*/
for (sp = str + 1; *sp && *sp != ','; sp++)
continue;
strucpy(start, str, sp - str);
/* Put the value into the option field */
if (op->o_putfunc != put_abil)
strcpy((char *)op->o_opt, (char *)value);
else if (*op->o_opt == -1) { /* Only init ability once */
register int len = strlen(value);
register int i;
if (isupper(value[0])) value[0] = tolower(value[0]);
for (i=0; i<NUM_CHARTYPES-1; i++) {
if (EQSTR(value, char_class[i].name, len)) {
*op->o_opt = i;
break;
}
}
}
}
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;
}
}
/*
* print the character type
*/
put_abil(ability, win)
int *ability;
WINDOW *win;
{
waddstr(win, char_class[*ability].name);
}
/*
* print out the quest
*/
put_quest(quest, win)
int *quest;
WINDOW *win;
{
waddstr(win, rel_magic[*quest].mi_name);
}
/*
* put out a boolean
*/
put_bool(b, win)
bool *b;
WINDOW *win;
{
waddstr(win, *b ? "True" : "False");
}
/*
* put out a string
*/
put_str(str, win)
char *str;
WINDOW *win;
{
waddstr(win, str);
}

213
arogue7/outside.c Normal file
View file

@ -0,0 +1,213 @@
/*
* outside.c - functions for dealing with the "outside" level
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "curses.h"
#include "rogue.h"
extern char rnd_terrain(), get_terrain();
/*
* init_terrain:
* Get the single "outside room" set up correctly
*/
void
init_terrain()
{
register struct room *rp;
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) {
rp->r_flags = ISGONE; /* kill all rooms */
rp->r_fires = NULL; /* no fires */
}
rp = &rooms[0]; /* point to only room */
rp->r_flags = ISDARK; /* outside is always dark */
rp->r_pos.x = 0; /* room fills whole screen */
rp->r_pos.y = 1;
rp->r_max.x = cols;
rp->r_max.y = lines - 3;
}
void
do_terrain(basey, basex, deltay, deltax, fresh)
int basey, basex, deltay, deltax;
bool fresh;
{
register cury, curx; /* Current y and x positions */
/* Lay out the boundary */
for (cury=1; cury<lines-2; cury++) { /* Vertical "walls" */
mvaddch(cury, 0, '|');
mvaddch(cury, cols-1, '|');
}
for (curx=0; curx<cols; curx++) { /* Horizontal "walls" */
mvaddch(1, curx, '-');
mvaddch(lines-3, curx, '-');
}
/* If we are not continuing, let's start out with a line of terrain */
if (fresh) {
char ch; /* Next char to add */
/* Move to the starting point (should be (1, 0)) */
move(basey, basex);
curx = basex;
/* Start with some random terrain */
if (basex == 0) {
ch = rnd_terrain();
addch(ch);
}
else ch = CCHAR( mvinch(basey, basex) );
curx += deltax;
/* Fill in the rest of the line */
while (curx > 0 && curx < cols-1) {
/* Put in the next piece */
ch = get_terrain(ch, '\0', '\0', '\0');
mvaddch(basey, curx, ch);
curx += deltax;
}
basey++; /* Advance to next line */
}
/* Fill in the rest of the lines */
cury = basey;
while (cury > 1 && cury < lines - 3) {
curx = basex;
while (curx > 0 && curx < cols-1) {
register char left, top_left, top, top_right;
register int left_pos, top_pos;
/* Get the surrounding terrain */
left_pos = curx - deltax;
top_pos = cury - deltay;
left = CCHAR( mvinch(cury, left_pos) );
top_left = CCHAR( mvinch(top_pos, left_pos) );
top = CCHAR( mvinch(top_pos, curx) );
top_right = CCHAR( mvinch(top_pos, curx + deltax) );
/* Put the piece of terrain on the map */
mvaddch(cury, curx, get_terrain(left, top_left, top, top_right));
/* Get the next x coordinate */
curx += deltax;
}
/* Get the next y coordinate */
cury += deltay;
}
genmonsters(5, (bool) 0);
}
/*
* do_paths:
* draw at least a single path-way through the terrain
*/
/*
* rnd_terrain:
* return a weighted, random type of outside terrain
*/
char
rnd_terrain()
{
int chance = rnd(100);
/* Forest is most likely */
if (chance < 60) return(FOREST);
/* Next comes meadow */
if (chance < 90) return(FLOOR);
/* Then comes lakes */
if (chance < 97) return(POOL);
/* Finally, mountains */
return(WALL);
}
/*
* get_terrain:
* return a terrain weighted by what is surrounding
*/
char
get_terrain(one, two, three, four)
char one, two, three, four;
{
register int i;
int forest = 0, mountain = 0, lake = 0, meadow = 0, total = 0;
char surrounding[4];
surrounding[0] = one;
surrounding[1] = two;
surrounding[2] = three;
surrounding[3] = four;
for (i=0; i<4; i++)
switch (surrounding[i]) {
case FOREST:
forest++;
total++;
when WALL:
mountain++;
total++;
when POOL:
lake++;
total++;
when FLOOR:
meadow++;
total++;
}
/* Should we continue mountain? */
if (rnd(total+1) < mountain) return(WALL);
/* Should we continue lakes? */
if (rnd(total+1) < lake) return(POOL);
/* Should we continue meadow? */
if (rnd(total+1) < meadow) return(FLOOR);
/* Should we continue forest? */
if (rnd(total+2) < forest) return(FOREST);
/* Return something random */
return(rnd_terrain());
}
/*
* lake_check:
* Determine if the player would drown
*/
void
lake_check(place)
coord *place;
{
}

1548
arogue7/pack.c Normal file

File diff suppressed because it is too large Load diff

366
arogue7/passages.c Normal file
View file

@ -0,0 +1,366 @@
/*
* passages.c - Draw the connecting passages
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Draw the connecting passages
*
* @(#)passages.c 3.4 (Berkeley) 6/15/81
*/
#include "curses.h"
#include "rogue.h"
/*
* do_passages:
* Draw all the passages on a level.
*/
do_passages()
{
register struct rdes *r1, *r2;
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 = (int)(r1 - rdes);
j = (int)(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 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 = (int)(r1 - rdes);
j = (int)(r2 - rdes);
conn(i, j);
r1->isconn[j] = TRUE;
r2->isconn[i] = TRUE;
}
}
}
/*
* conn:
* Draw a corridor from a room in a certain direction.
*/
conn(r1, r2)
int r1, r2;
{
register struct room *rpf, *rpt;
register char rmt;
register int distance, max_diag, offset, i;
register int rm;
int turns[3], turn_dist[3];
register char direc;
coord delta, curr, turn_delta, spos, epos;
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 */
delta.x = 0; /* direction of move */
delta.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);
offset = abs(spos.x - epos.x); /* how far to turn */
}
else if (direc == 'r') /* setup for moving right */
{
rmt = rm + 1;
rpt = &rooms[rmt];
delta.x = 1;
delta.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;
offset = abs(spos.y - epos.y);
}
else
debug("error in connection tables");
/*
* 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
{
cmov(spos);
addch('#');
}
if (!(rpt->r_flags & ISGONE)) door(rpt, &epos);
else
{
cmov(epos);
addch('#');
}
/* How far can we move diagonally? */
max_diag = min(distance, offset);
/*
* Decide how many turns we will have.
*/
for (i=0; i<3; i++) turn_dist[i] = 0; /* Init distances */
if (max_diag > 0) {
int nturns;
for (i=0, nturns=0; i<3; i++) {
if (rnd(3 - i + nturns) == 0) {
nturns++;
turns[i] = 0;
}
else turns[i] = -1;
}
}
else {
/* Just use a straight line (middle turn) */
turns[0] = turns[2] = -1;
turns[1] = 0;
}
/*
* Now decide how long each turn will be (for those selected above).
*/
while (max_diag > 0) {
for (i=0; i<3; i++) {
if (turns[i] >= 0 && max_diag > 0 && rnd(2) == 0) {
turn_dist[i]++;
max_diag--;
}
}
}
/*
* If we have extra offset space, add it to the straight turn.
*/
if (offset > distance) turn_dist[1] += offset - distance;
/*
* Decide where we want to make our turns.
* First calculate the offsets, then use those offsets to calculate
* the exact position relative to "distance."
*/
turns[0] = rnd(distance - turn_dist[0] - turn_dist[2]);
turns[2] = rnd(distance - turn_dist[0] - turn_dist[2] - turns[0]);
turns[1] = rnd(distance - turn_dist[0] - turn_dist[2] -
turns[0] - turns[2]);
turns[0] = distance - turns[0];
turns[1] = turns[0] - turn_dist[0] - turns[1];
turns[2] = turns[1] - turns[2];
/*
* Get ready to move...
*/
curr.x = spos.x;
curr.y = spos.y;
while (distance > 0) {
/*
* Move to next row/column
*/
curr.x += delta.x;
curr.y += delta.y;
/*
* Check if we are at a turn place; if so make a turn
*/
for (i=0; i<3; i++) {
if (distance == turns[i] && turn_dist[i] > 0) {
/*
* If this is the start of a straight path,
* we might put in a right-angle turn (33% chance).
*/
if (i == 1 && rnd(3) == 0) {
cmov(curr);
addch(PASSAGE);
}
/* Now dig the turn */
while (turn_dist[i]--) {
curr.x += turn_delta.x;
curr.y += turn_delta.y;
cmov(curr);
addch(PASSAGE);
if (i != 1) { /* A diagonal */
if (--distance > 0) {
curr.x += delta.x;
curr.y += delta.y;
}
}
}
}
}
if (distance > 0) {
/*
* Dig the passage.
*/
cmov(curr);
addch(PASSAGE);
distance--;
}
}
curr.x += delta.x;
curr.y += delta.y;
if (!ce(curr, epos))
msg("Warning, connectivity problem (%d, %d) to (%d, %d).",
curr.y, curr.x, epos.y, epos.x);
}
/*
* 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;
{
struct linked_list *newroom;
coord *exit;
cmov(*cp);
addch((rnd(10) < level - 1 && rnd(100) < 20) ? SECRETDOOR : DOOR);
/* Insert the new room into the linked list of rooms */
newroom = new_item(sizeof(coord));
exit = DOORPTR(newroom);
*exit = *cp;
attach(rm->r_exit, newroom);
}

812
arogue7/player.c Normal file
View file

@ -0,0 +1,812 @@
/*
* player.c - This file contains functions for dealing with special player
* abilities
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* This file contains functions for dealing with special player abilities
*/
#include <ctype.h>
#include "curses.h"
#include "rogue.h"
#ifdef PC7300
#include "menu.h"
#endif
/*
* affect:
* cleric affecting undead
*/
affect()
{
register struct linked_list *item;
register struct thing *tp;
register char *mname;
bool see;
coord new_pos;
int lvl;
if (!(player.t_ctype == C_CLERIC ||
(player.t_ctype == C_PALADIN && pstats.s_lvl > 4) ||
cur_relic[HEIL_ANKH] != 0)) {
msg("You cannot affect undead.");
return;
}
new_pos.y = hero.y + player.t_newpos.y;
new_pos.x = hero.x + player.t_newpos.x;
if (cansee(new_pos.y, new_pos.x)) see = TRUE;
else see = FALSE;
/* Anything there? */
if (new_pos.y < 0 || new_pos.y > lines-3 ||
new_pos.x < 0 || new_pos.x > cols-1 ||
mvwinch(mw, new_pos.y, new_pos.x) == ' ') {
msg("Nothing to affect.");
return;
}
if ((item = find_mons(new_pos.y, new_pos.x)) == NULL) {
debug("Affect what @ %d,%d?", new_pos.y, new_pos.x);
return;
}
tp = THINGPTR(item);
mname = monster_name(tp);
if (on(player, ISINVIS) && off(*tp, CANSEE)) {
msg("%s%s cannot see you", see ? "The " : "It",
see ? mname : "");
return;
}
if (off(*tp, TURNABLE) || on(*tp, WASTURNED))
goto annoy;
turn_off(*tp, TURNABLE);
lvl = pstats.s_lvl;
if (player.t_ctype == C_PALADIN && cur_relic[HEIL_ANKH] == 0) {
lvl -= 4;
}
/* Can cleric kill it? */
if (lvl >= 3 * tp->t_stats.s_lvl) {
unsigned long test; /* For overflow check */
msg("You have destroyed %s%s.", see ? "the " : "it", see ? mname : "");
test = pstats.s_exp + tp->t_stats.s_exp;
/* Be sure there is no overflow before increasing experience */
if (test > pstats.s_exp) pstats.s_exp = test;
killed(item, FALSE, TRUE, TRUE);
check_level();
return;
}
/* Can cleric turn it? */
if (rnd(100) + 1 >
(100 * ((2 * tp->t_stats.s_lvl) - lvl)) / lvl) {
unsigned long test; /* Overflow test */
/* Make the monster flee */
turn_on(*tp, WASTURNED); /* No more fleeing after this */
turn_on(*tp, ISFLEE);
runto(tp, &hero);
/* Disrupt it */
dsrpt_monster(tp, TRUE, TRUE);
/* Let player know */
msg("You have turned %s%s.", see ? "the " : "it", see ? mname : "");
/* get points for turning monster -- but check overflow first */
test = pstats.s_exp + tp->t_stats.s_exp/2;
if (test > pstats.s_exp) pstats.s_exp = test;
check_level();
/* If monster was suffocating, stop it */
if (on(*tp, DIDSUFFOCATE)) {
turn_off(*tp, DIDSUFFOCATE);
extinguish(suffocate);
}
/* If monster held us, stop it */
if (on(*tp, DIDHOLD) && (--hold_count == 0))
turn_off(player, ISHELD);
turn_off(*tp, DIDHOLD);
/* It is okay to turn tail */
tp->t_oldpos = tp->t_pos;
return;
}
/* Otherwise -- no go */
annoy:
if (see && tp->t_stats.s_intel > 16)
msg("%s laughs at you...", prname(mname, TRUE));
else
msg("You do not affect %s%s.", see ? "the " : "it", see ? mname : "");
/* Annoy monster */
if (off(*tp, ISFLEE)) runto(tp, &hero);
}
/*
* the magic user is going to try and cast a spell
*/
cast()
{
int spell_ability,
which_spell,
num_spells;
if (player.t_ctype != C_MAGICIAN && player.t_ctype != C_RANGER) {
msg("You are not permitted to cast spells.");
return;
}
spell_ability = pstats.s_lvl * pstats.s_intel;
if (player.t_ctype != C_MAGICIAN)
spell_ability /= 3;
if (player.t_action != C_CAST) {
/*
* Get the number of avilable spells
*/
num_spells = 0;
if (pstats.s_intel >= 16)
num_spells += pstats.s_intel - 15;
num_spells += pstats.s_lvl;
if (player.t_ctype != C_MAGICIAN)
num_spells /= 3;
if (num_spells > MAXSPELLS)
num_spells = MAXSPELLS;
if (num_spells < 1) {
msg("You are not allowed to cast spells yet.");
return;
}
if (pick_spell( magic_spells,
spell_ability,
num_spells,
spell_power,
"cast",
"spell"))
player.t_action = C_CAST;
return;
}
/* We've waited our required casting time. */
which_spell = player.t_selection;
player.t_selection = 0;
player.t_using = NULL;
player.t_action = A_NIL;
if ((spell_power + magic_spells[which_spell].s_cost) > spell_ability) {
msg("Your attempt fails.");
return;
}
msg("Your spell is successful.");
if (magic_spells[which_spell].s_type == TYP_POTION)
quaff( magic_spells[which_spell].s_which,
NULL,
magic_spells[which_spell].s_flag,
FALSE);
else if (magic_spells[which_spell].s_type == TYP_SCROLL)
read_scroll( magic_spells[which_spell].s_which,
magic_spells[which_spell].s_flag,
FALSE);
else if (magic_spells[which_spell].s_type == TYP_STICK) {
if (!player_zap(magic_spells[which_spell].s_which,
magic_spells[which_spell].s_flag)) {
after = FALSE;
return;
}
}
spell_power += magic_spells[which_spell].s_cost;
}
/*
* the druid asks his deity for a spell
*/
chant()
{
register int num_chants,
chant_ability,
which_chant;
which_chant = num_chants = chant_ability = 0;
if (player.t_ctype != C_DRUID && player.t_ctype != C_RANGER) {
msg("You are not permitted to chant.");
return;
}
if (cur_misc[WEAR_CLOAK] != NULL &&
cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
msg("You can't seem to chant!");
return;
}
chant_ability = pstats.s_lvl * pstats.s_wisdom;
if (player.t_ctype != C_DRUID)
chant_ability /= 3;
if (player.t_action != C_CHANT) {
num_chants = 0;
/* Get the number of avilable chants */
if (pstats.s_wisdom > 16)
num_chants = (pstats.s_wisdom - 15) / 2;
num_chants += pstats.s_lvl;
if (player.t_ctype != C_DRUID)
num_chants /= 3;
if (num_chants > MAXCHANTS)
num_chants = MAXCHANTS;
if (num_chants < 1) {
msg("You are not permitted to chant yet.");
return;
}
/* Prompt for chant */
if (pick_spell( druid_spells,
chant_ability,
num_chants,
chant_time,
"sing",
"chant"))
player.t_action = C_CHANT;
return;
}
/* We've waited our required chanting time. */
which_chant = player.t_selection;
player.t_selection = 0;
player.t_using = NULL;
player.t_action = A_NIL;
if (druid_spells[which_chant].s_cost + chant_time > chant_ability) {
msg("Your chant fails.");
return;
}
msg("Your chant has been granted.");
if (druid_spells[which_chant].s_type == TYP_POTION)
quaff( druid_spells[which_chant].s_which,
NULL,
druid_spells[which_chant].s_flag,
FALSE);
else if (druid_spells[which_chant].s_type == TYP_SCROLL)
read_scroll( druid_spells[which_chant].s_which,
druid_spells[which_chant].s_flag,
FALSE);
else if (druid_spells[which_chant].s_type == TYP_STICK) {
if (!player_zap(druid_spells[which_chant].s_which,
druid_spells[which_chant].s_flag)) {
after = FALSE;
return;
}
}
chant_time += druid_spells[which_chant].s_cost;
}
/* Constitution bonus */
const_bonus() /* Hit point adjustment for changing levels */
{
register int bonus;
if (pstats.s_const > 6 && pstats.s_const <= 14)
bonus = 0;
else if (pstats.s_const > 14)
bonus = pstats.s_const-14;
else if (pstats.s_const > 3)
bonus = -1;
else
bonus = -2;
switch(player.t_ctype) {
case C_FIGHTER: bonus = min(bonus, 11);
when C_MAGICIAN: bonus = min(bonus, 4);
when C_CLERIC: bonus = min(bonus, 4);
when C_THIEF: bonus = min(bonus, 4);
when C_RANGER: bonus = min(bonus, 6);
when C_PALADIN: bonus = min(bonus, 8);
when C_ASSASIN: bonus = min(bonus, 4);
when C_MONK: bonus = min(bonus, 6);
when C_DRUID: bonus = min(bonus, 4);
otherwise: bonus = min(bonus, 4);
}
return(bonus);
}
/* Routines for thieves */
/*
* gsense:
* Sense gold
*/
gsense()
{
/* Only thieves can do this */
if (player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) {
msg("You seem to have no gold sense.");
return;
}
read_scroll(S_GFIND, NULL, FALSE);
}
/*
* the cleric asks his deity for a spell
*/
pray()
{
register int num_prayers,
prayer_ability,
which_prayer;
which_prayer = num_prayers = prayer_ability = 0;
if (player.t_ctype != C_CLERIC &&
player.t_ctype != C_PALADIN &&
cur_relic[HEIL_ANKH] == 0) {
msg("You are not permitted to pray.");
return;
}
if (cur_misc[WEAR_CLOAK] != NULL &&
cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
msg("You can't seem to pray!");
return;
}
prayer_ability = pstats.s_lvl * pstats.s_wisdom;
if (player.t_ctype != C_CLERIC)
prayer_ability /= 3;
if (cur_relic[HEIL_ANKH]) prayer_ability *= 2;
if (player.t_action != C_PRAY) {
num_prayers = 0;
/* Get the number of avilable prayers */
if (pstats.s_wisdom > 16)
num_prayers += (pstats.s_wisdom - 15) / 2;
num_prayers += pstats.s_lvl;
if (cur_relic[HEIL_ANKH]) num_prayers += 3;
if (player.t_ctype != C_CLERIC)
num_prayers /= 3;
if (num_prayers > MAXPRAYERS)
num_prayers = MAXPRAYERS;
if (num_prayers < 1) {
msg("You are not permitted to pray yet.");
return;
}
/* Prompt for prayer */
if (pick_spell( cleric_spells,
prayer_ability,
num_prayers,
pray_time,
"offer",
"prayer"))
player.t_action = C_PRAY;
return;
}
/* We've waited our required praying time. */
which_prayer = player.t_selection;
player.t_selection = 0;
player.t_using = NULL;
player.t_action = A_NIL;
if (cleric_spells[which_prayer].s_cost + pray_time > prayer_ability) {
msg("Your prayer fails.");
return;
}
msg("Your prayer has been granted.");
if (cleric_spells[which_prayer].s_type == TYP_POTION)
quaff( cleric_spells[which_prayer].s_which,
NULL,
cleric_spells[which_prayer].s_flag,
FALSE);
else if (cleric_spells[which_prayer].s_type == TYP_SCROLL)
read_scroll( cleric_spells[which_prayer].s_which,
cleric_spells[which_prayer].s_flag,
FALSE);
else if (cleric_spells[which_prayer].s_type == TYP_STICK) {
if (!player_zap(cleric_spells[which_prayer].s_which,
cleric_spells[which_prayer].s_flag)) {
after = FALSE;
return;
}
}
pray_time += cleric_spells[which_prayer].s_cost;
}
/*
* steal:
* Steal in direction given in delta
*/
steal()
{
register struct linked_list *item;
register struct thing *tp;
register char *mname;
coord new_pos;
int thief_bonus = -50;
bool isinvisible = FALSE;
if (player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) {
msg("Only thieves and assassins can steal.");
return;
}
if (on(player, ISBLIND)) {
msg("You can't see anything.");
return;
}
new_pos.y = hero.y + player.t_newpos.y;
new_pos.x = hero.x + player.t_newpos.x;
/* Anything there? */
if (new_pos.y < 0 || new_pos.y > lines-3 ||
new_pos.x < 0 || new_pos.x > cols-1 ||
mvwinch(mw, new_pos.y, new_pos.x) == ' ') {
msg("Nothing to steal from.");
return;
}
if ((item = find_mons(new_pos.y, new_pos.x)) == NULL)
debug("Steal from what @ %d,%d?", new_pos.y, new_pos.x);
tp = THINGPTR(item);
if (on(*tp, ISSTONE)) {
msg ("You can't steal from stone!");
return;
}
if (isinvisible = invisible(tp)) mname = "creature";
else mname = monster_name(tp);
/* Can player steal something unnoticed? */
if (player.t_ctype == C_THIEF) thief_bonus = 10;
if (player.t_ctype == C_ASSASIN) thief_bonus = 0;
if (on(*tp, ISUNIQUE)) thief_bonus -= 15;
if (isinvisible) thief_bonus -= 20;
if (on(*tp, ISINWALL) && off(player, CANINWALL)) thief_bonus -= 50;
if (on(*tp, ISHELD) || tp->t_action == A_FREEZE ||
rnd(100) <
(thief_bonus + 2*dex_compute() + 5*pstats.s_lvl -
5*(tp->t_stats.s_lvl - 3))) {
register struct linked_list *s_item, *pack_ptr;
int count = 0;
unsigned long test; /* Overflow check */
s_item = NULL; /* Start stolen goods out as nothing */
/* Find a good item to take */
for (pack_ptr=tp->t_pack; pack_ptr != NULL; pack_ptr=next(pack_ptr))
if ((OBJPTR(pack_ptr))->o_type != RELIC &&
pack_ptr != tp->t_using && /* Monster can't be using it */
rnd(++count) == 0)
s_item = pack_ptr;
/*
* Find anything?
*/
if (s_item == NULL) {
msg("%s apparently has nothing to steal.", prname(mname, TRUE));
return;
}
/* Take it from monster */
if (tp->t_pack) detach(tp->t_pack, s_item);
/* Recalculate the monster's encumberance */
updpack(TRUE, tp);
/* Give it to player */
if (add_pack(s_item, FALSE, NULL) == FALSE) {
(OBJPTR(s_item))->o_pos = hero;
fall(s_item, TRUE);
}
/* Get points for stealing -- but first check for overflow */
test = pstats.s_exp + tp->t_stats.s_exp/2;
if (test > pstats.s_exp) pstats.s_exp = test;
/*
* Do adjustments if player went up a level
*/
check_level();
}
else {
msg("Your attempt fails.");
/* Annoy monster (maybe) */
if (rnd(35) >= dex_compute() + thief_bonus) {
/*
* If this is a charmed creature, there is a chance it
* will become uncharmed.
*/
if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) {
msg("The eyes of %s turn clear.", prname(mname, FALSE));
turn_off(*tp, ISCHARMED);
}
if (on(*tp, CANSELL)) {
turn_off(*tp, CANSELL);
tp->t_action = A_NIL;
tp->t_movement = 0;
if (rnd(100) < 50) /* make him steal something */
turn_on(*tp, STEALMAGIC);
else
turn_on(*tp, STEALGOLD);
if (!isinvisible)
msg("%s looks insulted.", prname(mname, TRUE));
}
runto(tp, &hero);
}
}
}
#ifdef PC7300
/* Use MAXSPELLS or whatever is the biggest number of spells/prayers/etc */
static menu_t Display; /* The menu structure */
static mitem_t Dispitems[MAXSPELLS+1]; /* Info for each line */
static char Displines[MAXSPELLS+1][LINELEN+1]; /* The lines themselves */
#endif
/*
* this routine lets the player pick the spell that they
* want to cast regardless of character class
*/
pick_spell(spells, ability, num_spells, power, prompt, type)
struct spells spells[]; /* spell list */
int ability; /* spell ability */
int num_spells; /* number of spells that can be cast */
int power; /* spell power */
char *prompt; /* prompt for spell list */
char *type; /* type of thing--> spell, prayer, chant */
{
bool nohw = FALSE;
register int i;
int curlen,
maxlen,
dummy,
which_spell,
spell_left;
#ifdef PC7300
char label[LINELEN], /* For menu label */
title[LINELEN]; /* For menu title */
#endif
if (cur_misc[WEAR_CLOAK] != NULL &&
cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
msg("You can't seem to start a %s!", type);
return(FALSE);
}
/* Prompt for spells */
msg("Which %s are you %sing? (* for list): ", type, prompt);
which_spell = (int) (readchar() - 'a');
msg(""); /* Get rid of the prompt */
if (which_spell == (int) ESCAPE - (int) 'a') {
after = FALSE;
return(FALSE);
}
if (which_spell >= 0 && which_spell < num_spells) nohw = TRUE;
else if (slow_invent) {
register char c;
nohw = TRUE;
do {
for (i=0; i<num_spells; i++) {
msg("");
mvwaddch(msgw, 0, 0, '[');
waddch(msgw, (char) ((int) 'a' + i));
wprintw(msgw, "] A %s of ", type);
if (spells[i].s_type == TYP_POTION)
waddstr(msgw, p_magic[spells[i].s_which].mi_name);
else if (spells[i].s_type == TYP_SCROLL)
waddstr(msgw, s_magic[spells[i].s_which].mi_name);
else if (spells[i].s_type == TYP_STICK)
waddstr(msgw, ws_magic[spells[i].s_which].mi_name);
waddstr(msgw, morestr);
wclrtobot(msgw);
clearok(msgw, FALSE);
draw(msgw);
do {
c = readchar();
} while (c != ' ' && c != ESCAPE);
if (c == ESCAPE)
break;
}
msg("");
wmove(msgw, 0, 0);
wprintw(msgw, "Which %s are you %sing? ", type, prompt);
clearok(msgw, FALSE);
draw(msgw);
which_spell = (int) (readchar() - 'a');
} while (which_spell != (int) (ESCAPE - 'a') &&
(which_spell < 0 || which_spell >= num_spells));
if (which_spell == (int) (ESCAPE - 'a')) {
mpos = 0;
msg("");
after = FALSE;
return(FALSE);
}
}
else {
/* Now display the possible spells */
wclear(hw);
touchwin(hw);
wmove(hw, 2, 0);
*type = toupper(*type);
wprintw(hw, " Cost %s", type);
*type = tolower(*type);
mvwaddstr(hw, 3, 0,
"-----------------------------------------------");
maxlen = 47; /* Maximum width of header */
for (i=0; i<num_spells; i++) {
sprintf(prbuf, "[%c] %3d A %s of ",
(char) ((int) 'a' + i), spells[i].s_cost, type);
if (spells[i].s_type == TYP_POTION)
strcat(prbuf, p_magic[spells[i].s_which].mi_name);
else if (spells[i].s_type == TYP_SCROLL)
strcat(prbuf, s_magic[spells[i].s_which].mi_name);
else if (spells[i].s_type == TYP_STICK)
strcat(prbuf, ws_magic[spells[i].s_which].mi_name);
mvwaddstr(hw, i+4, 0, prbuf);
/* Get the length of the line */
getyx(hw, dummy, curlen);
if (maxlen < curlen) maxlen = curlen;
#ifdef PC7300
/* Put it into the PC menu display */
strcpy(Displines[i], prbuf);
Dispitems[i].mi_name = Displines[i];
Dispitems[i].mi_flags = 0;
Dispitems[i].mi_val = i;
#endif
}
spell_left = ability - power;
if (spell_left < 0) {
spell_left = 0;
if (spell_left < -20) power = ability + 20;
}
sprintf(prbuf, "[Current %s power = %d]", type, spell_left);
mvwaddstr(hw, 0, 0, prbuf);
wprintw(hw, " Which %s are you %sing? ", type, prompt);
getyx(hw, dummy, curlen);
if (maxlen < curlen) maxlen = curlen;
#ifdef PC7300
/* Place an end marker for the items */
Dispitems[num_spells].mi_name = 0;
/* Design prompts */
sprintf(label, "Current %s power is %d", type, spell_left);
*type = toupper(*type);
sprintf(title, " Cost %s", type);
*type = tolower(*type);
sprintf(prbuf, "Select a %s or press Cancl to continue.", type);
/* Set up the main menu structure */
Display.m_label = label;
Display.m_title = title;
Display.m_prompt = prbuf;
Display.m_curptr = '\0';
Display.m_markptr = '\0';
Display.m_flags = M_ASISTITLE;
Display.m_selcnt = 1;
Display.m_items = Dispitems;
Display.m_curi = 0;
/*
* Try to display the menu. If we don't have a local terminal,
* the call will fail and we will just continue with the
* normal mode.
*/
if (menu(&Display) >= 0) {
if (Display.m_selcnt == 0) {
/* Menu was cancelled */
after = FALSE;
return FALSE; /* all done if abort */
}
else which_spell = (int) Display.m_curi->mi_val;
goto got_spell;
}
#endif
/* Should we overlay? */
if (menu_overlay && num_spells + 3 < lines / 2) {
over_win(cw, hw, num_spells + 5, maxlen + 3, 0, curlen, NULL);
}
else draw(hw);
}
if (!nohw) {
which_spell = (int) (readchar() - 'a');
while (which_spell < 0 || which_spell >= num_spells) {
if (which_spell == (int) ESCAPE - (int) 'a') {
after = FALSE;
/* Restore the screen */
touchwin(cw);
if (num_spells + 3 < lines / 2) clearok(cw, FALSE);
else clearok(cw, TRUE);
return(FALSE);
}
wmove(hw, 0, 0);
wclrtoeol(hw);
wprintw(hw, "Please enter one of the listed %ss. ", type);
getyx(hw, dummy, curlen);
if (maxlen < curlen) maxlen = curlen;
/* Should we overlay? */
if (menu_overlay && num_spells + 3 < lines / 2) {
over_win(cw, hw, num_spells + 5, maxlen + 3,
0, curlen, NULL);
}
else draw(hw);
which_spell = (int) (readchar() - 'a');
}
}
/* Now restore the screen if we have to */
if (!nohw) {
touchwin(cw);
if (num_spells + 3 < lines / 2) clearok(cw, FALSE);
else clearok(cw, TRUE);
}
#ifdef PC7300
got_spell:
#endif
if (spells[which_spell].s_type == TYP_STICK &&
need_dir(STICK, spells[which_spell].s_which)) {
if (!get_dir(&player.t_newpos)) {
after = FALSE;
return(FALSE);
}
}
player.t_selection = which_spell;
player.t_using = NULL;
player.t_no_move = (which_spell/3 + 1) * movement(&player);
return(TRUE);
}

980
arogue7/potions.c Normal file
View file

@ -0,0 +1,980 @@
/*
* potions.c - Function(s) for dealing with potions
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Function(s) for dealing with potions
*/
#include "curses.h"
#include "rogue.h"
/*
* add_abil is an array of functions used to change attributes. It must be
* ordered according to the attribute definitions in rogue.h.
*/
void (*add_abil[NUMABILITIES])() = {
add_intelligence, add_strength, add_wisdom, add_dexterity,
add_constitution, add_charisma
};
/*
* res_abil is an array of functions used to change attributes. It must be
* ordered according to the attribute definitions in rogue.h.
*/
void (*res_abil[NUMABILITIES])() = {
res_intelligence, res_strength, res_wisdom, res_dexterity,
res_constitution, res_charisma
};
/*
* Increase player's constitution
*/
void
add_constitution(change)
int change;
{
/* Do the potion */
if (change < 0) {
msg("You feel less healthy now.");
pstats.s_const += change;
if (pstats.s_const <= 0)
death(D_CONSTITUTION);
}
else {
msg("You feel healthier now.");
pstats.s_const = min(pstats.s_const + change, 25);
}
/* Adjust the maximum */
if (max_stats.s_const < pstats.s_const)
max_stats.s_const = pstats.s_const;
}
/*
* Increase player's charisma
*/
void
add_charisma(change)
int change;
{
/* Do the potion */
if (change < 0) msg("You feel less attractive now.");
else msg("You feel more attractive now.");
pstats.s_charisma += change;
if (pstats.s_charisma > 25) pstats.s_charisma = 25;
else if (pstats.s_charisma < 3) pstats.s_charisma = 3;
/* Adjust the maximum */
if (max_stats.s_charisma < pstats.s_charisma)
max_stats.s_charisma = pstats.s_charisma;
}
/*
* Increase player's dexterity
*/
void
add_dexterity(change)
int change;
{
int ring_str; /* Value of ring strengths */
/* Undo any ring changes */
ring_str = ring_value(R_ADDHIT);
pstats.s_dext -= ring_str;
/* Now do the potion */
if (change < 0) msg("You feel less dextrous now.");
else msg("You feel more dextrous now. Watch those hands!");
pstats.s_dext += change;
if (pstats.s_dext > 25) pstats.s_dext = 25;
else if (pstats.s_dext < 3) pstats.s_dext = 3;
/* Adjust the maximum */
if (max_stats.s_dext < pstats.s_dext)
max_stats.s_dext = pstats.s_dext;
/* Now put back the ring changes */
if (ring_str)
pstats.s_dext += ring_str;
}
/*
* add_haste:
* add a haste to the player
*/
add_haste(blessed)
bool blessed;
{
int hasttime;
if (player.t_ctype == C_MONK) { /* monks cannot be slowed or hasted */
msg(nothing);
return;
}
if (blessed) hasttime = HASTETIME*2;
else hasttime = HASTETIME;
if (on(player, ISSLOW)) { /* Is person slow? */
extinguish(noslow);
noslow();
if (blessed) hasttime = HASTETIME/2;
else return;
}
if (on(player, ISHASTE)) {
msg("You faint from exhaustion.");
player.t_no_move += movement(&player) * rnd(hasttime);
player.t_action = A_FREEZE;
lengthen(nohaste, roll(hasttime,hasttime));
}
else {
msg("You feel yourself moving %sfaster.", blessed ? "much " : "");
turn_on(player, ISHASTE);
fuse(nohaste, 0, roll(hasttime, hasttime), AFTER);
}
}
/*
* Increase player's intelligence
*/
void
add_intelligence(change)
int change;
{
int ring_str; /* Value of ring strengths */
/* Undo any ring changes */
ring_str = ring_value(R_ADDINTEL);
pstats.s_intel -= ring_str;
/* Now do the potion */
if (change < 0) msg("You feel slightly less intelligent now.");
else msg("You feel more intelligent now. What a mind!");
pstats.s_intel += change;
if (pstats.s_intel > 25) pstats.s_intel = 25;
else if (pstats.s_intel < 3) pstats.s_intel = 3;
/* Adjust the maximum */
if (max_stats.s_intel < pstats.s_intel)
max_stats.s_intel = pstats.s_intel;
/* Now put back the ring changes */
if (ring_str)
pstats.s_intel += ring_str;
}
/*
* this routine makes the hero move slower
*/
add_slow()
{
/* monks cannot be slowed or hasted */
if (player.t_ctype == C_MONK || ISWEARING(R_FREEDOM)) {
msg(nothing);
return;
}
if (on(player, ISHASTE)) { /* Already sped up */
extinguish(nohaste);
nohaste();
}
else {
msg("You feel yourself moving %sslower.",
on(player, ISSLOW) ? "even " : "");
if (on(player, ISSLOW))
lengthen(noslow, roll(HASTETIME,HASTETIME));
else {
turn_on(player, ISSLOW);
fuse(noslow, 0, roll(HASTETIME,HASTETIME), AFTER);
}
}
}
/*
* Increase player's strength
*/
void
add_strength(change)
int change;
{
if (change < 0) {
msg("You feel slightly weaker now.");
chg_str(change);
}
else {
msg("You feel stronger now. What bulging muscles!");
chg_str(change);
}
}
/*
* Increase player's wisdom
*/
void
add_wisdom(change)
int change;
{
int ring_str; /* Value of ring strengths */
/* Undo any ring changes */
ring_str = ring_value(R_ADDWISDOM);
pstats.s_wisdom -= ring_str;
/* Now do the potion */
if (change < 0) msg("You feel slightly less wise now.");
else msg("You feel wiser now. What a sage!");
pstats.s_wisdom += change;
if (pstats.s_wisdom > 25) pstats.s_wisdom = 25;
else if (pstats.s_wisdom < 3) pstats.s_wisdom = 3;
/* Adjust the maximum */
if (max_stats.s_wisdom < pstats.s_wisdom)
max_stats.s_wisdom = pstats.s_wisdom;
/* Now put back the ring changes */
if (ring_str)
pstats.s_wisdom += ring_str;
}
quaff(which, kind, flags, is_potion)
int which;
int kind;
int flags;
bool is_potion;
{
register struct object *obj;
register struct linked_list *item, *titem;
register struct thing *th;
bool cursed, blessed;
blessed = FALSE;
cursed = FALSE;
item = NULL;
if (which < 0) { /* figure out which ourselves */
/* This is a potion. */
if (player.t_action != C_QUAFF) {
int units;
item = get_item(pack, "quaff", QUAFFABLE, FALSE, FALSE);
/*
* Make certain that it is somethings that we want to drink
*/
if (item == NULL)
return;
/* How long does it take to quaff? */
units = usage_time(item);
if (units < 0) return;
player.t_using = item; /* Remember what it is */
player.t_no_move = units * movement(&player);
if ((OBJPTR(item))->o_type == POTION) player.t_action = C_QUAFF;
else player.t_action = C_USE;
return;
}
/* We have waited our time, let's quaff the potion */
item = player.t_using;
player.t_using = NULL;
player.t_action = A_NIL;
obj = OBJPTR(item);
/* remove it from the pack */
inpack--;
detach(pack, item);
flags = obj->o_flags;
which = obj->o_which;
kind = obj->o_kind;
}
cursed = flags & ISCURSED;
blessed = flags & ISBLESSED;
switch(which) {
case P_CLEAR:
if (cursed) {
confus_player();
}
else {
if (blessed) { /* Make player immune for the whole game */
extinguish(unclrhead); /* If we have a fuse, put it out */
msg("A strong blue aura surrounds your head.");
}
else { /* Just light a fuse for how long player is safe */
if (off(player, ISCLEAR)) {
fuse(unclrhead, 0, CLRDURATION, AFTER);
msg("A faint blue aura surrounds your head.");
}
else { /* If we have a fuse lengthen it, else we
* are permanently clear.
*/
if (find_slot(unclrhead) == 0)
msg("Your blue aura continues to glow strongly.");
else {
lengthen(unclrhead, CLRDURATION);
msg("Your blue aura brightens for a moment.");
}
}
}
turn_on(player, ISCLEAR);
/* If player is confused, unconfuse him */
if (on(player, ISHUH)) {
extinguish(unconfuse);
unconfuse();
}
}
when P_HEALING:
if (cursed) {
msg("You feel worse now.");
pstats.s_hpt -= roll(pstats.s_lvl, char_class[player.t_ctype].hit_pts);
if (pstats.s_hpt <= 0)
death(D_POISON);
}
else {
if (blessed) {
pstats.s_hpt += roll(pstats.s_lvl+1, char_class[player.t_ctype].hit_pts);
if (pstats.s_hpt > max_stats.s_hpt)
pstats.s_hpt = ++max_stats.s_hpt;
if (on(player, ISHUH)) {
extinguish(unconfuse);
unconfuse();
}
}
else {
pstats.s_hpt += roll(pstats.s_lvl+1, char_class[player.t_ctype].hit_pts/2);
if (pstats.s_hpt > max_stats.s_hpt)
pstats.s_hpt = ++max_stats.s_hpt;
}
msg("You begin to feel %sbetter.",
blessed ? "much " : "");
sight();
if (is_potion) p_know[P_HEALING] = TRUE;
}
when P_ABIL:
/* If it is cursed, we take a point away */
if (cursed) {
if (ISWEARING(R_SUSABILITY)) {
msg(nothing);
break;
}
else add_abil[kind](-1);
}
/* Otherwise we add points */
else add_abil[kind](blessed ? 3 : 1);
if (is_potion) p_know[P_ABIL] = TRUE;
when P_MFIND:
/*
* Potion of monster detection, if there are monters, detect them
*/
if (mlist != NULL)
{
register struct thing *tp;
register struct linked_list *item;
msg("You begin to sense the presence of monsters.");
wclear(hw);
for (item=mlist; item!=NULL; item=next(item)) {
tp = THINGPTR(item);
if (on(*tp, NODETECT))
continue;
if (off(*tp, ISRUN))/* turn off only on sleeping ones */
turn_off(*tp, CANSURPRISE);
mvwaddch(hw, tp->t_pos.y, tp->t_pos.x,
monsters[tp->t_index].m_appear);
}
waddstr(msgw, morestr);
clearok(msgw, FALSE);
draw(msgw);
overlay(hw, cw);
draw(cw);
wait_for(' ');
msg("");
if (is_potion) p_know[P_MFIND] = TRUE;
}
else
msg("You have a strange feeling for a moment, then it passes.");
when P_TFIND:
/*
* Potion of magic detection. Show the potions and scrolls
*/
{
register struct linked_list *mobj;
register struct object *tp;
bool show;
show = FALSE;
wclear(hw);
for (mobj = lvl_obj; mobj != NULL; mobj = next(mobj)) {
tp = OBJPTR(mobj);
if (is_magic(tp)) {
char mag_type=MAGIC;
/* Mark cursed items or bad weapons */
if ((tp->o_flags & ISCURSED) ||
(tp->o_type == WEAPON &&
(tp->o_hplus < 0 || tp->o_dplus < 0)))
mag_type = CMAGIC;
else if ((tp->o_flags & ISBLESSED) ||
(tp->o_type == WEAPON &&
(tp->o_hplus > 0 || tp->o_dplus > 0)))
mag_type = BMAGIC;
show = TRUE;
mvwaddch(hw, tp->o_pos.y, tp->o_pos.x, mag_type);
}
}
for (titem = mlist; titem != NULL; titem = next(titem)) {
register struct linked_list *pitem;
th = THINGPTR(titem);
if (on(*th, NODETECT)) continue;
for(pitem = th->t_pack; pitem != NULL; pitem = next(pitem)){
tp = OBJPTR(pitem);
if (is_magic(tp)) {
char mag_type=MAGIC;
/* Mark cursed items or bad weapons */
if ((tp->o_flags & ISCURSED) ||
(tp->o_type == WEAPON &&
(tp->o_hplus < 0 || tp->o_dplus < 0)))
mag_type = CMAGIC;
else if ((tp->o_flags & ISBLESSED) ||
(tp->o_type == WEAPON &&
(tp->o_hplus > 0 || tp->o_dplus > 0)))
mag_type = BMAGIC;
show = TRUE;
mvwaddch(hw, th->t_pos.y, th->t_pos.x, mag_type);
}
}
}
if (show) {
if (is_potion) p_know[P_TFIND] = TRUE;
msg("You sense the presence of magic on this level.");
waddstr(msgw, morestr);
clearok(msgw, FALSE);
draw(msgw);
overlay(hw,cw);
draw(cw);
wait_for(' ');
msg("");
break;
}
else
msg("You have a strange feeling for a moment, then it passes.");
}
when P_SEEINVIS:
if (cursed) {
if (!find_slot(sight))
{
msg("A cloak of darkness falls around you.");
turn_on(player, ISBLIND);
fuse(sight, 0, SEEDURATION, AFTER);
light(&hero);
}
else
lengthen(sight, SEEDURATION);
}
else {
if (off(player, CANSEE)) {
turn_on(player, CANSEE);
msg("Your eyes begin to tingle.");
fuse(unsee, 0, blessed ? SEEDURATION*3 :SEEDURATION, AFTER);
light(&hero);
}
else if (find_slot(unsee) != 0)
lengthen(unsee, blessed ? SEEDURATION*3 : SEEDURATION);
sight();
}
when P_PHASE:
if (cursed) {
msg("You can't move.");
player.t_no_move = movement(&player) * FREEZETIME;
player.t_action = A_FREEZE;
}
else {
int duration;
if (blessed) duration = 3;
else duration = 1;
if (on(player, CANINWALL))
lengthen(unphase, duration*PHASEDURATION);
else {
fuse(unphase, 0, duration*PHASEDURATION, AFTER);
turn_on(player, CANINWALL);
}
msg("You feel %slight-headed!",
blessed ? "very " : "");
}
when P_FLY: {
int duration;
bool say_message;
say_message = TRUE;
if (blessed) duration = 3;
else duration = 1;
if (on(player, ISFLY)) {
if (find_slot(land))
lengthen(land, duration*FLYTIME);
else {
msg("Nothing happens."); /* Flying by cloak */
say_message = FALSE;
}
}
else {
fuse(land, 0, duration*FLYTIME, AFTER);
turn_on(player, ISFLY);
}
if (say_message) {
if (is_potion) p_know[P_FLY] = TRUE;
msg("You feel %slighter than air!", blessed ? "much " : "");
}
}
when P_RAISE:
if (cursed) lower_level(D_POTION);
else {
msg("You suddenly feel %smore skillful",
blessed ? "much " : "");
p_know[P_RAISE] = TRUE;
raise_level();
if (blessed) raise_level();
}
when P_HASTE:
if (cursed) { /* Slow player down */
add_slow();
}
else {
add_haste(blessed);
if (is_potion) p_know[P_HASTE] = TRUE;
}
when P_RESTORE: {
register int i, howmuch, strength_tally;
msg("Hey, this tastes great. It make you feel %swarm all over.",
blessed ? "really " : "");
howmuch = blessed ? 2 : 1;
for (i=0; i<NUMABILITIES; i++) {
if (i == A_STRENGTH) {
if (lost_str) {
if (lost_str > howmuch) {
lost_str -= howmuch;
/*
* Save the lost strength. We have to set
* temporarilty set it to 0 so that res_strength
* will not restore it.
*/
strength_tally = lost_str;
lost_str = 0;
res_strength(howmuch);
lost_str = strength_tally;
}
else {
lost_str = 0;
extinguish(res_strength);
res_strength(howmuch);
}
}
else res_strength(howmuch);
}
else res_abil[i](howmuch);
}
}
when P_INVIS:
if (off(player, ISINVIS)) {
turn_on(player, ISINVIS);
msg("You have a tingling feeling all over your body");
fuse(appear, 0, blessed ? GONETIME*3 : GONETIME, AFTER);
PLAYER = IPLAYER;
light(&hero);
}
else {
if (find_slot(appear)) {
msg("Your tingling feeling surges.");
lengthen(appear, blessed ? GONETIME*3 : GONETIME);
}
else msg("Nothing happens."); /* Using cloak */
}
when P_FFIND:
{
register struct linked_list *nitem;
register struct object *nobj;
bool show;
show = FALSE;
wclear(hw);
for (nitem = lvl_obj; nitem != NULL; nitem = next(nitem)) {
nobj = OBJPTR(nitem);
if (nobj->o_type == FOOD) {
show = TRUE;
mvwaddch(hw, nobj->o_pos.y, nobj->o_pos.x, FOOD);
}
}
for (nitem = mlist; nitem != NULL; nitem = next(nitem)) {
register struct linked_list *pitem;
register struct thing *th;
th = THINGPTR(nitem);
if (on(*th, NODETECT)) continue;
for(pitem = th->t_pack; pitem != NULL; pitem = next(pitem)){
nobj = OBJPTR(pitem);
if (nobj->o_type == FOOD) {
show = TRUE;
mvwaddch(hw, th->t_pos.y, th->t_pos.x, FOOD);
}
}
}
if (show) {
if (is_potion) p_know[P_FFIND] = TRUE;
msg("Your nose tingles.");
msg("You sense the presence of food on this level.");
waddstr(msgw, morestr);
clearok(msgw, FALSE);
draw(msgw);
overlay(hw,cw);
draw(cw);
wait_for(' ');
msg("");
}
else
msg("You have a strange feeling for a moment, then it passes.");
}
when P_SKILL:
if (cursed) {
msg("You feel less skillful.");
/* Does he currently have an artifical skill? */
if (!find_slot(unskill)) { /* No skill */
pstats.s_lvladj = -2;
pstats.s_lvl += pstats.s_lvladj;
fuse(unskill, 0, SKILLDURATION, AFTER);
}
else { /* Has an artifical skill */
/* Is the skill beneficial? */
if (pstats.s_lvladj > 0) {
/* Decrease the previous skill advantage */
pstats.s_lvl -= 2;
pstats.s_lvladj -= 2;
/* If there is now a negative skill, lengthen time */
if (pstats.s_lvladj < 0)
lengthen(unskill, SKILLDURATION);
/* If there is no skill advantage, unfuse us */
else if (pstats.s_lvladj == 0) extinguish(unskill);
}
else { /* Already bad */
/* Make it a little worse, and lengthen it */
pstats.s_lvl--;
pstats.s_lvladj--;
lengthen(unskill, SKILLDURATION);
}
}
/* Is our level too low now? */
if (pstats.s_lvl < 1) death(D_POTION);
}
else {
int adjust;
msg("You feel more skillful.");
/* Get the adjustment */
adjust = blessed ? 3 : 2;
/* Does he currently have an artifical skill? */
if (!find_slot(unskill)) {
pstats.s_lvladj = adjust;
pstats.s_lvl += pstats.s_lvladj;
fuse(unskill, 0,
blessed ? SKILLDURATION*2 : SKILLDURATION, AFTER);
}
else { /* Has an artifical skill */
/* Is the skill detrimental? */
if (pstats.s_lvladj < 0) {
/* Decrease the previous skill advantage */
pstats.s_lvl += adjust;
pstats.s_lvladj += adjust;
/* If there is now a positive skill, lengthen time */
if (pstats.s_lvladj < 0)
lengthen(unskill, SKILLDURATION);
/* If there is no skill advantage, unfuse us */
else if (pstats.s_lvladj == 0) extinguish(unskill);
}
else { /* Already good */
/*
* Make the skill the maximum of the current good
* skill and what the adjust would give him.
*/
pstats.s_lvl -= pstats.s_lvladj;
pstats.s_lvladj = max(pstats.s_lvladj, adjust);
pstats.s_lvl += pstats.s_lvladj;
lengthen(unskill,
blessed ? SKILLDURATION*2 : SKILLDURATION);
}
}
}
when P_FIRE: {
int duration;
bool say_message;
say_message = TRUE;
if (blessed) duration = 3;
else duration = 1;
if (on(player, NOFIRE)) {
if (find_slot(nofire))
lengthen(nofire, duration*FIRETIME);
else {
msg("Nothing happens."); /* has on a ring */
say_message = FALSE;
}
}
else {
fuse(nofire, 0, duration*FIRETIME, AFTER);
turn_on(player, NOFIRE);
}
if (say_message) {
if (is_potion) p_know[P_FIRE] = TRUE;
msg("You feel %sfire resistant", blessed ? "very " : "");
}
}
when P_COLD: {
int duration;
bool say_message;
say_message = TRUE;
if (blessed) duration = 3;
else duration = 1;
if (on(player, NOCOLD)) {
if (find_slot(nocold))
lengthen(nocold, duration*COLDTIME);
else {
msg("Nothing happens."); /* has on a ring */
say_message = FALSE;
}
}
else {
fuse(nocold, 0, duration*COLDTIME, AFTER);
turn_on(player, NOCOLD);
}
if (say_message) {
if (is_potion) p_know[P_COLD] = TRUE;
msg("You feel %scold resistant", blessed ? "very " : "");
}
}
when P_LIGHTNING: {
int duration;
bool say_message;
say_message = TRUE;
if (blessed) duration = 3;
else duration = 1;
if (on(player, NOBOLT)) {
if (find_slot(nobolt))
lengthen(nobolt, duration*BOLTTIME);
}
else {
fuse(nobolt, 0, duration*BOLTTIME, AFTER);
turn_on(player, NOBOLT);
}
if (say_message)
msg("Your skin turns %sblue!", blessed ? "very " : "");
}
when P_POISON:
if (!save(VS_POISON, &player, -2)) {
msg("You feel very sick now.");
pstats.s_hpt /= 2;
if (!ISWEARING(R_SUSABILITY))
pstats.s_const--;
}
else {
msg("You feel sick now.");
pstats.s_hpt -= (pstats.s_hpt / 4);
}
if (pstats.s_const <= 0 || pstats.s_hpt <= 0)
death(D_POISON);
otherwise:
msg("What an odd tasting potion!");
return;
}
status(FALSE);
if (is_potion && item && p_know[which] && p_guess[which])
{
free(p_guess[which]);
p_guess[which] = NULL;
}
else if (is_potion &&
!p_know[which] &&
item &&
askme &&
(flags & ISKNOW) == 0 &&
(flags & ISPOST) == 0 &&
p_guess[which] == NULL) {
nameitem(item, FALSE);
}
if (item != NULL) o_discard(item);
updpack(TRUE, &player);
}
/*
* res_dexterity:
* Restore player's dexterity
* if called with zero the restore fully
*/
void
res_dexterity(howmuch)
int howmuch;
{
short save_max;
int ring_str;
if (howmuch < 0) return;
/* Discount the ring value */
ring_str = ring_value(R_ADDHIT);
pstats.s_dext -= ring_str;
if (pstats.s_dext < max_stats.s_dext ) {
if (howmuch == 0)
pstats.s_dext = max_stats.s_dext;
else
pstats.s_dext = min(pstats.s_dext+howmuch, max_stats.s_dext);
}
/* Redo the rings */
if (ring_str) {
save_max = max_stats.s_dext;
pstats.s_dext += ring_str;
max_stats.s_dext = save_max;
}
}
/*
* res_intelligence:
* Restore player's intelligence
*/
void
res_intelligence(howmuch)
int howmuch;
{
short save_max;
int ring_str;
if (howmuch <= 0) return;
/* Discount the ring value */
ring_str = ring_value(R_ADDINTEL);
pstats.s_intel -= ring_str;
pstats.s_intel = min(pstats.s_intel + howmuch, max_stats.s_intel);
/* Redo the rings */
if (ring_str) {
save_max = max_stats.s_intel;
pstats.s_intel += ring_str;
max_stats.s_intel = save_max;
}
}
/*
* res_wisdom:
* Restore player's wisdom
*/
void
res_wisdom(howmuch)
int howmuch;
{
short save_max;
int ring_str;
if (howmuch <= 0) return;
/* Discount the ring value */
ring_str = ring_value(R_ADDWISDOM);
pstats.s_wisdom -= ring_str;
pstats.s_wisdom = min(pstats.s_wisdom + howmuch, max_stats.s_wisdom);
/* Redo the rings */
if (ring_str) {
save_max = max_stats.s_wisdom;
pstats.s_wisdom += ring_str;
max_stats.s_wisdom = save_max;
}
}
/*
* res_constitution:
* Restore the players constitution.
*/
void
res_constitution(howmuch)
int howmuch;
{
if (howmuch > 0)
pstats.s_const = min(pstats.s_const + howmuch, max_stats.s_const);
}
/*
* res_charisma:
* Restore the players charisma.
*/
void
res_charisma(howmuch)
int howmuch;
{
if (howmuch > 0)
pstats.s_charisma =
min(pstats.s_charisma + howmuch, max_stats.s_charisma);
}

161
arogue7/rings.c Normal file
View file

@ -0,0 +1,161 @@
/*
* rings.c - routines dealing specifically with rings
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "curses.h"
#include "rogue.h"
/*
* routines dealing specifically with rings
*/
/*
* 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_VAMPREGEN:
return 3;
case R_REGEN:
return 2;
case R_HEALTH:
case R_SUSABILITY:
return 1;
case R_SEARCH:
case R_SEEINVIS:
return (rnd(100) < 33);
case R_DIGEST:
if (cur_ring[hand]->o_ac >= 0)
return (-(cur_ring[hand]->o_ac)-1);
else
return (-(cur_ring[hand]->o_ac));
}
return 0;
}
ring_on(item)
register struct linked_list *item;
{
register struct object *obj;
register int save_max;
obj = OBJPTR(item);
/*
* Calculate the effect it has on the poor guy.
*/
switch (obj->o_which)
{
case R_ADDSTR:
save_max = max_stats.s_str;
chg_str(obj->o_ac);
max_stats.s_str = save_max;
when R_ADDHIT:
pstats.s_dext += obj->o_ac;
when R_ADDINTEL:
pstats.s_intel += obj->o_ac;
when R_ADDWISDOM:
pstats.s_wisdom += obj->o_ac;
when R_SEEINVIS:
turn_on(player, CANSEE);
msg("Your eyes begin to tingle");
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
when R_AGGR:
aggravate(TRUE, TRUE);
when R_WARMTH:
turn_on(player, NOCOLD);
when R_FIRE:
turn_on(player, NOFIRE);
when R_LIGHT: {
if(roomin(&hero) != NULL) {
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
}
when R_SEARCH:
daemon(ring_search, 0, AFTER);
when R_TELEPORT:
daemon(ring_teleport, 0, AFTER);
}
status(FALSE);
if (r_know[obj->o_which] && r_guess[obj->o_which])
{
free(r_guess[obj->o_which]);
r_guess[obj->o_which] = NULL;
}
else if (!r_know[obj->o_which] &&
askme &&
(obj->o_flags & ISKNOW) == 0 &&
r_guess[obj->o_which] == NULL) {
nameitem(item, FALSE);
}
}
/*
* print ring bonuses
*/
char *
ring_num(obj)
register struct object *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:
case R_ADDINTEL:
case R_ADDWISDOM:
case R_DIGEST:
buf[0] = ' ';
strcpy(&buf[1], num(obj->o_ac, 0));
when R_AGGR:
case R_LIGHT:
case R_CARRY:
case R_TELEPORT:
if (obj->o_flags & ISCURSED)
return " cursed";
else
return "";
otherwise:
return "";
}
return buf;
}
/*
* Return the effect of the specified ring
*/
ring_value(type)
{
int result = 0;
if (ISRING(LEFT_1, type)) result += cur_ring[LEFT_1]->o_ac;
if (ISRING(LEFT_2, type)) result += cur_ring[LEFT_2]->o_ac;
if (ISRING(LEFT_3, type)) result += cur_ring[LEFT_3]->o_ac;
if (ISRING(LEFT_4, type)) result += cur_ring[LEFT_4]->o_ac;
if (ISRING(RIGHT_1, type)) result += cur_ring[RIGHT_1]->o_ac;
if (ISRING(RIGHT_2, type)) result += cur_ring[RIGHT_2]->o_ac;
if (ISRING(RIGHT_3, type)) result += cur_ring[RIGHT_3]->o_ac;
if (ISRING(RIGHT_4, type)) result += cur_ring[RIGHT_4]->o_ac;
return(result);
}

889
arogue7/rip.c Normal file
View file

@ -0,0 +1,889 @@
/*
* rip.c - File for the fun ends Death or a total win
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/* Print flags for scoring */
#define REALLIFE 1 /* Print out machine and logname */
#define EDITSCORE 2 /* Edit the current score file */
#define ADDSCORE 3 /* Add a new score */
#define NAMELEN 80
/*
* File for the fun ends
* Death or a total win
*
*/
#include "curses.h"
#ifdef BSD
#include <sys/time.h>
#else
#include <time.h>
#endif
#include <signal.h>
#include <ctype.h>
#include <sys/types.h>
#include <fcntl.h>
#include "mach_dep.h"
#include "network.h"
#include "rogue.h"
#ifdef PC7300
#include "sys/window.h"
extern struct uwdata wdata, oldwin;
extern char oldtext[WTXTNUM][WTXTLEN];
#endif
#ifdef NUMNET
/* Network machines (for mutual score keeping) */
static struct network Network[NUMNET] = {
{ "ihwpt", "/t1/michael/bin/rg" },
};
#endif
/*
* If you change this structure, change the compatibility routines
* scoreout() and scorein() to reflect the change. Also update SCORELEN.
*/
struct sc_ent {
unsigned long sc_score;
char sc_name[NAMELEN];
char sc_system[SYSLEN];
char sc_login[LOGLEN];
short sc_flags;
short sc_level;
short sc_ctype;
short sc_monster;
short sc_quest;
};
#define SCORELEN \
(sizeof(unsigned long) + NAMELEN + SYSLEN + LOGLEN + 5*sizeof(short))
static char *rip[] = {
" __________",
" / \\",
" / REST \\",
" / IN \\",
" / PEACE \\",
" / \\",
" | |",
" | |",
" | killed by |",
" | |",
" | 1984 |",
" *| * * * | *",
" ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______",
0
};
char *killname();
void
byebye(sig)
int sig;
{
if (!isendwin()) {
clear();
endwin();
}
#ifdef PC7300
endhardwin();
#endif
printf("\n");
exit(0);
}
/*
* death:
* Do something really fun when he dies
*/
death(monst)
register short monst;
{
register char **dp = rip, *killer;
register struct tm *lt;
time_t date;
char buf[LINELEN];
struct tm *localtime();
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, "%lu Points", pstats.s_exp );
mvaddstr(15, 28-((strlen(buf)+1)/2), buf);
killer = killname(monst);
mvaddstr(17, 28-((strlen(killer)+1)/2), killer);
mvaddstr(18, 26, (sprintf(prbuf, "%4d", 1900+lt->tm_year), prbuf));
move(lines-1, 0);
refresh();
score(pstats.s_exp, KILLED, monst);
endwin();
#ifdef PC7300
endhardwin();
#endif
exit(0);
}
#ifdef PC7300
/*
* Restore window characteristics on a hard window terminal (PC7300).
*/
endhardwin()
{
register int i;
struct utdata labelbuf;
/* Restore the old window size */
if (oldwin.uw_width) ioctl(1, WIOCSETD, &oldwin);
/* Restore the old window text */
for (i=0; i<WTXTNUM; i++) {
labelbuf.ut_num = i;
strcpy(labelbuf.ut_text, oldtext[i]);
ioctl(1, WIOCSETTEXT, &labelbuf);
}
}
#endif
char *
killname(monst)
register short monst;
{
static char mons_name[LINELEN];
int i;
if (monst > NUMMONST) return("a strange monster");
if (monst >= 0) {
switch (monsters[monst].m_name[0]) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
sprintf(mons_name, "an %s", monsters[monst].m_name);
break;
default:
sprintf(mons_name, "a %s", monsters[monst].m_name);
}
return(mons_name);
}
for (i = 0; i< DEATHNUM; i++) {
if (deaths[i].reason == monst)
break;
}
if (i >= DEATHNUM)
return ("strange death");
return (deaths[i].name);
}
/*
* score -- figure score and post it.
*/
/* VARARGS2 */
score(amount, flags, monst)
unsigned long amount;
short monst;
{
static struct sc_ent top_ten[NUMSCORE];
register struct sc_ent *scp;
register int i;
register struct sc_ent *sc2;
register int outfd;
register char *killer;
register int prflags = 0;
register int fd;
short upquest, wintype, uplevel, uptype; /* For network updating */
char upsystem[SYSLEN], uplogin[LOGLEN];
char *thissys; /* Holds the name of this system */
char *compatstr=NULL; /* Holds scores for writing compatible score files */
char scoreline[100];
#define REASONLEN 3
static char *reason[] = {
"killed",
"quit",
"A total winner",
"somehow left",
};
char *packend;
signal(SIGINT, byebye);
if (flags != WINNER && flags != SCOREIT && flags != UPDATE) {
if (flags == CHICKEN)
packend = "when you quit";
else
{
packend = "at your untimely demise";
mvaddstr(lines - 1, 0, retstr);
refresh();
getstr(prbuf);
}
showpack(packend);
}
purse = 0; /* Steal all the gold */
/*
* Open file and read list
*/
if ((fd = open(score_file, O_RDWR | O_CREAT, 0666)) < 0) return;
outfd = fd;
#ifndef SYSTEM
thissys = md_gethostname();
#else
thissys = SYSTEM;
#endif
for (scp = top_ten; scp <= &top_ten[NUMSCORE-1]; scp++)
{
scp->sc_score = 0L;
for (i = 0; i < NAMELEN; i++)
scp->sc_name[i] = rnd(255);
scp->sc_quest= RN;
scp->sc_flags = RN;
scp->sc_level = RN;
scp->sc_monster = RN;
scp->sc_ctype = 0;
strncpy(scp->sc_system, thissys, SYSLEN);
scp->sc_login[0] = '\0';
}
/*
* If this is a SCOREIT optin (rogue -s), don't call byebye. The
* endwin() call in byebye() will result in a core dump.
*/
if (flags == SCOREIT) signal(SIGINT, SIG_DFL);
else signal(SIGINT, byebye);
if (flags != SCOREIT && flags != UPDATE)
{
mvaddstr(lines - 1, 0, retstr);
refresh();
fflush(stdout);
getstr(prbuf);
}
/* Check for special options */
if (strcmp(prbuf, "names") == 0)
prflags = REALLIFE;
#ifdef WIZARD
else if (wizard) {
if (strcmp(prbuf, "edit") == 0) prflags = EDITSCORE;
else if (strcmp(prbuf, "add") == 0) {
prflags = ADDSCORE;
waswizard = FALSE; /* We want the new score recorded */
}
}
#endif
/* Read the score and convert it to a compatible format */
for(i = 0; i < NUMSCORE; i++)
{
encread(top_ten[i].sc_name, NAMELEN, fd);
encread(top_ten[i].sc_system, SYSLEN, fd);
encread(top_ten[i].sc_login, LOGLEN, fd);
encread(scoreline, 100, fd);
sscanf(scoreline, " %lu %hd %hd %hd %hd %hd \n",
&top_ten[i].sc_score, &top_ten[i].sc_flags,
&top_ten[i].sc_level, &top_ten[i].sc_ctype,
&top_ten[i].sc_monster, &top_ten[i].sc_quest
);
}
/* Get some values if this is an update */
if (flags == UPDATE) {
unsigned long netread();
int errcheck, errors = 0;
upquest = (short) netread(&errcheck, sizeof(short), stdin);
if (errcheck) errors++;
if (fread(whoami, 1, NAMELEN, stdin) != NAMELEN) errors++;
wintype = (short) netread(&errcheck, sizeof(short), stdin);
if (errcheck) errors++;
uplevel = (short) netread(&errcheck, sizeof(short), stdin);
if (errcheck) errors++;
uptype = (short) netread(&errcheck, sizeof(short), stdin);
if (errcheck) errors++;
if (fread(upsystem, 1, SYSLEN, stdin) != SYSLEN)
errors++;
if (fread(uplogin, 1, LOGLEN, stdin) != LOGLEN)
errors++;
if (errors) {
close(outfd);
free(compatstr);
return;
}
}
/*
* Insert player in list if need be
*/
if (!waswizard) {
char *login;
if (flags != UPDATE) {
login = md_getusername();
}
if (flags == UPDATE)
(void) update(top_ten, amount, upquest, whoami, wintype,
uplevel, monst, uptype, upsystem, uplogin);
else {
#ifdef WIZARD
if (prflags == ADDSCORE) { /* Overlay characteristic by new ones */
char buffer[LINELEN];
clear();
mvaddstr(1, 0, "Score: ");
mvaddstr(2, 0, "Quest (number): ");
mvaddstr(3, 0, "Name: ");
mvaddstr(4, 0, "System: ");
mvaddstr(5, 0, "Login: ");
mvaddstr(6, 0, "Level: ");
mvaddstr(7, 0, "Char type: ");
mvaddstr(8, 0, "Result: ");
/* Get the score */
move(1, 7);
get_str(buffer, stdscr);
amount = atol(buffer);
/* Get the character's quest -- must be a number */
move(2, 16);
get_str(buffer, stdscr);
quest_item = atoi(buffer);
/* Get the character's name */
move(3, 6);
get_str(buffer, stdscr);
strncpy(whoami, buffer, NAMELEN);
/* Get the system */
move(4, 8);
get_str(buffer, stdscr);
strncpy(thissys, buffer, SYSLEN);
/* Get the login */
move(5, 7);
get_str(buffer, stdscr);
strncpy(login, buffer, LOGLEN);
/* Get the level */
move(6, 7);
get_str(buffer, stdscr);
level = max_level = (short) atoi(buffer);
/* Get the character type */
move(7, 11);
get_str(buffer, stdscr);
for (i=0; i<NUM_CHARTYPES; i++) {
if (EQSTR(buffer, char_class[i].name, strlen(buffer)))
break;
}
player.t_ctype = i;
/* Get the win type */
move(8, 8);
get_str(buffer, stdscr);
switch (buffer[0]) {
case 'W':
case 'w':
case 'T':
case 't':
flags = WINNER;
break;
case 'Q':
case 'q':
flags = CHICKEN;
break;
case 'k':
case 'K':
default:
flags = KILLED;
break;
}
/* Get the monster if player was killed */
if (flags == KILLED) {
mvaddstr(9, 0, "Death type: ");
get_str(buffer, stdscr);
if (buffer[0] == 'M' || buffer[0] == 'm')
do {
monst = makemonster(TRUE, "Editing", "choose");
} while (monst < 0); /* Force a choice */
else monst = getdeath();
}
}
#endif
if (update(top_ten, amount, (short) quest_item, whoami, flags,
(flags == WINNER) ? (short) max_level : (short) level,
monst, player.t_ctype, thissys, login)
#ifdef NUMNET
&& fork() == 0 /* Spin off network process */
#endif
) {
#ifdef NUMNET
/* Send this update to the other systems in the network */
int i, j;
char cmd[256]; /* Command for remote execution */
FILE *rmf, *popen(); /* For input to remote command */
for (i=0; i<NUMNET; i++)
if (Network[i].system[0] != '!' &&
strcmp(Network[i].system, thissys)) {
sprintf(cmd, NETCOMMAND,
Network[i].system, Network[i].rogue);
/* Execute the command */
if ((rmf=popen(cmd, "w")) != NULL) {
unsigned long temp; /* Temporary value */
/* Write out the parameters */
(void) netwrite((unsigned long) amount,
sizeof(unsigned long), rmf);
(void) netwrite((unsigned long) monst,
sizeof(short), rmf);
(void) netwrite((unsigned long) quest_item,
sizeof(short), rmf);
(void) fwrite(whoami, 1, strlen(whoami), rmf);
for (j=strlen(whoami); j<NAMELEN; j++)
putc('\0', rmf);
(void) netwrite((unsigned long) flags,
sizeof(short), rmf);
temp = (unsigned long)
(flags==WINNER ? max_level : level);
(void) netwrite(temp, sizeof(short), rmf);
(void) netwrite((unsigned long) player.t_ctype,
sizeof(short), rmf);
(void) fwrite(thissys, 1,
strlen(thissys), rmf);
for (j=strlen(thissys); j<SYSLEN; j++)
putc('\0', rmf);
(void) fwrite(login, 1, strlen(login), rmf);
for (j=strlen(login); j<LOGLEN; j++)
putc('\0', rmf);
/* Close off the command */
(void) pclose(rmf);
}
}
_exit(0); /* Exit network process */
#endif
}
}
}
/*
* SCOREIT -- rogue -s option. Never started curses if this option.
* UPDATE -- network scoring update. Never started curses if this option.
* EDITSCORE -- want to delete or change a score.
*/
/* if (flags != SCOREIT && flags != UPDATE && prflags != EDITSCORE)
endwin(); */
if (flags != UPDATE) {
if (flags != SCOREIT) {
clear();
refresh();
endwin();
}
/*
* Print the list
*/
printf("\nTop %d Adventurers:\nRank Score\tName\n",
NUMSCORE);
for (scp = top_ten; scp <= &top_ten[NUMSCORE-1]; scp++) {
const char *class;
if (scp->sc_score != 0) {
class = char_class[scp->sc_ctype].name;
/* Make sure we have an in-bound reason */
if (scp->sc_flags > REASONLEN) scp->sc_flags = REASONLEN;
printf("%3d %10lu\t%s (%s)", scp - top_ten + 1,
scp->sc_score, scp->sc_name, class);
if (prflags == REALLIFE) printf(" [in real life %.*s!%.*s]",
SYSLEN, scp->sc_system, LOGLEN, scp->sc_login);
printf(":\n\t\t%s on level %d", reason[scp->sc_flags],
scp->sc_level);
switch (scp->sc_flags) {
case KILLED:
printf(" by");
killer = killname(scp->sc_monster);
printf(" %s", killer);
break;
case WINNER:
printf(" with the %s",
rel_magic[scp->sc_quest].mi_name);
break;
}
if (prflags == EDITSCORE)
{
fflush(stdout);
getstr(prbuf);
printf("\n");
if (prbuf[0] == 'd') {
for (sc2 = scp; sc2 < &top_ten[NUMSCORE-1]; sc2++)
*sc2 = *(sc2 + 1);
top_ten[NUMSCORE-1].sc_score = 0;
for (i = 0; i < NAMELEN; i++)
top_ten[NUMSCORE-1].sc_name[i] = rnd(255);
top_ten[NUMSCORE-1].sc_flags = RN;
top_ten[NUMSCORE-1].sc_level = RN;
top_ten[NUMSCORE-1].sc_monster = RN;
scp--;
}
else if (prbuf[0] == 'e') {
printf("Death type: ");
getstr(prbuf);
if (prbuf[0] == 'M' || prbuf[0] == 'm')
do {
scp->sc_monster =
makemonster(TRUE, "Editing", "choose");
} while (scp->sc_monster < 0); /* Force a choice */
else scp->sc_monster = getdeath();
clear();
refresh();
}
}
else printf("\n");
}
}
if ((flags != SCOREIT) && (flags != UPDATE)) {
printf("\n[Press return to exit]");
fflush(stdout);
fgets(prbuf,80,stdin);
}
/* if (prflags == EDITSCORE) endwin();*/ /* End editing windowing */
}
lseek(outfd, 0L, 0);
/*
* Update the list file
*/
for(i = 0; i < NUMSCORE; i++)
{
memset(scoreline,0,100);
encwrite(top_ten[i].sc_name, NAMELEN, outfd);
encwrite(top_ten[i].sc_system, SYSLEN, outfd);
encwrite(top_ten[i].sc_login, LOGLEN, outfd);
sprintf(scoreline, " %lu %hd %hd %hd %hd %hd \n",
top_ten[i].sc_score, top_ten[i].sc_flags,
top_ten[i].sc_level, top_ten[i].sc_ctype,
top_ten[i].sc_monster, top_ten[i].sc_quest);
encwrite(scoreline,100,outfd);
}
close(outfd);
}
/*
* scorein:
* Convert a character string that has been translated from a
* score file by scoreout() back to a score file structure.
*/
scorein(input, scores, num_bytes)
unsigned char *input;
struct sc_ent scores[];
int num_bytes; /* Number of bytes of input that we want to convert */
{
register int i, j;
unsigned long *lptr;
unsigned short *sptr;
unsigned char *cptr;
/* Convert a maximum of NUMSCORE entries */
for (i=0; num_bytes > 0 && i < NUMSCORE; num_bytes -= SCORELEN, i++) {
/* The long fields are first -- ordered low to high byte in input */
lptr = &scores[i].sc_score;
*lptr = ((unsigned long) *input++) & 0x000000ffL;
*lptr |= (((unsigned long) *input++) << 8) & 0x0000ff00L;
*lptr |= (((unsigned long) *input++) << 16) & 0x00ff0000L;
*lptr |= (((unsigned long) *input++) << 24) & 0xff000000L;
/* The short fields are next -- ordered low to high byte in input */
sptr = (unsigned short *) &scores[i].sc_flags;
*sptr = ((unsigned short) *input++) & 0xff;
*sptr |= (((unsigned short) *input++) << 8) & 0xff00;
sptr = (unsigned short *) &scores[i].sc_level;
*sptr = ((unsigned short) *input++) & 0xff;
*sptr |= (((unsigned short) *input++) << 8) & 0xff00;
sptr = (unsigned short *) &scores[i].sc_ctype;
*sptr = ((unsigned short) *input++) & 0xff;
*sptr |= (((unsigned short) *input++) << 8) & 0xff00;
sptr = (unsigned short *) &scores[i].sc_monster;
*sptr = ((unsigned short) *input++) & 0xff;
*sptr |= (((unsigned short) *input++) << 8) & 0xff00;
sptr = (unsigned short *) &scores[i].sc_quest;
*sptr = ((unsigned short) *input++) & 0xff;
*sptr |= (((unsigned short) *input++) << 8) & 0xff00;
/* Finally comes the char fields -- they're easy */
cptr = (unsigned char *) scores[i].sc_name;
for (j = 0; j < NAMELEN; j++) *cptr++ = *input++;
cptr = (unsigned char *) scores[i].sc_system;
for (j = 0; j < SYSLEN; j++) *cptr++ = *input++;
cptr = (unsigned char *) scores[i].sc_login;
for (j = 0; j < LOGLEN; j++) *cptr++ = *input++;
}
}
/*
* scoreout:
* Convert a score file structure to a character string. We do
* this for compatibility sake since some machines write out fields in
* different orders.
*/
scoreout(scores, output)
struct sc_ent scores[];
unsigned char *output;
{
register int i, j;
unsigned long *lptr;
unsigned short *sptr;
unsigned char *cptr;
for (i=0; i<NUMSCORE; i++) {
/* The long fields are first -- ordered low to high byte in input */
lptr = &scores[i].sc_score;
for (j = 0; j < sizeof(unsigned long); j++)
*output++ = (unsigned char) ((*lptr >> 8*j) & 0xff);
/* The short fields are next -- ordered low to high byte in input */
sptr = (unsigned short *) &scores[i].sc_flags;
*output++ = (unsigned char) (*sptr & 0xff);
*output++ = (unsigned char) ((*sptr >> 8) & 0xff);
sptr = (unsigned short *) &scores[i].sc_level;
*output++ = (unsigned char) (*sptr & 0xff);
*output++ = (unsigned char) ((*sptr >> 8) & 0xff);
sptr = (unsigned short *) &scores[i].sc_ctype;
*output++ = (unsigned char) (*sptr & 0xff);
*output++ = (unsigned char) ((*sptr >> 8) & 0xff);
sptr = (unsigned short *) &scores[i].sc_monster;
*output++ = (unsigned char) (*sptr & 0xff);
*output++ = (unsigned char) ((*sptr >> 8) & 0xff);
sptr = (unsigned short *) &scores[i].sc_quest;
*output++ = (unsigned char) (*sptr & 0xff);
*output++ = (unsigned char) ((*sptr >> 8) & 0xff);
/* Finally comes the char fields -- they're easy */
cptr = (unsigned char *) scores[i].sc_name;
for (j = 0; j < NAMELEN; j++) *output++ = *cptr++;
cptr = (unsigned char *) scores[i].sc_system;
for (j = 0; j < SYSLEN; j++) *output++ = *cptr++;
cptr = (unsigned char *) scores[i].sc_login;
for (j = 0; j < LOGLEN; j++) *output++ = *cptr++;
}
}
/*
* showpack:
* Display the contents of the hero's pack
*/
showpack(howso)
char *howso;
{
reg char *iname;
reg int cnt, packnum;
reg struct linked_list *item;
reg struct object *obj;
idenpack();
cnt = 1;
clear();
mvprintw(0, 0, "Contents of your pack %s:\n",howso);
packnum = 'a';
for (item = pack; item != NULL; item = next(item)) {
obj = OBJPTR(item);
iname = inv_name(obj, FALSE);
mvprintw(cnt, 0, "%c) %s\n",packnum++,iname);
if (++cnt >= lines - 2 &&
next(item) != NULL) {
cnt = 1;
mvaddstr(lines - 1, 0, morestr);
refresh();
wait_for(' ');
clear();
}
}
mvprintw(cnt + 1,0,"--- %d Gold Pieces ---",purse);
refresh();
}
total_winner()
{
register struct linked_list *item;
register struct object *obj;
register int worth;
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 appointed leader of a ");
switch (player.t_ctype) {
case C_MAGICIAN:addstr("magic user's guild.\n");
when C_FIGHTER: addstr("fighter's guild.\n");
when C_RANGER: addstr("ranger's guild.\n");
when C_CLERIC: addstr("monastery.\n");
when C_PALADIN: addstr("monastery.\n");
when C_MONK: addstr("monastery.\n");
when C_DRUID: addstr("monastery.\n");
when C_THIEF: addstr("thief's guild.\n");
when C_ASSASIN: addstr("assassin's guild.\n");
otherwise: addstr("tavern.\n");
}
mvaddstr(lines - 1, 0, spacemsg);
refresh();
wait_for(' ');
clear();
mvaddstr(0, 0, " Worth Item");
oldpurse = purse;
for (c = 'a', item = pack; item != NULL; c++, item = next(item))
{
obj = OBJPTR(item);
worth = get_worth(obj);
if (obj->o_group == 0)
worth *= obj->o_count;
whatis(item);
mvprintw(c - 'a' + 1, 0, "%c) %6d %s", c, worth, inv_name(obj, FALSE));
purse += worth;
}
mvprintw(c - 'a' + 1, 0," %5d Gold Pieces ", oldpurse);
refresh();
score(pstats.s_exp + (long) purse, WINNER, '\0');
endwin();
#ifdef PC7300
endhardwin();
#endif
exit(0);
}
update(top_ten, amount, quest, whoami, flags, level, monst, ctype, system, login)
struct sc_ent top_ten[];
unsigned long amount;
short quest, flags, level, monst, ctype;
char *whoami, *system, *login;
{
register struct sc_ent *scp, *sc2;
int retval=0; /* 1 if a change, 0 otherwise */
for (scp = top_ten; scp < &top_ten[NUMSCORE]; scp++) {
if (amount >= scp->sc_score)
break;
#ifdef LIMITSCORE /* Limits player to one entry per class per uid */
/* If this good score is the same class and uid, then forget it */
if (strncmp(scp->sc_login, login, LOGLEN) == 0 &&
scp->sc_ctype == ctype &&
strncmp(scp->sc_system, system, SYSLEN) == 0) return(0);
#endif
}
if (scp < &top_ten[NUMSCORE])
{
retval = 1;
#ifdef LIMITSCORE /* Limits player to one entry per class per uid */
/* If a lower scores exists for the same login and class, delete it */
for (sc2 = scp ;sc2 < &top_ten[NUMSCORE]; sc2++) {
if (sc2->sc_score == 0L) break; /* End of useful scores */
if (strncmp(sc2->sc_login, login, LOGLEN) == 0 &&
sc2->sc_ctype == ctype &&
strncmp(sc2->sc_system, system, SYSLEN) == 0) {
/* We want to delete this entry */
while (sc2 < &top_ten[NUMSCORE-1]) {
*sc2 = *(sc2+1);
sc2++;
}
sc2->sc_score = 0L;
}
}
#endif
for (sc2 = &top_ten[NUMSCORE-1]; sc2 > scp; sc2--)
*sc2 = *(sc2-1);
scp->sc_score = amount;
scp->sc_quest = quest;
strncpy(scp->sc_name, whoami, NAMELEN);
scp->sc_flags = flags;
scp->sc_level = level;
scp->sc_monster = monst;
scp->sc_ctype = ctype;
strncpy(scp->sc_system, system, SYSLEN);
strncpy(scp->sc_login, login, LOGLEN);
}
return(retval);
}

1689
arogue7/rogue.c Normal file

File diff suppressed because it is too large Load diff

1297
arogue7/rogue.h Normal file

File diff suppressed because it is too large Load diff

295
arogue7/rooms.c Normal file
View file

@ -0,0 +1,295 @@
/*
* rooms.c - Draw the nine rooms on the screen
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Draw the nine rooms on the screen
*
*/
#include "curses.h"
#include "rogue.h"
do_rooms()
{
register int i;
register struct room *rp;
register struct linked_list *item;
register struct thing *tp;
int left_out;
int num_monsters;
int which_monster;
int j;
coord top;
coord bsze;
coord mp;
coord *np;
/*
* bsze is the maximum room size
*/
bsze.x = cols/3;
bsze.y = (lines-2)/3;
/*
* Clear things for a new level
*/
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) {
rp->r_flags = 0;
rp->r_fires = NULL;
}
/*
* 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++)
{
bool has_gold=FALSE;
/*
* Find upper left corner of box that this room goes in
*/
top.x = (i%3)*bsze.x;
top.y = i/3*bsze.y + 1;
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-2);
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);
/* Draw the room */
draw_room(rp);
/*
* Put the gold in
*/
if (rnd(100) < 50 && level >= cur_max)
{
register struct linked_list *item;
register struct object *cur;
coord tp;
has_gold = TRUE; /* This room has gold in it */
item = spec_item(GOLD, NULL, NULL, NULL);
cur = OBJPTR(item);
/* Put the gold into the level list of items */
attach(lvl_obj, item);
/* Put it somewhere */
rnd_pos(rp, &tp);
mvaddch(tp.y, tp.x, GOLD);
cur->o_pos = tp;
if (roomin(&tp) != rp) {
endwin();
abort();
}
}
/*
* Put the monster in
*/
if (rnd(100) < (has_gold ? 80 : 25) + vlevel/2)
{
do
{
rnd_pos(rp, &mp);
} until(mvwinch(stdscr, mp.y, mp.x) == FLOOR);
which_monster = randmonster(FALSE, FALSE);
num_monsters = 1;
/*
* see if we should make a whole bunch
*/
for (j=0; j<MAXFLAGS; j++) {
if (monsters[which_monster].m_flags[j] == AREMANY)
num_monsters = roll(3,3);
}
for (j=0; j<num_monsters; j++) {
if ((np = fallpos(&mp, FALSE, 2)) != NULL &&
mvwinch(stdscr, np->y, np->x) == FLOOR) {
item = new_item(sizeof *tp);
tp = THINGPTR(item);
new_monster(item, which_monster, np, FALSE);
/*
* See if we want to give it a treasure to
* carry around.
*/
carry_obj(tp, monsters[tp->t_index].m_carry);
tp->t_no_move = movement(tp);
/*
* If it has a fire, mark it
*/
if (on(*tp, HASFIRE)) {
register struct linked_list *fire_item;
fire_item = creat_item();
ldata(fire_item) = (char *) tp;
attach(rp->r_fires, fire_item);
rp->r_flags |= HASFIRE;
}
}
}
}
}
}
/*
* Given a room pointer and a pointer to a door, supposedly in that room,
* return the coordinates of the entrance to the doorway.
*/
coord *
doorway(rp, door)
register struct room *rp;
register coord *door;
{
register int misses = 0;
static coord answer;
/* Do we have decent parameters? */
if (rp == NULL || door == NULL) return(NULL);
/* Initialize the answer to be the door, then calculate the offset */
answer = *door;
/* Calculate the x-offset */
if (door->x == rp->r_pos.x) answer.x++;
else if (door->x == rp->r_pos.x + rp->r_max.x - 1) answer.x--;
else misses++;
/* Calculate the y-offset */
if (door->y == rp->r_pos.y) answer.y++;
else if (door->y == rp->r_pos.y + rp->r_max.y - 1) answer.y--;
else misses++;
if (misses <= 1) return(&answer);
else return(NULL);
}
/*
* Draw a box around a room
*/
draw_room(rp)
register struct room *rp;
{
register int j, k;
move(rp->r_pos.y, rp->r_pos.x+1);
vert(rp->r_max.y-2); /* Draw left side */
move(rp->r_pos.y+rp->r_max.y-1, rp->r_pos.x);
horiz(rp->r_max.x); /* Draw bottom */
move(rp->r_pos.y, rp->r_pos.x);
horiz(rp->r_max.x); /* Draw top */
vert(rp->r_max.y-2); /* Draw right side */
/*
* Put the floor down
*/
for (j = 1; j < rp->r_max.y-1; j++)
{
move(rp->r_pos.y + j, rp->r_pos.x+1);
for (k = 1; k < rp->r_max.x-1; k++)
addch(FLOOR);
}
}
/*
* horiz:
* draw a horizontal line
*/
horiz(cnt)
register int cnt;
{
while (cnt--)
addch('-');
}
/*
* 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;
}
/*
* 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;
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
if (inroom(rp, cp))
return rp;
return NULL;
}
/*
* vert:
* draw a vertical line
*/
vert(cnt)
register int cnt;
{
register int x, y;
getyx(stdscr, y, x);
x--;
while (cnt--) {
move(++y, x);
addch('|');
}
}

302
arogue7/save.c Normal file
View file

@ -0,0 +1,302 @@
/*
* save.c - save and restore routines
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* save and restore routines
*
*/
#include "curses.h"
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include "rogue.h"
#include <fcntl.h>
#include <errno.h>
#include "mach_dep.h"
#ifdef PC7300
#include "sys/window.h"
extern struct uwdata wdata;
#endif
#if u370 || uts
#define ENCREAD(b,n,fd) read(fd,b,n)
#define ENCWRITE(b,n,fd) write(fd,b,n)
#endif
#ifndef ENCREAD
#define ENCREAD encread
#define ENCWRITE encwrite
#endif
typedef struct stat STAT;
extern char version[], encstr[];
/* extern bool _endwin; */
extern int errno;
STAT sbuf;
bool
save_game()
{
register int savefd;
register int c;
char buf[LINELEN];
/*
* get file name
*/
mpos = 0;
if (file_name[0] != '\0')
{
msg("Save file (%s)? ", file_name);
do
{
c = readchar();
if (c == ESCAPE) return(0);
} while (c != 'n' && c != 'N' && c != 'y' && c != 'Y');
mpos = 0;
if (c == 'y' || c == 'Y')
{
msg("File name: %s", file_name);
goto gotfile;
}
}
do
{
msg("File name: ");
mpos = 0;
buf[0] = '\0';
if (get_str(buf, msgw) == QUIT)
{
msg("");
return FALSE;
}
strcpy(file_name, buf);
gotfile:
if ((savefd = open(file_name, O_WRONLY|O_CREAT|O_TRUNC,0666)) < 0)
msg(strerror(errno)); /* fake perror() */
} while (savefd < 0);
/*
* write out encrpyted file (after a stat)
*/
if (save_file(savefd) == FALSE) {
msg("Cannot create save file.");
unlink(file_name);
return(FALSE);
}
else return(TRUE);
}
/*
* automatically save a file. This is used if a HUP signal is
* recieved
*/
void
auto_save(sig)
int sig;
{
register int savefd;
register int i;
for (i = 0; i < NSIG; i++)
signal(i, SIG_IGN);
if (file_name[0] != '\0' &&
pstats.s_hpt > 0 &&
(savefd = open(file_name, O_WRONLY|O_CREAT|O_TRUNC, 0600)) >= 0)
save_file(savefd);
endwin();
#ifdef PC7300
endhardwin();
#endif
exit(1);
}
/*
* write the saved game on the file
*/
bool
save_file(savefd)
register int savefd;
{
register unsigned num_to_write, num_written;
FILE *savef;
int ret;
wmove(cw, lines-1, 0);
draw(cw);
lseek(savefd, 0L, 0);
fstat(savefd, &sbuf);
num_to_write = strlen(version) + 1;
num_written = ENCWRITE(version, num_to_write, savefd);
sprintf(prbuf,"%d x %d\n", LINES, COLS);
ENCWRITE(prbuf,80,savefd);
savef = (FILE *) fdopen(savefd,"wb");
ret = rs_save_file(savef);
fclose(savef);
if (num_to_write == num_written && ret == 0) return(TRUE);
else return(FALSE);
}
restore(file, envp)
register char *file;
char **envp;
{
register int inf;
extern char **environ;
char buf[LINELEN];
STAT sbuf2;
int oldcol, oldline; /* Old number of columns and lines */
if (strcmp(file, "-r") == 0)
file = file_name;
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;
}
/*
* Get the lines and columns from the previous game
*/
ENCREAD(buf, 80, inf);
sscanf(buf, "%d x %d\n", &oldline, &oldcol);
fstat(inf, &sbuf2);
fflush(stdout);
initscr();
if (COLS < oldcol || LINES < oldline) {
endwin();
printf("Cannot restart the game on a smaller screen.\n");
return FALSE;
}
setup();
/*
* Set up windows
*/
cw = newwin(lines, cols, 0, 0);
mw = newwin(lines, cols, 0, 0);
hw = newwin(lines, cols, 0, 0);
msgw = newwin(4, cols, 0, 0);
keypad(cw,1);
keypad(msgw,1);
if (rs_restore_file(inf) != 0)
{
printf("Cannot restore file\n");
close(inf);
return(FALSE);
}
cols = COLS;
lines = LINES;
if (cols > 85) cols = 85;
if (lines > 24) lines = 24;
mpos = 0;
mvwprintw(msgw, 0, 0, "%s: %s", file, ctime(&sbuf2.st_mtime));
/*
* defeat multiple restarting from the same place
*/
if (!wizard && md_unlink_open_file(file, inf) < 0) {
printf("Cannot unlink file\n");
return FALSE;
}
environ = envp;
strcpy(file_name, file);
setup();
clearok(curscr, TRUE);
touchwin(cw);
srand(getpid());
playit();
/*NOTREACHED*/
return(0);
}
#define ENCWBSIZ 1024
/*
* perform an encrypted write
*/
encwrite(start, size, outf)
register char *start;
register unsigned size;
register int outf;
{
register char *ep;
register int i = 0;
int num_written = 0;
auto char buf[ENCWBSIZ];
ep = encstr;
while (size--)
{
buf[i++] = *start++ ^ *ep++ ;
if (*ep == '\0')
ep = encstr;
if (i == ENCWBSIZ || size == 0) {
if (write(outf, buf, (unsigned)i) < i)
return(num_written);
else {
num_written += i;
i = 0;
}
}
}
return(num_written);
}
/*
* perform an encrypted read
*/
encread(start, size, inf)
register char *start;
register unsigned size;
register int inf;
{
register char *ep;
register int read_size;
if ((read_size = read(inf, start, size)) == -1 || read_size == 0)
return read_size;
ep = encstr;
size = read_size;
while (size--)
{
*start++ ^= *ep++;
if (*ep == '\0')
ep = encstr;
}
return read_size;
}

841
arogue7/scrolls.c Normal file
View file

@ -0,0 +1,841 @@
/*
* scrolls.c - Functions for dealing with scrolls
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Read a scroll and let it happen
*
*/
#include "curses.h"
#include <ctype.h>
#include "rogue.h"
/*
* let the hero get rid of some type of monster (but not a UNIQUE!)
*/
genocide()
{
register struct linked_list *ip;
register struct thing *mp;
register struct linked_list *nip;
register int num_monst = NUMMONST-NUMUNIQUE-1, /* cannot genocide uniques */
pres_monst=1,
num_lines=2*(lines-3);
register int which_monst;
which_monst = makemonster(FALSE, "Genocide", "wipe out");
if (which_monst <= 0) {
msg("");
return;
}
/* Remove this monster from the present level */
for (ip = mlist; ip; ip = nip) {
mp = THINGPTR(ip);
nip = next(ip);
if (mp->t_index == which_monst) {
killed(ip, FALSE, FALSE, TRUE);
}
}
/* Remove from available monsters */
monsters[which_monst].m_normal = FALSE;
monsters[which_monst].m_wander = FALSE;
mpos = 0;
msg("You have wiped out the %s.", monsters[which_monst].m_name);
}
read_scroll(which, flag, is_scroll)
register int which;
int flag;
bool is_scroll;
{
register struct object *obj, *nobj;
register struct linked_list *item, *nitem;
register int i,j;
register char ch, nch;
bool cursed, blessed;
blessed = FALSE;
cursed = FALSE;
item = NULL;
if (which < 0) {
if (on(player, ISBLIND)) {
msg("You can't see to read anything");
return;
}
if (on(player, ISINWALL)) {
msg("You can't see the scroll while inside rock!");
return;
}
/* This is a scroll or book. */
if (player.t_action != C_READ) {
int units;
item = get_item(pack, "read", READABLE, FALSE, FALSE);
/*
* Make certain that it is somethings that we want to read
*/
if (item == NULL)
return;
/* How long does it take to read? */
units = usage_time(item);
if (units < 0) return;
player.t_using = item; /* Remember what it is */
player.t_no_move = units * movement(&player);
if ((OBJPTR(item))->o_type == SCROLL) player.t_action = C_READ;
else player.t_action = C_USE;
return;
}
/* We have waited our time, let's quaff the potion */
item = player.t_using;
player.t_using = NULL;
player.t_action = A_NIL;
obj = OBJPTR(item);
/* remove it from the pack */
inpack--;
detach(pack, item);
msg("As you read the scroll, it vanishes.");
cursed = (obj->o_flags & ISCURSED) != 0;
blessed = (obj->o_flags & ISBLESSED) != 0;
which = obj->o_which;
}
else {
cursed = flag & ISCURSED;
blessed = flag & ISBLESSED;
}
switch (which) {
case S_CONFUSE:
/*
* Scroll of monster confusion. Give him that power.
*/
msg("Your hands begin to glow red");
turn_on(player, CANHUH);
when S_CURING:
/*
* A cure disease spell
*/
if (on(player, HASINFEST) ||
on(player, HASDISEASE)||
on(player, DOROT)) {
if (on(player, HASDISEASE)) {
extinguish(cure_disease);
cure_disease();
}
if (on(player, HASINFEST)) {
msg(terse ? "You feel yourself improving."
: "You begin to feel yourself improving again.");
turn_off(player, HASINFEST);
infest_dam = 0;
}
if (on(player, DOROT)) {
msg("You feel your skin returning to normal.");
turn_off(player, DOROT);
}
}
else {
msg(nothing);
break;
}
if (is_scroll) s_know[S_CURING] = TRUE;
when S_LIGHT:
if (blue_light(blessed, cursed) && is_scroll)
s_know[S_LIGHT] = TRUE;
when S_HOLD:
if (cursed) {
/*
* This scroll aggravates all the monsters on the current
* level and sets them running towards the hero
*/
aggravate(TRUE, TRUE);
msg("You hear a high pitched humming noise.");
}
else if (blessed) { /* Hold all monsters on level */
if (mlist == NULL) msg(nothing);
else {
register struct linked_list *mon;
register struct thing *th;
for (mon = mlist; mon != NULL; mon = next(mon)) {
th = THINGPTR(mon);
turn_off(*th, ISRUN);
turn_on(*th, ISHELD);
}
msg("A sudden peace comes over the dungeon.");
}
}
else {
/*
* Hold monster scroll. Stop all monsters within two spaces
* from chasing after the hero.
*/
register int x,y;
register struct linked_list *mon;
bool gotone=FALSE;
for (x = hero.x-2; x <= hero.x+2; x++) {
for (y = hero.y-2; y <= hero.y+2; y++) {
if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1)
continue;
if (isalpha(mvwinch(mw, y, x))) {
if ((mon = find_mons(y, x)) != NULL) {
register struct thing *th;
gotone = TRUE;
th = THINGPTR(mon);
turn_off(*th, ISRUN);
turn_on(*th, ISHELD);
}
}
}
}
if (gotone) msg("A sudden peace surrounds you.");
else msg(nothing);
}
when S_SLEEP:
/*
* if cursed, you fall asleep
*/
if (is_scroll) s_know[S_SLEEP] = TRUE;
if (cursed) {
if (ISWEARING(R_ALERT))
msg("You feel drowsy for a moment.");
else {
msg("You fall asleep.");
player.t_no_move += movement(&player)*(4 + rnd(SLEEPTIME));
player.t_action = A_FREEZE;
}
}
else {
/*
* sleep monster scroll.
* puts all monsters within 2 spaces asleep
*/
register int x,y;
register struct linked_list *mon;
bool gotone=FALSE;
for (x = hero.x-2; x <= hero.x+2; x++) {
for (y = hero.y-2; y <= hero.y+2; y++) {
if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1)
continue;
if (isalpha(mvwinch(mw, y, x))) {
if ((mon = find_mons(y, x)) != NULL) {
register struct thing *th;
th = THINGPTR(mon);
if (on(*th, ISUNDEAD))
continue;
th->t_no_move += movement(th)*(SLEEPTIME+4);
th->t_action = A_FREEZE;
gotone = TRUE;
}
}
}
}
if (gotone)
msg("The monster(s) around you seem to have fallen asleep");
else
msg(nothing);
}
when S_CREATE:
/*
* Create a monster
* First look in a circle around him, next try his room
* otherwise give up
*/
creat_mons(&player, (short) 0, TRUE);
light(&hero);
when S_IDENT:
/*
* if its blessed then identify everything in the pack
*/
if (blessed) {
msg("You feel more Knowledgeable!");
idenpack();
}
else {
/*
* Identify, let the rogue figure something out
*/
if (is_scroll && s_know[S_IDENT] != TRUE) {
msg("This scroll is an identify scroll");
}
whatis(NULL);
}
if (is_scroll) s_know[S_IDENT] = TRUE;
when S_MAP:
/*
* Scroll of magic mapping.
*/
if (is_scroll && s_know[S_MAP] != TRUE) {
msg("Oh, now this scroll has a map on it.");
s_know[S_MAP] = TRUE;
}
overwrite(stdscr, hw);
/*
* Take all the things we want to keep hidden out of the window
*/
for (i = 1; i < lines-2; i++)
for (j = 0; j < cols; j++)
{
switch (nch = ch = CCHAR( mvwinch(hw, i, j) ))
{
case SECRETDOOR:
nch = secretdoor (i, j);
break;
case '-':
case '|':
case DOOR:
case PASSAGE:
case ' ':
case STAIRS:
if (mvwinch(mw, i, j) != ' ')
{
register struct thing *it;
it = THINGPTR(find_mons(i, j));
if (it && it->t_oldch == ' ')
it->t_oldch = nch;
}
break;
default:
nch = ' ';
}
if (nch != ch)
waddch(hw, nch);
}
/*
* Copy in what he has discovered
*/
overlay(cw, hw);
/*
* And set up for display
*/
overwrite(hw, cw);
when S_GFIND:
/*
* Scroll of gold detection
*/
{
int gtotal = 0;
wclear(hw);
for (nitem = lvl_obj; nitem != NULL; nitem = next(nitem)) {
nobj = OBJPTR(nitem);
if (nobj->o_type == GOLD) {
gtotal += nobj->o_count;
mvwaddch(hw, nobj->o_pos.y, nobj->o_pos.x, GOLD);
}
}
for (nitem = mlist; nitem != NULL; nitem = next(nitem)) {
register struct linked_list *gitem;
register struct thing *th;
th = THINGPTR(nitem);
if (on(*th, NODETECT)) continue;
for(gitem = th->t_pack; gitem != NULL; gitem = next(gitem)){
nobj = OBJPTR(gitem);
if (nobj->o_type == GOLD) {
gtotal += nobj->o_count;
mvwaddch(hw, th->t_pos.y, th->t_pos.x, GOLD);
}
}
}
if (gtotal) {
if (is_scroll) s_know[S_GFIND] = TRUE;
msg("You begin to feel greedy and you sense gold.");
waddstr(msgw, morestr);
clearok(msgw, FALSE);
draw(msgw);
overlay(hw, cw);
draw(cw);
wait_for(' ');
msg("");
break;
}
}
msg("You begin to feel a pull downward");
when S_TELEP:
/*
* Scroll of teleportation:
* Make him disappear and reappear
*/
if (cursed) {
int old_max = cur_max;
turns = (vlevel * 3) * LEVEL;
level = nfloors;
new_level(NORMLEV);
status(TRUE);
mpos = 0;
msg("You are banished to the lower regions.");
if (old_max == cur_max) /* if he's been here, make it harder */
aggravate(TRUE, TRUE);
}
else if (blessed) {
int old_level,
much = rnd(4) - 4;
old_level = level;
if (much != 0) {
level += much;
if (level < 1)
level = 1;
mpos = 0;
cur_max = level;
turns += much*LEVEL;
if (turns < 0)
turns = 0;
new_level(NORMLEV); /* change levels */
if (level == old_level)
status(TRUE);
msg("You are whisked away to another region.");
}
}
else {
teleport();
}
if (is_scroll) s_know[S_TELEP] = TRUE;
when S_SCARE:
/*
* A monster will refuse to step on a scare monster scroll
* if it is dropped. Thus 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 (cursed) { /* curse all player's possessions */
for (nitem = pack; nitem != NULL; nitem = next(nitem)) {
nobj = OBJPTR(nitem);
if (nobj->o_flags & ISBLESSED)
nobj->o_flags &= ~ISBLESSED;
else
nobj->o_flags |= ISCURSED;
}
msg("The smell of fire and brimstone fills the air.");
}
else if (blessed) {
for (nitem = pack; nitem != NULL; nitem = next(nitem)) {
nobj = OBJPTR(nitem);
nobj->o_flags &= ~ISCURSED;
}
msg("Your pack glistens brightly");
}
else {
nitem = get_item(pack, "remove the curse on",ALL,FALSE,FALSE);
if (nitem != NULL) {
nobj = OBJPTR(nitem);
nobj->o_flags &= ~ISCURSED;
msg("Removed the curse from %s",inv_name(nobj,TRUE));
}
}
if (is_scroll) s_know[S_REMOVE] = TRUE;
when S_PETRIFY:
switch (mvinch(hero.y, hero.x)) {
case TRAPDOOR:
case DARTTRAP:
case TELTRAP:
case ARROWTRAP:
case SLEEPTRAP:
case BEARTRAP:
{
register int i;
/* Find the right trap */
for (i=0; i<ntraps && !ce(traps[i].tr_pos, hero); i++);
ntraps--;
if (!ce(traps[i].tr_pos, hero))
msg("What a strange trap!");
else {
while (i < ntraps) {
traps[i] = traps[i + 1];
i++;
}
}
}
goto pet_message;
case DOOR:
case SECRETDOOR:
case FLOOR:
case PASSAGE:
pet_message: msg("The dungeon begins to rumble and shake!");
addch(WALL);
/* If the player is phased, unphase him */
if (on(player, CANINWALL)) {
extinguish(unphase);
turn_off(player, CANINWALL);
msg("Your dizzy feeling leaves you.");
}
/* Mark the player as in a wall */
turn_on(player, ISINWALL);
break;
default:
msg(nothing);
}
when S_GENOCIDE:
msg("You have been granted the boon of genocide!--More--");
wait_for(' ');
msg("");
genocide();
if (is_scroll) s_know[S_GENOCIDE] = TRUE;
when S_PROTECT: {
struct linked_list *ll;
struct object *lb;
bool did_it = FALSE;
msg("You are granted the power of protection.");
if ((ll=get_item(pack,"protect",PROTECTABLE,FALSE,FALSE)) != NULL) {
lb = OBJPTR(ll);
mpos = 0;
if (cursed) {
switch(lb->o_type) { /* ruin it completely */
case RING: if (lb->o_ac > 0) {
if (is_current(lb)) {
switch (lb->o_which) {
case R_ADDWISDOM:
pstats.s_wisdom -= lb->o_ac;
when R_ADDINTEL:
pstats.s_intel -= lb->o_ac;
when R_ADDSTR:
pstats.s_str -= lb->o_ac;
when R_ADDHIT:
pstats.s_dext -= lb->o_ac;
}
}
did_it = TRUE;
lb->o_ac = 0;
}
when ARMOR: if (lb->o_ac > 10) {
did_it = TRUE;
lb->o_ac = 10;
}
when STICK: if (lb->o_charges > 0) {
did_it = TRUE;
lb->o_charges = 0;
}
when WEAPON:if (lb->o_hplus > 0) {
did_it = TRUE;
lb->o_hplus = 0;
}
if (lb->o_dplus > 0) {
did_it = TRUE;
lb->o_dplus = 0;
}
}
if (lb->o_flags & ISPROT) {
did_it = TRUE;
lb->o_flags &= ~ISPROT;
}
if (lb->o_flags & ISBLESSED) {
did_it = TRUE;
lb->o_flags &= ~ISBLESSED;
}
if (did_it)
msg("Your %s glows red for a moment",inv_name(lb,TRUE));
else {
msg(nothing);
break;
}
}
else {
lb->o_flags |= ISPROT;
msg("Protected %s.",inv_name(lb,TRUE));
}
}
if (is_scroll) s_know[S_PROTECT] = TRUE;
}
when S_MAKEIT:
msg("You have been endowed with the power of creation.");
if (is_scroll) s_know[S_MAKEIT] = TRUE;
create_obj(TRUE, 0, 0);
when S_ALLENCH: {
struct linked_list *ll;
struct object *lb;
int howmuch, flags;
if (is_scroll && s_know[S_ALLENCH] == FALSE) {
msg("You are granted the power of enchantment.");
msg("You may enchant anything(weapon,ring,armor,scroll,potion)");
}
if ((ll = get_item(pack, "enchant", ALL, FALSE, FALSE)) != NULL) {
lb = OBJPTR(ll);
lb->o_flags &= ~ISCURSED;
if (blessed) {
howmuch = 2;
flags = ISBLESSED;
}
else if (cursed) {
howmuch = -1;
flags = ISCURSED;
}
else {
howmuch = 1;
flags = ISBLESSED;
}
switch(lb->o_type) {
case RING:
if (lb->o_ac + howmuch > MAXENCHANT) {
msg("The enchantment doesn't seem to work!");
break;
}
lb->o_ac += howmuch;
if (lb==cur_ring[LEFT_1] || lb==cur_ring[LEFT_2] ||
lb==cur_ring[LEFT_3] || lb==cur_ring[LEFT_4] ||
lb==cur_ring[RIGHT_1] || lb==cur_ring[RIGHT_2] ||
lb==cur_ring[RIGHT_3] || lb==cur_ring[RIGHT_4]) {
switch (lb->o_which) {
case R_ADDWISDOM: pstats.s_wisdom += howmuch;
when R_ADDINTEL: pstats.s_intel += howmuch;
when R_ADDSTR: pstats.s_str += howmuch;
when R_ADDHIT: pstats.s_dext += howmuch;
}
}
msg("Enchanted %s.",inv_name(lb,TRUE));
when ARMOR:
if ((armors[lb->o_which].a_class - lb->o_ac) +
howmuch > MAXENCHANT) {
msg("The enchantment doesn't seem to work!");
break;
}
else
lb->o_ac -= howmuch;
msg("Enchanted %s.",inv_name(lb,TRUE));
when STICK:
lb->o_charges += (howmuch * 10) + rnd(5);
if (lb->o_charges < 0)
lb->o_charges = 0;
if (EQUAL(ws_type[lb->o_which], "staff")) {
if (lb->o_charges > 100)
lb->o_charges = 100;
}
else {
if (lb->o_charges > 50)
lb->o_charges = 50;
}
msg("Enchanted %s.",inv_name(lb,TRUE));
when WEAPON:
if(lb->o_hplus+lb->o_dplus+howmuch > MAXENCHANT * 2){
msg("The enchantment doesn't seem to work!");
break;
}
if (rnd(100) < 50)
lb->o_hplus += howmuch;
else
lb->o_dplus += howmuch;
msg("Enchanted %s.",inv_name(lb,TRUE));
when MM:
switch (lb->o_which) {
case MM_BRACERS:
if (lb->o_ac + howmuch > MAXENCHANT) {
msg("The enchantment doesn't seem to work!");
break;
}
else lb->o_ac += howmuch;
msg("Enchanted %s.",inv_name(lb,TRUE));
when MM_PROTECT:
if (lb->o_ac + howmuch > MAXENCHANT/2) {
msg("The enchantment doesn't seem to work!");
break;
}
else lb->o_ac += howmuch;
msg("Enchanted %s.",inv_name(lb,TRUE));
}
lb->o_flags |= flags;
when POTION:
case SCROLL:
default:
lb->o_flags |= flags;
msg("Enchanted %s.",inv_name(lb,TRUE));
}
}
if (is_scroll) s_know[S_ALLENCH] = TRUE;
if (!is_scroll) {
pstats.s_const--;
max_stats.s_const--;
if (pstats.s_const <= 0)
death(D_CONSTITUTION);
msg("You feel less healthy now");
}
}
when S_FINDTRAPS:
for (i=0; i<ntraps; i++) {
if (!(traps[i].tr_flags & ISFOUND)) {
traps[i].tr_flags |= ISFOUND;
if (cansee(traps[i].tr_pos.y, traps[i].tr_pos.x))
mvwaddch(cw,traps[i].tr_pos.y,traps[i].tr_pos.x,
traps[i].tr_type);
}
}
if (ntraps > 0) {
msg("You sense the presence of traps");
if (is_scroll) s_know[S_FINDTRAPS] = TRUE;
}
else
msg(nothing);
when S_RUNES:
{
register struct linked_list *sitem;
msg("The scroll explodes in a ball of fire!");
if (on(player, NOFIRE)) {
msg("The fire does not seem to affect you");
break;
}
explode(&player);
if (pstats.s_hpt <= 0)
death(D_SCROLL);
for (sitem = pack; sitem != NULL; sitem = nitem) {
nitem = next(sitem); /* in case we delete it */
nobj = OBJPTR(sitem);
/*
* check for loss of all scrolls and give them
* a save versus fire
*/
if (nobj->o_type == SCROLL && roll(1,20) < 19) {
msg("%s burns up!", inv_name(nobj, TRUE));
inpack--;
detach(pack, sitem);
o_discard(sitem);
}
}
}
when S_CHARM:
{
bool spots[9];
int x, y, spot, count, numcharmed, something, bonus;
struct linked_list *item;
register struct thing *tp;
/* Initialize the places where we look around us */
for (i=0; i<9; i++) spots[i] = FALSE;
count = 0; /* No spots tried yet */
numcharmed = 0; /* Nobody charmed yet */
something = 0; /* Nothing has been seen yet */
bonus = 0; /* no bonus yet */
/* Now look around us randomly for a charmee */
while (count < 9) {
do {
spot = rnd(9);
} while (spots[spot] == TRUE);
/* We found a place */
count++;
spots[spot] = TRUE;
y = hero.y - 1 + (spot / 3);
x = hero.x - 1 + (spot % 3);
/* Be sure to stay on the board! */
if (x < 0 || x >= cols || (y < 1) || (y >= lines - 2))
continue;
/* Is there a monster here? */
if (!isalpha(mvwinch(mw, y, x))) continue;
/* What kind is it? */
item = find_mons(y, x);
if (item == NULL) continue;
tp = THINGPTR(item);
if (on(*tp,ISCHARMED) || on(*tp,ISUNIQUE) || on(*tp,ISUNDEAD))
continue;
/* Will the monster be charmed? */
if (blessed) bonus -= 3;
bonus -= (pstats.s_charisma - 13) / 3;
if ((player.t_ctype==C_PALADIN || player.t_ctype==C_RANGER) &&
off(*tp, ISMEAN))
bonus -= 3;
if (save(VS_MAGIC, tp, bonus)) continue;
/* We got him! */
numcharmed++;
/* Let the player know (maybe) */
if ((off(*tp, ISINVIS) || on(player, CANSEE)) &&
(off(*tp, ISSHADOW) || on(player, CANSEE)) &&
cansee(y, x)) {
if (on(*tp, CANSURPRISE)) {
turn_off(*tp, CANSURPRISE);
msg("Woah!");
}
msg("The eyes of %s glaze over!",
prname(monster_name(tp), FALSE));
something++;
}
/* Charm him and turn off any side effects */
turn_on(*tp, ISCHARMED);
runto(tp, &hero);
tp->t_action = A_NIL;
/* If monster was suffocating us, stop it */
if (on(*tp, DIDSUFFOCATE)) {
turn_off(*tp, DIDSUFFOCATE);
extinguish(suffocate);
}
/* If monster held us, stop it */
if (on(*tp, DIDHOLD) && (--hold_count == 0))
turn_off(player, ISHELD);
turn_off(*tp, DIDHOLD);
/* If frightened of this monster, stop */
if (on(player, ISFLEE) &&
player.t_dest == &tp->t_pos) turn_off(player, ISFLEE);
if ((blessed && numcharmed >= 2) || numcharmed > 0) break;
}
if (something == 0) msg(nothing);
}
otherwise:
msg("What a puzzling scroll!");
return;
}
look(TRUE, FALSE); /* put the result of the scroll on the screen */
status(FALSE);
if (is_scroll && item && s_know[which] && s_guess[which])
{
free(s_guess[which]);
s_guess[which] = NULL;
}
else if (is_scroll &&
!s_know[which] &&
item &&
askme &&
(obj->o_flags & ISKNOW) == 0 &&
(obj->o_flags & ISPOST) == 0 &&
s_guess[which] == NULL) {
nameitem(item, FALSE);
}
if (item != NULL) o_discard(item);
updpack(TRUE, &player);
}

2674
arogue7/state.c Normal file

File diff suppressed because it is too large Load diff

1247
arogue7/sticks.c Normal file

File diff suppressed because it is too large Load diff

930
arogue7/things.c Normal file
View file

@ -0,0 +1,930 @@
/*
* things.c - functions for dealing with things like potions and scrolls
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Contains functions for dealing with things like
* potions and scrolls
*
*/
#include "curses.h"
#include <ctype.h>
#include "rogue.h"
/*
* print out the number of charges on a stick
*/
char *
charge_str(obj)
register struct object *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;
}
/*
* inv_name:
* return the name of something as it would appear in an
* inventory.
*/
char *
inv_name(obj, drop)
register struct object *obj;
bool drop;
{
register char *pb;
pb = prbuf;
pb[0] = '\0';
switch(obj->o_type) {
case SCROLL:
if (obj->o_count == 1)
sprintf(pb, "A %sscroll ", blesscurse(obj->o_flags));
else
sprintf(pb, "%d %sscrolls ",
obj->o_count, blesscurse(obj->o_flags));
pb = &pb[strlen(pb)];
if (s_know[obj->o_which] || (obj->o_flags & ISPOST))
sprintf(pb, "of %s", s_magic[obj->o_which].mi_name);
else if (s_guess[obj->o_which])
sprintf(pb, "named %s", s_guess[obj->o_which]);
else
sprintf(pb, "titled '%s'", s_names[obj->o_which]);
when POTION:
if (obj->o_count == 1)
sprintf(pb, "A %spotion ", blesscurse(obj->o_flags));
else
sprintf(pb, "%d %spotions ",
obj->o_count, blesscurse(obj->o_flags));
pb = &pb[strlen(pb)];
if (p_know[obj->o_which])
sprintf(pb, "of %s (%s)", p_magic[obj->o_which].mi_name,
p_kind(obj));
else if (obj->o_flags & ISPOST)
sprintf(pb, "of %s", p_magic[obj->o_which].mi_name);
else if (p_guess[obj->o_which])
sprintf(pb, "named %s (%s)", p_guess[obj->o_which],
p_colors[obj->o_which]);
else {
pb = prbuf;
if (obj->o_count == 1)
sprintf(pb, "A%s %s potion",
vowelstr(p_colors[obj->o_which]),
p_colors[obj->o_which]);
else
sprintf(pb, "%d %s potions",
obj->o_count, p_colors[obj->o_which]);
}
when FOOD:
if (obj->o_count == 1)
sprintf(pb, "A%s %s", vowelstr(foods[obj->o_which].mi_name),
foods[obj->o_which].mi_name);
else
sprintf(pb, "%d %ss", obj->o_count,foods[obj->o_which].mi_name);
when WEAPON:
if (obj->o_count > 1)
sprintf(pb, "%d ", obj->o_count);
else
strcpy(pb, "A ");
pb = &pb[strlen(pb)];
if (obj->o_flags & ISKNOW) {
strcat(pb, num(obj->o_hplus, obj->o_dplus));
strcat (pb, " ");
}
strcat(pb, weaps[obj->o_which].w_name);
if (obj->o_count > 1)
strcat(pb, "s");
if (obj == cur_weapon)
strcat(pb, " (weapon in hand)");
if (obj->o_flags & ISPOISON)
strcat(pb, " {Poisoned}");
when ARMOR:
if (obj->o_flags & ISKNOW) {
strcat(pb, num(armors[obj->o_which].a_class - obj->o_ac, 0));
strcat(pb, " ");
}
strcat(pb, armors[obj->o_which].a_name);
if (obj == cur_armor)
strcat(pb, " (being worn)");
when STICK:
sprintf(pb, "A %s%s ",
blesscurse(obj->o_flags), ws_type[obj->o_which]);
pb = &pb[strlen(pb)];
if (ws_know[obj->o_which] || obj->o_flags & ISKNOW)
sprintf(pb, "of %s%s (%s)", ws_magic[obj->o_which].mi_name,
charge_str(obj), ws_made[obj->o_which]);
else if (obj->o_flags & ISPOST)
sprintf(pb, "of %s", ws_magic[obj->o_which].mi_name);
else if (ws_guess[obj->o_which])
sprintf(pb, "named %s (%s)", ws_guess[obj->o_which],
ws_made[obj->o_which]);
else {
pb = prbuf;
sprintf(pb, "A %s %s", ws_made[obj->o_which],
ws_type[obj->o_which]);
}
if (obj == cur_weapon)
strcat(prbuf, " (weapon in hand)");
when RING:
if (r_know[obj->o_which] || obj->o_flags & ISKNOW)
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 (obj->o_flags & ISPOST)
sprintf(pb, "A ring of %s", r_magic[obj->o_which].mi_name);
else if (r_guess[obj->o_which])
sprintf(pb, "A ring named %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]);
if (obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] ||
obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4])
strcat(pb, " (on left hand)");
if (obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] ||
obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4])
strcat(pb, " (on right hand)");
when RELIC:
if (obj->o_flags & ISKNOW)
switch(obj->o_which) {
case QUILL_NAGROM:
sprintf(pb, "%s%s", rel_magic[obj->o_which].mi_name,
charge_str(obj));
otherwise:
strcpy(pb, rel_magic[obj->o_which].mi_name);
}
else switch(obj->o_which) {
case MUSTY_DAGGER:
strcpy(pb, "Two very fine daggers marked MDDE");
when EMORI_CLOAK:
strcpy(pb, "A silk cloak");
when HEIL_ANKH:
strcpy(pb, "A golden ankh");
when MING_STAFF:
strcpy(pb, "A finely carved staff");
when ORCUS_WAND:
strcpy(pb, "A sparkling ivory wand");
when ASMO_ROD:
strcpy(pb, "A glistening ebony rod");
when YENDOR_AMULET:
strcpy(pb, "A silver amulet");
when STONEBONES_AMULET:
strcpy(pb, "A stone amulet");
when BRIAN_MANDOLIN:
strcpy(pb, "A gleaming mandolin");
when HRUGGEK_MSTAR:
strcpy(pb, "A huge morning star");
when AXE_AKLAD:
strcpy(pb, "A jewel encrusted axe");
when QUILL_NAGROM:
strcpy(pb, "A bright white feather");
when GERYON_HORN:
strcpy(pb, "A jet black horn");
when YEENOGHU_FLAIL:
strcpy(pb, "A shimmering flail");
when SURTUR_RING:
strcpy(pb, "A fiery red ring");
otherwise:
strcpy(pb, "A magical item");
}
/* Take care of wielding and wearing */
switch (obj->o_which) {
case EMORI_CLOAK:
if (cur_armor == NULL && cur_misc[WEAR_CLOAK] == NULL)
strcat(pb, " (being worn)");
if (obj->o_charges)
strcat(pb, " [charged]");
else
strcat(pb, " [discharged]");
when HEIL_ANKH:
if (cur_relic[HEIL_ANKH]) strcat(pb, " (in hand)");
when EYE_VECNA:
if (cur_relic[EYE_VECNA]) strcat(pb, " (in eye socket)");
when STONEBONES_AMULET:
if (cur_relic[STONEBONES_AMULET])
strcat(pb, " (in chest)");
when YENDOR_AMULET:
if (cur_relic[YENDOR_AMULET])
strcat(pb, " (in chest)");
when MUSTY_DAGGER:
case HRUGGEK_MSTAR:
case AXE_AKLAD:
case YEENOGHU_FLAIL:
case MING_STAFF:
case ASMO_ROD:
case ORCUS_WAND:
if (cur_weapon == obj) strcat(pb, " (weapon in hand)");
when SURTUR_RING:
if (cur_relic[SURTUR_RING])
strcat(pb, " (in nose)");
}
when MM:
if (m_know[obj->o_which])
strcpy(pb, misc_name(obj));
else {
switch (obj->o_which) {
case MM_JUG:
case MM_BEAKER:
strcpy(pb, "A bottle");
when MM_KEOGHTOM:
strcpy(pb, "A jar");
when MM_JEWEL:
strcpy(pb, "An amulet");
when MM_BOOK:
case MM_SKILLS:
strcpy(pb, "A book");
when MM_ELF_BOOTS:
case MM_DANCE:
strcpy(pb, "A pair of boots");
when MM_BRACERS:
strcpy(pb, "A pair of bracers");
when MM_OPEN:
case MM_HUNGER:
strcpy(pb, "A chime");
when MM_DISP:
case MM_R_POWERLESS:
case MM_PROTECT:
strcpy(pb, "A cloak");
when MM_DRUMS:
strcpy(pb, "A set of drums");
when MM_DISAPPEAR:
case MM_CHOKE:
strcpy(pb, "A pouch of dust");
when MM_G_DEXTERITY:
case MM_G_OGRE:
case MM_FUMBLE:
strcpy(pb, "A pair of gauntlets");
when MM_ADAPTION:
case MM_STRANGLE:
strcpy(pb, "A necklace");
otherwise:
strcpy(pb, "A magical item");
}
if (m_guess[obj->o_which]) {
strcat(pb, " named: ");
strcat(pb, m_guess[obj->o_which]);
}
}
if (obj == cur_misc[WEAR_BOOTS] ||
obj == cur_misc[WEAR_BRACERS] ||
obj == cur_misc[WEAR_CLOAK] ||
obj == cur_misc[WEAR_GAUNTLET] ||
obj == cur_misc[WEAR_NECKLACE] ||
obj == cur_misc[WEAR_JEWEL])
strcat(pb, " (being worn)");
when GOLD:
sprintf(pb, "%d Pieces of Gold", obj->o_count);
otherwise:
debug("Picked up something funny");
sprintf(pb, "Something bizarre %s", unctrl(obj->o_type));
}
/* Is it marked? */
if (obj->o_mark[0]) {
pb = &pb[strlen(pb)];
sprintf(pb, " <%s>", obj->o_mark);
}
if (obj->o_flags & ISPROT)
strcat(pb, " [protected]");
if (drop && isupper(prbuf[0]))
prbuf[0] = tolower(prbuf[0]);
else if (!drop && islower(*prbuf))
*prbuf = toupper(*prbuf);
if (!drop)
strcat(pb, ".");
/*
* Truncate if long. Use cols-4 to offset the "pack letter" of a normal
* inventory listing.
*/
prbuf[cols-4] = '\0';
return prbuf;
}
/*
* weap_name:
* Return the name of a weapon.
*/
char *
weap_name(obj)
register struct object *obj;
{
switch (obj->o_type) {
case WEAPON:
return(weaps[obj->o_which].w_name);
when MISSILE:
return(ws_magic[obj->o_which].mi_name);
when RELIC:
switch (obj->o_which) {
case MUSTY_DAGGER:
return("daggers");
when YEENOGHU_FLAIL:
return("flail");
when AXE_AKLAD:
return("axe");
when HRUGGEK_MSTAR:
return("morning star");
when MING_STAFF:
return("staff");
when ORCUS_WAND:
return("wand");
when ASMO_ROD:
return("rod");
}
}
return("weapon");
}
/*
* drop:
* put something down
*/
drop(item)
struct linked_list *item;
{
register char ch;
register struct linked_list *obj, *nobj;
register struct object *op;
if (item == NULL) {
/* We charge 2 movement times to drop something */
if (player.t_action == C_DROP && player.t_using != NULL) {
obj = player.t_using;
player.t_using = NULL;
player.t_action = A_NIL;
}
/* t_action == C_DROP always when called from command() */
else {
if ((obj = get_item(pack, "drop", ALL, FALSE, FALSE)) == NULL) {
player.t_action = A_NIL;
player.t_using = NULL;
return(FALSE);
}
if (player.t_action == C_DROP) {
player.t_using = obj;
player.t_no_move = 2 * movement(&player);
return(FALSE); /* We'll come back after we've waited */
}
}
switch(ch = CCHAR(mvwinch(stdscr, hero.y, hero.x))) {
case PASSAGE:
case SCROLL:
case POTION:
case WEAPON:
case FLOOR:
case STICK:
case ARMOR:
case POOL:
case RELIC:
case GOLD:
case FOOD:
case RING:
case MM:
break;
default:
msg("Can't leave it here");
return(FALSE);
}
}
else {
obj = item;
}
op = OBJPTR(obj);
if (!dropcheck(op))
return(FALSE);
/*
* If it is a scare monster scroll, curse it
*/
if (op->o_type == SCROLL && op->o_which == S_SCARE) {
if (op->o_flags & ISBLESSED)
op->o_flags &= ~ISBLESSED;
else op->o_flags |= ISCURSED;
}
/*
* Take it out of the pack
*/
if (op->o_count >= 2 && op->o_group == 0)
{
nobj = new_item(sizeof *op);
op->o_count--;
op = OBJPTR(nobj);
*op = *(OBJPTR(obj));
op->o_count = 1;
obj = nobj;
}
else {
detach(pack, obj);
inpack--;
}
if(ch == POOL) {
msg("Your %s sinks out of sight.",inv_name(op,TRUE));
o_discard(obj);
}
else if (levtype == POSTLEV) {
op->o_pos = hero; /* same place as hero */
fall(obj,FALSE);
if (item == NULL) /* if item wasn't sold */
msg("Thanks for your donation to the fiend's flea market.");
}
else {
/*
* Link it into the level object list
*/
attach(lvl_obj, obj);
mvaddch(hero.y, hero.x, op->o_type);
op->o_pos = hero;
msg("Dropped %s", inv_name(op, TRUE));
}
updpack(FALSE, &player);
return (TRUE);
}
/*
* do special checks for dropping or unweilding|unwearing|unringing
*/
dropcheck(op)
register struct object *op;
{
int save_max;
if (op == NULL)
return TRUE;
if (levtype == POSTLEV) {
if ((op->o_flags & ISCURSED) && (op->o_flags & ISKNOW)) {
msg("The trader does not accept your shoddy merchandise");
return(FALSE);
}
}
/* Player will not drop a relic */
if (op->o_type == RELIC) {
/*
* There is a 1% cumulative chance per relic that trying to get
* rid of it will cause the relic to turn on the player.
*/
if (rnd(100) < cur_relic[op->o_which]++) {
msg("The artifact turns on you.");
msg("It crushes your mind!!! -- More --");
pstats.s_hpt = -1;
wait_for (' ');
death(D_RELIC);
}
else {
if (terse) msg("Can't release it.");
else msg("You cannot bring yourself to release it.");
return FALSE;
}
}
/* If we aren't wearing it, we can drop it */
if (!is_current(op)) return TRUE;
/* At this point, we know we are wearing the item */
if (op->o_flags & ISCURSED) {
msg("You can't. It appears to be cursed.");
return FALSE;
}
if (op->o_type == RING && cur_misc[WEAR_GAUNTLET] != NULL) {
msg ("You have to remove your gauntlets first!");
return FALSE;
}
cur_null(op); /* set current to NULL */
if (op->o_type == RING) {
switch (op->o_which) {
case R_ADDSTR: save_max = max_stats.s_str;
chg_str(-op->o_ac);
max_stats.s_str = save_max;
when R_ADDHIT: pstats.s_dext -= op->o_ac;
when R_ADDINTEL: pstats.s_intel -= op->o_ac;
when R_ADDWISDOM: pstats.s_wisdom -= op->o_ac;
when R_SEEINVIS: if (!ISWEARING(R_SEEINVIS) &&
find_slot(unsee) == 0) {
turn_off(player, CANSEE);
msg("The tingling feeling leaves your eyes");
}
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
when R_WARMTH: if (!ISWEARING(R_WARMTH) && !find_slot(nocold))
turn_off(player, NOCOLD);
when R_FIRE: if (!ISWEARING(R_FIRE) &&
!cur_relic[SURTUR_RING] &&
!find_slot(nofire))
turn_off(player, NOFIRE);
when R_LIGHT: {
if(roomin(&hero) != NULL) {
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
}
when R_SEARCH: kill_daemon(ring_search);
when R_TELEPORT: kill_daemon(ring_teleport);
}
}
else if (op->o_type == MM) {
switch (op->o_which) {
case MM_ADAPTION:
turn_off(player, NOGAS);
when MM_STRANGLE:
msg("You can breathe again.....whew!");
kill_daemon(strangle);
when MM_DANCE:
turn_off(player, ISDANCE);
msg ("Your feet take a break.....whew!");
when MM_FUMBLE:
kill_daemon(fumble);
}
}
return TRUE;
}
/*
* return a new thing
*/
struct linked_list *
new_thing(thing_type, allow_curse)
int thing_type;
bool allow_curse;
{
register struct linked_list *item;
register struct object *cur;
register int j;
register int blesschance, cursechance;
item = new_item(sizeof *cur);
cur = OBJPTR(item);
cur->o_hplus = cur->o_dplus = 0;
strncpy(cur->o_damage, "0d0", sizeof(cur->o_damage));
strncpy(cur->o_hurldmg, "0d0", sizeof(cur->o_hurldmg));
cur->o_ac = 0;
cur->o_count = 1;
cur->o_group = 0;
cur->contents = NULL;
cur->o_flags = 0;
cur->o_weight = 0;
cur->o_mark[0] = '\0';
/*
* Decide what kind of object it will be
* If we haven't had food for a while, let it be food.
*/
blesschance = rnd(100);
if (allow_curse) cursechance = rnd(100);
else cursechance = 100; /* No chance of curse */
/* Get the type of item (pick one if 'any' is specified) */
if (thing_type == ALL) j = pick_one(things, NUMTHINGS);
else j = thing_type;
/*
* make sure he gets his vitamins
*/
if (thing_type == ALL && no_food > 3)
j = 2;
/*
* limit the number of foods on a level because it sometimes
* gets out of hand in the "deep" levels where there is a
* treasure room on most every level with lots of food in it
*/
while (thing_type == ALL && levtype != POSTLEV && foods_this_level > 2 &&
j == 2)
j = pick_one(things, NUMTHINGS); /* not too many.... */
switch (j)
{
case TYP_POTION:
cur->o_type = POTION;
do {
cur->o_which = pick_one(p_magic, MAXPOTIONS);
} while (!allow_curse && p_magic[cur->o_which].mi_curse == 100);
cur->o_weight = things[TYP_POTION].mi_wght;
if (cursechance < p_magic[cur->o_which].mi_curse)
cur->o_flags |= ISCURSED;
else if (blesschance < p_magic[cur->o_which].mi_bless)
cur->o_flags |= ISBLESSED;
/* If we made a gain ability potion, see what kind it is */
if (cur->o_which == P_ABIL) cur->o_kind = rnd(NUMABILITIES);
when TYP_SCROLL:
cur->o_type = SCROLL;
do {
cur->o_which = pick_one(s_magic, MAXSCROLLS);
} while (!allow_curse && s_magic[cur->o_which].mi_curse == 100);
cur->o_weight = things[TYP_SCROLL].mi_wght;
if (cursechance < s_magic[cur->o_which].mi_curse)
cur->o_flags |= ISCURSED;
else if (blesschance < s_magic[cur->o_which].mi_bless)
cur->o_flags |= ISBLESSED;
when TYP_FOOD:
no_food = 0;
cur->o_type = FOOD;
cur->o_weight = things[TYP_FOOD].mi_wght;
cur->o_count += extras();
foods_this_level += cur->o_count;
cur->o_which = pick_one(foods, MAXFOODS);
when TYP_WEAPON:
cur->o_type = WEAPON;
cur->o_which = rnd(MAXWEAPONS);
init_weapon(cur, cur->o_which);
if (cursechance < 20)
{
cur->o_flags |= ISCURSED;
cur->o_hplus -= rnd(2) + 1;
cur->o_dplus -= rnd(2) + 1;
}
else if (blesschance < 50) {
cur->o_hplus += rnd(5) + 1;
cur->o_dplus += rnd(5) + 1;
}
when TYP_ARMOR:
cur->o_type = ARMOR;
for (j = 0; j < MAXARMORS; j++)
if (blesschance < armors[j].a_prob)
break;
if (j == MAXARMORS)
{
debug("Picked a bad armor %d", blesschance);
j = 0;
}
cur->o_which = j;
cur->o_ac = armors[j].a_class;
cur->o_weight = armors[j].a_wght;
if (cursechance < 20)
{
cur->o_flags |= ISCURSED;
cur->o_ac += rnd(3)+1;
}
else if (blesschance < 35)
cur->o_ac -= rnd(3)+1;
when TYP_RING:
cur->o_type = RING;
do {
cur->o_which = pick_one(r_magic, MAXRINGS);
} while (!allow_curse && r_magic[cur->o_which].mi_curse == 100);
cur->o_weight = things[TYP_RING].mi_wght;
if (cursechance < r_magic[cur->o_which].mi_curse)
cur->o_flags |= ISCURSED;
else if (blesschance < r_magic[cur->o_which].mi_bless)
cur->o_flags |= ISBLESSED;
switch (cur->o_which)
{
case R_ADDSTR:
case R_ADDWISDOM:
case R_ADDINTEL:
case R_PROTECT:
case R_ADDHIT:
case R_ADDDAM:
cur->o_ac = rnd(2) + 1; /* From 1 to 3 */
if (cur->o_flags & ISCURSED)
cur->o_ac = -cur->o_ac;
if (cur->o_flags & ISBLESSED) cur->o_ac++;
when R_DIGEST:
if (cur->o_flags & ISCURSED) cur->o_ac = -1;
else if (cur->o_flags & ISBLESSED) cur->o_ac = 2;
else cur->o_ac = 1;
}
when TYP_STICK:
cur->o_type = STICK;
do {
cur->o_which = pick_one(ws_magic, MAXSTICKS);
} while (!allow_curse && ws_magic[cur->o_which].mi_curse == 100);
fix_stick(cur);
if (cursechance < ws_magic[cur->o_which].mi_curse)
cur->o_flags |= ISCURSED;
else if (blesschance < ws_magic[cur->o_which].mi_bless)
cur->o_flags |= ISBLESSED;
when TYP_MM:
cur->o_type = MM;
do {
cur->o_which = pick_one(m_magic, MAXMM);
} while (!allow_curse && m_magic[cur->o_which].mi_curse == 100);
cur->o_weight = things[TYP_MM].mi_wght;
if (cursechance < m_magic[cur->o_which].mi_curse)
cur->o_flags |= ISCURSED;
else if (blesschance < m_magic[cur->o_which].mi_bless)
cur->o_flags |= ISBLESSED;
switch (cur->o_which) {
case MM_JUG:
switch(rnd(11)) {
case 0: cur->o_ac = P_PHASE;
when 1: cur->o_ac = P_CLEAR;
when 2: cur->o_ac = P_SEEINVIS;
when 3: cur->o_ac = P_HEALING;
when 4: cur->o_ac = P_MFIND;
when 5: cur->o_ac = P_TFIND;
when 6: cur->o_ac = P_HASTE;
when 7: cur->o_ac = P_RESTORE;
when 8: cur->o_ac = P_FLY;
when 9: cur->o_ac = P_SKILL;
when 10:cur->o_ac = P_FFIND;
}
when MM_OPEN:
cur->o_ac = (4 + rnd(5)) * 5;
when MM_HUNGER:
case MM_DRUMS:
case MM_DISAPPEAR:
case MM_CHOKE:
case MM_KEOGHTOM:
cur->o_ac = 3 + (rnd(3)+1) * 3;
when MM_BRACERS:
if (cur->o_flags & ISCURSED)
cur->o_ac = -(rnd(3)+1);
else
cur->o_ac = rnd(8)+1;
when MM_PROTECT:
if (cur->o_flags & ISCURSED)
cur->o_ac = -(rnd(3)+1);
else
cur->o_ac = rnd(5)+1;
when MM_DISP:
cur->o_ac = 2;
when MM_SKILLS: /* set it to a character class */
cur->o_ac = rnd(NUM_CHARTYPES-1);
otherwise:
cur->o_ac = 0;
}
otherwise:
debug("Picked a bad kind of object");
wait_for(' ');
}
return item;
}
/*
* provide a new item tailored to specification
*/
struct linked_list *
spec_item(type, which, hit, damage)
int type, which, hit, damage;
{
register struct linked_list *item;
register struct object *obj;
item = new_item(sizeof *obj);
obj = OBJPTR(item);
obj->o_count = 1;
obj->o_group = 0;
obj->contents = NULL;
obj->o_type = type;
obj->o_which = which;
strncpy(obj->o_damage, "0d0", sizeof(obj->o_damage));
strncpy(obj->o_hurldmg, "0d0", sizeof(obj->o_hurldmg));
obj->o_hplus = 0;
obj->o_dplus = 0;
obj->o_flags = 0;
obj->o_mark[0] = '\0';
obj->o_text = NULL;
obj->o_launch = 0;
obj->o_weight = 0;
/* Handle special characteristics */
switch (type) {
case WEAPON:
init_weapon(obj, which);
obj->o_hplus = hit;
obj->o_dplus = damage;
obj->o_ac = 10;
if (hit > 0 || damage > 0) obj->o_flags |= ISBLESSED;
else if (hit < 0 || damage < 0) obj->o_flags |= ISCURSED;
when ARMOR:
obj->o_ac = armors[which].a_class - hit;
if (hit > 0) obj->o_flags |= ISBLESSED;
else if (hit < 0) obj->o_flags |= ISCURSED;
when RING:
obj->o_ac = hit;
switch (obj->o_which) {
case R_ADDSTR:
case R_ADDWISDOM:
case R_ADDINTEL:
case R_PROTECT:
case R_ADDHIT:
case R_ADDDAM:
case R_DIGEST:
if (hit > 1) obj->o_flags |= ISBLESSED;
else if (hit < 0) obj->o_flags |= ISCURSED;
}
when STICK:
fix_stick(obj);
obj->o_charges = hit;
when GOLD:
obj->o_type = GOLD;
obj->o_count = GOLDCALC;
obj->o_ac = 11;
when MM:
obj->o_type = MM;
obj->o_ac = hit;
when RELIC:
/* Handle weight here since these are all created uniquely */
obj->o_weight = things[TYP_RELIC].mi_wght;
if (obj->o_which == EMORI_CLOAK)
obj->o_charges = 1;
}
return(item);
}
/*
* 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(1000); magic < end; magic++)
if (i < magic->mi_prob)
break;
if (magic == end)
{
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);
}
magic = start;
}
return (int) (magic - start);
}
/* blesscurse returns whether, according to the flag, the object is
* blessed, cursed, or neither
*/
char *
blesscurse(flags)
int flags;
{
if (flags & ISKNOW) {
if (flags & ISCURSED) return("cursed ");
if (flags & ISBLESSED) return("blessed ");
return("normal ");
}
return("");
}
/*
* p_kind returns the type of potion for some types of identified potions;
* otherwise, it returns the color.
*/
char *
p_kind(obj)
struct object *obj; /* We assume that obj points to a potion */
{
if (obj->o_which == P_ABIL) return(abilities[obj->o_kind]);
else return(p_colors[obj->o_which]);
}
/*
* extras:
* Return the number of extra items to be created
*/
extras()
{
reg int i;
i = rnd(100);
if (i < 4) /* 4% for 2 more */
return (2);
else if (i < 11) /* 7% for 1 more */
return (1);
else /* otherwise no more */
return (0);
}

539
arogue7/trader.c Normal file
View file

@ -0,0 +1,539 @@
/*
* trader.c - Anything to do with trading posts
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Anything to do with trading posts
*/
#include "curses.h"
#include "rogue.h"
/*
* buy_it:
* Buy the item on which the hero stands
*/
buy_it()
{
reg int wh;
struct linked_list *item;
if (purse <= 0) {
msg("You have no money.");
return;
}
if (curprice < 0) { /* if not yet priced */
wh = price_it();
if (!wh) /* nothing to price */
return;
msg("Do you want to buy it? ");
do {
wh = tolower(readchar());
if (wh == ESCAPE || wh == 'n') {
msg("");
return;
}
} until(wh == 'y');
}
mpos = 0;
if (curprice > purse) {
msg("You can't afford to buy that %s !",curpurch);
return;
}
/*
* See if the hero has done all his transacting
*/
if (!open_market())
return;
/*
* The hero bought the item here
*/
item = find_obj(hero.y, hero.x);
mpos = 0;
if (add_pack(NULL, TRUE, &item)) { /* try to put it in his pack */
purse -= curprice; /* take his money */
++trader; /* another transaction */
trans_line(); /* show remaining deals */
curprice = -1; /* reset stuff */
curpurch[0] = 0;
whatis (item); /* identify it after purchase */
(OBJPTR(item))->o_flags &= ~ISPOST; /* turn off ISPOST */
msg("%s", inv_name(OBJPTR(item), TRUE));
}
}
/*
* do_post:
* Put a trading post room and stuff on the screen
*/
do_post(startup)
bool startup; /* True if equipping the player at the beginning of the game */
{
coord tp;
reg int i, j, k;
reg struct room *rp;
reg struct object *op;
reg struct linked_list *ll;
o_free_list(lvl_obj); /* throw old items away */
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
rp->r_flags = ISGONE; /* kill all rooms */
rp = &rooms[0]; /* point to only room */
rp->r_flags = 0; /* this room NOT gone */
rp->r_max.x = 40;
rp->r_max.y = 10; /* 10 * 40 room */
rp->r_pos.x = (cols - rp->r_max.x) / 2; /* center horizontal */
rp->r_pos.y = 1; /* 2nd line */
draw_room(rp); /* draw the only room */
/* Are we equipping the player? */
if (startup) {
int wpt;
/*
* Give the rogue some weaponry.
*/
for (wpt=0; wpt<MAXWEAPONS; wpt++) {
ll = spec_item(WEAPON, wpt, rnd(2), rnd(2)+1);
attach(lvl_obj, ll);
op = OBJPTR(ll);
op->o_flags |= (ISPOST | ISKNOW);
do {
rnd_pos(rp,&tp);
} until (mvinch(tp.y, tp.x) == FLOOR);
op->o_pos = tp;
mvaddch(tp.y,tp.x,op->o_type);
}
/*
* And his suit of armor.......
* Thieves can only wear leather armor,
* so make sure some is available for them.
*/
for (i=0; i<MAXARMORS; i++) {
ll = spec_item(ARMOR, i, 0, 0);
attach(lvl_obj, ll);
op = OBJPTR(ll);
op->o_flags |= (ISPOST | ISKNOW);
op->o_weight = armors[i].a_wght;
do {
rnd_pos(rp,&tp);
} until (mvinch(tp.y, tp.x) == FLOOR);
op->o_pos = tp;
mvaddch(tp.y,tp.x,op->o_type);
}
/* Now create some wands */
for (i=rnd(4)+2; i>0; i--) {
switch (rnd(8)) {
case 0: j = WS_SLOW_M;
when 1: j = WS_TELMON;
when 2: j = WS_CONFMON;
when 3: j = WS_PARALYZE;
when 4: j = WS_MDEG;
when 5: j = WS_WONDER;
when 6: j = WS_FEAR;
when 7: j = WS_LIGHT;
}
ll = spec_item(STICK, j, 0, 0);
attach(lvl_obj, ll);
op = OBJPTR(ll);
/* Let clerics and MU'S know what kind they are */
switch (player.t_ctype) {
case C_MAGICIAN:
case C_CLERIC:
case C_DRUID:
op->o_flags |= (ISPOST | ISKNOW);
otherwise:
op->o_flags |= ISPOST;
}
fix_stick(op);
do {
rnd_pos(rp,&tp);
} until (mvinch(tp.y, tp.x) == FLOOR);
op->o_pos = tp;
mvaddch(tp.y,tp.x,op->o_type);
}
/* Now let's make some rings */
for (i=rnd(4)+3; i>0; i--) {
k = 0;
switch (rnd(15)) {
case 0: j = R_PROTECT; k = roll(1,2);
when 1: j = R_ADDSTR; k = roll(1,3);
when 2: j = R_ADDHIT; k = roll(1,3);
when 3: j = R_ADDDAM; k = roll(1,3);
when 4: j = R_DIGEST; k = 1;
when 5: j = R_ADDINTEL; k = roll(1,3);
when 6: j = R_ADDWISDOM;k = roll(1,3);
when 7: j = R_SUSABILITY;
when 8: j = R_SEEINVIS;
when 9: j = R_ALERT;
when 10:j = R_HEALTH;
when 11:j = R_HEROISM;
when 12:j = R_FIRE;
when 13:j = R_WARMTH;
when 14:j = R_FREEDOM;
}
ll = spec_item(RING, j, k, 0);
attach(lvl_obj, ll);
op = OBJPTR(ll);
/*
* Let fighters, assassins, monks, and thieves know what kind
* of rings these are.
*/
switch (player.t_ctype) {
case C_FIGHTER:
case C_THIEF:
case C_ASSASIN:
case C_MONK:
op->o_flags |= (ISPOST | ISKNOW);
otherwise:
op->o_flags |= ISPOST;
}
do {
rnd_pos(rp,&tp);
} until (mvinch(tp.y, tp.x) == FLOOR);
op->o_pos = tp;
mvaddch(tp.y,tp.x,op->o_type);
}
/* Let's offer some potions */
for (i=rnd(3)+1; i>0; i--) {
/* Choose the type of potion */
if (i == 1 && player.t_ctype == C_ASSASIN) j = P_POISON;
else switch (rnd(8)) {
case 0: j = P_CLEAR;
when 1: j = P_HEALING;
when 2: j = P_MFIND;
when 3: j = P_TFIND;
when 4: j = P_HASTE;
when 5: j = P_RESTORE;
when 6: j = P_FLY;
when 7: j = P_FFIND;
}
/* Make the potion */
ll = spec_item(POTION, j, 0, 0);
attach(lvl_obj, ll);
op = OBJPTR(ll);
op->o_flags |= ISPOST;
/* Place the potion */
do {
rnd_pos(rp,&tp);
} until (mvinch(tp.y, tp.x) == FLOOR);
op->o_pos = tp;
mvaddch(tp.y,tp.x,op->o_type);
}
/* Let's offer some scrolls */
for (i=rnd(3)+1; i>0; i--) {
/* Choose the type of scrolls */
switch (rnd(8)) {
case 0: j = S_CONFUSE;
when 1: j = S_MAP;
when 2: j = S_LIGHT;
when 3: j = S_SLEEP;
when 4: j = S_IDENT;
when 5: j = S_GFIND;
when 6: j = S_REMOVE;
when 7: j = S_CURING;
}
/* Make the scroll */
ll = spec_item(SCROLL, j, 0, 0);
attach(lvl_obj, ll);
op = OBJPTR(ll);
op->o_flags |= ISPOST;
/* Place the scroll */
do {
rnd_pos(rp,&tp);
} until (mvinch(tp.y, tp.x) == FLOOR);
op->o_pos = tp;
mvaddch(tp.y,tp.x,op->o_type);
}
/* And finally, let's get some food */
for (i=rnd(3)+1; i>0; i--) {
ll = spec_item(FOOD, 0, 0, 0);
attach(lvl_obj, ll);
op = OBJPTR(ll);
op->o_weight = things[TYP_FOOD].mi_wght;
op->o_flags |= ISPOST;
do {
rnd_pos(rp,&tp);
} until (mvinch(tp.y, tp.x) == FLOOR);
op->o_pos = tp;
mvaddch(tp.y,tp.x,op->o_type);
}
}
else {
i = roll(10, 4); /* 10 to 40 items */
for (; i > 0 ; i--) { /* place all the items */
ll = new_thing(ALL, TRUE); /* get something */
attach(lvl_obj, ll);
op = OBJPTR(ll);
op->o_flags |= ISPOST; /* object in trading post */
do {
rnd_pos(rp,&tp);
} until (mvinch(tp.y, tp.x) == FLOOR);
op->o_pos = tp;
mvaddch(tp.y,tp.x,op->o_type);
}
}
wmove(cw,12,0);
trader = 0;
if (startup) {
waddstr(cw,"Welcome to Friendly Fiend's Equipage\n\r");
waddstr(cw,"====================================\n\r");
}
else {
waddstr(cw,"Welcome to Friendly Fiend's Flea Market\n\r");
waddstr(cw,"=======================================\n\r");
}
waddstr(cw,"$: Prices object that you stand upon.\n\r");
waddstr(cw,"#: Buys the object that you stand upon.\n\r");
waddstr(cw,"%: Trades in something in your pack for gold.\n\r");
trans_line();
}
/*
* get_worth:
* Calculate an objects worth in gold
*/
get_worth(obj)
reg struct object *obj;
{
reg int worth, wh;
worth = 0;
wh = obj->o_which;
switch (obj->o_type) {
case FOOD:
worth = 2;
when WEAPON:
if (wh < MAXWEAPONS) {
worth = weaps[wh].w_worth;
worth += s_magic[S_ALLENCH].mi_worth *
(obj->o_hplus + obj->o_dplus);
}
when ARMOR:
if (wh < MAXARMORS) {
worth = armors[wh].a_worth;
worth += s_magic[S_ALLENCH].mi_worth *
(armors[wh].a_class - obj->o_ac);
}
when SCROLL:
if (wh < MAXSCROLLS)
worth = s_magic[wh].mi_worth;
when POTION:
if (wh < MAXPOTIONS)
worth = p_magic[wh].mi_worth;
when RING:
if (wh < MAXRINGS) {
worth = r_magic[wh].mi_worth;
worth += obj->o_ac * 40;
}
when STICK:
if (wh < MAXSTICKS) {
worth = ws_magic[wh].mi_worth;
worth += 20 * obj->o_charges;
}
when MM:
if (wh < MAXMM) {
worth = m_magic[wh].mi_worth;
switch (wh) {
case MM_BRACERS: worth += 40 * obj->o_ac;
when MM_PROTECT: worth += 60 * obj->o_ac;
when MM_DISP: /* ac already figured in price*/
otherwise: worth += 20 * obj->o_ac;
}
}
when RELIC:
if (wh < MAXRELIC) {
worth = rel_magic[wh].mi_worth;
if (wh == quest_item) worth *= 10;
}
otherwise:
worth = 0;
}
if (obj->o_flags & ISPROT) /* 300% more for protected */
worth *= 3;
if (obj->o_flags & ISBLESSED) /* 50% more for blessed */
worth = worth * 3 / 2;
if (obj->o_flags & ISCURSED) /* half for cursed */
worth /= 2;
if (worth < 0)
worth = 0;
return worth;
}
/*
* open_market:
* Retruns TRUE when ok do to transacting
*/
open_market()
{
if (trader >= MAXPURCH && !wizard && level != 0) {
msg("The market is closed. The stairs are that-a-way.");
return FALSE;
}
else {
return TRUE;
}
}
/*
* price_it:
* Price the object that the hero stands on
*/
price_it()
{
reg struct linked_list *item;
reg struct object *obj;
reg int worth;
reg char *str;
if (!open_market()) /* after buying hours */
return FALSE;
if ((item = find_obj(hero.y,hero.x)) == NULL) {
debug("Can't find the item");
return FALSE;
}
obj = OBJPTR(item);
worth = get_worth(obj);
if (worth < 0) {
msg("That's not for sale.");
return FALSE;
}
if (worth < 25)
worth = 25;
/* Our shopkeeper is affected by the person's charisma */
worth = (int) ((float) worth * (17. / (float)pstats.s_charisma));
str = inv_name(obj, TRUE);
msg("%s for only %d pieces of gold", str, worth);
curprice = worth; /* save price */
strcpy(curpurch,str); /* save item */
return TRUE;
}
/*
* sell_it:
* Sell an item to the trading post
*/
sell_it()
{
reg struct linked_list *item;
reg struct object *obj;
reg int wo, ch;
if (!open_market()) /* after selling hours */
return;
if ((item = get_item(pack, "sell", ALL, FALSE, FALSE)) == NULL)
return;
obj = OBJPTR(item);
wo = get_worth(obj);
if (wo <= 0) {
mpos = 0;
msg("We don't buy those.");
return;
}
if (wo < 25)
wo = 25;
msg("Your %s is worth %d pieces of gold.",typ_name(obj),wo);
msg("Do you want to sell it? ");
do {
ch = tolower(readchar());
if (ch == ESCAPE || ch == 'n') {
msg("");
return;
}
} until (ch == 'y');
mpos = 0;
if (drop(item) == TRUE) { /* drop this item */
purse += wo; /* give him his money */
++trader; /* another transaction */
wo = obj->o_count;
if (obj->o_group == 0) /* dropped one at a time */
obj->o_count = 1;
msg("Sold %s",inv_name(obj,TRUE));
obj->o_count = wo;
trans_line(); /* show remaining deals */
}
}
/*
* trans_line:
* Show how many transactions the hero has left
*/
trans_line()
{
if (level == 0)
sprintf(prbuf, "You are welcome to spend whatever you have.");
else if (!wizard)
sprintf(prbuf,"You have %d transactions remaining.",
MAXPURCH - trader);
else
sprintf(prbuf,
"You have infinite transactions remaining oh great wizard.");
mvwaddstr(cw,lines - 3,0,prbuf);
}
/*
* typ_name:
* Return the name for this type of object
*/
char *
typ_name(obj)
reg struct object *obj;
{
static char buff[20];
reg int wh;
switch (obj->o_type) {
case POTION: wh = TYP_POTION;
when SCROLL: wh = TYP_SCROLL;
when STICK: wh = TYP_STICK;
when RING: wh = TYP_RING;
when ARMOR: wh = TYP_ARMOR;
when WEAPON: wh = TYP_WEAPON;
when MM: wh = TYP_MM;
when FOOD: wh = TYP_FOOD;
when RELIC: wh = TYP_RELIC;
otherwise: wh = -1;
}
if (wh < 0)
strcpy(buff,"unknown");
else
strcpy(buff,things[wh].mi_name);
return (buff);
}

1283
arogue7/util.c Normal file

File diff suppressed because it is too large Load diff

24
arogue7/vers.c Normal file
View file

@ -0,0 +1,24 @@
/*
* vers.c - version number
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* version number. Whenever a new version number is desired, use
* sccs to get vers.c. Environ and encstr are declared here to
* force them to be loaded before the version number, and therefore
* not to be written in saved games.
*/
char encstr[] = "\354\251\243\332A\201|\301\321p\210\251\327\"\257\365t\341%3\271^`~\203z{\341};\f\341\231\222e\234\351]\321\234";
char version[] = "@(#)vers.c 7.7 (Bell Labs) 07/07/86";
char *release = "7.7.1";

402
arogue7/weapons.c Normal file
View file

@ -0,0 +1,402 @@
/*
* weapons.c - Functions for dealing with problems brought about by weapons
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Functions for dealing with problems brought about by weapons
*
*/
#include "curses.h"
#include <ctype.h>
#include "rogue.h"
boomerang(ydelta, xdelta, item, tp)
int ydelta, xdelta;
register struct linked_list *item;
register struct thing *tp;
{
register struct object *obj;
struct thing midpoint;
coord oldpos;
obj = OBJPTR(item);
oldpos = obj->o_pos;
/*
* make it appear to fly at the target
*/
do_motion(obj, ydelta, xdelta, tp);
hit_monster(unc(obj->o_pos), obj, tp);
/*
* Now let's make it fly back to the wielder. We need to
* use midpoint to fool do_motion into thinking the action
* starts there. Do_motion only looks at the t_pos field.
*/
midpoint.t_pos = obj->o_pos; /* Simulate a new start position */
do_motion(obj, -ydelta, -xdelta, &midpoint);
obj->o_pos = oldpos;
}
/*
* do the actual motion on the screen done by an object traveling
* across the room. Note that we should not look at any field in
* tp other than t_pos unless we change boomerang().
*/
do_motion(obj, ydelta, xdelta, tp)
register struct object *obj;
register int ydelta, xdelta;
register struct thing *tp;
{
/*
* Come fly with us ...
*/
obj->o_pos = tp->t_pos;
for (; ;) {
register int ch;
/*
* Erase the old one
*/
if (!ce(obj->o_pos, tp->t_pos) &&
cansee(unc(obj->o_pos)) &&
mvwinch(cw, obj->o_pos.y, obj->o_pos.x) != ' ') {
mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, show(obj->o_pos.y, obj->o_pos.x));
}
/*
* Get the new position
*/
obj->o_pos.y += ydelta;
obj->o_pos.x += xdelta;
if (shoot_ok(ch = winat(obj->o_pos.y, obj->o_pos.x)) && ch != DOOR && !ce(obj->o_pos, hero)) {
/*
* It hasn't hit anything yet, so display it
* If it alright.
*/
if (cansee(unc(obj->o_pos)) &&
mvwinch(cw, obj->o_pos.y, obj->o_pos.x) != ' ') {
mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, obj->o_type);
draw(cw);
}
continue;
}
/*
* Did we stop because of a monster or the hero? If we did
* not, we want to move our position back one because we could
* not actually make it this far.
*/
if (!isalpha(ch) &&
!(obj->o_pos.y == hero.y && obj->o_pos.x == hero.x)) {
obj->o_pos.y -= ydelta;
obj->o_pos.x -= xdelta;
}
break;
}
}
/*
* fall:
* Drop an item someplace around here.
*/
fall(item, pr)
register struct linked_list *item;
bool pr;
{
register struct object *obj;
register struct room *rp;
register int i;
struct object *tobj;
struct linked_list *titem;
coord *fpos;
obj = OBJPTR(item);
/*
* try to drop the item, look up to 3 squares away for now
*/
for (i=1; i<4; i++) {
if ((fpos = fallpos(&obj->o_pos, FALSE, i)) != NULL)
break;
}
if (fpos != NULL) {
if (obj->o_group) { /* try to add groups together */
for(titem=lvl_obj; titem!=NULL; titem=next(titem)) {
tobj = OBJPTR(titem);
if (tobj->o_group == obj->o_group &&
tobj->o_pos.y == fpos->y &&
tobj->o_pos.x == fpos->x) {
tobj->o_count += obj->o_count;
o_discard(item);
return;
}
}
}
mvaddch(fpos->y, fpos->x, obj->o_type);
obj->o_pos = *fpos;
if ((rp = roomin(&hero)) != NULL &&
lit_room(rp)) {
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
attach(lvl_obj, item);
return;
}
if (pr) {
msg("The %s vanishes as it hits the ground.",
weaps[obj->o_which].w_name);
}
o_discard(item);
}
/*
* Does the missile hit the monster
*/
hit_monster(y, x, obj, tp)
register int y, x;
struct object *obj;
register struct thing *tp;
{
static coord mp;
mp.y = y;
mp.x = x;
if (tp == &player) {
/* Make sure there is a monster where it landed */
if (!isalpha(mvwinch(mw, y, x))) {
return(FALSE);
}
/* Player hits monster */
return(fight(&mp, obj, TRUE));
} else {
if (!ce(mp, hero)) {
/* Monster hits monster */
return(skirmish(tp, &mp, obj, TRUE));
}
/* Monster hits player */
return(attack(tp, obj, TRUE));
}
}
/*
* init_weapon:
* Set up the initial goodies for a weapon
*/
init_weapon(weap, type)
register struct object *weap;
char type;
{
register struct init_weps *iwp;
iwp = &weaps[type];
strncpy(weap->o_damage, iwp->w_dam, sizeof(weap->o_damage));
strncpy(weap->o_hurldmg, iwp->w_hrl, sizeof(weap->o_hurldmg));
weap->o_launch = iwp->w_launch;
weap->o_flags = iwp->w_flags;
weap->o_weight = iwp->w_wght;
if (weap->o_flags & ISMANY) {
weap->o_count = rnd(8) + 8;
weap->o_group = newgrp();
} else {
weap->o_count = 1;
}
}
/*
* missile:
* Fire a missile in a given direction
*/
missile(ydelta, xdelta, item, tp)
int ydelta, xdelta;
register struct linked_list *item;
register struct thing *tp;
{
register struct object *obj;
register struct linked_list *nitem;
char ch;
/*
* Get which thing we are hurling
*/
if (item == NULL) {
return;
}
obj = OBJPTR(item);
if (obj->o_type == RELIC && obj->o_which == AXE_AKLAD) {
boomerang(ydelta, xdelta, item, tp);
return;
}
if (!dropcheck(obj)) return; /* Can we get rid of it? */
if(!(obj->o_flags & ISMISL)) {
while (TRUE) {
msg(terse ? "Really throw? (y or n): "
: "Do you really want to throw %s? (y or n): ",
inv_name(obj, TRUE));
mpos = 0;
ch = readchar();
if (ch == 'n' || ch == ESCAPE) {
after = FALSE;
return;
}
if (ch == 'y')
break;
}
}
/*
* 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(tp->t_pack, item);
if (tp->t_pack == pack) {
inpack--;
}
}
else {
obj->o_count--;
nitem = (struct linked_list *) new_item(sizeof *obj);
obj = OBJPTR(nitem);
*obj = *(OBJPTR(item));
obj->o_count = 1;
item = nitem;
}
updpack(FALSE, tp);
do_motion(obj, ydelta, xdelta, tp);
/*
* 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 (!hit_monster(unc(obj->o_pos), obj, tp)) {
fall(item, TRUE);
}
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
/*
* num:
* Figure out the plus number for armor/weapons
*/
char *
num(n1, n2)
register int n1, n2;
{
static char numbuf[LINELEN];
if (n1 == 0 && n2 == 0) {
return "+0";
}
if (n2 == 0) {
sprintf(numbuf, "%s%d", n1 < 0 ? "" : "+", n1);
} else {
sprintf(numbuf, "%s%d, %s%d", n1 < 0 ? "" : "+", n1, n2 < 0 ? "" : "+", n2);
}
return(numbuf);
}
/*
* wield:
* Pull out a certain weapon
*/
wield()
{
register struct linked_list *item;
register struct object *obj, *oweapon;
/*
* It takes 2 movement periods to unwield a weapon and 2 movement
* periods to wield a weapon.
*/
if (player.t_action != C_WIELD) {
player.t_action = C_WIELD;
player.t_using = NULL; /* Make sure this is NULL! */
if (cur_weapon != NULL) {
player.t_no_move = 2 * movement(&player);
return;
}
}
if ((oweapon = cur_weapon) != NULL) {
/* At this point we have waited at least 2 units */
if (!dropcheck(cur_weapon)) {
cur_weapon = oweapon;
player.t_action = A_NIL;
return;
}
if (terse)
addmsg("Was ");
else
addmsg("You were ");
msg("wielding %s", inv_name(oweapon, TRUE));
}
/* We we have something picked out? */
if (player.t_using == NULL) {
/* Now, what does he want to wield? */
if ((item = get_item(pack, "wield", WIELDABLE, FALSE, FALSE)) == NULL) {
player.t_action = A_NIL;
after = FALSE;
return;
}
player.t_using = item;
player.t_no_move = 2 * movement(&player);
return;
}
/* We have waited our time, let's wield the weapon */
item = player.t_using;
player.t_using = NULL;
player.t_action = A_NIL;
obj = OBJPTR(item);
if (is_current(obj)) {
msg("Item in use.");
after = FALSE;
return;
}
if (player.t_ctype != C_FIGHTER &&
player.t_ctype != C_RANGER &&
player.t_ctype != C_PALADIN &&
obj->o_type == WEAPON &&
(obj->o_which == TWOSWORD ||
(obj->o_which == BASWORD &&
player.t_ctype != C_ASSASIN))) {
msg("Only fighter types can wield a %s",
weaps[obj->o_which].w_name);
return;
}
if (terse) {
addmsg("W");
} else {
addmsg("You are now w");
}
msg("ielding %s", inv_name(obj, TRUE));
cur_weapon = obj;
}

431
arogue7/wear.c Normal file
View file

@ -0,0 +1,431 @@
/*
* wear.c - functions for dealing with armor
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* This file contains misc functions for dealing with armor
*/
#include "curses.h"
#include "rogue.h"
/*
* take_off:
* Get the armor off of the players back
*/
take_off()
{
register struct object *obj;
register struct linked_list *item;
/* It takes time to take things off */
if (player.t_action != C_TAKEOFF) {
/* What does player want to take off? */
if ((item = get_item(pack, "take off", REMOVABLE, FALSE, FALSE))==NULL)
return;
obj = OBJPTR(item);
if (!is_current(obj)) {
msg("Not wearing %c) %s", pack_char(pack, obj),inv_name(obj, TRUE));
return;
}
player.t_using = item; /* Remember what it is */
player.t_action = C_TAKEOFF; /* We are taking something off */
/* Cursed items take almost no time */
if (obj->o_flags & ISCURSED) player.t_no_move = movement(&player);
else player.t_no_move = dress_units(item) * movement(&player);
return;
}
/* We have waited our time, let's take off our item */
item = player.t_using;
player.t_using = NULL;
player.t_action = A_NIL;
obj = OBJPTR(item);
if (!is_current(obj)) { /* Just to be on the safe side */
msg("Not wearing %c) %s", pack_char(pack, obj),inv_name(obj, TRUE));
return;
}
/* Can the player remove the item? */
if (!dropcheck(obj)) return;
updpack(TRUE, &player);
msg("Was wearing %c) %s", pack_char(pack, obj),inv_name(obj,TRUE));
}
/*
* wear:
* The player wants to wear something, so let him/her put it on.
*/
wear()
{
register struct linked_list *item;
register struct object *obj;
register int i;
/* It takes time to put things on */
if (player.t_action != C_WEAR) {
/* What does player want to wear? */
if ((item = get_item(pack, "wear", WEARABLE, FALSE, FALSE)) == NULL)
return;
obj = OBJPTR(item);
switch (obj->o_type) {
case ARMOR:
if (cur_armor != NULL) {
addmsg("You are already wearing armor");
if (!terse) addmsg(". You'll have to take it off first.");
endmsg();
after = FALSE;
return;
}
if (player.t_ctype == C_MONK) {
msg("Monks can't wear armor!");
return;
}
if (cur_misc[WEAR_BRACERS] != NULL) {
msg("You can't wear armor with bracers of defense.");
return;
}
if (cur_misc[WEAR_CLOAK] != NULL || cur_relic[EMORI_CLOAK]) {
msg("You can't wear armor with a cloak.");
return;
}
if (player.t_ctype == C_THIEF &&
(obj->o_which != LEATHER &&
obj->o_which != STUDDED_LEATHER)) {
if (terse) msg("Thieves can't wear that type of armor");
else
msg("Thieves can only wear leather or studded leather armor");
return;
}
if (player.t_ctype == C_ASSASIN &&
(obj->o_which != LEATHER &&
obj->o_which != STUDDED_LEATHER)) {
if (terse) msg("Assassins can't wear that type of armor");
else
msg("Assassins can only wear leather or studded leather armor");
return;
}
when MM:
switch (obj->o_which) {
/*
* when wearing the boots of elvenkind the player will not
* set off any traps
*/
case MM_ELF_BOOTS:
if (cur_misc[WEAR_BOOTS] != NULL) {
msg("Already wearing a pair of boots");
return;
}
/*
* when wearing the boots of dancing the player will dance
* uncontrollably
*/
when MM_DANCE:
if (cur_misc[WEAR_BOOTS] != NULL) {
msg("Already wearing a pair of boots");
return;
}
/*
* bracers give the hero protection in he same way armor does.
* they cannot be used with armor but can be used with cloaks
*/
when MM_BRACERS:
if (cur_misc[WEAR_BRACERS] != NULL) {
msg("Already wearing bracers");
return;
}
else {
if (cur_armor != NULL) {
msg("You can't wear bracers of defense with armor.");
return;
}
}
/*
* The robe (cloak) of powerlessness disallows any spell casting
*/
when MM_R_POWERLESS:
/*
* the cloak of displacement gives the hero an extra +2 on AC
* and saving throws. Cloaks cannot be used with armor.
*/
case MM_DISP:
/*
* the cloak of protection gives the hero +n on AC and saving
* throws with a max of +3 on saves
*/
case MM_PROTECT:
if (cur_misc[WEAR_CLOAK] != NULL ||
cur_relic[EMORI_CLOAK]) {
msg("%slready wearing a cloak.", terse ? "A"
: "You are a");
return;
}
else {
if (cur_armor != NULL) {
msg("You can't wear a cloak with armor.");
return;
}
}
/*
* the gauntlets of dexterity give the hero a dexterity of 18
* the gauntlets of ogre power give the hero a strength of 18
* the gauntlets of fumbling cause the hero to drop his weapon
*/
when MM_G_DEXTERITY:
case MM_G_OGRE:
case MM_FUMBLE:
if (cur_misc[WEAR_GAUNTLET] != NULL) {
msg("Already wearing a pair of gauntlets.");
return;
}
/*
* the jewel of attacks does an aggavate monster
*/
when MM_JEWEL:
if (cur_misc[WEAR_JEWEL] != NULL ||
cur_relic[YENDOR_AMULET] ||
cur_relic[STONEBONES_AMULET]) {
msg("Already wearing an amulet.");
return;
}
/*
* the necklace of adaption makes the hero immune to
* chlorine gas
*/
when MM_ADAPTION:
if (cur_misc[WEAR_NECKLACE] != NULL) {
msg("Already wearing a necklace");
return;
}
/*
* the necklace of stragulation will try to strangle the
* hero to death
*/
when MM_STRANGLE:
if (cur_misc[WEAR_NECKLACE] != NULL) {
msg("Already wearing a necklace");
return;
}
otherwise:
msg("what a strange item you have!");
return;
}
when RING:
if (cur_misc[WEAR_GAUNTLET] != NULL) {
msg ("You have to remove your gauntlets first!");
return;
}
/* Is there room to put the ring on */
for (i=0; i<NUM_FINGERS; i++)
if (cur_ring[i] == NULL) {
break;
}
if (i == NUM_FINGERS) { /* No room */
if (terse) msg("Wearing enough rings");
else msg("You already have on eight rings");
return;
}
}
player.t_using = item; /* Remember what it is */
player.t_action = C_WEAR; /* We are taking something off */
player.t_no_move = dress_units(item) * movement(&player);
return;
}
/* We have waited our time, let's put on our item */
item = player.t_using;
player.t_using = NULL;
player.t_action = A_NIL;
obj = OBJPTR(item);
switch (obj->o_type) {
case ARMOR:
obj->o_flags |= ISKNOW;
cur_armor = obj;
addmsg(terse ? "W" : "You are now w");
msg("earing %s.", armors[obj->o_which].a_name);
when MM:
switch (obj->o_which) {
/*
* when wearing the boots of elvenkind the player will not
* set off any traps
*/
case MM_ELF_BOOTS:
msg("Wearing %s",inv_name(obj,TRUE));
cur_misc[WEAR_BOOTS] = obj;
/*
* when wearing the boots of dancing the player will dance
* uncontrollably
*/
when MM_DANCE:
msg("Wearing %s",inv_name(obj,TRUE));
cur_misc[WEAR_BOOTS] = obj;
msg("You begin to dance uncontrollably!");
turn_on(player, ISDANCE);
/*
* bracers give the hero protection in he same way armor does.
* they cannot be used with armor but can be used with cloaks
*/
when MM_BRACERS:
msg("wearing %s",inv_name(obj,TRUE));
cur_misc[WEAR_BRACERS] = obj;
/*
* The robe (cloak) of powerlessness disallows any spell casting
*/
when MM_R_POWERLESS:
/*
* the cloak of displacement gives the hero an extra +2 on AC
* and saving throws. Cloaks cannot be used with armor.
*/
case MM_DISP:
/*
* the cloak of protection gives the hero +n on AC and saving
* throws with a max of +3 on saves
*/
case MM_PROTECT:
msg("wearing %s",inv_name(obj,TRUE));
cur_misc[WEAR_CLOAK] = obj;
/*
* the gauntlets of dexterity give the hero a dexterity of 18
* the gauntlets of ogre power give the hero a strength of 18
* the gauntlets of fumbling cause the hero to drop his weapon
*/
when MM_G_DEXTERITY:
case MM_G_OGRE:
case MM_FUMBLE:
msg("Wearing %s", inv_name(obj,TRUE));
cur_misc[WEAR_GAUNTLET] = obj;
if (obj->o_which == MM_FUMBLE)
daemon(fumble, 0, AFTER);
/*
* the jewel of attacks does an aggavate monster
*/
when MM_JEWEL:
msg("Wearing %s",inv_name(obj,TRUE));
cur_misc[WEAR_JEWEL] = obj;
aggravate(TRUE, TRUE);
/*
* the necklace of adaption makes the hero immune to
* chlorine gas
*/
when MM_ADAPTION:
msg("Wearing %s",inv_name(obj,TRUE));
cur_misc[WEAR_NECKLACE] = obj;
turn_on(player, NOGAS);
/*
* the necklace of stragulation will try to strangle the
* hero to death
*/
when MM_STRANGLE:
msg("Wearing %s",inv_name(obj,TRUE));
cur_misc[WEAR_NECKLACE] = obj;
msg("The necklace is beginning to strangle you!");
daemon(strangle, 0, AFTER);
otherwise:
msg("What a strange item you have!");
}
status(FALSE);
if (m_know[obj->o_which] && m_guess[obj->o_which]) {
free(m_guess[obj->o_which]);
m_guess[obj->o_which] = NULL;
}
else if (!m_know[obj->o_which] &&
askme &&
(obj->o_flags & ISKNOW) == 0 &&
m_guess[obj->o_which] == NULL) {
nameitem(item, FALSE);
}
when RING:
/* If there is room, put on the ring */
for (i=0; i<NUM_FINGERS; i++)
if (cur_ring[i] == NULL) {
cur_ring[i] = obj;
break;
}
if (i == NUM_FINGERS) { /* No room */
if (terse) msg("Wearing enough rings");
else msg("You already have on eight rings");
return;
}
/* Calculate the effect of the ring */
ring_on(item);
}
updpack(TRUE, &player);
}
/*
* dress_units:
* How many movements periods does it take to put on or remove the
* given item of "clothing"?
*/
dress_units(item)
struct linked_list *item;
{
register struct object *obj;
obj = OBJPTR(item);
switch (obj->o_type) {
case ARMOR:
return(10-armors[obj->o_which].a_class);
when RING:
return(2);
when MM:
switch (obj->o_which) {
case MM_ELF_BOOTS:
case MM_DANCE:
/* Boots */
return(4);
when MM_R_POWERLESS:
case MM_DISP:
case MM_PROTECT:
/* Robes */
return(4);
when MM_BRACERS:
case MM_G_DEXTERITY:
case MM_G_OGRE:
case MM_FUMBLE:
/* Hand garments */
return(3);
when MM_JEWEL:
case MM_ADAPTION:
case MM_STRANGLE:
/* Jewelry */
return(2);
otherwise:
return(1); /* What is it? */
}
otherwise:
return(1); /* What is it? */
}
}

696
arogue7/wizard.c Normal file
View file

@ -0,0 +1,696 @@
/*
* wizard.c - Special wizard commands
*
* Advanced Rogue
* Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* Special wizard commands (some of which are also non-wizard commands
* under strange circumstances)
*/
#include "curses.h"
#include <ctype.h>
#include "rogue.h"
#ifdef PC7300
#include "menu.h"
#endif
/*
* create_obj:
* Create any object for wizard, scroll, magician, or cleric
*/
create_obj(prompt, which_item, which_type)
bool prompt;
int which_item, which_type;
{
reg struct linked_list *item;
reg struct object *obj;
reg int wh;
reg char ch, newitem, newtype, whc, msz, *pt;
WINDOW *thiswin;
thiswin = cw;
if (prompt) {
bool nogood = TRUE;
thiswin = hw;
wclear(hw);
wprintw(hw,"Item\t\t\tKey\n\n");
wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_RING].mi_name,RING,
things[TYP_STICK].mi_name,STICK);
wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_POTION].mi_name,POTION,
things[TYP_SCROLL].mi_name,SCROLL);
wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_ARMOR].mi_name,ARMOR,
things[TYP_WEAPON].mi_name,WEAPON);
wprintw(hw,"%s\t%c\n",things[TYP_MM].mi_name,MM);
wprintw(hw,"%s\t\t\t%c\n",things[TYP_FOOD].mi_name,FOOD);
if (wizard) {
wprintw(hw,"%s\t\t%c\n",things[TYP_RELIC].mi_name,RELIC);
waddstr(hw,"monster\t\t\tm");
}
wprintw(hw,"\n\nWhat do you want to create? ");
draw(hw);
do {
ch = wgetch(hw);
if (ch == ESCAPE) {
restscr(cw);
return;
}
switch (ch) {
case RING:
case STICK:
case POTION:
case SCROLL:
case ARMOR:
case WEAPON:
case FOOD:
case MM:
nogood = FALSE;
break;
case RELIC:
case 'm':
if (wizard)
nogood = FALSE;
break;
default:
nogood = TRUE;
}
} while (nogood);
newitem = ch;
}
else
newitem = which_item;
pt = "those";
msz = 0;
if(newitem == 'm') {
/* make monster and be done with it */
wh = makemonster(TRUE, "Creation", "create");
if (wh > 0) {
creat_mons (&player, wh, TRUE);
light(&hero);
}
return;
}
if(newitem == GOLD)
pt = "gold";
/* else if(isatrap(newitem))
pt = "traps";
*/
switch(newitem) {
case POTION: whc = TYP_POTION; msz = MAXPOTIONS;
when SCROLL: whc = TYP_SCROLL; msz = MAXSCROLLS;
when WEAPON: whc = TYP_WEAPON; msz = MAXWEAPONS;
when ARMOR: whc = TYP_ARMOR; msz = MAXARMORS;
when RING: whc = TYP_RING; msz = MAXRINGS;
when STICK: whc = TYP_STICK; msz = MAXSTICKS;
when MM: whc = TYP_MM; msz = MAXMM;
when RELIC: whc = TYP_RELIC; msz = MAXRELIC;
when FOOD: whc = TYP_FOOD; msz = MAXFOODS;
otherwise:
if (thiswin == hw)
restscr(cw);
mpos = 0;
msg("Even wizards can't create %s !!",pt);
return;
}
if(msz == 1) { /* if only one type of item */
ch = 'a';
}
else if (prompt) {
register struct magic_item *wmi;
char wmn;
register int ii;
int old_prob;
mpos = 0;
wmi = NULL;
wmn = 0;
switch(newitem) {
case POTION: wmi = &p_magic[0];
when SCROLL: wmi = &s_magic[0];
when RING: wmi = &r_magic[0];
when STICK: wmi = &ws_magic[0];
when MM: wmi = &m_magic[0];
when RELIC: wmi = &rel_magic[0];
when FOOD: wmi = &foods[0];
when WEAPON: wmn = 1;
when ARMOR: wmn = 2;
}
wclear(hw);
thiswin = hw;
if (wmi != NULL) {
ii = old_prob = 0;
while (ii < msz) {
if(wmi->mi_prob == old_prob && wizard == FALSE) {
msz--; /* can't make a unique item */
}
else {
mvwaddch(hw,ii % 13,ii > 12 ? cols/2 : 0, ii + 'a');
waddstr(hw,") ");
waddstr(hw,wmi->mi_name);
ii++;
}
old_prob = wmi->mi_prob;
wmi++;
}
}
else if (wmn != 0) {
for(ii = 0 ; ii < msz ; ii++) {
mvwaddch(hw,ii % 13,ii > 12 ? cols/2 : 0, ii + 'a');
waddstr(hw,") ");
if(wmn == 1)
waddstr(hw,weaps[ii].w_name);
else
waddstr(hw,armors[ii].a_name);
}
}
sprintf(prbuf,"Which %s? ",things[whc].mi_name);
mvwaddstr(hw,lines - 1, 0, prbuf);
draw(hw);
do {
ch = wgetch(hw);
if (ch == ESCAPE) {
restscr(cw);
msg("");
return;
}
} until (isalpha(ch));
if (thiswin == hw) /* restore screen if need be */
restscr(cw);
newtype = tolower(ch) - 'a';
if(newtype < 0 || newtype >= msz) { /* if an illegal value */
mpos = 0;
msg("There is no such %s",things[whc].mi_name);
return;
}
}
else
newtype = which_type;
item = new_item(sizeof *obj); /* get some memory */
obj = OBJPTR(item);
obj->o_type = newitem; /* store the new items */
obj->o_mark[0] = '\0';
obj->o_which = newtype;
obj->o_group = 0;
obj->contents = NULL;
obj->o_count = 1;
obj->o_flags = 0;
obj->o_dplus = obj->o_hplus = 0;
obj->o_weight = 0;
wh = obj->o_which;
mpos = 0;
if (!wizard) /* users get 0 to +3 */
whc = rnd(4);
else /* wizard gets to choose */
whc = getbless();
if (whc < 0)
obj->o_flags |= ISCURSED;
switch (obj->o_type) {
case WEAPON:
case ARMOR:
if (obj->o_type == WEAPON) {
init_weapon(obj, wh);
obj->o_hplus += whc;
obj->o_dplus += whc;
}
else { /* armor here */
obj->o_weight = armors[wh].a_wght;
obj->o_ac = armors[wh].a_class - whc;
}
when RING:
if (whc > 1 && r_magic[wh].mi_bless != 0)
obj->o_flags |= ISBLESSED;
r_know[wh] = TRUE;
switch(wh) {
case R_ADDSTR:
case R_ADDWISDOM:
case R_ADDINTEL:
case R_PROTECT:
case R_ADDHIT:
case R_ADDDAM:
case R_DIGEST:
obj->o_ac = whc + 1;
break;
default:
obj->o_ac = 0;
}
obj->o_weight = things[TYP_RING].mi_wght;
when MM:
if (whc > 1 && m_magic[wh].mi_bless != 0)
obj->o_flags |= ISBLESSED;
m_know[wh] = TRUE;
switch(wh) {
case MM_JUG:
switch(rnd(11)) {
case 0: obj->o_ac = P_PHASE;
when 1: obj->o_ac = P_CLEAR;
when 2: obj->o_ac = P_SEEINVIS;
when 3: obj->o_ac = P_HEALING;
when 4: obj->o_ac = P_MFIND;
when 5: obj->o_ac = P_TFIND;
when 6: obj->o_ac = P_HASTE;
when 7: obj->o_ac = P_RESTORE;
when 8: obj->o_ac = P_FLY;
when 9: obj->o_ac = P_SKILL;
when 10:obj->o_ac = P_FFIND;
}
when MM_OPEN:
case MM_HUNGER:
case MM_DRUMS:
case MM_DISAPPEAR:
case MM_CHOKE:
case MM_KEOGHTOM:
if (whc < 0)
whc = -whc; /* these cannot be negative */
obj->o_ac = (whc + 1) * 5;
break;
when MM_BRACERS:
obj->o_ac = whc * 2 + 1;
when MM_DISP:
obj->o_ac = 2;
when MM_PROTECT:
obj->o_ac = whc;
when MM_SKILLS:
if (wizard && whc != 0)
obj->o_ac = rnd(NUM_CHARTYPES-1);
else
obj->o_ac = player.t_ctype;
otherwise:
obj->o_ac = 0;
}
obj->o_weight = things[TYP_MM].mi_wght;
when STICK:
if (whc > 1 && ws_magic[wh].mi_bless != 0)
obj->o_flags |= ISBLESSED;
ws_know[wh] = TRUE;
fix_stick(obj);
when SCROLL:
if (whc > 1 && s_magic[wh].mi_bless != 0)
obj->o_flags |= ISBLESSED;
obj->o_weight = things[TYP_SCROLL].mi_wght;
s_know[wh] = TRUE;
when POTION:
if (whc > 1 && p_magic[wh].mi_bless != 0)
obj->o_flags |= ISBLESSED;
obj->o_weight = things[TYP_POTION].mi_wght;
if (wh == P_ABIL) obj->o_kind = rnd(NUMABILITIES);
p_know[wh] = TRUE;
when RELIC:
obj->o_weight = things[TYP_RELIC].mi_wght;
switch (obj->o_which) {
case QUILL_NAGROM: obj->o_charges = QUILLCHARGES;
when EMORI_CLOAK: obj->o_charges = 1;
otherwise: break;
}
when FOOD:
obj->o_weight = things[TYP_FOOD].mi_wght;
}
mpos = 0;
obj->o_flags |= ISKNOW;
if (add_pack(item, FALSE, NULL) == FALSE) {
obj->o_pos = hero;
fall(item, TRUE);
}
}
/*
* getbless:
* Get a blessing for a wizards object
*/
getbless()
{
reg char bless;
msg("Blessing? (+,-,n)");
bless = wgetch(msgw);
if (bless == '+')
return (rnd(3) + 2);
else if (bless == '-')
return (-rnd(3) - 1);
else
return (0);
}
/*
* get a non-monster death type
*/
getdeath()
{
register int i;
int which_death;
char label[80];
clear();
for (i=0; i<DEATHNUM; i++) {
sprintf(label, "[%d] %s", i+1, deaths[i].name);
mvaddstr(i+2, 0, label);
}
mvaddstr(0, 0, "Which death? ");
refresh();
/* Get the death */
for (;;) {
get_str(label, stdscr);
which_death = atoi(label);
if ((which_death < 1 || which_death > DEATHNUM)) {
mvaddstr(0, 0, "Please enter a number in the displayed range -- ");
refresh();
}
else break;
}
return(deaths[which_death-1].reason);
}
#ifdef PC7300
static menu_t Display; /* The menu structure */
static mitem_t Dispitems[NUMMONST+1]; /* Info for each line */
static char Displines[NUMMONST+1][LINELEN+1]; /* The lines themselves */
#endif
/*
* make a monster for the wizard
*/
makemonster(showall, label, action)
bool showall; /* showall -> show uniques and genocided creatures */
char *label, *action;
{
#ifdef PC7300
register int nextmonst;
#endif
register int i;
register short which_monst;
register int num_monst = NUMMONST, pres_monst=1, num_lines=2*(lines-3);
int max_monster;
char monst_name[40];
/* If we're not showing all, subtract out the UNIQUES and quartermaster */
if (!showall) num_monst -= NUMUNIQUE + 1;
max_monster = num_monst;
#ifdef PC7300
nextmonst = 0;
for (i=1; i<=num_monst; i++) {
/* Only display existing monsters if we're not showing them all */
if (showall || monsters[i].m_normal) {
strcpy(Displines[nextmonst], monsters[i]);
Dispitems[nextmonst].mi_name = Displines[nextmonst];
Dispitems[nextmonst].mi_flags = 0;
Dispitems[nextmonst++].mi_val = i;
}
}
/* Place an end marker for the items */
Dispitems[nextmonst].mi_name = 0;
/* Set up the main menu structure */
Display.m_label = label;
Display.m_title = "Monster Listing";
Display.m_prompt = "Select a monster or press Cancl.";
Display.m_curptr = '\0';
Display.m_markptr = '\0';
Display.m_flags = 0;
Display.m_selcnt = 1;
Display.m_items = Dispitems;
Display.m_curi = 0;
/*
* Try to display the menu. If we don't have a local terminal,
* the call will fail and we will just continue with the
* normal mode.
*/
if (menu(&Display) >= 0) {
restscr(cw);
touchwin(cw);
return(Display.m_selcnt == 1 ? Display.m_curi->mi_val : -1);
}
#endif
/* Print out the monsters */
while (num_monst > 0) {
register left_limit;
if (num_monst < num_lines) left_limit = (num_monst+1)/2;
else left_limit = num_lines/2;
wclear(hw);
touchwin(hw);
/* Print left column */
wmove(hw, 2, 0);
for (i=0; i<left_limit; i++) {
sprintf(monst_name, "[%d] %c%s\n",
pres_monst,
(showall || monsters[pres_monst].m_normal)
? ' '
: '*',
monsters[pres_monst].m_name);
waddstr(hw, monst_name);
pres_monst++;
}
/* Print right column */
for (i=0; i<left_limit && pres_monst<=max_monster; i++) {
sprintf(monst_name, "[%d] %c%s",
pres_monst,
(showall || monsters[pres_monst].m_normal)
? ' '
: '*',
monsters[pres_monst].m_name);
wmove(hw, i+2, cols/2);
waddstr(hw, monst_name);
pres_monst++;
}
if ((num_monst -= num_lines) > 0) {
mvwaddstr(hw, lines-1, 0, morestr);
draw(hw);
wait_for(' ');
}
else {
mvwaddstr(hw, 0, 0, "Which monster");
if (!terse) {
waddstr(hw, " do you wish to ");
waddstr(hw, action);
}
waddstr(hw, "? ");
draw(hw);
}
}
get_monst:
get_str(monst_name, hw);
which_monst = atoi(monst_name);
if ((which_monst < 1 || which_monst > max_monster)) {
mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- ");
draw(hw);
goto get_monst;
}
restscr(cw);
touchwin(cw);
return(which_monst);
}
/*
* passwd:
* see if user knows password
*/
passwd()
{
register char *sp, c;
char buf[LINELEN], *crypt();
msg("Wizard's Password:");
mpos = 0;
sp = buf;
while ((c = readchar()) != '\n' && c != '\r' && c != '\033')
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, md_crypt(buf, "mT")) == 0);
}
/*
* teleport:
* Bamf the hero someplace else
*/
teleport()
{
register struct room *new_rp, *old_rp = roomin(&hero);
register int rm, which;
coord old;
bool got_position = FALSE;
/* Disrupt whatever the hero was doing */
dsrpt_player();
/*
* If the hero wasn't doing something disruptable, NULL out his
* action anyway and let him know about it. We don't want him
* swinging or moving into his old place.
*/
if (player.t_action != A_NIL) {
player.t_action = A_NIL;
msg("You feel momentarily disoriented.");
}
old = hero;
mvwaddch(cw, hero.y, hero.x, mvwinch(stdscr, hero.y, hero.x));
if (ISWEARING(R_TELCONTROL) || wizard) {
got_position = move_hero(H_TELEPORT);
if (!got_position)
msg("Your attempt fails.");
else {
new_rp = roomin(&hero);
msg("You teleport successfully.");
}
}
if (!got_position) {
do {
rm = rnd_room();
rnd_pos(&rooms[rm], &hero);
} until(winat(hero.y, hero.x) == FLOOR);
new_rp = &rooms[rm];
}
player.t_oldpos = old; /* Save last position */
/* If hero gets moved, darken old room */
if (old_rp && old_rp != new_rp) {
old_rp->r_flags |= FORCEDARK; /* Fake darkness */
light(&old);
old_rp->r_flags &= ~FORCEDARK; /* Restore light state */
}
/* Darken where we just came from */
else if (levtype == MAZELEV) light(&old);
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
/* if entering a treasure room, wake everyone up......Surprise! */
if (new_rp->r_flags & ISTREAS)
wake_room(new_rp);
/* Reset current room and position */
oldrp = new_rp; /* Used in look() */
player.t_oldpos = hero;
/*
* make sure we set/unset the ISINWALL on a teleport
*/
which = winat(hero.y, hero.x);
if (isrock(which)) turn_on(player, ISINWALL);
else turn_off(player, ISINWALL);
/*
* turn off ISHELD in case teleportation was done while fighting
* something that holds you
*/
if (on(player, ISHELD)) {
register struct linked_list *ip, *nip;
register struct thing *mp;
turn_off(player, ISHELD);
hold_count = 0;
for (ip = mlist; ip; ip = nip) {
mp = THINGPTR(ip);
nip = next(ip);
if (on(*mp, DIDHOLD)) {
turn_off(*mp, DIDHOLD);
turn_on(*mp, CANHOLD);
}
turn_off(*mp, DIDSUFFOCATE); /* Suffocation -- see below */
}
}
/* Make sure player does not suffocate */
extinguish(suffocate);
count = 0;
running = FALSE;
md_flushinp();
return rm;
}
/*
* whatis:
* What a certin object is
*/
whatis(what)
struct linked_list *what;
{
register struct object *obj;
register struct linked_list *item;
if (what == NULL) { /* do we need to ask which one? */
if ((item = get_item(pack, "identify", IDENTABLE, FALSE, FALSE))==NULL)
return;
}
else
item = what;
obj = OBJPTR(item);
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;
if (ws_guess[obj->o_which]) {
free(ws_guess[obj->o_which]);
ws_guess[obj->o_which] = NULL;
}
when RING:
r_know[obj->o_which] = TRUE;
if (r_guess[obj->o_which]) {
free(r_guess[obj->o_which]);
r_guess[obj->o_which] = NULL;
}
when MM:
/* If it's an identified jug, identify its potion */
if (obj->o_which == MM_JUG && (obj->o_flags & ISKNOW)) {
if (obj->o_ac != JUG_EMPTY)
p_know[obj->o_ac] = TRUE;
break;
}
m_know[obj->o_which] = TRUE;
if (m_guess[obj->o_which]) {
free(m_guess[obj->o_which]);
m_guess[obj->o_which] = NULL;
}
otherwise:
break;
}
obj->o_flags |= ISKNOW;
if (what == NULL)
msg(inv_name(obj, FALSE));
}

694
arogue7/xcrypt.c Normal file
View file

@ -0,0 +1,694 @@
/*
* 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>
#ifdef MASTER
# include <stdio.h>
#endif
#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(ch)
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(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(key)
const 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(l_in, r_in, l_out, r_out, count)
unsigned int l_in, r_in, *l_out, *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(in, out, salt, count)
const char *in;
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(key, setting)
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);
}