Import XRogue 8.0 from the Roguelike Restoration Project (r1490)

This commit is contained in:
John "Elwin" Edwards 2015-04-21 08:55:20 -04:00
parent 6af92da76a
commit 034d8d6484
51 changed files with 37250 additions and 0 deletions

178
xrogue/LICENSE.TXT Normal file
View file

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

115
xrogue/Makefile Normal file
View file

@ -0,0 +1,115 @@
# XRogue: Expeditions into the Dungeons of Doom
# Copyright (C) 1991 Robert Pietkivitch
# All rights reserved.
#
# Based on "Advanced Rogue"
# Copyright (C) 1984, 1985 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.
DISTNAME=xrogue8.0.3
PROGRAM=xrogue
O=o
HDRS = rogue.h mach_dep.h network.h
OBJS1 = vers.$(O) actions.$(O) bolt.$(O) chase.$(O) command.$(O) daemon.$(O) \
daemons.$(O) eat.$(O) effects.$(O) fight.$(O) encumb.$(O) help.$(O) \
init.$(O) io.$(O) list.$(O) main.$(O) maze.$(O) misc.$(O) monsters.$(O)
OBJS2 = mons_def.$(O) move.$(O) n_level.$(O) options.$(O) outside.$(O) pack.$(O) \
passages.$(O) player.$(O) potions.$(O) rings.$(O) rip.$(O) rooms.$(O) \
save.$(O) scrolls.$(O) sticks.$(O) things.$(O) trader.$(O) util.$(O) \
weapons.$(O) wear.$(O) wizard.$(O) rogue.$(O) state.$(O) xcrypt.$(O)
OBJS = $(OBJS1) $(OBJS2)
CFILES= vers.c actions.c bolt.c chase.c command.c daemon.c daemons.c eat.c \
effects.c fight.c encumb.c help.c init.c io.c list.c main.c maze.c \
misc.c monsters.c mons_def.c move.c n_level.c options.c outside.c \
pack.c passages.c player.c potions.c rings.c rip.c rooms.c save.c \
scrolls.c sticks.c things.c trader.c util.c weapons.c wear.c wizard.c \
rogue.c state.c xcrypt.c
MISC = Makefile README.TXT LICENSE.TXT $(PROGRAM).sln $(PROGRAM).vcproj
CC = gcc
CFLAGS= -O3
CRLIB = -lcurses
RM = rm -f
TAR = tar
.SUFFIXES: .obj
.c.obj:
$(CC) $(CFLAGS) /c $*.c
$(PROGRAM): $(HDRS) $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(CRLIB) -o $@
clean:
$(RM) $(OBJS1)
$(RM) $(OBJS2)
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip
dist.src:
make clean
tar cf $(DISTNAME)-src.tar $(CFILES) $(HDRS) $(MISC)
gzip -f $(DISTNAME)-src.tar
dist.irix:
make clean
make CC=cc CFLAGS="-woff 1116 -O3" $(PROGRAM)
tar cf $(DISTNAME)-irix.tar $(PROGRAM) README.TXT LICENSE.TXT
gzip -f $(DISTNAME)-irix.tar
dist.aix:
make clean
make CC=xlc CFLAGS="-qmaxmem=16768 -O3 -qstrict" $(PROGRAM)
tar cf $(DISTNAME)-aix.tar $(PROGRAM) README.TXT LICENSE.TXT
gzip -f $(DISTNAME)-aix.tar
dist.linux:
make clean
make $(PROGRAM)
tar cf $(DISTNAME)-linux.tar $(PROGRAM) README.TXT LICENSE.TXT
gzip -f $(DISTNAME)-linux.tar
dist.interix:
make clean
make $(PROGRAM)
tar cf $(DISTNAME)-interix.tar $(PROGRAM) README.TXT LICENSE.TXT
gzip -f $(DISTNAME)-interix.tar
dist.cygwin:
make clean
make $(PROGRAM)
tar cf $(DISTNAME)-cygwin.tar $(PROGRAM).exe README.TXT LICENSE.TXT
gzip -f $(DISTNAME)-cygwin.tar
dist.mingw32:
$(MAKE) RM="cmd /c del" clean
$(MAKE) CRLIB="-lpdcurses -lWs2_32" $(PROGRAM)
cmd /c del $(DISTNAME)-mingw32.zip
zip $(DISTNAME)-mingw32.zip $(PROGRAM).exe README.TXT LICENSE.TXT
dist.msys:
$(MAKE) clean
$(MAKE) CRLIB="-lcurses -lWs2_32" $(PROGRAM)
tar cf $(DISTNAME)-msys.tar $(PROGRAM).exe README.TXT LICENSE.TXT
gzip -f $(DISTNAME)-msys.tar
dist.djgpp:
make clean
make LDFLAGS="-L$(DJDIR)/LIB" CRLIB="-lpdcurses" $(PROGRAM)
rm -f $(DISTNAME)-djgpp.zip
zip $(DISTNAME)-djgpp.zip $(PROGRAM) README.TXT LICENSE.TXT
dist.win32:
nmake O="obj" RM="-del" clean
nmake O="obj" CC="CL" CRLIB="..\pdcurses.lib shell32.lib user32.lib Advapi32.lib Ws2_32.lib" CFLAGS="-DPDC_STATIC_BUILD -nologo -I.. -Ox -wd4033 -wd4716" $(PROGRAM)
-del $(DISTNAME)-win32.zip
zip $(DISTNAME)-win32.zip $(PROGRAM).exe README.TXT LICENSE.TXT

646
xrogue/README.TXT Normal file
View file

@ -0,0 +1,646 @@
Welcome to XRogue
http://roguelike.sourceforge.net/xrogue
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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.
XRogue: Expeditions into the Dungeons of Doom
---------------------------------------------
Introduction:
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.
The version of rogue described in this guide has been expanded to include
over 200 monsters with many new capabilities and has been renamed xrogue.
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. There are also a
number of new commands in this version not found in previous versions.
The game contains monsters, spells, weapons, armor, potions, and other
magical items that you will discover during your quest. 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.
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 item found in the Dungeon. To make things
interesting the player has a quest to return one of several unique and
magical artifacts which are rumored to lie deep within the Dungeon.
Returning with this artifact to the surface brings great honor.
However, after finding the artifact, the player may wish to continue
his quest deeper into the Dungeon to match wits with an arch-devil, a
demon-prince, or perhaps Charon the Boatman. Defeating such a creature
will gain the player many experience points which is the basis for
scoring in xrogue. It is very difficult to return from the Dungeons
of Doom alive. Very few players have won this game.
Character Classes:
Before placing the player in the Dungeon, the game requests that you
select what type of character they would like to be: Fighter, Paladin,
Ranger, Magic-User, Cleric, Thief, Assassin, Druid, or Monk.
The Fighter
A Fighter has the best odds at winning battles with monsters. At high
experience levels, the Fighter is able to attack his opponent multiple
times in a single turn. Strength is the main attribute of the Fighter.
The Magic-User
A Magic-User is able to cast spells. Intelligence is the main attribute.
The number of spells a Magic-User can cast increases as he gains in
experience points and in intelligence. His spell casting ability allows
him to identify any item in the Dungeon. 16 spells.
The Cleric
A Cleric is able to pray for assistance in battle. Wisdom is the main
attribute. The number of prayers granted to the Cleric increases as he
gains in experience points and in wisdom. Clerics can affect (turn) the
undead monsters to avoid battle. Ie., zombies, ghouls, etc. If the
Cleric is very powerful relative to the undead monster, turning it will
utterly destroy it. 16 prayers.
The Paladin
A Paladin is a type of holy warrior, being a cross between a Cleric
and a Fighter. He is able to pray and affect the undead like the Cleric
and fight like the Fighter, but both to a lesser extent. He is on the
side of all that is righteous and good and would never attack a monster
that has not attacked him first. If he happens to kill such a monster,
inadvertantly or otherwise, he will begin to feel increasingly uneasy.
If he kills too many such monsters, he will face karmic retaliation and
be reduced to a mere Fighter, minus all of the Cleric's ability.
Charisma is the main attribute with Wisdom second.
The Ranger
A Ranger is a type of mystical warrior, being a cross between the
Magic-User and Fighter. Like the Paladin, he is on the side of all
that is righteous and good and would never attack a monster that
has not attacked him first. A Ranger is able to cast spells like the
Magic-User and fight like the Fighter, but both to a lesser extent.
Charisma is the main attribute with Intelligence second.
The Thief
A Thief is exceptionally dexterous and has great skill at being able
to set a traps for and/or rob (steal) items from monsters. Thieves have
the ability to detect all the gold and hidden traps on each level of
the Dungeon. Their dexterous nature gives Thieves the ability to move
very quietly, so they are not as likely as to wake up sleeping monsters
as are the other character types. If a Thief manages to sneak up on a
creature without waking it he may be able to backstab the monster. The
damage from a backstab is greatly increased based upon the experience
level. Dexterity is the main attribute.
The Assassin
An Assassin is a person trained in the art of killing monsters by
surprise. He has some of the abilities of the Thief, but he cannot
sense traps or backstab. Instead, the Assassin has the chance to kill
an opponent outright with one deadly blow. He can recognize and use
poison found in the Dungeon on his weapon, thereby, making his next
attack exceptionally lethal. Dexterity is the main attribute.
The Druid
A Druid is a type of magical warrior, being a cross between the Cleric
and the Magic-User. A Druid can chant both spells and prayers plus a
few of his own. The number of chants available to the Druid increases
as he gains in experience points and in Wisdom. Wisdom is the main
attribute. 16 chants.
The Monk
A Monk is trained in the martial arts. He wears no armor and does not
need a weapon (although using them is not forbidden). As the Monk gains
in experience points his natural defense or ability to dodge attackers
increases. The Mong is a cross between the Druid and Fighter, so he
can chant and also fight like the Fighter, but both to a lesser extent.
Constitution is the main attribute, with wisdom second.
Attributes Of The Charaters:
Strength - The primary attribute for encumberance.
Intelligence - The primary attribute for casting spells.
Wisdom - The primary attribute for prayers and chanting.
Dexterity - The primary attribute for stealthiness.
Charisma - The primary attribute for good will. High Charisma also
affects the cost of objects when making transactions.
Constitution - The primary attribute for health. High Constitution
affects the amount of hit points you receive when
moving up in experience levels.
Note: The Ranger, Paladin, and Monk do not receive their "special"
magical abilities until they have advanced a few experience levels.
Experience Levels:
Characters gain experience points mostly from killing monsters. Other
actions, such as stealing items from monsters, backstabbing, and turning
monsters, also add extra experience points. Each character type gains
experience points and moves up in experience levels at different rates.
Moving up in experience levels adds extra hit points to the character
which determines how many "hits" he can take before being killed.
Allocating Attribute Points To The Characters:
A player starts with 75 attribute points to distribute in to the character
he has chosen to play. When you are prompted to distribute the attribute
points, the screen displays the minimum and maximum allowable values for
that particular attribute. The player can type a backspace (Ctrl-H) to go
back and change a previous value and typing an escape (ESC) sets all the
remaining attributes to the maximum value possible, given the number of
remaining attribute points to be distributed.
THE SCREEN
During the normal course of play, the screen consists of three separate
sections: the top line, the bottom two lines, and the remaining screen
in the middle. The top line reports actions which occur during the game,
the middle section depicts the Dungeon, and the bottom two lines describe
the player's current condition.
Whenever anything happens to the player, such as finding a scroll, hitting
a monster, or being hit by a monster, a short report appears on the top
line of the screen. When you see the word 'More' on the top line, that
means you must press the space key to continue.
The following items may be found within the Dungeon. Some of them have
more than one interpretation, depending upon whether your character
recognizes them or not.
| A wall of a room.
- A wall of a room.
* A pile of gold.
% A way to another level.
+ A doorway.
. The floor in a room.
# The floor in a passageway.
Solid rock (denoted by a space).
^ The entrance to a Trading Post
@ The player.
_ The player, when invisible.
: Some food.
! A flask containing a potion.
? A sealed scroll.
= A ring.
) A weapon.
] Some armor.
; A miscellaneous magic item
, An artifact
/ A wand or a staff.
> A trapdoor leading to the next level
{ An arrow trap
$ A sleeping gas trap
} A beartrap
~ A trap that teleports you somewhere else
` A poison dart trap
" A shimmering magic pool
' An entrance to a maze
$ Any magical item. (During magic detection)
> A blessed magical item. (During magic detection)
< A cursed magical item. (During magic detection)
Monsters are depicted as letters of the alphabet. Note that all letters
denote multiple monsters, depending on which level of the Dungeon you are
on. The player may identify a current monster by using the identify
command ('/') or the clarify command ('=').
The bottom two lines of the screen describe the player's current status.
The first line gives the player's characteristics:
Intelligence, Strength, Wisdom, Dexterity, Charisma, and Constitution
all have a normal maximum value of 50 points, but they can go higher if
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 encumberance causes you to use more food. The
attribute of Strength fortifies one's encumberance.
The player's current number of hit points are denoted as (Hp) and it is
followed in parentheses by the player's current maximum hit points. Hit
points express the player's survivability. As a player heals by resting,
using potions, or spells, the player's current hit points gradually increase
until they reach the current maximum. This maximum number will be increased
each time a player goes up an experience level. If the player's current hit
points reach 0, the player becomes "metabolically challenged".
The player's armor class is denoted as (Ac). 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 (Monk excepted). The lower
the armor class number, the better.
The player's current experience level is denoted as (Exp), followed by
the player's experience points. A new experience level brings extra hit
points and possibly added abilities, such as new spells for a Magic-user,
new prayers for a Cleric, and new chants for a Druid. There are a total
of 26 experience levels per character.
Commands:
A player can invoke most commands by typing in a single character.
Some commands, however, require a direction, in which case the player
types the command character followed by a directional letter. Many
commands can be prefaced by a number, indicating how many times the
command should be executed.
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 can then type the letter associated with the item. Typing a '*'
will produce a list of eligible items.
A list of basic games commands:
? Preceding a command by a '?' produces a brief explanation of the
command. The command '?*' gives an explanation of all the commands.
A '?@' gives information on things you encounter (rock, forest, etc).
/ Preceding a symbol by a '/' identifies the symbol.
= Clarify. After typing an '=' 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, the game will
identify whatever is there.
h Move one position to the left.
j Move one position down.
k Move one position up.
l Move one position to the right.
y Move one position to the top left.
u Move one position to the top right.
b Move one position to the bottom left.
n Move one position to the bottom right.
H Run to the left until reaching something interesting.
J Run down until reaching something interesting.
K Run up until reaching something interesting.
L Run to the right until reaching something interesting.
Y Run to the top left until reaching something interesting.
U Run to the top right until reaching something interesting.
B Run to the bottom left until reaching something interesting.
N Run to the bottom right until reaching something interesting.
> Go down the stairs to the next level or enter the outer region if you
are standing upon the wormhole trap (must be "flying" for this to work).
< Go up the stairs to the next level or enter the outer region if you are
standing upon the wormhole trap (must be "flying" for this to work).
* Count the gold in the player's pack.
! Escape to the shell level.
$ Price an item at the Trading Post.
# Buy an item at the Trading Post.
% Sell an item at the Trading Post.
. This command (a period) causes the player to rest one turn.
^ This command sets traps and is limited to Thieves and Assassins. If the
command is successful the game will ask the player for the trap type and
sets it where the player is standing.
a Affect the undead. This command is restricted to Clerics and Paladins
and must be followed by a directional letter.
A Choose your quest item (at game startup only!).
c This command is restricted to Druids and Monks and it produces a list of
available chants. The player can select one of the displayed chants and
if the player's energy level is sufficiently high, "chant" it. The more
complicated the spell, the more energy it will take.
C This command is restricted to Magic-Users and Rangers and it produces a
list of available spells. The player can select one of the displayed
spells and if the player's energy level is sufficiently high, "cast" it.
The more complicated the spell, the more energy it will take.
d Drop an item from the player's pack.
D Dip something into a magic pool.
e Eat some food from the player's pack.
f When this command is preceded with a directional command, the player will
move in the specified direction until he crosses something interesting.
F Frighten a monster. Not available to all characters. This command
loses it's power at around level 10.
g Give away or trade a slime-mold for food with a monster.
G This command is restricted to Thieves and Assassins. It causes the game
to display all of the gold on the current level.
i Display an inventory of the player's pack.
I This command prompts for an item from the player's pack and displays
the inventory information for that item.
m When the player types this command, you are prompted to mark an item
with a one-line name.
o Typing this command causes the game to display all the settable options.
The player can then examine them or change (some of) them
O Display your current character type and quest item.
p This command is restricted to Clerics and Paladins and it produces a
list of available prayers. The player can then select one of the
displayed prayers and if the player's energy level is sufficiently high,
"pray" it. The more complicated the prayer, the more energy it will
take.
P Pick up the items currently under the player.
q Quaff a potion from the player's pack.
Q Quit without saving the game.
r Read a scroll from the player's pack.
s Search for a secret door or a trap in the circle surrounding the player.
S Save your game to play at a later time.
t This command prompts for an object from the players pack. The player
then can throw the object in the specified direction.
T Take off whatever the player is wearing.
v Print the current xrogue version number.
w Wield a weapon from the player's pack.
W Wear some armor, ring, or a miscellaneous magic item from the player's
pack. The player can wear a maximum of 8 rings.
X This command is restricted to Thieves only. It causes the game to
display
all of the hidden traps on the current level.
z This command prompts for a wand or staff from the player's pack and zaps
it in the specified direction.
+ Fortune cookie! (Note: if you play xrogue over a modem, typing three
consecutive '+' will tell your modem to enter "command" mode. See your
modem manual on how to return from this mode).
Escape Pressing the Escape key will cancel the current command.
Ctrl-B Check your current score. Scoring is based on experience points
and gold. However, gold is not that important and 10% is hacked
off if a player is killed.
Ctrl-E Check your current food level. This command is used when you want
to see just how much food you have remaining in your stomach. A
full stomach is measured to be about 2000(2100). As you play the
game, this level drops until you become hungry at about 200(2100).
A food level over 2000(2100) makes the character satiated, and a
level under 200(2100) makes the character hungry, then weak, and
finally fainting. A level of 2000(2100) is the most the character
can eat, a full, satisfied stomach!
Ctrl-L Redraw the screen.
Ctrl-N When the player types this command, the game prompts you to type a
one-line name for a monster or for an item in the player's pack
To name a monster, position the cursor over the desired monster and
rename it.
Ctrl-O Display the current "affects" on the player (such as slow, phased,
confused, extra sight, flying, dancing, etc.).
Ctrl-R Repeat last message displayed on the top line of the screen.
Ctrl-T This command is restricted to Thieves and Assassins. It must be
followed by a directional letter. If a monster is standing next to
the player in the specified direction, the effect is to steal an
item from the monster's pack. If successful, the monster does not
notice anything, but if the player is unsuccessful, there is a
chance
the monster will suddenly wake up and attack.
Ctrl-U Use a magic item in the player's pack.
There is no explicit attack command. If a player wishes to do battle with a
monster, the player simply moves onto the spot where the monster is
standing.
Whatever the player is wielding will be used as the player's weapon.
As the player moves across items, the game automatically picks them up and
places them into the player's pack. If there is no room left in the pack,
the item is left on the floor. Setting the "pickup" option to "NO" will
allow the player to pick up items at will using the 'P' command.
All actions except for 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 one space varies with the type of armor
worn and the player's level of encumberance. Movement is always faster when
the player is "flying".
Actions also take time and 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. These
same rules apply to monsters as well.
Some of the rooms in the Dungeon possess a natural light source. In most
other rooms and in corridors, the player can see only those things within
a one-space radius around the player. Dark rooms can be lit with magical
light or by fire beetles and other monsters.
The player can wield only one weapon at a time. When a player attacks
a monster, the amount of damage depends on the particular weapon he 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.
A weapon may be cursed or blessed which will affect the likelihood of you
hitting a monster with it and the damage that it will inflict on the
monster.
If the player has identified the weapon he is using, the "to hit" and the
"to damage" bonuses appear (in that order) before the weapons name in the
inventory listing. A positive bonus indicates a blessed weapon, and a
negative bonus usually indicates a cursed or misguided weapon. A player
cannot release a cursed weapon until a remove curse scroll is read or cast
by magical means.
After the player has identified a suit of armor, the protection bonus
appears
before the armors name in the inventory listing. If the bonus is positive
the armor is blessed but if it is negative, the armor is probably cursed.
The player cannot remove a cursed suit of armor until a remove curse scroll
is read or cast by magical means.
Some monsters can corrode your armor! If such a monster hits a player
when the player is wearing metal armor, the armor will lose some of its
protective value. This same corrosive property also applies to weapons
when a player hits a monster with this ability. Search for a scroll of
"protection" to guard against corrosion of your armor and weapon.
A player will find many potions and scrolls in the Dungeon. Reading a
scroll or quaffing a potion will usually cause some magical occurrence.
Potions and scrolls may be either cursed or blessed. In this version of
xrogue, Monster Confusion scrolls will turn your hands a variety of colors.
A blessed Magic Mapping scroll shows very detailed maps. A scroll of
Genocide works within the dungeon as well as in the outer region. A
scroll of blessed Teleportation will teleport you "upward" a few levels.
Blessed Remove Curse will cause certain monsters to panic if the scroll
is read near them. Charm Monster will let you charm several monsters.
The player can wear a maximum of eight rings. Some of them 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. Rings
can be cursed or blessed and the player cannot remove a cursed ring until
a remove curse scroll is read or cast.
Wands, rods, and staves help a player in battle and affect the Dungeon.
A player uses the "z" (zap) command to use a wand either to shoot at a
monster, teleport, or to light up a dark room. Wands can be cursed or
blessed.
A player must be frugal with his food. Both moving and searching through
the Dungeon, and fighting monsters, consumes energy. Starving results in
the player's fainting for increasingly longer periods of time, during which
any nearby monster can attack the player at will. 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. Slime-Molds are monster
food and if you have one, you may be able to trade it for a regular food
ration, if the monster is of "friendly" persuasion.
Gold has a couple of uses in the Dungeon. The first use of gold is to buy
things, either at a Trading Post or from a Quartermaster. The Trading Post
when found, is entered via the '>' command, like going down a stairway.
A Quartermaster ('q') is a Dungeon vendor who appears at certain times and
will try to sell the player some of his wares. The Quartermaster's wares
are never cursed but they can be blessed, though blessed goods do cost more
than normal goods. If the player chooses to buy something offered by a
Quartermaster, he will make the transaction for the specified amount of gold
and then disappear. Attacking a Quartermaster causes him to vanish in
haste! You can sometimes find gold at the bottom of "magic pools". Use
the ">" command to dive for the gold, but be careful you don't drown!
When beginning a new game, a player is placed in the Trading Post with
an allotment of gold based upon the type of character chosen to play.
There are some restrictions on the use of certain items by character.
For example, only Fighters, Paladins, and Rangers can wield two-handed
swords while Thieves and Assassins can not wear certain types of armor.
However, the Trading Post (and Quartermaster) will happily sell a player
anything that he can afford, whether you need it or not.
Miscellaneous magical items such as a Pair of Boots or a Book are numerous
within the Dungeon. These items are usually used to a 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, Beaker, or Ointment.
The Medicine Crystal will heal you, remove all curses, heal you, and may
cause panic in some monsters.
There are a number of unique monsters deep within the depths of the Dungeon
that carry very special magical items or artifacts. When you begin the
game,
you are asked to choose a "quest item" to retrieve from the Dungeon. Most
of these items can be used to the player's advantage, even if they are not
one's own personal quest item during the game. However, care must be taken
when handling some of them for they have intelligence and some will reject
mishandling or abuse. These items consume your food (and your gold) so
carrying them around results in increased food use. Some of these items
will
kill you outright if you happen to pick them up while wielding another
artifact as your weapon. Don't be too greedy with the artifacts! Quest
items begin appearing in xrogue between levels 40-50. The less traumatic
quest items appear earlier while the more severe ones appear later. Once
a unique monster is killed, you will not encounter another one like it in
the Dungeon.
A variety of traps exist within the Dungeon, including trap doors, bear
traps, and sleeping traps. Sometimes they are hidden from sight until
sprung by a monster or by the player. A sprung trap continues to function,
but since it is visible, an intelligent monster is not likely to tread on
it.
A trap called the Wormhole trap, will transport you to the "outer region"
of the dungeon. There you will fight strange dinosaurs until you can make
your way back to a starwell, and promptly return from whence you came.
Each monster except for the Quartermaster appears in a limited range of
Dungeon levels. All monsters of the same type share the same abilities.
All giant rats, for example, can give the player a disease, and all
jackalweres can put the player to sleep. Monsters of the same type will
vary however, in strength and intelligence. For example, one kobold may
be much more difficult to kill off than another. In general, the more
difficult it is to kill a monster, the more experience points the monster
is worth.
Most monsters attack by biting and clawing, but some monsters carry weapons
and can use their breath as a weapon. Some monsters can even use magical
items, such as wands and artifacts. Monsters with distance weapons or magic
can sometimes attack a player from across a room or from down a corridor.
Some monsters are more intelligent than others, and the more intelligent
a monster is, the more likely it will run away if it is about to die.
A fleeing monster will not attack the player unless it is cornered.
It is sometimes possible to enlist a monster's aid. Reading a charm monster
scroll, for example, or singing a charm monster chants can make a monster
believe that the player is its friend. A charmed monster will fight hostile
monsters for the player as long as they are not of its own race. Be sure
your charmed monsters are in the same room with you when you enter the next
level, or they will be lost.
Options:
The game has several options, some of which can only be set by the player
at the beginning of the game and others during the course of play.
default - Play the character with "default" attribute settings.
terse - Shorten messages at top of screen.
jump - Speed up the display of the player's movement
step - Lists all inventories one line at a time.
overlay - Allows listings of inventories to overlay the currnt screen.
flush - Supposed to flush all typed-ahead characters.
askme - Prompt the player to name new types of scrolls, potions,
etc.
pickup - Pick up items automatically as you move across them
name - The player's name.
file - Saved game filename. Defaults to xrogue.sav.
score - Identifies the location of the game scorefile.
type - Specifies the character type (unchangable).
quested item - Set at start up (unchangeable).
A player can set the game options at the beginning of a game via the
ROGUEOPTS environment variable.
Some examples:
ROGUEOPTS="default nopickup, nooverlay, name=Corwin, class=magician"
ROGUEOPTS="pickup, overlay, file=xrg.sav, score=/home/games/scorefile"
The player may change an option at any time during the game via the 'o'
(option) command. On the options menu, typing a new value changes the
option and a RETURN moves to the next option in the list. Typing an '-'
moves you to the previous option and an ESCAPE returns you to the Dungeon.
A new option called "default" was added in xrogue. When you put the word
"default" into your ROGUEOPTS environment variable your character will be
created with "default" attribute settings, armor, weapon, quest item, and
some food.
Setting "default" will force the game to skip over the beginning screen
where you can choose/distribute your attribute points and it also skips
over the beginning "equippage screen" where you can choose your armor,
weapon, quest item, and etc.
If you use the "class" option with "default" in ROGUEOPTS, you will
start the game immediately at level 1 with the default selections
for your character.
Here is a list of the main and secondary attributes, special ability,
and quest item ("default" settings) for each character type:
Character Main Attr. Secondary Specialties Def. Quest Item
-------------------------------------------------------------------------
Fighter strength constitution sense gold Axe of Aklad
Ranger charisma intelligence cast spells Mandolin of Brian
Paladin charisma wisdom affect undead Ankh of Heil
Cleric wisdom dexterity prayer spells Horn of Geryon
Magician intelligence dexterity cast spells Stonebones Amulet
Thief dexterity strength sense traps Musty Daggers
Assassin dexterity strength steal/use poison Eye of Vecna
Druid wisdom dexterity chant spells Quill of Nagrom
Monk constitution dexterity chant spells Emori Cloak
A different quest item may be chosen ONLY while you are in the beginning
Trading Post (if you have NOT set the "default" option via ROGUEOPTS).
When a player is killed, his score will be equal to the amount of his
experience points gained, plus his gold (minus 10%). A player that
quits the game will not lose 10% of his gold. If a player makes it back
up and out of the Dungeon alive, his score will be equal to the amount
of experience points, plus the gold, plus additional gold received from
selling all of the items in his pack.
The game maintains a top-twenty player scorefile. As an installation
option, the game may be compiled so as to record only three entries per
character type and name.

1074
xrogue/actions.c Normal file

File diff suppressed because it is too large Load diff

401
xrogue/bolt.c Normal file
View file

@ -0,0 +1,401 @@
/*
bolt.c - functions shooting an object across the room
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <ctype.h>
#include "rogue.h"
/*
* shoot_bolt fires a bolt from the given starting point in the
* given direction
*/
shoot_bolt(shooter, start, dir, get_points, reason, name, damage)
struct thing *shooter;
coord start, dir;
bool get_points;
short reason;
char *name;
int damage;
{
unsigned char dirch = 0, ch;
bool used, change, see_him;
short y, x, bounces;
coord pos;
struct linked_list *target=NULL;
struct {
coord place;
char oldch;
} spotpos[BOLT_LENGTH];
switch (dir.y + dir.x) {
case 0: dirch = '/';
when 1: case -1: dirch = (dir.y == 0 ? '-' : '|');
when 2: case -2: dirch = '\\';
}
pos.y = start.y + dir.y;
pos.x = start.x + dir.x;
used = FALSE;
change = FALSE;
bounces = 0; /* No bounces yet */
nofont(cw);
for (y = 0; y < BOLT_LENGTH && !used; y++) {
ch = winat(pos.y, pos.x);
spotpos[y].place = pos;
spotpos[y].oldch = mvwinch(cw, pos.y, pos.x);
/* Are we at hero? */
if (ce(pos, hero)) goto at_hero;
switch (ch) {
case SECRETDOOR:
case VERTWALL:
case HORZWALL:
case ' ':
if (dirch == '-' || dirch == '|') {
dir.y = -dir.y;
dir.x = -dir.x;
}
else {
unsigned char chx = mvinch(pos.y-dir.y, pos.x),
chy = mvinch(pos.y, pos.x-dir.x);
bool anychange = FALSE; /* Did we change anthing */
if (chy == WALL || chy == SECRETDOOR ||
chy == HORZWALL || chy == VERTWALL) {
dir.y = -dir.y;
change ^= TRUE; /* Change at least one direction */
anychange = TRUE;
}
if (chx == WALL || chx == SECRETDOOR ||
chx == HORZWALL || chx == VERTWALL) {
dir.x = -dir.x;
change ^= TRUE; /* Change at least one direction */
anychange = TRUE;
}
/* If we didn't make any change, make both changes */
if (!anychange) {
dir.x = -dir.x;
dir.y = -dir.y;
}
}
/* Do we change how the bolt looks? */
if (change) {
change = FALSE;
if (dirch == '\\') dirch = '/';
else if (dirch == '/') dirch = '\\';
}
y--; /* The bounce doesn't count as using up the bolt */
/* Make sure we aren't in an infinite bounce */
if (++bounces > BOLT_LENGTH) used = TRUE;
msg("The %s bounces", name);
break;
default:
if (isalpha(ch)) {
register struct linked_list *item;
struct thing *tp;
register char *mname;
bool see_monster = cansee(pos.y, pos.x);
item = find_mons(unc(pos));
assert(item != NULL);
tp = THINGPTR(item);
mname = monster_name(tp);
/*
* If our prey shot this, let's record the fact that
* he can shoot, regardless of whether he hits us.
*/
if (tp->t_dest != NULL && ce(*tp->t_dest, shooter->t_pos))
tp->t_wasshot = TRUE;
if (!save(VS_BREATH, tp, -(shooter->t_stats.s_lvl/10))) {
if (see_monster) {
if (on(*tp, ISDISGUISE) &&
(tp->t_type != tp->t_disguise)) {
msg("Wait! That's a %s!", mname);
turn_off(*tp, ISDISGUISE);
}
turn_off(*tp, CANSURPRISE);
msg("The %s hits %s", name, prname(mname, FALSE));
}
/* Should we start to chase the shooter? */
if (shooter != &player &&
shooter != tp &&
shooter->t_index != tp->t_index &&
(tp->t_dest == NULL || rnd(100) < 25)) {
/*
* If we're intelligent enough to realize that this
* is a friendly monster, we will attack the hero
* instead.
*/
if (on(*shooter, ISFRIENDLY) &&
roll(3,6) < tp->t_stats.s_intel)
runto(tp, &hero);
/* Otherwise, let's chase the monster */
else runto(tp, &shooter->t_pos);
}
else if (shooter == &player) {
runto(tp, &hero);
/*
* If the player shot a charmed monster, it may
* not like being shot at.
*/
if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) {
msg("The eyes of %s turn clear.",
prname(mname, FALSE));
turn_off(*tp, ISCHARMED);
mname = monster_name(tp);
}
}
/*
* Let the defender know that the attacker has
* missiles!
*/
if (ce(*tp->t_dest, shooter->t_pos))
tp->t_wasshot = TRUE;
used = TRUE;
/* Hit the monster -- does it do anything? */
if ((EQUAL(name,"ice") && on(*tp, NOCOLD)) ||
(EQUAL(name,"flame") && on(*tp, NOFIRE)) ||
(EQUAL(name,"acid") && on(*tp, NOACID)) ||
(EQUAL(name,"lightning bolt")&& on(*tp,NOBOLT)) ||
(EQUAL(name,"nerve gas") &&on(*tp,NOPARALYZE))||
(EQUAL(name,"sleeping gas") &&
(on(*tp, NOSLEEP) || on(*tp, ISUNDEAD))) ||
(EQUAL(name,"slow gas") && on(*tp,NOSLOW)) ||
(EQUAL(name,"fear gas") && on(*tp,NOFEAR)) ||
(EQUAL(name,"confusion gas") && on(*tp,ISCLEAR)) ||
(EQUAL(name,"chlorine gas") && on(*tp,NOGAS))) {
if (see_monster)
msg("The %s has no effect on %s.",
name, prname(mname, FALSE));
}
else {
see_him = !invisible(tp);
/* Did a spell get disrupted? */
dsrpt_monster(tp, FALSE, see_him);
/*
* Check for gas with special effects
*/
if (EQUAL(name, "nerve gas")) {
tp->t_no_move = movement(tp) * FREEZETIME;
tp->t_action = A_FREEZE;
}
else if (EQUAL(name, "sleeping gas")) {
tp->t_no_move = movement(tp) * SLEEPTIME;
tp->t_action = A_FREEZE;
}
else if (EQUAL(name, "slow gas")) {
if (on(*tp, ISHASTE))
turn_off(*tp, ISHASTE);
else
turn_on(*tp, ISSLOW);
}
else if (EQUAL(name, "fear gas")) {
turn_on(*tp, ISFLEE);
tp->t_dest = &hero;
/* It is okay to turn tail */
tp->t_oldpos = tp->t_pos;
}
else if (EQUAL(name, "confusion gas")) {
turn_on(*tp, ISHUH);
tp->t_dest = &hero;
}
else if ((EQUAL(name, "lightning bolt")) &&
on(*tp, BOLTDIVIDE)) {
if (creat_mons(tp, tp->t_index, FALSE)) {
if (see_monster)
msg("The %s divides %s.",
name,prname(mname, FALSE));
light(&hero);
}
else if (see_monster)
msg("The %s has no effect on %s.",
name, prname(mname, FALSE));
}
else {
if (save(VS_BREATH, tp,
-(shooter->t_stats.s_lvl/10)))
damage /= 2;
/* The poor fellow got killed! */
if ((tp->t_stats.s_hpt -= damage) <= 0) {
if (see_monster)
msg("The %s kills %s",
name, prname(mname, FALSE));
else
msg("You hear a faint groan in the distance");
/*
* Instead of calling killed() here, we
* will record that the monster was killed
* and call it at the end of the routine,
* after we restore what was under the bolt.
* We have to do this because in the case
* of a bolt that first misses the monster
* and then gets it on the bounce. If we
* call killed here, the 'missed' space in
* spotpos puts the monster back on the
* screen
*/
target = item;
}
else { /* Not dead, so just scream */
if (!see_monster)
msg("You hear a scream in the distance");
}
}
}
}
else if (isalpha(show(pos.y, pos.x))) {
if (see_monster) {
if (terse)
msg("%s misses", name);
else
msg("The %s whizzes past %s",
name, prname(mname, FALSE));
}
if (get_points) runto(tp, &hero);
}
}
else if (pos.y == hero.y && pos.x == hero.x) {
at_hero: if (!save(VS_BREATH, &player,
-(shooter->t_stats.s_lvl/10))){
if (terse)
msg("The %s hits you", name);
else
msg("You are hit by the %s", name);
used = TRUE;
/*
* The Amulet of Yendor protects against all "breath"
*
* The following two if statements could be combined
* into one, but it makes the compiler barf, so split
* it up
*/
if (cur_relic[YENDOR_AMULET] ||
(EQUAL(name,"chlorine gas")&&on(player, NOGAS)) ||
(EQUAL(name,"acid")&&on(player, NOACID)) ||
(EQUAL(name,"sleeping gas")&&ISWEARING(R_ALERT))){
msg("The %s has no effect", name);
}
else if((EQUAL(name, "flame") && on(player, NOFIRE)) ||
(EQUAL(name, "ice") && on(player, NOCOLD)) ||
(EQUAL(name,"lightning bolt")&&
on(player,NOBOLT)) ||
(EQUAL(name,"fear gas")&&ISWEARING(R_HEROISM))){
msg("The %s has no effect", name);
}
else {
dsrpt_player();
/*
* Check for gas with special effects
*/
if (EQUAL(name, "nerve gas")) {
msg("The nerve gas paralyzes you.");
player.t_no_move +=
movement(&player) * FREEZETIME;
player.t_action = A_FREEZE;
}
else if (EQUAL(name, "sleeping gas")) {
msg("The sleeping gas puts you to sleep.");
player.t_no_move +=
movement(&player) * SLEEPTIME;
player.t_action = A_FREEZE;
}
else if (EQUAL(name, "confusion gas")) {
if (off(player, ISCLEAR)) {
if (on(player, ISHUH))
lengthen(unconfuse,
rnd(20)+HUHDURATION);
else {
turn_on(player, ISHUH);
fuse(unconfuse, (VOID *)NULL,
rnd(20)+HUHDURATION, AFTER);
msg("The confusion gas has confused you.");
}
}
else msg("You feel dizzy for a moment, but it quickly passes.");
}
else if (EQUAL(name, "slow gas")) {
add_slow();
}
else if (EQUAL(name, "fear gas")) {
turn_on(player, ISFLEE);
player.t_dest = &shooter->t_pos;
msg("The fear gas terrifies you.");
}
else {
if (EQUAL(name, "acid") &&
cur_armor != NULL &&
!(cur_armor->o_flags & ISPROT) &&
!save(VS_BREATH, &player, -2) &&
cur_armor->o_ac < pstats.s_arm+1) {
msg("Your armor corrodes from the acid");
cur_armor->o_ac++;
}
if (save(VS_BREATH, &player,
-(shooter->t_stats.s_lvl/10)) &&
off(player, NOACID))
damage /= 2;
if ((pstats.s_hpt -= damage) <= 0)
death(reason);
}
}
}
else
msg("The %s whizzes by you", name);
}
mvwaddch(cw, pos.y, pos.x, dirch);
draw(cw);
}
pos.y += dir.y;
pos.x += dir.x;
}
/* Restore what was under the bolt */
newfont(cw);
for (x = y - 1; x >= 0; x--)
mvwaddch(cw, spotpos[x].place.y, spotpos[x].place.x, spotpos[x].oldch);
/* If we killed something, do so now. This will also blank the monster. */
if (target) killed(target, FALSE, get_points, TRUE);
return;
}

936
xrogue/chase.c Normal file
View file

@ -0,0 +1,936 @@
/*
chase.c - Code for one object to chase another
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <curses.h>
#include <limits.h>
#include "rogue.h"
/*
* 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) {
unsigned 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 = 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 = 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.
*/
int
can_shoot(er, ee, shoot_dir)
register coord *er, *ee, *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)
{
shoot_dir->x = shoot_dir->y = 0;
return(-1);
}
/* Do we have a straight shot? */
if (!straight_shot(er->y, er->x, ee->y, ee->x, shoot_dir))
{
shoot_dir->x = shoot_dir->y = 0;
return(-2);
}
else
return(0);
}
/*
* 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 = INT_MAX;
register coord *er = &tp->t_pos;
struct thing *prey; /* What we are chasing */
coord ch_ret; /* Where chasing takes you */
unsigned 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 = INT_MIN; /* 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 : INT_MAX;
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 = 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 = 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, (coord *)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 = INT_MAX;
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 < INT_MAX)
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 < INT_MAX &&
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 != INT_MIN && /* It is possible to move back */
((flee && dist == 0) || /* No other possible moves */
(!flee && dist == INT_MAX))) {
/* 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((struct object *)NULL, tp);
if (tp->t_using == NULL)
tp->t_no_move += weap_move(tp, (struct object *)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 */
unsigned 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(*th, ISCHARMED) &&
off(player, ISBLIND) &&
cansee(unc(th->t_pos)) &&
!invisible(th) && (rnd(15) < 5)) {
switch (rnd(10)) {
case 0: case 1:
msg("%s lashes out at you! ",prname(monster_name(th),TRUE));
when 2: case 3:
msg("%s scrambles around. ",prname(monster_name(th), TRUE));
otherwise:
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((struct object *)NULL, th);
/*
* add in rest of time
*/
if (th->t_using == NULL)
th->t_no_move += weap_move(th, (struct object *)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 = 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 = mvwinch(cw, ch_ret.y, ch_ret.x); /* What player sees */
rch = 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==VERTWALL || rch==HORZWALL)) {
unsigned char nch; /* The new look to the tunnel */
if (rch == WALL && levtype == OUTSIDE) nch = FLOOR;
else if (rch == WALL) nch = PASSAGE;
else if (levtype == MAZELEV || levtype == OUTSIDE) 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 == VERTWALL || rch == HORZWALL) {
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) 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 = 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 */
unsigned 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 = winat(ery, erx)) {
case VERTWALL:
case HORZWALL:
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);
}

1305
xrogue/command.c Normal file

File diff suppressed because it is too large Load diff

264
xrogue/daemon.c Normal file
View file

@ -0,0 +1,264 @@
/*
daemon.c - functions for dealing with things that happen in the future
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 EMPTY 0
#define DAEMON -1
#define _X_ { EMPTY }
struct delayed_action {
int d_type;
int (*d_func)();
VOID *d_arg;
int d_time;
} ;
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(dfunc, arg, type)
reg VOID *arg;
reg int type, (*dfunc)();
{
reg struct delayed_action *dev;
dev = d_slot();
if (dev != NULL) {
dev->d_type = type;
dev->d_func = dfunc;
dev->d_arg = arg;
dev->d_time = DAEMON;
demoncnt += 1; /* update count */
}
}
/*
* kill_daemon:
* Remove a daemon from the list
*/
kill_daemon(dfunc)
reg int (*dfunc)();
{
reg struct delayed_action *dev;
reg int i;
for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++) {
if (dev->d_type != EMPTY && dfunc == 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 = NULL;
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;
{
struct delayed_action *dev;
int i;
/*
* Loop through the devil list
*/
for (i = 0; i < MAXDAEMONS; i++)
{
dev = &d_list[i];
/*
* Executing each one, giving it the proper arguments
*/
if ((dev->d_type == flag) && (dev->d_time == DAEMON) && (dev->d_func != NULL))
(*dev->d_func)(dev->d_arg);
}
}
/*
* fuse:
* Start a fuse to go off in a certain number of turns
*/
fuse(dfunc, arg, time, type)
VOID *arg;
reg int (*dfunc)(), time, type;
{
reg struct delayed_action *wire;
wire = f_slot();
if (wire != NULL) {
wire->d_type = type;
wire->d_func = dfunc;
wire->d_arg = arg;
wire->d_time = time;
fusecnt += 1; /* update count */
}
}
/*
* lengthen:
* Increase the time until a fuse goes off
*/
lengthen(dfunc, xtime)
reg int (*dfunc)(), xtime;
{
reg struct delayed_action *wire;
if ((wire = find_slot(dfunc)) == NULL)
return;
wire->d_time += xtime;
}
/*
* extinguish:
* Put out a fuse
*/
extinguish(dfunc)
reg int (*dfunc)();
{
reg struct delayed_action *wire;
if ((wire = find_slot(dfunc)) == NULL)
return;
wire->d_type = EMPTY;
wire->d_func = NULL;
wire->d_arg = NULL;
wire->d_time = 0;
fusecnt -= 1;
}
/*
* do_fuses:
* Decrement counters and start needed fuses
*/
do_fuses(flag)
reg int flag;
{
struct delayed_action *wire;
int i;
/*
* Step though the list
*/
for (i = 0; i < MAXFUSES; i++) {
wire = &f_list[i];
/*
* 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());
}

731
xrogue/daemons.c Normal file
View file

@ -0,0 +1,731 @@
/*
daemons.c - All the daemon and fuse functions are in here
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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"
/*
* 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 = 10 - curp->s_lvl;
new_points = curp->s_lvl - 2;
when C_CLERIC:
case C_DRUID:
limit = 12 - curp->s_lvl;
new_points = curp->s_lvl - 3;
when C_THIEF:
case C_ASSASSIN:
limit = 14 - curp->s_lvl;
new_points = curp->s_lvl - 4;
when C_MONK:
limit = 16 - curp->s_lvl;
new_points = curp->s_lvl - 5;
when C_RANGER:
case C_PALADIN:
limit = 18 - curp->s_lvl;
new_points = curp->s_lvl - 6;
when C_FIGHTER:
limit = 20 - curp->s_lvl;
new_points = curp->s_lvl - 7;
when C_MONSTER:
limit = 15 - curp->s_lvl;
new_points = curp->s_lvl - 5;
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, (VOID *)NULL, 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_ASSASSIN) ||
(rnd(30) >= dex_compute()))) {
if (levtype != POSTLEV)
wanderer();
kill_daemon(rollwand);
fuse(swander, (VOID *)NULL, 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))
msg("You begin to feel weird.. ");
}
/*
* land:
* Player can no longer fly
*/
int
land()
{
turn_off(player, ISFLY);
msg("You regain your normal weight");
running = FALSE;
return(0);
}
/*
* 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
*/
int
res_strength(howmuch)
long 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);
return(0);
}
/*
* 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()
{
pstats.s_hpt = -1;
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) > 12)
return;
if (hungry_state == F_FAINT && rnd(28) == 7) /*must have fainted once*/
{
pstats.s_hpt = -1;
msg("You starve to death!! --More-- ");
wait_for(' ');
death(D_STARVATION);
}
player.t_action = A_FREEZE;
player.t_no_move = movement(&player) * (rnd(8) + 3);
if (!terse)
addmsg("You feel too weak from the lack of food. ");
msg("You faint");
running = FALSE;
if (fight_flush) 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++;
}
/* Charge for wearing rings */
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) 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 = NULL;
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
*/
int
undance()
{
turn_off(player, ISDANCE);
msg ("Your feet take a break.....whew!");
return(0);
}
/*
* if he has our favorite necklace of strangulation then take damage every turn
*/
strangle()
{
if ((pstats.s_hpt -= 6) <= 0) {
pstats.s_hpt = -1;
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
* it's a lot like trap_look()
*/
ring_search()
{
if (rnd(75) < (2*dex_compute() + 5*pstats.s_lvl)) search(TRUE, FALSE);
else search(FALSE, FALSE);
}
/*
* this is called each turn the hero has the ring of teleportation on
*/
ring_teleport()
{
if (rnd(100) < 3) teleport();
}
/*
* this is called to charge up the quill of Nagrom
*/
quill_charge()
{
register struct object *tobj = NULL;
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, (VOID *)NULL, 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
*/
int
cloak_charge(obj)
register struct object *obj;
{
if (obj->o_charges < 1)
obj->o_charges = 1;
return(0);
}
/*
* 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 loses its bluish tint");
}
/*
* eat_gold:
* an artifact eats gold
*/
eat_gold(obj)
register struct object *obj;
{
if (purse == 250)
msg("%s.. Bids you to find some more gold. ", inv_name(obj, FALSE));
if (purse == 100)
msg("%s.. Demands that you find more gold! ", inv_name(obj, FALSE));
if (purse == 50)
msg("%s.. Commands you to find more gold!! ", inv_name(obj, FALSE));
if (purse == 0) {
if (rnd(10) >= 7)
msg("You feel the artifact gnawing away... ");
if (--pstats.s_hpt < 1) {
pstats.s_hpt = -1;
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, (VOID *)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, (VOID *)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, (VOID *)NULL, time, AFTER);
}

166
xrogue/eat.c Normal file
View file

@ -0,0 +1,166 @@
/*
eat.c - Functions for dealing with digestion
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 = -1;
msg ("Cough! Ack! 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 that food down!");
msg ("Your stomach feels like it's about to burst!");
}
else if (which != E_SLIMEMOLD) {
hungry_state = F_OKAY;
switch (rnd(10)) {
case 0: msg("Yuck, what a foul tasting %s! ", foods[which].mi_name);
when 1: msg("Mmmm, what a tasty %s. ", foods[which].mi_name);
when 2: msg("Wow, what a scrumptious %s! ", foods[which].mi_name);
when 3: msg("Hmmm, %s heaven! ", foods[which].mi_name);
when 4: msg("You've eaten better %s. ", foods[which].mi_name);
when 5: msg("You smack your lips ");
when 6: msg("Yum-yum-yum ");
when 7: msg("Gulp! ");
when 8: msg("Your tongue flips out! ");
when 9: msg("You lick your chin ");
}
}
updpack(TRUE, &player);
switch(which) {
case E_WHORTLEBERRY: /* add 1 to intelligence */
(*add_abil[A_INTELLIGENCE])(1);
when E_SWEETSOP: /* add 1 to strength */
case E_SOURSOP: /* add 1 to strength */
(*add_abil[A_STRENGTH])(1);
when E_SAPODILLA: /* add 1 to wisdom */
(*add_abil[A_WISDOM])(1);
when E_APPLE: /* add 1 to dexterity */
(*add_abil[A_DEXTERITY])(1);
when E_PRICKLEY: /* add 1 to constitution */
(*add_abil[A_CONSTITUTION])(1);
when E_PEACH: /* add 1 to charisma */
(*add_abil[A_CHARISMA])(1);
when E_PITANGA: /* add 1 hit point */
max_stats.s_hpt++;
pstats.s_hpt = max_stats.s_hpt;
msg("You feel a bit tougher now. ");
when E_HAGBERRY: /* armor class */
case E_JABOTICABA: /* armor class */
pstats.s_arm--;
msg("Your skin feels more resilient now. ");
when E_STRAWBERRY: /* add 10% experience points */
case E_RAMBUTAN: /* add 10% experience points */
temp = pstats.s_exp/100 + 10;
pstats.s_exp += temp;
msg("You feel slightly more experienced now. ");
check_level();
when E_DEWBERRY: /* encourage him to do more magic */
if (chant_time > 0) {
chant_time -= 80;
if (chant_time < 0)
chant_time = 0;
msg("You feel you have more chant ability. ");
}
if (pray_time > 0) {
pray_time -= 80;
if (pray_time < 0)
pray_time = 0;
msg("You feel you have more prayer ability. ");
}
if (spell_power > 0) {
spell_power -= 80;
if (spell_power < 0)
spell_power = 0;
msg("You feel you have more spell casting ability. ");
}
when E_CANDLEBERRY: /* cure him */
if (on(player, HASINFEST) ||
on(player, HASDISEASE)||
on(player, DOROT)) {
if (on(player, HASDISEASE)) {
extinguish(cure_disease);
cure_disease();
}
if (on(player, HASINFEST)) {
msg("You feel yourself improving. ");
turn_off(player, HASINFEST);
infest_dam = 0;
}
if (on(player, DOROT)) {
msg("You feel your skin returning to normal. ");
turn_off(player, DOROT);
}
}
when E_SLIMEMOLD: /* monster food */
msg("The slime-mold quivers around in your mouth. ");
player.t_no_move = 3*movement(&player);
if (off(player, HASDISEASE)) {
if (ISWEARING(R_HEALTH) || player.t_ctype == C_PALADIN ||
player.t_ctype == C_RANGER) {
msg("You feel lousy. ");
}
else {
turn_on(player, HASDISEASE);
fuse(cure_disease, (VOID *)NULL, roll(HEALTIME,SICKTIME),AFTER);
msg("You become ill. ");
}
}
pstats.s_const -= rnd(2)+1;
if (pstats.s_const <= 3) pstats.s_const = 3;
otherwise: /* not all the foods have to do something */
break;
}
}

721
xrogue/effects.c Normal file
View file

@ -0,0 +1,721 @@
/*
effects.c - functions for dealing with appllying effects to monsters
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 gets weaker!",
weaps[weap->o_which].w_name);
}
}
}
/* If the attacker hit something that shrieks, wake the dungeon */
if (on(*def, CANSHRIEK)) {
if (see_def)
msg("%s emits an ear piercing shriek! ", prname(defname, TRUE));
else
msg("You hear an ear piercing shriek!");
/* Friendly charactors should be immune */
if (player.t_ctype == C_PALADIN ||
player.t_ctype == C_RANGER || player.t_ctype == C_MONK)
aggravate(TRUE, FALSE);
else
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 < 1) {
pstats.s_hpt = -1;
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 return to normal. ");
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("Your life force is being drained out of 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 itself nastily against you!",
prname(attname, TRUE));
else if (see_att)
msg("%s squeezes real 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 your arm.");
else {
chg_str(-1);
msg(terse ? "A sting has weakened you." :
"You get stung in the arm! You 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 transformed into 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 (def->t_stats.s_intel > 15)
msg("%s staggers.. ", prname(defname, TRUE));
else if (see_def)
msg("%s turns to stone! ", prname(defname, TRUE));
else if (cansee(unc(def->t_pos)))
msg("A statue appears out of nowhere! ");
}
}
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 over.", 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 skillful.", 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 over!", 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. Blech!",
prname(attname, FALSE));
if (on(player, HASSTINK)) lengthen(unstink, STINKTIME);
else {
turn_on(player, HASSTINK);
fuse(unstink, (VOID *)NULL, 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, (VOID *)NULL, 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. Don't affect
* the Ranger or Paladin.
*/
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_RANGER) {
msg("The wound heals quickly.");
}
else {
turn_on(*def, HASDISEASE);
fuse(cure_disease, (VOID *)NULL, roll(HEALTIME,SICKTIME), AFTER);
msg(terse ? "You have been diseased!"
: "You have contracted an annoying 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 becomes weaker.");
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 apart!");
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 have dissolved!");
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. Don't affect the Monk.
*/
if (on(*att, CANINFEST) &&
rnd(def->t_stats.s_const) < att->t_stats.s_lvl) {
if (ISWEARING(R_HEALTH) || 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, (VOID *)NULL, 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) < 30 &&
(find_slot(suffocate) == 0)) {
turn_on(*att, DIDSUFFOCATE);
msg("%s is beginning to suffocate you!", prname(attname, TRUE));
fuse(suffocate, (VOID *)NULL, 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)) {
if (terse)
msg("Pheww!");
else
msg("You smell an unpleasant odor. Phew!");
}
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, (VOID *)NULL, 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. Don't affect the Monk,
* Paladin, or Ranger.
*/
if (on(*att, CANROT)) {
if (!ISWEARING(R_HEALTH) &&
player.t_ctype != C_MONK &&
player.t_ctype != C_RANGER &&
player.t_ctype != C_PALADIN &&
!save(VS_POISON, def, 0) &&
off(*def, DOROT)) {
turn_on(*def, DOROT);
msg("You feel your skin starting to rot and peel 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 * 2);
if (!save(VS_MAGIC, def, att->t_stats.s_lvl/10)) {
if (on(*att, ISUNIQUE))
purse -= (GOLDCALC * 5);
else
purse -= (GOLDCALC * 3);
}
if (purse < 0)
purse = 0;
if (purse != lastpurse) {
msg("You lost some gold! ");
/* 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;
strcpy(obj->o_damage,"0d0");
strcpy(obj->o_hurldmg,"0d0");
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);
}

202
xrogue/encumb.c Normal file
View file

@ -0,0 +1,202 @@
/*
encumb.c - Stuff to do with encumberance
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#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] != NULL && cur_ring[i]->o_which == R_CARRY) {
if (cur_ring[i]->o_flags & ISCURSED) temp--;
else temp += 2;
}
}
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 = mvwinch(stdscr, hero.y, hero.x);
if((ch != FLOOR && ch != PASSAGE)) {
extinguish(wghtchk);
fuse(wghtchk, (VOID *)NULL, 1, AFTER);
inwhgt = FALSE;
return;
}
extinguish(wghtchk);
msg("Your pack is far too heavy for you.. ");
do {
dropchk = drop((struct linked_list *)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);
}

1473
xrogue/fight.c Normal file

File diff suppressed because it is too large Load diff

651
xrogue/help.c Normal file
View file

@ -0,0 +1,651 @@
/*
help.c - Routines having to do with help
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <ctype.h>
#include "mach_dep.h"
#include "rogue.h"
/*
* Give character descripts
*/
static char *game_fighter = "Strength is the main attribute of the Fighter. \
He can wield any weapon and the two-handed sword is his weapon of choice. He \
can also wear any type of armor. Plate armor being the best choice and \
leather armor the worst. The Fighter is able to sense both traps and gold \
at higher experience levels. His natural quest item is the Axe of Aklad. \
Due to his superior form, the Fighter usually receives more hit-points per \
new experience level than the other characters. The Fighter is neither good \
or evil; he is a neutral character. The default attribute values of the \
Fighter are: Int=7, Str=16, Wis=7, Dxt=16, Con=17, and Chr=11. Default gold \
amount is 2000 pieces and default hit-points are 24.";
static char *game_thief = "Dexterity is the main attribute of the Thief. His \
stealth allows him to move quietly, thus disturbing less monsters. He can \
sense traps and gold and can take (steal) things from the monsters. The \
Thief can not wield the two-handed sword so the bastard sword is his weapon \
of choice. He can only wear studded leather armor. The Thief's natural \
quest item is the Daggers of Musty Doit. With higher dexterity the Thief \
is able to \"backstab\" monsters, thereby killing them with a single blow. \
His character type fluctuates between that of good, neutral, and evil. The \
default attribute values of the Thief are: Int=7, Str=14, Wis=7, Dxt=18, \
Con=17, and Chr=11. Default gold amount is 2000 pieces and default \
hit-points are 23.";
static char *game_assassin = "Dexterity is the main attribute of the \
Assassin. Like the Thief, he moves with an extra degree of stealth. He can \
sense gold and steal things from monsters. The ability to sense traps comes \
at higher experience levels. The Assassin can not wield the two-handed sword \
and he can only wear studded leather armor. The natural quest item of the \
Assassin is the Eye of Vecna. He is also skilled in the use of poison. \
Higher dexterity enables him to \"assassinate\" monsters with a single blow. \
The Assassin is aligned with the powers of evil. The default attribute \
values of the Assassin are: Int=7, Str=14, Wis=7, Dxt=18, Con=17, and \
Chr=11. Default gold amount is 2000 pieces and default hit-points are 23.";
static char *game_ranger = "Charisma is the main attribute of the Ranger who \
also has a secondary attribute of Intelligence. Like the Magician, this \
gives him the ability to cast spells which increases as he attains higher \
experience levels. Like the Fighter, he can wield any weapon and wear any \
armor. The Ranger's natural quest item is the Mandolin of Brian. He is \
aligned with the powers of good. Therefore, he can be made to suffer and \
even become cursed by the very powers that allow him to cast spells if he \
happens to cause the demise of a likewise good creature. The default \
attribute values of the Ranger are: Int=11, Str=11, Wis=7, Dxt=16, Con=16, \
and Chr=13. Default gold amount is 2000 pieces and default hit-points \
are 22.";
static char *game_paladin = "Charisma is the main attribute of the Paladin \
who has a secondary attribute of Wisdom. Like the Cleric, this gives him \
the ability to offer prayers, receive what his heart desires, and an ability \
to turn the undead. This ability will increase as he gains higher \
experience levels. Like the Fighter, he can wield any weapon and wear any \
armor. The Ankh of Heil is the Paladin's natural quest item. Like the \
Ranger, the Paladin is aligned with the powers of good. This can cause \
him to suffer and become cursed if he brings ruin to a likewise good \
creature. The default attribute values of the Paladin are: Int=7, \
Str=11, Wis=11, Dxt=16, Con=16, and Chr=13. Default gold amount is \
2000 pieces and default hit-points are 22.";
static char *game_druid = "Wisdom is the main attribute of the Druid. This \
gives him the ability to chant secret words and mantras, which is much \
greater than that of the Monk. The Druid can not wield the two-handed or \
bastard swords but he can wear any armor. His natural quest item is the Quill \
of Nagrom. Like the Magician and Cleric, the Druid is aligned neutral. He \
therefore, must rely upon his Wisdom and his chanting ability in order to \
remain alive. Likewise, he does not receive as many new hit-points per \
new experience level. The default attribute values of the Druid are: Int=7, \
Str=10, Wis=14, Dxt=16, Con=15, and Chr=12. Default gold amount is 2000 \
pieces and default hit-points are 21.";
static char *game_monk = "Constitution is the main attribute of the Monk who \
has a secondary aspect of Wisdom. Like the Druid, this gives him the \
ability to chant mantras which will increase as he gains higher experience. \
The Monk can not wield the two-handed sword and he can not wear any armor. \
The Cloak of Emori is the Monk's natural quest item. The Monk can also \
sense traps, though much less than the Thief or Assassin. He is the most \
healthy character. Like the Ranger and Paladin, he is aligned with the \
powers of good. Therefore, he is made to suffer and can become cursed if \
he kills a likewise good creature. The default attribute values of the \
Monk are: Int=7, Str=11, Wis=11, Dxt=16, Con=18, and Chr=11. Default \
gold amount is 2000 pieces and default hit-points are 22.";
static char *game_magician = "Intelligence is the main attribute of the \
Magician. The Magician's ability to cast spells is much greater than that \
of the Ranger. He can not wield the two- handed or bastard swords, but he \
can wear any kind of armor. His natural quest item is the Amulet of \
Stonebones. The Magician is aligned neutral. He must rely upon his \
Intelligence and spell casting abilities to remain alive. There- fore, he \
does not receive as many new hit-points per new experience level. The \
default attribute values of the Magician are: Int=14, Str=10, Wis=7, \
Dxt=16, Con=15, and Chr=12. Default gold amount is 2000 pieces and \
default hit-points are 21.";
static char *game_cleric = "Wisdom is the main attribute of the Cleric. The \
Cleric's ability to give or offer prayers, receive their due, and affect \
the undead are much greater than that of the Paladin. Like the Magician, \
the Cleric can not wield the two- handed or bastard swords, but he can \
wear any armor. His natural quest item is the Horn of Geryon. The Cleric \
is aligned neutral and he must rely upon his Wisdom and prayer ability to \
remain alive. He therefore, does not receive as many new hit-points per \
new experience level. The default attribute values of the Cleric are: Int=7, \
Str=10, Wis=14, Dxt=16, Con=15, and Chr=12. The default gold amount is 2000 \
pieces and default hit-points are 21.";
static char *game_food ="There are three types of food, regular food rations, \
various fruits, and slime- molds. Eating regular food will add 750 points to \
your current food level [see the CTRL(E) command]. Eating fruit adds \
300 points. Certain fruits also cure you, add an attribute point, add a \
hit-point, increase your armor, give you additional prayer, chant, or spell \
casting abilities, or add experience points. Eating slime-mold (monster \
food) can make you ill, but they will add 100 points to your current food \
level. If your food level points drop below 100 you will become weak. You \
will faint and might die if they drop to 0 or below. At the other extreme, \
if your food level points reach 2000 (and above) you will become satiated. \
Risk eating more and you could choke to death.";
/*
static char *game_monst ="To be updated.";
static char *game_potion ="To be updated...";
static char *game_scroll ="To be updated...";
static char *game_ring ="To be updated...";
static char *game_stick ="To be updated...";
static char *game_weapon ="To be updated...";
static char *game_armor ="To be updated...";
static char *game_miscm ="To be updated...";
static char *game_qitems ="To be updated...";
static char *game_dungeon ="To be updated...";
static char *game_traps ="To be updated...";
static char *game_mazes ="To be updated...";
static char *game_option ="To be updated...";
static char *game_begin ="To be updated...";
*/
/* help list */
static struct h_list helpstr[] = {
'?', " Print help",
'/', " Identify object",
'=', " Identify a screen character",
' ', "",
'h', " Move left",
'j', " Move down",
'k', " Move up",
'l', " Move right",
'y', " Move up and left",
'u', " Move up and right",
'b', " Move down and left",
'n', " Move down and right",
'H', " Run left",
'J', " Run down",
'K', " Run up",
'L', " Run right",
'Y', " Run up & left",
'U', " Run up & right",
'B', " Run down & left",
'N', " Run down & right",
' ', "",
'>', " Go down a staircase",
'<', " Go up a staircase",
'\\', " Game descriptions",
'.', " Rest for a while",
'*', " Count gold pieces",
'a', " Affect the undead",
'A', " Choose artifact (equipage)",
'c', " Chant a mantra",
'C', " Cast a spell",
'd', " Drop something",
'D', " Dip something (into a pool)",
'e', " Eat food or fruit",
'f', "<dir> Forward until find something",
'F', " Frighten a monster",
'g', " Give food to monster",
'G', " Sense for gold",
'i', " Inventory",
'I', " Inventory (single item)",
'm', " Mark an object (specific)",
'o', " Examine and/or set options",
'O', " Character type and quest item",
'p', " Pray to the powers that be",
'P', " Pick up object(s)",
'q', " Quaff a potion",
'Q', " Quit the game",
'r', " Read a scroll",
's', " Search for a trap/secret door",
'S', " Save your game",
't', "<dir> Throw something",
'T', " Take off something",
'v', " Print program version",
'w', " Wield a weapon",
'W', " Wear something",
'X', " Sense for traps",
'z', "<dir> Zap a wand or staff",
' ', "",
'^', " Set a trap",
'$', " Price an item (trading post)",
'#', " Buy an item (trading post)",
'%', " Sell an item (trading post)",
'!', " Shell escape",
ESC, " Cancel command (Esc)",
' ', "",
CTRL('B'), " Current score (if you win)",
CTRL('E'), " Current food level",
CTRL('L'), " Redraw the screen",
CTRL('N'), " Name an object or a monster",
CTRL('O'), " Character affect status",
CTRL('R'), " Repeat last message",
CTRL('T'), "<dir> Take (steal) from (direction)",
CTRL('U'), " Use a magic item",
0, 0
} ;
/* wizard help list */
static struct h_list wiz_help[] = {
' ', "",
'+', " Random fortunes",
'M', " Make an object",
'V', " Display vlevel and turns",
CTRL('A'), " System activity",
CTRL('C'), " Move to another dungeon level",
CTRL('D'), " Go down 1 dungeon level",
CTRL('F'), " Display the entire level",
CTRL('G'), " Charge wands and staffs",
CTRL('H'), " Jump 9 experience levels",
CTRL('I'), " Inventory of level",
CTRL('J'), " Teleport somewhere",
CTRL('K'), " Identify an object",
CTRL('M'), " Recharge wand or staff",
CTRL('P'), " Toggle wizard status",
CTRL('X'), " Detect monsters",
CTRL('Y'), " Display food levels",
0, 0
};
/* item help list */
static struct item_list item_help[] = {
'@', " You (visible)",
'_', " You (invisible)",
' ', "",
':', " Food ration or fruit (eat)",
'!', " Potion (quaff)",
'?', " Scroll (read)",
'=', " Ring (wear)",
')', " Weapon (wield)",
']', " Armor (wear)",
'/', " Wand or staff (zap)",
';', " Magic item (use)",
',', " Artifact (quest item)",
'*', " Gold or zapped missile",
' ', "",
'$', " Magical item in room",
'>', " Blessed magical item",
'<', " Cursed magical item",
' ', " ",
'`', " Dart trap",
'{', " Arrow trap",
'}', " Bear trap",
'~', " Teleport trap",
'$', " Sleeping gas trap",
'>', " Trap door",
'<', " Outer region entrance",
'\'', " Maze entrance",
'^', " Trading post entrance",
'"', " Magic pool or lake",
' ', " Solid rock or mountain",
'.', " Floor of a room or meadow",
'%', " Stairs (up or down)",
'+', " Doorway",
'&', " Secret doorway",
'#', " Passage between rooms",
'\\', " Forest",
HORZWALL, " Horizontal wall of a room",
VERTWALL, " Vertical wall of a room",
0, 0
};
ident_hero()
{
bool doit = TRUE;
wclear(hw);
wprintw(hw, "Characters, Items, and Game Descriptions:\n");
wprintw(hw, "-----------------------------------------\n");
wprintw(hw, "a) Fighter m) Scrolls\n");
wprintw(hw, "b) Thief n) Rings\n");
wprintw(hw, "c) Assassin o) Wands and Staffs\n");
wprintw(hw, "d) Ranger p) Weapons\n");
wprintw(hw, "e) Paladin q) Armors\n");
wprintw(hw, "f) Monk r) Miscellaneous Magic Items\n");
wprintw(hw, "g) Magician s) Quest Items (Artifacts and Relics)\n");
wprintw(hw, "h) Cleric t) The Dungeon\n");
wprintw(hw, "i) Druid u) Traps\n");
wprintw(hw, "j) Monsters v) Mazes and Outer Regions\n");
wprintw(hw, "k) Foods w) Setting game options\n");
wprintw(hw, "l) Potions x) Starting out\n");
wprintw(hw, "\nEnter a letter: ");
draw(hw);
while (doit) {
switch (wgetch(cw)) {
case EOF:
case ESC:
doit = FALSE;
when 'a':
wclear(hw);
wprintw(hw, "Fighter Characteristics:");
mvwaddstr(hw, 2, 0, game_fighter);
draw(hw);
doit = FALSE;
when 'b':
wclear(hw);
wprintw(hw, "Thief Characteristics:");
mvwaddstr(hw, 2, 0, game_thief);
draw(hw);
doit = FALSE;
when 'c':
wclear(hw);
wprintw(hw, "Assassin Characteristics:");
mvwaddstr(hw, 2, 0, game_assassin);
draw(hw);
doit = FALSE;
when 'd':
wclear(hw);
wprintw(hw, "Ranger Characteristics:");
mvwaddstr(hw, 2, 0, game_ranger);
draw(hw);
doit = FALSE;
when 'e':
wclear(hw);
wprintw(hw, "Paladin Characteristics:");
mvwaddstr(hw, 2, 0, game_paladin);
draw(hw);
doit = FALSE;
when 'f':
wclear(hw);
wprintw(hw, "Monk Characteristics:");
mvwaddstr(hw, 2, 0, game_monk);
draw(hw);
doit = FALSE;
when 'g':
wclear(hw);
wprintw(hw, "Magician Characteristics:");
mvwaddstr(hw, 2, 0, game_magician);
draw(hw);
doit = FALSE;
when 'h':
wclear(hw);
wprintw(hw, "Cleric Characteristics:");
mvwaddstr(hw, 2, 0, game_cleric);
draw(hw);
doit = FALSE;
when 'i':
wclear(hw);
wprintw(hw, "Druid Characteristics:");
mvwaddstr(hw, 2, 0, game_druid);
draw(hw);
doit = FALSE;
when 'j':
wclear(hw);
wprintw(hw, "Monster Characteristics:");
draw(hw);
doit = FALSE;
when 'k':
wclear(hw);
wprintw(hw, "Foods:");
mvwaddstr(hw, 2, 0, game_food);
draw(hw);
doit = FALSE;
when 'l':
wclear(hw);
wprintw(hw, "Potions:");
draw(hw);
doit = FALSE;
when 'm':
wclear(hw);
wprintw(hw, "Scrolls:");
draw(hw);
doit = FALSE;
when 'n':
wclear(hw);
wprintw(hw, "Rings:");
draw(hw);
doit = FALSE;
when 'o':
wclear(hw);
wprintw(hw, "Wands and Staffs:");
draw(hw);
doit = FALSE;
when 'p':
wclear(hw);
wprintw(hw, "Weapons:");
draw(hw);
doit = FALSE;
when 'q':
wclear(hw);
wprintw(hw, "Armors:");
draw(hw);
doit = FALSE;
when 'r':
wclear(hw);
wprintw(hw, "Miscellaneous Magic Items:");
draw(hw);
doit = FALSE;
when 's':
wclear(hw);
wprintw(hw, "Quest Items (Artifacts and Relics):");
draw(hw);
doit = FALSE;
when 't':
wclear(hw);
wprintw(hw, "The Dungeon:");
draw(hw);
doit = FALSE;
when 'u':
wclear(hw);
wprintw(hw, "Traps:");
draw(hw);
doit = FALSE;
when 'v':
wclear(hw);
wprintw(hw, "Mazes and Outer Regions:");
draw(hw);
doit = FALSE;
when 'w':
wclear(hw);
wprintw(hw, "Setting game options:");
draw(hw);
doit = FALSE;
when 'x':
wclear(hw);
wprintw(hw, "Starting out:");
draw(hw);
doit = FALSE;
otherwise:
doit = TRUE;
}
}
wmove(hw, lines-1, 0);
wprintw(hw, spacemsg);
draw(hw);
wait_for(' ');
wclear(hw);
draw(hw);
wmove(cw, 0, 0);
wclrtoeol(cw);
status(FALSE);
touchwin(cw);
}
/*
* Real Help
*/
help()
{
register struct h_list *strp = helpstr;
register struct item_list *itemp = item_help;
struct h_list *wizp = wiz_help;
register char helpch;
register int cnt;
msg("Character you want help for (* for commands, @ for items): ");
helpch = wgetch(cw);
mpos = 0;
/*
* If it's not a *, @, or +, then just print help string
* for the character entered.
*/
if (helpch != '*' && helpch != '@' && helpch != '+') {
wmove(msgw, 0, 0);
while (strp->h_ch) {
if (strp->h_ch == helpch) {
msg("%s%s", unctrl(strp->h_ch), strp->h_desc);
return;
}
strp++;
}
if (wizard) {
while (wizp->h_ch) {
if (wizp->h_ch == helpch) {
msg("%s%s", unctrl(wizp->h_ch), wizp->h_desc);
return;
}
wizp++;
}
}
msg("Unknown command '%s'", unctrl(helpch));
return;
}
/* fortunes - but let's not say so - explicitly */
if (helpch == '+') {
msg("Meaningless command '+'");
return;
}
/*
* Print help for everything else
*/
if (helpch == '*') {
wclear(hw);
cnt = 0;
while (strp->h_ch) {
mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(strp->h_ch));
waddstr(hw, strp->h_desc);
strp++;
if (++cnt >= 46 && strp->h_ch) {
wmove(hw, lines-1, 0);
wprintw(hw, morestr);
draw(hw);
wait_for(' ');
wclear(hw);
cnt = 0;
}
}
if (wizard) {
while (wizp->h_ch) {
mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(wizp->h_ch));
waddstr(hw, wizp->h_desc);
wizp++;
if (++cnt >= 46 && wizp->h_ch) {
wmove(hw, lines-1, 0);
wprintw(hw, morestr);
draw(hw);
wait_for(' ');
wclear(hw);
cnt = 0;
}
}
}
}
if (helpch == '@') {
wclear(hw);
cnt = 0;
while (itemp->item_ch) {
mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(itemp->item_ch));
waddstr(hw, itemp->item_desc);
itemp++;
if (++cnt >= 46 && itemp->item_ch) {
wmove(hw, lines-1, 0);
wprintw(hw, morestr);
draw(hw);
wait_for(' ');
wclear(hw);
cnt = 0;
}
}
}
wmove(hw, lines-1, 0);
wprintw(hw, spacemsg);
draw(hw);
wait_for(' ');
wclear(hw);
draw(hw);
wmove(cw, 0, 0);
wclrtoeol(cw);
status(FALSE);
touchwin(cw);
}
/*
* identify:
* Tell the player what a certain thing is.
*/
identify(ch)
register unsigned char ch;
{
register char *str = NULL;
if (ch == 0) {
msg("What do you want identified? ");
ch = wgetch(cw);
mpos = 0;
if (ch == ESC)
{
msg("");
return;
}
}
if (isalpha(ch))
msg("Use the \"=\" command to identify monsters. ");
else switch(ch)
{
case VPLAYER: str = "You (visibly)";
when IPLAYER: str = "You (invisibly)";
when GOLD: str = "Gold";
when STAIRS: str = (levtype == OUTSIDE) ? "Entrance to the dungeon"
: "Stairway";
when DOOR: str = "Doorway";
when SECRETDOOR:str = "Secret door";
when FLOOR: str = (levtype == OUTSIDE) ? "Meadow" : "Room floor";
when PASSAGE: str = "Passage";
when VERTWALL:
case HORZWALL:
str = (levtype == OUTSIDE) ? "Boundary of sector"
: "Wall of a room";
when POST: str = "Trading post";
when POOL: str = (levtype == OUTSIDE) ? "Lake"
: "A shimmering pool";
when TRAPDOOR: str = "Trap door";
when ARROWTRAP: str = "Arrow trap";
when SLEEPTRAP: str = "Sleeping gas trap";
when BEARTRAP: str = "Bear trap";
when TELTRAP: str = "Teleport trap";
when DARTTRAP: str = "Dart trap";
when MAZETRAP: str = "Entrance to a maze";
when WORMHOLE: str = "Entrance to a worm hole";
when FOREST: str = "Forest";
when ' ' : str = (levtype == OUTSIDE) ? "Mountain"
: "Solid rock";
when FOOD: str = "Food";
when POTION: str = "Potion";
when SCROLL: str = "Scroll";
when RING: str = "Ring";
when WEAPON: str = "Weapon";
when ARMOR: str = "Armor";
when MM: str = "Miscellaneous magic";
when STICK: str = "Wand or staff";
when RELIC: str = "Artifact";
otherwise: str = "Unknown character";
}
if (!isalpha(ch))
msg("%s %s", unctrl(ch), str);
}

825
xrogue/init.c Normal file
View file

@ -0,0 +1,825 @@
/*
init.c - global variable initializaton
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <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 = "Enter a number within the minimum and maximum \
range. When satisfied with your choices, enter a 'y'. For help at any \
other time enter a '?' or a '='.";
/* replace the above line with this when descriptions are done */
/* other time enter a '?' or a '='. For character and item descriptions \
enter a '\\' on any other screen.";
*/
struct words rainbow[NCOLORS] = {
"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",
};
struct words sylls[NSYLLS] = {
"a", "ae", "ak", "an", "ax", "ach", "ano", "ars", "bha", "bar", "bre",
"cha", "cre", "cum", "cow", "duh", "dha", "e", "ea", "em", "et", "ey",
"eck", "etk", "egg", "exl", "fu", "fen", "fid", "gan", "gle", "h", "ha",
"hr", "ht", "how", "hex", "hip", "hoc", "i", "ia", "ig", "it", "iz",
"ion", "ink", "ivi", "iss", "je", "jin", "jha", "jyr", "ka", "kho", "kal",
"kli", "lu", "lre", "lta", "lri", "m", "ma", "mh", "mi", "mr", "mar",
"myr", "moh", "mul", "nep", "nes", "o", "oc", "om", "oq", "ox", "orn",
"oxy", "olm", "ode", "po", "pie", "pod", "pot", "qar", "que", "ran", "rah",
"rok", "sa", "sat", "sha", "sol", "sri", "ti", "tem", "tar", "tki", "tch",
"tox", "u", "ub", "uh", "ur", "uv", "unk", "uwh", "ugh", "uyr", "va",
"vil", "vit", "vom", "vux", "wah", "wex", "xu", "xed", "xen", "ya", "yep",
"yih", "zef", "zen", "zil", "zym", "-"
};
struct words stones[NSTONES] = {
"Agate", "Alexandrite", "Amethyst",
"Azurite", "Bloodstone", "Cairngorm",
"Carnelian", "Chalcedony", "Chrysoberyl",
"Chrysolite", "Chrysoprase", "Citrine",
"Coral", "Diamond", "Emerald",
"Garnet", "Heliotrope", "Hematite",
"Hyacinth", "Jacinth", "Jade",
"Jargoon", "Jasper", "Kryptonite",
"Lapis lazuli", "Malachite", "Mocca stone",
"Moonstone", "Obsidian", "Olivine",
"Onyx", "Opal", "Pearl",
"Peridot", "Quartz", "Rhodochrosite",
"Rhodolite", "Ruby", "Sapphire",
"Sardonyx", "Serpentine", "Spinel",
"Tiger eye", "Topaz", "Tourmaline",
"Turquoise", "Zircon",
};
struct words wood[NWOOD] = {
"Avocado wood", "Balsa", "Banyan", "Birch",
"Cedar", "Cherry", "Cinnabar", "Dogwood",
"Driftwood", "Ebony", "Eucalyptus", "Hemlock",
"Ironwood", "Mahogany", "Manzanita", "Maple",
"Oak", "Pine", "Redwood", "Rosewood",
"Teak", "Walnut", "Aloe", "Sandalwood",
};
struct words metal[NMETAL] = {
"Aluminium", "Bone", "Brass", "Bronze",
"Copper", "Chromium", "Iron", "Lead",
"Magnesium", "Pewter", "Platinum", "Silver",
"Steel", "Tin", "Titanium", "Zinc",
};
/*
* 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;
register char *str;
for (i = 0 ; i < MAXPOTIONS ; i++)
{
do
str = rainbow[rnd(NCOLORS)].w_string;
until (isupper(*str));
*str = tolower(*str);
p_colors[i] = str;
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;
register char *str;
for (i = 0 ; i < MAXSTICKS ; i++)
{
do
if (rnd(100) > 50)
{
str = metal[rnd(NMETAL)].w_string;
if (isupper(*str))
ws_type[i] = "wand";
}
else
{
str = wood[rnd(NWOOD)].w_string;
if (isupper(*str))
ws_type[i] = "staff";
}
until (isupper(*str));
*str = tolower(*str);
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(5)+1;
while(nsyl--)
{
sp = sylls[rnd(NSYLLS)].w_string;
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 = 0, minimum, maximum, ch, i, j = 0;
short do_escape, *our_stats[NUMABILITIES-1];
struct linked_list *weap_item, *armor_item, *food_item;
struct object *obj;
weap_item = armor_item = food_item = NULL;
if (char_type == -1) { /* not set via options */
/* 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 = 3000;
switch (player.t_ctype) {
case C_FIGHTER:
purse += 200;
when C_MAGICIAN:
case C_CLERIC:
case C_DRUID:
purse += 100;
when C_THIEF:
case C_ASSASSIN:
purse += 0;
when C_RANGER:
case C_PALADIN:
purse -= 100;
when C_MONK:
purse -= 200;
}
/*
* allow me to describe a super character
*/
/* let's lessen the restrictions on this okay? */
if (wizard && strcmp(getenv("SUPER"),"YES") == 0) {
pstats.s_str = MAXATT;
pstats.s_intel = MAXATT;
pstats.s_wisdom = MAXATT;
pstats.s_dext = MAXATT;
pstats.s_const = MAXATT;
pstats.s_charisma = MAXATT;
pstats.s_exp = 10000000L;
pstats.s_lvl = 1;
pstats.s_lvladj = 0;
pstats.s_hpt = 500;
pstats.s_carry = totalenc(&player);
strcpy(pstats.s_dmg,"4d8");
check_level();
wmove(hw,0,0);
wclrtoeol(hw);
draw(hw);
mpos = 0;
/* set quest item */
if(player.t_ctype == C_FIGHTER) quest_item = AXE_AKLAD;
if(player.t_ctype == C_RANGER) quest_item = BRIAN_MANDOLIN;
if(player.t_ctype == C_PALADIN) quest_item = HEIL_ANKH;
if(player.t_ctype == C_MAGICIAN) quest_item = STONEBONES_AMULET;
if(player.t_ctype == C_CLERIC) quest_item = GERYON_HORN;
if(player.t_ctype == C_THIEF) quest_item = MUSTY_DAGGER;
if(player.t_ctype == C_ASSASSIN) quest_item = EYE_VECNA;
if(player.t_ctype == C_DRUID) quest_item = QUILL_NAGROM;
if(player.t_ctype == C_MONK) quest_item = EMORI_CLOAK;
/* armor */
if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN)
j = STUDDED_LEATHER;
else if (player.t_ctype == C_MONK) {
armor_item = spec_item(MM, MM_BRACERS, 20, 0);
obj = OBJPTR(armor_item);
obj->o_weight = things[TYP_MM].mi_wght;
whatis (armor_item); /* identify it */
obj->o_flags |= (ISKNOW | ISPROT);
add_pack(armor_item, TRUE);
cur_misc[WEAR_BRACERS] = obj;
goto w_armorjmp;
}
else j = PLATE_ARMOR;
armor_item = spec_item(ARMOR, j, 20, 0);
obj = OBJPTR(armor_item);
obj->o_weight = armors[j].a_wght;
obj->o_flags |= (ISKNOW | ISPROT);
add_pack(armor_item, TRUE);
cur_armor = obj;
w_armorjmp: /* monk doesn't wear armor */
/* weapons */
if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN ||
player.t_ctype == C_MONK)
j = BASWORD;
else if (player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER ||
player.t_ctype == C_PALADIN)
j = TWOSWORD;
else j = TRIDENT;
weap_item = spec_item(WEAPON, j, 20, 20);
obj = OBJPTR(weap_item);
obj->o_flags |= (ISKNOW | ISPROT);
obj->o_weight = weaps[j].w_wght;
add_pack(weap_item, TRUE);
cur_weapon = obj;
/* food */
food_item = spec_item(FOOD, E_RATION, 0, 0);
obj = OBJPTR(food_item);
obj->o_flags |= ISKNOW;
obj->o_weight = foods[TYP_FOOD].mi_wght;
add_pack(food_item, TRUE); /* just one */
/* give wizard plenty gold */
purse = 50000;
}
else
/* default attributes checked */
{
if (def_attr == TRUE) { /* "default" option used in ROGUEOPTS */
switch(player.t_ctype) {
/* set "default attributes" option and quest items here */
case C_FIGHTER:
case C_MONK:
pstats.s_intel = 7;
pstats.s_dext = 16;
pstats.s_charisma = 11;
if (player.t_ctype == C_FIGHTER) {
pstats.s_str = 16;
pstats.s_wisdom = 7;
pstats.s_const = 17;
quest_item = AXE_AKLAD;
}
else {
pstats.s_str = 11;
pstats.s_wisdom = 11;
pstats.s_const = 18;
quest_item = EMORI_CLOAK;
}
when C_RANGER:
case C_PALADIN:
pstats.s_str = 11;
pstats.s_dext = 16;
pstats.s_const = 16;
pstats.s_charisma = 13;
/* intelligence or wisdom */
if (player.t_ctype == C_RANGER) {
pstats.s_intel = 11;
pstats.s_wisdom = 7;
quest_item = BRIAN_MANDOLIN;
}
else {
pstats.s_intel = 7;
pstats.s_wisdom = 11;
quest_item = HEIL_ANKH;
}
when C_THIEF:
case C_ASSASSIN:
pstats.s_intel = 7;
pstats.s_str = 14;
pstats.s_wisdom = 7;
pstats.s_dext = 18;
pstats.s_const = 17;
pstats.s_charisma = 11;
if (player.t_ctype == C_THIEF)
quest_item = MUSTY_DAGGER;
else
quest_item = EYE_VECNA;
when C_MAGICIAN:
case C_CLERIC:
case C_DRUID:
pstats.s_str = 10;
pstats.s_dext = 16;
pstats.s_const = 15;
pstats.s_charisma = 12;
/* intelligence & wisdom */
if (player.t_ctype == C_MAGICIAN) {
pstats.s_intel = 14;
pstats.s_wisdom = 7;
}
else {
pstats.s_intel = 7;
pstats.s_wisdom = 14;
}
if (player.t_ctype == C_MAGICIAN)
quest_item = STONEBONES_AMULET;
else if (player.t_ctype == C_CLERIC)
quest_item = GERYON_HORN;
else
quest_item = QUILL_NAGROM;
}
/* Intialize */
pstats.s_exp = 0L;
pstats.s_lvl = 1;
pstats.s_lvladj = 0;
pstats.s_exp = 0L;
strcpy(pstats.s_dmg,"2d4");
pstats.s_carry = totalenc(&player);
check_level();
wmove(hw,0,0);
wclrtoeol(hw);
draw(hw);
mpos = 0;
/* 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;
/* dole out some armor */
if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN)
j = STUDDED_LEATHER;
else if (player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER ||
player.t_ctype == C_PALADIN) {
switch (rnd(4)) {
case 0: j = PLATE_ARMOR;
when 1: j = PLATE_MAIL;
when 2: case 3: j = BANDED_MAIL;
}
}
else if (player.t_ctype == C_MONK) {
if (rnd(3) == 0) j = MM_PROTECT;
else j = MM_BRACERS;
armor_item = spec_item(MM, j, rnd(125)/60+3, 0);
obj = OBJPTR(armor_item);
obj->o_weight = things[TYP_MM].mi_wght;
whatis (armor_item); /* identify it */
obj->o_flags |= ISKNOW;
add_pack(armor_item, TRUE);
goto p_armorjmp;
}
else { /* other characters */
switch (rnd(7)) {
case 0: j = PLATE_MAIL;
when 1: case 2: j = BANDED_MAIL;
when 3: case 4: j = SPLINT_MAIL;
when 5: case 6: j = PADDED_ARMOR;
}
}
armor_item = spec_item(ARMOR, j, rnd(100)/85, 0);
obj = OBJPTR(armor_item);
obj->o_weight = armors[j].a_wght;
obj->o_flags |= ISKNOW;
add_pack(armor_item, TRUE);
p_armorjmp: /* monk doesn't wear armor */
/* give him a weapon */
if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN ||
player.t_ctype == C_MONK) {
switch (rnd(5)) {
case 0: j = BASWORD;
when 1: case 2: j = TRIDENT;
when 3: case 4: j = BARDICHE;
}
}
else if (player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER ||
player.t_ctype == C_PALADIN) {
switch (rnd(5)) {
case 0: j= TWOSWORD;
when 1: case 2: j= TRIDENT;
when 3: case 4: j= SWORD;
}
}
else {
switch (rnd(7)) {
case 0: j = TRIDENT;
when 1: case 2: j = SWORD;
when 3: case 4: j = BARDICHE;
when 5: j = MACE;
when 6: j = SPETUM;
}
}
weap_item = spec_item(WEAPON, j, rnd(155)/75, rnd(165)/80);
obj = OBJPTR(weap_item);
obj->o_weight = weaps[j].w_wght;
obj->o_flags |= ISKNOW;
add_pack(weap_item, TRUE);
/* food rations */
food_item = spec_item(FOOD, E_RATION, 0, 0);
obj = OBJPTR(food_item);
obj->o_weight = foods[TYP_FOOD].mi_wght;
obj->o_flags |= ISKNOW;
add_pack(food_item, TRUE);
/* give him some fruit - coose from those w/o special effects */
switch (rnd(6)) {
case 0: j = E_BANANA;
when 1: j = E_BLUEBERRY;
when 2: j = E_ELDERBERRY;
when 3: j = E_GUANABANA;
when 4: j = E_CAPRIFIG;
when 5: j = E_GOOSEBERRY;
}
food_item = spec_item(FOOD, j, 0, 0);
obj = OBJPTR(food_item);
obj->o_weight = foods[TYP_FOOD].mi_wght;
obj->o_flags |= ISKNOW;
add_pack(food_item, TRUE);
/* adjust purse */
purse = 2000;
}
else { /* select attibutes */
switch(player.t_ctype) {
case C_FIGHTER: round = A_STRENGTH;
when C_RANGER: round = A_CHARISMA;
when C_PALADIN: round = A_CHARISMA;
when C_MAGICIAN: round = A_INTELLIGENCE;
when C_CLERIC: round = A_WISDOM;
when C_THIEF: round = A_DEXTERITY;
when C_ASSASSIN: round = A_DEXTERITY;
when C_DRUID: round = A_WISDOM;
when C_MONK: round = A_CONSTITUTION;
}
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;
strcpy(pstats.s_dmg,"2d4");
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: %ld", purse);
mvwaddstr(hw, 0, 0, "Is this character okay? ");
draw(hw);
} while(wgetch(hw) != 'y');
}
}
pstats.s_arm = 10;
max_stats = pstats;
/* Set up initial movement rate */
player.t_action = A_NIL;
player.t_movement = 6;
player.t_no_move = 0;
player.t_using = NULL;
wclear(hw);
}
/*
* init_stones:
* Initialize the ring stone setting scheme for this time
*/
init_stones()
{
register int i;
register char *str;
for (i = 0 ; i < MAXRINGS ; i++)
{
do
str = stones[rnd(NSTONES)].w_string;
until (isupper(*str));
*str = tolower(*str);
r_stones[i] = str;
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);
}

563
xrogue/io.c Normal file
View file

@ -0,0 +1,563 @@
/*
io.c - Various input/output functions
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <ctype.h>
#include <stdarg.h>
#include "rogue.h"
/*
* msg:
* Display a message at the top of the screen.
*/
static char msgbuf[BUFSIZ];
static int newpos = 0;
/* VARARGS */
void
msg(char *fmt, ...)
{
va_list ap;
/*
* if the string is "", just clear the line
*/
if (*fmt == '\0')
{
wclear(msgw);
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
*/
/* VARARGS */
void
addmsg(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
doadd(fmt, ap);
va_end(ap);
}
/*
* If there is no current message, do nothing. Otherwise, prompt the
* player with the --More-- string. Then erase the message.
*/
rmmsg()
{
if (mpos) {
wclear(msgw);
overwrite(cw, msgw);
mvwaddstr(msgw, 0, 0, huh);
waddstr(msgw, morestr);
clearok(msgw, FALSE);
draw(msgw);
wait_for(' ');
msg("");
}
}
/*
* 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;
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) + 5 < cols) {
wmove(msgw, 0, mpos + 5);
newpos += mpos + 5;
strcat(huh, " ");
}
else {
wclear(msgw);
overwrite(cw, msgw);
mvwaddstr(msgw, 0, 0, huh);
waddstr(msgw, morestr);
clearok(msgw, FALSE);
draw(msgw);
wait_for(' ');
wclear(msgw);
overwrite(cw, msgw);
wmove(msgw, 0, 0);
huh[0] = '\0';
}
}
else {
wclear(msgw);
overwrite(cw, msgw);
wmove(msgw, 0, 0);
huh[0] = '\0';
}
strcat(huh, msgbuf);
mvwaddstr(msgw, 0, 0, huh);
getyx(msgw, y, x);
mpos = newpos;
newpos = 0;
wmove(msgw, y, x);
clearok(msgw, FALSE);
draw(msgw);
}
doadd(char *fmt, va_list ap)
{
vsprintf((char *) &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;
unsigned char ch;
/* What is here? Don't check monster window if MONSTOK is set */
if (can_on_monst == MONSTOK) ch = mvinch(y, x);
else ch = 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 VERTWALL:
case HORZWALL:
case SECRETDOOR:
if (flgptr && on(*flgptr, CANINWALL)) return(TRUE);
return FALSE;
when SCROLL:
if (can_on_monst == MONSTOK) { /* Not a real obstacle */
move_free = 0; /* check free movement */
return(TRUE);
}
/*
* 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) {
move_free = 1;
item = find_obj(y, x);
if (item != NULL &&
(OBJPTR(item))->o_which==S_SCARE &&
(flgptr == NULL || flgptr->t_stats.s_intel < 17)) {
move_free = 2;
return(FALSE); /* All but smart ones are scared */
}
}
return(TRUE);
otherwise:
return (!isalpha(ch));
}
/* return(FALSE); */
/*NOTREACHED*/
}
/*
* shoot_ok:
* returns true if it is ok for type to shoot over ch
*/
shoot_ok(int ch)
{
switch (ch)
{
case ' ':
case VERTWALL:
case HORZWALL:
case SECRETDOOR:
case FOREST:
return FALSE;
default:
return (!isalpha(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 = 0, ox = 0, temp;
register char *pb;
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;
/* Go to English mode */
nofont(cw);
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 ) {
newfont(cw);
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);
newfont(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;
clearok(msgw, FALSE);
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;
{
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(' ');
restscr(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);
draw(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);
}

246
xrogue/list.c Normal file
View file

@ -0,0 +1,246 @@
/*
list.c - Functions for dealing with linked lists of goodies
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <stdlib.h>
#include <curses.h>
#include "rogue.h"
/*
* detach:
* Takes an item out of whatever linked list it might be in
*/
_detach(list, item)
register 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_fire_list
Throw the whole list of fire monsters away. But don't
discard the item (monster) itself as that belong to mlist.
*/
_r_free_fire_list(ptr)
register struct linked_list **ptr;
{
register struct linked_list *item;
while (*ptr != NULL)
{
item = *ptr;
*ptr = next(item);
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);
if (tp->t_pack != NULL)
o_free_list(tp->t_pack);
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;
memset(item->l_data,0,size);
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);
if (space == NULL) {
sprintf(prbuf,"Rogue ran out of memory (used = %d, wanted = %d).",
md_memused(), size);
fatal(prbuf);
}
total++;
return space;
}

58
xrogue/mach_dep.h Normal file
View file

@ -0,0 +1,58 @@
/*
mach_dep.h - machine dependents
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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/undefine that the wizard commands exist
*/
#if defined(_WIN32)
#define fstat _fstat
#define stat _stat
#define open _open
#define popen _popen
#define pclose _pclose
#if !defined(__MINGW32__)
#define PATH_MAX _MAX_PATH
#endif
#endif
#define NOOP(x) (x += 0)
extern char *md_getusername();
extern char *md_gethomedir();
extern char *md_getroguedir();
extern void md_flushinp();
extern char *md_getshell();
extern char *md_gethostname();
extern void md_dobinaryio();
extern char *md_getpass();
extern void md_init();
extern char *xcrypt();
/*
* define if you want to limit scores to one per class per userid
*/
/* #define LIMITSCORE 1*/
#undef LIMITSCORE
/*
* fudge factor allowed in time for saved game
*/
#define FUDGE_TIME 200

438
xrogue/main.c Normal file
View file

@ -0,0 +1,438 @@
/*
main.c - setup code
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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>
#include <time.h>
#include "mach_dep.h"
#include "network.h"
#include "rogue.h"
main(argc, argv, envp)
char **argv;
char **envp;
{
register char *env;
time_t now;
md_init();
/*
* get home and options from environment
*/
strncpy(home, md_gethomedir(), LINELEN);
/* Get default save file */
strcpy(file_name, home);
strcat(file_name, "xrogue.sav");
/* Get default score file */
strcpy(score_file, md_getroguedir());
if (*score_file)
strcat(score_file,"/");
strcat(score_file, "xrogue.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((long)0, SCOREIT, (short)0);
exit_game(0);
}
/*
* Check for a network update
*/
if (argc == 2 && strcmp(argv[1], "-u") == 0) {
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_game(0);
else {
score((long)amount, UPDATE, (short)monster);
exit_game(0);
}
}
/*
* Check to see if he is a wizard
*/
if (argc >= 2 && argv[1][0] == '\0')
if (strcmp(PASSWD, xcrypt(md_getpass("Wizard's password: "), "mT")) == 0)
{
wizard = TRUE;
argv++;
argc--;
}
if (betaover())
{
printf("Sorry, %s, but the test period of this prerelease version\n",whoami);
printf("of xrogue is over. Please acquire a new version. Sorry.\n");
exit_game(0);
}
if (!wizard && !author() && !playtime()) {
printf("Sorry, %s, but you can't play during working hours.\n", whoami);
printf("Try again later.\n");
exit_game(0);
}
if (!wizard && !author() && too_much()) {
printf("Sorry, %s, but the system is too loaded now.\n", whoami);
printf("Try again later.\n");
exit_game(0);
}
if (argc == 2)
if (!restore(argv[1], envp)) /* Note: restore will never return */
exit_game(0);
if (wizard && getenv("SEED") != NULL) {
seed = atoi(getenv("SEED"));
}
else {
seed = (int) time(&now) + getpid();
}
if (wizard)
printf("Hello %s, welcome to dungeon #%d", whoami, seed);
else
printf("Hello %s, just a moment while I dig the dungeon...", whoami);
fflush(stdout);
md_srand(seed);
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 */
init_names(); /* Set up names of scrolls */
init_misc(); /* Set up miscellaneous magic */
init_foods(); /* set up the food table */
initscr(); /* Start up cursor package */
typeahead(-1); /* turn off 3.2/4.0 curses feature */
if (COLS < MINCOLS)
{
printf("\n\nSorry, %s, but your terminal window has too few columns.\n", whoami);
printf("Your terminal has %d columns, needs 70.\n",COLS);
byebye(0);
}
if (LINES < MINLINES)
{
printf("\n\nSorry, %s, but your terminal window has too few lines.\n", whoami);
printf("Your terminal has %d lines, needs 22.\n",LINES);
byebye(0);
}
cols = COLS;
lines = LINES;
if ( cols % 2 != 0) cols -=1; /* must be even for maze code */
if (lines % 2 != 0) lines -=1; /* must be even for maze code */
/*
* Now that we have cols and lines, we can update our window
* structure for non-hardware windows.
*/
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);
if (cw == NULL || hw == NULL || mw == NULL || msgw == NULL) {
exit_game(EXIT_CLS | EXIT_ENDWIN);
}
keypad(cw, TRUE);
keypad(hw, TRUE);
init_player(); /* Roll up the rogue */
waswizard = wizard;
draw(cw);
/* A super wizard doesn't have to get equipped */
/* Check if "" option is TRUE and get environment flag */
if (wizard && strcmp(getenv("SUPER"),"YES") == 0 ||
def_attr == TRUE) {
level = 1;
new_level(NORMLEV);
}
else
new_level(STARTLEV); /* Draw current level */
/*
* Start up daemons and fuses
*/
daemon(doctor, &player, AFTER);
fuse(swander, (VOID *)NULL, WANDERTIME, AFTER);
/* Give characters their innate abilities */
if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_RANGER)
fuse(spell_recovery, (VOID *)NULL, SPELLTIME, AFTER);
if (player.t_ctype == C_DRUID || player.t_ctype == C_MONK)
fuse(chant_recovery, (VOID *)NULL, SPELLTIME, AFTER);
if (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN)
fuse(prayer_recovery, (VOID *)NULL, SPELLTIME, AFTER);
daemon(stomach, (VOID *)NULL, AFTER);
if (player.t_ctype == C_THIEF ||
player.t_ctype == C_ASSASSIN ||
player.t_ctype == C_MONK)
daemon(trap_look, (VOID *)NULL, AFTER);
/* Does this character have any special knowledge? */
switch (player.t_ctype) {
case C_ASSASSIN:
/* Assassins automatically recognize poison */
p_know[P_POISON] = TRUE;
when C_FIGHTER:
/* Fighters automatically recognize skill */
p_know[P_SKILL] = TRUE;
}
/* Choose an initial quest item */
if (!wizard) {
if (def_attr == FALSE)
quest_item = rnd(MAXRELIC);
}
mpos = 0;
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.
*/
/*UNUSED*/
void
endit(sig)
int sig;
{
NOOP(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);
printf("\n"); /* So the curser doesn't stop at the end of the line */
exit_game(EXIT_ENDWIN);
}
/*
* rnd:
* Pick a very random number.
*/
rnd(range)
register int range;
{
return( 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;
}
setup()
{
md_setup();
}
/*
* 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(-1);
}
/*
* see if the system is being used too much for this game
*/
too_much()
{
/* we no longer do load checking or user counts */
return(FALSE);
}
/*
* author:
* See if a user is an author of the program
*/
author()
{
switch (md_getuid()) {
case 0: /* always OK for root to play */
return TRUE;
default:
return FALSE;
}
}
/*
* playtime:
* Returns TRUE when it is a good time to play rogue
*/
playtime()
{
/* we no longer do playtime checking */
return TRUE;
}
/*
* betaover:
* Returns TRUE if the test period of this version of the game is over
*/
betaover()
{
return(FALSE);
}
exit_game(flag)
int flag;
{
int i;
if (flag & EXIT_CLS) /* Clear Screen */
{
wclear(cw);
draw(cw);
}
if (flag & EXIT_ENDWIN) /* Shutdown Curses */
{
keypad(cw,FALSE);
keypad(hw,FALSE);
delwin(cw);
delwin(mw);
delwin(hw);
delwin(msgw);
if (!isendwin())
endwin();
}
o_free_list(player.t_pack);
t_free_list(mlist);
t_free_list(rlist);
t_free_list(tlist);
o_free_list(lvl_obj); /* Free up previous objects (if any) */
for (i = 0; i < MAXROOMS; i++)
{
r_free_list(rooms[i].r_exit); /* Free up the exit lists */
_r_free_fire_list(&rooms[i].r_fires);
}
for(i=0; i<MAXSCROLLS; i++)
{
if (s_names[i] != NULL)
free( s_names[i] );
if (s_guess[i] != NULL)
free( s_guess[i] );
}
for(i=0; i<MAXPOTIONS; i++)
{
if (p_guess[i] != NULL)
free( p_guess[i] );
}
for(i=0; i<MAXRINGS; i++)
{
if (r_guess[i] != NULL)
free( r_guess[i] );
}
for(i=0; i<MAXSTICKS; i++)
{
if (ws_guess[i] != NULL)
free( ws_guess[i] );
}
exit(0);
}

385
xrogue/maze.c Normal file
View file

@ -0,0 +1,385 @@
/*
maze.c - functions for dealing with mazes
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdlib.h>
#include <curses.h>
#include "rogue.h"
struct cell {
char y_pos;
char x_pos;
};
struct b_cellscells {
char num_pos; /* number of frontier cells next to you */
struct cell conn[4]; /* the y,x position of above cell */
} b_cells;
static char *maze_frontier, *maze_bits;
static int maze_lines, maze_cols;
static char *moffset(), *foffset();
static int rmwall(),findcells(),crankout(),draw_maze();
/*
* crankout:
* Does actual drawing of maze to window
*/
static
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(HORZWALL);
else if(x==0 || x==cols-2) /* left | right side */
addch(VERTWALL);
else if (y % 2 == 0 && x % 2 == 0) {
if(*moffset(y, x-1) || *moffset(y, x+1))
addch(HORZWALL);
else
addch(VERTWALL);
}
else if (y % 2 == 0)
addch(HORZWALL);
else
addch(VERTWALL);
}
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(50) + 50); /* add in one large hunk */
attach(lvl_obj, item);
cnt = 0;
do {
rnd_pos(rp, &tp);
} until (mvinch(tp.y, tp.x) == FLOOR || cnt++ > 2500);
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++ > 2500);
mvaddch(tp.y, tp.x, FOOD);
obj->o_pos = tp;
/* it doesn't mater if it's a treasure maze or a normal maze,
* more than enough monsters will be genned.
*/
least = rnd(11)+5;
if (least < 6) {
least = 7;
treas = FALSE;
}
else treas = TRUE;
genmonsters(least, treas);
/* sometimes they're real angry */
if (rnd(100) < 65) {
/* protect the good charactors */
if (player.t_ctype == C_PALADIN ||
player.t_ctype == C_RANGER || player.t_ctype == C_MONK) {
aggravate(TRUE, FALSE);
}
else {
aggravate(TRUE, TRUE);
}
}
}
/*
* draw_maze:
* Generate and draw the maze on the screen
*/
static
draw_maze()
{
reg int i, j, more;
reg char *ptr;
maze_lines = (lines - 3) / 2;
maze_cols = (cols - 1) / 2;
maze_bits = ALLOC((lines - 3) * (cols - 1));
maze_frontier = ALLOC(maze_lines * maze_cols);
ptr = maze_frontier;
while (ptr < (maze_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(maze_frontier);
FREE(maze_bits);
}
/*
* findcells:
* Figure out cells to open up
*/
static findcells(y,x)
reg int x, y;
{
reg int rtpos, i;
*foffset(y, x) = FALSE;
b_cells.num_pos = 0;
if (y < maze_lines - 1) { /* look below */
if (*foffset(y + 1, x)) {
b_cells.conn[b_cells.num_pos].y_pos = y + 1;
b_cells.conn[b_cells.num_pos].x_pos = x;
b_cells.num_pos += 1;
}
}
if (y > 0) { /* look above */
if (*foffset(y - 1, x)) {
b_cells.conn[b_cells.num_pos].y_pos = y - 1;
b_cells.conn[b_cells.num_pos].x_pos = x;
b_cells.num_pos += 1;
}
}
if (x < maze_cols - 1) { /* look right */
if (*foffset(y, x + 1)) {
b_cells.conn[b_cells.num_pos].y_pos = y;
b_cells.conn[b_cells.num_pos].x_pos = x + 1;
b_cells.num_pos += 1;
}
}
if (x > 0) { /* look left */
if (*foffset(y, x - 1)) {
b_cells.conn[b_cells.num_pos].y_pos = y;
b_cells.conn[b_cells.num_pos].x_pos = x - 1;
b_cells.num_pos += 1;
}
}
if (b_cells.num_pos == 0) /* no neighbors available */
return 0;
else {
i = rnd(b_cells.num_pos);
rtpos = b_cells.num_pos - 1;
rmwall(b_cells.conn[i].y_pos, b_cells.conn[i].x_pos, y, x);
return rtpos;
}
}
/*
* foffset:
* Calculate memory address for frontier
*/
static char *
foffset(y, x)
int y, x;
{
return (maze_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 = 0, xcheck = 0, 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 VERTWALL:
case HORZWALL:
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 VERTWALL:
case HORZWALL:
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 VERTWALL:
case HORZWALL:
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;
if (xcheck < 0 || ycheck < 0)
return FALSE;
switch (winat(ycheck, xcheck)) {
case VERTWALL:
case HORZWALL:
case WALL:
case DOOR:
case SECRETDOOR:
return(FALSE);
}
start += delta;
}
return(TRUE);
}
/*
* moffset:
* Calculate memory address for bits
*/
static char *
moffset(y, x)
int y, x;
{
return (maze_bits + (y * (cols - 1)) + x);
}
/*
* rmwall:
* Removes appropriate walls from the maze
*/
static
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);
}

1296
xrogue/misc.c Normal file

File diff suppressed because it is too large Load diff

1660
xrogue/mons_def.c Normal file

File diff suppressed because it is too large Load diff

865
xrogue/monsters.c Normal file
View file

@ -0,0 +1,865 @@
/*
monsters.c - File with various monster functions in it
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <ctype.h>
#include <string.h>
#include "rogue.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 < (max(50, level) + least); i++) {
if (!treas && rnd(100) < 65) /* 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;
if (levtype == OUTSIDE) {
result = NLEVMONS*vlevel + (NUMMONST-NUMDINOS-1);
if (result > NUMMONST) result = NUMMONST;
}
else {
result = NLEVMONS*vlevel;
if (result > NUMMONST-NUMDINOS) result = NUMMONST-NUMDINOS;
}
if (levtype == OUTSIDE) {
for(; result>(NUMMONST-NUMDINOS-1); result--)
if (monsters[result].m_appear == monster) return(result);
for (result=(NLEVMONS*vlevel)+1; result <= NUMMONST-NUMDINOS; result++)
if (monsters[result].m_appear == monster) return(result);
}
else {
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;
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.x = tp->t_doorgoal.y = -1;
tp->t_quiet = 0;
tp->t_dest = NULL;
tp->t_name = NULL;
tp->t_pos = tp->t_oldpos = *cp;
tp->t_oldch = 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.ms_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.ms_lvl;
tp->t_stats.s_arm = mp->m_stats.ms_arm;
strcpy(tp->t_stats.s_dmg,mp->m_stats.ms_dmg);
tp->t_stats.s_str = mp->m_stats.ms_str;
tp->t_stats.s_dext = mp->m_stats.ms_dex;
tp->t_movement = mp->m_stats.ms_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.ms_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(7);
tp->t_stats.s_const = 8 + rnd(7);
tp->t_stats.s_charisma = 8 + rnd(7);
/* 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 = 70; /* base chance of breathing */
tp->t_artifact = 90; /* base chance of using artifact */
tp->t_summon = 50; /* base chance of summoning */
tp->t_cast = 70; /* 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) < 25)
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) < (20 + 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);
strcpy(cur->o_damage,"0d0");
strcpy(cur->o_hurldmg,"0d0");
strcpy(cur1->o_damage,"0d0");
strcpy(cur1->o_hurldmg,"0d0");
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 < 35) {
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 = 0;
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/3)
return NUMMONST;
cur_level = vlevel;
range = (4*NLEVMONS)+1; /* range is 0 thru 12 */
i = 0;
do
{
if (i++ > NUMMONST-1) { /* in case all have be genocided */
i = 0;
if (--cur_level <= 0)
fatal("rogue: Could not find a monster to make! ");
}
if (levtype == OUTSIDE) { /* create DINOSUARS */
d = (cur_level - rnd(range/2)) + (NUMMONST-NUMDINOS-1);
if (d < NUMMONST-NUMDINOS)
d = (NUMMONST-NUMDINOS) + rnd(range/2);
if (d > NUMMONST-1)
d = (NUMMONST-NUMDINOS) + rnd(NUMDINOS);
}
else { /* Create NORMALs and UNIQs here */
d = (NLEVMONS*(cur_level-1) + rnd(range) - (range-NLEVMONS-1));
if (d < 1) d = rnd(6)+1;
if (d > NUMMONST-NUMDINOS-1) { /* Entire range NORMs + UNIQs */
if (no_unique) /* Choose from last 12 NORMAL monsters */
d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) - rnd(NUMUNIQUE/5);
else /* Choose from entire UNIQ monsters + range */
d = (NUMMONST-NUMDINOS-1) - rnd(NUMUNIQUE+range);
}
/* Half-way into the UNIQs now */
else if (d > (NUMMONST-NUMDINOS-(NUMUNIQUE/2)-1)) {
if (no_unique) /* Choose from last 15 NORMAL monsters */
d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) - rnd(NUMUNIQUE/4);
else /* Choose from entire UNIQ monsters + range */
d = (NUMMONST-NUMDINOS-1) - rnd(NUMUNIQUE+range);
}
/* End NORMALs and begin relic bearing UNIQs */
else if (d > (NUMMONST-NUMDINOS-NUMUNIQUE-1)) {
if (no_unique) /* Choose from last 20 NORMAL monsters */
d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) - rnd(NUMUNIQUE/3);
else /* Choose from first 20 UNIQ monsters */
d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) + rnd(NUMUNIQUE/3);
}
}
}
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 long 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 him ISDEAD.
*/
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 %ld 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;
}
/* identify it */
whatis (item);
/* Remove the POST flag that we used for get_item() */
obj->o_flags &= ~ISPOST;
if (add_pack(item, FALSE) == 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) > 35 &&
(!is_stealth(&player) || (on(*tp, ISUNIQUE) && rnd(100) > 35)) &&
(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, (VOID *)NULL, 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 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, (VOID *)NULL, 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 < 1) {
pstats.s_hpt = -1;
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);
/* 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, (struct thing *)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));
}

1910
xrogue/move.c Normal file

File diff suppressed because it is too large Load diff

672
xrogue/n_level.c Normal file
View file

@ -0,0 +1,672 @@
/*
n_level.c - Dig and draw a new level
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 = 0, i, cnt;
register unsigned 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 = 0, startx = 0, deltay = 0, deltax = 0;
bool fresh=TRUE, vert = 0, top;
struct room *rp;
struct linked_list *nitem, *savmonst=NULL, *savitems=NULL;
coord stairs = {0,0};
if (wizard) {
msg("Turns: %ld", 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+20 + rnd(51);
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) == HORZWALL) vert = TRUE;
else vert = FALSE;
if (level < 1) {
fresh = TRUE;
starty = 2;
startx = 1;
deltay = deltax = 1;
level = max_level; /* Restore level to deepest attempt */
prev_max = level; /* reset for boundary crossings below */
}
else if (level >= 1 && prev_max == 1000) {
fresh = TRUE;
starty = 2;
startx = 1;
deltay = deltax = 1;
prev_max = level; /* reset for boundary crossings below */
}
else { /* Copy several lines of the terrain to the other end */
unsigned char cch; /* Copy character */
if (wizard) msg("Crossing sector boundary ");
/* 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 = mvinch(i+2, j);
mvaddch(lines-6+i, j, cch);
}
else {
cch = mvinch(lines-4-i, j);
mvaddch(4-i, j, cch);
}
}
else
for (j=2; j<lines-3; j++) {
if (top) {
cch = mvinch(j, i+1);
mvaddch(j, cols-4+i, cch);
}
else {
cch = 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;
/* Outside has plenty of monsters, don't need these.
* 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 || levtype != OUTSIDE) 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(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 */
/* What kind of level are we on? */
if (ltype == POSTLEV || ltype == STARTLEV) {
if (ltype == POSTLEV)
do_post(FALSE); /* Trading post */
else
do_post(TRUE); /* Equipage */
levtype = ltype = POSTLEV;
}
else if (ltype == MAZELEV) {
do_maze();
no_food++;
put_things(ltype); /* Place objects (if any) */
}
else if (ltype == OUTSIDE) {
/* Move the cursor back onto the hero */
wmove(cw, hero.y, hero.x);
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, 5) == 5) {
cnt = 0;
do {
rm = rnd_room();
rnd_pos(&rooms[rm], &stairs);
} until (mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 2500);
addch(STAIRS);
}
/*
* maybe add a trading post
*/
if (level > 5 && rnd(10) == 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++ > 2500);
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++ > 2500 || 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 = 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(tlist, item);
turn_off(*tp,ISELSEWHERE);
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 = 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)+2;
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++ > 2500);
traps[i].tr_flags = 0;
/* If we are at the bottom, we can't set a trap door */
if (level >= nfloors) ch = (unsigned char) rnd(8) + 1;
else ch = (unsigned char) rnd(9);
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;
when 8: ch = WORMHOLE;
}
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 = 2500;
do {
if (ltype != OUTSIDE) rm = rnd_room();
else continue;
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); /* affect all charactors */
/*
* 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;
draw(cw);
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;
int ITEMS = 0; /* number of items to place */
coord tp, *exit;
/*
* The only way to get new stuff is to go down into the dungeon.
*/
if (level < cur_max) {
if (ltype == NORMLEV)
return;
}
if (ltype == OUTSIDE) goto jmp_here; /* a jump for outside */
/*
* There is a chance that there is a Treasure Room on this level
*/
if (ltype == NORMLEV && rnd(150) < level) {
register int 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 ||
player.t_ctype==C_MONK) && 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,
* paladin, and monk.
*/
for(;;) {
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 &&
player.t_ctype != C_MONK)
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;
}
}
}
jmp_here: /* outside jumper for equippage */
/*
* Do ITEMS attempts to put things in dungeon, maze, or outside
*/
if (ltype == OUTSIDE) ITEMS = rnd(15)+1;
else if (ltype == MAZELEV) ITEMS = rnd(20)+1;
else ITEMS = MAXOBJ + rnd(4);
for (i = 0; i < ITEMS; i++)
if (rnd(100) < 65) {
/*
* 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 {
if (ltype == OUTSIDE) rm = 0;
else rm = rnd_room();
rnd_pos(&rooms[rm], &tp);
} until (winat(tp.y, tp.x) == FLOOR || cnt++ > 2500);
mvaddch(tp.y, tp.x, cur->o_type);
cur->o_pos = tp;
}
}

35
xrogue/network.h Normal file
View file

@ -0,0 +1,35 @@
/*
network.h - networking setup
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
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.
*/
/* #undef NETCOMMAND "uux - -n '%s!%s -u' >/dev/null 2>&1" */
/* #define NETCOMMAND "usend -s -d%s -uNoLogin -!'%s -u' - 2>/dev/null" */
#define NETCOMMAND ""
/* Networking information -- should not vary among networking machines */
struct network {
char *system;
char *rogue;
};
extern struct network Network[];
extern unsigned long netread();
extern unsigned long netwrite();

501
xrogue/options.c Normal file
View file

@ -0,0 +1,501 @@
/*
options.c - This file has all the code for the option command
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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.
*/
/*
* 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(),
get_default();
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 type: ",
(int *) &char_type, put_abil, get_abil },
{"quest", "Quest item: ",
(int *) &quest_item, put_quest, get_quest },
{"default", "Default Attributes: ",
(int *) &def_attr, put_bool, get_default }
};
/*
* The default attribute field is read-only
*/
get_default(bp, win)
bool *bp;
WINDOW *win;
{
register int oy, ox;
getyx(win, oy, ox);
put_bool(bp, win);
get_ro(win, oy, ox);
}
/*
* The ability (class) 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 == 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 == 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 += 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]; 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]; op++)
{
waddstr(hw, op->o_prompt);
retval = (*op->o_getfunc)(op->o_opt, hw);
if (retval)
if (retval == QUIT)
break;
else if (op > optlist) { /* MINUS */
wmove(hw, (op - optlist) - 1, 0);
op -= 2;
}
else /* trying to back up beyond the top */
{
putchar('\007');
wmove(hw, 0, 0);
op--;
}
}
/*
* Switch back to original screen
*/
mvwaddstr(hw, lines-1, 0, spacemsg);
draw(hw);
wait_for(' ');
restscr(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;
if (*str == '\"')
str++;
while (*str)
{
/*
* Get option name
*/
for (sp = str; isalpha(*sp); sp++)
continue;
len = (char *)sp - str;
/*
* Look it up and deal with it
*/
for (op = optlist; op < &optlist[NUM_OPTS]; op++)
if (EQSTR(str, op->o_name, len))
{
if (op->o_putfunc == put_bool) /* if option is a boolean */
*(bool *)op->o_opt = TRUE;
else /* string option */
{
register char *start;
char value[LINELEN];
/*
* Skip to start of string value
*/
for (str = sp + 1; *str == '=' || *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 != '\"'; sp++)
continue;
strucpy(start, str, (char *) sp - str);
/* Put the value into the option field */
if (op->o_putfunc != put_abil)
strcpy((char *)op->o_opt, value);
else if (*op->o_opt == -1) { /* Only init ability once */
register int len = strlen(value);
register int i;
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 default attributes
*/
/* put_default(b, win)
* bool *b;
* WINDOW *win;
* {
* waddstr(win, *b ? "True" : "False");
* }
*/
/*
* 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);
}

226
xrogue/outside.c Normal file
View file

@ -0,0 +1,226 @@
/*
outside.c - functions for dealing with the "outside" level
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
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 int cury, curx; /* Current y and x positions */
/* Lay out the boundary */
for (cury=1; cury<lines-2; cury++) { /* Vertical "walls" */
mvaddch(cury, 0, VERTWALL);
mvaddch(cury, cols-1, VERTWALL);
}
for (curx=0; curx<cols; curx++) { /* Horizontal "walls" */
mvaddch(1, curx, HORZWALL);
mvaddch(lines-3, curx, HORZWALL);
}
/* 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 = 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 = mvinch(cury, left_pos);
top_left = mvinch(top_pos, left_pos);
top = mvinch(top_pos, curx);
top_right = 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;
}
/* The deeper we go.. */
if (level > 40) genmonsters(20, (bool) 0);
else if (level > 10) genmonsters(15, (bool) 0);
else genmonsters(10, (bool) 0);
/* sometimes they're real angry */
if (rnd(100) < 65) {
/* protect good guys */
if (player.t_ctype == C_PALADIN ||
player.t_ctype == C_RANGER || player.t_ctype == C_MONK) {
aggravate(TRUE, FALSE);
}
else {
aggravate(TRUE, TRUE);
}
}
}
/*
* 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);
/* Meadow is most likely */
if (chance < 40) return(FLOOR);
/* Next comes forest */
if (chance < 65) return(FOREST);
/* Then comes lakes */
if (chance < 85) 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
*/
/*UNUSED*/
/* void
* lake_check(place)
* register coord *place;
* {
* }
*/

1582
xrogue/pack.c Normal file

File diff suppressed because it is too large Load diff

370
xrogue/passages.c Normal file
View file

@ -0,0 +1,370 @@
/*
passages.c - Draw the connecting passages
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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"
/*
* do_passages:
* Draw all the passages on a level.
*/
do_passages()
{
register struct rdes *r1, *r2 = NULL;
register int i, j;
register int roomcount;
static struct rdes
{
bool conn[MAXROOMS]; /* possible to connect to room i? */
bool isconn[MAXROOMS]; /* connection been made to room i? */
bool ingraph; /* this room in graph already? */
} rdes[MAXROOMS] = {
{ { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
};
/*
* reinitialize room graph description
*/
for (i = 0; i < MAXROOMS; i++)
{
r1 = &rdes[i];
for (j = 0; j < MAXROOMS; j++)
r1->isconn[j] = FALSE;
r1->ingraph = FALSE;
}
/*
* starting with one room, connect it to a random adjacent room and
* then pick a new room to start with.
*/
roomcount = 1;
r1 = &rdes[rnd(MAXROOMS)];
r1->ingraph = TRUE;
do
{
/*
* find a room to connect with
*/
j = 0;
for (i = 0; i < MAXROOMS; i++)
if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0)
r2 = &rdes[i];
/*
* if no adjacent rooms are outside the graph, pick a new room
* to look from
*/
if (j == 0)
{
do
r1 = &rdes[rnd(MAXROOMS)];
until (r1->ingraph);
}
/*
* otherwise, connect new room to the graph, and draw a tunnel
* to it
*/
else
{
r2->ingraph = TRUE;
i = r1 - rdes;
j = r2 - rdes;
conn(i, j);
r1->isconn[j] = TRUE;
r2->isconn[i] = TRUE;
roomcount++;
}
} while (roomcount < MAXROOMS);
/*
* attempt to add passages to the graph a random number of times so
* that there isn't just one unique passage through it.
*/
for (roomcount = rnd(5); roomcount > 0; roomcount--)
{
r1 = &rdes[rnd(MAXROOMS)]; /* a random room to look from */
/*
* find an adjacent room not already connected
*/
j = 0;
for (i = 0; i < MAXROOMS; i++)
if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0)
r2 = &rdes[i];
/*
* if there is one, connect it and look for the next added
* passage
*/
if (j != 0)
{
i = r1 - rdes;
j = r2 - rdes;
conn(i, j);
r1->isconn[j] = TRUE;
r2->isconn[i] = TRUE;
}
}
}
/*
* conn:
* Draw a corridor from a room in a certain direction.
*/
conn(r1, r2)
int r1, r2;
{
register struct room *rpf, *rpt = NULL;
register char rmt;
register int distance = 0, max_diag, offset = 0, i;
register int rm;
int turns[3], turn_dist[3];
register char direc;
coord delta = {0, 0}, curr, turn_delta = {0,0}, spos = {0,0}, epos = {0,0};
if (r1 < r2)
{
rm = r1;
if (r1 + 1 == r2)
direc = 'r';
else
direc = 'd';
}
else
{
rm = r2;
if (r2 + 1 == r1)
direc = 'r';
else
direc = 'd';
}
rpf = &rooms[rm];
/*
* Set up the movement variables, in two cases:
* first drawing one down.
*/
if (direc == 'd')
{
rmt = rm + 3; /* room # of dest */
rpt = &rooms[rmt]; /* room pointer of dest */
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);
if (rnd(10) < (level - 1) && rnd(100) < 20)
addch(SECRETDOOR);
else
addch(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);
}

1478
xrogue/player.c Normal file

File diff suppressed because it is too large Load diff

1058
xrogue/potions.c Normal file

File diff suppressed because it is too large Load diff

173
xrogue/rings.c Normal file
View file

@ -0,0 +1,173 @@
/*
rings.c - Routines dealing specificaly with rings
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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:
case R_SUSABILITY:
return 2;
case R_HEALTH:
return 1;
case R_SEARCH:
case R_SEEINVIS:
return (rnd(100) < 50); /* 0 or 1 */
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:
if (on(player, CANSEE)) msg("Your eyes sparkle.");
else msg("Your eyes begin to tingle.");
turn_on(player, CANSEE);
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
when R_AGGR:
aggravate(TRUE, TRUE); /* all charactors are affected*/
when R_WARMTH:
if (on(player, NOCOLD)) msg("You feel warm all over.");
else msg("You begin to feel warm.");
turn_on(player, NOCOLD);
when R_FIRE:
if (on(player, NOFIRE)) msg("You feel quite fire proof now.");
else msg("You begin to feel fire proof.");
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, (VOID *)NULL, AFTER);
when R_TELEPORT:
daemon(ring_teleport, (VOID *)NULL, 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);
}

763
xrogue/rip.c Normal file
View file

@ -0,0 +1,763 @@
/*
rip.c - File for the fun ends Death or a total win
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 REALLIFE 1 /* Print out machine and logname */
#define EDITSCORE 2 /* Edit the current score file */
#define ADDSCORE 3 /* Add a new score */
#include <curses.h>
#include <time.h>
#include <signal.h>
#include <ctype.h>
#include <sys/types.h>
#include <fcntl.h>
#include "mach_dep.h"
#include "network.h"
#include "rogue.h"
/* Network machines (for mutual score keeping) */
struct network Network[] = {
{ "", "" },
};
static char *rip[] = {
" ___________",
" / \\",
" / \\",
" / R. I. P. \\",
" / \\",
" / \\",
" | |",
" | |",
" | killed by |",
" | |",
" | |",
" | |",
" *| * * * |*",
" _________)|//\\\\///\\///\\//\\//\\/|(_________",
NULL
};
char *killname();
/*UNUSED*/
void
byebye(sig)
int sig;
{
NOOP(sig);
exit_game(EXIT_ENDWIN);
}
/*
* 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, 25, (sprintf(prbuf, "%4d", 1900+lt->tm_year), prbuf));
move(lines-1, 0);
refresh();
score(pstats.s_exp, KILLED, monst);
exit_game(EXIT_ENDWIN);
}
char *
killname(monst)
register short monst;
{
static char mons_name[LINELEN/2];
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;
int flags;
short monst;
{
struct sc_ent top_ten[NUMSCORE];
register struct sc_ent *scp;
register int i;
register struct sc_ent *sc2;
register FILE *outf;
register char *killer;
register int prflags = 0;
short upquest=0, wintype=0, uplevel=0, uptype=0; /* For network updating */
char upsystem[SYSLEN], uplogin[LOGLEN];
char *thissys; /* Holds the name of this system */
#define REASONLEN 3
static char *reason[] = {
"killed",
"quit",
"A total winner",
"somehow left",
};
char *packend;
memset(top_ten,0,sizeof(top_ten));
signal(SIGINT, byebye);
if (level == 0 && max_level == 0)
amount = 0; /*don't count if quit early */
if (flags != WINNER && flags != SCOREIT && flags != UPDATE) {
if (flags == CHICKEN) {
packend = "when you quit";
amount = amount / 100;
}
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 ((outf = fopen(score_file, "rb+")) == NULL)
{
if ((outf = fopen(score_file, "wb+")) == NULL)
{
mvprintw(lines - 1, 0, "Unable to open or create score file: %s",score_file);
refresh();
return;
}
}
thissys = md_gethostname();
/*
* If this is a SCOREIT optin (rogue -s), don't call byebye. The
* endwin() calls in byebye() will and this results 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;
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 */
}
}
/* Read the score and convert it to a compatible format */
fseek(outf, 0, SEEK_SET);
rs_read_scorefile(outf, top_ten, NUMSCORE);
/* Get some values if this is an update */
if (flags == UPDATE) {
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) {
fclose(outf);
return;
}
}
/*
* Insert player in list if need be
*/
if (!waswizard) {
char *login= NULL;
if (flags != UPDATE) {
login = md_getusername();
if ((login == NULL) || (*login == 0))
login = "another rogue fiend";
}
if (flags == UPDATE)
(void) update(top_ten, amount, upquest, whoami, wintype,
uplevel, monst, uptype, upsystem, uplogin);
else {
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, "choose");
} while (monst < 0); /* Force a choice */
else monst = getdeath();
}
}
if (update(top_ten, amount, (short) quest_item, whoami, flags,
(flags == WINNER) ? (short) max_level : (short) level,
monst, player.t_ctype, thissys, login)
) {
/* 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; Network[i].system[0] != 0; 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);
}
}
}
}
}
/*
* 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]; scp++) {
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, "choose");
} while (scp->sc_monster < 0); /* Force a choice */
else scp->sc_monster = getdeath();
clear();
refresh();
}
}
else printf("\n");
}
}
/* if (prflags == EDITSCORE) endwin();*/ /* End editing windowing */
}
fseek(outf, 0L, SEEK_SET);
if (flags != SCOREIT)
rs_write_scorefile(outf,top_ten,NUMSCORE);
fclose(outf);
}
/*
* 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,"--- %ld Gold Pieces ---",purse);
refresh();
}
total_winner()
{
register struct linked_list *item;
register struct object *obj;
register long worth;
register char c;
register long 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 ");
switch (player.t_ctype) {
case C_FIGHTER: addstr("Leader of the Fighter's Guild.\n");
when C_RANGER: addstr("King of the Northern Land.\n");
when C_PALADIN: addstr("King of the Southern Land.\n");
when C_MAGICIAN:addstr("High Wizard of the Sorcerer's Guild.\n");
when C_CLERIC: addstr("Bishop of the Monastery.\n");
when C_THIEF: addstr("Leader of the Thief's Guild.\n");
when C_MONK: addstr("Master of the Temple.\n");
when C_ASSASSIN: addstr("Leader of the Assassin's Guild.\n");
when C_DRUID: addstr("High Priest of the Monastery.\n");
otherwise: addstr("Town Drunk in the 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) %6ld %s", c, worth, inv_name(obj, FALSE));
purse += worth;
}
mvprintw(c - 'a' + 1, 0," %5ld Gold Pieces ", oldpurse);
refresh();
score(pstats.s_exp + (long) purse, WINNER, '\0');
exit_game(EXIT_ENDWIN);
}
void
delete_score(top_ten, idx)
struct sc_ent top_ten[NUMSCORE];
int idx;
{
for(;idx < NUMSCORE-1;idx++)
top_ten[idx] = top_ten[idx+1];
top_ten[NUMSCORE-1].sc_score = 0L;
}
int
insert_score(top_ten, sc)
struct sc_ent top_ten[NUMSCORE];
struct sc_ent *sc;
{
int i,j;
if (top_ten[NUMSCORE-1].sc_score > 0)
return(-1); /* no room */
for(i = 0; i < NUMSCORE; i++) {
if (sc->sc_score > top_ten[i].sc_score) {
for(j = NUMSCORE-1; j > i; j--)
top_ten[j] = top_ten[j-1];
top_ten[i] = *sc;
return(i);
}
}
return(-1);
}
/* PCS = player-class-system (used to determines uniqueness of player) */
int
is_pcs_match(sc1,sc2)
struct sc_ent *sc1;
struct sc_ent *sc2;
{
return( (strcmp(sc1->sc_name,sc2->sc_name) == 0) &&
(sc1->sc_ctype == sc2->sc_ctype) &&
(strcmp(sc1->sc_system, sc2->sc_system)==0) );
}
int
count_pcs_matches(top_ten,sc,lowest)
struct sc_ent top_ten[NUMSCORE];
struct sc_ent *sc;
int *lowest;
{
int i, matches = 0;
*lowest = -1;
for(i = 0; i < NUMSCORE; i++) {
if (is_pcs_match(sc,&top_ten[i])) {
matches++;
*lowest = i;
}
}
return(matches);
}
int
find_most_pcs_matches(top_ten,sc,num,idx)
struct sc_ent top_ten[NUMSCORE];
struct sc_ent *sc;
int *num, *idx;
{
int i, matches, max_match=0, max_match_idx=-1, lowest;
for(i = NUMSCORE-1; i > 0; i--) {
matches = count_pcs_matches(top_ten,&top_ten[i],&lowest);
if (matches > max_match) {
max_match = matches;
max_match_idx = lowest;
}
}
matches = count_pcs_matches(top_ten,sc,&lowest) + 1;
if (matches > max_match) {
*num = matches;
*idx = lowest;
}
else {
*num = max_match;
*idx = max_match_idx;
}
return(0);
}
int
add_score(top_ten,sc)
struct sc_ent top_ten[NUMSCORE];
struct sc_ent *sc;
{
int idx, count;
if (insert_score(top_ten,sc) == -1) {
/* Simple insert if space available in table */
find_most_pcs_matches(top_ten,sc,&count,&idx);
/* EVERY ENTRY UNIQUE, */
/* INSERT IF SCORE > LOWEST MATCH SCORE */
if (count == 1) {
if (sc->sc_score > top_ten[idx].sc_score) {
delete_score(top_ten,idx);
insert_score(top_ten,sc);
}
}
/* CURRENT PCS HAS HIGHEST DUPE COUNT */
/* INSERT IF SCORE > LOWEST MATCH SCORE */
else if (is_pcs_match(sc,&top_ten[idx])) {
if (sc->sc_score > top_ten[idx].sc_score) {
delete_score(top_ten,idx);
insert_score(top_ten,sc);
}
}
/* UNRELATED PCS HAS HIGHEST DUPE COUNT */
/* DELETE LOWEST DUPE TO MAKE ROOM AND INSERT */
else {
delete_score(top_ten,idx);
insert_score(top_ten,sc);
}
}
}
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;
{
struct sc_ent sc;
sc.sc_score = amount;
sc.sc_quest = quest;
strncpy(sc.sc_name, whoami, NAMELEN);
sc.sc_name[NAMELEN-1] = 0;
sc.sc_flags = flags;
sc.sc_level = level;
sc.sc_monster = monst;
sc.sc_ctype = ctype;
strncpy(sc.sc_system, system, SYSLEN);
sc.sc_system[SYSLEN - 1] = 0;
strncpy(sc.sc_login, login, LOGLEN);
sc.sc_login[LOGLEN-1] = 0;
add_score(top_ten, &sc);
return(1);
}

658
xrogue/rogue.c Normal file
View file

@ -0,0 +1,658 @@
/*
rogue.c - Global game variables
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <curses.h>
#include "rogue.h"
/*
* Now all the global variables
*/
struct trap traps[MAXTRAPS];
struct room rooms[MAXROOMS]; /* One for each room -- A level */
struct room *oldrp; /* Roomin(&player.t_oldpos) */
struct thing player; /* The rogue */
struct object *cur_armor; /* What a well dresssed rogue wears */
struct object *cur_ring[NUM_FINGERS]; /* Which rings are being worn */
struct object *cur_misc[NUM_MM]; /* which MM's are in use */
int cur_relic[MAXRELIC]; /* Currently used relics */
struct linked_list *lvl_obj = NULL;
struct linked_list *mlist = NULL;
struct linked_list *rlist = NULL; /* list of dead monsters to be reaped */
struct linked_list *tlist = NULL; /* list of monsters fallen down traps */
struct linked_list *monst_dead = NULL; /* monster killed by monster */
struct object *cur_weapon = NULL;
int char_type = -1; /* what type of character is player */
int foodlev = 1; /* how fast he eats food */
int ntraps; /* Number of traps on this level */
int trader = 0; /* no. of purchases */
int curprice = -1; /* current price of item */
int seed; /* Random number seed */
int max_level; /* Deepest player has gone ever */
int cur_max; /* Deepest player has gone currently */
int prev_max; /* A flag indicating worm hole */
int move_free = 0; /* Movement check (io.c & actions.c) */
int mpos = 0;
int level = 0;
long purse = 0;
int inpack = 0;
int total = 0;
int no_food = 0; /* how long has he gone with no food */
int foods_this_level = 0; /* foods made per level */
int count = 0;
int food_left = STOMACHSIZE-MORETIME-1;
int group = 1;
int hungry_state = F_OKAY;
int infest_dam=0;
int lost_str=0;
int lastscore = -1;
int hold_count = 0;
int trap_tries = 0;
int chant_time = 0;
int pray_time = 0;
int spell_power = 0;
long turns = 0; /* Number of turns player has taken */
int quest_item = 0; /* Item player is looking for */
int cols = 0; /* number of columns in terminal */
int lines = 0; /* number of lines on the terminal */
int nfloors = -1; /* Number of floors in this dungeon */
char curpurch[LINELEN]; /* name of item ready to buy */
char PLAYER = VPLAYER; /* what the player looks like */
char take; /* Thing the rogue is taking */
char prbuf[LINELEN*2]; /* Buffer for sprintfs */
char runch; /* Direction player is running */
char *s_names[MAXSCROLLS]; /* Names of the scrolls */
char *p_colors[MAXPOTIONS]; /* Colors of the potions */
char *r_stones[MAXRINGS]; /* Stone settings of the rings */
char *ws_made[MAXSTICKS]; /* What sticks are made of */
char whoami[LINELEN]; /* Name of player */
char huh[LINELEN]; /* The last message printed */
char *s_guess[MAXSCROLLS]; /* Players guess at what scroll is */
char *p_guess[MAXPOTIONS]; /* Players guess at what potion is */
char *r_guess[MAXRINGS]; /* Players guess at what ring is */
char *ws_guess[MAXSTICKS]; /* Players guess at what wand is */
char *m_guess[MAXMM]; /* Players guess at what MM is */
char *ws_type[MAXSTICKS]; /* Is it a wand or a staff */
char file_name[LINELEN]; /* Save file name */
char score_file[LINELEN]; /* Score file name */
char home[LINELEN]; /* User's home directory */
WINDOW *cw; /* Window that the player sees */
WINDOW *hw; /* Used for the help command */
WINDOW *mw; /* Used to store monsters */
WINDOW *msgw; /* Used to display messages */
bool pool_teleport = FALSE; /* just teleported from a pool */
bool inwhgt = FALSE; /* true if from wghtchk() */
bool after; /* True if we want after daemons */
bool waswizard; /* Was a wizard sometime */
bool s_know[MAXSCROLLS]; /* Does he know what a scroll does */
bool p_know[MAXPOTIONS]; /* Does he know what a potion does */
bool r_know[MAXRINGS]; /* Does he know what a ring does */
bool ws_know[MAXSTICKS]; /* Does he know what a stick does */
bool m_know[MAXMM]; /* Does he know what a MM does */
/* options */
bool playing = TRUE; /* Defaults */
bool running = FALSE;
bool wizard = FALSE;
bool notify = TRUE;
bool fight_flush = FALSE;
bool terse = FALSE;
bool auto_pickup = FALSE;
bool def_attr = FALSE; /* default attributes */
bool menu_overlay = TRUE;
bool door_stop = TRUE;
bool jump = TRUE;
bool slow_invent = FALSE;
bool firstmove = FALSE;
bool askme = TRUE;
bool in_shell = FALSE;
bool daytime = TRUE;
bool funfont = FALSE;
LEVTYPE levtype; /* what type of level am i'm on? */
char *nothing = "Nothing seems to happen. ";
char *spacemsg = "--Press space to continue--";
char *morestr = " --More--";
char *retstr = "[Press return to continue]";
/*
* This lays out all the class specific details
*
* Here are the beginning experience levels for all players.
* All further experience levels are computed by muliplying by 2
* up through MAXDOUBLE. Then exp pts are calculated by adding
* in the cap figure. You must change MAXDOUBLE if you change the
* cap figure.
*/
struct character_types char_class[NUM_CHARTYPES] = {
/* name exppts cap hitpts Base Maxlvl, Factor, Offset, Range */
{ "fighter", 90, 1310720, 13, 10, 30, 2, 1, 3 },
{ "ranger", 110, 2293760, 10, 10, 22, 2, 1, 2 },
{ "paladin", 110, 1966080, 10, 10, 23, 2, 1, 2 },
{ "magician", 105, 2129920, 9, 10, 24, 2, 1, 2 },
{ "cleric", 105, 1802240, 9, 10, 24, 2, 1, 2 },
{ "thief", 95, 1228800, 11, 10, 28, 2, 1, 3 },
{ "assassin", 95, 1392640, 11, 10, 26, 2, 1, 3 },
{ "druid", 105, 1638400, 9, 10, 24, 2, 1, 2 },
{ "monk", 100, 1556480, 10, 10, 25, 2, 1, 2 },
{ "monster", 0, 0, 8, 10, 20, 1, 0, 2 },
};
/*
* This array lists the names of the character's abilities. It must be ordered
* according to the ability definitions in rogue.h.
*/
struct words abilities[NUMABILITIES] = {
"Intelligence", "Strength", "Wisdom", "Dexterity", "Constitution", "Charisma"
};
/*
* NOTE: the ordering of the points in this array is critical. They MUST
* be listed in the following sequence:
*
* 7 4 6
* 1 0 2
* 5 3 8
*/
coord grid[9] = {{0,0},
{ 0,-1}, { 0, 1}, {-1, 0}, { 1, 0},
{-1,-1}, { 1, 1}, { 1,-1}, {-1, 1}
};
struct death_type deaths[DEATHNUM] = {
{ D_ARROW, "an arrow"},
{ D_DART, "a dart"},
{ D_BOLT, "a bolt"},
{ D_POISON, "poison"},
{ D_POTION, "a cursed potion"},
{ D_PETRIFY, "petrification"},
{ D_SUFFOCATION, "suffocation"},
{ D_INFESTATION, "a parasite"},
{ D_DROWN, "drowning"},
{ D_ROT, "body rot"},
{ D_CONSTITUTION, "poor health"},
{ D_STRENGTH, "being too weak"},
{ D_SIGNAL, "a bug"},
{ D_CHOKE, "dust of choking"},
{ D_STRANGLE, "strangulation"},
{ D_FALL, "a fall"},
{ D_RELIC, "an artifact's wrath"},
{ D_STARVATION, "starvation"},
{ D_FOOD_CHOKE, "choking on food"},
{ D_SCROLL, "reading a scroll"},
{ D_FRIGHT, "being too frightened"},
{ D_CRYSTAL, "being absorbed"},
{ D_CARD, "the face of death"},
};
/*
* weapons and their attributes
*/
struct init_weps weaps[MAXWEAPONS] = {
{ "mace", "2d10","2d10", NONE, ISMETAL, 6, 150, 15 },
{ "long sword", "3d4", "2d8", NONE, ISMETAL, 5, 200, 25 },
{ "short bow", "1d1", "1d1", NONE, 0, 8, 50, 4 },
{ "arrow", "2d4", "1d6", BOW, ISMANY|ISMISL, 1, 5, 4 },
{ "dagger", "2d8", "1d6", NONE, ISMETAL|ISMISL|ISMANY, 2,10,7},
{ "rock", "2d4", "1d6", SLING, ISMANY|ISMISL, 1, 20, 3 },
{ "two-handed sword","3d10","3d8", NONE, ISMETAL, 4, 250, 40 },
{ "sling", "1d1", "1d1", NONE, 0, 8, 25, 3 },
{ "dart", "2d4", "2d6", NONE, ISMANY|ISMISL, 2, 15, 7 },
{ "crossbow", "1d1", "1d1", NONE, 0, 8, 75, 5 },
{ "crossbow bolt", "2d4", "2d4", CROSSBOW, ISMANY|ISMISL, 1, 10, 5 },
{ "spear", "2d6", "3d10", NONE, ISMISL, 7, 100, 15 },
{ "trident", "3d6", "3d4", NONE, ISMETAL, 4, 200, 30 },
{ "spetum", "2d6", "2d8", NONE, ISMETAL, 6, 150, 20 },
{ "bardiche", "3d4", "2d10", NONE, ISMETAL, 5, 150, 25 },
{ "pike", "2d8", "2d8", NONE, ISMETAL, 7, 100, 15 },
{ "bastard sword", "3d8", "3d6", NONE, ISMETAL, 4, 175, 30 },
{ "halberd", "2d8", "2d4", NONE, ISMETAL, 6, 100, 10 },
{ "battle axe", "2d8", "3d8", NONE, ISMETAL, 5, 150, 15 },
} ;
struct init_armor armors[MAXARMORS] = {
{ "leather armor", 10, 8, 200, 100 },
{ "ring mail", 20, 7, 250, 200 },
{ "studded leather armor", 30, 5, 320, 250 },
{ "scale mail", 40, 7, 280, 250 },
{ "padded armor", 50, 6, 350, 300 },
{ "chain mail", 60, 6, 350, 600 },
{ "splint mail", 70, 5, 370, 400 },
{ "banded mail", 80, 5, 370, 350 },
{ "plate mail", 90, 4, 400, 400 },
{ "plate armor", 100, 3, 500, 450 },
};
struct magic_item things[NUMTHINGS] = {
{ "potion", 220, 10 }, /* potion */
{ "scroll", 220, 30 }, /* scroll */
{ "food", 190, 20 }, /* food */
{ "weapon", 90, 0 }, /* weapon */
{ "armor", 90, 0 }, /* armor */
{ "ring", 70, 5 }, /* ring */
{ "stick", 70, 0 }, /* stick */
{ "miscellaneous magic", 50, 50 }, /* miscellaneous magic */
{ "artifact", 0, 10 }, /* artifact */
};
struct magic_item s_magic[MAXSCROLLS] = {
{ "monster confusion", 40, 125, 0, 0 },
{ "magic mapping", 60, 150, 0, 5 },
{ "light", 60, 100, 15, 15 },
{ "hold monster", 30, 200, 20, 20 },
{ "sleep", 20, 150, 25, 0 },
{ "enchantment", 130, 200, 15, 15 },
{ "identify", 170, 100, 0, 20 },
{ "scare monster", 40, 250, 20, 30 },
{ "gold detection", 30, 110, 0, 0 },
{ "teleportation", 60, 165, 20, 20 },
{ "create monster", 20, 75, 0, 0 },
{ "remove curse", 80, 120, 15, 15 },
{ "petrification", 30, 185, 0, 0 },
{ "genocide", 10, 300, 0, 0 },
{ "cure disease", 80, 160, 0, 0 },
{ "acquirement", 10, 700, 0, 5 },
{ "protection", 30, 190, 10, 0 },
{ "trap finding", 50, 180, 0, 0 },
{ "runes", 20, 50, 0, 0 },
{ "charm monster", 30, 275, 0, 20 },
};
struct magic_item p_magic[MAXPOTIONS] = {
{ "clear thought", 50, 180, 10, 5 },
{ "gain ability", 160, 210, 10, 10 },
{ "see invisible", 40, 150, 20, 20 },
{ "healing", 140, 130, 15, 15 },
{ "monster detection", 40, 120, 0, 0 },
{ "magic detection", 70, 105, 0, 0 },
{ "raise level", 10, 450, 10, 5 },
{ "haste self", 50, 180, 20, 5 },
{ "restore abilities", 130, 140, 0, 15 },
{ "phasing", 60, 210, 10, 10 },
{ "invisibility", 20, 230, 0, 10 },
{ "flying", 50, 130, 0, 15 },
{ "food detection", 20, 150, 0, 0 },
{ "skill", 10, 200, 20, 5 },
{ "fire resistance", 40, 250, 10, 5 },
{ "cold resistance", 40, 250, 10, 5 },
{ "lightning protection", 40, 250, 20, 5 },
{ "poison", 30, 205, 25, 0 },
};
struct magic_item r_magic[MAXRINGS] = {
{ "protection", 60, 200, 25, 25 },
{ "add strength", 50, 200, 25, 25 },
{ "sustain ability", 50, 500, 0, 0 },
{ "searching", 40, 400, 0, 0 },
{ "extra sight", 60, 350, 0, 0 },
{ "alertness", 40, 380, 0, 0 },
{ "aggravate monster", 30, 100, 100, 0 },
{ "dexterity", 50, 220, 25, 25 },
{ "increase damage", 60, 220, 25, 25 },
{ "regeneration", 40, 600, 0, 0 },
{ "slow digestion", 50, 240, 20, 20 },
{ "teleportation", 20, 100, 90, 0 },
{ "stealth", 20, 300, 0, 0 },
{ "add intelligence", 50, 240, 25, 25 },
{ "increase wisdom", 40, 220, 25, 25 },
{ "sustain health", 80, 500, 0, 0 },
{ "carrying", 10, 100, 90, 0 },
{ "illumination", 30, 520, 0, 0 },
{ "delusion", 10, 100, 100, 0 },
{ "fear", 20, 100, 75, 0 },
{ "heroism", 50, 390, 0, 0 },
{ "fire resistance", 40, 400, 0, 0 },
{ "warmth", 40, 400, 0, 0 },
{ "vampiric regeneration", 10,1000, 0, 0 },
{ "free action", 40, 370, 0, 0 },
{ "teleport control", 10, 700, 0, 0 },
};
struct magic_item ws_magic[MAXSTICKS] = {
{ "light", 80, 120, 15, 15 },
{ "striking", 50, 115, 0, 0 },
{ "lightning", 40, 200, 0, 0 },
{ "fire", 30, 200, 0, 0 },
{ "cold", 30, 200, 0, 0 },
{ "polymorph", 80, 150, 0, 0 },
{ "magic missile", 90, 170, 0, 0 },
{ "slow", 70, 220, 20, 10 },
{ "drain life", 50, 210, 20, 0 },
{ "charging", 70, 400, 0, 0 },
{ "teleport", 90, 140, 20, 10 },
{ "cancellation", 50, 130, 0, 0 },
{ "confusion", 30, 100, 20, 0 },
{ "disintegration", 20, 300, 25, 0 },
{ "petrification", 30, 240, 0, 0 },
{ "paralyzation", 30, 180, 10, 0 },
{ "degeneration", 30, 250, 20, 0 },
{ "curing", 50, 250, 20, 5 },
{ "wonder", 40, 110, 20, 20 },
{ "fear", 40, 180, 0, 0 },
};
/*
* WARNING: unique miscellaneous magic items must be put at the end
* of this list. They MUST be the last items. The function
* create_obj() in wizard.c depends on it.
*/
struct magic_item m_magic[MAXMM] = {
{ "alchemy jug", 40, 240, 0, 0 },
{ "beaker of potions", 60, 300, 0, 0 },
{ "book of spells", 60, 300, 0, 0 },
{ "boots of elvenkind", 50, 500, 0, 0 },
{ "bracers of defense", 80, 400, 20, 10 },
{ "chime of opening", 30, 250, 0, 0 },
{ "chime of hunger", 20, 100, 100, 0 },
{ "cloak of displacement", 60, 500, 0, 0 },
{ "cloak of protection", 80, 400, 20, 10 },
{ "drums of panic", 60, 350, 0, 0 },
{ "dust of disappearance", 30, 300, 0, 0 },
{ "dust of choking", 30, 100, 100, 0 },
{ "gauntlets of dexterity", 40, 600, 25, 0 },
{ "gauntlets of ogre power", 40, 600, 25, 0 },
{ "jewel of attacks", 50, 150, 100, 0 },
{ "keoghtoms ointment", 60, 350, 0, 0 },
{ "robe of powerlessness", 20, 100, 100, 0 },
{ "gauntlets of fumbling", 30, 100, 100, 0 },
{ "necklace of adaptation", 50, 500, 0, 0 },
{ "necklace of strangulation", 30, 110, 100, 0 },
{ "boots of dancing", 40, 120, 100, 0 },
{ "book of skills", 30, 650, 0, 0 },
{ "medicine crystal", 10, 800, 25, 5 },
};
struct magic_item rel_magic[MAXRELIC] = {
{ "Daggers of Musty Doit", 0, 50000, 0, 0},
{ "Cloak of Emori", 0, 50000, 0, 0},
{ "Ankh of Heil", 0, 50000, 0, 0},
{ "Staff of Ming", 0, 50000, 0, 0},
{ "Wand of Orcus", 0, 50000, 0, 0},
{ "Rod of Asmodeus", 0, 50000, 0, 0},
{ "Amulet of Yendor", 0, 50000, 0, 0},
{ "Mandolin of Brian", 0, 50000, 0, 0},
{ "Horn of Geryon", 0, 50000, 0, 0},
{ "Morning Star of Hruggek", 0, 50000, 0, 0},
{ "Flail of Yeenoghu", 0, 50000, 0, 0},
{ "Eye of Vecna", 0, 50000, 0, 0},
{ "Axe of Aklad", 0, 50000, 0, 0},
{ "Quill of Nagrom", 0, 50000, 0, 0},
{ "Amulet of Stonebones", 0, 50000, 0, 0},
{ "Ring of Surtur", 0, 50000, 0, 0},
{ "Card of Alteran", 0, 50000, 0, 0},
};
/*
* food and fruits that you get
*/
struct magic_item foods[MAXFOODS] = {
{ "food ration", 690, 50, 750, 0},
{ "apple", 10, 20, 300, 0},
{ "banana", 30, 20, 300, 0},
{ "blueberry", 30, 20, 300, 0},
{ "candleberry", 10, 20, 300, 0},
{ "caprifig", 20, 20, 300, 0},
{ "dewberry", 10, 20, 300, 0},
{ "elderberry", 30, 20, 300, 0},
{ "gooseberry", 20, 20, 300, 0},
{ "guanabana", 30, 20, 300, 0},
{ "hagberry", 10, 20, 300, 0},
{ "jaboticaba", 10, 20, 300, 0},
{ "peach", 10, 20, 300, 0},
{ "pitanga", 10, 20, 300, 0},
{ "prickly pear", 10, 20, 300, 0},
{ "rambutan", 10, 20, 300, 0},
{ "sapodilla", 10, 20, 300, 0},
{ "soursop", 10, 20, 300, 0},
{ "strawberry", 10, 20, 300, 0},
{ "sweetsop", 10, 20, 300, 0},
{ "whortleberry", 10, 20, 300, 0},
{ "slime-mold", 10, 10, 100, 0},
};
/*
* these are the spells that a magician can cast
*/
struct spells magic_spells[MAXSPELLS] = {
{ P_TFIND, 3, TYP_POTION, 0 },
{ S_IDENT, 5, TYP_SCROLL, 0 },
{ S_LIGHT, 7, TYP_SCROLL, ISBLESSED },
{ S_REMOVE, 10, TYP_SCROLL, 0 },
{ S_FINDTRAPS, 15, TYP_SCROLL, 0 },
{ P_FLY, 20, TYP_POTION, 0 },
{ S_TELEP, 25, TYP_SCROLL, 0 },
{ S_SLEEP, 30, TYP_SCROLL, 0 },
{ P_SEEINVIS, 35, TYP_POTION, ISBLESSED },
{ P_CLEAR, 40, TYP_POTION, 0 },
{ WS_COLD, 45, TYP_STICK, 0 },
{ P_PHASE, 50, TYP_POTION, 0 },
{ WS_FIRE, 55, TYP_STICK, 0 },
{ P_HASTE, 60, TYP_POTION, ISBLESSED },
{ WS_ELECT, 65, TYP_STICK, 0 },
{ S_HOLD, 70, TYP_SCROLL, ISBLESSED },
};
/*
* these are the spells that a cleric can cast
*/
struct spells cleric_spells[MAXPRAYERS] = {
{ P_MFIND, 3, TYP_POTION, 0 },
{ P_TFIND, 5, TYP_POTION, 0 },
{ S_LIGHT, 7, TYP_SCROLL, ISBLESSED },
{ S_REMOVE, 10, TYP_SCROLL, 0 },
{ P_FFIND, 15, TYP_POTION, 0 },
{ P_FLY, 20, TYP_POTION, 0 },
{ P_HEALING, 25, TYP_POTION, 0 },
{ S_CURING, 30, TYP_SCROLL, 0 },
{ P_RESTORE, 35, TYP_POTION, 0 },
{ S_MAP, 40, TYP_SCROLL, 0 },
{ P_SEEINVIS, 45, TYP_POTION, ISBLESSED },
{ P_CLEAR, 50, TYP_POTION, 0 },
{ P_PHASE, 55, TYP_POTION, 0 },
{ WS_CURING, 60, TYP_STICK, ISBLESSED },
{ WS_PARALYZE, 65, TYP_STICK, 0 },
{ S_ALLENCH, 70, TYP_SCROLL, 0 },
};
/*
* these are the spells that a druid can chant
*/
struct spells druid_spells[MAXCHANTS] = {
{ P_MFIND, 3, TYP_POTION, 0 },
{ P_TFIND, 5, TYP_POTION, 0 },
{ S_LIGHT, 7, TYP_SCROLL, ISBLESSED },
{ S_REMOVE, 10, TYP_SCROLL, 0 },
{ S_FINDTRAPS, 15, TYP_SCROLL, 0 },
{ S_CONFUSE, 20, TYP_SCROLL, 0 },
{ P_FFIND, 25, TYP_POTION, 0 },
{ P_HEALING, 30, TYP_POTION, 0 },
{ S_MAP, 35, TYP_SCROLL, 0 },
{ P_CLEAR, 40, TYP_POTION, 0 },
{ P_COLD, 45, TYP_POTION, 0 },
{ P_FIRE, 50, TYP_POTION, 0 },
{ P_PHASE, 55, TYP_POTION, 0 },
{ P_LIGHTNING, 60, TYP_POTION, 0 },
{ S_CHARM, 65, TYP_SCROLL, ISBLESSED },
{ S_HOLD, 70, TYP_SCROLL, ISBLESSED },
};
/*
* these are the scrolls that a quill can write
*/
struct spells quill_scrolls[MAXQUILL] = {
{ S_GFIND, 5, },
{ S_IDENT, 10, },
{ S_LIGHT, 10, },
{ S_REMOVE, 15, },
{ S_MAP, 20, },
{ S_CONFUSE, 25, },
{ S_SLEEP, 30, },
{ S_CURING, 40, },
{ S_TELEP, 50, },
{ S_SCARE, 60, },
{ S_HOLD, 70, },
{ S_PETRIFY, 80, },
{ S_PROTECT, 90, },
{ S_ALLENCH, 100, },
};
/*
* Experience-level names of each character (see NUM_CNAMES in rogue.h)
*/
const char *cnames[NUM_CHARTYPES-1][NUM_CNAMES] = {
{ "Veteran", "Fighter", /* Fighter */
"Ruffian", "Tussler",
"Swordsman", "Hero",
"Bravo", "Picador",
"Stalwart", "Bashar",
"Swashbuckler", "Myrmidon",
"Fusileer", "Pugilist",
"Champion", "Superhero",
"Warrior", "Lord",
"Lord I", "Lord II",
"Lord III", "Lord IV",
"Lord V", "Lord VI",
"Lord VII", "Warrior Lord"
},
{ "Runner", "Strider", /* Ranger */
"Warden", "Steward",
"Scout", "Courser",
"Tracker", "Guide",
"Protector", "Bartizan",
"Gendarme", "Sentinel",
"Vigilant", "Pathfinder",
"Guardian", "Overseer",
"Castellan", "Ranger",
"Lord Ranger I", "Lord Ranger II",
"Lord Ranger III", "Lord Ranger IV",
"Lord Ranger V", "Lord Ranger VI",
"Lord Ranger VII", "Master Ranger"
},
{ "Gallant", "Keeper", /* Paladin */
"Bravado", "Brazen",
"Protector", "Defender",
"Warder", "Guardian",
"Champion", "Bulwark",
"Venturist", "Inspirator",
"Chevalier", "Justiciar",
"Undaunteer", "Plautus",
"Knight", "Paladin",
"Paladin I", "Paladin II",
"Paladin III", "Paladin IV",
"Paladin V", "Paladin VI",
"Paladin VII", "Lord Paladin"
},
{ "Prestidigitator", "Evoker", /* Magic User */
"Summoner", "Invoker",
"Conjurer", "Theurgist",
"Illusionist", "Diviner",
"Thaumaturgist", "Magician",
"Thelemist", "Magus",
"Enchanter", "Warlock",
"Witch", "Shaman",
"Sorcerer", "Wizard",
"Wizard I", "Wizard II",
"Wizard III", "Wizard IV",
"Wizard V", "Wizard VI",
"Wizard VII", "Lord Magus"
},
{ "Acolyte", "Adept", /* Cleric */
"Charmer", "Friar",
"Priest", "Curate",
"Vicar", "Deacon",
"Sabiast", "Cabalist",
"Prefect", "Canon",
"Minister", "Cardinal",
"Bishop", "Patriarch",
"Exorcist", "Archdeacon",
"High Priest I", "High Priest II",
"High Priest III", "High Priest IV",
"High Priest V", "High Priest VI",
"High Priest VII", "Reverend Lord"
},
{ "Rogue", "Footpad", /* Thief */
"Cutpurse", "Robber",
"Vagrant", "Truant",
"Burglar", "Filcher",
"Sharper", "Magsman",
"Racketeer", "Prowler",
"Crook", "Bounder",
"Quisling", "Malfeasor",
"Swindler", "Thief",
"Master Thief I", "Master Thief II",
"Master Thief III", "Master Thief IV",
"Master Thief V", "Master Thief VI",
"Master Thief VII", "Master Rogue"
},
{ "Bravo", "Rutterkin", /* Assassin */
"Waghalter", "Murderer",
"Butcher", "Desperado",
"Thug", "Killer",
"Cutthroat", "Executioner",
"Eradicator", "Obliterator",
"Mechanic", "Wiseguy",
"Nihilist", "Berserker",
"Assassin", "Expert Assassin",
"Prime Assassin I", "Prime Assassin II",
"Prime Assassin III", "Prime Assassin IV",
"Prime Assassin V", "Prime Assassin VI",
"Prime Assassin VII", "Master Assassin"
},
{ "Aspirant", "Ovate", /* Druid */
"Practitioner", "Devoutist",
"Initiate 1st Circle", "Initiate 2nd Circle",
"Initiate 3rd Circle", "Initiate 4th Circle",
"Initiate 5th Circle", "Initiate 6th Circle",
"Initiate 7th Circle", "Initiate 8th Circle",
"Initiate 9th Circle", "Illuminati",
"Lesser Druid", "Arch Druid",
"Druid", "Master Druid",
"Master Druid I", "Master Druid II",
"Master Druid III", "Master Druid IV",
"Master Druid V", "Master Druid VI",
"Master Druid VII", "Lord Druid"
},
{ "Novice", "Initiate", /* Monk */
"Brother", "Disciple",
"Canon", "Elder",
"Precept", "Lama",
"Immaculate", "Wizard",
"Shaman", "Master",
"Superior Master", "Master of Dragons",
"Master of North Wind", "Master of West Wind",
"Master of South Wind", "Master of East Wind",
"Grand Master I", "Grand Master II",
"Grand Master III", "Grand Master IV",
"Grand Master V", "Grand Master VI",
"Grand Master VII", "Lord Monk"
}
};

1405
xrogue/rogue.h Normal file

File diff suppressed because it is too large Load diff

295
xrogue/rooms.c Normal file
View file

@ -0,0 +1,295 @@
/*
rooms.c - Draw the nine rooms on the screen
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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"
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;
_r_free_fire_list(&rp->r_fires);
}
/*
* 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.y = -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) < 55 && 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(7,2);
}
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(HORZWALL);
}
/*
* 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(VERTWALL);
}
}

304
xrogue/save.c Normal file
View file

@ -0,0 +1,304 @@
/*
save.c - save and restore routines
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <ctype.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include "rogue.h"
#include "mach_dep.h"
extern char version[];
extern unsigned char encstr[];
extern int big_endian;
bool
save_game()
{
register FILE *savef;
register int c;
char buf[LINELEN];
/*
* get file name
*/
mpos = 0;
if (file_name[0] != '\0')
{
msg("Save file (%s)? ", file_name);
do
{
c = wgetch(cw);
if (c == ESC) 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;
}
}
else
goto gotfile; /* must save to file restored from */
do
{
msg("File name: ");
mpos = 0;
buf[0] = '\0';
if (get_str(buf, msgw) == QUIT)
{
msg("");
return FALSE;
}
strcpy(file_name, buf);
gotfile:
if ((savef = fopen(file_name, "wb")) == NULL)
msg(strerror(errno));
} while (savef == NULL);
msg("");
/*
* write out encrpyted file
*/
if (save_file(savef) == FALSE) {
fclose(savef);
msg("Cannot create save file.");
unlink(file_name);
return(FALSE);
}
fclose(savef);
return(TRUE);
}
/*
* automatically save a file. This is used if a HUP signal is recieved
*/
void
auto_save(int sig)
{
register FILE *savef = NULL;
register int i;
NOOP(sig);
for (i = 0; i < NSIG; i++)
signal(i, SIG_IGN);
if (file_name[0] != '\0' &&
pstats.s_hpt > 0 &&
((savef = fopen(file_name, "wb")) != NULL))
save_file(savef);
fclose(savef);
exit_game(EXIT_ENDWIN);
}
/*
* write the saved game on the file
*/
bool
save_file(savef)
register FILE *savef;
{
int slines = LINES;
int scols = COLS;
int ret = FALSE;
int endian = 0x01020304;
big_endian = ( *((char *)&endian) == 0x01 );
wmove(cw, LINES-1, 0);
draw(cw);
encwrite(version,strlen(version)+1,savef);
rs_write_int(savef,slines);
rs_write_int(savef,scols);
ret = rs_save_file(savef);
return(ret);
}
restore(file, envp)
register char *file;
char **envp;
{
register int inf;
extern char **environ;
char buf[LINELEN];
int endian = 0x01020304;
big_endian = ( *((char *)&endian) == 0x01 );
if (strcmp(file, "-r") == 0)
file = file_name;
if ((inf = open(file, O_RDONLY)) < 0)
{
perror(file);
return(-1);
}
fflush(stdout);
encread(buf, strlen(version) + 1, inf);
if (strcmp(buf, version) != 0)
{
printf("Sorry, saved game is out of date.\n");
return FALSE;
}
fflush(stdout);
rs_read_int(inf,&lines);
rs_read_int(inf,&cols);
initscr();
if (lines > LINES)
{
endwin();
printf("Sorry, original game was played on a screen with %d lines.\n",lines);
printf("Current screen only has %d lines. Unable to restore game\n",LINES);
return(FALSE);
}
if (cols > COLS)
{
endwin();
printf("Sorry, original game was played on a screen with %d columns.\n",cols);
printf("Current screen only has %d columns. Unable to restore game\n",COLS);
return(FALSE);
}
typeahead(-1);
setup();
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(hw, TRUE);
if (rs_restore_file(inf) == FALSE)
{
endwin();
printf("Cannot restore file\n");
close(inf);
return(FALSE);
}
close(inf);
if (!wizard)
unlink(file);
mpos = 0;
environ = envp;
strcpy(file_name, file);
clearok(curscr, TRUE);
touchwin(cw);
wrefresh(cw);
msg("Welcome back! --More-- ");
wait_for(' ');
msg("");
playit();
/*NOTREACHED*/
return(1);
}
#define ENCWBSIZ 1024
/*
* perform an encrypted write
*/
long
encwrite(start, size, outf)
register char *start;
register unsigned long size;
register FILE *outf;
{
register unsigned char *ep;
register int i = 0;
unsigned long num_written = 0;
char buf[ENCWBSIZ];
int ret;
ep = encstr;
while (size--)
{
buf[i++] = *start++ ^ *ep++;
if (*ep == '\0')
ep = encstr;
if (i == ENCWBSIZ || size == 0)
{
ret = (unsigned int) fwrite(buf, 1, i, outf);
if (ret > 0)
num_written += ret;
if (ret < i)
return(num_written);
i = 0;
}
}
return(num_written);
}
#define ENCRBSIZ 32768
/*
* perform an encrypted read
*/
long
encread(start, size, inf)
register char *start;
register unsigned long size;
int inf;
{
register unsigned char *ep;
register int rd_siz;
register unsigned long total_read;
total_read = 0;
while (total_read < size) {
rd_siz = ENCRBSIZ;
rd_siz = ((size-total_read) > ENCRBSIZ) ? ENCRBSIZ : (size-total_read);
rd_siz = read(inf,&start[total_read],rd_siz);
if(rd_siz==-1 || rd_siz==0)
break;
total_read += rd_siz;
}
ep = encstr;
size = total_read;
while (size--)
{
*start++ ^= *ep++;
if (*ep == '\0')
ep = encstr;
}
return total_read;
}

901
xrogue/scrolls.c Normal file
View file

@ -0,0 +1,901 @@
/*
scrolls.c - Functions for dealing with scrolls
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <ctype.h>
#include "rogue.h"
/*
* let the hero get rid of some type of monster
*/
genocide()
{
register struct linked_list *ip;
register struct thing *mp;
register struct linked_list *nip;
/* cannot genocide any uniques */
register int num_monst = NUMMONST-NUMUNIQUE-NUMDINOS;
register int which_monst;
which_monst = makemonster(FALSE, "wipe out");
if (which_monst <= 0 || which_monst >= num_monst) {
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 = NULL, *nobj;
register struct linked_list *item, *nitem;
register int i,j;
register unsigned 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;
blessed = obj->o_flags & ISBLESSED;
which = obj->o_which;
}
else {
cursed = flag & ISCURSED;
blessed = flag & ISBLESSED;
}
switch (which) {
case S_CONFUSE: /* Scroll of monster confusion. Give him that power. */
{
register char *str;
switch (rnd(5)) {
case 0:
str = "glow red";
when 1:
str = "vibrate";
when 2:
str = "glow blue";
when 3:
str = "radiate green";
otherwise:
str = "itch with a strange desire";
}
msg("Your hands begin to %s. ", str);
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.");
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
*/
msg("You hear a high-pitched humming noise.");
/* protect good charactors */
if (player.t_ctype == C_PALADIN ||
player.t_ctype == C_RANGER || player.t_ctype == C_MONK) {
msg("A chill runs up your spine! ");
aggravate(TRUE, FALSE);
}
else {
aggravate(TRUE, TRUE);
}
}
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);
turn_off(*th, ISCHARMED);
}
if (levtype == OUTSIDE)
msg("A sudden peace comes over the land.. ");
else
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);
turn_off(*th, ISCHARMED);
}
}
}
}
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((struct linked_list *)NULL);
}
if (is_scroll) s_know[S_IDENT] = TRUE;
when S_MAP:
/*
* Scroll of magic mapping.
*/
if (blessed) {
register int i;
if (is_scroll && s_know[S_MAP] != TRUE)
s_know[S_MAP] = TRUE;
/* light rooms */
for (i=0; i<MAXROOMS; i++){
rooms[i].r_flags &= ~ISDARK;
}
msg("This scroll has a very detailed map on it! --More--");
wait_for(' ');
overwrite(stdscr, hw);
overlay(stdscr, cw); /* wizard CTRL(F) */
overlay(mw, cw); /* wizard CTRL(X) */
draw(cw);
goto map_jump; /* skip over regular mapping routine */
}
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 = mvwinch(hw, i, j))
{
case SECRETDOOR:
nch = secretdoor (i, j);
break;
case HORZWALL:
case VERTWALL:
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);
map_jump: /* blessed map jump from above */
when S_GFIND:
/*
* Scroll of gold detection
*/
{
int gtotal = 0;
if (is_scroll) s_know[S_GFIND] = TRUE;
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) {
rmmsg();
overlay(hw,cw);
draw(cw);
msg("You begin to feel greedy. You sense gold!");
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 * NLEVMONS) * LEVEL;
/* if (turns > 42000) turns = 42000; limit turns */
debug ("vlevel = %d turns = %d", vlevel, turns);
level = rnd(201)+80; /* cursed teleport range */
msg("You are banished to the lower regions! ");
new_level(NORMLEV);
status(TRUE);
mpos = 0;
if (old_max == cur_max) { /* if he's been here make it harder */
/* protect good charactors */
if (player.t_ctype == C_PALADIN ||
player.t_ctype == C_RANGER || player.t_ctype == C_MONK) {
aggravate(TRUE, FALSE);
}
else {
aggravate(TRUE, TRUE);
}
}
}
else if (blessed) {
int old_level,
much = rnd(6) - 7;
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!");
/* return; leaks item, go through end of function */
}
else if (blessed) {
for (nitem = pack; nitem != NULL; nitem = next(nitem)) {
nobj = OBJPTR(nitem);
nobj->o_flags &= ~ISCURSED;
}
msg("Your pack glistens brightly!");
do_panic(NULL); /* this startles them */
/* return; leaks item, go through end of function */
}
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 WORMHOLE:
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("The 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 += rnd(16)+10;
if (lb->o_charges < 0)
lb->o_charges = 0;
if (EQUAL(ws_type[lb->o_which], "staff")) {
if (lb->o_charges > 200)
lb->o_charges = 200;
}
else {
if (lb->o_charges > 200) /* make em the same */
lb->o_charges = 200;
}
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) {
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 gotten here via prayer or Ankh, dock his wisdom. */
if (!is_scroll) {
pstats.s_wisdom--;
if (pstats.s_wisdom < 3) pstats.s_wisdom = 3;
msg("You feel a drain on your system. ");
}
}
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) {
pstats.s_hpt = -1;
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) < 17) {
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 - 12) / 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("What the !? ");
}
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 >= 5) || numcharmed > 0) break;
}
if (something == 0) msg(nothing);
}
otherwise:
msg("What a puzzling scroll!");
if (item != NULL) o_discard(item);
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);
}

3366
xrogue/state.c Normal file

File diff suppressed because it is too large Load diff

896
xrogue/sticks.c Normal file
View file

@ -0,0 +1,896 @@
/*
sticks.c - Functions to implement the various sticks one might find
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <ctype.h>
#include "rogue.h"
/*
* zap a stick and see what happens
*/
do_zap(zapper, obj, direction, which, flags)
struct thing *zapper;
struct object *obj;
coord *direction;
int which;
int flags;
{
register struct linked_list *item = NULL;
register struct thing *tp;
register int y = 0, x = 0, bonus;
struct linked_list *nitem;
struct object *nobj;
bool cursed, blessed, is_player = FALSE;
char *mname = NULL;
cursed = flags & ISCURSED;
blessed = flags & ISBLESSED;
if (obj && obj->o_type != RELIC) { /* all relics are chargeless */
if (obj->o_charges < 1) {
msg(nothing);
return;
}
obj->o_charges--;
}
if (which == WS_WONDER) {
switch (rnd(19)) {
case 0: which = WS_ELECT;
when 1: which = WS_FIRE;
when 2: which = WS_COLD;
when 3: which = WS_POLYMORPH;
when 4: which = WS_MISSILE;
when 5: which = WS_SLOW_M;
when 6: which = WS_TELMON;
when 7: which = WS_CANCEL;
when 8: which = WS_CONFMON;
when 9: which = WS_DISINTEGRATE;
when 10: which = WS_PETRIFY;
when 11: which = WS_PARALYZE;
when 12: which = WS_MDEG;
when 13: which = WS_FEAR;
when 14: which = WS_CURING;
when 15: which = WS_LIGHT;
when 16: which = WS_HIT;
when 17: which = WS_DRAIN;
when 18: which = WS_CHARGE;
}
if(ws_magic[which].mi_curse>0 && rnd(100)<=ws_magic[which].mi_curse){
cursed = TRUE;
blessed = FALSE;
}
}
tp = NULL;
switch (which) {
case WS_POLYMORPH:
case WS_SLOW_M:
case WS_TELMON:
case WS_CANCEL:
case WS_CONFMON:
case WS_DISINTEGRATE:
case WS_PETRIFY:
case WS_PARALYZE:
case WS_MDEG:
case WS_FEAR:
y = zapper->t_pos.y;
x = zapper->t_pos.x;
do {
y += direction->y;
x += direction->x;
}
while (shoot_ok(winat(y, x)) && !(y == hero.y && x == hero.x));
if (y == hero.y && x == hero.x)
is_player = TRUE;
else if (isalpha(mvwinch(mw, y, x))) {
item = find_mons(y, x);
tp = THINGPTR(item);
runto(tp, &hero);
turn_off(*tp, CANSURPRISE);
mname = monster_name(tp);
is_player = FALSE;
/* The monster may not like being shot at */
if ((zapper == &player) &&
on(*tp, ISCHARMED) &&
save(VS_MAGIC, tp, 0)) {
msg("The eyes of %s turn clear.", prname(mname, FALSE));
turn_off(*tp, ISCHARMED);
mname = monster_name(tp);
}
}
else {
/*
* if monster misses player because the player dodged then lessen
* the chances he will use the wand again since the player appears
* to be rather dextrous
*/
if (zapper != &player)
zapper->t_wand = zapper->t_wand * 3 / 5;
}
}
switch (which) {
case WS_LIGHT:
/*
* Reddy Kilowat wand. Light up the room
*/
blue_light(blessed, cursed);
when WS_DRAIN:
/*
* Take away 1/2 of hero's hit points, then take it away
* evenly from the monsters in the room or next to hero
* if he is in a passage (but leave the monsters alone
* if the stick is cursed)
*/
if (pstats.s_hpt < 2) {
msg("You are too weak to use it.");
}
else if (cursed)
pstats.s_hpt /= 2;
if (pstats.s_hpt <= 0) {
pstats.s_hpt = -1;
msg("You drain your own life away. --More--");
death(D_STRENGTH);
}
else
drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1);
when WS_POLYMORPH:
{
register char oldch;
register struct room *rp;
register struct linked_list *pitem;
coord delta;
if (tp == NULL)
break;
if (save(VS_MAGIC, tp, 0)) {
msg(nothing);
break;
}
rp = roomin(&tp->t_pos);
check_residue(tp);
delta.x = x;
delta.y = y;
detach(mlist, item);
oldch = tp->t_oldch;
pitem = tp->t_pack; /* save his pack */
tp->t_pack = NULL;
if (levtype == OUTSIDE)
new_monster(item,rnd(NUMDINOS)+NUMMONST-NUMDINOS,&delta,FALSE);
else
new_monster(item,rnd(NUMMONST-NUMUNIQUE-NUMDINOS-1)+1,&delta,FALSE);
if (tp->t_pack != NULL)
o_free_list (tp->t_pack);
tp->t_pack = pitem;
if (isalpha(mvwinch(cw, y, x)))
mvwaddch(cw, y, x, tp->t_type);
tp->t_oldch = oldch;
/*
* should the room light up?
*/
if (on(*tp, HASFIRE)) {
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 (cansee(tp->t_pos.y,tp->t_pos.x) &&
next(rp->r_fires) == NULL) light(&hero);
}
}
runto(tp, &hero);
msg(terse ? "A new %s!"
: "You have created a new %s!",
monster_name(tp));
}
when WS_PETRIFY:
if (tp == NULL)
break;
if (save(VS_MAGIC, tp, 0)) {
msg(nothing);
break;
}
check_residue(tp);
turn_on(*tp, ISSTONE);
turn_on(*tp, NOSTONE);
turn_off(*tp, ISRUN);
turn_off(*tp, ISINVIS);
turn_off(*tp, CANSURPRISE);
turn_off(*tp, ISDISGUISE);
tp->t_action = A_NIL;
tp->t_no_move = 0;
msg("%s is turned to stone!",prname(mname, TRUE));
when WS_TELMON:
{
register int rm;
register struct room *rp;
if (tp == NULL)
break;
if (save(VS_MAGIC, tp, 0)) {
msg(nothing);
break;
}
rp = NULL;
check_residue(tp);
tp->t_action = A_FREEZE; /* creature is disoriented */
tp->t_no_move = 2;
if (cursed) { /* Teleport monster to player */
if ((y == (hero.y + direction->y)) &&
(x == (hero.x + direction->x)))
msg(nothing);
else {
tp->t_pos.y = hero.y + direction->y;
tp->t_pos.x = hero.x + direction->x;
}
}
else if (blessed) { /* Get rid of monster */
killed(item, FALSE, TRUE, TRUE);
return;
}
else {
register int i=0;
do { /* Move monster to another room */
rm = rnd_room();
rnd_pos(&rooms[rm], &tp->t_pos);
}until(winat(tp->t_pos.y,tp->t_pos.x)==FLOOR ||i++>500);
rp = &rooms[rm];
}
/* Now move the monster */
if (isalpha(mvwinch(cw, y, x)))
mvwaddch(cw, y, x, tp->t_oldch);
mvwaddch(mw, y, x, ' ');
mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type);
if (tp->t_pos.y != y || tp->t_pos.x != x)
tp->t_oldch = mvwinch(cw, tp->t_pos.y, tp->t_pos.x);
/*
* check to see if room that creature appears in should
* light up
*/
if (on(*tp, HASFIRE)) {
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(cansee(tp->t_pos.y, tp->t_pos.x) &&
next(rp->r_fires) == NULL)
light(&hero);
}
}
}
when WS_CANCEL:
if (tp == NULL)
break;
if (save(VS_MAGIC, tp, 0)) {
msg(nothing);
break;
}
check_residue(tp);
tp->t_flags[0] &= CANC0MASK;
tp->t_flags[1] &= CANC1MASK;
tp->t_flags[2] &= CANC2MASK;
tp->t_flags[3] &= CANC3MASK;
tp->t_flags[4] &= CANC4MASK;
tp->t_flags[5] &= CANC5MASK;
tp->t_flags[6] &= CANC6MASK;
tp->t_flags[7] &= CANC7MASK;
tp->t_flags[8] &= CANC8MASK;
tp->t_flags[9] &= CANC9MASK;
tp->t_flags[10] &= CANCAMASK;
tp->t_flags[11] &= CANCBMASK;
tp->t_flags[12] &= CANCCMASK;
tp->t_flags[13] &= CANCDMASK;
tp->t_flags[14] &= CANCEMASK;
tp->t_flags[15] &= CANCFMASK;
when WS_MISSILE:
{
int dice;
static struct object bolt =
{
MISSILE , {0, 0}, 0, "", "1d4 " , NULL, 0, WS_MISSILE, 50, 1
};
if (!obj)
dice = zapper->t_stats.s_lvl;
if (obj->o_type == RELIC)
dice = 15;
else if (EQUAL(ws_type[which], "staff"))
dice = 10;
else
dice = 6;
sprintf(bolt.o_hurldmg, "%dd4", dice);
do_motion(&bolt, direction->y, direction->x, zapper);
if (!hit_monster(unc(bolt.o_pos), &bolt, zapper))
msg("The missile vanishes with a puff of smoke");
}
when WS_HIT:
{
register unsigned char ch;
struct object strike; /* don't want to change sticks attributes */
direction->y += hero.y;
direction->x += hero.x;
ch = winat(direction->y, direction->x);
if (isalpha(ch))
{
strike = *obj;
strike.o_hplus = 7;
if (EQUAL(ws_type[which], "staff"))
strcpy(strike.o_damage,"3d8");
else
strcpy(strike.o_damage,"2d8");
fight(direction, &strike, FALSE);
}
}
when WS_SLOW_M:
if (is_player) {
add_slow();
break;
}
if (tp == NULL)
break;
if (cursed) {
if (on(*tp, ISSLOW))
turn_off(*tp, ISSLOW);
else
turn_on(*tp, ISHASTE);
break;
}
if ((on(*tp,ISUNIQUE) && save(VS_MAGIC,tp,0)) || on(*tp,NOSLOW)) {
msg(nothing);
break;
}
else if (blessed) {
turn_off(*tp, ISRUN);
turn_on(*tp, ISHELD);
}
/*
* always slow in case he breaks free of HOLD
*/
if (on(*tp, ISHASTE))
turn_off(*tp, ISHASTE);
else
turn_on(*tp, ISSLOW);
when WS_CHARGE:
if (ws_know[WS_CHARGE] != TRUE && obj)
msg("This is a wand of charging.");
nitem = get_item(pack, "charge", STICK, FALSE, FALSE);
if (nitem != NULL) {
nobj = OBJPTR(nitem);
if ((++(nobj->o_charges) == 1) && (nobj->o_which == WS_HIT))
fix_stick(nobj);
if (blessed) ++(nobj->o_charges);
if (EQUAL(ws_type[nobj->o_which], "staff")) {
if (nobj->o_charges > 200)
nobj->o_charges = 200;
}
else {
if (nobj->o_charges > 200)
nobj->o_charges = 200;
}
}
when WS_ELECT:
shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT,
"lightning bolt", roll(zapper->t_stats.s_lvl,6));
when WS_FIRE:
shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT,
"flame", roll(zapper->t_stats.s_lvl,6));
when WS_COLD:
shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT,
"ice", roll(zapper->t_stats.s_lvl,6));
when WS_CONFMON:
if (cursed || is_player) {
if (!save(VS_WAND, &player, 0)) {
dsrpt_player();
confus_player();
}
else {
if (zapper != &player) zapper->t_wand /= 2;
msg(nothing);
}
}
else {
if (tp == NULL)
break;
if (save(VS_MAGIC, tp, 0) || on(*tp, ISCLEAR))
msg(nothing);
else
turn_on (*tp, ISHUH);
}
when WS_PARALYZE:
if (is_player || cursed) {
if ((obj && obj->o_type==RELIC) || !save(VS_WAND, &player, 0)){
player.t_no_move += 2 * movement(&player) * FREEZETIME;
player.t_action = A_FREEZE;
msg("You can't move.");
}
else {
if (zapper != &player) zapper->t_wand /= 2;
msg(nothing);
}
}
else {
if (tp == NULL)
break;
bonus = 0;
if (blessed) bonus = -3;
if (((obj && obj->o_type==RELIC) || !save(VS_WAND,tp,bonus)) &&
off(*tp, NOPARALYZE)) {
tp->t_no_move += 2 * movement(tp) * FREEZETIME;
tp->t_action = A_FREEZE;
}
else {
msg(nothing);
}
}
when WS_FEAR:
if (is_player) {
if (!on(player, ISFLEE) ||
ISWEARING(R_HEROISM) ||
save(VS_WAND, &player, 0)) {
msg(nothing);
zapper->t_wand /= 2;
}
else {
turn_on(player, ISFLEE);
player.t_dest = &zapper->t_pos;
msg("The sight of %s terrifies you.", prname(mname, FALSE));
}
break;
}
if (tp == NULL)
break;
bonus = 0;
if (blessed) bonus = -3;
if(save(VS_WAND, tp,bonus) || on(*tp,ISUNDEAD) || on(*tp,NOFEAR)){
msg(nothing);
break;
}
turn_on(*tp, ISFLEE);
turn_on(*tp, WASTURNED);
/* Stop it from attacking us */
dsrpt_monster(tp, TRUE, cansee(tp->t_pos.y, tp->t_pos.x));
/* 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;
when WS_MDEG:
if (is_player) {
if (save(VS_WAND, &player, 0)) {
msg (nothing);
zapper->t_wand /= 2;
break;
}
pstats.s_hpt /= 2;
if (pstats.s_hpt <= 0) {
pstats.s_hpt = -1;
msg("Your life has been sucked out from you! --More--");
wait_for(' ');
death(zapper);
}
else
msg("You feel a great drain on your system.");
}
if (tp == NULL)
break;
if (cursed) {
tp->t_stats.s_hpt *= 2;
msg("%s appears to be stronger now!", prname(mname, TRUE));
}
else if (on(*tp, ISUNIQUE) && save(VS_WAND, tp, 0))
msg (nothing);
else {
tp->t_stats.s_hpt /= 2;
msg("%s appears to be weaker now", prname(mname, TRUE));
}
if (tp->t_stats.s_hpt < 1)
killed(item, TRUE, TRUE, TRUE);
when WS_DISINTEGRATE:
if (tp == NULL)
break;
if (cursed) {
register int m1, m2;
coord mp;
struct linked_list *titem;
char ch;
struct thing *th;
if (on(*tp, ISUNIQUE) || on(*tp, CANSELL)) {
msg (nothing);
break;
}
for (m1=tp->t_pos.x-1 ; m1 <= tp->t_pos.x+1 ; m1++) {
for(m2=tp->t_pos.y-1 ; m2<=tp->t_pos.y+1 ; m2++) {
if (m1 == hero.x && m2 == hero.y)
continue;
ch = winat(m2,m1);
if (shoot_ok(ch)) {
mp.x = m1; /* create it */
mp.y = m2;
titem = new_item(sizeof(struct thing));
new_monster(titem,(short)tp->t_index,&mp,FALSE);
th = THINGPTR(titem);
turn_on (*th, ISMEAN);
runto(th,&hero);
if (on(*th, HASFIRE)) {
register struct room *rp;
rp = roomin(&th->t_pos);
if (rp) {
register struct linked_list *fire_item;
fire_item = creat_item();
ldata(fire_item) = (char *) th;
attach(rp->r_fires, fire_item);
rp->r_flags |= HASFIRE;
if (cansee(th->t_pos.y, th->t_pos.x) &&
next(rp->r_fires) == NULL)
light(&hero);
}
}
}
}
}
}
else { /* if its a UNIQUE it might still live */
if (on(*tp, ISUNIQUE) && save(VS_MAGIC, tp, 0)) {
tp->t_stats.s_hpt /= 2;
if (tp->t_stats.s_hpt < 1) {
killed(item, FALSE, TRUE, TRUE);
msg("You have disintegrated %s", prname(mname, FALSE));
}
else {
msg("%s appears wounded", prname(mname, TRUE));
}
}
else {
msg("You have disintegrated %s", prname(mname, FALSE));
killed (item, FALSE, TRUE, TRUE);
}
}
when WS_CURING:
if (cursed) {
bool sick = FALSE;
if (!save(VS_POISON, &player, 0)) {
msg("You feel extremely sick. ");
sick = TRUE;
pstats.s_hpt -= (pstats.s_hpt/3)+1;
if (pstats.s_hpt == 0) {
pstats.s_hpt = -1;
msg("You die! --More--");
wait_for(' ');
death (D_POISON);
}
}
if (!save(VS_WAND, &player, 0) && !ISWEARING(R_HEALTH)) {
turn_on(player, HASDISEASE);
turn_on(player, HASINFEST);
turn_on(player, DOROT);
fuse(cure_disease, (VOID *)NULL, roll(HEALTIME,SICKTIME), AFTER);
infest_dam++;
}
else if (sick == FALSE) msg("You feel momentarily sick");
}
else {
if (on(player, HASDISEASE) || on(player, HASINFEST)) {
extinguish(cure_disease);
turn_off(player, HASINFEST);
infest_dam = 0;
cure_disease(); /* this prints message */
}
if (on(player, DOROT)) {
msg("You feel your skin returning to normal.");
turn_off(player, DOROT);
}
pstats.s_hpt += roll(pstats.s_lvl, blessed ? 9 : 6);
if (pstats.s_hpt > max_stats.s_hpt)
pstats.s_hpt = max_stats.s_hpt;
msg("You begin to feel %sbetter.", blessed ? "much " : "");
}
otherwise:
msg("What a bizarre schtick!");
}
}
/*
* drain:
* Do drain hit points from player shtick
*/
drain(ymin, ymax, xmin, xmax)
int ymin, ymax, xmin, xmax;
{
register int i, j, count;
register struct thing *ick;
register struct linked_list *item;
/*
* First count how many things we need to spread the hit points among
*/
count = 0;
for (i = ymin; i <= ymax; i++) {
if (i < 1 || i > lines - 3)
continue;
for (j = xmin; j <= xmax; j++) {
if (j < 0 || j > cols - 1)
continue;
if (isalpha(mvwinch(mw, i, j)))
count++;
}
}
if (count == 0)
{
msg("You have a tingling feeling.");
return;
}
count = pstats.s_hpt / count;
pstats.s_hpt /= 2;
if (pstats.s_hpt <= 0) {
pstats.s_hpt = -1;
msg("Aarrgghhh!! --More--");
wait_for(' ');
death(D_STRENGTH);
}
/*
* Now zot all of the monsters
*/
for (i = ymin; i <= ymax; i++) {
if (i < 1 || i > lines - 3)
continue;
for (j = xmin; j <= xmax; j++) {
if (j < 0 || j > cols - 1)
continue;
if (isalpha(mvwinch(mw, i, j)) &&
((item = find_mons(i, j)) != NULL)) {
ick = THINGPTR(item);
if (on(*ick, ISUNIQUE) && save(VS_MAGIC, ick, 0))
ick->t_stats.s_hpt -= count / 2;
else
ick->t_stats.s_hpt -= count;
if (ick->t_stats.s_hpt < 1)
killed(item,
cansee(i,j)&&(!on(*ick,ISINVIS)||on(player,CANSEE)),
TRUE, TRUE);
else {
runto(ick, &hero);
/*
* The monster may not like being shot at. Since the
* shot is not aimed directly at the monster, we will
* give him a poorer save.
*/
if (on(*ick, ISCHARMED) && save(VS_MAGIC, ick, -2)) {
msg("The eyes of %s turn clear.",
prname(monster_name(ick), FALSE));
turn_off(*ick, ISCHARMED);
}
if (cansee(i,j) && (!on(*ick,ISINVIS)||on(player,CANSEE)))
msg("%s appears wounded",
prname(monster_name(ick), TRUE));
}
}
}
}
}
/*
* initialize a stick
*/
fix_stick(cur)
register struct object *cur;
{
if (EQUAL(ws_type[cur->o_which], "staff")) {
cur->o_weight = 100;
cur->o_charges = 5 + rnd(11);
strcpy(cur->o_damage,"3d4");
cur->o_hplus = 1;
cur->o_dplus = 0;
switch (cur->o_which) {
case WS_HIT:
cur->o_hplus = 3;
cur->o_dplus = 3;
strcpy(cur->o_damage,"2d8");
when WS_LIGHT:
cur->o_charges = 15 + rnd(11);
}
}
else {
strcpy(cur->o_damage,"2d3");
cur->o_weight = 75;
cur->o_hplus = 1;
cur->o_dplus = 0;
cur->o_charges = 5 + rnd(11);
switch (cur->o_which) {
case WS_HIT:
cur->o_hplus = 3;
cur->o_dplus = 3;
strcpy(cur->o_damage,"2d8");
when WS_LIGHT:
cur->o_charges = 15 + rnd(11);
}
}
strcpy(cur->o_hurldmg,"3d3");
}
/*
* Use the wand that our monster is wielding.
*/
m_use_wand(monster)
register struct thing *monster;
{
register struct object *obj;
/* Make sure we really have it */
if (monster->t_using)
obj = OBJPTR(monster->t_using);
else {
debug("Stick not set!");
monster->t_action = A_NIL;
return;
}
if (obj->o_type != STICK) {
debug("Stick not selected!");
monster->t_action = A_NIL;
return;
}
/*
* shoot the stick!
* assume all blessed sticks are normal for now.
* Note that we don't get here if the wand is cursed.
*/
msg("%s points a %s at you!", prname(monster_name(monster), TRUE),
ws_type[obj->o_which]);
do_zap(monster, obj, &monster->t_newpos, obj->o_which, NULL);
monster->t_wand /= 2; /* chance lowers with each use */
}
bool
need_dir(type, which)
int type, /* type of item, NULL means stick */
which; /* which item */
{
if (type == STICK || type == 0) {
switch (which) {
case WS_LIGHT:
case WS_DRAIN:
case WS_CHARGE:
case WS_CURING:
return(FALSE);
default:
return(TRUE);
}
}
else if (type == RELIC) {
switch (which) {
case MING_STAFF:
case ASMO_ROD:
case EMORI_CLOAK:
return(TRUE);
default:
return(FALSE);
}
}
return (FALSE); /* hope we don't get here */
}
/*
* let the player zap a stick and see what happens
*/
player_zap(which, flag)
int which;
int flag;
{
register struct linked_list *item;
register struct object *obj;
obj = NULL;
if (which == 0) {
/* This is a stick. It takes 2 movement periods to zap it */
if (player.t_action != C_ZAP) {
if ((item = get_item(pack,"zap with",ZAPPABLE,FALSE,FALSE)) == NULL)
return(FALSE);
obj = OBJPTR(item);
if (need_dir(obj->o_type, obj->o_which)) {
if (!get_dir(&player.t_newpos))
return(FALSE);
}
player.t_using = item; /* Remember what it is */
player.t_action = C_ZAP; /* We are quaffing */
player.t_no_move = 2 * movement(&player);
return(TRUE);
}
item = player.t_using;
/* We've waited our time, let's shoot 'em up! */
player.t_using = NULL;
player.t_action = A_NIL;
obj = OBJPTR(item);
/* Handle relics specially here */
if (obj->o_type == RELIC) {
switch (obj->o_which) {
case ORCUS_WAND:
/* msg(nothing); */
read_scroll(S_PETRIFY, NULL, FALSE);
return(TRUE);
when MING_STAFF:
which = WS_MISSILE;
when EMORI_CLOAK:
which = WS_PARALYZE;
obj->o_charges = 0; /* one zap/day (whatever that is) */
fuse(cloak_charge, obj, CLOAK_TIME, AFTER);
when ASMO_ROD:
switch (rnd(3)) {
case 0: which = WS_ELECT;
when 1: which = WS_COLD;
otherwise: which = WS_FIRE;
}
}
}
else {
which = obj->o_which;
ws_know[which] = TRUE;
flag = obj->o_flags;
}
}
do_zap(&player, obj, &player.t_newpos, which, flag);
return(TRUE);
}

951
xrogue/things.c Normal file
View file

@ -0,0 +1,951 @@
/*
things.c - functions for dealing with things like potions and scrolls
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <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 silvery 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");
when ALTERAN_CARD:
strcpy(pb, "A rectangular piece of wood");
otherwise:
strcpy(pb, "A wholly 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 palm)");
when EYE_VECNA:
if (cur_relic[EYE_VECNA]) strcat(pb, " (in forehead)");
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])
{
misc_name(pb,obj);
}
else {
switch (obj->o_which) {
case MM_JUG:
case MM_BEAKER:
case MM_KEOGHTOM:
strcpy(pb, "A crystalline jar");
when MM_BOOK:
case MM_SKILLS:
strcpy(pb, "A dusty book");
when MM_ELF_BOOTS:
case MM_DANCE:
strcpy(pb, "A pair of old boots");
when MM_BRACERS:
strcpy(pb, "A set of bracers");
when MM_OPEN:
case MM_HUNGER:
strcpy(pb, "A mysterious chime");
when MM_DISP:
case MM_R_POWERLESS:
case MM_PROTECT:
strcpy(pb, "A dark looking cloak");
when MM_DRUMS:
strcpy(pb, "A drum set");
when MM_DISAPPEAR:
case MM_CHOKE:
strcpy(pb, "A small pouch of dust");
when MM_G_DEXTERITY:
case MM_G_OGRE:
case MM_FUMBLE:
strcpy(pb, "A set of gauntlets");
when MM_ADAPTION:
case MM_JEWEL:
case MM_STRANGLE:
strcpy(pb, "A little necklace");
when MM_CRYSTAL:
strcpy(pb, "An unusual looking rock");
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 totally bizarre %s", unctrl(obj->o_type));
wait_for(' ');
}
/* 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 = 0;
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 = 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("You 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("Gloop... 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 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(150) < 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("You 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);
turn_off(player, NOACID);
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);
when MM_G_OGRE:
case MM_G_DEXTERITY:
save_max = max_stats.s_str;
chg_str(-op->o_ac);
max_stats.s_str = save_max;
}
}
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;
strcpy(cur->o_damage,"0d0");
strcpy(cur->o_hurldmg,"0d0");
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 > 4)
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 > 1 &&
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(3) + 1;
cur->o_dplus -= rnd(3) + 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);
wait_for(' ');
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(4)+1;
}
else if (blesschance < 40)
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;
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;
if (cur->o_flags & ISCURSED)
cur->o_ac = -cur->o_ac;
if (blesschance < r_magic[cur->o_which].mi_bless)
cur->o_ac+=rnd(vlevel/10)+1;
when R_DIGEST:
if (cur->o_flags & ISCURSED)
cur->o_ac = -1;
else if (blesschance < r_magic[cur->o_which].mi_bless)
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_HUNGER:
case MM_CHOKE:
cur->o_ac = (2 + rnd(2)) * 3;
when MM_OPEN:
case MM_DRUMS:
case MM_DISAPPEAR:
case MM_KEOGHTOM:
cur->o_ac = (5 + rnd(6)) * 3;
when MM_BRACERS:
if (cur->o_flags & ISCURSED)
cur->o_ac = -(rnd(5)+1);
else
cur->o_ac = rnd(5)+1;
when MM_PROTECT:
if (cur->o_flags & ISCURSED)
cur->o_ac = -(rnd(5)+1);
else
cur->o_ac = rnd(5)+1;
when MM_DISP:
cur->o_ac = 3;
when MM_SKILLS: /* set it to a character class */
cur->o_ac = rnd(NUM_CHARTYPES-1);
when MM_CRYSTAL:
cur->o_ac = 1; /* Use it just once */
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;
strcpy(obj->o_damage,"0d0");
strcpy(obj->o_hurldmg,"0d0");
obj->o_hplus = 0;
obj->o_dplus = 0;
obj->o_flags = 0;
obj->o_mark[0] = '\0';
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 |= ISCURSED;
when ARMOR:
obj->o_ac = armors[which].a_class - hit;
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 < 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 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].w_string);
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 < 3) /* 3% for 2 more */
return (2);
else if (i < 6) /* 6% for 1 more */
return (1);
else /* otherwise no more */
return (0);
}

498
xrogue/trader.c Normal file
View file

@ -0,0 +1,498 @@
/*
trader.c - Anything to do with trading posts
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#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 = NULL;
struct object *obj = NULL;
int wasfood = FALSE;
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 = wgetch(cw);
if (wh == ESC || wh == 'n') {
msg("");
return;
}
} until(wh == 'y');
}
mpos = 0;
if (curprice > purse) {
msg("You can't afford it!");
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);
obj = OBJPTR(item);
mpos = 0;
wasfood = ISMULT(obj->o_type);
if (add_pack((struct linked_list *)NULL,TRUE)) {/* 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;
if (!wasfood) /* if it was food then the object has been deleted */
{
whatis (item); /* identify it */
obj = OBJPTR(item);
obj->o_flags &= ~ISPOST; /* turn off ISPOST */
obj->o_flags |= ISKNOW; /* he knows the item */
msg("%s", inv_name(obj, TRUE));
}
else
msg("a food ration.");
}
}
/*
* 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 = 0, 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.
* Create every kind of weapon there is.
*/
for (wpt=0; wpt<MAXWEAPONS; wpt++) {
ll = spec_item(WEAPON, wpt, rnd(100)/80+1, rnd(121)/60);
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);
}
/*
* Suit of armor.
* Create every kind of armor there is.
*/
for (i=0; i<MAXARMORS; i++) {
ll = spec_item(ARMOR, i, rnd(100)/75, 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 rods/wands/staffs */
for (i=rnd(4)+2; i>0; i--) {
if (i == 1 && player.t_ctype != C_FIGHTER) j = WS_HIT;
else if (i == 5 && (player.t_ctype == C_RANGER ||
player.t_ctype == C_PALADIN ||
player.t_ctype == C_MONK)) j = WS_FEAR;
else 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_LIGHT;
when 7: j = WS_CANCEL;
}
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(5)+3; i>0; i--) {
k = 0;
if (i == 6 && player.t_ctype != C_MONK) j = R_HEALTH;
else if (i == 7) j = R_HEROISM;
else switch (rnd(21)) {
case 0: j = R_ADDINTEL; k = roll(1,3);
when 1: j = R_ADDSTR; k = roll(1,3);
when 2: j = R_ADDWISDOM; k = roll(1,3);
when 3: j = R_ADDHIT; k = roll(1,3);
when 4: j = R_ADDDAM; k = roll(1,3);
when 5: j = R_PROTECT; k = roll(1,3);
when 6: j = R_DIGEST; k = 1;
when 7: j = R_SUSABILITY;
when 8: j = R_SEEINVIS;
when 9: j = R_ALERT;
when 10: j = R_FIRE;
when 11: j = R_WARMTH;
when 12: j = R_FREEDOM;
when 13: j = R_STEALTH;
when 14: j = R_CARRY;
when 15: j = R_LIGHT;
when 16: j = R_TELCONTROL;
when 17: j = R_DELUSION;
when 18: j = R_FEAR;
when 19: j = R_AGGR;
when 20: j = R_SEARCH;
}
ll = spec_item(RING, j, k, 0);
attach(lvl_obj, ll);
op = OBJPTR(ll);
/*
* Let fighters, thieves, and monks know what kind
* of rings these are.
*/
switch (player.t_ctype) {
case C_FIGHTER:
case C_THIEF:
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(4)+3; i>0; i--) {
if (i == 1 && player.t_ctype == C_ASSASSIN) j = P_POISON;
else if (i == 6) j = P_PHASE;
else switch (rnd(11)) {
case 0: j = P_CLEAR;
when 1: j = P_HEALING;
when 2: j = P_MFIND;
when 3: j = P_HASTE;
when 4: j = P_RESTORE;
when 5: j = P_FLY;
when 6: j = P_FFIND;
when 7: j = P_SEEINVIS;
when 8: j = P_TFIND;
when 9: j = P_INVIS;
when 10: j = P_SKILL;
}
/* 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(4)+3; i>0; i--) {
if (i == 1 && player.t_ctype != C_MONK) j = S_CURING;
else if (i == 6 && player.t_ctype != C_THIEF) j = S_FINDTRAPS;
else switch (rnd(11)) {
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_HOLD;
when 8: j = S_PETRIFY;
when 9: j = S_SCARE;
when 10: j = S_TELEP;
}
/* 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)+2; 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 { /* in trading post itself */
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);
nofont(cw);
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");
newfont(cw);
trans_line();
}
/*
* 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 */
if (pstats.s_charisma > 24) /* but don't give it away! */
worth = (int) ((float) worth * (18. / (float)24));
else
worth = (int) ((float) worth * (18. / (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 = wgetch(cw);
if (ch == ESC || 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 gold 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.");
nofont(cw);
mvwaddstr(cw,lines - 4,0,prbuf);
newfont(cw);
}
/*
* 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);
}

1313
xrogue/util.c Normal file

File diff suppressed because it is too large Load diff

21
xrogue/vers.c Normal file
View file

@ -0,0 +1,21 @@
/*
vers.c - version number
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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.
*/
unsigned 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";
char version[] = "@(#)vers.c 8.0.3 - 12/10/2005";
char *release = "8.0.3";

428
xrogue/weapons.c Normal file
View file

@ -0,0 +1,428 @@
/*
weapons.c - Functions for dealing with problems brought about by weapons
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <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) != ' ') {
if (obj->o_type == MISSILE) nofont(cw);
mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, obj->o_type);
newfont(cw);
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 = NULL;
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];
strcpy(weap->o_damage,iwp->w_dam);
strcpy(weap->o_hurldmg,iwp->w_hrl);
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)) {
for(;;) {
msg(terse ? "Really throw? (y or n): "
: "Do you really want to throw %s? (y or n): ",
inv_name(obj, TRUE));
mpos = 0;
ch = wgetch(cw);
if (ch == 'n' || ch == ESC) {
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);
}
else
o_discard(item);
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/2];
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) {
switch (rnd(3)) {
case 0:
msg("Only fighter types can wield the two-handed sword.");
when 1:
msg("Your hand does not fit the two-handed sword.");
otherwise:
msg("You can not wield the two-handed sword.");
}
return;
}
if (player.t_ctype != C_FIGHTER &&
player.t_ctype != C_ASSASSIN &&
player.t_ctype != C_THIEF &&
player.t_ctype != C_MONK &&
obj->o_type == WEAPON &&
obj->o_which == BASWORD) {
switch (rnd(3)) {
case 0:
msg("Only thief types can wield the bastard sword.");
when 1:
msg("Your hand does not fit the bastard sword.");
otherwise:
msg("You can not wield the bastard sword.");
}
return;
}
if (terse) {
addmsg("W");
} else {
addmsg("You are now w");
}
msg("ielding %s", inv_name(obj, TRUE));
cur_weapon = obj;
}

438
xrogue/wear.c Normal file
View file

@ -0,0 +1,438 @@
/*
wear.c - functions for dealing with armor
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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"
/*
* 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 wear leather and studded leather armor.");
return;
}
if (player.t_ctype == C_ASSASSIN &&
(obj->o_which != LEATHER &&
obj->o_which != STUDDED_LEATHER)) {
if (terse) msg("Assassins can't wear that type of armor.");
else
msg("Assassins can wear leather and 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 and ogre power give the hero
* a dexterity of 21, 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 and acid breath.
*/
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) { /* Not enough fingers */
if (terse) msg("Wearing enough rings.");
else msg("You are already wearing 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 and ogre power give the hero
* a dexterity of 21, 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, (VOID *)NULL, 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); /* affect all charactors */
if (player.t_ctype == C_PALADIN ||
player.t_ctype == C_RANGER || player.t_ctype == C_MONK)
msg("A chill runs down your spine! ");
/*
* the necklace of adaption makes the hero immune to
* chlorine gas and acid
*/
when MM_ADAPTION:
msg("Wearing %s",inv_name(obj,TRUE));
cur_misc[WEAR_NECKLACE] = obj;
turn_on(player, NOGAS);
turn_on(player, NOACID);
/*
* 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, (VOID *)NULL, 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) { /* Not enough fingers */
if (terse) msg("Wearing enough rings.");
else msg("You are already wearing 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(5);
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? */
}
}

819
xrogue/wizard.c Normal file
View file

@ -0,0 +1,819 @@
/*
wizard.c - Special wizard commands
XRogue: Expeditions into the Dungeons of Doom
Copyright (C) 1991 Robert Pietkivitch
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 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 <string.h>
#include "rogue.h"
#include "mach_dep.h"
/*
* 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;
char *pt;
reg int ch, whc, newtype = 0, msz, newitem;
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);
wprintw(hw,"monster\t\t\tm");
}
wprintw(hw,"\n\nWhat do you want to create? ");
draw(hw);
do {
ch = wgetch(hw);
if (ch == ESC) {
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, "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 == ESC) {
restscr(cw);
msg("");
return;
}
} until (isalpha(ch));
if (thiswin == hw) /* restore screen if need be */
restscr(cw);
newtype = 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 +5 */
whc = rnd(6);
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;
if (!wizard) whc = rnd(6);
obj->o_dplus += whc;
}
else { /* armor here */
obj->o_weight = armors[wh].a_wght;
obj->o_ac = armors[wh].a_class - whc;
}
when RING:
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 + 2;
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_HUNGER:
case MM_CHOKE:
if (whc < 0 )
whc = -whc; /* cannot be negative */
obj->o_ac = (whc + 1) * 2;
break;
when MM_OPEN:
case MM_DRUMS:
case MM_DISAPPEAR:
case MM_KEOGHTOM:
if (whc < 0)
whc = -whc; /* these cannot be negative */
obj->o_ac = (whc + 3) * 5;
break;
when MM_BRACERS:
obj->o_ac = whc + 4;
when MM_DISP:
obj->o_ac = 3;
when MM_PROTECT:
obj->o_ac = whc + 4;
when MM_SKILLS:
if (whc < 2)
obj->o_ac = rnd(NUM_CHARTYPES-1);
else
obj->o_ac = player.t_ctype;
when MM_CRYSTAL:
obj->o_ac = 1;
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 > 3 && 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 > 3 && 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) == FALSE) {
obj->o_pos = hero;
fall(item, TRUE);
}
}
/*
* getbless:
* Get a blessing for a wizards object
*/
int
getbless()
{
reg char bless;
msg("Blessing? (+,-,n)");
bless = wgetch(msgw);
if (bless == '+')
return (15);
else if (bless == '-')
return (-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);
}
/*
* make a monster for the wizard
*/
makemonster(showall, action)
bool showall; /* showall -> show uniques and genocided creatures */
char *action;
{
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 UNIQUES, DINOS, and quartermaster */
if (!showall) num_monst -= NUMUNIQUE + NUMDINOS + 1;
max_monster = num_monst;
/* Print out the monsters */
if (levtype == OUTSIDE) {
num_monst = NUMDINOS;
max_monster = NUMMONST - 1;
pres_monst = (pres_monst + NUMMONST - NUMDINOS - 1);
}
while (num_monst > 0) {
register int 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 (levtype == OUTSIDE)
if ((which_monst < NUMMONST-NUMDINOS || which_monst > max_monster)) {
mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- ");
draw(hw);
goto get_monst;
}
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);
return(which_monst);
}
/*
* passwd:
* see if user knows password
*/
bool
passwd()
{
register char *sp, c;
char buf[LINELEN];
msg("Wizard's Password:");
mpos = 0;
sp = buf;
while ((c = wgetch(cw)) != '\n' && c != '\r' && c != '\033') {
if (c == killchar())
sp = buf;
else if (c == erasechar() && sp > buf)
sp--;
else
*sp++ = c;
}
if (sp == buf)
return FALSE;
*sp = '\0';
return (strcmp(PASSWD, xcrypt(buf, "mT")) == 0);
/* don't mess with the password here or elsewhere.
*
* If anyone goes wizard they forfeit being placed in the scorefile.
* So, no need to be secretive about it. Let them have it!
*
* Additionally, you can begin the game as wizard by starting it
* with a null argument, as in: xrogue ""
*/
}
/*
* teleport:
* Bamf the hero someplace else
*/
void
teleport()
{
register struct room *new_rp = NULL, *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;
flushinp();
}
/*
* 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));
}
/*
* Choose a quest item
* (if on STARTLEV equipage level = 0)
*/
choose_qst()
{
bool doit = TRUE;
bool escp = TRUE;
/* let wizard in on this too */
if (waswizard == TRUE || (levtype == POSTLEV && level == 0)) {
wclear(hw);
touchwin(hw);
wmove(hw, 2, 0);
wprintw(hw, "a) Cloak of Emori\n");
wprintw(hw, "b) Ankh of Heil\n");
wprintw(hw, "c) Quill of Nagrom\n");
wprintw(hw, "d) Eye of Vecna\n");
wprintw(hw, "e) Ring of Surtur\n");
wprintw(hw, "f) Staff of Ming\n");
wprintw(hw, "g) Wand of Orcus\n");
wprintw(hw, "h) Rod of Asmodeus\n");
wprintw(hw, "i) Amulet of Yendor\n");
wprintw(hw, "j) Amulet of Stonebones\n");
wprintw(hw, "k) Mandolin of Brian\n");
wprintw(hw, "l) Horn of Geryon\n");
wprintw(hw, "m) Daggers of Musty Doit\n");
wprintw(hw, "n) Axe of Aklad\n");
wprintw(hw, "o) Morning Star of Hruggek\n");
wprintw(hw, "p) Flail of Yeenoghu\n");
wprintw(hw, "q) Card of Alteran\n");
mvwaddstr(hw, 0, 0, "Select a quest item: "); /* prompt */
if (menu_overlay) /* Print the selections. The longest line is
* Hruggek (26 characters). The prompt is 21.
*/
over_win(cw, hw, 20, 29, 0, 21, NULL);
else
draw(hw);
while (doit) {
switch (wgetch(cw)) {
case EOF:
case ESC:
escp = FALSE; /* used below */
doit = FALSE;
when 'a':
quest_item = EMORI_CLOAK;
doit = FALSE;
when 'b':
quest_item = HEIL_ANKH;
doit = FALSE;
when 'c':
quest_item = QUILL_NAGROM;
doit = FALSE;
when 'd':
quest_item = EYE_VECNA;
doit = FALSE;
when 'e':
quest_item = SURTUR_RING;
doit = FALSE;
when 'f':
quest_item = MING_STAFF;
doit = FALSE;
when 'g':
quest_item = ORCUS_WAND;
doit = FALSE;
when 'h':
quest_item = ASMO_ROD;
doit = FALSE;
when 'i':
quest_item = YENDOR_AMULET;
doit = FALSE;
when 'j':
quest_item = STONEBONES_AMULET;
doit = FALSE;
when 'k':
quest_item = BRIAN_MANDOLIN;
doit = FALSE;
when 'l':
quest_item = GERYON_HORN;
doit = FALSE;
when 'm':
quest_item = MUSTY_DAGGER;
doit = FALSE;
when 'n':
quest_item = AXE_AKLAD;
doit = FALSE;
when 'o':
quest_item = HRUGGEK_MSTAR;
doit = FALSE;
when 'p':
quest_item = YEENOGHU_FLAIL;
doit = FALSE;
when 'q':
quest_item = ALTERAN_CARD;
doit = FALSE;
otherwise:
doit = TRUE;
}
}
if (menu_overlay) {
status(FALSE);
touchwin(cw);
if (escp == TRUE) {
msg("Your quest item is the %s. --More--",
rel_magic[quest_item].mi_name);
wait_for(' ');
}
return;
}
else {
if (escp == TRUE) {
wmove(hw, lines-4, 0);
wprintw(hw, "Your quest item is the %s.",
rel_magic[quest_item].mi_name);
}
wmove(hw, lines-1, 0);
wprintw(hw, spacemsg);
draw(hw);
wait_for(' ');
wclear(hw);
draw(hw);
wmove(cw, 0, 0);
wclrtoeol(cw);
status(FALSE);
touchwin(cw);
return;
}
}
else {
msg("You can no longer select a quest item. ");
return;
}
}

691
xrogue/xcrypt.c Normal file
View file

@ -0,0 +1,691 @@
/*
* 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>
#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);
}

21
xrogue/xrogue.sln Executable file
View file

@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 7.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrogue", "xrogue.vcproj", "{ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}"
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
ConfigName.0 = Debug
ConfigName.1 = Release
EndGlobalSection
GlobalSection(ProjectDependencies) = postSolution
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}.Debug.ActiveCfg = Debug|Win32
{ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}.Debug.Build.0 = Debug|Win32
{ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}.Release.ActiveCfg = Release|Win32
{ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

278
xrogue/xrogue.vcproj Executable file
View file

@ -0,0 +1,278 @@
<?xml version="1.0" encoding = "Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.00"
Name="xrogue"
ProjectGUID="{ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}"
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"
InlineFunctionExpansion="0"
OptimizeForWindowsApplication="TRUE"
AdditionalIncludeDirectories=".."
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;PDC_STATIC_BUILD"
StringPooling="TRUE"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
SmallerTypeCheck="TRUE"
RuntimeLibrary="5"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
BrowseInformation="1"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"
CompileAs="1"
DisableSpecificWarnings="4033;4716;4013;4131;4244;4201"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib pdcurses.lib"
OutputFile="$(OutDir)/xrogue.exe"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories=".."
IgnoreAllDefaultLibraries="FALSE"
IgnoreDefaultLibraryNames="LIBC.LIB"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/xrogue.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;_WINDOWS"
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/xrogue.exe"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="2"
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="bolt.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="help.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="misc.c">
</File>
<File
RelativePath="mons_def.c">
</File>
<File
RelativePath="monsters.c">
</File>
<File
RelativePath="move.c">
</File>
<File
RelativePath="n_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>
</Files>
<Globals>
</Globals>
</VisualStudioProject>