NetBSD rogue source

This commit is contained in:
David Meyer
2024-03-15 22:44:18 +09:00
parent 2a506c9af9
commit 1788470fab
29 changed files with 12932 additions and 0 deletions

55
CHANGES Normal file
View File

@@ -0,0 +1,55 @@
$NetBSD: CHANGES,v 1.4 2021/09/19 10:34:07 andvar Exp $
From: tektronix!zeus.TEK.COM!tims@ucbvax.Berkeley.EDU
Date: 30 Nov 87 15:08:15 PST (Mon)
To: okeeffe.Berkeley.EDU!mckusick@ucbvax.Berkeley.EDU (Kirk McKusick)
Subject: Re: Public domain rogue
Return-Path: tektronix!zeus.TEK.COM!tims@ucbvax.Berkeley.EDU
Here is a list of discrepancies from the documentation you sent me:
The -d option not implemented.
The -r option not implemented, use "rogue save_file" instead.
Strength is between 1 and 99, not 3 and 32.
The D command is not implemented.
Only scrolls,potions,wands,and rings may be "call"ed something.
The ^P command may be used to go 4 messages back, instead of just 1.
The @ command is not implemented.
There are no dark rooms.
ROGUEOPTS of flush,terse,seefloor,askme,inventory are ignored.
'askquit' is added to prevent ^\ from terminating the game accidentally.
If 'noaskquit' is
found in the ROGUEOPTS string, the ^\ kills the game, otherwise,
the player is asked if he really wants to quit. In either case, no
score file processing is attempted.
The score is keyed to winning scores, and no player may appear twice.
Other differences from "standard" rogue 5.3. This list covers externally
visible differences only.
There should be NO bugs with any severe consequences. Absolutely NO
game-stopping, or game-winning bugs should be present.
Traps fail occasionally, that is, they sometimes are sprung but miss.
The ^A command prints out some stuff you're probably not interested in.
The '&' command silently saves your screen into the file 'rogue.screen'
Any inventory selection command that takes '*' as a request to list all
appropriate items, can take one of "=?:)]!/" to list only rings,
scrolls, or whatever.
Scrolls and potions, once used, become identified. All other objects become
identified only by scroll of identification.
There is only one scroll of identification, and it works on any item.
ROGUEOPTS
Only the following are implemented:
file,jump,name,askquit,tombstone,passgo
"askquit" is used to prevent accidental termination of the game via ^\
You may drop objects in doorways.
Prints a picture of a skull, not a tombstone, upon death.
The save/restore game function is faster and machine-independent, but sometimes
requires modification when new variables are added to the source.
The potion of detect monster lasts for the whole level.
Their is no wand of light.

20
Makefile Normal file
View File

@@ -0,0 +1,20 @@
# $NetBSD: Makefile,v 1.22 2023/06/03 09:09:09 lukem Exp $
# @(#)Makefile 8.1 (Berkeley) 5/31/93
PROG= rogue
CPPFLAGS+=-DUNIX
SRCS= hit.c init.c inventory.c level.c machdep.c main.c \
message.c monster.c move.c object.c pack.c play.c random.c ring.c \
room.c save.c score.c spec_hit.c throw.c trap.c use.c zap.c
DPADD= ${LIBCURSES} ${LIBTERMINFO}
LDADD= -lcurses -lterminfo
HIDEGAME=hidegame
SETGIDGAME=yes
MAN= rogue.6
SUBDIR.roff+=USD.doc
COPTS.score.c+= ${CC_WNO_FORMAT_TRUNCATION}
.include <bsd.prog.mk>
.include <bsd.subdir.mk>

10
USD.doc/Makefile Normal file
View File

@@ -0,0 +1,10 @@
# $NetBSD: Makefile,v 1.7 2014/07/05 19:22:42 dholland Exp $
# @(#)Makefile 8.1 (Berkeley) 6/8/93
SECTION=reference/ref6
ARTICLE=rogue
SRCS= rogue.me
MACROS= -me
ROFF_TBL=yes
.include <bsd.doc.mk>

834
USD.doc/rogue.me Normal file
View File

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

466
hit.c Normal file
View File

@@ -0,0 +1,466 @@
/* $NetBSD: hit.c,v 1.10 2008/01/14 03:50:01 dholland Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)hit.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: hit.c,v 1.10 2008/01/14 03:50:01 dholland Exp $");
#endif
#endif /* not lint */
/*
* hit.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include "rogue.h"
static int damage_for_strength(void);
static int get_w_damage(const object *);
static int to_hit(const object *);
static object *fight_monster = NULL;
char hit_message[HIT_MESSAGE_SIZE] = "";
void
mon_hit(object *monster)
{
short damage, hit_chance;
const char *mn;
float minus;
if (fight_monster && (monster != fight_monster)) {
fight_monster = 0;
}
monster->trow = NO_ROOM;
if (cur_level >= (AMULET_LEVEL * 2)) {
hit_chance = 100;
} else {
hit_chance = monster->m_hit_chance;
hit_chance -= (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
}
if (wizard) {
hit_chance /= 2;
}
if (!fight_monster) {
interrupted = 1;
}
mn = mon_name(monster);
if (!rand_percent(hit_chance)) {
if (!fight_monster) {
messagef(1, "%sthe %s misses", hit_message, mn);
hit_message[0] = 0;
}
return;
}
if (!fight_monster) {
messagef(1, "%sthe %s hit", hit_message, mn);
hit_message[0] = 0;
}
if (!(monster->m_flags & STATIONARY)) {
damage = get_damage(monster->m_damage, 1);
if (cur_level >= (AMULET_LEVEL * 2)) {
minus = (float)((AMULET_LEVEL * 2) - cur_level);
} else {
minus = (float)get_armor_class(rogue.armor) * 3.00;
minus = minus/100.00 * (float)damage;
}
damage -= (short)minus;
} else {
damage = monster->stationary_damage++;
}
if (wizard) {
damage /= 3;
}
if (damage > 0) {
rogue_damage(damage, monster, 0);
}
if (monster->m_flags & SPECIAL_HIT) {
special_hit(monster);
}
}
void
rogue_hit(object *monster, boolean force_hit)
{
short damage, hit_chance;
if (monster) {
if (check_imitator(monster)) {
return;
}
hit_chance = force_hit ? 100 : get_hit_chance(rogue.weapon);
if (wizard) {
hit_chance *= 2;
}
if (!rand_percent(hit_chance)) {
if (!fight_monster) {
(void)strlcpy(hit_message, "you miss ",
sizeof(hit_message));
}
goto RET;
}
damage = get_weapon_damage(rogue.weapon);
if (wizard) {
damage *= 3;
}
if (con_mon) {
s_con_mon(monster);
}
if (mon_damage(monster, damage)) { /* still alive? */
if (!fight_monster) {
(void)strlcpy(hit_message, "you hit ",
sizeof(hit_message));
}
}
RET: check_gold_seeker(monster);
wake_up(monster);
}
}
void
rogue_damage(short d, object *monster, short other)
{
if (d >= rogue.hp_current) {
rogue.hp_current = 0;
print_stats(STAT_HP);
killed_by(monster, other);
}
if (d > 0) {
rogue.hp_current -= d;
print_stats(STAT_HP);
}
}
int
get_damage(const char *ds, boolean r)
{
int i = 0, j, n, d, total = 0;
while (ds[i]) {
n = get_number(ds+i);
while ((ds[i] != 'd') && ds[i]) {
i++;
}
if (ds[i] == 'd') {
i++;
}
d = get_number(ds+i);
while ((ds[i] != '/') && ds[i]) {
i++;
}
if (ds[i] == '/') {
i++;
}
for (j = 0; j < n; j++) {
if (r) {
total += get_rand(1, d);
} else {
total += d;
}
}
}
return(total);
}
static int
get_w_damage(const object *obj)
{
char new_damage[32];
int tmp_to_hit, tmp_damage;
int i = 0;
if ((!obj) || (obj->what_is != WEAPON)) {
return(-1);
}
tmp_to_hit = get_number(obj->damage) + obj->hit_enchant;
while ((obj->damage[i] != 'd') && obj->damage[i]) {
i++;
}
if (obj->damage[i] == 'd') {
i++;
}
tmp_damage = get_number(obj->damage + i) + obj->d_enchant;
snprintf(new_damage, sizeof(new_damage), "%dd%d",
tmp_to_hit, tmp_damage);
return(get_damage(new_damage, 1));
}
int
get_number(const char *s)
{
int i = 0;
int total = 0;
while ((s[i] >= '0') && (s[i] <= '9')) {
total = (10 * total) + (s[i] - '0');
i++;
}
return(total);
}
long
lget_number(const char *s)
{
short i = 0;
long total = 0;
while ((s[i] >= '0') && (s[i] <= '9')) {
total = (10 * total) + (s[i] - '0');
i++;
}
return(total);
}
static int
to_hit(const object *obj)
{
if (!obj) {
return(1);
}
return(get_number(obj->damage) + obj->hit_enchant);
}
static int
damage_for_strength(void)
{
short strength;
strength = rogue.str_current + add_strength;
if (strength <= 6) {
return(strength-5);
}
if (strength <= 14) {
return(1);
}
if (strength <= 17) {
return(3);
}
if (strength <= 18) {
return(4);
}
if (strength <= 20) {
return(5);
}
if (strength <= 21) {
return(6);
}
if (strength <= 30) {
return(7);
}
return(8);
}
int
mon_damage(object *monster, short damage)
{
const char *mn;
short row, col;
monster->hp_to_kill -= damage;
if (monster->hp_to_kill <= 0) {
row = monster->row;
col = monster->col;
dungeon[row][col] &= ~MONSTER;
mvaddch(row, col, get_dungeon_char(row, col));
fight_monster = 0;
cough_up(monster);
mn = mon_name(monster);
messagef(1, "%sdefeated the %s", hit_message, mn);
hit_message[0] = 0;
add_exp(monster->kill_exp, 1);
take_from_pack(monster, &level_monsters);
if (monster->m_flags & HOLDS) {
being_held = 0;
}
free_object(monster);
return(0);
}
return(1);
}
void
fight(boolean to_the_death)
{
short ch, c, d;
short row, col;
boolean first_miss = 1;
short possible_damage;
object *monster;
ch = 0;
while (!is_direction(ch = rgetchar(), &d)) {
sound_bell();
if (first_miss) {
messagef(0, "direction?");
first_miss = 0;
}
}
check_message();
if (ch == CANCEL) {
return;
}
row = rogue.row; col = rogue.col;
get_dir_rc(d, &row, &col, 0);
c = mvinch(row, col);
if (((c < 'A') || (c > 'Z')) ||
(!can_move(rogue.row, rogue.col, row, col))) {
messagef(0, "I see no monster there");
return;
}
if (!(fight_monster = object_at(&level_monsters, row, col))) {
return;
}
if (!(fight_monster->m_flags & STATIONARY)) {
possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3);
} else {
possible_damage = fight_monster->stationary_damage - 1;
}
while (fight_monster) {
(void)one_move_rogue(ch, 0);
if (((!to_the_death) && (rogue.hp_current <= possible_damage)) ||
interrupted || (!(dungeon[row][col] & MONSTER))) {
fight_monster = 0;
} else {
monster = object_at(&level_monsters, row, col);
if (monster != fight_monster) {
fight_monster = 0;
}
}
}
}
void
get_dir_rc(short dir, short *row, short *col, short allow_off_screen)
{
switch(dir) {
case LEFT:
if (allow_off_screen || (*col > 0)) {
(*col)--;
}
break;
case DOWN:
if (allow_off_screen || (*row < (DROWS-2))) {
(*row)++;
}
break;
case UPWARD:
if (allow_off_screen || (*row > MIN_ROW)) {
(*row)--;
}
break;
case RIGHT:
if (allow_off_screen || (*col < (DCOLS-1))) {
(*col)++;
}
break;
case UPLEFT:
if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) {
(*row)--;
(*col)--;
}
break;
case UPRIGHT:
if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) {
(*row)--;
(*col)++;
}
break;
case DOWNRIGHT:
if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) {
(*row)++;
(*col)++;
}
break;
case DOWNLEFT:
if (allow_off_screen || ((*row < (DROWS-2)) && (*col > 0))) {
(*row)++;
(*col)--;
}
break;
}
}
int
get_hit_chance(const object *weapon)
{
short hit_chance;
hit_chance = 40;
hit_chance += 3 * to_hit(weapon);
hit_chance += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
return(hit_chance);
}
int
get_weapon_damage(const object *weapon)
{
short damage;
damage = get_w_damage(weapon);
damage += damage_for_strength();
damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2);
return(damage);
}
void
s_con_mon(object *monster)
{
if (con_mon) {
monster->m_flags |= CONFUSED;
monster->moves_confused += get_rand(12, 22);
messagef(0, "the monster appears confused");
con_mon = 0;
}
}

366
init.c Normal file
View File

@@ -0,0 +1,366 @@
/* $NetBSD: init.c,v 1.18 2008/08/08 16:10:47 drochner Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: init.c,v 1.18 2008/08/08 16:10:47 drochner Exp $");
#endif
#endif /* not lint */
/*
* init.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include <stdlib.h>
#include <fcntl.h>
#include "rogue.h"
static void do_args(int, char **);
static void do_opts(void);
static void env_get_value(char **, char *, boolean);
static void init_str(char **, const char *);
static void player_init(void);
static char *rest_file = NULL;
static boolean init_curses = 0;
char login_name[MAX_OPT_LEN];
char *nick_name = NULL;
boolean cant_int = 0;
boolean did_int = 0;
boolean score_only;
boolean save_is_interactive = 1;
boolean ask_quit = 1;
boolean no_skull = 0;
boolean passgo = 0;
const char *error_file = "rogue.esave";
const char *byebye_string = "Okay, bye bye!";
gid_t gid, egid;
int
init(int argc, char *argv[])
{
const char *pn;
int seed;
int fd;
gid = getgid();
egid = getegid();
setegid(gid);
/* Check for dirty tricks with closed fds 0, 1, 2 */
fd = open("/dev/null", O_RDONLY);
if (fd < 3)
exit(1);
close(fd);
seed = 0;
pn = md_gln();
if ((!pn) || (strlen(pn) >= MAX_OPT_LEN)) {
clean_up("Hey! Who are you?");
}
/* LOGIN_NAME_SIZE == MAX_OPT_LEN now, but just in case... */
(void)strlcpy(login_name, pn, sizeof(login_name));
do_args(argc, argv);
do_opts();
if (!score_only && !rest_file) {
printf("Hello %s, just a moment while I dig the dungeon...",
nick_name);
fflush(stdout);
}
if (!initscr()) {
fprintf(stderr, "couldn't initialize screen\n");
exit (0);
}
if ((LINES < DROWS) || (COLS < DCOLS)) {
clean_up("must be played on at least 80 x 24 screen");
}
start_window();
init_curses = 1;
md_heed_signals();
if (score_only) {
put_scores(NULL, 0);
}
seed = md_gseed();
(void)srrandom(seed);
if (rest_file) {
restore(rest_file);
return(1);
}
mix_colors();
get_wand_and_ring_materials();
make_scroll_titles();
level_objects.next_object = NULL;
level_monsters.next_monster = NULL;
player_init();
ring_stats(0);
return(0);
}
static void
player_init(void)
{
object *obj;
rogue.pack.next_object = NULL;
obj = alloc_object();
get_food(obj, 1);
(void)add_to_pack(obj, &rogue.pack, 1);
obj = alloc_object(); /* initial armor */
obj->what_is = ARMOR;
obj->which_kind = RINGMAIL;
obj->class = RINGMAIL+2;
obj->is_protected = 0;
obj->d_enchant = 1;
(void)add_to_pack(obj, &rogue.pack, 1);
do_wear(obj);
obj = alloc_object(); /* initial weapons */
obj->what_is = WEAPON;
obj->which_kind = MACE;
obj->damage = "2d3";
obj->hit_enchant = obj->d_enchant = 1;
obj->identified = 1;
(void)add_to_pack(obj, &rogue.pack, 1);
do_wield(obj);
obj = alloc_object();
obj->what_is = WEAPON;
obj->which_kind = BOW;
obj->damage = "1d2";
obj->hit_enchant = 1;
obj->d_enchant = 0;
obj->identified = 1;
(void)add_to_pack(obj, &rogue.pack, 1);
obj = alloc_object();
obj->what_is = WEAPON;
obj->which_kind = ARROW;
obj->quantity = get_rand(25, 35);
obj->damage = "1d2";
obj->hit_enchant = 0;
obj->d_enchant = 0;
obj->identified = 1;
(void)add_to_pack(obj, &rogue.pack, 1);
}
void
clean_up(const char *estr)
{
if (save_is_interactive) {
if (init_curses) {
move(DROWS-1, 0);
refresh();
stop_window();
}
printf("\n%s\n", estr);
}
md_exit(0);
}
void
start_window(void)
{
cbreak();
noecho();
#ifndef BAD_NONL
nonl();
#endif
}
void
stop_window(void)
{
endwin();
}
void
byebye(int dummy __unused)
{
md_ignore_signals();
if (ask_quit) {
quit(1);
} else {
clean_up(byebye_string);
}
md_heed_signals();
}
void
onintr(int dummy __unused)
{
md_ignore_signals();
if (cant_int) {
did_int = 1;
} else {
check_message();
messagef(1, "interrupt");
}
md_heed_signals();
}
void
error_save(int dummy __unused)
{
save_is_interactive = 0;
save_into_file(error_file);
clean_up("");
}
static void
do_args(int argc, char *argv[])
{
int i, j;
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
for (j = 1; argv[i][j]; j++) {
switch(argv[i][j]) {
case 's':
score_only = 1;
break;
}
}
} else {
rest_file = argv[i];
}
}
}
static void
do_opts(void)
{
char *eptr;
if ((eptr = md_getenv("ROGUEOPTS")) != NULL) {
for (;;) {
while ((*eptr) == ' ') {
eptr++;
}
if (!(*eptr)) {
break;
}
if (!strncmp(eptr, "fruit=", 6)) {
eptr += 6;
env_get_value(&fruit, eptr, 1);
} else if (!strncmp(eptr, "file=", 5)) {
eptr += 5;
env_get_value(&save_file, eptr, 0);
} else if (!strncmp(eptr, "jump", 4)) {
jump = 1;
} else if (!strncmp(eptr, "name=", 5)) {
eptr += 5;
env_get_value(&nick_name, eptr, 0);
} else if (!strncmp(eptr, "noaskquit", 9)) {
ask_quit = 0;
} else if (!strncmp(eptr, "noskull", 5) ||
!strncmp(eptr,"notomb", 6)) {
no_skull = 1;
} else if (!strncmp(eptr, "passgo", 5)) {
passgo = 1;
}
while ((*eptr) && (*eptr != ',')) {
eptr++;
}
if (!(*(eptr++))) {
break;
}
}
}
/* If some strings have not been set through ROGUEOPTS, assign defaults
* to them so that the options editor has data to work with.
*/
init_str(&nick_name, login_name);
init_str(&save_file, "rogue.save");
init_str(&fruit, "slime-mold");
}
static void
env_get_value(char **s, char *e, boolean add_blank)
{
short i = 0;
const char *t;
t = e;
while ((*e) && (*e != ',')) {
if (*e == ':') {
*e = ';'; /* ':' reserved for score file purposes */
}
e++;
if (++i >= MAX_OPT_LEN) {
break;
}
}
/* note: edit_opts() in room.c depends on this being the right size */
*s = md_malloc(MAX_OPT_LEN + 2);
if (*s == NULL)
clean_up("out of memory");
(void)strncpy(*s, t, i);
if (add_blank) {
(*s)[i++] = ' ';
}
(*s)[i] = '\0';
}
static void
init_str(char **str, const char *dflt)
{
if (!(*str)) {
/* note: edit_opts() in room.c depends on this size */
*str = md_malloc(MAX_OPT_LEN + 2);
if (*str == NULL)
clean_up("out of memory");
(void)strlcpy(*str, dflt, MAX_OPT_LEN + 2);
}
}

841
inventory.c Normal file
View File

@@ -0,0 +1,841 @@
/* $NetBSD: inventory.c,v 1.15 2011/08/26 06:18:17 dholland Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)inventory.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: inventory.c,v 1.15 2011/08/26 06:18:17 dholland Exp $");
#endif
#endif /* not lint */
/*
* inventory.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include <stdarg.h>
#include "rogue.h"
boolean is_wood[WANDS];
const char *press_space = " --press space to continue--";
static const char *const wand_materials[WAND_MATERIALS] = {
"steel ",
"bronze ",
"gold ",
"silver ",
"copper ",
"nickel ",
"cobalt ",
"tin ",
"iron ",
"magnesium ",
"chrome ",
"carbon ",
"platinum ",
"silicon ",
"titanium ",
"teak ",
"oak ",
"cherry ",
"birch ",
"pine ",
"cedar ",
"redwood ",
"balsa ",
"ivory ",
"walnut ",
"maple ",
"mahogany ",
"elm ",
"palm ",
"wooden "
};
static const char *const gems[GEMS] = {
"diamond ",
"stibotantalite ",
"lapi-lazuli ",
"ruby ",
"emerald ",
"sapphire ",
"amethyst ",
"quartz ",
"tiger-eye ",
"opal ",
"agate ",
"turquoise ",
"pearl ",
"garnet "
};
static const char *const syllables[MAXSYLLABLES] = {
"blech ",
"foo ",
"barf ",
"rech ",
"bar ",
"blech ",
"quo ",
"bloto ",
"oh ",
"caca ",
"blorp ",
"erp ",
"festr ",
"rot ",
"slie ",
"snorf ",
"iky ",
"yuky ",
"ooze ",
"ah ",
"bahl ",
"zep ",
"druhl ",
"flem ",
"behil ",
"arek ",
"mep ",
"zihr ",
"grit ",
"kona ",
"kini ",
"ichi ",
"tims ",
"ogr ",
"oo ",
"ighr ",
"coph ",
"swerr ",
"mihln ",
"poxi "
};
#define COMS 48
struct id_com_s {
short com_char;
const char *com_desc;
};
static const struct id_com_s com_id_tab[COMS] = {
{'?', "? prints help"},
{'r', "r read scroll"},
{'/', "/ identify object"},
{'e', "e eat food"},
{'h', "h left "},
{'w', "w wield a weapon"},
{'j', "j down"},
{'W', "W wear armor"},
{'k', "k up"},
{'T', "T take armor off"},
{'l', "l right"},
{'P', "P put on ring"},
{'y', "y up & left"},
{'R', "R remove ring"},
{'u', "u up & right"},
{'d', "d drop object"},
{'b', "b down & left"},
{'c', "c call object"},
{'n', "n down & right"},
{'\0', "<SHIFT><dir>: run that way"},
{')', ") print current weapon"},
{'\0', "<CTRL><dir>: run till adjacent"},
{']', "] print current armor"},
{'f', "f<dir> fight till death or near death"},
{'=', "= print current rings"},
{'t', "t<dir> throw something"},
{'\001', "^A print Hp-raise average"},
{'m', "m<dir> move onto without picking up"},
{'z', "z<dir> zap a wand in a direction"},
{'o', "o examine/set options"},
{'^', "^<dir> identify trap type"},
{'\022', "^R redraw screen"},
{'&', "& save screen into 'rogue.screen'"},
{'s', "s search for trap/secret door"},
{'\020', "^P repeat last message"},
{'>', "> go down a staircase"},
{'\033', "^[ cancel command"},
{'<', "< go up a staircase"},
{'S', "S save game"},
{'.', ". rest for a turn"},
{'Q', "Q quit"},
{',', ", pick something up"},
{'!', "! shell escape"},
{'i', "i inventory"},
{'F', "F<dir> fight till either of you dies"},
{'I', "I inventory single item"},
{'v', "v print version number"},
{'q', "q quaff potion" }
};
static int get_com_id(int *, short);
static int pr_com_id(int);
static int pr_motion_char(int);
void
inventory(const object *pack, unsigned short mask)
{
object *obj;
short i = 0, j;
size_t maxlen = 0, n;
short row, col;
struct {
short letter;
short sepchar;
char desc[DCOLS];
char savebuf[DCOLS+8];
} descs[MAX_PACK_COUNT+1];
obj = pack->next_object;
if (!obj) {
messagef(0, "your pack is empty");
return;
}
while (obj) {
if (obj->what_is & mask) {
descs[i].letter = obj->ichar;
descs[i].sepchar = ((obj->what_is & ARMOR) && obj->is_protected)
? '}' : ')';
get_desc(obj, descs[i].desc, sizeof(descs[i].desc));
n = strlen(descs[i].desc) + 4;
if (n > maxlen) {
maxlen = n;
}
i++;
/*assert(i<=MAX_PACK_COUNT);*/
}
obj = obj->next_object;
}
if (maxlen < 27) maxlen = 27;
if (maxlen > DCOLS-2) maxlen = DCOLS-2;
col = DCOLS - (maxlen + 2);
for (row = 0; ((row <= i) && (row < DROWS)); row++) {
for (j = col; j < DCOLS; j++) {
descs[row].savebuf[j-col] = mvinch(row, j);
}
descs[row].savebuf[j-col] = 0;
if (row < i) {
mvprintw(row, col, " %c%c %s",
descs[row].letter, descs[row].sepchar,
descs[row].desc);
}
else {
mvaddstr(row, col, press_space);
}
clrtoeol();
}
refresh();
wait_for_ack();
move(0, 0);
clrtoeol();
for (j = 1; ((j <= i) && (j < DROWS)); j++) {
mvaddstr(j, col, descs[j].savebuf);
}
}
void
id_com(void)
{
int ch = 0;
short i, j, k;
while (ch != CANCEL) {
check_message();
messagef(0, "Character you want help for (* for all):");
refresh();
ch = getchar();
switch(ch) {
case LIST:
{
char save[(((COMS / 2) + (COMS % 2)) + 1)][DCOLS];
short rows = (((COMS / 2) + (COMS % 2)) + 1);
boolean need_two_screens = FALSE;
if (rows > LINES) {
need_two_screens = 1;
rows = LINES;
}
k = 0;
for (i = 0; i < rows; i++) {
for (j = 0; j < DCOLS; j++) {
save[i][j] = mvinch(i, j);
}
}
MORE:
for (i = 0; i < rows; i++) {
move(i, 0);
clrtoeol();
}
for (i = 0; i < (rows-1); i++) {
if (i < (LINES-1)) {
if (((i + i) < COMS) && ((i+i+k) < COMS)) {
mvaddstr(i, 0, com_id_tab[i+i+k].com_desc);
}
if (((i + i + 1) < COMS) && ((i+i+k+1) < COMS)) {
mvaddstr(i, (DCOLS/2),
com_id_tab[i+i+k+1].com_desc);
}
}
}
mvaddstr(rows - 1, 0, need_two_screens ? more : press_space);
refresh();
wait_for_ack();
if (need_two_screens) {
k += ((rows-1) * 2);
need_two_screens = 0;
goto MORE;
}
for (i = 0; i < rows; i++) {
move(i, 0);
for (j = 0; j < DCOLS; j++) {
addch(save[i][j]);
}
}
}
break;
default:
if (!pr_com_id(ch)) {
if (!pr_motion_char(ch)) {
check_message();
messagef(0, "unknown character");
}
}
ch = CANCEL;
break;
}
}
}
static int
pr_com_id(int ch)
{
int i;
if (!get_com_id(&i, ch)) {
return(0);
}
check_message();
messagef(0, "%s", com_id_tab[i].com_desc);
return(1);
}
static int
get_com_id(int *indexp, short ch)
{
short i;
for (i = 0; i < COMS; i++) {
if (com_id_tab[i].com_char == ch) {
*indexp = i;
return(1);
}
}
return(0);
}
static int
pr_motion_char(int ch)
{
if ( (ch == 'J') ||
(ch == 'K') ||
(ch == 'L') ||
(ch == 'H') ||
(ch == 'Y') ||
(ch == 'U') ||
(ch == 'N') ||
(ch == 'B') ||
(ch == '\012') ||
(ch == '\013') ||
(ch == '\010') ||
(ch == '\014') ||
(ch == '\025') ||
(ch == '\031') ||
(ch == '\016') ||
(ch == '\002')) {
const char *until;
int n = 0; /* XXX: GCC */
if (ch <= '\031') {
ch += 96;
until = " until adjacent";
} else {
ch += 32;
until = "";
}
(void)get_com_id(&n, ch);
check_message();
messagef(0, "run %s%s", com_id_tab[n].com_desc + 8, until);
return(1);
} else {
return(0);
}
}
void
mix_colors(void)
{
short i, j, k;
char t[MAX_ID_TITLE_LEN];
for (i = 0; i <= 32; i++) {
j = get_rand(0, (POTIONS - 1));
k = get_rand(0, (POTIONS - 1));
strlcpy(t, id_potions[j].title, sizeof(t));
strlcpy(id_potions[j].title, id_potions[k].title,
sizeof(id_potions[j].title));
strlcpy(id_potions[k].title, t, sizeof(id_potions[k].title));
}
}
void
make_scroll_titles(void)
{
short i, j, n;
short sylls, s;
size_t maxlen = sizeof(id_scrolls[0].title);
for (i = 0; i < SCROLS; i++) {
sylls = get_rand(2, 5);
(void)strlcpy(id_scrolls[i].title, "'", maxlen);
for (j = 0; j < sylls; j++) {
s = get_rand(1, (MAXSYLLABLES-1));
(void)strlcat(id_scrolls[i].title, syllables[s],
maxlen);
}
/* trim trailing space */
n = strlen(id_scrolls[i].title);
id_scrolls[i].title[n-1] = 0;
(void)strlcat(id_scrolls[i].title, "' ", maxlen);
}
}
struct sbuf {
char *buf;
size_t maxlen;
};
static void sbuf_init(struct sbuf *s, char *buf, size_t maxlen);
static void sbuf_addstr(struct sbuf *s, const char *str);
static void sbuf_addf(struct sbuf *s, const char *fmt, ...) __printflike(2,3);
static void desc_count(struct sbuf *s, int n);
static void desc_called(struct sbuf *s, const object *);
static
void
sbuf_init(struct sbuf *s, char *buf, size_t maxlen)
{
s->buf = buf;
s->maxlen = maxlen;
/*assert(maxlen>0);*/
s->buf[0] = 0;
}
static
void
sbuf_addstr(struct sbuf *s, const char *str)
{
strlcat(s->buf, str, s->maxlen);
}
static
void
sbuf_addf(struct sbuf *s, const char *fmt, ...)
{
va_list ap;
size_t initlen;
initlen = strlen(s->buf);
va_start(ap, fmt);
vsnprintf(s->buf+initlen, s->maxlen-initlen, fmt, ap);
va_end(ap);
}
static
void
desc_count(struct sbuf *s, int n)
{
if (n == 1) {
sbuf_addstr(s, "an ");
} else {
sbuf_addf(s, "%d ", n);
}
}
static
void
desc_called(struct sbuf *s, const object *obj)
{
struct id *id_table;
id_table = get_id_table(obj);
sbuf_addstr(s, name_of(obj));
sbuf_addstr(s, "called ");
sbuf_addstr(s, id_table[obj->which_kind].title);
}
void
get_desc(const object *obj, char *desc, size_t desclen)
{
const char *item_name;
struct id *id_table;
struct sbuf db;
unsigned short objtype_id_status;
if (obj->what_is == AMULET) {
(void)strlcpy(desc, "the amulet of Yendor ", desclen);
return;
}
if (obj->what_is == GOLD) {
snprintf(desc, desclen, "%d pieces of gold", obj->quantity);
return;
}
item_name = name_of(obj);
id_table = get_id_table(obj);
if (wizard || id_table == NULL) {
objtype_id_status = IDENTIFIED;
}
else {
objtype_id_status = id_table[obj->which_kind].id_status;
}
if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
if (obj->identified) {
objtype_id_status = IDENTIFIED;
}
}
sbuf_init(&db, desc, desclen);
switch (obj->what_is) {
case FOOD:
if (obj->which_kind == RATION) {
if (obj->quantity > 1) {
sbuf_addf(&db,
"%d rations of %s", obj->quantity,
item_name);
} else {
sbuf_addf(&db, "some %s", item_name);
}
} else {
sbuf_addf(&db, "an %s", item_name);
}
break;
case SCROL:
desc_count(&db, obj->quantity);
if (objtype_id_status==UNIDENTIFIED) {
sbuf_addstr(&db, item_name);
sbuf_addstr(&db, "entitled: ");
sbuf_addstr(&db, id_table[obj->which_kind].title);
} else if (objtype_id_status==CALLED) {
desc_called(&db, obj);
} else {
sbuf_addstr(&db, item_name);
sbuf_addstr(&db, id_table[obj->which_kind].real);
}
break;
case POTION:
desc_count(&db, obj->quantity);
if (objtype_id_status==UNIDENTIFIED) {
sbuf_addstr(&db, id_table[obj->which_kind].title);
sbuf_addstr(&db, item_name);
} else if (objtype_id_status==CALLED) {
desc_called(&db, obj);
} else {
sbuf_addstr(&db, item_name);
sbuf_addstr(&db, id_table[obj->which_kind].real);
}
break;
case WAND:
desc_count(&db, obj->quantity);
if (objtype_id_status==UNIDENTIFIED) {
sbuf_addstr(&db, id_table[obj->which_kind].title);
sbuf_addstr(&db, item_name);
} else if (objtype_id_status==CALLED) {
desc_called(&db, obj);
} else {
sbuf_addstr(&db, item_name);
sbuf_addstr(&db, id_table[obj->which_kind].real);
if (wizard || obj->identified) {
sbuf_addf(&db, "[%d]", obj->class);
}
}
break;
case RING:
desc_count(&db, obj->quantity);
if (objtype_id_status==UNIDENTIFIED) {
sbuf_addstr(&db, id_table[obj->which_kind].title);
sbuf_addstr(&db, item_name);
} else if (objtype_id_status==CALLED) {
desc_called(&db, obj);
} else {
if ((wizard || obj->identified) &&
(obj->which_kind == DEXTERITY ||
obj->which_kind == ADD_STRENGTH)) {
sbuf_addf(&db, "%+d ", obj->class);
}
sbuf_addstr(&db, item_name);
sbuf_addstr(&db, id_table[obj->which_kind].real);
}
break;
case ARMOR:
/* no desc_count() */
if (objtype_id_status==UNIDENTIFIED) {
sbuf_addstr(&db, id_table[obj->which_kind].title);
} else {
sbuf_addf(&db, "%+d %s[%d] ", obj->d_enchant,
id_table[obj->which_kind].title,
get_armor_class(obj));
}
break;
case WEAPON:
desc_count(&db, obj->quantity);
if (objtype_id_status==UNIDENTIFIED) {
sbuf_addstr(&db, name_of(obj));
} else {
sbuf_addf(&db, "%+d,%+d %s",
obj->hit_enchant, obj->d_enchant,
name_of(obj));
}
break;
}
if (obj->in_use_flags & BEING_WIELDED) {
sbuf_addstr(&db, "in hand");
} else if (obj->in_use_flags & BEING_WORN) {
sbuf_addstr(&db, "being worn");
} else if (obj->in_use_flags & ON_LEFT_HAND) {
sbuf_addstr(&db, "on left hand");
} else if (obj->in_use_flags & ON_RIGHT_HAND) {
sbuf_addstr(&db, "on right hand");
}
if (!strncmp(db.buf, "an ", 3)) {
if (!is_vowel(db.buf[3])) {
memmove(db.buf+2, db.buf+3, strlen(db.buf+3)+1);
db.buf[1] = ' ';
}
}
}
void
get_wand_and_ring_materials(void)
{
short i, j;
boolean used[WAND_MATERIALS];
for (i = 0; i < WAND_MATERIALS; i++) {
used[i] = 0;
}
for (i = 0; i < WANDS; i++) {
do {
j = get_rand(0, WAND_MATERIALS-1);
} while (used[j]);
used[j] = 1;
(void)strlcpy(id_wands[i].title, wand_materials[j],
sizeof(id_wands[i].title));
is_wood[i] = (j > MAX_METAL);
}
for (i = 0; i < GEMS; i++) {
used[i] = 0;
}
for (i = 0; i < RINGS; i++) {
do {
j = get_rand(0, GEMS-1);
} while (used[j]);
used[j] = 1;
(void)strlcpy(id_rings[i].title, gems[j],
sizeof(id_rings[i].title));
}
}
void
single_inv(short ichar)
{
short ch, ch2;
char desc[DCOLS];
object *obj;
ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS);
if (ch == CANCEL) {
return;
}
if (!(obj = get_letter_object(ch))) {
messagef(0, "no such item.");
return;
}
ch2 = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')';
get_desc(obj, desc, sizeof(desc));
messagef(0, "%c%c %s", ch, ch2, desc);
}
struct id *
get_id_table(const object *obj)
{
switch(obj->what_is) {
case SCROL:
return(id_scrolls);
case POTION:
return(id_potions);
case WAND:
return(id_wands);
case RING:
return(id_rings);
case WEAPON:
return(id_weapons);
case ARMOR:
return(id_armors);
}
return((struct id *)0);
}
void
inv_armor_weapon(boolean is_weapon)
{
if (is_weapon) {
if (rogue.weapon) {
single_inv(rogue.weapon->ichar);
} else {
messagef(0, "not wielding anything");
}
} else {
if (rogue.armor) {
single_inv(rogue.armor->ichar);
} else {
messagef(0, "not wearing anything");
}
}
}
void
id_type(void)
{
const char *id;
int ch;
messagef(0, "what do you want identified?");
ch = rgetchar();
if ((ch >= 'A') && (ch <= 'Z')) {
id = m_names[ch-'A'];
} else if (ch < 32) {
check_message();
return;
} else {
switch(ch) {
case '@':
id = "you";
break;
case '%':
id = "staircase";
break;
case '^':
id = "trap";
break;
case '+':
id = "door";
break;
case '-':
case '|':
id = "wall of a room";
break;
case '.':
id = "floor";
break;
case '#':
id = "passage";
break;
case ' ':
id = "solid rock";
break;
case '=':
id = "ring";
break;
case '?':
id = "scroll";
break;
case '!':
id = "potion";
break;
case '/':
id = "wand or staff";
break;
case ')':
id = "weapon";
break;
case ']':
id = "armor";
break;
case '*':
id = "gold";
break;
case ':':
id = "food";
break;
case ',':
id = "the Amulet of Yendor";
break;
default:
id = "unknown character";
break;
}
}
check_message();
messagef(0, "'%c': %s", ch, id);
}

900
level.c Normal file
View File

@@ -0,0 +1,900 @@
/* $NetBSD: level.c,v 1.10 2008/01/14 03:50:01 dholland Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)level.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: level.c,v 1.10 2008/01/14 03:50:01 dholland Exp $");
#endif
#endif /* not lint */
/*
* level.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include "rogue.h"
#define SWAP(x,y) (t = (x), (x) = (y), (y) = t)
static void add_mazes(void);
static int connect_rooms(short, short);
static void draw_simple_passage(short, short, short, short, short);
static void fill_it(int, boolean);
static void fill_out_level(void);
static int get_exp_level(long);
static void hide_boxed_passage(short, short, short, short, short);
static void make_maze(short, short, short, short, short, short);
static void make_room(short, short, short, short);
static boolean mask_room(short, short *, short *, unsigned short);
static void mix_random_rooms(void);
static void put_door(room *, short, short *, short *);
static void recursive_deadend(short, const short *, short, short);
static int same_col(int, int);
static int same_row(int, int);
short cur_level = 0;
short max_level = 1;
short cur_room;
const char *new_level_message = NULL;
short party_room = NO_ROOM;
static short r_de;
const long level_points[MAX_EXP_LEVEL] = {
10L,
20L,
40L,
80L,
160L,
320L,
640L,
1300L,
2600L,
5200L,
10000L,
20000L,
40000L,
80000L,
160000L,
320000L,
1000000L,
3333333L,
6666666L,
MAX_EXP,
99900000L
};
static short random_rooms[MAXROOMS] = {3, 7, 5, 2, 0, 6, 1, 4, 8};
void
make_level(void)
{
short i, j;
short must_1, must_2, must_3;
boolean big_room;
must_2 = must_3 = 0;
if (cur_level < LAST_DUNGEON) {
cur_level++;
}
if (cur_level > max_level) {
max_level = cur_level;
}
must_1 = get_rand(0, 5);
switch(must_1) {
case 0:
must_1 = 0;
must_2 = 1;
must_3 = 2;
break;
case 1:
must_1 = 3;
must_2 = 4;
must_3 = 5;
break;
case 2:
must_1 = 6;
must_2 = 7;
must_3 = 8;
break;
case 3:
must_1 = 0;
must_2 = 3;
must_3 = 6;
break;
case 4:
must_1 = 1;
must_2 = 4;
must_3 = 7;
break;
case 5:
must_1 = 2;
must_2 = 5;
must_3 = 8;
break;
}
if (rand_percent(8)) {
party_room = 0;
}
big_room = ((party_room != NO_ROOM) && rand_percent(1));
if (big_room) {
make_room(BIG_ROOM, 0, 0, 0);
} else {
for (i = 0; i < MAXROOMS; i++) {
make_room(i, must_1, must_2, must_3);
}
}
if (!big_room) {
add_mazes();
mix_random_rooms();
for (j = 0; j < MAXROOMS; j++) {
i = random_rooms[j];
if (i < (MAXROOMS-1)) {
(void)connect_rooms(i, i+1);
}
if (i < (MAXROOMS-3)) {
(void)connect_rooms(i, i+3);
}
if (i < (MAXROOMS-2)) {
if (rooms[i+1].is_room & R_NOTHING) {
if (connect_rooms(i, i+2)) {
rooms[i+1].is_room = R_CROSS;
}
}
}
if (i < (MAXROOMS-6)) {
if (rooms[i+3].is_room & R_NOTHING) {
if (connect_rooms(i, i+6)) {
rooms[i+3].is_room = R_CROSS;
}
}
}
if (is_all_connected()) {
break;
}
}
fill_out_level();
}
if (!has_amulet() && (cur_level >= AMULET_LEVEL)) {
put_amulet();
}
}
static void
make_room(short rn, short r1, short r2, short r3)
{
short left_col, right_col, top_row, bottom_row;
short width, height;
short row_offset, col_offset;
short i, j, ch;
left_col = right_col = top_row = bottom_row = 0;
switch(rn) {
case 0:
left_col = 0;
right_col = COL1-1;
top_row = MIN_ROW;
bottom_row = ROW1-1;
break;
case 1:
left_col = COL1+1;
right_col = COL2-1;
top_row = MIN_ROW;
bottom_row = ROW1-1;
break;
case 2:
left_col = COL2+1;
right_col = DCOLS-1;
top_row = MIN_ROW;
bottom_row = ROW1-1;
break;
case 3:
left_col = 0;
right_col = COL1-1;
top_row = ROW1+1;
bottom_row = ROW2-1;
break;
case 4:
left_col = COL1+1;
right_col = COL2-1;
top_row = ROW1+1;
bottom_row = ROW2-1;
break;
case 5:
left_col = COL2+1;
right_col = DCOLS-1;
top_row = ROW1+1;
bottom_row = ROW2-1;
break;
case 6:
left_col = 0;
right_col = COL1-1;
top_row = ROW2+1;
bottom_row = DROWS - 2;
break;
case 7:
left_col = COL1+1;
right_col = COL2-1;
top_row = ROW2+1;
bottom_row = DROWS - 2;
break;
case 8:
left_col = COL2+1;
right_col = DCOLS-1;
top_row = ROW2+1;
bottom_row = DROWS - 2;
break;
case BIG_ROOM:
top_row = get_rand(MIN_ROW, MIN_ROW+5);
bottom_row = get_rand(DROWS-7, DROWS-2);
left_col = get_rand(0, 10);
right_col = get_rand(DCOLS-11, DCOLS-1);
rn = 0;
goto B;
}
height = get_rand(4, (bottom_row - top_row + 1));
width = get_rand(7, (right_col - left_col - 2));
row_offset = get_rand(0, ((bottom_row - top_row) - height + 1));
col_offset = get_rand(0, ((right_col - left_col) - width + 1));
top_row += row_offset;
bottom_row = top_row + height - 1;
left_col += col_offset;
right_col = left_col + width - 1;
if ((rn != r1) && (rn != r2) && (rn != r3) && rand_percent(40)) {
goto END;
}
B:
rooms[rn].is_room = R_ROOM;
for (i = top_row; i <= bottom_row; i++) {
for (j = left_col; j <= right_col; j++) {
if ((i == top_row) || (i == bottom_row)) {
ch = HORWALL;
} else if ( ((i != top_row) && (i != bottom_row)) &&
((j == left_col) || (j == right_col))) {
ch = VERTWALL;
} else {
ch = FLOOR;
}
dungeon[i][j] = ch;
}
}
END:
rooms[rn].top_row = top_row;
rooms[rn].bottom_row = bottom_row;
rooms[rn].left_col = left_col;
rooms[rn].right_col = right_col;
}
static int
connect_rooms(short room1, short room2)
{
short row1, col1, row2, col2, dir;
if ((!(rooms[room1].is_room & (R_ROOM | R_MAZE))) ||
(!(rooms[room2].is_room & (R_ROOM | R_MAZE)))) {
return(0);
}
if (same_row(room1, room2) &&
(rooms[room1].left_col > rooms[room2].right_col)) {
put_door(&rooms[room1], LEFT, &row1, &col1);
put_door(&rooms[room2], RIGHT, &row2, &col2);
dir = LEFT;
} else if (same_row(room1, room2) &&
(rooms[room2].left_col > rooms[room1].right_col)) {
put_door(&rooms[room1], RIGHT, &row1, &col1);
put_door(&rooms[room2], LEFT, &row2, &col2);
dir = RIGHT;
} else if (same_col(room1, room2) &&
(rooms[room1].top_row > rooms[room2].bottom_row)) {
put_door(&rooms[room1], UPWARD, &row1, &col1);
put_door(&rooms[room2], DOWN, &row2, &col2);
dir = UPWARD;
} else if (same_col(room1, room2) &&
(rooms[room2].top_row > rooms[room1].bottom_row)) {
put_door(&rooms[room1], DOWN, &row1, &col1);
put_door(&rooms[room2], UPWARD, &row2, &col2);
dir = DOWN;
} else {
return(0);
}
do {
draw_simple_passage(row1, col1, row2, col2, dir);
} while (rand_percent(4));
rooms[room1].doors[dir/2].oth_room = room2;
rooms[room1].doors[dir/2].oth_row = row2;
rooms[room1].doors[dir/2].oth_col = col2;
rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_room = room1;
rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_row = row1;
rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_col = col1;
return(1);
}
void
clear_level(void)
{
short i, j;
for (i = 0; i < MAXROOMS; i++) {
rooms[i].is_room = R_NOTHING;
for (j = 0; j < 4; j++) {
rooms[i].doors[j].oth_room = NO_ROOM;
}
}
for (i = 0; i < MAX_TRAPS; i++) {
traps[i].trap_type = NO_TRAP;
}
for (i = 0; i < DROWS; i++) {
for (j = 0; j < DCOLS; j++) {
dungeon[i][j] = NOTHING;
}
}
detect_monster = see_invisible = 0;
being_held = bear_trap = 0;
party_room = NO_ROOM;
rogue.row = rogue.col = -1;
clear();
}
static void
put_door(room *rm, short dir, short *row, short *col)
{
short wall_width;
wall_width = (rm->is_room & R_MAZE) ? 0 : 1;
switch(dir) {
case UPWARD:
case DOWN:
*row = ((dir == UPWARD) ? rm->top_row : rm->bottom_row);
do {
*col = get_rand(rm->left_col+wall_width,
rm->right_col-wall_width);
} while (!(dungeon[*row][*col] & (HORWALL | TUNNEL)));
break;
case RIGHT:
case LEFT:
*col = (dir == LEFT) ? rm->left_col : rm->right_col;
do {
*row = get_rand(rm->top_row+wall_width,
rm->bottom_row-wall_width);
} while (!(dungeon[*row][*col] & (VERTWALL | TUNNEL)));
break;
}
if (rm->is_room & R_ROOM) {
dungeon[*row][*col] = DOOR;
}
if ((cur_level > 2) && rand_percent(HIDE_PERCENT)) {
dungeon[*row][*col] |= HIDDEN;
}
rm->doors[dir/2].door_row = *row;
rm->doors[dir/2].door_col = *col;
}
static void
draw_simple_passage(short row1, short col1, short row2, short col2, short dir)
{
short i, middle, t;
if ((dir == LEFT) || (dir == RIGHT)) {
if (col1 > col2) {
SWAP(row1, row2);
SWAP(col1, col2);
}
middle = get_rand(col1+1, col2-1);
for (i = col1+1; i != middle; i++) {
dungeon[row1][i] = TUNNEL;
}
for (i = row1; i != row2; i += (row1 > row2) ? -1 : 1) {
dungeon[i][middle] = TUNNEL;
}
for (i = middle; i != col2; i++) {
dungeon[row2][i] = TUNNEL;
}
} else {
if (row1 > row2) {
SWAP(row1, row2);
SWAP(col1, col2);
}
middle = get_rand(row1+1, row2-1);
for (i = row1+1; i != middle; i++) {
dungeon[i][col1] = TUNNEL;
}
for (i = col1; i != col2; i += (col1 > col2) ? -1 : 1) {
dungeon[middle][i] = TUNNEL;
}
for (i = middle; i != row2; i++) {
dungeon[i][col2] = TUNNEL;
}
}
if (rand_percent(HIDE_PERCENT)) {
hide_boxed_passage(row1, col1, row2, col2, 1);
}
}
static int
same_row(int room1, int room2)
{
return((room1 / 3) == (room2 / 3));
}
static int
same_col(int room1, int room2)
{
return((room1 % 3) == (room2 % 3));
}
static void
add_mazes(void)
{
short i, j;
short start;
short maze_percent;
if (cur_level > 1) {
start = get_rand(0, (MAXROOMS-1));
maze_percent = (cur_level * 5) / 4;
if (cur_level > 15) {
maze_percent += cur_level;
}
for (i = 0; i < MAXROOMS; i++) {
j = ((start + i) % MAXROOMS);
if (rooms[j].is_room & R_NOTHING) {
if (rand_percent(maze_percent)) {
rooms[j].is_room = R_MAZE;
make_maze(get_rand(rooms[j].top_row+1, rooms[j].bottom_row-1),
get_rand(rooms[j].left_col+1, rooms[j].right_col-1),
rooms[j].top_row, rooms[j].bottom_row,
rooms[j].left_col, rooms[j].right_col);
hide_boxed_passage(rooms[j].top_row, rooms[j].left_col,
rooms[j].bottom_row, rooms[j].right_col,
get_rand(0, 2));
}
}
}
}
}
static void
fill_out_level(void)
{
short i, rn;
mix_random_rooms();
r_de = NO_ROOM;
for (i = 0; i < MAXROOMS; i++) {
rn = random_rooms[i];
if ((rooms[rn].is_room & R_NOTHING) ||
((rooms[rn].is_room & R_CROSS) && coin_toss())) {
fill_it(rn, 1);
}
}
if (r_de != NO_ROOM) {
fill_it(r_de, 0);
}
}
static void
fill_it(int rn, boolean do_rec_de)
{
short i, tunnel_dir, door_dir, drow, dcol;
short target_room, rooms_found = 0;
short srow, scol, t;
static short offsets[4] = {-1, 1, 3, -3};
boolean did_this = 0;
for (i = 0; i < 10; i++) {
srow = get_rand(0, 3);
scol = get_rand(0, 3);
t = offsets[srow];
offsets[srow] = offsets[scol];
offsets[scol] = t;
}
for (i = 0; i < 4; i++) {
target_room = rn + offsets[i];
if (((target_room < 0) || (target_room >= MAXROOMS)) ||
(!(same_row(rn,target_room) || same_col(rn,target_room))) ||
(!(rooms[target_room].is_room & (R_ROOM | R_MAZE)))) {
continue;
}
if (same_row(rn, target_room)) {
tunnel_dir = (rooms[rn].left_col < rooms[target_room].left_col) ?
RIGHT : LEFT;
} else {
tunnel_dir = (rooms[rn].top_row < rooms[target_room].top_row) ?
DOWN : UPWARD;
}
door_dir = ((tunnel_dir + 4) % DIRS);
if (rooms[target_room].doors[door_dir/2].oth_room != NO_ROOM) {
continue;
}
if (((!do_rec_de) || did_this) ||
(!mask_room(rn, &srow, &scol, TUNNEL))) {
srow = (rooms[rn].top_row + rooms[rn].bottom_row) / 2;
scol = (rooms[rn].left_col + rooms[rn].right_col) / 2;
}
put_door(&rooms[target_room], door_dir, &drow, &dcol);
rooms_found++;
draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
rooms[rn].is_room = R_DEADEND;
dungeon[srow][scol] = TUNNEL;
if ((i < 3) && (!did_this)) {
did_this = 1;
if (coin_toss()) {
continue;
}
}
if ((rooms_found < 2) && do_rec_de) {
recursive_deadend(rn, offsets, srow, scol);
}
break;
}
}
static void
recursive_deadend(short rn, const short *offsets, short srow, short scol)
{
short i, de;
short drow, dcol, tunnel_dir;
rooms[rn].is_room = R_DEADEND;
dungeon[srow][scol] = TUNNEL;
for (i = 0; i < 4; i++) {
de = rn + offsets[i];
if (((de < 0) || (de >= MAXROOMS)) ||
(!(same_row(rn, de) || same_col(rn, de)))) {
continue;
}
if (!(rooms[de].is_room & R_NOTHING)) {
continue;
}
drow = (rooms[de].top_row + rooms[de].bottom_row) / 2;
dcol = (rooms[de].left_col + rooms[de].right_col) / 2;
if (same_row(rn, de)) {
tunnel_dir = (rooms[rn].left_col < rooms[de].left_col) ?
RIGHT : LEFT;
} else {
tunnel_dir = (rooms[rn].top_row < rooms[de].top_row) ?
DOWN : UPWARD;
}
draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
r_de = de;
recursive_deadend(de, offsets, drow, dcol);
}
}
static boolean
mask_room(short rn, short *row, short *col, unsigned short mask)
{
short i, j;
for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) {
for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) {
if (dungeon[i][j] & mask) {
*row = i;
*col = j;
return(1);
}
}
}
return(0);
}
static void
make_maze(short r, short c, short tr, short br, short lc, short rc)
{
char dirs[4];
short i, t;
dirs[0] = UPWARD;
dirs[1] = DOWN;
dirs[2] = LEFT;
dirs[3] = RIGHT;
dungeon[r][c] = TUNNEL;
if (rand_percent(20)) {
for (i = 0; i < 10; i++) {
short t1, t2;
t1 = get_rand(0, 3);
t2 = get_rand(0, 3);
SWAP(dirs[t1], dirs[t2]);
}
}
for (i = 0; i < 4; i++) {
switch(dirs[i]) {
case UPWARD:
if (((r-1) >= tr) &&
(dungeon[r-1][c] != TUNNEL) &&
(dungeon[r-1][c-1] != TUNNEL) &&
(dungeon[r-1][c+1] != TUNNEL) &&
(dungeon[r-2][c] != TUNNEL)) {
make_maze((r-1), c, tr, br, lc, rc);
}
break;
case DOWN:
if (((r+1) <= br) &&
(dungeon[r+1][c] != TUNNEL) &&
(dungeon[r+1][c-1] != TUNNEL) &&
(dungeon[r+1][c+1] != TUNNEL) &&
(dungeon[r+2][c] != TUNNEL)) {
make_maze((r+1), c, tr, br, lc, rc);
}
break;
case LEFT:
if (((c-1) >= lc) &&
(dungeon[r][c-1] != TUNNEL) &&
(dungeon[r-1][c-1] != TUNNEL) &&
(dungeon[r+1][c-1] != TUNNEL) &&
(dungeon[r][c-2] != TUNNEL)) {
make_maze(r, (c-1), tr, br, lc, rc);
}
break;
case RIGHT:
if (((c+1) <= rc) &&
(dungeon[r][c+1] != TUNNEL) &&
(dungeon[r-1][c+1] != TUNNEL) &&
(dungeon[r+1][c+1] != TUNNEL) &&
(dungeon[r][c+2] != TUNNEL)) {
make_maze(r, (c+1), tr, br, lc, rc);
}
break;
}
}
}
static void
hide_boxed_passage(short row1, short col1, short row2, short col2, short n)
{
short i, j, t;
short row, col, row_cut, col_cut;
short h, w;
if (cur_level > 2) {
if (row1 > row2) {
SWAP(row1, row2);
}
if (col1 > col2) {
SWAP(col1, col2);
}
h = row2 - row1;
w = col2 - col1;
if ((w >= 5) || (h >= 5)) {
row_cut = ((h >= 2) ? 1 : 0);
col_cut = ((w >= 2) ? 1 : 0);
for (i = 0; i < n; i++) {
for (j = 0; j < 10; j++) {
row = get_rand(row1 + row_cut, row2 - row_cut);
col = get_rand(col1 + col_cut, col2 - col_cut);
if (dungeon[row][col] == TUNNEL) {
dungeon[row][col] |= HIDDEN;
break;
}
}
}
}
}
}
/*
* try not to put in room NR
*/
void
put_player(short nr)
{
short rn = nr, misses;
short row, col;
for (misses = 0; ((misses < 2) && (rn == nr)); misses++) {
gr_row_col(&row, &col, (FLOOR | TUNNEL | OBJECT | STAIRS));
rn = get_room_number(row, col);
}
rogue.row = row;
rogue.col = col;
if (dungeon[rogue.row][rogue.col] & TUNNEL) {
cur_room = PASSAGE;
} else {
cur_room = rn;
}
if (cur_room != PASSAGE) {
light_up_room(cur_room);
} else {
light_passage(rogue.row, rogue.col);
}
rn = get_room_number(rogue.row, rogue.col);
wake_room(rn, 1, rogue.row, rogue.col);
if (new_level_message) {
messagef(0, "%s", new_level_message);
new_level_message = NULL;
}
mvaddch(rogue.row, rogue.col, rogue.fchar);
}
int
drop_check(void)
{
if (wizard) {
return(1);
}
if (dungeon[rogue.row][rogue.col] & STAIRS) {
if (levitate) {
messagef(0, "you're floating in the air!");
return(0);
}
return(1);
}
messagef(0, "I see no way down");
return(0);
}
int
check_up(void)
{
if (!wizard) {
if (!(dungeon[rogue.row][rogue.col] & STAIRS)) {
messagef(0, "I see no way up");
return(0);
}
if (!has_amulet()) {
messagef(0, "your way is magically blocked");
return(0);
}
}
new_level_message = "you feel a wrenching sensation in your gut";
if (cur_level == 1) {
win();
} else {
cur_level -= 2;
return(1);
}
return(0);
}
void
add_exp(int e, boolean promotion)
{
short new_exp;
short i, hp;
rogue.exp_points += e;
if (rogue.exp_points >= level_points[rogue.exp-1]) {
new_exp = get_exp_level(rogue.exp_points);
if (rogue.exp_points > MAX_EXP) {
rogue.exp_points = MAX_EXP + 1;
}
for (i = rogue.exp+1; i <= new_exp; i++) {
messagef(0, "welcome to level %d", i);
if (promotion) {
hp = hp_raise();
rogue.hp_current += hp;
rogue.hp_max += hp;
}
rogue.exp = i;
print_stats(STAT_HP | STAT_EXP);
}
} else {
print_stats(STAT_EXP);
}
}
static int
get_exp_level(long e)
{
short i;
for (i = 0; i < (MAX_EXP_LEVEL - 1); i++) {
if (level_points[i] > e) {
break;
}
}
return(i+1);
}
int
hp_raise(void)
{
int hp;
hp = (wizard ? 10 : get_rand(3, 10));
return(hp);
}
void
show_average_hp(void)
{
float real_average;
float effective_average;
if (rogue.exp == 1) {
real_average = effective_average = 0.00;
} else {
real_average = (float)
((rogue.hp_max - extra_hp - INIT_HP) + less_hp) / (rogue.exp - 1);
effective_average = (float)(rogue.hp_max - INIT_HP) / (rogue.exp - 1);
}
messagef(0, "R-Hp: %.2f, E-Hp: %.2f (!: %d, V: %d)", real_average,
effective_average, extra_hp, less_hp);
}
static void
mix_random_rooms(void)
{
short i, t;
short x, y;
for (i = 0; i < (3 * MAXROOMS); i++) {
do {
x = get_rand(0, (MAXROOMS-1));
y = get_rand(0, (MAXROOMS-1));
} while (x == y);
SWAP(random_rooms[x], random_rooms[y]);
}
}

492
machdep.c Normal file
View File

@@ -0,0 +1,492 @@
/* $NetBSD: machdep.c,v 1.20 2012/12/01 11:37:27 mbalmer Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)machdep.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: machdep.c,v 1.20 2012/12/01 11:37:27 mbalmer Exp $");
#endif
#endif /* not lint */
/*
* machdep.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
/* Included in this file are all system dependent routines. Extensive use
* of #ifdef's will be used to compile the appropriate code on each system:
*
* UNIX: all UNIX systems.
* UNIX_BSD4_2: UNIX BSD 4.2 and later, UTEK, (4.1 BSD too?)
* UNIX_SYSV: UNIX system V
* UNIX_V7: UNIX version 7
*
* All UNIX code should be included between the single "#ifdef UNIX" at the
* top of this file, and the "#endif" at the bottom.
*
* To change a routine to include a new UNIX system, simply #ifdef the
* existing routine, as in the following example:
*
* To make a routine compatible with UNIX system 5, change the first
* function to the second:
*
* md_function()
* {
* code;
* }
*
* md_function()
* {
* #ifdef UNIX_SYSV
* sys5code;
* #else
* code;
* #endif
* }
*
* Appropriate variations of this are of course acceptable.
* The use of "#elseif" is discouraged because of non-portability.
* If the correct #define doesn't exist, "UNIX_SYSV" in this case, make it up
* and insert it in the list at the top of the file. Alter the CFLAGS
* in you Makefile appropriately.
*
*/
#ifdef UNIX
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <pwd.h>
#ifdef UNIX_BSD4_2
#include <sys/time.h>
#endif
#ifdef UNIX_SYSV
#include <time.h>
#endif
#include <signal.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include "rogue.h"
#include "pathnames.h"
/* md_slurp:
*
* This routine throws away all keyboard input that has not
* yet been read. It is used to get rid of input that the user may have
* typed-ahead.
*
* This function is not necessary, so it may be stubbed. The might cause
* message-line output to flash by because the game has continued to read
* input without waiting for the user to read the message. Not such a
* big deal.
*/
void
md_slurp(void)
{
(void)fpurge(stdin);
}
/* md_heed_signals():
*
* This routine tells the program to call particular routines when
* certain interrupts/events occur:
*
* SIGINT: call onintr() to interrupt fight with monster or long rest.
* SIGQUIT: call byebye() to check for game termination.
* SIGHUP: call error_save() to save game when terminal hangs up.
*
* On VMS, SIGINT and SIGQUIT correspond to ^C and ^Y.
*
* This routine is not strictly necessary and can be stubbed. This will
* mean that the game cannot be interrupted properly with keyboard
* input, this is not usually critical.
*/
void
md_heed_signals(void)
{
signal(SIGINT, onintr);
signal(SIGQUIT, byebye);
signal(SIGHUP, error_save);
}
/* md_ignore_signals():
*
* This routine tells the program to completely ignore the events mentioned
* in md_heed_signals() above. The event handlers will later be turned on
* by a future call to md_heed_signals(), so md_heed_signals() and
* md_ignore_signals() need to work together.
*
* This function should be implemented or the user risks interrupting
* critical sections of code, which could cause score file, or saved-game
* file, corruption.
*/
void
md_ignore_signals(void)
{
signal(SIGQUIT, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
}
/* md_get_file_id():
*
* This function returns an integer that uniquely identifies the specified
* file. It need not check for the file's existence. In UNIX, the inode
* number is used.
*
* This function is used to identify saved-game files.
*/
int
md_get_file_id(const char *fname)
{
struct stat sbuf;
if (stat(fname, &sbuf)) {
return(-1);
}
return((int)sbuf.st_ino);
}
/* md_link_count():
*
* This routine returns the number of hard links to the specified file.
*
* This function is not strictly necessary. On systems without hard links
* this routine can be stubbed by just returning 1.
*/
int
md_link_count(const char *fname)
{
struct stat sbuf;
stat(fname, &sbuf);
return((int)sbuf.st_nlink);
}
/* md_gct(): (Get Current Time)
*
* This function returns the current year, month(1-12), day(1-31), hour(0-23),
* minute(0-59), and second(0-59). This is used for identifying the time
* at which a game is saved.
*
* This function is not strictly necessary. It can be stubbed by returning
* zeros instead of the correct year, month, etc. If your operating
* system doesn't provide all of the time units requested here, then you
* can provide only those that it does, and return zeros for the others.
* If you cannot provide good time values, then users may be able to copy
* saved-game files and play them.
*/
void
md_gct(struct rogue_time *rt_buf)
{
struct tm *t;
time_t seconds;
time(&seconds);
t = localtime(&seconds);
rt_buf->year = t->tm_year;
rt_buf->month = t->tm_mon + 1;
rt_buf->day = t->tm_mday;
rt_buf->hour = t->tm_hour;
rt_buf->minute = t->tm_min;
rt_buf->second = t->tm_sec;
}
/* md_gfmt: (Get File Modification Time)
*
* This routine returns a file's date of last modification in the same format
* as md_gct() above.
*
* This function is not strictly necessary. It is used to see if saved-game
* files have been modified since they were saved. If you have stubbed the
* routine md_gct() above by returning constant values, then you may do
* exactly the same here.
* Or if md_gct() is implemented correctly, but your system does not provide
* file modification dates, you may return some date far in the past so
* that the program will never know that a saved-game file being modified.
* You may also do this if you wish to be able to restore games from
* saved-games that have been modified.
*/
void
md_gfmt(const char *fname, struct rogue_time *rt_buf)
{
struct stat sbuf;
time_t seconds;
struct tm *t;
stat(fname, &sbuf);
seconds = sbuf.st_mtime;
t = localtime(&seconds);
rt_buf->year = t->tm_year;
rt_buf->month = t->tm_mon + 1;
rt_buf->day = t->tm_mday;
rt_buf->hour = t->tm_hour;
rt_buf->minute = t->tm_min;
rt_buf->second = t->tm_sec;
}
/* md_df: (Delete File)
*
* This function deletes the specified file, and returns true (1) if the
* operation was successful. This is used to delete saved-game files
* after restoring games from them.
*
* Again, this function is not strictly necessary, and can be stubbed
* by simply returning 1. In this case, saved-game files will not be
* deleted and can be replayed.
*/
boolean
md_df(const char *fname)
{
if (unlink(fname)) {
return(0);
}
return(1);
}
/* md_gln: (Get login name)
*
* This routine returns the login name of the user. This string is
* used mainly for identifying users in score files.
*
* A dummy string may be returned if you are unable to implement this
* function, but then the score file would only have one name in it.
*/
const char *
md_gln(void)
{
struct passwd *p;
if (!(p = getpwuid(getuid())))
return NULL;
return p->pw_name;
}
/* md_sleep:
*
* This routine causes the game to pause for the specified number of
* seconds.
*
* This routine is not particularly necessary at all. It is used for
* delaying execution, which is useful to this program at some times.
*/
void
md_sleep(int nsecs)
{
(void)sleep(nsecs);
}
/* md_getenv()
*
* This routine gets certain values from the user's environment. These
* values are strings, and each string is identified by a name. The names
* of the values needed, and their use, is as follows:
*
* ROGUEOPTS
* A string containing the various game options. This need not be
* defined.
* HOME
* The user's home directory. This is only used when the user specifies
* '~' as the first character of a saved-game file. This string need
* not be defined.
* SHELL
* The user's favorite shell. If not found, "/bin/sh" is assumed.
*
* If your system does not provide a means of searching for these values,
* you will have to do it yourself. None of the values above really need
* to be defined; you can get by with simply always returning zero.
* Returning zero indicates that their is no defined value for the
* given string.
*/
char *
md_getenv(const char *name)
{
char *value;
value = getenv(name);
return(value);
}
/* md_malloc()
*
* This routine allocates, and returns a pointer to, the specified number
* of bytes. This routines absolutely MUST be implemented for your
* particular system or the program will not run at all. Return zero
* when no more memory can be allocated.
*/
void *
md_malloc(size_t n)
{
char *t;
t = malloc(n);
return(t);
}
/* md_gseed() (Get Seed)
*
* This function returns a seed for the random number generator (RNG). This
* seed causes the RNG to begin generating numbers at some point in its
* sequence. Without a random seed, the RNG will generate the same set
* of numbers, and every game will start out exactly the same way. A good
* number to use is the process id, given by getpid() on most UNIX systems.
*
* You need to find some single random integer, such as:
* process id.
* current time (minutes + seconds) returned from md_gct(), if implemented.
*
* It will not help to return "get_rand()" or "rand()" or the return value of
* any pseudo-RNG. If you don't have a random number, you can just return 1,
* but this means your games will ALWAYS start the same way, and will play
* exactly the same way given the same input.
*/
int
md_gseed(void)
{
time_t seconds;
time(&seconds);
return((int)seconds);
}
/* md_exit():
*
* This function causes the program to discontinue execution and exit.
* This function must be implemented or the program will continue to
* hang when it should quit.
*/
void
md_exit(int status)
{
exit(status);
}
/* md_lock():
*
* This function is intended to give the user exclusive access to the score
* file. It does so by flock'ing the score file. The full path name of the
* score file should be defined for any particular site in rogue.h. The
* constants _PATH_SCOREFILE defines this file name.
*
* When the parameter 'l' is non-zero (true), a lock is requested. Otherwise
* the lock is released.
*/
void
md_lock(boolean l)
{
static int fd = -1;
short tries;
if (l) {
setegid(egid);
if ((fd = open(_PATH_SCOREFILE, O_RDONLY)) < 1) {
setegid(gid);
messagef(0, "cannot lock score file");
return;
}
setegid(gid);
for (tries = 0; tries < 5; tries++)
if (!flock(fd, LOCK_EX|LOCK_NB))
return;
} else {
(void)flock(fd, LOCK_UN|LOCK_NB);
(void)close(fd);
}
}
/* md_shell():
*
* This function spawns a shell for the user to use. When this shell is
* terminated, the game continues.
*
* It is important that the game not give the shell the privileges the
* game uses to access the scores file. This version of the game runs
* with privileges low by default; only the saved gid (if setgid) or uid
* (if setuid) will be privileged, but that privilege is discarded by
* exec().
*/
void
md_shell(const char *shell)
{
int w;
pid_t pid;
pid = fork();
switch (pid) {
case -1:
break;
case 0:
execl(shell, shell, (char *)NULL);
_exit(255);
default:
waitpid(pid, &w, 0);
break;
}
}
#endif /* UNIX */

84
main.c Normal file
View File

@@ -0,0 +1,84 @@
/* $NetBSD: main.c,v 1.9 2008/07/20 01:03:22 lukem Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1988, 1993\
The Regents of the University of California. All rights reserved.");
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: main.c,v 1.9 2008/07/20 01:03:22 lukem Exp $");
#endif
#endif /* not lint */
/*
* main.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include "rogue.h"
int
main(int argc, char *argv[])
{
if (init(argc, argv)) { /* restored game */
goto PL;
}
for (;;) {
clear_level();
make_level();
put_objects();
put_stairs();
add_traps();
put_mons();
put_player(party_room);
print_stats(STAT_ALL);
PL:
play_level();
free_stuff(&level_objects);
free_stuff(&level_monsters);
}
}

378
message.c Normal file
View File

@@ -0,0 +1,378 @@
/* $NetBSD: message.c,v 1.16 2023/08/01 07:55:57 mrg Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)message.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: message.c,v 1.16 2023/08/01 07:55:57 mrg Exp $");
#endif
#endif /* not lint */
/*
* message.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include <signal.h>
#include <termios.h>
#include <stdarg.h>
#include "rogue.h"
#include "pathnames.h"
static char msgs[NMESSAGES][DCOLS] = {"", "", "", "", ""};
static short msg_col = 0, imsg = -1;
static boolean rmsg = 0;
boolean msg_cleared = 1;
char hunger_str[HUNGER_STR_LEN] = "";
const char *more = "-more-";
static void save_screen(void);
static
void
message(const char *msg, boolean intrpt)
{
cant_int = 1;
if (!save_is_interactive) {
return;
}
if (intrpt) {
interrupted = 1;
md_slurp();
}
if (!msg_cleared) {
mvaddstr(MIN_ROW-1, msg_col, more);
refresh();
wait_for_ack();
check_message();
}
if (!rmsg) {
imsg = (imsg + 1) % NMESSAGES;
(void)strlcpy(msgs[imsg], msg, sizeof(msgs[imsg]));
}
mvaddstr(MIN_ROW-1, 0, msg);
addch(' ');
refresh();
msg_cleared = 0;
msg_col = strlen(msg);
cant_int = 0;
if (did_int) {
did_int = 0;
onintr(0);
}
}
void
messagef(boolean intrpt, const char *fmt, ...)
{
va_list ap;
char buf[DCOLS];
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
message(buf, intrpt);
}
void
remessage(short c)
{
if (imsg != -1) {
check_message();
rmsg = 1;
while (c > imsg) {
c -= NMESSAGES;
}
message(msgs[((imsg - c) % NMESSAGES)], 0);
rmsg = 0;
move(rogue.row, rogue.col);
refresh();
}
}
void
check_message(void)
{
if (msg_cleared) {
return;
}
move(MIN_ROW-1, 0);
clrtoeol();
refresh();
msg_cleared = 1;
}
int
get_input_line(const char *prompt, const char *insert,
char *buf, size_t buflen,
const char *if_cancelled,
boolean add_blank, boolean do_echo)
{
short ch;
size_t i = 0, n;
message(prompt, 0);
n = strlen(prompt);
if (insert[0]) {
mvaddstr(0, n + 1, insert);
(void)strlcpy(buf, insert, buflen);
i = strlen(buf);
move(0, (n + i + 1));
refresh();
}
while (((ch = rgetchar()) != '\r') && (ch != '\n') && (ch != CANCEL)) {
if ((ch >= ' ') && (ch <= '~') && (i < buflen-2)) {
if ((ch != ' ') || (i > 0)) {
buf[i++] = ch;
if (do_echo) {
addch(ch);
}
}
}
if ((ch == '\b') && (i > 0)) {
if (do_echo) {
mvaddch(0, i + n, ' ');
move(MIN_ROW-1, i+n);
}
i--;
}
refresh();
}
check_message();
if (add_blank) {
buf[i++] = ' ';
} else {
while ((i > 0) && (buf[i-1] == ' ')) {
i--;
}
}
buf[i] = 0;
if ((ch == CANCEL) || (i == 0) || ((i == 1) && add_blank)) {
if (if_cancelled) {
message(if_cancelled, 0);
}
return(0);
}
return(i);
}
int
rgetchar(void)
{
int ch;
for(;;) {
ch = getchar();
switch(ch) {
case '\022': /* ^R */
wrefresh(curscr);
break;
#ifdef UNIX_BSD4_2
case '\032': /* ^Z */
printf("%s", CL);
fflush(stdout);
tstp();
break;
#endif
case '&':
save_screen();
break;
default:
return(ch);
}
}
}
/*
Level: 99 Gold: 999999 Hp: 999(999) Str: 99(99) Arm: 99 Exp: 21/10000000 Hungry
0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5
*/
void
print_stats(int stat_mask)
{
char buf[16];
boolean label;
int row = DROWS - 1;
label = (stat_mask & STAT_LABEL) ? 1 : 0;
if (stat_mask & STAT_LEVEL) {
if (label) {
mvaddstr(row, 0, "Level: ");
}
/* max level taken care of in make_level() */
mvprintw(row, 7, "%-2d", cur_level);
}
if (stat_mask & STAT_GOLD) {
if (label) {
mvaddstr(row, 10, "Gold: ");
}
if (rogue.gold > MAX_GOLD) {
rogue.gold = MAX_GOLD;
}
mvprintw(row, 16, "%-6ld", rogue.gold);
}
if (stat_mask & STAT_HP) {
if (label) {
mvaddstr(row, 23, "Hp: ");
}
if (rogue.hp_max > MAX_HP) {
rogue.hp_current -= (rogue.hp_max - MAX_HP);
rogue.hp_max = MAX_HP;
}
snprintf(buf, sizeof(buf), "%d(%d)",
rogue.hp_current, rogue.hp_max);
mvprintw(row, 27, "%-8s", buf);
}
if (stat_mask & STAT_STRENGTH) {
if (label) {
mvaddstr(row, 36, "Str: ");
}
if (rogue.str_max > MAX_STRENGTH) {
rogue.str_current -= (rogue.str_max - MAX_STRENGTH);
rogue.str_max = MAX_STRENGTH;
}
snprintf(buf, sizeof(buf), "%d(%d)",
(rogue.str_current + add_strength), rogue.str_max);
mvprintw(row, 41, "%-6s", buf);
}
if (stat_mask & STAT_ARMOR) {
if (label) {
mvaddstr(row, 48, "Arm: ");
}
if (rogue.armor && (rogue.armor->d_enchant > MAX_ARMOR)) {
rogue.armor->d_enchant = MAX_ARMOR;
}
mvprintw(row, 53, "%-2d", get_armor_class(rogue.armor));
}
if (stat_mask & STAT_EXP) {
if (label) {
mvaddstr(row, 56, "Exp: ");
}
if (rogue.exp_points > MAX_EXP) {
rogue.exp_points = MAX_EXP;
}
if (rogue.exp > MAX_EXP_LEVEL) {
rogue.exp = MAX_EXP_LEVEL;
}
snprintf(buf, sizeof(buf), "%d/%lu",
rogue.exp, (unsigned long)rogue.exp_points);
mvprintw(row, 61, "%-11s", buf);
}
if (stat_mask & STAT_HUNGER) {
mvaddstr(row, 73, hunger_str);
clrtoeol();
}
refresh();
}
static void
save_screen(void)
{
FILE *fp;
short i, j;
char buf[DCOLS+2];
if ((fp = fopen(_PATH_SCREENDUMP, "w")) != NULL) {
for (i = 0; i < DROWS; i++) {
for (j=0; j<DCOLS; j++) {
buf[j] = mvinch(i, j);
}
/*buf[DCOLS] = 0; -- redundant */
for (j=DCOLS; j>0 && buf[j-1]==' '; j--);
buf[j] = 0;
fputs(buf, fp);
putc('\n', fp);
}
fclose(fp);
} else {
sound_bell();
}
}
void
sound_bell(void)
{
putchar(7);
fflush(stdout);
}
boolean
is_digit(int ch)
{
return((ch >= '0') && (ch <= '9'));
}
int
r_index(const char *str, int ch, boolean last)
{
int i = 0;
if (last) {
for (i = strlen(str) - 1; i >= 0; i--) {
if (str[i] == ch) {
return(i);
}
}
} else {
for (i = 0; str[i]; i++) {
if (str[i] == ch) {
return(i);
}
}
}
return(-1);
}

886
monster.c Normal file
View File

@@ -0,0 +1,886 @@
/* $NetBSD: monster.c,v 1.17 2013/08/11 03:44:27 dholland Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)monster.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: monster.c,v 1.17 2013/08/11 03:44:27 dholland Exp $");
#endif
#endif /* not lint */
/*
* monster.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include "rogue.h"
object level_monsters;
boolean mon_disappeared;
const char *const m_names[] = {
"aquator",
"bat",
"centaur",
"dragon",
"emu",
"venus fly-trap",
"griffin",
"hobgoblin",
"ice monster",
"jabberwock",
"kestrel",
"leprechaun",
"medusa",
"nymph",
"orc",
"phantom",
"quagga",
"rattlesnake",
"snake",
"troll",
"black unicorn",
"vampire",
"wraith",
"xeroc",
"yeti",
"zombie"
};
#define FILL 0,0,0,0,0,0,0,0,0,0,0,0,0,NULL
static object mon_tab[MONSTERS] = {
{(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0, FILL},
{(ASLEEP|WANDERS|FLITS|FLIES),"1d3",10,'B',2,1,8,60,0,0, FILL},
{(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10, FILL},
{(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90, FILL},
{(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0, FILL},
{(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0, FILL},
{(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
2000,20,126,85,0,10, FILL},
{(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0, FILL},
{(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0, FILL},
{(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0, FILL},
{(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0, FILL},
{(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0, FILL},
{(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
250,18,126,85,0,25, FILL},
{(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100, FILL},
{(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10, FILL},
{(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50, FILL},
{(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20, FILL},
{(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0, FILL},
{(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0, FILL},
{(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33, FILL},
{(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
200,17,26,85,0,33, FILL},
{(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
350,19,126,85,0,18, FILL},
{(ASLEEP|WANDERS|DROPS_LEVEL),"2d8",45,'W',55,14,23,75,0,0, FILL},
{(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0, FILL},
{(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20, FILL},
{(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0, FILL}
};
static void aim_monster(object *);
static int flit(object *);
static int move_confused(object *);
static int mtry(object *, short, short);
static int no_room_for_monster(int);
static void put_m_at(short, short, object *);
static int rogue_is_around(int, int);
void
put_mons(void)
{
short i;
short n;
object *monster;
short row, col;
n = get_rand(4, 6);
for (i = 0; i < n; i++) {
monster = gr_monster(NULL, 0);
if ((monster->m_flags & WANDERS) && coin_toss()) {
wake_up(monster);
}
gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
put_m_at(row, col, monster);
}
}
object *
gr_monster(object *monster, int mn)
{
if (!monster) {
monster = alloc_object();
for (;;) {
mn = get_rand(0, MONSTERS-1);
if ((cur_level >= mon_tab[mn].first_level) &&
(cur_level <= mon_tab[mn].last_level)) {
break;
}
}
}
*monster = mon_tab[mn];
if (monster->m_flags & IMITATES) {
monster->disguise = gr_obj_char();
}
if (cur_level > (AMULET_LEVEL + 2)) {
monster->m_flags |= HASTED;
}
monster->trow = NO_ROOM;
return(monster);
}
void
mv_mons(void)
{
object *monster, *next_monster, *test_mons;
boolean flew;
if (haste_self % 2) {
return;
}
monster = level_monsters.next_monster;
while (monster) {
next_monster = monster->next_monster;
mon_disappeared = 0;
if (monster->m_flags & HASTED) {
mv_1_monster(monster, rogue.row, rogue.col);
if (mon_disappeared) {
goto NM;
}
} else if (monster->m_flags & SLOWED) {
monster->slowed_toggle = !monster->slowed_toggle;
if (monster->slowed_toggle) {
goto NM;
}
}
if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
goto NM;
}
flew = 0;
if ( (monster->m_flags & FLIES) &&
!(monster->m_flags & NAPPING) &&
!mon_can_go(monster, rogue.row, rogue.col)) {
flew = 1;
mv_1_monster(monster, rogue.row, rogue.col);
if (mon_disappeared) {
goto NM;
}
}
if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
mv_1_monster(monster, rogue.row, rogue.col);
}
NM: test_mons = level_monsters.next_monster;
monster = NULL;
while (test_mons)
{
if (next_monster == test_mons)
{
monster = next_monster;
break;
}
test_mons = test_mons -> next_monster;
}
}
}
void
party_monsters(int rn, int n)
{
short i, j;
short row, col;
object *monster;
boolean found;
row = col = 0;
n += n;
for (i = 0; i < MONSTERS; i++) {
mon_tab[i].first_level -= (cur_level % 3);
}
for (i = 0; i < n; i++) {
if (no_room_for_monster(rn)) {
break;
}
for (j = found = 0; ((!found) && (j < 250)); j++) {
row = get_rand(rooms[rn].top_row+1,
rooms[rn].bottom_row-1);
col = get_rand(rooms[rn].left_col+1,
rooms[rn].right_col-1);
if ((!(dungeon[row][col] & MONSTER)) &&
(dungeon[row][col] & (FLOOR | TUNNEL))) {
found = 1;
}
}
if (found) {
monster = gr_monster((object *)0, 0);
if (!(monster->m_flags & IMITATES)) {
monster->m_flags |= WAKENS;
}
put_m_at(row, col, monster);
}
}
for (i = 0; i < MONSTERS; i++) {
mon_tab[i].first_level += (cur_level % 3);
}
}
char
gmc_row_col(int row, int col)
{
object *monster;
if ((monster = object_at(&level_monsters, row, col)) != NULL) {
if ((!(detect_monster || see_invisible || r_see_invisible) &&
(monster->m_flags & INVISIBLE)) || blind) {
return(monster->trail_char);
}
if (monster->m_flags & IMITATES) {
return(monster->disguise);
}
return(monster->m_char);
} else {
return('&'); /* BUG if this ever happens */
}
}
char
gmc(object *monster)
{
if ((!(detect_monster || see_invisible || r_see_invisible) &&
(monster->m_flags & INVISIBLE))
|| blind) {
return(monster->trail_char);
}
if (monster->m_flags & IMITATES) {
return(monster->disguise);
}
return(monster->m_char);
}
void
mv_1_monster(object *monster, short row, short col)
{
short i, n;
boolean tried[6];
if (monster->m_flags & ASLEEP) {
if (monster->m_flags & NAPPING) {
if (--monster->nap_length <= 0) {
monster->m_flags &= (~(NAPPING | ASLEEP));
}
return;
}
if ((monster->m_flags & WAKENS) &&
rogue_is_around(monster->row, monster->col) &&
rand_percent(((stealthy > 0) ?
(WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
WAKE_PERCENT))) {
wake_up(monster);
}
return;
} else if (monster->m_flags & ALREADY_MOVED) {
monster->m_flags &= (~ALREADY_MOVED);
return;
}
if ((monster->m_flags & FLITS) && flit(monster)) {
return;
}
if ((monster->m_flags & STATIONARY) &&
(!mon_can_go(monster, rogue.row, rogue.col))) {
return;
}
if (monster->m_flags & FREEZING_ROGUE) {
return;
}
if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
return;
}
if (mon_can_go(monster, rogue.row, rogue.col)) {
mon_hit(monster);
return;
}
if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
return;
}
if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
return;
}
if ((monster->trow == monster->row) &&
(monster->tcol == monster->col)) {
monster->trow = NO_ROOM;
} else if (monster->trow != NO_ROOM) {
row = monster->trow;
col = monster->tcol;
}
if (monster->row > row) {
row = monster->row - 1;
} else if (monster->row < row) {
row = monster->row + 1;
}
if ((dungeon[row][monster->col] & DOOR) &&
mtry(monster, row, monster->col)) {
return;
}
if (monster->col > col) {
col = monster->col - 1;
} else if (monster->col < col) {
col = monster->col + 1;
}
if ((dungeon[monster->row][col] & DOOR) &&
mtry(monster, monster->row, col)) {
return;
}
if (mtry(monster, row, col)) {
return;
}
for (i = 0; i <= 5; i++) tried[i] = 0;
for (i = 0; i < 6; i++) {
NEXT_TRY: n = get_rand(0, 5);
switch(n) {
case 0:
if (!tried[n] && mtry(monster, row, monster->col-1)) {
goto O;
}
break;
case 1:
if (!tried[n] && mtry(monster, row, monster->col)) {
goto O;
}
break;
case 2:
if (!tried[n] && mtry(monster, row, monster->col+1)) {
goto O;
}
break;
case 3:
if (!tried[n] && mtry(monster, monster->row-1, col)) {
goto O;
}
break;
case 4:
if (!tried[n] && mtry(monster, monster->row, col)) {
goto O;
}
break;
case 5:
if (!tried[n] && mtry(monster, monster->row+1, col)) {
goto O;
}
break;
}
if (!tried[n]) {
tried[n] = 1;
} else {
goto NEXT_TRY;
}
}
O:
if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
if (++(monster->o) > 4) {
if ((monster->trow == NO_ROOM) &&
(!mon_sees(monster, rogue.row, rogue.col))) {
monster->trow = get_rand(1, (DROWS - 2));
monster->tcol = get_rand(0, (DCOLS - 1));
} else {
monster->trow = NO_ROOM;
monster->o = 0;
}
}
} else {
monster->o_row = monster->row;
monster->o_col = monster->col;
monster->o = 0;
}
}
static int
mtry(object *monster, short row, short col)
{
if (mon_can_go(monster, row, col)) {
move_mon_to(monster, row, col);
return(1);
}
return(0);
}
void
move_mon_to(object *monster, short row, short col)
{
short c;
int mrow, mcol;
mrow = monster->row;
mcol = monster->col;
dungeon[mrow][mcol] &= ~MONSTER;
dungeon[row][col] |= MONSTER;
c = mvinch(mrow, mcol);
if ((c >= 'A') && (c <= 'Z')) {
if (!detect_monster) {
mvaddch(mrow, mcol, monster->trail_char);
} else {
if (rogue_can_see(mrow, mcol)) {
mvaddch(mrow, mcol, monster->trail_char);
} else {
if (monster->trail_char == '.') {
monster->trail_char = ' ';
}
mvaddch(mrow, mcol, monster->trail_char);
}
}
}
monster->trail_char = mvinch(row, col);
if (!blind && (detect_monster || rogue_can_see(row, col))) {
if ((!(monster->m_flags & INVISIBLE) ||
(detect_monster || see_invisible || r_see_invisible))) {
mvaddch(row, col, gmc(monster));
}
}
if ((dungeon[row][col] & DOOR) &&
(get_room_number(row, col) != cur_room) &&
(dungeon[mrow][mcol] == FLOOR) && !blind) {
mvaddch(mrow, mcol, ' ');
}
if (dungeon[row][col] & DOOR) {
dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
row, col);
} else {
monster->row = row;
monster->col = col;
}
}
int
mon_can_go(const object *monster, short row, short col)
{
object *obj;
short dr, dc;
dr = monster->row - row; /* check if move distance > 1 */
if ((dr >= 2) || (dr <= -2)) {
return(0);
}
dc = monster->col - col;
if ((dc >= 2) || (dc <= -2)) {
return(0);
}
if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
return(0);
}
if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
return(0);
}
if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
(dungeon[monster->row][monster->col]&DOOR))) {
return(0);
}
if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
(monster->trow == NO_ROOM)) {
if ((monster->row < rogue.row) && (row < monster->row)) return(0);
if ((monster->row > rogue.row) && (row > monster->row)) return(0);
if ((monster->col < rogue.col) && (col < monster->col)) return(0);
if ((monster->col > rogue.col) && (col > monster->col)) return(0);
}
if (dungeon[row][col] & OBJECT) {
obj = object_at(&level_objects, row, col);
if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) {
return(0);
}
}
return(1);
}
void
wake_up(object *monster)
{
if (!(monster->m_flags & NAPPING)) {
monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
}
}
void
wake_room(short rn, boolean entering, short row, short col)
{
object *monster;
short wake_percent;
boolean in_room;
wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
if (stealthy > 0) {
wake_percent /= (STEALTH_FACTOR + stealthy);
}
monster = level_monsters.next_monster;
while (monster) {
in_room = (rn == get_room_number(monster->row, monster->col));
if (in_room) {
if (entering) {
monster->trow = NO_ROOM;
} else {
monster->trow = row;
monster->tcol = col;
}
}
if ((monster->m_flags & WAKENS) &&
(rn == get_room_number(monster->row, monster->col))) {
if (rand_percent(wake_percent)) {
wake_up(monster);
}
}
monster = monster->next_monster;
}
}
const char *
mon_name(const object *monster)
{
short ch;
if (blind || ((monster->m_flags & INVISIBLE) &&
!(detect_monster || see_invisible || r_see_invisible))) {
return("something");
}
if (halluc) {
ch = get_rand('A', 'Z') - 'A';
return(m_names[ch]);
}
ch = monster->m_char - 'A';
return(m_names[ch]);
}
static int
rogue_is_around(int row, int col)
{
short rdif, cdif, retval;
rdif = row - rogue.row;
cdif = col - rogue.col;
retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
return(retval);
}
void
wanderer(void)
{
object *monster;
short row, col, i;
boolean found = 0;
monster = NULL; /* XXXGCC -Wuninitialized [powerpc] */
for (i = 0; ((i < 15) && (!found)); i++) {
monster = gr_monster(NULL, 0);
if (!(monster->m_flags & (WAKENS | WANDERS))) {
free_object(monster);
} else {
found = 1;
}
}
if (found) {
found = 0;
wake_up(monster);
for (i = 0; ((i < 25) && (!found)); i++) {
gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
if (!rogue_can_see(row, col)) {
put_m_at(row, col, monster);
found = 1;
}
}
if (!found) {
free_object(monster);
}
}
}
void
show_monsters(void)
{
object *monster;
detect_monster = 1;
if (blind) {
return;
}
monster = level_monsters.next_monster;
while (monster) {
mvaddch(monster->row, monster->col, monster->m_char);
if (monster->m_flags & IMITATES) {
monster->m_flags &= (~IMITATES);
monster->m_flags |= WAKENS;
}
monster = monster->next_monster;
}
}
void
create_monster(void)
{
short row, col;
short i;
boolean found = 0;
object *monster;
row = rogue.row;
col = rogue.col;
for (i = 0; i < 9; i++) {
rand_around(i, &row, &col);
if (((row == rogue.row) && (col == rogue.col)) ||
(row < MIN_ROW) || (row > (DROWS-2)) ||
(col < 0) || (col > (DCOLS-1))) {
continue;
}
if ((!(dungeon[row][col] & MONSTER)) &&
(dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
found = 1;
break;
}
}
if (found) {
monster = gr_monster((object *)0, 0);
put_m_at(row, col, monster);
mvaddch(row, col, gmc(monster));
if (monster->m_flags & (WANDERS | WAKENS)) {
wake_up(monster);
}
} else {
messagef(0, "you hear a faint cry of anguish in the distance");
}
}
static void
put_m_at(short row, short col, object *monster)
{
monster->row = row;
monster->col = col;
dungeon[row][col] |= MONSTER;
monster->trail_char = mvinch(row, col);
(void)add_to_pack(monster, &level_monsters, 0);
aim_monster(monster);
}
static void
aim_monster(object *monster)
{
short i, rn, d, r;
rn = get_room_number(monster->row, monster->col);
if (rn == NO_ROOM)
clean_up("aim_monster: monster not in room");
r = get_rand(0, 12);
for (i = 0; i < 4; i++) {
d = (r + i) % 4;
if (rooms[rn].doors[d].oth_room != NO_ROOM) {
monster->trow = rooms[rn].doors[d].door_row;
monster->tcol = rooms[rn].doors[d].door_col;
break;
}
}
}
int
rogue_can_see(int row, int col)
{
int retval;
retval = !blind &&
(((get_room_number(row, col) == cur_room) &&
!(rooms[cur_room].is_room & R_MAZE)) ||
rogue_is_around(row, col));
return(retval);
}
static int
move_confused(object *monster)
{
short i, row, col;
if (!(monster->m_flags & ASLEEP)) {
if (--monster->moves_confused <= 0) {
monster->m_flags &= (~CONFUSED);
}
if (monster->m_flags & STATIONARY) {
return(coin_toss() ? 1 : 0);
} else if (rand_percent(15)) {
return(1);
}
row = monster->row;
col = monster->col;
for (i = 0; i < 9; i++) {
rand_around(i, &row, &col);
if ((row == rogue.row) && (col == rogue.col)) {
return(0);
}
if (mtry(monster, row, col)) {
return(1);
}
}
}
return(0);
}
static int
flit(object *monster)
{
short i, row, col;
if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
return(0);
}
if (rand_percent(10)) {
return(1);
}
row = monster->row;
col = monster->col;
for (i = 0; i < 9; i++) {
rand_around(i, &row, &col);
if ((row == rogue.row) && (col == rogue.col)) {
continue;
}
if (mtry(monster, row, col)) {
return(1);
}
}
return(1);
}
char
gr_obj_char(void)
{
short r;
const char *rs = "%!?]=/):*";
r = get_rand(0, 8);
return(rs[r]);
}
static int
no_room_for_monster(int rn)
{
short i, j;
for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
if (!(dungeon[i][j] & MONSTER)) {
return(0);
}
}
}
return(1);
}
void
aggravate(void)
{
object *monster;
messagef(0, "you hear a high pitched humming noise");
monster = level_monsters.next_monster;
while (monster) {
wake_up(monster);
monster->m_flags &= (~IMITATES);
if (rogue_can_see(monster->row, monster->col)) {
mvaddch(monster->row, monster->col, monster->m_char);
}
monster = monster->next_monster;
}
}
boolean
mon_sees(const object *monster, int row, int col)
{
short rn, rdif, cdif, retval;
rn = get_room_number(row, col);
if ( (rn != NO_ROOM) &&
(rn == get_room_number(monster->row, monster->col)) &&
!(rooms[rn].is_room & R_MAZE)) {
return(1);
}
rdif = row - monster->row;
cdif = col - monster->col;
retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
return(retval);
}
void
mv_aquatars(void)
{
object *monster;
monster = level_monsters.next_monster;
while (monster) {
if ((monster->m_char == 'A') &&
mon_can_go(monster, rogue.row, rogue.col)) {
mv_1_monster(monster, rogue.row, rogue.col);
monster->m_flags |= ALREADY_MOVED;
}
monster = monster->next_monster;
}
}

649
move.c Normal file
View File

@@ -0,0 +1,649 @@
/* $NetBSD: move.c,v 1.13 2011/05/23 23:01:17 joerg Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)move.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: move.c,v 1.13 2011/05/23 23:01:17 joerg Exp $");
#endif
#endif /* not lint */
/*
* move.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include "rogue.h"
short m_moves = 0;
boolean jump = 0;
const char you_can_move_again[] = "you can move again";
static boolean can_turn(short, short);
static boolean check_hunger(boolean);
static char gr_dir(void);
static void heal(void);
static boolean next_to_something(int, int);
static void turn_passage(short, boolean);
int
one_move_rogue(short dirch, short pickup)
{
short row, col;
object *obj;
char desc[DCOLS];
short status, d = 0; /* XXX: GCC */
row = rogue.row;
col = rogue.col;
if (confused) {
dirch = gr_dir();
}
(void)is_direction(dirch, &d);
get_dir_rc(d, &row, &col, 1);
if (!can_move(rogue.row, rogue.col, row, col)) {
return(MOVE_FAILED);
}
if (being_held || bear_trap) {
if (!(dungeon[row][col] & MONSTER)) {
if (being_held) {
messagef(1, "you are being held");
} else {
messagef(0, "you are still stuck in the bear trap");
(void)reg_move();
}
return(MOVE_FAILED);
}
}
if (r_teleport) {
if (rand_percent(R_TELE_PERCENT)) {
tele();
return(STOPPED_ON_SOMETHING);
}
}
if (dungeon[row][col] & MONSTER) {
rogue_hit(object_at(&level_monsters, row, col), 0);
(void)reg_move();
return(MOVE_FAILED);
}
if (dungeon[row][col] & DOOR) {
if (cur_room == PASSAGE) {
cur_room = get_room_number(row, col);
if (cur_room == NO_ROOM)
clean_up("one_move_rogue: door to nowhere");
light_up_room(cur_room);
wake_room(cur_room, 1, row, col);
} else {
light_passage(row, col);
}
} else if ((dungeon[rogue.row][rogue.col] & DOOR) &&
(dungeon[row][col] & TUNNEL)) {
light_passage(row, col);
wake_room(cur_room, 0, rogue.row, rogue.col);
darken_room(cur_room);
cur_room = PASSAGE;
} else if (dungeon[row][col] & TUNNEL) {
light_passage(row, col);
}
mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col));
mvaddch(row, col, rogue.fchar);
if (!jump) {
refresh();
}
rogue.row = row;
rogue.col = col;
if (dungeon[row][col] & OBJECT) {
if (levitate && pickup) {
return(STOPPED_ON_SOMETHING);
}
if (pickup && !levitate) {
if ((obj = pick_up(row, col, &status)) != NULL) {
get_desc(obj, desc, sizeof(desc));
if (obj->what_is == GOLD) {
free_object(obj);
messagef(1, "%s", desc);
goto NOT_IN_PACK;
}
} else if (!status) {
goto MVED;
} else {
goto MOVE_ON;
}
} else {
MOVE_ON:
obj = object_at(&level_objects, row, col);
get_desc(obj, desc, sizeof(desc));
messagef(1, "moved onto %s", desc);
goto NOT_IN_PACK;
}
messagef(1, "%s(%c)", desc, obj->ichar);
NOT_IN_PACK:
(void)reg_move();
return(STOPPED_ON_SOMETHING);
}
if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) {
if ((!levitate) && (dungeon[row][col] & TRAP)) {
trap_player(row, col);
}
(void)reg_move();
return(STOPPED_ON_SOMETHING);
}
MVED: if (reg_move()) { /* fainted from hunger */
return(STOPPED_ON_SOMETHING);
}
return((confused ? STOPPED_ON_SOMETHING : MOVED));
}
void
multiple_move_rogue(short dirch)
{
short row, col;
short m;
switch(dirch) {
case '\010':
case '\012':
case '\013':
case '\014':
case '\031':
case '\025':
case '\016':
case '\002':
do {
row = rogue.row;
col = rogue.col;
if (((m = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) ||
(m == STOPPED_ON_SOMETHING) ||
interrupted) {
break;
}
} while (!next_to_something(row, col));
if ( (!interrupted) && passgo && (m == MOVE_FAILED) &&
(dungeon[rogue.row][rogue.col] & TUNNEL)) {
turn_passage(dirch + 96, 0);
}
break;
case 'H':
case 'J':
case 'K':
case 'L':
case 'B':
case 'Y':
case 'U':
case 'N':
while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED))
;
if ( (!interrupted) && passgo &&
(dungeon[rogue.row][rogue.col] & TUNNEL)) {
turn_passage(dirch + 32, 1);
}
break;
}
}
boolean
is_passable(int row, int col)
{
if ((row < MIN_ROW) || (row > (DROWS - 2)) || (col < 0) ||
(col > (DCOLS-1))) {
return(0);
}
if (dungeon[row][col] & HIDDEN) {
return((dungeon[row][col] & TRAP) ? 1 : 0);
}
return(dungeon[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS | TRAP));
}
static boolean
next_to_something(int drow, int dcol)
{
short i, j, i_end, j_end, row, col;
short pass_count = 0;
unsigned short s;
if (confused) {
return(1);
}
if (blind) {
return(0);
}
i_end = (rogue.row < (DROWS-2)) ? 1 : 0;
j_end = (rogue.col < (DCOLS-1)) ? 1 : 0;
for (i = ((rogue.row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
for (j = ((rogue.col > 0) ? -1 : 0); j <= j_end; j++) {
if ((i == 0) && (j == 0)) {
continue;
}
if (((rogue.row+i) == drow) && ((rogue.col+j) == dcol)) {
continue;
}
row = rogue.row + i;
col = rogue.col + j;
s = dungeon[row][col];
if (s & HIDDEN) {
continue;
}
/* If the rogue used to be right, up, left, down, or right of
* row,col, and now isn't, then don't stop */
if (s & (MONSTER | OBJECT | STAIRS)) {
if (((row == drow) || (col == dcol)) &&
(!((row == rogue.row) || (col == rogue.col)))) {
continue;
}
return(1);
}
if (s & TRAP) {
if (!(s & HIDDEN)) {
if (((row == drow) || (col == dcol)) &&
(!((row == rogue.row) || (col == rogue.col)))) {
continue;
}
return(1);
}
}
if ((((i - j) == 1) || ((i - j) == -1)) && (s & TUNNEL)) {
if (++pass_count > 1) {
return(1);
}
}
if ((s & DOOR) && ((i == 0) || (j == 0))) {
return(1);
}
}
}
return(0);
}
boolean
can_move(int row1, int col1, int row2, int col2)
{
if (!is_passable(row2, col2)) {
return(0);
}
if ((row1 != row2) && (col1 != col2)) {
if ((dungeon[row1][col1] & DOOR) || (dungeon[row2][col2] & DOOR)) {
return(0);
}
if ((!dungeon[row1][col2]) || (!dungeon[row2][col1])) {
return(0);
}
}
return(1);
}
void
move_onto(void)
{
short ch, d;
boolean first_miss = 1;
while (!is_direction(ch = rgetchar(), &d)) {
sound_bell();
if (first_miss) {
messagef(0, "direction? ");
first_miss = 0;
}
}
check_message();
if (ch != CANCEL) {
(void)one_move_rogue(ch, 0);
}
}
boolean
is_direction(short c, short *d)
{
switch(c) {
case 'h':
*d = LEFT;
break;
case 'j':
*d = DOWN;
break;
case 'k':
*d = UPWARD;
break;
case 'l':
*d = RIGHT;
break;
case 'b':
*d = DOWNLEFT;
break;
case 'y':
*d = UPLEFT;
break;
case 'u':
*d = UPRIGHT;
break;
case 'n':
*d = DOWNRIGHT;
break;
case CANCEL:
break;
default:
return(0);
}
return(1);
}
static boolean
check_hunger(boolean msg_only)
{
short i, n;
boolean fainted = 0;
if (rogue.moves_left == HUNGRY) {
(void)strlcpy(hunger_str, "hungry", sizeof(hunger_str));
messagef(0, "%s", hunger_str);
print_stats(STAT_HUNGER);
}
if (rogue.moves_left == WEAK) {
(void)strlcpy(hunger_str, "weak", sizeof(hunger_str));
messagef(1, "%s", hunger_str);
print_stats(STAT_HUNGER);
}
if (rogue.moves_left <= FAINT) {
if (rogue.moves_left == FAINT) {
(void)strlcpy(hunger_str, "faint", sizeof(hunger_str));
messagef(1, "%s", hunger_str);
print_stats(STAT_HUNGER);
}
n = get_rand(0, (FAINT - rogue.moves_left));
if (n > 0) {
fainted = 1;
if (rand_percent(40)) {
rogue.moves_left++;
}
messagef(1, "you faint");
for (i = 0; i < n; i++) {
if (coin_toss()) {
mv_mons();
}
}
messagef(1, "%s", you_can_move_again);
}
}
if (msg_only) {
return(fainted);
}
if (rogue.moves_left <= STARVE) {
killed_by(NULL, STARVATION);
}
switch(e_rings) {
/*case -2:
Subtract 0, i.e. do nothing.
break;*/
case -1:
rogue.moves_left -= (rogue.moves_left % 2);
break;
case 0:
rogue.moves_left--;
break;
case 1:
rogue.moves_left--;
(void)check_hunger(1);
rogue.moves_left -= (rogue.moves_left % 2);
break;
case 2:
rogue.moves_left--;
(void)check_hunger(1);
rogue.moves_left--;
break;
}
return(fainted);
}
boolean
reg_move(void)
{
boolean fainted;
if ((rogue.moves_left <= HUNGRY) || (cur_level >= max_level)) {
fainted = check_hunger(0);
} else {
fainted = 0;
}
mv_mons();
if (++m_moves >= 120) {
m_moves = 0;
wanderer();
}
if (halluc) {
if (!(--halluc)) {
unhallucinate();
} else {
hallucinate();
}
}
if (blind) {
if (!(--blind)) {
unblind();
}
}
if (confused) {
if (!(--confused)) {
unconfuse();
}
}
if (bear_trap) {
bear_trap--;
}
if (levitate) {
if (!(--levitate)) {
messagef(1, "you float gently to the ground");
if (dungeon[rogue.row][rogue.col] & TRAP) {
trap_player(rogue.row, rogue.col);
}
}
}
if (haste_self) {
if (!(--haste_self)) {
messagef(0, "you feel yourself slowing down");
}
}
heal();
if (auto_search > 0) {
search(auto_search, auto_search);
}
return(fainted);
}
void
rest(int count)
{
int i;
interrupted = 0;
for (i = 0; i < count; i++) {
if (interrupted) {
break;
}
(void)reg_move();
}
}
static char
gr_dir(void)
{
short d;
d = get_rand(1, 8);
switch(d) {
case 1:
d = 'j';
break;
case 2:
d = 'k';
break;
case 3:
d = 'l';
break;
case 4:
d = 'h';
break;
case 5:
d = 'y';
break;
case 6:
d = 'u';
break;
case 7:
d = 'b';
break;
case 8:
d = 'n';
break;
}
return(d);
}
static void
heal(void)
{
static short heal_exp = -1, n, c = 0;
static boolean alt;
if (rogue.hp_current == rogue.hp_max) {
c = 0;
return;
}
if (rogue.exp != heal_exp) {
heal_exp = rogue.exp;
switch(heal_exp) {
case 1:
n = 20;
break;
case 2:
n = 18;
break;
case 3:
n = 17;
break;
case 4:
n = 14;
break;
case 5:
n = 13;
break;
case 6:
n = 10;
break;
case 7:
n = 9;
break;
case 8:
n = 8;
break;
case 9:
n = 7;
break;
case 10:
n = 4;
break;
case 11:
n = 3;
break;
case 12:
default:
n = 2;
}
}
if (++c >= n) {
c = 0;
rogue.hp_current++;
if ((alt = !alt) != 0) {
rogue.hp_current++;
}
if ((rogue.hp_current += regeneration) > rogue.hp_max) {
rogue.hp_current = rogue.hp_max;
}
print_stats(STAT_HP);
}
}
static boolean
can_turn(short nrow, short ncol)
{
if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) {
return(1);
}
return(0);
}
static void
turn_passage(short dir, boolean fast)
{
short crow = rogue.row, ccol = rogue.col, turns = 0;
short ndir = 0;
if ((dir != 'h') && can_turn(crow, ccol + 1)) {
turns++;
ndir = 'l';
}
if ((dir != 'l') && can_turn(crow, ccol - 1)) {
turns++;
ndir = 'h';
}
if ((dir != 'k') && can_turn(crow + 1, ccol)) {
turns++;
ndir = 'j';
}
if ((dir != 'j') && can_turn(crow - 1, ccol)) {
turns++;
ndir = 'k';
}
if (turns == 1) {
multiple_move_rogue(ndir - (fast ? 32 : 96));
}
}

802
object.c Normal file
View File

@@ -0,0 +1,802 @@
/* $NetBSD: object.c,v 1.14 2009/08/12 08:44:45 dholland Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)object.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: object.c,v 1.14 2009/08/12 08:44:45 dholland Exp $");
#endif
#endif /* not lint */
/*
* object.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include "rogue.h"
object level_objects;
unsigned short dungeon[DROWS][DCOLS];
short foods = 0;
char *fruit = NULL;
static object *free_list = NULL;
fighter rogue = {
INIT_AW, /* armor */
INIT_AW, /* weapon */
INIT_RINGS, /* left ring */
INIT_RINGS, /* right ring */
INIT_HP, /* Hp current */
INIT_HP, /* Hp max */
INIT_STR, /* Str current */
INIT_STR, /* Str max */
INIT_PACK, /* pack */
INIT_GOLD, /* gold */
INIT_EXPLEVEL, /* exp level */
INIT_EXP, /* exp points */
0, 0, /* row, col */
INIT_CHAR, /* char */
INIT_MOVES /* moves */
};
struct id id_potions[POTIONS] = {
{100, "blue ", "of increase strength ", 0},
{250, "red ", "of restore strength ", 0},
{100, "green ", "of healing ", 0},
{200, "grey ", "of extra healing ", 0},
{10, "brown ", "of poison ", 0},
{300, "clear ", "of raise level ", 0},
{10, "pink ", "of blindness ", 0},
{25, "white ", "of hallucination ", 0},
{100, "purple ", "of detect monster ", 0},
{100, "black ", "of detect things ", 0},
{10, "yellow ", "of confusion ", 0},
{80, "plaid ", "of levitation ", 0},
{150, "burgundy ", "of haste self ", 0},
{145, "beige ", "of see invisible ", 0}
};
struct id id_scrolls[SCROLS] = {
{505, "", "of protect armor ", 0},
{200, "", "of hold monster ", 0},
{235, "", "of enchant weapon ", 0},
{235, "", "of enchant armor ", 0},
{175, "", "of identify ", 0},
{190, "", "of teleportation ", 0},
{25, "", "of sleep ", 0},
{610, "", "of scare monster ", 0},
{210, "", "of remove curse ", 0},
{80, "", "of create monster ",0},
{25, "", "of aggravate monster ",0},
{180, "", "of magic mapping ", 0},
{90, "", "of confuse monster ", 0}
};
struct id id_weapons[WEAPONS] = {
{150, "short bow ", "", 0},
{8, "darts ", "", 0},
{15, "arrows ", "", 0},
{27, "daggers ", "", 0},
{35, "shurikens ", "", 0},
{360, "mace ", "", 0},
{470, "long sword ", "", 0},
{580, "two-handed sword ", "", 0}
};
struct id id_armors[ARMORS] = {
{300, "leather armor ", "", (UNIDENTIFIED)},
{300, "ring mail ", "", (UNIDENTIFIED)},
{400, "scale mail ", "", (UNIDENTIFIED)},
{500, "chain mail ", "", (UNIDENTIFIED)},
{600, "banded mail ", "", (UNIDENTIFIED)},
{600, "splint mail ", "", (UNIDENTIFIED)},
{700, "plate mail ", "", (UNIDENTIFIED)}
};
struct id id_wands[WANDS] = {
{25, "", "of teleport away ",0},
{50, "", "of slow monster ", 0},
{8, "", "of invisibility ",0},
{55, "", "of polymorph ",0},
{2, "", "of haste monster ",0},
{20, "", "of magic missile ",0},
{20, "", "of cancellation ",0},
{0, "", "of do nothing ",0},
{35, "", "of drain life ",0},
{20, "", "of cold ",0},
{20, "", "of fire ",0}
};
struct id id_rings[RINGS] = {
{250, "", "of stealth ",0},
{100, "", "of teleportation ", 0},
{255, "", "of regeneration ",0},
{295, "", "of slow digestion ",0},
{200, "", "of add strength ",0},
{250, "", "of sustain strength ",0},
{250, "", "of dexterity ",0},
{25, "", "of adornment ",0},
{300, "", "of see invisible ",0},
{290, "", "of maintain armor ",0},
{270, "", "of searching ",0},
};
static void gr_armor(object *);
static void gr_potion(object *);
static void gr_scroll(object *);
static void gr_wand(object *);
static void gr_weapon(object *, int);
static unsigned short gr_what_is(void);
static void make_party(void);
static void plant_gold(short, short, boolean);
static void put_gold(void);
static void rand_place(object *);
void
put_objects(void)
{
short i, n;
object *obj;
if (cur_level < max_level) {
return;
}
n = coin_toss() ? get_rand(2, 4) : get_rand(3, 5);
while (rand_percent(33)) {
n++;
}
if (party_room != NO_ROOM) {
make_party();
}
for (i = 0; i < n; i++) {
obj = gr_object();
rand_place(obj);
}
put_gold();
}
static void
put_gold(void)
{
short i, j;
short row,col;
boolean is_maze, is_room;
for (i = 0; i < MAXROOMS; i++) {
is_maze = (rooms[i].is_room & R_MAZE) ? 1 : 0;
is_room = (rooms[i].is_room & R_ROOM) ? 1 : 0;
if (!(is_room || is_maze)) {
continue;
}
if (is_maze || rand_percent(GOLD_PERCENT)) {
for (j = 0; j < 50; j++) {
row = get_rand(rooms[i].top_row+1,
rooms[i].bottom_row-1);
col = get_rand(rooms[i].left_col+1,
rooms[i].right_col-1);
if ((dungeon[row][col] == FLOOR) ||
(dungeon[row][col] == TUNNEL)) {
plant_gold(row, col, is_maze);
break;
}
}
}
}
}
static void
plant_gold(short row, short col, boolean is_maze)
{
object *obj;
obj = alloc_object();
obj->row = row; obj->col = col;
obj->what_is = GOLD;
obj->quantity = get_rand((2 * cur_level), (16 * cur_level));
if (is_maze) {
obj->quantity += obj->quantity / 2;
}
dungeon[row][col] |= OBJECT;
(void)add_to_pack(obj, &level_objects, 0);
}
void
place_at(object *obj, int row, int col)
{
obj->row = row;
obj->col = col;
dungeon[row][col] |= OBJECT;
(void)add_to_pack(obj, &level_objects, 0);
}
object *
object_at(object *pack, short row, short col)
{
object *obj = NULL;
if (dungeon[row][col] & (MONSTER | OBJECT)) {
obj = pack->next_object;
while (obj && ((obj->row != row) || (obj->col != col))) {
obj = obj->next_object;
}
if (!obj) {
messagef(1, "object_at(): inconsistent");
}
}
return(obj);
}
object *
get_letter_object(int ch)
{
object *obj;
obj = rogue.pack.next_object;
while (obj && (obj->ichar != ch)) {
obj = obj->next_object;
}
return(obj);
}
void
free_stuff(object *objlist)
{
object *obj;
while (objlist->next_object) {
obj = objlist->next_object;
objlist->next_object =
objlist->next_object->next_object;
free_object(obj);
}
}
const char *
name_of(const object *obj)
{
const char *retstring;
switch(obj->what_is) {
case SCROL:
retstring = obj->quantity > 1 ? "scrolls " : "scroll ";
break;
case POTION:
retstring = obj->quantity > 1 ? "potions " : "potion ";
break;
case FOOD:
if (obj->which_kind == RATION) {
retstring = "food ";
} else {
retstring = fruit;
}
break;
case WAND:
retstring = is_wood[obj->which_kind] ? "staff " : "wand ";
break;
case WEAPON:
switch(obj->which_kind) {
case DART:
retstring=obj->quantity > 1 ? "darts " : "dart ";
break;
case ARROW:
retstring=obj->quantity > 1 ? "arrows " : "arrow ";
break;
case DAGGER:
retstring=obj->quantity > 1 ? "daggers " : "dagger ";
break;
case SHURIKEN:
retstring=obj->quantity > 1?"shurikens ":"shuriken ";
break;
default:
retstring = id_weapons[obj->which_kind].title;
}
break;
case ARMOR:
retstring = "armor ";
break;
case RING:
retstring = "ring ";
break;
case AMULET:
retstring = "amulet ";
break;
default:
retstring = "unknown ";
break;
}
return(retstring);
}
object *
gr_object(void)
{
object *obj;
obj = alloc_object();
if (foods < (cur_level / 3)) {
obj->what_is = FOOD;
foods++;
} else {
obj->what_is = gr_what_is();
}
switch(obj->what_is) {
case SCROL:
gr_scroll(obj);
break;
case POTION:
gr_potion(obj);
break;
case WEAPON:
gr_weapon(obj, 1);
break;
case ARMOR:
gr_armor(obj);
break;
case WAND:
gr_wand(obj);
break;
case FOOD:
get_food(obj, 0);
break;
case RING:
gr_ring(obj, 1);
break;
}
return(obj);
}
static unsigned short
gr_what_is(void)
{
short percent;
unsigned short what_is;
percent = get_rand(1, 91);
if (percent <= 30) {
what_is = SCROL;
} else if (percent <= 60) {
what_is = POTION;
} else if (percent <= 64) {
what_is = WAND;
} else if (percent <= 74) {
what_is = WEAPON;
} else if (percent <= 83) {
what_is = ARMOR;
} else if (percent <= 88) {
what_is = FOOD;
} else {
what_is = RING;
}
return(what_is);
}
static void
gr_scroll(object *obj)
{
short percent;
percent = get_rand(0, 91);
obj->what_is = SCROL;
if (percent <= 5) {
obj->which_kind = PROTECT_ARMOR;
} else if (percent <= 10) {
obj->which_kind = HOLD_MONSTER;
} else if (percent <= 20) {
obj->which_kind = CREATE_MONSTER;
} else if (percent <= 35) {
obj->which_kind = IDENTIFY;
} else if (percent <= 43) {
obj->which_kind = TELEPORT;
} else if (percent <= 50) {
obj->which_kind = SLEEP;
} else if (percent <= 55) {
obj->which_kind = SCARE_MONSTER;
} else if (percent <= 64) {
obj->which_kind = REMOVE_CURSE;
} else if (percent <= 69) {
obj->which_kind = ENCH_ARMOR;
} else if (percent <= 74) {
obj->which_kind = ENCH_WEAPON;
} else if (percent <= 80) {
obj->which_kind = AGGRAVATE_MONSTER;
} else if (percent <= 86) {
obj->which_kind = CON_MON;
} else {
obj->which_kind = MAGIC_MAPPING;
}
}
static void
gr_potion(object *obj)
{
short percent;
percent = get_rand(1, 118);
obj->what_is = POTION;
if (percent <= 5) {
obj->which_kind = RAISE_LEVEL;
} else if (percent <= 15) {
obj->which_kind = DETECT_OBJECTS;
} else if (percent <= 25) {
obj->which_kind = DETECT_MONSTER;
} else if (percent <= 35) {
obj->which_kind = INCREASE_STRENGTH;
} else if (percent <= 45) {
obj->which_kind = RESTORE_STRENGTH;
} else if (percent <= 55) {
obj->which_kind = HEALING;
} else if (percent <= 65) {
obj->which_kind = EXTRA_HEALING;
} else if (percent <= 75) {
obj->which_kind = BLINDNESS;
} else if (percent <= 85) {
obj->which_kind = HALLUCINATION;
} else if (percent <= 95) {
obj->which_kind = CONFUSION;
} else if (percent <= 105) {
obj->which_kind = POISON;
} else if (percent <= 110) {
obj->which_kind = LEVITATION;
} else if (percent <= 114) {
obj->which_kind = HASTE_SELF;
} else {
obj->which_kind = SEE_INVISIBLE;
}
}
static void
gr_weapon(object *obj, int assign_wk)
{
short percent;
short i;
short blessing, increment;
obj->what_is = WEAPON;
if (assign_wk) {
obj->which_kind = get_rand(0, (WEAPONS - 1));
}
if ((obj->which_kind == ARROW) || (obj->which_kind == DAGGER) ||
(obj->which_kind == SHURIKEN) || (obj->which_kind == DART)) {
obj->quantity = get_rand(3, 15);
obj->quiver = get_rand(0, 126);
} else {
obj->quantity = 1;
}
obj->hit_enchant = obj->d_enchant = 0;
percent = get_rand(1, 96);
blessing = get_rand(1, 3);
if (percent <= 32) {
if (percent <= 16) {
increment = 1;
} else {
increment = -1;
obj->is_cursed = 1;
}
for (i = 0; i < blessing; i++) {
if (coin_toss()) {
obj->hit_enchant += increment;
} else {
obj->d_enchant += increment;
}
}
}
switch(obj->which_kind) {
case BOW:
case DART:
obj->damage = "1d1";
break;
case ARROW:
obj->damage = "1d2";
break;
case DAGGER:
obj->damage = "1d3";
break;
case SHURIKEN:
obj->damage = "1d4";
break;
case MACE:
obj->damage = "2d3";
break;
case LONG_SWORD:
obj->damage = "3d4";
break;
case TWO_HANDED_SWORD:
obj->damage = "4d5";
break;
}
}
static void
gr_armor(object *obj)
{
short percent;
short blessing;
obj->what_is = ARMOR;
obj->which_kind = get_rand(0, (ARMORS - 1));
obj->class = obj->which_kind + 2;
if ((obj->which_kind == PLATE) || (obj->which_kind == SPLINT)) {
obj->class--;
}
obj->is_protected = 0;
obj->d_enchant = 0;
percent = get_rand(1, 100);
blessing = get_rand(1, 3);
if (percent <= 16) {
obj->is_cursed = 1;
obj->d_enchant -= blessing;
} else if (percent <= 33) {
obj->d_enchant += blessing;
}
}
static void
gr_wand(object *obj)
{
obj->what_is = WAND;
obj->which_kind = get_rand(0, (WANDS - 1));
obj->class = get_rand(3, 7);
}
void
get_food(object *obj, boolean force_ration)
{
obj->what_is = FOOD;
if (force_ration || rand_percent(80)) {
obj->which_kind = RATION;
} else {
obj->which_kind = FRUIT;
}
}
void
put_stairs(void)
{
short row, col;
gr_row_col(&row, &col, (FLOOR | TUNNEL));
dungeon[row][col] |= STAIRS;
}
int
get_armor_class(const object *obj)
{
if (obj) {
return(obj->class + obj->d_enchant);
}
return(0);
}
object *
alloc_object(void)
{
object *obj;
if (free_list) {
obj = free_list;
free_list = free_list->next_object;
} else if (!(obj = md_malloc(sizeof(object)))) {
messagef(0, "cannot allocate object, saving game");
save_into_file(error_file);
clean_up("alloc_object: save failed");
}
obj->quantity = 1;
obj->ichar = 'L';
obj->picked_up = obj->is_cursed = 0;
obj->in_use_flags = NOT_USED;
obj->identified = UNIDENTIFIED;
obj->damage = "1d1";
return(obj);
}
void
free_object(object *obj)
{
obj->next_object = free_list;
free_list = obj;
}
static void
make_party(void)
{
short n;
party_room = gr_room();
n = rand_percent(99) ? party_objects(party_room) : 11;
if (rand_percent(99)) {
party_monsters(party_room, n);
}
}
void
show_objects(void)
{
object *obj;
short mc, rc, row, col;
object *monster;
obj = level_objects.next_object;
while (obj) {
row = obj->row;
col = obj->col;
rc = get_mask_char(obj->what_is);
if (dungeon[row][col] & MONSTER) {
if ((monster =
object_at(&level_monsters, row, col)) != NULL) {
monster->trail_char = rc;
}
}
mc = mvinch(row, col);
if (((mc < 'A') || (mc > 'Z')) &&
((row != rogue.row) || (col != rogue.col))) {
mvaddch(row, col, rc);
}
obj = obj->next_object;
}
monster = level_monsters.next_object;
while (monster) {
if (monster->m_flags & IMITATES) {
mvaddch(monster->row, monster->col, (int)monster->disguise);
}
monster = monster->next_monster;
}
}
void
put_amulet(void)
{
object *obj;
obj = alloc_object();
obj->what_is = AMULET;
rand_place(obj);
}
static void
rand_place(object *obj)
{
short row, col;
gr_row_col(&row, &col, (FLOOR | TUNNEL));
place_at(obj, row, col);
}
void
c_object_for_wizard(void)
{
short ch, max, wk;
object *obj;
char buf[80];
max = 0;
if (pack_count(NULL) >= MAX_PACK_COUNT) {
messagef(0, "pack full");
return;
}
messagef(0, "type of object?");
while (r_index("!?:)]=/,\033", (ch = rgetchar()), 0) == -1) {
sound_bell();
}
check_message();
if (ch == '\033') {
return;
}
obj = alloc_object();
switch(ch) {
case '!':
obj->what_is = POTION;
max = POTIONS - 1;
break;
case '?':
obj->what_is = SCROL;
max = SCROLS - 1;
break;
case ',':
obj->what_is = AMULET;
break;
case ':':
get_food(obj, 0);
break;
case ')':
gr_weapon(obj, 0);
max = WEAPONS - 1;
break;
case ']':
gr_armor(obj);
max = ARMORS - 1;
break;
case '/':
gr_wand(obj);
max = WANDS - 1;
break;
case '=':
max = RINGS - 1;
obj->what_is = RING;
break;
}
if ((ch != ',') && (ch != ':')) {
GIL:
if (get_input_line("which kind?", "", buf, sizeof(buf), "", 0, 1)) {
wk = get_number(buf);
if ((wk >= 0) && (wk <= max)) {
obj->which_kind = wk;
if (obj->what_is == RING) {
gr_ring(obj, 0);
}
} else {
sound_bell();
goto GIL;
}
} else {
free_object(obj);
return;
}
}
get_desc(obj, buf, sizeof(buf));
messagef(0, "%s", buf);
(void)add_to_pack(obj, &rogue.pack, 1);
}

574
pack.c Normal file
View File

@@ -0,0 +1,574 @@
/* $NetBSD: pack.c,v 1.12 2011/05/23 23:01:17 joerg Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)pack.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: pack.c,v 1.12 2011/05/23 23:01:17 joerg Exp $");
#endif
#endif /* not lint */
/*
* pack.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include "rogue.h"
const char curse_message[] = "you can't, it appears to be cursed";
static object *check_duplicate(object *, object *);
static boolean is_pack_letter(short *, unsigned short *);
static boolean mask_pack(const object *, unsigned short);
static short next_avail_ichar(void);
object *
add_to_pack(object *obj, object *pack, int condense)
{
object *op;
if (condense) {
if ((op = check_duplicate(obj, pack)) != NULL) {
free_object(obj);
return(op);
} else {
obj->ichar = next_avail_ichar();
}
}
if (pack->next_object == 0) {
pack->next_object = obj;
} else {
op = pack->next_object;
while (op->next_object) {
op = op->next_object;
}
op->next_object = obj;
}
obj->next_object = 0;
return(obj);
}
void
take_from_pack(object *obj, object *pack)
{
while (pack->next_object != obj) {
pack = pack->next_object;
}
pack->next_object = pack->next_object->next_object;
}
/* Note: *status is set to 0 if the rogue attempts to pick up a scroll
* of scare-monster and it turns to dust. *status is otherwise set to 1.
*/
object *
pick_up(int row, int col, short *status)
{
object *obj;
*status = 1;
if (levitate) {
messagef(0, "you're floating in the air!");
return NULL;
}
obj = object_at(&level_objects, row, col);
if (!obj) {
messagef(1, "pick_up(): inconsistent");
return(obj);
}
if ( (obj->what_is == SCROL) &&
(obj->which_kind == SCARE_MONSTER) &&
obj->picked_up) {
messagef(0, "the scroll turns to dust as you pick it up");
dungeon[row][col] &= (~OBJECT);
vanish(obj, 0, &level_objects);
*status = 0;
if (id_scrolls[SCARE_MONSTER].id_status == UNIDENTIFIED) {
id_scrolls[SCARE_MONSTER].id_status = IDENTIFIED;
}
return NULL;
}
if (obj->what_is == GOLD) {
rogue.gold += obj->quantity;
dungeon[row][col] &= ~(OBJECT);
take_from_pack(obj, &level_objects);
print_stats(STAT_GOLD);
return(obj); /* obj will be free_object()ed in caller */
}
if (pack_count(obj) >= MAX_PACK_COUNT) {
messagef(1, "pack too full");
return NULL;
}
dungeon[row][col] &= ~(OBJECT);
take_from_pack(obj, &level_objects);
obj = add_to_pack(obj, &rogue.pack, 1);
obj->picked_up = 1;
return(obj);
}
void
drop(void)
{
object *obj, *new;
short ch;
char desc[DCOLS];
if (dungeon[rogue.row][rogue.col] & (OBJECT | STAIRS | TRAP)) {
messagef(0, "there's already something there");
return;
}
if (!rogue.pack.next_object) {
messagef(0, "you have nothing to drop");
return;
}
if ((ch = pack_letter("drop what?", ALL_OBJECTS)) == CANCEL) {
return;
}
if (!(obj = get_letter_object(ch))) {
messagef(0, "no such item.");
return;
}
if (obj->in_use_flags & BEING_WIELDED) {
if (obj->is_cursed) {
messagef(0, "%s", curse_message);
return;
}
unwield(rogue.weapon);
} else if (obj->in_use_flags & BEING_WORN) {
if (obj->is_cursed) {
messagef(0, "%s", curse_message);
return;
}
mv_aquatars();
unwear(rogue.armor);
print_stats(STAT_ARMOR);
} else if (obj->in_use_flags & ON_EITHER_HAND) {
if (obj->is_cursed) {
messagef(0, "%s", curse_message);
return;
}
un_put_on(obj);
}
obj->row = rogue.row;
obj->col = rogue.col;
if ((obj->quantity > 1) && (obj->what_is != WEAPON)) {
obj->quantity--;
new = alloc_object();
*new = *obj;
new->quantity = 1;
obj = new;
} else {
obj->ichar = 'L';
take_from_pack(obj, &rogue.pack);
}
place_at(obj, rogue.row, rogue.col);
get_desc(obj, desc, sizeof(desc));
messagef(0, "dropped %s", desc);
(void)reg_move();
}
static object *
check_duplicate(object *obj, object *pack)
{
object *op;
if (!(obj->what_is & (WEAPON | FOOD | SCROL | POTION))) {
return(0);
}
if ((obj->what_is == FOOD) && (obj->which_kind == FRUIT)) {
return(0);
}
op = pack->next_object;
while (op) {
if ((op->what_is == obj->what_is) &&
(op->which_kind == obj->which_kind)) {
if ((obj->what_is != WEAPON) ||
((obj->what_is == WEAPON) &&
((obj->which_kind == ARROW) ||
(obj->which_kind == DAGGER) ||
(obj->which_kind == DART) ||
(obj->which_kind == SHURIKEN)) &&
(obj->quiver == op->quiver))) {
op->quantity += obj->quantity;
return(op);
}
}
op = op->next_object;
}
return(0);
}
static short
next_avail_ichar(void)
{
object *obj;
int i;
boolean ichars[26];
for (i = 0; i < 26; i++) {
ichars[i] = 0;
}
obj = rogue.pack.next_object;
while (obj) {
if (obj->ichar >= 'a' && obj->ichar <= 'z') {
ichars[(obj->ichar - 'a')] = 1;
}
obj = obj->next_object;
}
for (i = 0; i < 26; i++) {
if (!ichars[i]) {
return(i + 'a');
}
}
return('?');
}
void
wait_for_ack(void)
{
while (rgetchar() != ' ')
;
}
short
pack_letter(const char *prompt, unsigned short mask)
{
short ch;
unsigned short tmask = mask;
if (!mask_pack(&rogue.pack, mask)) {
messagef(0, "nothing appropriate");
return(CANCEL);
}
for (;;) {
messagef(0, "%s", prompt);
for (;;) {
ch = rgetchar();
if (!is_pack_letter(&ch, &mask)) {
sound_bell();
} else {
break;
}
}
if (ch == LIST) {
check_message();
mask = tmask;
inventory(&rogue.pack, mask);
} else {
break;
}
mask = tmask;
}
check_message();
return(ch);
}
void
take_off(void)
{
char desc[DCOLS];
object *obj;
if (rogue.armor) {
if (rogue.armor->is_cursed) {
messagef(0, "%s", curse_message);
} else {
mv_aquatars();
obj = rogue.armor;
unwear(rogue.armor);
get_desc(obj, desc, sizeof(desc));
messagef(0, "was wearing %s", desc);
print_stats(STAT_ARMOR);
(void)reg_move();
}
} else {
messagef(0, "not wearing any");
}
}
void
wear(void)
{
short ch;
object *obj;
char desc[DCOLS];
if (rogue.armor) {
messagef(0, "you're already wearing some");
return;
}
ch = pack_letter("wear what?", ARMOR);
if (ch == CANCEL) {
return;
}
if (!(obj = get_letter_object(ch))) {
messagef(0, "no such item.");
return;
}
if (obj->what_is != ARMOR) {
messagef(0, "you can't wear that");
return;
}
obj->identified = 1;
get_desc(obj, desc, sizeof(desc));
messagef(0, "wearing %s", desc);
do_wear(obj);
print_stats(STAT_ARMOR);
(void)reg_move();
}
void
unwear(object *obj)
{
if (obj) {
obj->in_use_flags &= (~BEING_WORN);
}
rogue.armor = NULL;
}
void
do_wear(object *obj)
{
rogue.armor = obj;
obj->in_use_flags |= BEING_WORN;
obj->identified = 1;
}
void
wield(void)
{
short ch;
object *obj;
char desc[DCOLS];
if (rogue.weapon && rogue.weapon->is_cursed) {
messagef(0, "%s", curse_message);
return;
}
ch = pack_letter("wield what?", WEAPON);
if (ch == CANCEL) {
return;
}
if (!(obj = get_letter_object(ch))) {
messagef(0, "No such item.");
return;
}
if (obj->what_is & (ARMOR | RING)) {
messagef(0, "you can't wield %s",
((obj->what_is == ARMOR) ? "armor" : "rings"));
return;
}
if (obj->in_use_flags & BEING_WIELDED) {
messagef(0, "in use");
} else {
unwield(rogue.weapon);
get_desc(obj, desc, sizeof(desc));
messagef(0, "wielding %s", desc);
do_wield(obj);
(void)reg_move();
}
}
void
do_wield(object *obj)
{
rogue.weapon = obj;
obj->in_use_flags |= BEING_WIELDED;
}
void
unwield(object *obj)
{
if (obj) {
obj->in_use_flags &= (~BEING_WIELDED);
}
rogue.weapon = NULL;
}
void
call_it(void)
{
short ch;
object *obj;
struct id *id_table;
char buf[MAX_TITLE_LENGTH+2];
ch = pack_letter("call what?", (SCROL | POTION | WAND | RING));
if (ch == CANCEL) {
return;
}
if (!(obj = get_letter_object(ch))) {
messagef(0, "no such item.");
return;
}
if (!(obj->what_is & (SCROL | POTION | WAND | RING))) {
messagef(0, "surely you already know what that's called");
return;
}
id_table = get_id_table(obj);
if (get_input_line("call it:", "", buf, sizeof(buf),
id_table[obj->which_kind].title, 1, 1)) {
id_table[obj->which_kind].id_status = CALLED;
(void)strlcpy(id_table[obj->which_kind].title, buf,
sizeof(id_table[obj->which_kind].title));
}
}
short
pack_count(const object *new_obj)
{
object *obj;
short count = 0;
obj = rogue.pack.next_object;
while (obj) {
if (obj->what_is != WEAPON) {
count += obj->quantity;
} else if (!new_obj) {
count++;
} else if ((new_obj->what_is != WEAPON) ||
((obj->which_kind != ARROW) &&
(obj->which_kind != DAGGER) &&
(obj->which_kind != DART) &&
(obj->which_kind != SHURIKEN)) ||
(new_obj->which_kind != obj->which_kind) ||
(obj->quiver != new_obj->quiver)) {
count++;
}
obj = obj->next_object;
}
return(count);
}
static boolean
mask_pack(const object *pack, unsigned short mask)
{
while (pack->next_object) {
pack = pack->next_object;
if (pack->what_is & mask) {
return(1);
}
}
return(0);
}
static boolean
is_pack_letter(short *c, unsigned short *mask)
{
if (((*c == '?') || (*c == '!') || (*c == ':') || (*c == '=') ||
(*c == ')') || (*c == ']') || (*c == '/') || (*c == ','))) {
switch(*c) {
case '?':
*mask = SCROL;
break;
case '!':
*mask = POTION;
break;
case ':':
*mask = FOOD;
break;
case ')':
*mask = WEAPON;
break;
case ']':
*mask = ARMOR;
break;
case '/':
*mask = WAND;
break;
case '=':
*mask = RING;
break;
case ',':
*mask = AMULET;
break;
}
*c = LIST;
return(1);
}
return(((*c >= 'a') && (*c <= 'z')) || (*c == CANCEL) || (*c == LIST));
}
boolean
has_amulet(void)
{
return(mask_pack(&rogue.pack, AMULET));
}
void
kick_into_pack(void)
{
object *obj;
char desc[DCOLS];
short stat;
if (!(dungeon[rogue.row][rogue.col] & OBJECT)) {
messagef(0, "nothing here");
} else {
if ((obj = pick_up(rogue.row, rogue.col, &stat)) != NULL) {
get_desc(obj, desc, sizeof(desc));
if (obj->what_is == GOLD) {
messagef(0, "%s", desc);
free_object(obj);
} else {
messagef(0, "%s(%c)", desc, obj->ichar);
}
}
if (obj || (!stat)) {
(void)reg_move();
}
}
}

35
pathnames.h Normal file
View File

@@ -0,0 +1,35 @@
/* $NetBSD: pathnames.h,v 1.5 2008/01/14 03:50:02 dholland Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 5/31/93
*/
#define _PATH_SCOREFILE "/var/games/rogue.scores"
#define _PATH_SCREENDUMP "rogue.screen"

300
play.c Normal file
View File

@@ -0,0 +1,300 @@
/* $NetBSD: play.c,v 1.10 2019/02/03 03:19:25 mrg Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)play.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: play.c,v 1.10 2019/02/03 03:19:25 mrg Exp $");
#endif
#endif /* not lint */
/*
* play.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include "rogue.h"
boolean interrupted = 0;
static const char unknown_command[] = "unknown command";
void
play_level(void)
{
short ch;
int count;
for (;;) {
interrupted = 0;
if (hit_message[0]) {
messagef(1, "%s", hit_message);
hit_message[0] = 0;
}
if (trap_door) {
trap_door = 0;
return;
}
move(rogue.row, rogue.col);
refresh();
ch = rgetchar();
CMCH:
check_message();
count = 0;
CH:
switch(ch) {
case '.':
rest((count > 0) ? count : 1);
break;
case 's':
search(((count > 0) ? count : 1), 0);
break;
case 'i':
inventory(&rogue.pack, ALL_OBJECTS);
break;
case 'f':
fight(0);
break;
case 'F':
fight(1);
break;
case 'h':
case 'j':
case 'k':
case 'l':
case 'y':
case 'u':
case 'n':
case 'b':
(void)one_move_rogue(ch, 1);
break;
case 'H':
case 'J':
case 'K':
case 'L':
case 'B':
case 'Y':
case 'U':
case 'N':
case '\010':
case '\012':
case '\013':
case '\014':
case '\031':
case '\025':
case '\016':
case '\002':
multiple_move_rogue(ch);
break;
case 'e':
eat();
break;
case 'q':
quaff();
break;
case 'r':
read_scroll();
break;
case 'm':
move_onto();
break;
case ',':
kick_into_pack();
break;
case 'd':
drop();
break;
case 'P':
put_on_ring();
break;
case 'R':
remove_ring();
break;
case '\020':
do {
remessage(count++);
ch = rgetchar();
} while (ch == '\020');
goto CMCH;
break;
case '\027':
wizardize();
break;
case '>':
if (drop_check()) {
return;
}
break;
case '<':
if (check_up()) {
return;
}
break;
case ')':
case ']':
inv_armor_weapon(ch == ')');
break;
case '=':
inv_rings();
break;
case '^':
id_trap();
break;
case '/':
id_type();
break;
case '?':
id_com();
break;
case '!':
do_shell();
break;
case 'o':
edit_opts();
break;
case 'I':
single_inv(0);
break;
case 'T':
take_off();
break;
case 'W':
wear();
break;
case 'w':
wield();
break;
case 'c':
call_it();
break;
case 'z':
zapp();
break;
case 't':
throw();
break;
case 'v':
messagef(0, "rogue-clone: Version III. (Tim Stoehr was here), tektronix!zeus!tims");
break;
case 'Q':
quit(0);
__unreachable();
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
move(rogue.row, rogue.col);
refresh();
do {
if (count < 100) {
count = (10 * count) + (ch - '0');
}
ch = rgetchar();
} while (is_digit(ch));
if (ch != CANCEL) {
goto CH;
}
break;
case ' ':
break;
case '\011':
if (wizard) {
inventory(&level_objects, ALL_OBJECTS);
} else {
messagef(0, "%s", unknown_command);
}
break;
case '\023':
if (wizard) {
draw_magic_map();
} else {
messagef(0, "%s", unknown_command);
}
break;
case '\024':
if (wizard) {
show_traps();
} else {
messagef(0, "%s", unknown_command);
}
break;
case '\017':
if (wizard) {
show_objects();
} else {
messagef(0, "%s", unknown_command);
}
break;
case '\001':
show_average_hp();
break;
case '\003':
if (wizard) {
c_object_for_wizard();
} else {
messagef(0, "%s", unknown_command);
}
break;
case '\015':
if (wizard) {
show_monsters();
} else {
messagef(0, "%s", unknown_command);
}
break;
case 'S':
save_game();
break;
default:
messagef(0, "%s", unknown_command);
break;
}
}
}

146
random.c Normal file
View File

@@ -0,0 +1,146 @@
/* $NetBSD: random.c,v 1.8 2009/08/12 08:44:45 dholland Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)random.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: random.c,v 1.8 2009/08/12 08:44:45 dholland Exp $");
#endif
#endif /* not lint */
#include "rogue.h"
/*
* random.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
static long rntb[32] = {
3, 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342,
0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 0x7449e56b,
0xbeb1dbb0, 0xab5c5918, 0x946554fd, 0x8c2e680f, 0xeb3d799f,
0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, 0xe369735d,
0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e,
0x8999220b, 0x27fb47b9
};
static long *fptr = &rntb[4];
static long *rptr = &rntb[1];
static long *state = &rntb[1];
static int rand_type = 3;
static int rand_deg = 31;
static int rand_sep = 3;
static long *end_ptr = &rntb[32];
static long rrandom(void);
void
srrandom(int x)
{
int i;
state[0] = x;
if (rand_type != 0) {
for (i = 1; i < rand_deg; i++) {
state[i] = 1103515245 * state[i - 1] + 12345;
}
fptr = &state[rand_sep];
rptr = &state[0];
for (i = 0; i < 10 * rand_deg; i++) {
(void)rrandom();
}
}
}
static long
rrandom(void)
{
long i;
if (rand_type == 0) {
i = state[0] = (state[0]*1103515245 + 12345) & 0x7fffffff;
} else {
*fptr += *rptr;
i = (*fptr >> 1) & 0x7fffffff;
if (++fptr >= end_ptr) {
fptr = state;
++rptr;
} else {
if (++rptr >= end_ptr) {
rptr = state;
}
}
}
return(i);
}
int
get_rand(int x, int y)
{
int r, t;
long lr;
if (x > y) {
t = y;
y = x;
x = t;
}
lr = rrandom();
lr &= 0x00003fffL;
r = (int)lr;
r = (r % ((y - x) + 1)) + x;
return(r);
}
int
rand_percent(int percentage)
{
return(get_rand(1, 100) <= percentage);
}
int
coin_toss(void)
{
return(((rrandom() & 01) ? 1 : 0));
}

338
ring.c Normal file
View File

@@ -0,0 +1,338 @@
/* $NetBSD: ring.c,v 1.9 2008/01/14 03:50:02 dholland Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Timothy C. Stoehr.
*
* 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 of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)ring.c 8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: ring.c,v 1.9 2008/01/14 03:50:02 dholland Exp $");
#endif
#endif /* not lint */
/*
* ring.c
*
* This source herein may be modified and/or distributed by anybody who
* so desires, with the following restrictions:
* 1.) No portion of this notice shall be removed.
* 2.) Credit shall not be taken for the creation of this source.
* 3.) This code is not to be traded, sold, or used for personal
* gain or profit.
*
*/
#include "rogue.h"
static const char left_or_right[] = "left or right hand?";
static const char no_ring[] = "there's no ring on that hand";
short stealthy;
short r_rings;
short add_strength;
short e_rings;
short regeneration;
short ring_exp;
short auto_search;
boolean r_teleport;
boolean r_see_invisible;
boolean sustain_strength;
boolean maintain_armor;
void
put_on_ring(void)
{
short ch;
char desc[DCOLS];
object *ring;
if (r_rings == 2) {
messagef(0, "wearing two rings already");
return;
}
if ((ch = pack_letter("put on what?", RING)) == CANCEL) {
return;
}
if (!(ring = get_letter_object(ch))) {
messagef(0, "no such item.");
return;
}
if (!(ring->what_is & RING)) {
messagef(0, "that's not a ring");
return;
}
if (ring->in_use_flags & (ON_LEFT_HAND | ON_RIGHT_HAND)) {
messagef(0, "that ring is already being worn");
return;
}
if (r_rings == 1) {
ch = (rogue.left_ring ? 'r' : 'l');
} else {
messagef(0, "%s", left_or_right);
do {
ch = rgetchar();
} while ((ch != CANCEL) && (ch != 'l') && (ch != 'r') && (ch != '\n') &&
(ch != '\r'));
}
if ((ch != 'l') && (ch != 'r')) {
check_message();
return;
}
if (((ch == 'l') && rogue.left_ring)||((ch == '