NetBSD rogue source
This commit is contained in:
55
CHANGES
Normal file
55
CHANGES
Normal 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
20
Makefile
Normal 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
10
USD.doc/Makefile
Normal 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
834
USD.doc/rogue.me
Normal 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
466
hit.c
Normal 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
366
init.c
Normal 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
841
inventory.c
Normal 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
900
level.c
Normal 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
492
machdep.c
Normal 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
84
main.c
Normal 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
378
message.c
Normal 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
886
monster.c
Normal 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
649
move.c
Normal 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
802
object.c
Normal 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
574
pack.c
Normal 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
35
pathnames.h
Normal 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
300
play.c
Normal 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
146
random.c
Normal 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
338
ring.c
Normal 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 == ' | ||||