]> Zhao Yanbai Git Server - minix.git/commitdiff
Import NetBSD games/rogue 52/2952/2
authorRobin Karlsson <s.r.karlsson@gmail.com>
Sat, 14 Mar 2015 03:29:23 +0000 (04:29 +0100)
committerLionel Sambuc <lionel.sambuc@gmail.com>
Sat, 14 Mar 2015 13:59:16 +0000 (14:59 +0100)
Change-Id: Id4aef4950f250edef2d507910877aabc6b9580ea

32 files changed:
distrib/sets/lists/minix/mi
etc/mtree/NetBSD.dist.base
games/Makefile
games/rogue/CHANGES [new file with mode: 0644]
games/rogue/Makefile [new file with mode: 0644]
games/rogue/USD.doc/Makefile [new file with mode: 0644]
games/rogue/USD.doc/rogue.me [new file with mode: 0644]
games/rogue/hit.c [new file with mode: 0644]
games/rogue/init.c [new file with mode: 0644]
games/rogue/inventory.c [new file with mode: 0644]
games/rogue/level.c [new file with mode: 0644]
games/rogue/machdep.c [new file with mode: 0644]
games/rogue/main.c [new file with mode: 0644]
games/rogue/message.c [new file with mode: 0644]
games/rogue/monster.c [new file with mode: 0644]
games/rogue/move.c [new file with mode: 0644]
games/rogue/object.c [new file with mode: 0644]
games/rogue/pack.c [new file with mode: 0644]
games/rogue/pathnames.h [new file with mode: 0644]
games/rogue/play.c [new file with mode: 0644]
games/rogue/random.c [new file with mode: 0644]
games/rogue/ring.c [new file with mode: 0644]
games/rogue/rogue.6 [new file with mode: 0644]
games/rogue/rogue.h [new file with mode: 0644]
games/rogue/room.c [new file with mode: 0644]
games/rogue/save.c [new file with mode: 0644]
games/rogue/score.c [new file with mode: 0644]
games/rogue/spec_hit.c [new file with mode: 0644]
games/rogue/throw.c [new file with mode: 0644]
games/rogue/trap.c [new file with mode: 0644]
games/rogue/use.c [new file with mode: 0644]
games/rogue/zap.c [new file with mode: 0644]

index 320c424f5046ea239634910c7abbdba22dcc31bb..0fc13a37ccdb6c5430f4f01758a295bfaa7243c4 100644 (file)
 ./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
 ./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
 ./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
index ece90ce0c08056597b8f9d92c5d78c8199e67ee2..f99527388cb133e07f28635e74ff9f77e82d2fe0 100644 (file)
 ./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
index 085caaf4002d6561a6df377f1ec14edd8ae16d41..1fcc709e199c4f327a007f2284bb1d79752a7083 100644 (file)
@@ -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)
diff --git a/games/rogue/CHANGES b/games/rogue/CHANGES
new file mode 100644 (file)
index 0000000..066ac12
--- /dev/null
@@ -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.
diff --git a/games/rogue/Makefile b/games/rogue/Makefile
new file mode 100644 (file)
index 0000000..2d4a565
--- /dev/null
@@ -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>
diff --git a/games/rogue/USD.doc/Makefile b/games/rogue/USD.doc/Makefile
new file mode 100644 (file)
index 0000000..38881ba
--- /dev/null
@@ -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>
diff --git a/games/rogue/USD.doc/rogue.me b/games/rogue/USD.doc/rogue.me
new file mode 100644 (file)
index 0000000..b1592dd
--- /dev/null
@@ -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.
diff --git a/games/rogue/hit.c b/games/rogue/hit.c
new file mode 100644 (file)
index 0000000..9d27c1f
--- /dev/null
@@ -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;
+       }
+}
diff --git a/games/rogue/init.c b/games/rogue/init.c
new file mode 100644 (file)
index 0000000..982a95c
--- /dev/null
@@ -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);
+       }
+}
diff --git a/games/rogue/inventory.c b/games/rogue/inventory.c
new file mode 100644 (file)
index 0000000..934e8aa
--- /dev/null
@@ -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);
+}
diff --git a/games/rogue/level.c b/games/rogue/level.c
new file mode 100644 (file)
index 0000000..4b95277
--- /dev/null
@@ -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]);
+       }
+}
diff --git a/games/rogue/machdep.c b/games/rogue/machdep.c
new file mode 100644 (file)
index 0000000..e6d6292
--- /dev/null
@@ -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 */
diff --git a/games/rogue/main.c b/games/rogue/main.c
new file mode 100644 (file)
index 0000000..fb88436
--- /dev/null
@@ -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);
+       }
+}
diff --git a/games/rogue/message.c b/games/rogue/message.c
new file mode 100644 (file)
index 0000000..e38377d
--- /dev/null
@@ -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);
+}
diff --git a/games/rogue/monster.c b/games/rogue/monster.c
new file mode 100644 (file)
index 0000000..1d644f6
--- /dev/null
@@ -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;
+       }
+}
diff --git a/games/rogue/move.c b/games/rogue/move.c
new file mode 100644 (file)
index 0000000..8378654
--- /dev/null
@@ -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));
+       }
+}
diff --git a/games/rogue/object.c b/games/rogue/object.c
new file mode 100644 (file)
index 0000000..9897ec6
--- /dev/null
@@ -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);
+}
diff --git a/games/rogue/pack.c b/games/rogue/pack.c
new file mode 100644 (file)
index 0000000..f8aed6e
--- /dev/null
@@ -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();
+               }
+       }
+}
diff --git a/games/rogue/pathnames.h b/games/rogue/pathnames.h
new file mode 100644 (file)
index 0000000..d6e91a5
--- /dev/null
@@ -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"
diff --git a/games/rogue/play.c b/games/rogue/play.c
new file mode 100644 (file)
index 0000000..8824538
--- /dev/null
@@ -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;
+               }
+       }
+}
diff --git a/games/rogue/random.c b/games/rogue/random.c
new file mode 100644 (file)
index 0000000..f119c0f
--- /dev/null
@@ -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));
+}
diff --git a/games/rogue/ring.c b/games/rogue/ring.c
new file mode 100644 (file)
index 0000000..5cdcf5f
--- /dev/null
@@ -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();
+       }
+}
diff --git a/games/rogue/rogue.6 b/games/rogue/rogue.6
new file mode 100644 (file)
index 0000000..4598c7b
--- /dev/null
@@ -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.
diff --git a/games/rogue/rogue.h b/games/rogue/rogue.h
new file mode 100644 (file)
index 0000000..8ce9411
--- /dev/null
@@ -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;
diff --git a/games/rogue/room.c b/games/rogue/room.c
new file mode 100644 (file)
index 0000000..0071489
--- /dev/null
@@ -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
+}
diff --git a/games/rogue/save.c b/games/rogue/save.c
new file mode 100644 (file)
index 0000000..4a7190a
--- /dev/null
@@ -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);
+}
diff --git a/games/rogue/score.c b/games/rogue/score.c
new file mode 100644 (file)
index 0000000..4bcf4e3
--- /dev/null
@@ -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");
+}
diff --git a/games/rogue/spec_hit.c b/games/rogue/spec_hit.c
new file mode 100644 (file)
index 0000000..69e314c
--- /dev/null
@@ -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);
+       /*}*/
+}
diff --git a/games/rogue/throw.c b/games/rogue/throw.c
new file mode 100644 (file)
index 0000000..93c88c5
--- /dev/null
@@ -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;
+       }
+}
diff --git a/games/rogue/trap.c b/games/rogue/trap.c
new file mode 100644 (file)
index 0000000..ae3c918
--- /dev/null
@@ -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();
+               }
+       }
+}
diff --git a/games/rogue/use.c b/games/rogue/use.c
new file mode 100644 (file)
index 0000000..8371a6f
--- /dev/null
@@ -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;
+       }
+}
diff --git a/games/rogue/zap.c b/games/rogue/zap.c
new file mode 100644 (file)
index 0000000..3e9134f
--- /dev/null
@@ -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);
+               }
+       }
+}