Import NetBSD games/rogue
Change-Id: Id4aef4950f250edef2d507910877aabc6b9580ea
This commit is contained in:
parent
1b6a97c9c0
commit
e3b78ef14f
32 changed files with 12938 additions and 1 deletions
|
@ -636,6 +636,7 @@
|
|||
./usr/games/ppt minix-sys
|
||||
./usr/games/primes minix-sys
|
||||
./usr/games/random minix-sys
|
||||
./usr/games/rogue minix-sys
|
||||
./usr/games/snake minix-sys
|
||||
./usr/games/snscore minix-sys
|
||||
./usr/games/strfile minix-sys
|
||||
|
@ -5174,6 +5175,7 @@
|
|||
./usr/man/man6/ppt.6 minix-sys
|
||||
./usr/man/man6/primes.6 minix-sys
|
||||
./usr/man/man6/random.6 minix-sys
|
||||
./usr/man/man6/rogue.6 minix-sys
|
||||
./usr/man/man6/snake.6 minix-sys
|
||||
./usr/man/man6/tetris.6 minix-sys
|
||||
./usr/man/man6/wargames.6 minix-sys
|
||||
|
@ -5414,6 +5416,9 @@
|
|||
./usr/share/doc/usd/03.shell/t3 minix-sys
|
||||
./usr/share/doc/usd/03.shell/t4 minix-sys
|
||||
./usr/share/doc/usd/03.shell/t.mac minix-sys
|
||||
./usr/share/doc/usd/30.rogue minix-sys
|
||||
./usr/share/doc/usd/30.rogue/Makefile minix-sys
|
||||
./usr/share/doc/usd/30.rogue/rogue.me minix-sys
|
||||
./usr/share/examples minix-sys
|
||||
./usr/share/examples/atf minix-sys atf
|
||||
./usr/share/examples/atf/atf-run.hooks minix-sys atf,!kyua
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
./usr/share/doc/psd/19.curses
|
||||
./usr/share/doc/usd
|
||||
./usr/share/doc/usd/03.shell
|
||||
./usr/share/doc/usd/30.rogue
|
||||
./usr/share/examples
|
||||
./usr/share/examples/tmux
|
||||
./usr/share/info
|
||||
|
|
|
@ -13,7 +13,7 @@ SUBDIR= adventure arithmetic \
|
|||
factor fish fortune \
|
||||
monop morse number \
|
||||
pig ppt primes \
|
||||
random snake tetris \
|
||||
random rogue snake tetris \
|
||||
wargames
|
||||
|
||||
.if !defined(__MINIX)
|
||||
|
|
55
games/rogue/CHANGES
Normal file
55
games/rogue/CHANGES
Normal file
|
@ -0,0 +1,55 @@
|
|||
$NetBSD: CHANGES,v 1.3 2000/03/13 22:53:22 soren 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 discrepencies 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 @ comand 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
games/rogue/Makefile
Normal file
20
games/rogue/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
# $NetBSD: Makefile,v 1.18 2013/08/11 03:44:27 dholland 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
|
||||
|
||||
.if make(install)
|
||||
SUBDIR+=USD.doc
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
.include <bsd.subdir.mk>
|
11
games/rogue/USD.doc/Makefile
Normal file
11
games/rogue/USD.doc/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
# $NetBSD: Makefile,v 1.5 2013/02/17 12:17:40 jmcneill Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/8/93
|
||||
|
||||
DIR= usd/30.rogue
|
||||
SRCS= rogue.me
|
||||
MACROS= -me
|
||||
|
||||
paper.ps: ${SRCS}
|
||||
${TOOL_TBL} ${SRCS} | ${TOOL_ROFF_PS} ${MACROS} > ${.TARGET}
|
||||
|
||||
.include <bsd.doc.mk>
|
834
games/rogue/USD.doc/rogue.me
Normal file
834
games/rogue/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
games/rogue/hit.c
Normal file
466
games/rogue/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
games/rogue/init.c
Normal file
366
games/rogue/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
games/rogue/inventory.c
Normal file
841
games/rogue/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
games/rogue/level.c
Normal file
900
games/rogue/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
games/rogue/machdep.c
Normal file
492
games/rogue/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
games/rogue/main.c
Normal file
84
games/rogue/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
games/rogue/message.c
Normal file
378
games/rogue/message.c
Normal file
|
@ -0,0 +1,378 @@
|
|||
/* $NetBSD: message.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[] = "@(#)message.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: message.c,v 1.14 2009/08/12 08:44:45 dholland 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/%ld",
|
||||
rogue.exp, 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
games/rogue/monster.c
Normal file
886
games/rogue/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
games/rogue/move.c
Normal file
649
games/rogue/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
games/rogue/object.c
Normal file
802
games/rogue/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
games/rogue/pack.c
Normal file
574
games/rogue/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
games/rogue/pathnames.h
Normal file
35
games/rogue/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"
|
299
games/rogue/play.c
Normal file
299
games/rogue/play.c
Normal file
|
@ -0,0 +1,299 @@
|
|||
/* $NetBSD: play.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[] = "@(#)play.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: play.c,v 1.9 2008/01/14 03:50:02 dholland 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);
|
||||
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
games/rogue/random.c
Normal file
146
games/rogue/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
games/rogue/ring.c
Normal file
338
games/rogue/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 == 'r') && rogue.right_ring)) {
|
||||
check_message();
|
||||
messagef(0, "there's already a ring on that hand");
|
||||
return;
|
||||
}
|
||||
if (ch == 'l') {
|
||||
do_put_on(ring, 1);
|
||||
} else {
|
||||
do_put_on(ring, 0);
|
||||
}
|
||||
ring_stats(1);
|
||||
check_message();
|
||||
get_desc(ring, desc, sizeof(desc));
|
||||
messagef(0, "%s", desc);
|
||||
(void)reg_move();
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not call ring_stats() from within do_put_on(). It will cause
|
||||
* serious problems when do_put_on() is called from read_pack() in restore().
|
||||
*/
|
||||
|
||||
void
|
||||
do_put_on(object *ring, boolean on_left)
|
||||
{
|
||||
if (on_left) {
|
||||
ring->in_use_flags |= ON_LEFT_HAND;
|
||||
rogue.left_ring = ring;
|
||||
} else {
|
||||
ring->in_use_flags |= ON_RIGHT_HAND;
|
||||
rogue.right_ring = ring;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
remove_ring(void)
|
||||
{
|
||||
boolean left = 0, right = 0;
|
||||
short ch;
|
||||
char buf[DCOLS];
|
||||
object *ring;
|
||||
|
||||
ring = NULL;
|
||||
if (r_rings == 0) {
|
||||
inv_rings();
|
||||
} else if (rogue.left_ring && !rogue.right_ring) {
|
||||
left = 1;
|
||||
} else if (!rogue.left_ring && rogue.right_ring) {
|
||||
right = 1;
|
||||
} else {
|
||||
messagef(0, "%s", left_or_right);
|
||||
do {
|
||||
ch = rgetchar();
|
||||
} while ((ch != CANCEL) && (ch != 'l') && (ch != 'r') &&
|
||||
(ch != '\n') && (ch != '\r'));
|
||||
left = (ch == 'l');
|
||||
right = (ch == 'r');
|
||||
check_message();
|
||||
}
|
||||
if (left || right) {
|
||||
if (left) {
|
||||
if (rogue.left_ring) {
|
||||
ring = rogue.left_ring;
|
||||
} else {
|
||||
messagef(0, "%s", no_ring);
|
||||
}
|
||||
} else {
|
||||
if (rogue.right_ring) {
|
||||
ring = rogue.right_ring;
|
||||
} else {
|
||||
messagef(0, "%s", no_ring);
|
||||
}
|
||||
}
|
||||
if (ring->is_cursed) {
|
||||
messagef(0, "%s", curse_message);
|
||||
} else {
|
||||
un_put_on(ring);
|
||||
get_desc(ring, buf, sizeof(buf));
|
||||
messagef(0, "removed %s", buf);
|
||||
(void)reg_move();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
un_put_on(object *ring)
|
||||
{
|
||||
if (ring && (ring->in_use_flags & ON_LEFT_HAND)) {
|
||||
ring->in_use_flags &= (~ON_LEFT_HAND);
|
||||
rogue.left_ring = NULL;
|
||||
} else if (ring && (ring->in_use_flags & ON_RIGHT_HAND)) {
|
||||
ring->in_use_flags &= (~ON_RIGHT_HAND);
|
||||
rogue.right_ring = NULL;
|
||||
}
|
||||
ring_stats(1);
|
||||
}
|
||||
|
||||
void
|
||||
gr_ring(object *ring, boolean assign_wk)
|
||||
{
|
||||
ring->what_is = RING;
|
||||
if (assign_wk) {
|
||||
ring->which_kind = get_rand(0, (RINGS - 1));
|
||||
}
|
||||
ring->class = 0;
|
||||
|
||||
switch(ring->which_kind) {
|
||||
/*
|
||||
case STEALTH:
|
||||
break;
|
||||
case SLOW_DIGEST:
|
||||
break;
|
||||
case REGENERATION:
|
||||
break;
|
||||
case R_SEE_INVISIBLE:
|
||||
break;
|
||||
case SUSTAIN_STRENGTH:
|
||||
break;
|
||||
case R_MAINTAIN_ARMOR:
|
||||
break;
|
||||
case SEARCHING:
|
||||
break;
|
||||
*/
|
||||
case R_TELEPORT:
|
||||
ring->is_cursed = 1;
|
||||
break;
|
||||
case ADD_STRENGTH:
|
||||
case DEXTERITY:
|
||||
while ((ring->class = (get_rand(0, 4) - 2)) == 0)
|
||||
;
|
||||
ring->is_cursed = (ring->class < 0);
|
||||
break;
|
||||
case ADORNMENT:
|
||||
ring->is_cursed = coin_toss();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
inv_rings(void)
|
||||
{
|
||||
char buf[DCOLS];
|
||||
|
||||
if (r_rings == 0) {
|
||||
messagef(0, "not wearing any rings");
|
||||
} else {
|
||||
if (rogue.left_ring) {
|
||||
get_desc(rogue.left_ring, buf, sizeof(buf));
|
||||
messagef(0, "%s", buf);
|
||||
}
|
||||
if (rogue.right_ring) {
|
||||
get_desc(rogue.right_ring, buf, sizeof(buf));
|
||||
messagef(0, "%s", buf);
|
||||
}
|
||||
}
|
||||
if (wizard) {
|
||||
messagef(0, "ste %d, r_r %d, e_r %d, r_t %d, s_s %d, a_s %d, reg %d, r_e %d, s_i %d, m_a %d, aus %d",
|
||||
stealthy, r_rings, e_rings, r_teleport, sustain_strength,
|
||||
add_strength, regeneration, ring_exp, r_see_invisible,
|
||||
maintain_armor, auto_search);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ring_stats(boolean pr)
|
||||
{
|
||||
short i;
|
||||
object *ring;
|
||||
|
||||
stealthy = 0;
|
||||
r_rings = 0;
|
||||
e_rings = 0;
|
||||
r_teleport = 0;
|
||||
sustain_strength = 0;
|
||||
add_strength = 0;
|
||||
regeneration = 0;
|
||||
ring_exp = 0;
|
||||
r_see_invisible = 0;
|
||||
maintain_armor = 0;
|
||||
auto_search = 0;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (!(ring = ((i == 0) ? rogue.left_ring : rogue.right_ring))) {
|
||||
continue;
|
||||
}
|
||||
r_rings++;
|
||||
e_rings++;
|
||||
switch(ring->which_kind) {
|
||||
case STEALTH:
|
||||
stealthy++;
|
||||
break;
|
||||
case R_TELEPORT:
|
||||
r_teleport = 1;
|
||||
break;
|
||||
case REGENERATION:
|
||||
regeneration++;
|
||||
break;
|
||||
case SLOW_DIGEST:
|
||||
e_rings -= 2;
|
||||
break;
|
||||
case ADD_STRENGTH:
|
||||
add_strength += ring->class;
|
||||
break;
|
||||
case SUSTAIN_STRENGTH:
|
||||
sustain_strength = 1;
|
||||
break;
|
||||
case DEXTERITY:
|
||||
ring_exp += ring->class;
|
||||
break;
|
||||
case ADORNMENT:
|
||||
break;
|
||||
case R_SEE_INVISIBLE:
|
||||
r_see_invisible = 1;
|
||||
break;
|
||||
case MAINTAIN_ARMOR:
|
||||
maintain_armor = 1;
|
||||
break;
|
||||
case SEARCHING:
|
||||
auto_search += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pr) {
|
||||
print_stats(STAT_STRENGTH);
|
||||
relight();
|
||||
}
|
||||
}
|
107
games/rogue/rogue.6
Normal file
107
games/rogue/rogue.6
Normal file
|
@ -0,0 +1,107 @@
|
|||
.\" $NetBSD: rogue.6,v 1.11 2005/09/15 02:09:41 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1988, 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.6 8.1 (Berkeley) 5/31/93
|
||||
.\"
|
||||
.Dd May 31, 1993
|
||||
.Dt ROGUE 6
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rogue
|
||||
.Nd exploring The Dungeons of Doom
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl s
|
||||
.Op Ar save_file
|
||||
.\" .Op Fl r
|
||||
.\" .Op Fl d
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a computer fantasy game with a new twist.
|
||||
It is CRT oriented and the object of the game is to survive the attacks of
|
||||
various monsters and get a lot of gold, rather than the puzzle solving
|
||||
orientation of most computer fantasy games.
|
||||
.Pp
|
||||
To get started you really only need to know two commands.
|
||||
The command
|
||||
.Ic \&?
|
||||
will give you a list of the available commands and the command
|
||||
.Ic \&/
|
||||
will identify the things you see on the screen.
|
||||
.Pp
|
||||
To win the game (as opposed to merely playing to beat other people's high
|
||||
scores) you must locate the Amulet of Yendor which is somewhere below
|
||||
the 20th level of the dungeon and get it out.
|
||||
Nobody has achieved this yet and if somebody does, they will probably go
|
||||
down in history as a hero among heroes.
|
||||
.Pp
|
||||
When the game ends, either by your death, when you quit, or if you (by
|
||||
some miracle) manage to win,
|
||||
.Nm
|
||||
will give you a list of the top-ten scorers.
|
||||
The scoring is based entirely upon how much gold you get.
|
||||
There is a 10% penalty for getting yourself killed.
|
||||
.Pp
|
||||
If
|
||||
.Ar save_file
|
||||
is specified,
|
||||
rogue will be restored from the specified saved game file.
|
||||
.Pp
|
||||
The
|
||||
.Fl s
|
||||
option will print out the list of scores.
|
||||
.Pp
|
||||
For more detailed directions, read the document
|
||||
.Rs
|
||||
.%T A Guide to the Dungeons of Doom
|
||||
.Re
|
||||
.Sh FILES
|
||||
.Bl -tag -width /var/games/rogue.scores -compact
|
||||
.It Pa /var/games/rogue.scores
|
||||
Score file
|
||||
.It Pa ~/rogue.save
|
||||
Default save file
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Rs
|
||||
.%A Michael C. Toy
|
||||
.%A Kenneth C. R. C. Arnold
|
||||
.%T A guide to the Dungeons of Doom
|
||||
.Re
|
||||
.Sh AUTHORS
|
||||
.An Timothy Stoehr
|
||||
.An Michael C. Toy
|
||||
.An Kenneth C. R. C. Arnold
|
||||
.An Glenn Wichman
|
||||
.Sh BUGS
|
||||
Probably infinite, although none are known.
|
||||
However, that Ice Monsters sometimes transfix you permanently is
|
||||
.Em not
|
||||
a bug.
|
||||
It's a feature.
|
702
games/rogue/rogue.h
Normal file
702
games/rogue/rogue.h
Normal file
|
@ -0,0 +1,702 @@
|
|||
/* $NetBSD: rogue.h,v 1.24 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.
|
||||
*
|
||||
* @(#)rogue.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* rogue.h
|
||||
*
|
||||
* This source herein may be modified and/or distributed by anybody who
|
||||
* so desires, with the following restrictions:
|
||||
* 1.) This notice shall not 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.
|
||||
*/
|
||||
|
||||
#define boolean char
|
||||
|
||||
#define NOTHING ((unsigned short) 0)
|
||||
#define OBJECT ((unsigned short) 01)
|
||||
#define MONSTER ((unsigned short) 02)
|
||||
#define STAIRS ((unsigned short) 04)
|
||||
#define HORWALL ((unsigned short) 010)
|
||||
#define VERTWALL ((unsigned short) 020)
|
||||
#define DOOR ((unsigned short) 040)
|
||||
#define FLOOR ((unsigned short) 0100)
|
||||
#define TUNNEL ((unsigned short) 0200)
|
||||
#define TRAP ((unsigned short) 0400)
|
||||
#define HIDDEN ((unsigned short) 01000)
|
||||
|
||||
#define ARMOR ((unsigned short) 01)
|
||||
#define WEAPON ((unsigned short) 02)
|
||||
#define SCROL ((unsigned short) 04)
|
||||
#define POTION ((unsigned short) 010)
|
||||
#define GOLD ((unsigned short) 020)
|
||||
#define FOOD ((unsigned short) 040)
|
||||
#define WAND ((unsigned short) 0100)
|
||||
#define RING ((unsigned short) 0200)
|
||||
#define AMULET ((unsigned short) 0400)
|
||||
#define ALL_OBJECTS ((unsigned short) 0777)
|
||||
|
||||
#define LEATHER 0
|
||||
#define RINGMAIL 1
|
||||
#define SCALE 2
|
||||
#define CHAIN 3
|
||||
#define BANDED 4
|
||||
#define SPLINT 5
|
||||
#define PLATE 6
|
||||
#define ARMORS 7
|
||||
|
||||
#define BOW 0
|
||||
#define DART 1
|
||||
#define ARROW 2
|
||||
#define DAGGER 3
|
||||
#define SHURIKEN 4
|
||||
#define MACE 5
|
||||
#define LONG_SWORD 6
|
||||
#define TWO_HANDED_SWORD 7
|
||||
#define WEAPONS 8
|
||||
|
||||
#define MAX_PACK_COUNT 24
|
||||
|
||||
#define PROTECT_ARMOR 0
|
||||
#define HOLD_MONSTER 1
|
||||
#define ENCH_WEAPON 2
|
||||
#define ENCH_ARMOR 3
|
||||
#define IDENTIFY 4
|
||||
#define TELEPORT 5
|
||||
#define SLEEP 6
|
||||
#define SCARE_MONSTER 7
|
||||
#define REMOVE_CURSE 8
|
||||
#define CREATE_MONSTER 9
|
||||
#define AGGRAVATE_MONSTER 10
|
||||
#define MAGIC_MAPPING 11
|
||||
#define CON_MON 12
|
||||
#define SCROLS 13
|
||||
|
||||
#define INCREASE_STRENGTH 0
|
||||
#define RESTORE_STRENGTH 1
|
||||
#define HEALING 2
|
||||
#define EXTRA_HEALING 3
|
||||
#define POISON 4
|
||||
#define RAISE_LEVEL 5
|
||||
#define BLINDNESS 6
|
||||
#define HALLUCINATION 7
|
||||
#define DETECT_MONSTER 8
|
||||
#define DETECT_OBJECTS 9
|
||||
#define CONFUSION 10
|
||||
#define LEVITATION 11
|
||||
#define HASTE_SELF 12
|
||||
#define SEE_INVISIBLE 13
|
||||
#define POTIONS 14
|
||||
|
||||
#define TELE_AWAY 0
|
||||
#define SLOW_MONSTER 1
|
||||
#define INVISIBILITY 2
|
||||
#define POLYMORPH 3
|
||||
#define HASTE_MONSTER 4
|
||||
#define MAGIC_MISSILE 5
|
||||
#define CANCELLATION 6
|
||||
#define DO_NOTHING 7
|
||||
#define DRAIN_LIFE 8
|
||||
#define COLD 9
|
||||
#define FIRE 10
|
||||
#define WANDS 11
|
||||
|
||||
#define STEALTH 0
|
||||
#define R_TELEPORT 1
|
||||
#define REGENERATION 2
|
||||
#define SLOW_DIGEST 3
|
||||
#define ADD_STRENGTH 4
|
||||
#define SUSTAIN_STRENGTH 5
|
||||
#define DEXTERITY 6
|
||||
#define ADORNMENT 7
|
||||
#define R_SEE_INVISIBLE 8
|
||||
#define MAINTAIN_ARMOR 9
|
||||
#define SEARCHING 10
|
||||
#define RINGS 11
|
||||
|
||||
#define RATION 0
|
||||
#define FRUIT 1
|
||||
|
||||
#define NOT_USED ((unsigned short) 0)
|
||||
#define BEING_WIELDED ((unsigned short) 01)
|
||||
#define BEING_WORN ((unsigned short) 02)
|
||||
#define ON_LEFT_HAND ((unsigned short) 04)
|
||||
#define ON_RIGHT_HAND ((unsigned short) 010)
|
||||
#define ON_EITHER_HAND ((unsigned short) 014)
|
||||
#define BEING_USED ((unsigned short) 017)
|
||||
|
||||
#define NO_TRAP -1
|
||||
#define TRAP_DOOR 0
|
||||
#define BEAR_TRAP 1
|
||||
#define TELE_TRAP 2
|
||||
#define DART_TRAP 3
|
||||
#define SLEEPING_GAS_TRAP 4
|
||||
#define RUST_TRAP 5
|
||||
#define TRAPS 6
|
||||
|
||||
#define STEALTH_FACTOR 3
|
||||
#define R_TELE_PERCENT 8
|
||||
|
||||
#define UNIDENTIFIED ((unsigned short) 00) /* MUST BE ZERO! */
|
||||
#define IDENTIFIED ((unsigned short) 01)
|
||||
#define CALLED ((unsigned short) 02)
|
||||
|
||||
#define DROWS 24
|
||||
#define DCOLS 80
|
||||
#define NMESSAGES 5
|
||||
#define MAX_TITLE_LENGTH 30
|
||||
#define MAXSYLLABLES 40
|
||||
#define MAX_METAL 14
|
||||
#define WAND_MATERIALS 30
|
||||
#define GEMS 14
|
||||
|
||||
#define GOLD_PERCENT 46
|
||||
|
||||
#define MAX_OPT_LEN 40
|
||||
|
||||
#define MAX_ID_TITLE_LEN 64
|
||||
struct id {
|
||||
short value;
|
||||
char title[MAX_ID_TITLE_LEN];
|
||||
const char *real;
|
||||
unsigned short id_status;
|
||||
};
|
||||
|
||||
/* The following #defines provide more meaningful names for some of the
|
||||
* struct object fields that are used for monsters. This, since each monster
|
||||
* and object (scrolls, potions, etc) are represented by a struct object.
|
||||
* Ideally, this should be handled by some kind of union structure.
|
||||
*/
|
||||
|
||||
#define m_damage damage
|
||||
#define hp_to_kill quantity
|
||||
#define m_char ichar
|
||||
#define first_level is_protected
|
||||
#define last_level is_cursed
|
||||
#define m_hit_chance class
|
||||
#define stationary_damage identified
|
||||
#define drop_percent which_kind
|
||||
#define trail_char d_enchant
|
||||
#define slowed_toggle quiver
|
||||
#define moves_confused hit_enchant
|
||||
#define nap_length picked_up
|
||||
#define disguise what_is
|
||||
#define next_monster next_object
|
||||
|
||||
struct obj { /* comment is monster meaning */
|
||||
unsigned long m_flags; /* monster flags */
|
||||
const char *damage; /* damage it does */
|
||||
short quantity; /* hit points to kill */
|
||||
short ichar; /* 'A' is for aquator */
|
||||
short kill_exp; /* exp for killing it */
|
||||
short is_protected; /* level starts */
|
||||
short is_cursed; /* level ends */
|
||||
short class; /* chance of hitting you */
|
||||
short identified; /* 'F' damage, 1,2,3... */
|
||||
unsigned short which_kind; /* item carry/drop % */
|
||||
short o_row, o_col, o; /* o is how many times stuck at o_row, o_col */
|
||||
short row, col; /* current row, col */
|
||||
short d_enchant; /* room char when detect_monster */
|
||||
short quiver; /* monster slowed toggle */
|
||||
short trow, tcol; /* target row, col */
|
||||
short hit_enchant; /* how many moves is confused */
|
||||
unsigned short what_is; /* imitator's charactor (?!%: */
|
||||
short picked_up; /* sleep from wand of sleep */
|
||||
unsigned short in_use_flags;
|
||||
struct obj *next_object; /* next monster */
|
||||
};
|
||||
|
||||
typedef struct obj object;
|
||||
|
||||
#define INIT_AW NULL
|
||||
#define INIT_RINGS NULL
|
||||
#define INIT_HP 12
|
||||
#define INIT_STR 16
|
||||
#define INIT_EXPLEVEL 1
|
||||
#define INIT_EXP 0
|
||||
#define INIT_PACK {0,NULL,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL}
|
||||
#define INIT_GOLD 0
|
||||
#define INIT_CHAR '@'
|
||||
#define INIT_MOVES 1250
|
||||
|
||||
struct fightr {
|
||||
object *armor;
|
||||
object *weapon;
|
||||
object *left_ring, *right_ring;
|
||||
short hp_current;
|
||||
short hp_max;
|
||||
short str_current;
|
||||
short str_max;
|
||||
object pack;
|
||||
long gold;
|
||||
short exp;
|
||||
long exp_points;
|
||||
short row, col;
|
||||
short fchar;
|
||||
short moves_left;
|
||||
};
|
||||
|
||||
typedef struct fightr fighter;
|
||||
|
||||
struct dr {
|
||||
short oth_room;
|
||||
short oth_row,
|
||||
oth_col;
|
||||
short door_row,
|
||||
door_col;
|
||||
};
|
||||
|
||||
typedef struct dr door;
|
||||
|
||||
struct rm {
|
||||
short bottom_row, right_col, left_col, top_row;
|
||||
door doors[4];
|
||||
unsigned short is_room;
|
||||
};
|
||||
|
||||
typedef struct rm room;
|
||||
|
||||
#define MAXROOMS 9
|
||||
#define BIG_ROOM 10
|
||||
|
||||
#define NO_ROOM (-1)
|
||||
|
||||
#define PASSAGE (-3) /* cur_room value */
|
||||
|
||||
#define AMULET_LEVEL 26
|
||||
|
||||
#define R_NOTHING ((unsigned short) 01)
|
||||
#define R_ROOM ((unsigned short) 02)
|
||||
#define R_MAZE ((unsigned short) 04)
|
||||
#define R_DEADEND ((unsigned short) 010)
|
||||
#define R_CROSS ((unsigned short) 020)
|
||||
|
||||
#define MAX_EXP_LEVEL 21
|
||||
#define MAX_EXP 10000001L
|
||||
#define MAX_GOLD 999999
|
||||
#define MAX_ARMOR 99
|
||||
#define MAX_HP 999
|
||||
#define MAX_STRENGTH 99
|
||||
#define LAST_DUNGEON 99
|
||||
|
||||
#define STAT_LEVEL 01
|
||||
#define STAT_GOLD 02
|
||||
#define STAT_HP 04
|
||||
#define STAT_STRENGTH 010
|
||||
#define STAT_ARMOR 020
|
||||
#define STAT_EXP 040
|
||||
#define STAT_HUNGER 0100
|
||||
#define STAT_LABEL 0200
|
||||
#define STAT_ALL 0377
|
||||
|
||||
#define PARTY_TIME 10 /* one party somewhere in each 10 level span */
|
||||
|
||||
#define MAX_TRAPS 10 /* maximum traps per level */
|
||||
|
||||
#define HIDE_PERCENT 12
|
||||
|
||||
struct tr {
|
||||
short trap_type;
|
||||
short trap_row, trap_col;
|
||||
};
|
||||
|
||||
typedef struct tr trap;
|
||||
|
||||
extern fighter rogue;
|
||||
extern room rooms[];
|
||||
extern trap traps[];
|
||||
extern unsigned short dungeon[DROWS][DCOLS];
|
||||
extern object level_objects;
|
||||
|
||||
extern struct id id_scrolls[];
|
||||
extern struct id id_potions[];
|
||||
extern struct id id_wands[];
|
||||
extern struct id id_rings[];
|
||||
extern struct id id_weapons[];
|
||||
extern struct id id_armors[];
|
||||
|
||||
extern object level_monsters;
|
||||
|
||||
#define MONSTERS 26
|
||||
|
||||
#define HASTED 01L
|
||||
#define SLOWED 02L
|
||||
#define INVISIBLE 04L
|
||||
#define ASLEEP 010L
|
||||
#define WAKENS 020L
|
||||
#define WANDERS 040L
|
||||
#define FLIES 0100L
|
||||
#define FLITS 0200L
|
||||
#define CAN_FLIT 0400L /* can, but usually doesn't, flit */
|
||||
#define CONFUSED 01000L
|
||||
#define RUSTS 02000L
|
||||
#define HOLDS 04000L
|
||||
#define FREEZES 010000L
|
||||
#define STEALS_GOLD 020000L
|
||||
#define STEALS_ITEM 040000L
|
||||
#define STINGS 0100000L
|
||||
#define DRAINS_LIFE 0200000L
|
||||
#define DROPS_LEVEL 0400000L
|
||||
#define SEEKS_GOLD 01000000L
|
||||
#define FREEZING_ROGUE 02000000L
|
||||
#define RUST_VANISHED 04000000L
|
||||
#define CONFUSES 010000000L
|
||||
#define IMITATES 020000000L
|
||||
#define FLAMES 040000000L
|
||||
#define STATIONARY 0100000000L /* damage will be 1,2,3,... */
|
||||
#define NAPPING 0200000000L /* can't wake up for a while */
|
||||
#define ALREADY_MOVED 0400000000L
|
||||
|
||||
#define SPECIAL_HIT (RUSTS|HOLDS|FREEZES|STEALS_GOLD|STEALS_ITEM|STINGS|DRAINS_LIFE|DROPS_LEVEL)
|
||||
|
||||
#define WAKE_PERCENT 45
|
||||
#define FLIT_PERCENT 40
|
||||
#define PARTY_WAKE_PERCENT 75
|
||||
|
||||
#define HYPOTHERMIA 1
|
||||
#define STARVATION 2
|
||||
#define POISON_DART 3
|
||||
#define QUIT 4
|
||||
#define WIN 5
|
||||
#define KFIRE 6
|
||||
|
||||
#define UPWARD 0
|
||||
#define UPRIGHT 1
|
||||
#define RIGHT 2
|
||||
#define DOWNRIGHT 3
|
||||
#define DOWN 4
|
||||
#define DOWNLEFT 5
|
||||
#define LEFT 6
|
||||
#define UPLEFT 7
|
||||
#define DIRS 8
|
||||
|
||||
#define ROW1 7
|
||||
#define ROW2 15
|
||||
|
||||
#define COL1 26
|
||||
#define COL2 52
|
||||
|
||||
#define MOVED 0
|
||||
#define MOVE_FAILED -1
|
||||
#define STOPPED_ON_SOMETHING -2
|
||||
#define CANCEL '\033'
|
||||
#define LIST '*'
|
||||
|
||||
#define HUNGRY 300
|
||||
#define WEAK 150
|
||||
#define FAINT 20
|
||||
#define STARVE 0
|
||||
|
||||
#define MIN_ROW 1
|
||||
|
||||
struct rogue_time {
|
||||
short year; /* >= 1987 */
|
||||
short month; /* 1 - 12 */
|
||||
short day; /* 1 - 31 */
|
||||
short hour; /* 0 - 23 */
|
||||
short minute; /* 0 - 59 */
|
||||
short second; /* 0 - 59 */
|
||||
};
|
||||
|
||||
#include <curses.h>
|
||||
|
||||
/*
|
||||
* external routine declarations.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
object *alloc_object(void);
|
||||
object *get_letter_object(int);
|
||||
object *gr_monster(object *, int);
|
||||
object *gr_object(void);
|
||||
char *md_getenv(const char *);
|
||||
const char *
|
||||
md_gln(void);
|
||||
void *md_malloc(size_t);
|
||||
const char *mon_name(const object *);
|
||||
const char *name_of(const object *);
|
||||
object *object_at(object *, short, short);
|
||||
object *pick_up(int, int, short *);
|
||||
void add_exp(int, boolean);
|
||||
void add_traps(void);
|
||||
void aggravate(void);
|
||||
void bounce(short, short, short, short, short);
|
||||
void byebye(int);
|
||||
void c_object_for_wizard(void);
|
||||
void call_it(void);
|
||||
boolean can_move(int, int, int, int);
|
||||
void check_gold_seeker(object *);
|
||||
boolean check_imitator(object *);
|
||||
void check_message(void);
|
||||
int check_up(void);
|
||||
void clean_up(const char *) __dead;
|
||||
void clear_level(void);
|
||||
void cnfs(void);
|
||||
int coin_toss(void);
|
||||
void cough_up(object *);
|
||||
void create_monster(void);
|
||||
void darken_room(short);
|
||||
void do_put_on(object *, boolean);
|
||||
void do_shell(void);
|
||||
void do_wear(object *);
|
||||
void do_wield(object *);
|
||||
void dr_course(object *, boolean, short, short);
|
||||
void draw_magic_map(void);
|
||||
void drop(void);
|
||||
int drop_check(void);
|
||||
void eat(void);
|
||||
void edit_opts(void);
|
||||
void error_save(int) __dead;
|
||||
void fight(boolean);
|
||||
boolean flame_broil(object *);
|
||||
void free_object(object *);
|
||||
void free_stuff(object *);
|
||||
int get_armor_class(const object *);
|
||||
int get_damage(const char *, boolean);
|
||||
void get_desc(const object *, char *, size_t);
|
||||
void get_dir_rc(short, short *, short *, short);
|
||||
char get_dungeon_char(short, short);
|
||||
void get_food(object *, boolean);
|
||||
int get_hit_chance(const object *);
|
||||
int get_input_line(const char *, const char *, char *, size_t, const char *, boolean, boolean);
|
||||
char get_mask_char(unsigned short);
|
||||
int get_number(const char *);
|
||||
int get_rand(int, int);
|
||||
short get_room_number(int, int);
|
||||
void get_wand_and_ring_materials(void);
|
||||
int get_weapon_damage(const object *);
|
||||
char gmc(object *);
|
||||
char gmc_row_col(int, int);
|
||||
char gr_obj_char(void);
|
||||
void gr_ring(object *, boolean);
|
||||
short gr_room(void);
|
||||
void gr_row_col(short *, short *, unsigned short);
|
||||
void hallucinate(void);
|
||||
boolean has_amulet(void);
|
||||
int hp_raise(void);
|
||||
void id_com(void);
|
||||
void id_trap(void);
|
||||
void id_type(void);
|
||||
boolean imitating(short, short);
|
||||
int init(int, char **);
|
||||
void insert_score(char [][82], char [][30], const char *, short, short, const object *, int);
|
||||
void inv_armor_weapon(boolean);
|
||||
void inv_rings(void);
|
||||
void inventory(const object *, unsigned short);
|
||||
boolean is_all_connected(void);
|
||||
boolean is_digit(int);
|
||||
boolean is_direction(short, short *);
|
||||
boolean is_passable(int, int);
|
||||
boolean is_vowel(short);
|
||||
void kick_into_pack(void);
|
||||
void killed_by(const object *, short) __dead;
|
||||
long lget_number(const char *);
|
||||
void light_passage(int, int);
|
||||
void light_up_room(int);
|
||||
boolean m_confuse(object *);
|
||||
void make_level(void);
|
||||
void make_scroll_titles(void);
|
||||
boolean md_df(const char *);
|
||||
void md_exit(int) __dead;
|
||||
void md_gct(struct rogue_time *);
|
||||
int md_get_file_id(const char *);
|
||||
void md_gfmt(const char *, struct rogue_time *);
|
||||
int md_gseed(void);
|
||||
void md_heed_signals(void);
|
||||
void md_ignore_signals(void);
|
||||
int md_link_count(const char *);
|
||||
void md_lock(boolean);
|
||||
void md_shell(const char *);
|
||||
void md_sleep(int);
|
||||
void md_slurp(void);
|
||||
/*void message(const char *, boolean);*/
|
||||
void messagef(boolean, const char *, ...) __printflike(2, 3);
|
||||
void mix_colors(void);
|
||||
int mon_can_go(const object *, short, short);
|
||||
int mon_damage(object *, short);
|
||||
void mon_hit(object *);
|
||||
boolean mon_sees(const object *, int, int);
|
||||
void move_mon_to(object *, short, short);
|
||||
void move_onto(void);
|
||||
void multiple_move_rogue(short);
|
||||
void mv_1_monster(object *, short, short);
|
||||
void mv_aquatars(void);
|
||||
void mv_mons(void);
|
||||
int name_cmp(char *, const char *);
|
||||
void nickize(char *, const char *, const char *);
|
||||
int one_move_rogue(short, short);
|
||||
void onintr(int);
|
||||
short pack_count(const object *);
|
||||
short pack_letter(const char *, unsigned short);
|
||||
void pad(const char *, short);
|
||||
void party_monsters(int, int);
|
||||
short party_objects(int);
|
||||
void place_at(object *, int, int);
|
||||
void play_level(void);
|
||||
void print_stats(int);
|
||||
void put_amulet(void);
|
||||
void put_mons(void);
|
||||
void put_objects(void);
|
||||
void put_on_ring(void);
|
||||
void put_player(short);
|
||||
void put_scores(const object *, short) __dead;
|
||||
void put_stairs(void);
|
||||
void quaff(void);
|
||||
void quit(boolean);
|
||||
int r_index(const char *, int, boolean);
|
||||
void rand_around(short, short *, short *);
|
||||
int rand_percent(int);
|
||||
void read_scroll(void);
|
||||
boolean reg_move(void);
|
||||
void relight(void);
|
||||
void remessage(short);
|
||||
void remove_ring(void);
|
||||
void rest(int);
|
||||
void restore(const char *);
|
||||
int rgetchar(void);
|
||||
void ring_stats(boolean);
|
||||
int rogue_can_see(int, int);
|
||||
void rogue_damage(short, object *, short);
|
||||
void rogue_hit(object *, boolean);
|
||||
void rust(object *);
|
||||
void s_con_mon(object *);
|
||||
void save_game(void);
|
||||
void save_into_file(const char *);
|
||||
void search(short, boolean);
|
||||
boolean seek_gold(object *);
|
||||
void show_average_hp(void);
|
||||
void show_monsters(void);
|
||||
void show_objects(void);
|
||||
void show_traps(void);
|
||||
void single_inv(short);
|
||||
void sound_bell(void);
|
||||
void special_hit(object *);
|
||||
void srrandom(int);
|
||||
void start_window(void);
|
||||
void stop_window(void);
|
||||
void take_a_nap(void);
|
||||
void take_from_pack(object *, object *);
|
||||
void take_off(void);
|
||||
void tele(void);
|
||||
void throw(void);
|
||||
void trap_player(short, short);
|
||||
void un_put_on(object *);
|
||||
void unblind(void);
|
||||
void unconfuse(void);
|
||||
void unhallucinate(void);
|
||||
void unwear(object *);
|
||||
void unwield(object *);
|
||||
void vanish(object *, short, object *);
|
||||
void wait_for_ack(void);
|
||||
void wake_room(short, boolean, short, short);
|
||||
void wake_up(object *);
|
||||
void wanderer(void);
|
||||
void wear(void);
|
||||
void wield(void);
|
||||
void win(void) __dead;
|
||||
void wizardize(void);
|
||||
long xxx(boolean);
|
||||
void xxxx(char *, short);
|
||||
void zapp(void);
|
||||
object *add_to_pack(object *, object *, int);
|
||||
struct id *get_id_table(const object *);
|
||||
|
||||
extern boolean ask_quit;
|
||||
extern boolean being_held;
|
||||
extern boolean cant_int;
|
||||
extern boolean con_mon;
|
||||
extern boolean detect_monster;
|
||||
extern boolean did_int;
|
||||
extern boolean interrupted;
|
||||
extern boolean is_wood[];
|
||||
extern boolean jump;
|
||||
extern boolean maintain_armor;
|
||||
extern boolean mon_disappeared;
|
||||
extern boolean msg_cleared;
|
||||
extern boolean no_skull;
|
||||
extern boolean passgo;
|
||||
extern boolean r_see_invisible;
|
||||
extern boolean r_teleport;
|
||||
extern boolean save_is_interactive;
|
||||
extern boolean score_only;
|
||||
extern boolean see_invisible;
|
||||
extern boolean sustain_strength;
|
||||
extern boolean trap_door;
|
||||
extern boolean wizard;
|
||||
#define HIT_MESSAGE_SIZE 80
|
||||
extern char hit_message[HIT_MESSAGE_SIZE];
|
||||
#define HUNGER_STR_LEN 8
|
||||
extern char hunger_str[HUNGER_STR_LEN];
|
||||
extern char login_name[MAX_OPT_LEN];
|
||||
extern const char *byebye_string;
|
||||
extern const char curse_message[];
|
||||
extern const char *error_file;
|
||||
extern char *fruit;
|
||||
extern const char *const m_names[];
|
||||
extern const char *more;
|
||||
extern const char *new_level_message;
|
||||
extern char *nick_name;
|
||||
extern const char *press_space;
|
||||
extern char *save_file;
|
||||
extern const char you_can_move_again[];
|
||||
extern const long level_points[];
|
||||
extern short add_strength;
|
||||
extern short auto_search;
|
||||
extern short bear_trap;
|
||||
extern short blind;
|
||||
extern short confused;
|
||||
extern short cur_level;
|
||||
extern short cur_room;
|
||||
extern short e_rings;
|
||||
extern short extra_hp;
|
||||
extern short foods;
|
||||
extern short halluc;
|
||||
extern short haste_self;
|
||||
extern short less_hp;
|
||||
extern short levitate;
|
||||
extern short m_moves;
|
||||
extern short max_level;
|
||||
extern short party_room;
|
||||
extern short r_rings;
|
||||
extern short regeneration;
|
||||
extern short ring_exp;
|
||||
extern short stealthy;
|
||||
extern gid_t gid;
|
||||
extern gid_t egid;
|
671
games/rogue/room.c
Normal file
671
games/rogue/room.c
Normal file
|
@ -0,0 +1,671 @@
|
|||
/* $NetBSD: room.c,v 1.13 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[] = "@(#)room.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: room.c,v 1.13 2009/08/12 08:44:45 dholland Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* room.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"
|
||||
|
||||
room rooms[MAXROOMS];
|
||||
|
||||
static boolean rooms_visited[MAXROOMS];
|
||||
|
||||
#define NOPTS 7
|
||||
static const struct option {
|
||||
const char *prompt;
|
||||
boolean is_bool;
|
||||
char **strval;
|
||||
boolean *bval;
|
||||
} options[NOPTS] = {
|
||||
{
|
||||
"Show position only at end of run (\"jump\"): ",
|
||||
1, NULL, &jump
|
||||
},
|
||||
{
|
||||
"Follow turnings in passageways (\"passgo\"): ",
|
||||
1, NULL, &passgo
|
||||
},
|
||||
{
|
||||
"Don't print skull when killed (\"noskull\" or \"notombstone\"): ",
|
||||
1, NULL, &no_skull
|
||||
},
|
||||
{
|
||||
"Ask player before saying 'Okay, bye-bye!' (\"askquit\"): ",
|
||||
1, NULL, &ask_quit
|
||||
},
|
||||
{
|
||||
"Name (\"name\"): ",
|
||||
0, &nick_name, NULL
|
||||
},
|
||||
{
|
||||
"Fruit (\"fruit\"): ",
|
||||
0, &fruit, NULL
|
||||
},
|
||||
{
|
||||
"Save file (\"file\"): ",
|
||||
0, &save_file, NULL
|
||||
}
|
||||
};
|
||||
|
||||
static boolean get_oth_room(short, short *, short *);
|
||||
static void opt_erase(int);
|
||||
static void opt_go(int);
|
||||
static void opt_show(int);
|
||||
static void visit_rooms(int);
|
||||
|
||||
void
|
||||
light_up_room(int rn)
|
||||
{
|
||||
short i, j;
|
||||
|
||||
if (!blind) {
|
||||
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] & MONSTER) {
|
||||
object *monster;
|
||||
|
||||
if ((monster = object_at(
|
||||
&level_monsters, i, j)) != NULL) {
|
||||
dungeon[monster->row][monster->col] &= (~MONSTER);
|
||||
monster->trail_char =
|
||||
get_dungeon_char(monster->row, monster->col);
|
||||
dungeon[monster->row][monster->col] |= MONSTER;
|
||||
}
|
||||
}
|
||||
mvaddch(i, j, get_dungeon_char(i, j));
|
||||
}
|
||||
}
|
||||
mvaddch(rogue.row, rogue.col, rogue.fchar);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
light_passage(int row, int col)
|
||||
{
|
||||
short i, j, i_end, j_end;
|
||||
|
||||
if (blind) {
|
||||
return;
|
||||
}
|
||||
i_end = (row < (DROWS-2)) ? 1 : 0;
|
||||
j_end = (col < (DCOLS-1)) ? 1 : 0;
|
||||
|
||||
for (i = ((row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
|
||||
for (j = ((col > 0) ? -1 : 0); j <= j_end; j++) {
|
||||
if (can_move(row, col, row+i, col+j)) {
|
||||
mvaddch(row+i, col+j, get_dungeon_char(row+i, col+j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
darken_room(short 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 (blind) {
|
||||
mvaddch(i, j, ' ');
|
||||
} else {
|
||||
if (!(dungeon[i][j] & (OBJECT | STAIRS)) &&
|
||||
!(detect_monster && (dungeon[i][j] & MONSTER))) {
|
||||
if (!imitating(i, j)) {
|
||||
mvaddch(i, j, ' ');
|
||||
}
|
||||
if ((dungeon[i][j] & TRAP) && (!(dungeon[i][j] & HIDDEN))) {
|
||||
mvaddch(i, j, '^');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char
|
||||
get_dungeon_char(short row, short col)
|
||||
{
|
||||
unsigned short mask = dungeon[row][col];
|
||||
|
||||
if (mask & MONSTER) {
|
||||
return(gmc_row_col(row, col));
|
||||
}
|
||||
if (mask & OBJECT) {
|
||||
object *obj;
|
||||
|
||||
obj = object_at(&level_objects, row, col);
|
||||
return(get_mask_char(obj->what_is));
|
||||
}
|
||||
if (mask & (TUNNEL | STAIRS | HORWALL | VERTWALL | FLOOR | DOOR)) {
|
||||
if ((mask & (TUNNEL| STAIRS)) && (!(mask & HIDDEN))) {
|
||||
return(((mask & STAIRS) ? '%' : '#'));
|
||||
}
|
||||
if (mask & HORWALL) {
|
||||
return('-');
|
||||
}
|
||||
if (mask & VERTWALL) {
|
||||
return('|');
|
||||
}
|
||||
if (mask & FLOOR) {
|
||||
if (mask & TRAP) {
|
||||
if (!(dungeon[row][col] & HIDDEN)) {
|
||||
return('^');
|
||||
}
|
||||
}
|
||||
return('.');
|
||||
}
|
||||
if (mask & DOOR) {
|
||||
if (mask & HIDDEN) {
|
||||
if (((col > 0) && (dungeon[row][col-1] & HORWALL)) ||
|
||||
((col < (DCOLS-1)) && (dungeon[row][col+1] & HORWALL))) {
|
||||
return('-');
|
||||
} else {
|
||||
return('|');
|
||||
}
|
||||
} else {
|
||||
return('+');
|
||||
}
|
||||
}
|
||||
}
|
||||
return(' ');
|
||||
}
|
||||
|
||||
char
|
||||
get_mask_char(unsigned short mask)
|
||||
{
|
||||
switch(mask) {
|
||||
case SCROL:
|
||||
return('?');
|
||||
case POTION:
|
||||
return('!');
|
||||
case GOLD:
|
||||
return('*');
|
||||
case FOOD:
|
||||
return(':');
|
||||
case WAND:
|
||||
return('/');
|
||||
case ARMOR:
|
||||
return(']');
|
||||
case WEAPON:
|
||||
return(')');
|
||||
case RING:
|
||||
return('=');
|
||||
case AMULET:
|
||||
return(',');
|
||||
default:
|
||||
return('~'); /* unknown, something is wrong */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gr_row_col(short *row, short *col, unsigned short mask)
|
||||
{
|
||||
short rn;
|
||||
short r, c;
|
||||
|
||||
do {
|
||||
r = get_rand(MIN_ROW, DROWS-2);
|
||||
c = get_rand(0, DCOLS-1);
|
||||
rn = get_room_number(r, c);
|
||||
} while ((rn == NO_ROOM) ||
|
||||
(!(dungeon[r][c] & mask)) ||
|
||||
(dungeon[r][c] & (~mask)) ||
|
||||
(!(rooms[rn].is_room & (R_ROOM | R_MAZE))) ||
|
||||
((r == rogue.row) && (c == rogue.col)));
|
||||
|
||||
*row = r;
|
||||
*col = c;
|
||||
}
|
||||
|
||||
short
|
||||
gr_room(void)
|
||||
{
|
||||
short i;
|
||||
|
||||
do {
|
||||
i = get_rand(0, MAXROOMS-1);
|
||||
} while (!(rooms[i].is_room & (R_ROOM | R_MAZE)));
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
short
|
||||
party_objects(int rn)
|
||||
{
|
||||
short i, j, nf = 0;
|
||||
object *obj;
|
||||
short n, N, row, col;
|
||||
boolean found;
|
||||
|
||||
row = col = 0;
|
||||
N = ((rooms[rn].bottom_row - rooms[rn].top_row) - 1) *
|
||||
((rooms[rn].right_col - rooms[rn].left_col) - 1);
|
||||
n = get_rand(5, 10);
|
||||
if (n > N) {
|
||||
n = N - 2;
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
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] == FLOOR) || (dungeon[row][col] == TUNNEL)) {
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
obj = gr_object();
|
||||
place_at(obj, row, col);
|
||||
nf++;
|
||||
}
|
||||
}
|
||||
return(nf);
|
||||
}
|
||||
|
||||
short
|
||||
get_room_number(int row, int col)
|
||||
{
|
||||
short i;
|
||||
|
||||
for (i = 0; i < MAXROOMS; i++) {
|
||||
if ((row >= rooms[i].top_row) && (row <= rooms[i].bottom_row) &&
|
||||
(col >= rooms[i].left_col) && (col <= rooms[i].right_col)) {
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
return(NO_ROOM);
|
||||
}
|
||||
|
||||
boolean
|
||||
is_all_connected(void)
|
||||
{
|
||||
short i, starting_room;
|
||||
|
||||
starting_room = 0;
|
||||
for (i = 0; i < MAXROOMS; i++) {
|
||||
rooms_visited[i] = 0;
|
||||
if (rooms[i].is_room & (R_ROOM | R_MAZE)) {
|
||||
starting_room = i;
|
||||
}
|
||||
}
|
||||
|
||||
visit_rooms(starting_room);
|
||||
|
||||
for (i = 0; i < MAXROOMS; i++) {
|
||||
if ((rooms[i].is_room & (R_ROOM | R_MAZE)) && (!rooms_visited[i])) {
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void
|
||||
visit_rooms(int rn)
|
||||
{
|
||||
short i;
|
||||
short oth_rn;
|
||||
|
||||
rooms_visited[rn] = 1;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
oth_rn = rooms[rn].doors[i].oth_room;
|
||||
if ((oth_rn >= 0) && (!rooms_visited[oth_rn])) {
|
||||
visit_rooms(oth_rn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
draw_magic_map(void)
|
||||
{
|
||||
short i, j, ch, och;
|
||||
unsigned short mask = (HORWALL | VERTWALL | DOOR | TUNNEL | TRAP | STAIRS |
|
||||
MONSTER);
|
||||
unsigned short s;
|
||||
|
||||
for (i = 0; i < DROWS; i++) {
|
||||
for (j = 0; j < DCOLS; j++) {
|
||||
s = dungeon[i][j];
|
||||
if (s & mask) {
|
||||
if (((ch = mvinch(i, j)) == ' ') ||
|
||||
((ch >= 'A') && (ch <= 'Z')) || (s & (TRAP | HIDDEN))) {
|
||||
och = ch;
|
||||
dungeon[i][j] &= (~HIDDEN);
|
||||
if (s & HORWALL) {
|
||||
ch = '-';
|
||||
} else if (s & VERTWALL) {
|
||||
ch = '|';
|
||||
} else if (s & DOOR) {
|
||||
ch = '+';
|
||||
} else if (s & TRAP) {
|
||||
ch = '^';
|
||||
} else if (s & STAIRS) {
|
||||
ch = '%';
|
||||
} else if (s & TUNNEL) {
|
||||
ch = '#';
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if ((!(s & MONSTER)) || (och == ' ')) {
|
||||
addch(ch);
|
||||
}
|
||||
if (s & MONSTER) {
|
||||
object *monster;
|
||||
|
||||
if ((monster = object_at(
|
||||
&level_monsters, i, j))
|
||||
!= NULL) {
|
||||
monster->trail_char =
|
||||
ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dr_course(object *monster, boolean entering, short row, short col)
|
||||
{
|
||||
short i, j, k, rn;
|
||||
short r, rr;
|
||||
|
||||
monster->row = row;
|
||||
monster->col = col;
|
||||
|
||||
if (mon_sees(monster, rogue.row, rogue.col)) {
|
||||
monster->trow = NO_ROOM;
|
||||
return;
|
||||
}
|
||||
rn = get_room_number(row, col);
|
||||
|
||||
if (entering) { /* entering room */
|
||||
/* look for door to some other room */
|
||||
r = get_rand(0, MAXROOMS-1);
|
||||
for (i = 0; i < MAXROOMS; i++) {
|
||||
rr = (r + i) % MAXROOMS;
|
||||
if ((!(rooms[rr].is_room & (R_ROOM | R_MAZE))) || (rr == rn)) {
|
||||
continue;
|
||||
}
|
||||
for (k = 0; k < 4; k++) {
|
||||
if (rooms[rr].doors[k].oth_room == rn) {
|
||||
monster->trow = rooms[rr].doors[k].oth_row;
|
||||
monster->tcol = rooms[rr].doors[k].oth_col;
|
||||
if ((monster->trow == row) &&
|
||||
(monster->tcol == col)) {
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* look for door to dead end */
|
||||
if (rn == NO_ROOM)
|
||||
clean_up("dr_course: monster not in room");
|
||||
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 ((i != monster->row) && (j != monster->col) &&
|
||||
(dungeon[i][j] & DOOR)) {
|
||||
monster->trow = i;
|
||||
monster->tcol = j;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* return monster to room that he came from */
|
||||
for (i = 0; i < MAXROOMS; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (rooms[i].doors[j].oth_room == rn) {
|
||||
for (k = 0; k < 4; k++) {
|
||||
if (rooms[rn].doors[k].oth_room == i) {
|
||||
monster->trow = rooms[rn].doors[k].oth_row;
|
||||
monster->tcol = rooms[rn].doors[k].oth_col;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no place to send monster */
|
||||
monster->trow = NO_ROOM;
|
||||
} else { /* exiting room */
|
||||
if (rn == NO_ROOM || !get_oth_room(rn, &row, &col)) {
|
||||
monster->trow = NO_ROOM;
|
||||
} else {
|
||||
monster->trow = row;
|
||||
monster->tcol = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static boolean
|
||||
get_oth_room(short rn, short *row, short *col)
|
||||
{
|
||||
short d = -1;
|
||||
|
||||
if (*row == rooms[rn].top_row) {
|
||||
d = UPWARD/2;
|
||||
} else if (*row == rooms[rn].bottom_row) {
|
||||
d = DOWN/2;
|
||||
} else if (*col == rooms[rn].left_col) {
|
||||
d = LEFT/2;
|
||||
} else if (*col == rooms[rn].right_col) {
|
||||
d = RIGHT/2;
|
||||
}
|
||||
if ((d != -1) && (rooms[rn].doors[d].oth_room >= 0)) {
|
||||
*row = rooms[rn].doors[d].oth_row;
|
||||
*col = rooms[rn].doors[d].oth_col;
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
edit_opts(void)
|
||||
{
|
||||
char save[NOPTS+1][DCOLS];
|
||||
short i, j;
|
||||
short ch;
|
||||
boolean done = 0;
|
||||
char buf[MAX_OPT_LEN + 2];
|
||||
|
||||
for (i = 0; i < NOPTS+1; i++) {
|
||||
for (j = 0; j < DCOLS; j++) {
|
||||
save[i][j] = mvinch(i, j);
|
||||
}
|
||||
if (i < NOPTS) {
|
||||
opt_show(i);
|
||||
}
|
||||
}
|
||||
opt_go(0);
|
||||
i = 0;
|
||||
|
||||
while (!done) {
|
||||
refresh();
|
||||
ch = rgetchar();
|
||||
CH:
|
||||
switch(ch) {
|
||||
case '\033':
|
||||
done = 1;
|
||||
break;
|
||||
case '\012':
|
||||
case '\015':
|
||||
if (i == (NOPTS - 1)) {
|
||||
mvaddstr(NOPTS, 0, press_space);
|
||||
refresh();
|
||||
wait_for_ack();
|
||||
done = 1;
|
||||
} else {
|
||||
i++;
|
||||
opt_go(i);
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (i > 0) {
|
||||
opt_go(--i);
|
||||
} else {
|
||||
sound_bell();
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
case 'f':
|
||||
case 'F':
|
||||
if (options[i].is_bool) {
|
||||
*(options[i].bval) = (((ch == 't') || (ch == 'T')) ? 1 : 0);
|
||||
opt_show(i);
|
||||
opt_go(++i);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (options[i].is_bool) {
|
||||
sound_bell();
|
||||
break;
|
||||
}
|
||||
j = 0;
|
||||
if ((ch == '\010') || ((ch >= ' ') && (ch <= '~'))) {
|
||||
opt_erase(i);
|
||||
do {
|
||||
if ((ch >= ' ') && (ch <= '~') && (j < MAX_OPT_LEN)) {
|
||||
buf[j++] = ch;
|
||||
buf[j] = '\0';
|
||||
addch(ch);
|
||||
} else if ((ch == '\010') && (j > 0)) {
|
||||
buf[--j] = '\0';
|
||||
move(i, j + strlen(options[i].prompt));
|
||||
addch(' ');
|
||||
move(i, j + strlen(options[i].prompt));
|
||||
}
|
||||
refresh();
|
||||
ch = rgetchar();
|
||||
} while ((ch != '\012') && (ch != '\015') && (ch != '\033'));
|
||||
if (j != 0) {
|
||||
/*
|
||||
* We rely on the option string being
|
||||
* allocated to hold MAX_OPT_LEN+2
|
||||
* bytes. This is arranged in init.c.
|
||||
*/
|
||||
(void)strcpy(*(options[i].strval), buf);
|
||||
}
|
||||
opt_show(i);
|
||||
goto CH;
|
||||
} else {
|
||||
sound_bell();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < NOPTS+1; i++) {
|
||||
move(i, 0);
|
||||
for (j = 0; j < DCOLS; j++) {
|
||||
addch(save[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
opt_show(int i)
|
||||
{
|
||||
const char *s;
|
||||
const struct option *opt = &options[i];
|
||||
|
||||
opt_erase(i);
|
||||
|
||||
if (opt->is_bool) {
|
||||
s = *(opt->bval) ? "True" : "False";
|
||||
} else {
|
||||
s = *(opt->strval);
|
||||
}
|
||||
addstr(s);
|
||||
}
|
||||
|
||||
static void
|
||||
opt_erase(int i)
|
||||
{
|
||||
const struct option *opt = &options[i];
|
||||
|
||||
mvaddstr(i, 0, opt->prompt);
|
||||
clrtoeol();
|
||||
}
|
||||
|
||||
static void
|
||||
opt_go(int i)
|
||||
{
|
||||
move(i, strlen(options[i].prompt));
|
||||
}
|
||||
|
||||
void
|
||||
do_shell(void)
|
||||
{
|
||||
#ifdef UNIX
|
||||
const char *sh;
|
||||
|
||||
md_ignore_signals();
|
||||
if (!(sh = md_getenv("SHELL"))) {
|
||||
sh = "/bin/sh";
|
||||
}
|
||||
move(LINES-1, 0);
|
||||
refresh();
|
||||
stop_window();
|
||||
printf("\nCreating new shell...\n");
|
||||
md_shell(sh);
|
||||
start_window();
|
||||
wrefresh(curscr);
|
||||
md_heed_signals();
|
||||
#endif
|
||||
}
|
427
games/rogue/save.c
Normal file
427
games/rogue/save.c
Normal file
|
@ -0,0 +1,427 @@
|
|||
/* $NetBSD: save.c,v 1.13 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[] = "@(#)save.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: save.c,v 1.13 2008/01/14 03:50:02 dholland Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* save.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 <stdio.h>
|
||||
#include "rogue.h"
|
||||
|
||||
static boolean has_been_touched(const struct rogue_time *,
|
||||
const struct rogue_time *);
|
||||
static void r_read(FILE *, void *, size_t);
|
||||
static void r_write(FILE *, const void *, size_t);
|
||||
static void read_pack(object *, FILE *, boolean);
|
||||
static void read_string(char *, FILE *, size_t);
|
||||
static void rw_dungeon(FILE *, boolean);
|
||||
static void rw_id(struct id *, FILE *, int, boolean);
|
||||
static void rw_rooms(FILE *, boolean);
|
||||
static void write_pack(const object *, FILE *);
|
||||
static void write_string(char *, FILE *);
|
||||
|
||||
static short write_failed = 0;
|
||||
|
||||
char *save_file = NULL;
|
||||
|
||||
void
|
||||
save_game(void)
|
||||
{
|
||||
char fname[64];
|
||||
|
||||
if (!get_input_line("file name?", save_file, fname, sizeof(fname),
|
||||
"game not saved", 0, 1)) {
|
||||
return;
|
||||
}
|
||||
check_message();
|
||||
messagef(0, "%s", fname);
|
||||
save_into_file(fname);
|
||||
}
|
||||
|
||||
void
|
||||
save_into_file(const char *sfile)
|
||||
{
|
||||
FILE *fp;
|
||||
int file_id;
|
||||
char *name_buffer;
|
||||
size_t len;
|
||||
char *hptr;
|
||||
struct rogue_time rt_buf;
|
||||
|
||||
if (sfile[0] == '~') {
|
||||
if ((hptr = md_getenv("HOME")) != NULL) {
|
||||
len = strlen(hptr) + strlen(sfile);
|
||||
name_buffer = md_malloc(len);
|
||||
if (name_buffer == NULL) {
|
||||
messagef(0,
|
||||
"out of memory for save file name");
|
||||
sfile = error_file;
|
||||
} else {
|
||||
(void)strcpy(name_buffer, hptr);
|
||||
(void)strcat(name_buffer, sfile+1);
|
||||
sfile = name_buffer;
|
||||
}
|
||||
/*
|
||||
* Note: name_buffer gets leaked. But it's small,
|
||||
* and in the common case we're about to exit.
|
||||
*/
|
||||
}
|
||||
}
|
||||
if (((fp = fopen(sfile, "w")) == NULL) ||
|
||||
((file_id = md_get_file_id(sfile)) == -1)) {
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
messagef(0, "problem accessing the save file");
|
||||
return;
|
||||
}
|
||||
md_ignore_signals();
|
||||
write_failed = 0;
|
||||
(void)xxx(1);
|
||||
r_write(fp, &detect_monster, sizeof(detect_monster));
|
||||
r_write(fp, &cur_level, sizeof(cur_level));
|
||||
r_write(fp, &max_level, sizeof(max_level));
|
||||
write_string(hunger_str, fp);
|
||||
write_string(login_name, fp);
|
||||
r_write(fp, &party_room, sizeof(party_room));
|
||||
write_pack(&level_monsters, fp);
|
||||
write_pack(&level_objects, fp);
|
||||
r_write(fp, &file_id, sizeof(file_id));
|
||||
rw_dungeon(fp, 1);
|
||||
r_write(fp, &foods, sizeof(foods));
|
||||
r_write(fp, &rogue, sizeof(fighter));
|
||||
write_pack(&rogue.pack, fp);
|
||||
rw_id(id_potions, fp, POTIONS, 1);
|
||||
rw_id(id_scrolls, fp, SCROLS, 1);
|
||||
rw_id(id_wands, fp, WANDS, 1);
|
||||
rw_id(id_rings, fp, RINGS, 1);
|
||||
r_write(fp, traps, (MAX_TRAPS * sizeof(trap)));
|
||||
r_write(fp, is_wood, (WANDS * sizeof(boolean)));
|
||||
r_write(fp, &cur_room, sizeof(cur_room));
|
||||
rw_rooms(fp, 1);
|
||||
r_write(fp, &being_held, sizeof(being_held));
|
||||
r_write(fp, &bear_trap, sizeof(bear_trap));
|
||||
r_write(fp, &halluc, sizeof(halluc));
|
||||
r_write(fp, &blind, sizeof(blind));
|
||||
r_write(fp, &confused, sizeof(confused));
|
||||
r_write(fp, &levitate, sizeof(levitate));
|
||||
r_write(fp, &haste_self, sizeof(haste_self));
|
||||
r_write(fp, &see_invisible, sizeof(see_invisible));
|
||||
r_write(fp, &detect_monster, sizeof(detect_monster));
|
||||
r_write(fp, &wizard, sizeof(wizard));
|
||||
r_write(fp, &score_only, sizeof(score_only));
|
||||
r_write(fp, &m_moves, sizeof(m_moves));
|
||||
md_gct(&rt_buf);
|
||||
rt_buf.second += 10; /* allow for some processing time */
|
||||
r_write(fp, &rt_buf, sizeof(rt_buf));
|
||||
fclose(fp);
|
||||
|
||||
if (write_failed) {
|
||||
(void)md_df(sfile); /* delete file */
|
||||
} else {
|
||||
clean_up("");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
restore(const char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
struct rogue_time saved_time, mod_time;
|
||||
char buf[4];
|
||||
char tbuf[MAX_OPT_LEN];
|
||||
int new_file_id, saved_file_id;
|
||||
|
||||
fp = NULL;
|
||||
if (((new_file_id = md_get_file_id(fname)) == -1) ||
|
||||
((fp = fopen(fname, "r")) == NULL)) {
|
||||
clean_up("cannot open file");
|
||||
}
|
||||
if (md_link_count(fname) > 1) {
|
||||
clean_up("file has link");
|
||||
}
|
||||
(void)xxx(1);
|
||||
r_read(fp, &detect_monster, sizeof(detect_monster));
|
||||
r_read(fp, &cur_level, sizeof(cur_level));
|
||||
r_read(fp, &max_level, sizeof(max_level));
|
||||
read_string(hunger_str, fp, sizeof hunger_str);
|
||||
|
||||
(void)strlcpy(tbuf, login_name, sizeof tbuf);
|
||||
read_string(login_name, fp, sizeof login_name);
|
||||
if (strcmp(tbuf, login_name)) {
|
||||
clean_up("you're not the original player");
|
||||
}
|
||||
|
||||
r_read(fp, &party_room, sizeof(party_room));
|
||||
read_pack(&level_monsters, fp, 0);
|
||||
read_pack(&level_objects, fp, 0);
|
||||
r_read(fp, &saved_file_id, sizeof(saved_file_id));
|
||||
if (new_file_id != saved_file_id) {
|
||||
clean_up("sorry, saved game is not in the same file");
|
||||
}
|
||||
rw_dungeon(fp, 0);
|
||||
r_read(fp, &foods, sizeof(foods));
|
||||
r_read(fp, &rogue, sizeof(fighter));
|
||||
read_pack(&rogue.pack, fp, 1);
|
||||
rw_id(id_potions, fp, POTIONS, 0);
|
||||
rw_id(id_scrolls, fp, SCROLS, 0);
|
||||
rw_id(id_wands, fp, WANDS, 0);
|
||||
rw_id(id_rings, fp, RINGS, 0);
|
||||
r_read(fp, traps, (MAX_TRAPS * sizeof(trap)));
|
||||
r_read(fp, is_wood, (WANDS * sizeof(boolean)));
|
||||
r_read(fp, &cur_room, sizeof(cur_room));
|
||||
rw_rooms(fp, 0);
|
||||
r_read(fp, &being_held, sizeof(being_held));
|
||||
r_read(fp, &bear_trap, sizeof(bear_trap));
|
||||
r_read(fp, &halluc, sizeof(halluc));
|
||||
r_read(fp, &blind, sizeof(blind));
|
||||
r_read(fp, &confused, sizeof(confused));
|
||||
r_read(fp, &levitate, sizeof(levitate));
|
||||
r_read(fp, &haste_self, sizeof(haste_self));
|
||||
r_read(fp, &see_invisible, sizeof(see_invisible));
|
||||
r_read(fp, &detect_monster, sizeof(detect_monster));
|
||||
r_read(fp, &wizard, sizeof(wizard));
|
||||
r_read(fp, &score_only, sizeof(score_only));
|
||||
r_read(fp, &m_moves, sizeof(m_moves));
|
||||
r_read(fp, &saved_time, sizeof(saved_time));
|
||||
|
||||
if (fread(buf, 1, 1, fp) > 0) {
|
||||
clear();
|
||||
clean_up("extra characters in file");
|
||||
}
|
||||
|
||||
md_gfmt(fname, &mod_time); /* get file modification time */
|
||||
|
||||
if (has_been_touched(&saved_time, &mod_time)) {
|
||||
clear();
|
||||
clean_up("sorry, file has been touched");
|
||||
}
|
||||
if ((!wizard) && !md_df(fname)) {
|
||||
clean_up("cannot delete file");
|
||||
}
|
||||
msg_cleared = 0;
|
||||
ring_stats(0);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void
|
||||
write_pack(const object *pack, FILE *fp)
|
||||
{
|
||||
object t;
|
||||
|
||||
while ((pack = pack->next_object) != NULL) {
|
||||
r_write(fp, pack, sizeof(object));
|
||||
}
|
||||
t.ichar = t.what_is = 0;
|
||||
r_write(fp, &t, sizeof(object));
|
||||
}
|
||||
|
||||
static void
|
||||
read_pack(object *pack, FILE *fp, boolean is_rogue)
|
||||
{
|
||||
object read_obj, *new_obj;
|
||||
|
||||
for (;;) {
|
||||
r_read(fp, &read_obj, sizeof(object));
|
||||
if (read_obj.ichar == 0) {
|
||||
pack->next_object = NULL;
|
||||
break;
|
||||
}
|
||||
new_obj = alloc_object();
|
||||
*new_obj = read_obj;
|
||||
if (is_rogue) {
|
||||
if (new_obj->in_use_flags & BEING_WORN) {
|
||||
do_wear(new_obj);
|
||||
} else if (new_obj->in_use_flags & BEING_WIELDED) {
|
||||
do_wield(new_obj);
|
||||
} else if (new_obj->in_use_flags & (ON_EITHER_HAND)) {
|
||||
do_put_on(new_obj,
|
||||
((new_obj->in_use_flags & ON_LEFT_HAND) ? 1 : 0));
|
||||
}
|
||||
}
|
||||
pack->next_object = new_obj;
|
||||
pack = new_obj;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rw_dungeon(FILE *fp, boolean rw)
|
||||
{
|
||||
short i, j;
|
||||
char buf[DCOLS];
|
||||
|
||||
for (i = 0; i < DROWS; i++) {
|
||||
if (rw) {
|
||||
r_write(fp, dungeon[i], (DCOLS * sizeof(dungeon[0][0])));
|
||||
for (j = 0; j < DCOLS; j++) {
|
||||
buf[j] = mvinch(i, j);
|
||||
}
|
||||
r_write(fp, buf, DCOLS);
|
||||
} else {
|
||||
r_read(fp, dungeon[i], (DCOLS * sizeof(dungeon[0][0])));
|
||||
r_read(fp, buf, DCOLS);
|
||||
for (j = 0; j < DCOLS; j++) {
|
||||
mvaddch(i, j, buf[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rw_id(struct id id_table[], FILE *fp, int n, boolean wr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (wr) {
|
||||
r_write(fp, &id_table[i].value, sizeof(short));
|
||||
r_write(fp, &id_table[i].id_status,
|
||||
sizeof(unsigned short));
|
||||
write_string(id_table[i].title, fp);
|
||||
} else {
|
||||
r_read(fp, &id_table[i].value, sizeof(short));
|
||||
r_read(fp, &id_table[i].id_status,
|
||||
sizeof(unsigned short));
|
||||
read_string(id_table[i].title, fp, MAX_ID_TITLE_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_string(char *s, FILE *fp)
|
||||
{
|
||||
short n;
|
||||
|
||||
n = strlen(s) + 1;
|
||||
xxxx(s, n);
|
||||
r_write(fp, &n, sizeof(short));
|
||||
r_write(fp, s, n);
|
||||
}
|
||||
|
||||
static void
|
||||
read_string(char *s, FILE *fp, size_t len)
|
||||
{
|
||||
short n;
|
||||
|
||||
r_read(fp, &n, sizeof(short));
|
||||
if (n<=0 || (size_t)(unsigned short)n > len) {
|
||||
clean_up("read_string: corrupt game file");
|
||||
}
|
||||
r_read(fp, s, n);
|
||||
xxxx(s, n);
|
||||
/* ensure null termination */
|
||||
s[n-1] = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rw_rooms(FILE *fp, boolean rw)
|
||||
{
|
||||
short i;
|
||||
|
||||
for (i = 0; i < MAXROOMS; i++) {
|
||||
rw ? r_write(fp, (rooms + i), sizeof(room)) :
|
||||
r_read(fp, (rooms + i), sizeof(room));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
r_read(FILE *fp, void *buf, size_t n)
|
||||
{
|
||||
if (fread(buf, 1, n, fp) != n) {
|
||||
clean_up("fread() failed, don't know why");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
r_write(FILE *fp, const void *buf, size_t n)
|
||||
{
|
||||
if (!write_failed) {
|
||||
if (fwrite(buf, 1, n, fp) != n) {
|
||||
messagef(0, "write() failed, don't know why");
|
||||
sound_bell();
|
||||
write_failed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static boolean
|
||||
has_been_touched(const struct rogue_time *saved_time,
|
||||
const struct rogue_time *mod_time)
|
||||
{
|
||||
if (saved_time->year < mod_time->year) {
|
||||
return(1);
|
||||
} else if (saved_time->year > mod_time->year) {
|
||||
return(0);
|
||||
}
|
||||
if (saved_time->month < mod_time->month) {
|
||||
return(1);
|
||||
} else if (saved_time->month > mod_time->month) {
|
||||
return(0);
|
||||
}
|
||||
if (saved_time->day < mod_time->day) {
|
||||
return(1);
|
||||
} else if (saved_time->day > mod_time->day) {
|
||||
return(0);
|
||||
}
|
||||
if (saved_time->hour < mod_time->hour) {
|
||||
return(1);
|
||||
} else if (saved_time->hour > mod_time->hour) {
|
||||
return(0);
|
||||
}
|
||||
if (saved_time->minute < mod_time->minute) {
|
||||
return(1);
|
||||
} else if (saved_time->minute > mod_time->minute) {
|
||||
return(0);
|
||||
}
|
||||
if (saved_time->second < mod_time->second) {
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
674
games/rogue/score.c
Normal file
674
games/rogue/score.c
Normal file
|
@ -0,0 +1,674 @@
|
|||
/* $NetBSD: score.c,v 1.16 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[] = "@(#)score.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: score.c,v 1.16 2011/08/26 06:18:17 dholland Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* score.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 <stdio.h>
|
||||
#include "rogue.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
static void center(short, const char *);
|
||||
static int get_value(const object *);
|
||||
static void id_all(void);
|
||||
static void sell_pack(void);
|
||||
static void sf_error(void) __dead;
|
||||
|
||||
void
|
||||
killed_by(const object *monster, short other)
|
||||
{
|
||||
const char *mechanism = "killed by something unknown (?)";
|
||||
char mechanism_buf[128];
|
||||
const char *article;
|
||||
char message_buf[128];
|
||||
|
||||
md_ignore_signals();
|
||||
|
||||
if (other != QUIT) {
|
||||
rogue.gold = ((rogue.gold * 9) / 10);
|
||||
}
|
||||
|
||||
if (other) {
|
||||
switch(other) {
|
||||
case HYPOTHERMIA:
|
||||
mechanism = "died of hypothermia";
|
||||
break;
|
||||
case STARVATION:
|
||||
mechanism = "died of starvation";
|
||||
break;
|
||||
case POISON_DART:
|
||||
mechanism = "killed by a dart";
|
||||
break;
|
||||
case QUIT:
|
||||
mechanism = "quit";
|
||||
break;
|
||||
case KFIRE:
|
||||
mechanism = "killed by fire";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (is_vowel(m_names[monster->m_char - 'A'][0])) {
|
||||
article = "an";
|
||||
} else {
|
||||
article = "a";
|
||||
}
|
||||
snprintf(mechanism_buf, sizeof(mechanism_buf),
|
||||
"Killed by %s %s",
|
||||
article, m_names[monster->m_char - 'A']);
|
||||
mechanism = mechanism_buf;
|
||||
}
|
||||
snprintf(message_buf, sizeof(message_buf),
|
||||
"%s with %ld gold", mechanism, rogue.gold);
|
||||
|
||||
if ((!other) && (!no_skull)) {
|
||||
clear();
|
||||
mvaddstr(4, 32, "__---------__");
|
||||
mvaddstr(5, 30, "_~ ~_");
|
||||
mvaddstr(6, 29, "/ \\");
|
||||
mvaddstr(7, 28, "~ ~");
|
||||
mvaddstr(8, 27, "/ \\");
|
||||
mvaddstr(9, 27, "| XXXX XXXX |");
|
||||
mvaddstr(10, 27, "| XXXX XXXX |");
|
||||
mvaddstr(11, 27, "| XXX XXX |");
|
||||
mvaddstr(12, 28, "\\ @ /");
|
||||
mvaddstr(13, 29, "--\\ @@@ /--");
|
||||
mvaddstr(14, 30, "| | @@@ | |");
|
||||
mvaddstr(15, 30, "| | | |");
|
||||
mvaddstr(16, 30, "| vvVvvvvvvvVvv |");
|
||||
mvaddstr(17, 30, "| ^^^^^^^^^^^ |");
|
||||
mvaddstr(18, 31, "\\_ _/");
|
||||
mvaddstr(19, 33, "~---------~");
|
||||
center(21, nick_name);
|
||||
center(22, message_buf);
|
||||
} else {
|
||||
messagef(0, "%s", message_buf);
|
||||
}
|
||||
messagef(0, "%s", ""); /* gcc objects to just "" */
|
||||
put_scores(monster, other);
|
||||
}
|
||||
|
||||
void
|
||||
win(void)
|
||||
{
|
||||
unwield(rogue.weapon); /* disarm and relax */
|
||||
unwear(rogue.armor);
|
||||
un_put_on(rogue.left_ring);
|
||||
un_put_on(rogue.right_ring);
|
||||
|
||||
clear();
|
||||
mvaddstr(10, 11, "@ @ @@@ @ @ @ @ @ @@@ @ @ @");
|
||||
mvaddstr(11, 11, " @ @ @ @ @ @ @ @ @ @ @ @@ @ @");
|
||||
mvaddstr(12, 11, " @ @ @ @ @ @ @ @ @ @ @ @ @ @");
|
||||
mvaddstr(13, 11, " @ @ @ @ @ @ @ @ @ @ @ @@");
|
||||
mvaddstr(14, 11, " @ @@@ @@@ @@ @@ @@@ @ @ @");
|
||||
mvaddstr(17, 11, "Congratulations, you have been admitted to the");
|
||||
mvaddstr(18, 11, "Fighters' Guild. You return home, sell all your");
|
||||
mvaddstr(19, 11, "treasures at great profit and retire into comfort.");
|
||||
messagef(0, "%s", ""); /* gcc objects to just "" */
|
||||
messagef(0, "%s", ""); /* gcc objects to just "" */
|
||||
id_all();
|
||||
sell_pack();
|
||||
put_scores(NULL, WIN);
|
||||
}
|
||||
|
||||
void
|
||||
quit(boolean from_intrpt)
|
||||
{
|
||||
char buf[DCOLS];
|
||||
short i, orow, ocol;
|
||||
boolean mc;
|
||||
|
||||
orow = ocol = 0;
|
||||
mc = FALSE;
|
||||
md_ignore_signals();
|
||||
|
||||
if (from_intrpt) {
|
||||
orow = rogue.row;
|
||||
ocol = rogue.col;
|
||||
|
||||
mc = msg_cleared;
|
||||
|
||||
for (i = 0; i < DCOLS; i++) {
|
||||
buf[i] = mvinch(0, i);
|
||||
}
|
||||
}
|
||||
check_message();
|
||||
messagef(1, "really quit?");
|
||||
if (rgetchar() != 'y') {
|
||||
md_heed_signals();
|
||||
check_message();
|
||||
if (from_intrpt) {
|
||||
for (i = 0; i < DCOLS; i++) {
|
||||
mvaddch(0, i, buf[i]);
|
||||
}
|
||||
msg_cleared = mc;
|
||||
move(orow, ocol);
|
||||
refresh();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (from_intrpt) {
|
||||
clean_up(byebye_string);
|
||||
}
|
||||
check_message();
|
||||
killed_by(NULL, QUIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* The score file on disk is up to ten entries of the form
|
||||
* score block [80 bytes]
|
||||
* nickname block [30 bytes]
|
||||
*
|
||||
* The score block is to be parsed as follows:
|
||||
* bytes 0-1 Rank (" 1" to "10")
|
||||
* bytes 2-4 space padding
|
||||
* bytes 5-15 Score/gold
|
||||
* byte 15 up to a ':' Login name
|
||||
* past the ':' Death mechanism
|
||||
*
|
||||
* The nickname block is an alternate name to be printed in place of the
|
||||
* login name. Both blocks are supposed to contain a null-terminator.
|
||||
*/
|
||||
|
||||
struct score_entry {
|
||||
long gold;
|
||||
char username[80];
|
||||
char death[80];
|
||||
char nickname[30];
|
||||
};
|
||||
|
||||
#define NUM_SCORE_ENTRIES 10
|
||||
|
||||
static void make_score(struct score_entry *, const object *, int);
|
||||
|
||||
static
|
||||
void
|
||||
pad_spaces(char *str, size_t len)
|
||||
{
|
||||
size_t x;
|
||||
for (x=strlen(str); x<len-1; x++) {
|
||||
str[x] = ' ';
|
||||
}
|
||||
str[len-1] = 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
unpad_spaces(char *str)
|
||||
{
|
||||
size_t x;
|
||||
for (x=strlen(str); x>0 && str[x-1]==' '; x--);
|
||||
str[x] = 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
read_score_entry(struct score_entry *se, FILE *fp)
|
||||
{
|
||||
char score_block[80];
|
||||
char nickname_block[30];
|
||||
size_t n, x;
|
||||
|
||||
n = fread(score_block, 1, sizeof(score_block), fp);
|
||||
if (n==0) {
|
||||
/* EOF */
|
||||
return 0;
|
||||
}
|
||||
if (n != sizeof(score_block)) {
|
||||
sf_error();
|
||||
}
|
||||
|
||||
n = fread(nickname_block, 1, sizeof(nickname_block), fp);
|
||||
if (n != sizeof(nickname_block)) {
|
||||
sf_error();
|
||||
}
|
||||
|
||||
xxxx(score_block, sizeof(score_block));
|
||||
xxxx(nickname_block, sizeof(nickname_block));
|
||||
|
||||
/* Ensure null termination */
|
||||
score_block[sizeof(score_block)-1] = 0;
|
||||
nickname_block[sizeof(nickname_block)-1] = 0;
|
||||
|
||||
/* If there are other nulls in the score block, file is corrupt */
|
||||
if (strlen(score_block)!=sizeof(score_block)-1) {
|
||||
sf_error();
|
||||
}
|
||||
/* but this is NOT true of the nickname block */
|
||||
|
||||
/* quash trailing spaces */
|
||||
unpad_spaces(score_block);
|
||||
unpad_spaces(nickname_block);
|
||||
|
||||
for (x=5; score_block[x] == ' '; x++);
|
||||
se->gold = lget_number(score_block+x);
|
||||
|
||||
for (x=15; score_block[x] != 0 && score_block[x] != ':'; x++);
|
||||
if (score_block[x] == 0) {
|
||||
sf_error();
|
||||
}
|
||||
score_block[x++] = 0;
|
||||
strlcpy(se->username, score_block+15, sizeof(se->username));
|
||||
|
||||
strlcpy(se->death, score_block+x, sizeof(se->death));
|
||||
strlcpy(se->nickname, nickname_block, sizeof(se->nickname));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
write_score_entry(const struct score_entry *se, int rank, FILE *fp)
|
||||
{
|
||||
char score_block[80];
|
||||
char nickname_block[30];
|
||||
|
||||
/* avoid writing crap to score file */
|
||||
memset(score_block, 0, sizeof(score_block));
|
||||
memset(nickname_block, 0, sizeof(nickname_block));
|
||||
|
||||
snprintf(score_block, sizeof(score_block),
|
||||
"%2d %6ld %s: %s",
|
||||
rank+1, se->gold, se->username, se->death);
|
||||
strlcpy(nickname_block, se->nickname, sizeof(nickname_block));
|
||||
|
||||
/* pad blocks out with spaces */
|
||||
pad_spaces(score_block, sizeof(score_block));
|
||||
/*pad_spaces(nickname_block, sizeof(nickname_block)); -- wrong! */
|
||||
|
||||
xxxx(score_block, sizeof(score_block));
|
||||
xxxx(nickname_block, sizeof(nickname_block));
|
||||
|
||||
fwrite(score_block, 1, sizeof(score_block), fp);
|
||||
fwrite(nickname_block, 1, sizeof(nickname_block), fp);
|
||||
}
|
||||
|
||||
void
|
||||
put_scores(const object *monster, short other)
|
||||
{
|
||||
short i, rank=-1, found_player = -1, numscores = 0;
|
||||
struct score_entry scores[NUM_SCORE_ENTRIES];
|
||||
const char *name;
|
||||
FILE *fp;
|
||||
boolean dopause = score_only;
|
||||
|
||||
md_lock(1);
|
||||
|
||||
setegid(egid);
|
||||
if ((fp = fopen(_PATH_SCOREFILE, "r+")) == NULL &&
|
||||
(fp = fopen(_PATH_SCOREFILE, "w+")) == NULL) {
|
||||
setegid(gid);
|
||||
messagef(0, "cannot read/write/create score file");
|
||||
sf_error();
|
||||
}
|
||||
setegid(gid);
|
||||
rewind(fp);
|
||||
(void)xxx(1);
|
||||
|
||||
for (numscores = 0; numscores < NUM_SCORE_ENTRIES; numscores++) {
|
||||
if (read_score_entry(&scores[numscores], fp) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Search the score list. */
|
||||
for (i=0; i<numscores; i++) {
|
||||
if (!strcmp(scores[i].username, login_name)) {
|
||||
/* found our score */
|
||||
if (rogue.gold < scores[i].gold) {
|
||||
/* we didn't do as well as last time */
|
||||
score_only = 1;
|
||||
} else {
|
||||
/* we did better; mark entry for removal */
|
||||
found_player = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove a superseded entry, if any. */
|
||||
if (found_player != -1) {
|
||||
numscores--;
|
||||
for (i = found_player; i < numscores; i++) {
|
||||
scores[i] = scores[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're going to insert ourselves, do it now */
|
||||
if (!score_only) {
|
||||
|
||||
/* if we aren't better than anyone, add at end. */
|
||||
rank = numscores;
|
||||
|
||||
/* Otherwise, find our slot. */
|
||||
for (i = 0; i < numscores; i++) {
|
||||
if (rogue.gold >= scores[i].gold) {
|
||||
rank = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rank < NUM_SCORE_ENTRIES) {
|
||||
/* Open up a slot */
|
||||
for (i = numscores; i > rank; i--) {
|
||||
scores[i] = scores[i-1];
|
||||
}
|
||||
numscores++;
|
||||
|
||||
/* Put our info in the slot */
|
||||
make_score(&scores[rank], monster, other);
|
||||
}
|
||||
|
||||
/* Now rewrite the score file */
|
||||
|
||||
md_ignore_signals();
|
||||
rewind(fp);
|
||||
(void)xxx(1);
|
||||
|
||||
for (i = 0; i < numscores; i++) {
|
||||
write_score_entry(&scores[i], i, fp);
|
||||
}
|
||||
}
|
||||
md_lock(0);
|
||||
fclose(fp);
|
||||
|
||||
/* Display the scores */
|
||||
|
||||
clear();
|
||||
mvaddstr(3, 30, "Top Ten Rogueists");
|
||||
mvaddstr(8, 0, "Rank Score Name");
|
||||
|
||||
for (i = 0; i < numscores; i++) {
|
||||
if (i == rank) {
|
||||
standout();
|
||||
}
|
||||
|
||||
if (scores[i].nickname[0]) {
|
||||
name = scores[i].nickname;
|
||||
} else {
|
||||
name = scores[i].username;
|
||||
}
|
||||
|
||||
mvprintw(i+10, 0, "%2d %6ld %s: %s",
|
||||
i+1, scores[i].gold, name, scores[i].death);
|
||||
|
||||
if (i == rank) {
|
||||
standend();
|
||||
}
|
||||
}
|
||||
refresh();
|
||||
messagef(0, "%s", ""); /* gcc objects to just "" */
|
||||
if (dopause) {
|
||||
messagef(0, "%s", "");
|
||||
}
|
||||
clean_up("");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
make_score(struct score_entry *se, const object *monster, int other)
|
||||
{
|
||||
const char *death = "bolts from the blue (?)";
|
||||
const char *hasamulet;
|
||||
char deathbuf[80];
|
||||
|
||||
se->gold = rogue.gold;
|
||||
strlcpy(se->username, login_name, sizeof(se->username));
|
||||
|
||||
if (other) {
|
||||
switch(other) {
|
||||
case HYPOTHERMIA:
|
||||
death = "died of hypothermia";
|
||||
break;
|
||||
case STARVATION:
|
||||
death = "died of starvation";
|
||||
break;
|
||||
case POISON_DART:
|
||||
death = "killed by a dart";
|
||||
break;
|
||||
case QUIT:
|
||||
death = "quit";
|
||||
break;
|
||||
case WIN:
|
||||
death = "a total winner";
|
||||
break;
|
||||
case KFIRE:
|
||||
death = "killed by fire";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
const char *mn, *article;
|
||||
|
||||
mn = m_names[monster->m_char - 'A'];
|
||||
if (is_vowel(mn[0])) {
|
||||
article = "an";
|
||||
} else {
|
||||
article = "a";
|
||||
}
|
||||
|
||||
snprintf(deathbuf, sizeof(deathbuf),
|
||||
"killed by %s %s", article, mn);
|
||||
death = deathbuf;
|
||||
}
|
||||
|
||||
if (other != WIN && has_amulet()) {
|
||||
hasamulet = " with amulet";
|
||||
} else {
|
||||
hasamulet = "";
|
||||
}
|
||||
|
||||
snprintf(se->death, sizeof(se->death), "%s on level %d%s",
|
||||
death, max_level, hasamulet);
|
||||
|
||||
strlcpy(se->nickname, nick_name, sizeof(se->nickname));
|
||||
}
|
||||
|
||||
boolean
|
||||
is_vowel(short ch)
|
||||
{
|
||||
return( (ch == 'a') ||
|
||||
(ch == 'e') ||
|
||||
(ch == 'i') ||
|
||||
(ch == 'o') ||
|
||||
(ch == 'u') );
|
||||
}
|
||||
|
||||
static void
|
||||
sell_pack(void)
|
||||
{
|
||||
object *obj;
|
||||
short row = 2, val;
|
||||
char buf[DCOLS];
|
||||
|
||||
obj = rogue.pack.next_object;
|
||||
|
||||
clear();
|
||||
mvaddstr(1, 0, "Value Item");
|
||||
|
||||
while (obj) {
|
||||
if (obj->what_is != FOOD) {
|
||||
obj->identified = 1;
|
||||
val = get_value(obj);
|
||||
rogue.gold += val;
|
||||
|
||||
if (row < DROWS) {
|
||||
get_desc(obj, buf, sizeof(buf));
|
||||
mvprintw(row++, 0, "%5d %s", val, buf);
|
||||
}
|
||||
}
|
||||
obj = obj->next_object;
|
||||
}
|
||||
refresh();
|
||||
if (rogue.gold > MAX_GOLD) {
|
||||
rogue.gold = MAX_GOLD;
|
||||
}
|
||||
messagef(0, "%s", ""); /* gcc objects to just "" */
|
||||
}
|
||||
|
||||
static int
|
||||
get_value(const object *obj)
|
||||
{
|
||||
short wc;
|
||||
int val;
|
||||
|
||||
val = 0;
|
||||
wc = obj->which_kind;
|
||||
|
||||
switch(obj->what_is) {
|
||||
case WEAPON:
|
||||
val = id_weapons[wc].value;
|
||||
if ((wc == ARROW) || (wc == DAGGER) || (wc == SHURIKEN) ||
|
||||
(wc == DART)) {
|
||||
val *= obj->quantity;
|
||||
}
|
||||
val += (obj->d_enchant * 85);
|
||||
val += (obj->hit_enchant * 85);
|
||||
break;
|
||||
case ARMOR:
|
||||
val = id_armors[wc].value;
|
||||
val += (obj->d_enchant * 75);
|
||||
if (obj->is_protected) {
|
||||
val += 200;
|
||||
}
|
||||
break;
|
||||
case WAND:
|
||||
val = id_wands[wc].value * (obj->class + 1);
|
||||
break;
|
||||
case SCROL:
|
||||
val = id_scrolls[wc].value * obj->quantity;
|
||||
break;
|
||||
case POTION:
|
||||
val = id_potions[wc].value * obj->quantity;
|
||||
break;
|
||||
case AMULET:
|
||||
val = 5000;
|
||||
break;
|
||||
case RING:
|
||||
val = id_rings[wc].value * (obj->class + 1);
|
||||
break;
|
||||
}
|
||||
if (val <= 0) {
|
||||
val = 10;
|
||||
}
|
||||
return(val);
|
||||
}
|
||||
|
||||
static void
|
||||
id_all(void)
|
||||
{
|
||||
short i;
|
||||
|
||||
for (i = 0; i < SCROLS; i++) {
|
||||
id_scrolls[i].id_status = IDENTIFIED;
|
||||
}
|
||||
for (i = 0; i < WEAPONS; i++) {
|
||||
id_weapons[i].id_status = IDENTIFIED;
|
||||
}
|
||||
for (i = 0; i < ARMORS; i++) {
|
||||
id_armors[i].id_status = IDENTIFIED;
|
||||
}
|
||||
for (i = 0; i < WANDS; i++) {
|
||||
id_wands[i].id_status = IDENTIFIED;
|
||||
}
|
||||
for (i = 0; i < POTIONS; i++) {
|
||||
id_potions[i].id_status = IDENTIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xxxx(char *buf, short n)
|
||||
{
|
||||
short i;
|
||||
unsigned char c;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
|
||||
/* It does not matter if accuracy is lost during this assignment */
|
||||
c = (unsigned char)xxx(0);
|
||||
|
||||
buf[i] ^= c;
|
||||
}
|
||||
}
|
||||
|
||||
long
|
||||
xxx(boolean st)
|
||||
{
|
||||
static long f, s;
|
||||
long r;
|
||||
|
||||
if (st) {
|
||||
f = 37;
|
||||
s = 7;
|
||||
return(0L);
|
||||
}
|
||||
r = ((f * s) + 9337) % 8887;
|
||||
f = s;
|
||||
s = r;
|
||||
return(r);
|
||||
}
|
||||
|
||||
static void
|
||||
center(short row, const char *buf)
|
||||
{
|
||||
short margin;
|
||||
|
||||
margin = ((DCOLS - strlen(buf)) / 2);
|
||||
mvaddstr(row, margin, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
sf_error(void)
|
||||
{
|
||||
md_lock(0);
|
||||
messagef(1, "%s", ""); /* gcc objects to just "" */
|
||||
clean_up("sorry, score file is out of order");
|
||||
}
|
536
games/rogue/spec_hit.c
Normal file
536
games/rogue/spec_hit.c
Normal file
|
@ -0,0 +1,536 @@
|
|||
/* $NetBSD: spec_hit.c,v 1.9 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[] = "@(#)spec_hit.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: spec_hit.c,v 1.9 2011/05/23 23:01:17 joerg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* special_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 void disappear(object *);
|
||||
static void drain_life(void);
|
||||
static void drop_level(void);
|
||||
static void freeze(object *);
|
||||
static int get_dir(short, short, short, short);
|
||||
static boolean gold_at(short, short);
|
||||
static void steal_gold(object *);
|
||||
static void steal_item(object *);
|
||||
static void sting(object *);
|
||||
static boolean try_to_cough(short, short, object *);
|
||||
|
||||
short less_hp = 0;
|
||||
boolean being_held;
|
||||
|
||||
void
|
||||
special_hit(object *monster)
|
||||
{
|
||||
if ((monster->m_flags & CONFUSED) && rand_percent(66)) {
|
||||
return;
|
||||
}
|
||||
if (monster->m_flags & RUSTS) {
|
||||
rust(monster);
|
||||
}
|
||||
if ((monster->m_flags & HOLDS) && !levitate) {
|
||||
being_held = 1;
|
||||
}
|
||||
if (monster->m_flags & FREEZES) {
|
||||
freeze(monster);
|
||||
}
|
||||
if (monster->m_flags & STINGS) {
|
||||
sting(monster);
|
||||
}
|
||||
if (monster->m_flags & DRAINS_LIFE) {
|
||||
drain_life();
|
||||
}
|
||||
if (monster->m_flags & DROPS_LEVEL) {
|
||||
drop_level();
|
||||
}
|
||||
if (monster->m_flags & STEALS_GOLD) {
|
||||
steal_gold(monster);
|
||||
} else if (monster->m_flags & STEALS_ITEM) {
|
||||
steal_item(monster);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rust(object *monster)
|
||||
{
|
||||
if ((!rogue.armor) || (get_armor_class(rogue.armor) <= 1) ||
|
||||
(rogue.armor->which_kind == LEATHER)) {
|
||||
return;
|
||||
}
|
||||
if ((rogue.armor->is_protected) || maintain_armor) {
|
||||
if (monster && (!(monster->m_flags & RUST_VANISHED))) {
|
||||
messagef(0, "the rust vanishes instantly");
|
||||
monster->m_flags |= RUST_VANISHED;
|
||||
}
|
||||
} else {
|
||||
rogue.armor->d_enchant--;
|
||||
messagef(0, "your armor weakens");
|
||||
print_stats(STAT_ARMOR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
freeze(object *monster)
|
||||
{
|
||||
short freeze_percent = 99;
|
||||
short i, n;
|
||||
|
||||
if (rand_percent(12)) {
|
||||
return;
|
||||
}
|
||||
freeze_percent -= (rogue.str_current+(rogue.str_current / 2));
|
||||
freeze_percent -= ((rogue.exp + ring_exp) * 4);
|
||||
freeze_percent -= (get_armor_class(rogue.armor) * 5);
|
||||
freeze_percent -= (rogue.hp_max / 3);
|
||||
|
||||
if (freeze_percent > 10) {
|
||||
monster->m_flags |= FREEZING_ROGUE;
|
||||
messagef(1, "you are frozen");
|
||||
|
||||
n = get_rand(4, 8);
|
||||
for (i = 0; i < n; i++) {
|
||||
mv_mons();
|
||||
}
|
||||
if (rand_percent(freeze_percent)) {
|
||||
for (i = 0; i < 50; i++) {
|
||||
mv_mons();
|
||||
}
|
||||
killed_by(NULL, HYPOTHERMIA);
|
||||
}
|
||||
messagef(1, "%s", you_can_move_again);
|
||||
monster->m_flags &= (~FREEZING_ROGUE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
steal_gold(object *monster)
|
||||
{
|
||||
int amount;
|
||||
|
||||
if ((rogue.gold <= 0) || rand_percent(10)) {
|
||||
return;
|
||||
}
|
||||
|
||||
amount = get_rand((cur_level * 10), (cur_level * 30));
|
||||
|
||||
if (amount > rogue.gold) {
|
||||
amount = rogue.gold;
|
||||
}
|
||||
rogue.gold -= amount;
|
||||
messagef(0, "your purse feels lighter");
|
||||
print_stats(STAT_GOLD);
|
||||
disappear(monster);
|
||||
}
|
||||
|
||||
void
|
||||
steal_item(object *monster)
|
||||
{
|
||||
object *obj;
|
||||
short i, n, t = 0;
|
||||
char desc[80];
|
||||
boolean has_something = 0;
|
||||
|
||||
if (rand_percent(15)) {
|
||||
return;
|
||||
}
|
||||
obj = rogue.pack.next_object;
|
||||
|
||||
if (!obj) {
|
||||
goto DSPR;
|
||||
}
|
||||
while (obj) {
|
||||
if (!(obj->in_use_flags & BEING_USED)) {
|
||||
has_something = 1;
|
||||
break;
|
||||
}
|
||||
obj = obj->next_object;
|
||||
}
|
||||
if (!has_something) {
|
||||
goto DSPR;
|
||||
}
|
||||
n = get_rand(0, MAX_PACK_COUNT);
|
||||
obj = rogue.pack.next_object;
|
||||
|
||||
for (i = 0; i <= n; i++) {
|
||||
obj = obj->next_object;
|
||||
while ((!obj) || (obj->in_use_flags & BEING_USED)) {
|
||||
if (!obj) {
|
||||
obj = rogue.pack.next_object;
|
||||
} else {
|
||||
obj = obj->next_object;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (obj->what_is != WEAPON) {
|
||||
t = obj->quantity;
|
||||
obj->quantity = 1;
|
||||
}
|
||||
get_desc(obj, desc, sizeof(desc));
|
||||
messagef(0, "she stole %s", desc);
|
||||
|
||||
obj->quantity = ((obj->what_is != WEAPON) ? t : 1);
|
||||
|
||||
vanish(obj, 0, &rogue.pack);
|
||||
DSPR:
|
||||
disappear(monster);
|
||||
}
|
||||
|
||||
static void
|
||||
disappear(object *monster)
|
||||
{
|
||||
short row, col;
|
||||
|
||||
row = monster->row;
|
||||
col = monster->col;
|
||||
|
||||
dungeon[row][col] &= ~MONSTER;
|
||||
if (rogue_can_see(row, col)) {
|
||||
mvaddch(row, col, get_dungeon_char(row, col));
|
||||
}
|
||||
take_from_pack(monster, &level_monsters);
|
||||
free_object(monster);
|
||||
mon_disappeared = 1;
|
||||
}
|
||||
|
||||
void
|
||||
cough_up(object *monster)
|
||||
{
|
||||
object *obj;
|
||||
short row, col, i, n;
|
||||
|
||||
if (cur_level < max_level) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (monster->m_flags & STEALS_GOLD) {
|
||||
obj = alloc_object();
|
||||
obj->what_is = GOLD;
|
||||
obj->quantity = get_rand((cur_level * 15), (cur_level * 30));
|
||||
} else {
|
||||
if (!rand_percent((int)monster->drop_percent)) {
|
||||
return;
|
||||
}
|
||||
obj = gr_object();
|
||||
}
|
||||
row = monster->row;
|
||||
col = monster->col;
|
||||
|
||||
for (n = 0; n <= 5; n++) {
|
||||
for (i = -n; i <= n; i++) {
|
||||
if (try_to_cough(row+n, col+i, obj)) {
|
||||
return;
|
||||
}
|
||||
if (try_to_cough(row-n, col+i, obj)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i = -n; i <= n; i++) {
|
||||
if (try_to_cough(row+i, col-n, obj)) {
|
||||
return;
|
||||
}
|
||||
if (try_to_cough(row+i, col+n, obj)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
free_object(obj);
|
||||
}
|
||||
|
||||
static boolean
|
||||
try_to_cough(short row, short col, object *obj)
|
||||
{
|
||||
if ((row < MIN_ROW) ||
|
||||
(row > (DROWS-2)) || (col < 0) || (col>(DCOLS-1))) {
|
||||
return(0);
|
||||
}
|
||||
if ((!(dungeon[row][col] & (OBJECT | STAIRS | TRAP))) &&
|
||||
(dungeon[row][col] & (TUNNEL | FLOOR | DOOR))) {
|
||||
place_at(obj, row, col);
|
||||
if (((row != rogue.row) || (col != rogue.col)) &&
|
||||
(!(dungeon[row][col] & MONSTER))) {
|
||||
mvaddch(row, col, get_dungeon_char(row, col));
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
boolean
|
||||
seek_gold(object *monster)
|
||||
{
|
||||
short i, j, rn, s;
|
||||
|
||||
if ((rn = get_room_number(monster->row, monster->col)) < 0) {
|
||||
return(0);
|
||||
}
|
||||
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 ((gold_at(i, j)) && !(dungeon[i][j] & MONSTER)) {
|
||||
monster->m_flags |= CAN_FLIT;
|
||||
s = mon_can_go(monster, i, j);
|
||||
monster->m_flags &= (~CAN_FLIT);
|
||||
if (s) {
|
||||
move_mon_to(monster, i, j);
|
||||
monster->m_flags |= ASLEEP;
|
||||
monster->m_flags &= (~(WAKENS | SEEKS_GOLD));
|
||||
return(1);
|
||||
}
|
||||
monster->m_flags &= (~SEEKS_GOLD);
|
||||
monster->m_flags |= CAN_FLIT;
|
||||
mv_1_monster(monster, i, j);
|
||||
monster->m_flags &= (~CAN_FLIT);
|
||||
monster->m_flags |= SEEKS_GOLD;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static boolean
|
||||
gold_at(short row, short col)
|
||||
{
|
||||
if (dungeon[row][col] & OBJECT) {
|
||||
object *obj;
|
||||
|
||||
if ((obj = object_at(&level_objects, row, col)) &&
|
||||
(obj->what_is == GOLD)) {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
check_gold_seeker(object *monster)
|
||||
{
|
||||
monster->m_flags &= (~SEEKS_GOLD);
|
||||
}
|
||||
|
||||
boolean
|
||||
check_imitator(object *monster)
|
||||
{
|
||||
if (monster->m_flags & IMITATES) {
|
||||
wake_up(monster);
|
||||
if (!blind) {
|
||||
mvaddch(monster->row, monster->col,
|
||||
get_dungeon_char(monster->row, monster->col));
|
||||
check_message();
|
||||
messagef(1, "wait, that's a %s!", mon_name(monster));
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
boolean
|
||||
imitating(short row, short col)
|
||||
{
|
||||
if (dungeon[row][col] & MONSTER) {
|
||||
object *monster;
|
||||
|
||||
if ((monster = object_at(&level_monsters, row, col)) != NULL) {
|
||||
if (monster->m_flags & IMITATES) {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void
|
||||
sting(object *monster)
|
||||
{
|
||||
short sting_chance = 35;
|
||||
|
||||
if ((rogue.str_current <= 3) || sustain_strength) {
|
||||
return;
|
||||
}
|
||||
sting_chance += (6 * (6 - get_armor_class(rogue.armor)));
|
||||
|
||||
if ((rogue.exp + ring_exp) > 8) {
|
||||
sting_chance -= (6 * ((rogue.exp + ring_exp) - 8));
|
||||
}
|
||||
if (rand_percent(sting_chance)) {
|
||||
messagef(0, "the %s's bite has weakened you",
|
||||
mon_name(monster));
|
||||
rogue.str_current--;
|
||||
print_stats(STAT_STRENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drop_level(void)
|
||||
{
|
||||
int hp;
|
||||
|
||||
if (rand_percent(80) || (rogue.exp <= 5)) {
|
||||
return;
|
||||
}
|
||||
rogue.exp_points = level_points[rogue.exp-2] - get_rand(9, 29);
|
||||
rogue.exp -= 2;
|
||||
hp = hp_raise();
|
||||
if ((rogue.hp_current -= hp) <= 0) {
|
||||
rogue.hp_current = 1;
|
||||
}
|
||||
if ((rogue.hp_max -= hp) <= 0) {
|
||||
rogue.hp_max = 1;
|
||||
}
|
||||
add_exp(1, 0);
|
||||
}
|
||||
|
||||
void
|
||||
drain_life(void)
|
||||
{
|
||||
short n;
|
||||
|
||||
if (rand_percent(60) || (rogue.hp_max <= 30) || (rogue.hp_current < 10)) {
|
||||
return;
|
||||
}
|
||||
n = get_rand(1, 3); /* 1 Hp, 2 Str, 3 both */
|
||||
|
||||
if ((n != 2) || (!sustain_strength)) {
|
||||
messagef(0, "you feel weaker");
|
||||
}
|
||||
if (n != 2) {
|
||||
rogue.hp_max--;
|
||||
rogue.hp_current--;
|
||||
less_hp++;
|
||||
}
|
||||
if (n != 1) {
|
||||
if ((rogue.str_current > 3) && (!sustain_strength)) {
|
||||
rogue.str_current--;
|
||||
if (coin_toss()) {
|
||||
rogue.str_max--;
|
||||
}
|
||||
}
|
||||
}
|
||||
print_stats((STAT_STRENGTH | STAT_HP));
|
||||
}
|
||||
|
||||
boolean
|
||||
m_confuse(object *monster)
|
||||
{
|
||||
if (!rogue_can_see(monster->row, monster->col)) {
|
||||
return(0);
|
||||
}
|
||||
if (rand_percent(45)) {
|
||||
monster->m_flags &= (~CONFUSES); /* will not confuse the rogue */
|
||||
return(0);
|
||||
}
|
||||
if (rand_percent(55)) {
|
||||
monster->m_flags &= (~CONFUSES);
|
||||
messagef(1, "the gaze of the %s has confused you",
|
||||
mon_name(monster));
|
||||
cnfs();
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
boolean
|
||||
flame_broil(object *monster)
|
||||
{
|
||||
short row, col, dir;
|
||||
|
||||
if ((!mon_sees(monster, rogue.row, rogue.col)) || coin_toss()) {
|
||||
return(0);
|
||||
}
|
||||
row = rogue.row - monster->row;
|
||||
col = rogue.col - monster->col;
|
||||
if (row < 0) {
|
||||
row = -row;
|
||||
}
|
||||
if (col < 0) {
|
||||
col = -col;
|
||||
}
|
||||
if (((row != 0) && (col != 0) && (row != col)) ||
|
||||
((row > 7) || (col > 7))) {
|
||||
return(0);
|
||||
}
|
||||
dir = get_dir(monster->row, monster->col, row, col);
|
||||
bounce(FIRE, dir, monster->row, monster->col, 0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
get_dir(short srow, short scol, short drow, short dcol)
|
||||
{
|
||||
if (srow == drow) {
|
||||
if (scol < dcol) {
|
||||
return(RIGHT);
|
||||
} else {
|
||||
return(LEFT);
|
||||
}
|
||||
}
|
||||
if (scol == dcol) {
|
||||
if (srow < drow) {
|
||||
return(DOWN);
|
||||
} else {
|
||||
return(UPWARD);
|
||||
}
|
||||
}
|
||||
if ((srow > drow) && (scol > dcol)) {
|
||||
return(UPLEFT);
|
||||
}
|
||||
if ((srow < drow) && (scol < dcol)) {
|
||||
return(DOWNRIGHT);
|
||||
}
|
||||
if ((srow < drow) && (scol > dcol)) {
|
||||
return(DOWNLEFT);
|
||||
}
|
||||
/*if ((srow > drow) && (scol < dcol)) {*/
|
||||
return(UPRIGHT);
|
||||
/*}*/
|
||||
}
|
324
games/rogue/throw.c
Normal file
324
games/rogue/throw.c
Normal file
|
@ -0,0 +1,324 @@
|
|||
/* $NetBSD: throw.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[] = "@(#)throw.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: throw.c,v 1.12 2011/05/23 23:01:17 joerg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* throw.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 void flop_weapon(object *, short, short);
|
||||
static object *get_thrown_at_monster(object *, short, short *, short *);
|
||||
static boolean throw_at_monster(object *, object *);
|
||||
|
||||
void
|
||||
throw(void)
|
||||
{
|
||||
short wch, d;
|
||||
boolean first_miss = 1;
|
||||
object *weapon;
|
||||
short dir, row, col;
|
||||
object *monster;
|
||||
|
||||
while (!is_direction(dir = rgetchar(), &d)) {
|
||||
sound_bell();
|
||||
if (first_miss) {
|
||||
messagef(0, "direction? ");
|
||||
first_miss = 0;
|
||||
}
|
||||
}
|
||||
check_message();
|
||||
if (dir == CANCEL) {
|
||||
return;
|
||||
}
|
||||
if ((wch = pack_letter("throw what?", WEAPON)) == CANCEL) {
|
||||
return;
|
||||
}
|
||||
check_message();
|
||||
|
||||
if (!(weapon = get_letter_object(wch))) {
|
||||
messagef(0, "no such item.");
|
||||
return;
|
||||
}
|
||||
if ((weapon->in_use_flags & BEING_USED) && weapon->is_cursed) {
|
||||
messagef(0, "%s", curse_message);
|
||||
return;
|
||||
}
|
||||
row = rogue.row; col = rogue.col;
|
||||
|
||||
if ((weapon->in_use_flags & BEING_WIELDED) && (weapon->quantity <= 1)) {
|
||||
unwield(rogue.weapon);
|
||||
} else if (weapon->in_use_flags & BEING_WORN) {
|
||||
mv_aquatars();
|
||||
unwear(rogue.armor);
|
||||
print_stats(STAT_ARMOR);
|
||||
} else if (weapon->in_use_flags & ON_EITHER_HAND) {
|
||||
un_put_on(weapon);
|
||||
}
|
||||
monster = get_thrown_at_monster(weapon, d, &row, &col);
|
||||
mvaddch(rogue.row, rogue.col, rogue.fchar);
|
||||
refresh();
|
||||
|
||||
if (rogue_can_see(row, col) && ((row != rogue.row) || (col != rogue.col))){
|
||||
mvaddch(row, col, get_dungeon_char(row, col));
|
||||
}
|
||||
if (monster) {
|
||||
wake_up(monster);
|
||||
check_gold_seeker(monster);
|
||||
|
||||
if (!throw_at_monster(monster, weapon)) {
|
||||
flop_weapon(weapon, row, col);
|
||||
}
|
||||
} else {
|
||||
flop_weapon(weapon, row, col);
|
||||
}
|
||||
vanish(weapon, 1, &rogue.pack);
|
||||
}
|
||||
|
||||
boolean
|
||||
throw_at_monster(object *monster, object *weapon)
|
||||
{
|
||||
short damage, hit_chance;
|
||||
short t;
|
||||
|
||||
hit_chance = get_hit_chance(weapon);
|
||||
damage = get_weapon_damage(weapon);
|
||||
if ((weapon->which_kind == ARROW) &&
|
||||
(rogue.weapon && (rogue.weapon->which_kind == BOW))) {
|
||||
damage += get_weapon_damage(rogue.weapon);
|
||||
damage = ((damage * 2) / 3);
|
||||
hit_chance += (hit_chance / 3);
|
||||
} else if ((weapon->in_use_flags & BEING_WIELDED) &&
|
||||
((weapon->which_kind == DAGGER) ||
|
||||
(weapon->which_kind == SHURIKEN) ||
|
||||
(weapon->which_kind == DART))) {
|
||||
damage = ((damage * 3) / 2);
|
||||
hit_chance += (hit_chance / 3);
|
||||
}
|
||||
t = weapon->quantity;
|
||||
weapon->quantity = 1;
|
||||
snprintf(hit_message, HIT_MESSAGE_SIZE, "the %s", name_of(weapon));
|
||||
weapon->quantity = t;
|
||||
|
||||
if (!rand_percent(hit_chance)) {
|
||||
(void)strlcat(hit_message, "misses ", HIT_MESSAGE_SIZE);
|
||||
return(0);
|
||||
}
|
||||
s_con_mon(monster);
|
||||
(void)strlcat(hit_message, "hit ", HIT_MESSAGE_SIZE);
|
||||
(void)mon_damage(monster, damage);
|
||||
return(1);
|
||||
}
|
||||
|
||||
object *
|
||||
get_thrown_at_monster(object *obj, short dir, short *row, short *col)
|
||||
{
|
||||
short orow, ocol;
|
||||
short i, ch;
|
||||
|
||||
orow = *row; ocol = *col;
|
||||
|
||||
ch = get_mask_char(obj->what_is);
|
||||
|
||||
for (i = 0; i < 24; i++) {
|
||||
get_dir_rc(dir, row, col, 0);
|
||||
if ( (((*col <= 0) || (*col >= DCOLS-1)) ||
|
||||
(dungeon[*row][*col] == NOTHING)) ||
|
||||
((dungeon[*row][*col] & (HORWALL | VERTWALL | HIDDEN)) &&
|
||||
(!(dungeon[*row][*col] & TRAP)))) {
|
||||
*row = orow;
|
||||
*col = ocol;
|
||||
return(0);
|
||||
}
|
||||
if ((i != 0) && rogue_can_see(orow, ocol)) {
|
||||
mvaddch(orow, ocol, get_dungeon_char(orow, ocol));
|
||||
}
|
||||
if (rogue_can_see(*row, *col)) {
|
||||
if (!(dungeon[*row][*col] & MONSTER)) {
|
||||
mvaddch(*row, *col, ch);
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
orow = *row; ocol = *col;
|
||||
if (dungeon[*row][*col] & MONSTER) {
|
||||
if (!imitating(*row, *col)) {
|
||||
return(object_at(&level_monsters, *row, *col));
|
||||
}
|
||||
}
|
||||
if (dungeon[*row][*col] & TUNNEL) {
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
flop_weapon(object *weapon, short row, short col)
|
||||
{
|
||||
object *new_weapon, *monster;
|
||||
short i = 0;
|
||||
boolean found = 0;
|
||||
short mch, dch;
|
||||
unsigned short mon;
|
||||
|
||||
if ((row < 0) || (row >= DROWS) || (col < 0) || (col >= DCOLS))
|
||||
clean_up("flop_weapon: weapon landed outside of dungeon");
|
||||
|
||||
while ((i < 9) && dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER)) {
|
||||
rand_around(i++, &row, &col);
|
||||
if ((row > (DROWS-2)) || (row < MIN_ROW) ||
|
||||
(col > (DCOLS-1)) || (col < 0) || (!dungeon[row][col]) ||
|
||||
(dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER))) {
|
||||
continue;
|
||||
}
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (found || (i == 0)) {
|
||||
new_weapon = alloc_object();
|
||||
*new_weapon = *weapon;
|
||||
new_weapon->in_use_flags = NOT_USED;
|
||||
new_weapon->quantity = 1;
|
||||
new_weapon->ichar = 'L';
|
||||
place_at(new_weapon, row, col);
|
||||
if (rogue_can_see(row, col) &&
|
||||
((row != rogue.row) || (col != rogue.col))) {
|
||||
mon = dungeon[row][col] & MONSTER;
|
||||
dungeon[row][col] &= (~MONSTER);
|
||||
dch = get_dungeon_char(row, col);
|
||||
if (mon) {
|
||||
mch = mvinch(row, col);
|
||||
if ((monster = object_at(&level_monsters,
|
||||
row, col)) != NULL) {
|
||||
monster->trail_char = dch;
|
||||
}
|
||||
if ((mch < 'A') || (mch > 'Z')) {
|
||||
mvaddch(row, col, dch);
|
||||
}
|
||||
} else {
|
||||
mvaddch(row, col, dch);
|
||||
}
|
||||
dungeon[row][col] |= mon;
|
||||
}
|
||||
} else {
|
||||
short t;
|
||||
|
||||
t = weapon->quantity;
|
||||
weapon->quantity = 1;
|
||||
messagef(0, "the %svanishes as it hits the ground",
|
||||
name_of(weapon));
|
||||
weapon->quantity = t;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rand_around(short i, short *r, short *c)
|
||||
{
|
||||
static char pos[] = "\010\007\001\003\004\005\002\006\0";
|
||||
static short row, col;
|
||||
short j;
|
||||
|
||||
if (i == 0) {
|
||||
short x, y, o, t;
|
||||
|
||||
row = *r;
|
||||
col = *c;
|
||||
|
||||
o = get_rand(1, 8);
|
||||
|
||||
for (j = 0; j < 5; j++) {
|
||||
x = get_rand(0, 8);
|
||||
y = (x + o) % 9;
|
||||
t = pos[x];
|
||||
pos[x] = pos[y];
|
||||
pos[y] = t;
|
||||
}
|
||||
}
|
||||
switch((short)pos[i]) {
|
||||
case 0:
|
||||
*r = row + 1;
|
||||
*c = col + 1;
|
||||
break;
|
||||
case 1:
|
||||
*r = row + 1;
|
||||
*c = col - 1;
|
||||
break;
|
||||
case 2:
|
||||
*r = row - 1;
|
||||
*c = col + 1;
|
||||
break;
|
||||
case 3:
|
||||
*r = row - 1;
|
||||
*c = col - 1;
|
||||
break;
|
||||
case 4:
|
||||
*r = row;
|
||||
*c = col + 1;
|
||||
break;
|
||||
case 5:
|
||||
*r = row + 1;
|
||||
*c = col;
|
||||
break;
|
||||
case 6:
|
||||
*r = row;
|
||||
*c = col;
|
||||
break;
|
||||
case 7:
|
||||
*r = row - 1;
|
||||
*c = col;
|
||||
break;
|
||||
case 8:
|
||||
*r = row;
|
||||
*c = col - 1;
|
||||
break;
|
||||
}
|
||||
}
|
282
games/rogue/trap.c
Normal file
282
games/rogue/trap.c
Normal file
|
@ -0,0 +1,282 @@
|
|||
/* $NetBSD: trap.c,v 1.10 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[] = "@(#)trap.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: trap.c,v 1.10 2009/08/12 08:44:45 dholland Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* trap.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"
|
||||
|
||||
trap traps[MAX_TRAPS];
|
||||
boolean trap_door = 0;
|
||||
short bear_trap = 0;
|
||||
|
||||
static const char *const trap_strings[TRAPS * 2] = {
|
||||
"trap door",
|
||||
"you fell down a trap",
|
||||
"bear trap",
|
||||
"you are caught in a bear trap",
|
||||
"teleport trap",
|
||||
"teleport",
|
||||
"poison dart trap",
|
||||
"a small dart just hit you in the shoulder",
|
||||
"sleeping gas trap",
|
||||
"a strange white mist envelops you and you fall asleep",
|
||||
"rust trap",
|
||||
"a gush of water hits you on the head"
|
||||
};
|
||||
|
||||
static short
|
||||
trap_at(int row, int col)
|
||||
{
|
||||
short i;
|
||||
|
||||
for (i = 0; ((i < MAX_TRAPS) && (traps[i].trap_type != NO_TRAP)); i++) {
|
||||
if ((traps[i].trap_row == row) && (traps[i].trap_col == col)) {
|
||||
return(traps[i].trap_type);
|
||||
}
|
||||
}
|
||||
return(NO_TRAP);
|
||||
}
|
||||
|
||||
void
|
||||
trap_player(short row, short col)
|
||||
{
|
||||
short t;
|
||||
|
||||
if ((t = trap_at(row, col)) == NO_TRAP) {
|
||||
return;
|
||||
}
|
||||
dungeon[row][col] &= (~HIDDEN);
|
||||
if (rand_percent(rogue.exp + ring_exp)) {
|
||||
messagef(1, "the trap failed");
|
||||
return;
|
||||
}
|
||||
switch(t) {
|
||||
case TRAP_DOOR:
|
||||
trap_door = 1;
|
||||
new_level_message = trap_strings[(t*2)+1];
|
||||
break;
|
||||
case BEAR_TRAP:
|
||||
messagef(1, "%s", trap_strings[(t*2)+1]);
|
||||
bear_trap = get_rand(4, 7);
|
||||
break;
|
||||
case TELE_TRAP:
|
||||
mvaddch(rogue.row, rogue.col, '^');
|
||||
tele();
|
||||
break;
|
||||
case DART_TRAP:
|
||||
messagef(1, "%s", trap_strings[(t*2)+1]);
|
||||
rogue.hp_current -= get_damage("1d6", 1);
|
||||
if (rogue.hp_current <= 0) {
|
||||
rogue.hp_current = 0;
|
||||
}
|
||||
if ((!sustain_strength) && rand_percent(40) &&
|
||||
(rogue.str_current >= 3)) {
|
||||
rogue.str_current--;
|
||||
}
|
||||
print_stats(STAT_HP | STAT_STRENGTH);
|
||||
if (rogue.hp_current <= 0) {
|
||||
killed_by((object *)0, POISON_DART);
|
||||
}
|
||||
break;
|
||||
case SLEEPING_GAS_TRAP:
|
||||
messagef(1, "%s", trap_strings[(t*2)+1]);
|
||||
take_a_nap();
|
||||
break;
|
||||
case RUST_TRAP:
|
||||
messagef(1, "%s", trap_strings[(t*2)+1]);
|
||||
rust(NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
add_traps(void)
|
||||
{
|
||||
short i, n, tries = 0;
|
||||
short row, col;
|
||||
|
||||
if (cur_level <= 2) {
|
||||
n = 0;
|
||||
} else if (cur_level <= 7) {
|
||||
n = get_rand(0, 2);
|
||||
} else if (cur_level <= 11) {
|
||||
n = get_rand(1, 2);
|
||||
} else if (cur_level <= 16) {
|
||||
n = get_rand(2, 3);
|
||||
} else if (cur_level <= 21) {
|
||||
n = get_rand(2, 4);
|
||||
} else if (cur_level <= (AMULET_LEVEL + 2)) {
|
||||
n = get_rand(3, 5);
|
||||
} else {
|
||||
n = get_rand(5, MAX_TRAPS);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
traps[i].trap_type = get_rand(0, (TRAPS - 1));
|
||||
|
||||
if ((i == 0) && (party_room != NO_ROOM)) {
|
||||
do {
|
||||
row = get_rand((rooms[party_room].top_row+1),
|
||||
(rooms[party_room].bottom_row-1));
|
||||
col = get_rand((rooms[party_room].left_col+1),
|
||||
(rooms[party_room].right_col-1));
|
||||
tries++;
|
||||
} while (((dungeon[row][col] & (OBJECT|STAIRS|TRAP|TUNNEL)) ||
|
||||
(dungeon[row][col] == NOTHING)) && (tries < 15));
|
||||
if (tries >= 15) {
|
||||
gr_row_col(&row, &col, (FLOOR | MONSTER));
|
||||
}
|
||||
} else {
|
||||
gr_row_col(&row, &col, (FLOOR | MONSTER));
|
||||
}
|
||||
traps[i].trap_row = row;
|
||||
traps[i].trap_col = col;
|
||||
dungeon[row][col] |= (TRAP | HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
id_trap(void)
|
||||
{
|
||||
short dir, row, col, d, t;
|
||||
|
||||
messagef(0, "direction? ");
|
||||
|
||||
while (!is_direction(dir = rgetchar(), &d)) {
|
||||
sound_bell();
|
||||
}
|
||||
check_message();
|
||||
|
||||
if (dir == CANCEL) {
|
||||
return;
|
||||
}
|
||||
row = rogue.row;
|
||||
col = rogue.col;
|
||||
|
||||
get_dir_rc(d, &row, &col, 0);
|
||||
|
||||
if ((dungeon[row][col] & TRAP) && (!(dungeon[row][col] & HIDDEN))) {
|
||||
t = trap_at(row, col);
|
||||
messagef(0, "%s", trap_strings[t*2]);
|
||||
} else {
|
||||
messagef(0, "no trap there");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
show_traps(void)
|
||||
{
|
||||
short i, j;
|
||||
|
||||
for (i = 0; i < DROWS; i++) {
|
||||
for (j = 0; j < DCOLS; j++) {
|
||||
if (dungeon[i][j] & TRAP) {
|
||||
mvaddch(i, j, '^');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
search(short n, boolean is_auto)
|
||||
{
|
||||
short s, i, j, row, col, t;
|
||||
short shown = 0, found = 0;
|
||||
static boolean reg_search;
|
||||
|
||||
for (i = -1; i <= 1; i++) {
|
||||
for (j = -1; j <= 1; j++) {
|
||||
row = rogue.row + i;
|
||||
col = rogue.col + j;
|
||||
if ((row < MIN_ROW) || (row >= (DROWS-1)) ||
|
||||
(col < 0) || (col >= DCOLS)) {
|
||||
continue;
|
||||
}
|
||||
if (dungeon[row][col] & HIDDEN) {
|
||||
found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (s = 0; s < n; s++) {
|
||||
for (i = -1; i <= 1; i++) {
|
||||
for (j = -1; j <= 1; j++) {
|
||||
row = rogue.row + i;
|
||||
col = rogue.col + j ;
|
||||
if ((row < MIN_ROW) || (row >= (DROWS-1)) ||
|
||||
(col < 0) || (col >= DCOLS)) {
|
||||
continue;
|
||||
}
|
||||
if (dungeon[row][col] & HIDDEN) {
|
||||
if (rand_percent(17 + (rogue.exp + ring_exp))) {
|
||||
dungeon[row][col] &= (~HIDDEN);
|
||||
if ((!blind) && ((row != rogue.row) ||
|
||||
(col != rogue.col))) {
|
||||
mvaddch(row, col, get_dungeon_char(row, col));
|
||||
}
|
||||
shown++;
|
||||
if (dungeon[row][col] & TRAP) {
|
||||
t = trap_at(row, col);
|
||||
messagef(1, "%s",
|
||||
trap_strings[t*2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (((shown == found) && (found > 0)) || interrupted) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((!is_auto) && (reg_search = !reg_search)) {
|
||||
(void)reg_move();
|
||||
}
|
||||
}
|
||||
}
|
625
games/rogue/use.c
Normal file
625
games/rogue/use.c
Normal file
|
@ -0,0 +1,625 @@
|
|||
/* $NetBSD: use.c,v 1.10 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[] = "@(#)use.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: use.c,v 1.10 2009/08/12 08:44:45 dholland Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* use.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 halluc = 0;
|
||||
short blind = 0;
|
||||
short confused = 0;
|
||||
short levitate = 0;
|
||||
short haste_self = 0;
|
||||
boolean see_invisible = 0;
|
||||
short extra_hp = 0;
|
||||
boolean detect_monster = 0;
|
||||
boolean con_mon = 0;
|
||||
|
||||
static const char strange_feeling[] =
|
||||
"you have a strange feeling for a moment, then it passes";
|
||||
|
||||
static const char *get_ench_color(void);
|
||||
static void go_blind(void);
|
||||
static void hold_monster(void);
|
||||
static void idntfy(void);
|
||||
static void potion_heal(int);
|
||||
static void uncurse_all(void);
|
||||
|
||||
void
|
||||
quaff(void)
|
||||
{
|
||||
short ch;
|
||||
object *obj;
|
||||
|
||||
ch = pack_letter("quaff what?", POTION);
|
||||
|
||||
if (ch == CANCEL) {
|
||||
return;
|
||||
}
|
||||
if (!(obj = get_letter_object(ch))) {
|
||||
messagef(0, "no such item.");
|
||||
return;
|
||||
}
|
||||
if (obj->what_is != POTION) {
|
||||
messagef(0, "you can't drink that");
|
||||
return;
|
||||
}
|
||||
switch(obj->which_kind) {
|
||||
case INCREASE_STRENGTH:
|
||||
messagef(0, "you feel stronger now, what bulging muscles!");
|
||||
rogue.str_current++;
|
||||
if (rogue.str_current > rogue.str_max) {
|
||||
rogue.str_max = rogue.str_current;
|
||||
}
|
||||
break;
|
||||
case RESTORE_STRENGTH:
|
||||
rogue.str_current = rogue.str_max;
|
||||
messagef(0, "this tastes great, you feel warm all over");
|
||||
break;
|
||||
case HEALING:
|
||||
messagef(0, "you begin to feel better");
|
||||
potion_heal(0);
|
||||
break;
|
||||
case EXTRA_HEALING:
|
||||
messagef(0, "you begin to feel much better");
|
||||
potion_heal(1);
|
||||
break;
|
||||
case POISON:
|
||||
if (!sustain_strength) {
|
||||
rogue.str_current -= get_rand(1, 3);
|
||||
if (rogue.str_current < 1) {
|
||||
rogue.str_current = 1;
|
||||
}
|
||||
}
|
||||
messagef(0, "you feel very sick now");
|
||||
if (halluc) {
|
||||
unhallucinate();
|
||||
}
|
||||
break;
|
||||
case RAISE_LEVEL:
|
||||
rogue.exp_points = level_points[rogue.exp - 1];
|
||||
messagef(0, "you suddenly feel much more skillful");
|
||||
add_exp(1, 1);
|
||||
break;
|
||||
case BLINDNESS:
|
||||
go_blind();
|
||||
break;
|
||||
case HALLUCINATION:
|
||||
messagef(0, "oh wow, everything seems so cosmic");
|
||||
halluc += get_rand(500, 800);
|
||||
break;
|
||||
case DETECT_MONSTER:
|
||||
show_monsters();
|
||||
if (!(level_monsters.next_monster)) {
|
||||
messagef(0, "%s", strange_feeling);
|
||||
}
|
||||
break;
|
||||
case DETECT_OBJECTS:
|
||||
if (level_objects.next_object) {
|
||||
if (!blind) {
|
||||
show_objects();
|
||||
}
|
||||
} else {
|
||||
messagef(0, "%s", strange_feeling);
|
||||
}
|
||||
break;
|
||||
case CONFUSION:
|
||||
messagef(0, (halluc ? "what a trippy feeling" :
|
||||
"you feel confused"));
|
||||
cnfs();
|
||||
break;
|
||||
case LEVITATION:
|
||||
messagef(0, "you start to float in the air");
|
||||
levitate += get_rand(15, 30);
|
||||
being_held = bear_trap = 0;
|
||||
break;
|
||||
case HASTE_SELF:
|
||||
messagef(0, "you feel yourself moving much faster");
|
||||
haste_self += get_rand(11, 21);
|
||||
if (!(haste_self % 2)) {
|
||||
haste_self++;
|
||||
}
|
||||
break;
|
||||
case SEE_INVISIBLE:
|
||||
messagef(0, "hmm, this potion tastes like %sjuice",
|
||||
fruit);
|
||||
if (blind) {
|
||||
unblind();
|
||||
}
|
||||
see_invisible = 1;
|
||||
relight();
|
||||
break;
|
||||
}
|
||||
print_stats((STAT_STRENGTH | STAT_HP));
|
||||
if (id_potions[obj->which_kind].id_status != CALLED) {
|
||||
id_potions[obj->which_kind].id_status = IDENTIFIED;
|
||||
}
|
||||
vanish(obj, 1, &rogue.pack);
|
||||
}
|
||||
|
||||
void
|
||||
read_scroll(void)
|
||||
{
|
||||
short ch;
|
||||
object *obj;
|
||||
|
||||
ch = pack_letter("read what?", SCROL);
|
||||
|
||||
if (ch == CANCEL) {
|
||||
return;
|
||||
}
|
||||
if (!(obj = get_letter_object(ch))) {
|
||||
messagef(0, "no such item.");
|
||||
return;
|
||||
}
|
||||
if (obj->what_is != SCROL) {
|
||||
messagef(0, "you can't read that");
|
||||
return;
|
||||
}
|
||||
switch(obj->which_kind) {
|
||||
case SCARE_MONSTER:
|
||||
messagef(0, "you hear a maniacal laughter in the distance");
|
||||
break;
|
||||
case HOLD_MONSTER:
|
||||
hold_monster();
|
||||
break;
|
||||
case ENCH_WEAPON:
|
||||
if (rogue.weapon) {
|
||||
if (rogue.weapon->what_is == WEAPON) {
|
||||
messagef(0, "your %sglow%s %sfor a moment",
|
||||
name_of(rogue.weapon),
|
||||
((rogue.weapon->quantity <= 1) ? "s" : ""),
|
||||
get_ench_color());
|
||||
if (coin_toss()) {
|
||||
rogue.weapon->hit_enchant++;
|
||||
} else {
|
||||
rogue.weapon->d_enchant++;
|
||||
}
|
||||
}
|
||||
rogue.weapon->is_cursed = 0;
|
||||
} else {
|
||||
messagef(0, "your hands tingle");
|
||||
}
|
||||
break;
|
||||
case ENCH_ARMOR:
|
||||
if (rogue.armor) {
|
||||
messagef(0, "your armor glows %sfor a moment",
|
||||
get_ench_color());
|
||||
rogue.armor->d_enchant++;
|
||||
rogue.armor->is_cursed = 0;
|
||||
print_stats(STAT_ARMOR);
|
||||
} else {
|
||||
messagef(0, "your skin crawls");
|
||||
}
|
||||
break;
|
||||
case IDENTIFY:
|
||||
messagef(0, "this is a scroll of identify");
|
||||
obj->identified = 1;
|
||||
id_scrolls[obj->which_kind].id_status = IDENTIFIED;
|
||||
idntfy();
|
||||
break;
|
||||
case TELEPORT:
|
||||
tele();
|
||||
break;
|
||||
case SLEEP:
|
||||
messagef(0, "you fall asleep");
|
||||
take_a_nap();
|
||||
break;
|
||||
case PROTECT_ARMOR:
|
||||
if (rogue.armor) {
|
||||
messagef(0, "your armor is covered by a shimmering gold shield");
|
||||
rogue.armor->is_protected = 1;
|
||||
rogue.armor->is_cursed = 0;
|
||||
} else {
|
||||
messagef(0, "your acne seems to have disappeared");
|
||||
}
|
||||
break;
|
||||
case REMOVE_CURSE:
|
||||
messagef(0, (!halluc) ?
|
||||
"you feel as though someone is watching over you" :
|
||||
"you feel in touch with the universal oneness");
|
||||
uncurse_all();
|
||||
break;
|
||||
case CREATE_MONSTER:
|
||||
create_monster();
|
||||
break;
|
||||
case AGGRAVATE_MONSTER:
|
||||
aggravate();
|
||||
break;
|
||||
case MAGIC_MAPPING:
|
||||
messagef(0, "this scroll seems to have a map on it");
|
||||
draw_magic_map();
|
||||
break;
|
||||
case CON_MON:
|
||||
con_mon = 1;
|
||||
messagef(0, "your hands glow %sfor a moment",
|
||||
get_ench_color());
|
||||
break;
|
||||
}
|
||||
if (id_scrolls[obj->which_kind].id_status != CALLED) {
|
||||
id_scrolls[obj->which_kind].id_status = IDENTIFIED;
|
||||
}
|
||||
vanish(obj, (obj->which_kind != SLEEP), &rogue.pack);
|
||||
}
|
||||
|
||||
/* vanish() does NOT handle a quiver of weapons with more than one
|
||||
* arrow (or whatever) in the quiver. It will only decrement the count.
|
||||
*/
|
||||
|
||||
void
|
||||
vanish(object *obj, short rm, object *pack)
|
||||
{
|
||||
if (obj->quantity > 1) {
|
||||
obj->quantity--;
|
||||
} else {
|
||||
if (obj->in_use_flags & BEING_WIELDED) {
|
||||
unwield(obj);
|
||||
} else if (obj->in_use_flags & BEING_WORN) {
|
||||
unwear(obj);
|
||||
} else if (obj->in_use_flags & ON_EITHER_HAND) {
|
||||
un_put_on(obj);
|
||||
}
|
||||
take_from_pack(obj, pack);
|
||||
free_object(obj);
|
||||
}
|
||||
if (rm) {
|
||||
(void)reg_move();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
potion_heal(int extra)
|
||||
{
|
||||
float ratio;
|
||||
short add;
|
||||
|
||||
rogue.hp_current += rogue.exp;
|
||||
|
||||
ratio = ((float)rogue.hp_current) / rogue.hp_max;
|
||||
|
||||
if (ratio >= 1.00) {
|
||||
rogue.hp_max += (extra ? 2 : 1);
|
||||
extra_hp += (extra ? 2 : 1);
|
||||
rogue.hp_current = rogue.hp_max;
|
||||
} else if (ratio >= 0.90) {
|
||||
rogue.hp_max += (extra ? 1 : 0);
|
||||
extra_hp += (extra ? 1 : 0);
|
||||
rogue.hp_current = rogue.hp_max;
|
||||
} else {
|
||||
if (ratio < 0.33) {
|
||||
ratio = 0.33;
|
||||
}
|
||||
if (extra) {
|
||||
ratio += ratio;
|
||||
}
|
||||
add = (short)(ratio * (rogue.hp_max - rogue.hp_current));
|
||||
rogue.hp_current += add;
|
||||
if (rogue.hp_current > rogue.hp_max) {
|
||||
rogue.hp_current = rogue.hp_max;
|
||||
}
|
||||
}
|
||||
if (blind) {
|
||||
unblind();
|
||||
}
|
||||
if (confused && extra) {
|
||||
unconfuse();
|
||||
} else if (confused) {
|
||||
confused = (confused / 2) + 1;
|
||||
}
|
||||
if (halluc && extra) {
|
||||
unhallucinate();
|
||||
} else if (halluc) {
|
||||
halluc = (halluc / 2) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
idntfy(void)
|
||||
{
|
||||
short ch;
|
||||
object *obj;
|
||||
struct id *id_table;
|
||||
char desc[DCOLS];
|
||||
AGAIN:
|
||||
ch = pack_letter("what would you like to identify?", ALL_OBJECTS);
|
||||
|
||||
if (ch == CANCEL) {
|
||||
return;
|
||||
}
|
||||
if (!(obj = get_letter_object(ch))) {
|
||||
messagef(0, "no such item, try again");
|
||||
messagef(0, "%s", ""); /* gcc objects to just "" */
|
||||
check_message();
|
||||
goto AGAIN;
|
||||
}
|
||||
obj->identified = 1;
|
||||
if (obj->what_is & (SCROL | POTION | WEAPON | ARMOR | WAND | RING)) {
|
||||
id_table = get_id_table(obj);
|
||||
id_table[obj->which_kind].id_status = IDENTIFIED;
|
||||
}
|
||||
get_desc(obj, desc, sizeof(desc));
|
||||
messagef(0, "%s", desc);
|
||||
}
|
||||
|
||||
void
|
||||
eat(void)
|
||||
{
|
||||
short ch;
|
||||
short moves;
|
||||
object *obj;
|
||||
|
||||
ch = pack_letter("eat what?", FOOD);
|
||||
|
||||
if (ch == CANCEL) {
|
||||
return;
|
||||
}
|
||||
if (!(obj = get_letter_object(ch))) {
|
||||
messagef(0, "no such item.");
|
||||
return;
|
||||
}
|
||||
if (obj->what_is != FOOD) {
|
||||
messagef(0, "you can't eat that");
|
||||
return;
|
||||
}
|
||||
if ((obj->which_kind == FRUIT) || rand_percent(60)) {
|
||||
moves = get_rand(950, 1150);
|
||||
if (obj->which_kind == RATION) {
|
||||
messagef(0, "yum, that tasted good");
|
||||
} else {
|
||||
messagef(0, "my, that was a yummy %s", fruit);
|
||||
}
|
||||
} else {
|
||||
moves = get_rand(750, 950);
|
||||
messagef(0, "yuk, that food tasted awful");
|
||||
add_exp(2, 1);
|
||||
}
|
||||
rogue.moves_left /= 3;
|
||||
rogue.moves_left += moves;
|
||||
hunger_str[0] = 0;
|
||||
print_stats(STAT_HUNGER);
|
||||
|
||||
vanish(obj, 1, &rogue.pack);
|
||||
}
|
||||
|
||||
static void
|
||||
hold_monster(void)
|
||||
{
|
||||
short i, j;
|
||||
short mcount = 0;
|
||||
object *monster;
|
||||
short row, col;
|
||||
|
||||
for (i = -2; i <= 2; i++) {
|
||||
for (j = -2; j <= 2; j++) {
|
||||
row = rogue.row + i;
|
||||
col = rogue.col + j;
|
||||
if ((row < MIN_ROW) || (row > (DROWS-2)) || (col < 0) ||
|
||||
(col > (DCOLS-1))) {
|
||||
continue;
|
||||
}
|
||||
if (dungeon[row][col] & MONSTER) {
|
||||
monster = object_at(&level_monsters, row, col);
|
||||
monster->m_flags |= ASLEEP;
|
||||
monster->m_flags &= (~WAKENS);
|
||||
mcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mcount == 0) {
|
||||
messagef(0, "you feel a strange sense of loss");
|
||||
} else if (mcount == 1) {
|
||||
messagef(0, "the monster freezes");
|
||||
} else {
|
||||
messagef(0, "the monsters around you freeze");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tele(void)
|
||||
{
|
||||
mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col));
|
||||
|
||||
if (cur_room >= 0) {
|
||||
darken_room(cur_room);
|
||||
}
|
||||
put_player(get_room_number(rogue.row, rogue.col));
|
||||
being_held = 0;
|
||||
bear_trap = 0;
|
||||
}
|
||||
|
||||
void
|
||||
hallucinate(void)
|
||||
{
|
||||
object *obj, *monster;
|
||||
short ch;
|
||||
|
||||
if (blind) return;
|
||||
|
||||
obj = level_objects.next_object;
|
||||
|
||||
while (obj) {
|
||||
ch = mvinch(obj->row, obj->col);
|
||||
if (((ch < 'A') || (ch > 'Z')) &&
|
||||
((obj->row != rogue.row) || (obj->col != rogue.col)))
|
||||
if ((ch != ' ') && (ch != '.') && (ch != '#') && (ch != '+')) {
|
||||
addch(gr_obj_char());
|
||||
}
|
||||
obj = obj->next_object;
|
||||
}
|
||||
monster = level_monsters.next_monster;
|
||||
|
||||
while (monster) {
|
||||
ch = mvinch(monster->row, monster->col);
|
||||
if ((ch >= 'A') && (ch <= 'Z')) {
|
||||
addch(get_rand('A', 'Z'));
|
||||
}
|
||||
monster = monster->next_monster;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
unhallucinate(void)
|
||||
{
|
||||
halluc = 0;
|
||||
relight();
|
||||
messagef(1, "everything looks SO boring now");
|
||||
}
|
||||
|
||||
void
|
||||
unblind(void)
|
||||
{
|
||||
blind = 0;
|
||||
messagef(1, "the veil of darkness lifts");
|
||||
relight();
|
||||
if (halluc) {
|
||||
hallucinate();
|
||||
}
|
||||
if (detect_monster) {
|
||||
show_monsters();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
relight(void)
|
||||
{
|
||||
if (cur_room == PASSAGE) {
|
||||
light_passage(rogue.row, rogue.col);
|
||||
} else {
|
||||
light_up_room(cur_room);
|
||||
}
|
||||
mvaddch(rogue.row, rogue.col, rogue.fchar);
|
||||
}
|
||||
|
||||
void
|
||||
take_a_nap(void)
|
||||
{
|
||||
short i;
|
||||
|
||||
i = get_rand(2, 5);
|
||||
md_sleep(1);
|
||||
|
||||
while (i--) {
|
||||
mv_mons();
|
||||
}
|
||||
md_sleep(1);
|
||||
messagef(0, "%s", you_can_move_again);
|
||||
}
|
||||
|
||||
static void
|
||||
go_blind(void)
|
||||
{
|
||||
short i, j;
|
||||
|
||||
if (!blind) {
|
||||
messagef(0, "a cloak of darkness falls around you");
|
||||
}
|
||||
blind += get_rand(500, 800);
|
||||
|
||||
if (detect_monster) {
|
||||
object *monster;
|
||||
|
||||
monster = level_monsters.next_monster;
|
||||
|
||||
while (monster) {
|
||||
mvaddch(monster->row, monster->col, monster->trail_char);
|
||||
monster = monster->next_monster;
|
||||
}
|
||||
}
|
||||
if (cur_room >= 0) {
|
||||
for (i = rooms[cur_room].top_row + 1;
|
||||
i < rooms[cur_room].bottom_row; i++) {
|
||||
for (j = rooms[cur_room].left_col + 1;
|
||||
j < rooms[cur_room].right_col; j++) {
|
||||
mvaddch(i, j, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
mvaddch(rogue.row, rogue.col, rogue.fchar);
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_ench_color(void)
|
||||
{
|
||||
if (halluc) {
|
||||
return(id_potions[get_rand(0, POTIONS-1)].title);
|
||||
} else if (con_mon) {
|
||||
return("red ");
|
||||
}
|
||||
return("blue ");
|
||||
}
|
||||
|
||||
void
|
||||
cnfs(void)
|
||||
{
|
||||
confused += get_rand(12, 22);
|
||||
}
|
||||
|
||||
void
|
||||
unconfuse(void)
|
||||
{
|
||||
confused = 0;
|
||||
messagef(1, "you feel less %s now", (halluc ? "trippy" : "confused"));
|
||||
}
|
||||
|
||||
static void
|
||||
uncurse_all(void)
|
||||
{
|
||||
object *obj;
|
||||
|
||||
obj = rogue.pack.next_object;
|
||||
|
||||
while (obj) {
|
||||
obj->is_cursed = 0;
|
||||
obj = obj->next_object;
|
||||
}
|
||||
}
|
407
games/rogue/zap.c
Normal file
407
games/rogue/zap.c
Normal file
|
@ -0,0 +1,407 @@
|
|||
/* $NetBSD: zap.c,v 1.9 2008/01/14 03:50:03 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[] = "@(#)zap.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: zap.c,v 1.9 2008/01/14 03:50:03 dholland Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* zap.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 object *get_zapped_monster(short, short *, short *);
|
||||
static void tele_away(object *);
|
||||
static void wdrain_life(object *);
|
||||
static void zap_monster(object *, unsigned short);
|
||||
|
||||
boolean wizard = 0;
|
||||
|
||||
void
|
||||
zapp(void)
|
||||
{
|
||||
short wch;
|
||||
boolean first_miss = 1;
|
||||
object *wand;
|
||||
short dir, d, row, col;
|
||||
object *monster;
|
||||
|
||||
while (!is_direction(dir = rgetchar(), &d)) {
|
||||
sound_bell();
|
||||
if (first_miss) {
|
||||
messagef(0, "direction? ");
|
||||
first_miss = 0;
|
||||
}
|
||||
}
|
||||
check_message();
|
||||
if (dir == CANCEL) {
|
||||
return;
|
||||
}
|
||||
if ((wch = pack_letter("zap with what?", WAND)) == CANCEL) {
|
||||
return;
|
||||
}
|
||||
check_message();
|
||||
|
||||
if (!(wand = get_letter_object(wch))) {
|
||||
messagef(0, "no such item.");
|
||||
return;
|
||||
}
|
||||
if (wand->what_is != WAND) {
|
||||
messagef(0, "you can't zap with that");
|
||||
return;
|
||||
}
|
||||
if (wand->class <= 0) {
|
||||
messagef(0, "nothing happens");
|
||||
} else {
|
||||
wand->class--;
|
||||
row = rogue.row; col = rogue.col;
|
||||
if ((wand->which_kind == COLD) || (wand->which_kind == FIRE)) {
|
||||
bounce((short)wand->which_kind, d, row, col, 0);
|
||||
} else {
|
||||
monster = get_zapped_monster(d, &row, &col);
|
||||
if (wand->which_kind == DRAIN_LIFE) {
|
||||
wdrain_life(monster);
|
||||
} else if (monster) {
|
||||
wake_up(monster);
|
||||
s_con_mon(monster);
|
||||
zap_monster(monster, wand->which_kind);
|
||||
relight();
|
||||
}
|
||||
}
|
||||
}
|
||||
(void)reg_move();
|
||||
}
|
||||
|
||||
static object *
|
||||
get_zapped_monster(short dir, short *row, short *col)
|
||||
{
|
||||
short orow, ocol;
|
||||
|
||||
for (;;) {
|
||||
orow = *row; ocol = *col;
|
||||
get_dir_rc(dir, row, col, 0);
|
||||
if (((*row == orow) && (*col == ocol)) ||
|
||||
(dungeon[*row][*col] & (HORWALL | VERTWALL)) ||
|
||||
(dungeon[*row][*col] == NOTHING)) {
|
||||
return(0);
|
||||
}
|
||||
if (dungeon[*row][*col] & MONSTER) {
|
||||
if (!imitating(*row, *col)) {
|
||||
return(object_at(&level_monsters, *row, *col));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
zap_monster(object *monster, unsigned short kind)
|
||||
{
|
||||
short row, col;
|
||||
object *nm;
|
||||
short tc;
|
||||
|
||||
row = monster->row;
|
||||
col = monster->col;
|
||||
|
||||
switch(kind) {
|
||||
case SLOW_MONSTER:
|
||||
if (monster->m_flags & HASTED) {
|
||||
monster->m_flags &= (~HASTED);
|
||||
} else {
|
||||
monster->slowed_toggle = 0;
|
||||
monster->m_flags |= SLOWED;
|
||||
}
|
||||
break;
|
||||
case HASTE_MONSTER:
|
||||
if (monster->m_flags & SLOWED) {
|
||||
monster->m_flags &= (~SLOWED);
|
||||
} else {
|
||||
monster->m_flags |= HASTED;
|
||||
}
|
||||
break;
|
||||
case TELE_AWAY:
|
||||
tele_away(monster);
|
||||
break;
|
||||
case INVISIBILITY:
|
||||
monster->m_flags |= INVISIBLE;
|
||||
break;
|
||||
case POLYMORPH:
|
||||
if (monster->m_flags & HOLDS) {
|
||||
being_held = 0;
|
||||
}
|
||||
nm = monster->next_monster;
|
||||
tc = monster->trail_char;
|
||||
(void)gr_monster(monster, get_rand(0, MONSTERS-1));
|
||||
monster->row = row;
|
||||
monster->col = col;
|
||||
monster->next_monster = nm;
|
||||
monster->trail_char = tc;
|
||||
if (!(monster->m_flags & IMITATES)) {
|
||||
wake_up(monster);
|
||||
}
|
||||
break;
|
||||
case MAGIC_MISSILE:
|
||||
rogue_hit(monster, 1);
|
||||
break;
|
||||
case CANCELLATION:
|
||||
if (monster->m_flags & HOLDS) {
|
||||
being_held = 0;
|
||||
}
|
||||
if (monster->m_flags & STEALS_ITEM) {
|
||||
monster->drop_percent = 0;
|
||||
}
|
||||
monster->m_flags &= (~(FLIES | FLITS | SPECIAL_HIT | INVISIBLE |
|
||||
FLAMES | IMITATES | CONFUSES | SEEKS_GOLD | HOLDS));
|
||||
break;
|
||||
case DO_NOTHING:
|
||||
messagef(0, "nothing happens");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tele_away(object *monster)
|
||||
{
|
||||
short row, col;
|
||||
|
||||
if (monster->m_flags & HOLDS) {
|
||||
being_held = 0;
|
||||
}
|
||||
gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
|
||||
mvaddch(monster->row, monster->col, monster->trail_char);
|
||||
dungeon[monster->row][monster->col] &= ~MONSTER;
|
||||
monster->row = row; monster->col = col;
|
||||
dungeon[row][col] |= MONSTER;
|
||||
monster->trail_char = mvinch(row, col);
|
||||
if (detect_monster || rogue_can_see(row, col)) {
|
||||
mvaddch(row, col, gmc(monster));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wizardize(void)
|
||||
{
|
||||
char buf[100];
|
||||
|
||||
if (wizard) {
|
||||
wizard = 0;
|
||||
messagef(0, "not wizard anymore");
|
||||
} else {
|
||||
if (get_input_line("wizard's password:", "", buf, sizeof(buf),
|
||||
"", 0, 0)) {
|
||||
(void)xxx(1);
|
||||
xxxx(buf, strlen(buf));
|
||||
if (!strncmp(buf, "\247\104\126\272\115\243\027", 7)) {
|
||||
wizard = 1;
|
||||
score_only = 1;
|
||||
messagef(0, "Welcome, mighty wizard!");
|
||||
} else {
|
||||
messagef(0, "sorry");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wdrain_life(object *monster)
|
||||
{
|
||||
short hp;
|
||||
object *lmon, *nm;
|
||||
|
||||
hp = rogue.hp_current / 3;
|
||||
rogue.hp_current = (rogue.hp_current + 1) / 2;
|
||||
|
||||
if (cur_room >= 0) {
|
||||
lmon = level_monsters.next_monster;
|
||||
while (lmon) {
|
||||
nm = lmon->next_monster;
|
||||
if (get_room_number(lmon->row, lmon->col) == cur_room) {
|
||||
wake_up(lmon);
|
||||
(void)mon_damage(lmon, hp);
|
||||
}
|
||||
lmon = nm;
|
||||
}
|
||||
} else {
|
||||
if (monster) {
|
||||
wake_up(monster);
|
||||
(void)mon_damage(monster, hp);
|
||||
}
|
||||
}
|
||||
print_stats(STAT_HP);
|
||||
relight();
|
||||
}
|
||||
|
||||
void
|
||||
bounce(short ball, short dir, short row, short col, short r)
|
||||
{
|
||||
short orow, ocol;
|
||||
const char *s;
|
||||
short i, ch, new_dir = -1, damage;
|
||||
static short btime;
|
||||
|
||||
if (++r == 1) {
|
||||
btime = get_rand(3, 6);
|
||||
} else if (r > btime) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ball == FIRE) {
|
||||
s = "fire";
|
||||
} else {
|
||||
s = "ice";
|
||||
}
|
||||
if (r > 1) {
|
||||
messagef(0, "the %s bounces", s);
|
||||
}
|
||||
orow = row;
|
||||
ocol = col;
|
||||
do {
|
||||
ch = mvinch(orow, ocol);
|
||||
standout();
|
||||
mvaddch(orow, ocol, ch);
|
||||
get_dir_rc(dir, &orow, &ocol, 1);
|
||||
} while (!( (ocol <= 0) ||
|
||||
(ocol >= DCOLS-1) ||
|
||||
(dungeon[orow][ocol] == NOTHING) ||
|
||||
(dungeon[orow][ocol] & MONSTER) ||
|
||||
(dungeon[orow][ocol] & (HORWALL | VERTWALL)) ||
|
||||
((orow == rogue.row) && (ocol == rogue.col))));
|
||||
standend();
|
||||
refresh();
|
||||
do {
|
||||
orow = row;
|
||||
ocol = col;
|
||||
ch = mvinch(row, col);
|
||||
mvaddch(row, col, ch);
|
||||
get_dir_rc(dir, &row, &col, 1);
|
||||
} while (!( (col <= 0) ||
|
||||
(col >= DCOLS-1) ||
|
||||
(dungeon[row][col] == NOTHING) ||
|
||||
(dungeon[row][col] & MONSTER) ||
|
||||
(dungeon[row][col] & (HORWALL | VERTWALL)) ||
|
||||
((row == rogue.row) && (col == rogue.col))));
|
||||
|
||||
if (dungeon[row][col] & MONSTER) {
|
||||
object *monster;
|
||||
|
||||
monster = object_at(&level_monsters, row, col);
|
||||
|
||||
wake_up(monster);
|
||||
if (rand_percent(33)) {
|
||||
messagef(0, "the %s misses the %s", s,
|
||||
mon_name(monster));
|
||||
goto ND;
|
||||
}
|
||||
if (ball == FIRE) {
|
||||
if (!(monster->m_flags & RUSTS)) {
|
||||
if (monster->m_flags & FREEZES) {
|
||||
damage = monster->hp_to_kill;
|
||||
} else if (monster->m_flags & FLAMES) {
|
||||
damage = (monster->hp_to_kill / 10) + 1;
|
||||
} else {
|
||||
damage = get_rand((rogue.hp_current / 3), rogue.hp_max);
|
||||
}
|
||||
} else {
|
||||
damage = (monster->hp_to_kill / 2) + 1;
|
||||
}
|
||||
messagef(0, "the %s hits the %s", s,
|
||||
mon_name(monster));
|
||||
(void)mon_damage(monster, damage);
|
||||
} else {
|
||||
damage = -1;
|
||||
if (!(monster->m_flags & FREEZES)) {
|
||||
if (rand_percent(33)) {
|
||||
messagef(0, "the monster is frozen");
|
||||
monster->m_flags |= (ASLEEP | NAPPING);
|
||||
monster->nap_length = get_rand(3, 6);
|
||||
} else {
|
||||
damage = rogue.hp_current / 4;
|
||||
}
|
||||
} else {
|
||||
damage = -2;
|
||||
}
|
||||
if (damage != -1) {
|
||||
messagef(0, "the %s hits the %s", s,
|
||||
mon_name(monster));
|
||||
(void)mon_damage(monster, damage);
|
||||
}
|
||||
}
|
||||
} else if ((row == rogue.row) && (col == rogue.col)) {
|
||||
if (rand_percent(10 + (3 * get_armor_class(rogue.armor)))) {
|
||||
messagef(0, "the %s misses", s);
|
||||
goto ND;
|
||||
} else {
|
||||
damage = get_rand(3, (3 * rogue.exp));
|
||||
if (ball == FIRE) {
|
||||
damage = (damage * 3) / 2;
|
||||
damage -= get_armor_class(rogue.armor);
|
||||
}
|
||||
rogue_damage(damage, NULL,
|
||||
((ball == FIRE) ? KFIRE : HYPOTHERMIA));
|
||||
messagef(0, "the %s hits", s);
|
||||
}
|
||||
} else {
|
||||
short nrow, ncol;
|
||||
|
||||
ND: for (i = 0; i < 10; i++) {
|
||||
dir = get_rand(0, DIRS-1);
|
||||
nrow = orow;
|
||||
ncol = ocol;
|
||||
get_dir_rc(dir, &nrow, &ncol, 1);
|
||||
if (((ncol >= 0) && (ncol <= DCOLS-1)) &&
|
||||
(dungeon[nrow][ncol] != NOTHING) &&
|
||||
(!(dungeon[nrow][ncol] & (VERTWALL | HORWALL)))) {
|
||||
new_dir = dir;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (new_dir != -1) {
|
||||
bounce(ball, new_dir, orow, ocol, r);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue