Mercurial > hg > early-roguelike
changeset 142:6b5fbd7c3ece
Merge arogue7 and xrogue trees.
author | John "Elwin" Edwards |
---|---|
date | Tue, 12 May 2015 21:39:39 -0400 |
parents | 66b0263af424 (current diff) cc5148bdf345 (diff) |
children | 7faf4568c295 |
files | |
diffstat | 51 files changed, 37418 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/LICENSE.TXT Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,178 @@ +Copyright (C) 1991 Robert Pietkivitch +Portions Copyright (C) 1985 Michael Morgan, Ken Dalka and AT&T +Portions Copyright (C) 1981 Michael Toy, Ken Arnold and Glenn Wichman +Portions Copyright (C) 2000 Nicholas J. Kisseberth +Portions Copyright (C) 1994 David Burren +All rights reserved. + +=========================================================================== + +XRogue: Expeditions into the Dungeons of Doom +Copyright (C) 1991 Robert Pietkivitch +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name(s) of the author(s) nor the names of other contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +4. The name "XRogue" must not be used to endorse or promote products + derived from this software without prior written permission. +5. Products derived from this software may not be called "XRogue", + nor may "XRogue" appear in their name, without prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +=========================================================================== + +Portions of this software are based on the work of Michael Morgan and +Ken Dalka. Used under license: + +Advanced Rogue +Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name(s) of the author(s) nor the names of other contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +4. The name "Advanced Rogue" and "ARogue" must not be used to endorse or + promote products derived from this software without prior written + permission. +5. Products derived from this software may not be called "Advanced Rogue" or + "ARogue", nor may "Advanced Rogue" or "ARogue" appear in their name, + without prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +=========================================================================== + +Portions of this software are based on the work of Michael Toy, Ken Arnold +and Glenn Wichman. Used under license: + +Rogue: Exploring the Dungeons of Doom +Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name(s) of the author(s) nor the names of other contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +=========================================================================== + +Portions of this software (save/restore game state) are based on the work +of Nicholas J. Kisseberth. Used under license: + +Copyright (C) 2000 Nicholas J. Kisseberth + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name(s) of the author(s) nor the names of other contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +=========================================================================== + +Portions of this software (encryption) are based on the work +of David Burren. Used under license: + +FreeSec: libcrypt + +Copyright (C) 1994 David Burren +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name(s) of the author(s) nor the names of other contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/Makefile Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,115 @@ +# XRogue: Expeditions into the Dungeons of Doom +# Copyright (C) 1991 Robert Pietkivitch +# All rights reserved. +# +# Based on "Advanced Rogue" +# Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T +# All rights reserved. +# +# Based on "Rogue: Exploring the Dungeons of Doom" +# Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman +# All rights reserved. +# +# See the file LICENSE.TXT for full copyright and licensing information. + +DISTNAME=xrogue8.0.3 +PROGRAM=xrogue + +O=o + +HDRS = rogue.h mach_dep.h network.h + +OBJS1 = vers.$(O) actions.$(O) bolt.$(O) chase.$(O) command.$(O) daemon.$(O) \ + daemons.$(O) eat.$(O) effects.$(O) fight.$(O) encumb.$(O) help.$(O) \ + init.$(O) io.$(O) list.$(O) main.$(O) maze.$(O) misc.$(O) monsters.$(O) +OBJS2 = mons_def.$(O) move.$(O) n_level.$(O) options.$(O) outside.$(O) pack.$(O) \ + passages.$(O) player.$(O) potions.$(O) rings.$(O) rip.$(O) rooms.$(O) \ + save.$(O) scrolls.$(O) sticks.$(O) things.$(O) trader.$(O) util.$(O) \ + weapons.$(O) wear.$(O) wizard.$(O) rogue.$(O) state.$(O) xcrypt.$(O) +OBJS = $(OBJS1) $(OBJS2) + +CFILES= vers.c actions.c bolt.c chase.c command.c daemon.c daemons.c eat.c \ + effects.c fight.c encumb.c help.c init.c io.c list.c main.c maze.c \ + misc.c monsters.c mons_def.c move.c n_level.c options.c outside.c \ + pack.c passages.c player.c potions.c rings.c rip.c rooms.c save.c \ + scrolls.c sticks.c things.c trader.c util.c weapons.c wear.c wizard.c \ + rogue.c state.c xcrypt.c + +MISC = Makefile README.TXT LICENSE.TXT $(PROGRAM).sln $(PROGRAM).vcproj + +CC = gcc +CFLAGS= -O3 +CRLIB = -lcurses +RM = rm -f +TAR = tar +.SUFFIXES: .obj + +.c.obj: + $(CC) $(CFLAGS) /c $*.c + +$(PROGRAM): $(HDRS) $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(CRLIB) -o $@ + +clean: + $(RM) $(OBJS1) + $(RM) $(OBJS2) + $(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip + +dist.src: + make clean + tar cf $(DISTNAME)-src.tar $(CFILES) $(HDRS) $(MISC) + gzip -f $(DISTNAME)-src.tar + +dist.irix: + make clean + make CC=cc CFLAGS="-woff 1116 -O3" $(PROGRAM) + tar cf $(DISTNAME)-irix.tar $(PROGRAM) README.TXT LICENSE.TXT + gzip -f $(DISTNAME)-irix.tar + +dist.aix: + make clean + make CC=xlc CFLAGS="-qmaxmem=16768 -O3 -qstrict" $(PROGRAM) + tar cf $(DISTNAME)-aix.tar $(PROGRAM) README.TXT LICENSE.TXT + gzip -f $(DISTNAME)-aix.tar + +dist.linux: + make clean + make $(PROGRAM) + tar cf $(DISTNAME)-linux.tar $(PROGRAM) README.TXT LICENSE.TXT + gzip -f $(DISTNAME)-linux.tar + +dist.interix: + make clean + make $(PROGRAM) + tar cf $(DISTNAME)-interix.tar $(PROGRAM) README.TXT LICENSE.TXT + gzip -f $(DISTNAME)-interix.tar + +dist.cygwin: + make clean + make $(PROGRAM) + tar cf $(DISTNAME)-cygwin.tar $(PROGRAM).exe README.TXT LICENSE.TXT + gzip -f $(DISTNAME)-cygwin.tar + +dist.mingw32: + $(MAKE) RM="cmd /c del" clean + $(MAKE) CRLIB="-lpdcurses -lWs2_32" $(PROGRAM) + cmd /c del $(DISTNAME)-mingw32.zip + zip $(DISTNAME)-mingw32.zip $(PROGRAM).exe README.TXT LICENSE.TXT + +dist.msys: + $(MAKE) clean + $(MAKE) CRLIB="-lcurses -lWs2_32" $(PROGRAM) + tar cf $(DISTNAME)-msys.tar $(PROGRAM).exe README.TXT LICENSE.TXT + gzip -f $(DISTNAME)-msys.tar + +dist.djgpp: + make clean + make LDFLAGS="-L$(DJDIR)/LIB" CRLIB="-lpdcurses" $(PROGRAM) + rm -f $(DISTNAME)-djgpp.zip + zip $(DISTNAME)-djgpp.zip $(PROGRAM) README.TXT LICENSE.TXT + +dist.win32: + nmake O="obj" RM="-del" clean + nmake O="obj" CC="CL" CRLIB="..\pdcurses.lib shell32.lib user32.lib Advapi32.lib Ws2_32.lib" CFLAGS="-DPDC_STATIC_BUILD -nologo -I.. -Ox -wd4033 -wd4716" $(PROGRAM) + -del $(DISTNAME)-win32.zip + zip $(DISTNAME)-win32.zip $(PROGRAM).exe README.TXT LICENSE.TXT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/README.TXT Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,646 @@ + Welcome to XRogue + http://roguelike.sourceforge.net/xrogue + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. + + +XRogue: Expeditions into the Dungeons of Doom +--------------------------------------------- + +Introduction: + +Rogue was introduced at the University of California at Berkeley as a +screen-oriented fantasy game. The game had 26 types of monsters that +the player could meet while exploring a Dungeon generated by the computer. +Scrolls, potions, rings, wands, staves, armor, and weapons helped the +player to battle these monsters and to gain gold, the basis for scoring. + +The version of rogue described in this guide has been expanded to include +over 200 monsters with many new capabilities and has been renamed xrogue. +Many of the monsters are intelligent and they, like the player, must avoid +traps and decide when it is better to fight or to run. There are also a +number of new commands in this version not found in previous versions. + +The game contains monsters, spells, weapons, armor, potions, and other +magical items that you will discover during your quest. The Dungeon's +geography changes with every game and although many magical items have +certain identifiable properties, such as turning the player invisible, +the physical manifestation of the magic changes each game. A red potion, +for example, will cause the same reaction throughout a given game but +it may be a completely different potion in a new game. + +Entering the Dungeon with only a little food, armor, and a weapon, the +player must develop a good strategy of when to fight, when to run, and +how to best use any magical item found in the Dungeon. To make things +interesting the player has a quest to return one of several unique and +magical artifacts which are rumored to lie deep within the Dungeon. +Returning with this artifact to the surface brings great honor. + +However, after finding the artifact, the player may wish to continue +his quest deeper into the Dungeon to match wits with an arch-devil, a +demon-prince, or perhaps Charon the Boatman. Defeating such a creature +will gain the player many experience points which is the basis for +scoring in xrogue. It is very difficult to return from the Dungeons +of Doom alive. Very few players have won this game. + +Character Classes: + +Before placing the player in the Dungeon, the game requests that you +select what type of character they would like to be: Fighter, Paladin, +Ranger, Magic-User, Cleric, Thief, Assassin, Druid, or Monk. + + The Fighter + +A Fighter has the best odds at winning battles with monsters. At high +experience levels, the Fighter is able to attack his opponent multiple +times in a single turn. Strength is the main attribute of the Fighter. + + The Magic-User + +A Magic-User is able to cast spells. Intelligence is the main attribute. +The number of spells a Magic-User can cast increases as he gains in +experience points and in intelligence. His spell casting ability allows +him to identify any item in the Dungeon. 16 spells. + + The Cleric + +A Cleric is able to pray for assistance in battle. Wisdom is the main +attribute. The number of prayers granted to the Cleric increases as he +gains in experience points and in wisdom. Clerics can affect (turn) the +undead monsters to avoid battle. Ie., zombies, ghouls, etc. If the +Cleric is very powerful relative to the undead monster, turning it will +utterly destroy it. 16 prayers. + + The Paladin + +A Paladin is a type of holy warrior, being a cross between a Cleric +and a Fighter. He is able to pray and affect the undead like the Cleric +and fight like the Fighter, but both to a lesser extent. He is on the +side of all that is righteous and good and would never attack a monster +that has not attacked him first. If he happens to kill such a monster, +inadvertantly or otherwise, he will begin to feel increasingly uneasy. +If he kills too many such monsters, he will face karmic retaliation and +be reduced to a mere Fighter, minus all of the Cleric's ability. +Charisma is the main attribute with Wisdom second. + + The Ranger + +A Ranger is a type of mystical warrior, being a cross between the +Magic-User and Fighter. Like the Paladin, he is on the side of all +that is righteous and good and would never attack a monster that +has not attacked him first. A Ranger is able to cast spells like the +Magic-User and fight like the Fighter, but both to a lesser extent. +Charisma is the main attribute with Intelligence second. + + The Thief + +A Thief is exceptionally dexterous and has great skill at being able +to set a traps for and/or rob (steal) items from monsters. Thieves have +the ability to detect all the gold and hidden traps on each level of +the Dungeon. Their dexterous nature gives Thieves the ability to move +very quietly, so they are not as likely as to wake up sleeping monsters +as are the other character types. If a Thief manages to sneak up on a +creature without waking it he may be able to backstab the monster. The +damage from a backstab is greatly increased based upon the experience +level. Dexterity is the main attribute. + + The Assassin + +An Assassin is a person trained in the art of killing monsters by +surprise. He has some of the abilities of the Thief, but he cannot +sense traps or backstab. Instead, the Assassin has the chance to kill +an opponent outright with one deadly blow. He can recognize and use +poison found in the Dungeon on his weapon, thereby, making his next +attack exceptionally lethal. Dexterity is the main attribute. + + The Druid + +A Druid is a type of magical warrior, being a cross between the Cleric +and the Magic-User. A Druid can chant both spells and prayers plus a +few of his own. The number of chants available to the Druid increases +as he gains in experience points and in Wisdom. Wisdom is the main +attribute. 16 chants. + + The Monk + +A Monk is trained in the martial arts. He wears no armor and does not +need a weapon (although using them is not forbidden). As the Monk gains +in experience points his natural defense or ability to dodge attackers +increases. The Mong is a cross between the Druid and Fighter, so he +can chant and also fight like the Fighter, but both to a lesser extent. +Constitution is the main attribute, with wisdom second. + +Attributes Of The Charaters: + +Strength - The primary attribute for encumberance. + +Intelligence - The primary attribute for casting spells. + +Wisdom - The primary attribute for prayers and chanting. + +Dexterity - The primary attribute for stealthiness. + +Charisma - The primary attribute for good will. High Charisma also + affects the cost of objects when making transactions. + +Constitution - The primary attribute for health. High Constitution + affects the amount of hit points you receive when + moving up in experience levels. + +Note: The Ranger, Paladin, and Monk do not receive their "special" +magical abilities until they have advanced a few experience levels. + +Experience Levels: + +Characters gain experience points mostly from killing monsters. Other +actions, such as stealing items from monsters, backstabbing, and turning +monsters, also add extra experience points. Each character type gains +experience points and moves up in experience levels at different rates. +Moving up in experience levels adds extra hit points to the character +which determines how many "hits" he can take before being killed. + +Allocating Attribute Points To The Characters: + +A player starts with 75 attribute points to distribute in to the character +he has chosen to play. When you are prompted to distribute the attribute +points, the screen displays the minimum and maximum allowable values for +that particular attribute. The player can type a backspace (Ctrl-H) to go +back and change a previous value and typing an escape (ESC) sets all the +remaining attributes to the maximum value possible, given the number of +remaining attribute points to be distributed. + +THE SCREEN + +During the normal course of play, the screen consists of three separate +sections: the top line, the bottom two lines, and the remaining screen +in the middle. The top line reports actions which occur during the game, +the middle section depicts the Dungeon, and the bottom two lines describe +the player's current condition. + +Whenever anything happens to the player, such as finding a scroll, hitting +a monster, or being hit by a monster, a short report appears on the top +line of the screen. When you see the word 'More' on the top line, that +means you must press the space key to continue. + +The following items may be found within the Dungeon. Some of them have +more than one interpretation, depending upon whether your character +recognizes them or not. + +| A wall of a room. +- A wall of a room. +* A pile of gold. +% A way to another level. ++ A doorway. +. The floor in a room. +# The floor in a passageway. + Solid rock (denoted by a space). +^ The entrance to a Trading Post +@ The player. +_ The player, when invisible. +: Some food. +! A flask containing a potion. +? A sealed scroll. += A ring. +) A weapon. +] Some armor. +; A miscellaneous magic item +, An artifact +/ A wand or a staff. + > A trapdoor leading to the next level +{ An arrow trap +$ A sleeping gas trap +} A beartrap +~ A trap that teleports you somewhere else +` A poison dart trap +" A shimmering magic pool +' An entrance to a maze +$ Any magical item. (During magic detection) + > A blessed magical item. (During magic detection) +< A cursed magical item. (During magic detection) + +Monsters are depicted as letters of the alphabet. Note that all letters +denote multiple monsters, depending on which level of the Dungeon you are +on. The player may identify a current monster by using the identify +command ('/') or the clarify command ('='). + +The bottom two lines of the screen describe the player's current status. +The first line gives the player's characteristics: + +Intelligence, Strength, Wisdom, Dexterity, Charisma, and Constitution +all have a normal maximum value of 50 points, but they can go higher if +augmented by a ring. Encumberance is a measurement of how much the player +can carry versus how much he is currently carrying. The more you carry +relative to your maximum encumberance causes you to use more food. The +attribute of Strength fortifies one's encumberance. + +The player's current number of hit points are denoted as (Hp) and it is +followed in parentheses by the player's current maximum hit points. Hit +points express the player's survivability. As a player heals by resting, +using potions, or spells, the player's current hit points gradually increase +until they reach the current maximum. This maximum number will be increased +each time a player goes up an experience level. If the player's current hit +points reach 0, the player becomes "metabolically challenged". + +The player's armor class is denoted as (Ac). This number describes the +amount of protection provided by the armor, cloaks, and/or rings currently +worn by the player. It is also affected by high or low dexterity. Wearing +no armor is equivalent to an armor class of 10 (Monk excepted). The lower +the armor class number, the better. + +The player's current experience level is denoted as (Exp), followed by +the player's experience points. A new experience level brings extra hit +points and possibly added abilities, such as new spells for a Magic-user, +new prayers for a Cleric, and new chants for a Druid. There are a total +of 26 experience levels per character. + +Commands: + +A player can invoke most commands by typing in a single character. +Some commands, however, require a direction, in which case the player +types the command character followed by a directional letter. Many +commands can be prefaced by a number, indicating how many times the +command should be executed. + +When the player invokes a command referring to an item in the player's +pack (such as reading a scroll), the game prompts for the item. The +player can then type the letter associated with the item. Typing a '*' +will produce a list of eligible items. + +A list of basic games commands: + +? Preceding a command by a '?' produces a brief explanation of the + command. The command '?*' gives an explanation of all the commands. + A '?@' gives information on things you encounter (rock, forest, etc). +/ Preceding a symbol by a '/' identifies the symbol. += Clarify. After typing an '=' sign, the player can use the movement + keys to position the cursor anywhere on the current level. As long + as the player can normally see the selected position, the game will + identify whatever is there. +h Move one position to the left. +j Move one position down. +k Move one position up. +l Move one position to the right. +y Move one position to the top left. +u Move one position to the top right. +b Move one position to the bottom left. +n Move one position to the bottom right. +H Run to the left until reaching something interesting. +J Run down until reaching something interesting. +K Run up until reaching something interesting. +L Run to the right until reaching something interesting. +Y Run to the top left until reaching something interesting. +U Run to the top right until reaching something interesting. +B Run to the bottom left until reaching something interesting. +N Run to the bottom right until reaching something interesting. + + > Go down the stairs to the next level or enter the outer region if you + are standing upon the wormhole trap (must be "flying" for this to work). +< Go up the stairs to the next level or enter the outer region if you are + standing upon the wormhole trap (must be "flying" for this to work). + +* Count the gold in the player's pack. +! Escape to the shell level. +$ Price an item at the Trading Post. +# Buy an item at the Trading Post. +% Sell an item at the Trading Post. +. This command (a period) causes the player to rest one turn. +^ This command sets traps and is limited to Thieves and Assassins. If the + command is successful the game will ask the player for the trap type and + sets it where the player is standing. +a Affect the undead. This command is restricted to Clerics and Paladins + and must be followed by a directional letter. +A Choose your quest item (at game startup only!). +c This command is restricted to Druids and Monks and it produces a list of + available chants. The player can select one of the displayed chants and + if the player's energy level is sufficiently high, "chant" it. The more + complicated the spell, the more energy it will take. +C This command is restricted to Magic-Users and Rangers and it produces a + list of available spells. The player can select one of the displayed + spells and if the player's energy level is sufficiently high, "cast" it. + The more complicated the spell, the more energy it will take. +d Drop an item from the player's pack. +D Dip something into a magic pool. +e Eat some food from the player's pack. +f When this command is preceded with a directional command, the player will + move in the specified direction until he crosses something interesting. +F Frighten a monster. Not available to all characters. This command + loses it's power at around level 10. +g Give away or trade a slime-mold for food with a monster. +G This command is restricted to Thieves and Assassins. It causes the game + to display all of the gold on the current level. +i Display an inventory of the player's pack. +I This command prompts for an item from the player's pack and displays + the inventory information for that item. +m When the player types this command, you are prompted to mark an item + with a one-line name. +o Typing this command causes the game to display all the settable options. + The player can then examine them or change (some of) them +O Display your current character type and quest item. +p This command is restricted to Clerics and Paladins and it produces a + list of available prayers. The player can then select one of the + displayed prayers and if the player's energy level is sufficiently high, + "pray" it. The more complicated the prayer, the more energy it will +take. +P Pick up the items currently under the player. +q Quaff a potion from the player's pack. +Q Quit without saving the game. +r Read a scroll from the player's pack. +s Search for a secret door or a trap in the circle surrounding the player. +S Save your game to play at a later time. +t This command prompts for an object from the players pack. The player + then can throw the object in the specified direction. +T Take off whatever the player is wearing. +v Print the current xrogue version number. +w Wield a weapon from the player's pack. +W Wear some armor, ring, or a miscellaneous magic item from the player's + pack. The player can wear a maximum of 8 rings. +X This command is restricted to Thieves only. It causes the game to +display + all of the hidden traps on the current level. +z This command prompts for a wand or staff from the player's pack and zaps + it in the specified direction. ++ Fortune cookie! (Note: if you play xrogue over a modem, typing three + consecutive '+' will tell your modem to enter "command" mode. See your + modem manual on how to return from this mode). + +Escape Pressing the Escape key will cancel the current command. +Ctrl-B Check your current score. Scoring is based on experience points + and gold. However, gold is not that important and 10% is hacked + off if a player is killed. +Ctrl-E Check your current food level. This command is used when you want + to see just how much food you have remaining in your stomach. A + full stomach is measured to be about 2000(2100). As you play the + game, this level drops until you become hungry at about 200(2100). + A food level over 2000(2100) makes the character satiated, and a + level under 200(2100) makes the character hungry, then weak, and + finally fainting. A level of 2000(2100) is the most the character + can eat, a full, satisfied stomach! +Ctrl-L Redraw the screen. +Ctrl-N When the player types this command, the game prompts you to type a + one-line name for a monster or for an item in the player's pack + To name a monster, position the cursor over the desired monster and + rename it. +Ctrl-O Display the current "affects" on the player (such as slow, phased, + confused, extra sight, flying, dancing, etc.). +Ctrl-R Repeat last message displayed on the top line of the screen. +Ctrl-T This command is restricted to Thieves and Assassins. It must be + followed by a directional letter. If a monster is standing next to + the player in the specified direction, the effect is to steal an + item from the monster's pack. If successful, the monster does not + notice anything, but if the player is unsuccessful, there is a +chance + the monster will suddenly wake up and attack. +Ctrl-U Use a magic item in the player's pack. + +There is no explicit attack command. If a player wishes to do battle with a +monster, the player simply moves onto the spot where the monster is +standing. +Whatever the player is wielding will be used as the player's weapon. + +As the player moves across items, the game automatically picks them up and +places them into the player's pack. If there is no room left in the pack, +the item is left on the floor. Setting the "pickup" option to "NO" will +allow the player to pick up items at will using the 'P' command. + +All actions except for bookkeeping commands, such as taking an inventory, +take time. The amount of time varies with the command. Swinging a weapon, +for example, takes more time than simply moving; so a monster could move +several spaces in the time it takes the player to make one attack. The +time it takes to swing a weapon also varies based on the bulk of the weapon, +and the time it takes to simply move one space varies with the type of armor +worn and the player's level of encumberance. Movement is always faster when +the player is "flying". + +Actions also take time and some of them can be disrupted. If the player is +casting a spell for example, and gets hit before finishing it, the spell is +lost. Similarly, the player might choke if hit while trying to eat. These +same rules apply to monsters as well. + +Some of the rooms in the Dungeon possess a natural light source. In most +other rooms and in corridors, the player can see only those things within +a one-space radius around the player. Dark rooms can be lit with magical +light or by fire beetles and other monsters. + +The player can wield only one weapon at a time. When a player attacks +a monster, the amount of damage depends on the particular weapon he is +wielding. To fire a projectile weapon, such as a crossbow or a short bow, +the player should wield the bow and throw the bolt or arrow at the monster. + +A weapon may be cursed or blessed which will affect the likelihood of you +hitting a monster with it and the damage that it will inflict on the +monster. +If the player has identified the weapon he is using, the "to hit" and the +"to damage" bonuses appear (in that order) before the weapons name in the +inventory listing. A positive bonus indicates a blessed weapon, and a +negative bonus usually indicates a cursed or misguided weapon. A player +cannot release a cursed weapon until a remove curse scroll is read or cast +by magical means. + +After the player has identified a suit of armor, the protection bonus +appears +before the armors name in the inventory listing. If the bonus is positive +the armor is blessed but if it is negative, the armor is probably cursed. +The player cannot remove a cursed suit of armor until a remove curse scroll +is read or cast by magical means. + +Some monsters can corrode your armor! If such a monster hits a player +when the player is wearing metal armor, the armor will lose some of its +protective value. This same corrosive property also applies to weapons +when a player hits a monster with this ability. Search for a scroll of +"protection" to guard against corrosion of your armor and weapon. + +A player will find many potions and scrolls in the Dungeon. Reading a +scroll or quaffing a potion will usually cause some magical occurrence. +Potions and scrolls may be either cursed or blessed. In this version of +xrogue, Monster Confusion scrolls will turn your hands a variety of colors. +A blessed Magic Mapping scroll shows very detailed maps. A scroll of +Genocide works within the dungeon as well as in the outer region. A +scroll of blessed Teleportation will teleport you "upward" a few levels. +Blessed Remove Curse will cause certain monsters to panic if the scroll +is read near them. Charm Monster will let you charm several monsters. + +The player can wear a maximum of eight rings. Some of them have a magical +effect on the player as long as they are worn. Some rings also speed up +the player's metabolism, making the player require food more often. Rings +can be cursed or blessed and the player cannot remove a cursed ring until +a remove curse scroll is read or cast. + +Wands, rods, and staves help a player in battle and affect the Dungeon. +A player uses the "z" (zap) command to use a wand either to shoot at a +monster, teleport, or to light up a dark room. Wands can be cursed or +blessed. + +A player must be frugal with his food. Both moving and searching through +the Dungeon, and fighting monsters, consumes energy. Starving results in +the player's fainting for increasingly longer periods of time, during which +any nearby monster can attack the player at will. Food comes in the form +of standard rations and as a variety of berries. Some berries have side +effects in addition to satisfying one's hunger. Slime-Molds are monster +food and if you have one, you may be able to trade it for a regular food +ration, if the monster is of "friendly" persuasion. + +Gold has a couple of uses in the Dungeon. The first use of gold is to buy +things, either at a Trading Post or from a Quartermaster. The Trading Post +when found, is entered via the '>' command, like going down a stairway. +A Quartermaster ('q') is a Dungeon vendor who appears at certain times and +will try to sell the player some of his wares. The Quartermaster's wares +are never cursed but they can be blessed, though blessed goods do cost more +than normal goods. If the player chooses to buy something offered by a +Quartermaster, he will make the transaction for the specified amount of gold +and then disappear. Attacking a Quartermaster causes him to vanish in +haste! You can sometimes find gold at the bottom of "magic pools". Use +the ">" command to dive for the gold, but be careful you don't drown! + +When beginning a new game, a player is placed in the Trading Post with +an allotment of gold based upon the type of character chosen to play. +There are some restrictions on the use of certain items by character. +For example, only Fighters, Paladins, and Rangers can wield two-handed +swords while Thieves and Assassins can not wear certain types of armor. +However, the Trading Post (and Quartermaster) will happily sell a player +anything that he can afford, whether you need it or not. + +Miscellaneous magical items such as a Pair of Boots or a Book are numerous +within the Dungeon. These items are usually used to a player's advantage, +assuming they are not cursed. Some of these items can be worn, such as a +Cloak, while others are to be used, such as a Book, Beaker, or Ointment. +The Medicine Crystal will heal you, remove all curses, heal you, and may +cause panic in some monsters. + +There are a number of unique monsters deep within the depths of the Dungeon +that carry very special magical items or artifacts. When you begin the +game, +you are asked to choose a "quest item" to retrieve from the Dungeon. Most +of these items can be used to the player's advantage, even if they are not +one's own personal quest item during the game. However, care must be taken +when handling some of them for they have intelligence and some will reject +mishandling or abuse. These items consume your food (and your gold) so +carrying them around results in increased food use. Some of these items +will +kill you outright if you happen to pick them up while wielding another +artifact as your weapon. Don't be too greedy with the artifacts! Quest +items begin appearing in xrogue between levels 40-50. The less traumatic +quest items appear earlier while the more severe ones appear later. Once +a unique monster is killed, you will not encounter another one like it in +the Dungeon. + +A variety of traps exist within the Dungeon, including trap doors, bear +traps, and sleeping traps. Sometimes they are hidden from sight until +sprung by a monster or by the player. A sprung trap continues to function, +but since it is visible, an intelligent monster is not likely to tread on +it. +A trap called the Wormhole trap, will transport you to the "outer region" +of the dungeon. There you will fight strange dinosaurs until you can make +your way back to a starwell, and promptly return from whence you came. + +Each monster except for the Quartermaster appears in a limited range of +Dungeon levels. All monsters of the same type share the same abilities. +All giant rats, for example, can give the player a disease, and all +jackalweres can put the player to sleep. Monsters of the same type will +vary however, in strength and intelligence. For example, one kobold may +be much more difficult to kill off than another. In general, the more +difficult it is to kill a monster, the more experience points the monster +is worth. + +Most monsters attack by biting and clawing, but some monsters carry weapons +and can use their breath as a weapon. Some monsters can even use magical +items, such as wands and artifacts. Monsters with distance weapons or magic +can sometimes attack a player from across a room or from down a corridor. + +Some monsters are more intelligent than others, and the more intelligent +a monster is, the more likely it will run away if it is about to die. +A fleeing monster will not attack the player unless it is cornered. + +It is sometimes possible to enlist a monster's aid. Reading a charm monster +scroll, for example, or singing a charm monster chants can make a monster +believe that the player is its friend. A charmed monster will fight hostile +monsters for the player as long as they are not of its own race. Be sure +your charmed monsters are in the same room with you when you enter the next +level, or they will be lost. + +Options: + +The game has several options, some of which can only be set by the player +at the beginning of the game and others during the course of play. + + default - Play the character with "default" attribute settings. + terse - Shorten messages at top of screen. + jump - Speed up the display of the player's movement + step - Lists all inventories one line at a time. + overlay - Allows listings of inventories to overlay the currnt screen. + flush - Supposed to flush all typed-ahead characters. + askme - Prompt the player to name new types of scrolls, potions, +etc. + pickup - Pick up items automatically as you move across them + name - The player's name. + file - Saved game filename. Defaults to xrogue.sav. + score - Identifies the location of the game scorefile. + type - Specifies the character type (unchangable). +quested item - Set at start up (unchangeable). + +A player can set the game options at the beginning of a game via the +ROGUEOPTS environment variable. + +Some examples: + + ROGUEOPTS="default nopickup, nooverlay, name=Corwin, class=magician" + ROGUEOPTS="pickup, overlay, file=xrg.sav, score=/home/games/scorefile" + +The player may change an option at any time during the game via the 'o' +(option) command. On the options menu, typing a new value changes the +option and a RETURN moves to the next option in the list. Typing an '-' +moves you to the previous option and an ESCAPE returns you to the Dungeon. + +A new option called "default" was added in xrogue. When you put the word +"default" into your ROGUEOPTS environment variable your character will be +created with "default" attribute settings, armor, weapon, quest item, and +some food. + +Setting "default" will force the game to skip over the beginning screen +where you can choose/distribute your attribute points and it also skips +over the beginning "equippage screen" where you can choose your armor, +weapon, quest item, and etc. + +If you use the "class" option with "default" in ROGUEOPTS, you will +start the game immediately at level 1 with the default selections +for your character. + +Here is a list of the main and secondary attributes, special ability, +and quest item ("default" settings) for each character type: + + Character Main Attr. Secondary Specialties Def. Quest Item + ------------------------------------------------------------------------- + Fighter strength constitution sense gold Axe of Aklad + Ranger charisma intelligence cast spells Mandolin of Brian + Paladin charisma wisdom affect undead Ankh of Heil + Cleric wisdom dexterity prayer spells Horn of Geryon + Magician intelligence dexterity cast spells Stonebones Amulet + Thief dexterity strength sense traps Musty Daggers + Assassin dexterity strength steal/use poison Eye of Vecna + Druid wisdom dexterity chant spells Quill of Nagrom + Monk constitution dexterity chant spells Emori Cloak + +A different quest item may be chosen ONLY while you are in the beginning +Trading Post (if you have NOT set the "default" option via ROGUEOPTS). + +When a player is killed, his score will be equal to the amount of his +experience points gained, plus his gold (minus 10%). A player that +quits the game will not lose 10% of his gold. If a player makes it back +up and out of the Dungeon alive, his score will be equal to the amount +of experience points, plus the gold, plus additional gold received from +selling all of the items in his pack. + +The game maintains a top-twenty player scorefile. As an installation +option, the game may be compiled so as to record only three entries per +character type and name.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/actions.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1074 @@ +/* + actions.c - functions for dealing with monster actions + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <ctype.h> +#include <curses.h> +#include <limits.h> +#include "rogue.h" + +int mf_count = 0; /* move_free counter - see actions.c(m_act()) */ +int mf_jmpcnt = 0; /* move_free counter for # of jumps */ + +/* + * Did we disrupt a spell? + */ +dsrpt_monster(tp, always, see_him) +register struct thing *tp; +bool always, see_him; +{ + switch (tp->t_action) { + case A_SUMMON: + case A_MISSILE: + case A_SLOW: + tp->t_action = A_NIL; /* Just make the old fellow start over again */ + tp->t_no_move = movement(tp); + tp->t_using = NULL; /* Just to be on the safe side */ + turn_on(*tp, WASDISRUPTED); + if (see_him) + msg("%s's spell has been disrupted.",prname(monster_name(tp),TRUE)); + /* + * maybe choose something else to do next time since player + * is disrupting us + */ + tp->t_summon *= 2; + tp->t_cast /= 2; + return; + } + + /* We may want to disrupt other actions, too */ + if (always) { + tp->t_action = A_NIL; /* Just make the old fellow start over again */ + tp->t_no_move = movement(tp); + tp->t_using = NULL;/* Just to be on the safe side */ + } +} + +dsrpt_player() +{ + int which, action; + struct linked_list *item; + struct object *obj; + + action = player.t_action; + which = player.t_selection; + + switch (action) { + case C_CAST: /* Did we disrupt a spell? */ + case C_PRAY: + case C_CHANT: + { + msg("Your %s was disrupted!", action == C_CAST ? "spell" : "prayer"); + + /* Charge him 1/4 anyway */ + if (action == C_CAST) + spell_power += magic_spells[which].s_cost / 4; + else if (action == C_PRAY) + pray_time += cleric_spells[which].s_cost / 4; + else if (action == C_CHANT) + chant_time += druid_spells[which].s_cost / 4; + } + when C_COUNT: /* counting of gold? */ + { + if (purse > 0) { + msg("Your gold goes flying everywhere!"); + do { + item = spec_item(GOLD, NULL, NULL, NULL); + obj = OBJPTR(item); + obj->o_count = min(purse, rnd(20)+1); + purse -= obj->o_count; + obj->o_pos = hero; + fall(item, FALSE); + } while (purse > 0 && rnd(25) != 1); + } + } + when C_EAT: + msg("Ack! You gag on your food for a moment. "); + del_pack(player.t_using); + + when A_PICKUP: + msg("You drop what you are picking up! "); + + when C_SEARCH: /* searching for traps and secret doors... */ + msg("Ouch! You decide to stop searching. "); + count = 0; /* don't search again */ + + when C_SETTRAP: + msg("Ouch! You can't set a trap right now. "); + + when A_NIL: + default: + return; + } + player.t_no_move = movement(&player); /* disoriented for a while */ + player.t_action = A_NIL; + player.t_selection = 0; +} + +/* + * m_act: + * If the critter isn't doing anything, choose an action for it. + * Otherwise, let it perform its chosen action. + */ + +m_act(tp) +register struct thing *tp; +{ + struct object *obj; + bool flee; /* Are we scared? */ + + /* What are we planning to do? */ + switch (tp->t_action) { + default: + /* An unknown action! */ + msg("Unknown monster action (%d)", tp->t_action); + + /* Fall through */ + + case A_NIL: + /* If the monster is fairly intelligent and about to die, it + * may turn tail and run. But if we are a FRIENDLY creature + * in the hero's service, don't run. + */ + if (off(*tp, ISFLEE) && + tp->t_stats.s_hpt < tp->maxstats.s_hpt && + tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/6) && + (off(*tp, ISFRIENDLY) || tp->t_dest != &hero) && + rnd(25) < tp->t_stats.s_intel) { + turn_on(*tp, ISFLEE); + + /* It is okay to turn tail */ + tp->t_oldpos = tp->t_pos; + } + + /* Should the monster run away? */ + flee = on(*tp, ISFLEE) || + ((tp->t_dest == &hero) && on(player, ISINWALL) && + off(*tp, CANINWALL)); + + m_select(tp, flee); /* Select an action */ + return; + + when A_ATTACK: + /* + * We're trying to attack the player or monster at t_newpos + * if the prey moved, do nothing + */ + obj = tp->t_using ? OBJPTR(tp->t_using) : NULL; + if (ce(tp->t_newpos, hero)) { + attack(tp, obj, FALSE); + } + else if (mvwinch(mw, tp->t_newpos.y, tp->t_newpos.x) && + step_ok(tp->t_newpos.y, tp->t_newpos.x, FIGHTOK, tp)) { + skirmish(tp, &tp->t_newpos, obj, FALSE); + } + + when A_SELL: + /* Is the quartermaster still next to us? */ + if (ce(tp->t_newpos, hero)) sell(tp); + + /* The quartermaster moved away */ + else if (off(player, ISBLIND) && cansee(unc(tp->t_pos)) && + (off(*tp, ISINVIS) || on(player, CANSEE)) && + (off(*tp, ISSHADOW) || on(player, CANSEE)) && + (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT)) && + (rnd(12) < 4)) + msg("%s grunts with frustration",prname(monster_name(tp),TRUE)); + + when A_MOVE: + /* Let's try to move */ + do_chase(tp); + + /* If t_no_move > 0, we found that we have to fight! */ + if (tp->t_no_move > 0) return; + + when A_BREATHE: + /* Breathe on the critter */ + m_breathe(tp); + + when A_SLOW: + /* make him move slower */ + add_slow(); + turn_off(*tp, CANSLOW); + + when A_MISSILE: + /* Start up a magic missile spell */ + m_spell(tp); + + when A_SONIC: + /* Let out a sonic blast! */ + m_sonic(tp); + + when A_THROW: + /* We're throwing something (like an arrow) */ + missile(tp->t_newpos.y, tp->t_newpos.x, tp->t_using, tp); + + when A_SUMMON: + /* We're summoning help */ + m_summon(tp); + + when A_USERELIC: + /* Use our relic */ + m_use_relic(tp); + + when A_USEWAND: + /* use the wand we have */ + m_use_wand(tp); + } + + /* Can we in fact move? (we might have solidified in solid rock) */ + if (!step_ok(hero.y, hero.x, NOMONST, &player)) { + + if (move_free > 1) goto jump_over; /* avoid messages */ + if (mf_count > 2) goto jump_over; /* limit messages */ + + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + msg("You have merged into the surroundings! --More--"); + wait_for(' '); + death(D_PETRIFY); + } + else { + mf_count += 1; /* count number of times we are here */ + pstats.s_hpt -= rnd(2)+1; + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + msg("You have merged into the surroundings! --More--"); + wait_for(' '); + death(D_PETRIFY); + } + } + switch (rnd(51)) { + case 0: msg("Arrrggghhhhh!! "); + when 5: msg("You can't move! "); + when 10: msg("You motion angrily! "); + when 15: msg("You feel so weird! "); + when 20: msg("If only you could phase. "); + when 25: msg("The rock maggots are closing in! "); + when 30: msg("You wrench and wrench and wrench... "); + when 35: msg("You wish you could teleport out of here! "); + when 40: msg("Your feel your life force ebbing away... "); + when 45: msg("You partially regain your senses. "); + when 50: msg("The rock maggots have found you!!! "); + otherwise: pstats.s_hpt -= rnd(4)+1; + } + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + msg("You lose the urge to live... --More--"); + wait_for(' '); + death(D_PETRIFY); + } + jump_over: + mf_jmpcnt++; /* count this jump */ + if (mf_jmpcnt > 9) { /* take a few turns, then reset it */ + mf_jmpcnt = 0; + mf_count = 0; + } + } + + /* No action now */ + tp->t_action = A_NIL; + tp->t_using = NULL; +} + +/* + * m_breathe: + * Breathe in the chosen direction. + */ + +m_breathe(tp) +register struct thing *tp; +{ + register int damage; + register char *breath = NULL; + + damage = tp->t_stats.s_hpt; + turn_off(*tp, CANSURPRISE); + + /* Will it breathe at random */ + if (on(*tp, CANBRANDOM)) { + /* Turn off random breath */ + turn_off(*tp, CANBRANDOM); + + /* Select type of breath */ + switch (rnd(10)) { + case 0: breath = "acid"; + turn_on(*tp, NOACID); + when 1: breath = "flame"; + turn_on(*tp, NOFIRE); + when 2: breath = "lightning bolt"; + turn_on(*tp, NOBOLT); + when 3: breath = "chlorine gas"; + turn_on(*tp, NOGAS); + when 4: breath = "ice"; + turn_on(*tp, NOCOLD); + when 5: breath = "nerve gas"; + turn_on(*tp, NOPARALYZE); + when 6: breath = "sleeping gas"; + turn_on(*tp, NOSLEEP); + when 7: breath = "slow gas"; + turn_on(*tp, NOSLOW); + when 8: breath = "confusion gas"; + turn_on(*tp, ISCLEAR); + when 9: breath = "fear gas"; + turn_on(*tp, NOFEAR); + } + } + + /* Or can it breathe acid? */ + else if (on(*tp, CANBACID)) { + turn_off(*tp, CANBACID); + breath = "acid"; + } + + /* Or can it breathe fire */ + else if (on(*tp, CANBFIRE)) { + turn_off(*tp, CANBFIRE); + breath = "flame"; + } + + /* Or can it breathe electricity? */ + else if (on(*tp, CANBBOLT)) { + turn_off(*tp, CANBBOLT); + breath = "lightning bolt"; + } + + /* Or can it breathe gas? */ + else if (on(*tp, CANBGAS)) { + turn_off(*tp, CANBGAS); + breath = "chlorine gas"; + } + + /* Or can it breathe ice? */ + else if (on(*tp, CANBICE)) { + turn_off(*tp, CANBICE); + breath = "ice"; + } + + else if (on(*tp, CANBPGAS)) { + turn_off(*tp, CANBPGAS); + breath = "nerve gas"; + } + + /* can it breathe sleeping gas */ + else if (on(*tp, CANBSGAS)) { + turn_off(*tp, CANBSGAS); + breath = "sleeping gas"; + } + + /* can it breathe slow gas */ + else if (on(*tp, CANBSLGAS)) { + turn_off(*tp, CANBSLGAS); + breath = "slow gas"; + } + + /* can it breathe confusion gas */ + else if (on(*tp, CANBCGAS)) { + turn_off(*tp, CANBCGAS); + breath = "confusion gas"; + } + + /* can it breathe fear gas */ + else { + turn_off(*tp, CANBFGAS); + breath = "fear gas"; + } + + /* Now breathe */ + shoot_bolt(tp, tp->t_pos, tp->t_newpos, FALSE, + tp->t_index, breath, damage); + + running = FALSE; + if (fight_flush) flushinp(); +} + +/* + * m_select: + * Select an action for the monster. + */ + +m_select(th, flee) +register struct thing *th; +register bool flee; /* True if running away or player is inaccessible in wall */ +{ + register struct room *rer, *ree; /* room of chaser, room of chasee */ + int dist = INT_MIN; + int mindist = INT_MAX, maxdist = INT_MIN; + bool rundoor; /* TRUE means run to a door */ + char sch; + coord *last_door=0, /* Door we just came from */ + this; /* Temporary destination for chaser */ + + rer = roomin(&th->t_pos); /* Find room of chaser */ + ree = roomin(th->t_dest); /* Find room of chasee */ + + /* First see if we want to use an ability or weapon */ + if (m_use_it(th, flee, rer, ree)) return; + + /* + * We don't count monsters on doors as inside rooms here because when + * a monster is in a room and the player is not in that room, the + * monster looks for the best door out. If we counted doors as part + * of the room, the monster would already be on the best door out; + * so he would never move. + */ + if ((sch = mvwinch(stdscr, th->t_pos.y, th->t_pos.x)) == DOOR || + sch == SECRETDOOR || sch == PASSAGE) { + rer = NULL; + } + this = *th->t_dest; + + /* + * If we are in a room heading for the player and the player is not + * in the room with us, we run to the "best" door. + * If we are in a room fleeing from the player, then we run to the + * "best" door if he IS in the same room. + * + * Note: We don't bother with doors in mazes or if we can walk + * through walls. + */ + if (rer != NULL && levtype != MAZELEV && off(*th, CANINWALL)) { + if (flee) rundoor = (rer == ree); + else rundoor = (rer != ree); + } + else rundoor = FALSE; + + if (rundoor) { + register struct linked_list *exitptr; /* For looping through exits */ + coord *exit, /* A particular door */ + *entrance; /* Place just inside doorway */ + int exity, exitx; /* Door's coordinates */ + char dch='\0'; /* Door character */ + + if ((th->t_doorgoal.x != -1) && (th->t_doorgoal.y != -1)) + dch = mvwinch(stdscr, th->t_doorgoal.y, th->t_doorgoal.x); + + /* Do we have a valid goal? */ + if ((dch == PASSAGE || dch == DOOR) && /* A real door */ + (!flee || !ce(th->t_doorgoal, *th->t_dest))) { /* Prey should not + * be at door if + * we are running + * away + */ + /* Make sure the player is not in the doorway, either */ + entrance = doorway(rer, &th->t_doorgoal); + if (!flee || entrance == NULL || !ce(*entrance, *th->t_dest)) { + this = th->t_doorgoal; + dist = 0; /* Indicate that we have our door */ + } + } + + /* Go through all the doors */ + else for (exitptr = rer->r_exit; exitptr; exitptr = next(exitptr)) { + exit = DOORPTR(exitptr); + exity = exit->y; + exitx = exit->x; + + /* Make sure it is a real door */ + dch = mvwinch(stdscr, exity, exitx); + if (dch == PASSAGE || dch == DOOR) { + /* Don't count a door if we are fleeing from someone and + * he is standing on it. Also, don't count it if he is + * standing in the doorway. + */ + if (flee) { + if (ce(*exit, *th->t_dest)) continue; + + entrance = doorway(rer, exit); + if (entrance != NULL && ce(*entrance, *th->t_dest)) + continue; + } + + /* Were we just on this door? */ + if (ce(*exit, th->t_oldpos)) last_door = exit; + + else { + dist = DISTANCE(th->t_dest->y, th->t_dest->x, exity, exitx); + + /* If fleeing, we want to maximize distance from door to + * what we flee, and minimize distance from door to us. + */ + if (flee) + dist -= DISTANCE(th->t_pos.y, th->t_pos.x, exity, exitx); + + /* Maximize distance if fleeing, otherwise minimize it */ + if ((flee && (dist > maxdist)) || + (!flee && (dist < mindist))) { + th->t_doorgoal = *exit; /* Use this door */ + this = *exit; + mindist = maxdist = dist; + } + } + } + } + + /* Could we not find a door? */ + if (dist == INT_MIN) { + /* If we were on a door, go ahead and use it */ + if (last_door) { + th->t_doorgoal = *last_door; + this = th->t_oldpos; + dist = 0; /* Indicate that we found a door */ + } + else th->t_doorgoal.x = th->t_doorgoal.y = -1; /* No more door goal */ + } + + /* Indicate that we do not want to flee from the door */ + if (dist != INT_MIN) flee = FALSE; + } + else th->t_doorgoal.x = th->t_doorgoal.y = -1; /* Not going to any door */ + + /* Now select someplace to go and start the action */ + chase(th, &this, rer, ree, flee); +} + +/* + * m_sonic: + * The monster is sounding a sonic blast. + */ + +m_sonic(tp) +register struct thing *tp; +{ + register int damage; + struct object blast = + { + MISSILE, {0, 0}, 0, "", "150" , NULL, 0, 0, 0, 0 + }; + + turn_off(*tp, CANSONIC); + turn_off(*tp, CANSURPRISE); + do_motion(&blast, tp->t_newpos.y, tp->t_newpos.x, tp); + damage = rnd(61)+40; + if (save(VS_BREATH, &player, -3)) + damage /= 2; + msg ("%s's ultra-sonic blast hits you", prname(monster_name(tp), TRUE)); + if ((pstats.s_hpt -= damage) <= 0) { + pstats.s_hpt = -1; + death(tp->t_index); + } + running = FALSE; + if (fight_flush) flushinp(); + dsrpt_player(); +} + +/* + * m_spell: + * The monster casts a spell. Currently this is limited to + * magic missile. + */ +m_spell(tp) +register struct thing *tp; +{ + struct object missile = + { + MISSILE, {0, 0}, 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1 + }; + + sprintf(missile.o_hurldmg, "%dd4", tp->t_stats.s_lvl); + do_motion(&missile, tp->t_newpos.y, tp->t_newpos.x, tp); + hit_monster(unc(missile.o_pos), &missile, tp); + turn_off(*tp, CANMISSILE); + turn_off(*tp, CANSURPRISE); + + running = FALSE; + if (fight_flush) flushinp(); +} + +/* + * m_summon: + * Summon aid. + */ + +m_summon(tp) +register struct thing *tp; +{ + register char *helpname, *mname; + int fail, numsum; + register int which, i; + + /* Let's make sure our prey is still here */ + if (!cansee(unc(tp->t_pos)) || fallpos(&hero, FALSE, 2) == NULL) return; + + /* + * Non-uniques can only summon once. Uniques get fewer + * creatures with each successive summoning. Also, the + * probability of summoning goes down + */ + if (off(*tp, ISUNIQUE)) + turn_off(*tp, CANSUMMON); + + turn_off(*tp, CANSURPRISE); + mname = monster_name(tp); + helpname = monsters[tp->t_index].m_typesum; + which = findmindex(helpname); + + if ((off(*tp, ISINVIS) || on(player, CANSEE)) && + (off(*tp, ISSHADOW) || on(player, CANSEE)) && + (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) { + if (monsters[which].m_normal == FALSE) { /* genocided? */ + msg("%s appears dismayed", prname(mname, TRUE)); + monsters[tp->t_index].m_numsum = 0; + } + else { + msg("%s summons %ss for help", prname(mname, TRUE), helpname); + } + } + else { + if (monsters[which].m_normal == FALSE) /* genocided? */ + monsters[tp->t_index].m_numsum = 0; + else { + msg("%ss seem to appear from nowhere!", helpname); + } + } + numsum = monsters[tp->t_index].m_numsum; + if (numsum && on(*tp, ISUNIQUE)) { /* UNIQUEs summon less each time */ + monsters[tp->t_index].m_numsum--; + tp->t_summon *= 2; /* cut probability in half */ + } + + /* + * try to make all the creatures around player but remember + * if unsuccessful + */ + for (i=0, fail=0; i<numsum; i++) { + if (!creat_mons(&player, which, FALSE)) + fail++; /* remember the failures */ + } + + /* + * try once again to make the buggers + */ + for (i=0; i<fail; i++) + creat_mons(tp, which, FALSE); + + /* Now let the poor fellow see all the trouble */ + light(&hero); + turn_on(*tp, HASSUMMONED); +} + +/* + * m_use_it: + * See if the monster (tp) has anything useful it can do + * (ie. an ability or a weapon) other than just move. + */ + +bool +m_use_it(tp, flee, rer, ree) +register struct thing *tp; +bool flee; +register struct room *rer, *ree; +{ + int dist; + register coord *ee = tp->t_dest, *er = &tp->t_pos; + coord *shoot_dir = NULL; + coord straight_dir; + int straight_shot = FALSE; + struct thing *prey; + bool dest_player; /* Are we after the player? */ + + /* + * If we are fleeing, there's a chance, depending on our + * intelligence, that we'll just run in terror. + */ + if (flee && rnd(25) >= tp->t_stats.s_intel) return(FALSE); + + /* + * Make sure that we have a living destination, and record whether + * it is the player. + */ + if (ee != NULL) { + if (ce(*ee, hero)) { + dest_player = TRUE; + prey = &player; + } + else { + struct linked_list *item; + + dest_player = FALSE; + + /* What is the monster we're chasing? */ + item = find_mons(ee->y, ee->x); + if (item != NULL) prey = THINGPTR(item); + else return(FALSE); + } + } + else return(FALSE); + + /* + * If we are friendly to the hero, we don't do anything. + */ + if (on(*tp, ISFRIENDLY) && dest_player) return(FALSE); + + /* + * Also, for now, if our prey is in a wall, we won't do + * anything. The prey must be in the same room as we are OR + * we must have a straight shot at him. Note that + * shoot_dir must get set before rer is checked so + * that we get a valid value. + */ + + if (can_shoot(er, ee, &straight_dir) == 0) + shoot_dir = &straight_dir; + else + shoot_dir = NULL; + + if (on(*prey, ISINWALL) || + ( (shoot_dir == NULL) && (rer == NULL || rer != ree))) + return(FALSE); + + /* + * If we can't see the prey then forget it + */ + if (on(*prey, ISINVIS) && off(*tp, CANSEE)) + return(FALSE); + + /* How far are we from our prey? */ + dist = DISTANCE(er->y, er->x, ee->y, ee->x); + + /* + * Shall we summon aid so we don't have to get our hands dirty? + * For now, we will only summon aid against the player. + * We'll wait until he's within 2 dots of a missile length. + */ + if (on(*tp, CANSUMMON) && dest_player && + dist < (BOLT_LENGTH+2)*(BOLT_LENGTH+2) && + rnd(tp->t_summon) < tp->t_stats.s_lvl && + monsters[tp->t_index].m_numsum > 0 && + fallpos(&hero, FALSE, 2) != NULL) { + tp->t_action = A_SUMMON; /* We're going to summon help */ + tp->t_no_move = movement(tp); /* It takes time! */ + return(TRUE); + } + + /* + * If the creature can cast a slow spell and if the prey is within + * 2 dots of a missile fire, then see whether we will cast it. + * if next to player, lessen chance because we don't like being + * disrupted + */ + if (on(*tp, CANSLOW) && dest_player && + dist < (BOLT_LENGTH+5)*(BOLT_LENGTH+5) && + rnd(100) < (dist > 3 ? tp->t_cast : tp->t_cast/2)) { + tp->t_action = A_SLOW; /* We're going to slow him */ + tp->t_no_move = 3 * movement(tp); /* Takes time! */ + debug("casting slow spell!"); + return(TRUE); + } + + /* + * If we have a special magic item, we might use it. We will restrict + * this options to uniques with relics and creatures with wands for now. + * Also check for the quartermaster. Don't want him shooting wands.... + */ + if ((on(*tp, ISUNIQUE) || on(*tp, CARRYSTICK)) && + off(*tp, CANSELL) && dest_player && + m_use_pack(tp, ee, dist, shoot_dir)) { + return(TRUE); + } + + /* From now on, we must have a direct shot at the prey */ + if (!straight_shot) return(FALSE); + + /* We may use a sonic blast if we can, only on the player */ + if (on(*tp, CANSONIC) && + dest_player && + (dist < BOLT_LENGTH*2) && + (rnd(100) < tp->t_breathe)) { + tp->t_newpos = *shoot_dir; /* Save the direction */ + tp->t_action = A_SONIC; /* We're going to sonic blast */ + tp->t_no_move = 2 * movement(tp); /* Takes 2 movement periods */ + } + + /* If we can breathe, we may do so */ + else if (on(*tp, CANBREATHE) && + (dist < BOLT_LENGTH*BOLT_LENGTH) && + (rnd(100) < tp->t_breathe)) { + tp->t_newpos = *shoot_dir; /* Save the direction */ + tp->t_action = A_BREATHE; /* We're going to breathe */ + tp->t_no_move = movement(tp); /* It takes 1 movement period */ + } + + /* + * We may shoot missiles if we can + * if next to player, lessen chance so we don't get disrupted as often + */ + else if (on(*tp,CANMISSILE) && + rnd(100) < (dist > 3 ? tp->t_cast : tp->t_cast/2)){ + tp->t_newpos = *shoot_dir; /* Save the direction */ + tp->t_action = A_MISSILE; /* We're going to shoot MM's */ + tp->t_no_move = 3 * movement(tp); /* Takes time! */ + } + + /* + * If we can shoot or throw something, we might do so. + * If next to player, then forget it + */ + else if ((on(*tp,CANSHOOT) || on(*tp,CARRYWEAPON) || + on(*tp,CARRYDAGGER) || on(*tp, CARRYAXE)) && + dist > 3 && + off(*tp, CANSELL) && + (get_hurl(tp) != NULL)) { + tp->t_newpos = *shoot_dir; /* Save the direction */ + tp->t_action = A_THROW; /* We're going to throw something */ + tp->t_using = get_hurl(tp); /* Save our weapon */ + tp->t_no_move = 2 * movement(tp); /* Takes 2 movement periods */ + } + + /* We couldn't find anything to do */ + else return(FALSE); + + return(TRUE); + +} + +reap() +{ + _t_free_list(&rlist); +} + +/* + * runners: + * Make all the awake monsters try to do something. + */ + +runners(segments) +int segments; /* Number of segments since last called */ +{ + register struct linked_list *item; + register struct thing *tp = NULL; + register int min_time = 20; /* Minimum time until a monster can act */ + + /* + * loop thru the list of running (wandering) monsters and see what + * each one will do this time. + * + * Note: the special case that one of this buggers kills another. + * if this happens than we have to see if the monster killed + * himself or someone else. In case its himself we have to get next + * one immediately. If it wasn't we have to get next one at very + * end in case he killed the next one. + */ + for (item = mlist; item != NULL; item = item->l_next) + { + tp = THINGPTR(item); + turn_on(*tp, NEEDSTOACT); + } + + for(;;) + { + for (item = mlist; item != NULL; item = item->l_next) + { + tp = THINGPTR(item); + + if (on(*tp, NEEDSTOACT)) + break; + } + + if (item == NULL) + break; + + turn_off(*tp, NEEDSTOACT); + + /* If we are not awake, just skip us */ + + if (off(*tp, ISRUN) && off(*tp, ISHELD)) + continue; + + /* See if it's our turn */ + + tp->t_no_move -= segments; + + if (tp->t_no_move > 0) + { + if (tp->t_no_move < min_time) min_time = tp->t_no_move; + continue; + } + + /* If we were frozen, we're moving now */ + + if (tp->t_action == A_FREEZE) + tp->t_action = A_NIL; + + if (on(*tp, ISHELD)) + { + /* Make sure the action and using are nil */ + + tp->t_action = A_NIL; + tp->t_using = NULL; + + /* Can we break free? */ + + if (rnd(tp->t_stats.s_lvl) > 11) + { + turn_off(*tp, ISHELD); + + runto(tp, &hero); + + if (cansee(tp->t_pos.y, tp->t_pos.x)) + msg("%s breaks free from the hold spell", + prname(monster_name(tp), TRUE)); + } + else /* Too bad -- try again later */ + tp->t_no_move = movement(tp); + } + + /* Heal the creature if it's not in the middle of some action */ + + if (tp->t_action == A_NIL) + doctor(tp); + + while (off(*tp, ISELSEWHERE) && + off(*tp, ISDEAD) && + tp->t_no_move <= 0 && + off(*tp, ISHELD) && + on(*tp, ISRUN) ) + { + /* Let's act (or choose an action if t_action = A_NIL) */ + + m_act(tp); + } + + if ( off(*tp,ISELSEWHERE) && off(*tp,ISDEAD) ) + { + if (tp->t_no_move < min_time) + min_time = tp->t_no_move; + + if (tp->t_quiet < 0) + tp->t_quiet = 0; + } + } + + return(min_time); +} + +/* + * See if a monster has some magic it can use. Return TRUE if so. + * Only care about relics and wands for now. + */ +bool +m_use_pack(monster, defend_pos, dist, shoot_dir) +register struct thing *monster; +coord *defend_pos; +register int dist; +register coord *shoot_dir; +{ + register struct object *obj; + register struct linked_list *pitem, *relic, *stick; + register int units = -1; + + relic = stick = NULL; + + for (pitem=monster->t_pack; pitem; pitem=next(pitem)) { + obj = OBJPTR(pitem); + if (obj->o_flags & ISCURSED) continue; + if (obj->o_type == RELIC) { + switch (obj->o_which) { + case MING_STAFF: + if (shoot_dir != NULL) { + units = 2; /* Use 2 time units */ + relic = pitem; + } + + when EMORI_CLOAK: + if (obj->o_charges != 0 && + shoot_dir != NULL) { + units = 2; /* Use 2 time units */ + relic = pitem; + } + + when ASMO_ROD: + /* The bolt must be able to reach the defendant */ + if (shoot_dir != NULL && + dist < BOLT_LENGTH * BOLT_LENGTH) { + units = 2; /* Use 2 time units */ + relic = pitem; + } + + when BRIAN_MANDOLIN: + /* The defendant must be the player and within 4 spaces */ + if (ce(*defend_pos, hero) && + dist < 25 && + player.t_action != A_FREEZE) { + units = 4; + relic = pitem; + } + + when GERYON_HORN: + /* The defendant must be the player and within 5 spaces */ + if (ce(*defend_pos, hero) && + dist < 25 && + (off(player,ISFLEE)|| player.t_dest!=&monster->t_pos)) { + units = 3; + relic = pitem; + } + } + } + if (obj->o_type == STICK) { + if (obj->o_charges < 1) continue; + switch(obj->o_which) { + case WS_ELECT: + case WS_FIRE: + case WS_COLD: + /* The bolt must be able to reach the defendant */ + if (shoot_dir != NULL && + dist < BOLT_LENGTH * BOLT_LENGTH) { + units = 3; + stick = pitem; + } + + when WS_MISSILE: + case WS_SLOW_M: + case WS_CONFMON: + case WS_PARALYZE: + case WS_MDEG: + case WS_FEAR: + if (shoot_dir != NULL) { + units = 3; + stick = pitem; + } + + otherwise: + break; + } + } + } + + /* use relics in preference to all others */ + if (relic) debug("chance to use relic = %d%%", monster->t_artifact); + if (stick) debug("chance to use stick = %d%%", monster->t_wand); + if (relic && rnd(100) < monster->t_artifact) { + monster->t_action = A_USERELIC; + pitem = relic; + } + else if (stick && rnd(100) < monster->t_wand) { + /* + * see if the monster will use the wand + */ + pitem = stick; + monster->t_action = A_USEWAND; + } + else { + return(FALSE); + } + + monster->t_no_move = units * movement(monster); + monster->t_using = pitem; + monster->t_newpos = *shoot_dir; + return(TRUE); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/bolt.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,401 @@ +/* + bolt.c - functions shooting an object across the room + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include "rogue.h" + +/* + * shoot_bolt fires a bolt from the given starting point in the + * given direction + */ + +shoot_bolt(shooter, start, dir, get_points, reason, name, damage) +struct thing *shooter; +coord start, dir; +bool get_points; +short reason; +char *name; +int damage; +{ + unsigned char dirch = 0, ch; + bool used, change, see_him; + short y, x, bounces; + coord pos; + struct linked_list *target=NULL; + struct { + coord place; + char oldch; + } spotpos[BOLT_LENGTH]; + + switch (dir.y + dir.x) { + case 0: dirch = '/'; + when 1: case -1: dirch = (dir.y == 0 ? '-' : '|'); + when 2: case -2: dirch = '\\'; + } + pos.y = start.y + dir.y; + pos.x = start.x + dir.x; + used = FALSE; + change = FALSE; + + bounces = 0; /* No bounces yet */ + nofont(cw); + for (y = 0; y < BOLT_LENGTH && !used; y++) { + ch = winat(pos.y, pos.x); + spotpos[y].place = pos; + spotpos[y].oldch = mvwinch(cw, pos.y, pos.x); + + /* Are we at hero? */ + if (ce(pos, hero)) goto at_hero; + + switch (ch) { + case SECRETDOOR: + case VERTWALL: + case HORZWALL: + case ' ': + if (dirch == '-' || dirch == '|') { + dir.y = -dir.y; + dir.x = -dir.x; + } + else { + unsigned char chx = mvinch(pos.y-dir.y, pos.x), + chy = mvinch(pos.y, pos.x-dir.x); + bool anychange = FALSE; /* Did we change anthing */ + + if (chy == WALL || chy == SECRETDOOR || + chy == HORZWALL || chy == VERTWALL) { + dir.y = -dir.y; + change ^= TRUE; /* Change at least one direction */ + anychange = TRUE; + } + if (chx == WALL || chx == SECRETDOOR || + chx == HORZWALL || chx == VERTWALL) { + dir.x = -dir.x; + change ^= TRUE; /* Change at least one direction */ + anychange = TRUE; + } + + /* If we didn't make any change, make both changes */ + if (!anychange) { + dir.x = -dir.x; + dir.y = -dir.y; + } + } + + /* Do we change how the bolt looks? */ + if (change) { + change = FALSE; + if (dirch == '\\') dirch = '/'; + else if (dirch == '/') dirch = '\\'; + } + + y--; /* The bounce doesn't count as using up the bolt */ + + /* Make sure we aren't in an infinite bounce */ + if (++bounces > BOLT_LENGTH) used = TRUE; + msg("The %s bounces", name); + break; + default: + if (isalpha(ch)) { + register struct linked_list *item; + struct thing *tp; + register char *mname; + bool see_monster = cansee(pos.y, pos.x); + + item = find_mons(unc(pos)); + assert(item != NULL); + tp = THINGPTR(item); + mname = monster_name(tp); + + /* + * If our prey shot this, let's record the fact that + * he can shoot, regardless of whether he hits us. + */ + if (tp->t_dest != NULL && ce(*tp->t_dest, shooter->t_pos)) + tp->t_wasshot = TRUE; + + if (!save(VS_BREATH, tp, -(shooter->t_stats.s_lvl/10))) { + if (see_monster) { + if (on(*tp, ISDISGUISE) && + (tp->t_type != tp->t_disguise)) { + msg("Wait! That's a %s!", mname); + turn_off(*tp, ISDISGUISE); + } + + turn_off(*tp, CANSURPRISE); + msg("The %s hits %s", name, prname(mname, FALSE)); + } + + /* Should we start to chase the shooter? */ + if (shooter != &player && + shooter != tp && + shooter->t_index != tp->t_index && + (tp->t_dest == NULL || rnd(100) < 25)) { + /* + * If we're intelligent enough to realize that this + * is a friendly monster, we will attack the hero + * instead. + */ + if (on(*shooter, ISFRIENDLY) && + roll(3,6) < tp->t_stats.s_intel) + runto(tp, &hero); + + /* Otherwise, let's chase the monster */ + else runto(tp, &shooter->t_pos); + } + else if (shooter == &player) { + runto(tp, &hero); + + /* + * If the player shot a charmed monster, it may + * not like being shot at. + */ + if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) { + msg("The eyes of %s turn clear.", + prname(mname, FALSE)); + turn_off(*tp, ISCHARMED); + mname = monster_name(tp); + } + } + + /* + * Let the defender know that the attacker has + * missiles! + */ + if (ce(*tp->t_dest, shooter->t_pos)) + tp->t_wasshot = TRUE; + + used = TRUE; + + /* Hit the monster -- does it do anything? */ + if ((EQUAL(name,"ice") && on(*tp, NOCOLD)) || + (EQUAL(name,"flame") && on(*tp, NOFIRE)) || + (EQUAL(name,"acid") && on(*tp, NOACID)) || + (EQUAL(name,"lightning bolt")&& on(*tp,NOBOLT)) || + (EQUAL(name,"nerve gas") &&on(*tp,NOPARALYZE))|| + (EQUAL(name,"sleeping gas") && + (on(*tp, NOSLEEP) || on(*tp, ISUNDEAD))) || + (EQUAL(name,"slow gas") && on(*tp,NOSLOW)) || + (EQUAL(name,"fear gas") && on(*tp,NOFEAR)) || + (EQUAL(name,"confusion gas") && on(*tp,ISCLEAR)) || + (EQUAL(name,"chlorine gas") && on(*tp,NOGAS))) { + if (see_monster) + msg("The %s has no effect on %s.", + name, prname(mname, FALSE)); + } + + else { + see_him = !invisible(tp); + + /* Did a spell get disrupted? */ + dsrpt_monster(tp, FALSE, see_him); + + /* + * Check for gas with special effects + */ + if (EQUAL(name, "nerve gas")) { + tp->t_no_move = movement(tp) * FREEZETIME; + tp->t_action = A_FREEZE; + } + else if (EQUAL(name, "sleeping gas")) { + tp->t_no_move = movement(tp) * SLEEPTIME; + tp->t_action = A_FREEZE; + } + else if (EQUAL(name, "slow gas")) { + if (on(*tp, ISHASTE)) + turn_off(*tp, ISHASTE); + else + turn_on(*tp, ISSLOW); + } + else if (EQUAL(name, "fear gas")) { + turn_on(*tp, ISFLEE); + tp->t_dest = &hero; + + /* It is okay to turn tail */ + tp->t_oldpos = tp->t_pos; + } + else if (EQUAL(name, "confusion gas")) { + turn_on(*tp, ISHUH); + tp->t_dest = &hero; + } + else if ((EQUAL(name, "lightning bolt")) && + on(*tp, BOLTDIVIDE)) { + if (creat_mons(tp, tp->t_index, FALSE)) { + if (see_monster) + msg("The %s divides %s.", + name,prname(mname, FALSE)); + light(&hero); + } + else if (see_monster) + msg("The %s has no effect on %s.", + name, prname(mname, FALSE)); + } + else { + if (save(VS_BREATH, tp, + -(shooter->t_stats.s_lvl/10))) + damage /= 2; + + /* The poor fellow got killed! */ + if ((tp->t_stats.s_hpt -= damage) <= 0) { + if (see_monster) + msg("The %s kills %s", + name, prname(mname, FALSE)); + else + msg("You hear a faint groan in the distance"); + /* + * Instead of calling killed() here, we + * will record that the monster was killed + * and call it at the end of the routine, + * after we restore what was under the bolt. + * We have to do this because in the case + * of a bolt that first misses the monster + * and then gets it on the bounce. If we + * call killed here, the 'missed' space in + * spotpos puts the monster back on the + * screen + */ + target = item; + } + else { /* Not dead, so just scream */ + if (!see_monster) + msg("You hear a scream in the distance"); + } + } + } + } + else if (isalpha(show(pos.y, pos.x))) { + if (see_monster) { + if (terse) + msg("%s misses", name); + else + msg("The %s whizzes past %s", + name, prname(mname, FALSE)); + } + if (get_points) runto(tp, &hero); + } + } + else if (pos.y == hero.y && pos.x == hero.x) { +at_hero: if (!save(VS_BREATH, &player, + -(shooter->t_stats.s_lvl/10))){ + if (terse) + msg("The %s hits you", name); + else + msg("You are hit by the %s", name); + used = TRUE; + + /* + * The Amulet of Yendor protects against all "breath" + * + * The following two if statements could be combined + * into one, but it makes the compiler barf, so split + * it up + */ + if (cur_relic[YENDOR_AMULET] || + (EQUAL(name,"chlorine gas")&&on(player, NOGAS)) || + (EQUAL(name,"acid")&&on(player, NOACID)) || + (EQUAL(name,"sleeping gas")&&ISWEARING(R_ALERT))){ + msg("The %s has no effect", name); + } + else if((EQUAL(name, "flame") && on(player, NOFIRE)) || + (EQUAL(name, "ice") && on(player, NOCOLD)) || + (EQUAL(name,"lightning bolt")&& + on(player,NOBOLT)) || + (EQUAL(name,"fear gas")&&ISWEARING(R_HEROISM))){ + msg("The %s has no effect", name); + } + + else { + dsrpt_player(); + + /* + * Check for gas with special effects + */ + if (EQUAL(name, "nerve gas")) { + msg("The nerve gas paralyzes you."); + player.t_no_move += + movement(&player) * FREEZETIME; + player.t_action = A_FREEZE; + } + else if (EQUAL(name, "sleeping gas")) { + msg("The sleeping gas puts you to sleep."); + player.t_no_move += + movement(&player) * SLEEPTIME; + player.t_action = A_FREEZE; + } + else if (EQUAL(name, "confusion gas")) { + if (off(player, ISCLEAR)) { + if (on(player, ISHUH)) + lengthen(unconfuse, + rnd(20)+HUHDURATION); + else { + turn_on(player, ISHUH); + fuse(unconfuse, (VOID *)NULL, + rnd(20)+HUHDURATION, AFTER); + msg("The confusion gas has confused you."); + } + } + else msg("You feel dizzy for a moment, but it quickly passes."); + } + else if (EQUAL(name, "slow gas")) { + add_slow(); + } + else if (EQUAL(name, "fear gas")) { + turn_on(player, ISFLEE); + player.t_dest = &shooter->t_pos; + msg("The fear gas terrifies you."); + } + else { + if (EQUAL(name, "acid") && + cur_armor != NULL && + !(cur_armor->o_flags & ISPROT) && + !save(VS_BREATH, &player, -2) && + cur_armor->o_ac < pstats.s_arm+1) { + msg("Your armor corrodes from the acid"); + cur_armor->o_ac++; + } + if (save(VS_BREATH, &player, + -(shooter->t_stats.s_lvl/10)) && + off(player, NOACID)) + damage /= 2; + if ((pstats.s_hpt -= damage) <= 0) + death(reason); + } + } + } + else + msg("The %s whizzes by you", name); + } + + mvwaddch(cw, pos.y, pos.x, dirch); + draw(cw); + } + + pos.y += dir.y; + pos.x += dir.x; + } + + /* Restore what was under the bolt */ + newfont(cw); + for (x = y - 1; x >= 0; x--) + mvwaddch(cw, spotpos[x].place.y, spotpos[x].place.x, spotpos[x].oldch); + + /* If we killed something, do so now. This will also blank the monster. */ + if (target) killed(target, FALSE, get_points, TRUE); + return; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/chase.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,936 @@ +/* + chase.c - Code for one object to chase another + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <ctype.h> +#include <curses.h> +#include <limits.h> +#include "rogue.h" + +/* + * Canblink checks if the monster can teleport (blink). If so, it will + * try to blink the monster next to the player. + */ + +bool +can_blink(tp) +register struct thing *tp; +{ + register int y, x, index=9; + coord tryp; /* To hold the coordinates for use in diag_ok */ + bool spots[9], found_one=FALSE; + + /* + * First, can the monster even blink? And if so, there is only a 50% + * chance that it will do so. And it won't blink if it is running or + * held. + */ + if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) || + on(*tp, ISFLEE) || + tp->t_action == A_FREEZE || + (rnd(12) < 6)) return(FALSE); + + + /* Initialize the spots as illegal */ + do { + spots[--index] = FALSE; + } while (index > 0); + + /* Find a suitable spot next to the player */ + for (y=hero.y-1; y<hero.y+2; y++) + for (x=hero.x-1; x<hero.x+2; x++, index++) { + /* Make sure x coordinate is in range and that we are + * not at the player's position + */ + if (x<0 || x >= cols || index == 4) continue; + + /* Is it OK to move there? */ + if (step_ok(y, x, NOMONST, tp) && + (!isatrap(mvwinch(cw, y, x)) || + rnd(10) >= tp->t_stats.s_intel || + on(*tp, ISFLY))) { + /* OK, we can go here. But don't go there if + * monster can't get at player from there + */ + tryp.y = y; + tryp.x = x; + if (diag_ok(&tryp, &hero, tp)) { + spots[index] = TRUE; + found_one = TRUE; + } + } + } + + /* If we found one, go to it */ + if (found_one) { + unsigned char rch; /* What's really where the creatures moves to */ + + /* Find a legal spot */ + while (spots[index=rnd(9)] == FALSE) continue; + + /* Get the coordinates */ + y = hero.y + (index/3) - 1; + x = hero.x + (index % 3) - 1; + + /* Move the monster from the old space */ + mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch); + + /* Move it to the new space */ + tp->t_oldch = mvwinch(cw, y, x); + + /* Display the creature if our hero can see it */ + if (cansee(y, x) && + off(*tp, ISINWALL) && + !invisible(tp)) + mvwaddch(cw, y, x, tp->t_type); + + /* Fix the monster window */ + mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Clear old position */ + mvwaddch(mw, y, x, tp->t_type); + + /* Record the new position */ + tp->t_pos.y = y; + tp->t_pos.x = x; + + /* If the monster is on a trap, trap it */ + rch = mvinch(y, x); + if (isatrap(rch)) { + if (cansee(y, x)) tp->t_oldch = rch; + be_trapped(tp, &(tp->t_pos)); + } + } + + return(found_one); +} + +/* + * Can_shoot determines if the monster (er) has a direct line of shot + * at the prey (ee). If so, it returns the direction in which to shoot. + */ + +int +can_shoot(er, ee, shoot_dir) +register coord *er, *ee, *shoot_dir; +{ + /* + * They must be in the same room or very close (at door) + */ + if (roomin(er) != roomin(ee) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1) + { + shoot_dir->x = shoot_dir->y = 0; + return(-1); + } + + /* Do we have a straight shot? */ + if (!straight_shot(er->y, er->x, ee->y, ee->x, shoot_dir)) + { + shoot_dir->x = shoot_dir->y = 0; + return(-2); + } + else + return(0); +} + +/* + * chase: + * Find the spot for the chaser(er) to move closer to the + * chasee(ee). Rer is the room of the chaser, and ree is the + * room of the creature being chased (chasee). + */ + +chase(tp, ee, rer, ree, flee) +register struct thing *tp; +register coord *ee; +register struct room *rer, *ree; +bool flee; /* True if destination (ee) is player and monster is running away + * or the player is in a wall and the monster can't get to it + */ +{ + int dist, thisdist, monst_dist = INT_MAX; + register coord *er = &tp->t_pos; + struct thing *prey; /* What we are chasing */ + coord ch_ret; /* Where chasing takes you */ + unsigned char ch, mch; + bool next_player = FALSE; + + /* + * set the distance from the chas(er) to the chas(ee) here and then + * we won't have to reset it unless the chas(er) moves (instead of shoots) + */ + dist = DISTANCE(er->y, er->x, ee->y, ee->x); + + /* + * See if our destination is a monster or player. If so, make "prey" point + * to it. + */ + if (ce(hero, *ee)) prey = &player; /* Is it the player? */ + else if (tp->t_dest && ce(*(tp->t_dest), *ee)) { /* Is it a monster? */ + struct linked_list *item; + + /* What is the monster we're chasing? */ + item = find_mons(ee->y, ee->x); + if (item != NULL) prey = THINGPTR(item); + else prey = NULL; + } + else prey = NULL; + + /* We will use at least one movement period */ + tp->t_no_move = movement(tp); + if (on(*tp, ISFLY)) /* If the creature is flying, speed it up */ + tp->t_no_move /= 2; + + /* + * If the thing is confused or it can't see the player, + * let it move randomly. + */ + if ((on(*tp, ISHUH) && rnd(10) < 8) || + (prey && on(*prey, ISINVIS) && off(*tp, CANSEE))) { /* invisible prey */ + /* + * get a valid random move + */ + tp->t_newpos = rndmove(tp); + dist = DISTANCE(tp->t_newpos.y, tp->t_newpos.x, ee->y, ee->x); + } + + /* + * Otherwise, find the empty spot next to the chaser that is + * closest to the chasee. + */ + else { + register int ey, ex, x, y; + int dist_to_old = INT_MIN; /* Dist from goal to old position */ + + /* + * This will eventually hold where we move to get closer + * If we can't find an empty spot, we stay where we are. + */ + dist = flee ? 0 : INT_MAX; + ch_ret = *er; + + /* Are we at our goal already? */ + if (!flee && ce(ch_ret, *ee)) { + turn_off(*tp, ISRUN); /* So stop running! */ + return; + } + + ey = er->y + 1; + ex = er->x + 1; + + /* Check all possible moves */ + for (x = er->x - 1; x <= ex; x++) { + if (x < 0 || x >= cols) /* Don't try off the board */ + continue; + for (y = er->y - 1; y <= ey; y++) { + coord tryp; + + if ((y < 1) || (y >= lines - 2)) /* Don't try off the board */ + continue; + + /* Don't try the player if not going after the player */ + if ((flee || !ce(hero, *ee) || on(*tp, ISFRIENDLY)) && + x == hero.x && y == hero.y) { + next_player = TRUE; + continue; + } + + tryp.x = x; + tryp.y = y; + + /* Is there a monster on this spot closer to our goal? + * Don't look in our spot or where we were. + */ + if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) && + isalpha(mch = mvwinch(mw, y, x))) { + int test_dist; + + test_dist = DISTANCE(y, x, ee->y, ee->x); + if (test_dist <= 25 && /* Let's be fairly close */ + test_dist < monst_dist) { + /* Could we really move there? */ + mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */ + if (diag_ok(er, &tryp, tp)) monst_dist = test_dist; + mvwaddch(mw, y, x, mch); /* Restore monster */ + } + } + + /* Can we move onto the spot? */ + if (!diag_ok(er, &tryp, tp)) continue; + + ch = mvwinch(cw, y, x); /* Screen character */ + + /* + * Stepping on player is NOT okay if we are fleeing. + * If we are friendly to the player and there is a monster + * in the way that is not of our race, it is okay to move + * there. + */ + if (step_ok(y, x, FIGHTOK, tp) && + (off(*tp, ISFLEE) || ch != PLAYER)) + { + /* + * If it is a trap, an intelligent monster may not + * step on it (unless our hero is on top!) + */ + if ((isatrap(ch)) && + (rnd(10) < tp->t_stats.s_intel) && + (!on(*tp, ISFLY)) && + (y != hero.y || x != hero.x)) + continue; + + /* + * OK -- this place counts + */ + thisdist = DISTANCE(y, x, ee->y, ee->x); + + /* Adjust distance if we are being shot at */ + if (tp->t_wasshot && tp->t_stats.s_intel > 5 && + prey != NULL) { + /* Move out of line of sight */ + if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, (coord *)NULL)) { + if (flee) thisdist -= SHOTPENALTY; + else thisdist += SHOTPENALTY; + } + + /* But do we want to leave the room? */ + else if (rer && rer == ree && ch == DOOR) + thisdist += DOORPENALTY; + } + + /* Don't move to the last position if we can help it + * (unless out prey just moved there) + */ + if (ce(tryp, tp->t_oldpos) && (flee || !ce(tryp, hero))) + dist_to_old = thisdist; + + else if ((flee && (thisdist > dist)) || + (!flee && (thisdist < dist))) + { + ch_ret = tryp; + dist = thisdist; + } + } + } + } + + /* If we aren't trying to get the player, but he is in our way, + * hit him (unless we have been turned or are friendly). next_player + * being TRUE -> we are next to the player but don't want to hit him. + * + * If we are friendly to the player, following him, and standing next + * to him, we will try to help him out in battle. + */ + if (next_player && off(*tp, WASTURNED)) { + if (off(*tp, ISFRIENDLY) && + ((flee && ce(ch_ret, *er)) || + (!flee && DISTANCE(er->y, er->x, ee->y, ee->x) < dist)) && + step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) { + /* Okay to hit player */ + debug("Switching to hero."); + tp->t_newpos = hero; + tp->t_action = A_MOVE; + return; + } + else if (on(*tp, ISFRIENDLY) && !flee && ce(*ee, hero)) { + /* + * Look all around the player. If there is a fightable + * creature next to both of us, hit it. Otherwise, if + * there is a fightable creature next to the player, try + * to move next to it. + */ + dist = INT_MAX; + for (x = hero.x - 1; x <= hero.x + 1; x++) { + if (x < 0 || x >= cols) /* Don't try off the board */ + continue; + for (y = hero.y - 1; y <= hero.y + 1; y++) { + if ((y < 1) || (y >= lines - 2)) /* Stay on the board */ + continue; + + /* Is there a fightable monster here? */ + if (isalpha(mvwinch(mw, y, x)) && + step_ok(y, x, FIGHTOK, tp) && + off(*tp, ISSTONE)) { + thisdist = DISTANCE(er->y, er->x, y, x); + if (thisdist < dist) { + dist = thisdist; + ch_ret.y = y; + ch_ret.x = x; + } + } + } + } + + /* Are we next to a bad guy? */ + if (dist <= 2) { /* Get him! */ + tp->t_newpos = ch_ret; + tp->t_action = A_MOVE; + } + + /* Try to move to the bad guy */ + else if (dist < INT_MAX) + chase(tp, &ch_ret, + roomin(&tp->t_pos), roomin(&ch_ret), FALSE); + + else tp->t_action = A_NIL; + + return; + } + } + + /* + * If we have decided that we can move onto a monster (we are + * friendly to the player, go to it. + */ + if (!ce(ch_ret, *er) && isalpha(mvwinch(mw, ch_ret.y, ch_ret.x))) { + debug("Attack monster"); + tp->t_newpos = ch_ret; + tp->t_action = A_MOVE; + return; + } + + /* If we can't get closer to the player (if that's our goal) + * because other monsters are in the way, just stay put + */ + if (!flee && ce(hero, *ee) && monst_dist < INT_MAX && + DISTANCE(er->y, er->x, hero.y, hero.x) < dist) { + tp->t_action = A_NIL; /* do nothing for awhile */ + return; + } + + /* Do we want to go back to the last position? */ + else if (dist_to_old != INT_MIN && /* It is possible to move back */ + ((flee && dist == 0) || /* No other possible moves */ + (!flee && dist == INT_MAX))) { + /* Do we move back or just stay put (default)? */ + dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */ + if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos; + } + + /* Record the new destination */ + tp->t_newpos = ch_ret; + } + + /* + * Do we want to fight or move? If our selected destination (ch_ret) + * is our hero, then we want to fight. Otherwise, we want to move. + */ + if (ce(tp->t_newpos, hero)) { + /* Fight! (or sell) */ + if (on(*tp, CANSELL)) { + tp->t_action = A_SELL; + tp->t_no_move += movement(tp); /* takes a little time to sell */ + } + else { + tp->t_action = A_ATTACK; + + /* + * Try to find a weapon to wield. Wield_weap will return a + * projector if weapon is a projectile (eg. bow for arrow). + * If weapon is NULL (the case here), it will try to find + * a suitable weapon. + * + * Add in rest of time. Fight is + * movement() + weap_move() + FIGHTBASE + */ + tp->t_using = wield_weap((struct object *)NULL, tp); + if (tp->t_using == NULL) + tp->t_no_move += weap_move(tp, (struct object *)NULL); + else + tp->t_no_move += weap_move(tp, OBJPTR(tp->t_using)); + + if (on(*tp, ISHASTE)) + tp->t_no_move += FIGHTBASE/2; + else if (on(*tp, ISSLOW)) + tp->t_no_move += FIGHTBASE*2; + else + tp->t_no_move += FIGHTBASE; + } + } + else { + /* Move */ + tp->t_action = A_MOVE; + + /* + * Check if the creature is not next to the player. If it + * is not and has held or suffocated the player, then stop it! + * Note that this code should more appropriately appear in + * the area that actually moves the monster, but for now it + * is okay here because the player can't move while held or + * suffocating. + */ + if (dist > 2) { + if (on(*tp, DIDHOLD)) { + turn_off(*tp, DIDHOLD); + turn_on(*tp, CANHOLD); + if (--hold_count == 0) + turn_off(player, ISHELD); + } + + /* If monster was suffocating, stop it */ + if (on(*tp, DIDSUFFOCATE)) { + turn_off(*tp, DIDSUFFOCATE); + turn_on(*tp, CANSUFFOCATE); + extinguish(suffocate); + msg("You can breathe again.....Whew!"); + } + } + } +} + +/* + * do_chase: + * Make one thing chase another. + */ + +do_chase(th) +register struct thing *th; +{ + register struct room *orig_rer, /* Original room of chaser */ + *new_room; /* new room of monster */ + unsigned char floor, rch, sch; + coord old_pos, /* Old position of monster */ + ch_ret; /* Where we want to go */ + + if (on(*th, NOMOVE)) return; + + ch_ret = th->t_newpos; /* Record our desired new position */ + + /* + * Make sure we have an open spot (no other monster's gotten in our way, + * someone didn't just drop a scare monster there, our prey didn't just + * get there, etc.) + */ + if (!step_ok(th->t_newpos.y, th->t_newpos.x, FIGHTOK, th)) { + /* + * Most monsters get upset now. Guardians are all friends, + * and we don't want to see 50 messages in a row! + */ + if (th->t_stats.s_intel > 4 && + off(*th, ISUNDEAD) && + off(*th, ISGUARDIAN) && + off(*th, AREMANY) && + off(*th, ISHUH) && + off(*th, ISCHARMED) && + off(player, ISBLIND) && + cansee(unc(th->t_pos)) && + !invisible(th) && (rnd(15) < 5)) { + switch (rnd(10)) { + case 0: case 1: + msg("%s lashes out at you! ",prname(monster_name(th),TRUE)); + when 2: case 3: + msg("%s scrambles around. ",prname(monster_name(th), TRUE)); + otherwise: + msg("%s motions angrily. ", prname(monster_name(th), TRUE)); + } + } + return; + } + else if (ce(th->t_newpos, hero) || /* Player just got in our way */ + isalpha(mvwinch(mw, th->t_newpos.y, th->t_newpos.x))) { + bool fightplayer = ce(th->t_newpos, hero); + + /* If we were turned or are friendly, we just have to sit here! */ + if (fightplayer && (on(*th, WASTURNED) || on(*th, ISFRIENDLY))) return; + + /* Do we want to sell something? */ + if (fightplayer && on(*th, CANSELL)) { + th->t_action = A_SELL; + th->t_no_move += movement(th); /* takes a little time to sell */ + return; + } + + /* Let's hit him */ + th->t_action = A_ATTACK; + + /* + * Try to find a weapon to wield. Wield_weap will return a + * projector if weapon is a projectile (eg. bow for arrow). + * If weapon is NULL (the case here), it will try to find + * a suitable weapon. + */ + th->t_using = wield_weap((struct object *)NULL, th); + /* + * add in rest of time + */ + if (th->t_using == NULL) + th->t_no_move += weap_move(th, (struct object *)NULL); + else + th->t_no_move += weap_move(th, OBJPTR(th->t_using)); + if (on(*th, ISHASTE)) + th->t_no_move += FIGHTBASE/2; + else if (on(*th, ISSLOW)) + th->t_no_move += FIGHTBASE*2; + else + th->t_no_move += FIGHTBASE; + return; + } + + /* + * Blank out the old position and record the new position -- + * the blanking must be done first in case the positions are the same. + */ + mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); + mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type); + + /* Get new and old rooms of monster */ + new_room = roomin(&ch_ret); + orig_rer = roomin(&th->t_pos); + + /* Store the critter's old position and update the current one */ + old_pos = th->t_pos; + th->t_pos = ch_ret; + floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR; + + /* If we have a scavenger, it can pick something up */ + if (off(*th, ISGUARDIAN)) { + register struct linked_list *n_item, *o_item; + register int item_count = 0; + bool want_something = FALSE; + + while ((n_item = find_obj(ch_ret.y, ch_ret.x)) != NULL) { + register struct object *n_obj, *o_obj; + bool wants_it; + + /* Does this monster want anything? */ + if (want_something == FALSE) { + if (on(*th, ISSCAVENGE) || on(*th, CARRYFOOD) || + on(*th, CARRYGOLD) || on(*th, CARRYSCROLL) || + on(*th, CARRYPOTION) || on(*th, CARRYRING) || + on(*th, CARRYSTICK) || on(*th, CARRYMISC) || + on(*th, CARRYWEAPON) || on(*th, CARRYARMOR) || + on(*th, CARRYDAGGER)) { + want_something = TRUE; + + /* + * Blank the area. We have to do it only before the + * first item in case an item gets dropped in same + * place. We don't want to blank it out after it get + * dropped. + */ + mvaddch(ch_ret.y, ch_ret.x, floor); + + /* Were we specifically after something here? */ + if (ce(*th->t_dest, ch_ret)) { + /* If we're mean, we go after the hero */ + if (on(*th, ISMEAN)) runto(th, &hero); + + /* Otherwise just go back to sleep */ + else { + turn_off(*th, ISRUN); + th->t_dest = NULL; + } + } + } + else break; + } + + item_count++; /* Count the number of items */ + + /* + * see if he's got one of this group already + */ + o_item = NULL; + n_obj = OBJPTR(n_item); + detach(lvl_obj, n_item); + + /* See if he wants it */ + if (n_obj->o_type == SCROLL && n_obj->o_which == S_SCARE && + th->t_stats.s_intel < 16) + wants_it = FALSE; /* Most monsters don't want a scare monster */ + else if (on(*th, ISSCAVENGE)) wants_it = TRUE; + else { + wants_it = FALSE; /* Default case */ + switch (n_obj->o_type) { + case FOOD: if(on(*th, CARRYFOOD)) wants_it = TRUE; + when GOLD: if(on(*th, CARRYGOLD)) wants_it = TRUE; + when SCROLL:if(on(*th, CARRYSCROLL)) wants_it = TRUE; + when POTION:if(on(*th, CARRYPOTION)) wants_it = TRUE; + when RING: if(on(*th, CARRYRING)) wants_it = TRUE; + when STICK: if(on(*th, CARRYSTICK)) wants_it = TRUE; + when MM: if(on(*th, CARRYMISC)) wants_it = TRUE; + when ARMOR: if(on(*th, CARRYARMOR)) wants_it = TRUE; + when WEAPON:if(on(*th, CARRYWEAPON) || + (on(*th,CARRYDAGGER)&&n_obj->o_which==DAGGER)) + wants_it = TRUE; + } + } + /* + * The quartermaster doesn't sell cursed stuff so he won't + * pick it up + */ + if (on(*th, CANSELL) && (n_obj->o_flags & ISCURSED)) + wants_it = FALSE; + + /* If he doesn't want it, throw it away */ + if (wants_it == FALSE) { + fall(n_item, FALSE); + continue; + } + + /* Otherwise, let's pick it up */ + if (n_obj->o_group) { + for(o_item = th->t_pack; o_item != NULL; o_item = next(o_item)){ + o_obj = OBJPTR(o_item); + if (o_obj->o_group == n_obj->o_group) { + o_obj->o_count += n_obj->o_count; + o_discard(n_item); + break; + } + } + } + if (o_item == NULL) { /* didn't find it */ + attach(th->t_pack, n_item); + } + } + + /* If there was anything here, we may have to update the screen */ + if (item_count) { + if (cansee(ch_ret.y, ch_ret.x)) + mvwaddch(cw, ch_ret.y, ch_ret.x, mvinch(ch_ret.y, ch_ret.x)); + updpack(TRUE, th); /* Update the monster's encumberance, too */ + } + } + + rch = mvwinch(stdscr, old_pos.y, old_pos.x); + if (th->t_oldch == floor && rch != floor && !isatrap(rch)) + mvwaddch(cw, old_pos.y, old_pos.x, rch); + else + mvwaddch(cw, old_pos.y, old_pos.x, th->t_oldch); + sch = mvwinch(cw, ch_ret.y, ch_ret.x); /* What player sees */ + rch = mvwinch(stdscr, ch_ret.y, ch_ret.x); /* What's really there */ + + /* If we have a tunneling monster, it may be making a tunnel */ + if (on(*th, CANTUNNEL) && + (rch==SECRETDOOR || rch==WALL || rch==VERTWALL || rch==HORZWALL)) { + unsigned char nch; /* The new look to the tunnel */ + + if (rch == WALL && levtype == OUTSIDE) nch = FLOOR; + else if (rch == WALL) nch = PASSAGE; + else if (levtype == MAZELEV || levtype == OUTSIDE) nch = FLOOR; + else nch = DOOR; + addch(nch); + + if (cansee(ch_ret.y, ch_ret.x)) sch = nch; /* Can player see this? */ + + /* Does this make a new exit? */ + if (rch == VERTWALL || rch == HORZWALL) { + struct linked_list *newroom; + coord *exit; + + newroom = new_item(sizeof(coord)); + exit = DOORPTR(newroom); + *exit = ch_ret; + attach(new_room->r_exit, newroom); + } + } + + /* Mark if the monster is inside a wall */ + if (isrock(mvinch(ch_ret.y, ch_ret.x))) turn_on(*th, ISINWALL); + else turn_off(*th, ISINWALL); + + /* If the monster can illuminate rooms, check for a change */ + if (on(*th, HASFIRE)) { + register struct linked_list *fire_item; + + /* Is monster entering a room? */ + if (orig_rer != new_room && new_room != NULL) { + fire_item = creat_item(); /* Get an item-only structure */ + ldata(fire_item) = (char *) th; + + attach(new_room->r_fires, fire_item); + new_room->r_flags |= HASFIRE; + + if (cansee(ch_ret.y, ch_ret.x) && next(new_room->r_fires) == NULL) + light(&hero); + } + + /* Is monster leaving a room? */ + if (orig_rer != new_room && orig_rer != NULL) { + /* Find the bugger in the list and delete him */ + for (fire_item = orig_rer->r_fires; fire_item != NULL; + fire_item = next(fire_item)) { + if (THINGPTR(fire_item) == th) { /* Found him! */ + detach(orig_rer->r_fires, fire_item); + destroy_item(fire_item); + if (orig_rer->r_fires == NULL) { + orig_rer->r_flags &= ~HASFIRE; + if (cansee(old_pos.y, old_pos.x)) + light(&old_pos); + } + break; + } + } + } + } + + /* If monster is entering player's room and player can see it, + * stop the player's running. + */ + if (new_room != orig_rer && new_room != NULL && + new_room == roomin(th->t_dest) && cansee(unc(ch_ret)) && + (off(*th, ISINVIS) || on(player, CANSEE)) && + (off(*th, ISSHADOW) || on(player, CANSEE)) && + (off(*th, CANSURPRISE) || ISWEARING(R_ALERT))) { + running = FALSE; + if (fight_flush) flushinp(); + } + + th->t_oldch = sch; + + /* Let's display those creatures that we can see. */ + if (cansee(unc(ch_ret)) && + off(*th, ISINWALL) && + !invisible(th)) + mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type); + + /* Record monster's last position (if new one is different) */ + if (!ce(ch_ret, old_pos)) th->t_oldpos = old_pos; + + /* If the monster is on a trap, trap it */ + sch = mvinch(ch_ret.y, ch_ret.x); + if (isatrap(sch)) { + if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch; + be_trapped(th, &ch_ret); + } +} + +/* + * Get_hurl returns the weapon that the monster will "throw" if he has one + */ + +struct linked_list * +get_hurl(tp) +register struct thing *tp; +{ + struct linked_list *arrow=NULL, *bolt=NULL, *rock=NULL, + *spear = NULL, *dagger=NULL, *dart=NULL, *aklad=NULL; + register struct linked_list *pitem; + register struct object *obj; + bool bow=FALSE, crossbow=FALSE, sling=FALSE; + + for (pitem=tp->t_pack; pitem; pitem=next(pitem)) { + obj = OBJPTR(pitem); + if (obj->o_type == WEAPON) + switch (obj->o_which) { + case BOW: bow = TRUE; + when CROSSBOW: crossbow = TRUE; + when SLING: sling = TRUE; + when ROCK: rock = pitem; + when ARROW: arrow = pitem; + when BOLT: bolt = pitem; + when SPEAR: spear = pitem; + when DAGGER: + /* Don't throw the dagger if it's our last one */ + if (obj->o_count > 1) dagger = pitem; + when DART: dart = pitem; + } + else if (obj->o_type == RELIC && + obj->o_which == AXE_AKLAD) + aklad = pitem; + } + + /* Do we have that all-powerful Aklad Axe? */ + if (aklad) return(aklad); + + /* Use crossbow bolt if possible */ + if (crossbow && bolt) return(bolt); + if (bow && arrow) return(arrow); + if (spear) return(spear); + if (dagger) return(dagger); + if (sling && rock) return(rock); + if (dart) return(dart); + return(NULL); +} + +/* + * runto: + * Set a monster running after something + */ + +runto(runner, spot) +register struct thing *runner; +coord *spot; +{ + if (on(*runner, ISSTONE)) + return; + + /* If we are chasing a new creature, forget about thrown weapons */ + if (runner->t_dest && !ce(*runner->t_dest, *spot)) runner->t_wasshot=FALSE; + + /* + * Start the beastie running + */ + runner->t_dest = spot; + turn_on(*runner, ISRUN); + turn_off(*runner, ISDISGUISE); +} + +/* + * straight_shot: + * See if there is a straight line of sight between the two + * given coordinates. If shooting is not NULL, it is a pointer + * to a structure which should be filled with the direction + * to shoot (if there is a line of sight). If shooting, monsters + * get in the way. Otherwise, they do not. + */ + +bool +straight_shot(ery, erx, eey, eex, shooting) +register int ery, erx, eey, eex; +register coord *shooting; +{ + register int dy, dx; /* Deltas */ + unsigned char ch; + + /* Does the monster have a straight shot at prey */ + if ((ery != eey) && (erx != eex) && + (abs(ery - eey) != abs(erx - eex))) return(FALSE); + + /* Get the direction to shoot */ + if (eey > ery) dy = 1; + else if (eey == ery) dy = 0; + else dy = -1; + + if (eex > erx) dx = 1; + else if (eex == erx) dx = 0; + else dx = -1; + + /* Make sure we have free area all the way to the player */ + ery += dy; + erx += dx; + while ((ery != eey) || (erx != eex)) { + switch (ch = winat(ery, erx)) { + case VERTWALL: + case HORZWALL: + case WALL: + case DOOR: + case SECRETDOOR: + case FOREST: + return(FALSE); + default: + if (shooting && isalpha(ch)) return(FALSE); + } + ery += dy; + erx += dx; + } + + if (shooting) { /* If we are shooting -- put in the directions */ + shooting->y = dy; + shooting->x = dx; + } + return(TRUE); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/command.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1312 @@ +/* + command.c - Read and execute the user commands + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include "mach_dep.h" +#include "rogue.h" + +/* + * command: + * Process the user commands + */ + +command() +{ + unsigned int ch; + struct linked_list *item; + unsigned int countch = 0, direction = 0, newcount = FALSE; + int segment = 1; + int monst_limit, monst_current; + + monst_limit = monst_current = 1; + while (playing) { + /* + * Let the daemons start up, but only do them once a round + * (round = 10 segments). + */ + if (segment >= 10) { + do_daemons(BEFORE); + do_fuses(BEFORE); + } + + after = TRUE; + do { + /* One more tick of the clock. */ + if (segment >= 10 && after && (++turns % DAYLENGTH) == 0) { + daytime ^= TRUE; + if (levtype == OUTSIDE) { + if (daytime) msg("A bright star flares above the horizon."); + else msg("The bright star travels beyond the horizon."); + } + light(&hero); + } + + /* + * Don't bother with these updates unless the player's going + * to do something. + */ + if (player.t_action == A_NIL && player.t_no_move <= 1) { + look(after, FALSE); + lastscore = purse; + wmove(cw, hero.y, hero.x); + if (!((running || count) && jump)) { + status(FALSE); + } + } + + /* Draw the screen */ + if (!((running || count) && jump)) { + wmove(cw, hero.y, hero.x); + draw(cw); + } + + after = TRUE; + + /* + * Read command or continue run + */ + if (--player.t_no_move <= 0) { + take = 0; /* Nothing here to start with */ + player.t_no_move = 0; /* Be sure we don't go too negative */ + if (!running) door_stop = FALSE; + + /* Was the player being held? */ + if (player.t_action == A_FREEZE) { + player.t_action = A_NIL; + msg("You can move again."); + } + + if (player.t_action != A_NIL) ch = player.t_action; + else if (running) { + char scratch; + + /* If in a corridor or maze, if we are at a turn with + * only one way to go, turn that way. + */ + scratch = winat(hero.y, hero.x); + if ((scratch==PASSAGE||scratch==DOOR||levtype==MAZELEV) && + off(player, ISHUH) && + off(player, ISBLIND)) { + int y, x; + if (getdelta(runch, &y, &x) == TRUE) { + corr_move(y, x); + } + } + ch = runch; + } + else if (count) ch = countch; + else { + ch = wgetch(cw); + if (mpos != 0 && !running) /* Erase message if its there */ + msg(""); + } + + /* + * check for prefixes + */ + if (isascii(ch) && isdigit(ch)) + { + count = 0; + newcount = TRUE; + while (isascii(ch) && isdigit(ch)) + { + count = count * 10 + (ch - '0'); + ch = wgetch(cw); + } + countch = ch; + /* + * turn off count for commands which don't make sense + * to repeat + */ + switch (ch) { + case 'h': case 'j': case 'k': case 'l': + case 'y': case 'u': case 'b': case 'n': + case 'H': case 'J': case 'K': case 'L': + case 'Y': case 'U': case 'B': case 'N': + case C_SEARCH: case '.': + break; + default: + count = 0; + } + } + + /* Save current direction */ + if (!running) { /* If running, it is already saved */ + switch (ch) { + case 'h': case 'j': case 'k': case 'l': + case 'y': case 'u': case 'b': case 'n': + case 'H': case 'J': case 'K': case 'L': + case 'Y': case 'U': case 'B': case 'N': + runch = tolower(ch); + } + } + + /* Perform the action */ + switch (ch) { + case 'f': + if (!on(player, ISBLIND)) + { + door_stop = TRUE; + firstmove = TRUE; + } + if (count && !newcount) + ch = direction; + else + ch = wgetch(cw); + switch (ch) + { + case 'h': case 'j': case 'k': case 'l': + case 'y': case 'u': case 'b': case 'n': + ch = toupper(ch); + } + direction = ch; + } + newcount = FALSE; + + /* + * execute a command + */ + if (count && !running) + count--; + + switch (ch) { + case '!' : shell(); + case KEY_LEFT : do_move(0, -1); + when KEY_DOWN : do_move(1, 0); + when KEY_UP : do_move(-1, 0); + when KEY_RIGHT : do_move(0, 1); + when KEY_HOME : do_move(-1, -1); + when KEY_A1 : do_move(-1, -1); + when KEY_PPAGE : do_move(-1, 1); + when KEY_A3 : do_move(-1, 1); + when KEY_END : do_move(1, -1); + when KEY_C1 : do_move(1, -1); + when KEY_NPAGE : do_move(1, 1); + when KEY_C3 : do_move(1, 1); +#ifdef CTL_RIGHT + when CTL_RIGHT : do_run('l'); + when CTL_LEFT : do_run('h'); + when CTL_UP : do_run('k'); + when CTL_DOWN : do_run('j'); + when CTL_HOME : do_run('y'); + when CTL_PGUP : do_run('u'); + when CTL_END : do_run('b'); + when CTL_PGDN : do_run('n'); +#endif + when 'h' : do_move(0, -1); + when 'j' : do_move(1, 0); + when 'k' : do_move(-1, 0); + when 'l' : do_move(0, 1); + when 'y' : do_move(-1, -1); + when 'u' : do_move(-1, 1); + when 'b' : do_move(1, -1); + when 'n' : do_move(1, 1); + when 'H' : do_run('h'); + when 'J' : do_run('j'); + when 'K' : do_run('k'); + when 'L' : do_run('l'); + when 'Y' : do_run('y'); + when 'U' : do_run('u'); + when 'B' : do_run('b'); + when 'N' : do_run('n'); + when A_ATTACK: + /* Is our attackee still there? */ + if (isalpha(winat(player.t_newpos.y, + player.t_newpos.x))) { + /* Our friend is still here */ + player.t_action = A_NIL; + fight(&player.t_newpos, cur_weapon, FALSE); + } + else { /* Our monster has moved */ + player.t_action = A_NIL; + } + when A_PICKUP: + player.t_action = A_NIL; + if (add_pack((struct linked_list *)NULL, FALSE)) { + char tch; + tch = mvwinch(stdscr, hero.y, hero.x); + if (tch != FLOOR && tch != PASSAGE) { + player.t_action = A_PICKUP; /*get more */ + player.t_no_move += 2 * movement(&player); + } + } + when A_THROW: + if (player.t_action == A_NIL) { + item = get_item(pack, "throw", ALL, FALSE, FALSE); + if (item != NULL && get_dir(&player.t_newpos)) { + player.t_action = A_THROW; + player.t_using = item; + player.t_no_move = 2 * movement(&player); + } + else + after = FALSE; + } + else { + missile(player.t_newpos.y, player.t_newpos.x, + player.t_using, &player); + player.t_action = A_NIL; + player.t_using = 0; + } + when 'a' : + if (player.t_action == A_NIL) { + if (get_dir(&player.t_newpos)) { + player.t_action = 'a'; + player.t_no_move = 1 + movement(&player); + } + else + after = FALSE; + } + else { + affect(); + player.t_action = A_NIL; + } + when 'A' : choose_qst(); + when 'F' : /* frighten a monster */ + if (player.t_action == A_NIL) { + player.t_action = 'F'; + player.t_no_move = 2*movement(&player); + } + else { + after = FALSE; + player.t_action = A_NIL; + fright(); + } + when 'g' : /* Give command: give slime-molds to monsters */ + if (player.t_action == A_NIL) { + player.t_action = 'g'; + player.t_no_move = 2*movement(&player); + } + else { + after = FALSE; + player.t_action = A_NIL; + give(); + } + when 'G' : + if (player.t_action == A_NIL) { + player.t_action = 'G'; + player.t_no_move = movement(&player); + } + else { + player.t_action = A_NIL; + gsense(); + } + when 'i' : after = FALSE; inventory(pack, ALL); + when 'I' : after = FALSE; picky_inven(); + when 'm' : nameitem((struct linked_list *)NULL, TRUE); + when 'o' : option(); + when 'O' : msg("Charactor type: %s Quest item: %s", char_class[char_type].name, rel_magic[quest_item].mi_name); + when ',' : + case 'P' : + if (levtype != POSTLEV) { + /* We charge 2 movement units per item */ + player.t_no_move = + 2 * grab(hero.y, hero.x) * movement(&player); + } + else { + /* Let's quote the wise guy a price */ + buy_it(); + after = FALSE; + } + when 'Q' : after = FALSE; quit(0); + when 'S' : + after = FALSE; + if (save_game()) + exit_game(EXIT_CLS | EXIT_ENDWIN); + when 'v' : after = FALSE; + msg("Advanced xrogue, Version %s ", release); + when 'X' : /* trap sense */ + after = FALSE; + if (player.t_action == A_NIL) { + player.t_action = 'X'; + player.t_no_move = movement(&player); + } + else { + xsense(); + player.t_action = A_NIL; + } + when '.' : + player.t_no_move = movement(&player); /* Rest */ + player.t_action = A_NIL; + when ' ' : after = FALSE; /* Do Nothing */ + when '>' : after = FALSE; d_level(); + when '<' : after = FALSE; u_level(); + when '=' : after = FALSE; display(); + when '?' : after = FALSE; help(); + + /* no character descriptions yet until updated (help.c) */ + /* when '\\' : after = FALSE; ident_hero(); */ + when '\\' : msg("Charon (the Boatman) looks at you... "); + + when '/' : after = FALSE; identify(NULL); + when C_COUNT : count_gold(); + when C_DIP : dip_it(); + when C_DROP : player.t_action = C_DROP; + drop((struct linked_list *)NULL); + when C_EAT : eat(); + when C_QUAFF : quaff(-1, NULL, NULL, TRUE); + when C_READ : read_scroll(-1, NULL, TRUE); + when C_SETTRAP : set_trap(&player, hero.y, hero.x); + when C_SEARCH : + if (player.t_action == A_NIL) { + player.t_action = C_SEARCH; + player.t_no_move = 2 + movement(&player); + } + else { + search(FALSE, FALSE); + player.t_action = A_NIL; + } + when C_TAKEOFF : take_off(); + when C_USE : use_mm(-1); + when C_WEAR : wear(); + when C_WIELD : wield(); + when C_ZAP : if (!player_zap(NULL, FALSE)) after=FALSE; + when C_CAST : cast(); + when C_CHANT : chant(); + when C_PRAY : pray(); + when CTRL('B') : msg("Current score: %d", + pstats.s_exp + (long) purse); + when CTRL('E') : msg("Current food level: %d(2000)", + food_left); + when CTRL('L') : after = FALSE; clearok(curscr, TRUE); + touchwin(cw); + when CTRL('N') : nameit(); + when CTRL('O') : after = FALSE; opt_player(); + when CTRL('R') : after = FALSE; msg(huh); + when CTRL('T') : + if (player.t_action == A_NIL) { + if (get_dir(&player.t_newpos)) { + player.t_action = CTRL('T'); + player.t_no_move = 2 * movement(&player); + } + else + after = FALSE; + } + else { + steal(); + player.t_action = A_NIL; + } + when ESC : /* Escape */ + door_stop = FALSE; + count = 0; + after = FALSE; + when '#': + if (levtype == POSTLEV) /* buy something */ + buy_it(); + after = FALSE; + when '$': + if (levtype == POSTLEV) /* price something */ + price_it(); + after = FALSE; + when '%': + if (levtype == POSTLEV) /* sell something */ + sell_it(); + after = FALSE; + when '+': /* instant karma! */ + switch (rnd(100)) { + case 0: msg("You waste some time. "); + when 5: msg("An oak tree in the garden. "); + when 10: msg("Character is what you become in the dark. "); + when 15: msg("May you live all the days of your life. "); + when 20: msg("A hero is no braver than an ordinary man, but he is brave five minutes longer. "); + when 25: msg("Get down! "); + when 30: msg("Go back to sleep. "); + when 35: msg("Be here now. "); + when 40: msg("Choose the rock that feels right to you. "); + when 45: msg("Wait... "); + when 50: msg("You take a break (yawn)... "); + when 55: msg("Without danger there is no pleasure. "); + when 60: msg("Define meaningless? "); + when 65: msg("Don't push your luck! "); + when 70: msg("Gung ho. "); + when 75: msg("You are inside a computer. "); + when 80: msg("Directive is now required... "); + when 85: msg("Charon (the Boatman) awaits you... "); + when 95: msg(nothing); + otherwise: msg(""); + } + after = FALSE; + when CTRL('P') : +#ifdef WIZARD + after = FALSE; + if (wizard) + { + wizard = FALSE; + trader = 0; + msg("Not wizard any more"); + } + else + { + if (waswizard || passwd()) + { + msg("Welcome, O Mighty Wizard! "); + wizard = waswizard = TRUE; + } + else + msg("Sorry"); + } +#else + msg("Sorry"); +#endif + + otherwise : + after = FALSE; + if (wizard) switch (ch) { + case 'M' : create_obj(TRUE, 0, 0); + when 'V' : msg("vlevel = %d turns = %d", + vlevel, turns); + when CTRL('A') : activity(); + when CTRL('C') : do_teleport(); + when CTRL('D') : level++; + take_with(); + new_level(NORMLEV); + when CTRL('F') : overlay(stdscr,cw); + when CTRL('G') : + { + item=get_item(pack,"charge",STICK,FALSE,FALSE); + if (item != NULL) { + (OBJPTR(item))->o_charges=10000; + } + } + when CTRL('H') : + { + register int i, j; + register struct object *obj; + + for (i = 0; i < 9; i++) + raise_level(); + /* + * Give the rogue a sword + */ + if (cur_weapon==NULL || cur_weapon->o_type != + RELIC) { + if (player.t_ctype == C_THIEF || + player.t_ctype == C_ASSASSIN || + player.t_ctype == C_MONK) + item = spec_item(WEAPON, BASWORD, 20, 20); + else + item = spec_item(WEAPON,TWOSWORD, 20, 20); + if (add_pack(item, TRUE)) + { + cur_weapon = OBJPTR(item); + (OBJPTR(item))->o_flags |= (ISKNOW|ISPROT); + } + else + o_discard(item); + /* + * And his suit of armor + */ + if (player.t_ctype == C_THIEF || + player.t_ctype == C_ASSASSIN || + player.t_ctype == C_MONK) + j = PADDED_ARMOR; + else + j = PLATE_ARMOR; + item = spec_item(ARMOR, j, 20, 0); + obj = OBJPTR(item); + obj->o_flags |= (ISKNOW | ISPROT); + obj->o_weight = armors[j].a_wght; + if (add_pack(item, TRUE)) + cur_armor = obj; + else + o_discard(item); + } + purse += 20000; + } + when CTRL('I') : inventory(lvl_obj, ALL); + when CTRL('J') : teleport(); + when CTRL('K') : whatis((struct linked_list *)NULL); + when CTRL('W') : wanderer(); + when CTRL('X') : overlay(mw,cw); + when CTRL('Y') : msg("food left: %d\tfood level: %d", + food_left, foodlev); + otherwise : + msg("Illegal wizard command '%s'.", unctrl(ch)); + count = 0; + } + else + { + msg("Illegal command '%s'.", unctrl(ch)); + count = 0; + after = FALSE; + } + } + + /* + * If he ran into something to take, let him pick it up. + * unless it's a trading post + */ + if (auto_pickup && take != 0 && levtype != POSTLEV) { + /* get ready to pick it up */ + player.t_action = A_PICKUP; + player.t_no_move += 2 * movement(&player); + } + } + + /* If he was fighting, let's stop (for now) */ + if (player.t_quiet < 0) player.t_quiet = 0; + + if (!running) + door_stop = FALSE; + + if (after && segment >= 10) { + /* + * Kick off the rest if the daemons and fuses + */ + + /* + * If player is infested, take off a hit point + */ + if (on(player, HASINFEST)) { + pstats.s_hpt -= infest_dam; + if (pstats.s_hpt == 50 || pstats.s_hpt == 25) + msg("You feel yourself withering away... "); + if (pstats.s_hpt < 1) { + msg("You die a festering mass. --More--"); + wait_for(' '); + pstats.s_hpt = -1; + death(D_INFESTATION); + } + } + + /* + * The eye of Vecna is a constant drain on the player + */ + if (cur_relic[EYE_VECNA]) { + pstats.s_hpt -= 1; + if (pstats.s_hpt == 50 || pstats.s_hpt == 25) + msg("You feel Vecna's eye looking about. "); + if (pstats.s_hpt <= 10 && pstats.s_hpt >= 3) + msg("Vecna's eye moves about very quickly. "); + if (pstats.s_hpt < 1) { + msg("Vecna's curse is upon you! --More--"); + wait_for(' '); + pstats.s_hpt = -1; + death(D_RELIC); + } + } + + /* + * if player has body rot then take off three hits + */ + if (on(player, DOROT)) { + pstats.s_hpt -= rnd(3)+1; + if (pstats.s_hpt == 50 || pstats.s_hpt == 25) + msg("Something really begins to stink and smell! "); + if (pstats.s_hpt < 1) { + msg("You keel over with rot. --More--"); + wait_for(' '); + pstats.s_hpt = -1; + death(D_ROT); + } + } + do_daemons(AFTER); + do_fuses(AFTER); + } + } while (after == FALSE); + + /* Make the monsters go */ + if (--monst_current <= 0) + monst_current = monst_limit = runners(monst_limit); + + if (++segment > 10) segment = 1; + reap(); /* bury all the dead monsters */ + } +} + +/* + * display + * tell the player what is at a certain coordinates assuming + * it can be seen. + */ +display() +{ + coord c; + struct linked_list *item; + struct thing *tp; + int what; + + msg("What do you want to display (* for help)?"); + c = get_coordinates(); + mpos = 0; + if (!cansee(c.y, c.x)) { + msg("You can't see what is there."); + return; + } + what = mvwinch(cw, c.y, c.x); + if (isalpha(what)) { + item = find_mons(c.y, c.x); + tp = THINGPTR(item); + msg("%s", monster_name(tp)); + return; + } + if ((item = find_obj(c.y, c.x)) != NULL) { + msg("%s", inv_name(OBJPTR(item), FALSE)); + return; + } + identify(what); +} + +/* + * quit: + * Have player make certain, then exit. + */ + +/*UNUSED*/ +void +quit(sig) +int sig; +{ + register int oy, ox; + + NOOP(sig); + + /* + * Reset the signal in case we got here via an interrupt + */ + + if ((VOID(*)())signal(SIGINT, quit) != (VOID(*)())quit) + mpos = 0; + + getyx(cw, oy, ox); + if (level < 1) { /* if not down in the dungeon proper; exit the game */ + wclear(hw); + wmove(hw, lines-1, 0); + draw(hw); + wmove(hw, 12, 30); + wprintw(hw, "Good-bye!"); + draw(hw); + exit_game(EXIT_ENDWIN); + } + msg("Really quit? <yes or no> "); /* otherwise ask about quitting */ + draw(cw); + prbuf[0] = '\0'; + if ((get_str(prbuf, msgw) == NORM) && strcmp(prbuf, "yes") == 0) { + clear(); + move(lines-1, 0); + draw(stdscr); + writelog(pstats.s_exp + (long) purse, CHICKEN, 0); + score(pstats.s_exp + (long) purse, CHICKEN, 0); + exit_game(EXIT_ENDWIN); + } + else { + signal(SIGINT, quit); + wmove(msgw, 0, 0); + wclrtoeol(msgw); + draw(msgw); + status(FALSE); + wmove(cw, oy, ox); + draw(cw); + mpos = 0; + count = 0; + running = FALSE; + } +} + +/* + * bugkill: + * killed by a program bug instead of voluntarily. + */ + +bugkill(sig) +int sig; +{ + signal(sig, quit); /* If we get it again, give up */ + if (levtype == OUTSIDE) { + msg("Oh no! You walk right into a flying swarm of nasty little bugs!! "); + msg("One of them penetrates your brain!!! --More--"); + } + else { + msg("Charon (the Boatman) has finally come for you... --More--"); + } + wait_for(' '); + pstats.s_hpt = -1; + death(D_SIGNAL); /* Killed by a bug */ +} + +/* + * search: + * Player gropes about him to find hidden things. + */ + +search(is_thief, door_chime) +register bool is_thief, door_chime; +{ + register int x, y; + register char ch, /* The trap or door character */ + sch; /* Trap or door character (as seen on screen) */ + register unsigned char mch; /* Monster, if a monster is on the trap or door */ + register struct linked_list *item; + register struct thing *mp; /* Status on surrounding monster */ + + /* + * Look all around the hero, if there is something hidden there, + * give him a chance to find it. If its found, display it. + */ + if (on(player, ISBLIND)) + return; + for (x = hero.x - 1; x <= hero.x + 1; x++) + for (y = hero.y - 1; y <= hero.y + 1; y++) + { + if (y==hero.y && x==hero.x) + continue; + + if (x < 0 || y < 0 || x >= cols || y >= lines) + continue; + + /* Mch and ch will be the same unless there is a monster here */ + mch = winat(y, x); + ch = mvwinch(stdscr, y, x); + sch = mvwinch(cw, y, x); /* What's on the screen */ + + if (door_chime == FALSE && isatrap(ch)) { + register struct trap *tp; + + /* Is there a monster on the trap? */ + if (mch != ch && (item = find_mons(y, x)) != NULL) { + mp = THINGPTR(item); + if (sch == mch) sch = mp->t_oldch; + } + else mp = NULL; + + /* + * is this one found already? + */ + if (isatrap(sch)) + continue; /* give him chance for other traps */ + tp = trap_at(y, x); + /* + * if the thief set it then don't display it. + * if its not a thief he has 50/50 shot + */ + if((tp->tr_flags&ISTHIEFSET) || (!is_thief && rnd(100)>50)) + continue; /* give him chance for other traps */ + tp->tr_flags |= ISFOUND; + + /* Let's update the screen */ + if (mp != NULL && mvwinch(cw, y, x) == mch) + mp->t_oldch = ch; /* Will change when monst moves */ + else mvwaddch(cw, y, x, ch); + + count = 0; + running = FALSE; + + /* Stop what we were doing */ + player.t_no_move = movement(&player); + player.t_action = A_NIL; + player.t_using = NULL; + + if (fight_flush) flushinp(); + msg(tr_name(tp->tr_type)); + } + else if (ch == SECRETDOOR) { + if (door_chime == TRUE || (!is_thief && rnd(100) < 20)) { + struct room *rp; + coord cp; + + /* Is there a monster on the door? */ + if (mch != ch && (item = find_mons(y, x)) != NULL) { + mp = THINGPTR(item); + + /* Screen will change when monster moves */ + if (sch == mch) mp->t_oldch = ch; + } + mvaddch(y, x, DOOR); + count = 0; + /* + * if its the entrance to a treasure room, wake it up + */ + cp.y = y; + cp.x = x; + rp = roomin(&cp); + if (rp->r_flags & ISTREAS) + wake_room(rp); + + /* Make sure we don't shoot into the room */ + if (door_chime == FALSE) { + count = 0; + running = FALSE; + + /* Stop what we were doing */ + player.t_no_move = movement(&player); + player.t_action = A_NIL; + player.t_using = NULL; + } + } + } + } +} + +/* + * d_level: + * He wants to go down a level + */ + +d_level() +{ + bool no_phase=FALSE; + char position = winat(hero.y, hero.x); + int au; + + + /* If we are on a trading post, go to a trading post level. */ + if (position == POST) { + take_with(); /* Take charmed monsters with you while shopping */ + new_level(POSTLEV); + return; + } + + /* Dive for gold */ + if (position == POOL) { + if (rnd(300) < 2) { + msg("Oh no!!! You drown in the pool!!! --More--"); + pstats.s_hpt = -1; + wait_for(' '); + death(D_DROWN); + } + else if (rnd(125) < 25) { + au = rnd(350) + (level * 10); + msg("You dive under the water momentarily.. "); + msg("You found %d gold pieces! ", au); + purse = purse + au; + return; + } + else return; /* doesn't happen all of the time */ + } + + /* Going down traps is hazardous */ + switch (position) { + case WORMHOLE: + case TRAPDOOR: + case MAZETRAP: + case DARTTRAP: + case SLEEPTRAP: + case ARROWTRAP: + case BEARTRAP: + case TELTRAP: + msg ("You find yourself in some sort of quicksand!? "); + msg ("Hey! There are rock maggots in here!! "); + player.t_no_move += movement(&player) * FREEZETIME; + player.t_action = A_FREEZE; + msg("You can't move. "); /* spare monks */ + if (!ISWEARING(R_HEALTH) && player.t_ctype != C_MONK) { + turn_on(player, DOROT); + msg("You feel your skin starting to rot and peel away!! "); + } + return; + } + + /* If we are at a top-level trading post, we probably can't go down */ + if (levtype == POSTLEV && level == 0 && position != STAIRS) { + msg("I see no way down."); + return; + } + + if (winat(hero.y, hero.x) != STAIRS) { + if (off(player, CANINWALL) || /* Must use stairs if can't phase */ + (levtype == OUTSIDE && rnd(100) < 90)) { + msg("I see no way down."); + return; + } + if (levtype == OUTSIDE) { + level++; + take_with(); + new_level(NORMLEV); + if (no_phase) unphase(); + return; + } + + /* Is there any dungeon left below? */ + if (level >= nfloors) { + msg("There is only solid rock below."); + return; + } + + extinguish(unphase); /* Using phase to go down gets rid of it */ + no_phase = TRUE; + } + + /* Is this the bottom? */ + if (level >= nfloors) { + msg("The stairway only goes up."); + return; + } + + level++; + take_with(); + new_level(NORMLEV); + if (no_phase) unphase(); +} + +/* + * u_level: + * He wants to go up a level + */ + +u_level() +{ + bool no_phase = FALSE; + register struct linked_list *item; + char position = winat(hero.y, hero.x); + struct thing *tp; + struct object *obj; + + /* You can go up into the outside if standing on top of a worm hole */ + if (position == WORMHOLE) { + prev_max = 1000; + level--; + if (level <= 0) level = 1; + msg("You find yourself in strange surroundings... "); + if (wizard) addmsg("Going up through a worm hole. "); + take_with(); + new_level(OUTSIDE); + return; + } + + if (winat(hero.y, hero.x) != STAIRS) { + if (off(player, CANINWALL)) { /* Must use stairs if can't phase */ + msg("I see no way up."); + return; + } + + extinguish(unphase); + no_phase = TRUE; + } + + if (position != STAIRS) return; + + if (level == 0 || levtype == OUTSIDE) { + msg("The stairway only goes down."); + return; + } + + /* + * does he have the item he was quested to get? + */ + if (level == 1) { + for (item = pack; item != NULL; item = next(item)) { + obj = OBJPTR(item); + if (obj->o_type == RELIC && obj->o_which == quest_item) + total_winner(); + } + } + /* + * check to see if he trapped a UNIQUE, If he did then put it back + * in the monster table for next time + */ + for (item = tlist; item != NULL; item = next(item)) { + tp = THINGPTR(item); + if (on(*tp, ISUNIQUE)) + monsters[tp->t_index].m_normal = TRUE; + } + t_free_list(tlist); /* Monsters that fell below are long gone! */ + + if (levtype != POSTLEV) + level--; + if (level > 0) { + take_with(); + new_level(NORMLEV); + } + else if (cur_max > level) { + prev_max = 1000; /* flag used in n_level.c */ + level--; + if (level <= 0) level = 1; + msg("You emerge into the %s. ", daytime ? "eerie light" : "dark night"); + if (wizard) msg("Going up: cur_max=%d level=%d. ", cur_max, level); + take_with(); + new_level(OUTSIDE); /* Leaving the dungeon for outside */ + return; + } + else { + prev_max = 1; /* flag used in n_level.c */ + level = -1; /* Indicate that we are new to the outside */ + msg("You emerge into the %s. ", daytime ? "eerie light" : "dark night"); + if (wizard) msg("Going up: cur_max=%d level=%d. ", cur_max, level); + take_with(); + new_level(OUTSIDE); + return; + } + + if (no_phase) unphase(); +} + +/* + * Let him escape for a while + */ + +shell() +{ + /* + * Set the terminal back to original mode + */ + wclear(hw); + wmove(hw, lines-1, 0); + draw(hw); + endwin(); + in_shell = TRUE; + fflush(stdout); + + md_shellescape(); + + printf(retstr); + fflush(stdout); + noecho(); + crmode(); + in_shell = FALSE; + wait_for('\n'); + restscr(cw); +} + +/* + * see what we want to name -- an item or a monster. + */ +nameit() +{ + char answer; + + msg("Name monster or item (m or i)? "); + answer = wgetch(cw); + mpos = 0; + + while (answer != 'm' && answer != 'i' && answer != ESC) { + mpos = 0; + msg("Please specify m or i, for monster or item - "); + answer = wgetch(cw); + } + + switch (answer) { + case 'm': namemonst(); + when 'i': nameitem((struct linked_list *)NULL, FALSE); + } +} + +/* + * allow a user to call a potion, scroll, or ring something + */ + +nameitem(item, mark) +struct linked_list *item; +bool mark; +{ + register struct object *obj; + register char **guess = NULL, *elsewise = NULL; + register bool *know; + + if (item == NULL) { + if (mark) item = get_item(pack, "mark", ALL, FALSE, FALSE); + else item = get_item(pack, "name", CALLABLE, FALSE, FALSE); + if (item == NULL) return; + } + /* + * Make certain that it is somethings that we want to wear + */ + obj = OBJPTR(item); + switch (obj->o_type) + { + case RING: + guess = r_guess; + know = r_know; + elsewise = (r_guess[obj->o_which] != NULL ? + r_guess[obj->o_which] : r_stones[obj->o_which]); + when POTION: + guess = p_guess; + know = p_know; + elsewise = (p_guess[obj->o_which] != NULL ? + p_guess[obj->o_which] : p_colors[obj->o_which]); + when SCROLL: + guess = s_guess; + know = s_know; + elsewise = (s_guess[obj->o_which] != NULL ? + s_guess[obj->o_which] : s_names[obj->o_which]); + when STICK: + guess = ws_guess; + know = ws_know; + elsewise = (ws_guess[obj->o_which] != NULL ? + ws_guess[obj->o_which] : ws_made[obj->o_which]); + when MM: + guess = m_guess; + know = m_know; + elsewise = (m_guess[obj->o_which] != NULL ? + m_guess[obj->o_which] : "nothing"); + otherwise: + if (!mark) { + msg("You can't call that anything."); + return; + } + else know = (bool *) 0; + } + if ((obj->o_flags & ISPOST) || (know && know[obj->o_which]) && !mark) { + msg("That has already been identified."); + return; + } + if (mark) { + if (obj->o_mark[0]) { + addmsg(terse ? "M" : "Was m"); + msg("arked \"%s\"", obj->o_mark); + } + msg(terse ? "Mark it: " : "What do you want to mark it? "); + prbuf[0] = '\0'; + } + else { + if (elsewise) { + addmsg(terse ? "N" : "Was n"); + msg("amed \"%s\"", elsewise); + strcpy(prbuf, elsewise); + } + else prbuf[0] = '\0'; + msg(terse ? "Name it: " : "What do you want to name it? "); + } + if (get_str(prbuf, msgw) == NORM) { + if (mark) { + strncpy((char *)obj->o_mark, prbuf, MARKLEN-1); + obj->o_mark[MARKLEN-1] = '\0'; + } + else if (prbuf[0] != '\0') { + if (guess[obj->o_which] != NULL) + free(guess[obj->o_which]); + guess[obj->o_which] = new((unsigned int) strlen(prbuf) + 1); + strcpy(guess[obj->o_which], prbuf); + } + } +} + +/* Name a monster */ + +namemonst() +{ + register struct thing *tp; + struct linked_list *item; + coord c; + + /* Find the monster */ + msg("Choose the monster (* for help)"); + c = get_coordinates(); + + /* Make sure we can see it and that it is a monster. */ + mpos = 0; + if (!cansee(c.y, c.x)) { + msg("You can't see what is there."); + return; + } + + if (isalpha(mvwinch(cw, c.y, c.x))) { + item = find_mons(c.y, c.x); + if (item != NULL) { + tp = THINGPTR(item); + if (tp->t_name == NULL) + strcpy(prbuf, monsters[tp->t_index].m_name); + else + strcpy(prbuf, tp->t_name); + + addmsg(terse ? "N" : "Was n"); + msg("amed \"%s\"", prbuf); + msg(terse ? "Name it: " : "What do you want to name it? "); + + if (get_str(prbuf, msgw) == NORM) { + if (prbuf[0] != '\0') { + if (tp->t_name != NULL) + free(tp->t_name); + tp->t_name = new((unsigned int) strlen(prbuf) + 1); + strcpy(tp->t_name, prbuf); + } + } + return; + } + } + + msg("There is no monster there to name."); +} + +count_gold() +{ + if (player.t_action != C_COUNT) { + msg("You take a break to count your money.. "); + player.t_using = NULL; + player.t_action = C_COUNT; /* We are counting */ + if (purse > 500000) msg("This may take some time... 10, 20, 30..."); + player.t_no_move = (purse/75000 + 1) * movement(&player); + return; + } + if (purse > 10000) + msg("You have %ld pieces of gold. ", purse); + else if (purse == 1) + msg("You have 1 piece of gold. "); + else + msg("You have %ld gold pieces. ", purse); + player.t_action = A_NIL; +} + +/* + * Teleport somewhere, anywhere... + */ + +do_teleport() +{ + int tlev; + prbuf[0] = '\0'; + msg("To which level do you wish to teleport? "); + if(get_str(prbuf,msgw) == NORM) { + tlev = atoi(prbuf); + if (quest_item == ALTERAN_CARD || wizard) { + if (wizard && (tlev < 1 || tlev > LEVEL)) { /* wizard */ + mpos = 0; + msg("The power of teleportation does have its limitations. "); + return; + } + else if (!wizard && (tlev < 10 || tlev > LEVEL)) { + mpos = 0; + msg("The power of teleportation does have its limitations. "); + return; + } + else if (tlev >= LEVEL-100 && tlev < LEVEL-50) { + levtype = OUTSIDE; + level = LEVEL-100; + prev_max = 1000; /* a flag for going outside */ + } + else if (tlev >= LEVEL-150 && tlev < LEVEL-100) { + levtype = MAZELEV; + level = LEVEL-150; + } + else if (tlev >= LEVEL-200 && tlev < LEVEL-150) { + levtype = POSTLEV; + level = LEVEL-200; + } + else { + levtype = NORMLEV; + level = tlev; + } + } + else if (tlev < 40 || tlev > 399) { /* not quest item or wizard */ + mpos = 0; + msg("The power of teleportation does have its limitations. "); + return; + } + else { + levtype = NORMLEV; + level = tlev; + } + + /* okay, now send him off */ + cur_max = level; /* deepest he's been */ + new_level(levtype); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/daemon.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,258 @@ +/* + daemon.c - functions for dealing with things that happen in the future + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include "rogue.h" + +#define EMPTY 0 +#define DAEMON -1 + +#define _X_ { EMPTY } + +struct delayed_action d_list[MAXDAEMONS] = { + _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_ +}; +struct delayed_action f_list[MAXFUSES] = { + _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, + _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_ +}; + +int demoncnt = 0; /* number of active daemons */ +int fusecnt = 0; + + +/* + * d_slot: + * Find an empty slot in the daemon list + */ +struct delayed_action * +d_slot() +{ + reg int i; + reg struct delayed_action *dev; + + for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++) + if (dev->d_type == EMPTY) + return dev; + return NULL; +} + +/* + * f_slot: + * Find an empty slot in the fuses list + */ +struct delayed_action * +f_slot() +{ + reg int i; + reg struct delayed_action *dev; + + for (i = 0, dev = f_list; i < MAXFUSES; i++, dev++) + if (dev->d_type == EMPTY) + return dev; + return NULL; +} + +/* + * find_slot: + * Find a particular slot in the table + */ + +struct delayed_action * +find_slot(func) +reg int (*func)(); +{ + reg int i; + reg struct delayed_action *dev; + + for (i = 0, dev = f_list; i < MAXFUSES; i++, dev++) + if (dev->d_type != EMPTY && func == dev->d_func) + return dev; + return NULL; +} + +/* + * daemon: + * Start a daemon, takes a function. + */ + +daemon(dfunc, arg, type) +reg VOID *arg; +reg int type, (*dfunc)(); +{ + reg struct delayed_action *dev; + + dev = d_slot(); + if (dev != NULL) { + dev->d_type = type; + dev->d_func = dfunc; + dev->d_arg.vp = arg; + dev->d_time = DAEMON; + demoncnt += 1; /* update count */ + } +} + +/* + * kill_daemon: + * Remove a daemon from the list + */ + +kill_daemon(dfunc) +reg int (*dfunc)(); +{ + reg struct delayed_action *dev; + reg int i; + + for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++) { + if (dev->d_type != EMPTY && dfunc == dev->d_func) + break; + } + if (i >= MAXDAEMONS) return; /* if not found, forget it */ + /* + * Take it out of the list + */ + dev->d_type = EMPTY; + dev->d_arg.vp = NULL; + dev->d_func = NULL; + dev->d_time = 0; + + demoncnt -= 1; /* update count */ +} + +/* + * do_daemons: + * Run all the daemons that are active with the current flag, + * passing the argument to the function. + */ + +do_daemons(flag) +reg int flag; +{ + struct delayed_action *dev; + int i; + + /* + * Loop through the devil list + */ + for (i = 0; i < MAXDAEMONS; i++) + { + dev = &d_list[i]; + /* + * Executing each one, giving it the proper arguments + */ + if ((dev->d_type == flag) && (dev->d_time == DAEMON) && (dev->d_func != NULL)) + (*dev->d_func)(dev->d_arg.vp); + } +} + +/* + * fuse: + * Start a fuse to go off in a certain number of turns + */ + +fuse(dfunc, arg, time, type) +VOID *arg; +reg int (*dfunc)(), time, type; +{ + reg struct delayed_action *wire; + + wire = f_slot(); + if (wire != NULL) { + wire->d_type = type; + wire->d_func = dfunc; + wire->d_arg.vp = arg; + wire->d_time = time; + fusecnt += 1; /* update count */ + } +} + +/* + * lengthen: + * Increase the time until a fuse goes off + */ + +lengthen(dfunc, xtime) +reg int (*dfunc)(), xtime; +{ + reg struct delayed_action *wire; + + if ((wire = find_slot(dfunc)) == NULL) + return; + wire->d_time += xtime; +} + +/* + * extinguish: + * Put out a fuse + */ + +extinguish(dfunc) +reg int (*dfunc)(); +{ + reg struct delayed_action *wire; + + if ((wire = find_slot(dfunc)) == NULL) + return; + wire->d_type = EMPTY; + wire->d_func = NULL; + wire->d_arg.vp = NULL; + wire->d_time = 0; + fusecnt -= 1; +} + +/* + * do_fuses: + * Decrement counters and start needed fuses + */ + +do_fuses(flag) +reg int flag; +{ + struct delayed_action *wire; + int i; + + /* + * Step though the list + */ + for (i = 0; i < MAXFUSES; i++) { + wire = &f_list[i]; + /* + * Decrementing counters and starting things we want. We also need + * to remove the fuse from the list once it has gone off. + */ + if(flag == wire->d_type && wire->d_time > 0 && + --wire->d_time == 0) { + wire->d_type = EMPTY; + if (wire->d_func != NULL) + (*wire->d_func)(wire->d_arg.vp); + fusecnt -= 1; + } + } +} + +/* + * activity: + * Show wizard number of demaons and memory blocks used + */ + +activity() +{ + msg("Daemons = %d : Fuses = %d : Memory Items = %d : Memory Used = %d", + demoncnt,fusecnt,total,md_memused()); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/daemons.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,731 @@ +/* + daemons.c - All the daemon and fuse functions are in here + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include "rogue.h" + +/* + * doctor: + * A healing daemon that restors hit points after rest + */ + +doctor(tp) +register struct thing *tp; +{ + register int ohp; + register int limit, new_points; + register struct stats *curp; /* current stats pointer */ + register struct stats *maxp; /* max stats pointer */ + + curp = &(tp->t_stats); + maxp = &(tp->maxstats); + if (curp->s_hpt == maxp->s_hpt) { + tp->t_quiet = 0; + return; + } + tp->t_quiet++; + switch (tp->t_ctype) { + case C_MAGICIAN: + limit = 10 - curp->s_lvl; + new_points = curp->s_lvl - 2; + when C_CLERIC: + case C_DRUID: + limit = 12 - curp->s_lvl; + new_points = curp->s_lvl - 3; + when C_THIEF: + case C_ASSASSIN: + limit = 14 - curp->s_lvl; + new_points = curp->s_lvl - 4; + when C_MONK: + limit = 16 - curp->s_lvl; + new_points = curp->s_lvl - 5; + when C_RANGER: + case C_PALADIN: + limit = 18 - curp->s_lvl; + new_points = curp->s_lvl - 6; + when C_FIGHTER: + limit = 20 - curp->s_lvl; + new_points = curp->s_lvl - 7; + when C_MONSTER: + limit = 15 - curp->s_lvl; + new_points = curp->s_lvl - 5; + otherwise: + debug("what a strange character you are!"); + return; + } + ohp = curp->s_hpt; + if (off(*tp, HASDISEASE) && off(*tp, DOROT)) { + if (curp->s_lvl < 8) { + if (tp->t_quiet > limit) { + curp->s_hpt++; + tp->t_quiet = 0; + } + } + else { + if (tp->t_quiet >= 3) { + curp->s_hpt += rnd(new_points)+1; + tp->t_quiet = 0; + } + } + } + if (tp == &player) { + if (ISRING(LEFT_1, R_REGEN)) curp->s_hpt++; + if (ISRING(LEFT_2, R_REGEN)) curp->s_hpt++; + if (ISRING(LEFT_3, R_REGEN)) curp->s_hpt++; + if (ISRING(LEFT_4, R_REGEN)) curp->s_hpt++; + if (ISRING(RIGHT_1, R_REGEN)) curp->s_hpt++; + if (ISRING(RIGHT_2, R_REGEN)) curp->s_hpt++; + if (ISRING(RIGHT_3, R_REGEN)) curp->s_hpt++; + if (ISRING(RIGHT_4, R_REGEN)) curp->s_hpt++; + } + if (on(*tp, ISREGEN)) + curp->s_hpt += curp->s_lvl/10 + 1; + if (ohp != curp->s_hpt) { + if (curp->s_hpt >= maxp->s_hpt) { + curp->s_hpt = maxp->s_hpt; + if (off(*tp, WASTURNED) && on(*tp, ISFLEE) && tp != &player) { + turn_off(*tp, ISFLEE); + tp->t_oldpos = tp->t_pos; /* Start our trek over */ + } + } + } +} + +/* + * Swander: + * Called when it is time to start rolling for wandering monsters + */ + +swander() +{ + daemon(rollwand, (VOID *)NULL, BEFORE); +} + +/* + * rollwand: + * Called to roll to see if a wandering monster starts up + */ + +int between = 0; + +rollwand() +{ + + if (++between >= 4) + { + /* Theives may not awaken a monster */ + if ((roll(1, 6) == 4) && + ((player.t_ctype != C_THIEF && player.t_ctype != C_ASSASSIN) || + (rnd(30) >= dex_compute()))) { + if (levtype != POSTLEV) + wanderer(); + kill_daemon(rollwand); + fuse(swander, (VOID *)NULL, WANDERTIME, BEFORE); + } + between = 0; + } +} + +/* + * this function is a daemon called each turn when the character is a thief + */ + +trap_look() +{ + if (rnd(100) < (2*dex_compute() + 5*pstats.s_lvl)) + search(TRUE, FALSE); +} + +/* + * unconfuse: + * Release the poor player from his confusion + */ + +unconfuse() +{ + turn_off(player, ISHUH); + msg("You feel less confused now"); +} + +/* + * unsee: + * He lost his see invisible power + */ + +unsee() +{ + if (!ISWEARING(R_SEEINVIS)) { + turn_off(player, CANSEE); + msg("The tingling feeling leaves your eyes"); + } +} + +/* + * unstink: + * Remove to-hit handicap from player + */ + +unstink() +{ + turn_off(player, HASSTINK); +} + +/* + * unclrhead: + * Player is no longer immune to confusion + */ + +unclrhead() +{ + turn_off(player, ISCLEAR); + msg("The blue aura about your head fades away."); +} + +/* + * unphase: + * Player can no longer walk through walls + */ + +unphase() +{ + turn_off(player, CANINWALL); + msg("Your dizzy feeling leaves you."); + if (!step_ok(hero.y, hero.x, NOMONST, &player)) + msg("You begin to feel weird.. "); +} + +/* + * land: + * Player can no longer fly + */ + +int +land() +{ + turn_off(player, ISFLY); + msg("You regain your normal weight"); + running = FALSE; + return(0); +} + +/* + * sight: + * He gets his sight back + */ + +sight() +{ + if (on(player, ISBLIND)) + { + extinguish(sight); + turn_off(player, ISBLIND); + light(&hero); + msg("The veil of darkness lifts"); + } +} + +/* + * res_strength: + * Restore player's strength + */ + +int +res_strength(howmuch) +long howmuch; +{ + + /* If lost_str is non-zero, restore that amount of strength, + * else all of it + */ + if (lost_str) { + chg_str(lost_str); + lost_str = 0; + } + + /* Now, add in the restoral, but no greater than maximum strength */ + if (howmuch > 0) + pstats.s_str = + min(pstats.s_str + howmuch, max_stats.s_str + ring_value(R_ADDSTR)); + + updpack(TRUE, &player); + return(0); +} + +/* + * nohaste: + * End the hasting + */ + +nohaste() +{ + turn_off(player, ISHASTE); + msg("You feel yourself slowing down."); +} + +/* + * noslow: + * End the slowing + */ + +noslow() +{ + turn_off(player, ISSLOW); + msg("You feel yourself speeding up."); +} + +/* + * suffocate: + * If this gets called, the player has suffocated + */ + +suffocate() +{ + pstats.s_hpt = -1; + death(D_SUFFOCATION); +} + +/* + * digest the hero's food + */ + +stomach() +{ + register int oldfood, old_hunger, food_use, i; + + /* + * avoid problems of fainting while eating by just not saying it + * takes food to eat food + */ + if (player.t_action == C_EAT) + return; + + old_hunger = hungry_state; + if (food_left <= 0) + { + /* + * the hero is fainting + */ + if (player.t_action == A_FREEZE) + return; + if (rnd(100) > 12) + return; + if (hungry_state == F_FAINT && rnd(28) == 7) /*must have fainted once*/ + { + pstats.s_hpt = -1; + msg("You starve to death!! --More-- "); + wait_for(' '); + death(D_STARVATION); + } + player.t_action = A_FREEZE; + player.t_no_move = movement(&player) * (rnd(8) + 3); + if (!terse) + addmsg("You feel too weak from the lack of food. "); + msg("You faint"); + running = FALSE; + if (fight_flush) flushinp(); + count = 0; + hungry_state = F_FAINT; + } + else + { + oldfood = food_left; + food_use = 0; + for (i=0; i<MAXRELIC; i++) { /* each relic eats an additional food */ + if (cur_relic[i]) + food_use++; + } + /* Charge for wearing rings */ + food_use += (ring_eat(LEFT_1) + ring_eat(LEFT_2) + + ring_eat(LEFT_3) + ring_eat(LEFT_4) + + ring_eat(RIGHT_1) + ring_eat(RIGHT_2) + + ring_eat(RIGHT_3) + ring_eat(RIGHT_4) + + foodlev); + if (food_use < 1) + food_use = 1; + food_left -= food_use; + if (food_left < MORETIME && oldfood >= MORETIME) { + msg("You are starting to feel weak"); + running = FALSE; + if (fight_flush) flushinp(); + count = 0; + hungry_state = F_WEAK; + } + else if (food_left < 2 * MORETIME && oldfood >= 2 * MORETIME) + { + msg(terse ? "Getting hungry" : "You are starting to get hungry"); + running = FALSE; + hungry_state = F_HUNGRY; + } + else if(food_left<STOMACHSIZE-MORETIME && oldfood>=STOMACHSIZE-MORETIME) + { + hungry_state = F_OKAY; + } + } + if (old_hunger != hungry_state) { + updpack(TRUE, &player); + status(TRUE); + } + wghtchk(); +} + +/* + * daemon for curing the diseased + */ + +cure_disease() +{ + turn_off(player, HASDISEASE); + if (off (player, HASINFEST)) + msg(terse ? "You feel yourself improving" + : "You begin to feel yourself improving again"); +} + +/* + * appear: + * Become visible again + */ + +appear() +{ + turn_off(player, ISINVIS); + PLAYER = VPLAYER; + msg("The tingling feeling leaves your body"); + light(&hero); +} + +/* + * dust_appear: + * dust of disappearance wears off + */ + +dust_appear() +{ + turn_off(player, ISINVIS); + PLAYER = VPLAYER; + msg("You become visible again"); + light(&hero); +} + +/* + * unchoke: + * the effects of "dust of choking and sneezing" wear off + */ + +unchoke() +{ + if (!find_slot(unconfuse)) + turn_off(player, ISHUH); + if (!find_slot(sight)) + turn_off(player, ISBLIND); + light(&hero); + msg("Your throat and eyes return to normal"); +} + +/* + * make some potion for the guy in the Alchemy jug + */ + +alchemy(obj) +register struct object *obj; +{ + register struct object *tobj = NULL; + register struct linked_list *item; + + /* + * verify that the object pointer we have still points to an alchemy + * jug (hopefully the right one!) because the hero could have thrown + * it away + */ + for (item = pack; item != NULL; item = next(item)) { + tobj = OBJPTR(item); + if (tobj == obj && + tobj->o_type == MM && + tobj->o_which== MM_JUG && + tobj->o_ac == JUG_EMPTY ) + break; + } + if (item == NULL) { /* not in the pack, check the level */ + for (item = lvl_obj; item != NULL; item = next(item)) { + tobj = OBJPTR(item); + if (tobj == obj && + tobj->o_type == MM && + tobj->o_which== MM_JUG && + tobj->o_ac == JUG_EMPTY ) + break; + } + } + if (item == NULL) /* can't find it.....too bad */ + return; + + switch(rnd(11)) { + case 0: tobj->o_ac = P_PHASE; + when 1: tobj->o_ac = P_CLEAR; + when 2: tobj->o_ac = P_SEEINVIS; + when 3: tobj->o_ac = P_HEALING; + when 4: tobj->o_ac = P_MFIND; + when 5: tobj->o_ac = P_TFIND; + when 6: tobj->o_ac = P_HASTE; + when 7: tobj->o_ac = P_RESTORE; + when 8: tobj->o_ac = P_FLY; + when 9: tobj->o_ac = P_SKILL; + when 10:tobj->o_ac = P_FFIND; + } +} + +/* + * otto's irresistable dance wears off + */ + +int +undance() +{ + turn_off(player, ISDANCE); + msg ("Your feet take a break.....whew!"); + return(0); +} + +/* + * if he has our favorite necklace of strangulation then take damage every turn + */ + +strangle() +{ + if ((pstats.s_hpt -= 6) <= 0) { + pstats.s_hpt = -1; + death(D_STRANGLE); + } +} + +/* + * if he has on the gauntlets of fumbling he might drop his weapon each turn + */ + +fumble() +{ + register struct linked_list *item; + + if (cur_weapon!=NULL && + !(cur_weapon->o_flags & ISCURSED) && + cur_weapon->o_type != RELIC && + rnd(100)<3) { + for (item = pack; item != NULL; item = next(item)) { + if (OBJPTR(item) == cur_weapon) + break; + } + if (item != NULL) { + switch(mvwinch(stdscr, hero.y, hero.x)) { + case PASSAGE: + case SCROLL: + case POTION: + case WEAPON: + case FLOOR: + case STICK: + case ARMOR: + case POOL: + case RELIC: + case GOLD: + case FOOD: + case RING: + case MM: + drop(item); + running = FALSE; + break; + default: + break; + } + } + } +} + +/* + * This is called each turn the hero has the ring of searching on + * it's a lot like trap_look() + */ + +ring_search() +{ + if (rnd(75) < (2*dex_compute() + 5*pstats.s_lvl)) search(TRUE, FALSE); + else search(FALSE, FALSE); +} + +/* + * this is called each turn the hero has the ring of teleportation on + */ + +ring_teleport() +{ + if (rnd(100) < 3) teleport(); +} + +/* + * this is called to charge up the quill of Nagrom + */ + +quill_charge() +{ + register struct object *tobj = NULL; + register struct linked_list *item; + + /* + * find the Quill of Nagrom in the hero's pack. It should still be there + * because it can't be dropped. If its not then don't do anything. + */ + for (item = pack; item != NULL; item = next(item)) { + tobj = OBJPTR(item); + if (tobj->o_type == RELIC && tobj->o_which == QUILL_NAGROM) + break; + } + if (item == NULL) + return; + if (tobj->o_charges < QUILLCHARGES) + tobj->o_charges++; + fuse (quill_charge, (VOID *)NULL, player.t_ctype == C_MAGICIAN ? 4 : 8, AFTER); +} + +/* + * take the skills away gained (or lost) by the potion of skills + */ + +unskill() +{ + if (pstats.s_lvladj != 0) { + pstats.s_lvl -= pstats.s_lvladj; + pstats.s_lvladj = 0; + msg("You feel your normal skill level return."); + status(TRUE); + } +} + +/* + * charge up the cloak of Emori + */ + +int +cloak_charge(obj) +register struct object *obj; +{ + if (obj->o_charges < 1) + obj->o_charges = 1; + return(0); +} + +/* + * nofire: + * He lost his fire resistance + */ + +nofire() +{ + if (!ISWEARING(R_FIRE)) { + turn_off(player, NOFIRE); + msg("Your feeling of fire resistance leaves you"); + } +} + +/* + * nocold: + * He lost his cold resistance + */ + +nocold() +{ + if (!ISWEARING(R_WARMTH)) { + turn_off(player, NOCOLD); + msg("Your feeling of warmth leaves you"); + } +} + +/* + * nobolt: + * He lost his protection from lightning + */ + +nobolt() +{ + turn_off(player, NOBOLT); + msg("Your skin loses its bluish tint"); +} + +/* + * eat_gold: + * an artifact eats gold + */ + +eat_gold(obj) +register struct object *obj; +{ + if (purse == 250) + msg("%s.. Bids you to find some more gold. ", inv_name(obj, FALSE)); + if (purse == 100) + msg("%s.. Demands that you find more gold! ", inv_name(obj, FALSE)); + if (purse == 50) + msg("%s.. Commands you to find more gold!! ", inv_name(obj, FALSE)); + if (purse == 0) { + if (rnd(10) >= 7) + msg("You feel the artifact gnawing away... "); + if (--pstats.s_hpt < 1) { + pstats.s_hpt = -1; + death(D_RELIC); + } + } + else + purse--; +} + +/* + * give the hero back some spell points + */ + +spell_recovery() +{ + int time; + + time = SPELLTIME - max(17-pstats.s_intel, 0); + time = max(time, 5); + if (spell_power > 0) spell_power--; + fuse(spell_recovery, (VOID *)NULL, time, AFTER); +} + +/* + * give the hero back some prayer points + */ + +prayer_recovery() +{ + int time; + + time = SPELLTIME - max(17-pstats.s_wisdom, 0); + time = max(time, 5); + if (pray_time > 0) pray_time--; + fuse(prayer_recovery, (VOID *)NULL, time, AFTER); +} + +/* + * give the hero back some chant points + */ + +chant_recovery() +{ + int time; + + time = SPELLTIME - max(17-pstats.s_wisdom, 0); + time = max(time, 5); + if (chant_time > 0) chant_time--; + fuse(chant_recovery, (VOID *)NULL, time, AFTER); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/eat.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,166 @@ +/* + eat.c - Functions for dealing with digestion + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include "rogue.h" + +/* + * eat: + * He wants to eat something, so let him try + */ + +eat() +{ + register struct linked_list *item; + int which; + unsigned long temp; + + if (player.t_action != C_EAT) { + if ((item = get_item(pack, "eat", FOOD, FALSE, FALSE)) == NULL) + return; + + player.t_using = item; /* Remember what it is */ + player.t_action = C_EAT; /* We are eating */ + which = (OBJPTR(item))->o_which; + player.t_no_move = max(foods[which].mi_food/100, 1) * movement(&player); + return; + } + + /* We have waited our time, let's eat the food */ + item = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + which = (OBJPTR(item))->o_which; + if ((food_left += foods[which].mi_food) > STOMACHSIZE) + food_left = STOMACHSIZE; + del_pack(item); + if (hungry_state == F_SATIATED && food_left == STOMACHSIZE && rnd(4) == 1) { + pstats.s_hpt = -1; + msg ("Cough! Ack! You choke on all that food and die! --More--"); + wait_for(' '); + death(D_FOOD_CHOKE); + } + if (food_left >= STOMACHSIZE-MORETIME) { + hungry_state = F_SATIATED; + msg ("You have trouble getting that food down!"); + msg ("Your stomach feels like it's about to burst!"); + } + else if (which != E_SLIMEMOLD) { + hungry_state = F_OKAY; + switch (rnd(10)) { + case 0: msg("Yuck, what a foul tasting %s! ", foods[which].mi_name); + when 1: msg("Mmmm, what a tasty %s. ", foods[which].mi_name); + when 2: msg("Wow, what a scrumptious %s! ", foods[which].mi_name); + when 3: msg("Hmmm, %s heaven! ", foods[which].mi_name); + when 4: msg("You've eaten better %s. ", foods[which].mi_name); + when 5: msg("You smack your lips "); + when 6: msg("Yum-yum-yum "); + when 7: msg("Gulp! "); + when 8: msg("Your tongue flips out! "); + when 9: msg("You lick your chin "); + } + } + updpack(TRUE, &player); + switch(which) { + case E_WHORTLEBERRY: /* add 1 to intelligence */ + (*add_abil[A_INTELLIGENCE])(1); + when E_SWEETSOP: /* add 1 to strength */ + case E_SOURSOP: /* add 1 to strength */ + (*add_abil[A_STRENGTH])(1); + when E_SAPODILLA: /* add 1 to wisdom */ + (*add_abil[A_WISDOM])(1); + when E_APPLE: /* add 1 to dexterity */ + (*add_abil[A_DEXTERITY])(1); + when E_PRICKLEY: /* add 1 to constitution */ + (*add_abil[A_CONSTITUTION])(1); + when E_PEACH: /* add 1 to charisma */ + (*add_abil[A_CHARISMA])(1); + when E_PITANGA: /* add 1 hit point */ + max_stats.s_hpt++; + pstats.s_hpt = max_stats.s_hpt; + msg("You feel a bit tougher now. "); + when E_HAGBERRY: /* armor class */ + case E_JABOTICABA: /* armor class */ + pstats.s_arm--; + msg("Your skin feels more resilient now. "); + when E_STRAWBERRY: /* add 10% experience points */ + case E_RAMBUTAN: /* add 10% experience points */ + temp = pstats.s_exp/100 + 10; + pstats.s_exp += temp; + msg("You feel slightly more experienced now. "); + check_level(); + when E_DEWBERRY: /* encourage him to do more magic */ + if (chant_time > 0) { + chant_time -= 80; + if (chant_time < 0) + chant_time = 0; + msg("You feel you have more chant ability. "); + } + if (pray_time > 0) { + pray_time -= 80; + if (pray_time < 0) + pray_time = 0; + msg("You feel you have more prayer ability. "); + } + if (spell_power > 0) { + spell_power -= 80; + if (spell_power < 0) + spell_power = 0; + msg("You feel you have more spell casting ability. "); + } + when E_CANDLEBERRY: /* cure him */ + if (on(player, HASINFEST) || + on(player, HASDISEASE)|| + on(player, DOROT)) { + if (on(player, HASDISEASE)) { + extinguish(cure_disease); + cure_disease(); + } + if (on(player, HASINFEST)) { + msg("You feel yourself improving. "); + turn_off(player, HASINFEST); + infest_dam = 0; + } + if (on(player, DOROT)) { + msg("You feel your skin returning to normal. "); + turn_off(player, DOROT); + } + } + when E_SLIMEMOLD: /* monster food */ + msg("The slime-mold quivers around in your mouth. "); + player.t_no_move = 3*movement(&player); + if (off(player, HASDISEASE)) { + if (ISWEARING(R_HEALTH) || player.t_ctype == C_PALADIN || + player.t_ctype == C_RANGER) { + msg("You feel lousy. "); + } + else { + turn_on(player, HASDISEASE); + fuse(cure_disease, (VOID *)NULL, roll(HEALTIME,SICKTIME),AFTER); + msg("You become ill. "); + } + } + pstats.s_const -= rnd(2)+1; + if (pstats.s_const <= 3) pstats.s_const = 3; + + otherwise: /* not all the foods have to do something */ + break; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/effects.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,722 @@ +/* + effects.c - functions for dealing with appllying effects to monsters + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <string.h> +#include <curses.h> +#include "rogue.h" + +/* + * effect: + * Check for effects of one thing hitting another thing. Return + * the reason code if the defender is killed. Otherwise return 0. + */ + +effect(att, def, weap, thrown, see_att, see_def) +register struct thing *att, *def; +struct object *weap; +bool thrown; +register bool see_att, see_def; +{ + register bool att_player, def_player; + char attname[LINELEN+1], defname[LINELEN+1]; + + /* See if the attacker or defender is the player */ + att_player = (att == &player); + def_player = (def == &player); + + /* + * If the player could see the attacker or defender, they can't + * surprise anymore (don't bother checking if they could). + */ + if (see_att) turn_off(*att, CANSURPRISE); + if (see_def) turn_off(*def, CANSURPRISE); + + /* What are the attacker and defender names? */ + if (att_player) strcpy(attname, "you"); + else { + if (see_att) strcpy(attname, monster_name(att)); + else strcpy(attname, "something"); + } + + if (def_player) strcpy(defname, "you"); + else { + if (see_def) strcpy(defname, monster_name(def)); + else strcpy(defname, "something"); + } + + /* + * See what happens to the attacker first. We can skip this + * whole section, however, if the defender is the player. + * Nothing happens (yet) to anyone just for hitting the player. + */ + if (!def_player) { + if (!thrown) { /* Some things require a direct hit. */ + /* + * If the attacker hits a rusting monster, The weapon + * may be damaged + */ + if (on(*def, CANRUST) && weap && + weap->o_type != RELIC && (weap->o_flags & ISMETAL) && + !(weap->o_flags & ISPROT)) { + if ((weap->o_hplus < 1 && weap->o_dplus < 1) || + roll(1,20) < weap->o_hplus+weap->o_dplus+10) { + if (rnd(100) < 50) weap->o_hplus--; + else weap->o_dplus--; + if (att_player) + msg(terse ? "Your %s weakens!" + : "Your %s gets weaker!", + weaps[weap->o_which].w_name); + } + } + } + + /* If the attacker hit something that shrieks, wake the dungeon */ + if (on(*def, CANSHRIEK)) { + if (see_def) + msg("%s emits an ear piercing shriek! ", prname(defname, TRUE)); + else + msg("You hear an ear piercing shriek!"); + + /* Friendly charactors should be immune */ + if (player.t_ctype == C_PALADIN || + player.t_ctype == C_RANGER || player.t_ctype == C_MONK) + aggravate(TRUE, FALSE); + else + aggravate(TRUE, TRUE); + } + + /* + * does the creature explode when hit? + */ + if (on(*def, CANEXPLODE)) { + if (see_def) msg("%s explodes!", prname(defname, TRUE)); + else msg("You hear a tremendous explosion!"); + explode(def); + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + death(def->t_index); + } + } + } + + /* + * Now let's see what happens to the defender. Start out with + * the things that everyone can do. Then exit if the attacker + * is the player. + */ + if (!thrown) { + /* + * Can the player confuse? + */ + if (on(*att, CANHUH) && att_player) { + msg("Your hands return to normal. "); + if (off(*def, ISCLEAR) && + (off(*def, ISUNIQUE) || !save(VS_MAGIC, def, 0))) { + if (see_def) msg("%s appears confused!", prname(defname, TRUE)); + turn_on(*def, ISHUH); + } + turn_off(*att, CANHUH); + } + + /* Return now if the attacker is the player. */ + if (att_player) return(0); + + /* + * Some monsters may take half your hit points + */ + if (on(*att, CANSUCK) && !save(VS_MAGIC, def, 0)) { + if (def->t_stats.s_hpt == 1) return(att->t_index); /* Killed! */ + else { + def->t_stats.s_hpt /= 2; + if (def_player) + msg("Your life force is being drained out of you."); + } + } + + /* + * If a hugging monster hits, it may SQUEEEEEEEZE. + */ + if (on(*att, CANHUG)) { + if (roll(1,20) >= 18 || roll(1,20) >= 18) { + if (def_player) + msg("%s squeezes itself nastily against you!", + prname(attname, TRUE)); + else if (see_att) + msg("%s squeezes real hard!", prname(attname, TRUE)); + + if ((def->t_stats.s_hpt -= roll(2,8)) <= 0) + return(att->t_index); + } + } + + /* + * Some monsters have poisonous bites. + */ + if (on(*att, CANPOISON) && !save(VS_POISON, def, 0)) { + if (def_player) { + if (ISWEARING(R_SUSABILITY)) + msg(terse ? "Sting has no effect." + : "A sting momentarily weakens your arm."); + else { + chg_str(-1); + msg(terse ? "A sting has weakened you." : + "You get stung in the arm! You feel weaker. "); + } + } + else { + /* Subtract a strength point and see if it kills it */ + if (--def->t_stats.s_str <= 0) return(D_STRENGTH); + } + } + + /* + * Turning to stone: + */ + if (on(*att, TOUCHSTONE)) { + if (def_player) turn_off(*att, TOUCHSTONE); + if (on(*def, CANINWALL)) { + if (def_player) + msg("%s's touch has no effect.", prname(attname, TRUE)); + } + else { + if (!save(VS_PETRIFICATION, def, 0) && rnd(100) < 10) { + if (def_player) { + msg("Your body begins to solidify.. "); + msg("You are transformed into stone!! --More--"); + wait_for(' '); + return(D_PETRIFY); + } + else { + /* The monster got stoned! */ + turn_on(*def, ISSTONE); + turn_off(*def, ISRUN); + turn_off(*def, ISINVIS); + turn_off(*def, ISDISGUISE); + if (def->t_stats.s_intel > 15) + msg("%s staggers.. ", prname(defname, TRUE)); + else if (see_def) + msg("%s turns to stone! ", prname(defname, TRUE)); + else if (cansee(unc(def->t_pos))) + msg("A statue appears out of nowhere! "); + } + } + else if (def->t_action != A_FREEZE) { + if (def_player) + msg("%s's touch stiffens your limbs.", + prname(attname, TRUE)); + else if (see_def) + msg("%s appears to freeze over.", prname(defname, TRUE)); + + def->t_no_move += movement(def) * STONETIME; + def->t_action = A_FREEZE; + } + } + } + + /* + * Wraiths might drain energy levels + */ + if ((on(*att, CANDRAIN) || on(*att, DOUBLEDRAIN)) && + !save(VS_POISON, def, 3-(att->t_stats.s_lvl/5))) { + if (def_player) { + lower_level(att->t_index); + if (on(*att, DOUBLEDRAIN)) lower_level(att->t_index); + turn_on(*att, DIDDRAIN); + } + else { + def->t_stats.s_hpt -= roll(1, 8); + def->t_stats.s_lvl--; + if (on(*att, DOUBLEDRAIN)) { + def->t_stats.s_hpt -= roll(1, 8); + def->t_stats.s_lvl--; + } + if (see_def) + msg("%s appears less skillful.", prname(defname, TRUE)); + + /* Did it kill it? */ + if (def->t_stats.s_hpt <= 0 || + def->t_stats.s_lvl <= 0) + return(att->t_index); + } + } + + /* + * Paralyzation: + */ + if (on(*att, CANPARALYZE) && def->t_action != A_FREEZE) { + if (def_player) turn_off(*att, CANPARALYZE); + if (!save(VS_PARALYZATION, def, 0)) { + if (on(*def, CANINWALL)) { + if (def_player) + msg("%s's touch has no effect.", prname(attname, TRUE)); + } + else { + if (def_player) + msg("%s's touch paralyzes you.", prname(attname, TRUE)); + else if (see_def) + msg("%s appears to freeze over!", prname(defname, TRUE)); + + def->t_no_move += movement(def) * FREEZETIME; + def->t_action = A_FREEZE; + } + } + } + + /* + * Painful wounds make the defendant faint + */ + if (on(*att, CANPAIN) && def->t_action != A_FREEZE) { + if (def_player) turn_off(*att, CANPAIN); + if (!ISWEARING(R_ALERT) && !save(VS_POISON, def, 0)) { + if (def_player) + msg("You faint from the painful wound!"); + else if (see_def) + msg("%s appears to faint!", prname(defname, TRUE)); + + def->t_no_move += movement(def) * PAINTIME; + def->t_action = A_FREEZE; + } + } + + /* + * Some things currently affect only the player. Let's make + * a check here so we don't have to check for each thing. + */ + if (def_player) { + /* + * Stinking monsters make the defender weaker (to hit). For now + * this will only affect the player. We may later add the HASSTINK + * effect to monsters, too. + */ + if (on(*att, CANSTINK)) { + turn_off(*att, CANSTINK); + if (!save(VS_POISON, def, 0)) { + msg("The stench of %s sickens you. Blech!", + prname(attname, FALSE)); + if (on(player, HASSTINK)) lengthen(unstink, STINKTIME); + else { + turn_on(player, HASSTINK); + fuse(unstink, (VOID *)NULL, STINKTIME, AFTER); + } + } + } + + /* + * Chilling monster reduces strength each time. This only + * affects the player for now because of its temporary nature. + */ + if (on(*att, CANCHILL)) { + if (!ISWEARING(R_SUSABILITY) && !save(VS_POISON, def, 0)) { + msg("You cringe at %s's chilling touch.", + prname(attname, FALSE)); + chg_str(-1); + if (lost_str++ == 0) + fuse(res_strength, (VOID *)NULL, CHILLTIME, AFTER); + else lengthen(res_strength, CHILLTIME); + } + } + + /* + * Itching monsters reduce dexterity (temporarily). This only + * affects the player for now because of its temporary nature. + */ + if (on(*att, CANITCH) && !save(VS_POISON, def, 0)) { + msg("The claws of %s scratch you!", prname(attname, FALSE)); + if (ISWEARING(R_SUSABILITY)) { + msg("The scratch has no effect."); + } + else { + (*add_abil[A_DEXTERITY])(-1); + } + } + + /* + * If a disease-carrying monster hits, there is a chance the + * defender will catch the disease. This only applies to the + * player for now because of the temporary nature. Don't affect + * the Ranger or Paladin. + */ + if (on(*att, CANDISEASE) && + (rnd(def->t_stats.s_const) < att->t_stats.s_lvl) && + off(*def, HASDISEASE)) { + if (ISWEARING(R_HEALTH) || + player.t_ctype == C_PALADIN || + player.t_ctype == C_RANGER) { + msg("The wound heals quickly."); + } + else { + turn_on(*def, HASDISEASE); + fuse(cure_disease, (VOID *)NULL, roll(HEALTIME,SICKTIME), AFTER); + msg(terse ? "You have been diseased!" + : "You have contracted an annoying disease!"); + } + } + + /* + * If a rusting monster hits, you lose armor. This only applies to + * the player because monsters don't wear armor (for now). + */ + if (on(*att, CANRUST)) { + if (cur_armor != NULL && + cur_armor->o_which != LEATHER && + cur_armor->o_which != STUDDED_LEATHER && + cur_armor->o_which != PADDED_ARMOR && + !(cur_armor->o_flags & ISPROT) && + cur_armor->o_ac < def->t_stats.s_arm+1) { + msg(terse ? "Your armor weakens." + : "Your armor becomes weaker."); + cur_armor->o_ac++; + } + if (cur_misc[WEAR_BRACERS] != NULL && + cur_misc[WEAR_BRACERS]->o_ac > 0 && + !(cur_misc[WEAR_BRACERS]->o_flags & ISPROT)) { + cur_misc[WEAR_BRACERS]->o_ac--; + if (cur_misc[WEAR_BRACERS]->o_ac == 0) { + register struct linked_list *item; + + for (item=pack; item!=NULL; item=next(item)) { + if (OBJPTR(item) == cur_misc[WEAR_BRACERS]) { + detach(pack, item); + o_discard(item); + break; + } + } + msg ("Your bracers crumble apart!"); + cur_misc[WEAR_BRACERS] = NULL; + inpack--; + } + else { + msg("Your bracers weaken!"); + } + } + } + + /* + * If can dissolve and hero has leather type armor. This + * also only applies to the player for now because of the + * armor. + */ + if (on(*att, CANDISSOLVE) && cur_armor != NULL && + (cur_armor->o_which == LEATHER || + cur_armor->o_which == STUDDED_LEATHER || + cur_armor->o_which == PADDED_ARMOR) && + !(cur_armor->o_flags & ISPROT) && + cur_armor->o_ac < def->t_stats.s_arm+1) { + msg(terse ? "Your armor dissolves!" + : "Your armor appears to have dissolved!"); + cur_armor->o_ac++; + } + + /* + * If an infesting monster hits you, you get a parasite or rot. + * This will only affect the player until we figure out how to + * make it affect monsters. Don't affect the Monk. + */ + if (on(*att, CANINFEST) && + rnd(def->t_stats.s_const) < att->t_stats.s_lvl) { + if (ISWEARING(R_HEALTH) || player.t_ctype == C_MONK) { + msg("The wound heals quickly."); + } + else { + turn_off(*att, CANINFEST); + msg(terse ? "You have been infested." + : "You have contracted a parasitic infestation!"); + infest_dam++; + turn_on(*def, HASINFEST); + } + } + + /* + * Does it take wisdom away? This currently affects only + * the player because of its temporary nature. + */ + if (on(*att, TAKEWISDOM) && + !save(VS_MAGIC, def, 0) && + !ISWEARING(R_SUSABILITY)) { + (*add_abil[A_WISDOM])(-1); + } + + /* + * Does it take intelligence away? This currently affects + * only the player because of its temporary nature. + */ + if (on(*att, TAKEINTEL) && + !save(VS_MAGIC, &player, 0) && + !ISWEARING(R_SUSABILITY)) { + (*add_abil[A_INTELLIGENCE])(-1); + } + + /* + * Cause fear by touching. This currently affects only + * the player until we figure out how we want it to + * affect monsters. + */ + if (on(*att, TOUCHFEAR)) { + turn_off(*att, TOUCHFEAR); + if (!ISWEARING(R_HEROISM) && + !save(VS_WAND, def, 0) && + !(on(*def, ISFLEE) && (def->t_dest == &att->t_pos))) { + turn_on(*def, ISFLEE); + def->t_dest = &att->t_pos; + msg("%s's touch terrifies you!", prname(attname, TRUE)); + + /* It is okay to turn tail */ + if (!def_player) def->t_oldpos = def->t_pos; + } + } + + /* + * Make the hero dance (as in otto's irresistable dance) + * This should be fairly easy to do to monsters, but + * we'll restrict it to players until we decide what to + * do about the temporary nature. + */ + if (on(*att, CANDANCE) && + !on(*def, ISDANCE) && + def->t_action != A_FREEZE && + !save(VS_MAGIC, def, -4)) { + turn_off(*att, CANDANCE); + turn_on(*def, ISDANCE); + msg("You begin to dance uncontrollably!"); + fuse(undance, (VOID *)NULL, roll(2,4), AFTER); + } + + /* + * Suffocating our hero. Monsters don't get suffocated. + * That's too hard for now. + */ + if (on(*att, CANSUFFOCATE) && + !ISWEARING(R_FREEDOM) && + rnd(100) < 30 && + (find_slot(suffocate) == 0)) { + turn_on(*att, DIDSUFFOCATE); + msg("%s is beginning to suffocate you!", prname(attname, TRUE)); + fuse(suffocate, (VOID *)NULL, roll(9,3), AFTER); + } + + /* + * some creatures stops the poor guy from moving. + * How can we do this to a monster? + */ + if (on(*att,CANHOLD) && off(*att,DIDHOLD) && !ISWEARING(R_FREEDOM)){ + turn_on(*def, ISHELD); + turn_on(*att, DIDHOLD); + hold_count++; + } + + /* + * Sucker will suck blood and run. This + * should be easy to have happen to a monster, + * but we have to decide how to handle the fleeing. + */ + if (on(*att, CANDRAW)) { + turn_off(*att, CANDRAW); + turn_on(*att, ISFLEE); + msg("%s sates itself with your blood!", prname(attname, TRUE)); + if ((def->t_stats.s_hpt -= 12) <= 0) return(att->t_index); + + /* It is okay to turn tail */ + att->t_oldpos = att->t_pos; + } + + /* + * Bad smell will force a reduction in strength. + * This will happen only to the player because of + * the temporary nature. + */ + if (on(*att, CANSMELL)) { + turn_off(*att, CANSMELL); + if (save(VS_MAGIC, def, 0) || ISWEARING(R_SUSABILITY)) { + if (terse) + msg("Pheww!"); + else + msg("You smell an unpleasant odor. Phew!"); + } + + else { + int odor_str = -(rnd(6)+1); + + msg("You are overcome by a foul odor!"); + if (lost_str == 0) { + chg_str(odor_str); + fuse(res_strength, (VOID *)NULL, SMELLTIME, AFTER); + lost_str -= odor_str; + } + else lengthen(res_strength, SMELLTIME); + } + } + + /* + * The monsters touch slows the defendant down. + */ + if (on(*att, TOUCHSLOW)) { + turn_off(*att, TOUCHSLOW); + if (!save(VS_PARALYZATION, def, 0)) + add_slow(); + } + + /* + * Rotting only affects the player. Don't affect the Monk, + * Paladin, or Ranger. + */ + if (on(*att, CANROT)) { + if (!ISWEARING(R_HEALTH) && + player.t_ctype != C_MONK && + player.t_ctype != C_RANGER && + player.t_ctype != C_PALADIN && + !save(VS_POISON, def, 0) && + off(*def, DOROT)) { + turn_on(*def, DOROT); + msg("You feel your skin starting to rot and peel away!"); + } + } + + /* + * Monsters should be able to steal gold from anyone, + * but until this is rewritten, they will only steal + * from the player (tough break). + */ + if (on(*att, STEALGOLD)) { + /* + * steal some gold + */ + register long lastpurse; + register struct linked_list *item; + register struct object *obj; + + lastpurse = purse; + purse -= (GOLDCALC * 2); + if (!save(VS_MAGIC, def, att->t_stats.s_lvl/10)) { + if (on(*att, ISUNIQUE)) + purse -= (GOLDCALC * 5); + else + purse -= (GOLDCALC * 3); + } + if (purse < 0) + purse = 0; + if (purse != lastpurse) { + msg("You lost some gold! "); + + /* Give the gold to the thief */ + for (item=att->t_pack; item != NULL; item=next(item)) { + obj = OBJPTR(item); + if (obj->o_type == GOLD) { + obj->o_count += lastpurse - purse; + break; + } + } + + /* Did we do it? */ + if (item == NULL) { /* Then make some */ + item = new_item(sizeof *obj); + obj = OBJPTR(item); + obj->o_type = GOLD; + obj->o_count = lastpurse - purse; + obj->o_hplus = obj->o_dplus = 0; + strcpy(obj->o_damage,"0d0"); + strcpy(obj->o_hurldmg,"0d0"); + obj->o_ac = 11; + obj->contents = NULL; + obj->o_group = 0; + obj->o_flags = 0; + obj->o_mark[0] = '\0'; + obj->o_pos = att->t_pos; + + attach(att->t_pack, item); + } + } + + turn_on(*att, ISFLEE); + turn_on(*att, ISINVIS); + + /* It is okay to turn tail */ + att->t_oldpos = att->t_pos; + } + } + + /* + * Stealing happens last since the monster disappears + * after the act. + */ + if (on(*att, STEALMAGIC)) { + register struct linked_list *list, *steal; + register struct object *obj; + register int nobj; + + /* + * steal a magic item, look through the pack + * and pick out one we like. + */ + steal = NULL; + for (nobj = 0, list = def->t_pack; list != NULL; list = next(list)) + { + obj = OBJPTR(list); + if (!is_current(obj) && + list != def->t_using && + obj->o_type != RELIC && + is_magic(obj) && + rnd(++nobj) == 0) + steal = list; + } + if (steal != NULL) + { + register struct object *obj; + struct linked_list *item; + + obj = OBJPTR(steal); + if (on(*att, ISUNIQUE)) + monsters[att->t_index].m_normal = TRUE; + item = find_mons(att->t_pos.y, att->t_pos.x); + + killed(item, FALSE, FALSE, FALSE); /* Remove the attacker */ + + if (obj->o_count > 1 && obj->o_group == 0) { + register int oc; + + oc = --(obj->o_count); + obj->o_count = 1; + if (def_player) + msg("%s stole %s!", prname(attname, TRUE), + inv_name(obj, TRUE)); + obj->o_count = oc; + } + else { + if (def_player) { + msg("%s stole %s!", prname(attname, TRUE), + inv_name(obj, TRUE)); + + /* If this is a relic, clear its holding field */ + if (obj->o_type == RELIC) + cur_relic[obj->o_which] = 0; + + inpack--; + } + + detach(def->t_pack, steal); + o_discard(steal); + } + + updpack(FALSE, def); + } + } + } + + /* Didn't kill the defender */ + return(0); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/encumb.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,202 @@ +/* + encumb.c - Stuff to do with encumberance + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include "rogue.h" + +/* + * updpack: + * Update his pack weight and adjust fooduse accordingly + */ + +updpack(getmax, tp) +int getmax; +struct thing *tp; +{ + + reg int topcarry, curcarry; + + if (getmax) + tp->t_stats.s_carry = totalenc(tp); /* get total encumb */ + curcarry = packweight(tp); /* get pack weight */ + + /* Only update food use for the player (for now) */ + if (tp == &player) { + topcarry = tp->t_stats.s_carry / 5; /* 20% of total carry */ + if(curcarry > 4 * topcarry) { + if(rnd(100) < 80) + foodlev = 3; /* > 80% of pack */ + } else if(curcarry > 3 * topcarry) { + if(rnd(100) < 60) + foodlev = 2; /* > 60% of pack */ + } else + foodlev = 1; /* <= 60% of pack */ + } + tp->t_stats.s_pack = curcarry; /* update pack weight */ +} + + +/* + * packweight: + * Get the total weight of the hero's pack + */ + +packweight(tp) +register struct thing *tp; +{ + reg struct object *obj; + reg struct linked_list *pc; + reg int weight; + + weight = 0; + for (pc = tp->t_pack ; pc != NULL ; pc = next(pc)) { + obj = OBJPTR(pc); + weight += itemweight(obj); + } + if (weight < 0) /* in case of amulet */ + weight = 0; + + /* If this is the player, is he wearing a ring of carrying? */ + if (tp == &player && ISWEARING(R_CARRY)) { + register int temp, i; + + temp = 0; + for (i=0; i<NUM_FINGERS; i++) { + if (cur_ring[i] != NULL && cur_ring[i]->o_which == R_CARRY) { + if (cur_ring[i]->o_flags & ISCURSED) temp--; + else temp += 2; + } + } + weight -= (temp * weight) / 4; + } + + return(weight); +} + +/* + * itemweight: + * Get the weight of an object + */ + +itemweight(wh) +reg struct object *wh; +{ + reg int weight; + reg int ac; + + weight = wh->o_weight; /* get base weight */ + switch(wh->o_type) { + case ARMOR: + /* + * subtract 10% for each enchantment + * this will add weight for negative items + */ + ac = armors[wh->o_which].a_class - wh->o_ac; + weight = ((weight*10) - (weight*ac)) / 10; + if (weight < 0) weight = 0; + when WEAPON: + if ((wh->o_hplus + wh->o_dplus) > 0) + weight /= 2; + } + if(wh->o_flags & ISCURSED) + weight += weight / 5; /* 20% more for cursed */ + weight *= wh->o_count; + return(weight); +} + +/* + * playenc: + * Get hero's carrying ability above norm + */ + +playenc(tp) +register struct thing *tp; +{ + register int strength; + + if (tp == &player) strength = str_compute(); + else strength = tp->t_stats.s_str; + + return ((strength-8)*50); +} + +/* + * totalenc: + * Get total weight that the hero can carry + */ + +totalenc(tp) +register struct thing *tp; +{ + reg int wtotal; + + wtotal = NORMENCB + playenc(tp); + if (tp == &player) switch(hungry_state) { + case F_SATIATED: + case F_OKAY: + case F_HUNGRY: ; /* no change */ + when F_WEAK: wtotal -= wtotal / 10; /* 10% off weak */ + when F_FAINT: wtotal /= 2; /* 50% off faint */ + } + return(wtotal); +} + +/* + * whgtchk: + * See if the hero can carry his pack + */ + +wghtchk() +{ + reg int dropchk, err = TRUE; + reg char ch; + int wghtchk(); + + inwhgt = TRUE; + if (pstats.s_pack > pstats.s_carry) { + ch = mvwinch(stdscr, hero.y, hero.x); + if((ch != FLOOR && ch != PASSAGE)) { + extinguish(wghtchk); + fuse(wghtchk, (VOID *)NULL, 1, AFTER); + inwhgt = FALSE; + return; + } + extinguish(wghtchk); + msg("Your pack is far too heavy for you.. "); + do { + dropchk = drop((struct linked_list *)NULL); + if(dropchk == 0) { + mpos = 0; + msg("You must drop something"); + } + if(dropchk == TRUE) + err = FALSE; + } while(err); + } + inwhgt = FALSE; +} + +/* + * hitweight: + * Gets the fighting ability according to current weight + * This returns a +1 hit for light pack weight + * 0 hit for medium pack weight + * -1 hit for heavy pack weight + */ + +hitweight() +{ + return(2 - foodlev); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/fight.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1474 @@ +/* + fight.c - All the fighting gets done here + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" + +#define CONF_DAMAGE -1 +#define PARAL_DAMAGE -2 +#define DEST_DAMAGE -3 +#define DRAIN_DAMAGE -4 + +int killed_chance = 0; /* cumulative chance for goodies to loose it */ + +/* + * returns true if player has a any chance to hit the monster + */ + +player_can_hit(tp, weap) +register struct thing *tp; +register struct object *weap; +{ + if (off(*tp, CMAGICHIT) && off(*tp, BMAGICHIT) && off(*tp, MAGICHIT)) + return(TRUE); + if (weap && weap->o_type == RELIC) + return(TRUE); + if (on(*tp, CMAGICHIT) && weap && (weap->o_hplus>2 || weap->o_dplus>2)) + return(TRUE); + if (on(*tp, BMAGICHIT) && weap && (weap->o_hplus>1 || weap->o_dplus>1)) + return(TRUE); + if (on(*tp, MAGICHIT) && weap && (weap->o_hplus>0 || weap->o_dplus>0)) + return(TRUE); + if (player.t_ctype == C_MONK) { + if (on(*tp, CMAGICHIT) && pstats.s_lvl > 15) + return(TRUE); + if (on(*tp, BMAGICHIT) && pstats.s_lvl > 10) + return(TRUE); + if (on(*tp, MAGICHIT) && pstats.s_lvl > 5) + return(TRUE); + } + return(FALSE); +} + +/* + * fight: + * The player attacks the monster. + */ + +fight(mp, weap, thrown) +register coord *mp; +struct object *weap; +bool thrown; +{ + register struct thing *tp; + register struct linked_list *item; + register bool did_hit = TRUE; + bool see_def, back_stab = FALSE; + register char *mname; + + /* + * Find the monster we want to fight + */ + if ((item = find_mons(mp->y, mp->x)) == NULL) { + return(FALSE); /* must have killed him already */ + } + tp = THINGPTR(item); + + /* + * Since we are fighting, things are not quiet so no healing takes + * place. The -1 also tells us that we are in a fight. + */ + player.t_quiet = -1; + tp->t_quiet = -1; + + see_def = ((off(*tp, ISINVIS) || on(player, CANSEE)) && + (off(*tp, ISSHADOW) || on(player, CANSEE)) && + (!thrown || cansee(unc(tp->t_pos)))); + + mname = see_def ? monster_name(tp) : "something"; + + /* + * if its in the wall, we can't hit it + */ + if (on(*tp, ISINWALL) && off(player, CANINWALL)) + return(FALSE); + + if (on(*tp, ISSTONE)) { + killed(item, FALSE, FALSE, FALSE); + if (see_def) + msg("%s shatters into a million pieces!", prname(mname, TRUE)); + count = 0; + return (TRUE); + } + /* + * Let him know it was really a mimic (if it was one). + */ + if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise) && + off(player, ISBLIND)) + { + if (see_def) { + msg("Wait! That's a %s!", mname); + turn_off(*tp, ISDISGUISE); + } + did_hit = thrown; + } + if (on(*tp, CANSURPRISE) && off(player, ISBLIND) && !ISWEARING(R_ALERT)) { + if (see_def) { + msg("Wait! There's a %s!", mname); + turn_off(*tp, CANSURPRISE); + } + did_hit = thrown; + } + + /* + * if he's a thief or assassin and the creature is asleep then he gets + * a chance for a backstab + */ + if ((player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN) && + !thrown && + !on(*tp, NOSTAB) && + !invisible(tp) && + (!on(*tp, ISRUN) || on(*tp, ISHELD) || tp->t_action == A_FREEZE)) + back_stab = TRUE; + + /* + * assassins get an assassination chance, if it fails then its normal + * damage + */ + if (back_stab && player.t_ctype == C_ASSASSIN) { + int chance; + + chance = 50 + (pstats.s_lvl - tp->t_stats.s_lvl) * 5; + if (cur_weapon && (cur_weapon->o_flags & ISPOISON)) + chance += 20; + if (roll(1,100) > chance || on(*tp, ISUNIQUE)) + back_stab = FALSE; + } + + runto(tp, &hero); + + /* Let the monster know that the player has missiles! */ + if (thrown) tp->t_wasshot = TRUE; + + if (did_hit) + { + + did_hit = FALSE; + if (!can_blink(tp) && + player_can_hit(tp, weap) && + roll_em(&player, tp, weap, thrown, cur_weapon, back_stab)) + { + did_hit = TRUE; + + if (on(*tp, NOMETAL) && weap != NULL && + weap->o_type != RELIC && weap->o_flags & ISMETAL) { + msg("Your %s passes right through %s!", + weaps[weap->o_which].w_name, prname(mname, FALSE)); + } + else if (weap != NULL && weap->o_type == MISSILE && on(*tp, CARRYBAMULET)) { + msg("The magic missile has no effect on %s. ", + prname(mname, FALSE)); + } + else { + hit(thrown ? (struct object *)NULL : weap, + TRUE, see_def, + thrown ? weap_name(weap) : NULL, + mname, back_stab, thrown, terse); + + /* See if there are any special effects */ + if (effect(&player, tp, weap, thrown, TRUE, see_def) != 0) + killed(item, FALSE, FALSE, TRUE); + + /* + * Merchants just disappear if hit + */ + else if (on(*tp, CANSELL)) { + if (see_def) + msg("%s disappears with his wares in a flash! ", + prname(mname, FALSE)); + killed(item, FALSE, FALSE, FALSE); + } + + else if (tp->t_stats.s_hpt <= 0) + killed(item, TRUE, TRUE, TRUE); + + else { + /* If the victim was charmed, it now gets a saving throw! */ + if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) { + msg("The eyes of %s turn clear.", prname(mname, FALSE)); + turn_off(*tp, ISCHARMED); + } + + dsrpt_monster(tp, FALSE, see_def); /* Disrupt a spell? */ + } + } + } + else { + miss(thrown ? (struct object *)NULL : weap, + TRUE, see_def, + thrown ? weap_name(weap) : (char *)NULL, + mname, thrown, terse); + } + } + count = 0; + return did_hit; +} + +/* + * attack: + * The monster attacks the player + */ + +attack(mp, weapon, thrown) +register struct thing *mp; +register struct object *weapon; +bool thrown; +{ + register char *mname; + register bool see_att, did_hit = FALSE; + register struct object *wielded; /* The wielded weapon */ + struct linked_list *get_wield; /* Linked list header for wielded */ + + /* + * Since this is an attack, stop running and any healing that was + * going on at the time. The -1 also tells us that we're fighting. + */ + running = FALSE; + player.t_quiet = -1; + mp->t_quiet = -1; + + if (on(*mp, ISDISGUISE) && off(player, ISBLIND)) + turn_off(*mp, ISDISGUISE); + + see_att = ((off(*mp, ISINVIS) || on(player, CANSEE)) && + (off(*mp, ISSHADOW) || on(player, CANSEE)) && + (!thrown || cansee(unc(mp->t_pos)))); + + mname = see_att ? monster_name(mp) : "something"; + + /* + * Try to find a weapon to wield. Wield_weap will return a + * projector if weapon is a projectile (eg. bow for arrow). + * If weapon is NULL, it will try to find a suitable weapon. + */ + get_wield = wield_weap(weapon, mp); + if (get_wield) wielded = OBJPTR(get_wield); + else wielded = NULL; + + /* If we aren't wielding a weapon, wield what we found (could be NULL) */ + if (weapon == NULL) weapon = wielded; + + if (roll_em(mp, &player, weapon, thrown, wielded, FALSE)) { + int death_type; /* From one of the effects of getting hit */ + + did_hit = TRUE; + + if (weapon != NULL && weapon->o_type == MISSILE && cur_relic[STONEBONES_AMULET]) { + hit(weapon, see_att, TRUE, mname, (char *)NULL, FALSE, thrown, terse); + msg("Your amulet absorbs the magic missile. "); + } + else { + hit(weapon, see_att, TRUE, mname, (char *)NULL, FALSE, thrown, terse); + dsrpt_player(); /* see if we disrupted some activity */ + if (pstats.s_hpt <= 0) + death(mp->t_index); /* Bye bye life ... */ + death_type = effect(mp, &player, weapon, thrown, see_att, TRUE); + if (death_type != 0) { + pstats.s_hpt = -1; + death(death_type); + } + } + + } + else { + /* If the thing was trying to surprise, no good */ + if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE); + + /* If it couldn't surprise, let's tell the player. */ + else miss(weapon, see_att, TRUE, mname, (char *)NULL, thrown, terse); + } + if (fight_flush) flushinp(); + count = 0; + status(FALSE); + return(did_hit); +} + +/* + * swing: + * returns true if the swing hits + */ + +swing(class, at_lvl, op_arm, wplus) +short class; +int at_lvl, op_arm, wplus; +{ + register int res = rnd(20)+1; + register int need; + + need = char_class[class].base - + char_class[class].factor * + ((min(at_lvl, char_class[class].max_lvl) - + char_class[class].offset)/char_class[class].range) + + (10 - op_arm); + if (need > 20 && need <= 25) need = 20; + + return (res+wplus >= need); +} + +/* + * roll_em: + * Roll several attacks + */ + +roll_em(att_er, def_er, weap, hurl, cur_weapon, back_stab) +struct thing *att_er, *def_er; +struct object *weap; +bool hurl; +struct object *cur_weapon; +bool back_stab; +{ + register struct stats *att, *def; + register char *cp = NULL; + register int ndice, nsides, nplus, def_arm; + char dmgbuf[20]; + bool did_hit = FALSE; + int prop_hplus, prop_dplus; + int vampiric_damage; + + /* Get statistics */ + att = &att_er->t_stats; + def = &def_er->t_stats; + + prop_hplus = prop_dplus = 0; + if (weap == NULL) { + /* + * monks damage grows with level + */ + if (att == &pstats && player.t_ctype == C_MONK) { + sprintf(dmgbuf, "%dd4", att->s_lvl/3+2); + cp = dmgbuf; + } + else + cp = att->s_dmg; + } + else if (weap->o_type == RELIC) { + switch (weap->o_which) { + case MUSTY_DAGGER: + if (player.t_ctype == C_THIEF) + cp = "4d8+2/4d8+2"; + else + cp = "4d8/4d8"; + when YEENOGHU_FLAIL: + cp = "4d8+3/paralyze/confuse"; + when HRUGGEK_MSTAR: + cp = "4d8+3"; + when AXE_AKLAD: + if (player.t_ctype == C_FIGHTER) { + if (hurl) + cp = "4d8+6/drain"; + else + cp = "4d8+4/drain"; + } + else { + if (hurl) + cp = "4d8+4/drain"; + else + cp = "4d8+2/drain"; + } + when MING_STAFF: + cp = "4d8+4"; + when ASMO_ROD: + cp = "4d8/4d8"; + when ORCUS_WAND: + cp = "4d8/destroy"; + } + } + else if (hurl) { + if ((weap->o_flags&ISMISL) && cur_weapon != NULL && + cur_weapon->o_which == weap->o_launch) + { + cp = weap->o_hurldmg; + prop_hplus = cur_weapon->o_hplus; + prop_dplus = cur_weapon->o_dplus; + } + else + cp = (weap->o_flags&ISMISL ? weap->o_damage : weap->o_hurldmg); + } + else { + cp = weap->o_damage; + /* + * Drain a staff of striking + */ + if(weap->o_type==STICK && weap->o_which==WS_HIT && weap->o_charges==0) + { + strcpy(weap->o_damage,"4d8"); + weap->o_hplus = weap->o_dplus = 0; + } + } + /* + * If defender is wearing a cloak of displacement -- no damage + * the first time. (unless its a hurled magic missile or the + * attacker is very smart and can see thru the illusion) + */ + if ((weap == NULL || weap->o_type != MISSILE) && + def == &pstats && + off(*att_er, MISSEDDISP) && + att->s_intel < 21 && + ((cur_misc[WEAR_CLOAK]!=NULL && + cur_misc[WEAR_CLOAK]->o_which==MM_DISP) || + cur_relic[EMORI_CLOAK])) { + turn_on(*att_er, MISSEDDISP); + if (cansee(att_er->t_pos.y, att_er->t_pos.x) && !invisible(att_er)) + msg("%s looks amazed! ", prname(monster_name(att_er), TRUE)); + return (FALSE); + } + if (on(*def_er, CARRYCLOAK) && + def != &pstats && + (weap == NULL || weap->o_type != MISSILE) && + off (*att_er, MISSEDDISP) && + pstats.s_intel < 21) { + turn_on(*att_er, MISSEDDISP); + msg("You feel amazed! "); + return(FALSE); + } + for (;;) + { + int damage; + int hplus = prop_hplus; + int dplus = prop_dplus; + + if (weap != NULL && weap->o_type == RELIC) { + switch (weap->o_which) { + case MUSTY_DAGGER: + if (att != &pstats || /* Not player or good stats */ + (str_compute() > 15 && dex_compute() > 15)) { + + hplus += 6; + dplus += 6; + + /* Give an additional strength and dex bonus */ + if (att == &pstats) { + hplus += str_plus(str_compute()) + + dext_plus(dex_compute()); + dplus += dext_plus(dex_compute()) + + add_dam(str_compute()); + } + else { + hplus += str_plus(att->s_str) + + dext_plus(att->s_dext); + dplus += dext_plus(att->s_dext) + + add_dam(att->s_str); + } + } + else { + hplus -= 3; + dplus -= 3; + } + when YEENOGHU_FLAIL: + case HRUGGEK_MSTAR: + hplus += 3; + dplus += 3; + when MING_STAFF: + hplus += 2; + dplus += 2; + when AXE_AKLAD: + hplus += 5; + dplus += 5; + } + } + else if (weap != NULL) { + hplus += weap->o_hplus; + dplus += weap->o_dplus; + } + + /* Is attacker weak? */ + if (on(*att_er, HASSTINK)) hplus -= 2; + + if (att == &pstats) /* Is the attacker the player? */ + { + hplus += hitweight(); /* adjust for encumberence */ + dplus += hung_dam(); /* adjust damage for hungry player */ + dplus += ring_value(R_ADDDAM); + } + if (back_stab || (weap && att != &pstats && on(*att_er, CANBSTAB))) + hplus += 4; /* add in pluses for backstabbing */ + + /* Get the damage */ + while (isspace(*cp)) cp++; + if (!isdigit(*cp)) { + if (strncmp(cp, "confuse", 7) == 0) ndice = CONF_DAMAGE; + else if (strncmp(cp, "paralyze", 8) == 0) ndice = PARAL_DAMAGE; + else if (strncmp(cp, "destroy", 6) == 0) ndice = DEST_DAMAGE; + else if (strncmp(cp, "drain", 5) == 0) ndice = DRAIN_DAMAGE; + else ndice = 0; + nsides = 0; + nplus = 0; + } + else { + char *oldcp; + + /* Get the number of damage dice */ + ndice = atoi(cp); + if ((cp = strchr(cp, 'd')) == NULL) + break; + + /* Skip the 'd' and get the number of sides per die */ + nsides = atoi(++cp); + + /* Check for an addition -- save old place in case none is found */ + oldcp = cp; + if ((cp = strchr(cp, '+')) != NULL) nplus = atoi(++cp); + else { + nplus = 0; + cp = oldcp; + } + } + + if (def == &pstats) { /* Monster attacks player */ + if (on(*att_er, NOMETAL)) + def_arm = ac_compute(TRUE) - dext_prot(dex_compute()); + else + def_arm = ac_compute(FALSE) - dext_prot(dex_compute()); + hplus += str_plus(att->s_str)+dext_plus(att->s_dext); + } + else if (att == &pstats) { /* Player attacks monster */ + def_arm = def->s_arm - dext_prot(def->s_dext); + if (player.t_ctype == C_MONK) /* no strength bonus for monk */ + if (weap == NULL) + hplus += att->s_lvl/5; /* monks hplus varies with level */ + else + hplus += str_plus(str_compute())+dext_plus(dex_compute()); + } + else { /* Monster attacks monster */ + def_arm = def->s_arm - dext_prot(def->s_dext); + hplus += str_plus(att->s_str)+dext_plus(att->s_dext); + } + + if (swing(att_er->t_ctype, att->s_lvl, def_arm, hplus)) { + register int proll; + + /* Take care of special effects */ + switch (ndice) { + case CONF_DAMAGE: + if (def == &pstats) { /* Monster attacks player */ + if (!save(VS_MAGIC, &player, 0) && off(player, ISCLEAR)) { + msg("You feel disoriented."); + if (find_slot(unconfuse)) + lengthen(unconfuse, HUHDURATION); + else + fuse(unconfuse, (VOID *)NULL, HUHDURATION, AFTER); + turn_on(player, ISHUH); + } + else msg("You feel dizzy, but it quickly passes."); + } + /* Player or monster hits monster */ + else if (!save(VS_MAGIC, def_er, 0) && off(*def_er, ISCLEAR)) { + if (att == &pstats) { + if (rnd(10) > 6) + msg("The artifact warms you with pleasure! "); + } + turn_on(*def_er, ISHUH); + } + did_hit = TRUE; + when PARAL_DAMAGE: + if (def == &pstats) { /* Monster attacks player */ + if (!save(VS_MAGIC, &player, 0) && off(player, CANINWALL)) { + msg("You stiffen up."); + player.t_no_move += movement(&player) * FREEZETIME; + player.t_action = A_FREEZE; + } + } + else if (!save(VS_MAGIC, def_er, 0)) { /* Player hits monster */ + if (att == &pstats) { + if (rnd(10) > 6) + msg("The artifact hums happily! "); + } + turn_off(*def_er, ISRUN); + turn_on(*def_er, ISHELD); + } + did_hit = TRUE; + when DEST_DAMAGE: + if (def == &pstats) { /* Monster attacks player */ + if (rnd(10) > 5) + msg("You feel a tug at your life force."); + if (!save(VS_MAGIC, &player, -4)) { + msg("The wand devours your soul! --More--"); + wait_for(' '); + def->s_hpt = -1; + death(D_RELIC); + } + } + /* Player hits monster */ + else if (!save(VS_MAGIC, def_er, -4)) { + if (att == &pstats) { + if (rnd(10) > 4) + msg("The artifact draws some energy."); + } + /* The player loses some major hit pts */ + att->s_hpt -= (att->s_hpt/5)+1; + if (att->s_hpt <= 0) { + msg("The wand has devoured your soul! --More--"); + wait_for(' '); + att->s_hpt = -1; + death(D_RELIC); + } + /* Kill the monster */ + def->s_hpt = 0; + } + did_hit = TRUE; + when DRAIN_DAMAGE: + if (def == &pstats) { /* Monster attacks player */ + if (!save(VS_MAGIC, &player, -4)) { + lower_level(att_er->t_index); + } + } + /* Player hits monster */ + else if (!save(VS_MAGIC, def_er, -4)) { + def->s_hpt -= roll(1, 8); + def->s_lvl--; + if (def->s_lvl <= 0) + def->s_hpt = 0; /* he's dead */ + if (att == &pstats) { + if (rnd(10) > 7) + msg("The artifact cackles with laughter! "); + } + } + did_hit = TRUE; + otherwise: + /* Heil's ankh always gives maximum damage */ + if (att == &pstats && cur_relic[HEIL_ANKH]) + proll = ndice * nsides; + else proll = roll(ndice, nsides); + + if (ndice + nsides > 0 && proll < 1) + debug("Damage for %dd%d came out %d.", + ndice, nsides, proll); + damage = dplus + proll + nplus; + if (att == &pstats) { + /* + * Monks do not get strength bonus on damage. Instead, + * if they are wielding a weapon, they get at extra + * 1/2 point per level of damage. + */ + if(player.t_ctype == C_MONK) { + /* Bonus does not apply for hands. */ + if (weap != NULL) damage += att->s_lvl / 2; + } + else + damage += add_dam(str_compute()); + } + else + damage += add_dam(att->s_str); + + /* Check for half damage monsters */ + if (on(*def_er, HALFDAMAGE)) damage /= 2; + + /* add in multipliers for backstabbing */ + if (back_stab || + (weap && att != &pstats && on(*att_er, CANBSTAB))) { + int mult = 2 + (att->s_lvl-1)/4; /* Normal multiplier */ + + if (mult > 5) + mult = 5; + if (weap && weap->o_type == RELIC && + weap->o_which == MUSTY_DAGGER) + mult++; + damage *= mult; + } + if (att == &pstats) { + if (cur_weapon && (cur_weapon->o_flags & ISPOISON)) { + cur_weapon->o_flags &= ~ISPOISON; + if (save(VS_POISON, def_er, -2)) + damage += def->s_hpt/4; + else + damage += def->s_hpt/2; + } + if (back_stab && player.t_ctype == C_ASSASSIN) + damage = def->s_hpt + 1; + } + /* Check for no-damage and division */ + if (on(*def_er, BLOWDIVIDE)) { + damage = 0; + creat_mons(def_er, def_er->t_index, FALSE); + if (cansee(unc(def_er->t_pos))) light(&hero); + } + /* check for immunity to metal -- RELICS are always bad */ + if (on(*def_er, NOMETAL) && weap != NULL && + weap->o_type != RELIC && weap->o_flags & ISMETAL) { + damage = 0; + } + if (weap != NULL && weap->o_type == MISSILE) { + if ((def == &pstats && cur_relic[STONEBONES_AMULET]) || + (att == &pstats && on(*def_er, CARRYBAMULET))) { + damage = 0; + } + } + def->s_hpt -= max(0, damage); /* Do the damage */ + did_hit = TRUE; + vampiric_damage = damage; + if (def->s_hpt < 0) /* only want REAL damage inflicted */ + vampiric_damage += def->s_hpt; + if (vampiric_damage < 0) + vampiric_damage = 0; + if (att == &pstats && ISWEARING(R_VAMPREGEN) && !hurl) { + if ((pstats.s_hpt += vampiric_damage/2) > max_stats.s_hpt) + pstats.s_hpt = max_stats.s_hpt; + } + if (hplus < 0) hplus = 0; + if (damage < 0) damage = 0; + debug ("hplus=%d dmg=%d", hplus, damage); + } + } + if ((cp = strchr(cp, '/')) == NULL) + break; + cp++; + } + return did_hit; +} + +/* + * prname: + * The print name of a combatant + */ + +char * +prname(who, upper) +register char *who; +bool upper; +{ + static char tbuf[LINELEN]; + + *tbuf = '\0'; + if (who == 0) + strcpy(tbuf, "you"); + else if (on(player, ISBLIND) || strcmp(who, "something") == 0) + strcpy(tbuf, "something"); + else + { + /* If we have a name (starts with a capital), don't use a "the" */ + if (islower(*who)) strcpy(tbuf, "the "); + strcat(tbuf, who); + } + if (upper) + *tbuf = toupper(*tbuf); + return tbuf; +} + +/* + * hit: + * Print a message to indicate a succesful hit + */ + +hit(weapon, see_att, see_def, er, ee, back_stab, thrown, short_msg) +register struct object *weapon; +bool see_att, see_def; +register char *er, *ee; +bool back_stab, thrown, short_msg; +{ + register char *s = NULL; + char att_name[LINELEN], /* Name of attacker */ + def_name[LINELEN]; /* Name of defender */ + + /* If we can't see either the attacker or defender, don't say anything */ + if (!see_att && !see_def) return; + + /* What do we call the attacker? */ + strcpy(att_name, see_att ? prname(er, TRUE) : "Something"); + if (er) { /* A monster is attacking */ + + /* If the monster is using a weapon and we can see it, report it */ + if (weapon != NULL && (see_att || thrown)) { + strcat(att_name, "'s "); + strcat(att_name, weap_name(weapon)); + } + } + + /* What do we call the defender? */ + strcpy(def_name, see_def ? prname(ee, FALSE) : "something"); + + addmsg(att_name); + if (short_msg) { + if (back_stab) { + if (player.t_ctype == C_ASSASSIN) + s = (er == 0 ? " assassinate!" : " assassinates!"); + else + s = (er == 0 ? " backstab!" : " backstabs!"); + } + else + s = " hit."; + } + else { + if (back_stab) { + if (player.t_ctype == C_ASSASSIN) + s = (er == 0 ? " have assassinated " : " has assassinated "); + else + s = (er == 0 ? " have backstabbed " : " has backstabbed "); + } + else { + switch (rnd(thrown ? 2 : 3)) + { + case 0: s = " hit "; + when 1: s = " injured "; + when 2: s = " smacked "; + } + } + } + if (short_msg) addmsg(s); + else addmsg("%s%s.", s, def_name); + endmsg(); +} + +/* + * miss: + * Print a message to indicate a poor swing + */ + +miss(weapon, see_att, see_def, er, ee, thrown, short_msg) +register struct object *weapon; +bool see_att, see_def; +register char *er, *ee; +bool thrown, short_msg; +{ + register char *s = NULL; + char att_name[LINELEN], /* Name of attacker */ + def_name[LINELEN]; /* Name of defender */ + + /* If we can't see either the attacker or defender, don't say anything */ + if (!see_att && !see_def) return; + + /* What do we call the attacker? */ + strcpy(att_name, see_att ? prname(er, TRUE) : "Something"); + if (er) { /* A monster is attacking */ + + /* If the monster is using a weapon and we can see it, report it */ + if (weapon != NULL && (see_att || thrown)) { + strcat(att_name, "'s "); + strcat(att_name, weap_name(weapon)); + } + } + + /* What do we call the defender? */ + strcpy(def_name, see_def ? prname(ee, FALSE) : "something"); + + addmsg(att_name); + switch (short_msg ? 0 : rnd(thrown ? 3 : 2)) + { + case 0: s = (er == 0 ? " miss" : " misses"); + when 1: s = (er == 0 ? " don't hit" : " doesn't hit"); + when 2: s = (" whizzes by"); + } + if (short_msg) addmsg("%s.", s); + else addmsg("%s %s.", s, def_name); + endmsg(); +} + +/* + * dext_plus: + * compute to-hit bonus for dexterity + */ + +dext_plus(dexterity) +register int dexterity; +{ + return (dexterity > 10 ? (dexterity-13)/3 : (dexterity-10)/3); +} + + +/* + * dext_prot: + * compute armor class bonus for dexterity + */ + +dext_prot(dexterity) +register int dexterity; +{ + return ((dexterity-10)/2); +} + +/* + * str_plus: + * compute bonus/penalties for strength on the "to hit" roll + */ + +str_plus(str) +register short str; +{ + return((str-10)/3); +} + +/* + * add_dam: + * compute additional damage done for exceptionally high or low strength + */ + +add_dam(str) +register short str; +{ + return((str-9)/2); +} + +/* + * hung_dam: + * Calculate damage depending on players hungry state + */ + +hung_dam() +{ + reg int howmuch = 0; + + switch(hungry_state) { + case F_SATIATED: + case F_OKAY: + case F_HUNGRY: howmuch = 0; + when F_WEAK: howmuch = -1; + when F_FAINT: howmuch = -2; + } + return howmuch; +} + +/* + * is_magic: + * Returns true if an object radiates magic + */ + +is_magic(obj) +register struct object *obj; +{ + switch (obj->o_type) + { + case ARMOR: + return obj->o_ac != armors[obj->o_which].a_class; + when WEAPON: + return obj->o_hplus != 0 || obj->o_dplus != 0; + when POTION: + case SCROLL: + case STICK: + case RING: + case MM: + case RELIC: + return TRUE; + } + return FALSE; +} + +/* + * killed: + * Called to put a monster to death + */ + +killed(item, pr, points, treasure) +register struct linked_list *item; +bool pr, points, treasure; +{ + register struct thing *tp, *mp; + register struct linked_list *pitem, *nexti, *mitem; + char *monst; + int adj; /* used for hit point adj. below. */ + long temp; + + tp = THINGPTR(item); + + if (pr) + { + addmsg(terse ? "Defeated " : "You have defeated "); + if (on(player, ISBLIND)) + msg("it."); + else + { + if (cansee(tp->t_pos.y, tp->t_pos.x) && !invisible(tp)) + monst = monster_name(tp); + else { + if (terse) monst = "something"; + else monst = "thing"; + } + if (!terse) + addmsg("the "); + msg("%s.", monst); + } + } + + /* Take care of any residual effects of the monster */ + check_residue(tp); + + /* Make sure that no one is still chasing us */ + for (mitem = mlist; mitem != NULL; mitem = next(mitem)) { + mp = THINGPTR(mitem); + if (mp->t_dest == &tp->t_pos) { + mp->t_dest = &hero; + mp->t_wasshot = FALSE; + turn_off(*mp, ISFLEE); /* Be sure we aren't running away! */ + } + } + if (points) { /* you feel uneasy for a moment */ + if ((off(*tp, ISMEAN) || on(*tp, ISFRIENDLY)) && + (player.t_ctype == C_RANGER || player.t_ctype == C_PALADIN || + player.t_ctype == C_MONK)) { + if (tp->t_stats.s_exp > pstats.s_exp) + pstats.s_exp = 0; + else + pstats.s_exp -= tp->t_stats.s_exp; + /* Take care of hit points. */ + if (level <= 12) adj = rnd(2)+1; + else if (level <= 25) adj = rnd(3)+2; + else if (level <= 50) adj = rnd(4)+3; + else if (level <= 80) adj = rnd(5)+4; + else adj = rnd(6)+5; + /* adjust hit points */ + max_stats.s_hpt -= adj; + pstats.s_hpt -= adj; + /* Are hit points now too low? */ + if (pstats.s_hpt <= 0) { + pstats.s_hpt = -1; + death(D_STRENGTH); + } + killed_chance += rnd(3)+1; + if (on(*tp, ISUNIQUE)) /* real bad news to kill a diety */ + killed_chance += 25; + if (roll(1,100) < killed_chance) { + msg("You had a feeling this was going to happen... "); + msg("**POOF** "); + temp = C_ASSASSIN; /* make him pay */ + changeclass(&temp); + } + else { + switch (rnd(9)) { + case 0: + msg("You become solid and stiff for a while. "); + player.t_no_move += (5*movement(&player)*FREEZETIME); + player.t_action = A_FREEZE; + when 1: + msg("You collapse, losing it totally. "); + player.t_no_move += (2*movement(&player)*FREEZETIME); + player.t_action = A_FREEZE; + when 2: + msg("Your face changes shape! ARGGHH!!!! "); + pstats.s_charisma -= rnd(8)+3; + if (pstats.s_charisma <= 3) pstats.s_charisma = 3; + when 3: + case 4: + msg("You cry out, I didn't mean to do that! Honest!! "); + player.t_no_move += (movement(&player)*FREEZETIME); + msg("The Great Old Ones grant you a reprieve. "); + otherwise: msg("You feel uneasy for a moment.. "); + } + } + } + else { + unsigned long test; /* For overflow check */ + /* + * Do an overflow check before increasing experience + */ + test = pstats.s_exp + tp->t_stats.s_exp; + if (test > pstats.s_exp) + pstats.s_exp = test; + } + + /* + * Do adjustments if he went up a level + */ + check_level(); + } + + /* + * Empty the monsters pack + */ + pitem = tp->t_pack; + + /* + * Get rid of the monster. + */ + mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); + mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch); + detach(mlist, item); + if (on(*tp, AREMANY) && levtype == NORMLEV) /* AREMANYs stick together */ + wake_room(roomin(&tp->t_pos)); + /* + * empty his pack + */ + while (pitem != NULL) + { + nexti = next(pitem); + (OBJPTR(pitem))->o_pos = tp->t_pos; + detach(tp->t_pack, pitem); + if (treasure) + fall(pitem, FALSE); + else + o_discard(pitem); + pitem = nexti; + } + + turn_on(*tp,ISDEAD); + attach(rlist,item); +} + +/* + * Returns a pointer to the weapon the monster is wielding corresponding to + * the given thrown weapon. If no thrown item is given, try to find any + * decent weapon. + */ + +struct linked_list * +wield_weap(thrown, mp) +struct object *thrown; +struct thing *mp; +{ + int look_for = 0, /* The projectile weapon we are looking for */ + new_rate, /* The rating of a prospective weapon */ + cand_rate = -1; /* Rating of current candidate -- higher is better */ + register struct linked_list *pitem, *candidate = NULL; + register struct object *obj; + + if (thrown != NULL) { /* Using a projectile weapon */ + switch (thrown->o_which) { + case BOLT: look_for = CROSSBOW; /* Find the crossbow */ + when ARROW: look_for = BOW; /* Find the bow */ + when ROCK: look_for = SLING; /* find the sling */ + otherwise: return(NULL); + } + } + else if (off(*mp, ISUNIQUE) && off(*mp, CARRYWEAPON)) return(NULL); + + for (pitem=mp->t_pack; pitem; pitem=next(pitem)) { + obj = OBJPTR(pitem); + + /* + * If we have a thrown weapon, just return the first match + * we come to. + */ + if (thrown != NULL && obj->o_type == WEAPON && obj->o_which == look_for) + return(pitem); + + /* If we have a usable RELIC, return it */ + if (thrown == NULL && obj->o_type == RELIC) { + switch (obj->o_which) { + case MUSTY_DAGGER: + case YEENOGHU_FLAIL: + case HRUGGEK_MSTAR: + case AXE_AKLAD: + case MING_STAFF: + case ASMO_ROD: + case ORCUS_WAND: + return(pitem); + } + } + + /* Otherwise if it's a usable weapon, it is a good candidate */ + else if (thrown == NULL && obj->o_type == WEAPON) { + switch (obj->o_which) { + case DAGGER: + case SPEAR: + new_rate = 0; + when BATTLEAXE: + new_rate = 1; + when MACE: + new_rate = 2; + when SWORD: + new_rate = 3; + when PIKE: + new_rate = 4; + when HALBERD: + case SPETUM: + new_rate = 6; + when BARDICHE: + new_rate = 7; + when TRIDENT: + new_rate = 8; + when BASWORD: + new_rate = 9; + when TWOSWORD: + new_rate = 10; + otherwise: + new_rate = -1; + } + + /* Only switch if this is better than the current candidate */ + if (new_rate > cand_rate) { + cand_rate = new_rate; + candidate = pitem; + } + } + } + + return(candidate); +} +explode(tp) +register struct thing *tp; +{ + + register int x,y, damage; + struct linked_list *item; + struct thing *th; + + /* + * check to see if it got the hero + */ + if (off(player, ISINWALL) && + DISTANCE(hero.x, hero.y, tp->t_pos.x, tp->t_pos.y) <= 25) { + msg("The explosion hits you! "); + damage = roll(6,6); + if (save(VS_WAND, &player, 0)) + damage /= 2; + pstats.s_hpt -= damage; + } + + /* + * now check for monsters in vicinity + */ + for (x = tp->t_pos.x-5; x<=tp->t_pos.x+5; x++) { + if (x < 0 || x > cols - 1) + continue; + for (y = tp->t_pos.y-5; y<=tp->t_pos.y+5; y++) { + if (y < 1 || y > lines - 3) + continue; + if (isalpha(mvwinch(mw, y, x))) { + if ((item = find_mons(y, x)) != NULL) { + th = THINGPTR(item); + if (th == tp || /* don't count gas spore */ + on(*th, ISINWALL)) /* Don't count monsters in wall */ + continue; + damage = roll(6, 6); + if (save(VS_WAND, th, 0)) + damage /= 2; + runto(th, &hero); + if ((th->t_stats.s_hpt -= damage) <= 0) { + msg("The explosion kills %s! ", + prname(monster_name(th), FALSE)); + killed(item, FALSE, FALSE, TRUE); + } + } + } + } + } +} + +/* + * skirmish: + * Called when one monster attacks another monster. + */ + +skirmish(attacker, mp, weap, thrown) +register struct thing *attacker; +register coord *mp; +struct object *weap; +bool thrown; +{ + register struct thing *defender; + register struct linked_list *item; + register bool did_hit = TRUE, see_att, see_def; + char attname[LINELEN+1], defname[LINELEN+1]; + struct object *wielded; /* The wielded weapon */ + struct linked_list *get_wield; /* Linked list header for wielded */ + + /* + * Find the monster we want to fight + */ + if ((item = find_mons(mp->y, mp->x)) == NULL) { + return(FALSE); /* must have killed him already */ + } + defender = THINGPTR(item); + + /* Can the player see either of the fighters? */ + see_att = (cansee(unc(attacker->t_pos)) && + (off(*attacker, ISINVIS) || on(player, CANSEE)) && + (off(*attacker, ISSHADOW) || on(player, CANSEE))); + see_def = (cansee(unc(defender->t_pos)) && + (off(*defender, ISINVIS) || on(player, CANSEE)) && + (off(*defender, ISSHADOW) || on(player, CANSEE))); + + /* + * Since we are fighting, things are not quiet so no healing takes + * place. The -1 also tells us that we are in a fight. + */ + attacker->t_quiet = -1; + defender->t_quiet = -1; + + if (see_att) strcpy(attname, monster_name(attacker)); + else strcpy(attname, "something"); + + if (see_def) strcpy(defname, monster_name(defender)); + else strcpy(defname, "something"); + + /* + * if its in the wall, we can't hit it + */ + if (on(*defender, ISINWALL) && off(*attacker, CANINWALL)) + return(FALSE); + + if (on(*defender, ISSTONE)) { + killed(item, FALSE, FALSE, FALSE); + if (see_def) + msg("%s shatters into a million pieces!", prname(defname, TRUE)); + return (TRUE); + } + + /* + * Let him know it was really a mimic (if it was one). + */ + if (see_def && on(*defender, ISDISGUISE) && + (defender->t_type != defender->t_disguise)) { + msg("Wait! There's a %s!", defname); + turn_off(*defender, ISDISGUISE); + did_hit = thrown; + } + + if (see_def && on(*defender, CANSURPRISE) && !ISWEARING(R_ALERT)) { + msg("Wait! There's a %s!", defname); + turn_off(*defender, CANSURPRISE); + did_hit = thrown; + } + + if (did_hit) { + + did_hit = FALSE; + + /* + * Try to find a weapon to wield. Wield_weap will return a + * projector if weapon is a projectile (eg. bow for arrow). + * If weapon is NULL, it will try to find a suitable weapon. + */ + get_wield = wield_weap(weap, attacker); + if (get_wield) wielded = OBJPTR(get_wield); + else wielded = NULL; + +#ifdef DOBLINK + /* + * For now Blink Dogs will not blink away from monsters. We + * have to fix can_blink so it isn't dependant on the player + * before we can add it. + */ + if (!can_blink(defender) && +#endif + if (((weap && weap->o_type == RELIC) || + ((off(*defender, MAGICHIT) || + attacker->t_stats.s_lvl > 4 || + (weap && (weap->o_hplus > 0 || weap->o_dplus > 0))) && + (off(*defender, BMAGICHIT) || + attacker->t_stats.s_lvl > 6 || + (weap && (weap->o_hplus > 1 || weap->o_dplus > 1))) && + (off(*defender, CMAGICHIT) || + attacker->t_stats.s_lvl > 8 || + (weap && (weap->o_hplus > 2 || weap->o_dplus > 2))))) + && roll_em(attacker, defender, weap, thrown, wielded, FALSE)) + { + did_hit = TRUE; + + /* Should we start to chase this creature? */ + if (attacker->t_index != defender->t_index && + (off(*defender, ISRUN) || rnd(100) < 50)) { + /* + * If we're intelligent enough to realize that this + * is a friendly monster, we will attack the hero instead. + */ + if (on(*attacker, ISFRIENDLY) && + roll(3,6) < defender->t_stats.s_intel) { + runto(defender, &hero); + debug("%s attacking %s's hero", defname, attname); + } + + /* Otherwise, let's chase the monster */ + else { + runto(defender, &attacker->t_pos); + debug("%s now attacking %s", defname, attname); + } + } + else if (off(*defender, ISRUN)) runto(defender, &hero); + + /* Let the defender know that the attacker has missiles! */ + if ((defender->t_dest == &attacker->t_pos) && thrown) + defender->t_wasshot = TRUE; + + if (on(*defender, NOMETAL) && weap != NULL && + weap->o_type != RELIC && weap->o_flags & ISMETAL) { + if (see_def && see_att) + msg("The %s passes right through %s!", + weaps[weap->o_which].w_name, prname(defname, FALSE)); + } + else { + hit(weap, see_att, see_def, + attname, defname, FALSE, thrown, FALSE); + } + + /* See if there are any special effects */ + if (effect(attacker, defender, + weap, thrown, see_att, see_def) != 0) { + killed(item, FALSE, FALSE, TRUE); + if (see_def) msg("%s dies.", prname(defname, TRUE)); + else msg("You hear a blood-curdling scream! "); + } + + /* + * Merchants just disappear if hit + */ + else if (on(*defender, CANSELL)) { + if (see_def) + msg("%s disappears with his wares in a flash! ", + prname(defname, TRUE)); + killed(item, FALSE, FALSE, FALSE); + } + + else if (defender->t_stats.s_hpt <= 0) { + killed(item, FALSE, FALSE, TRUE); + if (see_def) msg("%s dies.", prname(defname, TRUE)); + else msg("You hear a blood-curdling scream! "); + } + + else { + /* Did we disrupt a spell? */ + /* Don't turn on WASDISRUPTED since player didn't do it */ + if (defender->t_action == A_SUMMON || + defender->t_action == A_MISSILE) { + /* Just make the old fellow start over again */ + defender->t_action = A_NIL; + defender->t_no_move = movement(defender); + defender->t_using = NULL; + + if (see_def) + msg("%s was disrupted.", prname(defname, TRUE)); + } + +#ifdef FLEEMONST + /* + * If the monster is fairly intelligent and about to die, + * it may turn tail and run. + */ + if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/10)) && + (rnd(21) < tp->t_stats.s_intel)) { + turn_on(*tp, ISFLEE); + + /* If monster was suffocating, stop it */ + if (on(*tp, DIDSUFFOCATE)) { + turn_off(*tp, DIDSUFFOCATE); + extinguish(suffocate); + } + + /* If monster held us, stop it */ + if (on(*tp, DIDHOLD) && (--hold_count == 0)) + turn_off(player, ISHELD); + turn_off(*tp, DIDHOLD); + + /* It is okay to turn tail */ + tp->t_oldpos = tp->t_pos; + } +#endif + } + } + else { + /* If the thing was trying to surprise, no good */ + if (on(*attacker, CANSURPRISE)) { + /* If we can't see it, it keeps surprise (from us) */ + if (see_att) turn_off(*attacker, CANSURPRISE); + } + + miss(weap, see_att, see_def, attname, defname, thrown, FALSE); + } + } + return did_hit; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/help.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,651 @@ +/* + help.c - Routines having to do with help + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include "mach_dep.h" +#include "rogue.h" + +/* + * Give character descripts + */ + +static char *game_fighter = "Strength is the main attribute of the Fighter. \ +He can wield any weapon and the two-handed sword is his weapon of choice. He \ +can also wear any type of armor. Plate armor being the best choice and \ +leather armor the worst. The Fighter is able to sense both traps and gold \ +at higher experience levels. His natural quest item is the Axe of Aklad. \ +Due to his superior form, the Fighter usually receives more hit-points per \ +new experience level than the other characters. The Fighter is neither good \ +or evil; he is a neutral character. The default attribute values of the \ +Fighter are: Int=7, Str=16, Wis=7, Dxt=16, Con=17, and Chr=11. Default gold \ +amount is 2000 pieces and default hit-points are 24."; + +static char *game_thief = "Dexterity is the main attribute of the Thief. His \ +stealth allows him to move quietly, thus disturbing less monsters. He can \ +sense traps and gold and can take (steal) things from the monsters. The \ +Thief can not wield the two-handed sword so the bastard sword is his weapon \ +of choice. He can only wear studded leather armor. The Thief's natural \ +quest item is the Daggers of Musty Doit. With higher dexterity the Thief \ +is able to \"backstab\" monsters, thereby killing them with a single blow. \ +His character type fluctuates between that of good, neutral, and evil. The \ +default attribute values of the Thief are: Int=7, Str=14, Wis=7, Dxt=18, \ +Con=17, and Chr=11. Default gold amount is 2000 pieces and default \ +hit-points are 23."; + +static char *game_assassin = "Dexterity is the main attribute of the \ +Assassin. Like the Thief, he moves with an extra degree of stealth. He can \ +sense gold and steal things from monsters. The ability to sense traps comes \ +at higher experience levels. The Assassin can not wield the two-handed sword \ +and he can only wear studded leather armor. The natural quest item of the \ +Assassin is the Eye of Vecna. He is also skilled in the use of poison. \ +Higher dexterity enables him to \"assassinate\" monsters with a single blow. \ +The Assassin is aligned with the powers of evil. The default attribute \ +values of the Assassin are: Int=7, Str=14, Wis=7, Dxt=18, Con=17, and \ +Chr=11. Default gold amount is 2000 pieces and default hit-points are 23."; + +static char *game_ranger = "Charisma is the main attribute of the Ranger who \ +also has a secondary attribute of Intelligence. Like the Magician, this \ +gives him the ability to cast spells which increases as he attains higher \ +experience levels. Like the Fighter, he can wield any weapon and wear any \ +armor. The Ranger's natural quest item is the Mandolin of Brian. He is \ +aligned with the powers of good. Therefore, he can be made to suffer and \ +even become cursed by the very powers that allow him to cast spells if he \ +happens to cause the demise of a likewise good creature. The default \ +attribute values of the Ranger are: Int=11, Str=11, Wis=7, Dxt=16, Con=16, \ +and Chr=13. Default gold amount is 2000 pieces and default hit-points \ +are 22."; + +static char *game_paladin = "Charisma is the main attribute of the Paladin \ +who has a secondary attribute of Wisdom. Like the Cleric, this gives him \ +the ability to offer prayers, receive what his heart desires, and an ability \ +to turn the undead. This ability will increase as he gains higher \ +experience levels. Like the Fighter, he can wield any weapon and wear any \ +armor. The Ankh of Heil is the Paladin's natural quest item. Like the \ +Ranger, the Paladin is aligned with the powers of good. This can cause \ +him to suffer and become cursed if he brings ruin to a likewise good \ +creature. The default attribute values of the Paladin are: Int=7, \ +Str=11, Wis=11, Dxt=16, Con=16, and Chr=13. Default gold amount is \ +2000 pieces and default hit-points are 22."; + +static char *game_druid = "Wisdom is the main attribute of the Druid. This \ +gives him the ability to chant secret words and mantras, which is much \ +greater than that of the Monk. The Druid can not wield the two-handed or \ +bastard swords but he can wear any armor. His natural quest item is the Quill \ +of Nagrom. Like the Magician and Cleric, the Druid is aligned neutral. He \ +therefore, must rely upon his Wisdom and his chanting ability in order to \ +remain alive. Likewise, he does not receive as many new hit-points per \ +new experience level. The default attribute values of the Druid are: Int=7, \ +Str=10, Wis=14, Dxt=16, Con=15, and Chr=12. Default gold amount is 2000 \ +pieces and default hit-points are 21."; + +static char *game_monk = "Constitution is the main attribute of the Monk who \ +has a secondary aspect of Wisdom. Like the Druid, this gives him the \ +ability to chant mantras which will increase as he gains higher experience. \ +The Monk can not wield the two-handed sword and he can not wear any armor. \ +The Cloak of Emori is the Monk's natural quest item. The Monk can also \ +sense traps, though much less than the Thief or Assassin. He is the most \ +healthy character. Like the Ranger and Paladin, he is aligned with the \ +powers of good. Therefore, he is made to suffer and can become cursed if \ +he kills a likewise good creature. The default attribute values of the \ +Monk are: Int=7, Str=11, Wis=11, Dxt=16, Con=18, and Chr=11. Default \ +gold amount is 2000 pieces and default hit-points are 22."; + +static char *game_magician = "Intelligence is the main attribute of the \ +Magician. The Magician's ability to cast spells is much greater than that \ +of the Ranger. He can not wield the two- handed or bastard swords, but he \ +can wear any kind of armor. His natural quest item is the Amulet of \ +Stonebones. The Magician is aligned neutral. He must rely upon his \ +Intelligence and spell casting abilities to remain alive. There- fore, he \ +does not receive as many new hit-points per new experience level. The \ +default attribute values of the Magician are: Int=14, Str=10, Wis=7, \ +Dxt=16, Con=15, and Chr=12. Default gold amount is 2000 pieces and \ +default hit-points are 21."; + +static char *game_cleric = "Wisdom is the main attribute of the Cleric. The \ +Cleric's ability to give or offer prayers, receive their due, and affect \ +the undead are much greater than that of the Paladin. Like the Magician, \ +the Cleric can not wield the two- handed or bastard swords, but he can \ +wear any armor. His natural quest item is the Horn of Geryon. The Cleric \ +is aligned neutral and he must rely upon his Wisdom and prayer ability to \ +remain alive. He therefore, does not receive as many new hit-points per \ +new experience level. The default attribute values of the Cleric are: Int=7, \ +Str=10, Wis=14, Dxt=16, Con=15, and Chr=12. The default gold amount is 2000 \ +pieces and default hit-points are 21."; + + +static char *game_food ="There are three types of food, regular food rations, \ +various fruits, and slime- molds. Eating regular food will add 750 points to \ +your current food level [see the CTRL(E) command]. Eating fruit adds \ +300 points. Certain fruits also cure you, add an attribute point, add a \ +hit-point, increase your armor, give you additional prayer, chant, or spell \ +casting abilities, or add experience points. Eating slime-mold (monster \ +food) can make you ill, but they will add 100 points to your current food \ +level. If your food level points drop below 100 you will become weak. You \ +will faint and might die if they drop to 0 or below. At the other extreme, \ +if your food level points reach 2000 (and above) you will become satiated. \ +Risk eating more and you could choke to death."; + +/* +static char *game_monst ="To be updated."; +static char *game_potion ="To be updated..."; +static char *game_scroll ="To be updated..."; +static char *game_ring ="To be updated..."; +static char *game_stick ="To be updated..."; +static char *game_weapon ="To be updated..."; +static char *game_armor ="To be updated..."; +static char *game_miscm ="To be updated..."; +static char *game_qitems ="To be updated..."; +static char *game_dungeon ="To be updated..."; +static char *game_traps ="To be updated..."; +static char *game_mazes ="To be updated..."; +static char *game_option ="To be updated..."; +static char *game_begin ="To be updated..."; +*/ + +/* help list */ +static struct h_list helpstr[] = { + '?', " Print help", + '/', " Identify object", + '=', " Identify a screen character", + ' ', "", + 'h', " Move left", + 'j', " Move down", + 'k', " Move up", + 'l', " Move right", + 'y', " Move up and left", + 'u', " Move up and right", + 'b', " Move down and left", + 'n', " Move down and right", + 'H', " Run left", + 'J', " Run down", + 'K', " Run up", + 'L', " Run right", + 'Y', " Run up & left", + 'U', " Run up & right", + 'B', " Run down & left", + 'N', " Run down & right", + ' ', "", + '>', " Go down a staircase", + '<', " Go up a staircase", + '\\', " Game descriptions", + '.', " Rest for a while", + '*', " Count gold pieces", + 'a', " Affect the undead", + 'A', " Choose artifact (equipage)", + 'c', " Chant a mantra", + 'C', " Cast a spell", + 'd', " Drop something", + 'D', " Dip something (into a pool)", + 'e', " Eat food or fruit", + 'f', "<dir> Forward until find something", + 'F', " Frighten a monster", + 'g', " Give food to monster", + 'G', " Sense for gold", + 'i', " Inventory", + 'I', " Inventory (single item)", + 'm', " Mark an object (specific)", + 'o', " Examine and/or set options", + 'O', " Character type and quest item", + 'p', " Pray to the powers that be", + 'P', " Pick up object(s)", + 'q', " Quaff a potion", + 'Q', " Quit the game", + 'r', " Read a scroll", + 's', " Search for a trap/secret door", + 'S', " Save your game", + 't', "<dir> Throw something", + 'T', " Take off something", + 'v', " Print program version", + 'w', " Wield a weapon", + 'W', " Wear something", + 'X', " Sense for traps", + 'z', "<dir> Zap a wand or staff", + ' ', "", + '^', " Set a trap", + '$', " Price an item (trading post)", + '#', " Buy an item (trading post)", + '%', " Sell an item (trading post)", + '!', " Shell escape", + ESC, " Cancel command (Esc)", + ' ', "", + CTRL('B'), " Current score (if you win)", + CTRL('E'), " Current food level", + CTRL('L'), " Redraw the screen", + CTRL('N'), " Name an object or a monster", + CTRL('O'), " Character affect status", + CTRL('R'), " Repeat last message", + CTRL('T'), "<dir> Take (steal) from (direction)", + CTRL('U'), " Use a magic item", + 0, 0 +} ; + +/* wizard help list */ +static struct h_list wiz_help[] = { + ' ', "", + '+', " Random fortunes", + 'M', " Make an object", + 'V', " Display vlevel and turns", + CTRL('A'), " System activity", + CTRL('C'), " Move to another dungeon level", + CTRL('D'), " Go down 1 dungeon level", + CTRL('F'), " Display the entire level", + CTRL('G'), " Charge wands and staffs", + CTRL('H'), " Jump 9 experience levels", + CTRL('I'), " Inventory of level", + CTRL('J'), " Teleport somewhere", + CTRL('K'), " Identify an object", + CTRL('M'), " Recharge wand or staff", + CTRL('P'), " Toggle wizard status", + CTRL('X'), " Detect monsters", + CTRL('Y'), " Display food levels", + 0, 0 +}; + +/* item help list */ +static struct item_list item_help[] = { + '@', " You (visible)", + '_', " You (invisible)", + ' ', "", + ':', " Food ration or fruit (eat)", + '!', " Potion (quaff)", + '?', " Scroll (read)", + '=', " Ring (wear)", + ')', " Weapon (wield)", + ']', " Armor (wear)", + '/', " Wand or staff (zap)", + ';', " Magic item (use)", + ',', " Artifact (quest item)", + '*', " Gold or zapped missile", + ' ', "", + '$', " Magical item in room", + '>', " Blessed magical item", + '<', " Cursed magical item", + ' ', " ", + '`', " Dart trap", + '{', " Arrow trap", + '}', " Bear trap", + '~', " Teleport trap", + '$', " Sleeping gas trap", + '>', " Trap door", + '<', " Outer region entrance", + '\'', " Maze entrance", + '^', " Trading post entrance", + '"', " Magic pool or lake", + ' ', " Solid rock or mountain", + '.', " Floor of a room or meadow", + '%', " Stairs (up or down)", + '+', " Doorway", + '&', " Secret doorway", + '#', " Passage between rooms", + '\\', " Forest", + HORZWALL, " Horizontal wall of a room", + VERTWALL, " Vertical wall of a room", + 0, 0 +}; + +ident_hero() +{ + bool doit = TRUE; + + wclear(hw); + wprintw(hw, "Characters, Items, and Game Descriptions:\n"); + wprintw(hw, "-----------------------------------------\n"); + wprintw(hw, "a) Fighter m) Scrolls\n"); + wprintw(hw, "b) Thief n) Rings\n"); + wprintw(hw, "c) Assassin o) Wands and Staffs\n"); + wprintw(hw, "d) Ranger p) Weapons\n"); + wprintw(hw, "e) Paladin q) Armors\n"); + wprintw(hw, "f) Monk r) Miscellaneous Magic Items\n"); + wprintw(hw, "g) Magician s) Quest Items (Artifacts and Relics)\n"); + wprintw(hw, "h) Cleric t) The Dungeon\n"); + wprintw(hw, "i) Druid u) Traps\n"); + wprintw(hw, "j) Monsters v) Mazes and Outer Regions\n"); + wprintw(hw, "k) Foods w) Setting game options\n"); + wprintw(hw, "l) Potions x) Starting out\n"); + wprintw(hw, "\nEnter a letter: "); + draw(hw); + while (doit) { + switch (wgetch(cw)) { + case EOF: + case ESC: + doit = FALSE; + when 'a': + wclear(hw); + wprintw(hw, "Fighter Characteristics:"); + mvwaddstr(hw, 2, 0, game_fighter); + draw(hw); + doit = FALSE; + when 'b': + wclear(hw); + wprintw(hw, "Thief Characteristics:"); + mvwaddstr(hw, 2, 0, game_thief); + draw(hw); + doit = FALSE; + when 'c': + wclear(hw); + wprintw(hw, "Assassin Characteristics:"); + mvwaddstr(hw, 2, 0, game_assassin); + draw(hw); + doit = FALSE; + when 'd': + wclear(hw); + wprintw(hw, "Ranger Characteristics:"); + mvwaddstr(hw, 2, 0, game_ranger); + draw(hw); + doit = FALSE; + when 'e': + wclear(hw); + wprintw(hw, "Paladin Characteristics:"); + mvwaddstr(hw, 2, 0, game_paladin); + draw(hw); + doit = FALSE; + when 'f': + wclear(hw); + wprintw(hw, "Monk Characteristics:"); + mvwaddstr(hw, 2, 0, game_monk); + draw(hw); + doit = FALSE; + when 'g': + wclear(hw); + wprintw(hw, "Magician Characteristics:"); + mvwaddstr(hw, 2, 0, game_magician); + draw(hw); + doit = FALSE; + when 'h': + wclear(hw); + wprintw(hw, "Cleric Characteristics:"); + mvwaddstr(hw, 2, 0, game_cleric); + draw(hw); + doit = FALSE; + when 'i': + wclear(hw); + wprintw(hw, "Druid Characteristics:"); + mvwaddstr(hw, 2, 0, game_druid); + draw(hw); + doit = FALSE; + when 'j': + wclear(hw); + wprintw(hw, "Monster Characteristics:"); + draw(hw); + doit = FALSE; + when 'k': + wclear(hw); + wprintw(hw, "Foods:"); + mvwaddstr(hw, 2, 0, game_food); + draw(hw); + doit = FALSE; + when 'l': + wclear(hw); + wprintw(hw, "Potions:"); + draw(hw); + doit = FALSE; + when 'm': + wclear(hw); + wprintw(hw, "Scrolls:"); + draw(hw); + doit = FALSE; + when 'n': + wclear(hw); + wprintw(hw, "Rings:"); + draw(hw); + doit = FALSE; + when 'o': + wclear(hw); + wprintw(hw, "Wands and Staffs:"); + draw(hw); + doit = FALSE; + when 'p': + wclear(hw); + wprintw(hw, "Weapons:"); + draw(hw); + doit = FALSE; + when 'q': + wclear(hw); + wprintw(hw, "Armors:"); + draw(hw); + doit = FALSE; + when 'r': + wclear(hw); + wprintw(hw, "Miscellaneous Magic Items:"); + draw(hw); + doit = FALSE; + when 's': + wclear(hw); + wprintw(hw, "Quest Items (Artifacts and Relics):"); + draw(hw); + doit = FALSE; + when 't': + wclear(hw); + wprintw(hw, "The Dungeon:"); + draw(hw); + doit = FALSE; + when 'u': + wclear(hw); + wprintw(hw, "Traps:"); + draw(hw); + doit = FALSE; + when 'v': + wclear(hw); + wprintw(hw, "Mazes and Outer Regions:"); + draw(hw); + doit = FALSE; + when 'w': + wclear(hw); + wprintw(hw, "Setting game options:"); + draw(hw); + doit = FALSE; + when 'x': + wclear(hw); + wprintw(hw, "Starting out:"); + draw(hw); + doit = FALSE; + otherwise: + doit = TRUE; + } + } + wmove(hw, lines-1, 0); + wprintw(hw, spacemsg); + draw(hw); + wait_for(' '); + wclear(hw); + draw(hw); + wmove(cw, 0, 0); + wclrtoeol(cw); + status(FALSE); + touchwin(cw); +} + +/* + * Real Help + */ + +help() +{ + register struct h_list *strp = helpstr; + register struct item_list *itemp = item_help; + struct h_list *wizp = wiz_help; + register char helpch; + register int cnt; + + msg("Character you want help for (* for commands, @ for items): "); + helpch = wgetch(cw); + mpos = 0; + /* + * If it's not a *, @, or +, then just print help string + * for the character entered. + */ + if (helpch != '*' && helpch != '@' && helpch != '+') { + wmove(msgw, 0, 0); + while (strp->h_ch) { + if (strp->h_ch == helpch) { + msg("%s%s", unctrl(strp->h_ch), strp->h_desc); + return; + } + strp++; + } + if (wizard) { + while (wizp->h_ch) { + if (wizp->h_ch == helpch) { + msg("%s%s", unctrl(wizp->h_ch), wizp->h_desc); + return; + } + wizp++; + } + } + msg("Unknown command '%s'", unctrl(helpch)); + return; + } + + /* fortunes - but let's not say so - explicitly */ + if (helpch == '+') { + msg("Meaningless command '+'"); + return; + } + + /* + * Print help for everything else + */ + if (helpch == '*') { + wclear(hw); + cnt = 0; + while (strp->h_ch) { + mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(strp->h_ch)); + waddstr(hw, strp->h_desc); + strp++; + if (++cnt >= 46 && strp->h_ch) { + wmove(hw, lines-1, 0); + wprintw(hw, morestr); + draw(hw); + wait_for(' '); + wclear(hw); + cnt = 0; + } + } + if (wizard) { + while (wizp->h_ch) { + mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(wizp->h_ch)); + waddstr(hw, wizp->h_desc); + wizp++; + if (++cnt >= 46 && wizp->h_ch) { + wmove(hw, lines-1, 0); + wprintw(hw, morestr); + draw(hw); + wait_for(' '); + wclear(hw); + cnt = 0; + } + } + } + } + if (helpch == '@') { + wclear(hw); + cnt = 0; + while (itemp->item_ch) { + mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(itemp->item_ch)); + waddstr(hw, itemp->item_desc); + itemp++; + if (++cnt >= 46 && itemp->item_ch) { + wmove(hw, lines-1, 0); + wprintw(hw, morestr); + draw(hw); + wait_for(' '); + wclear(hw); + cnt = 0; + } + } + } + wmove(hw, lines-1, 0); + wprintw(hw, spacemsg); + draw(hw); + wait_for(' '); + wclear(hw); + draw(hw); + wmove(cw, 0, 0); + wclrtoeol(cw); + status(FALSE); + touchwin(cw); +} + +/* + * identify: + * Tell the player what a certain thing is. + */ + +identify(ch) +register unsigned char ch; +{ + register char *str = NULL; + + if (ch == 0) { + msg("What do you want identified? "); + ch = wgetch(cw); + mpos = 0; + if (ch == ESC) + { + msg(""); + return; + } + } + if (isalpha(ch)) + msg("Use the \"=\" command to identify monsters. "); + else switch(ch) + { + case VPLAYER: str = "You (visibly)"; + when IPLAYER: str = "You (invisibly)"; + when GOLD: str = "Gold"; + when STAIRS: str = (levtype == OUTSIDE) ? "Entrance to the dungeon" + : "Stairway"; + when DOOR: str = "Doorway"; + when SECRETDOOR:str = "Secret door"; + when FLOOR: str = (levtype == OUTSIDE) ? "Meadow" : "Room floor"; + when PASSAGE: str = "Passage"; + when VERTWALL: + case HORZWALL: + str = (levtype == OUTSIDE) ? "Boundary of sector" + : "Wall of a room"; + when POST: str = "Trading post"; + when POOL: str = (levtype == OUTSIDE) ? "Lake" + : "A shimmering pool"; + when TRAPDOOR: str = "Trap door"; + when ARROWTRAP: str = "Arrow trap"; + when SLEEPTRAP: str = "Sleeping gas trap"; + when BEARTRAP: str = "Bear trap"; + when TELTRAP: str = "Teleport trap"; + when DARTTRAP: str = "Dart trap"; + when MAZETRAP: str = "Entrance to a maze"; + when WORMHOLE: str = "Entrance to a worm hole"; + when FOREST: str = "Forest"; + when ' ' : str = (levtype == OUTSIDE) ? "Mountain" + : "Solid rock"; + when FOOD: str = "Food"; + when POTION: str = "Potion"; + when SCROLL: str = "Scroll"; + when RING: str = "Ring"; + when WEAPON: str = "Weapon"; + when ARMOR: str = "Armor"; + when MM: str = "Miscellaneous magic"; + when STICK: str = "Wand or staff"; + when RELIC: str = "Artifact"; + otherwise: str = "Unknown character"; + } + if (!isalpha(ch)) + msg("%s %s", unctrl(ch), str); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/init.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,826 @@ +/* + init.c - global variable initializaton + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" +#include "mach_dep.h" + +/* + * If there is any news, put it in a character string and assign it to + * rogue_news. Otherwise, assign NULL to rogue_news. + */ + +static char *rogue_news = "Enter a number within the minimum and maximum \ +range. When satisfied with your choices, enter a 'y'. For help at any \ +other time enter a '?' or a '='."; + +/* replace the above line with this when descriptions are done */ +/* other time enter a '?' or a '='. For character and item descriptions \ +enter a '\\' on any other screen."; +*/ + +struct words rainbow[NCOLORS] = { +"Amber", "Aquamarine", "Beige", +"Black", "Blue", "Brown", +"Clear", "Crimson", "Ecru", +"Gold", "Green", "Grey", +"Indigo", "Khaki", "Lavender", +"Magenta", "Orange", "Pink", +"Plaid", "Purple", "Red", +"Silver", "Saffron", "Scarlet", +"Tan", "Tangerine", "Topaz", +"Turquoise", "Vermilion", "Violet", +"White", "Yellow", +}; + +struct words sylls[NSYLLS] = { + "a", "ae", "ak", "an", "ax", "ach", "ano", "ars", "bha", "bar", "bre", + "cha", "cre", "cum", "cow", "duh", "dha", "e", "ea", "em", "et", "ey", + "eck", "etk", "egg", "exl", "fu", "fen", "fid", "gan", "gle", "h", "ha", + "hr", "ht", "how", "hex", "hip", "hoc", "i", "ia", "ig", "it", "iz", + "ion", "ink", "ivi", "iss", "je", "jin", "jha", "jyr", "ka", "kho", "kal", + "kli", "lu", "lre", "lta", "lri", "m", "ma", "mh", "mi", "mr", "mar", + "myr", "moh", "mul", "nep", "nes", "o", "oc", "om", "oq", "ox", "orn", + "oxy", "olm", "ode", "po", "pie", "pod", "pot", "qar", "que", "ran", "rah", + "rok", "sa", "sat", "sha", "sol", "sri", "ti", "tem", "tar", "tki", "tch", + "tox", "u", "ub", "uh", "ur", "uv", "unk", "uwh", "ugh", "uyr", "va", + "vil", "vit", "vom", "vux", "wah", "wex", "xu", "xed", "xen", "ya", "yep", + "yih", "zef", "zen", "zil", "zym", "-" +}; + +struct words stones[NSTONES] = { + "Agate", "Alexandrite", "Amethyst", + "Azurite", "Bloodstone", "Cairngorm", + "Carnelian", "Chalcedony", "Chrysoberyl", + "Chrysolite", "Chrysoprase", "Citrine", + "Coral", "Diamond", "Emerald", + "Garnet", "Heliotrope", "Hematite", + "Hyacinth", "Jacinth", "Jade", + "Jargoon", "Jasper", "Kryptonite", + "Lapis lazuli", "Malachite", "Mocca stone", + "Moonstone", "Obsidian", "Olivine", + "Onyx", "Opal", "Pearl", + "Peridot", "Quartz", "Rhodochrosite", + "Rhodolite", "Ruby", "Sapphire", + "Sardonyx", "Serpentine", "Spinel", + "Tiger eye", "Topaz", "Tourmaline", + "Turquoise", "Zircon", +}; + +struct words wood[NWOOD] = { + "Avocado wood", "Balsa", "Banyan", "Birch", + "Cedar", "Cherry", "Cinnabar", "Dogwood", + "Driftwood", "Ebony", "Eucalyptus", "Hemlock", + "Ironwood", "Mahogany", "Manzanita", "Maple", + "Oak", "Pine", "Redwood", "Rosewood", + "Teak", "Walnut", "Aloe", "Sandalwood", +}; + +struct words metal[NMETAL] = { + "Aluminium", "Bone", "Brass", "Bronze", + "Copper", "Chromium", "Iron", "Lead", + "Magnesium", "Pewter", "Platinum", "Silver", + "Steel", "Tin", "Titanium", "Zinc", +}; + +/* + * make sure all the percentages specified in the tables add up to the + * right amounts + */ + +badcheck(name, magic, bound) +char *name; +register struct magic_item *magic; +register int bound; +{ + register struct magic_item *end; + + if (magic[bound - 1].mi_prob == 1000) + return; + printf("\nBad percentages for %s:\n", name); + for (end = &magic[bound] ; magic < end ; magic++) + printf("%4d%% %s\n", magic->mi_prob, magic->mi_name); + printf(retstr); + fflush(stdout); + while (getchar() != '\n') + continue; +} + +/* + * init_colors: + * Initialize the potion color scheme for this time + */ + +init_colors() +{ + register int i; + register char *str; + + for (i = 0 ; i < MAXPOTIONS ; i++) + { + do + str = rainbow[rnd(NCOLORS)].w_string; + until (isupper(*str)); + *str = tolower(*str); + p_colors[i] = str; + p_know[i] = FALSE; + p_guess[i] = NULL; + if (i > 0) + p_magic[i].mi_prob += p_magic[i-1].mi_prob; + } + badcheck("potions", p_magic, MAXPOTIONS); +} + +/* + * do any initialization for food + */ + +init_foods() +{ + register int i; + + for (i=0; i < MAXFOODS; i++) { + if (i > 0) + foods[i].mi_prob += foods[i-1].mi_prob; + } + badcheck("foods", foods, MAXFOODS); +} + +/* + * init_materials: + * Initialize the construction materials for wands and staffs + */ + +init_materials() +{ + register int i; + register char *str; + + for (i = 0 ; i < MAXSTICKS ; i++) + { + do + if (rnd(100) > 50) + { + str = metal[rnd(NMETAL)].w_string; + if (isupper(*str)) + ws_type[i] = "wand"; + } + else + { + str = wood[rnd(NWOOD)].w_string; + if (isupper(*str)) + ws_type[i] = "staff"; + } + until (isupper(*str)); + *str = tolower(*str); + ws_made[i] = str; + ws_know[i] = FALSE; + ws_guess[i] = NULL; + if (i > 0) + ws_magic[i].mi_prob += ws_magic[i-1].mi_prob; + } + badcheck("sticks", ws_magic, MAXSTICKS); +} + +/* + * do any initialization for miscellaneous magic + */ + +init_misc() +{ + register int i; + + for (i=0; i < MAXMM; i++) { + m_know[i] = FALSE; + m_guess[i] = NULL; + if (i > 0) + m_magic[i].mi_prob += m_magic[i-1].mi_prob; + } + badcheck("miscellaneous magic", m_magic, MAXMM); +} + +/* + * init_names: + * Generate the names of the various scrolls + */ + +init_names() +{ + register int nsyl; + register char *cp, *sp; + register int i, nwords; + + for (i = 0 ; i < MAXSCROLLS ; i++) + { + cp = prbuf; + nwords = rnd(cols/20) + 1 + (cols > 40 ? 1 : 0); + while(nwords--) + { + nsyl = rnd(5)+1; + while(nsyl--) + { + sp = sylls[rnd(NSYLLS)].w_string; + while(*sp) + *cp++ = *sp++; + } + *cp++ = ' '; + } + *--cp = '\0'; + s_names[i] = (char *) new(strlen(prbuf)+1); + s_know[i] = FALSE; + s_guess[i] = NULL; + strcpy(s_names[i], prbuf); + if (i > 0) + s_magic[i].mi_prob += s_magic[i-1].mi_prob; + } + badcheck("scrolls", s_magic, MAXSCROLLS); +} + +/* + * init_player: + * roll up the rogue + */ + +init_player() +{ + int stat_total, round = 0, minimum, maximum, ch, i, j = 0; + short do_escape, *our_stats[NUMABILITIES-1]; + struct linked_list *weap_item, *armor_item, *food_item; + struct object *obj; + + weap_item = armor_item = food_item = NULL; + + if (char_type == -1) { /* not set via options */ + /* See what type character will be */ + wclear(hw); + touchwin(hw); + wmove(hw,2,0); + for(i=1; i<=NUM_CHARTYPES-1; i++) { + wprintw(hw,"[%d] %s\n",i,char_class[i-1].name); + } + mvwaddstr(hw, 0, 0, "What character class do you desire? "); + draw(hw); + char_type = (wgetch(hw) - '0'); + while (char_type < 1 || char_type > NUM_CHARTYPES-1) { + wmove(hw,0,0); + wprintw(hw,"Please enter a character type between 1 and %d: ", + NUM_CHARTYPES-1); + draw(hw); + char_type = (wgetch(hw) - '0'); + } + char_type--; + } + player.t_ctype = char_type; + player.t_quiet = 0; + pack = NULL; + + /* Select the gold */ + purse = 3000; + switch (player.t_ctype) { + case C_FIGHTER: + purse += 200; + when C_MAGICIAN: + case C_CLERIC: + case C_DRUID: + purse += 100; + when C_THIEF: + case C_ASSASSIN: + purse += 0; + when C_RANGER: + case C_PALADIN: + purse -= 100; + when C_MONK: + purse -= 200; + } + /* + * allow me to describe a super character + */ + /* let's lessen the restrictions on this okay? */ + if (wizard && strcmp(getenv("SUPER"),"YES") == 0) { + pstats.s_str = MAXATT; + pstats.s_intel = MAXATT; + pstats.s_wisdom = MAXATT; + pstats.s_dext = MAXATT; + pstats.s_const = MAXATT; + pstats.s_charisma = MAXATT; + pstats.s_exp = 10000000L; + pstats.s_lvl = 1; + pstats.s_lvladj = 0; + pstats.s_hpt = 500; + pstats.s_carry = totalenc(&player); + strcpy(pstats.s_dmg,"4d8"); + check_level(); + wmove(hw,0,0); + wclrtoeol(hw); + draw(hw); + mpos = 0; + + /* set quest item */ + if(player.t_ctype == C_FIGHTER) quest_item = AXE_AKLAD; + if(player.t_ctype == C_RANGER) quest_item = BRIAN_MANDOLIN; + if(player.t_ctype == C_PALADIN) quest_item = HEIL_ANKH; + if(player.t_ctype == C_MAGICIAN) quest_item = STONEBONES_AMULET; + if(player.t_ctype == C_CLERIC) quest_item = GERYON_HORN; + if(player.t_ctype == C_THIEF) quest_item = MUSTY_DAGGER; + if(player.t_ctype == C_ASSASSIN) quest_item = EYE_VECNA; + if(player.t_ctype == C_DRUID) quest_item = QUILL_NAGROM; + if(player.t_ctype == C_MONK) quest_item = EMORI_CLOAK; + + /* armor */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN) + j = STUDDED_LEATHER; + else if (player.t_ctype == C_MONK) { + armor_item = spec_item(MM, MM_BRACERS, 20, 0); + obj = OBJPTR(armor_item); + obj->o_weight = things[TYP_MM].mi_wght; + whatis (armor_item); /* identify it */ + obj->o_flags |= (ISKNOW | ISPROT); + add_pack(armor_item, TRUE); + cur_misc[WEAR_BRACERS] = obj; + goto w_armorjmp; + } + else j = PLATE_ARMOR; + + armor_item = spec_item(ARMOR, j, 20, 0); + obj = OBJPTR(armor_item); + obj->o_weight = armors[j].a_wght; + obj->o_flags |= (ISKNOW | ISPROT); + add_pack(armor_item, TRUE); + cur_armor = obj; + + w_armorjmp: /* monk doesn't wear armor */ + + /* weapons */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || + player.t_ctype == C_MONK) + j = BASWORD; + else if (player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER || + player.t_ctype == C_PALADIN) + j = TWOSWORD; + else j = TRIDENT; + + weap_item = spec_item(WEAPON, j, 20, 20); + obj = OBJPTR(weap_item); + obj->o_flags |= (ISKNOW | ISPROT); + obj->o_weight = weaps[j].w_wght; + add_pack(weap_item, TRUE); + cur_weapon = obj; + + /* food */ + food_item = spec_item(FOOD, E_RATION, 0, 0); + obj = OBJPTR(food_item); + obj->o_flags |= ISKNOW; + obj->o_weight = foods[TYP_FOOD].mi_wght; + add_pack(food_item, TRUE); /* just one */ + + /* give wizard plenty gold */ + purse = 50000; + } + else + /* default attributes checked */ + { + if (def_attr == TRUE) { /* "default" option used in ROGUEOPTS */ + switch(player.t_ctype) { + /* set "default attributes" option and quest items here */ + case C_FIGHTER: + case C_MONK: + pstats.s_intel = 7; + pstats.s_dext = 16; + pstats.s_charisma = 11; + if (player.t_ctype == C_FIGHTER) { + pstats.s_str = 16; + pstats.s_wisdom = 7; + pstats.s_const = 17; + quest_item = AXE_AKLAD; + } + else { + pstats.s_str = 11; + pstats.s_wisdom = 11; + pstats.s_const = 18; + quest_item = EMORI_CLOAK; + } + when C_RANGER: + case C_PALADIN: + pstats.s_str = 11; + pstats.s_dext = 16; + pstats.s_const = 16; + pstats.s_charisma = 13; + /* intelligence or wisdom */ + if (player.t_ctype == C_RANGER) { + pstats.s_intel = 11; + pstats.s_wisdom = 7; + quest_item = BRIAN_MANDOLIN; + } + else { + pstats.s_intel = 7; + pstats.s_wisdom = 11; + quest_item = HEIL_ANKH; + } + when C_THIEF: + case C_ASSASSIN: + pstats.s_intel = 7; + pstats.s_str = 14; + pstats.s_wisdom = 7; + pstats.s_dext = 18; + pstats.s_const = 17; + pstats.s_charisma = 11; + if (player.t_ctype == C_THIEF) + quest_item = MUSTY_DAGGER; + else + quest_item = EYE_VECNA; + when C_MAGICIAN: + case C_CLERIC: + case C_DRUID: + pstats.s_str = 10; + pstats.s_dext = 16; + pstats.s_const = 15; + pstats.s_charisma = 12; + /* intelligence & wisdom */ + if (player.t_ctype == C_MAGICIAN) { + pstats.s_intel = 14; + pstats.s_wisdom = 7; + } + else { + pstats.s_intel = 7; + pstats.s_wisdom = 14; + } + if (player.t_ctype == C_MAGICIAN) + quest_item = STONEBONES_AMULET; + else if (player.t_ctype == C_CLERIC) + quest_item = GERYON_HORN; + else + quest_item = QUILL_NAGROM; + } + /* Intialize */ + pstats.s_exp = 0L; + pstats.s_lvl = 1; + pstats.s_lvladj = 0; + pstats.s_exp = 0L; + strcpy(pstats.s_dmg,"2d4"); + pstats.s_carry = totalenc(&player); + check_level(); + wmove(hw,0,0); + wclrtoeol(hw); + draw(hw); + mpos = 0; + + /* Get the hit points. */ + pstats.s_hpt = 12 + const_bonus(); /* Base plus bonus */ + + /* Add in the component that varies according to class */ + pstats.s_hpt += char_class[player.t_ctype].hit_pts; + + /* dole out some armor */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN) + j = STUDDED_LEATHER; + else if (player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER || + player.t_ctype == C_PALADIN) { + switch (rnd(4)) { + case 0: j = PLATE_ARMOR; + when 1: j = PLATE_MAIL; + when 2: case 3: j = BANDED_MAIL; + } + } + else if (player.t_ctype == C_MONK) { + if (rnd(3) == 0) j = MM_PROTECT; + else j = MM_BRACERS; + armor_item = spec_item(MM, j, rnd(125)/60+3, 0); + obj = OBJPTR(armor_item); + obj->o_weight = things[TYP_MM].mi_wght; + whatis (armor_item); /* identify it */ + obj->o_flags |= ISKNOW; + add_pack(armor_item, TRUE); + goto p_armorjmp; + } + else { /* other characters */ + switch (rnd(7)) { + case 0: j = PLATE_MAIL; + when 1: case 2: j = BANDED_MAIL; + when 3: case 4: j = SPLINT_MAIL; + when 5: case 6: j = PADDED_ARMOR; + } + } + armor_item = spec_item(ARMOR, j, rnd(100)/85, 0); + obj = OBJPTR(armor_item); + obj->o_weight = armors[j].a_wght; + obj->o_flags |= ISKNOW; + add_pack(armor_item, TRUE); + + p_armorjmp: /* monk doesn't wear armor */ + + /* give him a weapon */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || + player.t_ctype == C_MONK) { + switch (rnd(5)) { + case 0: j = BASWORD; + when 1: case 2: j = TRIDENT; + when 3: case 4: j = BARDICHE; + } + } + else if (player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER || + player.t_ctype == C_PALADIN) { + switch (rnd(5)) { + case 0: j= TWOSWORD; + when 1: case 2: j= TRIDENT; + when 3: case 4: j= SWORD; + } + } + else { + switch (rnd(7)) { + case 0: j = TRIDENT; + when 1: case 2: j = SWORD; + when 3: case 4: j = BARDICHE; + when 5: j = MACE; + when 6: j = SPETUM; + } + } + weap_item = spec_item(WEAPON, j, rnd(155)/75, rnd(165)/80); + obj = OBJPTR(weap_item); + obj->o_weight = weaps[j].w_wght; + obj->o_flags |= ISKNOW; + add_pack(weap_item, TRUE); + + /* food rations */ + food_item = spec_item(FOOD, E_RATION, 0, 0); + obj = OBJPTR(food_item); + obj->o_weight = foods[TYP_FOOD].mi_wght; + obj->o_flags |= ISKNOW; + add_pack(food_item, TRUE); + + /* give him some fruit - coose from those w/o special effects */ + switch (rnd(6)) { + case 0: j = E_BANANA; + when 1: j = E_BLUEBERRY; + when 2: j = E_ELDERBERRY; + when 3: j = E_GUANABANA; + when 4: j = E_CAPRIFIG; + when 5: j = E_GOOSEBERRY; + } + food_item = spec_item(FOOD, j, 0, 0); + obj = OBJPTR(food_item); + obj->o_weight = foods[TYP_FOOD].mi_wght; + obj->o_flags |= ISKNOW; + add_pack(food_item, TRUE); + + /* adjust purse */ + purse = 2000; + } + else { /* select attibutes */ + switch(player.t_ctype) { + case C_FIGHTER: round = A_STRENGTH; + when C_RANGER: round = A_CHARISMA; + when C_PALADIN: round = A_CHARISMA; + when C_MAGICIAN: round = A_INTELLIGENCE; + when C_CLERIC: round = A_WISDOM; + when C_THIEF: round = A_DEXTERITY; + when C_ASSASSIN: round = A_DEXTERITY; + when C_DRUID: round = A_WISDOM; + when C_MONK: round = A_CONSTITUTION; + } + + do { + wclear(hw); + + /* If there is any news, display it */ + if (rogue_news) { + register int i; + + /* Print a separator line */ + wmove(hw, 12, 0); + for (i=0; i<cols; i++) waddch(hw, '-'); + + /* Print the news */ + mvwaddstr(hw, 14, 0, rogue_news); + } + + stat_total = MAXSTATS; + do_escape = FALSE; /* No escape seen yet */ + + /* Initialize abilities */ + pstats.s_intel = 0; + pstats.s_str = 0; + pstats.s_wisdom = 0; + pstats.s_dext = 0; + pstats.s_const = 0; + pstats.s_charisma = 0; + + /* Initialize pointer into abilities */ + our_stats[A_INTELLIGENCE] = &pstats.s_intel; + our_stats[A_STRENGTH] = &pstats.s_str; + our_stats[A_WISDOM] = &pstats.s_wisdom; + our_stats[A_DEXTERITY] = &pstats.s_dext; + our_stats[A_CONSTITUTION] = &pstats.s_const; + + /* Let player distribute attributes */ + for (i=0; i<NUMABILITIES-1; i++) { + wmove(hw, 2, 0); + wprintw(hw, "You are creating a %s with %2d attribute points.", + char_class[player.t_ctype].name, stat_total); + + /* + * Player must have a minimum of 7 in any attribute and 11 in + * the player's primary attribute. + */ + minimum = (round == i ? 11 : 7); + + /* Subtract out remaining minimums */ + maximum = stat_total - (7 * (NUMABILITIES-1 - i)); + + /* Subtract out remainder of profession minimum (11 - 7) */ + if (round > i) maximum -= 4; + + /* Maximum can't be greater than 18 */ + if (maximum > 18) maximum = 18; + + wmove(hw, 4, 0); + wprintw(hw, + "Minimum: %2d; Maximum: %2d (%s corrects previous entry)", + minimum, maximum, unctrl('\b')); + + wmove(hw, 6, 0); + wprintw(hw, " Int: %-2d", pstats.s_intel); + wprintw(hw, " Str: %-2d", pstats.s_str); + wprintw(hw, " Wis: %-2d", pstats.s_wisdom); + wprintw(hw, " Dex: %-2d", pstats.s_dext); + wprintw(hw, " Con: %-2d", pstats.s_const); + wprintw(hw, " Cha: %-2d", pstats.s_charisma); + wclrtoeol(hw); + wmove(hw, 6, 11*i + 9); + if (do_escape == FALSE) draw(hw); + + /* Get player's input */ + if (do_escape || maximum == minimum) { + *our_stats[i] = maximum; + stat_total -= maximum; + } + else for (;;) { + ch = wgetch(hw); + if (ch == '\b') { /* Backspace */ + if (i == 0) continue; /* Can't move back */ + else { + stat_total += *our_stats[i-1]; + *our_stats[i] = 0; + *our_stats[i-1] = 0; + i -= 2; /* Back out */ + break; + } + } + if (ch == '\033') { /* Escape */ + /* + * Escape will result in using all maximums for + * remaining abilities. + */ + do_escape = TRUE; + *our_stats[i] = maximum; + stat_total -= maximum; + break; + } + + /* Do we have a legal digit? */ + if (ch >= '0' && ch <= '9') { + ch -= '0'; /* Convert it to a number */ + *our_stats[i] = 10 * *our_stats[i] + ch; + + /* Is the number in range? */ + if (*our_stats[i] >= minimum && + *our_stats[i] <= maximum) { + stat_total -= *our_stats[i]; + break; + } + + /* + * If it's too small, get more - 1x is the only + * allowable case. + */ + if (*our_stats[i] < minimum && *our_stats[i] == 1) { + /* Print the player's one */ + waddch(hw, '1'); + draw(hw); + continue; + } + } + + /* Error condition */ + putchar('\007'); + *our_stats[i] = 0; + i--; /* Rewind */ + break; + } + } + + /* Discard extra points over 18 */ + if (stat_total > 18) stat_total = 18; + + /* Charisma gets what's left */ + pstats.s_charisma = stat_total; + + /* Intialize constants */ + pstats.s_lvl = 1; + pstats.s_lvladj = 0; + pstats.s_exp = 0L; + strcpy(pstats.s_dmg,"2d4"); + pstats.s_carry = totalenc(&player); + + /* Get the hit points. */ + pstats.s_hpt = 12 + const_bonus(); /* Base plus bonus */ + + /* Add in the component that varies according to class */ + pstats.s_hpt += char_class[player.t_ctype].hit_pts; + + /* Display the character */ + wmove(hw, 2, 0); + wprintw(hw,"You are creating a %s.", + char_class[player.t_ctype].name); + wclrtoeol(hw); + + /* Get rid of max/min line */ + wmove(hw, 4, 0); + wclrtoeol(hw); + + wmove(hw, 6, 0); + wprintw(hw, " Int: %2d", pstats.s_intel); + wprintw(hw, " Str: %2d", pstats.s_str); + wprintw(hw, " Wis: %2d", pstats.s_wisdom); + wprintw(hw, " Dex: %2d", pstats.s_dext); + wprintw(hw, " Con: %2d", pstats.s_const); + wprintw(hw, " Cha: %2d", pstats.s_charisma); + wclrtoeol(hw); + + wmove(hw, 8, 0); + wprintw(hw, " Hp: %2d", pstats.s_hpt); + wclrtoeol(hw); + + wmove(hw, 10, 0); + wprintw(hw, " Gold: %ld", purse); + + mvwaddstr(hw, 0, 0, "Is this character okay? "); + draw(hw); + } while(wgetch(hw) != 'y'); + } + } + pstats.s_arm = 10; + max_stats = pstats; + /* Set up initial movement rate */ + player.t_action = A_NIL; + player.t_movement = 6; + player.t_no_move = 0; + player.t_using = NULL; + wclear(hw); +} + +/* + * init_stones: + * Initialize the ring stone setting scheme for this time + */ + +init_stones() +{ + register int i; + register char *str; + + for (i = 0 ; i < MAXRINGS ; i++) + { + do + str = stones[rnd(NSTONES)].w_string; + until (isupper(*str)); + *str = tolower(*str); + r_stones[i] = str; + r_know[i] = FALSE; + r_guess[i] = NULL; + if (i > 0) + r_magic[i].mi_prob += r_magic[i-1].mi_prob; + } + badcheck("rings", r_magic, MAXRINGS); +} + +/* + * init_things + * Initialize the probabilities for types of things + */ + +init_things() +{ + register struct magic_item *mp; + + for (mp = &things[1] ; mp < &things[NUMTHINGS] ; mp++) + mp->mi_prob += (mp-1)->mi_prob; + badcheck("things", things, NUMTHINGS); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/io.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,564 @@ +/* + io.c - Various input/output functions + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <stdarg.h> +#include <string.h> +#include "rogue.h" + +/* + * msg: + * Display a message at the top of the screen. + */ + +static char msgbuf[BUFSIZ]; +static int newpos = 0; + +/* VARARGS */ +void +msg(char *fmt, ...) +{ + va_list ap; + /* + * if the string is "", just clear the line + */ + if (*fmt == '\0') + { + wclear(msgw); + overwrite(cw, msgw); + wmove(msgw, 0, 0); + clearok(msgw, FALSE); + draw(msgw); + mpos = 0; + return; + } + /* + * otherwise add to the message and flush it out + */ + va_start(ap, fmt); + doadd(fmt, ap); + va_end(ap); + endmsg(); +} + +/* + * add things to the current message + */ + +/* VARARGS */ +void +addmsg(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + doadd(fmt, ap); + va_end(ap); +} + +/* + * If there is no current message, do nothing. Otherwise, prompt the + * player with the --More-- string. Then erase the message. + */ + +rmmsg() +{ + if (mpos) { + wclear(msgw); + overwrite(cw, msgw); + mvwaddstr(msgw, 0, 0, huh); + waddstr(msgw, morestr); + clearok(msgw, FALSE); + draw(msgw); + wait_for(' '); + msg(""); + } +} + +/* + * Display a new msg (giving him a chance to see the previous one if it + * is up there with the --More--) + */ + +endmsg() +{ + /* Needed to track where we are for 5.0 (PC) curses */ + register int x, y; + + if (mpos) { + /* + * If this message will fit on the line (plus space for --More--) + * then just add it (only during combat). + */ + if (player.t_quiet < 0 && mpos + newpos + strlen(morestr) + 5 < cols) { + wmove(msgw, 0, mpos + 5); + newpos += mpos + 5; + strcat(huh, " "); + } + else { + wclear(msgw); + overwrite(cw, msgw); + mvwaddstr(msgw, 0, 0, huh); + waddstr(msgw, morestr); + clearok(msgw, FALSE); + draw(msgw); + wait_for(' '); + wclear(msgw); + overwrite(cw, msgw); + wmove(msgw, 0, 0); + huh[0] = '\0'; + } + } + else { + wclear(msgw); + overwrite(cw, msgw); + wmove(msgw, 0, 0); + huh[0] = '\0'; + } + strcat(huh, msgbuf); + mvwaddstr(msgw, 0, 0, huh); + getyx(msgw, y, x); + mpos = newpos; + newpos = 0; + wmove(msgw, y, x); + clearok(msgw, FALSE); + draw(msgw); +} + +doadd(char *fmt, va_list ap) +{ + vsprintf((char *) &msgbuf[newpos], fmt, ap); + newpos = strlen(msgbuf); +} + +/* + * step_ok: + * returns true if it is ok for type to step on ch + * flgptr will be NULL if we don't know what the monster is yet! + */ + +step_ok(y, x, can_on_monst, flgptr) +register int y, x, can_on_monst; +register struct thing *flgptr; +{ + /* can_on_monst = MONSTOK if all we care about are physical obstacles */ + register struct linked_list *item; + register struct thing *tp; + unsigned char ch; + + /* What is here? Don't check monster window if MONSTOK is set */ + if (can_on_monst == MONSTOK) ch = mvinch(y, x); + else ch = winat(y, x); + + if (can_on_monst == FIGHTOK && isalpha(ch) && + (item = find_mons(y, x)) != NULL) { + tp = THINGPTR(item); /* What monster is here? */ + + /* We can hit it if we're after it */ + if (flgptr->t_dest == &tp->t_pos) return TRUE; + + /* + * Otherwise, if we're friendly we'll hit it unless it is also + * friendly or is our race. + */ + if (off(*flgptr, ISFRIENDLY) || + on(*tp, ISFRIENDLY) || + flgptr->t_index == tp->t_index) return FALSE; + else return TRUE; + } + else switch (ch) + { + case ' ': + case VERTWALL: + case HORZWALL: + case SECRETDOOR: + if (flgptr && on(*flgptr, CANINWALL)) return(TRUE); + return FALSE; + when SCROLL: + if (can_on_monst == MONSTOK) { /* Not a real obstacle */ + move_free = 0; /* check free movement */ + return(TRUE); + } + /* + * If it is a scroll, it might be a scare monster scroll + * so we need to look it up to see what type it is. + */ + if (flgptr && flgptr->t_ctype == C_MONSTER) { + move_free = 1; + item = find_obj(y, x); + if (item != NULL && + (OBJPTR(item))->o_which==S_SCARE && + (flgptr == NULL || flgptr->t_stats.s_intel < 17)) { + move_free = 2; + return(FALSE); /* All but smart ones are scared */ + } + } + return(TRUE); + otherwise: + return (!isalpha(ch)); + } + /* return(FALSE); */ + /*NOTREACHED*/ +} + +/* + * shoot_ok: + * returns true if it is ok for type to shoot over ch + */ + +shoot_ok(int ch) +{ + switch (ch) + { + case ' ': + case VERTWALL: + case HORZWALL: + case SECRETDOOR: + case FOREST: + return FALSE; + default: + return (!isalpha(ch)); + } +} + +/* + * status: + * Display the important stats line. Keep the cursor where it was. + */ + +status(display) +bool display; /* is TRUE, display unconditionally */ +{ + register struct stats *stat_ptr, *max_ptr; + register int oy = 0, ox = 0, temp; + register char *pb; + char buf[LINELEN]; + static int hpwidth = 0, s_hungry = -1; + static int s_lvl = -1, s_hp = -1, s_str, maxs_str, + s_ac = 0; + static short s_intel, s_dext, s_wisdom, s_const, s_charisma; + static short maxs_intel, maxs_dext, maxs_wisdom, maxs_const, maxs_charisma; + static unsigned long s_exp = 0; + static int s_carry, s_pack; + bool first_line=FALSE; + + /* Go to English mode */ + nofont(cw); + + stat_ptr = &pstats; + max_ptr = &max_stats; + + /* + * If nothing has changed in the first line, then skip it + */ + if (!display && + s_lvl == level && + s_intel == stat_ptr->s_intel && + s_wisdom == stat_ptr->s_wisdom && + s_dext == dex_compute() && + s_const == stat_ptr->s_const && + s_charisma == stat_ptr->s_charisma && + s_str == str_compute() && + s_hungry == hungry_state && + maxs_intel == max_ptr->s_intel && + maxs_wisdom == max_ptr->s_wisdom && + maxs_dext == max_ptr->s_dext && + maxs_const == max_ptr->s_const && + maxs_charisma == max_ptr->s_charisma && + maxs_str == max_ptr->s_str ) goto line_two; + + /* Display the first line */ + first_line = TRUE; + getyx(cw, oy, ox); + sprintf(buf, "Int:%d(%d) Str:%d", stat_ptr->s_intel, + max_ptr->s_intel, str_compute()); + + /* Maximum strength */ + pb = &buf[strlen(buf)]; + sprintf(pb, "(%d)", max_ptr->s_str); + + pb = &buf[strlen(buf)]; + sprintf(pb, " Wis:%d(%d) Dxt:%d(%d) Con:%d(%d) Cha:%d(%d)", + stat_ptr->s_wisdom,max_ptr->s_wisdom,dex_compute(),max_ptr->s_dext, + stat_ptr->s_const,max_ptr->s_const,stat_ptr->s_charisma, + max_ptr->s_charisma); + + /* Update first line status */ + s_intel = stat_ptr->s_intel; + s_wisdom = stat_ptr->s_wisdom; + s_dext = dex_compute(); + s_const = stat_ptr->s_const; + s_charisma = stat_ptr->s_charisma; + s_str = str_compute(); + maxs_intel = max_ptr->s_intel; + maxs_wisdom = max_ptr->s_wisdom; + maxs_dext = max_ptr->s_dext; + maxs_const = max_ptr->s_const; + maxs_charisma = max_ptr->s_charisma; + maxs_str = max_ptr->s_str; + + /* Print the line */ + mvwaddstr(cw, lines-2, 0, buf); + switch (hungry_state) { + case F_SATIATED: + waddstr(cw, " Satiated"); + when F_OKAY: ; + when F_HUNGRY: + waddstr(cw, " Hungry"); + when F_WEAK: + waddstr(cw, " Weak"); + when F_FAINT: + waddstr(cw, " Fainting"); + } + wclrtoeol(cw); + s_hungry = hungry_state; + + /* + * If nothing has changed since the last status, don't + * bother. + */ +line_two: + if (!display && + s_lvl == level && + s_hp == stat_ptr->s_hpt && + s_ac == ac_compute(FALSE) - dext_prot(s_dext) && + s_pack == stat_ptr->s_pack && + s_carry == stat_ptr->s_carry && + s_exp == stat_ptr->s_exp ) { + newfont(cw); + return; + } + + if (!first_line) getyx(cw, oy, ox); + if (s_hp != max_ptr->s_hpt) { + temp = s_hp = max_ptr->s_hpt; + for (hpwidth = 0; temp; hpwidth++) + temp /= 10; + } + sprintf(buf, "Lvl:%d Hp:%*d(%*d) Ac:%d Carry:%d(%d) Exp:%d/%lu %s", + level, hpwidth, stat_ptr->s_hpt, hpwidth, max_ptr->s_hpt, + ac_compute(FALSE) - dext_prot(s_dext),stat_ptr->s_pack/10, + stat_ptr->s_carry/10, stat_ptr->s_lvl, stat_ptr->s_exp, + cnames[player.t_ctype][min(stat_ptr->s_lvl-1, NUM_CNAMES-1)]); + + /* + * Save old status + */ + s_lvl = level; + s_hp = stat_ptr->s_hpt; + s_ac = ac_compute(FALSE) - dext_prot(s_dext); + s_pack = stat_ptr->s_pack; + s_carry = stat_ptr->s_carry; + s_exp = stat_ptr->s_exp; + mvwaddstr(cw, lines-1, 0, buf); + wclrtoeol(cw); + newfont(cw); + wmove(cw, oy, ox); +} + +/* + * wait_for + * Sit around until the guy types the right key + */ + +wait_for(ch) +register char ch; +{ + register char c; + + clearok(msgw, FALSE); + if (ch == '\n') { + while ((c = wgetch(msgw)) != '\n' && c != '\r') { + continue; + } + } + else { + while (wgetch(msgw) != ch) { + continue; + } + } +} + + +/* + * over_win: + * Given a current window, a new window, and the max y and x of the + * new window, paint the new window on top of the old window without + * destroying any of the old window. Current window and new window + * are assumed to have lines lines and cols columns (max y and max x + * pertain only the the useful information to be displayed. + * If redraw is non-zero, we wait for the character "redraw" to be + * typed and then redraw the starting screen. + */ + +over_win(oldwin, newin, maxy, maxx, cursory, cursorx, redraw) +WINDOW *oldwin, *newin; +int maxy, maxx, cursory, cursorx; +char redraw; +{ + char blanks[LINELEN+1]; + register int line, i; + WINDOW *ow; /* Overlay window */ + + /* Create a blanking line */ + for (i=0; i<maxx && i<cols && i<LINELEN; i++) blanks[i] = ' '; + blanks[i] = '\0'; + + /* Create the window we will display */ + ow = newwin(lines, cols, 0, 0); + + /* Blank out the area we want to use */ + if (oldwin == cw) { + msg(""); + line = 1; + } + else line = 0; + + overwrite(oldwin, ow); /* Get a copy of the old window */ + + /* Do the remaining blanking */ + for (; line < maxy; line++) mvwaddstr(ow, line, 0, blanks); + + overlay(newin, ow); /* Overlay our new window */ + + /* Move the cursor to the specified location */ + wmove(ow, cursory, cursorx); + + clearok(ow, FALSE); /* Draw inventory without clearing */ + draw(ow); + + if (redraw) { + wait_for(redraw); + + clearok(oldwin, FALSE); /* Setup to redraw current screen */ + touchwin(oldwin); /* clearing first */ + draw(oldwin); + } + + delwin(ow); +} + + +/* + * show_win: + * function used to display a window and wait before returning + */ + +show_win(scr, message) +register WINDOW *scr; +char *message; +{ + mvwaddstr(scr, 0, 0, message); + touchwin(scr); + wmove(scr, hero.y, hero.x); + draw(scr); + wait_for(' '); + restscr(cw); +} + +/* + * dbotline: + * Displays message on bottom line and waits for a space to return + */ + +dbotline(scr,message) +WINDOW *scr; +char *message; +{ + mvwaddstr(scr,lines-1,0,message); + draw(scr); + wait_for(' '); +} + +/* + * restscr: + * Restores the screen to the terminal + */ + +restscr(scr) +WINDOW *scr; +{ + clearok(scr,TRUE); + touchwin(scr); + draw(scr); +} + +/* + * netread: + * Read a byte, short, or long machine independently + * Always returns the value as an unsigned long. + */ + +unsigned long +netread(error, size, stream) +int *error; +int size; +FILE *stream; +{ + unsigned long result = 0L, /* What we read in */ + partial; /* Partial value */ + int nextc, /* The next byte */ + i; /* To index through the result a byte at a time */ + + /* Be sure we have a right sized chunk */ + if (size < 1 || size > 4) { + *error = 1; + return(0L); + } + + for (i=0; i<size; i++) { + nextc = getc(stream); + if (nextc == EOF) { + *error = 1; + return(0L); + } + else { + partial = (unsigned long) (nextc & 0xff); + partial <<= 8*i; + result |= partial; + } + } + + *error = 0; + return(result); +} + +/* + * netwrite: + * Write out a byte, short, or long machine independently. + */ + +netwrite(value, size, stream) +unsigned long value; /* What to write */ +int size; /* How much to write out */ +FILE *stream; /* Where to write it */ +{ + int i; /* Goes through value one byte at a time */ + char outc; /* The next character to be written */ + + /* Be sure we have a right sized chunk */ + if (size < 1 || size > 4) return(0); + + for (i=0; i<size; i++) { + outc = (char) ((value >> (8 * i)) & 0xff); + putc(outc, stream); + } + return(size); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/list.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,247 @@ +/* + list.c - Functions for dealing with linked lists of goodies + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <stdlib.h> +#include <string.h> +#include <curses.h> +#include "rogue.h" + +/* + * detach: + * Takes an item out of whatever linked list it might be in + */ + +_detach(list, item) +register struct linked_list **list, *item; +{ + if (*list == item) + *list = next(item); + if (prev(item) != NULL) item->l_prev->l_next = next(item); + if (next(item) != NULL) item->l_next->l_prev = prev(item); + item->l_next = NULL; + item->l_prev = NULL; +} + +/* + * _attach: + * add an item to the head of a list + */ + +_attach(list, item) +register struct linked_list **list, *item; +{ + if (*list != NULL) + { + item->l_next = *list; + (*list)->l_prev = item; + item->l_prev = NULL; + } + else + { + item->l_next = NULL; + item->l_prev = NULL; + } + + *list = item; +} + +/* + * o_free_list: + * Throw the whole object list away + */ + +_o_free_list(ptr) +register struct linked_list **ptr; +{ + register struct linked_list *item; + + while (*ptr != NULL) + { + item = *ptr; + *ptr = next(item); + o_discard(item); + } +} + +/* + * o_discard: + * free up an item and its object(and maybe contents) + */ + +o_discard(item) +register struct linked_list *item; +{ + register struct object *obj; + + obj = OBJPTR(item); + if (obj->contents != NULL) + o_free_list(obj->contents); + total -= 2; + FREE(obj); + FREE(item); +} + +/* + r_free_fire_list + Throw the whole list of fire monsters away. But don't + discard the item (monster) itself as that belong to mlist. +*/ + +_r_free_fire_list(ptr) +register struct linked_list **ptr; +{ + register struct linked_list *item; + + while (*ptr != NULL) + { + item = *ptr; + *ptr = next(item); + free(item); + } +} +/* + * r_free_list: + * Throw the whole list of room exits away + */ + +_r_free_list(ptr) +register struct linked_list **ptr; +{ + register struct linked_list *item; + + while (*ptr != NULL) + { + item = *ptr; + *ptr = next(item); + r_discard(item); + } +} + +/* + * r_discard: + * free up an item and its room + */ + +r_discard(item) +register struct linked_list *item; +{ + total -= 2; + FREE(DOORPTR(item)); + FREE(item); +} + +/* + * t_free_list: + * Throw the whole thing list away + */ + +_t_free_list(ptr) +register struct linked_list **ptr; +{ + register struct linked_list *item; + + while (*ptr != NULL) + { + item = *ptr; + *ptr = next(item); + t_discard(item); + } +} + +/* + * t_discard: + * free up an item and its thing + */ + +t_discard(item) +register struct linked_list *item; +{ + register struct thing *tp; + + total -= 2; + tp = THINGPTR(item); + if (tp->t_name != NULL) FREE(tp->t_name); + if (tp->t_pack != NULL) + o_free_list(tp->t_pack); + FREE(tp); + FREE(item); +} + +/* + * destroy_item: + * get rid of an item structure -- don't worry about contents + */ + +destroy_item(item) +register struct linked_list *item; +{ + total--; + FREE(item); +} + +/* + * new_item + * get a new item with a specified size + */ + +struct linked_list * +new_item(size) +int size; +{ + register struct linked_list *item; + + if ((item = (struct linked_list *) new(sizeof *item)) == NULL) + msg("Ran out of memory for header after %d items", total); + if ((item->l_data = new(size)) == NULL) + msg("Ran out of memory for data after %d items", total); + item->l_next = item->l_prev = NULL; + memset(item->l_data,0,size); + return item; +} + +/* + * creat_item: + * Create just an item structure -- don't make any contents + */ + +struct linked_list * +creat_item() +{ + register struct linked_list *item; + + if ((item = (struct linked_list *) new(sizeof *item)) == NULL) + msg("Ran out of memory for header after %d items", total); + item->l_next = item->l_prev = NULL; + return item; +} + +char * +new(size) +int size; +{ + register char *space = ALLOC(size); + + if (space == NULL) { + sprintf(prbuf,"Rogue ran out of memory (used = %d, wanted = %d).", + md_memused(), size); + fatal(prbuf); + } + total++; + return space; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/mach_dep.h Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,59 @@ +/* + mach_dep.h - machine dependents + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +/* + * define/undefine that the wizard commands exist + */ +#undef WIZARD + +#if defined(_WIN32) +#define fstat _fstat +#define stat _stat +#define open _open +#define popen _popen +#define pclose _pclose +#if !defined(__MINGW32__) +#define PATH_MAX _MAX_PATH +#endif +#endif + +#define NOOP(x) (x += 0) + +extern char *md_getusername(); +extern char *md_gethomedir(); +extern char *md_getroguedir(); +extern void md_flushinp(); +extern char *md_getshell(); +extern char *md_gethostname(); +extern void md_dobinaryio(); +extern char *md_getpass(); +extern void md_init(); +extern char *xcrypt(); + +/* + * define if you want to limit scores to one per class per userid + */ + +/* #define LIMITSCORE 1*/ +#undef LIMITSCORE + +/* + * fudge factor allowed in time for saved game + */ + +#define FUDGE_TIME 200
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/main.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,472 @@ +/* + main.c - setup code + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <stdlib.h> +#include <string.h> +#include <curses.h> +#include <signal.h> +#include <time.h> + +#include "mach_dep.h" +#include "network.h" +#include "rogue.h" + +#define SCOREFILE "xrogue.scr" +#define SAVEDIR "." + +main(argc, argv, envp) +char **argv; +char **envp; +{ + register char *env; + time_t now; + + md_init(); + + /* + * get home and options from environment + */ + + strncpy(home, md_gethomedir(), LINELEN); + + /* Get default save file */ + strcpy(file_name, home); + strcat(file_name, "xrogue.sav"); + + /* Get default score file */ +#ifdef SCOREFILE + strncpy(score_file, SCOREFILE, LINELEN); + score_file[LINELEN-1] = '\0'; +#else + strcpy(score_file, md_getroguedir()); + + if (*score_file) + strcat(score_file,"/"); + + strcat(score_file, "xrogue.scr"); +#endif + +#ifdef SAVEDIR + /* Check for common save location */ + if (argc >= 3 && strcmp(argv[1], "-n") == 0) + { + strncpy(whoami, argv[2], 79); + whoami[79] = '\0'; + use_savedir = TRUE; + if (LINELEN <= snprintf(file_name, LINELEN, "%s/%d-%s.xrsav", SAVEDIR, + md_getuid(), whoami)) + { + strcpy(file_name, "xrogue.sav"); + use_savedir = FALSE; + } + } +#endif + + if ((env = getenv("ROGUEOPTS")) != NULL) + parse_opts(env); + + if (whoami[0] == '\0') + strucpy(whoami, md_getusername(), strlen(md_getusername())); + + /* + * check for print-score option + */ + if (argc == 2 && strcmp(argv[1], "-s") == 0) + { + waswizard = TRUE; + score((long)0, SCOREIT, (short)0); + exit_game(0); + } + + /* + * Check for a network update + */ + if (argc == 2 && strcmp(argv[1], "-u") == 0) { + int errcheck, errors = 0; + unsigned long amount; + short monster; + + /* Read in the amount and monster values to pass to score */ + amount = netread(&errcheck, sizeof(unsigned long), stdin); + if (errcheck) errors++; + + monster = (short) netread(&errcheck, sizeof(short), stdin); + if (errcheck) errors++; + + /* Now do the update if there were no errors */ + if (errors) exit_game(0); + else { + score((long)amount, UPDATE, (short)monster); + exit_game(0); + } + } + + /* + * Check to see if he is a wizard + */ +#ifdef WIZARD + if (argc >= 2 && argv[1][0] == '\0') + if (strcmp(PASSWD, xcrypt(md_getpass("Wizard's password: "), "mT")) == 0) + { + wizard = TRUE; + argv++; + argc--; + } +#endif + + if (betaover()) + { + printf("Sorry, %s, but the test period of this prerelease version\n",whoami); + printf("of xrogue is over. Please acquire a new version. Sorry.\n"); + exit_game(0); + } + + if (!wizard && !author() && !playtime()) { + printf("Sorry, %s, but you can't play during working hours.\n", whoami); + printf("Try again later.\n"); + exit_game(0); + } + if (!wizard && !author() && too_much()) { + printf("Sorry, %s, but the system is too loaded now.\n", whoami); + printf("Try again later.\n"); + exit_game(0); + } + + if (use_savedir) + { + /* restore() will return TRUE if a new game should be started. */ + if (!restore(file_name, envp)) + exit_game(0); + } + if (argc == 2) + if (!restore(argv[1], envp)) /* Note: restore will never return */ + exit_game(0); + + if (wizard && getenv("SEED") != NULL) { + seed = atoi(getenv("SEED")); + } + else { + seed = (int) time(&now) + getpid(); + } + if (wizard) + printf("Hello %s, welcome to dungeon #%d", whoami, seed); + else + printf("Hello %s, just a moment while I dig the dungeon...", whoami); + fflush(stdout); + + md_srand(seed); + + init_things(); /* Set up probabilities of things */ + init_colors(); /* Set up colors of potions */ + init_stones(); /* Set up stone settings of rings */ + init_materials(); /* Set up materials of wands */ + init_names(); /* Set up names of scrolls */ + init_misc(); /* Set up miscellaneous magic */ + init_foods(); /* set up the food table */ + + initscr(); /* Start up cursor package */ + + typeahead(-1); /* turn off 3.2/4.0 curses feature */ + + if (COLS < MINCOLS) + { + printf("\n\nSorry, %s, but your terminal window has too few columns.\n", whoami); + printf("Your terminal has %d columns, needs 70.\n",COLS); + byebye(0); + } + if (LINES < MINLINES) + { + printf("\n\nSorry, %s, but your terminal window has too few lines.\n", whoami); + printf("Your terminal has %d lines, needs 22.\n",LINES); + byebye(0); + } + + cols = COLS; + lines = LINES; + + if ( cols % 2 != 0) cols -=1; /* must be even for maze code */ + if (lines % 2 != 0) lines -=1; /* must be even for maze code */ + + /* + * Now that we have cols and lines, we can update our window + * structure for non-hardware windows. + */ + setup(); + /* + * Set up windows + */ + cw = newwin(lines, cols, 0, 0); + mw = newwin(lines, cols, 0, 0); + hw = newwin(lines, cols, 0, 0); + msgw = newwin(4, cols, 0, 0); + if (cw == NULL || hw == NULL || mw == NULL || msgw == NULL) { + exit_game(EXIT_CLS | EXIT_ENDWIN); + } + + keypad(cw, TRUE); + keypad(hw, TRUE); + + init_player(); /* Roll up the rogue */ + waswizard = wizard; + + draw(cw); + /* A super wizard doesn't have to get equipped */ + /* Check if "" option is TRUE and get environment flag */ + if (wizard && strcmp(getenv("SUPER"),"YES") == 0 || + def_attr == TRUE) { + level = 1; + new_level(NORMLEV); + } + else + new_level(STARTLEV); /* Draw current level */ + + /* + * Start up daemons and fuses + */ + daemon(doctor, &player, AFTER); + fuse(swander, (VOID *)NULL, WANDERTIME, AFTER); + /* Give characters their innate abilities */ + if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_RANGER) + fuse(spell_recovery, (VOID *)NULL, SPELLTIME, AFTER); + if (player.t_ctype == C_DRUID || player.t_ctype == C_MONK) + fuse(chant_recovery, (VOID *)NULL, SPELLTIME, AFTER); + if (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN) + fuse(prayer_recovery, (VOID *)NULL, SPELLTIME, AFTER); + daemon(stomach, (VOID *)NULL, AFTER); + if (player.t_ctype == C_THIEF || + player.t_ctype == C_ASSASSIN || + player.t_ctype == C_MONK) + daemon(trap_look, (VOID *)NULL, AFTER); + + /* Does this character have any special knowledge? */ + switch (player.t_ctype) { + case C_ASSASSIN: + /* Assassins automatically recognize poison */ + p_know[P_POISON] = TRUE; + when C_FIGHTER: + /* Fighters automatically recognize skill */ + p_know[P_SKILL] = TRUE; + } + + /* Choose an initial quest item */ + if (!wizard) { + if (def_attr == FALSE) + quest_item = rnd(MAXRELIC); + } + mpos = 0; + draw(cw); + msg("You have been quested to retrieve the %s....", + rel_magic[quest_item].mi_name); + mpos = 0; + playit(); +} + +/* + * endit: + * Exit the program abnormally. + */ + +/*UNUSED*/ +void +endit(sig) +int sig; +{ + NOOP(sig); + fatal("Ok, if you want to exit that badly, I'll have to allow it\n"); +} + +/* + * fatal: + * Exit the program, printing a message. + */ + +fatal(s) +char *s; +{ + clear(); + move(lines-2, 0); + printw("%s", s); + draw(stdscr); + printf("\n"); /* So the curser doesn't stop at the end of the line */ + exit_game(EXIT_ENDWIN); +} + +/* + * rnd: + * Pick a very random number. + */ + +rnd(range) +register int range; +{ + return( md_rand(range) ); +} + +/* + * roll: + * roll a number of dice + */ + +roll(number, sides) +register int number, sides; +{ + register int dtotal = 0; + + while(number--) + dtotal += rnd(sides)+1; + return dtotal; +} + +setup() +{ + md_setup(); +} + +/* + * playit: + * The main loop of the program. Loop until the game is over, + * refreshing things and looking at the proper times. + */ + +playit() +{ + register char *opts; + + /* + * parse environment declaration of options + */ + if ((opts = getenv("ROGUEOPTS")) != NULL) + parse_opts(opts); + + player.t_oldpos = hero; + oldrp = roomin(&hero); + after = TRUE; + command(); /* Command execution */ + endit(-1); +} + +/* + * see if the system is being used too much for this game + */ + +too_much() +{ + /* we no longer do load checking or user counts */ + return(FALSE); +} + +/* + * author: + * See if a user is an author of the program + */ + +author() +{ + switch (md_getuid()) { + case 0: /* always OK for root to play */ + return TRUE; + default: + return FALSE; + } +} + +/* + * playtime: + * Returns TRUE when it is a good time to play rogue + */ + +playtime() +{ + /* we no longer do playtime checking */ + + return TRUE; +} + +/* + * betaover: + * Returns TRUE if the test period of this version of the game is over + */ + +betaover() +{ + return(FALSE); +} + + +exit_game(flag) +int flag; +{ + int i; + + if (flag & EXIT_CLS) /* Clear Screen */ + { + wclear(cw); + draw(cw); + } + + if (flag & EXIT_ENDWIN) /* Shutdown Curses */ + { + keypad(cw,FALSE); + keypad(hw,FALSE); + delwin(cw); + delwin(mw); + delwin(hw); + delwin(msgw); + if (!isendwin()) + endwin(); + } + o_free_list(player.t_pack); + t_free_list(mlist); + t_free_list(rlist); + t_free_list(tlist); + o_free_list(lvl_obj); /* Free up previous objects (if any) */ + for (i = 0; i < MAXROOMS; i++) + { + r_free_list(rooms[i].r_exit); /* Free up the exit lists */ + _r_free_fire_list(&rooms[i].r_fires); + } + + for(i=0; i<MAXSCROLLS; i++) + { + if (s_names[i] != NULL) + free( s_names[i] ); + if (s_guess[i] != NULL) + free( s_guess[i] ); + } + + for(i=0; i<MAXPOTIONS; i++) + { + if (p_guess[i] != NULL) + free( p_guess[i] ); + } + + for(i=0; i<MAXRINGS; i++) + { + if (r_guess[i] != NULL) + free( r_guess[i] ); + } + + for(i=0; i<MAXSTICKS; i++) + { + if (ws_guess[i] != NULL) + free( ws_guess[i] ); + } + + exit(0); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/maze.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,385 @@ +/* + maze.c - functions for dealing with mazes + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <stdlib.h> +#include <curses.h> +#include "rogue.h" + +struct cell { + char y_pos; + char x_pos; +}; +struct b_cellscells { + char num_pos; /* number of frontier cells next to you */ + struct cell conn[4]; /* the y,x position of above cell */ +} b_cells; + +static char *maze_frontier, *maze_bits; +static int maze_lines, maze_cols; +static char *moffset(), *foffset(); +static int rmwall(),findcells(),crankout(),draw_maze(); + +/* + * crankout: + * Does actual drawing of maze to window + */ + +static +crankout() +{ + reg int x, y; + + for (y = 0; y < lines - 3; y++) { + move(y + 1, 0); + for (x = 0; x < cols - 1; x++) { + if (*moffset(y, x)) { /* here is a wall */ + if(y==0 || y==lines-4) /* top or bottom line */ + addch(HORZWALL); + else if(x==0 || x==cols-2) /* left | right side */ + addch(VERTWALL); + else if (y % 2 == 0 && x % 2 == 0) { + if(*moffset(y, x-1) || *moffset(y, x+1)) + addch(HORZWALL); + else + addch(VERTWALL); + } + else if (y % 2 == 0) + addch(HORZWALL); + else + addch(VERTWALL); + } + else + addch(FLOOR); + } + } +} + +/* + * domaze: + * Draw the maze on this level. + */ + +do_maze() +{ + reg int least; + reg struct room *rp; + reg struct linked_list *item; + reg struct object *obj; + int cnt; + bool treas; + coord tp; + + for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) { + rp->r_flags = ISGONE; /* kill all rooms */ + rp->r_fires = NULL; /* no fires */ + } + rp = &rooms[0]; /* point to only room */ + rp->r_flags = ISDARK; /* mazes always dark */ + rp->r_pos.x = 0; /* room fills whole screen */ + rp->r_pos.y = 1; + rp->r_max.x = cols - 1; + rp->r_max.y = lines - 3; + draw_maze(); /* put maze into window */ + /* + * add some gold to make it worth looking for + */ + item = spec_item(GOLD, NULL, NULL, NULL); + obj = OBJPTR(item); + obj->o_count *= (rnd(50) + 50); /* add in one large hunk */ + attach(lvl_obj, item); + cnt = 0; + do { + rnd_pos(rp, &tp); + } until (mvinch(tp.y, tp.x) == FLOOR || cnt++ > 2500); + mvaddch(tp.y, tp.x, GOLD); + obj->o_pos = tp; + /* + * add in some food to make sure he has enough + */ + item = spec_item(FOOD, NULL, NULL, NULL); + obj = OBJPTR(item); + attach(lvl_obj, item); + do { + rnd_pos(rp, &tp); + } until (mvinch(tp.y, tp.x) == FLOOR || cnt++ > 2500); + mvaddch(tp.y, tp.x, FOOD); + obj->o_pos = tp; + + /* it doesn't mater if it's a treasure maze or a normal maze, + * more than enough monsters will be genned. + */ + least = rnd(11)+5; + if (least < 6) { + least = 7; + treas = FALSE; + } + else treas = TRUE; + genmonsters(least, treas); + + /* sometimes they're real angry */ + if (rnd(100) < 65) { + /* protect the good charactors */ + if (player.t_ctype == C_PALADIN || + player.t_ctype == C_RANGER || player.t_ctype == C_MONK) { + aggravate(TRUE, FALSE); + } + else { + aggravate(TRUE, TRUE); + } + } +} + +/* + * draw_maze: + * Generate and draw the maze on the screen + */ + +static +draw_maze() +{ + reg int i, j, more; + reg char *ptr; + + maze_lines = (lines - 3) / 2; + maze_cols = (cols - 1) / 2; + maze_bits = ALLOC((lines - 3) * (cols - 1)); + maze_frontier = ALLOC(maze_lines * maze_cols); + ptr = maze_frontier; + while (ptr < (maze_frontier + (maze_lines * maze_cols))) + *ptr++ = TRUE; + for (i = 0; i < lines - 3; i++) { + for (j = 0; j < cols - 1; j++) { + if (i % 2 == 1 && j % 2 == 1) + *moffset(i, j) = FALSE; /* floor */ + else + *moffset(i, j) = TRUE; /* wall */ + } + } + for (i = 0; i < maze_lines; i++) { + for (j = 0; j < maze_cols; j++) { + do + more = findcells(i,j); + while(more != 0); + } + } + crankout(); + FREE(maze_frontier); + FREE(maze_bits); +} + +/* + * findcells: + * Figure out cells to open up + */ + +static findcells(y,x) +reg int x, y; +{ + reg int rtpos, i; + + *foffset(y, x) = FALSE; + b_cells.num_pos = 0; + if (y < maze_lines - 1) { /* look below */ + if (*foffset(y + 1, x)) { + b_cells.conn[b_cells.num_pos].y_pos = y + 1; + b_cells.conn[b_cells.num_pos].x_pos = x; + b_cells.num_pos += 1; + } + } + if (y > 0) { /* look above */ + if (*foffset(y - 1, x)) { + b_cells.conn[b_cells.num_pos].y_pos = y - 1; + b_cells.conn[b_cells.num_pos].x_pos = x; + b_cells.num_pos += 1; + + } + } + if (x < maze_cols - 1) { /* look right */ + if (*foffset(y, x + 1)) { + b_cells.conn[b_cells.num_pos].y_pos = y; + b_cells.conn[b_cells.num_pos].x_pos = x + 1; + b_cells.num_pos += 1; + } + } + if (x > 0) { /* look left */ + if (*foffset(y, x - 1)) { + b_cells.conn[b_cells.num_pos].y_pos = y; + b_cells.conn[b_cells.num_pos].x_pos = x - 1; + b_cells.num_pos += 1; + + } + } + if (b_cells.num_pos == 0) /* no neighbors available */ + return 0; + else { + i = rnd(b_cells.num_pos); + rtpos = b_cells.num_pos - 1; + rmwall(b_cells.conn[i].y_pos, b_cells.conn[i].x_pos, y, x); + return rtpos; + } +} + +/* + * foffset: + * Calculate memory address for frontier + */ + +static char * +foffset(y, x) +int y, x; +{ + + return (maze_frontier + (y * maze_cols) + x); +} + + +/* + * Maze_view: + * Returns true if the player can see the specified location within + * the confines of a maze (within one column or row) + */ + +bool +maze_view(y, x) +int y, x; +{ + register int start, goal, delta, ycheck = 0, xcheck = 0, absy, absx, see_radius; + register bool row; + + /* Get the absolute value of y and x differences */ + absy = hero.y - y; + absx = hero.x - x; + if (absy < 0) absy = -absy; + if (absx < 0) absx = -absx; + + /* If we are standing in a wall, we can see a bit more */ + switch (winat(hero.y, hero.x)) { + case VERTWALL: + case HORZWALL: + case WALL: + case SECRETDOOR: + case DOOR: + see_radius = 2; + otherwise: + see_radius = 1; + } + + /* Must be within one or two rows or columns */ + if (absy > see_radius && absx > see_radius) return(FALSE); + + if (absx > see_radius) { /* Go along row */ + start = hero.x; + goal = x; + ycheck = hero.y; + row = TRUE; + } + else { /* Go along column */ + start = hero.y; + goal = y; + xcheck = hero.x; + row = FALSE; + } + + if (start <= goal) delta = 1; + else delta = -1; + + /* Start one past where we are standing */ + if (start != goal) start += delta; + + /* If we are in a wall, we want to look in the area outside the wall */ + if (see_radius > 1) { + if (row) { + /* See if above us it okay first */ + switch (winat(ycheck, start)) { + case VERTWALL: + case HORZWALL: + case WALL: + case DOOR: + case SECRETDOOR: + /* No good, try one up */ + if (y > hero.y) ycheck++; + else ycheck--; + otherwise: + see_radius = 1; /* Just look straight over the row */ + } + } + else { + /* See if above us it okay first */ + switch (winat(start, xcheck)) { + case VERTWALL: + case HORZWALL: + case WALL: + case DOOR: + case SECRETDOOR: + /* No good, try one over */ + if (x > hero.x) xcheck++; + else xcheck--; + otherwise: + see_radius = 1; /* Just look straight up the column */ + } + } + } + + /* Check boundary again */ + if (absy > see_radius && absx > see_radius) return(FALSE); + + while (start != goal) { + if (row) xcheck = start; + else ycheck = start; + + if (xcheck < 0 || ycheck < 0) + return FALSE; + switch (winat(ycheck, xcheck)) { + case VERTWALL: + case HORZWALL: + case WALL: + case DOOR: + case SECRETDOOR: + return(FALSE); + } + start += delta; + } + return(TRUE); +} + + +/* + * moffset: + * Calculate memory address for bits + */ + +static char * +moffset(y, x) +int y, x; +{ + return (maze_bits + (y * (cols - 1)) + x); +} + +/* + * rmwall: + * Removes appropriate walls from the maze + */ +static +rmwall(newy, newx, oldy, oldx) +int newy, newx, oldy, oldx; +{ + reg int xdif,ydif; + + xdif = newx - oldx; + ydif = newy - oldy; + + *moffset((oldy * 2) + ydif + 1, (oldx * 2) + xdif + 1) = FALSE; + findcells(newy, newx); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/misc.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1298 @@ +/* + misc.c - routines dealing specifically with miscellaneous magic + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <stdlib.h> +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" + +/* + * changeclass: + * Change the player's class to the specified one. + */ + +changeclass(newclass) +long *newclass; +{ + if (*newclass == player.t_ctype) { + msg("You feel more skillful."); + raise_level(); + } + else { + /* + * reset his class and then use check_level to reset hit + * points and the right level for his exp pts + * drop exp pts by 10% + */ + long save; + + msg("You are transformed into a %s! ", char_class[*newclass].name); + + /* + * if he becomes a thief or an assassin give him studded leather armor + */ + if ((*newclass == C_THIEF || *newclass == C_ASSASSIN) && + cur_armor != NULL && cur_armor->o_which != STUDDED_LEATHER) + cur_armor->o_which = STUDDED_LEATHER; + /* + * if he becomes a monk he can't wear any armor + * so give him a cloak of protection + */ + if (*newclass == C_MONK && cur_armor != NULL) { + cur_armor->o_ac = armors[cur_armor->o_which].a_class - + cur_armor->o_ac; + cur_armor->o_type = MM; + cur_armor->o_which = MM_PROTECT; + cur_armor->o_flags &= ~(ISPROT | ISKNOW); + cur_misc[WEAR_CLOAK] = cur_armor; + cur_armor = NULL; + } + /* + * otherwise give him plate armor + */ + if ((*newclass != C_THIEF || + *newclass != C_ASSASSIN || *newclass != C_MONK) && + cur_armor != NULL && cur_armor->o_which != PLATE_ARMOR) + cur_armor->o_which = PLATE_ARMOR; + + /* + * if he used to be a spell caster of some sort, kill the fuse + */ + if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_RANGER) + extinguish(spell_recovery); + if (player.t_ctype == C_DRUID || player.t_ctype == C_MONK) + extinguish(chant_recovery); + if ((player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN) && + !cur_relic[HEIL_ANKH]) + extinguish(prayer_recovery); + + /* + * if he becomes a spell caster of some kind, give him a fuse + */ + if (*newclass == C_MAGICIAN || *newclass == C_RANGER) + fuse(spell_recovery, (VOID *)NULL, SPELLTIME, AFTER); + if (*newclass == C_DRUID || *newclass == C_MONK) + fuse(chant_recovery, (VOID *)NULL, SPELLTIME, AFTER); + if ((*newclass==C_CLERIC || *newclass==C_PALADIN) && !cur_misc[HEIL_ANKH]) + fuse(prayer_recovery, (VOID *)NULL, SPELLTIME, AFTER); + /* + * if he's changing from a fighter, ranger, or paladin then we + * may have to change his sword since only these types can wield + * the two-handed sword. + */ + if ((player.t_ctype == C_FIGHTER || + player.t_ctype == C_RANGER || + player.t_ctype == C_PALADIN) && + cur_weapon != NULL && cur_weapon->o_type == WEAPON && + (cur_weapon->o_which == BASWORD || + cur_weapon->o_which == TWOSWORD) && + !(*newclass == C_FIGHTER || *newclass == C_RANGER || + *newclass == C_PALADIN) && + cur_weapon->o_which == TWOSWORD) + cur_weapon->o_which = SWORD; + + /* + * if he's changing from a thief, assassin, fighter, or monk + * then we may have to change his sword again since only these + * types can wield the bastard sword. + */ + if ((player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || + player.t_ctype == C_FIGHTER || player.t_ctype == C_MONK) && + cur_weapon != NULL && cur_weapon->o_type == WEAPON && + (cur_weapon->o_which == BASWORD || + cur_weapon->o_which == TWOSWORD) && + !(*newclass == C_THIEF || *newclass == C_ASSASSIN || + *newclass == C_MONK) && + cur_weapon->o_which == BASWORD) + cur_weapon->o_which = SWORD; + + /* + * if he was a thief, assassin, or monk then take out + * the trap_look() daemon + */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_MONK || + player.t_ctype == C_ASSASSIN) + kill_daemon(trap_look); + + /* + * if he becomes a thief, assassin, or monk then add + * the trap_look() daemon + */ + if (*newclass == C_THIEF || *newclass == C_ASSASSIN || + *newclass == C_MONK) + daemon(trap_look, (VOID *)NULL, AFTER); + + /* adjust stats */ + char_type = player.t_ctype = *newclass; + save = pstats.s_hpt; + max_stats.s_hpt = pstats.s_hpt = 0; + max_stats.s_lvl = pstats.s_lvl = 0; + max_stats.s_lvladj = pstats.s_lvladj = 0; + max_stats.s_exp = pstats.s_exp + rnd(4); + check_level(); + if (pstats.s_hpt > save) /* don't add to current hits */ + pstats.s_hpt = save; + } + dsrpt_player(); /* this should disrupt whatever we were doing */ +} + +/* + * Use the relic that our monster is wielding. + */ + +m_use_relic(monster) +register struct thing *monster; +{ + register struct object *obj; + + /* Make sure we really have it */ + if (monster->t_using) obj = OBJPTR(monster->t_using); + else { + debug("Relic not set!"); + monster->t_action = A_NIL; + return; + } + + /* Now let's see what we're using */ + if (obj->o_type == RELIC) switch (obj->o_which) { + case MING_STAFF: { + static struct object missile = { + MISSILE, {0,0}, 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1 + }; + + debug("Firing Ming's staff"); + sprintf(missile.o_hurldmg, "%dd4", monster->t_stats.s_lvl); + do_motion(&missile, + monster->t_newpos.y, monster->t_newpos.x, monster); + hit_monster(unc(missile.o_pos), &missile, monster); + monster->t_artifact = monster->t_artifact * 4 / 5; + } + when EMORI_CLOAK: + debug("stunning with Emori's cloak"); + do_zap(monster, obj, &monster->t_newpos, WS_PARALYZE, NULL); + obj->o_charges = 0; + + when ASMO_ROD: { + char *name; + + switch (rnd(3)) { /* Select a function */ + case 0: name = "lightning bolt"; + when 1: name = "flame"; + otherwise: name = "ice"; + } + shoot_bolt( monster, + monster->t_pos, + monster->t_newpos, + FALSE, + monster->t_index, + name, + roll(monster->t_stats.s_lvl,6)); + monster->t_artifact /= 2; + } + when BRIAN_MANDOLIN: + /* Make sure the defendant is still around */ + if (DISTANCE(monster->t_pos.y, monster->t_pos.x, + hero.y, hero.x) < 25) { + if (!save(VS_MAGIC, &player, -4) && + !ISWEARING(R_ALERT)) { + msg("Some beautiful music enthralls you."); + player.t_no_move += movement(&player) * FREEZETIME; + player.t_action = A_FREEZE; + monster->t_artifact = monster->t_artifact * 2 / 3; + } + else { + msg("You wince at a sour note."); + monster->t_artifact /= 3; + } + } + when GERYON_HORN: + /* Make sure the defendant is still around */ + if (DISTANCE(monster->t_pos.y, monster->t_pos.x, + hero.y, hero.x) < 25) { + if (!ISWEARING(R_HEROISM) && + !save(VS_MAGIC, &player, -4)) { + turn_on(player, ISFLEE); + player.t_dest = &monster->t_pos; + msg("A shrill blast terrifies you."); + monster->t_artifact = monster->t_artifact * 3 / 4; + } + else { + msg("A shrill blast sends chills up your spine! "); + monster->t_artifact /= 3; + } + } + + otherwise: + /* Unknown RELIC! */ + debug("Unknown wielded relic %d", obj->o_which); + } + else debug("Declared relic is %d", obj->o_type); + + turn_off(*monster, CANSURPRISE); + /* Reset the monsters actions */ + monster->t_action = A_NIL; + monster->t_using = NULL; +} + +/* + * add something to the contents of something else + */ + +put_contents(bag, item) +register struct object *bag; /* the holder of the items */ +register struct linked_list *item; /* the item to put inside */ +{ + register struct linked_list *titem; + register struct object *tobj; + + bag->o_ac++; + tobj = OBJPTR(item); + for (titem = bag->contents; titem != NULL; titem = next(titem)) { + if ((OBJPTR(titem))->o_which == tobj->o_which) + break; + } + if (titem == NULL) { /* if not a duplicate put at beginning */ + attach(bag->contents, item); + } + else { + item->l_prev = titem; + item->l_next = titem->l_next; + if (next(titem) != NULL) + (titem->l_next)->l_prev = item; + titem->l_next = item; + } +} + +/* + * remove something from something else + */ + +take_contents(bag, item) +register struct object *bag; /* the holder of the items */ +register struct linked_list *item; +{ + + if (bag->o_ac <= 0) { + msg("Nothing to take out"); + return; + } + bag->o_ac--; + detach(bag->contents, item); + if (!add_pack(item, FALSE)) + put_contents(bag, item); +} + + +do_bag(item) +register struct linked_list *item; +{ + + register struct linked_list *titem = NULL; + register struct object *obj, *tobj; + bool doit = TRUE; + + obj = OBJPTR(item); + while (doit) { + msg("What do you want to do? (* for a list): "); + mpos = 0; + switch (wgetch(cw)) { + case EOF: + case ESC: + msg (""); + doit = FALSE; + when '1': + inventory(obj->contents, ALL); + + when '2': + if (obj->o_ac >= MAXCONTENTS) { + msg("the %s is full", m_magic[obj->o_which].mi_name); + break; + } + switch (obj->o_which) { + case MM_BEAKER: + titem = get_item(pack, "put in", POTION, FALSE, FALSE); + when MM_BOOK: + titem = get_item(pack, "put in", SCROLL, FALSE, FALSE); + } + if (titem == NULL) + break; + detach(pack, titem); + inpack--; + put_contents(obj, titem); + + when '3': + titem = get_item(obj->contents,"take out",ALL,FALSE,FALSE); + if (titem == NULL) + break; + take_contents(obj, titem); + + when '4': + switch (obj->o_which) { + case MM_BEAKER: + titem = get_item(obj->contents,"quaff",ALL,FALSE,FALSE); + if (titem == NULL) + break; + tobj = OBJPTR(titem); + obj->o_ac--; + detach(obj->contents, titem); + quaff(tobj->o_which, + tobj->o_kind, + tobj->o_flags, + TRUE); + if (p_know[tobj->o_which] && p_guess[tobj->o_which]) + { + free(p_guess[tobj->o_which]); + p_guess[tobj->o_which] = NULL; + } + else if (!p_know[tobj->o_which] && + askme && + (tobj->o_flags & ISKNOW) == 0 && + (tobj->o_flags & ISPOST) == 0 && + p_guess[tobj->o_which] == NULL) { + nameitem(titem, FALSE); + } + o_discard(titem); + when MM_BOOK: + if (on(player, ISBLIND)) { + msg("You can't see to read anything! "); + break; + } + titem = get_item(obj->contents,"read",ALL,FALSE,FALSE); + if (titem == NULL) + break; + tobj = OBJPTR(titem); + obj->o_ac--; + detach(obj->contents, titem); + read_scroll(tobj->o_which, + tobj->o_flags & (ISCURSED|ISBLESSED), + TRUE); + if (s_know[tobj->o_which] && s_guess[tobj->o_which]) + { + free(s_guess[tobj->o_which]); + s_guess[tobj->o_which] = NULL; + } + else if (!s_know[tobj->o_which] && + askme && + (tobj->o_flags & ISKNOW) == 0 && + (tobj->o_flags & ISPOST) == 0 && + s_guess[tobj->o_which] == NULL) { + nameitem(titem, FALSE); + } + o_discard(titem); + } + doit = FALSE; + + otherwise: + wclear(hw); + touchwin(hw); + mvwaddstr(hw,0,0,"The following operations are available:"); + mvwaddstr(hw,2,0,"[1]\tInventory\n"); + wprintw(hw,"[2]\tPut something in the %s\n", + m_magic[obj->o_which].mi_name); + wprintw(hw,"[3]\tTake something out of the %s\n", + m_magic[obj->o_which].mi_name); + switch(obj->o_which) { + case MM_BEAKER: waddstr(hw,"[4]\tQuaff a potion\n"); + when MM_BOOK: waddstr(hw,"[4]\tRead a scroll\n"); + } + /* this is confusing! <press space to continue> */ + /* waddstr(hw,"[ESC]\tLeave this menu\n"); */ + mvwaddstr(hw, lines-1, 0, spacemsg); + draw(hw); + wait_for (' '); + restscr(cw); + } + } +} + +do_panic(who) +int who; /* Kind of monster to panic (all if who is NULL) */ +{ + register int x,y; + register struct linked_list *mon, *item; + register struct thing *th; + + for (x = hero.x-2; x <= hero.x+2; x++) { + for (y = hero.y-2; y <= hero.y+2; y++) { + if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1) + continue; + if (isalpha(mvwinch(mw, y, x))) { + + if ((mon = find_mons(y, x)) != NULL) { + th = THINGPTR(mon); + + /* Is this the right kind of monster to panic? */ + if (who && th->t_index != who) continue; + + if ((who && th->t_stats.s_intel < 14) || + (!on(*th, ISUNDEAD) && !save(VS_MAGIC, th, 0) && + off(*th, WASTURNED))) { + msg("%s %s.", prname(monster_name(th), TRUE), + terse ? "panics" : "turns to run in panic"); + + turn_on(*th, ISFLEE); + turn_on(*th, WASTURNED); + turn_off(*th, CANSURPRISE); + + /* Disrupt what it was doing */ + dsrpt_monster(th, TRUE, TRUE); + + /* If monster was suffocating, stop it */ + if (on(*th, DIDSUFFOCATE)) { + turn_off(*th, DIDSUFFOCATE); + extinguish(suffocate); + } + + /* If monster held us, stop it */ + if (on(*th, DIDHOLD) && (--hold_count == 0)) + turn_off(player, ISHELD); + turn_off(*th, DIDHOLD); + + /* + * if he has something he might drop it + */ + if ((item = th->t_pack) != NULL && + (OBJPTR(item))->o_type != RELIC && + rnd(100) < 67) { + detach(th->t_pack, item); + fall(item, FALSE); + } + + /* It is okay to turn tail */ + th->t_oldpos = th->t_pos; + } + runto(th, &hero); + } + } + } + } +} + +/* + * print miscellaneous magic bonuses + */ + +int +misc_name(str,obj) +char *str; +register struct object *obj; +{ + char buf1[LINELEN]; + + *str = 0; + buf1[0] = 0; + + if (!(obj->o_flags & ISKNOW)) + { + strcat(str,m_magic[obj->o_which].mi_name); + return(0); + } + + switch (obj->o_which) + { + case MM_BRACERS: + case MM_PROTECT: + strcat(str, num(obj->o_ac, 0)); + strcat(str, " "); + } + switch (obj->o_which) { + case MM_CRYSTAL: + if (obj->o_flags & ISBLESSED) + strcat(str, "glowing "); + } + switch (obj->o_which) { + case MM_G_OGRE: + case MM_G_DEXTERITY: + case MM_JEWEL: + case MM_STRANGLE: + case MM_R_POWERLESS: + case MM_DANCE: + if (obj->o_flags & ISCURSED) + strcat(str, "cursed "); + when MM_CRYSTAL: + if (obj->o_flags & ISCURSED) + strcat(str, "opaque "); + } + strcat(str, m_magic[obj->o_which].mi_name); + + switch (obj->o_which) + { + case MM_JUG: + if (obj->o_ac == JUG_EMPTY) + strcat(buf1, " [empty]"); + else if (p_know[obj->o_ac]) + sprintf(buf1, " [containing a potion of %s (%s)]", + p_magic[obj->o_ac].mi_name, + p_colors[obj->o_ac]); + else sprintf(buf1, " [containing a%s %s liquid]", + vowelstr(p_colors[obj->o_ac]), + p_colors[obj->o_ac]); + when MM_BEAKER: + case MM_BOOK: { + sprintf(buf1, " [containing %d]", obj->o_ac); + } + when MM_OPEN: + case MM_HUNGER: + sprintf(buf1, " [%d ring%s]", obj->o_charges, + obj->o_charges == 1 ? "" : "s"); + when MM_DRUMS: + sprintf(buf1, " [%d beat%s]", obj->o_charges, + obj->o_charges == 1 ? "" : "s"); + when MM_DISAPPEAR: + case MM_CHOKE: + sprintf(buf1, " [%d pinch%s]", obj->o_charges, + obj->o_charges == 1 ? "" : "es"); + when MM_KEOGHTOM: + sprintf(buf1, " [%d application%s]", obj->o_charges, + obj->o_charges == 1 ? "" : "s"); + when MM_SKILLS: + sprintf(buf1, " [%s]", char_class[obj->o_ac].name); + } + strcat(str, buf1); + + return(0); +} + +use_emori() +{ + char selection; /* Cloak function */ + int state = 0; /* Menu state */ + + msg("What do you want to do? (* for a list): "); + do { + selection = wgetch(cw); + switch (selection) { + case '*': + if (state != 1) { + wclear(hw); + touchwin(hw); + mvwaddstr(hw, 2, 0, "[1] Fly\n[2] Stop flying\n"); + waddstr(hw, "[3] Turn invisible\n[4] Turn Visible\n"); + mvwaddstr(hw, 0, 0, "What do you want to do? "); + draw(hw); + state = 1; /* Now in prompt window */ + } + break; + + case ESC: + if (state == 1) { + restscr(cw); + } + msg(""); + + after = FALSE; + return; + + when '1': + case '2': + case '3': + case '4': + if (state == 1) { /* In prompt window */ + restscr(cw); + } + + msg(""); + + state = 2; /* Finished */ + break; + + default: + if (state == 1) { /* In the prompt window */ + mvwaddstr(hw, 0, 0, + "Please enter a selection between 1 and 4: "); + draw(hw); + } + else { /* Normal window */ + mpos = 0; + msg("Please enter a selection between 1 and 4: "); + } + } + } while (state != 2); + + /* We now must have a selection between 1 and 4 */ + switch (selection) { + case '1': /* Fly */ + if (on(player, ISFLY)) { + extinguish(land); /* Extinguish in case of potion */ + msg("%slready flying.", terse ? "A" : "You are a"); + } + else { + msg("You feel lighter than air!"); + turn_on(player, ISFLY); + } + when '2': /* Stop flying */ + if (off(player, ISFLY)) + msg("%sot flying.", terse ? "N" : "You are n"); + else { + if (find_slot(land)) + msg("%sot flying by the cloak.", + terse ? "N" : "You are n"); + else land(); + } + when '3': /* Turn invisible */ + if (off(player, ISINVIS)) { + turn_on(player, ISINVIS); + msg("You have a tingling feeling all over your body. "); + PLAYER = IPLAYER; + light(&hero); + } + else { + extinguish(appear); /* Extinguish in case of potion */ + extinguish(dust_appear);/* dust of disappearance */ + msg("%slready invisible.", terse ? "A" : "You are a"); + } + when '4': /* Turn visible */ + if (off(player, ISINVIS)) + msg("%sot invisible.", terse ? "N" : "You are n"); + else { + if (find_slot(appear) || find_slot(dust_appear)) + msg("%sot invisible by the cloak.", + terse ? "N" : "You are n"); + else appear(); + } + } +} + +/* + * try to write a scroll with the quill of Nagrom + */ + +use_quill(obj) +struct object *obj; +{ + struct linked_list *item; + register int i, + scroll_ability; + int which_scroll, + curlen, + maxlen = 0, + dummy = 0; + bool nohw = FALSE; + + i = which_scroll = 0; + scroll_ability = obj->o_charges; + + /* Prompt for scrolls */ + msg("Which scroll are you writing? (* for list): "); + + which_scroll = (int) (wgetch(cw) - 'a'); + msg(""); /* Get rid of the prompt */ + if (which_scroll == (int) ESC - (int) 'a') { + after = FALSE; + return; + } + if (which_scroll >= 0 && which_scroll < MAXQUILL) nohw = TRUE; + + else if (slow_invent) { + register char c; + + nohw = TRUE; + do { + for (i=0; i<MAXQUILL; i++) { + msg(""); + mvwaddch(msgw, 0, 0, '['); + waddch(msgw, (char) ((int) 'a' + i)); + waddstr(msgw, "] A scroll of "); + waddstr(msgw, s_magic[quill_scrolls[i].s_which].mi_name); + waddstr(msgw, morestr); + clearok(msgw, FALSE); + draw(msgw); + do { + c = wgetch(cw); + } while (c != ' ' && c != ESC); + if (c == ESC) + break; + } + msg(""); + mvwaddstr(msgw, 0, 0, "Which scroll are you writing? "); + clearok(msgw, FALSE); + draw(msgw); + + which_scroll = (int) (wgetch(cw) - 'a'); + } while (which_scroll != (int) (ESC - 'a') && + (which_scroll < 0 || which_scroll >= MAXQUILL)); + + if (which_scroll == (int) (ESC - 'a')) { + mpos = 0; + msg(""); + after = FALSE; + return; + } + } + else { + /* Now display the possible scrolls */ + wclear(hw); + touchwin(hw); + mvwaddstr(hw, 2, 0, " Cost Scroll"); + mvwaddstr(hw, 3, 0, + "-----------------------------------------------"); + maxlen = 47; /* Maximum width of header */ + + for (i=0; i<MAXQUILL; i++) { + wmove(hw, i+4, 0); + sprintf(prbuf, "[%c] %3d A scroll of %s", + (char) ((int) 'a' + i), + quill_scrolls[i].s_cost, + s_magic[quill_scrolls[i].s_which].mi_name); + waddstr(hw, prbuf); + + /* Get the length of the line */ + getyx(hw, dummy, curlen); + if (maxlen < curlen) maxlen = curlen; + } + + sprintf(prbuf, "[Current scroll power = %d]", scroll_ability); + mvwaddstr(hw, 0, 0, prbuf); + waddstr(hw, " Which scroll are you writing? "); + getyx(hw, dummy, curlen); + if (maxlen < curlen) maxlen = curlen; + + /* Should we overlay? */ + if (menu_overlay && MAXQUILL + 3 < lines - 3) { + over_win(cw, hw, MAXQUILL + 5, maxlen + 3, 0, curlen, NULL); + } + else draw(hw); + } + + if (!nohw) { + which_scroll = (int) (wgetch(cw) - 'a'); + while (which_scroll < 0 || which_scroll >= MAXQUILL) { + if (which_scroll == (int) ESC - (int) 'a') { + after = FALSE; + + /* Restore the screen */ + if (MAXQUILL + 3 < lines / 2) { + clearok(cw, FALSE); + touchwin(cw); + } + else restscr(cw); + return; + } + wmove(hw, 0, 0); + wclrtoeol(hw); + waddstr(hw, "Please enter one of the listed scrolls. "); + getyx(hw, dummy, curlen); + if (maxlen < curlen) maxlen = curlen; + + /* Should we overlay? */ + if (menu_overlay && MAXQUILL + 3 < lines - 3) { + over_win(cw, hw, MAXQUILL + 5, maxlen + 3, + 0, curlen, NULL); + } + else draw(hw); + + which_scroll = (int) (wgetch(cw) - 'a'); + } + } + + /* Now restore the screen if we have to */ + if (!nohw) { + if (MAXQUILL + 3 < lines / 2) { + touchwin(cw); + clearok(cw, FALSE); + } + else restscr(cw); + } + + /* We've waited our required time. */ + player.t_using = NULL; + player.t_action = A_NIL; + + if (quill_scrolls[which_scroll].s_cost > scroll_ability) { + msg("Your attempt fails."); + return; + } + + obj->o_charges -= quill_scrolls[which_scroll].s_cost; + item = spec_item(SCROLL, quill_scrolls[which_scroll].s_which, 0, 0); + if (add_pack(item, FALSE) == FALSE) { + (OBJPTR(item))->o_pos = hero; + fall(item, TRUE); + } + + which_scroll = dummy; /* Hack to stop IRIX complaint about dummy not */ + /* being used */ +} + +/* + * Use something + */ + +use_mm(which) +int which; +{ + register struct object *obj = NULL; + register struct linked_list *item = NULL; + bool is_mm; + + is_mm = FALSE; + + if (which < 0) { /* A real miscellaneous magic item */ + /* This is miscellaneous magic. It takes 3 movement periods to use */ + if (player.t_action != C_USE) { + int units; /* Number of movement units for the item */ + + item = get_item(pack, "use", USEABLE, FALSE, FALSE); + + /* + * Make certain that it is a micellaneous magic item + */ + if (item == NULL) + return; + + units = usage_time(item); + if (units < 0) return; + + player.t_using = item; /* Remember what it is */ + player.t_action = C_USE; /* We are quaffing */ + player.t_no_move = units * movement(&player); + return; + } + + /* We have waited our time, let's use the item */ + item = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + is_mm = TRUE; + + obj = OBJPTR(item); + which = obj->o_which; + } + + if (obj->o_type == POTION) { /* A potion */ + is_mm = FALSE; + inpack--; + detach (pack, item); + switch (obj->o_which) { + case P_POISON: + if (cur_weapon) { + if (cur_weapon->o_type == RELIC) { + msg("The poison burns off %s", + inv_name(cur_weapon,FALSE)); + } + else { + cur_weapon->o_flags |= ISPOISON; + msg("Your weapon has %s gooey stuff on it", + p_colors[cur_weapon->o_which]); + } + } + else + msg("The poison pours on the floor and disappears!"); + } + o_discard(item); + } + else if (obj->o_type == RELIC) { /* An artifact */ + is_mm = FALSE; + switch (obj->o_which) { + case EMORI_CLOAK: + use_emori(); + when QUILL_NAGROM: + use_quill(obj); + when BRIAN_MANDOLIN: + /* Put monsters around us to sleep */ + read_scroll(S_HOLD, 0, FALSE); + when GERYON_HORN: + /* Chase close monsters away */ + msg("The horn blasts a shrill tone."); + do_panic(NULL); + when EYE_VECNA: + msg("The pain slowly subsides.. "); + when HEIL_ANKH: + msg("Your hand grows very warm. "); + when YENDOR_AMULET: + msg("Your chest glows! "); + do_panic(findmindex("frost giant")); + when STONEBONES_AMULET: + msg("Your chest glows! "); + do_panic(findmindex("storm giant")); + when SURTUR_RING: + do_panic(findmindex("fire giant")); + when ALTERAN_CARD: /* the card allows you to teleport anywhere */ + do_teleport(); + } + } + else switch (which) { /* Miscellaneous Magic */ + /* + * the jug of alchemy manufactures potions when you drink + * the potion it will make another after a while + */ + case MM_JUG: + if (obj->o_ac == JUG_EMPTY) { + msg("The jug is empty"); + break; + } + quaff (obj->o_ac, NULL, NULL, FALSE); + obj->o_ac = JUG_EMPTY; + fuse (alchemy, obj, ALCHEMYTIME, AFTER); + if (!(obj->o_flags & ISKNOW)) + whatis(item); + + /* + * the beaker of plentiful potions is used to hold potions + * the book of infinite spells is used to hold scrolls + */ + when MM_BEAKER: + case MM_BOOK: + do_bag(item); + + /* + * the chime of opening opens up secret doors + */ + when MM_OPEN: + { + register struct linked_list *exit; + register struct room *rp; + register coord *cp; + + if (obj->o_charges <= 0) { + msg("The chime is cracked!"); + break; + } + obj->o_charges--; + msg("chime... chime... hime... ime... me... e..."); + if ((rp = roomin(&hero)) == NULL) { + search(FALSE, TRUE); /* Non-failing search for door */ + break; + } + for (exit = rp->r_exit; exit != NULL; exit = next(exit)) { + cp = DOORPTR(exit); + if (winat(cp->y, cp->x) == SECRETDOOR) { + mvaddch (cp->y, cp->x, DOOR); + if (cansee (cp->y, cp->x)) + mvwaddch(cw, cp->y, cp->x, DOOR); + } + } + } + + /* + * the chime of hunger just makes the hero hungry + */ + when MM_HUNGER: + if (obj->o_charges <= 0) { + msg("The chime is spent. "); + break; + } + obj->o_charges--; + if (food_left >= MORETIME + 5) { + food_left = MORETIME + 5; + msg("A strange sensation comes over you.. "); + msg(terse? "Getting hungry" : "You are starting to get hungry"); + hungry_state = F_HUNGRY; + } + if (player.t_ctype == C_PALADIN || + player.t_ctype == C_RANGER || player.t_ctype == C_MONK) { + msg("You feel a chilling sensation!"); + aggravate(TRUE, FALSE); + } + else { + aggravate(TRUE, TRUE); + } + + /* + * the drums of panic make all creatures within two squares run + * from the hero in panic unless they save or they are mindless + * undead + */ + when MM_DRUMS: + if (obj->o_charges <= 0) { + msg("The drum is broken."); + break; + } + obj->o_charges--; + do_panic(NULL); + return; + /* + * dust of disappearance makes the player invisible for a while + */ + when MM_DISAPPEAR: + m_know[MM_DISAPPEAR] = TRUE; + if (obj->o_charges <= 0) { + msg("No more dust!"); + break; + } + obj->o_charges--; + if (terse) msg("You sneeze! "); + else msg("Ahh.. Ahh... Choo!! "); + if (!find_slot(dust_appear)) { + turn_on(player, ISINVIS); + fuse(dust_appear, (VOID *)NULL, DUSTTIME, AFTER); + PLAYER = IPLAYER; + light(&hero); + } + else lengthen(dust_appear, DUSTTIME); + + /* + * dust of choking and sneezing can kill the hero if he misses + * the save + */ + when MM_CHOKE: + m_know[MM_CHOKE] = TRUE; + if (obj->o_charges <= 0) { + msg("No more dust!"); + break; + } + obj->o_charges--; + if (terse) msg("You snort! "); + else msg("aaAAACHOOOooo. Cough. Cough. Sneeze. Sneeze."); + if (!cur_relic[SURTUR_RING] && !save(VS_POISON, &player, 0)) { + msg ("You choke to death!!! --More--"); + wait_for(' '); + pstats.s_hpt = -1; /* in case he hangs up the phone! */ + death(D_CHOKE); + } + else { + msg("You begin to cough and choke uncontrollably! "); + if (find_slot(unchoke)) + lengthen(unchoke, DUSTTIME); + else + fuse(unchoke, (VOID *)NULL, DUSTTIME, AFTER); + turn_on(player, ISHUH); + turn_on(player, ISBLIND); + light(&hero); + } + + when MM_KEOGHTOM: + /* + * this is a very powerful healing ointment + * but it takes a while to put on... + */ + obj->o_charges--; + if (on(player, HASDISEASE)) { + extinguish(cure_disease); + cure_disease(); + msg(terse ? "You feel yourself improving." + : "You begin to feel yourself improving again."); + } + if (on(player, HASINFEST)) { + turn_off(player, HASINFEST); + infest_dam = 0; + msg(terse ? "You feel yourself improving." + : "You begin to feel yourself improving again."); + } + if (on(player, DOROT)) { + msg("You feel your skin returning to normal."); + turn_off(player, DOROT); + } + pstats.s_hpt += roll(pstats.s_lvl, 6); + if (pstats.s_hpt > max_stats.s_hpt) + pstats.s_hpt = max_stats.s_hpt; + sight(); + msg("You begin to feel much better."); + + /* + * The book has a character class associated with it. + * if your class matches that of the book, it will raise your + * level by one. If your class does not match the one of the book, + * it change your class to that of book. + * Note that it takes a while to read. + */ + when MM_SKILLS: + detach (pack, item); + inpack--; + changeclass(&obj->o_ac); + when MM_CRYSTAL: + { + register char *str; + + detach (pack, item); + inpack--; + if (obj->o_flags & ISCURSED) { + if (is_mm && !m_know[MM_CRYSTAL]) + str = "rock in a curious sort of way"; + else + str = "crystal briefly"; + msg("You rub the %s and yell out in agony! ", str); + /* curse his pack */ + read_scroll(S_REMOVE, obj->o_flags & ISCURSED, FALSE); + /* aggravate monsters */ + read_scroll(S_HOLD, obj->o_flags & ISCURSED, FALSE); + player.t_no_move += (2 * movement(&player) * FREEZETIME); + player.t_action = A_FREEZE; + /* loss of 1/4 total hit points */ + pstats.s_hpt -= ((max_stats.s_hpt / 4)); + max_stats.s_hpt -= rnd(3)+3; + if (pstats.s_hpt > max_stats.s_hpt) + pstats.s_hpt = max_stats.s_hpt; + if ((pstats.s_hpt < 1) || (max_stats.s_hpt < 1)) { + pstats.s_hpt = -1; + msg("The crystal has absorbed you... --More--"); + wait_for(' '); + death(D_CRYSTAL); + } + } + else { /* if normal, give him a bonus */ + if (is_mm && !m_know[MM_CRYSTAL]) + str = "flashes brightly"; + else + str = "vibrates softly"; + msg("You rub the crystal and it %s... ", str); + /* cure him */ + read_scroll(S_CURING, NULL, FALSE); + /* give him weird hands */ + turn_on(player, CANHUH); + msg("Your fingertips turn blue. "); + /* add intelligence */ + if (player.t_ctype == C_MAGICIAN) { + max_stats.s_intel += 1; + pstats.s_intel += 1; + } + /* add strength */ + if (player.t_ctype == C_FIGHTER) { + max_stats.s_str += 1; + pstats.s_str += 1; + } + /* add wisdom */ + if (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN) { + max_stats.s_wisdom += 1; + pstats.s_wisdom += 1; + } + /* add dexterity */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN) { + max_stats.s_dext += 1; + pstats.s_dext += 1; + } + /* add constitution */ + if (player.t_ctype == C_MONK) { + max_stats.s_const += 1; + pstats.s_const += 1; + } + /* add charisma */ + if (player.t_ctype == C_RANGER || player.t_ctype == C_PALADIN) { + max_stats.s_charisma += 1; + pstats.s_charisma += 1; + } + } + if (obj->o_flags & ISBLESSED) { /* if blessed */ + if (is_mm && !m_know[MM_CRYSTAL]) + msg("The crystal disappears from your hands. "); + else + msg("Your hands absorb the medicine crystal. "); + /* set hit points to at least 50 */ + if (max_stats.s_hpt < 50) { + max_stats.s_hpt = 50; + pstats.s_hpt = max_stats.s_hpt; + } + else { /* or just add 10% */ + max_stats.s_hpt += (max_stats.s_hpt / 10); + pstats.s_hpt = max_stats.s_hpt; + } + /* heck, really make it memorable */ + read_scroll(S_REMOVE, obj->o_flags & ISBLESSED, FALSE); + } + } + otherwise: + msg("What a strange magic item you have!"); + } + status(FALSE); + if (is_mm && m_know[which] && m_guess[which]) { + free(m_guess[which]); + m_guess[which] = NULL; + } + else if (is_mm && !m_know[which] && askme && + (obj->o_flags & ISKNOW) == 0 && + m_guess[which] == NULL) { + nameitem(item, FALSE); + } + if (item != NULL && (which == MM_SKILLS || which == MM_CRYSTAL)) + o_discard(item); + updpack(TRUE, &player); +} + +/* + * usage_time: + * Return how long it takes to use an item. For now we only give time + * for MM, RELIC, SCROLL, and POTION items. + */ + +int +usage_time(item) +struct linked_list *item; +{ + register struct object *obj; + register int units = -1; + + obj = OBJPTR(item); + switch (obj->o_type) { + case SCROLL: units = 4; + when POTION: units = 3; + when RELIC: /* An artifact */ + switch (obj->o_which) { + case BRIAN_MANDOLIN: + case GERYON_HORN: units = 4; + when QUILL_NAGROM: + case EMORI_CLOAK: + case HEIL_ANKH: units = 3; + when YENDOR_AMULET: + case STONEBONES_AMULET: units = 2; + when EYE_VECNA: units = 6; + /* The eye will do nothing other than give a headache */ + pstats.s_hpt -= rnd(25)+1; + msg("You feel a sharp pain shoot through your forehead!"); + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + msg ("The pain is too much for you to bear! --More--"); + wait_for(' '); + death(D_RELIC); + } + when SURTUR_RING: + units = 3; + msg("Your nose tickles a bit."); + when ALTERAN_CARD: + units = 2; + msg("You gaze intently at the card... "); + } + when MM: + switch (obj->o_which) { /* Miscellaneous Magic */ + case MM_JUG: + if (obj->o_ac == JUG_EMPTY) { + msg("The jug is empty"); + return (-1); + } + units = 2; + when MM_BEAKER: + case MM_BOOK: + /* This is a strange case because it can go forever */ + units = 1; + case MM_CHOKE: /* Dust */ + when MM_HUNGER: /* Chimes */ + units = 3; + when MM_OPEN: + case MM_DRUMS: + case MM_DISAPPEAR: + units = 4; + when MM_KEOGHTOM: + /* Ointment */ + if (obj->o_charges <= 0) { + msg("The jar is empty!"); + return (-1); + } + units = 5; + when MM_SKILLS: + /* A whole book! */ + units = 15; + when MM_CRYSTAL: + /* Enhance player's quest */ + units = 5; + otherwise: + /* What is it? */ + units = -1; + } + otherwise: units = -1; + } + + return (units); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/mons_def.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1660 @@ +/* + mons_def.c - monster data initializer + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <ctype.h> +#include <curses.h> +#include "rogue.h" + +#define HPT(x) x + +struct monster monsters[NUMMONST+1] = { +/* {"Name", + CARRY, NORMAL, WANDER, APPEAR, INTEL, + {ATTRIBUTES}, + "SUMMONED_CREATURE", NUMBER_SUMMONED, + ADDED_EXPERIENCE/HIT_POINT, + {str dex, move, exp, level, "armor", hit_points, + "damage"}}, */ +{"unknown", + 0, FALSE, FALSE, '\0', "", + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + "", 0, + 0, + {0, 0, 0, 0, 0, 0, HPT(""), + ""}}, +{"giant rat", + 0, TRUE, TRUE, 'R', "2-6", + {ISMEAN, CANDISEASE}, + "", 0, + 0, + {10, 10, 6, 5, 1, 7, HPT("1d4"), + "1d3"}}, +{"kobold", + 50, TRUE, TRUE, 'K', "8-12", + {ISMEAN, CANSHOOT, CARRYWEAPON}, + "", 0, + 2, + {9, 9, 5, 8, 2, 7, HPT("1d4"), + "1d4"}}, +{"bat", + 0, TRUE, TRUE, 'b', "2-6", + {ISMEAN, AREMANY, CANDISEASE, ISFLY}, + "", 0, + 0, + {5, 5, 6, 5, 1, 10, HPT("1d2"), + "1d2"}}, +{"gnome", + 50, TRUE, FALSE, 'G', "10-15", + {CANSHOOT, CARRYPOTION, CARRYWEAPON, NOSTAB}, + "", 0, + 3, + {10, 10, 6, 8, 1, 5, HPT("1d6"), + "1d6"}}, +{"halfling", + 50, TRUE, FALSE, 'H', "11-16", + {CANSHOOT, CARRYSCROLL, CARRYWEAPON, NOSTAB}, + "", 0, + 3, + {8, 10, 6, 10, 1, 4, HPT("1d8"), + "1d6"}}, +{"xvart", + 50, TRUE, TRUE, 'x', "4-14", + {ISMEAN, AREMANY, CARRYDAGGER, CANTELEPORT}, + "", 0, + 1, + {8, 10, 7, 8, 1, 7, HPT("1d2"), + "1d3"}}, +{"manes", + 0, TRUE, TRUE, 'M', "2-8", + {ISMEAN, ISUNDEAD, TURNABLE, CANDISEASE}, + "", 0, + 0, + {5, 5, 5, 15, 2, 7, HPT("1d8"), + "1d2/1d2/1d4"}}, +{"rot grub", + 0, TRUE, TRUE, 'r', "10", + {ISMEAN, CANDISEASE, CANINFEST, CANSMELL}, + "", 0, + 0, + {10, 10, 8, 8, 1, 8, HPT("1d6"), + "1d6"}}, +{"giant ant", + 0, TRUE, TRUE, 'A', "1", + {ISMEAN, CANPOISON}, + "", 0, + 3, + {10, 10, 6, 30, 3, 3, HPT("2d8"), + "1d6/1d6"}}, +{"orc", + 50, TRUE, TRUE, 'O', "8", + {ISMEAN, CANSHOOT, CARRYFOOD}, + "", 0, + 2, + {12, 12, 5, 15, 4, 6, HPT("2d8"), + "1d8"}}, +{"dwarf", + 50, TRUE, FALSE, 'D', "10-14", + {CARRYSCROLL, CARRYGOLD, CARRYDAGGER, NOSTAB}, + "", 0, + 4, + {10, 10, 6, 20, 1, 4, HPT("2d8"), + "1d8"}}, +{"elf", + 50, TRUE, FALSE, 'E', "10-14", + {CARRYPOTION, CARRYWEAPON, NOSTAB, CARRYFOOD}, + "", 0, + 4, + {12, 10, 6, 20, 1, 4, HPT("2d8+2"), + "1d10"}}, +{"hobgoblin", + 50, TRUE, TRUE, 'h', "8-10", + {ISMEAN, CANSHOOT, NOSLOW}, + "", 0, + 3, + {14, 14, 4, 30, 4, 5, HPT("1d8"), + "1d8"}}, +{"urchin", + 50, TRUE, TRUE, 'u', "6-15", + {ISMEAN, ISGREED, CARRYGOLD, CARRYRING}, + "", 0, + 1, + {10, 10, 6, 25, 1, 3, HPT("2d8"), + "1d6"}}, +{"fire beetle", + 0, TRUE, TRUE, 'B', "10", + {ISMEAN, HASFIRE}, + "", 0, + 2, + {10, 10, 6, 20, 1, 4, HPT("1d8+2"), + "2d4"}}, +{"ear seeker", + 0, TRUE, TRUE, 'e', "0", + {ISMEAN, AREMANY, CANINFEST, CANSURPRISE}, + "", 0, + 0, + {10, 10, 5, 10, 1, 8, HPT("1d2"), + "1d1"}}, +{"shrieker", + 0, TRUE, TRUE, 'S', "0", + {ISMEAN, CANSHRIEK, NOMOVE, NOSTAB}, + "", 0, + 4, + {10, 10, 7, 20, 2, 7, HPT("3d8"), + "0d0"}}, +{"stirge", + 0, TRUE, TRUE, 's', "1", + {ISMEAN, CANDRAW, ISFLY}, + "", 0, + 2, + {10, 10, 4, 30, 1, 8, HPT("2d6"), + "1d3"}}, +{"troglodyte", + 50, TRUE, TRUE, 'T', "5-15", + {ISMEAN, CANSMELL, CANSTINK, CANSHOOT, HASFIRE}, + "", 0, + 3, + {10, 10, 6, 30, 5, 4, HPT("2d8"), + "1d6/2d6"}}, +{"zombie", + 0, TRUE, TRUE, 'Z', "0", + {ISMEAN, ISUNDEAD, TURNABLE, CANSURPRISE, ISSHADOW, NOSLEEP}, + "", 0, + 6, + {10, 10, 5, 60, 1, 0, HPT("2d8+5"), + "2d8"}}, +{"gas spore", + 0, TRUE, TRUE, 'a', "0", + {ISMEAN, CANEXPLODE, CANINFEST, ISFLY}, + "", 0, + 5, + {10, 10, 8, 30, 2, 5, HPT("2d8"), + "1d2/1d4"}}, +{"giant tick", + 0, TRUE, TRUE, 't', "0", + {ISMEAN, CANPOISON, CANROT}, + "", 0, + 1, + {10, 10, 7, 70, 2, 4, HPT("1d8"), + "1d4"}}, +{"lemure", + 0, TRUE, TRUE, 'L', "5-10", + {ISMEAN, ISREGEN, CANSUMMON, NOBOLT}, + "bat", 5, + 6, + {12, 12, 5, 45, 4, 2, HPT("3d8"), + "1d6"}}, +{"zoo spore", + 0, TRUE, TRUE, 'z', "8-20", + {ISMEAN, CANDISEASE, CANEXPLODE, TURNABLE, ISUNDEAD, ISFLY}, + "", 0, + 10, + {20, 20, 4, 80, 2, 0, HPT("2d8+6"), + "1d8"}}, +{"bugbear", + 30, TRUE, TRUE, 'b', "5-12", + {ISMEAN, CANSHOOT, CANSURPRISE, ISGREED}, + "", 0, + 3, + {16, 10, 6, 60, 2, 5, HPT("3d8+4"), + "2d4"}}, +{"gray ooze", + 0, TRUE, TRUE, 'o', "1", + {ISMEAN, CANRUST, NOCOLD, NOFIRE, NOSTAB}, + "", 0, + 1, + {10, 10, 9, 100, 2, 8, HPT("1d8"), + "1d8"}}, +{"lonchu", + 50, TRUE, TRUE, 'l', "6", + {ISMEAN, CANTELEPORT, CARRYARMOR, NOBOLT}, + "", 0, + 3, + {10, 10, 6, 120, 2, 3, HPT("3d8+4"), + "2d6"}}, +{"wererat", + 50, TRUE, TRUE, 'r', "10-15", + {ISMEAN, CARRYPOTION, CANSUMMON, CANDRAW, NOSTAB}, + "giant rat", 3, + 5, + {10, 10, 5, 70, 5, 4, HPT("3d8+6"), + "2d8"}}, +{"ghoul", + 50, TRUE, TRUE, 'g', "12-15", + {ISMEAN, CARRYFOOD, CANPARALYZE, ISUNDEAD, TURNABLE, CANDRAW, + AREMANY}, + "", 0, + 7, + {12, 12, 5, 75, 2, 2, HPT("4d4"), + "1d4/1d6"}}, +{"leprechaun", + 75, TRUE, FALSE, 'l', "10-16", + {CARRYGOLD, STEALGOLD, ISGREED, CARRYSCROLL, CARRYPOTION, + NOSTAB}, + "", 0, + 9, + {15, 15, 3, 100, 7, 0, HPT("3d8"), + "1d1/3d6"}}, +{"junk monster", + 100, TRUE, TRUE, 'j', "10-14", + {ISMEAN, CANSTINK, CANSMELL, ISSCAVENGE, ISGREED, CANDRAW, + ISREGEN, CANSHOOT, CARRYSTICK}, + "", 0, + 7, + {12, 12, 5, 100, 2, 4, HPT("3d8+3"), + "1d6/2d8"}}, +{"jacaranda", + 40, TRUE, TRUE, 'j', "8-18", + {ISMEAN, ISUNIQUE, ISREGEN, CANSUMMON, NOCOLD, NOFIRE, NOBOLT, + CANDANCE, CARRYGOLD, CANTELEPORT, CANBLIND, ISSHADOW, NOSTAB, + ISGREED, STEALGOLD, CARRYFOOD}, + "zombie", 4, + 20, + {18, 18, 2, 40000, 10, -15, HPT("6d8+40"), + "1d6/2d6/3d6"}}, +{"gnoll", + 0, TRUE, TRUE, 'n', "10-16", + {ISMEAN, CANINFEST, CANROT, ISREGEN, TURNABLE}, + "", 0, + 4, + {10, 10, 6, 140, 2, 4, HPT("6d8"), + "2d8"}}, +{"fire toad", + 0, TRUE, TRUE, 'f', "5-7", + {ISMEAN, CANBFIRE, NOFIRE, NOBOLT}, + "", 0, + 4, + {10, 10, 6, 200, 2, 5, HPT("5d8"), + "1d8"}}, +{"gelatinous cube", + 50, TRUE, TRUE, 'c', "0", + {ISMEAN, CANPARALYZE, CARRYFOOD, NOCOLD}, + "", 0, + 4, + {10, 10, 7, 160, 2, 1, HPT("4d8"), + "2d8"}}, +{"moon dog", + 0, TRUE, TRUE, 'm', "10-12", + {ISMEAN, ISFLY, NOCOLD, NOFIRE, CANDRAW}, + "", 0, + 6, + {12, 12, 4, 250, 2, 3, HPT("3d8+3"), + "2d10"}}, +{"violet fungi", + 0, TRUE, TRUE, 'F', "0", + {ISMEAN, CANSHRIEK, CANSUMMON, CANHOLD, NOMOVE, CANROT}, + "violet fungi", 1, + 5, + {10, 10, 5, 150, 9, 0, HPT("4d6+10"), + "1d8/2d8/3d8"}}, +{"ogre", + 50, TRUE, TRUE, 'O', "7-12", + {ISMEAN, CARRYGOLD, CARRYDAGGER, NOBOLT}, + "", 0, + 7, + {18, 10, 6, 170, 3, 3, HPT("4d8+8"), + "2d10"}}, +{"centaur", + 50, TRUE, FALSE, 'C', "5-15", + {STEALGOLD, CARRYGOLD, CARRYRING, NOSLEEP, NOSTAB}, + "", 0, + 9, + {10, 10, 4, 180, 2, 4, HPT("4d8+10"), + "1d8/2d6"}}, +{"nymph", + 75, TRUE, FALSE, 'N', "10-16", + {STEALMAGIC, CARRYSCROLL, CARRYPOTION, CARRYSTICK, NOSTAB, + CARRYFOOD, NOSLOW}, + "", 0, + 8, + {16, 16, 3, 190, 5, 3, HPT("3d8+10"), + "1d1"}}, +{"blindheim", + 0, TRUE, TRUE, 'b', "10", + {ISMEAN, CANBLIND, NOSLOW}, + "", 0, + 5, + {8, 8, 5, 260, 3, 1, HPT("4d8+6"), + "2d10"}}, +{"blink dog", + 0, TRUE, TRUE, 'B', "8-10", + {ISMEAN, CANBLINK, CANSEE, CANINFEST}, + "", 0, + 9, + {10, 10, 6, 220, 3, 5, HPT("4d8+4"), + "1d8/2d4"}}, +{"ghast", + 50, TRUE, TRUE, 'G', "10-12", + {ISMEAN, CANPARALYZE, CANSTINK, ISUNDEAD, TURNABLE, AREMANY, + NOBOLT}, + "", 0, + 10, + {10, 10, 4, 250, 1, 1, HPT("5d8+6"), + "2d4/2d6"}}, +{"rust monster", + 0, TRUE, TRUE, 'R', "1", + {ISMEAN, CANRUST, CANDISEASE}, + "", 0, + 6, + {10, 10, 7, 200, 4, 6, HPT("2d8+6"), + "1d1/1d1"}}, +{"imp", + 0, TRUE, TRUE, 'I', "8-10", + {ISMEAN, ISREGEN, CANPAIN, CANTELEPORT, NOCOLD, NOFIRE}, + "", 0, + 9, + {10, 10, 6, 300, 3, 2, HPT("3d8+12"), + "2d8"}}, +{"doppelganger", + 50, TRUE, TRUE, 'D', "10-15", + {ISMEAN, CANSURPRISE, CARRYPOTION, NOSTAB, NOSLOW}, + "", 0, + 8, + {10, 10, 5, 360, 5, 3, HPT("7d8"), + "1d12+2"}}, +{"shadow", + 0, TRUE, TRUE, 'S', "13", + {ISMEAN, ISSHADOW, CANCHILL, ISUNDEAD, TURNABLE, CANINWALL}, + "", 0, + 9, + {13, 13, 5, 370, 6, 1, HPT("3d8+10"), + "2d4/2d4"}}, +{"very young dragon", + 50, TRUE, TRUE, 'd', "12-16", + {ISMEAN, MAGICHIT, ISGREED, CARRYPOTION, CARRYGOLD, NOSTAB, + CANBRANDOM, CARRYMISC, NOBOLT}, + "", 0, + 11, + {16, 16, 6, 300, 8, -2, HPT("4d8+20"), + "2d4/1d6/1d8"}}, +{"yeti", + 0, TRUE, TRUE, 'Y', "8-16", + {ISMEAN, CANPARALYZE, CANSURPRISE, NOBOLT, NOSTAB, NOCOLD}, + "", 0, + 9, + {13, 10, 5, 400, 3, 6, HPT("5d8+6"), + "1d8/2d8"}}, +{"ice weasel", + 0, TRUE, TRUE, 'i', "10-16", + {ISMEAN, AREMANY, ISSHADOW, CANPAIN, NOCOLD, NOSLEEP}, + "", 0, + 7, + {10, 10, 4, 400, 6, 1, HPT("10d8+10"), + "1d10"}}, +{"mimic", + 50, TRUE, TRUE, 'M', "2-16", + {ISMEAN, ISDISGUISE, NODETECT, CANHOLD, NOMOVE, NOSTAB, NOBOLT, + CARRYRING}, + "", 0, + 12, + {10, 10, 6, 500, 4, 8, HPT("10d8"), + "3d4"}}, +{"owlbear", + 50, TRUE, TRUE, 'O', "8-12", + {ISMEAN, CANHUG, NOFEAR, NOSTAB, CARRYFOOD}, + "", 0, + 10, + {10, 10, 3, 340, 3, 2, HPT("5d8+10"), + "1d6/1d6/2d6"}}, +{"otyugh", + 50, TRUE, TRUE, 'o', "5-10", + {ISMEAN, ISFLY, CARRYARMOR, NOSLOW, NOFIRE}, + "", 0, + 11, + {10, 10, 5, 750, 4, 4, HPT("4d8+15"), + "1d8/1d8/1d4+4"}}, +{"gargoyle", + 50, TRUE, TRUE, 'g', "5-7", + {ISMEAN, MAGICHIT, CARRYWEAPON, NOSTAB}, + "", 0, + 9, + {10, 10, 4, 290, 3, 5, HPT("4d8+6"), + "1d6/2d6"}}, +{"su-monster", + 50, TRUE, TRUE, 's', "8-10", + {ISMEAN, CARRYGOLD, ISGREED, HASFIRE, CANSUMMON, CARRYSCROLL, + NOFEAR}, + "moon dog", 4, + 12, + {10, 10, 5, 450, 4, 3, HPT("5d8+10"), + "2d4/2d4"}}, +{"leucrotta", + 0, TRUE, TRUE, 'L', "8-10", + {ISMEAN, NOFEAR, NOSLOW, NOSTAB, CANSEE}, + "", 0, + 10, + {10, 10, 2, 470, 3, 4, HPT("6d8+10"), + "3d6/1d6/1d6"}}, +{"cockatrice", + 50, TRUE, TRUE, 'C', "1", + {ISMEAN, CARRYSTICK, TOUCHSTONE, NOSTAB}, + "", 0, + 15, + {12, 12, 5, 500, 6, 4, HPT("5d8+8"), + "4d4"}}, +{"wight", + 0, TRUE, TRUE, 'W', "8-10", + {ISMEAN, CANDRAIN, MAGICHIT, NOSTONE, ISUNDEAD, TURNABLE, + NOBOLT}, + "", 0, + 12, + {10, 10, 6, 550, 4, 2, HPT("4d8+15"), + "2d8"}}, +{"phibian", + 0, TRUE, TRUE, 'p', "2-16", + {ISMEAN, NOBOLT, CANFRIGHTEN, TURNABLE, NOSLOW}, + "", 0, + 13, + {10, 10, 2, 600, 8, -2, HPT("6d8"), + "1d20"}}, +{"fireworm", + 0, TRUE, TRUE, 'z', "7-10", + {ISMEAN, AREMANY, CANEXPLODE, NOFIRE, ISFLY, NOSLEEP}, + "", 0, + 15, + {10, 10, 5, 500, 2, 0, HPT("1d8"), + "1d4"}}, +{"flumph", + 50, TRUE, TRUE, 'f', "10-16", + {ISMEAN, AREMANY, CARRYGOLD, STEALGOLD, NOMOVE}, + "", 0, + 13, + {12, 12, 3, 320, 3, -7, HPT("5d8+8"), + "2d8"}}, +{"treant", + 50, TRUE, TRUE, 't', "10-14", + {ISMEAN, CANSUMMON, CARRYGOLD, ISGREED, CANSTINK, CANSMELL}, + "treant", 1, + 16, + {12, 12, 4, 1500, 2, 0, HPT("5d8+10"), + "3d8"}}, +{"troll", + 50, TRUE, FALSE, 'T', "10-15", + {ISREGEN, CANSHOOT, CARRYGOLD, CARRYSCROLL, NOSTAB}, + "", 0, + 18, + {18, 18, 6, 600, 7, 3, HPT("6d8+10"), + "1d4+4/1d4+4/2d6+2"}}, +{"ettin", + 50, TRUE, TRUE, 'e', "1-18", + {ISMEAN, AREMANY, CARRYWEAPON, NOFIRE, CANROT}, + "", 0, + 10, + {10, 10, 3, 1000, 3, 1, HPT("8d8+8"), + "2d8/2d6/2d6"}}, +{"lava child", + 0, TRUE, TRUE, 'l', "8-10", + {ISMEAN, NOMETAL, NOFIRE, NOBOLT, NOSTAB}, + "", 0, + 9, + {10, 10, 5, 700, 2, 4, HPT("5d8+10"), + "2d12"}}, +{"erinyes", + 0, TRUE, TRUE, 'E', "8-10", + {ISMEAN, CANFRIGHTEN, TURNABLE, ISUNDEAD, CANPAIN, NOFIRE}, + "", 0, + 11, + {10, 10, 6, 750, 4, 3, HPT("6d8+4"), + "6d2+4"}}, +{"ulodyte", + 0, TRUE, TRUE, 'u', "9-13", + {ISMEAN, CANSMELL, CANHUG, TURNABLE, NOSTAB, CANSURPRISE}, + "", 0, + 12, + {10, 8, 6, 2000, 5, 3, HPT("6d8+10"), + "3d4/2d6"}}, +{"wraith", + 0, TRUE, TRUE, 'w', "10-14", + {ISMEAN, CANDRAIN, MAGICHIT, ISUNDEAD, TURNABLE, NOBOLT, + NOSTAB, AREMANY}, + "", 0, + 16, + {10, 10, 8, 800, 3, 2, HPT("5d8+10"), + "2d6/1d8"}}, +{"jackalwere", + 50, TRUE, TRUE, 'J', "10-15", + {ISMEAN, CANSMELL, CANSNORE, MAGICHIT}, + "", 0, + 10, + {10, 10, 4, 900, 6, 3, HPT("5d8+20"), + "2d4/2d4"}}, +{"basilisk", + 50, TRUE, TRUE, 'B', "1", + {ISMEAN, LOOKSTONE, CARRYSCROLL, NOSTAB, NOFIRE}, + "", 0, + 10, + {10, 10, 6, 1000, 5, 4, HPT("6d8+20"), + "2d10"}}, +{"vrock", + 0, TRUE, TRUE, 'v', "10-12", + {ISMEAN, CANSEE, TURNABLE, CANTELEPORT, CANDRAW}, + "", 0, + 12, + {10, 10, 6, 2300, 5, 1, HPT("7d8+25"), + "1d4/1d4/1d8/1d8/1d6/1d6"}}, +{"hezrou", + 50, TRUE, TRUE, 'h', "5-13", + {ISMEAN, CANFRIGHTEN, TURNABLE, CANTELEPORT, CARRYSTICK}, + "", 0, + 12, + {10, 10, 6, 3000, 6, -1, HPT("9d8+10"), + "1d4/2d4/4d4"}}, +{"glabrezu", + 50, TRUE, TRUE, 'G', "8-10", + {ISMEAN, CANFRIGHTEN, CANSEE, TURNABLE, CANTELEPORT, + CARRYWEAPON, CARRYPOTION}, + "", 0, + 12, + {10, 10, 6, 2500, 6, -4, HPT("10d8+6"), + "2d6/2d6/1d6/1d6"}}, +{"wyvern", + 50, TRUE, TRUE, 'w', "10-16", + {ISMEAN, CANPAIN, CARRYGOLD, CANSUMMON, CANINFEST, NODETECT}, + "fireworm", 4, + 15, + {10, 10, 5, 2200, 4, -2, HPT("8d8+10"), + "2d8/2d8"}}, +{"specter", + 0, TRUE, TRUE, 'S', "10-16", + {ISMEAN, DOUBLEDRAIN, ISUNDEAD, TURNABLE, NOFIRE, NOCOLD, + NOSTAB, NOACID, NOGAS}, + "", 0, + 17, + {12, 12, 6, 2000, 7, 1, HPT("7d8+20"), + "1d8/1d8"}}, +{"mummy", + 0, TRUE, TRUE, 'm', "5-14", + {ISMEAN, CANROT, MAGICHIT, CANFRIGHTEN, HALFDAMAGE, ISUNDEAD, + NOGAS, NOACID, NOSTAB, TURNABLE}, + "", 0, + 18, + {10, 10, 5, 2000, 5, 2, HPT("8d8+10"), + "1d12"}}, +{"chimera", + 0, TRUE, TRUE, 'c', "10-16", + {ISMEAN, BMAGICHIT, NOFEAR, NOCOLD, ISREGEN, CANITCH}, + "", 0, + 19, + {10, 10, 6, 2300, 5, 0, HPT("6d8+25"), + "1d3/1d3/1d4/1d4/2d4/2d4"}}, +{"neo-otyugh", + 50, TRUE, TRUE, 'N', "10-12", + {ISMEAN, CARRYPOTION, CANINFEST, NOCOLD, NOFEAR, MAGICHIT}, + "", 0, + 17, + {12, 10, 6, 2500, 6, 0, HPT("12d8"), + "2d8/2d6/1d3"}}, +{"adult dragon", + 80, TRUE, TRUE, 'd', "12-16", + {ISMEAN, CANBRANDOM, ISGREED, CANFRIGHTEN, NOSTAB, NOCOLD, + CARRYPOTION, CARRYMISC, CARRYRING, CANSURPRISE}, + "", 0, + 20, + {18, 18, 5, 2600, 7, -3, HPT("7d8+20"), + "2d6/2d6/2d6"}}, +{"horned devil", + 0, TRUE, TRUE, 'H', "10-14", + {ISMEAN, CANPOISON, NOBOLT, CANTELEPORT}, + "", 0, + 17, + {10, 10, 6, 2200, 5, -2, HPT("5d8+30"), + "1d4/1d6/1d8"}}, +{"barbed devil", + 0, TRUE, TRUE, 'B', "10-16", + {ISMEAN, TOUCHFEAR, NOBOLT, CANHOLD, TURNABLE, NOFIRE}, + "", 0, + 17, + {10, 10, 6, 2200, 5, 0, HPT("8d8+20"), + "2d4/2d4/3d4"}}, +{"ice devil", + 0, TRUE, TRUE, 'I', "12-15", + {ISMEAN, ISREGEN, CANBICE, NOCOLD, NOBOLT}, + "", 0, + 17, + {12, 10, 6, 2500, 6, -4, HPT("10d8+10"), + "1d4/2d4/3d4"}}, +{"bone devil", + 0, TRUE, TRUE, 'b', "12-15", + {ISMEAN, CANSURPRISE, CANCHILL, CANSEE, NOFIRE, NOACID, + NOGAS, CANFRIGHTEN, NOSTAB, NOCOLD, CANTELEPORT}, + "", 0, + 17, + {12, 12, 5, 3500, 8, -1, HPT("10d8+20"), + "2d4/3d6"}}, +{"rhinosphynx", + 80, TRUE, TRUE, 'r', "13-18", + {ISMEAN, CANPOISON, CANSURPRISE, CANCHILL, NOCOLD, CARRYGOLD, + ISGREED}, + "", 0, + 18, + {12, 12, 6, 3000, 7, -1, HPT("9d8+10"), + "4d6"}}, +{"lamia", + 80, TRUE, TRUE, 'L', "10-17", + {ISMEAN, TAKEWISDOM, CARRYSTICK, NOFEAR, NOCOLD}, + "", 0, + 16, + {16, 16, 3, 2500, 7, -2, HPT("9d8+15"), + "2d4/2d6"}}, +{"intellect devourer", + 0, TRUE, TRUE, 'D', "12-16", + {ISMEAN, TAKEINTEL, BMAGICHIT, CANSURPRISE, NOBOLT, NOSTAB}, + "", 0, + 16, + {16, 16, 3, 2500, 9, -2, HPT("10d8+15"), + "1d6/2d6/3d6"}}, +{"quasit", + 80, TRUE, TRUE, 'Q', "10-15", + {ISMEAN, ISREGEN, BMAGICHIT, CANSURPRISE, CANITCH, NOGAS, + NOACID, CARRYSCROLL, CARRYPOTION, NOCOLD, NOBOLT}, + "", 0, + 20, + {10, 10, 6, 3000, 6, -2, HPT("6d8+20"), + "2d6/1d8/2d6"}}, +{"will-o-wisp", + 80, TRUE, TRUE, 'W', "12-16", + {ISMEAN, CANSURPRISE, ISFLY, CARRYMISC, NOSTAB, NOBOLT}, + "", 0, + 20, + {10, 10, 5, 4000, 6, -5, HPT("9d8+20"), + "2d14"}}, +{"invisible stalker", + 0, TRUE, TRUE, 'i', "12-16", + {ISMEAN, ISINVIS, ISSHADOW, NOBOLT, CANINWALL, NOGAS, NOSTAB, + NOACID, TOUCHFEAR}, + "", 0, + 20, + {10, 10, 4, 3800, 5, -2, HPT("8d8+20"), + "2d12"}}, +{"hellmaid", + 80, TRUE, TRUE, 'h', "10-20", + {ISMEAN, AREMANY, CANBRANDOM, CARRYFOOD, NOBOLT, NOGAS, + NOACID, NOCOLD, NOFIRE}, + "", 0, + 20, + {12, 12, 7, 4000, 4, 1, HPT("8d8+12"), + "2d8/2d8"}}, +{"shadow dragon", + 80, TRUE, TRUE, 'S', "16-20", + {ISMEAN, TURNABLE, CANDRAW, NOSTAB, HASFIRE, CANSMELL, + CARRYGOLD, STEALGOLD, ISINVIS, ISSHADOW, NOSLOW}, + "", 0, + 25, + {10, 10, 2, 4800, 3, -7, HPT("8d8+18"), + "3d4/2d8"}}, +{"umber hulk", + 80, TRUE, TRUE, 'U', "8-16", + {ISMEAN, CANHUH, CANINWALL, CANTUNNEL, CARRYSCROLL, NOSTAB, + NOACID, NOGAS, BMAGICHIT, NOBOLT}, + "", 0, + 22, + {14, 14, 5, 5000, 8, -3, HPT("10d8+20"), + "3d4/3d4/3d4"}}, +{"xorn", + 0, TRUE, TRUE, 'X', "8-18", + {ISMEAN, CANINWALL, NOFIRE, CANSURPRISE, NOBOLT, NOSTAB, NOGAS, + NOACID}, + "", 0, + 23, + {13, 13, 4, 5000, 8, -4, HPT("7d8+25"), + "2d6/4d6"}}, +{"xenolith", + 80, TRUE, TRUE, 'x', "12-18", + {ISMEAN, NOSTAB, NOFIRE, NOBOLT, NOCOLD, CANTELEPORT, + STEALGOLD, CARRYGOLD, ISGREED}, + "", 0, + 24, + {12, 12, 4, 3500, 6, -2, HPT("9d8+20"), + "2d8/2d10"}}, +{"shambling mound", + 80, TRUE, TRUE, 's', "5-7", + {ISMEAN, CANSUFFOCATE, NOCOLD, CANHOLD, CARRYGOLD, CANSUMMON, + NOGAS, NOSTAB, NOACID, CARRYPOTION, CARRYSCROLL, ISSCAVENGE}, + "mummy", 3, + 20, + {10, 10, 5, 4500, 5, 0, HPT("9d8+15"), + "2d8/2d10"}}, +{"black pudding", + 80, TRUE, TRUE, 'P', "0", + {ISMEAN, CANRUST, NOCOLD, BOLTDIVIDE, BLOWDIVIDE, ISSCAVENGE, + NOSTAB, NOGAS, CARRYRING}, + "", 0, + 20, + {10, 10, 6, 4500, 6, 5, HPT("10d8+10"), + "3d8"}}, +{"vampire", + 0, TRUE, TRUE, 'V', "5-16", + {ISMEAN, ISREGEN, CANSUCK, CANDRAW, CANDRAIN, ISUNDEAD, + NOACID, TURNABLE, TOUCHFEAR, NOGAS, NOSTAB, NOBOLT}, + "", 0, + 23, + {16, 16, 5, 5000, 7, -4, HPT("8d8+25"), + "2d6+6"}}, +{"morkoth", + 80, TRUE, TRUE, 'm', "10-18", + {ISMEAN, ISSHADOW, CANSEE, HALFDAMAGE, CARRYARMOR, NOGAS, + CANSUMMON, NOMETAL}, + "wyvern", 2, + 21, + {11, 11, 8, 7000, 6, -1, HPT("12d8+10"), + "4d8/4d8"}}, +{"white pudding", + 80, TRUE, TRUE, 'w', "0", + {ISMEAN, CANDISSOLVE, NOFIRE, BOLTDIVIDE, BLOWDIVIDE, NOGAS, + ISSCAVENGE, NOSTAB, CARRYMISC}, + "", 0, + 20, + {10, 10, 4, 8000, 8, 5, HPT("10d8+10"), + "4d8"}}, +{"purple worm", + 0, TRUE, TRUE, 'p', "10", + {ISMEAN, CANPOISON, CANINWALL, CANTUNNEL, NOSTAB, NOFEAR, + NOBOLT, NOACID, CMAGICHIT, NOGAS}, + "", 0, + 25, + {10, 10, 5, 9000, 8, -3, HPT("12d8+20"), + "2d12/2d8+4"}}, +{"pit fiend", + 80, TRUE, TRUE, 'f', "12-18", + {ISMEAN, CANSEE, BMAGICHIT, CANFRIGHTEN, CANHOLD, HASFIRE, + CARRYRING, CARRYSTICK, NOACID, NOGAS, NOSTAB}, + "", 0, + 26, + {16, 16, 5, 10000, 6, -2, HPT("12d8+25"), + "2d6+4/2d6+8"}}, +{"ghost", + 0, TRUE, TRUE, 'g', "14-16", + {ISMEAN, CANFRIGHTEN, CANAGE, ISUNDEAD, TURNABLE, BMAGICHIT, + NOGAS, NOACID, CANINWALL, CANSUMMON, NOSTAB, ISREGEN}, + "invisible stalker", 3, + 28, + {13, 13, 5, 9500, 5, -4, HPT("10d8+25"), + "2d10/2d4"}}, +{"ancient black dragon", + 80, TRUE, TRUE, 'a', "12-16", + {ISMEAN, CANBACID, NOSTAB, NOACID, ISGREED, CARRYGOLD, NOSLEEP, + CANMISSILE, CANTELEPORT, NOBOLT, NOCOLD, NOGAS, NOFIRE}, + "", 0, + 30, + {14, 14, 6, 11000, 7, -4, HPT("10d8+50"), + "2d6/3d4/4d6"}}, +{"ancient blue dragon", + 80, TRUE, TRUE, 'u', "12-16", + {ISMEAN, CANBBOLT, CANSEE, NOBOLT, CARRYMISC, NOSTAB, CANBPGAS, + NOACID, NOGAS, NOFIRE, NOCOLD, CANTELEPORT, NOFIRE, NOSLEEP}, + "", 0, + 30, + {14, 14, 4, 11000, 7, -6, HPT("10d8+50"), + "4d4/4d6/4d8"}}, +{"ancient red dragon", + 80, TRUE, TRUE, 'R', "12-16", + {ISMEAN, CANMISSILE, CANSEE, NOFIRE, CARRYRING, NOGAS, NOBOLT, + NOSTAB, CANBFIRE, NOFEAR, NOCOLD, NOFIRE, NOACID, CANTELEPORT}, + "", 0, + 30, + {14, 14, 6, 11000, 7, -8, HPT("10d8+50"), + "4d6/3d8/5d8"}}, +{"ancient brass dragon", + 80, TRUE, FALSE, 'r', "12-16", + {CANBFGAS, CANSEE, NOSLEEP, CANBSGAS, NOGAS, NOSTAB, + CANTELEPORT, NOACID, NOFIRE, CARRYSTICK, NOBOLT, NOCOLD}, + "", 0, + 30, + {14, 14, 6, 11000, 7, -4, HPT("10d8+50"), + "2d6/3d4/4d6"}}, +{"frost giant", + 80, TRUE, TRUE, 'F', "5-16", + {ISMEAN, NOCOLD, CARRYGOLD, AREMANY, CANBICE, NOGAS, CANCHILL, + CANSMELL, NOCOLD, NOACID, ISGREED}, + "", 0, + 35, + {18, 18, 4, 12000, 8, 0, HPT("8d8+30"), + "6d8"}}, +{"lich", + 80, TRUE, TRUE, 'l', "12-18", + {ISMEAN, CANSEE, CANPARALYZE, CANFRIGHTEN, CMAGICHIT, NOSTAB, + NOBOLT, CANMISSILE, CARRYGOLD, CARRYSCROLL, CARRYPOTION, + CARRYRING, NOCOLD, NOFIRE, NOACID, NOGAS}, + "", 0, + 35, + {12, 12, 4, 14000, 8, -5, HPT("10d8+60"), + "2d10/3d8"}}, +{"ancient green dragon", + 80, TRUE, TRUE, 'E', "12-16", + {ISMEAN,CANBGAS, ISGREED, CANSEE, CARRYGOLD, NOSTAB, NOGAS, + NOACID, CANMISSILE, NOBOLT, NOSLEEP, CANTELEPORT, NOFIRE}, + "", 0, + 40, + {16, 16, 6, 16000, 8, -6, HPT("10d8+60"), + "4d4/4d6/4d8"}}, +{"ancient white dragon", + 80, TRUE, TRUE, 'W', "12-16", + {ISMEAN, CANSEE, NOGAS, NOSTAB, CARRYSCROLL, CANTELEPORT, + NOACID, NOFIRE, CANBICE, CANMISSILE, NOBOLT, NOCOLD, NOSLEEP}, + "", 0, + 40, + {16, 16, 4, 16000, 8, -4, HPT("10d8+60"), + "2d6/3d4/4d6"}}, +{"ancient bronze dragon", + 80, TRUE, FALSE, 'L', "12-16", + {CANBBOLT, CANSEE, NOBOLT, NOSTAB, CANBCGAS, NOFIRE, + CARRYSCROLL, CARRYSTICK, NOCOLD, NOSLEEP, NOGAS, NOACID}, + "", 0, + 40, + {16, 16, 8, 16000, 8, -6, HPT("10d8+60"), + "4d4/4d6/4d8"}}, +{"ancient copper dragon", + 80, TRUE, FALSE, 'c', "12-16", + {NOACID, CANBSLGAS, CANSEE, NOFIRE, NOBOLT, NOSLEEP, NOCOLD, + CARRYMISC, CARRYPOTION, CANTELEPORT, NOSTAB, CANBACID, NOGAS}, + "", 0, + 40, + {16, 16, 5, 16000, 8, -6, HPT("10d8+60"), + "4d4/4d6/4d8"}}, +{"fire giant", + 80, TRUE, TRUE, 'f', "15-18", + {ISMEAN, AREMANY, CARRYGOLD, ISGREED, NOSLOW, NOGAS, NOBOLT, + NOFIRE, CANSTINK, NOACID}, + "", 0, + 45, + {15, 15, 3, 15000, 9, -1, HPT("8d8+30"), + "8d6"}}, +{"nemesis", + 80, TRUE, TRUE, 'n', "10-18", + {ISMEAN, ISGREED, CANSEE, NOBOLT, STEALGOLD, CMAGICHIT, NOGAS, + NODETECT, CARRYFOOD, CANBLINK, NOCOLD}, + "", 0, + 45, + {13, 13, 6, 18000, 9, -7, HPT("10d8+70"), + "3d6/3d8/3d10"}}, +{"ancient amethyst dragon", + 80, TRUE, TRUE, 'y', "12-16", + {ISMEAN, CANSTINK, CANMISSILE, ISGREED, NOBOLT, NOGAS, NOSLEEP, + NOFIRE, NOCOLD, CARRYSCROLL, CANTELEPORT, NOSTAB, NOACID}, + "", 0, + 50, + {18, 18, 4, 20000, 9, -8, HPT("10d8+70"), + "4d6/3d8/5d8"}}, +{"ancient silver dragon", + 80, TRUE, FALSE, 'S', "12-16", + {CANBPGAS, NOSLEEP, CANBICE, NOCOLD, NOPARALYZE, NOGAS, + NOFIRE, NOACID, CARRYSTICK, NOSTAB, CANTELEPORT}, + "", 0, + 50, + {18, 18, 8, 20000, 9, -8, HPT("10d8+70"), + "4d6/3d8/5d8"}}, +{"ancient saphire dragon", + 80, TRUE, TRUE, 'H', "12-16", + {ISMEAN, NOBOLT, CANSEE, CARRYRING, NOSTAB, NOACID, CANSONIC, + CANTELEPORT, NOFIRE, NOCOLD, NOGAS, NOSLEEP}, + "", 0, + 50, + {18, 18, 6, 20000, 9, -6, HPT("10d8+20"), + "2d6/3d4/4d6"}}, +{"ancient gold dragon", + 80, TRUE, FALSE, 'G', "12-16", + {CANBGAS, ISGREED, NOACID, NOFIRE, NOGAS, CARRYGOLD, + CANBFIRE, CANTELEPORT, NOBOLT, NOSTAB, NOCOLD, NOSLEEP}, + "", 0, + 50, + {18, 18, 5, 20000, 9, -8, HPT("10d8+70"), + "4d6/3d8/5d8"}}, +{"titan", + 80, TRUE, TRUE, 't', "13-18", + {ISMEAN, ISSHADOW, CANSEE, CARRYPOTION, NOSTAB, CANTELEPORT, + TOUCHFEAR, CANROT, NOGAS, NOACID, NOFEAR, NOBOLT}, + "", 0, + 55, + {16, 16, 5, 22000, 10, -5, HPT("8d8+70"), + "8d8"}}, +{"storm giant", + 80, TRUE, TRUE, 's', "10-16", + {ISMEAN, NOBOLT, CANBBOLT, CANPAIN, NOGAS, NOSTAB, NOACID, + CARRYGOLD, ISGREED, CANBBOLT, NOBOLT, CANSUMMON}, + "shadow dragon", 2, + 55, + {14, 14, 6, 20000, 10, -7, HPT("10d8+60"), + "7d8/5d10"}}, +{"lesser god (Hruggek)", + 100, TRUE, FALSE, 'H', "20", + {ISMEAN, ISUNIQUE, CARRYMSTAR, ISREGEN, MAGICHIT, CANSEE, NOGAS, + NOFIRE, NOSTAB, CANMISSILE, CANTELEPORT, NOBOLT, CARRYFOOD}, + "", 0, + 60, + {18, 18, 5, 40000, 10, -5, HPT("10d8+100"), + "5d10/5d10"}}, +{"lesser god (Surtur)", + 100, TRUE, FALSE, 'S', "20", + {ISMEAN, ISUNIQUE, CARRYSURTURRING, ISREGEN, MAGICHIT, CANSEE, + NOFIRE, NOSTAB, CANMISSILE, CANTELEPORT, NOBOLT, CARRYRING}, + "", 0, + 60, + {18, 18, 4, 40000, 10, -5, HPT("10d8+100"), + "5d10/5d10"}}, +{"demon prince (Yeenoghu)", + 100, TRUE, FALSE, 'Y', "20", + {ISMEAN, ISUNIQUE, CARRYFLAIL, CMAGICHIT, CANPOISON, NOBOLT, + CANBBOLT, CANTELEPORT, NOFIRE, NOSTAB, NOGAS, CARRYSCROLL, + NOCOLD, NOSLOW}, + "", 0, + 60, + {18, 18, 5, 50000, 11, -6, HPT("10d8+100"), + "2d8+4/2d6+8"}}, +{"demon prince (Orcus)", + 100, TRUE, FALSE, 'O', "20", + {ISMEAN, ISUNIQUE, CARRYWAND, CMAGICHIT, CANFRIGHTEN, CANSEE, + CANBBOLT, NOBOLT, CANTELEPORT, NOFIRE, CARRYPOTION, NOSTAB}, + "", 0, + 60, + {18, 18, 5, 30000, 10, -6, HPT("10d8+90"), + "2d8+4/2d6+8"}}, +{"arch devil (Geryon)", + 100, TRUE, FALSE, 'g', "20", + {ISMEAN, ISUNIQUE, CARRYHORN, BMAGICHIT, NOGAS, NOBOLT, NOSTAB, + ISINVIS, CANTELEPORT, NOCOLD, NOFIRE, CARRYSTICK, CARRYHORN}, + "", 0, + 60, + {18, 18, 5, 30000, 10, -4, HPT("10d8+90"), + "3d6/3d8/3d10"}}, +{"arch devil (Asmodeus)", + 100, TRUE, FALSE, 'A', "20", + {ISMEAN, ISUNIQUE, CARRYROD, BMAGICHIT, NOGAS, NOBOLT, ISINVIS, + NOSTAB, CANFRIGHTEN, CANTELEPORT, NOCOLD, NOFIRE, CARRYMISC}, + "", 0, + 60, + {20, 20, 5, 40000, 10, -4, HPT("10d8+100"), + "3d6/3d8/3d10"}}, +{"poet (Brian)", + 100, TRUE, FALSE, 'p', "20", + {ISMEAN, ISUNIQUE, CARRYMANDOLIN, STEALGOLD, ISSHADOW, ISREGEN, + NOCOLD, NOBOLT, NOFIRE, NOFEAR, CANTUNNEL, CANSEE, NOSTAB, + CANINWALL, ISCLEAR, CARRYPOTION, NOGAS}, + "", 0, + 60, + {20, 20, 4, 40000, 10, -8, HPT("10d8+100"), + "4d4+20/4d4+20"}}, +{"witch (Emori)", + 100, TRUE, FALSE, 'w', "20", + {ISMEAN, ISUNIQUE, CARRYCLOAK, CANMISSILE, ISINVIS, CANBBOLT, + CANSEE, CANSUMMON, CANSNORE, ISFLY, NOBOLT, NOFIRE, NOSTAB, + ISCLEAR, CARRYSTICK, NOSLOW, NOGAS}, + "nemesis", 4, + 60, + {20, 20, 4, 50000, 11, -8, HPT("10d8+100"), + "4d4+20/4d4+20"}}, +{"hero (aklad)", + 100, TRUE, FALSE, 'k', "20", + {ISMEAN, ISUNIQUE, CARRYAXE, ISREGEN, NOBOLT, NOSLOW, NOGAS, + CANSEE, ISCLEAR, CANBLINK, CARRYMISC, CANMISSILE, NOSTAB}, + "", 0, + 60, + {20, 20, 5, 50000, 11, -9, HPT("10d8+100"), + "2d8+15/2d8+15/1d6+15/1d6+15"}}, +{"cleric of thoth (Heil)", + 100, TRUE, FALSE, 'h', "20", + {ISMEAN, ISUNIQUE, CARRYANKH, CARRYRING, CANSEE, NOFEAR, + ISREGEN, CANHOLD, NOSTAB, DOUBLEDRAIN, NOCOLD, CANMISSILE, + TAKEWISDOM, ISINVIS, NOGAS}, + "", 0, + 60, + {20, 20, 4, 50000, 11, -8, HPT("10d8+100"), + "3d6+10"}}, +{"magician/thief (Nagrom)", + 100, TRUE, FALSE, 'N', "20", + {ISMEAN, ISUNIQUE, CARRYQUILL, STEALMAGIC, ISINVIS, ISREGEN, + NOSTAB, NOGAS, CANMISSILE, CANSEE, CARRYRING, CANBSTAB, NOBOLT, + CANBBOLT, CANSURPRISE, NODETECT, CANTELEPORT, CANSLOW}, + "", 0, + 60, + {20, 20, 5, 60000, 12, -8, HPT("10d8+100"), + "7d10/7d10"}}, +{"magician (Tsoming Zen)", + 100, TRUE, FALSE, 'z', "20", + {ISMEAN, ISUNIQUE, CARRYSTAFF, ISINVIS, ISREGEN, CANBFIRE, + CANBICE, NOSTAB, CANBBOLT, NOFIRE, NOCOLD, NOBOLT, CANHOLD, + NOGAS, CANPAIN, NOSLOW, CARRYPOTION}, + "", 0, + 60, + {20, 20, 4, 60000, 11, -5, HPT("10d8+100"), + "2d8+10/2d8+10/2d8+10/2d8+10"}}, +{"dwarven thief (Musty Doit)", + 100, TRUE, FALSE, 'm', "20", + {ISMEAN, ISUNIQUE, CARRYMDAGGER, NOFIRE, NOGAS, NOSTAB, + STEALGOLD, STEALMAGIC, CANPAIN, CARRYGOLD, CANSURPRISE, + NOBOLT, CARRYPOTION, CARRYSCROLL, ISSCAVENGE}, + "", 0, + 60, + {20, 20, 5, 70000, 11, -8, HPT("10d8+100"), + "4d8+10/4d8+10"}}, +{"ruler of titans (Yendor)", + 100, TRUE, FALSE, 'y', "20", + {ISMEAN, ISUNIQUE, CARRYYAMULET, CANINWALL, BMAGICHIT, NOCOLD, + CANSUMMON, CANMISSILE, CANFRIGHTEN, NOFIRE, NOGAS, NOSTAB, + TOUCHFEAR, ISSHADOW, NOBOLT, CARRYSTICK, CARRYSCROLL}, + "titan", 4, + 60, + {20, 20, 5, 70000, 12, -10, HPT("10d8+100"), + "2d10+5/2d10+5"}}, +{"maker of rock (Stonebones)", + 100, TRUE, FALSE, 'b', "20", + {ISMEAN, ISUNIQUE, CARRYBAMULET, ISREGEN, CMAGICHIT, CANSEE, + NOFIRE, NOSTAB, CANFRIGHTEN, CANMISSILE, CANTELEPORT, NOBOLT, + CANITCH, NOGAS, CANINWALL, CANSONIC, CARRYSTICK}, + "", 0, + 60, + {20, 20, 4, 70000, 12, -10, HPT("10d8+100"), + "6d10/6d10"}}, +{"creator of liches (Vecna)", + 100, TRUE, FALSE, 'V', "20", + {ISMEAN, ISUNIQUE, CARRYEYE, ISREGEN, CMAGICHIT, NOSTAB, NOGAS, + CANSNORE, CANSUMMON, CANMISSILE, CANFRIGHTEN, NOFIRE, CANBBOLT, + NOBOLT, CANSEE, ISINVIS, HALFDAMAGE, CARRYRING, LOOKSTONE}, + "lich", 4, + 60, + {20, 20, 4, 70000, 12, -10, HPT("10d8+100"), + "6d10/6d10"}}, +{"lesser god (Thrym)", + 0, TRUE, TRUE, 'T', "15-20", + {ISMEAN, ISUNIQUE, ISREGEN, MAGICHIT, CANSEE, NOFIRE, NOSTAB, + CANMISSILE, CANTELEPORT, NOBOLT, CANITCH, NOGAS}, + "", 0, + 60, + {18, 18, 5, 60000, 11, -5, HPT("10d8+100"), + "5d10/5d10"}}, +{"lesser god (Kurtulmak)", + 0, TRUE, TRUE, 'K', "15-20", + {ISMEAN, ISUNIQUE, ISREGEN, MAGICHIT, CANSEE, NOFIRE, NOSTAB, + CANMISSILE, CANTELEPORT, NOBOLT, NOGAS, CANITCH}, + "", 0, + 60, + {18, 18, 5, 60000, 10, -5, HPT("10d8+100"), + "5d10/5d10"}}, +{"lesser god (\"The Destroyer\")", + 0, TRUE, TRUE, 'v', "15-20", + {ISMEAN, ISUNIQUE, ISREGEN, MAGICHIT, CANSEE, NOFIRE, NOSTAB, + CANMISSILE, CANTELEPORT, NOBOLT, CANITCH, NOGAS}, + "", 0, + 60, + {18, 18, 5, 70000, 12, -6, HPT("10d8+100"), + "5d10/5d10"}}, +{"lesser god (Antar)", + 100, TRUE, TRUE, 'A', "17-25", + {ISMEAN, ISUNIQUE, ISREGEN, NOCOLD, NOFIRE, NOBOLT, NOSTAB, + CANDANCE, CANTELEPORT, CANBLIND, CANSEE, ISSHADOW, NOSLOW, + ISGREED, CANSUMMON, CARRYFOOD, CANBRANDOM, CANINWALL, ISFLY}, + "ancient black dragon", 4, + 60, + {22, 22, 2, 90000, 10, -15, HPT("10d8+100"), + "6d10/6d10"}}, +{"demon prince (Jubilex)", + 0, TRUE, TRUE, 'J', "15-20", + {ISMEAN, ISUNIQUE, CMAGICHIT, CANPOISON, CANFRIGHTEN, CANBBOLT, + NOBOLT, CANTELEPORT, NOFIRE, NOSTAB, NOGAS}, + "", 0, + 60, + {18, 18, 5, 70000, 11, -6, HPT("10d8+100"), + "2d8+4/2d6+8"}}, +{"demon prince (Bone)", + 0, TRUE, TRUE, 'B', "15-20", + {ISMEAN, ISUNIQUE, CMAGICHIT, CANPOISON, CANFRIGHTEN, CANBBOLT, + NOBOLT, CANTELEPORT, NOFIRE, NOSTAB}, + "", 0, + 60, + {18, 18, 5, 50000, 10, -6, HPT("10d8+90"), + "2d8+4/2d6+8"}}, +{"demon prince (Graz'zt)", + 0, TRUE, TRUE, 'g', "15-20", + {ISMEAN, ISUNIQUE, CMAGICHIT, CANPOISON, CANFRIGHTEN, + NOBOLT, CANTELEPORT, NOFIRE, NOSTAB, NOGAS}, + "", 0, + 60, + {18, 18, 3, 60000, 11, -6, HPT("10d8+100"), + "2d8+4/2d6+8"}}, +{"demon prince (Demogorgon)", + 0, TRUE, TRUE, 'D', "15-20", + {ISMEAN, ISUNIQUE, CMAGICHIT, CANPOISON, CANFRIGHTEN, CANBBOLT, + NOBOLT, CANTELEPORT, NOFIRE, NOSTAB, NOGAS}, + "", 0, + 70, + {18, 18, 5, 60000, 12, -6, HPT("10d8+120"), + "2d8+4/2d6+8"}}, +{"arch devil (Mammon)", + 0, TRUE, TRUE, 'M', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, NOGAS, NOBOLT, ISINVIS, NOSTAB, + CANFRIGHTEN, CANPAIN, CANTELEPORT, NOCOLD, NOFIRE}, + "", 0, + 60, + {18, 18, 5, 80000, 10, -4, HPT("10d8+90"), + "3d6/3d8/3d10"}}, +{"arch devil (Baalzebul)", + 0, TRUE, TRUE, 'B', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, NOGAS, NOBOLT, ISINVIS, NOSTAB, + CANFRIGHTEN, CANPAIN, CANTELEPORT, NOCOLD}, + "", 0, + 60, + {18, 18, 6, 80000, 11, -4, HPT("10d8+100"), + "3d6/3d8/3d10"}}, +{"arch devil (Moloch)", + 100, TRUE, TRUE, 'M', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, NOGAS, NOBOLT, ISINVIS, ISGREED, + CANFRIGHTEN, CANPAIN, CANTELEPORT, NOCOLD, CARRYGOLD, NOSTAB}, + "", 0, + 70, + {18, 18, 6, 80000, 12, -7, HPT("10d8+120"), + "3d6/3d8/3d10"}}, +{"arch devil (Dispater)", + 100, TRUE, TRUE, 'd', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, NOGAS, NOBOLT, ISINVIS, ISGREED, + CANFRIGHTEN, CANPAIN, CANTELEPORT, NOCOLD, CARRYGOLD, NOSTAB}, + "", 0, + 70, + {18, 18, 6, 80000, 12, -7, HPT("10d8+120"), + "3d6/3d8/3d10"}}, +{"platinum dragon (Bahamut)", + 0, TRUE, FALSE, 'P', "20", + {ISUNIQUE, CANBGAS, CANBBOLT, NOBOLT, NOCOLD, NOFIRE, NOGAS, + CANMISSILE, CANSUMMON, CANBACID, CANFRIGHTEN, NOACID, NOSTAB}, + "frost giant", 6, + 70, + {20, 20, 5, 90000, 12, -6, HPT("10d8+120"), + "2d10+10/2d10+10"}}, +{"diablero (Prithivi)", + 100, TRUE, TRUE, 'o', "15-20", + {ISMEAN, ISUNIQUE, ISREGEN, ISSHADOW, CANBACID, NOACID, NOGAS, + ISINVIS, ISSCAVENGE, CANDRAW, MAGICHIT, NOSTAB}, + "", 0, + 70, + {18, 18, 3, 90000, 12, -5, HPT("10d8+120"), + "3d12/4d8+6"}}, +{"diablero (Apas)", + 100, TRUE, TRUE, 'o', "15-20", + {ISMEAN, ISUNIQUE, ISREGEN, ISSHADOW, CANBACID, NOACID, NOGAS, + ISINVIS, ISSCAVENGE, CANDRAW, MAGICHIT, NOSTAB}, + "", 0, + 70, + {18, 18, 3, 90000, 13, -5, HPT("10d8+120"), + "3d12/4d8+6"}}, +{"chromatic dragon (Tiamat)", + 0, TRUE, FALSE, 'C', "20", + {ISUNIQUE, CANBGAS, CANBBOLT, NOBOLT, NOCOLD, NOFIRE, NOGAS, + CANMISSILE, CANSUMMON, CANBACID, CANFRIGHTEN, NOACID, NOSTAB}, + "fire giant", 6, + 70, + {20, 20, 5, 90000, 13, -6, HPT("10d8+120"), + "2d10+10/2d10+10"}}, +{"diablero (Vayu)", + 100, TRUE, TRUE, 'o', "15-20", + {ISMEAN, ISUNIQUE, ISREGEN, ISSHADOW, CANBACID, NOACID, NOGAS, + ISINVIS, ISSCAVENGE, CANDRAW, MAGICHIT, NOSTAB}, + "", 0, + 70, + {18, 18, 2, 90000, 13, -7, HPT("10d8+120"), + "3d12/4d8+6"}}, +{"diablero (Tejas)", + 100, TRUE, TRUE, 'o', "15-20", + {ISMEAN, ISUNIQUE, ISREGEN, ISSHADOW, CANBACID, NOACID, NOGAS, + ISINVIS, ISSCAVENGE, CANDRAW, MAGICHIT, NOSTAB}, + "", 0, + 70, + {18, 18, 2, 90000, 13, -7, HPT("10d8+120"), + "3d12/4d8+6"}}, +{"etheric dragon (Ishtar)", + 0, TRUE, FALSE, 'E', "20", + {ISUNIQUE, CANBGAS, CANBBOLT, NOBOLT, NOCOLD, NOFIRE, NOGAS, + CANMISSILE, CANSUMMON, CANBACID, CANFRIGHTEN, NOACID, NOSTAB}, + "storm giant", 6, + 70, + {20, 20, 5, 90000, 13, -8, HPT("10d8+120"), + "2d10+10/2d10+10"}}, +{"diablero (Akasa)", + 100, TRUE, TRUE, 'o', "15-20", + {ISMEAN, ISUNIQUE, ISREGEN, ISSHADOW, CANBACID, NOACID, NOGAS, + ISINVIS, ISSCAVENGE, CANDRAW, MAGICHIT, NOSTAB}, + "", 0, + 70, + {18, 18, 2, 90000, 13, -8, HPT("10d8+120"), + "3d12/4d8+6"}}, +{"greater god (Maglubiyet)", + 100, TRUE, FALSE, 'm', "20", + {ISMEAN, ISUNIQUE, CMAGICHIT, ISREGEN, CANINWALL, NOGAS, + CANBBOLT, NOBOLT, ISCLEAR, CARRYRING, CARRYFOOD, CARRYPOTION, + CARRYSCROLL, NOSTAB, NOFIRE, NOCOLD}, + "", 0, + 80, + {18, 18, 5, 100000, 13, -12, HPT("10d8+120"), + "6d10/6d10"}}, +{"greater god (Gruumsh)", + 100, TRUE, FALSE, 'G', "20", + {ISMEAN, ISUNIQUE, CMAGICHIT, ISREGEN, NOGAS, CANINWALL, + CANBBOLT, NOBOLT, ISCLEAR, CARRYMISC, CARRYSCROLL, CARRYFOOD, + CARRYPOTION, NOSTAB, NOFIRE, NOCOLD}, + "", 0, + 80, + {18, 18, 5, 100000, 13, -12, HPT("10d8+120"), + "6d10/6d10"}}, +{"semi-demon (Cambion)", + 0, TRUE, TRUE, 'c', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOSTAB, + CANTELEPORT, CANFRIGHTEN, CANBRANDOM, NOBOLT}, + "", 0, + 80, + {18, 18, 6, 100000, 13, -5, HPT("10d8+150"), + "5d8/5d8"}}, +{"minor demon (Dretch)", + 0, TRUE, TRUE, 'd', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOSTAB, + CANTELEPORT, CANFRIGHTEN, CANBRANDOM, NOBOLT}, + "", 0, + 80, + {18, 18, 6, 100000, 13, -6, HPT("10d8+150"), + "3d12/3d12"}}, +{"major demon (Nabassu)", + 0, TRUE, TRUE, 'n', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOSTAB, + CANTELEPORT, CANFRIGHTEN, CANBRANDOM, NOBOLT}, + "", 0, + 80, + {18, 18, 6, 110000, 14, -7, HPT("10d8+150"), + "4d10/4d10"}}, +{"demon lord (Baphomet)", + 0, TRUE, TRUE, 'B', "20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOSTAB, + CANSUMMON, CANTELEPORT, CANFRIGHTEN, CANBRANDOM, NOBOLT}, + "ancient blue dragon", 2, + 90, + {20, 20, 5, 110000, 14, -8, HPT("10d8+150"), + "5d10/5d10"}}, +{"incubus (Ravana)", + 0, TRUE, TRUE, 'R', "10-20", + {ISMEAN, ISUNIQUE, LOOKSTONE, NOFEAR, ISUNDEAD, TURNABLE, + CANBRANDOM, TOUCHFEAR, NOCOLD, NOSTAB, NOGAS}, + "", 0, + 90, + {18, 18, 6, 120000, 14, -7, HPT("10d8+150"), + "3d10/3d10"}}, +{"succubus (Azazel)", + 0, TRUE, TRUE, 'a', "10-20", + {ISMEAN, ISUNIQUE, LOOKSTONE, NOFEAR, ISUNDEAD, TURNABLE, + CANBRANDOM, TOUCHFEAR, NOFIRE, NOSTAB, NOGAS}, + "", 0, + 90, + {18, 18, 6, 120000, 14, -9, HPT("10d8+150"), + "3d10/3d10"}}, +{"incubus (Putana)", + 0, TRUE, TRUE, 'P', "10-20", + {ISMEAN, ISUNIQUE, LOOKSTONE, NOFEAR, ISUNDEAD, TURNABLE, + CANBRANDOM, TOUCHFEAR, NOCOLD, NOSTAB, NOGAS}, + "", 0, + 90, + {18, 18, 6, 120000, 14, -9, HPT("10d8+150"), + "3d10/3d10"}}, +{"succubus (Sammael)", + 0, TRUE, TRUE, 'S', "10-20", + {ISMEAN, ISUNIQUE, LOOKSTONE, NOFEAR, ISUNDEAD, TURNABLE, + CANBRANDOM, TOUCHFEAR, NOFIRE, NOGAS, NOSTAB}, + "", 0, + 90, + {18, 18, 6, 120000, 14, -7, HPT("10d8+150"), + "3d10/3d10"}}, +{"incubus (Aeshma)", + 0, TRUE, TRUE, 'A', "10-20", + {ISMEAN, ISUNIQUE, LOOKSTONE, NOFEAR, ISUNDEAD, TURNABLE, + CANBRANDOM, TOUCHFEAR, NOCOLD, NOSTAB, NOGAS}, + "", 0, + 90, + {18, 18, 6, 120000, 14, -8, HPT("10d8+150"), + "3d10/3d10"}}, +{"succubus (Belial)", + 0, TRUE, TRUE, 'b', "10-20", + {ISMEAN, ISUNIQUE, LOOKSTONE, NOFEAR, ISUNDEAD, TURNABLE, + CANBRANDOM, TOUCHFEAR, NOFIRE, NOSTAB, NOGAS}, + "", 0, + 90, + {18, 18, 6, 120000, 14, -8, HPT("10d8+150"), + "3d10/3d10"}}, +{"prince of hell (Hutijin)", + 0, TRUE, FALSE, 'h', "15-20", + {ISMEAN, ISUNIQUE, CMAGICHIT, ISREGEN, CANSUMMON, CANBCGAS, + NOGAS, CANINWALL, CANFRIGHTEN, CANBRANDOM, NOBOLT, ISFLY, + NOSTAB, NOFIRE}, + "ancient green dragon", 2, + 90, + {18, 18, 3, 130000, 14, -10, HPT("10d8+150"), + "4d12+8/4d12+8"}}, +{"princess of hell (Glasya)", + 0, TRUE, FALSE, 'G', "15-20", + {ISMEAN, ISUNIQUE, CMAGICHIT, ISREGEN, CANSUMMON, CANBCGAS, + NOGAS, CANINWALL, CANFRIGHTEN, CANBRANDOM, NOBOLT, ISFLY, + NOSTAB, NOCOLD}, + "ancient red dragon", 2, + 90, + {18, 18, 3, 130000, 14, -10, HPT("10d8+150"), + "4d12+8/4d12+8"}}, +{"prince of hell (Titivilus)", + 0, TRUE, FALSE, 't', "15-20", + {ISMEAN, ISUNIQUE, CMAGICHIT, ISREGEN, CANSUMMON, CANBCGAS, + NOGAS, CANINWALL, CANFRIGHTEN, CANBRANDOM, NOBOLT, ISFLY, + NOSTAB, NOFIRE}, + "ancient white dragon", 2, + 90, + {18, 18, 3, 130000, 15, -10, HPT("10d8+150"), + "4d12+8/4d12+8"}}, +{"lesser daemon (Pisco)", + 0, TRUE, TRUE, 'P', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOSTAB, + TOUCHSTONE, CANPAIN, NOSLOW, NOBOLT}, + "", 0, + 90, + {18, 18, 5, 140000, 15, -8, HPT("10d8+160"), + "10d12"}}, +{"lesser daemon (Dergho)", + 0, TRUE, TRUE, 'd', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOSTAB, + TOUCHSTONE, CANPAIN, NOSLOW, NOBOLT}, + "", 0, + 90, + {18, 18, 5, 140000, 15, -8, HPT("10d8+160"), + "10d12"}}, +{"greater daemon (Ultro)", + 0, TRUE, TRUE, 'U', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOSTAB, + TOUCHSTONE, CANAGE, NOSLOW, NOBOLT}, + "", 0, + 90, + {18, 18, 5, 140000, 15, -9, HPT("10d8+160"), + "10d10+10"}}, +{"lesser daemon (Hydro)", + 0, TRUE, TRUE, 'H', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOSTAB, + TOUCHSTONE, CANPAIN, NOSLOW, NOBOLT}, + "", 0, + 90, + {18, 18, 5, 140000, 15, -8, HPT("10d8+160"), + "10d12"}}, +{"lesser daemon (Yagno)", + 0, TRUE, TRUE, 'y', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOSTAB, + TOUCHSTONE, CANPAIN, NOSLOW, NOBOLT}, + "", 0, + 90, + {18, 18, 5, 140000, 15, -8, HPT("10d8+160"), + "10d12"}}, +{"greater daemon (Arcana)", + 0, TRUE, TRUE, 'a', "15-20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOSTAB, + TOUCHSTONE, CANAGE, NOSLOW, NOBOLT}, + "", 0, + 90, + {18, 18, 5, 140000, 15, -9, HPT("10d8+160"), + "10d10+10"}}, +{"oino daemon (Anthraxus)", + 0, TRUE, FALSE, 'O', "20", + {ISMEAN, ISUNIQUE, BMAGICHIT, ISREGEN, CANBGAS, NOGAS, NOBOLT, + TOUCHSTONE, CANFRIGHTEN, CANPAIN, CANAGE, NOFIRE, CANMISSILE, + CANHOLD, HALFDAMAGE, CANSUMMON, CANBBOLT, NOCOLD, NOSTAB}, + "ancient amethyst dragon", 4, + 90, + {20, 20, 3, 150000, 15, -12, HPT("10d8+170"), + "10d10+20"}}, +{"ipsissimus (Alteran)", + 100, TRUE, FALSE, 'i', "25", + {ISUNIQUE, CARRYCARD, CARRYFOOD, CMAGICHIT, ISREGEN, NOGAS, + CANINWALL, CANFRIGHTEN, CANBACID, NOACID, NOBOLT, ISCLEAR, + NOSLOW, NOFEAR, NODETECT, NOFIRE, NOCOLD, NOSTAB, CANSONIC}, + "", 0, + 100, + {25, 25, 2, 250000, 16, -30, HPT("10d8+200"), + "10d10/10d10"}}, +{"boatman (Charon)", + 0, TRUE, FALSE, 'c', "20", + {ISMEAN, ISUNIQUE, CMAGICHIT, ISREGEN, CANSUMMON, NOGAS, NOBOLT, + CANTELEPORT, CANFRIGHTEN, CANBRANDOM, NOSTAB, NOBOLT, NOFEAR, + CANPAIN, DOUBLEDRAIN, CANPOISON, CANHOLD, CANINWALL}, + "ancient saphire dragon", 4, + 100, + {20, 20, 2, 250000, 18, -20, HPT("10d8+200"), + "12d12/12d12"}}, +{"anole", + 0, TRUE, TRUE, 'a', "10-15", + {ISMEAN, CANDISEASE}, + "", 0, + 1, + {10, 10, 3, 10, 1, 5, HPT("1d8+5"), + "1d4"}}, +{"creodont", + 50, TRUE, TRUE, 'c', "12-14", + {ISMEAN, CANSTINK, NOSLOW}, + "", 0, + 1, + {10, 10, 6, 10, 1, 3, HPT("2d8+5"), + "1d4"}}, +{"gorgosaur", + 0, TRUE, TRUE, 'g', "8-14", + {ISMEAN, CANTELEPORT, CANINFEST, NOSTAB}, + "", 0, + 3, + {10, 10, 9, 30, 1, 2, HPT("3d8+5"), + "1d4/1d6"}}, +{"giant cicada", + 0, TRUE, TRUE, 'C', "4", + {ISMEAN, AREMANY, ISUNDEAD, TURNABLE, CANPOISON, NOSTAB}, + "", 0, + 3, + {10, 10, 6, 30, 2, 4, HPT("4d8+5"), + "1d6"}}, +{"elasmosaurus", + 50, TRUE, TRUE, 'e', "10-15", + {ISMEAN, CANDRAW, CANPARALYZE, CANSMELL}, + "", 0, + 5, + {10, 10, 12, 40, 2, 8, HPT("2d8+10"), + "2d8"}}, +{"trilobite", + 0, TRUE, TRUE, 't', "10-20", + {ISMEAN, AREMANY, NOFIRE, NOCOLD, CANINWALL}, + "", 0, + 2, + {12, 14, 3, 50, 2, 6, HPT("2d8+20"), + "2d8"}}, +{"mammoth", + 50, TRUE, TRUE, 'M', "15", + {ISMEAN, AREMANY, CANTELEPORT, CANSTINK, CARRYARMOR}, + "", 0, + 7, + {12, 12, 15, 80, 3, 0, HPT("3d8+50"), + "2d4/2d6"}}, +{"ichthyosaur", + 50, TRUE, TRUE, 'i', "10-14", + {ISMEAN, CARRYWEAPON, CANPOISON, CANINFEST}, + "", 0, + 4, + {12, 12, 6, 70, 3, 2, HPT("2d8+30"), + "2d6"}}, +{"grig", + 50, TRUE, TRUE, 'g', "8-16", + {ISMEAN, CANBFIRE, CANCHILL, NOFIRE, NOCOLD}, + "", 0, + 5, + {12, 12, 3, 100, 3, -1, HPT("3d8+20"), + "1d4/4d6"}}, +{"saber-tooth", + 0, TRUE, TRUE, 's', "10-17", + {ISMEAN, CANBICE, ISSHADOW, NOSTAB, NOBOLT, CANHUG, CANTUNNEL}, + "", 0, + 8, + {12, 12, 6, 100, 4, -2, HPT("3d8+50"), + "2d8/1d12"}}, +{"merychippus", + 0, TRUE, TRUE, 'm', "16", + {ISMEAN, CANSHRIEK, CANBLIND, CANHUG, CANSNORE}, + "", 0, + 6, + {12, 12, 9, 150, 4, 0, HPT("3d8+30"), + "4d8"}}, +{"nematode", + 100, TRUE, TRUE, 'n', "8-14", + {ISMEAN, CANINWALL, CANTELEPORT, NOSTAB, ISSCAVENGE, CARRYFOOD}, + "", 0, + 10, + {12, 12, 3, 150, 4, 3, HPT("3d8+20"), + "2d12"}}, +{"tussah", + 0, TRUE, TRUE, 't', "12-18", + {ISMEAN, CANBICE, NOCOLD, NOBOLT, NOSTAB, CANPAIN, NOFEAR}, + "", 0, + 9, + {12, 12, 4, 200, 4, -3, HPT("4d8+30"), + "3d8"}}, +{"theropod", + 0, TRUE, TRUE, 'T', "15-20", + {ISMEAN, ISFLY, CANROT, CANSTINK, CANBFIRE, CANEXPLODE}, + "", 0, + 8, + {14, 14, 12, 200, 5, 0, HPT("4d8+10"), + "3d8+2"}}, +{"mastodon", + 0, TRUE, TRUE, 'm', "10-15", + {ISMEAN, CANBFIRE, NOBOLT, NOFIRE, NOCOLD, TURNABLE, NOSTAB}, + "", 0, + 10, + {14, 14, 15, 500, 5, -10, HPT("4d8+50"), + "4d8"}}, +{"sloth", + 0, TRUE, TRUE, 'S', "10-18", + {ISMEAN, NOSTAB, CANSMELL, CANSTINK, NOCOLD, CANSUMMON, + TOUCHSTONE}, + "trilobite", 4, + 11, + {14, 14, 18, 300, 5, -1, HPT("4d8+60"), + "4d8"}}, +{"pterodactyl", + 0, TRUE, TRUE, 'P', "15-20", + {ISMEAN, AREMANY, ISFLY, NOSLOW, NOBOLT, NOSTAB, CANPAIN}, + "", 0, + 9, + {14, 14, 3, 250, 5, 0, HPT("4d8+30"), + "2d8/3d8/4d8"}}, +{"brontosaurus", + 0, TRUE, TRUE, 'b', "1", + {ISMEAN, NOFIRE, CANBFIRE, ISREGEN, CANHOLD, NOBOLT, NOSTAB}, + "", 0, + 12, + {14, 14, 12, 900, 5, -3, HPT("8d8+50"), + "6d8"}}, +{"sauropod", + 0, TRUE, TRUE, 's', "10-18", + {ISMEAN, CANSONIC, NOPARALYZE, NOCOLD, NOSTAB, CANSUMMON, + NOFIRE}, + "grig", 6, + 10, + {14, 16, 6, 800, 6, -4, HPT("4d8+30"), + "3d8"}}, +{"wooly mammoth", + 0, TRUE, TRUE, 'w', "15-20", + {ISMEAN, AREMANY, NOBOLT, NOGAS, NOFIRE, NOACID, CANHUH, + TAKEINTEL, NOSTAB}, + "", 0, + 13, + {14, 14, 12, 1000, 6, -7, HPT("8d8+60"), + "4d8/6d8"}}, +{"brontops", + 0, TRUE, TRUE, 'B', "10-14", + {ISMEAN, NOGAS, NOFIRE, NOBOLT, NOFEAR, CANDRAW, TAKEWISDOM}, + "", 0, + 12, + {14, 14, 18, 900, 7, -1, HPT("8d8+80"), + "8d8+2"}}, +{"tricerotops", + 0, TRUE, TRUE, 'T', "15-20", + {ISMEAN, CANSURPRISE, CANMISSILE, CANPOISON, NOBOLT, NOFIRE}, + "", 0, + 8, + {14, 14, 6, 1000, 7, -2, HPT("8d8+70"), + "8d8/6d8"}}, +{"sinanthropus", + 50, TRUE, TRUE, 's', "12-20", + {ISMEAN, CANBACID, NOACID, NOBOLT, CANDRAW, NOFEAR, NOGAS, + CANFRIGHTEN, BMAGICHIT}, + "", 0, + 13, + {15, 15, 6, 2000, 8, -8, HPT("8d8+100"), + "8d8+5"}}, +{"stegosaurus", + 0, TRUE, TRUE, 's', "15-20", + {ISMEAN, CANBGAS, CANROT, NOFEAR, NOGAS, CANTUNNEL, NOACID, + NOSTAB, CANBCGAS}, + "", 0, + 14, + {16, 16, 4, 2500, 8, -10, HPT("8d8+75"), + "8d8+7"}}, +{"plesiosaurus", + 0, TRUE, TRUE, 'p', "8-15", + {ISMEAN, NOGAS, NOSTAB, DOUBLEDRAIN, NOBOLT}, + "", 0, + 11, + {18, 18, 9, 2000, 8, -8, HPT("8d8+40"), + "1d4/8d8"}}, +{"tyranosaurus rex", + 0, TRUE, TRUE, 'R', "10-20", + {ISMEAN, ISREGEN, CANTUNNEL, NOSTAB, NOGAS, NOFIRE, NOBOLT, + AREMANY, CMAGICHIT, CANFRIGHTEN}, + "", 0, + 15, + {18, 18, 2, 3000, 8, -10, HPT("10d8+100"), + "6d8/8d8"}}, +{"anaconda", + 80, TRUE, TRUE, 'A', "12-20", + {ISMEAN, NOGAS, CANSUMMON, CARRYGOLD, STEALGOLD, NOSTAB, + NOFIRE, NOBOLT, CANAGE, CANFRIGHTEN}, + "nematode", 6, + 20, + {18, 18, 4, 4000, 9, -8, HPT("10d8+150"), + "8d8/8d8"}}, +{"imperial mammoth", + 0, TRUE, TRUE, 'I', "15-20", + {ISMEAN, AREMANY, NOFEAR, ISREGEN, CANHUH, NOCOLD, CANSURPRISE, + NOSTAB, CANBGAS, NOGAS, NOFIRE, NOACID, CANBACID}, + "", 0, + 20, + {18, 18, 12, 5000, 9, -10, HPT("10d8+200"), + "6d8+10"}}, +{"zinjanthropus", + 80, TRUE, TRUE, 'Z', "18-20", + {ISMEAN, NOSLOW, CANBICE, CANBFIRE, CANSUMMON, LOOKSTONE, + NOSTAB, NOBOLT, NOACID, NOCOLD, NOFIRE, NOSLOW}, + "mastodon", 6, + 20, + {18, 18, 3, 5000, 9, -15, HPT("10d8+250"), + "8d8+10"}}, +{"positron", + 0, TRUE, TRUE, 'X', "1-18", + {ISMEAN, CANEXPLODE, ISFLY, TURNABLE, ISUNDEAD, BLOWDIVIDE, + NOSLOW, HASFIRE, NOFIRE, NOBOLT, CANFRIGHTEN}, + "", 0, + 25, + {18, 18, 10, 10000, 9, -1, HPT("10d8+250"), + "4d8/6d8"}}, +{"quartermaster", + 80, FALSE, TRUE, 'q', "25", + {CANSELL, ISCLEAR, CANTELEPORT, ISFLY, NOSLOW, NOSTAB, NOBOLT, + NOSLEEP, NOFIRE, NOCOLD, NOFEAR, CANINWALL}, + "", 0, + 30, + {25, 25, 5, 1000, 7, -6, HPT("2d8+20"), + "8d10"}}, +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/monsters.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,865 @@ +/* + monsters.c - File with various monster functions in it + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" + +/* + * Check_residue takes care of any effect of the monster + */ + +check_residue(tp) +register struct thing *tp; +{ + /* + * Take care of special abilities + */ + if (on(*tp, DIDHOLD) && (--hold_count == 0)) { + turn_off(player, ISHELD); + turn_off(*tp, DIDHOLD); + } + + /* If frightened of this monster, stop */ + if (on(player, ISFLEE) && + player.t_dest == &tp->t_pos) turn_off(player, ISFLEE); + + /* If monster was suffocating player, stop it */ + if (on(*tp, DIDSUFFOCATE)) { + extinguish(suffocate); + turn_off(*tp, DIDSUFFOCATE); + } + + /* If something with fire, may darken */ + if (on(*tp, HASFIRE)) { + register struct room *rp=roomin(&tp->t_pos); + register struct linked_list *fire_item; + + if (rp) { + for (fire_item = rp->r_fires; fire_item != NULL; + fire_item = next(fire_item)) { + if (THINGPTR(fire_item) == tp) { + detach(rp->r_fires, fire_item); + destroy_item(fire_item); + if (rp->r_fires == NULL) { + rp->r_flags &= ~HASFIRE; + if (cansee(tp->t_pos.y, tp->t_pos.x)) light(&hero); + } + break; + } + } + } + } +} + +/* + * Creat_mons creates the specified monster -- any if 0 + */ + +bool +creat_mons(person, monster, report) +struct thing *person; /* Where to create next to */ +short monster; +bool report; +{ + struct linked_list *nitem; + register struct thing *tp; + struct room *rp; + coord *mp; + + if (levtype == POSTLEV) + return(FALSE); + if ((mp = fallpos(&(person->t_pos), FALSE, 2)) != NULL) { + nitem = new_item(sizeof (struct thing)); + new_monster(nitem, + monster == 0 ? randmonster(FALSE, FALSE) + : monster, + mp, + TRUE); + tp = THINGPTR(nitem); + runto(tp, &hero); + carry_obj(tp, monsters[tp->t_index].m_carry/2); /* only half chance */ + + /* since it just got here, it is disoriented */ + tp->t_no_move = 2 * movement(tp); + + if (on(*tp, HASFIRE)) { + rp = roomin(&tp->t_pos); + if (rp) { + register struct linked_list *fire_item; + + /* Put the new fellow in the room list */ + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rp->r_fires, fire_item); + + rp->r_flags |= HASFIRE; + } + } + + /* + * If we can see this monster, set oldch to ' ' to make light() + * think the creature used to be invisible (ie. not seen here) + */ + if (cansee(tp->t_pos.y, tp->t_pos.x)) tp->t_oldch = ' '; + return(TRUE); + } + if (report) msg("You hear a faint cry of anguish in the distance.. "); + return(FALSE); +} + +/* + * Genmonsters: + * Generate at least 'least' monsters for this single room level. + * 'Treas' indicates whether this is a "treasure" level. + */ + +void +genmonsters(least, treas) +register int least; +bool treas; +{ + reg int i; + reg struct room *rp = &rooms[0]; + reg struct linked_list *item; + reg struct thing *mp; + coord tp; + + for (i = 0; i < (max(50, level) + least); i++) { + if (!treas && rnd(100) < 65) /* put in some little buggers */ + continue; + + /* + * Put the monster in + */ + item = new_item(sizeof *mp); + mp = THINGPTR(item); + do { + rnd_pos(rp, &tp); + } until(mvwinch(stdscr, tp.y, tp.x) == FLOOR); + + new_monster(item, randmonster(FALSE, FALSE), &tp, FALSE); + /* + * See if we want to give it a treasure to carry around. + */ + carry_obj(mp, monsters[mp->t_index].m_carry); + + /* Calculate a movement rate */ + mp->t_no_move = movement(mp); + + /* Is it going to give us some light? */ + if (on(*mp, HASFIRE)) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) mp; + attach(rp->r_fires, fire_item); + rp->r_flags |= HASFIRE; + } + } +} + +/* + * id_monst returns the index of the monster given its letter + */ + +short +id_monst(monster) +register char monster; +{ + register short result; + + if (levtype == OUTSIDE) { + result = NLEVMONS*vlevel + (NUMMONST-NUMDINOS-1); + if (result > NUMMONST) result = NUMMONST; + } + else { + result = NLEVMONS*vlevel; + if (result > NUMMONST-NUMDINOS) result = NUMMONST-NUMDINOS; + } + + if (levtype == OUTSIDE) { + for(; result>(NUMMONST-NUMDINOS-1); result--) + if (monsters[result].m_appear == monster) return(result); + for (result=(NLEVMONS*vlevel)+1; result <= NUMMONST-NUMDINOS; result++) + if (monsters[result].m_appear == monster) return(result); + } + else { + for(; result>0; result--) + if (monsters[result].m_appear == monster) return(result); + for (result=(NLEVMONS*vlevel)+1; result <= NUMMONST; result++) + if (monsters[result].m_appear == monster) return(result); + } + return(0); +} + + +/* + * new_monster: + * Pick a new monster and add it to the list + */ + +new_monster(item, type, cp, max_monster) +struct linked_list *item; +short type; +coord *cp; +bool max_monster; +{ + register struct thing *tp; + register struct monster *mp; + register char *ip, *hitp; + register int i, min_intel, max_intel; + register int num_dice, num_sides=8, num_extra=0; + + attach(mlist, item); + tp = THINGPTR(item); + tp->t_pack = NULL; + tp->t_index = type; + tp->t_wasshot = FALSE; + tp->t_type = monsters[type].m_appear; + tp->t_ctype = C_MONSTER; + tp->t_action = A_NIL; + tp->t_doorgoal.x = tp->t_doorgoal.y = -1; + tp->t_quiet = 0; + tp->t_dest = NULL; + tp->t_name = NULL; + tp->t_pos = tp->t_oldpos = *cp; + tp->t_oldch = mvwinch(cw, cp->y, cp->x); + mvwaddch(mw, cp->y, cp->x, tp->t_type); + mp = &monsters[tp->t_index]; + + /* Figure out monster's hit points */ + hitp = mp->m_stats.ms_hpt; + num_dice = atoi(hitp); + if ((hitp = strchr(hitp, 'd')) != NULL) { + num_sides = atoi(++hitp); + if ((hitp = strchr(hitp, '+')) != NULL) + num_extra = atoi(++hitp); + } + + tp->t_stats.s_lvladj = 0; + tp->t_stats.s_lvl = mp->m_stats.ms_lvl; + tp->t_stats.s_arm = mp->m_stats.ms_arm; + strcpy(tp->t_stats.s_dmg,mp->m_stats.ms_dmg); + tp->t_stats.s_str = mp->m_stats.ms_str; + tp->t_stats.s_dext = mp->m_stats.ms_dex; + tp->t_movement = mp->m_stats.ms_move; + if (vlevel > HARDER) { /* the deeper, the meaner we get */ + tp->t_stats.s_lvl += (vlevel - HARDER); + num_dice += (vlevel - HARDER)/2; + tp->t_stats.s_arm -= (vlevel - HARDER) / 4; + } + if (max_monster) + tp->t_stats.s_hpt = num_dice * num_sides + num_extra; + else + tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra; + tp->t_stats.s_exp = mp->m_stats.ms_exp + mp->m_add_exp*tp->t_stats.s_hpt; + + /* + * just initailize others values to something reasonable for now + * maybe someday will *really* put these in monster table + */ + tp->t_stats.s_wisdom = 8 + rnd(7); + tp->t_stats.s_const = 8 + rnd(7); + tp->t_stats.s_charisma = 8 + rnd(7); + + /* Set the initial flags */ + for (i=0; i<16; i++) tp->t_flags[i] = 0; + for (i=0; i<MAXFLAGS; i++) + turn_on(*tp, mp->m_flags[i]); + + /* + * these are the base chances that a creatures will do something + * assuming it can. These are(or can be) modified at runtime + * based on what the creature experiences + */ + tp->t_breathe = 70; /* base chance of breathing */ + tp->t_artifact = 90; /* base chance of using artifact */ + tp->t_summon = 50; /* base chance of summoning */ + tp->t_cast = 70; /* base chance of casting a spell */ + tp->t_wand = on(*tp, ISUNIQUE) ? 35 : 50; /* base chance of using wands */ + + /* suprising monsters don't always surprise you */ + if (!max_monster && on(*tp, CANSURPRISE) && + off(*tp, ISUNIQUE) && rnd(100) < 25) + turn_off(*tp, CANSURPRISE); + + /* If this monster is unique, gen it */ + if (on(*tp, ISUNIQUE)) mp->m_normal = FALSE; + + /* + * If it is the quartermaster, then compute his level and exp pts + * based on the level. This will make it fair when thieves try to + * steal and give them reasonable experience if they succeed. + * Then fill his pack with his wares. + */ + if (on(*tp, CANSELL)) { + tp->t_stats.s_exp = vlevel * 100; + tp->t_stats.s_lvl = vlevel/2 + 1; + make_sell_pack(tp); + } + + /* Normally scared monsters have a chance to not be scared */ + if (on(*tp, ISFLEE) && (rnd(4) == 0)) turn_off(*tp, ISFLEE); + + /* Figure intelligence */ + min_intel = atoi(mp->m_intel); + if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL) + tp->t_stats.s_intel = min_intel; + else { + max_intel = atoi(++ip); + if (max_monster) + tp->t_stats.s_intel = max_intel; + else + tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel); + } + if (vlevel > HARDER) + tp->t_stats.s_intel += ((vlevel - HARDER)/2); + tp->maxstats = tp->t_stats; + + /* If the monster can shoot, it may have a weapon */ + if (on(*tp, CANSHOOT) && ((rnd(100) < (20 + vlevel)) || max_monster)) { + struct linked_list *item1; + register struct object *cur, *cur1; + + item = new_item(sizeof *cur); + item1 = new_item(sizeof *cur1); + cur = OBJPTR(item); + cur1 = OBJPTR(item1); + cur->o_hplus = (rnd(4) < 3) ? 0 + : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1); + cur->o_dplus = (rnd(4) < 3) ? 0 + : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1); + cur1->o_hplus = (rnd(4) < 3) ? 0 + : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1); + cur1->o_dplus = (rnd(4) < 3) ? 0 + : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1); + strcpy(cur->o_damage,"0d0"); + strcpy(cur->o_hurldmg,"0d0"); + strcpy(cur1->o_damage,"0d0"); + strcpy(cur1->o_hurldmg,"0d0"); + cur->o_ac = cur1->o_ac = 11; + cur->o_count = cur1->o_count = 1; + cur->o_group = cur1->o_group = 0; + cur->contents = cur1->contents = NULL; + if ((cur->o_hplus <= 0) && (cur->o_dplus <= 0)) cur->o_flags = ISCURSED; + if ((cur1->o_hplus <= 0) && (cur1->o_dplus <= 0)) + cur1->o_flags = ISCURSED; + cur->o_flags = cur1->o_flags = 0; + cur->o_type = cur1->o_type = WEAPON; + cur->o_mark[0] = cur1->o_mark[0] = '\0'; + + /* The monster may use a crossbow, sling, or an arrow */ + i = rnd(100); + if (i < 35) { + cur->o_which = CROSSBOW; + cur1->o_which = BOLT; + init_weapon(cur, CROSSBOW); + init_weapon(cur1, BOLT); + } + else if (i < 70) { + cur->o_which = BOW; + cur1->o_which = ARROW; + init_weapon(cur, BOW); + init_weapon(cur1, ARROW); + } + else { + cur->o_which = SLING; + cur1->o_which = ROCK; + init_weapon(cur, SLING); + init_weapon(cur1, ROCK); + } + + attach(tp->t_pack, item); + attach(tp->t_pack, item1); + } + + + /* Calculate the initial movement rate */ + updpack(TRUE, tp); + tp->t_no_move = movement(tp); + + if (ISWEARING(R_AGGR)) + runto(tp, &hero); + + if (on(*tp, ISDISGUISE)) + { + char mch = 0; + + if (tp->t_pack != NULL) + mch = (OBJPTR(tp->t_pack))->o_type; + else + switch (rnd(10)) { + case 0: mch = GOLD; + when 1: mch = POTION; + when 2: mch = SCROLL; + when 3: mch = FOOD; + when 4: mch = WEAPON; + when 5: mch = ARMOR; + when 6: mch = RING; + when 7: mch = STICK; + when 8: mch = monsters[randmonster(FALSE, FALSE)].m_appear; + when 9: mch = MM; + } + tp->t_disguise = mch; + } +} + +/* + * randmonster: + * Pick a monster to show up. The lower the level, + * the meaner the monster. + */ + +short +randmonster(wander, no_unique) +register bool wander, no_unique; +{ + register int d, cur_level, range, i; + + /* + * Do we want a merchant? Merchant is always in place 'NUMMONST' + */ + if (wander && monsters[NUMMONST].m_wander && rnd(100) < pstats.s_charisma/3) + return NUMMONST; + + cur_level = vlevel; + range = (4*NLEVMONS)+1; /* range is 0 thru 12 */ + i = 0; + do + { + if (i++ > NUMMONST-1) { /* in case all have be genocided */ + i = 0; + if (--cur_level <= 0) + fatal("rogue: Could not find a monster to make! "); + } + if (levtype == OUTSIDE) { /* create DINOSUARS */ + d = (cur_level - rnd(range/2)) + (NUMMONST-NUMDINOS-1); + if (d < NUMMONST-NUMDINOS) + d = (NUMMONST-NUMDINOS) + rnd(range/2); + if (d > NUMMONST-1) + d = (NUMMONST-NUMDINOS) + rnd(NUMDINOS); + } + else { /* Create NORMALs and UNIQs here */ + d = (NLEVMONS*(cur_level-1) + rnd(range) - (range-NLEVMONS-1)); + if (d < 1) d = rnd(6)+1; + + if (d > NUMMONST-NUMDINOS-1) { /* Entire range NORMs + UNIQs */ + if (no_unique) /* Choose from last 12 NORMAL monsters */ + d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) - rnd(NUMUNIQUE/5); + else /* Choose from entire UNIQ monsters + range */ + d = (NUMMONST-NUMDINOS-1) - rnd(NUMUNIQUE+range); + } + /* Half-way into the UNIQs now */ + else if (d > (NUMMONST-NUMDINOS-(NUMUNIQUE/2)-1)) { + if (no_unique) /* Choose from last 15 NORMAL monsters */ + d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) - rnd(NUMUNIQUE/4); + else /* Choose from entire UNIQ monsters + range */ + d = (NUMMONST-NUMDINOS-1) - rnd(NUMUNIQUE+range); + } + /* End NORMALs and begin relic bearing UNIQs */ + else if (d > (NUMMONST-NUMDINOS-NUMUNIQUE-1)) { + if (no_unique) /* Choose from last 20 NORMAL monsters */ + d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) - rnd(NUMUNIQUE/3); + else /* Choose from first 20 UNIQ monsters */ + d = (NUMMONST-NUMDINOS-NUMUNIQUE-1) + rnd(NUMUNIQUE/3); + } + } + } + while (wander ? !monsters[d].m_wander || !monsters[d].m_normal + : !monsters[d].m_normal); + return d; +} + +/* Sell displays a menu of goods from which the player may choose + * to purchase something. + */ + +sell(tp) +register struct thing *tp; +{ + register struct linked_list *item, *seller; + register struct linked_list *sellpack; + register struct object *obj; + register long worth, min_worth; + char buffer[LINELEN]; + + /* + * Get a linked_list pointer to the seller. We need this in case + * he disappears so we can set him ISDEAD. + */ + seller = find_mons(tp->t_pos.y, tp->t_pos.x); + + sellpack = tp->t_pack; + if (sellpack == NULL) { + msg("%s looks puzzled and departs.", prname(monster_name(tp), TRUE)); + + /* Get rid of the monster */ + killed(seller, FALSE, FALSE, FALSE); + return; + } + + /* See how much the minimum pack item is worth */ + min_worth = 100000; + for (item = sellpack; item != NULL; item = next(item)) { + obj = OBJPTR(item); + obj->o_flags |= ISPOST; /* Force a long description of the item */ + worth = get_worth(obj); + if (worth < min_worth) min_worth = worth; + } + + /* See if player can afford an item */ + if (min_worth > purse) { + msg("%s eyes your small purse and departs.", + prname(monster_name(tp), TRUE)); + + /* Get rid of the monster */ + killed(seller, FALSE, FALSE, FALSE); + return; + } + + /* Announce our intentions */ + msg("%s opens his pack. --More--", prname(monster_name(tp), TRUE)); + wait_for(' '); + + /* Try to sell something */ + sprintf(buffer, "You got %ld gold pieces. Buy", purse); + item = get_item(sellpack, buffer, ALL, TRUE, TRUE); + + /* Get rid of the monster */ + if (item != NULL) detach(tp->t_pack, item); /* Take it out of the pack */ + killed(seller, FALSE, FALSE, FALSE); + + if (item == NULL) return; + + /* Can he afford the selected item? */ + obj = OBJPTR(item); + + worth = get_worth(obj); + if (worth > purse) { + msg("You cannot afford it."); + o_discard(item); + return; + } + + /* Charge him through the nose */ + purse -= worth; + + /* If a stick or ring, let player know the type */ + switch (obj->o_type) { + case RING: r_know[obj->o_which] = TRUE; + when POTION: p_know[obj->o_which] = TRUE; + when SCROLL: s_know[obj->o_which] = TRUE; + when STICK: ws_know[obj->o_which] = TRUE; + when MM: m_know[obj->o_which] = TRUE; + + } + + /* identify it */ + whatis (item); + + /* Remove the POST flag that we used for get_item() */ + obj->o_flags &= ~ISPOST; + + if (add_pack(item, FALSE) == FALSE) { + obj->o_pos = hero; + fall(item, TRUE); + } +} + +/* + * what to do when the hero steps next to a monster + */ + +struct linked_list * +wake_monster(y, x) +int y, x; +{ + register struct thing *tp; + register struct linked_list *it; + register struct room *trp; + register char *mname; + bool nasty; /* Will the monster "attack"? */ + + if ((it = find_mons(y, x)) == NULL) { + msg("Wake: can't find monster in show (%d, %d)", y, x); + return (NULL); + } + tp = THINGPTR(it); + if (on(*tp, ISSTONE)) /* if stoned, don't do anything */ + return it; + + /* + * For now, if we are a friendly monster, we won't do any of + * our special effects. + */ + if (on(*tp, ISFRIENDLY)) return it; + + trp = roomin(&tp->t_pos); /* Current room for monster */ + + /* + * Let greedy ones in a room guard gold + * (except in a maze where lots of creatures would all go for the + * same piece of gold) + */ + if (on(*tp, ISGREED) && off(*tp, ISRUN) && levtype != MAZELEV && + trp != NULL && lvl_obj != NULL) { + register struct linked_list *item; + register struct object *cur; + + for (item = lvl_obj; item != NULL; item = next(item)) { + cur = OBJPTR(item); + if ((cur->o_type == GOLD) && (roomin(&cur->o_pos) == trp)) { + /* Run to the gold */ + runto(tp, &cur->o_pos); + + /* Make it worth protecting */ + cur->o_count += GOLDCALC + GOLDCALC; + break; + } + } + } + + /* + * Every time he sees mean monster, it might start chasing him + */ + if (on(*tp, ISMEAN) && + off(*tp, ISHELD) && + off(*tp, ISRUN) && + rnd(100) > 35 && + (!is_stealth(&player) || (on(*tp, ISUNIQUE) && rnd(100) > 35)) && + (off(player, ISINVIS) || on(*tp, CANSEE)) || + (trp != NULL && (trp->r_flags & ISTREAS))) { + runto(tp, &hero); + } + + /* + * Get the name; we don't want to do it until here because we need to + * know whether the monster is still sleeping or not. + */ + mname = monster_name(tp); + + /* See if the monster will bother the player */ + nasty = (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x)); + + /* + * if the creature is awake and can see the player and the + * player has the dreaded "eye of vecna" then see if the + * creature is turned to stone + */ + if (cur_relic[EYE_VECNA] && nasty && off(*tp, NOSTONE) && + (off(player, ISINVIS) || on(*tp, CANSEE))) { + turn_on(*tp, NOSTONE); /* only have to save once */ + if (!save(VS_PETRIFICATION, tp, -2)) { + turn_on(*tp, ISSTONE); + turn_off(*tp, ISRUN); + turn_off(*tp, ISINVIS); + turn_off(*tp, CANSURPRISE); + turn_off(*tp, ISDISGUISE); + msg("%s is turned to stone!", prname(mname, TRUE)); + return it; + } + } + + /* + * Handle monsters that can gaze and do things while running + * Player must be able to see the monster and the monster must + * not be asleep + */ + if (nasty && !invisible(tp)) { + /* + * Confusion + */ + if (on(*tp, CANHUH) && + (off(*tp, ISINVIS) || on(player, CANSEE)) && + (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) { + if (!save(VS_MAGIC, &player, 0)) { + if (off(player, ISCLEAR)) { + if (find_slot(unconfuse)) + lengthen(unconfuse, HUHDURATION); + else { + fuse(unconfuse, (VOID *)NULL, HUHDURATION, AFTER); + msg("%s's gaze has confused you.",prname(mname, TRUE)); + turn_on(player, ISHUH); + } + } + else msg("You feel dizzy for a moment, but it quickly passes."); + } + else if (rnd(100) < 67) + turn_off(*tp, CANHUH); /* Once you save, maybe that's it */ + } + + /* Sleep */ + if(on(*tp, CANSNORE) && + player.t_action != A_FREEZE && + !save(VS_PARALYZATION, &player, 0)) { + if (ISWEARING(R_ALERT)) + msg("You feel drowsy for a moment.. "); + else { + msg("%s's gaze puts you to sleep! ", prname(mname, TRUE)); + player.t_no_move += movement(&player) * SLEEPTIME; + player.t_action = A_FREEZE; + if (rnd(100) < 50) turn_off(*tp, CANSNORE); + } + } + + /* Fear */ + if (on(*tp, CANFRIGHTEN) && !on(player, ISFLEE)) { + turn_off(*tp, CANFRIGHTEN); + if (!ISWEARING(R_HEROISM) && + !save(VS_WAND, &player, -(tp->t_stats.s_lvl/10))) { + turn_on(player, ISFLEE); + player.t_dest = &tp->t_pos; + msg("The sight of %s terrifies you!", prname(mname, FALSE)); + } + } + + /* blinding creatures */ + if(on(*tp, CANBLIND) && !find_slot(sight)) { + turn_off(*tp, CANBLIND); + if (!save(VS_WAND, &player, 0)) { + msg("The gaze of %s blinds you! ", prname(mname, FALSE)); + turn_on(player, ISBLIND); + fuse(sight, (VOID *)NULL, rnd(30)+20, AFTER); + light(&hero); + } + } + + /* the sight of the ghost can age you! */ + if (on(*tp, CANAGE)) { + turn_off (*tp, CANAGE); + if (!save(VS_MAGIC, &player, 0)) { + msg ("The sight of %s ages you!", prname(mname, FALSE)); + pstats.s_const--; + /* max_stats.s_const--; */ + if (pstats.s_const < 1) { + pstats.s_hpt = -1; + death (D_CONSTITUTION); + } + } + } + + /* Turning to stone */ + if (on(*tp, LOOKSTONE)) { + turn_off(*tp, LOOKSTONE); + + if (on(player, CANINWALL)) + msg("The gaze of %s has no effect.", prname(mname, FALSE)); + else { + if (!save(VS_PETRIFICATION, &player, 0) && rnd(100) < 5) { + pstats.s_hpt = -1; + msg("The gaze of %s petrifies you!", prname(mname, FALSE)); + msg("You are turned to stone!!! --More--"); + wait_for(' '); + death(D_PETRIFY); + } + else { + msg("The gaze of %s stiffens your limbs.", + prname(mname, FALSE)); + player.t_no_move += movement(&player) * STONETIME; + player.t_action = A_FREEZE; + } + } + } + } + + return it; +} +/* + * wanderer: + * A wandering monster has awakened and is headed for the player + */ + +wanderer() +{ + register int i; + register struct room *hr = roomin(&hero); + register struct linked_list *item; + register struct thing *tp; + register long *attr; /* Points to monsters' attributes */ + int carry; /* Chance of wanderer carrying anything */ + short rmonst; /* Our random wanderer */ + bool canteleport = FALSE, /* Can the monster teleport? */ + seehim; /* Is monster within sight? */ + coord cp; + + rmonst = randmonster(TRUE, FALSE); /* Choose a random wanderer */ + attr = &monsters[rmonst].m_flags[0]; /* Start of attributes */ + for (i=0; i<MAXFLAGS; i++) + if (*attr++ == CANTELEPORT) { + canteleport = TRUE; + break; + } + + /* Find a place for it -- avoid the player's room if can't teleport */ + do { + do { + i = rnd_room(); + } until (canteleport || hr != &rooms[i] || levtype == MAZELEV || + levtype == OUTSIDE); + + /* Make sure the monster does not teleport on top of the player */ + do { + rnd_pos(&rooms[i], &cp); + } while (hr == &rooms[i] && ce(cp, hero)); + } until (step_ok(cp.y, cp.x, NOMONST, (struct thing *)NULL)); + + /* Create a new wandering monster */ + item = new_item(sizeof *tp); + new_monster(item, rmonst, &cp, FALSE); + tp = THINGPTR(item); + runto(tp, &hero); + tp->t_pos = cp; /* Assign the position to the monster */ + seehim = cansee(tp->t_pos.y, tp->t_pos.x); + if (on(*tp, HASFIRE)) { + register struct room *rp; + + rp = roomin(&tp->t_pos); + if (rp) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rp->r_fires, fire_item); + + rp->r_flags |= HASFIRE; + if (seehim && next(rp->r_fires) == NULL) + light(&hero); + } + } + + /* See if we give the monster anything */ + carry = monsters[tp->t_index].m_carry; + if (off(*tp, ISUNIQUE)) carry /= 2; /* Non-unique has only a half chance */ + carry_obj(tp, carry); + + /* Calculate its movement rate */ + tp->t_no_move = movement(tp); + + /* Alert the player if a monster just teleported in */ + if (hr == &rooms[i] && canteleport && seehim && !invisible(tp)) { + msg("A %s just teleported in", monster_name(tp)); + light(&hero); + running = FALSE; + } + + if (wizard) + msg("Started a wandering %s", monster_name(tp)); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/move.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1910 @@ +/* + move.c - Hero movement commands + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include "rogue.h" + +/* + * Used to hold the new hero position + */ + +coord move_nh; + +static char Moves[3][3] = { + { 'y', 'k', 'u' }, + { 'h', '.', 'l' }, + { 'b', 'j', 'n' } +}; + +/* + * be_trapped: + * The guy stepped on a trap.... Make him pay. + */ + +be_trapped(th, tc) +register struct thing *th; +register coord *tc; +{ + register struct trap *tp; + register char ch, *mname = NULL; + register bool is_player = (th == &player), + can_see; + register struct linked_list *mitem = NULL; + register struct thing *mp; + + + /* Can the player see the creature? */ + can_see = cansee(tc->y, tc->x); + can_see &= (is_player || !invisible(th)); + + tp = trap_at(tc->y, tc->x); + /* + * if he's wearing boots of elvenkind, he won't set off the trap + * unless its a magic pool (they're not really traps) + */ + if (is_player && + cur_misc[WEAR_BOOTS] != NULL && + cur_misc[WEAR_BOOTS]->o_which == MM_ELF_BOOTS && + tp->tr_type != POOL) + return '\0'; + + /* + * if the creature is flying then it won't set off the trap + */ + if (on(*th, ISFLY)) + return '\0'; + + tp->tr_flags |= ISFOUND; + + if (!is_player) { + mitem = find_mons(th->t_pos.y, th->t_pos.x); + mname = monster_name(th); + } + else { + count = running = FALSE; + mvwaddch(cw, tp->tr_pos.y, tp->tr_pos.x, tp->tr_type); + } + switch (ch = tp->tr_type) { + case TRAPDOOR: + if (is_player) { + level++; + pstats.s_hpt -= roll(1, 10); + msg("You fell through a trap! "); + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + death(D_FALL); + } + wclear(cw); + wclear(mw); + new_level(NORMLEV); + } + else { + if (can_see) msg("%s fell into a trap!", prname(mname, TRUE)); + + /* + * See if the fall killed the monster + * don't let a UNIQUE die since it might have an artifact + * that we need + */ + if (off(*th,ISUNIQUE) && (th->t_stats.s_hpt-=roll(1,10)) <= 0){ + killed(mitem, FALSE, FALSE, FALSE); + } + else { /* Just move monster to next level */ + check_residue(th); + + /* Erase the monster from the old position */ + if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) + mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); + mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); + + /* let him summon on next lvl */ + if (on (*th, HASSUMMONED)) { + turn_off(*th, HASSUMMONED); + turn_on(*th, CANSUMMON); + } + turn_on(*th,ISELSEWHERE); + detach(mlist, mitem); + attach(tlist, mitem); /* remember him next level */ + + /* Make sure that no one is still chasing us */ + for (mitem = mlist; mitem != NULL; mitem = next(mitem)) { + mp = THINGPTR(mitem); + if (mp->t_dest == &th->t_pos) { + mp->t_dest = &hero; + mp->t_wasshot = FALSE; + turn_off(*mp, ISFLEE); /* Don't run away! */ + } + } + + /* Make sure we were not chasing a monster here */ + th->t_dest = &hero; + if (on(*th, ISFRIENDLY)) turn_off(*th, ISFLEE); + } + } + /* worm hole trap to OUTSIDE */ + when WORMHOLE: + if (is_player) { + prev_max = 1000; /* flag used in n_level.c */ + level++; + msg("You suddenly find yourself in strange surroundings! "); + pstats.s_hpt -= roll(1, 10); + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + death(D_FALL); + } + new_level(OUTSIDE); + return(ch); + } + else { + if (can_see) msg("%s fell into the worm hole! ", prname(mname, TRUE)); + + /* + * See if the fall killed the monster + * don't let a UNIQUE die since it might have an artifact + * that we need + */ + if (off(*th,ISUNIQUE) && (th->t_stats.s_hpt-=roll(1,10)) <= 0){ + killed(mitem, FALSE, FALSE, FALSE); + } + else { /* Just move monster to next level */ + check_residue(th); + + /* Erase the monster from the old position */ + if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) + mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); + mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); + + /* let him summon on next lvl */ + if (on (*th, HASSUMMONED)) { + turn_off(*th, HASSUMMONED); + turn_on(*th, CANSUMMON); + } + + turn_on(*th,ISELSEWHERE); + detach(mlist, mitem); + attach(tlist, mitem); /* remember him next level */ + + /* Make sure that no one is still chasing us */ + for (mitem = mlist; mitem != NULL; mitem = next(mitem)) { + mp = THINGPTR(mitem); + if (mp->t_dest == &th->t_pos) { + mp->t_dest = &hero; + mp->t_wasshot = FALSE; + turn_off(*mp, ISFLEE); /* Don't run away! */ + } + } + + /* Make sure we were not chasing a monster here */ + th->t_dest = &hero; + if (on(*th, ISFRIENDLY)) turn_off(*th, ISFLEE); + } + } + when BEARTRAP: + if (is_stealth(th)) { + if (is_player) msg("You pass a bear trap."); + else if (can_see) msg("%s passes a bear trap.", + prname(mname, TRUE)); + } + else { + th->t_no_move += movement(&player) * BEARTIME; + th->t_action = A_FREEZE; + if (is_player) msg("You are caught in a bear trap."); + else if (can_see) msg("%s is caught in a bear trap.", + prname(mname, TRUE)); + } + when SLEEPTRAP: + if (is_player) { + if (!ISWEARING(R_ALERT)) { + msg("A strange white mist envelops you. You fall asleep. "); + player.t_no_move += movement(&player) * SLEEPTIME; + player.t_action = A_FREEZE; + } + else { + msg("The white mist invigorates you. "); + } + } + else { + if (can_see) + msg("A strange white mist envelops %s. ", + prname(mname, FALSE)); + if (on(*th, ISUNDEAD)) { + if (can_see) + msg("The mist doesn't seem to affect %s.", + prname(mname, FALSE)); + } + else { + th->t_no_move += movement(th) * SLEEPTIME; + th->t_action = A_FREEZE; + } + } + when ARROWTRAP: + if (swing(th->t_ctype, th->t_stats.s_lvl-1, th->t_stats.s_arm, 1)) + { + if (is_player) { + msg("Oh no! An arrow shot you."); + if ((pstats.s_hpt -= roll(1, 8)) < 1) { + pstats.s_hpt = -1; + msg("The arrow killed you. --More--"); + wait_for(' '); + death(D_ARROW); + } + } + else { + if (can_see) + msg("An arrow shot %s.", prname(mname, FALSE)); + if ((th->t_stats.s_hpt -= roll(1, 8)) < 1) { + if (can_see) + msg("The arrow killed %s.", prname(mname, FALSE)); + killed(mitem, FALSE, FALSE, TRUE); + } + } + } + else + { + register struct linked_list *item; + register struct object *arrow; + + if (is_player) msg("An arrow shoots past you."); + else if (can_see) + msg("An arrow shoots by %s.", prname(mname, FALSE)); + item = new_item(sizeof *arrow); + arrow = OBJPTR(item); + arrow->o_type = WEAPON; + arrow->contents = NULL; + arrow->o_which = ARROW; + arrow->o_hplus = rnd(7) - 1; + arrow->o_dplus = rnd(7) - 1; + init_weapon(arrow, ARROW); + arrow->o_count = 1; + arrow->o_pos = *tc; + arrow->o_mark[0] = '\0'; + fall(item, FALSE); + } + when TELTRAP: + if (is_player) teleport(); + else { + register int rm; + struct room *old_room; /* old room of monster */ + + /* + * Erase the monster from the old position + */ + if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) + mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); + mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); + /* + * check to see if room should go dark + */ + if (on(*th, HASFIRE)) { + old_room=roomin(&th->t_pos); + if (old_room != NULL) { + register struct linked_list *fire_item; + + for (fire_item = old_room->r_fires; fire_item != NULL; + fire_item = next(fire_item)) { + if (THINGPTR(fire_item) == th) { + detach(old_room->r_fires, fire_item); + destroy_item(fire_item); + + if (old_room->r_fires == NULL) { + old_room->r_flags &= ~HASFIRE; + if (can_see) light(&hero); + } + } + } + } + } + + /* Get a new position */ + do { + rm = rnd_room(); + rnd_pos(&rooms[rm], &th->t_pos); + } until(winat(th->t_pos.y, th->t_pos.x) == FLOOR); + + /* Put it there */ + mvwaddch(mw, th->t_pos.y, th->t_pos.x, th->t_type); + th->t_oldch = mvwinch(cw, th->t_pos.y, th->t_pos.x); + /* + * check to see if room that creature appears in should + * light up + */ + if (on(*th, HASFIRE)) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) th; + attach(rooms[rm].r_fires, fire_item); + + rooms[rm].r_flags |= HASFIRE; + if(cansee(th->t_pos.y, th->t_pos.x) && + next(rooms[rm].r_fires) == NULL) + light(&hero); + } + if (can_see) + msg("%s seems to have disappeared!", prname(mname, TRUE)); + } + when DARTTRAP: + if (swing(th->t_ctype, th->t_stats.s_lvl+1, th->t_stats.s_arm, 1)) { + if (is_player) { + msg("A small dart just hit you. "); + if ((pstats.s_hpt -= roll(1, 8)) < 1) { + pstats.s_hpt = -1; + msg("The dart killed you."); + wait_for(' '); + death(D_DART); + } + + /* Now the poison */ + if (!save(VS_POISON, &player, 0)) { + /* 75% chance it will do point damage - else strength */ + if (rnd(100) < 75) { + pstats.s_hpt /= 2; + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + death(D_POISON); + } + } + else if (!ISWEARING(R_SUSABILITY)) + chg_str(-1); + } + } + else { + if (can_see) + msg("A small dart stabs the %s. ", + prname(mname, FALSE)); + if ((th->t_stats.s_hpt -= roll(1,8)) < 1) { + if (can_see) + msg("The dart killed %s.", prname(mname, FALSE)); + killed(mitem, FALSE, FALSE, TRUE); + } + if (!save(VS_POISON, th, 0)) { + th->t_stats.s_hpt /= 2 + level; + if (th->t_stats.s_hpt < 1) { + if (can_see) + msg("The dart killed %s.", prname(mname,FALSE)); + killed(mitem, FALSE, FALSE, TRUE); + } + } + } + } + else { + if (is_player) + msg("A small dart whizzes by your ear and vanishes."); + else if (can_see) + msg("A small dart whizzes by %s's ear and vanishes.", + prname(mname, FALSE)); + } + when POOL: { + register int i; + + i = rnd(100); + if (is_player) { + if ((tp->tr_flags & ISGONE)) { + if (i < 56) { + teleport(); /* teleport away */ + pool_teleport = TRUE; + } + else if((i < 72) && level > 4) { + level -= rnd(4) + 1; + cur_max = level; + new_level(NORMLEV); + pool_teleport = TRUE; + msg("You here a faint groan from below."); + } + else if(i < 85) { + level += rnd(4) + 1; + new_level(NORMLEV); + pool_teleport = TRUE; + msg("You find yourself in strange surroundings."); + } + else if(i > 96) { + msg("Oh no!!! You drown in the pool!!! --More--"); + wait_for(' '); + pstats.s_hpt = -1; + death(D_DROWN); + } + else { + new_level(NORMLEV); + pool_teleport = TRUE; + msg("You are whisked away to another region."); + } + } + } + else { + if (i < 60) { + if (can_see) { + /* Drowns */ + if (i < 50) + msg("%s drowned in the pool!", prname(mname, TRUE)); + + /* Teleported to another level */ + else msg("%s disappeared!", prname(mname, TRUE)); + } + killed(mitem, FALSE, FALSE, TRUE); + } + } + } + when MAZETRAP: + if (is_player) { + pstats.s_hpt -= roll(1, 10); + level++; + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + death(D_FALL); + } + wclear(cw); + wclear(mw); + new_level(MAZELEV); + msg("You are surrounded by twisty passages! "); + } + else { + if (can_see) msg("%s fell into a maze trap!", prname(mname, TRUE)); + if (on(*th, ISUNIQUE)) { + check_residue(th); + + /* Erase the monster from the old position */ + if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) + mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); + mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); + + /* let him summon on next lvl */ + if (on (*th, HASSUMMONED)) { + turn_off(*th, HASSUMMONED); + turn_on(*th, CANSUMMON); + } + turn_on(*th,ISELSEWHERE); + detach(mlist, mitem); + attach(tlist, mitem); /* remember him next level */ + + /* Make sure that no one is still chasing us */ + for (mitem = mlist; mitem != NULL; mitem = next(mitem)) { + mp = THINGPTR(mitem); + if (mp->t_dest == &th->t_pos) { + mp->t_dest = &hero; + mp->t_wasshot = FALSE; + turn_off(*mp, ISFLEE); /* Don't run away! */ + } + } + + /* Make sure we were not chasing a monster here */ + th->t_dest = &hero; + if (on(*th, ISFRIENDLY)) turn_off(*th, ISFLEE); + } + else + killed(mitem, FALSE, FALSE, FALSE); + } + } + + /* Move the cursor back onto the hero */ + wmove(cw, hero.y, hero.x); + + flushinp(); + return(ch); +} + +/* + * blue_light: + * magically light up a room (or level or make it dark) + */ + +bool +blue_light(blessed, cursed) +bool blessed, cursed; +{ + register struct room *rp; + bool ret_val=FALSE; /* Whether or not affect is known */ + + rp = roomin(&hero); /* What room is hero in? */ + + /* Darken the room if the magic is cursed */ + if (cursed) { + if ((rp == NULL) || !lit_room(rp)) msg(nothing); + else { + rp->r_flags |= ISDARK; + if (!lit_room(rp) && (levtype != OUTSIDE || !daytime) && + !ISWEARING(R_LIGHT)) + msg("The %s suddenly goes dark.", + levtype == OUTSIDE ? "area" : "room"); + else msg(nothing); + ret_val = TRUE; + } + } + else { + ret_val = TRUE; + if (rp && !lit_room(rp) && + (levtype != OUTSIDE || !daytime)) { + addmsg("The %s is lit", levtype == OUTSIDE ? "area" : "room"); + addmsg(" by a %s blue light.", blessed ? "bright" : "shimmering"); + endmsg(); + } + else if (winat(hero.y, hero.x) == PASSAGE) + msg("The corridor glows %sand then fades", + blessed ? "brightly " : ""); + else { + ret_val = FALSE; + msg(nothing); + } + if (blessed) { + register int i; /* Index through rooms */ + + for (i=0; i<MAXROOMS; i++) + rooms[i].r_flags &= ~ISDARK; + } + else if (rp) rp->r_flags &= ~ISDARK; + } + + /* + * Light the room and put the player back up + */ + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + return(ret_val); +} + +/* + * corr_move: + * Check to see that a move is legal. If so, return correct character. + * If not, if player came from a legal place, then try to turn him. + */ + +corr_move(dy, dx) +int dy, dx; +{ + int legal=0; /* Number of legal alternatives */ + register int y, x, /* Indexes though possible positions */ + locy = 0, locx = 0; /* Hold delta of chosen location */ + + /* New position */ + move_nh.y = hero.y + dy; + move_nh.x = hero.x + dx; + + /* If it is a legal move, just return */ + if (move_nh.x >= 0 && move_nh.x < cols && move_nh.y > 0 && move_nh.y < lines - 2) { + + switch (winat(move_nh.y, move_nh.x)) { + case WALL: + case VERTWALL: + case HORZWALL: + break; + default: + if (diag_ok(&hero, &move_nh, &player)) + return; + } + } + + /* Check legal places surrounding the player -- ignore previous position */ + for (y = hero.y - 1; y <= hero.y + 1; y++) { + if (y < 1 || y > lines - 3) + continue; + for (x = hero.x - 1; x <= hero.x + 1; x++) { + /* Ignore borders of the screen */ + if (x < 0 || x > cols - 1) + continue; + + /* + * Ignore where we came from, where we are, and where we couldn't go + */ + if ((x == hero.x - dx && y == hero.y - dy) || + (x == hero.x + dx && y == hero.y + dy) || + (x == hero.x && y == hero.y)) + continue; + + switch (winat(y, x)) { + case WALL: + case VERTWALL: + case HORZWALL: + break; + default: + move_nh.y = y; + move_nh.x = x; + if (diag_ok(&hero, &move_nh, &player)) { + legal++; + locy = y - (hero.y - 1); + locx = x - (hero.x - 1); + } + } + } + } + + /* If we have 2 or more legal moves, make no change */ + if (legal != 1) { + return; + } + + runch = Moves[locy][locx]; + + /* + * For mazes, pretend like it is the beginning of a new run at each turn + * in order to get the lighting correct. + */ + if (levtype == MAZELEV) firstmove = TRUE; + return; +} + +/* + * dip_it: + * Dip an object into a magic pool + */ + +dip_it() +{ + reg struct linked_list *what; + reg struct object *ob; + reg struct trap *tp; + reg int wh, i; + + tp = trap_at(hero.y,hero.x); + if (tp == NULL || tp->tr_type != POOL) { + msg("I see no shimmering pool here"); + return; + } + if (tp->tr_flags & ISGONE) { + msg("This shimmering pool appears to have been used once already."); + return; + } + + /* It takes 3 movement periods to dip something */ + if (player.t_action != C_DIP) { + if ((what = get_item(pack, "dip", ALL, FALSE, FALSE)) == NULL) { + msg(""); + after = FALSE; + return; + } + + ob = OBJPTR(what); + if (ob == cur_armor || + ob == cur_misc[WEAR_BOOTS] || + ob == cur_misc[WEAR_JEWEL] || + ob == cur_misc[WEAR_GAUNTLET] || + ob == cur_misc[WEAR_CLOAK] || + ob == cur_misc[WEAR_BRACERS] || + ob == cur_misc[WEAR_NECKLACE] || + ob == cur_ring[LEFT_1] || ob == cur_ring[LEFT_2] || + ob == cur_ring[LEFT_3] || ob == cur_ring[LEFT_4] || + ob == cur_ring[RIGHT_1] || ob == cur_ring[RIGHT_2] || + ob == cur_ring[RIGHT_3] || ob == cur_ring[RIGHT_4]) { + mpos = 0; + msg("You'll have to take it off first."); + return; + } + + player.t_using = what; /* Remember what it is */ + player.t_action = C_DIP; /* We are dipping */ + player.t_no_move = 3 * movement(&player); + return; + } + + /* We have waited our time, let's dip it */ + what = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + ob = OBJPTR(what); + + tp->tr_flags |= ISGONE; + if (ob != NULL) { + wh = ob->o_which; + ob->o_flags |= ISKNOW; + i = rnd(100); + if (ob->o_group != 0) + ob->o_group = newgrp(); /* change the group */ + switch(ob->o_type) { + case WEAPON: + if(i < 60) { /* enchant weapon here */ + if ((ob->o_flags & ISCURSED) == 0) { + ob->o_hplus += 1; + ob->o_dplus += 1; + } + else { /* weapon was prev cursed here */ + ob->o_hplus = rnd(2); + ob->o_dplus = rnd(2); + } + ob->o_flags &= ~ISCURSED; + msg("The %s glows blue for a moment.",weaps[wh].w_name); + } + else if(i < 75) { /* curse weapon here */ + if ((ob->o_flags & ISCURSED) == 0) { + ob->o_hplus = -(rnd(2)+1); + ob->o_dplus = -(rnd(2)+1); + } + else { /* if already cursed */ + ob->o_hplus--; + ob->o_dplus--; + } + ob->o_flags |= ISCURSED; + msg("The %s glows red for a moment.",weaps[wh].w_name); + } + else + msg(nothing); + when ARMOR: + if (i < 60) { /* enchant armor */ + if((ob->o_flags & ISCURSED) == 0) + ob->o_ac -= rnd(2) + 1; + else + ob->o_ac = -rnd(3)+ armors[wh].a_class; + ob->o_flags &= ~ISCURSED; + msg("The %s glows blue for a moment",armors[wh].a_name); + } + else if(i < 75){ /* curse armor */ + if ((ob->o_flags & ISCURSED) == 0) + ob->o_ac = rnd(3)+ armors[wh].a_class; + else + ob->o_ac += rnd(2) + 1; + ob->o_flags |= ISCURSED; + msg("The %s glows red for a moment.",armors[wh].a_name); + } + else + msg(nothing); + when STICK: { + int j; + j = rnd(14) + 1; + if(i < 60) { /* add charges */ + ob->o_charges += j; + ws_know[wh] = TRUE; + if (ob->o_flags & ISCURSED) + ob->o_flags &= ~ISCURSED; + msg("The %s %s glows blue for a moment.", + ws_made[wh],ws_type[wh]); + } + else if(i < 75) { /* remove charges */ + if ((ob->o_charges -= i) < 0) + ob->o_charges = 0; + ws_know[wh] = TRUE; + if (ob->o_flags & ISBLESSED) + ob->o_flags &= ~ISBLESSED; + else + ob->o_flags |= ISCURSED; + msg("The %s %s glows red for a moment.", + ws_made[wh],ws_type[wh]); + } + else + msg(nothing); + } + when SCROLL: + s_know[wh] = TRUE; + msg("The '%s' scroll unfurls.",s_names[wh]); + when POTION: + p_know[wh] = TRUE; + msg("The %s potion bubbles for a moment.. ",p_colors[wh]); + when RING: + if(i < 60) { /* enchant ring */ + if ((ob->o_flags & ISCURSED) == 0) + ob->o_ac += rnd(2) + 1; + else + ob->o_ac = rnd(2) + 1; + ob->o_flags &= ~ISCURSED; + } + else if(i < 75) { /* curse ring */ + if ((ob->o_flags & ISCURSED) == 0) + ob->o_ac = -(rnd(2) + 1); + else + ob->o_ac -= (rnd(2) + 1); + ob->o_flags |= ISCURSED; + } + r_know[wh] = TRUE; + msg("The %s ring vibrates for a moment.",r_stones[wh]); + when MM: + m_know[wh] = TRUE; + switch (ob->o_which) { + case MM_BRACERS: + case MM_PROTECT: + if(i < 60) { /* enchant item */ + if ((ob->o_flags & ISCURSED) == 0) + ob->o_ac += rnd(2) + 1; + else + ob->o_ac = rnd(2) + 1; + ob->o_flags &= ~ISCURSED; + } + else if(i < 75) { /* curse item */ + if ((ob->o_flags & ISCURSED) == 0) + ob->o_ac = -(rnd(2) + 1); + else + ob->o_ac -= (rnd(2) + 1); + ob->o_flags |= ISCURSED; + } + msg("The item vibrates for a moment."); + when MM_CHOKE: + case MM_DISAPPEAR: + ob->o_ac = 0; + msg ("The dust dissolves in the pool!"); + } + otherwise: + msg("The pool bubbles up for a moment.. "); + } + updpack(FALSE, &player); + } + else + msg(nothing); +} + +/* + * do_move: + * Check to see that a move is legal. If it is handle the + * consequences (fighting, picking up, etc.) + */ + +do_move(dy, dx) +int dy, dx; +{ + register struct room *rp, *orp; + register unsigned char ch; + struct linked_list *item; + register struct thing *tp = NULL; + coord old_hero; + register int wasfirstmove, moved, num_hits; + bool changed=FALSE; /* Did we switch places with a friendly monster? */ + + wasfirstmove = firstmove; + firstmove = FALSE; + curprice = -1; /* if in trading post, we've moved off obj */ + + /* + * Do a confused move (maybe) + */ + if (player.t_action == A_NIL && + ((on(player, ISHUH) && rnd(100) < 80) || + (on(player, ISDANCE) && rnd(100) < 90) || + (ISWEARING(R_DELUSION) && rnd(100) < 70))) + { + /* Get a random move */ + move_nh = rndmove(&player); + dy = move_nh.y - hero.y; + dx = move_nh.x - hero.x; + } + else { + move_nh.y = hero.y + dy; + move_nh.x = hero.x + dx; + } + + /* + * Check if he tried to move off the screen or make an illegal + * diagonal move, and stop him if he did. + */ + if (move_nh.x < 0 || move_nh.x > cols-1 || move_nh.y < 1 || move_nh.y >= lines - 2 + || !diag_ok(&hero, &move_nh, &player)) + { + after = running = FALSE; + player.t_action = A_NIL; + return; + } + if (running && ce(hero, move_nh)) + after = running = FALSE; + ch = winat(move_nh.y, move_nh.x); + + /* Take care of hero trying to move close to something frightening */ + if (on(player, ISFLEE)) { + if (rnd(100) < 12) { + turn_off(player, ISFLEE); + msg("You regain your composure."); + } + else if (DISTANCE(move_nh.y, move_nh.x, player.t_dest->y, player.t_dest->x) < + DISTANCE(hero.y, hero.x, player.t_dest->y, player.t_dest->x)) { + running = FALSE; + msg("You are too terrified to move that way"); + player.t_action = A_NIL; + player.t_no_move = movement(&player); + return; + } + } + + /* If we want to move to a monster, see what it is */ + if (isalpha(ch)) { + item = find_mons(move_nh.y, move_nh.x); + if (item == NULL) { + debug("Cannot find monster in move."); + player.t_action = A_NIL; + return; + } + tp = THINGPTR(item); + } + + /* + * Take care of hero being held. If the player is being held, he + * can't move unless he is either attacking a non-friendly monster + * or attacking a friendly monster that can't move. + */ + if (on(player, ISHELD) && + (!isalpha(ch) || (on(*tp, ISFRIENDLY) && off(*tp, ISHELD)))) { + msg("You are being held."); + player.t_action = A_NIL; + return; + } + + /* See if we have to wait for our movement rate */ + if (player.t_action == A_NIL) { + after = FALSE; + firstmove = wasfirstmove; /* Remember if this is first move */ + player.t_no_move = movement(&player); + if (player.t_ctype == C_MONK) + player.t_no_move -= pstats.s_lvl/6; + if (on(player, ISFLY)) + player.t_no_move /= 2; /* If flying, speed him up */ + + if (player.t_no_move < 1) player.t_no_move = 1; + + /* Remember our action */ + player.t_action = Moves[dy+1][dx+1]; + return; + } + + /* Now let's forget the old move and just do it */ + player.t_action = A_NIL; + + /* If we're moving onto a friendly monster, let's change places. */ + if (isalpha(ch) && on(*tp, ISFRIENDLY) && off(*tp, ISHELD)) { + coord tpos, /* Where monster may have been going */ + current; /* Current hero position */ + int action; /* The monster's action */ + + current = hero; + tpos = tp->t_newpos; + action = tp->t_action; + + /* Disrupt whatever our friend was doing */ + tp->t_action = A_NIL; + + /* Tentatively move us to where he is */ + hero = tp->t_pos; + + /* See if we can move him to where we were */ + tp->t_newpos = current; + do_chase(tp); + + /* Did we succeed? */ + if (ce(tp->t_pos, current)) { + /* Reset our idea of what ch is */ + ch = winat(move_nh.y, move_nh.x); + + /* Let it be known that we made the switch */ + changed = TRUE; + old_hero = current; + + /* Make the monster think it didn't move */ + tp->t_oldpos = current; + tp->t_doorgoal.x = tp->t_doorgoal.y = -1; + + /* Let the player know something funny happened. */ + msg("What a sidestep!"); + } + else { + /* Restore things -- we couldn't move */ + hero = current; + tp->t_newpos = tpos; + tp->t_action = action; + } + } + + /* assume he's not in a wall */ + if (!isalpha(ch)) turn_off(player, ISINWALL); + + switch (ch) { + case VERTWALL: + case HORZWALL: + if (levtype == OUTSIDE) { + hero = move_nh; + new_level(OUTSIDE); + return; + } + case WALL: + case SECRETDOOR: + if (off(player, CANINWALL) || running) { + after = running = FALSE; + + /* Light if finishing run */ + if (levtype == MAZELEV && lit_room(&rooms[0])) + look(FALSE, TRUE); + + after = running = FALSE; + + return; + } + turn_on(player, ISINWALL); + break; + case POOL: + if (levtype == OUTSIDE) { + /* lake_check(&move_nh); */ /* not implemented yet */ + running = FALSE; + break; + } + case MAZETRAP: + if (levtype == OUTSIDE) { + running = FALSE; + break; + } + case TRAPDOOR: + case TELTRAP: + case BEARTRAP: + case SLEEPTRAP: + case ARROWTRAP: + case DARTTRAP: + case WORMHOLE: + ch = be_trapped(&player, &move_nh); + if (ch == TRAPDOOR || ch == TELTRAP || + pool_teleport || ch == MAZETRAP) { + pool_teleport = FALSE; + return; + } + break; + case GOLD: + case POTION: + case SCROLL: + case FOOD: + case WEAPON: + case ARMOR: + case RING: + case MM: + case RELIC: + case STICK: + running = FALSE; + take = ch; + break; + case DOOR: + case STAIRS: + case POST: + running = FALSE; + break; + default: + break; + } + + if (isalpha(ch)) { /* if its a monster then fight it */ + /* + * If we were running down a corridor and didn't start right + * next to the critter, don't do anything. + */ + if (running && wasfirstmove == FALSE && roomin(&hero) == NULL) { + struct linked_list *item; + + item = find_mons(move_nh.y, move_nh.x); + if (item != NULL && !invisible(THINGPTR(item))) { + after = running = FALSE; + return; + } + } + + /* We have to add time because we're attacking */ + player.t_no_move = FIGHTBASE; + player.t_no_move += weap_move(&player, cur_weapon); + if (on(player, ISHASTE)) + player.t_no_move /= 2; + else if (on(player, ISSLOW)) + player.t_no_move *= 2; + + /* We may attack faster if we're high enough level + * and the right class + */ + switch(player.t_ctype) { + case C_FIGHTER: num_hits = player.t_stats.s_lvl/25 + 1; + when C_PALADIN: num_hits = player.t_stats.s_lvl/35 + 1; + when C_RANGER: num_hits = player.t_stats.s_lvl/35 + 1; + when C_MONK: if(cur_weapon) num_hits = player.t_stats.s_lvl/40 + 1; + else num_hits = player.t_stats.s_lvl/30 + 1; + otherwise: num_hits = player.t_stats.s_lvl/60 + 1; + } + + /* + * The player has already moved the initial movement period. + * Let's add that in, do our division, and then subtract it + * out so that the total time is divided, not just the + * additional attack time. + */ + moved = movement(&player), + player.t_no_move += moved; + player.t_no_move /= num_hits; + player.t_no_move -= moved; + running = FALSE; + + /* Mark that we are attacking and save the attack coordinate */ + player.t_action = A_ATTACK; + player.t_newpos = move_nh; + runch = Moves[dy+1][dx+1]; /* Remember the direction */ + + if (player.t_no_move <= 0) after = FALSE; + return; + } + + /* + * if not fighting then move the hero + */ + if (changed == FALSE) { + old_hero = hero; /* Save hero's old position */ + hero = move_nh; /* Move the hero */ + } + rp = roomin(&hero); + orp = roomin(&old_hero); + + /* Unlight any possible cross-corridor */ + if (levtype == MAZELEV) { + register bool call_light = FALSE; + register unsigned char wall_check; + + if (wasfirstmove && lit_room(&rooms[0])) { + /* Are we moving out of a corridor? */ + switch (runch) { + case 'h': + case 'l': + if (old_hero.y + 1 < lines - 2) { + wall_check = winat(old_hero.y + 1, old_hero.x); + if (!isrock(wall_check)) call_light = TRUE; + } + if (old_hero.y - 1 > 0) { + wall_check = winat(old_hero.y - 1, old_hero.x); + if (!isrock(wall_check)) call_light = TRUE; + } + break; + case 'j': + case 'k': + if (old_hero.x + 1 < cols) { + wall_check = winat(old_hero.y, old_hero.x + 1); + if (!isrock(wall_check)) call_light = TRUE; + } + if (old_hero.x - 1 >= 0) { + wall_check = winat(old_hero.y, old_hero.x - 1); + if (!isrock(wall_check)) call_light = TRUE; + } + break; + default: + call_light = TRUE; + } + player.t_oldpos = old_hero; + if (call_light) light(&old_hero); + } + } + + else if (orp != NULL && rp == NULL) { /* Leaving a room -- darken it */ + orp->r_flags |= FORCEDARK; /* Fake darkness */ + light(&old_hero); + orp->r_flags &= ~FORCEDARK; /* Restore light state */ + } + else if (rp != NULL && orp == NULL){/* Entering a room */ + light(&hero); + if (rp->r_flags & ISTREAS) + wake_room(rp); + } + ch = winat(old_hero.y, old_hero.x); + wmove(cw, unc(old_hero)); + waddch(cw, ch); + wmove(cw, unc(hero)); + waddch(cw, PLAYER); +} + +/* + * do_run: + * Start the hero running + */ + +do_run(ch) +char ch; +{ + firstmove = TRUE; + running = TRUE; + after = FALSE; + runch = ch; +} + +/* + * getdelta: + * Takes a movement character (eg. h, j, k, l) and returns the + * y and x delta corresponding to it in the remaining arguments. + * Returns TRUE if it could find it, FALSE otherwise. + */ + +bool +getdelta(match, dy, dx) +char match; +int *dy, *dx; +{ + register int y, x; + + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) + if (Moves[y][x] == match) { + *dy = y - 1; + *dx = x - 1; + return(TRUE); + } + + return(FALSE); +} + +/* + * isatrap: + * Returns TRUE if this character is some kind of trap + */ + +isatrap(ch) +reg char ch; +{ + switch(ch) { + case WORMHOLE: + case DARTTRAP: + case TELTRAP: + case TRAPDOOR: + case ARROWTRAP: + case SLEEPTRAP: + case BEARTRAP: return(TRUE); + case MAZETRAP: + case POOL: return(levtype != OUTSIDE); + default: return(FALSE); + } +} + +/* + * Called to illuminate a room. + * If it is dark, remove anything that might move. + */ + +light(cp) +coord *cp; +{ + register struct room *rp; + register int j, k, x, y; + register unsigned char ch, rch, sch; + register struct linked_list *item; + int jlow, jhigh, klow, khigh; /* Boundaries of lit area */ + + if ((rp = roomin(cp)) != NULL) { + /* + * is he wearing ring of illumination? + */ + if (&hero == cp && ISWEARING(R_LIGHT)) /* Must be hero's room */ + rp->r_flags &= ~ISDARK; + + /* If we are in a maze, don't look at the whole room (level) */ + if (levtype == MAZELEV) { + int see_radius; + + see_radius = 1; + + /* If we are looking at the hero in a rock, broaden our sights */ + if (&hero == cp || &player.t_oldpos == cp) { + ch = winat(hero.y, hero.x); + if (isrock(ch)) see_radius = 2; + ch = winat(player.t_oldpos.y, player.t_oldpos.x); + if (isrock(ch)) see_radius = 2; + } + + jlow = max(0, cp->y - see_radius - rp->r_pos.y); + jhigh = min(rp->r_max.y, cp->y + see_radius + 1 - rp->r_pos.y); + klow = max(0, cp->x - see_radius - rp->r_pos.x); + khigh = min(rp->r_max.x, cp->x + see_radius + 1 - rp->r_pos.x); + } + else { + jlow = klow = 0; + jhigh = rp->r_max.y; + khigh = rp->r_max.x; + } + for (j = 0; j < rp->r_max.y; j++) + { + for (k = 0; k < rp->r_max.x; k++) + { + bool see_here = 0, see_before = 0; + + /* Is this in the give area -- needed for maze */ + if ((j < jlow || j >= jhigh) && (k < klow || k >= khigh)) + continue; + + y = rp->r_pos.y + j; + x = rp->r_pos.x + k; + + /* + * If we are in a maze do not look at this area unless + * we can see it from where we are or where we last were + * (for erasing purposes). + */ + if (levtype == MAZELEV) { + /* If we can't see it from here, could we see it before? */ + if ((see_here = maze_view(y, x)) == FALSE) { + coord savhero; + + /* Could we see it from where we were? */ + savhero = hero; + hero = player.t_oldpos; + see_before = maze_view(y, x); + hero = savhero; + + if (!see_before) continue; + } + } + + ch = show(y, x); + wmove(cw, y, x); + /* + * Figure out how to display a secret door + */ + if (ch == SECRETDOOR) { + if (j == 0 || j == rp->r_max.y - 1) + ch = HORZWALL; + else + ch = VERTWALL; + } + /* For monsters, if they were previously not seen and + * now can be seen, or vice-versa, make sure that will + * happen. This is for dark rooms as opposed to invisibility. + * + * Call winat() in the test because ch will not reveal + * invisible monsters. + */ + if (isalpha(winat(y, x))) { + struct thing *tp; /* The monster */ + + item = wake_monster(y, x); + tp = THINGPTR(item); + + /* Previously not seen -- now can see it */ + if (tp->t_oldch == ' ' && cansee(tp->t_pos.y, tp->t_pos.x)) + tp->t_oldch = mvinch(y, x); + + /* Previously seen -- now can't see it */ + else if (!cansee(tp->t_pos.y, tp->t_pos.x) && + roomin(&tp->t_pos) != NULL) + switch (tp->t_oldch) { + /* + * Only blank it out if it is in a room and not + * the border (or other wall) of the room. + */ + case DOOR: + case SECRETDOOR: + case HORZWALL: + case VERTWALL: + break; + + otherwise: + tp->t_oldch = ' '; + } + } + + /* + * If the room is a dark room, we might want to remove + * monsters and the like from it (since they might + * move). + * A dark room. + */ + if ((!lit_room(rp) && (levtype != OUTSIDE)) || + (levtype == OUTSIDE && !daytime) || + on(player, ISBLIND) || + (rp->r_flags & FORCEDARK) || + (levtype == MAZELEV && !see_here && see_before)) { + sch = mvwinch(cw, y, x); /* What's seen */ + rch = mvinch(y, x); /* What's really there */ + switch (rch) { + case DOOR: + case SECRETDOOR: + case STAIRS: + case TRAPDOOR: + case WORMHOLE: + case TELTRAP: + case BEARTRAP: + case SLEEPTRAP: + case ARROWTRAP: + case DARTTRAP: + case MAZETRAP: + case POOL: + case POST: + case VERTWALL: + case HORZWALL: + case WALL: + if (isalpha(sch)) ch = rch; + else if (sch != FLOOR) ch = sch; + else ch = ' '; /* Hide undiscoverd things */ + when FLOOR: + ch = ' '; + otherwise: + ch = ' '; + } + /* Take care of our magic bookkeeping. */ + switch (sch) { + case MAGIC: + case BMAGIC: + case CMAGIC: + ch = sch; + } + } + mvwaddch(cw, y, x, ch); + } + } + } +} + +/* + * lit_room: + * Called to see if the specified room is lit up or not. + */ + +bool +lit_room(rp) +register struct room *rp; +{ + register struct linked_list *fire_item; + register struct thing *fire_creature; + + if (!(rp->r_flags & ISDARK)) return(TRUE); /* A definitely lit room */ + + /* Is it lit by fire light? */ + if (rp->r_flags & HASFIRE) { + switch ((int)levtype) { + case MAZELEV: + /* See if a fire creature is in line of sight */ + for (fire_item = rp->r_fires; fire_item != NULL; + fire_item = next(fire_item)) { + fire_creature = THINGPTR(fire_item); + if (maze_view(fire_creature->t_pos.y, + fire_creature->t_pos.x)) return(TRUE); + } + + /* Couldn't find any in line-of-sight */ + return(FALSE); + + /* We should probably do something special for the outside */ + otherwise: + return TRUE; + } + } + return(FALSE); +} + +/* + * movement: + * Given a pointer to a player/monster structure, calculate the + * movement rate for that character. + */ + +short +movement(tp) +register struct thing *tp; +{ + register int result; + register int carry; /* Percentage carried */ + + result = 0; + + /* Adjust for armor (player only) */ + if (tp == &player && cur_armor) { + int diff; /* Now armor class differs from normal one of same type */ + + /* Blessed armor adds less */ + diff = cur_armor->o_ac - armors[cur_armor->o_which].a_class; + switch (cur_armor->o_which) { + case LEATHER: + case RING_MAIL: + case CHAIN_MAIL: + case SCALE_MAIL: + case PADDED_ARMOR: + diff += 1; + when STUDDED_LEATHER: + case SPLINT_MAIL: + case BANDED_MAIL: + case PLATE_MAIL: + diff += 2; + when PLATE_ARMOR: + diff += 3; + otherwise: + debug("forgot an armor in movement()"); + } + if (diff < 0) diff = 0; + result += diff; + + } + + /* Adjust for the pack */ + carry = 100 * tp->t_stats.s_pack / tp->t_stats.s_carry; + if (carry > 75) result++; + + /* Get a bonus for dexterity */ + result -= dext_plus(tp == &player ? dex_compute() : tp->t_stats.s_dext); + + /* only allow adjust for the minus's */ + if (result < 0) result = 0; + result += tp->t_movement; /* now add in movement rate */ + + /* Is the character slowed? */ + if (on(*tp, ISSLOW) || on(*tp, ISDANCE)) result *= 2; + + /* Is the character hasted? */ + if (on(*tp, ISHASTE)) result /= 2; + + /* We have a minimum of 1 */ + if (result < 1) result = 1; + + return(result); +} + +/* + * rndmove: + * move in a random direction if the monster/person is confused + */ + +coord +rndmove(who) +struct thing *who; +{ + register int x, y; + register int ex, ey, nopen = 0; + coord ret; /* what we will be returning */ + coord dest; + + ret = who->t_pos; + /* + * Now go through the spaces surrounding the player and + * set that place in the array to true if the space can be + * moved into + */ + ey = ret.y + 1; + ex = ret.x + 1; + for (y = who->t_pos.y - 1; y <= ey; y++) + if (y > 0 && y < lines - 2) + for (x = who->t_pos.x - 1; x <= ex; x++) + { + if (x < 0 || x >= cols) + continue; + if (step_ok(y, x, NOMONST, who) == TRUE) + { + dest.y = y; + dest.x = x; + if (!diag_ok(&who->t_pos, &dest, who)) + continue; + if (rnd(++nopen) == 0) + ret = dest; + } + } + return ret; +} + +#define TRAPTYPES 9 /* 9 total trap types that can be set */ +#define WIZARDTRAPS 3 /* Only wizards can set the last 3 */ + /* CTRL(C) to level 400 for POST level */ +static const char *trap_types[TRAPTYPES] = { + "Trap Door", + "Bear Trap", + "Sleep Trap", + "Arrow Trap", + "Teleport Trap", + "Dart Trap", + "Magic pool", + "Maze Trap", + "Worm Hole" +}; + +/* + * set_trap: + * set a trap at (y, x) on screen. + */ + +set_trap(tp, y, x) +register struct thing *tp; +register int y, x; +{ + register bool is_player = (tp == &player); + register int selection = rnd(TRAPTYPES-WIZARDTRAPS) + '1'; + register int i, num_traps; + register unsigned char ch = 0, och; + int thief_bonus = 0; + int s_dext; + + /* let wizard in on this too */ + if (wizard) goto can_traps; + if (is_player && player.t_ctype != C_THIEF && player.t_ctype !=C_ASSASSIN) { + msg("Only thieves and assassins can set traps. "); + return; + } + can_traps: + switch (och = mvinch(y, x)) { + case WALL: + case FLOOR: + case PASSAGE: + break; + default: + if (is_player) msg("The trap failed!"); + return; + } + + if (is_player) { + int state = 0, /* 0 -> current screen, 1 -> prompt screen, 2 -> done */ + units; /* Number of movement units for the given trap */ + + if (player.t_action == C_SETTRAP) { + selection = player.t_selection; + player.t_selection = 0; + player.t_action = A_NIL; + } + else { + msg("Which kind of trap do you wish to set? (* for a list): "); + num_traps = TRAPTYPES - (wizard ? 0 : WIZARDTRAPS); + do { + selection = wgetch(cw); + switch (selection) { + case '*': + if (state != 1) { + wclear(hw); + touchwin(hw); + for (i=0; i<num_traps; i++) { + wmove(hw, i+2, 0); + wprintw(hw, "[%d] %s", i+1, trap_types[i]); + } + mvwaddstr(hw, 0, 0, + "Which kind of trap do you wish to set? "); + + if (menu_overlay) + /* + * Put out the selection. The longest line is + * the prompt line (39 characters long). + */ + over_win(cw, hw, num_traps + 3, 41, 0, 39, NULL); + else + draw(hw); + state = 1; /* Now in prompt window */ + } + break; + + case ESC: + if (state == 1) { + clearok(cw, FALSE); + touchwin(cw); + } + msg(""); + + trap_tries--; /* Don't count this one */ + after = FALSE; + return; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (selection < '7' || wizard) { + if (state == 1) { /* In prompt window */ + clearok(cw, FALSE); /* Set up for redraw */ + touchwin(cw); + } + + msg(""); + + /* + * Make sure there is a floor below us for trap + * doors. + */ + if (selection == '1' && level >= nfloors) { + if (state == 1) draw(cw); + msg("There is no level below this one."); + return; + } + state = 2; /* Finished */ + break; + } + + /* Fall through for non-wizard, unusual trap case */ + default: + if (state == 1) { /* In the prompt window */ + wmove(hw, 0, 0); + wprintw(hw, + "Please enter a selection between 1 and %d: ", + num_traps); + if (menu_overlay) + /* + * Put out the selection. The longest line is + * the prompt line (43 characters long). + */ + over_win(cw, hw, num_traps+3, 45, 0, 43, NULL); + else + draw(hw); + } + else { /* Normal window */ + mpos = 0; + msg("Please enter a selection between 1 and %d: ", + num_traps); + } + } + } while (state != 2); + + player.t_selection = selection; + + switch (selection) { + case '1': units = 10; /* Trap door */ + when '2': units = 5; /* Bear trap */ + when '3': units = 7; /* Sleeping gas trap */ + when '4': units = 5; /* Arrow trap */ + when '5': units = 10; /* Teleport trap */ + when '6': units = 7; /* Dart trap */ + otherwise: units = 5; /* Unknown trap */ + } + player.t_no_move = units * movement(&player); + player.t_action = C_SETTRAP; + return; + } + } + + if (is_player && player.t_ctype == C_THIEF) thief_bonus = 20; + if (is_player && player.t_ctype == C_ASSASSIN) thief_bonus = 15; + if (is_player && player.t_ctype == C_FIGHTER) thief_bonus = 10; + + s_dext = (tp == &player) ? dex_compute() : tp->t_stats.s_dext; + + if (ntraps >= MAXTRAPS || ++trap_tries >= MAXTRPTRY || + levtype == POSTLEV || levtype == OUTSIDE || + rnd(80) >= (s_dext + tp->t_stats.s_lvl/2 + thief_bonus)) { + if (is_player) msg("The trap failed!"); + return; + } + + switch (selection) { + case '1': ch = TRAPDOOR; + when '2': ch = BEARTRAP; + when '3': ch = SLEEPTRAP; + when '4': ch = ARROWTRAP; + when '5': ch = TELTRAP; + when '6': ch = DARTTRAP; + when '7': ch = POOL; + when '8': ch = MAZETRAP; + when '9': ch = WORMHOLE; + } + + mvaddch(y, x, ch); + traps[ntraps].tr_show = och; + traps[ntraps].tr_type = ch; + traps[ntraps].tr_pos.y = y; + traps[ntraps].tr_pos.x = x; + if (is_player) + traps[ntraps].tr_flags = ISTHIEFSET; + if (ch == POOL || ch == POST) { + traps[ntraps].tr_flags |= ISFOUND; + } + + ntraps++; +} + +/* + * show: + * returns what a certain thing will display as to the un-initiated + */ + +show(y, x) +register int y, x; +{ + register unsigned char ch = winat(y, x); + register struct linked_list *it; + register struct thing *tp; + + if (isatrap(ch)) { + register struct trap *trp = trap_at(y, x); + + return (trp->tr_flags & ISFOUND) ? ch : trp->tr_show; + } + else if (isalpha(ch)) { + if ((it = find_mons(y, x)) == NULL) { + msg("Show: Can't find monster in show (%d, %d)", y, x); + return(mvwinch(stdscr, y, x)); + } + tp = THINGPTR(it); + + if (on(*tp, ISDISGUISE)) ch = tp->t_disguise; /* As a mimic */ + + /* Hide invisible creatures */ + else if (invisible(tp)) { + /* We can't see surprise-type creatures through "see invisible" */ + if (off(player,CANSEE) || on(*tp,CANSURPRISE)) + ch = mvwinch(stdscr, y, x); /* Invisible */ + } + else if (on(*tp, CANINWALL)) { + if (isrock(mvwinch(stdscr, y, x))) ch = winch(stdscr); /* As Xorn */ + } + } + return ch; +} + + +/* + * trap_at: + * find the trap at (y,x) on screen. + */ + +struct trap * +trap_at(y, x) +register int y, x; +{ + register struct trap *tp, *ep; + + ep = &traps[ntraps]; + for (tp = traps; tp < ep; tp++) + if (tp->tr_pos.y == y && tp->tr_pos.x == x) + break; + if (tp == ep) + debug((sprintf(prbuf, "Trap at %d,%d not in array", y, x), prbuf)); + return tp; +} + +/* + * weap_move: + * Calculate how many segments it will take to swing the given + * weapon (note that the weapon may actually be a stick or + * even something else). + */ + +weap_move(wielder, weap) +register struct thing *wielder; /* Who's wielding the weapon */ +register struct object *weap; /* The weapon */ +{ + register int weap_rate; + int dexterity; + int strength; + + if (weap == NULL) return(1); /* hand, claw, bite attacks are quick */ + + switch (weap->o_type) { + case STICK: + if (EQUAL(ws_type[weap->o_which], "staff")) + weap_rate = 2; + else weap_rate = 1; /* A wand */ + + when WEAPON: + weap_rate = weaps[weap->o_which].w_rate; + + /* Adjust for blessed or cursed weapon */ + if (weap->o_hplus < 0) /* Cursed */ + weap_rate -= (weap->o_hplus - 2) / 3; + else if (weap_rate > 0) /* Blessed */ + weap_rate -= (2*weap->o_hplus + weap_rate - 1) / weap_rate; + + when RELIC: + switch (weap->o_which) { + case MUSTY_DAGGER: + case HRUGGEK_MSTAR: + case AXE_AKLAD: + case YEENOGHU_FLAIL: + case MING_STAFF: + case ORCUS_WAND: + case ASMO_ROD: + /* These operate in the blink of an eye */ + weap_rate = 1; + otherwise: + /* What is it? */ + weap_rate = 10; + debug("unknown weapon in weap_move()"); + } + otherwise: + /* What is it? */ + weap_rate = 10; + debug("unknown weapon in weap_move()"); + } + + /* Put in a dexterity bonus */ + if (wielder == &player) dexterity = dex_compute(); + else dexterity = wielder->t_stats.s_dext; + weap_rate -= dext_plus(dexterity) / 2; + + /* Put in a strength bonus */ + if (wielder == &player) strength = str_compute(); + else strength = wielder->t_stats.s_str; + weap_rate -= str_plus(strength) / 2; + + /* It can't speed you up and it must take SOME time */ + if (weap_rate <= 0) weap_rate = 1; + + /* Do we need to adjust for fast/slow movement? */ + if (on(*wielder, ISSLOW) || on(*wielder, ISDANCE)) weap_rate *= 2; + if (on(*wielder, ISHASTE)) weap_rate /= 2; + + /* Return the result */ + return(weap_rate); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/n_level.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,672 @@ +/* + n_level.c - Dig and draw a new level + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include "rogue.h" +#define TERRASAVE 3 + +/* + * new_level: + * Dig and draw a new level + */ + +new_level(ltype) +LEVTYPE ltype; /* designates type of level to create */ +{ + register int rm = 0, i, cnt; + register unsigned char ch; + register struct linked_list *item; + register struct thing *tp; + register struct object *obj; + int waslit = 0; /* Was the previous outside level lit? */ + int starty = 0, startx = 0, deltay = 0, deltax = 0; + bool fresh=TRUE, vert = 0, top; + struct room *rp; + struct linked_list *nitem, *savmonst=NULL, *savitems=NULL; + coord stairs = {0,0}; + + if (wizard) { + msg("Turns: %ld", turns); /* Number of turns for last level */ + mpos = 0; + } + + /* Start player off right */ + turn_off(player, ISHELD); + turn_off(player, ISFLEE); + extinguish(suffocate); + hold_count = 0; + trap_tries = 0; + + /* Are we just entering a dungeon? If so, how big is it? */ + if (ltype != OUTSIDE && nfloors < 0) nfloors = HARDER+20 + rnd(51); + + if (level > max_level) + max_level = level; + + /* Are we starting a new outside level? */ + if (ltype == OUTSIDE) { + register int i, j; + + /* Save some information prior to clearing the screen */ + if (level == -1 || mvinch(hero.y, hero.x) == HORZWALL) vert = TRUE; + else vert = FALSE; + + if (level < 1) { + fresh = TRUE; + starty = 2; + startx = 1; + deltay = deltax = 1; + level = max_level; /* Restore level to deepest attempt */ + prev_max = level; /* reset for boundary crossings below */ + } + else if (level >= 1 && prev_max == 1000) { + fresh = TRUE; + starty = 2; + startx = 1; + deltay = deltax = 1; + prev_max = level; /* reset for boundary crossings below */ + } + else { /* Copy several lines of the terrain to the other end */ + + unsigned char cch; /* Copy character */ + + if (wizard) msg("Crossing sector boundary "); + + /* Was the area dark (not magically lit)? */ + if (!(rooms[0].r_flags & ISDARK)) waslit = 1; + + fresh = FALSE; + if ((vert && hero.y == 1) || (!vert && hero.x == 0)) top = TRUE; + else top = FALSE; + for (i=0; i<TERRASAVE; i++) { + if (vert) + for (j=1; j<cols-1; j++) { + if (top) { + cch = mvinch(i+2, j); + mvaddch(lines-6+i, j, cch); + } + else { + cch = mvinch(lines-4-i, j); + mvaddch(4-i, j, cch); + } + } + else + for (j=2; j<lines-3; j++) { + if (top) { + cch = mvinch(j, i+1); + mvaddch(j, cols-4+i, cch); + } + else { + cch = mvinch(j, cols-2-i); + mvaddch(j, 3-i, cch); + } + } + } + + if (vert) { + startx = deltax = 1; + if (top) { + starty = lines-4-TERRASAVE; + deltay = -1; + } + else { + starty = TERRASAVE + 2; + deltay = 1; + } + } + else { + starty = 2; + deltay = 1; + if (top) { + startx = cols-2-TERRASAVE; + deltax = -1; + } + else { + deltax = 1; + startx = TERRASAVE + 1; + } + } + + /* Check if any monsters should be saved */ + for (item = mlist; item != NULL; item = nitem) { + nitem = next(item); + tp = THINGPTR(item); + if (vert) { + if (top) { + if (tp->t_pos.y < TERRASAVE + 2) + tp->t_pos.y += lines - 5 - TERRASAVE; + else continue; + } + else { + if (tp->t_pos.y > lines - 4 - TERRASAVE) + tp->t_pos.y += 5 + TERRASAVE - lines; + else continue; + } + } + else { + if (top) { + if (tp->t_pos.x < TERRASAVE + 1) + tp->t_pos.x += cols - 2 - TERRASAVE; + else continue; + } + else { + if (tp->t_pos.x > cols - 2 - TERRASAVE) + tp->t_pos.x += 2 + TERRASAVE - cols; + else continue; + } + } + + /* + * If the monster is busy chasing another monster, don't save + * it + */ + if (tp->t_dest && tp->t_dest != &hero) continue; + + /* Outside has plenty of monsters, don't need these. + * detach(mlist, item); + * attach(savmonst, item); + */ + } + + /* Check if any treasure should be saved */ + for (item = lvl_obj; item != NULL; item = nitem) { + nitem = next(item); + obj = OBJPTR(item); + if (vert) { + if (top) { + if (obj->o_pos.y < TERRASAVE + 2) + obj->o_pos.y += lines - 5 - TERRASAVE; + else continue; + } + else { + if (obj->o_pos.y > lines - 4 - TERRASAVE) + obj->o_pos.y += 5 + TERRASAVE - lines; + else continue; + } + } + else { + if (top) { + if (obj->o_pos.x < TERRASAVE + 1) + obj->o_pos.x += cols - 2 - TERRASAVE; + else continue; + } + else { + if (obj->o_pos.x > cols - 2 - TERRASAVE) + obj->o_pos.x += 2 + TERRASAVE - cols; + else continue; + } + } + detach(lvl_obj, item); + attach(savitems, item); + } + } + } + + wclear(cw); + wclear(mw); + if (fresh || levtype != OUTSIDE) clear(); + /* + * check to see if he missed a UNIQUE, If he did then put it back + * in the monster table for next time + */ + for (item = mlist; item != NULL; item = next(item)) { + tp = THINGPTR(item); + if (on(*tp, ISUNIQUE)) + monsters[tp->t_index].m_normal = TRUE; + } + /* + * Free up the monsters on the last level + */ + t_free_list(mlist); + o_free_list(lvl_obj); /* Free up previous objects (if any) */ + for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) + r_free_list(rp->r_exit); /* Free up the exit lists */ + + levtype = ltype; + foods_this_level = 0; /* food for hero this level */ + + /* What kind of level are we on? */ + if (ltype == POSTLEV || ltype == STARTLEV) { + if (ltype == POSTLEV) + do_post(FALSE); /* Trading post */ + else + do_post(TRUE); /* Equipage */ + + levtype = ltype = POSTLEV; + } + else if (ltype == MAZELEV) { + do_maze(); + no_food++; + put_things(ltype); /* Place objects (if any) */ + } + else if (ltype == OUTSIDE) { + /* Move the cursor back onto the hero */ + wmove(cw, hero.y, hero.x); + init_terrain(); + do_terrain(starty, startx, deltay, deltax, (bool) (fresh || !vert)); + no_food++; + put_things(ltype); + + /* Should we magically light this area? */ + if (waslit) rooms[0].r_flags &= ~ISDARK; + } + else { + do_rooms(); /* Draw rooms */ + do_passages(); /* Draw passages */ + no_food++; + put_things(ltype); /* Place objects (if any) */ + } + /* + * Place the staircase down. Only a small chance for an outside stairway. + */ + if (ltype != OUTSIDE || roll(1, 5) == 5) { + cnt = 0; + do { + rm = rnd_room(); + rnd_pos(&rooms[rm], &stairs); + } until (mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 2500); + addch(STAIRS); + } + /* + * maybe add a trading post + */ + if (level > 5 && rnd(10) == 7 && ltype == NORMLEV) { + cnt = 0; + do { + rm = rnd_room(); + if (rooms[rm].r_flags & ISTREAS) + continue; + rnd_pos(&rooms[rm], &stairs); + } until (winat(stairs.y, stairs.x) == FLOOR || cnt++ > 2500); + addch(POST); + } + if (ltype != POSTLEV) { /* Add monsters that fell through */ + nitem = tlist; + while (nitem != NULL) { + item = nitem; + nitem = next(item); /* because detach and attach mess up ptrs */ + tp = THINGPTR(item); + cnt = 0; + do { + rm = rnd_room(); + rnd_pos(&rooms[rm], &tp->t_pos); + } until (cnt++ > 2500 || winat(tp->t_pos.y, tp->t_pos.x) == FLOOR); + mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type); + tp->t_oldch = mvwinch(cw, tp->t_pos.y, tp->t_pos.x); + + /* + * If it has a fire, mark it + */ + if (on(*tp, HASFIRE)) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rooms[rm].r_fires, fire_item); + rooms[rm].r_flags |= HASFIRE; + } + + detach(tlist, item); + turn_off(*tp,ISELSEWHERE); + attach(mlist, item); + } + } + + /* Restore any saved monsters */ + for (item = savmonst; item != NULL; item = nitem) { + nitem = next(item); + tp = THINGPTR(item); + mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type); + tp->t_oldch = mvwinch(cw, tp->t_pos.y, tp->t_pos.x); + + /* + * If it has a fire, mark it + */ + if (on(*tp, HASFIRE)) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rooms[rm].r_fires, fire_item); + rooms[rm].r_flags |= HASFIRE; + } + + detach(savmonst, item); + attach(mlist, item); + } + + /* Restore any saved objects */ + for(item = savitems; item != NULL; item = nitem) { + nitem = next(item); + obj = OBJPTR(item); + mvaddch(obj->o_pos.y, obj->o_pos.x, obj->o_type); + detach(savitems, item); + attach(lvl_obj, item); + } + + /* + * Place the traps (except for trading post) + */ + ntraps = 0; /* No traps yet */ + if (levtype == NORMLEV) { + if (rnd(10) < vlevel) { + ntraps = rnd(vlevel/4)+2; + if (ntraps > MAXTRAPS) + ntraps = MAXTRAPS; + i = ntraps; + while (i--) + { + cnt = 0; + do { + rm = rnd_room(); + if (rooms[rm].r_flags & ISTREAS) + continue; + rnd_pos(&rooms[rm], &stairs); + } until (winat(stairs.y, stairs.x) == FLOOR || cnt++ > 2500); + + traps[i].tr_flags = 0; + + /* If we are at the bottom, we can't set a trap door */ + if (level >= nfloors) ch = (unsigned char) rnd(8) + 1; + else ch = (unsigned char) rnd(9); + + switch((int) ch) { + case 0: ch = TRAPDOOR; + when 1: ch = BEARTRAP; + when 2: ch = SLEEPTRAP; + when 3: ch = ARROWTRAP; + when 4: ch = TELTRAP; + when 5: ch = DARTTRAP; + when 6: ch = POOL; + traps[i].tr_flags = ISFOUND; + when 7: ch = MAZETRAP; + when 8: ch = WORMHOLE; + } + addch(ch); + traps[i].tr_type = ch; + traps[i].tr_show = FLOOR; + traps[i].tr_pos = stairs; + } + } + } + if (fresh) { /* A whole new picture */ + /* + * try to find a room for the hero. The objective here is to: + * --> don't put him in a treasure room + * --> don't put him on an object + * --> try not to put him next to the stairs + */ + cnt = 2500; + do { + if (ltype != OUTSIDE) rm = rnd_room(); + else continue; + + if (rooms[rm].r_flags & ISTREAS) + continue; + + rnd_pos(&rooms[rm], &hero); + } until( cnt-- == 0 || + (winat(hero.y, hero.x) == FLOOR && + DISTANCE(hero.y, hero.x, stairs.y, stairs.x) > cnt/10)); + } + else { /* We're extending into an adjacent outside plane */ + rm = 0; + if (vert) { + if (hero.y == 1) hero.y = lines - 3 - TERRASAVE; /* Top to bottom */ + else hero.y = TERRASAVE + 1; /* Bottom to top */ + } + else { + if (hero.x == 0) hero.x = cols - 1 - TERRASAVE; /* Right to left */ + else hero.x = TERRASAVE; /* Left to right */ + } + } + oldrp = &rooms[rm]; /* Set the current room */ + player.t_oldpos = player.t_pos; /* Set the current position */ + + if (ISWEARING(R_AGGR) || + (cur_misc[WEAR_JEWEL] != NULL && + cur_misc[WEAR_JEWEL]->o_which == MM_JEWEL)) + aggravate(TRUE, TRUE); /* affect all charactors */ + + /* + * If player is moving up or above his deepest point, wake up any + * non-uniques + */ + else if (level < cur_max) { + aggravate(FALSE, FALSE); + } + + light(&hero); + wmove(cw, hero.y, hero.x); + waddch(cw, PLAYER); + + if (level > cur_max) + cur_max = level; + + draw(cw); + + status(TRUE); + + /* Do we sense any food on this level? */ + if (cur_relic[SURTUR_RING]) + quaff(P_FFIND, NULL, NULL, FALSE); +} + +/* + * Pick a room that is really there + */ + +rnd_room() +{ + register int rm; + + if (levtype != NORMLEV) + rm = 0; + else do + { + rm = rnd(MAXROOMS); + } while (rooms[rm].r_flags & ISGONE); + return rm; +} + +/* + * put_things: + * put potions and scrolls on this level + */ + +put_things(ltype) +LEVTYPE ltype; /* designates type of level to create */ +{ + register int i, rm, cnt; + register struct object *cur; + register struct linked_list *item, *nextitem, *exitptr; + int length, width; + int ITEMS = 0; /* number of items to place */ + coord tp, *exit; + + /* + * The only way to get new stuff is to go down into the dungeon. + */ + if (level < cur_max) { + if (ltype == NORMLEV) + return; + } + + if (ltype == OUTSIDE) goto jmp_here; /* a jump for outside */ + + /* + * There is a chance that there is a Treasure Room on this level + */ + if (ltype == NORMLEV && rnd(150) < level) { + register int j; + register struct room *rp; + + /* Count the number of free spaces */ + i = 0; /* 0 tries */ + do { + rp = &rooms[rnd_room()]; + width = rp->r_max.y - 2; + length = rp->r_max.x - 2; + } until ((width*length >= MAXTREAS) || (i++ > MAXROOMS*4)); + + /* Mark the room as a treasure room */ + rp->r_flags |= ISTREAS; + + /* Make all the doors secret doors */ + for (exitptr = rp->r_exit; exitptr; exitptr = next(exitptr)) { + exit = DOORPTR(exitptr); + move(exit->y, exit->x); + addch(SECRETDOOR); + } + + /* + * check to see if there are any monsters in room already + */ + for (item = mlist; item != NULL; item = nextitem) { + register struct thing *tp; + + tp = THINGPTR(item); + nextitem = next(item); + if (rp == roomin(&tp->t_pos)) { + /* + * Don't let nice creatures be generated in a treasure + * room. + */ + if ((player.t_ctype==C_PALADIN || player.t_ctype==C_RANGER || + player.t_ctype==C_MONK) && off(*tp, ISMEAN)) { + int index; + + if (on(*tp, ISUNIQUE)) index = tp->t_index; + else index = -1; + + /* Get rid of the monster */ + killed(item, FALSE, FALSE, FALSE); + + /* Restore uniques back in the table */ + if (index != -1) monsters[index].m_normal = TRUE; + + continue; + } + turn_on(*tp, ISMEAN); + turn_on(*tp, ISGUARDIAN); + } + } + + /* Put in the monsters and treasures */ + for (j=1; j<rp->r_max.y-1; j++) + for (i=1; i<rp->r_max.x-1; i++) { + coord trp; + + trp.y = rp->r_pos.y+j; + trp.x = rp->r_pos.x+i; + + /* Monsters */ + if ((rnd(100) < (MAXTREAS*100)/(width*length)) && + (mvwinch(mw, rp->r_pos.y+j, rp->r_pos.x+i) == ' ')) { + register struct thing *tp; + + /* + * Put it there and leave it asleep. Wake the monsters + * when the player enters the room. Hopefully, all bases + * are covered as far as the ways to get in. This way + * cpu time is not wasted on the awake monsters that + * can't get to the player anyway. + * try not to put any UNIQUEs in a treasure room. + * note that they may have put put in already by the + * non-treasure room code. + * also, try not to put ISMEAN monsters in a treasure + * room as these are supposed to be non-hostile until + * attacked. It also makes life simpler for the ranger, + * paladin, and monk. + */ + for(;;) { + item = new_item(sizeof *tp); /* Make a monster */ + tp = THINGPTR(item); + new_monster(item,randmonster(FALSE, TRUE),&trp,TRUE); + if (on(*tp, HASFIRE)) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rp->r_fires, fire_item); + rp->r_flags |= HASFIRE; + } + /* + * only picky for these classes + */ + if (player.t_ctype != C_RANGER && + player.t_ctype != C_PALADIN && + player.t_ctype != C_MONK) + break; + if (on(*tp, ISMEAN)) + break; + killed (item, FALSE, FALSE, FALSE); + } + if (on(*tp, ISUNIQUE)) { /* just in case */ + carry_obj(tp, monsters[tp->t_index].m_carry); + tp->t_no_move = movement(tp); + } + turn_on(*tp, ISGUARDIAN); + + } + + /* Treasures */ + if ((rnd(100) < (MAXTREAS*100)/(width*length)) && + (mvinch(rp->r_pos.y+j, rp->r_pos.x+i) == FLOOR)) { + item = new_thing(ALL, TRUE); + attach(lvl_obj, item); + cur = OBJPTR(item); + + mvaddch(trp.y, trp.x, cur->o_type); + cur->o_pos = trp; + } + } + } + + jmp_here: /* outside jumper for equippage */ + + /* + * Do ITEMS attempts to put things in dungeon, maze, or outside + */ + + if (ltype == OUTSIDE) ITEMS = rnd(15)+1; + else if (ltype == MAZELEV) ITEMS = rnd(20)+1; + else ITEMS = MAXOBJ + rnd(4); + + for (i = 0; i < ITEMS; i++) + if (rnd(100) < 65) { + /* + * Pick a new object and link it in the list + */ + item = new_thing(ALL, TRUE); + attach(lvl_obj, item); + cur = OBJPTR(item); + /* + * Put it somewhere + */ + cnt = 0; + do { + if (ltype == OUTSIDE) rm = 0; + else rm = rnd_room(); + rnd_pos(&rooms[rm], &tp); + } until (winat(tp.y, tp.x) == FLOOR || cnt++ > 2500); + mvaddch(tp.y, tp.x, cur->o_type); + cur->o_pos = tp; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/network.h Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,35 @@ +/* + network.h - networking setup + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +/* + * Note that networking is set up for machines that can communicate + * via some system such as uucp. The mechanism listed here uses uux + * and assumes that the target machine allows access to the game via + * the uux command. NETCOMMAND must be defined if networking is desired. + */ + +/* #undef NETCOMMAND "uux - -n '%s!%s -u' >/dev/null 2>&1" */ +/* #define NETCOMMAND "usend -s -d%s -uNoLogin -!'%s -u' - 2>/dev/null" */ +#define NETCOMMAND "" + +/* Networking information -- should not vary among networking machines */ + +struct network { + char *system; + char *rogue; +}; +extern struct network Network[]; +extern unsigned long netread(); +extern unsigned long netwrite(); +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/options.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,536 @@ +/* + options.c - This file has all the code for the option command + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + + /* + * I would rather this command were not necessary, but + * it is the only way to keep the wolves off of my back. + */ + +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" + +#define NUM_OPTS (sizeof optlist / sizeof (OPTION)) + +/* + * description of an option and what to do with it + */ +struct optstruct { + char *o_name; /* option name */ + char *o_prompt; /* prompt for interactive entry */ + int *o_opt; /* pointer to thing to set */ + int (*o_putfunc)(); /* function to print value */ + int (*o_getfunc)(); /* function to get value interactively */ +}; + +typedef struct optstruct OPTION; + +int put_bool(), + get_bool(), + put_str(), + get_str(), + put_abil(), + get_abil(), + get_quest(), + put_quest(), + get_default(); + +int get_str_prot(char *opt, WINDOW *win); +bool allowchange(OPTION *op); + +OPTION optlist[] = { + {"terse", "Terse output: ", + (int *) &terse, put_bool, get_bool }, + {"flush", "Flush typeahead during battle: ", + (int *) &fight_flush, put_bool, get_bool }, + {"jump", "Show position only at end of run: ", + (int *) &jump, put_bool, get_bool }, + {"step", "Do inventories one line at a time: ", + (int *) &slow_invent, put_bool, get_bool }, + {"askme", "Ask me about unidentified things: ", + (int *) &askme, put_bool, get_bool }, + {"pickup", "Pick things up automatically: ", + (int *) &auto_pickup, put_bool, get_bool }, + {"overlay", "Overlay menu: ", + (int *) &menu_overlay, put_bool, get_bool }, + {"name", "Name: ", + (int *) whoami, put_str, get_str_prot }, + {"file", "Save file: ", + (int *) file_name, put_str, get_str_prot }, + {"score", "Score file: ", + (int *) score_file, put_str, get_str_prot }, + {"class", "Character type: ", + (int *) &char_type, put_abil, get_abil }, + {"quest", "Quest item: ", + (int *) &quest_item, put_quest, get_quest }, + {"default", "Default Attributes: ", + (int *) &def_attr, put_bool, get_default } +}; + +/* + * The default attribute field is read-only + */ + +get_default(bp, win) +bool *bp; +WINDOW *win; +{ + register int oy, ox; + + getyx(win, oy, ox); + put_bool(bp, win); + get_ro(win, oy, ox); +} + +/* + * The ability (class) field is read-only + */ + +get_abil(abil, win) +int *abil; +WINDOW *win; +{ + register int oy, ox; + + getyx(win, oy, ox); + put_abil(abil, win); + get_ro(win, oy, ox); +} + +/* + * The quest field is read-only + */ + +get_quest(quest, win) +int *quest; +WINDOW *win; +{ + register int oy, ox; + + getyx(win, oy, ox); + waddstr(win, rel_magic[*quest].mi_name); + get_ro(win, oy, ox); +} + +/* + * get_ro: + * "Get" a read-only value. + */ + +get_ro(win, oy, ox) +WINDOW *win; +register int oy, ox; +{ + register int ny, nx; + register bool op_bad; + + op_bad = TRUE; + getyx(win, ny, nx); + while(op_bad) + { + wmove(win, oy, ox); + draw(win); + switch (wgetch(win)) + { + case '\n': + case '\r': + op_bad = FALSE; + break; + case '\033': + case '\007': + return QUIT; + case '-': + return MINUS; + default: + mvwaddstr(win, ny, nx + 5, "(no change allowed)"); + } + } + wmove(win, ny, nx + 5); + wclrtoeol(win); + wmove(win, ny, nx); + waddch(win, '\n'); + return NORM; +} + +/* + * allow changing a boolean option and print it out + */ + +get_bool(bp, win) +bool *bp; +WINDOW *win; +{ + register int oy, ox; + register bool op_bad; + + op_bad = TRUE; + getyx(win, oy, ox); + waddstr(win, *bp ? "True" : "False"); + while(op_bad) + { + wmove(win, oy, ox); + draw(win); + switch (wgetch(win)) + { + case 't': + case 'T': + *bp = TRUE; + op_bad = FALSE; + break; + case 'f': + case 'F': + *bp = FALSE; + op_bad = FALSE; + break; + case '\n': + case '\r': + op_bad = FALSE; + break; + case '\033': + case '\007': + return QUIT; + case '-': + return MINUS; + default: + mvwaddstr(win, oy, ox + 10, "(T or F)"); + } + } + wmove(win, oy, ox); + wclrtoeol(win); + waddstr(win, *bp ? "True" : "False"); + waddch(win, '\n'); + return NORM; +} + +/* + * set a string option + */ + +get_str(opt, win) +register char *opt; +WINDOW *win; +{ + register char *sp; + register int c, oy, ox; + char buf[LINELEN]; + + draw(win); + getyx(win, oy, ox); + /* + * loop reading in the string, and put it in a temporary buffer + */ + for (sp = buf; + (c = wgetch(win)) != '\n' && + c != '\r' && + c != '\033' && + c != '\007' && + sp < &buf[LINELEN-1]; + wclrtoeol(win), draw(win)) + { + if (c == -1) + continue; + else if (c == erasechar()) /* process erase character */ + { + if (sp > buf) + { + register int i; + + sp--; + for (i = strlen(unctrl(*sp)); i; i--) + waddch(win, '\b'); + } + continue; + } + else if (c == killchar()) /* process kill character */ + { + sp = buf; + wmove(win, oy, ox); + continue; + } + else if (sp == buf) + if (c == '-' && win == hw) /* To move back a line in hw */ + break; + else if (c == '~') + { + strcpy(buf, home); + waddstr(win, home); + sp += strlen(home); + continue; + } + *sp++ = c; + waddstr(win, unctrl(c)); + } + *sp = '\0'; + if (sp > buf) /* only change option if something has been typed */ + strucpy(opt, buf, strlen(buf)); + wmove(win, oy, ox); + waddstr(win, opt); + waddch(win, '\n'); + draw(win); + if (win == msgw) + mpos += sp - buf; + if (c == '-') + return MINUS; + else if (c == '\033' || c == '\007') + return QUIT; + else + return NORM; +} + +/* + * print and then set options from the terminal + */ + +option() +{ + register OPTION *op; + register int retval; + + wclear(hw); + touchwin(hw); + /* + * Display current values of options + */ + for (op = optlist; op < &optlist[NUM_OPTS]; op++) + { + waddstr(hw, op->o_prompt); + (*op->o_putfunc)(op->o_opt, hw); + waddch(hw, '\n'); + } + /* + * Set values + */ + wmove(hw, 0, 0); + for (op = optlist; op < &optlist[NUM_OPTS]; op++) + { + waddstr(hw, op->o_prompt); + + retval = (*op->o_getfunc)(op->o_opt, hw); + + if (retval) + if (retval == QUIT) + break; + else if (op > optlist) { /* MINUS */ + wmove(hw, (op - optlist) - 1, 0); + op -= 2; + } + else /* trying to back up beyond the top */ + { + putchar('\007'); + wmove(hw, 0, 0); + op--; + } + } + /* + * Switch back to original screen + */ + mvwaddstr(hw, lines-1, 0, spacemsg); + draw(hw); + wait_for(' '); + restscr(cw); + after = FALSE; +} + +/* + * parse options from string, usually taken from the environment. + * the string is a series of comma seperated values, with booleans + * being stated as "name" (true) or "noname" (false), and strings + * being "name=....", with the string being defined up to a comma + * or the end of the entire option string. + */ + +parse_opts(str) +register char *str; +{ + register char *sp; + register OPTION *op; + register int len; + + if (*str == '\"') + str++; + + while (*str) + { + /* + * Get option name + */ + + for (sp = str; isalpha(*sp); sp++) + continue; + len = (char *)sp - str; + /* + * Look it up and deal with it + */ + for (op = optlist; op < &optlist[NUM_OPTS]; op++) + if (EQSTR(str, op->o_name, len)) + { + if (op->o_putfunc == put_bool) /* if option is a boolean */ + *(bool *)op->o_opt = TRUE; + else /* string option */ + { + register char *start; + char value[LINELEN]; + + /* + * Skip to start of string value + */ + for (str = sp + 1; *str == '=' || *str == ':'; str++) + continue; + + if (*str == '~') + { + strcpy((char *) value, home); + start = (char *) value + strlen(home); + while (*++str == '/') + continue; + } + else + start = (char *) value; + /* + * Skip to end of string value + */ + for (sp = str + 1; *sp && *sp != ',' && *sp != '\"'; sp++) + continue; + strucpy(start, str, (char *) sp - str); + + /* Put the value into the option field */ + if (op->o_putfunc != put_abil) { + if (allowchange(op)) + strcpy((char *)op->o_opt, value); + } + + else if (*op->o_opt == -1) { /* Only init ability once */ + register int len = strlen(value); + register int i; + + for (i=0; i<NUM_CHARTYPES-1; i++) { + if (EQSTR(value, char_class[i].name, len)) { + *op->o_opt = i; + break; + } + } + } + } + break; + } + /* + * check for "noname" for booleans + */ + else if (op->o_putfunc == put_bool + && EQSTR(str, "no", 2) && EQSTR(str + 2, op->o_name, len - 2)) + { + *(bool *)op->o_opt = FALSE; + break; + } + + /* + * skip to start of next option name + */ + while (*sp && !isalpha(*sp)) + sp++; + str = sp; + } +} + + +/* + * print the default attributes + */ + +/* put_default(b, win) + * bool *b; + * WINDOW *win; + * { + * waddstr(win, *b ? "True" : "False"); + * } + */ + +/* + * print the character type + */ + +put_abil(ability, win) +int *ability; +WINDOW *win; +{ + waddstr(win, char_class[*ability].name); +} + +/* + * print out the quest + */ + +put_quest(quest, win) +int *quest; +WINDOW *win; +{ + waddstr(win, rel_magic[*quest].mi_name); +} + +/* + * put out a boolean + */ + +put_bool(b, win) +bool *b; +WINDOW *win; +{ + waddstr(win, *b ? "True" : "False"); +} + +/* + * put out a string + */ + +put_str(str, win) +char *str; +WINDOW *win; +{ + waddstr(win, str); +} + +/* Like get_str, but disallows changes when use_savedir is set. */ +int +get_str_prot(char *opt, WINDOW *win) +{ + int oy, ox; + + if (use_savedir) { + getyx(win, oy, ox); + waddstr(win, opt); + return get_ro(win, oy, ox); + } + else { + return get_str(opt, win); + } +} + +bool +allowchange(OPTION *op) +{ + if (!use_savedir) + return TRUE; + if (!strcmp(op->o_name, "name")) + return FALSE; + if (!strcmp(op->o_name, "file")) + return FALSE; + if (!strcmp(op->o_name, "score")) + return FALSE; + return TRUE; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/outside.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,226 @@ +/* + outside.c - functions for dealing with the "outside" level + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include "rogue.h" + +extern char rnd_terrain(), get_terrain(); + +/* + * init_terrain: + * Get the single "outside room" set up correctly + */ + +void +init_terrain() +{ + register struct room *rp; + + for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) { + rp->r_flags = ISGONE; /* kill all rooms */ + rp->r_fires = NULL; /* no fires */ + } + rp = &rooms[0]; /* point to only room */ + rp->r_flags = ISDARK; /* outside is always dark */ + rp->r_pos.x = 0; /* room fills whole screen */ + rp->r_pos.y = 1; + rp->r_max.x = cols; + rp->r_max.y = lines - 3; +} + +void +do_terrain(basey, basex, deltay, deltax, fresh) +int basey, basex, deltay, deltax; +bool fresh; +{ + register int cury, curx; /* Current y and x positions */ + + /* Lay out the boundary */ + for (cury=1; cury<lines-2; cury++) { /* Vertical "walls" */ + mvaddch(cury, 0, VERTWALL); + mvaddch(cury, cols-1, VERTWALL); + } + for (curx=0; curx<cols; curx++) { /* Horizontal "walls" */ + mvaddch(1, curx, HORZWALL); + mvaddch(lines-3, curx, HORZWALL); + } + + /* If we are not continuing, let's start out with a line of terrain */ + if (fresh) { + char ch; /* Next char to add */ + + /* Move to the starting point (should be (1, 0)) */ + move(basey, basex); + curx = basex; + + /* Start with some random terrain */ + if (basex == 0) { + ch = rnd_terrain(); + addch(ch); + } + else ch = mvinch(basey, basex); + + curx += deltax; + + /* Fill in the rest of the line */ + while (curx > 0 && curx < cols-1) { + /* Put in the next piece */ + ch = get_terrain(ch, '\0', '\0', '\0'); + mvaddch(basey, curx, ch); + curx += deltax; + } + + basey++; /* Advance to next line */ + } + + /* Fill in the rest of the lines */ + cury = basey; + while (cury > 1 && cury < lines - 3) { + curx = basex; + while (curx > 0 && curx < cols-1) { + register char left, top_left, top, top_right; + register int left_pos, top_pos; + + /* Get the surrounding terrain */ + left_pos = curx - deltax; + top_pos = cury - deltay; + + left = mvinch(cury, left_pos); + top_left = mvinch(top_pos, left_pos); + top = mvinch(top_pos, curx); + top_right = mvinch(top_pos, curx + deltax); + + /* Put the piece of terrain on the map */ + mvaddch(cury, curx, get_terrain(left, top_left, top, top_right)); + + /* Get the next x coordinate */ + curx += deltax; + } + + /* Get the next y coordinate */ + cury += deltay; + } + /* The deeper we go.. */ + if (level > 40) genmonsters(20, (bool) 0); + else if (level > 10) genmonsters(15, (bool) 0); + else genmonsters(10, (bool) 0); + + /* sometimes they're real angry */ + if (rnd(100) < 65) { + /* protect good guys */ + if (player.t_ctype == C_PALADIN || + player.t_ctype == C_RANGER || player.t_ctype == C_MONK) { + aggravate(TRUE, FALSE); + } + else { + aggravate(TRUE, TRUE); + } + } +} + +/* + * do_paths: + * draw at least a single path-way through the terrain + */ + +/* + * rnd_terrain: + * return a weighted, random type of outside terrain + */ + +char +rnd_terrain() +{ + int chance = rnd(100); + + /* Meadow is most likely */ + if (chance < 40) return(FLOOR); + + /* Next comes forest */ + if (chance < 65) return(FOREST); + + /* Then comes lakes */ + if (chance < 85) return(POOL); + + /* Finally, mountains */ + return(WALL); +} + + +/* + * get_terrain: + * return a terrain weighted by what is surrounding + */ + +char +get_terrain(one, two, three, four) +char one, two, three, four; +{ + register int i; + int forest = 0, mountain = 0, lake = 0, meadow = 0, total = 0; + char surrounding[4]; + + surrounding[0] = one; + surrounding[1] = two; + surrounding[2] = three; + surrounding[3] = four; + + for (i=0; i<4; i++) + switch (surrounding[i]) { + case FOREST: + forest++; + total++; + + when WALL: + mountain++; + total++; + + when POOL: + lake++; + total++; + + when FLOOR: + meadow++; + total++; + } + + /* Should we continue mountain? */ + if (rnd(total+1) < mountain) return(WALL); + + /* Should we continue lakes? */ + if (rnd(total+1) < lake) return(POOL); + + /* Should we continue meadow? */ + if (rnd(total+1) < meadow) return(FLOOR); + + /* Should we continue forest? */ + if (rnd(total+2) < forest) return(FOREST); + + /* Return something random */ + return(rnd_terrain()); +} + +/* + * lake_check: + * Determine if the player would drown + */ + +/*UNUSED*/ +/* void + * lake_check(place) + * register coord *place; + * { + * } + */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/pack.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1583 @@ +/* + pack.c - Routines to deal with the pack. + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" + +/* + * add_pack: + * Pick up an object and add it to the pack. If the argument is non-null + * use it as the linked_list pointer instead of gettting it off the ground. + */ + +bool +add_pack(item, silent) +register struct linked_list *item; +bool silent; +{ + register struct linked_list *ip, *lp = NULL, *ap; + register struct object *obj, *op = NULL; + register bool exact, from_floor; + bool giveflag = 0; + static long cleric = C_CLERIC, + monk = C_MONK, + magician = C_MAGICIAN, + assassin = C_ASSASSIN, + druid = C_DRUID, + thief = C_THIEF, + fighter = C_FIGHTER, + ranger = C_RANGER, + paladin = C_PALADIN; + + if (item == NULL) + { + from_floor = TRUE; + if ((item = find_obj(hero.y, hero.x)) == NULL) + return(FALSE); + } + else + from_floor = FALSE; + obj = OBJPTR(item); + /* + * If it is gold, just add its value to rogue's purse and get rid + * of it. + */ + if (obj->o_type == GOLD) { + register struct linked_list *mitem; + register struct thing *tp; + + if (!silent) { + if (!terse) addmsg("You found "); + msg("%d gold pieces.", obj->o_count); + } + + /* First make sure no greedy monster is after this gold. + * If so, make the monster run after the rogue instead. + */ + for (mitem = mlist; mitem != NULL; mitem = next(mitem)) { + tp = THINGPTR(mitem); + if (tp->t_dest == &obj->o_pos) tp->t_dest = &hero; + } + + purse += obj->o_count; + if (from_floor) { + detach(lvl_obj, item); + if ((ap = find_obj(hero.y, hero.x)) == NULL) + mvaddch(hero.y,hero.x,(roomin(&hero)==NULL ? PASSAGE : FLOOR)); + else + mvaddch(hero.y,hero.x,(OBJPTR(ap))->o_type); + } + o_discard(item); + return(TRUE); + } + + /* + * see if he can carry any more weight + */ + if (itemweight(obj) + pstats.s_pack > pstats.s_carry) { + msg("Too much for you to carry."); + return FALSE; + } + /* + * Link it into the pack. Search the pack for a object of similar type + * if there isn't one, stuff it at the beginning, if there is, look for one + * that is exactly the same and just increment the count if there is. + * it that. Food is always put at the beginning for ease of access, but + * is not ordered so that you can't tell good food from bad. First check + * to see if there is something in thr same group and if there is then + * increment the count. + */ + if (obj->o_group) + { + for (ip = pack; ip != NULL; ip = next(ip)) + { + op = OBJPTR(ip); + if (op->o_group == obj->o_group) + { + /* + * Put it in the pack and notify the user + */ + op->o_count += obj->o_count; + if (from_floor) + { + detach(lvl_obj, item); + if ((ap = find_obj(hero.y, hero.x)) == NULL) + mvaddch(hero.y,hero.x, + (roomin(&hero)==NULL ? PASSAGE : FLOOR)); + else + mvaddch(hero.y,hero.x,(OBJPTR(ap))->o_type); + } + o_discard(item); + item = ip; + goto picked_up; + } + } + } + + /* + * Check for and deal with scare monster scrolls + */ + if (obj->o_type == SCROLL && obj->o_which == S_SCARE) + if (obj->o_flags & ISCURSED) + { + msg("The scroll turns to dust as you pick it up."); + detach(lvl_obj, item); + if ((ap = find_obj(hero.y, hero.x)) == NULL) + mvaddch(hero.y,hero.x,(roomin(&hero)==NULL ? PASSAGE : FLOOR)); + else + mvaddch(hero.y,hero.x,(OBJPTR(ap))->o_type); + return(TRUE); + } + + /* + * Search for an object of the same type + */ + exact = FALSE; + for (ip = pack; ip != NULL; ip = next(ip)) + { + op = OBJPTR(ip); + if (obj->o_type == op->o_type) + break; + } + if (ip == NULL) + { + /* + * Put it at the end of the pack since it is a new type + */ + for (ip = pack; ip != NULL; ip = next(ip)) + { + op = OBJPTR(ip); + if (op->o_type != FOOD) + break; + lp = ip; + } + } + else + { + /* + * Search for an object which is exactly the same + */ + while (ip != NULL && op->o_type == obj->o_type) + { + if (op->o_which == obj->o_which) + { + exact = TRUE; + break; + } + lp = ip; + if ((ip = next(ip)) == NULL) + break; + op = OBJPTR(ip); + } + } + /* + * Check if there is room + */ + if (ip == NULL || !exact || !ISMULT(obj->o_type)) { + if (inpack == MAXPACK-1) { + msg(terse ? "No room." : "You can't carry anything else."); + return(FALSE); + } + } + inpack++; + if (from_floor) + { + detach(lvl_obj, item); + if ((ap = find_obj(hero.y, hero.x)) == NULL) + mvaddch(hero.y,hero.x,(roomin(&hero)==NULL ? PASSAGE : FLOOR)); + else + mvaddch(hero.y,hero.x,(OBJPTR(ap))->o_type); + } + if (ip == NULL) + { + /* + * Didn't find an exact match, just stick it here + */ + if (pack == NULL) + pack = item; + else + { + lp->l_next = item; + item->l_prev = lp; + item->l_next = NULL; + } + } + else + { + /* + * If we found an exact match. If it is food, + * increase the count, otherwise put it with its clones. + */ + if (exact && ISMULT(obj->o_type)) + { + op->o_count += obj->o_count; + inpack--; /* adjust for previous addition */ + o_discard(item); + item = ip; + goto picked_up; + } + if ((item->l_prev = prev(ip)) != NULL) + item->l_prev->l_next = item; + else + pack = item; + item->l_next = ip; + ip->l_prev = item; + } +picked_up: + /* + * Notify the user + */ + obj = OBJPTR(item); + if (!silent) + { + if (!terse) + addmsg("You now have "); + msg("%s (%c)", inv_name(obj, !terse), pack_char(pack, obj)); + } + + /* Relics do strange things when you pick them up */ + if (obj->o_type == RELIC) { + switch (obj->o_which) { + /* the ankh of Heil gives you prayers */ + case HEIL_ANKH: + msg("The ankh welds itself into your hand. "); + if (player.t_ctype != C_CLERIC && player.t_ctype != C_PALADIN) + fuse(prayer_recovery, (VOID *)NULL, SPELLTIME, AFTER); + /* start a fuse to change player into a paladin */ + if (quest_item != HEIL_ANKH) { + msg("You hear a strange, distant hypnotic calling... "); + if (player.t_ctype != C_PALADIN && obj->o_which ==HEIL_ANKH) + fuse(changeclass, &paladin, roll(8, 8), AFTER); + } + + /* A cloak must be worn. */ + when EMORI_CLOAK: + if (cur_armor != NULL || cur_misc[WEAR_CLOAK]) { + msg("The cloak insists you remove your current garments."); + if (!dropcheck(cur_armor != NULL ? cur_armor + : cur_misc[WEAR_CLOAK])) { + pstats.s_hpt = -1; + msg("The cloak constricts around you..."); + msg("It draws your life force from you!!! --More--"); + wait_for(' '); + death(D_RELIC); + } + } + if (obj->o_charges < 0) /* should never happen, but.... */ + obj->o_charges = 0; + if (obj->o_charges == 0) + fuse(cloak_charge, obj, CLOAK_TIME, AFTER); + /* start a fuse to change player into a monk */ + if (quest_item != EMORI_CLOAK) { + msg("You suddenly become calm and quiet. "); + if (player.t_ctype != C_MONK && obj->o_which == EMORI_CLOAK) + fuse(changeclass, &monk, roll(8, 8), AFTER); + } + + /* The amulet must be worn. */ + when STONEBONES_AMULET: + case YENDOR_AMULET: + if (cur_misc[WEAR_JEWEL] || cur_relic[STONEBONES_AMULET] || + cur_relic[YENDOR_AMULET]) { + msg("You have an urge to remove your current amulet."); + } + if((cur_misc[WEAR_JEWEL] && !dropcheck(cur_misc[WEAR_JEWEL])) || + cur_relic[STONEBONES_AMULET] || cur_relic[YENDOR_AMULET]) { + pstats.s_hpt = -1; + msg("The %s begins pulsating... ",inv_name(obj, TRUE)); + msg("It fades completely away! --More--"); + wait_for(' '); + death(D_RELIC); + } + msg("The %s welds itself into your chest. ",inv_name(obj,TRUE)); + /* start a fuse to change into a magician */ + if (quest_item != STONEBONES_AMULET) { + if (player.t_ctype != C_MAGICIAN && + obj->o_which == STONEBONES_AMULET) { + msg("You sense approaching etheric forces... "); + fuse(changeclass, &magician, roll(8, 8), AFTER); + } + } + + /* The eye is now inserted in forehead */ + when EYE_VECNA: + msg("The eye forces itself into your forehead! "); + pstats.s_hpt -= (rnd(80)+21); + if (pstats.s_hpt <= 0) { + pstats.s_hpt = -1; + msg ("The pain is too much for you to bear! --More--"); + wait_for(' '); + death(D_RELIC); + } + waste_time(); + msg("The excruciating pain slowly turns into a dull throb."); + /* start a fuse to change player into an assassin */ + if (quest_item != EYE_VECNA) { + msg("Your blood rushes and you begin to sweat profusely... "); + if (player.t_ctype != C_ASSASSIN && obj->o_which == EYE_VECNA) + fuse(changeclass, &assassin, roll(8, 8), AFTER); + } + + when QUILL_NAGROM: + fuse(quill_charge,(VOID *)NULL, 8, AFTER); + /* start a fuse to change player into a druid */ + if (quest_item != QUILL_NAGROM) { + msg("You begin to see things differently... "); + if (player.t_ctype != C_DRUID && obj->o_which == QUILL_NAGROM) + fuse(changeclass, &druid, roll(8, 8), AFTER); + } + + /* Weapons will insist on being wielded. */ + when MUSTY_DAGGER: + case HRUGGEK_MSTAR: + case YEENOGHU_FLAIL: + case AXE_AKLAD: + /* set a daemon to eat gold for daggers and axe */ + if (obj->o_which == MUSTY_DAGGER || obj->o_which == AXE_AKLAD) { + if (purse > 0) msg("Your purse feels lighter! "); + else purse = 1; /* fudge to get right msg from eat_gold() */ + + eat_gold(obj); + daemon(eat_gold, obj, AFTER); + } + /* start a fuse to change player into a thief */ + if (quest_item != MUSTY_DAGGER) { + if (player.t_ctype != C_THIEF && + obj->o_which == MUSTY_DAGGER) { + msg("You look about furtively. "); + fuse(changeclass, &thief, roll(8, 8), AFTER); + } + } + /* start a fuse to change player into a fighter */ + if (quest_item != AXE_AKLAD) { + if (player.t_ctype != C_FIGHTER && + obj->o_which == AXE_AKLAD) { + msg("Your bones feel strengthened. "); + fuse(changeclass, &fighter, roll(8, 8), AFTER); + } + } + if (cur_weapon != NULL) { + msg("The artifact insists you release your current weapon!"); + if (!dropcheck(cur_weapon)) { + pstats.s_hpt = -1; + msg("The artifact forces your weapon into your heart! "); + msg("It hums with satisfaction! --More--"); + wait_for(' '); + death(D_RELIC); + } + } + cur_weapon = obj; + + /* acquire a sense of smell */ + when SURTUR_RING: + msg("The ring forces itself through your nose!"); + pstats.s_hpt -= rnd(40)+1; + if (pstats.s_hpt < 0) { + pstats.s_hpt = -1; + msg("The pain is too much for you to bear! --More--"); + wait_for(' '); + death(D_RELIC); + } + waste_time(); + turn_on(player, NOFIRE); + msg("The pain slowly subsides.. "); + + /* become a wandering musician */ + when BRIAN_MANDOLIN: + msg("You hear an ancient haunting sound... "); + /* start a fuse to change player into a ranger */ + if (quest_item != BRIAN_MANDOLIN) { + msg("You are transfixed with empathy. "); + if (player.t_ctype != C_RANGER && obj->o_which == BRIAN_MANDOLIN) + fuse(changeclass, &ranger, roll(8, 8), AFTER); + } + + /* add to the music */ + when GERYON_HORN: + msg("You begin to hear trumpets!"); + /* start a fuse to change player into a cleric */ + if (quest_item != GERYON_HORN) { + msg("You follow their calling. "); + if (player.t_ctype != C_CLERIC && obj->o_which == GERYON_HORN) + fuse(changeclass, &cleric, roll(8, 8), AFTER); + } + + /* the card can not be picked up, it must be traded for */ + when ALTERAN_CARD: + if (giveflag == FALSE) { + if (!wizard) { + msg("You look at the dark card and it chills you to the bone!! "); + msg("You stand for a moment, face to face with death... --More--"); + wait_for(' '); + pstats.s_hpt = -1; + death(D_CARD); + } + else { + msg("Got it! "); + if (purse > 0) msg("Your purse feels lighter! "); + else purse = 1; /* fudge to get right msg */ + + eat_gold(obj); + daemon(eat_gold, obj, AFTER); + } + } + else { + msg("You accept it hesitantly... "); + if (purse > 0) msg("Your purse feels lighter! "); + else purse = 1; /* fudge to get right msg */ + + eat_gold(obj); + daemon(eat_gold, obj, AFTER); + } + + otherwise: + break; + } + cur_relic[obj->o_which]++; /* Note that we have it */ + } + + updpack(FALSE, &player); + return(TRUE); +} + +/* + * inventory: + * list what is in the pack + */ + +inventory(list, type) +register struct linked_list *list; +register int type; +{ + register struct object *obj; + register char ch; + register int n_objs, cnt, maxx = 0, curx; + char inv_temp[2*LINELEN+1]; + + cnt = 0; + n_objs = 0; + for (ch = 'a'; list != NULL; ch++, list = next(list)) { + obj = OBJPTR(list); + if (!is_type(obj, type)) + continue; + switch (n_objs++) { + /* + * For the first thing in the inventory, just save the string + * in case there is only one. + */ + case 0: + sprintf(inv_temp, "%c) %s", ch, inv_name(obj, FALSE)); + break; + /* + * If there is more than one, clear the screen, print the + * saved message and fall through to ... + */ + case 1: + if (slow_invent) + msg(inv_temp); + else + { + wclear(hw); + waddstr(hw, inv_temp); + waddch(hw, '\n'); + + maxx = strlen(inv_temp); /* Length of the listing */ + } + /* + * Print the line for this object + */ + default: + if (ch > 'z') + ch = 'A'; + if (slow_invent) + msg("%c) %s", ch, inv_name(obj, FALSE)); + else { + if (++cnt >= lines - 2) { /* if bottom of screen */ + dbotline(hw, morestr); + cnt = 0; + wclear(hw); + } + sprintf(inv_temp, "%c) %s\n", ch, inv_name(obj, FALSE)); + curx = strlen(inv_temp) - 1; /* Don't count new-line */ + if (curx > maxx) maxx = curx; + waddstr(hw, inv_temp); + } + } + } + if (n_objs == 0) { + if (terse) + msg(type == ALL ? "Empty-handed." : + "Nothing appropriate"); + else + msg(type == ALL ? "You are empty-handed." : + "You don't have anything appropriate"); + return FALSE; + } + if (n_objs == 1) { + msg(inv_temp); + return TRUE; + } + if (!slow_invent) + { + waddstr(hw, spacemsg); + curx = strlen(spacemsg); + if (curx > maxx) maxx = curx; + + /* + * If we have fewer than half a screenful, don't clear the screen. + * Leave an extra blank line at the bottom and 3 blank columns + * to he right. + */ + if (menu_overlay && n_objs < lines - 3) { + over_win(cw, hw, n_objs + 2, maxx + 3, n_objs, curx, ' '); + return TRUE; + } + + draw(hw); + wait_for(' '); + restscr(cw); + } + return TRUE; +} + +/* + * picky_inven: + * Allow player to inventory a single item + */ + +void +picky_inven() +{ + register struct linked_list *item; + register char ch, mch; + + if (pack == NULL) + msg("You aren't carrying anything"); + else if (next(pack) == NULL) + msg("a) %s", inv_name(OBJPTR(pack), FALSE)); + else + { + msg(terse ? "Item: " : "Which item do you wish to inventory: "); + mpos = 0; + if ((mch = wgetch(cw)) == ESC) + { + msg(""); + return; + } + + /* Check for a special character */ + switch (mch) { + case FOOD: + case SCROLL: + case POTION: + case RING: + case STICK: + case RELIC: + case ARMOR: + case WEAPON: + case MM: + msg(""); + if (get_item(pack, (char *)NULL, mch, FALSE, FALSE) == NULL) { + if (terse) msg("No '%c' in your pack.", mch); + else msg("You have no '%c' in your pack.", mch); + } + return; + } + + for (ch = 'a', item = pack; item != NULL; item = next(item), ch++) + if (ch == mch) + { + msg("%c) %s",ch,inv_name(OBJPTR(item), FALSE)); + return; + } + if (!terse) + msg("'%s' not in pack.", unctrl(mch)); + msg("Range is 'a' to '%c'", --ch); + } +} + +/* + * get_item: + * pick something out of a pack for a purpose + */ + +struct linked_list * +get_item(list, purpose, type, askfirst, showcost) +reg struct linked_list *list; +char *purpose; /* NULL if we should be silent (no prompts) */ +int type; +bool askfirst, showcost; +{ + reg struct linked_list *item; + reg struct object *obj; + reg int cnt, pagecnt, ch, och, maxx, curx, confused; + struct linked_list *saveitem = NULL; + char description[2*LINELEN+1]; + char cost[LINELEN/2]; + char cap_purpose[LINELEN]; /* capitalize the "doings" */ + + cap_purpose[0] = '\0'; + + /* Get a capitalized purpose for starting sentences */ + if (purpose) { + strcpy(cap_purpose, purpose); + cap_purpose[0] = toupper(cap_purpose[0]); + } + + /* + * If this is the player's pack and the player is confused, we + * might just take anything. + */ + if (list == player.t_pack && on(player, ISHUH) && rnd(100) < 70) + confused = 1; + else confused = 0; + + cnt = 0; + if (list == NULL) { + msg("You aren't carrying anything."); + return NULL; + } + /* see if we have any of the type requested */ + for(ch = 'a',item = list ; item != NULL ; item = next(item), ch++) { + obj = OBJPTR(item); + if (is_type(obj, type)) { + cnt++; + saveitem = item; + } + } + if (cnt == 0) { + if (purpose) msg("Nothing to %s", purpose); + after = FALSE; + return NULL; + } + else if (cnt == 1) { /* only found one of 'em */ + obj = OBJPTR(saveitem); + for(;;) { + if (purpose) { /* Should we prompt the player? */ + msg("%s what (* for the item)?", cap_purpose); + ch = wgetch(cw); + } + else { + ch = pack_char(list, obj); + msg("%c) %s", ch, inv_name(obj,FALSE)); + } + + if (ch == '*') { + mpos = 0; + msg("%c) %s",pack_char(list, obj),inv_name(obj,FALSE)); + continue; + } + if (ch == ESC) { + msg(""); + after = FALSE; + return NULL; + } + for(item = list,och = 'a'; item != NULL; item = next(item),och++) { + if (ch == och) break; + if (och == 'z') och = 'A' - 1; + } + if (item == NULL) { + msg("Please specify a letter between 'a' and '%c'", + och == 'A' ? 'z' : och-1); + continue; + } + if (is_type (OBJPTR(item), type)) { + if (purpose) mpos = 0; + return item; + } + else + msg ("You can't %s that!", purpose); + + } + } + for(;;) { + if (!askfirst && purpose) { + msg("%s what? (* for list): ", cap_purpose); + ch = wgetch(cw); + } + else ch = '*'; + + mpos = 0; + if (ch == ESC) { /* abort if escape hit */ + after = FALSE; + msg(""); /* clear display */ + return NULL; + } + + if (ch == '*') { + wclear(hw); + pagecnt = 0; + maxx = 0; + for(item = list,ch = 'a'; item != NULL ; item = next(item), ch++) { + obj = OBJPTR(item); + if (!is_type(OBJPTR(item), type)) + continue; + cost[0] = '\0'; + if (showcost) { + sprintf(description, "[%ld] ", get_worth(obj)); + sprintf(cost, "%8.8s", description); + } + sprintf(description,"%c) %s%s\n\r",ch,cost,inv_name(obj,FALSE)); + waddstr(hw, description); + curx = strlen(description) - 2; /* Don't count \n or \r */ + if (maxx < curx) maxx = curx; + if (++pagecnt >= lines - 2 && next(item) != NULL) { + pagecnt = 0; + dbotline(hw, spacemsg); + wclear(hw); + } + if (ch == 'z') ch = 'A' - 1; + } + + /* Put in the prompt */ + if (purpose) sprintf(description, "%s what? ", cap_purpose); + else strcpy(description, spacemsg); + waddstr(hw, description); + curx = strlen(description); + if (maxx < curx) maxx = curx; + + /* Write the screen */ + if ((menu_overlay && cnt < lines - 3) || cnt == 1) { + over_win(cw, hw, cnt + 2, maxx + 3, cnt, curx, NULL); + cnt = -1; /* Indicate we used over_win */ + } + else draw(hw); + + if (purpose) { + do { + ch = wgetch(cw); + } until (isalpha(ch) || ch == ESC); + } + else { + ch = pack_char(list, OBJPTR(saveitem)); /* Pick a valid item */ + wait_for(' '); + } + + /* Redraw original screen */ + if (cnt < 0) { + clearok(cw, FALSE); /* Setup to redraw current screen */ + touchwin(cw); /* clearing first */ + draw(cw); + } + else restscr(cw); + + if(ch == ESC) { + after = FALSE; + msg(""); /* clear top line */ + return NULL; /* all done if abort */ + } + /* ch has item to get from list */ + } + + for (item = list,och = 'a'; item != NULL; item = next(item),och++) { + if (confused) { + /* + * Confused is incremented each time so that if the rnd(cnt) + * clause keeps failing, confused will equal cnt for the + * last item of the correct type and rnd(cnt) < cnt will + * have to be true. + */ + if (is_type(OBJPTR(item), type) && rnd(cnt) < confused++) + break; + } + else if (ch == och) break; + if (och == 'z') och = 'A' - 1; + } + + if (item == NULL) { + msg("Please specify a letter between 'a' and '%c' ", + och == 'A' ? 'z' : och-1); + continue; + } + + if (is_type(OBJPTR(item), type)) + return (item); + else + msg ("You can't %s that!", purpose); + } +} + +pack_char(list, obj) +register struct object *obj; +struct linked_list *list; +{ + register struct linked_list *item; + register char c; + + c = 'a'; + for (item = list; item != NULL; item = next(item)) { + if (OBJPTR(item) == obj) + return c; + else { + if (c == 'z') c = 'A'; + else c++; + } + } + return 'z'; +} + +/* + * cur_null: + * This updates cur_weapon etc for dropping things + */ + +cur_null(op) +reg struct object *op; +{ + if (op == cur_weapon) cur_weapon = NULL; + else if (op == cur_armor) cur_armor = NULL; + else if (op == cur_ring[LEFT_1]) cur_ring[LEFT_1] = NULL; + else if (op == cur_ring[LEFT_2]) cur_ring[LEFT_2] = NULL; + else if (op == cur_ring[LEFT_3]) cur_ring[LEFT_3] = NULL; + else if (op == cur_ring[LEFT_4]) cur_ring[LEFT_4] = NULL; + else if (op == cur_ring[RIGHT_1]) cur_ring[RIGHT_1] = NULL; + else if (op == cur_ring[RIGHT_2]) cur_ring[RIGHT_2] = NULL; + else if (op == cur_ring[RIGHT_3]) cur_ring[RIGHT_3] = NULL; + else if (op == cur_ring[RIGHT_4]) cur_ring[RIGHT_4] = NULL; + else if (op == cur_misc[WEAR_BOOTS]) cur_misc[WEAR_BOOTS] = NULL; + else if (op == cur_misc[WEAR_JEWEL]) cur_misc[WEAR_JEWEL] = NULL; + else if (op == cur_misc[WEAR_GAUNTLET]) cur_misc[WEAR_GAUNTLET] = NULL; + else if (op == cur_misc[WEAR_CLOAK]) cur_misc[WEAR_CLOAK] = NULL; + else if (op == cur_misc[WEAR_BRACERS]) cur_misc[WEAR_BRACERS] = NULL; + else if (op == cur_misc[WEAR_NECKLACE]) cur_misc[WEAR_NECKLACE] = NULL; +} + +/* + * idenpack: + * Identify all the items in the pack + */ + +idenpack() +{ + reg struct linked_list *pc; + + for (pc = pack ; pc != NULL ; pc = next(pc)) + whatis(pc); +} + +is_type (obj, type) +register struct object *obj; +register int type; +{ + register bool current; + + if (type == obj->o_type) + return (TRUE); + + switch (type) { + case ALL: + return (TRUE); + when READABLE: + if (obj->o_type == SCROLL || + (obj->o_type == MM && obj->o_which == MM_SKILLS)) + return (TRUE); + when QUAFFABLE: + if (obj->o_type == POTION || + (obj->o_type == MM && obj->o_which == MM_JUG)) + return (TRUE); + when ZAPPABLE: + if (obj->o_type == STICK) return (TRUE); + if (obj->o_type == RELIC) + switch (obj->o_which) { + case MING_STAFF: + case ASMO_ROD: + case ORCUS_WAND: + case EMORI_CLOAK: + return (TRUE); + } + when WEARABLE: + case REMOVABLE: + current = is_current(obj); + + /* + * Don't wear thing we are already wearing or remove things + * we aren't wearing. + */ + if (type == WEARABLE && current) return (FALSE); + else if (type == REMOVABLE && !current) return (FALSE); + + switch (obj->o_type) { + case RELIC: + switch (obj->o_which) { + case HEIL_ANKH: + case EMORI_CLOAK: + return (TRUE); + } + when MM: + switch (obj->o_which) { + case MM_ELF_BOOTS: + case MM_DANCE: + case MM_BRACERS: + case MM_DISP: + case MM_PROTECT: + case MM_G_DEXTERITY: + case MM_G_OGRE: + case MM_JEWEL: + case MM_R_POWERLESS: + case MM_FUMBLE: + case MM_STRANGLE: + case MM_ADAPTION: + return (TRUE); + } + when ARMOR: + case RING: + return (TRUE); + } + when CALLABLE: + switch (obj->o_type) { + case RING: if (!r_know[obj->o_which]) return(TRUE); + when POTION: if (!p_know[obj->o_which]) return(TRUE); + when STICK: if (!ws_know[obj->o_which]) return(TRUE); + when SCROLL: if (!s_know[obj->o_which]) return(TRUE); + when MM: if (!m_know[obj->o_which]) return(TRUE); + } + when WIELDABLE: + switch (obj->o_type) { + case STICK: + case WEAPON: + return(TRUE); + when RELIC: + switch (obj->o_which) { + case MUSTY_DAGGER: + case HRUGGEK_MSTAR: + case YEENOGHU_FLAIL: + case AXE_AKLAD: + case MING_STAFF: + case ORCUS_WAND: + case ASMO_ROD: + return(TRUE); + } + } + when IDENTABLE: + if (!(obj->o_flags & ISKNOW) && obj->o_type != FOOD) + return (TRUE); + if (obj->o_type == MM) { + switch (obj->o_which) { + case MM_JUG: + /* Can still identify a jug if we don't know the potion */ + if (obj->o_ac != JUG_EMPTY && !p_know[obj->o_ac]) + return (TRUE); + } + } + when USEABLE: + if (obj->o_type == MM) { + switch(obj->o_which) { + case MM_BEAKER: + case MM_BOOK: + case MM_OPEN: + case MM_HUNGER: + case MM_DRUMS: + case MM_DISAPPEAR: + case MM_CHOKE: + case MM_KEOGHTOM: + case MM_CRYSTAL: + return (TRUE); + } + } + else if (obj->o_type == RELIC) { + switch (obj->o_which) { + case EMORI_CLOAK: + case BRIAN_MANDOLIN: + case HEIL_ANKH: + case YENDOR_AMULET: + case STONEBONES_AMULET: + case GERYON_HORN: + case EYE_VECNA: + case QUILL_NAGROM: + case SURTUR_RING: + case ALTERAN_CARD: + return (TRUE); + } + } + else if (obj->o_type == POTION) { + /* + * only assassins can use poison + */ + if (player.t_ctype == C_ASSASSIN && obj->o_which == P_POISON) + return(TRUE); + } + when PROTECTABLE: + switch (obj->o_type) { + case WEAPON: + if ((obj->o_flags & ISMETAL) == 0) return (FALSE); + + /* Fall through */ + case ARMOR: + return (TRUE); + + when MM: + if (obj->o_which == MM_BRACERS) return (TRUE); + } + } + return(FALSE); +} + +del_pack(item) +register struct linked_list *item; +{ + register struct object *obj; + + obj = OBJPTR(item); + if (obj->o_count > 1) { + obj->o_count--; + } + else { + cur_null(obj); + detach(pack, item); + o_discard(item); + inpack--; + } +} + +/* + * carry_obj: + * Check to see if a monster is carrying something and, if so, give + * it to him. + */ + +carry_obj(mp, chance) +register struct thing *mp; +int chance; +{ + reg struct linked_list *item; + reg struct object *obj; + + /* + * If there is no chance, just return. + * Note that this means there must be a "chance" in order for + * the creature to carry a relic. + */ + if (chance <= 0) return; + + /* + * check for the relic/artifacts + * Do the relics first so they end up last in the pack. Attach() + * always adds things to the beginning. This way they will be the + * last things dropped when the creature is killed. This will ensure + * the relic will be on top if there is a stack of item lying on the + * floor and so the hero will know where it is if he's trying to + * avoid it. Note that only UNIQUEs carry relics. + */ + if (on(*mp, ISUNIQUE)) { + if (on(*mp, CARRYMDAGGER)) { + item = spec_item(RELIC, MUSTY_DAGGER, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + if (on(*mp, CARRYCLOAK)) { + item = spec_item(RELIC, EMORI_CLOAK, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + if (on(*mp, CARRYANKH)) { + item = spec_item(RELIC, HEIL_ANKH, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + if (on(*mp, CARRYSTAFF)) { + item = spec_item(RELIC, MING_STAFF, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + if (on(*mp, CARRYWAND)) { + item = spec_item(RELIC, ORCUS_WAND, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + if (on(*mp, CARRYROD)) { + item = spec_item(RELIC, ASMO_ROD, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + if (on(*mp, CARRYYAMULET)) { + item = spec_item(RELIC, YENDOR_AMULET, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + if (on(*mp, CARRYBAMULET)) { + item = spec_item(RELIC, STONEBONES_AMULET, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + if (on(*mp, CARRYMANDOLIN)) { + item = spec_item(RELIC, BRIAN_MANDOLIN, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + if (on(*mp, CARRYEYE)) { + item = spec_item(RELIC, EYE_VECNA, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + if (on(*mp, CARRYAXE)) { + item = spec_item(RELIC, AXE_AKLAD, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + if (on(*mp, CARRYQUILL)) { + register int i, howmany; + + item = spec_item(RELIC, QUILL_NAGROM, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + obj->o_charges = rnd(QUILLCHARGES); + attach(mp->t_pack, item); + howmany = roll(4,3); + for (i=0; i<howmany; i++) { + /* + * the quill writes scrolls so give him a bunch + */ + item = new_thing(TYP_SCROLL, FALSE); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + } + if (on(*mp, CARRYMSTAR)) { + item = spec_item(RELIC, HRUGGEK_MSTAR, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + if (on(*mp, CARRYFLAIL)) { + item = spec_item(RELIC, YEENOGHU_FLAIL, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + if (on(*mp, CARRYHORN)) { + item = spec_item(RELIC, GERYON_HORN, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + if (on(*mp, CARRYSURTURRING)) { + item = spec_item(RELIC, SURTUR_RING, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + if (on(*mp, CARRYCARD)) { + item = spec_item(RELIC, ALTERAN_CARD, NULL, NULL); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + } + /* + * If it carries gold, give it some + */ + if (on(*mp, CARRYGOLD) && rnd(100) < chance) { + item = spec_item(GOLD, NULL, NULL, NULL); + obj = OBJPTR(item); + obj->o_count = GOLDCALC + GOLDCALC; + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + /* + * If it carries food, give it some + */ + if (on(*mp, CARRYFOOD) && rnd(100) < chance) { + int type; + switch (rnd(41)) { + case 3: type = E_APPLE; + when 6: type = E_HAGBERRY; + when 9: type = E_SOURSOP; + when 12: type = E_RAMBUTAN; + when 15: type = E_DEWBERRY; + when 18: type = E_CANDLEBERRY; + when 21: type = E_BANANA; + when 24: type = E_CAPRIFIG; + when 27: type = E_STRAWBERRY; + when 30: type = E_GOOSEBERRY; + when 33: type = E_ELDERBERRY; + when 36: type = E_BLUEBERRY; + when 40: type = E_SLIMEMOLD; /* monster food */ + otherwise: type = E_RATION; + } + item = spec_item(FOOD, type, NULL, NULL); + obj = OBJPTR(item); + obj->o_weight = things[TYP_FOOD].mi_wght; + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + /* + * If it carries a weapon, give it one + */ + if (on(*mp, CARRYWEAPON) && rnd(100) < chance) { + int type, hit, dam; + + /* Get the "bonuses" */ + hit = rnd(5 + (vlevel / 5)) - 2; + dam = rnd(5 + (vlevel / 5)) - 2; + + /* Only choose an appropriate type of weapon */ + switch (rnd(12)) { + case 0: type = DAGGER; + when 1: type = BATTLEAXE; + when 2: type = MACE; + when 3: type = SWORD; + when 4: type = PIKE; + when 5: type = HALBERD; + when 6: type = SPETUM; + when 7: type = BARDICHE; + when 8: type = TRIDENT; + when 9: type = BASWORD; + when 10:type = DART; + otherwise: type = TWOSWORD; + } + + /* Create the item */ + item = spec_item(WEAPON, type, hit, dam); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + /* + * If it carries a dagger, give it one + */ + if (on(*mp, CARRYDAGGER) && rnd(100) < chance) { + int hit, dam; + + /* Get the "bonuses" */ + hit = rnd(3 + (vlevel / 5)) - 1; + dam = rnd(3 + (vlevel / 5)) - 1; + + /* Create the item */ + item = spec_item(WEAPON, DAGGER, hit, dam); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + /* + * If it carries a scroll, give it one + */ + if (on(*mp, CARRYSCROLL) && rnd(100) < chance) { + item = new_thing(TYP_SCROLL, TRUE); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + + /* Can the monster carry this scroll? */ + if (obj->o_which == S_SCARE && mp->t_stats.s_intel < 16) + fall(item, FALSE); /* This would scare us! */ + else attach(mp->t_pack, item); + } + + /* + * If it carries a potion, give it one + */ + if (on(*mp, CARRYPOTION) && rnd(100) < chance) { + item = new_thing(TYP_POTION, TRUE); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + /* + * If it carries a ring, give it one + */ + if (on(*mp, CARRYRING) && rnd(100) < chance) { + item = new_thing(TYP_RING, TRUE); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + /* + * If it carries a wand or staff, give it one + */ + if (on(*mp, CARRYSTICK) && rnd(100) < chance) { + item = new_thing(TYP_STICK, TRUE); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + /* + * If it carries any miscellaneous magic, give it one + */ + if (on(*mp, CARRYMISC) && rnd(100) < chance) { + item = new_thing(TYP_MM, TRUE); + obj = OBJPTR(item); + obj->o_pos = mp->t_pos; + attach(mp->t_pack, item); + } + + /* Update the monster's encumberance */ + updpack(TRUE, mp); +} + + +/* + * grab(): + * See what is on the spot where the player is standing. If + * nothing is there, do nothing. If there is one thing, pick it + * up. If there are multiple things, prompt the player for what + * he wants (* means everything). + */ + +grab(y, x) +register int y, x; +{ + register struct linked_list *next_item, *item; + register struct object *obj; + register int cnt, pagecnt; + int num_there = 0, ch, och; + + /* + * Count how many objects there are and move them to the front + * of the level list. + */ + for (item = lvl_obj; item != NULL; item = next_item) { + obj = OBJPTR(item); + next_item = next(item); + if (obj->o_pos.y == y && obj->o_pos.x == x) { + num_there++; + detach(lvl_obj, item); /* Remove it from the list */ + attach(lvl_obj, item); /* Place it at the front of the list */ + } + } + + /* Nothing there. */ + if (num_there < 1) msg("Nothing %s", terse ? "there." : "to pick up."); + + /* Something or things there */ + else { + char linebuf[2*LINELEN+1]; + int curlen, maxlen = 0; + + wclear(hw); + cnt = 0; + pagecnt = 0; + for (item = lvl_obj, ch = 'a'; item != NULL && cnt < num_there; + item = next(item), ch++, cnt++) { + obj = OBJPTR(item); + /* Construct how the line will look */ + sprintf(linebuf, "%c) %s\n\r", ch, inv_name(obj,FALSE)); + + /* See how long it is */ + curlen = strlen(linebuf) - 2; /* Don't count \n or \r */ + if (maxlen < curlen) maxlen = curlen; + + /* Draw it in the window */ + waddstr(hw, linebuf); + + if (++pagecnt >= lines - 2 && next(item) != NULL) { + pagecnt = 0; + maxlen = 0; + dbotline(hw, spacemsg); + wclear(hw); + } + if (ch == 'z') ch = 'A' - 1; + } + + strcpy(linebuf, "Pick up what? (* for all): "); + + /* See how long it is */ + curlen = strlen(linebuf); /* Don't count \n or \r */ + if (maxlen < curlen) maxlen = curlen; + + /* Draw it in the window */ + waddstr(hw, linebuf); + + /* + * If we have fewer than half a screenful, don't clear the screen. + * Leave 3 blank lines at the bottom and 3 blank columns to he right. + */ + if (menu_overlay && num_there < lines - 3) { + over_win(cw, hw, num_there + 2, maxlen + 3, num_there, curlen, NULL); + pagecnt = -1; /* Indicate we used over_win */ + } + else draw(hw); /* write screen */ + + for (;;) { + do { + ch = wgetch(cw); + } until (isalpha(ch) || ch == '*' || ch == ESC); + + /* Redraw original screen */ + if (pagecnt < 0) { + clearok(cw, FALSE); /* Setup to redraw current screen */ + touchwin(cw); /* clearing first */ + draw(cw); + } + else restscr(cw); + + if (ch == ESC) { + after = FALSE; + msg(""); /* clear top line */ + break; + } + if (ch == '*') { + player.t_action = A_PICKUP; + return(1); /* set action to PICKUP and delay for first one */ + } + /* ch has item to get from list */ + + cnt = 0; + for (item = lvl_obj, och = 'a'; item != NULL && cnt < num_there; + item = next(item), och++, cnt++) { + if (ch == och) + break; + if (och == 'z') och = 'A' - 1; + } + if (item == NULL || cnt >= num_there) { + wmove(hw, pagecnt < 0 ? num_there : pagecnt, 25); + wprintw(hw, " [between 'a' and '%c']: ", + och == 'A' ? 'z' : och-1); + if (maxlen < 49) maxlen = 49; + + /* + * If we have fewer than half a screenful, don't clear the + * screen. Leave an extra blank line at the bottom and + * 3 blank columns to the right. + */ + if (menu_overlay && num_there < lines - 3) { + over_win(cw, hw, num_there + 2, maxlen + 3, + num_there, 49, NULL); + cnt = -1; /* Indicate we used over_win */ + } + else draw(hw); /* write screen */ + continue; + } + else { + detach(lvl_obj, item); + if (add_pack(item, FALSE)) { + /* + * We make sure here that the dungeon floor gets + * updated with what's left on the vacated spot. + */ + if ((item = find_obj(y, x)) == NULL) { + coord roomcoord; /* Needed to pass to roomin() */ + + roomcoord.y = y; + roomcoord.x = x; + mvaddch(y, x, + (roomin(&roomcoord) == NULL ? PASSAGE : FLOOR)); + } + else mvaddch(y, x, (OBJPTR(item))->o_type); + return(1); + } + else attach(lvl_obj, item); /* Couldn't pick it up! */ + break; + } + } + } + + return(0); +} + +/* + * make_sell_pack: + * + * Create a pack for sellers (a la quartermaster) + */ + +make_sell_pack(tp) +struct thing *tp; +{ + reg struct linked_list *item; + reg struct object *obj; + reg int sell_type = 0, nitems, i; + + /* Select the items */ + nitems = rnd(5) + 7; + + switch (rnd(14)) { + /* Armor */ + case 0: + case 1: + turn_on(*tp, CARRYARMOR); + sell_type = TYP_ARMOR; + break; + + /* Weapon */ + when 2: + case 3: + turn_on(*tp, CARRYWEAPON); + sell_type = TYP_WEAPON; + break; + + /* Staff or wand */ + when 4: + case 5: + turn_on(*tp, CARRYSTICK); + sell_type = TYP_STICK; + break; + + /* Ring */ + when 6: + case 7: + turn_on(*tp, CARRYRING); + sell_type = TYP_RING; + break; + + /* scroll */ + when 8: + case 9: + turn_on(*tp, CARRYSCROLL); + sell_type = TYP_SCROLL; + break; + + /* potions */ + when 10: + case 11: + turn_on(*tp, CARRYPOTION); + sell_type = TYP_POTION; + break; + + /* Miscellaneous magic */ + when 12: + case 13: + turn_on(*tp, CARRYMISC); + sell_type = TYP_MM; + break; + } + for (i=0; i<nitems; i++) { + item = new_thing(sell_type, FALSE); + obj = OBJPTR(item); + obj->o_pos = tp->t_pos; + attach(tp->t_pack, item); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/passages.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,370 @@ +/* + passages.c - Draw the connecting passages + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include "rogue.h" + +/* + * do_passages: + * Draw all the passages on a level. + */ + +do_passages() +{ + register struct rdes *r1, *r2 = NULL; + register int i, j; + register int roomcount; + static struct rdes + { + bool conn[MAXROOMS]; /* possible to connect to room i? */ + bool isconn[MAXROOMS]; /* connection been made to room i? */ + bool ingraph; /* this room in graph already? */ + } rdes[MAXROOMS] = { + { { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + }; + + /* + * reinitialize room graph description + */ + for (i = 0; i < MAXROOMS; i++) + { + r1 = &rdes[i]; + for (j = 0; j < MAXROOMS; j++) + r1->isconn[j] = FALSE; + r1->ingraph = FALSE; + } + + /* + * starting with one room, connect it to a random adjacent room and + * then pick a new room to start with. + */ + roomcount = 1; + r1 = &rdes[rnd(MAXROOMS)]; + r1->ingraph = TRUE; + do + { + /* + * find a room to connect with + */ + j = 0; + for (i = 0; i < MAXROOMS; i++) + if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0) + r2 = &rdes[i]; + /* + * if no adjacent rooms are outside the graph, pick a new room + * to look from + */ + if (j == 0) + { + do + r1 = &rdes[rnd(MAXROOMS)]; + until (r1->ingraph); + } + /* + * otherwise, connect new room to the graph, and draw a tunnel + * to it + */ + else + { + r2->ingraph = TRUE; + i = r1 - rdes; + j = r2 - rdes; + conn(i, j); + r1->isconn[j] = TRUE; + r2->isconn[i] = TRUE; + roomcount++; + } + } while (roomcount < MAXROOMS); + + /* + * attempt to add passages to the graph a random number of times so + * that there isn't just one unique passage through it. + */ + for (roomcount = rnd(5); roomcount > 0; roomcount--) + { + r1 = &rdes[rnd(MAXROOMS)]; /* a random room to look from */ + /* + * find an adjacent room not already connected + */ + j = 0; + for (i = 0; i < MAXROOMS; i++) + if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0) + r2 = &rdes[i]; + /* + * if there is one, connect it and look for the next added + * passage + */ + if (j != 0) + { + i = r1 - rdes; + j = r2 - rdes; + conn(i, j); + r1->isconn[j] = TRUE; + r2->isconn[i] = TRUE; + } + } +} + +/* + * conn: + * Draw a corridor from a room in a certain direction. + */ + +conn(r1, r2) +int r1, r2; +{ + register struct room *rpf, *rpt = NULL; + register char rmt; + register int distance = 0, max_diag, offset = 0, i; + register int rm; + int turns[3], turn_dist[3]; + register char direc; + coord delta = {0, 0}, curr, turn_delta = {0,0}, spos = {0,0}, epos = {0,0}; + + if (r1 < r2) + { + rm = r1; + if (r1 + 1 == r2) + direc = 'r'; + else + direc = 'd'; + } + else + { + rm = r2; + if (r2 + 1 == r1) + direc = 'r'; + else + direc = 'd'; + } + rpf = &rooms[rm]; + /* + * Set up the movement variables, in two cases: + * first drawing one down. + */ + if (direc == 'd') + { + rmt = rm + 3; /* room # of dest */ + rpt = &rooms[rmt]; /* room pointer of dest */ + delta.x = 0; /* direction of move */ + delta.y = 1; + spos.x = rpf->r_pos.x; /* start of move */ + spos.y = rpf->r_pos.y; + epos.x = rpt->r_pos.x; /* end of move */ + epos.y = rpt->r_pos.y; + if (!(rpf->r_flags & ISGONE)) /* if not gone pick door pos */ + { + spos.x += rnd(rpf->r_max.x-2)+1; + spos.y += rpf->r_max.y-1; + } + if (!(rpt->r_flags & ISGONE)) + epos.x += rnd(rpt->r_max.x-2)+1; + distance = abs(spos.y - epos.y) - 1; /* distance to move */ + turn_delta.y = 0; /* direction to turn */ + turn_delta.x = (spos.x < epos.x ? 1 : -1); + offset = abs(spos.x - epos.x); /* how far to turn */ + } + else if (direc == 'r') /* setup for moving right */ + { + rmt = rm + 1; + rpt = &rooms[rmt]; + delta.x = 1; + delta.y = 0; + spos.x = rpf->r_pos.x; + spos.y = rpf->r_pos.y; + epos.x = rpt->r_pos.x; + epos.y = rpt->r_pos.y; + if (!(rpf->r_flags & ISGONE)) + { + spos.x += rpf->r_max.x-1; + spos.y += rnd(rpf->r_max.y-2)+1; + } + if (!(rpt->r_flags & ISGONE)) + epos.y += rnd(rpt->r_max.y-2)+1; + distance = abs(spos.x - epos.x) - 1; + turn_delta.y = (spos.y < epos.y ? 1 : -1); + turn_delta.x = 0; + offset = abs(spos.y - epos.y); + } + else + debug("error in connection tables"); + + /* + * Draw in the doors on either side of the passage or just put #'s + * if the rooms are gone. + */ + if (!(rpf->r_flags & ISGONE)) door(rpf, &spos); + else + { + cmov(spos); + addch('#'); + } + if (!(rpt->r_flags & ISGONE)) door(rpt, &epos); + else + { + cmov(epos); + addch('#'); + } + + /* How far can we move diagonally? */ + max_diag = min(distance, offset); + + /* + * Decide how many turns we will have. + */ + for (i=0; i<3; i++) turn_dist[i] = 0; /* Init distances */ + if (max_diag > 0) { + int nturns; + + for (i=0, nturns=0; i<3; i++) { + if (rnd(3 - i + nturns) == 0) { + nturns++; + turns[i] = 0; + } + else turns[i] = -1; + } + } + else { + /* Just use a straight line (middle turn) */ + turns[0] = turns[2] = -1; + turns[1] = 0; + } + + /* + * Now decide how long each turn will be (for those selected above). + */ + while (max_diag > 0) { + for (i=0; i<3; i++) { + if (turns[i] >= 0 && max_diag > 0 && rnd(2) == 0) { + turn_dist[i]++; + max_diag--; + } + } + } + + /* + * If we have extra offset space, add it to the straight turn. + */ + if (offset > distance) turn_dist[1] += offset - distance; + + /* + * Decide where we want to make our turns. + * First calculate the offsets, then use those offsets to calculate + * the exact position relative to "distance." + */ + turns[0] = rnd(distance - turn_dist[0] - turn_dist[2]); + turns[2] = rnd(distance - turn_dist[0] - turn_dist[2] - turns[0]); + turns[1] = rnd(distance - turn_dist[0] - turn_dist[2] - + turns[0] - turns[2]); + + turns[0] = distance - turns[0]; + turns[1] = turns[0] - turn_dist[0] - turns[1]; + turns[2] = turns[1] - turns[2]; + + /* + * Get ready to move... + */ + curr.x = spos.x; + curr.y = spos.y; + while (distance > 0) { + /* + * Move to next row/column + */ + curr.x += delta.x; + curr.y += delta.y; + + /* + * Check if we are at a turn place; if so make a turn + */ + for (i=0; i<3; i++) { + if (distance == turns[i] && turn_dist[i] > 0) { + /* + * If this is the start of a straight path, + * we might put in a right-angle turn (33% chance). + */ + if (i == 1 && rnd(3) == 0) { + cmov(curr); + addch(PASSAGE); + } + + /* Now dig the turn */ + while (turn_dist[i]--) { + curr.x += turn_delta.x; + curr.y += turn_delta.y; + cmov(curr); + addch(PASSAGE); + if (i != 1) { /* A diagonal */ + if (--distance > 0) { + curr.x += delta.x; + curr.y += delta.y; + } + } + } + } + } + + if (distance > 0) { + /* + * Dig the passage. + */ + cmov(curr); + addch(PASSAGE); + distance--; + } + } + curr.x += delta.x; + curr.y += delta.y; + if (!ce(curr, epos)) + msg("Warning, connectivity problem (%d, %d) to (%d, %d).", + curr.y, curr.x, epos.y, epos.x); +} + +/* + * Add a door or possibly a secret door + * also enters the door in the exits array of the room. + */ + +door(rm, cp) +register struct room *rm; +register coord *cp; +{ + struct linked_list *newroom; + coord *exit; + + cmov(*cp); + + if (rnd(10) < (level - 1) && rnd(100) < 20) + addch(SECRETDOOR); + else + addch(DOOR); + + /* Insert the new room into the linked list of rooms */ + newroom = new_item(sizeof(coord)); + exit = DOORPTR(newroom); + *exit = *cp; + attach(rm->r_exit, newroom); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/player.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1479 @@ +/* + player.c - functions for dealing with special player abilities + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <ctype.h> +#include <string.h> +#include <curses.h> +#include "rogue.h" + +/* + * affect: + * cleric affecting undead + */ + +affect() +{ + register struct linked_list *item; + register struct thing *tp; + register char *mname; + bool see; + coord new_pos; + int lvl; + + if (!(player.t_ctype == C_CLERIC || + (player.t_ctype == C_PALADIN && pstats.s_lvl > 4) || + cur_relic[HEIL_ANKH] != 0)) { + msg("You cannot affect undead."); + return; + } + + new_pos.y = hero.y + player.t_newpos.y; + new_pos.x = hero.x + player.t_newpos.x; + + if (cansee(new_pos.y, new_pos.x)) see = TRUE; + else see = FALSE; + + /* Anything there? */ + if (new_pos.y < 0 || new_pos.y > lines-3 || + new_pos.x < 0 || new_pos.x > cols-1 || + mvwinch(mw, new_pos.y, new_pos.x) == ' ') { + msg("Nothing to affect."); + return; + } + + if ((item = find_mons(new_pos.y, new_pos.x)) == 0) { + debug("Affect what @ %d,%d?", new_pos.y, new_pos.x); + return; + } + tp = THINGPTR(item); + mname = monster_name(tp); + + if (on(player, ISINVIS) && off(*tp, CANSEE)) { + msg("%s%s cannot see you", see ? "The " : "It", + see ? mname : ""); + return; + } + + if (off(*tp, TURNABLE) || on(*tp, WASTURNED)) + goto annoy; + turn_off(*tp, TURNABLE); + + lvl = pstats.s_lvl; + if (player.t_ctype == C_PALADIN && cur_relic[HEIL_ANKH] == 0) { + lvl -= 4; + } + /* Can cleric kill it? */ + if (lvl >= 3 * tp->t_stats.s_lvl) { + unsigned long test; /* For overflow check */ + + msg("You have destroyed %s%s.", see ? "the " : "it", see ? mname : ""); + test = pstats.s_exp + tp->t_stats.s_exp; + + /* Be sure there is no overflow before increasing experience */ + if (test > pstats.s_exp) pstats.s_exp = test; + killed(item, FALSE, TRUE, TRUE); + check_level(); + return; + } + + /* Can cleric turn it? */ + if (rnd(100) + 1 > + (100 * ((2 * tp->t_stats.s_lvl) - lvl)) / lvl) { + unsigned long test; /* Overflow test */ + + /* Make the monster flee */ + turn_on(*tp, WASTURNED); /* No more fleeing after this */ + turn_on(*tp, ISFLEE); + runto(tp, &hero); + + /* Disrupt it */ + dsrpt_monster(tp, TRUE, TRUE); + + /* Let player know */ + msg("You have turned %s%s.", see ? "the " : "it", see ? mname : ""); + + /* get points for turning monster -- but check overflow first */ + test = pstats.s_exp + tp->t_stats.s_exp/2; + if (test > pstats.s_exp) pstats.s_exp = test; + check_level(); + + /* If monster was suffocating, stop it */ + if (on(*tp, DIDSUFFOCATE)) { + turn_off(*tp, DIDSUFFOCATE); + extinguish(suffocate); + } + + /* If monster held us, stop it */ + if (on(*tp, DIDHOLD) && (--hold_count == 0)) + turn_off(player, ISHELD); + turn_off(*tp, DIDHOLD); + + /* It is okay to turn tail */ + tp->t_oldpos = tp->t_pos; + + return; + } + + /* Otherwise -- no go */ +annoy: + if (see && tp->t_stats.s_intel > 16) + msg("%s laughs at you...", prname(mname, TRUE)); + else + msg("You do not affect %s%s.", see ? "the " : "it", see ? mname : ""); + + /* Annoy monster */ + if (off(*tp, ISFLEE)) runto(tp, &hero); +} + +/* + * the cleric asks his deity for a spell + */ + +pray() +{ + register int num_prayers, prayer_ability, which_prayer; + + which_prayer = num_prayers = prayer_ability = 0; + + if (player.t_ctype != C_CLERIC && player.t_ctype != C_PALADIN && + cur_relic[HEIL_ANKH] == 0) { + msg("You are not permitted to pray."); + return; + } + if (cur_misc[WEAR_CLOAK] != NULL && + cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) { + msg("You can't seem to pray!"); + return; + } + + prayer_ability = pstats.s_lvl * pstats.s_wisdom - 5; + if (player.t_ctype != C_CLERIC) + prayer_ability /= 2; + + if (cur_relic[HEIL_ANKH]) prayer_ability += 75; + + if (player.t_action != C_PRAY) { + num_prayers = 0; + + /* Get the number of avilable prayers */ + if (pstats.s_wisdom > 16) + num_prayers += pstats.s_wisdom - 16; + + num_prayers += pstats.s_lvl; + if (cur_relic[HEIL_ANKH]) + num_prayers += pstats.s_wisdom - 18; + + if (player.t_ctype != C_CLERIC) + num_prayers /= 2; + + if (num_prayers > MAXPRAYERS) + num_prayers = MAXPRAYERS; + if (num_prayers < 1) { + msg("You are not permitted to pray yet."); + return; + } + + /* Prompt for prayer */ + if (pick_spell( cleric_spells, + prayer_ability, + num_prayers, + pray_time, + "offer", + "prayer")) + player.t_action = C_PRAY; + + return; + } + + /* We've waited our required praying time. */ + which_prayer = player.t_selection; + player.t_selection = 0; + player.t_action = A_NIL; + + if (cleric_spells[which_prayer].s_cost + pray_time > prayer_ability) { + msg("Your prayer fails."); + return; + } + + msg("Your prayer has been granted. "); + + if (cleric_spells[which_prayer].s_type == TYP_POTION) + quaff( cleric_spells[which_prayer].s_which, + NULL, + cleric_spells[which_prayer].s_flag, + FALSE); + else if (cleric_spells[which_prayer].s_type == TYP_SCROLL) + read_scroll( cleric_spells[which_prayer].s_which, + cleric_spells[which_prayer].s_flag, + FALSE); + else if (cleric_spells[which_prayer].s_type == TYP_STICK) { + if (!player_zap(cleric_spells[which_prayer].s_which, + cleric_spells[which_prayer].s_flag)) { + after = FALSE; + return; + } + } + pray_time += cleric_spells[which_prayer].s_cost; +} + +/* + * the magician is going to try and cast a spell + */ + +cast() +{ + register int spell_ability, which_spell, num_spells; + + if (player.t_ctype != C_MAGICIAN && player.t_ctype != C_RANGER) { + msg("You are not permitted to cast spells."); + return; + } + if (cur_misc[WEAR_CLOAK] != NULL && + cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) { + msg("You can't seem to cast spells!"); + return; + } + spell_ability = pstats.s_lvl * pstats.s_intel - 5; + if (player.t_ctype != C_MAGICIAN) + spell_ability /= 2; + + if (player.t_action != C_CAST) { + /* + * Get the number of avilable spells + */ + num_spells = 0; + if (pstats.s_intel > 16) + num_spells += pstats.s_intel - 16; + + num_spells += pstats.s_lvl; + if (player.t_ctype != C_MAGICIAN) + num_spells /= 2; + if (num_spells > MAXSPELLS) + num_spells = MAXSPELLS; + if (num_spells < 1) { + msg("You are not allowed to cast spells yet."); + return; + } + + /* prompt for spell */ + if (pick_spell( magic_spells, + spell_ability, + num_spells, + spell_power, + "cast", + "spell")) + player.t_action = C_CAST; + return; + } + + /* We've waited our required casting time. */ + which_spell = player.t_selection; + player.t_selection = 0; + player.t_action = A_NIL; + + if ((spell_power + magic_spells[which_spell].s_cost) > spell_ability) { + msg("Your attempt fails."); + return; + } + + msg("Your spell is successful. "); + + if (magic_spells[which_spell].s_type == TYP_POTION) + quaff( magic_spells[which_spell].s_which, + NULL, + magic_spells[which_spell].s_flag, + FALSE); + else if (magic_spells[which_spell].s_type == TYP_SCROLL) + read_scroll( magic_spells[which_spell].s_which, + magic_spells[which_spell].s_flag, + FALSE); + else if (magic_spells[which_spell].s_type == TYP_STICK) { + if (!player_zap(magic_spells[which_spell].s_which, + magic_spells[which_spell].s_flag)) { + after = FALSE; + return; + } + } + spell_power += magic_spells[which_spell].s_cost; +} + +/* + * the druid asks his deity for a spell + */ + +chant() +{ + register int num_chants, chant_ability, which_chant; + + which_chant = num_chants = chant_ability = 0; + + if (player.t_ctype != C_DRUID && player.t_ctype != C_MONK) { + msg("You are not permitted to chant."); + return; + } + if (cur_misc[WEAR_CLOAK] != NULL && + cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) { + msg("You can't seem to chant!"); + return; + } + chant_ability = pstats.s_lvl * pstats.s_wisdom - 5; + if (player.t_ctype != C_DRUID) + chant_ability /= 2; + + if (player.t_action != C_CHANT) { + num_chants = 0; + + /* Get the number of avilable chants */ + if (pstats.s_wisdom > 16) + num_chants += pstats.s_wisdom - 16; + + num_chants += pstats.s_lvl; + + if (player.t_ctype != C_DRUID) + num_chants /= 2; + + if (num_chants > MAXCHANTS) + num_chants = MAXCHANTS; + + if (num_chants < 1) { + msg("You are not permitted to chant yet."); + return; + } + + /* Prompt for chant */ + if (pick_spell( druid_spells, + chant_ability, + num_chants, + chant_time, + "sing", + "chant")) + player.t_action = C_CHANT; + + return; + } + + /* We've waited our required chanting time. */ + which_chant = player.t_selection; + player.t_selection = 0; + player.t_action = A_NIL; + + if (druid_spells[which_chant].s_cost + chant_time > chant_ability) { + msg("Your chant fails."); + return; + } + + msg("Your chant has been granted. "); + + if (druid_spells[which_chant].s_type == TYP_POTION) + quaff( druid_spells[which_chant].s_which, + NULL, + druid_spells[which_chant].s_flag, + FALSE); + else if (druid_spells[which_chant].s_type == TYP_SCROLL) + read_scroll( druid_spells[which_chant].s_which, + druid_spells[which_chant].s_flag, + FALSE); + else if (druid_spells[which_chant].s_type == TYP_STICK) { + if (!player_zap(druid_spells[which_chant].s_which, + druid_spells[which_chant].s_flag)) { + after = FALSE; + return; + } + } + chant_time += druid_spells[which_chant].s_cost; +} + +/* Constitution bonus */ + +const_bonus() /* Hit point adjustment for changing levels */ +{ + register int bonus; + if (pstats.s_const > 9 && pstats.s_const < 18) + bonus = 0; + else if (pstats.s_const >= 18 && pstats.s_const < 20) + bonus = 1; + else if (pstats.s_const >= 20 && pstats.s_const < 26) + bonus = 2; + else if (pstats.s_const >= 26 && pstats.s_const < 36) + bonus = 3; + else if (pstats.s_const >= 36) + bonus = 4; + else if (pstats.s_const > 7) + bonus = -1; + else + bonus = -2; + switch(player.t_ctype) { + case C_FIGHTER: bonus = min(bonus, 11); + when C_RANGER: bonus = min(bonus, 9); + when C_PALADIN: bonus = min(bonus, 9); + when C_MAGICIAN: bonus = min(bonus, 8); + when C_CLERIC: bonus = min(bonus, 8); + when C_THIEF: bonus = min(bonus, 10); + when C_ASSASSIN: bonus = min(bonus, 10); + when C_DRUID: bonus = min(bonus, 8); + when C_MONK: bonus = min(bonus, 9); + otherwise: bonus = min(bonus, 7); + } + return(bonus); +} + +/* + * Give away slime-molds to monsters. If monster is friendly, + * it will give you a "regular" food ration in return. You have + * to give a slime-mold to Alteran (a unique monster) in order to + * get the special "Card of Alteran" quest item. There's no other + * way to get this artifact and remain alive. + */ + +give(th) +register struct thing *th; +{ + /* + * Find any monster within one space of you + */ + struct linked_list *ll; + struct object *lb; + register int x,y; + register struct linked_list *mon = NULL; + bool gotone = FALSE; + + if (levtype != POSTLEV) { /* no monsters at trading post */ + for (x = hero.x-1; x <= hero.x+1; x++) { + for (y = hero.y-1; y <= hero.y+1; y++) { + if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1) + continue; + if (isalpha(mvwinch(mw, y, x))) { + if ((mon = find_mons(y, x)) != NULL) { + gotone = TRUE; /* found a monster to give away to */ + th = THINGPTR(mon); + } + } + } + } + } + if (gotone) { + if ((ll=get_item(pack, "give away", ALL, FALSE, FALSE)) != NULL) { + lb = OBJPTR(ll); + mpos = 0; + switch(lb->o_type) { + case FOOD: + switch (lb->o_which) { + case E_SLIMEMOLD: /* only slime-molds for now */ + if (on(*th, CANSELL)) { /* quartermaster */ + msg("%s laughs at you. "); + return; + } + if ((on(*th, ISFRIENDLY) || off(*th, ISMEAN)) && + off(*th, ISUNIQUE) && off(*th, CANSELL)) { + turn_on(*th, ISRUN); /* we want him awake */ + msg("%s accepts and promptly eats your gift of food. --More--", prname(monster_name(th), TRUE)); + wait_for(' '); + del_pack(ll); /* delete slime-mold */ + /* and add a food ration */ + create_obj(FALSE, FOOD, E_RATION); + msg("%s gives you food in return and nods off to sleep. ", prname(monster_name(th), TRUE)); + turn_off(*th, ISRUN); /* put him to sleep */ + return; + } + else if (on(*th, CARRYCARD) && on(*th, ISUNIQUE)) { + /* Now you get the Card of Alteran */ + msg("%s gives you a strange rectangular card. --More--", prname(monster_name(th), TRUE)); + wait_for(' '); + del_pack(ll); /* get rid of slime-mold */ + create_obj(FALSE, RELIC, ALTERAN_CARD); + msg("%s bids you farewell. ", prname(monster_name(th), TRUE)); + killed(mon, FALSE, FALSE, FALSE); + return; + } + else if (on(*th, ISUNIQUE) && off(*th, ISMEAN)) { + /* Dragons */ + msg("%s is set free by your generosity. ", prname(monster_name(th), TRUE)); + del_pack(ll); /* get rid of it */ + /* just let him roam around */ + turn_on(*th, ISRUN); + if (on(*th, ISFLEE)) turn_off(*th, ISFLEE); + runto(th, &player); + th->t_action = A_NIL; + return; + } + else if (on(*th, ISRUN) && off(*th, ISUNIQUE)) { + /* if NOT sleeping and not a unique */ + switch (rnd(2)) { + case 0: msg("%s ignores you. ", prname(monster_name(th), TRUE)); + when 1: { + msg("%s nips at your hand. ", prname(monster_name(th), TRUE)); + if (rnd(100) < 10) { + del_pack(ll); /* delete it */ + if (off(*th, ISMEAN)) { + msg("The slime-mold makes %s sleepy. ", prname(monster_name(th), TRUE)); + /* put him to sleep */ + turn_off(*th, ISRUN); + return; + } + else { + switch (rnd(2)) { + case 0: msg("%s's eyes roll back. ", prname(monster_name(th), TRUE)); + when 1: msg("%s becomes wanderlust. ", prname(monster_name(th), TRUE)); + } + /* just let him roam around */ + turn_on(*th, ISRUN); + if (on(*th, ISFLEE)) + turn_off(*th, ISFLEE); + runto(th, &player); + th->t_action = A_NIL; + return; + } + } + } + } + } + else { + msg("%s's mouth waters. ", prname(monster_name(th), TRUE)); + /* this wakes him up */ + if (off(*th, ISUNIQUE)) turn_on(*th, ISRUN); + return; + } + otherwise: + switch (rnd(3)) { /* mention food (hint hint) */ + case 0: msg("You cannot give away the %s! ", foods[lb->o_which].mi_name); + when 1: msg("The %s looks rancid! ", foods[lb->o_which].mi_name); + when 2: msg("You change your mind. "); + } + return; + } + otherwise: + switch (rnd(3)) { /* do not mention other items */ + case 0: msg("You feel foolish. "); + when 1: msg("You change your mind. "); + when 2: msg("%s ignores you. ", prname(monster_name(th), TRUE)); + } + + return; + } + } + } + else msg("Your efforts are futile. "); + return; +} + +/* + * Frighten a monster. Useful for the 'good' characters. + */ + +fright(th) +register struct thing *th; +{ + /* + * Find any monster within one space of you + */ + register int x,y; + register struct linked_list *mon; + bool gotone = FALSE; + + if (levtype != POSTLEV) { /* no monsters at trading post */ + for (x = hero.x-1; x <= hero.x+1; x++) { + for (y = hero.y-1; y <= hero.y+1; y++) { + if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1) + continue; + if (isalpha(mvwinch(mw, y, x))) { + if ((mon = find_mons(y, x)) != NULL) { + gotone = TRUE; /* found a monster to give away to */ + th = THINGPTR(mon); + } + } + } + } + } + if (gotone) { /* If 'good' character or is wearing a ring of fear */ + if (player.t_ctype == C_RANGER || player.t_ctype == C_PALADIN || + player.t_ctype == C_MONK || ISWEARING(R_FEAR) != 0) { + + player.t_action = A_NIL; + player.t_no_move = movement(&player); + switch (player.t_ctype) { + case C_FIGHTER: /* loss of strength */ + pstats.s_str--; + if (pstats.s_str < 3) pstats.s_str = 3; + when C_RANGER: /* loss of charisma */ + case C_PALADIN: + pstats.s_charisma--; + if (pstats.s_charisma < 3) pstats.s_charisma = 3; + when C_CLERIC: /* loss of wisdom */ + case C_DRUID: + pstats.s_wisdom--; + if (pstats.s_wisdom < 3) pstats.s_wisdom = 3; + when C_MAGICIAN: /* loss of wisdom intelligence */ + pstats.s_intel--; + if (pstats.s_intel < 3) pstats.s_intel = 3; + when C_THIEF: /* loss of dexterity */ + case C_ASSASSIN: + pstats.s_dext--; + if (pstats.s_dext < 3) pstats.s_dext = 3; + when C_MONK: /* loss of constitution */ + pstats.s_const--; + if (pstats.s_const < 3) pstats.s_const = 3; + otherwise: /* this msg can induce great fear */ + msg("You miss. "); + } + + /* Cause a panic. Good thru level 16. */ + if (level < 17) { + msg("You wave your arms and yell! "); + do_panic(th->t_index); + pstats.s_hpt -= (pstats.s_hpt/2)+1; + if (pstats.s_hpt < 25) msg("You heart quivers... "); + if (pstats.s_hpt < 1) { + msg("Your heart stops!! --More--"); + wait_for(' '); + pstats.s_hpt = -1; + death(D_FRIGHT); + } + return; + } + else { + /* He can't do it after level 16 */ + switch (rnd(20)) { + case 0: case 2: + msg("You stamp your foot!! "); + when 4: case 8: + msg("%s laughs at you! ",prname(monster_name(th),TRUE)); + when 10: case 12: + msg("You forget what you are doing? "); + otherwise: + msg(nothing); + } + return; + } + } + else { + switch (rnd(25)) { + case 0: case 2: case 4: + msg("You motion angrily! "); + when 6: case 8: case 10: + msg("You can't frighten anything. "); + when 12: case 14: case 16: + msg("Your puff up your face. "); + otherwise: + msg(nothing); + } + return; + } + } + else { + msg("There is nothing to fear but fear itself. "); + return; + } +} + +/* Routines for thieves */ + +/* + * gsense: Sense gold + */ + +gsense() +{ + /* Thief & assassin can do this, but fighter & ranger can later */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || + ((player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER) && + pstats.s_lvl >= 12)) { + read_scroll(S_GFIND, NULL, FALSE); + } + else msg("You seem to have no gold sense."); + return; +} + +/* + * xsense: Sense traps + */ + +xsense() +{ + /* Only thief can do this, but assassin, fighter, & monk can later */ + if (player.t_ctype == C_THIEF || ((player.t_ctype == C_ASSASSIN || + player.t_ctype == C_FIGHTER || player.t_ctype == C_MONK) && + pstats.s_lvl >= 14)) { + read_scroll(S_FINDTRAPS, NULL, FALSE); + } + else msg("You seem not to be able to sense traps."); + return; +} + +/* + * steal: + * Steal in direction given in delta + */ + +steal() +{ + register struct linked_list *item; + register struct thing *tp; + register char *mname; + coord new_pos; + int thief_bonus = -50; + bool isinvisible = FALSE; + + + /* let the fighter steal after level 15 */ + if (player.t_ctype == C_FIGHTER && pstats.s_lvl < 15) { + msg(nothing); + return; + } + else if (player.t_ctype != C_THIEF && + player.t_ctype != C_ASSASSIN && + player.t_ctype != C_FIGHTER) { + msg("Only thieves and assassins can steal."); + return; + } + if (on(player, ISBLIND)) { + msg("You can't see anything."); + return; + } + + new_pos.y = hero.y + player.t_newpos.y; + new_pos.x = hero.x + player.t_newpos.x; + + /* Anything there? */ + if (new_pos.y < 0 || new_pos.y > lines-3 || + new_pos.x < 0 || new_pos.x > cols-1 || + mvwinch(mw, new_pos.y, new_pos.x) == ' ') { + msg("Nothing to steal from."); + return; + } + + if ((item = find_mons(new_pos.y, new_pos.x)) == NULL) + debug("Steal from what @ %d,%d?", new_pos.y, new_pos.x); + tp = THINGPTR(item); + if (on(*tp, ISSTONE)) { + msg ("You can't steal from stone!"); + return; + } + + if (on(*tp, ISFLEE)) { + msg("You can't get your hand in anywhere! "); + return; + } + + isinvisible = invisible(tp); + if (isinvisible) mname = "creature"; + else mname = monster_name(tp); + + /* Can player steal something unnoticed? */ + if (player.t_ctype == C_THIEF) thief_bonus = 9; + if (player.t_ctype == C_ASSASSIN) thief_bonus = 6; + if (player.t_ctype == C_FIGHTER) thief_bonus = 3; + if (on(*tp, ISUNIQUE)) thief_bonus -= 15; + if (isinvisible) thief_bonus -= 20; + if (on(*tp, ISINWALL) && off(player, CANINWALL)) thief_bonus -= 50; + + if (on(*tp, ISHELD) || tp->t_action == A_FREEZE || + rnd(100) < + (thief_bonus + 2*dex_compute() + 5*pstats.s_lvl - + 5*(tp->t_stats.s_lvl - 3))) { + register struct linked_list *s_item, *pack_ptr; + int count = 0; + unsigned long test; /* Overflow check */ + + s_item = NULL; /* Start stolen goods out as nothing */ + + /* Find a good item to take */ + for (pack_ptr=tp->t_pack; pack_ptr != NULL; pack_ptr=next(pack_ptr)) + if ((OBJPTR(pack_ptr))->o_type != RELIC && + pack_ptr != tp->t_using && /* Monster can't be using it */ + rnd(++count) == 0) + s_item = pack_ptr; + + /* + * Find anything? + */ + if (s_item == NULL) { + msg("%s apparently has nothing to steal.", prname(mname, TRUE)); + return; + } + + /* Take it from monster */ + if (tp->t_pack) detach(tp->t_pack, s_item); + + /* Recalculate the monster's encumberance */ + updpack(TRUE, tp); + + /* Give it to player */ + if (add_pack(s_item, FALSE) == FALSE) { + (OBJPTR(s_item))->o_pos = hero; + fall(s_item, TRUE); + } + + /* Get points for stealing -- but first check for overflow */ + test = pstats.s_exp + tp->t_stats.s_exp/2; + if (test > pstats.s_exp) pstats.s_exp = test; + + /* + * Do adjustments if player went up a level + */ + check_level(); + } + + else { + msg("Your attempt fails."); + + /* Annoy monster (maybe) */ + if (rnd(40) >= dex_compute() + thief_bonus) { + /* + * If this is a charmed creature, there is a chance it + * will become uncharmed. + */ + if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) { + msg("The eyes of %s turn clear.", prname(mname, FALSE)); + turn_off(*tp, ISCHARMED); + } + if (on(*tp, CANSELL)) { + turn_off(*tp, CANSELL); + tp->t_action = A_NIL; + tp->t_movement = 0; + if (rnd(100) < 50) /* make him steal something */ + turn_on(*tp, STEALMAGIC); + else + turn_on(*tp, STEALGOLD); + if (!isinvisible) + msg("%s looks insulted.", prname(mname, TRUE)); + } + runto(tp, &hero); + } + } +} + +/* + * Take charmed monsters with you via up or down commands. + */ + +take_with() +{ + register struct thing *tp; + register struct linked_list *item; + struct linked_list *nitem; + register int t; + + t = 0; + for (item = mlist; item != NULL; item = nitem) { + nitem = next(item); + t++; + if (t > 5) break; + tp = THINGPTR(item); + if (on(*tp, ISCHARMED)) { + monsters[tp->t_index].m_normal = TRUE; + turn_on(*tp, ISELSEWHERE); + detach(mlist, item); + attach(tlist, item); /* remember him next level */ + check_residue(tp); + continue; + } + } +} + +/* + * this routine lets the player pick the spell that they + * want to cast regardless of character class + */ + +pick_spell(spells, ability, num_spells, power, prompt, type) +struct spells spells[]; /* spell list */ +int ability; /* spell ability */ +int num_spells; /* number of spells that can be cast */ +int power; /* spell power */ +const char *prompt; /* prompt for spell list */ +const char *type; /* type of thing--> spell, prayer, chant */ +{ + bool nohw = FALSE; + register int i; + int curlen, + maxlen = 0, + dummy = 0, + which_spell, + spell_left; + if (cur_misc[WEAR_CLOAK] != NULL && + cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) { + msg("You can't seem to start a %s!", type); + return(FALSE); + } + + /* Prompt for spells */ + msg("Which %s are you %sing? (* for list): ", type, prompt); + + which_spell = (int) (wgetch(cw) - 'a'); + msg(""); /* Get rid of the prompt */ + if (which_spell == (int) ESC - (int) 'a') { + after = FALSE; + return(FALSE); + } + if (which_spell >= 0 && which_spell < num_spells) nohw = TRUE; + + else if (slow_invent) { + register char c; + + nohw = TRUE; + do { + for (i=0; i<num_spells; i++) { + msg(""); + mvwaddch(msgw, 0, 0, '['); + waddch(msgw, (char) ((int) 'a' + i)); + wprintw(msgw, "] A %s of ", type); + if (spells[i].s_type == TYP_POTION) + waddstr(msgw, p_magic[spells[i].s_which].mi_name); + else if (spells[i].s_type == TYP_SCROLL) + waddstr(msgw, s_magic[spells[i].s_which].mi_name); + else if (spells[i].s_type == TYP_STICK) + waddstr(msgw, ws_magic[spells[i].s_which].mi_name); + waddstr(msgw, morestr); + wclrtobot(msgw); + clearok(msgw, FALSE); + draw(msgw); + do { + c = wgetch(cw); + } while (c != ' ' && c != ESC); + if (c == ESC) + break; + } + msg(""); + wmove(msgw, 0, 0); + wprintw(msgw, "Which %s are you %sing? ", type, prompt); + clearok(msgw, FALSE); + draw(msgw); + + which_spell = (int) (wgetch(cw) - 'a'); + } while (which_spell != (int) (ESC - 'a') && + (which_spell < 0 || which_spell >= num_spells)); + + if (which_spell == (int) (ESC - 'a')) { + mpos = 0; + msg(""); + after = FALSE; + return(FALSE); + } + } + else { + /* Now display the possible spells */ + wclear(hw); + touchwin(hw); + wmove(hw, 2, 0); + wprintw(hw, " Cost %c%s", toupper(*type),type+1); + mvwaddstr(hw, 3, 0, + "-----------------------------------------------"); + maxlen = 47; /* Maximum width of header */ + + for (i=0; i<num_spells; i++) { + sprintf(prbuf, "[%c] %3d A %s of ", + (char) ((int) 'a' + i), spells[i].s_cost, type); + if (spells[i].s_type == TYP_POTION) + strcat(prbuf, p_magic[spells[i].s_which].mi_name); + else if (spells[i].s_type == TYP_SCROLL) + strcat(prbuf, s_magic[spells[i].s_which].mi_name); + else if (spells[i].s_type == TYP_STICK) + strcat(prbuf, ws_magic[spells[i].s_which].mi_name); + mvwaddstr(hw, i+4, 0, prbuf); + + /* Get the length of the line */ + getyx(hw, dummy, curlen); + if (maxlen < curlen) maxlen = curlen; + } + + spell_left = ability - power; + if (spell_left < 0) { + spell_left = 0; + if (spell_left < -20) power = ability + 20; + } + sprintf(prbuf, "[Current %s power = %d]", type, spell_left); + + mvwaddstr(hw, 0, 0, prbuf); + wprintw(hw, " Which %s are you %sing? ", type, prompt); + getyx(hw, dummy, curlen); + if (maxlen < curlen) maxlen = curlen; + + /* Should we overlay? */ + if (menu_overlay && num_spells + 3 < lines - 3) { + over_win(cw, hw, num_spells + 5, maxlen + 3, 0, curlen, NULL); + } + else draw(hw); + } + + if (!nohw) { + which_spell = (int) (wgetch(cw) - 'a'); + while (which_spell < 0 || which_spell >= num_spells) { + if (which_spell == (int) ESC - (int) 'a') { + after = FALSE; + + /* Restore the screen */ + if (num_spells + 3 < lines / 2) { + clearok(cw, FALSE); + touchwin(cw); + } + else restscr(cw); + return(FALSE); + } + wmove(hw, 0, 0); + wclrtoeol(hw); + wprintw(hw, "Please enter one of the listed %ss. ", type); + getyx(hw, dummy, curlen); + if (maxlen < curlen) maxlen = curlen; + + /* Should we overlay? */ + if (menu_overlay && num_spells + 3 < lines - 3) { + over_win(cw, hw, num_spells + 5, maxlen + 3, + 0, curlen, NULL); + } + else draw(hw); + + which_spell = (int) (wgetch(cw) - 'a'); + } + } + + /* Now restore the screen if we have to */ + if (!nohw) { + if (num_spells + 3 < lines / 2) { + touchwin(cw); + clearok(cw, FALSE); + } + else { + restscr(cw); + } + } + + if (spells[which_spell].s_type == TYP_STICK && + need_dir(STICK, spells[which_spell].s_which)) { + if (!get_dir(&player.t_newpos)) { + after = FALSE; + return(FALSE); + } + } + player.t_selection = which_spell; + player.t_no_move = (which_spell/3 + 1) * movement(&player); + + spell_left = dummy; /* hack to stop IRIX complaint about dummy */ + /* not being used. */ + return(TRUE); +} + +/* + * opt_player: + * Let the player know what's happening with himself + */ + +opt_player() +{ + int i = 1; /* initialize counters */ + int j = 2; + + wclear(hw); + wmove(hw, 0, 0); + wprintw(hw, "Current player effects:"); + wmove(hw, 2, 0); + + /* Print a list of what is happening. + * If longer than 16 lines, make it two columns. + * Currently, a maximum of 32 (out of 39) "effects" + * can be happening all at once to a player. + */ + + /* 1 - Sense gold */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || + ((player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER) && + pstats.s_lvl >= 12)) { + wprintw(hw, "You can sense gold\n"); + i++; + } + /* 2 - Sense traps */ + if (player.t_ctype == C_THIEF || ((player.t_ctype == C_ASSASSIN || + player.t_ctype == C_FIGHTER || player.t_ctype == C_MONK) && + pstats.s_lvl >= 14)) { + wprintw(hw, "You can sense traps\n"); + i++; + } + /* 3 - Steal */ + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || + (player.t_ctype == C_FIGHTER && pstats.s_lvl >= 15)) { + wprintw(hw, "You can steal\n"); + i++; + } + /* 4 - Cast spells */ + if (player.t_ctype == C_MAGICIAN || + (player.t_ctype == C_RANGER && pstats.s_lvl > 1)) { + wprintw(hw, "You can cast spells\n"); + i++; + } + /* 5 - Make chants */ + if (player.t_ctype == C_DRUID || + (player.t_ctype == C_MONK && pstats.s_lvl > 1)) { + wprintw(hw, "You can chant\n"); + i++; + } + /* 6 - Give prayers */ + if (cur_relic[HEIL_ANKH] != 0 || player.t_ctype == C_CLERIC || + (player.t_ctype == C_PALADIN && pstats.s_lvl > 1)) { + wprintw(hw, "You can pray\n"); + i++; + } + /* 7 - Affect the undead */ + if (cur_relic[HEIL_ANKH] != 0 || player.t_ctype == C_CLERIC || + (player.t_ctype == C_PALADIN && pstats.s_lvl > 4)) { + wprintw(hw, "You can affect the undead\n"); + i++; + } + /* 8 - Cause fear */ + if (ISWEARING(R_FEAR) != 0 || ((player.t_ctype == C_RANGER || + player.t_ctype == C_PALADIN || player.t_ctype == C_MONK) && + pstats.s_lvl > 1)) { + wprintw(hw, "You are fearful\n"); + i++; + } + /* 9 - Confuse monster */ + if (on(player, CANHUH) != 0) { + wprintw(hw, "You have multi-colored hands\n"); + i++; + } + /* 10 - Confused yourself */ + if (on(player, ISHUH) != 0) { + wprintw(hw, "You are confused\n"); + i++; + } /* really ISHUH or ISCLEAR */ + /* 11 - Clear thought */ + if (on(player, ISCLEAR) != 0) { + wprintw(hw, "You are clear headed\n"); + i++; + } + /* 12 - Slow */ + if (on(player, ISSLOW) != 0) { + wprintw(hw, "You are moving slow\n"); + i++; + } /* really ISSLOW or ISHASTE */ + /* 13 - Haste */ + if (on(player, ISHASTE) != 0) { + wprintw(hw, "You are moving fast\n"); + i++; + } + /* 14 - Flying */ + if (on(player, ISFLY) != 0) { + wprintw(hw, "You are flying\n"); + i++; + } + /* 15 - Blind */ + if (on(player, ISBLIND) != 0) { + wprintw(hw, "You are blind\n"); + i++; + } /* really ISBLIND or CANSEE */ + /* 16 - Extra sight */ + if (on(player, CANSEE) != 0) { + wprintw(hw, "You have extra sight\n"); + i++; + } + /* 17 - Invisibility */ + if (on(player, ISINVIS) != 0) { + /* Okay, start a second column of effects to the screen. */ + if (i > 16) { + mvwaddstr(hw, j, 37, "You are invisible"); + j++; + } + else { + wprintw(hw, "You are invisible\n"); + i++; + } + } + /* 18 - Regeneration and vampiric regen */ + if (ISWEARING(R_VAMPREGEN) != 0 || ISWEARING(R_REGEN) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You have regenerative powers"); + j++; + } + else { + wprintw(hw, "You have regenerative powers\n"); + i++; + } + } + /* 19 - Phasing */ + if (on(player, CANINWALL) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You can walk through walls"); + j++; + } + else { + wprintw(hw, "You can walk through walls\n"); + i++; + } + } + /* 20 - Skill (good or bad, it won't last) */ + if (find_slot(unskill) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You feel skillful"); + j++; + } + else { + wprintw(hw, "You feel skillful\n"); + i++; + } + } + /* 21 - Stealthy */ + if (ISWEARING(R_STEALTH) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You have stealth"); + j++; + } + else { + wprintw(hw, "You have stealth\n"); + i++; + } + } + /* 22 - Alertness */ + if (ISWEARING(R_ALERT) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are awake and alert"); + j++; + } + else { + wprintw(hw, "You are awake and alert\n"); + i++; + } + } + /* 23 - Free action */ + if (ISWEARING(R_FREEDOM) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You feel free"); + j++; + } + else { + wprintw(hw, "You feel free\n"); + i++; + } + } + /* 24 - Heroism */ + if (ISWEARING(R_HEROISM) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are brave"); + j++; + } + else { + wprintw(hw, "You are brave\n"); + i++; + } + } + /* 25 - Ice protection */ + if (on(player, NOCOLD) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from ice"); + j++; + } + else { + wprintw(hw, "You are protected from ice\n"); + i++; + } + } + /* 26 - Fire protection */ + if (on(player, NOFIRE) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from fire"); + j++; + } + else { + wprintw(hw, "You are protected from fire\n"); + i++; + } + } + /* 27 - Lightning protection */ + if (on(player, NOBOLT) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from lightning"); + j++; + } + else { + wprintw(hw, "You are protected from lightning\n"); + i++; + } + } + /* 28 - Gas protection */ + if (on(player, NOGAS) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from gas"); + j++; + } + else { + wprintw(hw, "You are protected from gas\n"); + i++; + } + } + /* 29 - Acid protection */ + if (on(player, NOACID) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from acid"); + j++; + } + else { + wprintw(hw, "You are protected from acid\n"); + i++; + } + } + /* 30 - Breath protection */ + if (cur_relic[YENDOR_AMULET] != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from monster breath"); + j++; + } + else { + wprintw(hw, "You are protected from monster breath\n"); + i++; + } /* really only YENDOR or STONEBONES */ + } + /* 31 - Magic missile protection */ + if (cur_relic[STONEBONES_AMULET] != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are protected from magic missiles"); + j++; + } + else { + wprintw(hw, "You are protected from magic missiles\n"); + i++; + } + } + /* 32 - Sustain health */ + if (ISWEARING(R_HEALTH) != 0 && (off(player, HASDISEASE) && + off(player, HASINFEST) && off(player, DOROT))) { + if (i > 16) { /* he's really healthy */ + mvwaddstr(hw, j, 37, "You are in good health"); + j++; + } + else { + wprintw(hw, "You are in good health\n"); + i++; + } + } + /* 33 - Being held */ + if (on(player, ISHELD) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are being held"); + j++; + } + else { + wprintw(hw, "You are being held\n"); + i++; + } + } + /* 34 - Stinks */ + if (on(player, HASSTINK) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are affronted by a bad smell"); + j++; + } + else { + wprintw(hw, "You are affronted by a bad smell\n"); + i++; + } + } + /* 35 - Any attribute that is down */ + if (pstats.s_intel < max_stats.s_intel || + pstats.s_str < max_stats.s_str || + pstats.s_wisdom < max_stats.s_wisdom || + pstats.s_dext < max_stats.s_dext || + pstats.s_const < max_stats.s_const || + pstats.s_charisma < max_stats.s_charisma) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are afflicted"); + j++; + } + else { + wprintw(hw, "You are afflicted\n"); + i++; + } + } + /* 36 - Diseased */ + if (on(player, HASDISEASE) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You have a disease"); + j++; + } + else { + wprintw(hw, "You have a disease\n"); + i++; + } + } + /* 37 - Infested */ + if (on(player, HASINFEST) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You have an infestation"); + j++; + } + else { + wprintw(hw, "You have an infestation\n"); + i++; + } + } + /* 38 - Body rot */ + if (on(player, DOROT) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You have body rot"); + j++; + } + else { + wprintw(hw, "You have body rot\n"); + i++; + } + } + /* 39 - Dancing */ + if (on(player, ISDANCE) != 0) { + if (i > 16) { + mvwaddstr(hw, j, 37, "You are a dancing fool"); + j++; + } + else { + wprintw(hw, "You are a dancing fool\n"); + i++; + } + } + if (i == 1) { + wclear(hw); + msg("No player effects. "); + return; + } + else { + if (i > 1 && i < 17) { + j = 39; + if (menu_overlay) { /* Print the list. */ + wmove(hw, i+2, 0); + wprintw(hw, spacemsg); + over_win(cw, hw, i+3, j, i+2, 27, NULL); + } + else { + wmove(hw, i+2, 0); + wprintw(hw, spacemsg); + draw(hw); + } + } + else { + i = 17; + if (menu_overlay) { /* Print the list. */ + wmove(hw, i+2, 0); + wprintw(hw, spacemsg); + if (j > 2) j = 78; + else j = 39; + over_win(cw, hw, i+3, j, i+2, 27, NULL); + } + else { + wmove(hw, i+2, 0); + wprintw(hw, spacemsg); + draw(hw); + } + } + wait_for(' '); + wclear(hw); + status(FALSE); + touchwin(cw); + return; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/potions.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1059 @@ +/* + potions.c - Functions for dealing with potions + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <stdlib.h> +#include <curses.h> +#include "rogue.h" + +/* + * add_abil is an array of functions used to change attributes. It must be + * ordered according to the attribute definitions in rogue.h. + */ + +int (*add_abil[NUMABILITIES])() = { + add_intelligence, add_strength, add_wisdom, add_dexterity, + add_constitution, add_charisma +}; + +/* + * res_abil is an array of functions used to change attributes. It must be + * ordered according to the attribute definitions in rogue.h. + */ + +int (*res_abil[NUMABILITIES])() = { + res_intelligence, res_strength, res_wisdom, res_dexterity, + res_constitution, res_charisma +}; + +/* + * Increase player's constitution + */ + +int +add_constitution(change) +int change; +{ + /* Do the potion */ + if (change < 0) { + msg("You feel less healthy now."); + pstats.s_const += change; + if (pstats.s_const < 1) { + pstats.s_hpt = -1; + msg("You collapse! --More--"); + wait_for(' '); + death(D_CONSTITUTION); + } + } + else { + msg("You feel healthier now."); + pstats.s_const = min(pstats.s_const + change, MAXATT); + } + + /* Adjust the maximum */ + if (max_stats.s_const < pstats.s_const) + max_stats.s_const = pstats.s_const; + + return(0); +} + +/* + * Increase player's charisma + */ + +int +add_charisma(change) +int change; +{ + /* Do the potion */ + if (change < 0) msg("You feel less attractive now."); + else msg("You feel more attractive now."); + + pstats.s_charisma += change; + if (pstats.s_charisma > MAXATT) pstats.s_charisma = MAXATT; + else if (pstats.s_charisma < 3) pstats.s_charisma = 3; + + /* Adjust the maximum */ + if (max_stats.s_charisma < pstats.s_charisma) + max_stats.s_charisma = pstats.s_charisma; + + return(0); +} + +/* + * Increase player's dexterity + */ + +int +add_dexterity(change) +int change; +{ + int ring_str; /* Value of ring strengths */ + + /* Undo any ring changes */ + ring_str = ring_value(R_ADDHIT); + pstats.s_dext -= ring_str; + + /* Now do the potion */ + if (change < 0) msg("You feel less dextrous now."); + else msg("You feel more dextrous now. Watch those hands!"); + + pstats.s_dext += change; + if (pstats.s_dext > MAXATT) pstats.s_dext = MAXATT; + else if (pstats.s_dext < 3) pstats.s_dext = 3; + + /* Adjust the maximum */ + if (max_stats.s_dext < pstats.s_dext) + max_stats.s_dext = pstats.s_dext; + + /* Now put back the ring changes */ + if (ring_str) + pstats.s_dext += ring_str; + + return(0); +} + +/* + * add_haste: + * add a haste to the player + */ + +add_haste(blessed) +bool blessed; +{ + int hasttime; + + if (player.t_ctype == C_MONK) { /* monks cannot be slowed or hasted */ + msg(nothing); + return; + } + + if (blessed) hasttime = HASTETIME*2; + else hasttime = HASTETIME; + + if (on(player, ISSLOW)) { /* Is person slow? */ + extinguish(noslow); + noslow(); + + if (blessed) hasttime = HASTETIME/2; + else return; + } + + if (on(player, ISHASTE)) { + msg("You faint from exhaustion."); + player.t_no_move += movement(&player) * rnd(hasttime); + player.t_action = A_FREEZE; + lengthen(nohaste, roll(hasttime,hasttime)); + } + else { + msg("You feel yourself moving %sfaster.", blessed ? "much " : ""); + turn_on(player, ISHASTE); + fuse(nohaste, (VOID *)NULL, roll(hasttime, hasttime), AFTER); + } +} + +/* + * Increase player's intelligence + */ + +int +add_intelligence(change) +int change; +{ + int ring_str; /* Value of ring strengths */ + + /* Undo any ring changes */ + ring_str = ring_value(R_ADDINTEL); + pstats.s_intel -= ring_str; + + /* Now do the potion */ + if (change < 0) msg("You feel slightly less intelligent now."); + else msg("You feel more intelligent now. What a mind!"); + + pstats.s_intel += change; + if (pstats.s_intel > MAXATT) pstats.s_intel = MAXATT; + else if (pstats.s_intel < 3) pstats.s_intel = 3; + + /* Adjust the maximum */ + if (max_stats.s_intel < pstats.s_intel) + max_stats.s_intel = pstats.s_intel; + + /* Now put back the ring changes */ + if (ring_str) + pstats.s_intel += ring_str; + + return(0); +} + +/* + * this routine makes the hero move slower + */ + +add_slow() +{ + /* monks cannot be slowed or hasted */ + if (player.t_ctype == C_MONK || ISWEARING(R_FREEDOM)) { + msg(nothing); + return; + } + + if (on(player, ISHASTE)) { /* Already sped up */ + extinguish(nohaste); + nohaste(); + } + else { + msg("You feel yourself moving %sslower.", + on(player, ISSLOW) ? "even " : ""); + if (on(player, ISSLOW)) + lengthen(noslow, roll(HASTETIME,HASTETIME)); + else { + turn_on(player, ISSLOW); + fuse(noslow, (VOID *)NULL, roll(HASTETIME,HASTETIME), AFTER); + } + } +} + +/* + * Increase player's strength + */ + +int +add_strength(change) +int change; +{ + + if (change < 0) { + msg("You feel slightly weaker now."); + chg_str(change); + } + else { + msg("You feel stronger now. What bulging muscles!"); + chg_str(change); + } + return(0); +} + +/* + * Increase player's wisdom + */ + +int +add_wisdom(change) +int change; +{ + int ring_str; /* Value of ring strengths */ + + /* Undo any ring changes */ + ring_str = ring_value(R_ADDWISDOM); + pstats.s_wisdom -= ring_str; + + /* Now do the potion */ + if (change < 0) msg("You feel slightly less wise now."); + else msg("You feel wiser now. What a sage!"); + + pstats.s_wisdom += change; + if (pstats.s_wisdom > MAXATT) pstats.s_wisdom = MAXATT; + else if (pstats.s_wisdom < 3) pstats.s_wisdom = 3; + + /* Adjust the maximum */ + if (max_stats.s_wisdom < pstats.s_wisdom) + max_stats.s_wisdom = pstats.s_wisdom; + + /* Now put back the ring changes */ + if (ring_str) + pstats.s_wisdom += ring_str; + + return(0); +} + +quaff(which, kind, flags, is_potion) +int which; +int kind; +int flags; +bool is_potion; +{ + register struct object *obj; + register struct linked_list *item, *titem; + register struct thing *th; + bool cursed, blessed; + + blessed = FALSE; + cursed = FALSE; + item = NULL; + + if (which < 0) { /* figure out which ourselves */ + /* This is a potion. */ + if (player.t_action != C_QUAFF) { + int units; + + item = get_item(pack, "quaff", QUAFFABLE, FALSE, FALSE); + + /* + * Make certain that it is somethings that we want to drink + */ + if (item == NULL) + return; + + /* How long does it take to quaff? */ + units = usage_time(item); + if (units < 0) return; + + player.t_using = item; /* Remember what it is */ + player.t_no_move = units * movement(&player); + if ((OBJPTR(item))->o_type == POTION) player.t_action = C_QUAFF; + else player.t_action = C_USE; + return; + } + + /* We have waited our time, let's quaff the potion */ + item = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + obj = OBJPTR(item); + /* remove it from the pack */ + inpack--; + detach(pack, item); + + flags = obj->o_flags; + which = obj->o_which; + kind = obj->o_kind; + } + cursed = flags & ISCURSED; + blessed = flags & ISBLESSED; + + switch(which) { + case P_CLEAR: + if (cursed) { + confus_player(); + } + else { + if (blessed) { /* Make player immune for the whole game */ + extinguish(unclrhead); /* If we have a fuse, put it out */ + msg("A strong blue aura surrounds your head."); + } + else { /* Just light a fuse for how long player is safe */ + if (off(player, ISCLEAR)) { + fuse(unclrhead, (VOID *)NULL, CLRDURATION, AFTER); + msg("A faint blue aura surrounds your head."); + } + else { /* If we have a fuse lengthen it, else we + * are permanently clear. + */ + if (find_slot(unclrhead) == 0) + msg("Your blue aura continues to glow strongly."); + else { + lengthen(unclrhead, CLRDURATION); + msg("Your blue aura brightens for a moment."); + } + } + } + turn_on(player, ISCLEAR); + /* If player is confused, unconfuse him */ + if (on(player, ISHUH)) { + extinguish(unconfuse); + unconfuse(); + } + } + when P_HEALING: + if (cursed) { + msg("You feel worse now."); + pstats.s_hpt -= roll(pstats.s_lvl, char_class[player.t_ctype].hit_pts); + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + msg("You're life passes before your eyes.. --More--"); + wait_for(' '); + death(D_POTION); + } + } + else { + if (blessed) { + pstats.s_hpt += roll(pstats.s_lvl+1, char_class[player.t_ctype].hit_pts); + if (pstats.s_hpt > max_stats.s_hpt) { + pstats.s_hpt = ++max_stats.s_hpt; + pstats.s_hpt = ++max_stats.s_hpt; + } + if (on(player, ISHUH)) { + extinguish(unconfuse); + unconfuse(); + } + } + else { + pstats.s_hpt += roll(pstats.s_lvl+1, char_class[player.t_ctype].hit_pts/2); + if (pstats.s_hpt > max_stats.s_hpt) + pstats.s_hpt = ++max_stats.s_hpt; + } + msg("You begin to feel %sbetter.", + blessed ? "much " : ""); + sight(); + if (is_potion) p_know[P_HEALING] = TRUE; + } + when P_ABIL: + /* If it is cursed, we take a point away */ + if (cursed) { + if (ISWEARING(R_SUSABILITY)) { + msg(nothing); + break; + } + else (*add_abil[kind])(-1); + } + + /* Otherwise we add points */ + else (*add_abil[kind])(blessed ? 3 : 1); + + if (is_potion) p_know[P_ABIL] = TRUE; + when P_MFIND: + /* + * Potion of monster detection, if there are monters, detect them + */ + if (mlist != NULL) + { + register struct thing *tp; + register struct linked_list *item; + + wclear(hw); + for (item=mlist; item!=NULL; item=next(item)) { + tp = THINGPTR(item); + if (on(*tp, NODETECT)) + continue; + if (off(*tp, ISRUN))/* turn off only on sleeping ones */ + turn_off(*tp, CANSURPRISE); + mvwaddch(hw, tp->t_pos.y, tp->t_pos.x, + monsters[tp->t_index].m_appear); + } + rmmsg(); + overlay(hw,cw); + draw(cw); + msg("You begin to sense the presence of monsters."); + if (is_potion) p_know[P_MFIND] = TRUE; + } + else + msg("You have a strange feeling for a moment, then it passes."); + when P_TFIND: + /* + * Potion of magic detection. Show the potions and scrolls + */ + { + register struct linked_list *mobj; + register struct object *tp; + bool show; + + show = FALSE; + wclear(hw); + for (mobj = lvl_obj; mobj != NULL; mobj = next(mobj)) { + tp = OBJPTR(mobj); + if (is_magic(tp)) { + char mag_type=MAGIC; + + /* Mark cursed items or bad weapons */ + if ((tp->o_flags & ISCURSED) || + (tp->o_type == WEAPON && + (tp->o_hplus < 0 || tp->o_dplus < 0))) + mag_type = CMAGIC; + else if ((tp->o_flags & ISBLESSED) || + (tp->o_type == WEAPON && + (tp->o_hplus > 0 || tp->o_dplus > 0))) + mag_type = BMAGIC; + show = TRUE; + mvwaddch(hw, tp->o_pos.y, tp->o_pos.x, mag_type); + } + } + for (titem = mlist; titem != NULL; titem = next(titem)) { + register struct linked_list *pitem; + + th = THINGPTR(titem); + if (on(*th, NODETECT)) continue; + for(pitem = th->t_pack; pitem != NULL; pitem = next(pitem)){ + tp = OBJPTR(pitem); + if (is_magic(tp)) { + char mag_type=MAGIC; + + /* Mark cursed items or bad weapons */ + if ((tp->o_flags & ISCURSED) || + (tp->o_type == WEAPON && + (tp->o_hplus < 0 || tp->o_dplus < 0))) + mag_type = CMAGIC; + else if ((tp->o_flags & ISBLESSED) || + (tp->o_type == WEAPON && + (tp->o_hplus > 0 || tp->o_dplus > 0))) + mag_type = BMAGIC; + show = TRUE; + mvwaddch(hw, th->t_pos.y, th->t_pos.x, mag_type); + } + } + } + if (show) { + if (is_potion) p_know[P_TFIND] = TRUE; + rmmsg(); + overlay(hw,cw); + draw(cw); + msg("You sense the presence of magic on this level."); + break; + } + else + msg("You have a strange feeling for a moment, then it passes."); + } + when P_SEEINVIS: + if (cursed) { + if (!find_slot(sight)) + { + msg("A cloak of darkness falls around you."); + turn_on(player, ISBLIND); + fuse(sight, (VOID *)NULL, SEEDURATION, AFTER); + light(&hero); + } + else + msg("The darkness around you thickens. "); + lengthen(sight, SEEDURATION); + } + else { + if (off(player, CANSEE)) { + turn_on(player, CANSEE); + msg("Your eyes begin to tingle."); + fuse(unsee, (VOID *)NULL, blessed ? SEEDURATION*3 :SEEDURATION, AFTER); + light(&hero); + } + else if (find_slot(unsee) != 0) { + msg("You eyes continue to tingle."); + lengthen(unsee, blessed ? SEEDURATION*3 : SEEDURATION); + } + sight(); + } + when P_PHASE: + if (cursed) { + msg("You can't move."); + player.t_no_move = movement(&player) * FREEZETIME; + player.t_action = A_FREEZE; + } + else { + int duration; + + if (blessed) duration = 3; + else duration = 1; + + if (on(player, CANINWALL)) + lengthen(unphase, duration*PHASEDURATION); + else { + fuse(unphase, (VOID *)NULL, duration*PHASEDURATION, AFTER); + turn_on(player, CANINWALL); + } + msg("You feel %slight-headed!", + blessed ? "very " : ""); + } + when P_FLY: { + int duration; + bool say_message; + + say_message = TRUE; + + if (blessed) duration = 3; + else duration = 1; + + if (on(player, ISFLY)) { + if (find_slot(land)) + lengthen(land, duration*FLYTIME); + else { + msg("Nothing happens."); /* Flying by cloak */ + say_message = FALSE; + } + } + else { + fuse(land, (VOID *)NULL, duration*FLYTIME, AFTER); + turn_on(player, ISFLY); + } + if (say_message) { + if (is_potion) p_know[P_FLY] = TRUE; + msg("You feel %slighter than air!", blessed ? "much " : ""); + } + } + when P_RAISE: + if (cursed) lower_level(D_POTION); + else { + msg("You suddenly feel %smore skillful", + blessed ? "much " : ""); + p_know[P_RAISE] = TRUE; + raise_level(); + do_panic(NULL); /* this startles them */ + if (blessed) raise_level(); + } + when P_HASTE: + if (cursed) { /* Slow player down */ + add_slow(); + } + else { + add_haste(blessed); + if (is_potion) p_know[P_HASTE] = TRUE; + } + when P_RESTORE: { + register int i, howmuch, strength_tally; + + msg("Hey, this tastes great. It make you feel %swarm all over.", + blessed ? "really " : ""); + howmuch = blessed ? 3 : 1; + + for (i=0; i<NUMABILITIES; i++) { + if (i == A_STRENGTH) { + if (lost_str) { + if (lost_str > howmuch) { + lost_str -= howmuch; + + /* + * Save the lost strength. We have to set + * temporarilty set it to 0 so that res_strength + * will not restore it. + */ + strength_tally = lost_str; + lost_str = 0; + res_strength(howmuch); + lost_str = strength_tally; + } + else { + lost_str = 0; + extinguish(res_strength); + res_strength(howmuch); + } + } + else res_strength(howmuch); + } + else (*res_abil[i])(howmuch); + } + } + when P_INVIS: + if (off(player, ISINVIS)) { + turn_on(player, ISINVIS); + msg("You have a tingling feeling all over your body"); + fuse(appear, (VOID *)NULL, blessed ? GONETIME*3 : GONETIME, AFTER); + PLAYER = IPLAYER; + light(&hero); + } + else { + if (find_slot(appear)) { + msg("Your tingling feeling surges."); + lengthen(appear, blessed ? GONETIME*3 : GONETIME); + } + else msg("Nothing happens."); /* Using cloak */ + } + + when P_FFIND: + { + register struct linked_list *nitem; + register struct object *nobj; + bool show; + + show = FALSE; + wclear(hw); + for (nitem = lvl_obj; nitem != NULL; nitem = next(nitem)) { + nobj = OBJPTR(nitem); + if (nobj->o_type == FOOD) { + show = TRUE; + mvwaddch(hw, nobj->o_pos.y, nobj->o_pos.x, FOOD); + } + } + for (nitem = mlist; nitem != NULL; nitem = next(nitem)) { + register struct linked_list *pitem; + register struct thing *th; + + th = THINGPTR(nitem); + if (on(*th, NODETECT)) continue; + for(pitem = th->t_pack; pitem != NULL; pitem = next(pitem)){ + nobj = OBJPTR(pitem); + if (nobj->o_type == FOOD) { + show = TRUE; + mvwaddch(hw, th->t_pos.y, th->t_pos.x, FOOD); + } + } + } + if (is_potion) p_know[P_FFIND] = TRUE; + if (show) { + rmmsg(); + msg("Your nose tingles."); + rmmsg(); + overlay(hw,cw); + draw(cw); + msg("You sense the presence of food on this level."); + } + else + msg("You have a strange feeling for a moment, then it passes."); + } + + when P_SKILL: + if (cursed) { + msg("You feel less skillful."); + + /* Does he currently have an artifical skill? */ + if (!find_slot(unskill)) { /* No skill */ + pstats.s_lvladj = -2; + pstats.s_lvl += pstats.s_lvladj; + fuse(unskill, (VOID *)NULL, SKILLDURATION, AFTER); + } + else { /* Has an artifical skill */ + /* Is the skill beneficial? */ + if (pstats.s_lvladj > 0) { + /* Decrease the previous skill advantage */ + pstats.s_lvl -= 2; + pstats.s_lvladj -= 2; + + /* If there is now a negative skill, lengthen time */ + if (pstats.s_lvladj < 0) + lengthen(unskill, SKILLDURATION); + + /* If there is no skill advantage, unfuse us */ + else if (pstats.s_lvladj == 0) extinguish(unskill); + } + else { /* Already bad */ + /* Make it a little worse, and lengthen it */ + pstats.s_lvl--; + pstats.s_lvladj--; + lengthen(unskill, SKILLDURATION); + } + } + + /* Is our level too low now? */ + if (pstats.s_lvl < 1) { + pstats.s_hpt = -1; + msg("You cough, choke, and finally die. --More--"); + wait_for(' '); + death(D_POTION); + } + } + else { + int adjust; + + msg("You feel more skillful."); + max_stats.s_hpt++; + pstats.s_hpt++; + + /* Get the adjustment */ + if (blessed) + adjust = rnd(4) + 2; + else + adjust = rnd(2) + 1; + + /* The Fighter likes this */ + if (player.t_ctype == C_FIGHTER) { + max_stats.s_hpt++; + pstats.s_hpt++; + adjust = rnd(2) + 1; + } + + /* Does he currently have an artifical skill? */ + if (!find_slot(unskill)) { + pstats.s_lvladj = adjust; + pstats.s_lvl += pstats.s_lvladj; + fuse(unskill, (VOID *)NULL, + blessed ? SKILLDURATION*2 : SKILLDURATION, AFTER); + } + else { /* Has an artifical skill */ + /* Is the skill detrimental? */ + if (pstats.s_lvladj < 0) { + /* Decrease the previous skill advantage */ + pstats.s_lvl += adjust; + pstats.s_lvladj += adjust; + + /* If there is now a positive skill, lengthen time */ + if (pstats.s_lvladj < 0) + lengthen(unskill, SKILLDURATION); + + /* If there is no skill advantage, unfuse us */ + else if (pstats.s_lvladj == 0) extinguish(unskill); + } + else { /* Already good */ + /* + * Make the skill the maximum of the current good + * skill and what the adjust would give him. + */ + pstats.s_lvl -= pstats.s_lvladj; + pstats.s_lvladj = max(pstats.s_lvladj, adjust); + pstats.s_lvl += pstats.s_lvladj; + lengthen(unskill, + blessed ? SKILLDURATION*2 : SKILLDURATION); + } + } + } + + when P_FIRE: { + int duration; + bool say_message; + + say_message = TRUE; + + if (blessed) duration = 8; + else duration = 3; + + if (on(player, NOFIRE)) { + if (cursed) { + msg("You quench your thirst. "); + say_message = FALSE; + } + else if (find_slot(nofire)) { + lengthen(nofire, duration*FIRETIME); + msg("Your feeling of fire resistance increases. "); + say_message = FALSE; + } + else { + msg("You experience heat waves. "); /* has on a ring */ + say_message = FALSE; + } + } + else if (cursed) { + msg("You quench your thirst. "); + say_message = FALSE; + } + else { + fuse(nofire, (VOID *)NULL, duration*FIRETIME, AFTER); + turn_on(player, NOFIRE); + } + if (say_message) { + if (is_potion) p_know[P_FIRE] = TRUE; + msg("You feel %sfire resistant", blessed ? "very " : ""); + } + } + when P_COLD: { + int duration; + bool say_message; + + say_message = TRUE; + + if (blessed) duration = 8; + else duration = 3; + + if (on(player, NOCOLD)) { + if (cursed) { + msg("You quench your thirst. "); + say_message = FALSE; + } + else if (find_slot(nocold)) { + lengthen(nocold, duration*COLDTIME); + msg("Your feeling of cold resistance increases. "); + say_message = FALSE; + } + else { + msg("You feel a cold chill. "); /* has on a ring */ + say_message = FALSE; + } + } + else if (cursed) { + msg("You quench your thirst. "); + say_message = FALSE; + } + else { + fuse(nocold, (VOID *)NULL, duration*COLDTIME, AFTER); + turn_on(player, NOCOLD); + } + if (say_message) { + if (is_potion) p_know[P_COLD] = TRUE; + msg("You feel %scold resistant", blessed ? "very " : ""); + } + } + when P_LIGHTNING: { + int duration; + bool say_message; + + say_message = TRUE; + + if (blessed) duration = 8; + else duration = 3; + + if (on(player, NOBOLT)) { + if (cursed) { + msg("You quench your thirst. "); + say_message = FALSE; + } + else if (find_slot(nobolt)) { + lengthen(nobolt, duration*BOLTTIME); + msg("Your blue skin deepens in hue. "); + say_message = FALSE; + } + else msg(nothing); + } + else if (cursed) { + msg("You quench your thirst. "); + say_message = FALSE; + } + else { + fuse(nobolt, (VOID *)NULL, duration*BOLTTIME, AFTER); + turn_on(player, NOBOLT); + } + if (say_message) { + if (is_potion) p_know[P_LIGHTNING] = TRUE; + msg("Your skin turns %sblue!", blessed ? "very " : ""); + } + } + when P_POISON: + if (!save(VS_POISON, &player, -2)) { + msg("You feel very sick now."); + pstats.s_hpt /= 2; + if (!ISWEARING(R_SUSABILITY)) + pstats.s_const--; + } + else { + msg("You feel sick now."); + pstats.s_hpt -= (pstats.s_hpt / 3); + } + if (pstats.s_const < 1 || pstats.s_hpt < 1) { + pstats.s_hpt = -1; + msg("You didn't survive! --More--"); + wait_for(' '); + death(D_POISON); + } + otherwise: + msg("What an odd tasting potion!"); + return; + } + status(FALSE); + if (is_potion && item && p_know[which] && p_guess[which]) + { + free(p_guess[which]); + p_guess[which] = NULL; + } + else if (is_potion && + !p_know[which] && + item && + askme && + (flags & ISKNOW) == 0 && + (flags & ISPOST) == 0 && + p_guess[which] == NULL) { + nameitem(item, FALSE); + } + if (item != NULL) o_discard(item); + updpack(TRUE, &player); +} + + +/* + * res_dexterity: + * Restore player's dexterity + * if called with zero the restore fully + */ + +int +res_dexterity(howmuch) +int howmuch; +{ + short save_max; + int ring_str; + + if (howmuch < 0) return(0); + + /* Discount the ring value */ + ring_str = ring_value(R_ADDHIT); + pstats.s_dext -= ring_str; + + if (pstats.s_dext < max_stats.s_dext ) { + if (howmuch == 0) + pstats.s_dext = max_stats.s_dext; + else + pstats.s_dext = min(pstats.s_dext+howmuch, max_stats.s_dext); + } + + /* Redo the rings */ + if (ring_str) { + save_max = max_stats.s_dext; + pstats.s_dext += ring_str; + max_stats.s_dext = save_max; + } + return(0); +} + +/* + * res_intelligence: + * Restore player's intelligence + */ + +int +res_intelligence(howmuch) +int howmuch; +{ + short save_max; + int ring_str; + + if (howmuch <= 0) return(0); + + /* Discount the ring value */ + ring_str = ring_value(R_ADDINTEL); + pstats.s_intel -= ring_str; + + pstats.s_intel = min(pstats.s_intel + howmuch, max_stats.s_intel); + + /* Redo the rings */ + if (ring_str) { + save_max = max_stats.s_intel; + pstats.s_intel += ring_str; + max_stats.s_intel = save_max; + } + return(0); +} + +/* + * res_wisdom: + * Restore player's wisdom + */ + +int +res_wisdom(howmuch) +int howmuch; +{ + short save_max; + int ring_str; + + if (howmuch <= 0) return(0); + + /* Discount the ring value */ + ring_str = ring_value(R_ADDWISDOM); + pstats.s_wisdom -= ring_str; + + pstats.s_wisdom = min(pstats.s_wisdom + howmuch, max_stats.s_wisdom); + + /* Redo the rings */ + if (ring_str) { + save_max = max_stats.s_wisdom; + pstats.s_wisdom += ring_str; + max_stats.s_wisdom = save_max; + } + return(0); +} + +/* + * res_constitution: + * Restore the players constitution. + */ + +int +res_constitution(howmuch) +int howmuch; +{ + if (howmuch > 0) + pstats.s_const = min(pstats.s_const + howmuch, max_stats.s_const); + + return(0); +} + +/* + * res_charisma: + * Restore the players charisma. + */ + +int +res_charisma(howmuch) +int howmuch; +{ + if (howmuch > 0) + pstats.s_charisma = + min(pstats.s_charisma + howmuch, max_stats.s_charisma); + + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/rings.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,175 @@ +/* + rings.c - Routines dealing specificaly with rings + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <stdlib.h> +#include <string.h> +#include <curses.h> +#include "rogue.h" + +/* + * routines dealing specifically with rings + */ + +/* + * how much food does this ring use up? + */ + +ring_eat(hand) +register int hand; +{ + if (cur_ring[hand] == NULL) + return 0; + switch (cur_ring[hand]->o_which) { + case R_VAMPREGEN: + return 3; + case R_REGEN: + case R_SUSABILITY: + return 2; + case R_HEALTH: + return 1; + case R_SEARCH: + case R_SEEINVIS: + return (rnd(100) < 50); /* 0 or 1 */ + case R_DIGEST: + if (cur_ring[hand]->o_ac >= 0) + return (-(cur_ring[hand]->o_ac)-1); + else + return (-(cur_ring[hand]->o_ac)); + } + return 0; +} + +ring_on(item) +register struct linked_list *item; +{ + register struct object *obj; + register int save_max; + + obj = OBJPTR(item); + + /* + * Calculate the effect it has on the poor guy. + */ + switch (obj->o_which) + { + case R_ADDSTR: + save_max = max_stats.s_str; + chg_str(obj->o_ac); + max_stats.s_str = save_max; + when R_ADDHIT: + pstats.s_dext += obj->o_ac; + when R_ADDINTEL: + pstats.s_intel += obj->o_ac; + when R_ADDWISDOM: + pstats.s_wisdom += obj->o_ac; + when R_SEEINVIS: + if (on(player, CANSEE)) msg("Your eyes sparkle."); + else msg("Your eyes begin to tingle."); + turn_on(player, CANSEE); + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + when R_AGGR: + aggravate(TRUE, TRUE); /* all charactors are affected*/ + when R_WARMTH: + if (on(player, NOCOLD)) msg("You feel warm all over."); + else msg("You begin to feel warm."); + turn_on(player, NOCOLD); + when R_FIRE: + if (on(player, NOFIRE)) msg("You feel quite fire proof now."); + else msg("You begin to feel fire proof."); + turn_on(player, NOFIRE); + when R_LIGHT: { + if(roomin(&hero) != NULL) { + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + } + } + when R_SEARCH: + daemon(ring_search, (VOID *)NULL, AFTER); + when R_TELEPORT: + daemon(ring_teleport, (VOID *)NULL, AFTER); + } + status(FALSE); + if (r_know[obj->o_which] && r_guess[obj->o_which]) { + free(r_guess[obj->o_which]); + r_guess[obj->o_which] = NULL; + } + else if (!r_know[obj->o_which] && + askme && + (obj->o_flags & ISKNOW) == 0 && + r_guess[obj->o_which] == NULL) { + nameitem(item, FALSE); + } +} + +/* + * print ring bonuses + */ + +char * +ring_num(obj) +register struct object *obj; +{ + static char buf[5]; + + if (!(obj->o_flags & ISKNOW)) + return ""; + switch (obj->o_which) + { + case R_PROTECT: + case R_ADDSTR: + case R_ADDDAM: + case R_ADDHIT: + case R_ADDINTEL: + case R_ADDWISDOM: + case R_DIGEST: + buf[0] = ' '; + strcpy(&buf[1], num(obj->o_ac, 0)); + when R_AGGR: + case R_LIGHT: + case R_CARRY: + case R_TELEPORT: + if (obj->o_flags & ISCURSED) + return " cursed"; + else + return ""; + otherwise: + return ""; + } + return buf; +} + +/* + * Return the effect of the specified ring + */ + +ring_value(type) +{ + int result = 0; + + if (ISRING(LEFT_1, type)) result += cur_ring[LEFT_1]->o_ac; + if (ISRING(LEFT_2, type)) result += cur_ring[LEFT_2]->o_ac; + if (ISRING(LEFT_3, type)) result += cur_ring[LEFT_3]->o_ac; + if (ISRING(LEFT_4, type)) result += cur_ring[LEFT_4]->o_ac; + if (ISRING(RIGHT_1, type)) result += cur_ring[RIGHT_1]->o_ac; + if (ISRING(RIGHT_2, type)) result += cur_ring[RIGHT_2]->o_ac; + if (ISRING(RIGHT_3, type)) result += cur_ring[RIGHT_3]->o_ac; + if (ISRING(RIGHT_4, type)) result += cur_ring[RIGHT_4]->o_ac; + return(result); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/rip.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,816 @@ +/* + rip.c - File for the fun ends Death or a total win + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#define REALLIFE 1 /* Print out machine and logname */ +#define EDITSCORE 2 /* Edit the current score file */ +#define ADDSCORE 3 /* Add a new score */ + +#define LOGFILE "xrogue.log" + +#include <curses.h> +#include <time.h> +#include <signal.h> +#include <ctype.h> +#include <string.h> +#include <sys/types.h> +#include <fcntl.h> +#include "mach_dep.h" +#include "network.h" +#include "rogue.h" + +/* Network machines (for mutual score keeping) */ +struct network Network[] = { + { "", "" }, +}; + +static char *rip[] = { +" ___________", +" / \\", +" / \\", +" / R. I. P. \\", +" / \\", +" / \\", +" | |", +" | |", +" | killed by |", +" | |", +" | |", +" | |", +" *| * * * |*", +" _________)|//\\\\///\\///\\//\\//\\/|(_________", +NULL +}; + +char *killname(); + +/*UNUSED*/ +void +byebye(sig) +int sig; +{ + NOOP(sig); + exit_game(EXIT_ENDWIN); +} + + +/* + * death: + * Do something really fun when he dies + */ + +death(monst) +register short monst; +{ + register char **dp = rip, *killer; + register struct tm *lt; + time_t date; + char buf[LINELEN]; + struct tm *localtime(); + + writelog(pstats.s_exp, KILLED, monst); + time(&date); + lt = localtime(&date); + clear(); + move(8, 0); + while (*dp) + printw("%s\n", *dp++); + mvaddstr(14, 28-((strlen(whoami)+1)/2), whoami); + sprintf(buf, "%lu Points", pstats.s_exp ); + mvaddstr(15, 28-((strlen(buf)+1)/2), buf); + killer = killname(monst); + mvaddstr(17, 28-((strlen(killer)+1)/2), killer); + mvaddstr(18, 25, (sprintf(prbuf, "%4d", 1900+lt->tm_year), prbuf)); + move(lines-1, 0); + refresh(); + score(pstats.s_exp, KILLED, monst); + exit_game(EXIT_ENDWIN); +} + +char * +killname(monst) +register short monst; +{ + static char mons_name[LINELEN/2]; + int i; + + if (monst > NUMMONST) return("a strange monster"); + + if (monst >= 0) { + switch (monsters[monst].m_name[0]) { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + sprintf(mons_name, "an %s", monsters[monst].m_name); + break; + default: + sprintf(mons_name, "a %s", monsters[monst].m_name); + } + return(mons_name); + } + for (i = 0; i< DEATHNUM; i++) { + if (deaths[i].reason == monst) + break; + } + if (i >= DEATHNUM) + return ("strange death"); + return (deaths[i].name); +} + +/* Writes an entry in the log file */ + +void +writelog(unsigned long amount, int flags, short monst) +{ + FILE *logwriter; + char had_quest = '0'; + char fate[LINELEN]; + struct linked_list *item; + struct object *obj; +#ifdef LOGFILE + if (waswizard) + return; + /* Adjustments to the score */ + if (level == 0 && max_level == 0) + amount = 0; + if (flags == CHICKEN) + amount /= 100; + /* Check for quest item */ + for (item = pack; item != NULL; item = next(item)) { + obj = OBJPTR(item); + if (obj->o_type == RELIC && obj->o_which == quest_item) + had_quest = '1'; + } + /* Describe what happened */ + if (flags == KILLED) { + snprintf(fate, LINELEN, "killed by %s", killname(monst)); + } + else if (flags == CHICKEN) { + strcpy(fate, "quit"); + } + else if (flags == WINNER) { + strcpy(fate, "escaped"); + } + else + return; + /* Open and write */ + logwriter = fopen(LOGFILE, "a"); + if (logwriter == NULL) + return; + fprintf(logwriter, "%d %d %s %d %s %d %d %d %c %s\n", time(NULL), amount, + whoami, pstats.s_lvl, char_class[char_type].name, level, max_level, + quest_item, had_quest, fate); + fclose(logwriter); +#endif + return; +} + +/* + * score -- figure score and post it. + */ + +/* VARARGS2 */ +score(amount, flags, monst) +unsigned long amount; +int flags; +short monst; +{ + struct sc_ent top_ten[NUMSCORE]; + register struct sc_ent *scp; + register int i; + register struct sc_ent *sc2; + register FILE *outf; + register char *killer; + register int prflags = 0; + short upquest=0, wintype=0, uplevel=0, uptype=0; /* For network updating */ + char upsystem[SYSLEN], uplogin[LOGLEN]; + char *thissys; /* Holds the name of this system */ + +#define REASONLEN 3 + static char *reason[] = { + "killed", + "quit", + "A total winner", + "somehow left", + }; + char *packend; + + memset(top_ten,0,sizeof(top_ten)); + + signal(SIGINT, byebye); + if (level == 0 && max_level == 0) + amount = 0; /*don't count if quit early */ + if (flags != WINNER && flags != SCOREIT && flags != UPDATE) { + if (flags == CHICKEN) { + packend = "when you quit"; + amount = amount / 100; + } + else + packend = "at your untimely demise"; + mvaddstr(lines - 1, 0, retstr); + refresh(); + getstr(prbuf); + showpack(packend); + } + purse = 0; /* Steal all the gold */ + + /* + * Open file and read list + */ + + if ((outf = fopen(score_file, "rb+")) == NULL) + { + if ((outf = fopen(score_file, "wb+")) == NULL) + { + mvprintw(lines - 1, 0, "Unable to open or create score file: %s",score_file); + refresh(); + return; + } + } + + thissys = md_gethostname(); + + /* + * If this is a SCOREIT optin (rogue -s), don't call byebye. The + * endwin() calls in byebye() will and this results in a core dump. + */ + if (flags == SCOREIT) signal(SIGINT, SIG_DFL); + else signal(SIGINT, byebye); + + if (flags != SCOREIT && flags != UPDATE) + { + mvaddstr(lines - 1, 0, retstr); + refresh(); + fflush(stdout); + getstr(prbuf); + } + + /* Check for special options */ + if (strcmp(prbuf, "names") == 0) + prflags = REALLIFE; + else if (wizard) { + if (strcmp(prbuf, "edit") == 0) prflags = EDITSCORE; + else if (strcmp(prbuf, "add") == 0) { + prflags = ADDSCORE; + waswizard = FALSE; /* We want the new score recorded */ + } + } + + /* Read the score and convert it to a compatible format */ + + fseek(outf, 0, SEEK_SET); + rs_read_scorefile(outf, top_ten, NUMSCORE); + + /* Get some values if this is an update */ + if (flags == UPDATE) { + int errcheck, errors = 0; + + upquest = (short) netread(&errcheck, sizeof(short), stdin); + if (errcheck) errors++; + + if (fread(whoami, 1, NAMELEN, stdin) != NAMELEN) errors++; + + wintype = (short) netread(&errcheck, sizeof(short), stdin); + if (errcheck) errors++; + + uplevel = (short) netread(&errcheck, sizeof(short), stdin); + if (errcheck) errors++; + + uptype = (short) netread(&errcheck, sizeof(short), stdin); + if (errcheck) errors++; + + if (fread(upsystem, 1, SYSLEN, stdin) != SYSLEN) + errors++; + if (fread(uplogin, 1, LOGLEN, stdin) != LOGLEN) + errors++; + + if (errors) { + fclose(outf); + return; + } + } + + /* + * Insert player in list if need be + */ + if (!waswizard) { + char *login= NULL; + + if (flags != UPDATE) { + login = md_getusername(); + + if ((login == NULL) || (*login == 0)) + login = "another rogue fiend"; + } + + if (flags == UPDATE) + (void) update(top_ten, amount, upquest, whoami, wintype, + uplevel, monst, uptype, upsystem, uplogin); + else { + if (prflags == ADDSCORE) { /* Overlay characteristic by new ones */ + char buffer[LINELEN]; + + clear(); + mvaddstr(1, 0, "Score: "); + mvaddstr(2, 0, "Quest (number): "); + mvaddstr(3, 0, "Name: "); + mvaddstr(4, 0, "System: "); + mvaddstr(5, 0, "Login: "); + mvaddstr(6, 0, "Level: "); + mvaddstr(7, 0, "Char type: "); + mvaddstr(8, 0, "Result: "); + + /* Get the score */ + move(1, 7); + get_str(buffer, stdscr); + amount = atol(buffer); + + /* Get the character's quest -- must be a number */ + move(2, 16); + get_str(buffer, stdscr); + quest_item = atoi(buffer); + + /* Get the character's name */ + move(3, 6); + get_str(buffer, stdscr); + strncpy(whoami, buffer, NAMELEN); + + /* Get the system */ + move(4, 8); + get_str(buffer, stdscr); + strncpy(thissys, buffer, SYSLEN); + + /* Get the login */ + move(5, 7); + get_str(buffer, stdscr); + strncpy(login, buffer, LOGLEN); + + /* Get the level */ + move(6, 7); + get_str(buffer, stdscr); + level = max_level = (short) atoi(buffer); + + /* Get the character type */ + move(7, 11); + get_str(buffer, stdscr); + for (i=0; i<NUM_CHARTYPES; i++) { + if (EQSTR(buffer, char_class[i].name, strlen(buffer))) + break; + } + player.t_ctype = i; + + /* Get the win type */ + move(8, 8); + get_str(buffer, stdscr); + switch (buffer[0]) { + case 'W': + case 'w': + case 'T': + case 't': + flags = WINNER; + break; + + case 'Q': + case 'q': + flags = CHICKEN; + break; + + case 'k': + case 'K': + default: + flags = KILLED; + break; + } + + /* Get the monster if player was killed */ + if (flags == KILLED) { + mvaddstr(9, 0, "Death type: "); + get_str(buffer, stdscr); + if (buffer[0] == 'M' || buffer[0] == 'm') + do { + monst = makemonster(TRUE, "choose"); + } while (monst < 0); /* Force a choice */ + else monst = getdeath(); + } + } + + if (update(top_ten, amount, (short) quest_item, whoami, flags, + (flags == WINNER) ? (short) max_level : (short) level, + monst, player.t_ctype, thissys, login) + ) { + /* Send this update to the other systems in the network */ + int i, j; + char cmd[256]; /* Command for remote execution */ + FILE *rmf, *popen(); /* For input to remote command */ + + for (i=0; Network[i].system[0] != 0; i++) + if (Network[i].system[0] != '!' && + strcmp(Network[i].system, thissys)) { + sprintf(cmd, NETCOMMAND, + Network[i].system, Network[i].rogue); + + /* Execute the command */ + if ((rmf=popen(cmd, "w")) != NULL) { + unsigned long temp; /* Temporary value */ + + /* Write out the parameters */ + (void) netwrite((unsigned long) amount, + sizeof(unsigned long), rmf); + + (void) netwrite((unsigned long) monst, + sizeof(short), rmf); + + (void) netwrite((unsigned long) quest_item, + sizeof(short), rmf); + + (void) fwrite(whoami, 1, strlen(whoami), rmf); + for (j=strlen(whoami); j<NAMELEN; j++) + putc('\0', rmf); + + (void) netwrite((unsigned long) flags, + sizeof(short), rmf); + + temp = (unsigned long) + (flags==WINNER ? max_level : level); + (void) netwrite(temp, sizeof(short), rmf); + + (void) netwrite((unsigned long) player.t_ctype, + sizeof(short), rmf); + + (void) fwrite(thissys, 1, + strlen(thissys), rmf); + for (j=strlen(thissys); j<SYSLEN; j++) + putc('\0', rmf); + + (void) fwrite(login, 1, strlen(login), rmf); + for (j=strlen(login); j<LOGLEN; j++) + putc('\0', rmf); + + /* Close off the command */ + (void) pclose(rmf); + } + } + } + } + } + + /* + * SCOREIT -- rogue -s option. Never started curses if this option. + * UPDATE -- network scoring update. Never started curses if this option. + * EDITSCORE -- want to delete or change a score. + */ +/* if (flags != SCOREIT && flags != UPDATE && prflags != EDITSCORE) + endwin(); */ + + if (flags != UPDATE) { + if (flags != SCOREIT) { + clear(); + refresh(); + endwin(); + } + /* + * Print the list + */ + printf("\nTop %d Adventurers:\nRank Score\tName\n", + NUMSCORE); + for (scp = top_ten; scp < &top_ten[NUMSCORE]; scp++) { + char *class; + + if (scp->sc_score != 0) { + class = char_class[scp->sc_ctype].name; + + /* Make sure we have an in-bound reason */ + if (scp->sc_flags > REASONLEN) scp->sc_flags = REASONLEN; + + printf("%3d %10lu\t%s (%s)", scp - top_ten + 1, + scp->sc_score, scp->sc_name, class); + + if (prflags == REALLIFE) printf(" [in real life %.*s!%.*s]", + SYSLEN, scp->sc_system, LOGLEN, scp->sc_login); + + printf(":\n\t\t%s on level %d", reason[scp->sc_flags], + scp->sc_level); + + switch (scp->sc_flags) { + case KILLED: + printf(" by"); + killer = killname(scp->sc_monster); + printf(" %s", killer); + break; + + case WINNER: + printf(" with the %s", + rel_magic[scp->sc_quest].mi_name); + break; + } + + if (prflags == EDITSCORE) + { + fflush(stdout); + getstr(prbuf); + printf("\n"); + if (prbuf[0] == 'd') { + for (sc2 = scp; sc2 < &top_ten[NUMSCORE-1]; sc2++) + *sc2 = *(sc2 + 1); + top_ten[NUMSCORE-1].sc_score = 0; + for (i = 0; i < NAMELEN; i++) + top_ten[NUMSCORE-1].sc_name[i] = rnd(255); + top_ten[NUMSCORE-1].sc_flags = RN; + top_ten[NUMSCORE-1].sc_level = RN; + top_ten[NUMSCORE-1].sc_monster = RN; + scp--; + } + else if (prbuf[0] == 'e') { + printf("Death type: "); + getstr(prbuf); + if (prbuf[0] == 'M' || prbuf[0] == 'm') + do { + scp->sc_monster = + makemonster(TRUE, "choose"); + } while (scp->sc_monster < 0); /* Force a choice */ + else scp->sc_monster = getdeath(); + clear(); + refresh(); + } + } + else printf("\n"); + } + } +/* if (prflags == EDITSCORE) endwin();*/ /* End editing windowing */ + } + fseek(outf, 0L, SEEK_SET); + + if (flags != SCOREIT) + rs_write_scorefile(outf,top_ten,NUMSCORE); + fclose(outf); +} + +/* + * showpack: + * Display the contents of the hero's pack + */ + +showpack(howso) +char *howso; +{ + reg char *iname; + reg int cnt, packnum; + reg struct linked_list *item; + reg struct object *obj; + + idenpack(); + cnt = 1; + clear(); + mvprintw(0, 0, "Contents of your pack %s:\n",howso); + packnum = 'a'; + for (item = pack; item != NULL; item = next(item)) { + obj = OBJPTR(item); + iname = inv_name(obj, FALSE); + mvprintw(cnt, 0, "%c) %s\n",packnum++,iname); + if (++cnt >= lines - 2 && + next(item) != NULL) { + cnt = 1; + mvaddstr(lines - 1, 0, morestr); + refresh(); + wait_for(' '); + clear(); + } + } + mvprintw(cnt + 1,0,"--- %ld Gold Pieces ---",purse); + refresh(); +} + +total_winner() +{ + register struct linked_list *item; + register struct object *obj; + register long worth; + register char c; + register long oldpurse; + + clear(); + standout(); + addstr(" \n"); + addstr(" @ @ @ @ @ @@@ @ @ \n"); + addstr(" @ @ @@ @@ @ @ @ @ \n"); + addstr(" @ @ @@@ @ @ @ @ @ @@@ @@@@ @@@ @ @@@ @ \n"); + addstr(" @@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ \n"); + addstr(" @ @ @ @ @ @ @ @@@@ @ @ @@@@@ @ @ @ \n"); + addstr(" @ @ @ @ @ @@ @ @ @ @ @ @ @ @ @ @ \n"); + addstr(" @@@ @@@ @@ @ @ @ @@@@ @@@@ @@@ @@@ @@ @ \n"); + addstr(" \n"); + addstr(" Congratulations, you have made it to the light of day! \n"); + standend(); + addstr("\nYou have joined the elite ranks of those who have escaped the\n"); + addstr("Dungeons of Doom alive. You journey home and sell all your loot at\n"); + addstr("a great profit and are appointed "); + switch (player.t_ctype) { + case C_FIGHTER: addstr("Leader of the Fighter's Guild.\n"); + when C_RANGER: addstr("King of the Northern Land.\n"); + when C_PALADIN: addstr("King of the Southern Land.\n"); + when C_MAGICIAN:addstr("High Wizard of the Sorcerer's Guild.\n"); + when C_CLERIC: addstr("Bishop of the Monastery.\n"); + when C_THIEF: addstr("Leader of the Thief's Guild.\n"); + when C_MONK: addstr("Master of the Temple.\n"); + when C_ASSASSIN: addstr("Leader of the Assassin's Guild.\n"); + when C_DRUID: addstr("High Priest of the Monastery.\n"); + otherwise: addstr("Town Drunk in the Tavern.\n"); + } + mvaddstr(lines - 1, 0, spacemsg); + refresh(); + wait_for(' '); + clear(); + mvaddstr(0, 0, " Worth Item"); + oldpurse = purse; + for (c = 'a', item = pack; item != NULL; c++, item = next(item)) + { + obj = OBJPTR(item); + worth = get_worth(obj); + if (obj->o_group == 0) + worth *= obj->o_count; + whatis(item); + mvprintw(c-'a'+1, 0, "%c) %6ld %s", c, worth, inv_name(obj, FALSE)); + purse += worth; + } + mvprintw(c - 'a' + 1, 0," %5ld Gold Pieces ", oldpurse); + refresh(); + writelog(pstats.s_exp + (long) purse, WINNER, '\0'); + score(pstats.s_exp + (long) purse, WINNER, '\0'); + exit_game(EXIT_ENDWIN); +} + + +void +delete_score(top_ten, idx) +struct sc_ent top_ten[NUMSCORE]; +int idx; +{ + for(;idx < NUMSCORE-1;idx++) + top_ten[idx] = top_ten[idx+1]; + + top_ten[NUMSCORE-1].sc_score = 0L; +} + +int +insert_score(top_ten, sc) +struct sc_ent top_ten[NUMSCORE]; +struct sc_ent *sc; +{ + int i,j; + + if (top_ten[NUMSCORE-1].sc_score > 0) + return(-1); /* no room */ + + for(i = 0; i < NUMSCORE; i++) { + if (sc->sc_score > top_ten[i].sc_score) { + for(j = NUMSCORE-1; j > i; j--) + top_ten[j] = top_ten[j-1]; + top_ten[i] = *sc; + return(i); + } + } + + return(-1); +} + +/* PCS = player-class-system (used to determines uniqueness of player) */ + +int +is_pcs_match(sc1,sc2) +struct sc_ent *sc1; +struct sc_ent *sc2; +{ + return( (strcmp(sc1->sc_name,sc2->sc_name) == 0) && + (sc1->sc_ctype == sc2->sc_ctype) && + (strcmp(sc1->sc_system, sc2->sc_system)==0) ); +} + +int +count_pcs_matches(top_ten,sc,lowest) +struct sc_ent top_ten[NUMSCORE]; +struct sc_ent *sc; +int *lowest; +{ + int i, matches = 0; + + *lowest = -1; + + for(i = 0; i < NUMSCORE; i++) { + if (is_pcs_match(sc,&top_ten[i])) { + matches++; + *lowest = i; + } + } + return(matches); +} + +int +find_most_pcs_matches(top_ten,sc,num,idx) +struct sc_ent top_ten[NUMSCORE]; +struct sc_ent *sc; +int *num, *idx; +{ + int i, matches, max_match=0, max_match_idx=-1, lowest; + + for(i = NUMSCORE-1; i > 0; i--) { + matches = count_pcs_matches(top_ten,&top_ten[i],&lowest); + + if (matches > max_match) { + max_match = matches; + max_match_idx = lowest; + } + } + + matches = count_pcs_matches(top_ten,sc,&lowest) + 1; + + if (matches > max_match) { + *num = matches; + *idx = lowest; + } + else { + *num = max_match; + *idx = max_match_idx; + } + + return(0); +} + + +int +add_score(top_ten,sc) +struct sc_ent top_ten[NUMSCORE]; +struct sc_ent *sc; +{ + int idx, count; + + if (insert_score(top_ten,sc) == -1) { + /* Simple insert if space available in table */ + + find_most_pcs_matches(top_ten,sc,&count,&idx); + + /* EVERY ENTRY UNIQUE, */ + /* INSERT IF SCORE > LOWEST MATCH SCORE */ + if (count == 1) { + if (sc->sc_score > top_ten[idx].sc_score) { + delete_score(top_ten,idx); + insert_score(top_ten,sc); + } + } + /* CURRENT PCS HAS HIGHEST DUPE COUNT */ + /* INSERT IF SCORE > LOWEST MATCH SCORE */ + else if (is_pcs_match(sc,&top_ten[idx])) { + if (sc->sc_score > top_ten[idx].sc_score) { + delete_score(top_ten,idx); + insert_score(top_ten,sc); + } + } + /* UNRELATED PCS HAS HIGHEST DUPE COUNT */ + /* DELETE LOWEST DUPE TO MAKE ROOM AND INSERT */ + else { + delete_score(top_ten,idx); + insert_score(top_ten,sc); + } + } +} + +update(top_ten, amount, quest, whoami, flags, level, monst, ctype, system, login) +struct sc_ent top_ten[]; +unsigned long amount; +short quest, flags, level, monst, ctype; +char *whoami, *system, *login; +{ + struct sc_ent sc; + + sc.sc_score = amount; + sc.sc_quest = quest; + strncpy(sc.sc_name, whoami, NAMELEN); + sc.sc_name[NAMELEN-1] = 0; + sc.sc_flags = flags; + sc.sc_level = level; + sc.sc_monster = monst; + sc.sc_ctype = ctype; + strncpy(sc.sc_system, system, SYSLEN); + sc.sc_system[SYSLEN - 1] = 0; + strncpy(sc.sc_login, login, LOGLEN); + sc.sc_login[LOGLEN-1] = 0; + + add_score(top_ten, &sc); + return(1); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/rogue.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,659 @@ +/* + rogue.c - Global game variables + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <ctype.h> +#include <curses.h> +#include "rogue.h" + +/* + * Now all the global variables + */ + +struct trap traps[MAXTRAPS]; +struct room rooms[MAXROOMS]; /* One for each room -- A level */ +struct room *oldrp; /* Roomin(&player.t_oldpos) */ +struct thing player; /* The rogue */ +struct object *cur_armor; /* What a well dresssed rogue wears */ +struct object *cur_ring[NUM_FINGERS]; /* Which rings are being worn */ +struct object *cur_misc[NUM_MM]; /* which MM's are in use */ +int cur_relic[MAXRELIC]; /* Currently used relics */ +struct linked_list *lvl_obj = NULL; +struct linked_list *mlist = NULL; +struct linked_list *rlist = NULL; /* list of dead monsters to be reaped */ +struct linked_list *tlist = NULL; /* list of monsters fallen down traps */ +struct linked_list *monst_dead = NULL; /* monster killed by monster */ +struct object *cur_weapon = NULL; +int char_type = -1; /* what type of character is player */ +int foodlev = 1; /* how fast he eats food */ +int ntraps; /* Number of traps on this level */ +int trader = 0; /* no. of purchases */ +int curprice = -1; /* current price of item */ +int seed; /* Random number seed */ +int max_level; /* Deepest player has gone ever */ +int cur_max; /* Deepest player has gone currently */ +int prev_max; /* A flag indicating worm hole */ +int move_free = 0; /* Movement check (io.c & actions.c) */ +int mpos = 0; +int level = 0; +long purse = 0; +int inpack = 0; +int total = 0; +int no_food = 0; /* how long has he gone with no food */ +int foods_this_level = 0; /* foods made per level */ +int count = 0; +int food_left = STOMACHSIZE-MORETIME-1; +int group = 1; +int hungry_state = F_OKAY; +int infest_dam=0; +int lost_str=0; +int lastscore = -1; +int hold_count = 0; +int trap_tries = 0; +int chant_time = 0; +int pray_time = 0; +int spell_power = 0; +long turns = 0; /* Number of turns player has taken */ +int quest_item = 0; /* Item player is looking for */ +int cols = 0; /* number of columns in terminal */ +int lines = 0; /* number of lines on the terminal */ +int nfloors = -1; /* Number of floors in this dungeon */ +char curpurch[LINELEN]; /* name of item ready to buy */ +char PLAYER = VPLAYER; /* what the player looks like */ +char take; /* Thing the rogue is taking */ +char prbuf[LINELEN*2]; /* Buffer for sprintfs */ +char runch; /* Direction player is running */ +char *s_names[MAXSCROLLS]; /* Names of the scrolls */ +char *p_colors[MAXPOTIONS]; /* Colors of the potions */ +char *r_stones[MAXRINGS]; /* Stone settings of the rings */ +char *ws_made[MAXSTICKS]; /* What sticks are made of */ +char whoami[LINELEN]; /* Name of player */ +char huh[LINELEN]; /* The last message printed */ +char *s_guess[MAXSCROLLS]; /* Players guess at what scroll is */ +char *p_guess[MAXPOTIONS]; /* Players guess at what potion is */ +char *r_guess[MAXRINGS]; /* Players guess at what ring is */ +char *ws_guess[MAXSTICKS]; /* Players guess at what wand is */ +char *m_guess[MAXMM]; /* Players guess at what MM is */ +char *ws_type[MAXSTICKS]; /* Is it a wand or a staff */ +char file_name[LINELEN]; /* Save file name */ +char score_file[LINELEN]; /* Score file name */ +char home[LINELEN]; /* User's home directory */ +WINDOW *cw; /* Window that the player sees */ +WINDOW *hw; /* Used for the help command */ +WINDOW *mw; /* Used to store monsters */ +WINDOW *msgw; /* Used to display messages */ +bool pool_teleport = FALSE; /* just teleported from a pool */ +bool inwhgt = FALSE; /* true if from wghtchk() */ +bool after; /* True if we want after daemons */ +bool use_savedir = FALSE; /* Use common save location? */ +bool waswizard; /* Was a wizard sometime */ +bool s_know[MAXSCROLLS]; /* Does he know what a scroll does */ +bool p_know[MAXPOTIONS]; /* Does he know what a potion does */ +bool r_know[MAXRINGS]; /* Does he know what a ring does */ +bool ws_know[MAXSTICKS]; /* Does he know what a stick does */ +bool m_know[MAXMM]; /* Does he know what a MM does */ + +/* options */ +bool playing = TRUE; /* Defaults */ +bool running = FALSE; +bool wizard = FALSE; +bool notify = TRUE; +bool fight_flush = FALSE; +bool terse = FALSE; +bool auto_pickup = FALSE; +bool def_attr = FALSE; /* default attributes */ +bool menu_overlay = TRUE; +bool door_stop = TRUE; +bool jump = TRUE; +bool slow_invent = FALSE; +bool firstmove = FALSE; +bool askme = TRUE; +bool in_shell = FALSE; +bool daytime = TRUE; +bool funfont = FALSE; + +LEVTYPE levtype; /* what type of level am i'm on? */ + +char *nothing = "Nothing seems to happen. "; +char *spacemsg = "--Press space to continue--"; +char *morestr = " --More--"; +char *retstr = "[Press return to continue]"; + +/* + * This lays out all the class specific details + * + * Here are the beginning experience levels for all players. + * All further experience levels are computed by muliplying by 2 + * up through MAXDOUBLE. Then exp pts are calculated by adding + * in the cap figure. You must change MAXDOUBLE if you change the + * cap figure. + */ + +struct character_types char_class[NUM_CHARTYPES] = { +/* name exppts cap hitpts Base Maxlvl, Factor, Offset, Range */ +{ "fighter", 90, 1310720, 13, 10, 30, 2, 1, 3 }, +{ "ranger", 110, 2293760, 10, 10, 22, 2, 1, 2 }, +{ "paladin", 110, 1966080, 10, 10, 23, 2, 1, 2 }, +{ "magician", 105, 2129920, 9, 10, 24, 2, 1, 2 }, +{ "cleric", 105, 1802240, 9, 10, 24, 2, 1, 2 }, +{ "thief", 95, 1228800, 11, 10, 28, 2, 1, 3 }, +{ "assassin", 95, 1392640, 11, 10, 26, 2, 1, 3 }, +{ "druid", 105, 1638400, 9, 10, 24, 2, 1, 2 }, +{ "monk", 100, 1556480, 10, 10, 25, 2, 1, 2 }, +{ "monster", 0, 0, 8, 10, 20, 1, 0, 2 }, +}; + +/* + * This array lists the names of the character's abilities. It must be ordered + * according to the ability definitions in rogue.h. + */ + +struct words abilities[NUMABILITIES] = { + "Intelligence", "Strength", "Wisdom", "Dexterity", "Constitution", "Charisma" +}; + +/* + * NOTE: the ordering of the points in this array is critical. They MUST + * be listed in the following sequence: + * + * 7 4 6 + * 1 0 2 + * 5 3 8 + */ + +coord grid[9] = {{0,0}, + { 0,-1}, { 0, 1}, {-1, 0}, { 1, 0}, + {-1,-1}, { 1, 1}, { 1,-1}, {-1, 1} + }; + +struct death_type deaths[DEATHNUM] = { + { D_ARROW, "an arrow"}, + { D_DART, "a dart"}, + { D_BOLT, "a bolt"}, + { D_POISON, "poison"}, + { D_POTION, "a cursed potion"}, + { D_PETRIFY, "petrification"}, + { D_SUFFOCATION, "suffocation"}, + { D_INFESTATION, "a parasite"}, + { D_DROWN, "drowning"}, + { D_ROT, "body rot"}, + { D_CONSTITUTION, "poor health"}, + { D_STRENGTH, "being too weak"}, + { D_SIGNAL, "a bug"}, + { D_CHOKE, "dust of choking"}, + { D_STRANGLE, "strangulation"}, + { D_FALL, "a fall"}, + { D_RELIC, "an artifact's wrath"}, + { D_STARVATION, "starvation"}, + { D_FOOD_CHOKE, "choking on food"}, + { D_SCROLL, "reading a scroll"}, + { D_FRIGHT, "being too frightened"}, + { D_CRYSTAL, "being absorbed"}, + { D_CARD, "the face of death"}, +}; + +/* + * weapons and their attributes + */ + +struct init_weps weaps[MAXWEAPONS] = { + { "mace", "2d10","2d10", NONE, ISMETAL, 6, 150, 15 }, + { "long sword", "3d4", "2d8", NONE, ISMETAL, 5, 200, 25 }, + { "short bow", "1d1", "1d1", NONE, 0, 8, 50, 4 }, + { "arrow", "2d4", "1d6", BOW, ISMANY|ISMISL, 1, 5, 4 }, + { "dagger", "2d8", "1d6", NONE, ISMETAL|ISMISL|ISMANY, 2,10,7}, + { "rock", "2d4", "1d6", SLING, ISMANY|ISMISL, 1, 20, 3 }, + { "two-handed sword","3d10","3d8", NONE, ISMETAL, 4, 250, 40 }, + { "sling", "1d1", "1d1", NONE, 0, 8, 25, 3 }, + { "dart", "2d4", "2d6", NONE, ISMANY|ISMISL, 2, 15, 7 }, + { "crossbow", "1d1", "1d1", NONE, 0, 8, 75, 5 }, + { "crossbow bolt", "2d4", "2d4", CROSSBOW, ISMANY|ISMISL, 1, 10, 5 }, + { "spear", "2d6", "3d10", NONE, ISMISL, 7, 100, 15 }, + { "trident", "3d6", "3d4", NONE, ISMETAL, 4, 200, 30 }, + { "spetum", "2d6", "2d8", NONE, ISMETAL, 6, 150, 20 }, + { "bardiche", "3d4", "2d10", NONE, ISMETAL, 5, 150, 25 }, + { "pike", "2d8", "2d8", NONE, ISMETAL, 7, 100, 15 }, + { "bastard sword", "3d8", "3d6", NONE, ISMETAL, 4, 175, 30 }, + { "halberd", "2d8", "2d4", NONE, ISMETAL, 6, 100, 10 }, + { "battle axe", "2d8", "3d8", NONE, ISMETAL, 5, 150, 15 }, +} ; + +struct init_armor armors[MAXARMORS] = { + { "leather armor", 10, 8, 200, 100 }, + { "ring mail", 20, 7, 250, 200 }, + { "studded leather armor", 30, 5, 320, 250 }, + { "scale mail", 40, 7, 280, 250 }, + { "padded armor", 50, 6, 350, 300 }, + { "chain mail", 60, 6, 350, 600 }, + { "splint mail", 70, 5, 370, 400 }, + { "banded mail", 80, 5, 370, 350 }, + { "plate mail", 90, 4, 400, 400 }, + { "plate armor", 100, 3, 500, 450 }, +}; + +struct magic_item things[NUMTHINGS] = { + { "potion", 220, 10 }, /* potion */ + { "scroll", 220, 30 }, /* scroll */ + { "food", 190, 20 }, /* food */ + { "weapon", 90, 0 }, /* weapon */ + { "armor", 90, 0 }, /* armor */ + { "ring", 70, 5 }, /* ring */ + { "stick", 70, 0 }, /* stick */ + { "miscellaneous magic", 50, 50 }, /* miscellaneous magic */ + { "artifact", 0, 10 }, /* artifact */ +}; + +struct magic_item s_magic[MAXSCROLLS] = { + { "monster confusion", 40, 125, 0, 0 }, + { "magic mapping", 60, 150, 0, 5 }, + { "light", 60, 100, 15, 15 }, + { "hold monster", 30, 200, 20, 20 }, + { "sleep", 20, 150, 25, 0 }, + { "enchantment", 130, 200, 15, 15 }, + { "identify", 170, 100, 0, 20 }, + { "scare monster", 40, 250, 20, 30 }, + { "gold detection", 30, 110, 0, 0 }, + { "teleportation", 60, 165, 20, 20 }, + { "create monster", 20, 75, 0, 0 }, + { "remove curse", 80, 120, 15, 15 }, + { "petrification", 30, 185, 0, 0 }, + { "genocide", 10, 300, 0, 0 }, + { "cure disease", 80, 160, 0, 0 }, + { "acquirement", 10, 700, 0, 5 }, + { "protection", 30, 190, 10, 0 }, + { "trap finding", 50, 180, 0, 0 }, + { "runes", 20, 50, 0, 0 }, + { "charm monster", 30, 275, 0, 20 }, +}; + +struct magic_item p_magic[MAXPOTIONS] = { + { "clear thought", 50, 180, 10, 5 }, + { "gain ability", 160, 210, 10, 10 }, + { "see invisible", 40, 150, 20, 20 }, + { "healing", 140, 130, 15, 15 }, + { "monster detection", 40, 120, 0, 0 }, + { "magic detection", 70, 105, 0, 0 }, + { "raise level", 10, 450, 10, 5 }, + { "haste self", 50, 180, 20, 5 }, + { "restore abilities", 130, 140, 0, 15 }, + { "phasing", 60, 210, 10, 10 }, + { "invisibility", 20, 230, 0, 10 }, + { "flying", 50, 130, 0, 15 }, + { "food detection", 20, 150, 0, 0 }, + { "skill", 10, 200, 20, 5 }, + { "fire resistance", 40, 250, 10, 5 }, + { "cold resistance", 40, 250, 10, 5 }, + { "lightning protection", 40, 250, 20, 5 }, + { "poison", 30, 205, 25, 0 }, +}; + +struct magic_item r_magic[MAXRINGS] = { + { "protection", 60, 200, 25, 25 }, + { "add strength", 50, 200, 25, 25 }, + { "sustain ability", 50, 500, 0, 0 }, + { "searching", 40, 400, 0, 0 }, + { "extra sight", 60, 350, 0, 0 }, + { "alertness", 40, 380, 0, 0 }, + { "aggravate monster", 30, 100, 100, 0 }, + { "dexterity", 50, 220, 25, 25 }, + { "increase damage", 60, 220, 25, 25 }, + { "regeneration", 40, 600, 0, 0 }, + { "slow digestion", 50, 240, 20, 20 }, + { "teleportation", 20, 100, 90, 0 }, + { "stealth", 20, 300, 0, 0 }, + { "add intelligence", 50, 240, 25, 25 }, + { "increase wisdom", 40, 220, 25, 25 }, + { "sustain health", 80, 500, 0, 0 }, + { "carrying", 10, 100, 90, 0 }, + { "illumination", 30, 520, 0, 0 }, + { "delusion", 10, 100, 100, 0 }, + { "fear", 20, 100, 75, 0 }, + { "heroism", 50, 390, 0, 0 }, + { "fire resistance", 40, 400, 0, 0 }, + { "warmth", 40, 400, 0, 0 }, + { "vampiric regeneration", 10,1000, 0, 0 }, + { "free action", 40, 370, 0, 0 }, + { "teleport control", 10, 700, 0, 0 }, +}; + +struct magic_item ws_magic[MAXSTICKS] = { + { "light", 80, 120, 15, 15 }, + { "striking", 50, 115, 0, 0 }, + { "lightning", 40, 200, 0, 0 }, + { "fire", 30, 200, 0, 0 }, + { "cold", 30, 200, 0, 0 }, + { "polymorph", 80, 150, 0, 0 }, + { "magic missile", 90, 170, 0, 0 }, + { "slow", 70, 220, 20, 10 }, + { "drain life", 50, 210, 20, 0 }, + { "charging", 70, 400, 0, 0 }, + { "teleport", 90, 140, 20, 10 }, + { "cancellation", 50, 130, 0, 0 }, + { "confusion", 30, 100, 20, 0 }, + { "disintegration", 20, 300, 25, 0 }, + { "petrification", 30, 240, 0, 0 }, + { "paralyzation", 30, 180, 10, 0 }, + { "degeneration", 30, 250, 20, 0 }, + { "curing", 50, 250, 20, 5 }, + { "wonder", 40, 110, 20, 20 }, + { "fear", 40, 180, 0, 0 }, +}; + +/* + * WARNING: unique miscellaneous magic items must be put at the end + * of this list. They MUST be the last items. The function + * create_obj() in wizard.c depends on it. + */ + +struct magic_item m_magic[MAXMM] = { + { "alchemy jug", 40, 240, 0, 0 }, + { "beaker of potions", 60, 300, 0, 0 }, + { "book of spells", 60, 300, 0, 0 }, + { "boots of elvenkind", 50, 500, 0, 0 }, + { "bracers of defense", 80, 400, 20, 10 }, + { "chime of opening", 30, 250, 0, 0 }, + { "chime of hunger", 20, 100, 100, 0 }, + { "cloak of displacement", 60, 500, 0, 0 }, + { "cloak of protection", 80, 400, 20, 10 }, + { "drums of panic", 60, 350, 0, 0 }, + { "dust of disappearance", 30, 300, 0, 0 }, + { "dust of choking", 30, 100, 100, 0 }, + { "gauntlets of dexterity", 40, 600, 25, 0 }, + { "gauntlets of ogre power", 40, 600, 25, 0 }, + { "jewel of attacks", 50, 150, 100, 0 }, + { "keoghtoms ointment", 60, 350, 0, 0 }, + { "robe of powerlessness", 20, 100, 100, 0 }, + { "gauntlets of fumbling", 30, 100, 100, 0 }, + { "necklace of adaptation", 50, 500, 0, 0 }, + { "necklace of strangulation", 30, 110, 100, 0 }, + { "boots of dancing", 40, 120, 100, 0 }, + { "book of skills", 30, 650, 0, 0 }, + { "medicine crystal", 10, 800, 25, 5 }, +}; + +struct magic_item rel_magic[MAXRELIC] = { + { "Daggers of Musty Doit", 0, 50000, 0, 0}, + { "Cloak of Emori", 0, 50000, 0, 0}, + { "Ankh of Heil", 0, 50000, 0, 0}, + { "Staff of Ming", 0, 50000, 0, 0}, + { "Wand of Orcus", 0, 50000, 0, 0}, + { "Rod of Asmodeus", 0, 50000, 0, 0}, + { "Amulet of Yendor", 0, 50000, 0, 0}, + { "Mandolin of Brian", 0, 50000, 0, 0}, + { "Horn of Geryon", 0, 50000, 0, 0}, + { "Morning Star of Hruggek", 0, 50000, 0, 0}, + { "Flail of Yeenoghu", 0, 50000, 0, 0}, + { "Eye of Vecna", 0, 50000, 0, 0}, + { "Axe of Aklad", 0, 50000, 0, 0}, + { "Quill of Nagrom", 0, 50000, 0, 0}, + { "Amulet of Stonebones", 0, 50000, 0, 0}, + { "Ring of Surtur", 0, 50000, 0, 0}, + { "Card of Alteran", 0, 50000, 0, 0}, +}; + +/* + * food and fruits that you get + */ +struct magic_item foods[MAXFOODS] = { + + { "food ration", 690, 50, 750, 0}, + { "apple", 10, 20, 300, 0}, + { "banana", 30, 20, 300, 0}, + { "blueberry", 30, 20, 300, 0}, + { "candleberry", 10, 20, 300, 0}, + { "caprifig", 20, 20, 300, 0}, + { "dewberry", 10, 20, 300, 0}, + { "elderberry", 30, 20, 300, 0}, + { "gooseberry", 20, 20, 300, 0}, + { "guanabana", 30, 20, 300, 0}, + { "hagberry", 10, 20, 300, 0}, + { "jaboticaba", 10, 20, 300, 0}, + { "peach", 10, 20, 300, 0}, + { "pitanga", 10, 20, 300, 0}, + { "prickly pear", 10, 20, 300, 0}, + { "rambutan", 10, 20, 300, 0}, + { "sapodilla", 10, 20, 300, 0}, + { "soursop", 10, 20, 300, 0}, + { "strawberry", 10, 20, 300, 0}, + { "sweetsop", 10, 20, 300, 0}, + { "whortleberry", 10, 20, 300, 0}, + { "slime-mold", 10, 10, 100, 0}, +}; + +/* + * these are the spells that a magician can cast + */ + +struct spells magic_spells[MAXSPELLS] = { + { P_TFIND, 3, TYP_POTION, 0 }, + { S_IDENT, 5, TYP_SCROLL, 0 }, + { S_LIGHT, 7, TYP_SCROLL, ISBLESSED }, + { S_REMOVE, 10, TYP_SCROLL, 0 }, + { S_FINDTRAPS, 15, TYP_SCROLL, 0 }, + { P_FLY, 20, TYP_POTION, 0 }, + { S_TELEP, 25, TYP_SCROLL, 0 }, + { S_SLEEP, 30, TYP_SCROLL, 0 }, + { P_SEEINVIS, 35, TYP_POTION, ISBLESSED }, + { P_CLEAR, 40, TYP_POTION, 0 }, + { WS_COLD, 45, TYP_STICK, 0 }, + { P_PHASE, 50, TYP_POTION, 0 }, + { WS_FIRE, 55, TYP_STICK, 0 }, + { P_HASTE, 60, TYP_POTION, ISBLESSED }, + { WS_ELECT, 65, TYP_STICK, 0 }, + { S_HOLD, 70, TYP_SCROLL, ISBLESSED }, +}; + +/* + * these are the spells that a cleric can cast + */ + +struct spells cleric_spells[MAXPRAYERS] = { + { P_MFIND, 3, TYP_POTION, 0 }, + { P_TFIND, 5, TYP_POTION, 0 }, + { S_LIGHT, 7, TYP_SCROLL, ISBLESSED }, + { S_REMOVE, 10, TYP_SCROLL, 0 }, + { P_FFIND, 15, TYP_POTION, 0 }, + { P_FLY, 20, TYP_POTION, 0 }, + { P_HEALING, 25, TYP_POTION, 0 }, + { S_CURING, 30, TYP_SCROLL, 0 }, + { P_RESTORE, 35, TYP_POTION, 0 }, + { S_MAP, 40, TYP_SCROLL, 0 }, + { P_SEEINVIS, 45, TYP_POTION, ISBLESSED }, + { P_CLEAR, 50, TYP_POTION, 0 }, + { P_PHASE, 55, TYP_POTION, 0 }, + { WS_CURING, 60, TYP_STICK, ISBLESSED }, + { WS_PARALYZE, 65, TYP_STICK, 0 }, + { S_ALLENCH, 70, TYP_SCROLL, 0 }, +}; + +/* + * these are the spells that a druid can chant + */ + +struct spells druid_spells[MAXCHANTS] = { + { P_MFIND, 3, TYP_POTION, 0 }, + { P_TFIND, 5, TYP_POTION, 0 }, + { S_LIGHT, 7, TYP_SCROLL, ISBLESSED }, + { S_REMOVE, 10, TYP_SCROLL, 0 }, + { S_FINDTRAPS, 15, TYP_SCROLL, 0 }, + { S_CONFUSE, 20, TYP_SCROLL, 0 }, + { P_FFIND, 25, TYP_POTION, 0 }, + { P_HEALING, 30, TYP_POTION, 0 }, + { S_MAP, 35, TYP_SCROLL, 0 }, + { P_CLEAR, 40, TYP_POTION, 0 }, + { P_COLD, 45, TYP_POTION, 0 }, + { P_FIRE, 50, TYP_POTION, 0 }, + { P_PHASE, 55, TYP_POTION, 0 }, + { P_LIGHTNING, 60, TYP_POTION, 0 }, + { S_CHARM, 65, TYP_SCROLL, ISBLESSED }, + { S_HOLD, 70, TYP_SCROLL, ISBLESSED }, +}; + +/* + * these are the scrolls that a quill can write + */ + +struct spells quill_scrolls[MAXQUILL] = { + { S_GFIND, 5, }, + { S_IDENT, 10, }, + { S_LIGHT, 10, }, + { S_REMOVE, 15, }, + { S_MAP, 20, }, + { S_CONFUSE, 25, }, + { S_SLEEP, 30, }, + { S_CURING, 40, }, + { S_TELEP, 50, }, + { S_SCARE, 60, }, + { S_HOLD, 70, }, + { S_PETRIFY, 80, }, + { S_PROTECT, 90, }, + { S_ALLENCH, 100, }, +}; + +/* + * Experience-level names of each character (see NUM_CNAMES in rogue.h) + */ + +const char *cnames[NUM_CHARTYPES-1][NUM_CNAMES] = { +{ "Veteran", "Fighter", /* Fighter */ + "Ruffian", "Tussler", + "Swordsman", "Hero", + "Bravo", "Picador", + "Stalwart", "Bashar", + "Swashbuckler", "Myrmidon", + "Fusileer", "Pugilist", + "Champion", "Superhero", + "Warrior", "Lord", + "Lord I", "Lord II", + "Lord III", "Lord IV", + "Lord V", "Lord VI", + "Lord VII", "Warrior Lord" +}, +{ "Runner", "Strider", /* Ranger */ + "Warden", "Steward", + "Scout", "Courser", + "Tracker", "Guide", + "Protector", "Bartizan", + "Gendarme", "Sentinel", + "Vigilant", "Pathfinder", + "Guardian", "Overseer", + "Castellan", "Ranger", + "Lord Ranger I", "Lord Ranger II", + "Lord Ranger III", "Lord Ranger IV", + "Lord Ranger V", "Lord Ranger VI", + "Lord Ranger VII", "Master Ranger" +}, +{ "Gallant", "Keeper", /* Paladin */ + "Bravado", "Brazen", + "Protector", "Defender", + "Warder", "Guardian", + "Champion", "Bulwark", + "Venturist", "Inspirator", + "Chevalier", "Justiciar", + "Undaunteer", "Plautus", + "Knight", "Paladin", + "Paladin I", "Paladin II", + "Paladin III", "Paladin IV", + "Paladin V", "Paladin VI", + "Paladin VII", "Lord Paladin" +}, +{ "Prestidigitator", "Evoker", /* Magic User */ + "Summoner", "Invoker", + "Conjurer", "Theurgist", + "Illusionist", "Diviner", + "Thaumaturgist", "Magician", + "Thelemist", "Magus", + "Enchanter", "Warlock", + "Witch", "Shaman", + "Sorcerer", "Wizard", + "Wizard I", "Wizard II", + "Wizard III", "Wizard IV", + "Wizard V", "Wizard VI", + "Wizard VII", "Lord Magus" +}, +{ "Acolyte", "Adept", /* Cleric */ + "Charmer", "Friar", + "Priest", "Curate", + "Vicar", "Deacon", + "Sabiast", "Cabalist", + "Prefect", "Canon", + "Minister", "Cardinal", + "Bishop", "Patriarch", + "Exorcist", "Archdeacon", + "High Priest I", "High Priest II", + "High Priest III", "High Priest IV", + "High Priest V", "High Priest VI", + "High Priest VII", "Reverend Lord" +}, +{ "Rogue", "Footpad", /* Thief */ + "Cutpurse", "Robber", + "Vagrant", "Truant", + "Burglar", "Filcher", + "Sharper", "Magsman", + "Racketeer", "Prowler", + "Crook", "Bounder", + "Quisling", "Malfeasor", + "Swindler", "Thief", + "Master Thief I", "Master Thief II", + "Master Thief III", "Master Thief IV", + "Master Thief V", "Master Thief VI", + "Master Thief VII", "Master Rogue" +}, +{ "Bravo", "Rutterkin", /* Assassin */ + "Waghalter", "Murderer", + "Butcher", "Desperado", + "Thug", "Killer", + "Cutthroat", "Executioner", + "Eradicator", "Obliterator", + "Mechanic", "Wiseguy", + "Nihilist", "Berserker", + "Assassin", "Expert Assassin", + "Prime Assassin I", "Prime Assassin II", + "Prime Assassin III", "Prime Assassin IV", + "Prime Assassin V", "Prime Assassin VI", + "Prime Assassin VII", "Master Assassin" +}, +{ "Aspirant", "Ovate", /* Druid */ + "Practitioner", "Devoutist", + "Initiate 1st Circle", "Initiate 2nd Circle", + "Initiate 3rd Circle", "Initiate 4th Circle", + "Initiate 5th Circle", "Initiate 6th Circle", + "Initiate 7th Circle", "Initiate 8th Circle", + "Initiate 9th Circle", "Illuminati", + "Lesser Druid", "Arch Druid", + "Druid", "Master Druid", + "Master Druid I", "Master Druid II", + "Master Druid III", "Master Druid IV", + "Master Druid V", "Master Druid VI", + "Master Druid VII", "Lord Druid" +}, +{ "Novice", "Initiate", /* Monk */ + "Brother", "Disciple", + "Canon", "Elder", + "Precept", "Lama", + "Immaculate", "Wizard", + "Shaman", "Master", + "Superior Master", "Master of Dragons", + "Master of North Wind", "Master of West Wind", + "Master of South Wind", "Master of East Wind", + "Grand Master I", "Grand Master II", + "Grand Master III", "Grand Master IV", + "Grand Master V", "Grand Master VI", + "Grand Master VII", "Lord Monk" +} +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/rogue.h Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1418 @@ +/* + rogue.h - Rogue definitions and variable declarations + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +/* + * some compiler don't handle void pointers well so + */ +#include <assert.h> +#define reg register +#define VOID long +#undef lines +#define ENCREAD encread +#define ENCWRITE encwrite +#undef SCROLL /* UNIX/370 defines SCROLL for some bizarre reason */ +#define exfork fork /* Standard fork with no paging available */ + +/* + * Maximum number of different things + */ + +#define MINCOLS 70 +#define MINLINES 22 +#define MAXROOMS 9 +#define MAXTHINGS 9 +#define MAXOBJ 9 +#define MAXSTATS 74 /* max total of all stats at startup */ +#define MAXPACK 27 /* max number of items in pack */ +#define MAXDOUBLE 14 /* max number of times exppts is doubled */ +#define MAXCONTENTS 20 /* max number of things beaker/book can hold */ +#define MAXENCHANT 30 /* max number of enchantments on an item */ +#define MAXTREAS 25 /* number monsters/treasure in treasure room */ +#define MAXTRAPS 20 /* max number of traps that may be on level */ +#define MAXTRPTRY 15 /* attempts/level allowed for setting traps */ +#define MAXDOORS 4 /* maximum doors to a room */ +#define MAXCHANTS 16 /* maximum number of chants for a druid */ +#define MAXPRAYERS 16 /* maximum number of prayers for cleric */ +#define MAXSPELLS 16 /* maximum number of spells for magician */ +#define MAXQUILL 14 /* scrolls the Quill of Nagrom can write */ +#define QUILLCHARGES 300 /* max num of charges in the Quill of Nagrom */ +#define NUM_CNAMES 26 /* number of names per character level */ +#define NUMMONST 211 /* current number of monsters */ +#define NUMUNIQUE 60 /* number of UNIQUEs (minus jacaranda) */ +#define NUMDINOS 30 /* number of dinosaurs (for OUTSIDE level) */ +#define NLEVMONS 3 /* number of new monsters per level */ +#define NUMSCORE 20 /* number of entries in score file */ +#define HARDER 40 /* at this level start making things harder */ +#define LINELEN 256 /* characters in a buffer */ +#define JUG_EMPTY -1 /* signifys that the alchemy jug is empty */ +#define MAXPURCH (pstats.s_charisma/3) /* num of purchases at t.post */ +#define MAXATT 50 /* charactor's attribute maximum number */ + +/* Movement penalties */ +#define BACKPENALTY 3 +#define SHOTPENALTY 2 /* In line of sight of missile */ +#define DOORPENALTY 1 /* Moving out of current room */ + +/* + * these defines are used in calls to get_item() to signify what + * it is we want + */ + +#define ALL -1 +#define WEARABLE -2 +#define CALLABLE -3 +#define WIELDABLE -4 +#define USEABLE -5 +#define IDENTABLE -6 +#define REMOVABLE -7 +#define PROTECTABLE -8 +#define ZAPPABLE -9 +#define READABLE -10 +#define QUAFFABLE -11 + +/* + * stuff to do with encumberance + */ + +#define NORMENCB 1400 /* normal encumberance */ +#define F_SATIATED 0 /* player's stomach is very full */ +#define F_OKAY 1 /* have plenty of food in stomach */ +#define F_HUNGRY 2 /* player is hungry */ +#define F_WEAK 3 /* weak from lack of food */ +#define F_FAINT 4 /* fainting from lack of food */ + +/* + * actions a player/monster will take + */ + +#define A_MOVE 0200 /* normal movement */ +#define A_FREEZE 0201 /* frozen in place */ +#define A_ATTACK 0202 /* trying to hit */ +#define A_SELL 0203 /* trying to sell goods */ +#define A_NIL 0204 /* not doing anything */ +#define A_BREATHE 0205 /* breathing */ +#define A_MISSILE 0206 /* Firing magic missiles */ +#define A_SONIC 0207 /* Sounding a sonic blast */ +#define A_SUMMON 0210 /* Summoning help */ +#define A_USERELIC 0211 /* Monster uses a relic */ +#define A_SLOW 0212 /* monster slows the player */ +#define A_ZAP 0213 /* monster shoots a wand */ +#define A_PICKUP 0214 /* player is picking something up */ +#define A_USEWAND 0215 /* monster is shooting a wand */ +#define A_THROW 't' +#define C_CAST 'C' +#define C_COUNT '*' +#define C_DIP 'D' +#define C_DROP 'd' +#define C_EAT 'e' +#define C_PRAY 'p' +#define C_CHANT 'c' +#define C_QUAFF 'q' +#define C_READ 'r' +#define C_SEARCH 's' +#define C_SETTRAP '^' +#define C_TAKEOFF 'T' +#define C_USE CTRL('U') +#define C_WEAR 'W' +#define C_WIELD 'w' +#define C_ZAP 'z' + +/* Possible ways for the hero to move */ + +#define H_TELEPORT 0 + +/* + * return values for get functions + */ + +#define NORM 0 /* normal exit */ +#define QUIT 1 /* quit option setting */ +#define MINUS 2 /* back up one option */ + +/* + * The character types + */ + +#define C_FIGHTER 0 +#define C_RANGER 1 +#define C_PALADIN 2 +#define C_MAGICIAN 3 +#define C_CLERIC 4 +#define C_THIEF 5 +#define C_ASSASSIN 6 +#define C_DRUID 7 +#define C_MONK 8 +#define C_MONSTER 9 +#define NUM_CHARTYPES 10 + +/* + * define the ability types + */ + +#define A_INTELLIGENCE 0 +#define A_STRENGTH 1 +#define A_WISDOM 2 +#define A_DEXTERITY 3 +#define A_CONSTITUTION 4 +#define A_CHARISMA 5 +#define NUMABILITIES 6 + +/* + * values for games end + */ + +#define UPDATE -2 +#define SCOREIT -1 +#define KILLED 0 +#define CHICKEN 1 +#define WINNER 2 + +/* + * definitions for function step_ok: + * MONSTOK indicates it is OK to step on a monster -- it + * is only OK when stepping diagonally AROUND a monster; + * it is also OK if the stepper is a friendly monster and + * is in a fighting mood. + */ + +#define MONSTOK 1 +#define NOMONST 2 +#define FIGHTOK 3 + +/* + * used for ring stuff + */ + +#define LEFT_1 0 +#define LEFT_2 1 +#define LEFT_3 2 +#define LEFT_4 3 +#define RIGHT_1 4 +#define RIGHT_2 5 +#define RIGHT_3 6 +#define RIGHT_4 7 +#define NUM_FINGERS 8 + +/* + * used for micellaneous magic (MM) stuff + */ + +#define WEAR_BOOTS 0 +#define WEAR_BRACERS 1 +#define WEAR_CLOAK 2 +#define WEAR_GAUNTLET 3 +#define WEAR_JEWEL 4 +#define WEAR_NECKLACE 5 +#define NUM_MM 6 + +/* + How to exit flags: +*/ + +#define EXIT_CLS 1 /* Clear screen first */ +#define EXIT_ENDWIN 2 /* Shutdown Curses */ + + +/* + * All the fun defines + */ + +#define next(ptr) (*ptr).l_next +#define prev(ptr) (*ptr).l_prev +#define ldata(ptr) (*ptr).l_data +#define inroom(rp, cp) (\ + (cp)->x <= (rp)->r_pos.x + ((rp)->r_max.x - 1) && (rp)->r_pos.x <= (cp)->x \ + && (cp)->y <= (rp)->r_pos.y + ((rp)->r_max.y - 1) && (rp)->r_pos.y <= (cp)->y) +#define winat(y, x) (mvwinch(mw, y, x)==' '?mvwinch(stdscr, y, x):winch(mw)) +#define debug if (wizard) msg +#define RN (((seed = seed*11109+13849) & 0x7fff) >> 1) +#define unc(cp) (cp).y, (cp).x +#define cmov(xy) move((xy).y, (xy).x) +#define DISTANCE(y1, x1, y2, x2) ((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)) +#define OBJPTR(what) (struct object *)((*what).l_data) +#define THINGPTR(what) (struct thing *)((*what).l_data) +#define DOORPTR(what) (coord *)((*what).l_data) +#define when break;case +#define otherwise break;default +#define until(expr) while(!(expr)) +#define ce(a, b) ((a).x == (b).x && (a).y == (b).y) +#define draw(window) wrefresh(window) +#define newfont(window) if (funfont) wattron(window, A_ALTCHARSET); +#define nofont(window) if (funfont) wattroff(window, A_ALTCHARSET); +#define hero player.t_pos +#define pstats player.t_stats +#define max_stats player.maxstats +#define pack player.t_pack +#define attach(a, b) _attach(&a, b) +#define detach(a, b) _detach(&a, b) +#define o_free_list(a) _o_free_list(&a) +#define r_free_list(a) _r_free_list(&a) +#define t_free_list(a) _t_free_list(&a) +#undef min +#undef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define on(thing, flag) \ + (((thing).t_flags[(flag >> FLAGSHIFT) & FLAGINDEX] & flag) != 0) +#define off(thing, flag) \ + (((thing).t_flags[(flag >> FLAGSHIFT) & FLAGINDEX] & flag) == 0) +#define turn_on(thing, flag) \ + ((thing).t_flags[(flag >> FLAGSHIFT) & FLAGINDEX] |= (flag & ~FLAGMASK)) +#define turn_off(thing, flag) \ + ((thing).t_flags[(flag >> FLAGSHIFT) & FLAGINDEX] &= ~flag) + +/* define the control character */ + +#undef CTRL +#define CTRL(ch) (ch & 037) + +#define ALLOC(x) malloc((unsigned int) x) +#define FREE(x) free((char *) x) +#define EQSTR(a, b, c) (strncmp(a, b, c) == 0) +#define EQUAL(a, b) (strcmp(a, b) == 0) +#define GOLDCALC (rnd(50 + 10 * level) + 2) +#define ISRING(h, r) (cur_ring[h] != NULL && cur_ring[h]->o_which == r) +#define ISWEARING(r) (ISRING(LEFT_1, r) || ISRING(LEFT_2, r) ||\ + ISRING(LEFT_3, r) || ISRING(LEFT_4, r) ||\ + ISRING(RIGHT_1, r) || ISRING(RIGHT_2, r) ||\ + ISRING(RIGHT_3, r) || ISRING(RIGHT_4, r)) +#define newgrp() ++group +#define o_charges o_ac +#define o_kind o_ac +#define ISMULT(type) (type == FOOD) +#define isrock(ch) ((ch == WALL) || (ch == HORZWALL) || (ch == VERTWALL) || (ch == SECRETDOOR)) +#define is_stealth(tp) \ + (rnd(25) < (tp)->t_stats.s_dext || (tp == &player && ISWEARING(R_STEALTH))) + +#define has_light(rp) (((rp)->r_flags & HASFIRE) || ISWEARING(R_LIGHT)) + +#define mi_wght mi_worth +#define mi_food mi_curse + +/* + * Ways to die + */ + +#define D_PETRIFY -1 +#define D_ARROW -2 +#define D_DART -3 +#define D_POISON -4 +#define D_BOLT -5 +#define D_SUFFOCATION -6 +#define D_POTION -7 +#define D_INFESTATION -8 +#define D_DROWN -9 +#define D_ROT -10 +#define D_CONSTITUTION -11 +#define D_STRENGTH -12 +#define D_SIGNAL -13 +#define D_CHOKE -14 +#define D_STRANGLE -15 +#define D_FALL -16 +#define D_RELIC -17 +#define D_STARVATION -18 +#define D_FOOD_CHOKE -19 +#define D_SCROLL -20 +#define D_FRIGHT -21 +#define D_CRYSTAL -22 +#define D_CARD -23 +#define DEATHNUM 23 /* number of ways to die */ + +/* + * Things that appear on the screens + */ + +#define WALL ' ' +#define PASSAGE '#' +#define DOOR '+' +#define FLOOR '.' +#define HORZWALL '-' +#define VERTWALL '|' +#define VPLAYER '@' +#define IPLAYER '_' +#define POST '^' +#define TRAPDOOR '>' +#define ARROWTRAP '{' +#define SLEEPTRAP '$' +#define BEARTRAP '}' +#define TELTRAP '~' +#define DARTTRAP '`' +#define WORMHOLE '<' +#define POOL '"' +#define MAZETRAP '\'' +#define SECRETDOOR '&' +#define STAIRS '%' +#define GOLD '*' +#define POTION '!' +#define SCROLL '?' +#define MAGIC '$' +#define BMAGIC '>' /* Blessed magic */ +#define CMAGIC '<' /* Cursed magic */ +#define FOOD ':' +#define WEAPON ')' +#define MISSILE '*' /* Magic Missile */ +#define ARMOR ']' +#define MM ';' +#define RELIC ',' +#define RING '=' +#define STICK '/' +#define FOREST '\\' + +/* + * Various constants + * Crypt() returns a different string on the PC for some silly reason + */ + +#define PASSWD "mT5uKwhm5WDRs" +#define FIGHTBASE 10 +#define BEFORE 1 +#define AFTER 2 +#define ESC 27 +#define BOLT_LENGTH 12 +#define MARKLEN 20 +#define SLEEPTIME (roll(15, 2)) +#define BEARTIME (roll(15, 2)) +#define FREEZETIME 30 +#define HEALTIME 40 +#define SICKTIME 40 +#define MORETIME 80 +#define STOMACHSIZE 2100 +#define PAINTIME (roll(15, 2)) +#define CLOAK_TIME (roll(15, 2)) +#define CHILLTIME (roll(15, 2)) +#define STONETIME (roll(15, 2)) +#define SMELLTIME (50+rnd(30)) +#define DUSTTIME (50+rnd(30)) +#define STINKTIME (50+rnd(30)) +#define HASTETIME (50+rnd(30)) +#define HUHDURATION (50+rnd(30)) +#define GONETIME (50+rnd(30)) +#define SKILLDURATION (50+rnd(30)) +#define SEEDURATION (150+rnd(50)) +#define CLRDURATION (150+rnd(50)) +#define FLYTIME (150+rnd(50)) +#define PHASEDURATION (150+rnd(50)) +#define ALCHEMYTIME (250+rnd(100)) +#define FIRETIME (180+roll(20, 2)) +#define COLDTIME (180+roll(20, 2)) +#define BOLTTIME (180+roll(20, 2)) +#define DAYLENGTH 700 +#define LEVEL 700 /* make depth of dungeon equal to DAYLENGTH */ +#define WANDERTIME (max(5, (HARDER+rnd(25))-rnd(vlevel*2))) +#define SPELLTIME ((max(30-pstats.s_lvl,5))) +#define vlevel (max(level, turns/LEVEL + 1)) + +/* + * Save against things + */ + +#define VS_POISON 00 +#define VS_PARALYZATION 00 +#define VS_DEATH 00 +#define VS_PETRIFICATION 01 +#define VS_WAND 02 +#define VS_BREATH 03 +#define VS_MAGIC 04 + +/* + * attributes for treasures in dungeon + */ + +#define ISCURSED 01 +#define ISKNOW 02 +#define ISPOST 04 /* object is in a trading post */ +#define ISMETAL 010 +#define ISPROT 020 /* object is protected */ +#define ISBLESSED 040 +#define ISPOISON 0100 +#define ISMISL 020000 +#define ISMANY 040000 + +/* + * Various flag bits + */ + +#define ISDARK 01 +#define ISGONE 02 +#define ISTREAS 04 +#define ISFOUND 010 +#define ISTHIEFSET 020 +#define FORCEDARK 040 + +/* + * 1st set of creature flags (this might include player) + */ + +#define ISBLIND 0x00000001 +#define ISINWALL 0x00000002 +#define ISRUN 0x00000004 +#define ISFLEE 0x00000008 +#define ISINVIS 0x00000010 +#define ISMEAN 0x00000020 +#define ISGREED 0x00000040 +#define CANSHOOT 0x00000080 +#define ISHELD 0x00000100 +#define ISHUH 0x00000200 +#define ISREGEN 0x00000400 +#define CANHUH 0x00000800 +#define CANSEE 0x00001000 +#define HASFIRE 0x00002000 +#define ISSLOW 0x00004000 +#define ISHASTE 0x00008000 +#define ISCLEAR 0x00010000 +#define CANINWALL 0x00020000 +#define ISDISGUISE 0x00040000 +#define CANBLINK 0x00080000 +#define CANSNORE 0x00100000 +#define HALFDAMAGE 0x00200000 +#define CANSUCK 0x00400000 +#define CANRUST 0x00800000 +#define CANPOISON 0x01000000 +#define CANDRAIN 0x02000000 +#define ISUNIQUE 0x04000000 +#define STEALGOLD 0x08000000 + +/* + * Second set of flags + */ + +#define STEALMAGIC 0x10000001 +#define CANDISEASE 0x10000002 +#define HASDISEASE 0x10000004 +#define CANSUFFOCATE 0x10000008 +#define DIDSUFFOCATE 0x10000010 +#define BOLTDIVIDE 0x10000020 +#define BLOWDIVIDE 0x10000040 +#define NOCOLD 0x10000080 +#define TOUCHFEAR 0x10000100 +#define BMAGICHIT 0x10000200 +#define NOFIRE 0x10000400 +#define NOBOLT 0x10000800 +#define CARRYGOLD 0x10001000 +#define CANITCH 0x10002000 +#define HASITCH 0x10004000 +#define DIDDRAIN 0x10008000 +#define WASTURNED 0x10010000 +#define CANSELL 0x10020000 +#define CANBLIND 0x10040000 +#define NOACID 0x10080000 +#define NOSLOW 0x10100000 +#define NOFEAR 0x10200000 +#define NOSLEEP 0x10400000 +#define NOPARALYZE 0x10800000 +#define NOGAS 0x11000000 +#define CANMISSILE 0x12000000 +#define CMAGICHIT 0x14000000 +#define CANPAIN 0x18000000 + +/* + * Third set of flags + */ + +#define CANSLOW 0x20000001 +#define CANTUNNEL 0x20000002 +#define TAKEWISDOM 0x20000004 +#define NOMETAL 0x20000008 +#define MAGICHIT 0x20000010 +#define CANINFEST 0x20000020 +#define HASINFEST 0x20000040 +#define NOMOVE 0x20000080 +#define CANSHRIEK 0x20000100 +#define CANDRAW 0x20000200 +#define CANSMELL 0x20000400 +#define CANPARALYZE 0x20000800 +#define CANROT 0x20001000 +#define ISSCAVENGE 0x20002000 +#define DOROT 0x20004000 +#define CANSTINK 0x20008000 +#define HASSTINK 0x20010000 +#define ISSHADOW 0x20020000 +#define CANCHILL 0x20040000 +#define CANHUG 0x20080000 +#define CANSURPRISE 0x20100000 +#define CANFRIGHTEN 0x20200000 +#define CANSUMMON 0x20400000 +#define TOUCHSTONE 0x20800000 +#define LOOKSTONE 0x21000000 +#define CANHOLD 0x22000000 +#define DIDHOLD 0x24000000 +#define DOUBLEDRAIN 0x28000000 + +/* + * Fourth set of flags + */ + +#define CANBRANDOM 0x30000001 /* Types of breath */ +#define CANBACID 0x30000002 /* acid */ +#define CANBFIRE 0x30000004 /* Fire */ +#define CANBCGAS 0x30000008 /* confusion gas */ +#define CANBBOLT 0x30000010 /* lightning bolt */ +#define CANBGAS 0x30000020 /* chlorine gas */ +#define CANBICE 0x30000040 /* ice */ +#define CANBFGAS 0x30000080 /* Fear gas */ +#define CANBPGAS 0x30000100 /* Paralyze gas */ +#define CANBSGAS 0x30000200 /* Sleeping gas */ +#define CANBSLGAS 0x30000400 /* Slow gas */ +#define CANBREATHE 0x300007ff /* Can it breathe at all? */ + +/* + * Fifth set of flags + */ + +#define ISUNDEAD 0x40000001 +#define CANSONIC 0x40000002 +#define TURNABLE 0x40000004 +#define TAKEINTEL 0x40000008 +#define NOSTAB 0x40000010 +#define CANDISSOLVE 0x40000020 +#define ISFLY 0x40000040 /* creature can fly */ +#define CANTELEPORT 0x40000080 /* creature can teleport */ +#define CANEXPLODE 0x40000100 /* creature explodes when hit */ +#define CANDANCE 0x40000200 /* creature can make hero "dance" */ +#define ISDANCE 0x40000400 /* creature (hero) is dancing */ +#define CARRYFOOD 0x40000800 +#define CARRYSCROLL 0x40001000 +#define CARRYPOTION 0x40002000 +#define CARRYRING 0x40004000 +#define CARRYSTICK 0x40008000 +#define CARRYMISC 0x40010000 +#define CARRYMDAGGER 0x40020000 /* Dagger of Musty */ +#define CARRYCLOAK 0x40040000 /* Cloak of Emori */ +#define CARRYANKH 0x40080000 /* Ankh of Heil */ +#define CARRYSTAFF 0x40100000 /* Staff of Ming */ +#define CARRYWAND 0x40200000 /* Wand of Orcus */ +#define CARRYROD 0x40400000 /* Rod of Asmodeus */ +#define CARRYYAMULET 0x40800000 /* Amulet of Yendor */ +#define CARRYMANDOLIN 0x41000000 /* Mandolin of Brian */ +#define MISSEDDISP 0x42000000 /* Missed Cloak of Displacement */ +#define CANBSTAB 0x44000000 /* Can backstab */ +#define ISGUARDIAN 0x48000000 /* Guardian of a treasure room */ + +/* + * Sixth set of flags + */ + +#define CARRYHORN 0x50000001 /* Horn of Geryon */ +#define CARRYMSTAR 0x50000002 /* Morning Star of Hruggek */ +#define CARRYFLAIL 0x50000004 /* Flail of Yeenoghu */ +#define CARRYWEAPON 0x50000008 /* A generic weapon */ +#define CANAGE 0x50000010 /* can age you */ +#define CARRYDAGGER 0x50000020 /* carry's a dumb old dagger */ +#define AREMANY 0x50000040 /* they come in droves */ +#define CARRYEYE 0x50000080 /* has the eye of Vecna */ +#define HASSUMMONED 0x50000100 /* has already summoned */ +#define ISSTONE 0x50000200 /* has been turned to stone */ +#define NODETECT 0x50000400 /* detect monster will not show him */ +#define NOSTONE 0x50000800 /* creature made its save vrs stone */ +#define CARRYQUILL 0x50001000 /* has the quill of Nagrom */ +#define CARRYAXE 0x50002000 /* has the axe of Aklad */ +#define TOUCHSLOW 0x50004000 /* touch will slow hero */ +#define WASDISRUPTED 0x50008000 /* creature was disrupted by player */ +#define CARRYARMOR 0x50010000 /* creature will pick up armor */ +#define CARRYBAMULET 0x50020000 /* amulet of skoraus stonebones */ +#define CARRYSURTURRING 0x50040000 /* ring of Surtur */ +#define CARRYCARD 0x50080000 /* carry the card of Alteran */ +#define ISCHARMED 0x50100000 /* is the monster charmed? */ +#define ISFRIENDLY 0x50100000 /* monster friendly for any reason? */ + +#define NEEDSTOACT 0x60000001 /* monster ready to act this turn n */ +#define ISDEAD 0x60000002 /* monster is dead */ +#define ISELSEWHERE 0x60000004 /* monster has been whisked away */ + +/* Masks for choosing the right flag */ + +#define FLAGMASK 0xf0000000 +#define FLAGINDEX 0x0000000f +#define FLAGSHIFT 28 +#define MAXFLAGS 25 /* max initial flags per creature */ + +/* + * Mask for cancelling special abilities + * The flags listed here will be the ones left on after the + * cancellation takes place + */ + +#define CANC0MASK ( ISBLIND | ISINWALL | ISRUN | \ + ISFLEE | ISMEAN | ISGREED | \ + CANSHOOT | ISHELD | ISHUH | \ + ISSLOW | ISHASTE | ISCLEAR | \ + ISUNIQUE ) +#define CANC1MASK ( HASDISEASE | DIDSUFFOCATE | CARRYGOLD | \ + HASITCH | CANSELL | DIDDRAIN | \ + WASTURNED ) +#define CANC2MASK ( HASINFEST | NOMOVE | ISSCAVENGE | \ + DOROT | HASSTINK | DIDHOLD ) +#define CANC3MASK ( CANBREATHE ) +#define CANC4MASK ( ISUNDEAD | CANSONIC | NOSTAB | \ + ISFLY | CARRYFOOD | CANEXPLODE | \ + ISDANCE | CARRYSCROLL | CARRYPOTION | \ + CARRYRING | CARRYSTICK | CARRYMISC | \ + CARRYMDAGGER | CARRYCLOAK | CARRYANKH | \ + CARRYSTAFF | CARRYWAND | CARRYROD | \ + CARRYYAMULET | CARRYMANDOLIN | ISGUARDIAN ) +#define CANC5MASK ( CARRYHORN | CARRYMSTAR | CARRYFLAIL | \ + CARRYEYE | CARRYDAGGER | HASSUMMONED | \ + AREMANY | CARRYWEAPON | NOSTONE | \ + CARRYQUILL | CARRYAXE | WASDISRUPTED | \ + CARRYARMOR | CARRYBAMULET | CARRYSURTURRING ) +#define CANC6MASK ( CARRYCARD ) +#define CANC7MASK ( 0 ) +#define CANC8MASK ( 0 ) +#define CANC9MASK ( 0 ) +#define CANCAMASK ( 0 ) +#define CANCBMASK ( 0 ) +#define CANCCMASK ( 0 ) +#define CANCDMASK ( 0 ) +#define CANCEMASK ( 0 ) +#define CANCFMASK ( 0 ) + +/* types of things */ + +#define TYP_POTION 0 +#define TYP_SCROLL 1 +#define TYP_FOOD 2 +#define TYP_WEAPON 3 +#define TYP_ARMOR 4 +#define TYP_RING 5 +#define TYP_STICK 6 +#define TYP_MM 7 +#define TYP_RELIC 8 +#define NUMTHINGS 9 + +/* + * food types + */ + +#define E_RATION 0 +#define E_APPLE 1 +#define E_BANANA 2 +#define E_BLUEBERRY 3 +#define E_CANDLEBERRY 4 +#define E_CAPRIFIG 5 +#define E_DEWBERRY 6 +#define E_ELDERBERRY 7 +#define E_GOOSEBERRY 8 +#define E_GUANABANA 9 +#define E_HAGBERRY 10 +#define E_JABOTICABA 11 +#define E_PEACH 12 +#define E_PITANGA 13 +#define E_PRICKLEY 14 +#define E_RAMBUTAN 15 +#define E_SAPODILLA 16 +#define E_SOURSOP 17 +#define E_STRAWBERRY 18 +#define E_SWEETSOP 19 +#define E_WHORTLEBERRY 20 +#define E_SLIMEMOLD 21 +#define MAXFOODS 22 + +/* + * Potion types + */ + +#define P_CLEAR 0 +#define P_ABIL 1 +#define P_SEEINVIS 2 +#define P_HEALING 3 +#define P_MFIND 4 +#define P_TFIND 5 +#define P_RAISE 6 +#define P_HASTE 7 +#define P_RESTORE 8 +#define P_PHASE 9 +#define P_INVIS 10 +#define P_FLY 11 +#define P_FFIND 12 +#define P_SKILL 13 +#define P_FIRE 14 +#define P_COLD 15 +#define P_LIGHTNING 16 +#define P_POISON 17 +#define MAXPOTIONS 18 + +/* + * Scroll types + */ + +#define S_CONFUSE 0 +#define S_MAP 1 +#define S_LIGHT 2 +#define S_HOLD 3 +#define S_SLEEP 4 +#define S_ALLENCH 5 +#define S_IDENT 6 +#define S_SCARE 7 +#define S_GFIND 8 +#define S_TELEP 9 +#define S_CREATE 10 +#define S_REMOVE 11 +#define S_PETRIFY 12 +#define S_GENOCIDE 13 +#define S_CURING 14 +#define S_MAKEIT 15 +#define S_PROTECT 16 +#define S_FINDTRAPS 17 +#define S_RUNES 18 +#define S_CHARM 19 +#define MAXSCROLLS 20 + +/* + * Weapon types + */ + +#define MACE 0 /* mace */ +#define SWORD 1 /* long sword */ +#define BOW 2 /* short bow */ +#define ARROW 3 /* arrow */ +#define DAGGER 4 /* dagger */ +#define ROCK 5 /* rocks */ +#define TWOSWORD 6 /* two-handed sword */ +#define SLING 7 /* sling */ +#define DART 8 /* darts */ +#define CROSSBOW 9 /* crossbow */ +#define BOLT 10 /* crossbow bolt */ +#define SPEAR 11 /* spear */ +#define TRIDENT 12 /* trident */ +#define SPETUM 13 /* spetum */ +#define BARDICHE 14 /* bardiche */ +#define PIKE 15 /* pike */ +#define BASWORD 16 /* bastard sword */ +#define HALBERD 17 /* halberd */ +#define BATTLEAXE 18 /* battle axe */ +#define MAXWEAPONS 19 /* types of weapons */ +#define NONE 100 /* no weapon */ + +/* + * Armor types + */ + +#define LEATHER 0 +#define RING_MAIL 1 +#define STUDDED_LEATHER 2 +#define SCALE_MAIL 3 +#define PADDED_ARMOR 4 +#define CHAIN_MAIL 5 +#define SPLINT_MAIL 6 +#define BANDED_MAIL 7 +#define PLATE_MAIL 8 +#define PLATE_ARMOR 9 +#define MAXARMORS 10 + +/* + * Ring types + */ + +#define R_PROTECT 0 +#define R_ADDSTR 1 +#define R_SUSABILITY 2 +#define R_SEARCH 3 +#define R_SEEINVIS 4 +#define R_ALERT 5 +#define R_AGGR 6 +#define R_ADDHIT 7 +#define R_ADDDAM 8 +#define R_REGEN 9 +#define R_DIGEST 10 +#define R_TELEPORT 11 +#define R_STEALTH 12 +#define R_ADDINTEL 13 +#define R_ADDWISDOM 14 +#define R_HEALTH 15 +#define R_CARRY 16 +#define R_LIGHT 17 +#define R_DELUSION 18 +#define R_FEAR 19 +#define R_HEROISM 20 +#define R_FIRE 21 +#define R_WARMTH 22 +#define R_VAMPREGEN 23 +#define R_FREEDOM 24 +#define R_TELCONTROL 25 +#define MAXRINGS 26 + +/* + * Rod/Wand/Staff types + */ + +#define WS_LIGHT 0 +#define WS_HIT 1 +#define WS_ELECT 2 +#define WS_FIRE 3 +#define WS_COLD 4 +#define WS_POLYMORPH 5 +#define WS_MISSILE 6 +#define WS_SLOW_M 7 +#define WS_DRAIN 8 +#define WS_CHARGE 9 +#define WS_TELMON 10 +#define WS_CANCEL 11 +#define WS_CONFMON 12 +#define WS_DISINTEGRATE 13 +#define WS_PETRIFY 14 +#define WS_PARALYZE 15 +#define WS_MDEG 16 +#define WS_CURING 17 +#define WS_WONDER 18 +#define WS_FEAR 19 +#define MAXSTICKS 20 + +/* + * miscellaneous magic items + */ + +#define MM_JUG 0 +#define MM_BEAKER 1 +#define MM_BOOK 2 +#define MM_ELF_BOOTS 3 +#define MM_BRACERS 4 +#define MM_OPEN 5 +#define MM_HUNGER 6 +#define MM_DISP 7 +#define MM_PROTECT 8 +#define MM_DRUMS 9 +#define MM_DISAPPEAR 10 +#define MM_CHOKE 11 +#define MM_G_DEXTERITY 12 +#define MM_G_OGRE 13 +#define MM_JEWEL 14 +#define MM_KEOGHTOM 15 +#define MM_R_POWERLESS 16 +#define MM_FUMBLE 17 +#define MM_ADAPTION 18 +#define MM_STRANGLE 19 +#define MM_DANCE 20 +#define MM_SKILLS 21 +#define MM_CRYSTAL 22 +#define MAXMM 23 + +/* + * Relic types + */ + +#define MUSTY_DAGGER 0 +#define EMORI_CLOAK 1 +#define HEIL_ANKH 2 +#define MING_STAFF 3 +#define ORCUS_WAND 4 +#define ASMO_ROD 5 +#define YENDOR_AMULET 6 +#define BRIAN_MANDOLIN 7 +#define GERYON_HORN 8 +#define HRUGGEK_MSTAR 9 +#define YEENOGHU_FLAIL 10 +#define EYE_VECNA 11 +#define AXE_AKLAD 12 +#define QUILL_NAGROM 13 +#define STONEBONES_AMULET 14 +#define SURTUR_RING 15 +#define ALTERAN_CARD 16 +#define MAXRELIC 17 + +#define MAXDAEMONS 10 +#define MAXFUSES 20 + +struct delayed_action { + int d_type; + int (*d_func)(); + union { + VOID *vp; + int i; + } d_arg; + int d_time; +}; + +extern struct delayed_action d_list[MAXDAEMONS]; +extern struct delayed_action f_list[MAXFUSES]; +extern int demoncnt; /* number of active daemons */ +extern int fusecnt; + +/* Now define the structures and types */ + +/* + * character types + */ + +struct character_types { + char name[40]; /* name of character class */ + long start_exp; /* starting exp pts for 2nd level */ + long cap; /* stop doubling here */ + int hit_pts; /* hit pts gained per level */ + int base; /* Base to-hit value (AC 10) */ + int max_lvl; /* Maximum level for changing value */ + int factor; /* Amount base changes each time */ + int offset; /* What to offset level */ + int range; /* Range of levels for each offset */ +}; + +/* + * level types + */ + +typedef enum { + NORMLEV, /* normal level */ + POSTLEV, /* trading post level */ + MAZELEV, /* maze level */ + OUTSIDE, /* outside region */ + STARTLEV /* beginning of the game */ +} LEVTYPE; + +/* + * Help lists + */ + +struct h_list { + char h_ch; + char h_desc[40]; +}; + +struct item_list { + unsigned char item_ch; + char item_desc[40]; +}; + +/* + * Coordinate data type + */ + +typedef struct { + int x; + int y; +} coord; + +/* + * structure for the ways to die + */ + +struct death_type { + int reason; + char name[30]; +}; + +/* + * Linked list data type + */ + +struct linked_list { + struct linked_list *l_next; + struct linked_list *l_prev; + char *l_data; /* Various structure pointers */ +}; + +/* + * Stuff about magic items + */ + +struct magic_item { + char mi_name[30]; + int mi_prob; + int mi_worth; + int mi_curse; + int mi_bless; +}; + +/* + * Room structure + */ + +struct room { + coord r_pos; /* Upper left corner */ + coord r_max; /* Size of room */ + long r_flags; /* Info about the room */ + struct linked_list *r_fires; /* List of fire creatures in room */ + struct linked_list *r_exit; /* Linked list of exits */ +}; + +/* + * Array of all traps on this level + */ + +struct trap { + unsigned char tr_type; /* What kind of trap */ + unsigned char tr_show; /* Where disguised trap looks like */ + coord tr_pos; /* Where trap is */ + long tr_flags; /* Info about trap (i.e. ISFOUND) */ +}; + +/* + * Structure describing a fighting being + */ + +struct stats { + short s_str; /* Strength */ + short s_intel; /* Intelligence */ + short s_wisdom; /* Wisdom */ + short s_dext; /* Dexterity */ + short s_const; /* Constitution */ + short s_charisma; /* Charisma */ + unsigned long s_exp; /* Experience */ + int s_lvladj; /* how much level is adjusted */ + int s_lvl; /* Level of mastery */ + int s_arm; /* Armor class */ + int s_hpt; /* Hit points */ + int s_pack; /* current weight of his pack */ + int s_carry; /* max weight he can carry */ + char s_dmg[30]; /* String describing damage done */ +}; + +/* + * Structure describing a fighting being (monster at initialization) + */ + +struct mstats { + short ms_str; /* Strength */ + short ms_dex; /* dexterity */ + short ms_move; /* movement rate */ + unsigned long ms_exp; /* Experience */ + short ms_lvl; /* Level of mastery */ + short ms_arm; /* Armor class */ + char ms_hpt[9]; /* Hit points */ + char ms_dmg[30]; /* String describing damage done */ +}; + +/* + * Structure for monsters and player + */ + +struct thing { + bool t_wasshot; /* Was character shot last round? */ + unsigned char t_type; /* What it is */ + unsigned char t_disguise; /* What mimic looks like */ + unsigned char t_oldch; /* Character that was where it was */ + short t_ctype; /* Character type */ + short t_index; /* Index into monster table */ + short t_no_move; /* How long the thing can't move */ + short t_quiet; /* used in healing */ + short t_movement; /* Base movement rate */ + short t_action; /* Action we're waiting to do */ + short t_artifact; /* base chance of using artifact */ + short t_wand; /* base chance of using wands */ + short t_summon; /* base chance of summoning */ + short t_cast; /* base chance of casting a spell */ + short t_breathe; /* base chance to swing at player */ + char *t_name; /* name player gave his pet */ + coord t_doorgoal; /* What door are we heading to? */ + coord *t_dest; /* Where it is running to */ + coord t_pos; /* Position */ + coord t_oldpos; /* Last position */ + coord t_newpos; /* Where we want to go */ + unsigned long t_flags[16]; /* State word */ + struct linked_list *t_pack; /* What the thing is carrying */ + struct linked_list *t_using; /* What the thing is using */ + int t_selection; + struct stats t_stats; /* Physical description */ + struct stats maxstats; /* maximum(or initial) stats */ + int t_reserved; /* reserved for save/restore code */ +}; + +/* + * Array containing information on all the various types of monsters + */ + +struct monster { + char m_name[30]; /* What to call the monster */ + short m_carry; /* Probability of carrying something */ + bool m_normal; /* Does monster exist? */ + bool m_wander; /* Does monster wander? */ + char m_appear; /* What does monster look like? */ + char m_intel[8]; /* Intelligence range */ + long m_flags[MAXFLAGS]; /* Things about the monster */ + char m_typesum[30]; /* type of creature can he summon */ + short m_numsum; /* how many creatures can he summon */ + short m_add_exp; /* Added experience per hit point */ + struct mstats m_stats; /* Initial stats */ +}; + +/* + * Structure for a thing that the rogue can carry + */ + +struct object { + int o_type; /* What kind of object it is */ + coord o_pos; /* Where it lives on the screen */ + char o_launch; /* What you need to launch it */ + char o_damage[8]; /* Damage if used like sword */ + char o_hurldmg[8]; /* Damage if thrown */ + struct linked_list *contents; /* contents of this object */ + int o_count; /* Count for plural objects */ + int o_which; /* Which object of a type it is */ + int o_hplus; /* Plusses to hit */ + int o_dplus; /* Plusses to damage */ + int o_ac; /* Armor class */ + long o_flags; /* Information about objects */ + int o_group; /* Group number for this object */ + int o_weight; /* weight of this object */ + unsigned char o_mark[MARKLEN]; /* Mark the specific object */ +}; + +/* + * weapon structure + */ + +struct init_weps { + char w_name[20]; /* name of weapon */ + char w_dam[8]; /* hit damage */ + char w_hrl[8]; /* hurl damage */ + char w_launch; /* need to launch it */ + int w_flags; /* flags */ + int w_rate; /* rate of fire */ + int w_wght; /* weight of weapon */ + int w_worth; /* worth of this weapon */ +}; + +/* + * armor structure + */ + +struct init_armor { + char a_name[30]; /* name of armor */ + int a_prob; /* chance of getting armor */ + int a_class; /* normal armor class */ + int a_worth; /* worth of armor */ + int a_wght; /* weight of armor */ +}; + +struct spells { + short s_which; /* which scroll or potion */ + short s_cost; /* cost of casting spell */ + short s_type; /* scroll or potion */ + int s_flag; /* is the spell blessed/cursed? */ +}; + +struct words +{ + char w_string[30]; +}; + +#define NAMELEN 80 +#define SYSLEN 10 +#define LOGLEN 9 + +struct sc_ent { + unsigned long sc_score; + char sc_name[NAMELEN]; + char sc_system[SYSLEN]; + char sc_login[LOGLEN]; + short sc_flags; + short sc_level; + short sc_ctype; + short sc_monster; + short sc_quest; +}; + +/* + * Other structures + */ + +struct linked_list *find_mons(), *find_obj(), *get_item(), *new_item(), + *new_thing(), *wake_monster(), *get_hurl(), *spec_item(), + *creat_item(), *wield_weap(); + +struct room *roomin(); +struct trap *trap_at(); + +char *getenv(), *tr_name(), *new(), *vowelstr(), + *inv_name(), *num(), + *ring_num(), *misc_num(), *blesscurse(), *p_kind(), *typ_name(), + *prname(), *monster_name(), *weap_name(); + +coord rndmove(), *fallpos(), *doorway(), get_coordinates(); +int can_shoot(),misc_name(); + +short randmonster(), id_monst(), movement(); + +int bugkill(), nohaste(), spell_recovery(), doctor(), runners(), swander(), + unconfuse(), unsee(), fumble(), unclrhead(), unphase(), noslow(), + rollwand(), stomach(), sight(), unstink(), suffocate(), cure_disease(), + shoot_bolt(), changeclass(), appear(), dust_appear(), unchoke(), + alchemy(), trap_look(), strangle(), ring_teleport(), ring_search(), + grab(), dsrpt_player(), quill_charge(), make_sell_pack(), unskill(), + findmindex(), nobolt(), nofire(), nocold(), usage_time(), eat_gold(), + chant_recovery(), prayer_recovery(), dsrpt_monster(), opt_player(); + +bool blue_light(), can_blink(), creat_mons(), add_pack(), invisible(), + straight_shot(), maze_view(), lit_room(), getdelta(), save_file(), + save_game(), m_use_it(), m_use_pack(), get_dir(), need_dir(),passwd(); + +long check_level(); +long encread(); +long get_worth(); +long encwrite(); + +void byebye(int sig), genmonsters(), quit(int sig), + auto_save(int sig), endit(int sig), tstp(); + +void teleport(); + +void writelog(unsigned long amount, int flags, short monst); + +int undance(), land(), cloak_charge(), wghtchk(); + +int add_intelligence(), add_strength(), add_wisdom(), add_dexterity(), + add_constitution(), add_charisma(), res_intelligence(), res_strength(), + res_wisdom(), res_dexterity(), res_constitution(), res_charisma(); + +/* + * Now all the global variables + */ + +extern struct trap traps[]; +extern struct character_types char_class[]; /* character classes */ +extern struct room rooms[]; /* One for each room -- A level */ +extern struct room *oldrp; /* Roomin(&oldpos) */ +extern struct linked_list *mlist; /* List of monsters on the level */ +extern struct linked_list *tlist; /* list of monsters fallen down traps */ +extern struct linked_list *rlist; /* list of monsters that have died */ +extern struct death_type deaths[]; /* all the ways to die */ +extern struct thing player; /* The rogue */ +extern struct monster monsters[NUMMONST+1]; /* The initial monster states */ +extern struct linked_list *lvl_obj; /* List of objects on this level */ +extern struct linked_list *monst_dead; /* Indicates monster that got killed */ +extern struct object *cur_weapon; /* Which weapon he is weilding */ +extern struct object *cur_armor; /* What a well dresssed rogue wears */ +extern struct object *cur_ring[]; /* Which rings are being worn */ +extern struct object *cur_misc[]; /* which MM's are in use */ +extern struct magic_item things[]; /* Chances for each type of item */ +extern struct magic_item s_magic[]; /* Names and chances for scrolls */ +extern struct magic_item p_magic[]; /* Names and chances for potions */ +extern struct magic_item r_magic[]; /* Names and chances for rings */ +extern struct magic_item ws_magic[]; /* Names and chances for sticks */ +extern struct magic_item m_magic[]; /* Names and chances for MM */ +extern struct magic_item rel_magic[]; /* Names and chances for relics */ +extern struct magic_item foods[]; /* Names and chances for foods */ +extern struct spells magic_spells[]; /* spells for magicians */ +extern struct spells cleric_spells[]; /* spells for clerics */ +extern struct spells druid_spells[]; /* spells for druids */ +extern struct spells quill_scrolls[]; /* scrolls for quill */ +extern const char *cnames[][NUM_CNAMES]; /* Character level names */ +extern struct words abilities[NUMABILITIES]; /* Names of the various abilities */ +extern char curpurch[]; /* name of item ready to buy */ +extern char PLAYER; /* what the player looks like */ +extern int nfloors; /* Number of floors in this dungeon */ +extern int cols; /* number of columns on terminal */ +extern int lines; /* number of lines in terminal */ +extern int char_type; /* what type of character is player */ +extern int foodlev; /* how fast he eats food */ +extern int level; /* What level rogue is on */ +extern int trader; /* number of purchases */ +extern int curprice; /* price of an item */ +extern long purse; /* How much gold the rogue has */ +extern int mpos; /* Where cursor is on top line */ +extern int ntraps; /* Number of traps on this level */ +extern int inpack; /* Number of things in pack */ +extern int total; /* Total dynamic memory bytes */ +extern int lastscore; /* Score before this turn */ +extern int no_food; /* Number of levels without food */ +extern int foods_this_level; /* num of foods this level */ +extern int seed; /* Random number seed */ +extern int count; /* Number of times to repeat command */ +extern int max_level; /* Deepest player has gone */ +extern int cur_max; /* Deepest player has gone currently */ +extern int prev_max; /* A flag for worm hole */ +extern int move_free; /* Free movement check */ +extern int food_left; /* Amount of food in hero's stomach */ +extern int group; /* Current group number */ +extern int hungry_state; /* How hungry is he */ +extern int infest_dam; /* Damage from parasites */ +extern int lost_str; /* Amount of strength lost */ +extern int hold_count; /* Number of monsters holding player */ +extern int trap_tries; /* Number of attempts to set traps */ +extern int chant_time; /* Number of chant points/exp level */ +extern int pray_time; /* Number of prayer points/exp level */ +extern int spell_power; /* Spell power left at this level */ +extern long turns; /* Number of turns player has taken */ +extern int quest_item; /* Item hero is looking for */ +extern int cur_relic[]; /* Current relics */ +extern char take; /* Thing the rogue is taking */ +extern char prbuf[]; /* Buffer for sprintfs */ +extern char outbuf[]; /* Output buffer for stdout */ +extern char runch; /* Direction player is running */ +extern char *s_names[]; /* Names of the scrolls */ +extern char *p_colors[]; /* Colors of the potions */ +extern char *r_stones[]; /* Stone settings of the rings */ +extern struct init_weps weaps[]; /* weapons and attributes */ +extern struct init_armor armors[]; /* armors and attributes */ +extern char *ws_made[]; /* What sticks are made of */ +extern char *release; /* Release number of rogue */ +extern char whoami[]; /* Name of player */ +extern char fruit[]; /* Favorite fruit */ +extern char huh[]; /* The last message printed */ +extern char *s_guess[]; /* Players guess at what scroll is */ +extern char *p_guess[]; /* Players guess at what potion is */ +extern char *r_guess[]; /* Players guess at what ring is */ +extern char *ws_guess[]; /* Players guess at what wand is */ +extern char *m_guess[]; /* Players guess at what MM is */ +extern char *ws_type[]; /* Is it a wand or a staff */ +extern char file_name[]; /* Save file name */ +extern char score_file[]; /* Score file name */ +extern char home[]; /* User's home directory */ +extern WINDOW *cw; /* Window that the player sees */ +extern WINDOW *hw; /* Used for the help command */ +extern WINDOW *mw; /* Used to store mosnters */ +extern WINDOW *msgw; /* Message window */ +extern bool pool_teleport; /* just teleported from a pool */ +extern bool inwhgt; /* true if from wghtchk() */ +extern bool running; /* True if player is running */ +extern bool playing; /* True until he quits */ +extern bool wizard; /* True if allows wizard commands */ +extern bool after; /* True if we want after daemons */ +extern bool notify; /* True if player wants to know */ +extern bool fight_flush; /* True if toilet input */ +extern bool terse; /* True if we should be short */ +extern bool auto_pickup; /* Pick up things automatically? */ +extern bool menu_overlay; /* Use overlay type menu */ +extern bool door_stop; /* Stop running when we pass a door */ +extern bool jump; /* Show running as series of jumps */ +extern bool slow_invent; /* Inventory one line at a time */ +extern bool def_attr; /* True for default attributes */ +extern bool firstmove; /* First move after setting door_stop */ +extern bool waswizard; /* Was a wizard sometime */ +extern bool askme; /* Ask about unidentified things */ +extern bool use_savedir; /* Use common save location */ +extern bool s_know[]; /* Does he know what a scroll does */ +extern bool p_know[]; /* Does he know what a potion does */ +extern bool r_know[]; /* Does he know what a ring does */ +extern bool ws_know[]; /* Does he know what a stick does */ +extern bool m_know[]; /* Does he know what a MM does */ +extern bool in_shell; /* True if executing a shell */ +extern bool daytime; /* Indicates whether it is daytime */ +extern bool funfont; /* Is fun font available? */ +extern coord oldpos; /* Position before last look() call */ +extern coord grid[]; /* used for random pos generation */ +extern char *nothing; /* "Nothing seems to happen." */ +extern char *spacemsg; +extern char *morestr; +extern char *retstr; +extern LEVTYPE levtype; +extern int (*add_abil[NUMABILITIES])(); /* Functions to change abilities */ +extern int (*res_abil[NUMABILITIES])(); /* Functions to change abilities */ +extern int mf_count; /* move_free counter - see actions.c(m_act()) */ +extern int mf_jmpcnt; /* move_free counter for # of jumps */ +extern int killed_chance; /* cumulative chance for goodies to loose it, fight.c */ +extern coord move_nh; /* move.c */ +#define NCOLORS 32 +#define NSYLLS 127 +#define NSTONES 47 +#define NWOOD 24 +#define NMETAL 16 +extern struct words rainbow[NCOLORS]; +extern struct words sylls[NSYLLS]; +extern struct words stones[NSTONES]; +extern struct words wood[NWOOD]; +extern struct words metal[NMETAL]; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/rooms.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,296 @@ +/* + rooms.c - Draw the nine rooms on the screen + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <stdlib.h> +#include <curses.h> +#include "rogue.h" + +do_rooms() +{ + register int i; + register struct room *rp; + register struct linked_list *item; + register struct thing *tp; + int left_out; + int num_monsters; + int which_monster; + int j; + coord top; + coord bsze; + coord mp; + coord *np; + + /* + * bsze is the maximum room size + */ + bsze.x = cols/3; + bsze.y = (lines-2)/3; + /* + * Clear things for a new level + */ + for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) { + rp->r_flags = 0; + _r_free_fire_list(&rp->r_fires); + } + /* + * Put the gone rooms, if any, on the level + */ + left_out = rnd(4); + for (i = 0; i < left_out; i++) + rooms[rnd_room()].r_flags |= ISGONE; + /* + * dig and populate all the rooms on the level + */ + for (i = 0, rp = rooms; i < MAXROOMS; rp++, i++) + { + bool has_gold=FALSE; + + /* + * Find upper left corner of box that this room goes in + */ + top.x = (i%3)*bsze.x; + top.y = i/3*bsze.y + 1; + if (rp->r_flags & ISGONE) + { + /* + * Place a gone room. Make certain that there is a blank line + * for passage drawing. + */ + do + { + rp->r_pos.x = top.x + rnd(bsze.x-2) + 1; + rp->r_pos.y = top.y + rnd(bsze.y-2) + 1; + rp->r_max.x = -cols; + rp->r_max.y = -lines; + } until(rp->r_pos.y > 0 && rp->r_pos.y < lines-2); + continue; + } + if (rnd(10) < level-1) + rp->r_flags |= ISDARK; + /* + * Find a place and size for a random room + */ + do + { + rp->r_max.x = rnd(bsze.x - 4) + 4; + rp->r_max.y = rnd(bsze.y - 4) + 4; + rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x); + rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y); + } until (rp->r_pos.y != 0); + + /* Draw the room */ + draw_room(rp); + + /* + * Put the gold in + */ + if (rnd(100) < 55 && level >= cur_max) + { + register struct linked_list *item; + register struct object *cur; + coord tp; + + has_gold = TRUE; /* This room has gold in it */ + + item = spec_item(GOLD, NULL, NULL, NULL); + cur = OBJPTR(item); + + /* Put the gold into the level list of items */ + attach(lvl_obj, item); + + /* Put it somewhere */ + rnd_pos(rp, &tp); + mvaddch(tp.y, tp.x, GOLD); + cur->o_pos = tp; + if (roomin(&tp) != rp) { + endwin(); + abort(); + } + } + + /* + * Put the monster in + */ + if (rnd(100) < (has_gold ? 80 : 25) + vlevel/2) + { + do + { + rnd_pos(rp, &mp); + } until(mvwinch(stdscr, mp.y, mp.x) == FLOOR); + which_monster = randmonster(FALSE, FALSE); + num_monsters = 1; + /* + * see if we should make a whole bunch + */ + for (j=0; j<MAXFLAGS; j++) { + if (monsters[which_monster].m_flags[j] == AREMANY) + num_monsters = roll(7,2); + } + for (j=0; j<num_monsters; j++) { + if ((np = fallpos(&mp, FALSE, 2)) != NULL && + mvwinch(stdscr, np->y, np->x) == FLOOR) { + item = new_item(sizeof *tp); + tp = THINGPTR(item); + new_monster(item, which_monster, np, FALSE); + /* + * See if we want to give it a treasure to + * carry around. + */ + carry_obj(tp, monsters[tp->t_index].m_carry); + tp->t_no_move = movement(tp); + + /* + * If it has a fire, mark it + */ + if (on(*tp, HASFIRE)) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rp->r_fires, fire_item); + rp->r_flags |= HASFIRE; + } + } + } + } + } +} + +/* + * Given a room pointer and a pointer to a door, supposedly in that room, + * return the coordinates of the entrance to the doorway. + */ + +coord * +doorway(rp, door) +register struct room *rp; +register coord *door; +{ + register int misses = 0; + static coord answer; + + /* Do we have decent parameters? */ + if (rp == NULL || door == NULL) return(NULL); + + /* Initialize the answer to be the door, then calculate the offset */ + answer = *door; + + /* Calculate the x-offset */ + if (door->x == rp->r_pos.x) answer.x++; + else if (door->x == rp->r_pos.x + rp->r_max.x - 1) answer.x--; + else misses++; + + /* Calculate the y-offset */ + if (door->y == rp->r_pos.y) answer.y++; + else if (door->y == rp->r_pos.y + rp->r_max.y - 1) answer.y--; + else misses++; + + if (misses <= 1) return(&answer); + else return(NULL); +} + +/* + * Draw a box around a room + */ + +draw_room(rp) +register struct room *rp; +{ + register int j, k; + + move(rp->r_pos.y, rp->r_pos.x+1); + vert(rp->r_max.y-2); /* Draw left side */ + move(rp->r_pos.y+rp->r_max.y-1, rp->r_pos.x); + horiz(rp->r_max.x); /* Draw bottom */ + move(rp->r_pos.y, rp->r_pos.x); + horiz(rp->r_max.x); /* Draw top */ + vert(rp->r_max.y-2); /* Draw right side */ + /* + * Put the floor down + */ + for (j = 1; j < rp->r_max.y-1; j++) + { + move(rp->r_pos.y + j, rp->r_pos.x+1); + for (k = 1; k < rp->r_max.x-1; k++) + addch(FLOOR); + } +} + +/* + * horiz: + * draw a horizontal line + */ + +horiz(cnt) +register int cnt; +{ + while (cnt--) + addch(HORZWALL); +} + +/* + * rnd_pos: + * pick a random spot in a room + */ + +rnd_pos(rp, cp) +register struct room *rp; +register coord *cp; +{ + cp->x = rp->r_pos.x + rnd(rp->r_max.x-2) + 1; + cp->y = rp->r_pos.y + rnd(rp->r_max.y-2) + 1; +} + + + +/* + * roomin: + * Find what room some coordinates are in. NULL means they aren't + * in any room. + */ + +struct room * +roomin(cp) +register coord *cp; +{ + register struct room *rp; + + for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) + if (inroom(rp, cp)) + return rp; + return NULL; +} + +/* + * vert: + * draw a vertical line + */ + +vert(cnt) +register int cnt; +{ + register int x, y; + + getyx(stdscr, y, x); + x--; + while (cnt--) { + move(++y, x); + addch(VERTWALL); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/save.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,321 @@ +/* + save.c - save and restore routines + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include <sys/types.h> +#include <signal.h> +#include <fcntl.h> +#include <errno.h> +#include "rogue.h" +#include "mach_dep.h" + +extern char version[]; +extern unsigned char encstr[]; +extern int big_endian; + +bool +save_game() +{ + register FILE *savef; + register int c; + char buf[LINELEN]; + + /* + * get file name + */ + mpos = 0; + if (file_name[0] != '\0') + { + if (use_savedir) + msg("Save game? "); + else + msg("Save file (%s)? ", file_name); + do + { + c = wgetch(cw); + if (c == ESC) return(0); + } while (c != 'n' && c != 'N' && c != 'y' && c != 'Y'); + mpos = 0; + if (c == 'y' || c == 'Y') + { + msg("File name: %s", file_name); + goto gotfile; + } + } + else + goto gotfile; /* must save to file restored from */ + + if (use_savedir) { + msg(""); + return FALSE; + } + + do + { + msg("File name: "); + mpos = 0; + buf[0] = '\0'; + if (get_str(buf, msgw) == QUIT) + { + msg(""); + return FALSE; + } + strcpy(file_name, buf); +gotfile: + + if ((savef = fopen(file_name, "wb")) == NULL) { + msg(strerror(errno)); + if (use_savedir) + return FALSE; + } + } while (savef == NULL); + + msg(""); + /* + * write out encrpyted file + */ + if (save_file(savef) == FALSE) { + fclose(savef); + msg("Cannot create save file."); + unlink(file_name); + return(FALSE); + } + fclose(savef); + return(TRUE); +} + +/* + * automatically save a file. This is used if a HUP signal is recieved + */ + +void +auto_save(int sig) +{ + register FILE *savef = NULL; + register int i; + NOOP(sig); + for (i = 0; i < NSIG; i++) + signal(i, SIG_IGN); + if (file_name[0] != '\0' && + pstats.s_hpt > 0 && + ((savef = fopen(file_name, "wb")) != NULL)) + save_file(savef); + fclose(savef); + exit_game(EXIT_ENDWIN); +} + +/* + * write the saved game on the file + */ + +bool +save_file(savef) +register FILE *savef; +{ + int slines = LINES; + int scols = COLS; + int ret = FALSE; + int endian = 0x01020304; + big_endian = ( *((char *)&endian) == 0x01 ); + + wmove(cw, LINES-1, 0); + draw(cw); + + encwrite(version,strlen(version)+1,savef); + rs_write_int(savef,slines); + rs_write_int(savef,scols); + + ret = rs_save_file(savef); + + return(ret); +} + +restore(file, envp) +register char *file; +char **envp; +{ + register int inf; + extern char **environ; + char buf[LINELEN]; + int endian = 0x01020304; + big_endian = ( *((char *)&endian) == 0x01 ); + + if (strcmp(file, "-r") == 0) + file = file_name; + + if ((inf = open(file, O_RDONLY)) < 0) + { + if (use_savedir && errno == ENOENT) + { + /* No game in progress, so one will be started. */ + return TRUE; + } + perror(file); + return FALSE; + } + + fflush(stdout); + + encread(buf, strlen(version) + 1, inf); + + if (strcmp(buf, version) != 0) + { + printf("Sorry, saved game is out of date.\n"); + return FALSE; + } + + fflush(stdout); + + rs_read_int(inf,&lines); + rs_read_int(inf,&cols); + + initscr(); + + if (lines > LINES) + { + endwin(); + printf("Sorry, original game was played on a screen with %d lines.\n",lines); + printf("Current screen only has %d lines. Unable to restore game\n",LINES); + return(FALSE); + } + if (cols > COLS) + { + endwin(); + printf("Sorry, original game was played on a screen with %d columns.\n",cols); + printf("Current screen only has %d columns. Unable to restore game\n",COLS); + return(FALSE); + } + + typeahead(-1); + setup(); + cw = newwin(LINES, COLS, 0, 0); + mw = newwin(LINES, COLS, 0, 0); + hw = newwin(LINES, COLS, 0, 0); + msgw = newwin(4, cols, 0, 0); + + keypad(cw, TRUE); + keypad(hw, TRUE); + + if (rs_restore_file(inf) == FALSE) + { + endwin(); + printf("Cannot restore file\n"); + close(inf); + return(FALSE); + } + + close(inf); + + if (!wizard) + unlink(file); + + mpos = 0; + environ = envp; + strcpy(file_name, file); + clearok(curscr, TRUE); + touchwin(cw); + wrefresh(cw); + msg("Welcome back! --More-- "); + wait_for(' '); + msg(""); + playit(); + + /*NOTREACHED*/ + return FALSE; +} + +#define ENCWBSIZ 1024 + +/* + * perform an encrypted write + */ + +long +encwrite(start, size, outf) +register char *start; +register unsigned long size; +register FILE *outf; +{ + register unsigned char *ep; + register int i = 0; + unsigned long num_written = 0; + char buf[ENCWBSIZ]; + int ret; + + ep = encstr; + + while (size--) + { + buf[i++] = *start++ ^ *ep++; + if (*ep == '\0') + ep = encstr; + + if (i == ENCWBSIZ || size == 0) + { + ret = (unsigned int) fwrite(buf, 1, i, outf); + if (ret > 0) + num_written += ret; + + if (ret < i) + return(num_written); + + i = 0; + } + } + return(num_written); +} + +#define ENCRBSIZ 32768 + +/* + * perform an encrypted read + */ + +long +encread(start, size, inf) +register char *start; +register unsigned long size; +int inf; +{ + register unsigned char *ep; + register int rd_siz; + register unsigned long total_read; + + total_read = 0; + while (total_read < size) { + rd_siz = ENCRBSIZ; + rd_siz = ((size-total_read) > ENCRBSIZ) ? ENCRBSIZ : (size-total_read); + rd_siz = read(inf,&start[total_read],rd_siz); + if(rd_siz==-1 || rd_siz==0) + break; + total_read += rd_siz; + } + ep = encstr; + + size = total_read; + while (size--) + { + *start++ ^= *ep++; + if (*ep == '\0') + ep = encstr; + } + return total_read; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/scrolls.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,902 @@ +/* + scrolls.c - Functions for dealing with scrolls + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <stdlib.h> +#include <curses.h> +#include <ctype.h> +#include "rogue.h" + +/* + * let the hero get rid of some type of monster + */ + +genocide() +{ + register struct linked_list *ip; + register struct thing *mp; + register struct linked_list *nip; + /* cannot genocide any uniques */ + register int num_monst = NUMMONST-NUMUNIQUE-NUMDINOS; + register int which_monst; + + which_monst = makemonster(FALSE, "wipe out"); + if (which_monst <= 0 || which_monst >= num_monst) { + msg(""); + return; + } + + /* Remove this monster from the present level */ + for (ip = mlist; ip; ip = nip) { + mp = THINGPTR(ip); + nip = next(ip); + if (mp->t_index == which_monst) { + killed(ip, FALSE, FALSE, TRUE); + } + } + + /* Remove from available monsters */ + monsters[which_monst].m_normal = FALSE; + monsters[which_monst].m_wander = FALSE; + mpos = 0; + msg("You have wiped out the %s.", monsters[which_monst].m_name); +} + +read_scroll(which, flag, is_scroll) +register int which; +int flag; +bool is_scroll; +{ + register struct object *obj = NULL, *nobj; + register struct linked_list *item, *nitem; + register int i,j; + register unsigned char ch, nch; + bool cursed, blessed; + + blessed = FALSE; + cursed = FALSE; + item = NULL; + + if (which < 0) { + if (on(player, ISBLIND)) { + msg("You can't see to read anything!"); + return; + } + if (on(player, ISINWALL)) { + msg("You can't see the scroll while inside rock!"); + return; + } + + /* This is a scroll or book. */ + if (player.t_action != C_READ) { + int units; + + item = get_item(pack, "read", READABLE, FALSE, FALSE); + + /* + * Make certain that it is somethings that we want to read + */ + if (item == NULL) + return; + + /* How long does it take to read? */ + units = usage_time(item); + if (units < 0) return; + + player.t_using = item; /* Remember what it is */ + player.t_no_move = units * movement(&player); + if ((OBJPTR(item))->o_type == SCROLL) player.t_action = C_READ; + else player.t_action = C_USE; + return; + } + + /* We have waited our time, let's quaff the potion */ + item = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + obj = OBJPTR(item); + /* remove it from the pack */ + inpack--; + detach(pack, item); + + msg("As you read the scroll, it vanishes."); + cursed = obj->o_flags & ISCURSED; + blessed = obj->o_flags & ISBLESSED; + + which = obj->o_which; + } + else { + cursed = flag & ISCURSED; + blessed = flag & ISBLESSED; + } + + switch (which) { + case S_CONFUSE: /* Scroll of monster confusion. Give him that power. */ + { + register char *str; + + switch (rnd(5)) { + case 0: + str = "glow red"; + when 1: + str = "vibrate"; + when 2: + str = "glow blue"; + when 3: + str = "radiate green"; + otherwise: + str = "itch with a strange desire"; + } + msg("Your hands begin to %s. ", str); + turn_on(player, CANHUH); + } + when S_CURING: + /* + * A cure disease spell + */ + if (on(player, HASINFEST) || + on(player, HASDISEASE)|| + on(player, DOROT)) { + if (on(player, HASDISEASE)) { + extinguish(cure_disease); + cure_disease(); + } + if (on(player, HASINFEST)) { + msg(terse ? "You feel yourself improving." + : "You begin to feel yourself improving."); + turn_off(player, HASINFEST); + infest_dam = 0; + } + if (on(player, DOROT)) { + msg("You feel your skin returning to normal."); + turn_off(player, DOROT); + } + } + else { + /* msg(nothing); */ + break; + } + if (is_scroll) s_know[S_CURING] = TRUE; + when S_LIGHT: + if (blue_light(blessed, cursed) && is_scroll) + s_know[S_LIGHT] = TRUE; + when S_HOLD: + if (cursed) { + /* + * This scroll aggravates all the monsters on the current + * level and sets them running towards the hero + */ + msg("You hear a high-pitched humming noise."); + /* protect good charactors */ + if (player.t_ctype == C_PALADIN || + player.t_ctype == C_RANGER || player.t_ctype == C_MONK) { + msg("A chill runs up your spine! "); + aggravate(TRUE, FALSE); + } + else { + aggravate(TRUE, TRUE); + } + } + else if (blessed) { /* Hold all monsters on level */ + if (mlist == NULL) msg(nothing); + else { + register struct linked_list *mon; + register struct thing *th; + + for (mon = mlist; mon != NULL; mon = next(mon)) { + th = THINGPTR(mon); + turn_off(*th, ISRUN); + turn_on(*th, ISHELD); + turn_off(*th, ISCHARMED); + } + if (levtype == OUTSIDE) + msg("A sudden peace comes over the land.. "); + else + msg("A sudden peace comes over the dungeon.. "); + } + } + else { + /* + * Hold monster scroll. Stop all monsters within two spaces + * from chasing after the hero. + */ + register int x,y; + register struct linked_list *mon; + bool gotone=FALSE; + + for (x = hero.x-2; x <= hero.x+2; x++) { + for (y = hero.y-2; y <= hero.y+2; y++) { + if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1) + continue; + if (isalpha(mvwinch(mw, y, x))) { + if ((mon = find_mons(y, x)) != NULL) { + register struct thing *th; + + gotone = TRUE; + th = THINGPTR(mon); + turn_off(*th, ISRUN); + turn_on(*th, ISHELD); + turn_off(*th, ISCHARMED); + } + } + } + } + if (gotone) msg("A sudden peace surrounds you."); + else msg(nothing); + } + when S_SLEEP: + /* + * if cursed, you fall asleep + */ + if (is_scroll) s_know[S_SLEEP] = TRUE; + if (cursed) { + if (ISWEARING(R_ALERT)) + msg("You feel drowsy for a moment."); + else { + msg("You fall asleep."); + player.t_no_move += movement(&player)*(4 + rnd(SLEEPTIME)); + player.t_action = A_FREEZE; + } + } + else { + /* + * sleep monster scroll. + * puts all monsters within 2 spaces asleep + */ + register int x,y; + register struct linked_list *mon; + bool gotone=FALSE; + + for (x = hero.x-2; x <= hero.x+2; x++) { + for (y = hero.y-2; y <= hero.y+2; y++) { + if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1) + continue; + if (isalpha(mvwinch(mw, y, x))) { + if ((mon = find_mons(y, x)) != NULL) { + register struct thing *th; + + th = THINGPTR(mon); + if (on(*th, ISUNDEAD)) + continue; + th->t_no_move += movement(th)*(SLEEPTIME+4); + th->t_action = A_FREEZE; + gotone = TRUE; + } + } + } + } + if (gotone) + msg("The monster(s) around you seem to have fallen asleep!"); + else + msg(nothing); + } + when S_CREATE: + /* + * Create a monster + * First look in a circle around him, next try his room + * otherwise give up + */ + creat_mons(&player, (short) 0, TRUE); + light(&hero); + when S_IDENT: + /* + * if its blessed then identify everything in the pack + */ + if (blessed) { + msg("You feel more Knowledgeable!"); + idenpack(); + } + else { + /* + * Identify, let the rogue figure something out + */ + if (is_scroll && s_know[S_IDENT] != TRUE) { + msg("This scroll is an identify scroll"); + } + whatis((struct linked_list *)NULL); + } + if (is_scroll) s_know[S_IDENT] = TRUE; + when S_MAP: + /* + * Scroll of magic mapping. + */ + if (blessed) { + register int i; + + if (is_scroll && s_know[S_MAP] != TRUE) + s_know[S_MAP] = TRUE; + /* light rooms */ + for (i=0; i<MAXROOMS; i++){ + rooms[i].r_flags &= ~ISDARK; + } + + msg("This scroll has a very detailed map on it! --More--"); + wait_for(' '); + overwrite(stdscr, hw); + overlay(stdscr, cw); /* wizard CTRL(F) */ + overlay(mw, cw); /* wizard CTRL(X) */ + draw(cw); + goto map_jump; /* skip over regular mapping routine */ + } + if (is_scroll && s_know[S_MAP] != TRUE) { + msg("Oh, now this scroll has a map on it."); + s_know[S_MAP] = TRUE; + } + overwrite(stdscr, hw); + /* + * Take all the things we want to keep hidden out of the window + */ + for (i = 1; i < lines-2; i++) + for (j = 0; j < cols; j++) + { + switch (nch = ch = mvwinch(hw, i, j)) + { + case SECRETDOOR: + nch = secretdoor (i, j); + break; + case HORZWALL: + case VERTWALL: + case DOOR: + case PASSAGE: + case ' ': + case STAIRS: + if (mvwinch(mw, i, j) != ' ') + { + register struct thing *it; + + it = THINGPTR(find_mons(i, j)); + if (it && it->t_oldch == ' ') + it->t_oldch = nch; + } + break; + default: + nch = ' '; + } + if (nch != ch) + waddch(hw, nch); + } + /* + * Copy in what he has discovered + */ + overlay(cw, hw); + /* + * And set up for display + */ + overwrite(hw, cw); + map_jump: /* blessed map jump from above */ + when S_GFIND: + /* + * Scroll of gold detection + */ + { + int gtotal = 0; + + if (is_scroll) s_know[S_GFIND] = TRUE; + wclear(hw); + for (nitem = lvl_obj; nitem != NULL; nitem = next(nitem)) { + nobj = OBJPTR(nitem); + if (nobj->o_type == GOLD) { + gtotal += nobj->o_count; + mvwaddch(hw, nobj->o_pos.y, nobj->o_pos.x, GOLD); + } + } + for (nitem = mlist; nitem != NULL; nitem = next(nitem)) { + register struct linked_list *gitem; + register struct thing *th; + + th = THINGPTR(nitem); + if (on(*th, NODETECT)) continue; + for(gitem = th->t_pack; gitem != NULL; gitem = next(gitem)){ + nobj = OBJPTR(gitem); + if (nobj->o_type == GOLD) { + gtotal += nobj->o_count; + mvwaddch(hw, th->t_pos.y, th->t_pos.x, GOLD); + } + } + } + if (gtotal) { + rmmsg(); + overlay(hw,cw); + draw(cw); + msg("You begin to feel greedy. You sense gold!"); + break; + } + } + msg("You begin to feel a pull downward.."); + when S_TELEP: + /* + * Scroll of teleportation: + * Make him disappear and reappear + */ + if (cursed) { + int old_max = cur_max; + + turns = (vlevel * NLEVMONS) * LEVEL; + /* if (turns > 42000) turns = 42000; limit turns */ + debug ("vlevel = %d turns = %d", vlevel, turns); + + level = rnd(201)+80; /* cursed teleport range */ + + msg("You are banished to the lower regions! "); + new_level(NORMLEV); + + status(TRUE); + mpos = 0; + if (old_max == cur_max) { /* if he's been here make it harder */ + /* protect good charactors */ + if (player.t_ctype == C_PALADIN || + player.t_ctype == C_RANGER || player.t_ctype == C_MONK) { + aggravate(TRUE, FALSE); + } + else { + aggravate(TRUE, TRUE); + } + } + } + else if (blessed) { + int old_level, + much = rnd(6) - 7; + + old_level = level; + if (much != 0) { + level += much; + if (level < 1) + level = 1; + mpos = 0; + cur_max = level; + turns += much*LEVEL; + if (turns < 0) + turns = 0; + new_level(NORMLEV); /* change levels */ + if (level == old_level) + status(TRUE); + msg("You are whisked away to another region!"); + } + } + else { + teleport(); + } + if (is_scroll) s_know[S_TELEP] = TRUE; + when S_SCARE: + /* + * A monster will refuse to step on a scare monster scroll + * if it is dropped. Thus reading it is a mistake and produces + * laughter at the poor rogue's boo boo. + */ + msg("You hear maniacal laughter in the distance."); + when S_REMOVE: + if (cursed) { /* curse all player's possessions */ + for (nitem = pack; nitem != NULL; nitem = next(nitem)) { + nobj = OBJPTR(nitem); + if (nobj->o_flags & ISBLESSED) + nobj->o_flags &= ~ISBLESSED; + else + nobj->o_flags |= ISCURSED; + } + msg("The smell of fire and brimstone fills the air!"); + /* return; leaks item, go through end of function */ + } + else if (blessed) { + for (nitem = pack; nitem != NULL; nitem = next(nitem)) { + nobj = OBJPTR(nitem); + nobj->o_flags &= ~ISCURSED; + } + msg("Your pack glistens brightly!"); + do_panic(NULL); /* this startles them */ + /* return; leaks item, go through end of function */ + } + else { + nitem = get_item(pack, "remove the curse on",ALL,FALSE,FALSE); + if (nitem != NULL) { + nobj = OBJPTR(nitem); + nobj->o_flags &= ~ISCURSED; + msg("Removed the curse from %s",inv_name(nobj,TRUE)); + } + } + if (is_scroll) s_know[S_REMOVE] = TRUE; + when S_PETRIFY: + switch (mvinch(hero.y, hero.x)) { + case WORMHOLE: + case TRAPDOOR: + case DARTTRAP: + case TELTRAP: + case ARROWTRAP: + case SLEEPTRAP: + case BEARTRAP: + { + register int i; + + /* Find the right trap */ + for (i=0; i<ntraps && !ce(traps[i].tr_pos, hero); i++); + ntraps--; + + if (!ce(traps[i].tr_pos, hero)) + msg("What a strange trap!"); + else { + while (i < ntraps) { + traps[i] = traps[i + 1]; + i++; + } + } + } + goto pet_message; + case DOOR: + case SECRETDOOR: + case FLOOR: + case PASSAGE: +pet_message: msg("The dungeon begins to rumble and shake!"); + addch(WALL); + + /* If the player is phased, unphase him */ + if (on(player, CANINWALL)) { + extinguish(unphase); + turn_off(player, CANINWALL); + msg("The dizzy feeling leaves you."); + } + + /* Mark the player as in a wall */ + turn_on(player, ISINWALL); + break; + default: + msg(nothing); + } + when S_GENOCIDE: + msg("You have been granted the boon of genocide! --More--"); + wait_for(' '); + msg(""); + genocide(); + if (is_scroll) s_know[S_GENOCIDE] = TRUE; + when S_PROTECT: { + struct linked_list *ll; + struct object *lb; + bool did_it = FALSE; + msg("You are granted the power of protection."); + if ((ll=get_item(pack,"protect",PROTECTABLE,FALSE,FALSE)) != NULL) { + lb = OBJPTR(ll); + mpos = 0; + if (cursed) { + switch(lb->o_type) { /* ruin it completely */ + case RING: if (lb->o_ac > 0) { + if (is_current(lb)) { + switch (lb->o_which) { + case R_ADDWISDOM: + pstats.s_wisdom -= lb->o_ac; + when R_ADDINTEL: + pstats.s_intel -= lb->o_ac; + when R_ADDSTR: + pstats.s_str -= lb->o_ac; + when R_ADDHIT: + pstats.s_dext -= lb->o_ac; + } + } + did_it = TRUE; + lb->o_ac = 0; + } + when ARMOR: if (lb->o_ac > 10) { + did_it = TRUE; + lb->o_ac = 10; + } + when STICK: if (lb->o_charges > 0) { + did_it = TRUE; + lb->o_charges = 0; + } + when WEAPON:if (lb->o_hplus > 0) { + did_it = TRUE; + lb->o_hplus = 0; + } + if (lb->o_dplus > 0) { + did_it = TRUE; + lb->o_dplus = 0; + } + } + if (lb->o_flags & ISPROT) { + did_it = TRUE; + lb->o_flags &= ~ISPROT; + } + if (lb->o_flags & ISBLESSED) { + did_it = TRUE; + lb->o_flags &= ~ISBLESSED; + } + if (did_it) + msg("Your %s glows red for a moment",inv_name(lb,TRUE)); + else { + msg(nothing); + break; + } + } + else { + lb->o_flags |= ISPROT; + msg("Protected %s.",inv_name(lb,TRUE)); + } + } + if (is_scroll) s_know[S_PROTECT] = TRUE; + } + when S_MAKEIT: + msg("You have been endowed with the power of creation!"); + if (is_scroll) s_know[S_MAKEIT] = TRUE; + create_obj(TRUE, 0, 0); + when S_ALLENCH: { + struct linked_list *ll; + struct object *lb; + int howmuch, flags; + if (is_scroll && s_know[S_ALLENCH] == FALSE) { + msg("You are granted the power of enchantment."); + msg("You may enchant anything (weapon, ring, armor, scroll, potion)"); + } + if ((ll = get_item(pack, "enchant", ALL, FALSE, FALSE)) != NULL) { + lb = OBJPTR(ll); + lb->o_flags &= ~ISCURSED; + if (blessed) { + howmuch = 2; + flags = ISBLESSED; + } + else if (cursed) { + howmuch = -1; + flags = ISCURSED; + } + else { + howmuch = 1; + flags = ISBLESSED; + } + switch(lb->o_type) { + case RING: + if (lb->o_ac + howmuch > MAXENCHANT) { + msg("The enchantment doesn't seem to work!"); + break; + } + lb->o_ac += howmuch; + if (lb==cur_ring[LEFT_1] || lb==cur_ring[LEFT_2] || + lb==cur_ring[LEFT_3] || lb==cur_ring[LEFT_4] || + lb==cur_ring[RIGHT_1] || lb==cur_ring[RIGHT_2] || + lb==cur_ring[RIGHT_3] || lb==cur_ring[RIGHT_4]) { + switch (lb->o_which) { + case R_ADDWISDOM: pstats.s_wisdom += howmuch; + when R_ADDINTEL: pstats.s_intel += howmuch; + when R_ADDSTR: pstats.s_str += howmuch; + when R_ADDHIT: pstats.s_dext += howmuch; + } + } + msg("Enchanted %s.",inv_name(lb,TRUE)); + when ARMOR: + if ((armors[lb->o_which].a_class - lb->o_ac) + + howmuch > MAXENCHANT) { + msg("The enchantment doesn't seem to work!"); + break; + } + else + lb->o_ac -= howmuch; + msg("Enchanted %s.",inv_name(lb,TRUE)); + when STICK: + lb->o_charges += rnd(16)+10; + if (lb->o_charges < 0) + lb->o_charges = 0; + if (EQUAL(ws_type[lb->o_which], "staff")) { + if (lb->o_charges > 200) + lb->o_charges = 200; + } + else { + if (lb->o_charges > 200) /* make em the same */ + lb->o_charges = 200; + } + msg("Enchanted %s.",inv_name(lb,TRUE)); + when WEAPON: + if(lb->o_hplus+lb->o_dplus+howmuch > MAXENCHANT * 2){ + msg("The enchantment doesn't seem to work!"); + break; + } + if (rnd(100) < 50) + lb->o_hplus += howmuch; + else + lb->o_dplus += howmuch; + msg("Enchanted %s.",inv_name(lb,TRUE)); + when MM: + switch (lb->o_which) { + case MM_BRACERS: + if (lb->o_ac + howmuch > MAXENCHANT) { + msg("The enchantment doesn't seem to work!"); + break; + } + else lb->o_ac += howmuch; + msg("Enchanted %s.",inv_name(lb,TRUE)); + when MM_PROTECT: + if (lb->o_ac + howmuch > MAXENCHANT) { + msg("The enchantment doesn't seem to work!"); + break; + } + else lb->o_ac += howmuch; + msg("Enchanted %s.",inv_name(lb,TRUE)); + } + lb->o_flags |= flags; + when POTION: + case SCROLL: + default: + lb->o_flags |= flags; + msg("Enchanted %s.",inv_name(lb,TRUE)); + } + } + if (is_scroll) s_know[S_ALLENCH] = TRUE; + + /* If gotten here via prayer or Ankh, dock his wisdom. */ + if (!is_scroll) { + pstats.s_wisdom--; + if (pstats.s_wisdom < 3) pstats.s_wisdom = 3; + msg("You feel a drain on your system. "); + } + } + when S_FINDTRAPS: + for (i=0; i<ntraps; i++) { + if (!(traps[i].tr_flags & ISFOUND)) { + traps[i].tr_flags |= ISFOUND; + if (cansee(traps[i].tr_pos.y, traps[i].tr_pos.x)) + mvwaddch(cw,traps[i].tr_pos.y,traps[i].tr_pos.x, + traps[i].tr_type); + } + } + if (ntraps > 0) { + msg("You sense the presence of traps."); + if (is_scroll) s_know[S_FINDTRAPS] = TRUE; + } + else + msg(nothing); + + when S_RUNES: + { + register struct linked_list *sitem; + + msg("The scroll explodes in a ball of fire!"); + if (on(player, NOFIRE)) { + msg("The fire does not seem to affect you."); + break; + } + explode(&player); + if (pstats.s_hpt <= 0) { + pstats.s_hpt = -1; + death(D_SCROLL); + } + for (sitem = pack; sitem != NULL; sitem = nitem) { + nitem = next(sitem); /* in case we delete it */ + nobj = OBJPTR(sitem); + /* + * check for loss of all scrolls and give them + * a save versus fire + */ + if (nobj->o_type == SCROLL && roll(1,20) < 17) { + msg("%s burns up!", inv_name(nobj, TRUE)); + inpack--; + detach(pack, sitem); + o_discard(sitem); + } + } + } + + when S_CHARM: + { + bool spots[9]; + int x, y, spot, count, numcharmed, something, bonus; + struct linked_list *item; + register struct thing *tp; + + /* Initialize the places where we look around us */ + for (i=0; i<9; i++) spots[i] = FALSE; + count = 0; /* No spots tried yet */ + numcharmed = 0; /* Nobody charmed yet */ + something = 0; /* Nothing has been seen yet */ + bonus = 0; /* no bonus yet */ + + /* Now look around us randomly for a charmee */ + while (count < 9) { + do { + spot = rnd(9); + } while (spots[spot] == TRUE); + + /* We found a place */ + count++; + spots[spot] = TRUE; + y = hero.y - 1 + (spot / 3); + x = hero.x - 1 + (spot % 3); + + /* Be sure to stay on the board! */ + if (x < 0 || x >= cols || (y < 1) || (y >= lines - 2)) + continue; + + /* Is there a monster here? */ + if (!isalpha(mvwinch(mw, y, x))) continue; + + /* What kind is it? */ + item = find_mons(y, x); + if (item == NULL) continue; + + tp = THINGPTR(item); + if (on(*tp,ISCHARMED) || on(*tp,ISUNIQUE) || on(*tp,ISUNDEAD)) + continue; + + /* Will the monster be charmed? */ + if (blessed) bonus -= 3; + bonus -= (pstats.s_charisma - 12) / 3; + if ((player.t_ctype==C_PALADIN || player.t_ctype==C_RANGER) && + off(*tp, ISMEAN)) + bonus -= 3; + if (save(VS_MAGIC, tp, bonus)) continue; + + /* We got him! */ + numcharmed++; + + /* Let the player know (maybe) */ + if ((off(*tp, ISINVIS) || on(player, CANSEE)) && + (off(*tp, ISSHADOW) || on(player, CANSEE)) && + cansee(y, x)) { + if (on(*tp, CANSURPRISE)) { + turn_off(*tp, CANSURPRISE); + msg("What the !? "); + } + msg("The eyes of %s glaze over!", + prname(monster_name(tp), FALSE)); + something++; + } + + /* Charm him and turn off any side effects */ + turn_on(*tp, ISCHARMED); + runto(tp, &hero); + tp->t_action = A_NIL; + + /* If monster was suffocating us, stop it */ + if (on(*tp, DIDSUFFOCATE)) { + turn_off(*tp, DIDSUFFOCATE); + extinguish(suffocate); + } + + /* If monster held us, stop it */ + if (on(*tp, DIDHOLD) && (--hold_count == 0)) + turn_off(player, ISHELD); + turn_off(*tp, DIDHOLD); + + /* If frightened of this monster, stop */ + if (on(player, ISFLEE) && + player.t_dest == &tp->t_pos) turn_off(player, ISFLEE); + + if ((blessed && numcharmed >= 5) || numcharmed > 0) break; + } + + if (something == 0) msg(nothing); + } + + otherwise: + msg("What a puzzling scroll!"); + if (item != NULL) o_discard(item); + return; + } + look(TRUE, FALSE); /* put the result of the scroll on the screen */ + status(FALSE); + if (is_scroll && item && s_know[which] && s_guess[which]) + { + free(s_guess[which]); + s_guess[which] = NULL; + } + else if (is_scroll && + !s_know[which] && + item && + askme && + (obj->o_flags & ISKNOW) == 0 && + (obj->o_flags & ISPOST) == 0 && + s_guess[which] == NULL) { + nameitem(item, FALSE); + } + if (item != NULL) o_discard(item); + updpack(TRUE, &player); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/state.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,3358 @@ +/* + state.c - Portable Rogue Save State Code + + Copyright (C) 2000 Nicholas J. Kisseberth + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name(s) of the author(s) nor the names of other contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + +#define RSXR_STATS 0xABCD0001 +#define RSXR_THING 0xABCD0002 +#define RSXR_OBJECT 0xABCD0003 +#define RSXR_MAGICITEMS 0xABCD0004 +#define RSXR_KNOWS 0xABCD0005 +#define RSXR_GUESSES 0xABCD0006 +#define RSXR_OBJECTLIST 0xABCD0007 +#define RSXR_BAGOBJECT 0xABCD0008 +#define RSXR_MONSTERLIST 0xABCD0009 +#define RSXR_MONSTERSTATS 0xABCD000A +#define RSXR_MONSTERS 0xABCD000B +#define RSXR_TRAP 0xABCD000C +#define RSXR_WINDOW 0xABCD000D +#define RSXR_DAEMONS 0xABCD000E +#define RSXR_IWEAPS 0xABCD000F +#define RSXR_IARMOR 0xABCD0010 +#define RSXR_SPELLS 0xABCD0011 +#define RSXR_ILIST 0xABCD0012 +#define RSXR_HLIST 0xABCD0013 +#define RSXR_DEATHTYPE 0xABCD0014 +#define RSXR_CTYPES 0XABCD0015 +#define RSXR_COORDLIST 0XABCD0016 +#define RSXR_ROOMS 0XABCD0017 + +#if defined(_WIN32) +#include <Windows.h> +#include <Lmcons.h> +#include <process.h> +#include <shlobj.h> +#include <Shlwapi.h> +#undef VOID +#undef MOUSE_MOVED +#elif defined(__DJGPP__) +#include <process.h> +#else +#include <pwd.h> +#include <sys/utsname.h> +#include <unistd.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <curses.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdarg.h> +#include <assert.h> +#include <fcntl.h> +#include <limits.h> +#include <time.h> +#include <signal.h> +#include "rogue.h" +#include "mach_dep.h" + + +#define READSTAT ((format_error == 0) && (read_error == 0)) +#define WRITESTAT (write_error == 0) + +int read_error = FALSE; +int write_error = FALSE; +int format_error = FALSE; + +int save_debug = FALSE; +#define DBG(x) {if (save_debug) rsPrintf x;} + +int +rsPrintf(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr,fmt, ap); + va_end(ap); + + return(0); +} + + +void * +get_list_item(struct linked_list *l, int i) +{ + int count = 0; + + while(l != NULL) + { + if (count == i) + return(l->l_data); + + l = l->l_next; + + count++; + } + + return(NULL); +} + +rs_write(FILE *savef, void *ptr, size_t size) +{ + size_t i = 0; + + if (!write_error) + i = ENCWRITE(ptr,size,savef); + if (i != size) + write_error = TRUE; + + assert(write_error == 0); + return(WRITESTAT); +} + +int end_of_file = FALSE; + +rs_read(int inf, void *ptr, size_t size) +{ + int actual; + end_of_file =FALSE; + if (!read_error && !format_error) + { + actual = ENCREAD(ptr, size, inf); + + if ((actual == 0) && (size != 0)) + end_of_file = TRUE; + } + + if (read_error){ + printf("read error has occurred. restore short-circuited.\n");abort();} + if (format_error) + {printf("game format invalid. restore short-circuited.\n");abort();} + + return(READSTAT); +} + +int big_endian = 0; + +rs_write_uint(FILE *savef, unsigned int c) +{ + char bytes[4]; + char *buf = (char *) &c; + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + rs_write(savef, buf, 4); + + return(WRITESTAT); +} + +rs_write_int(FILE *savef, int c) +{ + char bytes[4]; + char *buf = (char *) &c; + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + rs_write(savef, buf, 4); + + return(WRITESTAT); +} + +rs_write_ulong(FILE *savef, unsigned long c) +{ + char bytes[4]; + char *buf = (char *)&c; + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + rs_write(savef, buf, 4); + + return(WRITESTAT); +} + +rs_write_long(FILE *savef, long c) +{ + char bytes[4]; + char *buf = (char *)&c; + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + rs_write(savef, buf, 4); + + return(WRITESTAT); +} + +rs_write_boolean(FILE *savef, bool c) +{ + char buf; + + if (c == 0) + buf = 0; + else + buf = 1; + + rs_write(savef, &buf, 1); + + return(WRITESTAT); +} + +rs_read_int(int inf, int *i) +{ + char bytes[4]; + int input; + char *buf = (char *)&input; + + rs_read(inf, &input, 4); + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + *i = *((int *) buf); + + return(READSTAT); +} + +rs_read_uint(int inf, unsigned int *i) +{ + char bytes[4]; + int input; + char *buf = (char *)&input; + + rs_read(inf, &input, 4); + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + *i = *((int *) buf); + + return(READSTAT); +} + +rs_read_ulong(int inf, unsigned long *i) +{ + char bytes[4]; + unsigned long input; + char *buf = (char *) &input; + + rs_read(inf, &input, 4); + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + *i = *((unsigned long *) buf); + return(READSTAT); +} + +rs_read_long(int inf, long *i) +{ + char bytes[4]; + long input; + char *buf = (char *) &input; + + rs_read(inf, &input, 4); + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + *i = *((long *) buf); + return(READSTAT); +} + +rs_read_boolean(int inf, bool *i) +{ + char buf; + + rs_read(inf, &buf, 1); + + *i = buf; + + return(READSTAT); +} + +rs_write_ints(FILE *savef, int *c, int count) +{ + int n=0; + + rs_write_int(savef,count); + + for(n=0;n<count;n++) + rs_write_int(savef,c[n]); + + return(WRITESTAT); +} + +rs_write_short(FILE *savef, short c) +{ + char bytes[2]; + char *buf = (char *) &c; + + if (big_endian) + { + bytes[1] = buf[0]; + bytes[0] = buf[1]; + buf = bytes; + } + + rs_write(savef, buf, 2); + + return(WRITESTAT); +} + +rs_read_short(int inf, short *s) +{ + char bytes[2]; + short input; + char *buf = (char *)&input; + + rs_read(inf, &input, 2); + + if (big_endian) + { + bytes[1] = buf[0]; + bytes[0] = buf[1]; + buf = bytes; + } + + *s = *((short *) buf); + return(READSTAT); +} + + +rs_write_shorts(FILE *savef, short *c, int count) +{ + int n=0; + + rs_write_int(savef,count); + + for(n=0;n<count;n++) + rs_write_short(savef,c[n]); + + return(WRITESTAT); +} + +rs_write_longs(FILE *savef, long *c, int count) +{ + int n=0; + + rs_write_int(savef,count); + + for(n=0;n<count;n++) + rs_write_long(savef,c[n]); + + return(WRITESTAT); +} + +rs_write_ulongs(FILE *savef, unsigned long *c, int count) +{ + int n=0; + + rs_write_int(savef,count); + + for(n=0;n<count;n++) + rs_write_ulong(savef,c[n]); + + return(WRITESTAT); +} + +rs_write_booleans(FILE *savef, bool *c, int count) +{ + int n=0; + + rs_write_int(savef,count); + + for(n=0;n<count;n++) + rs_write_boolean(savef,c[n]); + + return(WRITESTAT); +} + +rs_read_ints(int inf, int *i, int count) +{ + int n=0,value=0; + + if (rs_read_int(inf,&value) != 0) + { + if (value != count) + format_error = TRUE; + else + { + for(n=0;n<value;n++) + rs_read_int(inf, &i[n]); + } + } + + return(READSTAT); +} + +rs_read_shorts(int inf, short *i, int count) +{ + int n=0,value=0; + + if (rs_read_int(inf,&value) != 0) + { + if (value != count) + format_error = TRUE; + else + { + for(n=0;n<value;n++) + rs_read_short(inf, &i[n]); + } + } + + return(READSTAT); +} + +rs_read_longs(int inf, long *i, int count) +{ + int n=0,value=0; + + if (rs_read_int(inf,&value) != 0) + { + if (value != count) + format_error = TRUE; + else + { + for(n=0;n<value;n++) + rs_read_long(inf, &i[n]); + } + } + + return(READSTAT); +} + +rs_read_ulongs(int inf, unsigned long *i, int count) +{ + int n=0,value=0; + + if (rs_read_int(inf,&value) != 0) + { + if (value != count) + format_error = TRUE; + else + { + for(n=0;n<value;n++) + rs_read_ulong(inf, &i[n]); + } + } + + return(READSTAT); +} + +rs_read_booleans(int inf, bool *i, int count) +{ + int n=0,value=0; + + if (rs_read_int(inf,&value) != 0) + { + if (value != count) + format_error = TRUE; + else + { + for(n=0;n<value;n++) + rs_read_boolean(inf, &i[n]); + } + } + + return(READSTAT); +} + +rs_write_levtype(FILE *savef, LEVTYPE c) +{ + int lt; + + switch(c) + { + case NORMLEV: lt = 1; break; + case POSTLEV: lt = 2; break; + case MAZELEV: lt = 3; break; + case OUTSIDE: lt = 4; break; + case STARTLEV: lt = 5; break; + default: lt = -1; break; + } + + rs_write_int(savef,lt); + + return(WRITESTAT); +} + +rs_read_levtype(int inf, LEVTYPE *l) +{ + int lt; + + rs_read_int(inf, <); + + switch(lt) + { + case 1: *l = NORMLEV; break; + case 2: *l = POSTLEV; break; + case 3: *l = MAZELEV; break; + case 4: *l = OUTSIDE; break; + case 5: *l = STARTLEV; break; + default: *l = NORMLEV; break; + } + + return(READSTAT); +} + +rs_write_char(FILE *savef, char c) +{ + rs_write(savef, &c, 1); + DBG(("%c",c)); + + return(WRITESTAT); +} + +rs_read_char(int inf, char *c) +{ + rs_read(inf, c, 1); + + return(READSTAT); +} + +rs_write_uchar(FILE *savef, unsigned char c) +{ + rs_write(savef, &c, 1); + DBG(("%c",c)); + + return(WRITESTAT); +} + +rs_read_uchar(int inf, unsigned char *c) +{ + rs_read(inf, c, 1); + + return(READSTAT); +} + +rs_write_string(FILE *savef, char *s) +{ + int len = 0; + + len = (s == NULL) ? 0 : (int) strlen(s) + 1; + + rs_write_uint(savef, (unsigned int) len); + rs_write(savef, s, len); + + return(WRITESTAT); +} + +rs_read_string_index(int inf, struct words master[], int maxindex, char **str) +{ + int i; + + if (rs_read_int(inf,&i) != 0) + { + if (i > maxindex) + { + printf("String index is out of range. %d > %d\n", + i, maxindex); + printf("Sorry, invalid save game format\n"); + format_error = TRUE; + } + else if (i >= 0) + *str = master[i].w_string; + else + *str = NULL; + } + return(READSTAT); +} + +rs_write_string_index(FILE *savef, struct words master[], int maxindex, char *str) +{ + int i; + + for(i = 0; i < maxindex; i++) + { + if (str == master[i].w_string) + { + rs_write_int(savef,i); + return(WRITESTAT); + } + } + + rs_write_int(savef,-1); + return(WRITESTAT); +} + +rs_read_scrolls(int inf) +{ + int i; + + for(i = 0; i < MAXSCROLLS; i++) + { + rs_read_new_string(inf,&s_names[i]); + rs_read_boolean(inf,&s_know[i]); + rs_read_new_string(inf,&s_guess[i]); + } + + return(READSTAT); +} + +rs_write_scrolls(FILE *savef) +{ + int i; + + for(i = 0; i < MAXSCROLLS; i++) + { + rs_write_string(savef,s_names[i]); + rs_write_boolean(savef,s_know[i]); + rs_write_string(savef,s_guess[i]); + } + return(READSTAT); +} + +rs_read_potions(int inf) +{ + int i; + + for(i = 0; i < MAXPOTIONS; i++) + { + rs_read_string_index(inf,rainbow,NCOLORS,&p_colors[i]); + rs_read_boolean(inf,&p_know[i]); + rs_read_new_string(inf,&p_guess[i]); + } + + return(READSTAT); +} + +rs_write_potions(FILE *savef) +{ + int i; + + for(i = 0; i < MAXPOTIONS; i++) + { + rs_write_string_index(savef,rainbow,NCOLORS,p_colors[i]); + rs_write_boolean(savef,p_know[i]); + rs_write_string(savef,p_guess[i]); + } + + return(WRITESTAT); +} + +rs_read_rings(int inf) +{ + int i; + + for(i = 0; i < MAXRINGS; i++) + { + rs_read_string_index(inf,stones,NSTONES,&r_stones[i]); + rs_read_boolean(inf,&r_know[i]); + rs_read_new_string(inf,&r_guess[i]); + } + + return(READSTAT); +} + +rs_write_rings(FILE *savef) +{ + int i; + + for(i = 0; i < MAXRINGS; i++) + { + rs_write_string_index(savef,stones,NSTONES,r_stones[i]); + rs_write_boolean(savef,r_know[i]); + rs_write_string(savef,r_guess[i]); + } + + return(WRITESTAT); +} + +rs_read_misc(int inf) +{ + int i; + + for(i = 0; i < MAXMM; i++) + { + rs_read_boolean(inf,&m_know[i]); + rs_read_new_string(inf,&m_guess[i]); + } + + return(READSTAT); +} + +rs_write_misc(FILE *savef) +{ + int i; + + for(i = 0; i < MAXMM; i++) + { + rs_write_boolean(savef,m_know[i]); + rs_write_string(savef,m_guess[i]); + } + + return(WRITESTAT); +} + +rs_write_sticks(FILE *savef) +{ + int i; + + for (i = 0; i < MAXSTICKS; i++) + { + if (strcmp(ws_type[i],"staff") == 0) + { + rs_write_int(savef,0); + rs_write_string_index(savef, wood, NWOOD, ws_made[i]); + } + else + { + rs_write_int(savef,1); + rs_write_string_index(savef, metal, NMETAL, ws_made[i]); + } + rs_write_boolean(savef, ws_know[i]); + rs_write_string(savef, ws_guess[i]); + } + + return(WRITESTAT); +} + +rs_read_sticks(int inf) +{ + int i = 0, list = 0; + + for(i = 0; i < MAXSTICKS; i++) + { + rs_read_int(inf,&list); + if (list == 0) + { + rs_read_string_index(inf,wood,NWOOD,&ws_made[i]); + ws_type[i] = "staff"; + } + else + { + rs_read_string_index(inf,metal,NMETAL,&ws_made[i]); + ws_type[i] = "wand"; + } + rs_read_boolean(inf, &ws_know[i]); + rs_read_new_string(inf, &ws_guess[i]); + } + + return(READSTAT); +} + +rs_read_string(int inf, char *s, int max) +{ + int len = 0; + + if (rs_read_int(inf, &len) != FALSE) + { + if (len > max) + { + printf("String too long to restore. %d > %d\n",len,max); + printf("Sorry, invalid save game format\n"); + format_error = TRUE; + } + + rs_read(inf, s, len); + } + + return(READSTAT); +} + +rs_read_new_string(int inf, char **s) +{ + int len=0; + char *buf=0; + + if (rs_read_int(inf, &len) != 0) + { + if (len == 0) + *s = NULL; + else + { + buf = malloc(len); + + if (buf == NULL) + read_error = TRUE; + else + { + rs_read(inf, buf, len); + *s = buf; + } + } + } + + return(READSTAT); +} + +rs_write_strings(FILE *savef, char *s[], int count) +{ + int len = 0; + int n = 0; + + rs_write_int(savef,count); + + for(n = 0; n < count; n++) + { + len = (s[n] == NULL) ? 0L : (int) strlen(s[n]) + 1; + rs_write_int(savef, len); + rs_write(savef, s[n], len); + DBG(("%s",s[n])); + } + + return(WRITESTAT); +} + +rs_write_words(FILE *savef, struct words *w, int count) +{ + int n = 0; + + rs_write_int(savef,count); + + for(n = 0; n < count; n++) + { + rs_write(savef, w[n].w_string, sizeof(w[n].w_string)); + DBG(("%s",w[n].w_string)); + } + + return(WRITESTAT); +} + +rs_read_words(int inf, struct words *w, int count) +{ + int n = 0; + int value = 0; + + rs_read_int(inf,&value); + + if (value != count) + { + printf("Incorrect number of words in block. %d != %d.", + value,count); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else for(n = 0; n < count; n++) + { + rs_read(inf, w[n].w_string, sizeof(w[n].w_string)); + } + + return(READSTAT); +} + +rs_read_new_strings(int inf, char **s, int count) +{ + int len = 0; + int n = 0; + int value = 0; + + if (rs_read_int(inf,&value) != 0) + { + if (value != count) + { + printf("Incorrect number of strings in block. %d > %d.", + value,count); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else + for(n=0; n<value; n++) + { + rs_read_int(inf, &len); + + if (len == 0) + s[n]=0; + else + { + s[n] = malloc(len); + rs_read(inf,s[n],len); + } + } + } + + return(READSTAT); +} + +rs_write_coord(FILE *savef, coord *c) +{ + DBG(("X =")); + rs_write_int(savef, c->x); + DBG(("Y =")); + rs_write_int(savef, c->y); + + return(WRITESTAT); +} + +rs_read_coord(int inf, coord *c) +{ + rs_read_int(inf,&c->x); + rs_read_int(inf,&c->y); + + return(READSTAT); +} + +rs_write_daemons(FILE *savef, struct delayed_action *d_list,int count) +{ + int i = 0; + int func = 0; + + DBG(("Daemons\n")); + rs_write_int(savef, RSXR_DAEMONS); + rs_write_int(savef, count); + + for(i=0; i < count; i++) + { + if (d_list[i].d_func == rollwand) + func = 1; + else if (d_list[i].d_func == doctor) + func = 2; + else if (d_list[i].d_func == stomach) + func = 3; + else if (d_list[i].d_func == trap_look) + func = 4; + else if (d_list[i].d_func == eat_gold) + func = 5; + else if (d_list[i].d_func == ring_search) + func = 6; + else if (d_list[i].d_func == ring_teleport) + func = 7; + else if (d_list[i].d_func == fumble) + func = 8; + else if (d_list[i].d_func == strangle) + func = 9; + else if (d_list[i].d_func == unconfuse) + func = 10; + else if (d_list[i].d_func == swander) + func = 11; + else if (d_list[i].d_func == spell_recovery) + func = 12; + else if (d_list[i].d_func == chant_recovery) + func = 13; + else if (d_list[i].d_func == prayer_recovery) + func = 14; + else if (d_list[i].d_func == cure_disease) + func = 15; + else if (d_list[i].d_func == unstink) + func = 16; + else if (d_list[i].d_func == res_strength) + func = 17; + else if (d_list[i].d_func == undance) + func = 18; + else if (d_list[i].d_func == suffocate) + func = 19; + else if (d_list[i].d_func == wghtchk) + func = 20; + else if (d_list[i].d_func == dust_appear) + func = 21; + else if (d_list[i].d_func == unchoke) + func = 22; + else if (d_list[i].d_func == sight) + func = 23; + else if (d_list[i].d_func == changeclass) + func = 24; + else if (d_list[i].d_func == cloak_charge) + func = 25; + else if (d_list[i].d_func == quill_charge) + func = 26; + else if (d_list[i].d_func == nohaste) + func = 27; + else if (d_list[i].d_func == noslow) + func = 28; + else if (d_list[i].d_func == unclrhead) + func = 29; + else if (d_list[i].d_func == unsee) + func = 30; + else if (d_list[i].d_func == unphase) + func = 31; + else if (d_list[i].d_func == land) + func = 32; + else if (d_list[i].d_func == appear) + func = 33; + else if (d_list[i].d_func == unskill) + func = 34; + else if (d_list[i].d_func == nofire) + func = 35; + else if (d_list[i].d_func == nocold) + func = 36; + else if (d_list[i].d_func == nobolt) + func = 37; + else if (d_list[i].d_func == NULL) + func = 0; + else + func = -1; + + rs_write_int(savef, d_list[i].d_type); + rs_write_int(savef, func); + + if (d_list[i].d_func == doctor) + rs_write_int(savef, 1); + else if (d_list[i].d_func == eat_gold) + { + int index; + index = find_list_ptr(player.t_pack,d_list[i].d_arg.vp); + rs_write_int(savef,index); + } + else if (d_list[i].d_func == changeclass) + { + rs_write_int(savef, d_list[i].d_arg.i); + } + else if (d_list[i].d_func == cloak_charge) + { + int index; + index = find_list_ptr(player.t_pack,d_list[i].d_arg.vp); + rs_write_int(savef,index); + } + else + rs_write_int(savef, d_list[i].d_arg.i); + + rs_write_int(savef, d_list[i].d_time); + } + + return(WRITESTAT); +} + +rs_read_daemons(int inf, struct delayed_action *d_list, int count) +{ + int i = 0; + int func = 0; + int value = 0; + int id = 0; + int dummy = 0; + + if (d_list == NULL) + printf("HELP THERE ARE NO DAEMONS\n"); + + if (rs_read_int(inf, &id) != 0) + { + if (id != RSXR_DAEMONS) + { + printf("Invalid id. %x != %x(RSXR_DAEMONS)\n", + id,RSXR_DAEMONS); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else if (rs_read_int(inf, &value) != 0) + { + if (value > count) + { + printf("Incorrect number of daemons in block. %d > %d.", + value,count); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else + { + for(i=0; i < value; i++) + { + func = 0; + rs_read_int(inf, &d_list[i].d_type); + rs_read_int(inf, &func); + + switch(func) + { + case 1: d_list[i].d_func = rollwand; + break; + case 2: d_list[i].d_func = doctor; + break; + case 3: d_list[i].d_func = stomach; + break; + case 4: d_list[i].d_func = trap_look; + break; + case 5: d_list[i].d_func = eat_gold; + break; + case 6: d_list[i].d_func = ring_search; + break; + case 7: d_list[i].d_func = ring_teleport; + break; + case 8: d_list[i].d_func = fumble; + break; + case 9: d_list[i].d_func = strangle; + break; + case 10: d_list[i].d_func = unconfuse; + break; + case 11: d_list[i].d_func = swander; + break; + case 12: d_list[i].d_func = spell_recovery; + break; + case 13: d_list[i].d_func = chant_recovery; + break; + case 14: d_list[i].d_func = prayer_recovery; + break; + case 15: d_list[i].d_func = cure_disease; + break; + case 16: d_list[i].d_func = unstink; + break; + case 17: d_list[i].d_func = res_strength; + break; + case 18: d_list[i].d_func = undance; + break; + case 19: d_list[i].d_func = suffocate; + break; + case 20: d_list[i].d_func = wghtchk; + break; + case 21: d_list[i].d_func = dust_appear; + break; + case 22: d_list[i].d_func = unchoke; + break; + case 23: d_list[i].d_func = sight; + break; + case 24: d_list[i].d_func = changeclass; + break; + case 25: d_list[i].d_func = cloak_charge; + break; + case 26: d_list[i].d_func = quill_charge; + break; + case 27: d_list[i].d_func = nohaste; + break; + case 28: d_list[i].d_func = noslow; + break; + case 29: d_list[i].d_func = unclrhead; + break; + case 30: d_list[i].d_func = unsee; + break; + case 31: d_list[i].d_func = unphase; + break; + case 32: d_list[i].d_func = land; + break; + case 33: d_list[i].d_func = appear; + break; + case 34: d_list[i].d_func = unskill; + break; + case 35: d_list[i].d_func = nofire; + break; + case 36: d_list[i].d_func = nocold; + break; + case 37: d_list[i].d_func = nobolt; + break; + case 0: + case -1: + default: d_list[i].d_func = NULL; + break; + } + + if (d_list[i].d_func == doctor) + { + rs_read_int(inf, &dummy); + d_list[i].d_arg.vp = (void *)&player; + } + else if (d_list[i].d_func == eat_gold) + { + rs_read_int(inf, &dummy); + d_list[i].d_arg.vp = get_list_item(player.t_pack,dummy); + if (d_list[i].d_arg.vp == NULL) + d_list[i].d_type = 0; + } + else if (d_list[i].d_func == changeclass) + { + rs_read_int(inf, &d_list[i].d_arg.i); + } + else if (d_list[i].d_func == cloak_charge) + { + rs_read_int(inf, &dummy); + d_list[i].d_arg.vp = get_list_item(player.t_pack,dummy); + if (d_list[i].d_arg.vp == NULL) + d_list[i].d_type = 0; + } + else + rs_read_int(inf, &d_list[i].d_arg.i); + + rs_read_int(inf, &d_list[i].d_time); + + if (d_list[i].d_func == NULL) + { + d_list[i].d_time = 0; + d_list[i].d_arg.vp = NULL; + d_list[i].d_type = 0; + } + + } + } + } + } + + return(READSTAT); +} + +rs_write_rooms(FILE *savef, struct room r[], int count) +{ + int n = 0,i = -1; + struct linked_list *l; + + DBG(("Rooms\n")); + rs_write_int(savef, RSXR_ROOMS); + rs_write_int(savef, count); + + for(n=0; n<count; n++) + { + rs_write_coord(savef, &r[n].r_pos); + rs_write_coord(savef, &r[n].r_max); + rs_write_long(savef, r[n].r_flags); + rs_write_coord_list(savef, r[n].r_exit); + + l = r[n].r_fires; + i = list_size(l); + + rs_write_int(savef, i); + + if (i >0) + while (l != NULL) + { + i = find_list_ptr(mlist,l->l_data); + rs_write_int(savef,i); + l = l->l_next; + } + } + return(WRITESTAT); +} + +rs_read_rooms(int inf, struct room *r, int count) +{ + int value = 0, n = 0, i = 0, index = 0, id = 0; + struct linked_list *fires=NULL, *item = NULL; + + if (rs_read_int(inf,&id) != 0) + { + if (id != RSXR_ROOMS) + { + printf("Invalid id. %x != %x(RSXR_ROOMS)\n", + id,RSXR_ROOMS); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else if (rs_read_int(inf,&value) != 0) + { + if (value != count) + { + printf("Incorrect number of rooms in block. %d > %d.", + value,count); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else + { + for(n=0; n<value; n++) + { + rs_read_coord(inf,&r[n].r_pos); + rs_read_coord(inf,&r[n].r_max); + rs_read_long(inf,&r[n].r_flags); + rs_read_coord_list(inf, &r[n].r_exit); + + rs_read_int(inf, &i); + fires = NULL; + while (i>0) + { + rs_read_int(inf,&index); + + if (index >= 0) + { + void *data; + data = get_list_item(mlist,index); + item = creat_item(); + item->l_data = data; + if (fires == NULL) + fires = item; + else + attach(fires,item); + } + i--; + } + r[n].r_fires=fires; + } + } + } + } + + return(READSTAT); +} + +rs_write_object(FILE *savef, struct object *o) +{ + rs_write_int(savef, RSXR_OBJECT); + rs_write_int(savef, o->o_type); + rs_write_coord(savef, &o->o_pos); + rs_write_char(savef, o->o_launch); + rs_write(savef, o->o_damage, sizeof(o->o_damage)); + rs_write(savef, o->o_hurldmg, sizeof(o->o_hurldmg)); + rs_write_int(savef, o->o_count); + rs_write_int(savef, o->o_which); + rs_write_int(savef, o->o_hplus); + rs_write_int(savef, o->o_dplus); + rs_write_int(savef, o->o_ac); + rs_write_long(savef, o->o_flags); + rs_write_int(savef, o->o_group); + rs_write_int(savef, o->o_weight); + rs_write(savef, o->o_mark, MARKLEN); + + DBG(("Object\n")); + DBG((" SaveID : %X\n",RSXR_OBJECT)); + DBG((" Type : %d\n",o->o_type)); + DBG((" Pos : %d %d\n",o->o_pos.x,o->o_pos.y)); + DBG((" Launch : %c\n",o->o_launch)); + DBG((" Damage : %s\n",o->o_damage)); + DBG((" Hurl : %s\n",o->o_hurldmg)); + DBG((" Count : %d\n",o->o_count)); + DBG((" Which : %d\n",o->o_which)); + DBG((" HPlus : %d\n",o->o_hplus)); + DBG((" DPlus : %d\n",o->o_dplus)); + DBG((" AC : %d\n",o->o_ac)); + DBG((" Flags : %X\n",o->o_flags)); + DBG((" Group : %d\n",o->o_group)); + DBG((" Weight : %d\n",o->o_weight)); + DBG((" Mark : %s\n",o->o_mark)); + if (o->contents == NULL) + { + DBG((" Contents: None\n")); + } + else + { + DBG((" CONTENTS\n")); + } + + rs_write_object_list(savef, o->contents); + + if (o->contents != NULL) + DBG((" END_CONTENTS\n")); + + return(WRITESTAT); +} + +rs_read_object(int inf, struct object *o) +{ + int id; + + if (rs_read_int(inf, &id) != 0) + { + if (id != RSXR_OBJECT) + { + printf("Invalid id. %x != %x(RSXR_OBJECT)\n", id,RSXR_OBJECT); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else + { + rs_read_int(inf, &o->o_type); + rs_read_coord(inf, &o->o_pos); + rs_read_char(inf, &o->o_launch); + rs_read(inf, o->o_damage,sizeof(o->o_damage)); + rs_read(inf, o->o_hurldmg,sizeof(o->o_hurldmg)); + rs_read_int(inf, &o->o_count); + rs_read_int(inf, &o->o_which); + rs_read_int(inf, &o->o_hplus); + rs_read_int(inf, &o->o_dplus); + rs_read_int(inf,&o->o_ac); + rs_read_long(inf,&o->o_flags); + rs_read_int(inf,&o->o_group); + rs_read_int(inf, &o->o_weight); + rs_read(inf, o->o_mark, MARKLEN); + rs_read_object_list(inf,&o->contents); + + } + } + + return(READSTAT); +} + +rs_write_stats(FILE *savef, struct stats *s) +{ + DBG(("Stats\n")); + rs_write_int(savef, RSXR_STATS); + + rs_write_short(savef, s->s_str); + rs_write_short(savef, s->s_intel); + rs_write_short(savef, s->s_wisdom); + rs_write_short(savef, s->s_dext); + rs_write_short(savef, s->s_const); + rs_write_short(savef, s->s_charisma); + rs_write_ulong(savef, s->s_exp); + rs_write_int(savef, s->s_lvladj); + rs_write_int(savef, s->s_lvl); + rs_write_int(savef, s->s_arm); + rs_write_int(savef, s->s_hpt); + rs_write_int(savef, s->s_pack); + rs_write_int(savef, s->s_carry); + rs_write(savef, s->s_dmg, sizeof(s->s_dmg)); + + return(WRITESTAT); +} + +rs_read_stats(int inf, struct stats *s) +{ + int id; + + if (rs_read_int(inf, &id) != 0) + { + if (id != RSXR_STATS) + { + printf("Invalid id. %x != %x(RSXR_STATS)\n", id,RSXR_STATS); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else + { + rs_read_short(inf,&s->s_str); + rs_read_short(inf,&s->s_intel); + rs_read_short(inf,&s->s_wisdom); + rs_read_short(inf,&s->s_dext); + rs_read_short(inf,&s->s_const); + rs_read_short(inf,&s->s_charisma); + rs_read_ulong(inf,&s->s_exp); + rs_read_int(inf,&s->s_lvladj); + rs_read_int(inf,&s->s_lvl); + rs_read_int(inf,&s->s_arm); + rs_read_int(inf,&s->s_hpt); + rs_read_int(inf,&s->s_pack); + rs_read_int(inf,&s->s_carry); + rs_read(inf,s->s_dmg,sizeof(s->s_dmg)); + } + } + + return(READSTAT); +} + +rs_write_mstats(FILE *savef, struct mstats *s) +{ + DBG(("M-Stats\n")); + rs_write_int(savef, RSXR_STATS); + rs_write_short(savef, s->ms_str); + /*printf(" Strength: %d\n",s->ms_str);*/ + rs_write_short(savef, s->ms_dex); + rs_write_short(savef, s->ms_move); + rs_write_ulong(savef, s->ms_exp); + rs_write_short(savef, s->ms_lvl); + rs_write_short(savef, s->ms_arm); + rs_write(savef, s->ms_hpt, sizeof(s->ms_hpt)); + rs_write(savef, s->ms_dmg, sizeof(s->ms_dmg)); + /*printf(" Damage: %s\n",s->ms_dmg);*/ + + return(WRITESTAT); +} + +rs_read_mstats(int inf, struct mstats *s) +{ + int id; + + if (rs_read_int(inf, &id) != 0) + { + if (id != RSXR_STATS) + { + printf("Invalid id. %x != %x(RSXR_STATS)\n", id,RSXR_STATS); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else + { + rs_read_short(inf,&s->ms_str); + /*printf(" Strength: %d\n",s->ms_str);*/ + rs_read_short(inf,&s->ms_dex); + /*printf(" Dexterity: %d\n",s->ms_dex);*/ + rs_read_short(inf,&s->ms_move); + /*printf(" Moves: %d\n",s->ms_move);*/ + rs_read_ulong(inf,&s->ms_exp); + /*printf(" Experience: %d\n",s->ms_exp);*/ + rs_read_short(inf,&s->ms_lvl); + /*printf(" Level: %d\n",s->ms_lvl);*/ + rs_read_short(inf,&s->ms_arm); + /*printf(" Armor: %d\n",s->ms_arm);*/ + rs_read(inf,s->ms_hpt,sizeof(s->ms_hpt)); + /*printf(" HP: %s\n",s->ms_hpt);*/ + rs_read(inf,s->ms_dmg,sizeof(s->ms_dmg)); + /*printf(" Damage: %s\n",s->ms_dmg);*/ + } + } + + return(READSTAT); +} + +rs_write_init_weps(FILE *savef, struct init_weps *w, int count) +{ + int i; + + DBG(("Init-Weps\n")); + rs_write_int(savef, RSXR_IWEAPS); + rs_write_int(savef, count); + + for(i=0;i<count;i++) + { + rs_write(savef, w[i].w_name, sizeof(w[i].w_name)); + rs_write(savef, w[i].w_dam, sizeof(w[i].w_dam)); + rs_write(savef, w[i].w_hrl, sizeof(w[i].w_hrl)); + rs_write_char(savef, w[i].w_launch); + rs_write_int(savef, w[i].w_flags); + rs_write_int(savef, w[i].w_rate); + rs_write_int(savef, w[i].w_wght); + rs_write_int(savef, w[i].w_worth); + } + return(WRITESTAT); +} + +rs_read_init_weps(int inf, struct init_weps *w,int count) +{ + int id,value,i; + + rs_read_int(inf, &id); + rs_read_int(inf, &value); + + if (value != count) + { + printf("Incorrect number of init_weps in block. %d != %d.", + value,count); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else for (i = 0; i < count; i++) + { + rs_read(inf, w[i].w_name, sizeof(w[i].w_name)); + rs_read(inf, w[i].w_dam, sizeof(w[i].w_dam)); + rs_read(inf, w[i].w_hrl, sizeof(w[i].w_hrl)); + rs_read_char(inf, &w[i].w_launch); + rs_read_int(inf, &w[i].w_flags); + rs_read_int(inf, &w[i].w_rate); + rs_read_int(inf, &w[i].w_wght); + rs_read_int(inf, &w[i].w_worth); + } + return(READSTAT); +} + +rs_write_init_armor(FILE *savef, struct init_armor *a, int count) +{ + int i; + DBG(("Init-Armor\n")); + rs_write_int(savef, RSXR_IARMOR); + rs_write_int(savef, count); + for(i=0;i<count;i++) + { + rs_write(savef, a[i].a_name, sizeof(a[i].a_name)); + rs_write_int(savef, a[i].a_prob); + rs_write_int(savef, a[i].a_class); + rs_write_int(savef, a[i].a_worth); + rs_write_int(savef, a[i].a_wght); + } + return(WRITESTAT); +} + +rs_read_init_armor(int inf, struct init_armor *a,int count) +{ + int id,value,i; + + rs_read_int(inf, &id); + rs_read_int(inf, &value); + + for(i=0;i<count;i++) + { + rs_read(inf, a[i].a_name, sizeof(a[i].a_name)); + rs_read_int(inf, &a[i].a_prob); + rs_read_int(inf, &a[i].a_class); + rs_read_int(inf, &a[i].a_worth); + rs_read_int(inf, &a[i].a_wght); + } + + return(READSTAT); +} + +rs_write_spells(FILE *savef, struct spells *s, int count) +{ + int i; + DBG(("Spells\n")); + rs_write_int(savef, RSXR_SPELLS); + rs_write_int(savef, count); + for(i=0;i<count;i++) + { + rs_write_short(savef, s[i].s_which); + rs_write_short(savef, s[i].s_cost); + rs_write_short(savef, s[i].s_type); + rs_write_int(savef, s[i].s_flag); + } + return(WRITESTAT); +} + +rs_read_spells(int inf, struct spells *s,int count) +{ + int id,value,i; + + rs_read_int(inf, &id); + rs_read_int(inf, &value); + + for(i=0;i<count;i++) + { + rs_read_short(inf, &s[i].s_which); + rs_read_short(inf, &s[i].s_cost); + rs_read_short(inf, &s[i].s_type); + rs_read_int(inf, &s[i].s_flag); + } + return(READSTAT); +} + +rs_write_item_list(FILE *savef, struct item_list *i) +{ + DBG(("Item List\n")); + rs_write_int(savef, RSXR_ILIST); + rs_write_char(savef, i->item_ch); + rs_write(savef, i->item_desc, sizeof(i->item_desc)); + return(WRITESTAT); +} +rs_read_item_list(int inf, struct item_list *i) +{ + int id; + + rs_read_int(inf, &id); + + rs_read_uchar(inf, &i->item_ch); + rs_read(inf, i->item_desc,sizeof(i->item_desc)); + return(READSTAT); +} + +rs_write_h_list(FILE *savef, struct h_list *h) +{ + DBG(("H List\n")); + rs_write_int(savef, RSXR_HLIST); + rs_write_char(savef, h->h_ch); + rs_write(savef, h->h_desc, sizeof(h->h_desc)); + return(WRITESTAT); +} + +rs_read_h_list(int inf, struct h_list *h) +{ + int id; + + rs_read_int(inf, &id); + + rs_read_char(inf, &h->h_ch); + rs_read(inf, h->h_desc,sizeof(h->h_desc)); + return(READSTAT); +} + +rs_write_death_types(FILE *savef, struct death_type *d,int count) +{ + int i; + + DBG(("Death Types\n")); + rs_write_int(savef, RSXR_DEATHTYPE); + rs_write_int(savef, count); + + for(i=0; i < count; i++) + { + rs_write_int(savef, d[i].reason); + rs_write(savef, d[i].name, sizeof(d[i].name)); + } + return(WRITESTAT); +} +rs_read_death_types(int inf, struct death_type *d, int count) +{ + int id,value,i; + + rs_read_int(inf, &id); + rs_read_int(inf, &value); + if (value != count) + { + printf("Incorrect number of death_types in block. %d > %d.", + value,count); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else for(i=0;i < count;i++) + { + rs_read_int(inf, &d[i].reason); + rs_read(inf, d[i].name,sizeof(d[i].name)); + } + return(READSTAT); +} + +rs_write_character_types(FILE *savef, struct character_types *c, int count) +{ + int i; + + DBG(("Character Types\n")); + rs_write_int(savef, RSXR_CTYPES); + rs_write_int(savef,count); + + for(i=0;i<count;i++) + { + rs_write(savef, c[i].name, sizeof(c[i].name)); + rs_write_long(savef, c[i].start_exp); + rs_write_long(savef, c[i].cap); + rs_write_int(savef, c[i].hit_pts); + rs_write_int(savef, c[i].base); + rs_write_int(savef, c[i].max_lvl); + rs_write_int(savef, c[i].factor); + rs_write_int(savef, c[i].offset); + rs_write_int(savef, c[i].range); + } + return(WRITESTAT); +} + +rs_read_character_types(int inf, struct character_types *c,int count) +{ + int id,value,i; + + rs_read_int(inf, &id); + rs_read_int(inf, &value); + + if (value != count) + { + printf("Incorrect number of character types in block. %d > %d.", + value,count); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else for (i = 0; i < count; i++) + { + rs_read(inf, c[i].name,sizeof(c[i].name)); + rs_read_long(inf, &c[i].start_exp); + rs_read_long(inf, &c[i].cap); + rs_read_int(inf, &c[i].hit_pts); + rs_read_int(inf, &c[i].base); + rs_read_int(inf, &c[i].max_lvl); + rs_read_int(inf, &c[i].factor); + rs_read_int(inf, &c[i].offset); + rs_read_int(inf, &c[i].range); + } + return(READSTAT); +} + +rs_write_traps(FILE *savef, struct trap *trap,int count) +{ + int n; + + DBG(("Traps\n")); + rs_write_int(savef, RSXR_TRAP); + rs_write_int(savef, count); + + for(n=0; n<count; n++) + { + rs_write_char(savef, trap[n].tr_type); + rs_write_char(savef, trap[n].tr_show); + rs_write_coord(savef, &trap[n].tr_pos); + rs_write_long(savef, trap[n].tr_flags); + } +} + +rs_read_traps(int inf, struct trap *trap, int count) +{ + int id = 0, value = 0, n = 0; + + if (rs_read_int(inf,&id) != 0) + { + if (id != RSXR_TRAP) + { + printf("Invalid id. %x != %x(RSXR_TRAP)\n", + id,RSXR_TRAP); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else if (rs_read_int(inf,&value) != 0) + { + if (value != count) + { + printf("Incorrect number of traps in block. %d > %d.", + value,count); + printf("Sorry, invalid save game format\n"); + format_error = TRUE; + } + else + { + for(n=0;n<value;n++) + { + rs_read_uchar(inf,&trap[n].tr_type); + rs_read_uchar(inf,&trap[n].tr_show); + rs_read_coord(inf,&trap[n].tr_pos); + rs_read_long(inf,&trap[n].tr_flags); + } + } + } + else + format_error = TRUE; + } + + return(READSTAT); +} + +rs_write_monsters(FILE * savef, struct monster * m, int count) +{ + int n; + + DBG(("Monsters\n")); + rs_write_int(savef, RSXR_MONSTERS); + rs_write_int(savef, count); + + for(n=0;n<count;n++) + { + rs_write(savef, m[n].m_name, sizeof(m[n].m_name)); + /*printf("Monster: %s/%d/%d\n",m[n].m_name,sizeof(m[n].m_name),strlen(m[n].m_name));*/ + rs_write_short(savef, m[n].m_carry); + rs_write_boolean(savef, m[n].m_normal); + rs_write_boolean(savef, m[n].m_wander); + rs_write_char(savef, m[n].m_appear); + rs_write(savef, m[n].m_intel,sizeof(m[n].m_intel)); + rs_write_longs(savef, m[n].m_flags, MAXFLAGS); + rs_write(savef, m[n].m_typesum,sizeof(m[n].m_typesum)); + rs_write_short(savef, m[n].m_numsum); + rs_write_short(savef, m[n].m_add_exp); + + rs_write_mstats(savef, &m[n].m_stats); + } + + return(WRITESTAT); +} + +rs_read_monsters(int inf, struct monster *m, int count) +{ + int id = 0, value = 0, n = 0; + char buffer[1024]; + + if (rs_read_int(inf, &id) != 0) + { + if (id != RSXR_MONSTERS) + { + printf("Invalid id. %x != %x(RSXR_MONSTERS)\n", + id,RSXR_MONSTERS); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else if (rs_read_int(inf, &value) != 0) + { + if (value != count) + { printf("Incorrect number of monsters in block. %d != %d.", + value,count); + printf("Sorry, invalid save game format\n"); + format_error = TRUE; + + } + else for(n=0;n<value;n++) + { + rs_read(inf, buffer,sizeof(m[n].m_name)); + assert( strcmp(buffer,m[n].m_name) == 0); + /*printf("Monster: %s\n",m[n].m_name);*/ + rs_read_short(inf, &m[n].m_carry); + /*printf(" Carry: %d\n",m[n].m_carry); */ + rs_read_boolean(inf, &m[n].m_normal); + /*printf(" Normal: %d\n",m[n].m_normal);*/ + rs_read_boolean(inf, &m[n].m_wander); + /*printf(" Wander: %d\n",m[n].m_wander);*/ + rs_read_char(inf, &m[n].m_appear); + /*printf(" Appears: %c\n",m[n].m_appear);*/ + rs_read(inf, m[n].m_intel,sizeof(m[n].m_intel)); + /*printf(" Intelligence: %s\n",m[n].m_intel);*/ + rs_read_longs(inf, m[n].m_flags, MAXFLAGS); + /*printf(" Flags: %X\n",m[n].m_flags);*/ + rs_read(inf, m[n].m_typesum, sizeof(m[n].m_typesum)); + /*printf(" Summons: %s\n",m[n].m_typesum);*/ + rs_read_short(inf, &m[n].m_numsum); + /*printf(" # Summons: %d\n",m[n].m_numsum);*/ + rs_read_short(inf, &m[n].m_add_exp); + /*printf(" Experience: %d\n",m[n].m_add_exp);*/ + rs_read_mstats(inf, &m[n].m_stats); + + } + } + else + format_error = TRUE; + } + + return(READSTAT); +} + +/*****************************************************************************/ + +rs_write_coord_list(FILE *savef, struct linked_list *l) +{ + DBG(("Coordinate List\n")); + rs_write_int(savef, RSXR_COORDLIST); + rs_write_int(savef, list_size(l)); + + while (l != NULL) + { + rs_write_coord(savef, (coord *) l->l_data); + l = l->l_next; + } + + return(WRITESTAT); +} + +rs_read_coord_list(int inf, struct linked_list **list) +{ + int id; + int i, cnt; + struct linked_list *l = NULL, *previous = NULL, *head = NULL; + + if (rs_read_int(inf,&id) != 0) + { + if (id != RSXR_COORDLIST) + { + printf("Invalid id. %x != %x(RSXR_COORDLIST)\n", + id,RSXR_COORDLIST); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else if (rs_read_int(inf,&cnt) != 0) + { + for (i = 0; i < cnt; i++) + { + l = new_item(sizeof(coord)); + l->l_prev = previous; + if (previous != NULL) + previous->l_next = l; + rs_read_coord(inf,(coord *) l->l_data); + if (previous == NULL) + head = l; + previous = l; + } + + if (l != NULL) + l->l_next = NULL; + + *list = head; + } + else + format_error = TRUE; + } + else + format_error = TRUE; + + return(READSTAT); +} + +rs_write_object_list(FILE *savef, struct linked_list *l) +{ + DBG(("Object List\n")); + rs_write_int(savef, RSXR_OBJECTLIST); + rs_write_int(savef, list_size(l)); + + while (l != NULL) + { + rs_write_object(savef, (struct object *) l->l_data); + l = l->l_next; + } + + return(WRITESTAT); +} + +rs_read_object_list(int inf, struct linked_list **list) +{ + int id; + int i, cnt; + struct linked_list *l = NULL, *previous = NULL, *head = NULL; + + if (rs_read_int(inf,&id) != 0) + { + if (rs_read_int(inf,&cnt) != 0) + { + for (i = 0; i < cnt; i++) + { + l = new_item(sizeof(struct object)); + memset(l->l_data,0,sizeof(struct object)); + l->l_prev = previous; + if (previous != NULL) + previous->l_next = l; + rs_read_object(inf,(struct object *) l->l_data); + if (previous == NULL) + head = l; + previous = l; + } + + if (l != NULL) + l->l_next = NULL; + + *list = head; + } + else + format_error = TRUE; + } + else + format_error = TRUE; + + + return(READSTAT); +} + +int +find_thing_coord(monlist, c) +struct linked_list *monlist; +coord *c; +{ + struct linked_list *mitem; + struct thing *tp; + int i = 0; + + for(mitem = monlist; mitem != NULL; mitem = mitem->l_next) + { + tp = THINGPTR(mitem); + if (c == &tp->t_pos) + return(i); + i++; + } + + return(-1); +} + +int +find_object_coord(objlist, c) +struct linked_list *objlist; +coord *c; +{ + struct linked_list *oitem; + struct object *obj; + int i = 0; + + for(oitem = objlist; oitem != NULL; oitem = oitem->l_next) + { + obj = OBJPTR(oitem); + if (c == &obj->o_pos) + return(i); + i++; + } + + return(-1); +} + +rs_write_thing(FILE *savef, struct thing *t) +{ + int i = -1; + + DBG(("Thing\n")); + rs_write_int(savef, RSXR_THING); + rs_write_boolean(savef,t->t_wasshot); + rs_write_char(savef, t->t_type); + rs_write_char(savef, t->t_disguise); + rs_write_char(savef, t->t_oldch); + rs_write_short(savef, t->t_ctype); + rs_write_short(savef, t->t_index); + rs_write_short(savef, t->t_no_move); + rs_write_short(savef, t->t_quiet); + rs_write_short(savef, t->t_movement); + rs_write_short(savef, t->t_action); + rs_write_short(savef, t->t_artifact); + rs_write_short(savef, t->t_wand); + rs_write_short(savef, t->t_summon); + rs_write_short(savef, t->t_cast); + rs_write_short(savef, t->t_breathe); + + rs_write_string(savef,t->t_name); + rs_write_coord(savef, &t->t_doorgoal); + + if (t->t_dest == &hero) + { + rs_write_int(savef,0); + rs_write_int(savef,1); + } + else if (t->t_dest != NULL) + { + i = find_thing_coord(mlist, t->t_dest); + + if (i >= 0) + { + rs_write_int(savef,1); + rs_write_int(savef,i); + } + else + { + i = find_object_coord(lvl_obj, t->t_dest); + + if (i >= 0) + { + rs_write_int(savef,2); + rs_write_int(savef,i); + } + else + { + rs_write_int(savef,0); + rs_write_int(savef,1); /* chase the hero anyway */ + } + } + } + else + { + rs_write_int(savef,0); + rs_write_int(savef,0); + } + + rs_write_coord(savef, &t->t_pos); + rs_write_coord(savef, &t->t_oldpos); + rs_write_coord(savef, &t->t_newpos); + rs_write_ulongs(savef, t->t_flags, 16); + + DBG(("Thing\n")); + DBG((" SaveID : %X\n",RSXR_THING)); + DBG((" Name : %s\n",t->t_name)); + DBG((" WasShot : %d\n",t->t_wasshot)); + DBG((" Type : %c(%d)\n",t->t_type,t->t_type)); + DBG((" Disguise: %c(%d)\n",t->t_disguise,t->t_disguise)); + DBG((" OldCh : %c(%d)\n",t->t_oldch,t->t_oldch)); + DBG((" CType : %d\n",t->t_ctype)); + DBG((" Index : %d\n",t->t_index)); + DBG((" NoMove : %d\n",t->t_no_move)); + DBG((" Quiet : %d\n",t->t_quiet)); + DBG((" Movement: %d\n",t->t_movement)); + DBG((" Action : %d\n",t->t_action)); + DBG((" Artifact: %d\n",t->t_artifact)); + DBG((" Wand : %d\n",t->t_wand)); + DBG((" Summon : %d\n",t->t_summon)); + DBG((" Cast : %d\n",t->t_cast)); + DBG((" Breathe : %d\n",t->t_breathe)); + DBG((" DoorGoal: %d %d\n",t->t_doorgoal.x,t->t_doorgoal.y)); + if (t->t_dest) + { + DBG((" Dest : %d %d\n",t->t_dest->x,t->t_dest->y)); + } + else + { + DBG((" Dest : None\n")); + } + DBG((" Pos : %d %d\n",t->t_pos.x,t->t_pos.y)); + DBG((" OldPos : %d %d\n",t->t_oldpos.x,t->t_oldpos.y)); + DBG((" NewPos : %d %d\n",t->t_newpos.x,t->t_newpos.y)); + DBG((" Flags : ")); + { int i; for(i=0;i<16;i++) {DBG(("%d ",t->t_flags[i]));} DBG(("\n")); } + + rs_write_object_list(savef, t->t_pack); + i = -1; + if (t->t_using != NULL) + i = find_list_ptr(t->t_pack, t->t_using->l_data); + rs_write_int(savef, i); + rs_write_stats(savef, &t->t_stats); + rs_write_stats(savef, &t->maxstats); + + return(WRITESTAT); +} + +rs_fix_thing(struct thing *t) +{ + struct linked_list *item; + struct thing *tp; + + if (t->t_reserved < 0) + return; + + item = get_list_item(mlist,t->t_reserved); + + if (item != NULL) + { + tp = THINGPTR(item); + t->t_dest = &tp->t_pos; + } +} + +rs_read_thing(int inf, struct thing *t) +{ + int id; + int listid = 0, index = -1; + struct linked_list *item; + + if (rs_read_int(inf, &id) != 0) + { + if (id != RSXR_THING) + format_error = TRUE; + else + { + rs_read_boolean(inf,&t->t_wasshot); + rs_read_uchar(inf, &t->t_type); + rs_read_uchar(inf, &t->t_disguise); + rs_read_uchar(inf, &t->t_oldch); + rs_read_short(inf, &t->t_ctype); + rs_read_short(inf, &t->t_index); + rs_read_short(inf, &t->t_no_move); + rs_read_short(inf, &t->t_quiet); + rs_read_short(inf, &t->t_movement); + rs_read_short(inf, &t->t_action); + rs_read_short(inf, &t->t_artifact); + rs_read_short(inf, &t->t_wand); + rs_read_short(inf, &t->t_summon); + rs_read_short(inf, &t->t_cast); + rs_read_short(inf, &t->t_breathe); + rs_read_new_string(inf,&t->t_name); + rs_read_coord(inf,&t->t_doorgoal); + + rs_read_int(inf,&listid); + rs_read_int(inf,&index); + t->t_reserved = -1; + if (listid == 0) + { + if (index == 1) + t->t_dest = &hero; + else + t->t_dest = NULL; + } + else if (listid == 1) + { + t->t_dest = NULL; + t->t_reserved = index; + } + else if (listid == 2) + { + struct object *obj; + item = get_list_item(lvl_obj,index); + if (item != NULL) + { + obj = OBJPTR(item); + t->t_dest = &obj->o_pos; + } + } + else + t->t_dest = NULL; + + rs_read_coord(inf,&t->t_pos); + rs_read_coord(inf,&t->t_oldpos); + rs_read_coord(inf,&t->t_newpos); + rs_read_ulongs(inf,t->t_flags,16); + rs_read_object_list(inf,&t->t_pack); + rs_read_int(inf,&index); + t->t_using = get_list_item(t->t_pack, index); + rs_read_stats(inf,&t->t_stats); + rs_read_stats(inf,&t->maxstats); + } + } + else format_error = TRUE; + + return(READSTAT); +} + +int +find_list_ptr(struct linked_list *l, void *ptr) +{ + int count = 0; + + while(l != NULL) + { + if (l->l_data == ptr) + return(count); + + l = l->l_next; + count++; + } + + return(-1); +} + + +int +list_size(struct linked_list *l) +{ + int count = 0; + + while(l != NULL) + { + if (l->l_data == NULL) + return(count); + + count++; + + l = l->l_next; + } + + return(count); +} + + +rs_write_monster_list(FILE *savef, struct linked_list *l) +{ + int cnt = 0; + + DBG(("Monster List\n")); + rs_write_int(savef, RSXR_MONSTERLIST); + + cnt = list_size(l); + + rs_write_int(savef, cnt); + + if (cnt < 1) + return(WRITESTAT); + + while (l != NULL) { + rs_write_thing(savef, (struct thing *)l->l_data); + l = l->l_next; + } + + return(WRITESTAT); +} + +rs_fix_monster_list(list) +struct linked_list *list; +{ + struct linked_list *item; + + for(item = list; item != NULL; item = item->l_next) + rs_fix_thing(THINGPTR(item)); +} + +rs_read_monster_list(int inf, struct linked_list **list) +{ + int id; + int i, cnt; + struct linked_list *l = NULL, *previous = NULL, *head = NULL; + + if (rs_read_int(inf,&id) != 0) + { + if (id != RSXR_MONSTERLIST) + { + printf("Invalid id. %x != %x(RSXR_MONSTERLIST)\n", + id,RSXR_MONSTERLIST); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else if (rs_read_int(inf,&cnt) != 0) + { + for (i = 0; i < cnt; i++) + { + l = new_item(sizeof(struct thing)); + l->l_prev = previous; + if (previous != NULL) + previous->l_next = l; + rs_read_thing(inf,(struct thing *)l->l_data); + if (previous == NULL) + head = l; + previous = l; + } + + + if (l != NULL) + l->l_next = NULL; + + *list = head; + } + } + else format_error = TRUE; + + return(READSTAT); +} + +rs_write_magic_items(FILE *savef, struct magic_item *i, int count) +{ + int n; + + DBG(("Magic Items\n")); + rs_write_int(savef, RSXR_MAGICITEMS); + rs_write_int(savef, count); + + for(n=0;n<count;n++) + { + rs_write(savef,i[n].mi_name,sizeof(i[n].mi_name)); + rs_write_int(savef,i[n].mi_prob); + rs_write_int(savef,i[n].mi_worth); + rs_write_int(savef,i[n].mi_curse); + rs_write_int(savef,i[n].mi_bless); + } + + return(WRITESTAT); +} + +rs_read_magic_items(int inf, struct magic_item *mi, int count) +{ + int id; + int n; + int value; + + if (rs_read_int(inf, &id) != 0) + { + if (id != RSXR_MAGICITEMS) + { + printf("Invalid id. %x != %x(RSXR_MAGICITEMS)\n", + id,RSXR_MAGICITEMS); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else if (rs_read_int(inf, &value) != 0) + { + if (value > count) + { + printf("Incorrect number of magic items in block. %d > %d.", + value,count); + printf("Sorry, invalid save game format"); + format_error = TRUE; + } + else + { + for(n = 0; n < value; n++) + { + rs_read(inf,mi[n].mi_name,sizeof(mi[n].mi_name)); + rs_read_int(inf,&mi[n].mi_prob); + rs_read_int(inf,&mi[n].mi_worth); + rs_read_int(inf,&mi[n].mi_curse); + rs_read_int(inf,&mi[n].mi_bless); + } + } + } + } + + return(READSTAT); +} + +rs_write_window(FILE *savef, WINDOW *win) +{ + int row,col,height,width; + width = getmaxx(win); + height = getmaxy(win); + DBG(("Window\n")); + rs_write_int(savef,height); + rs_write_int(savef,width); + + for(row=0;row<height;row++) + for(col=0;col<width;col++) + rs_write_int(savef, mvwinch(win,row,col)); +} + +rs_read_window(int inf, WINDOW *win) +{ + int row,col,maxlines,maxcols,value,width,height; + + width = getmaxx(win); + height = getmaxy(win); + + rs_read_int(inf,&maxlines); + rs_read_int(inf,&maxcols); + if (maxlines > height) + abort(); + if (maxcols > width) + abort(); + + for(row=0;row<maxlines;row++) + for(col=0;col<maxcols;col++) + { + rs_read_int(inf, &value); + if ((value == '-') || (value == 196)) + value = HORZWALL; + else if ((value == '|') || (value == 179)) + value = VERTWALL; + mvwaddch(win,row,col,value); + } + + return(READSTAT); +} + +rs_save_file(FILE *savef) +{ + int i, weapon, armor, ring, misc, room = -1; + int endian = 0x01020304; + big_endian = ( *((char *)&endian) == 0x01 ); + + rs_write_thing(savef, &player); /* rogue.c */ + rs_write_object_list(savef, lvl_obj); /* rogue.c */ + rs_write_monster_list(savef, mlist); /* rogue.c */ + rs_write_monster_list(savef, tlist); /* rogue.c */ + + rs_write_traps(savef, traps, MAXTRAPS); /* rogue.c */ + + armor = find_list_ptr(player.t_pack, cur_armor); + rs_write_int(savef, armor); /* rogue.c */ + + for (i = 0; i < NUM_FINGERS; i++) + { + ring = find_list_ptr(player.t_pack, cur_ring[i]); + rs_write_int(savef, ring); /* rogue.c */ + } + + for (i = 0; i < NUM_MM; i++) + { + misc = find_list_ptr(player.t_pack, cur_misc[i]); + rs_write_int(savef, misc); /* rogue.c */ + } + + for (i=0; i<MAXRELIC; i++) + rs_write_int(savef,cur_relic[i]); /* rogue.c */ + + + rs_write_rooms(savef, rooms, MAXROOMS); /* rogue.c */ + + for (i = 0; i < MAXROOMS; i++) + if (&rooms[i] == oldrp) + room = i; + rs_write_int(savef, room); /* rogue.c */ + + weapon = find_list_ptr(player.t_pack, cur_weapon); + rs_write_int(savef, weapon); /* rogue..c */ + rs_write_int(savef,char_type); + rs_write_int(savef,foodlev); + rs_write_int(savef,ntraps); + rs_write_int(savef,trader); + rs_write_int(savef,curprice); + rs_write_int(savef,seed); + rs_write_int(savef,max_level); + rs_write_int(savef,cur_max); + rs_write_int(savef,prev_max); + rs_write_int(savef,move_free); + rs_write_int(savef,mpos); + rs_write_int(savef,level); + rs_write_long(savef,purse); + rs_write_int(savef,inpack); + rs_write_int(savef,total); + rs_write_int(savef,no_food); + rs_write_int(savef,foods_this_level); + rs_write_int(savef,count); + rs_write_int(savef,food_left); + rs_write_int(savef,group); + rs_write_int(savef,hungry_state); + rs_write_int(savef,infest_dam); + rs_write_int(savef,lost_str); + rs_write_int(savef,lastscore); + rs_write_int(savef,hold_count); + rs_write_int(savef,trap_tries); + rs_write_int(savef,chant_time); + rs_write_int(savef,pray_time); + rs_write_int(savef,spell_power); + rs_write_long(savef,turns); + rs_write_int(savef,quest_item); + rs_write_int(savef,cols); + rs_write_int(savef,lines); + rs_write_int(savef,nfloors); + rs_write(savef,curpurch,LINELEN); + rs_write_char(savef,PLAYER); + rs_write_char(savef,take); + rs_write_int(savef,1234);/*checkpoint*/ + rs_write(savef,prbuf,LINELEN*2); + rs_write_int(savef,1234);/*checkpoint*/ + rs_write_char(savef,runch); + rs_write_int(savef,1234);/*checkpoint*/ + rs_write_scrolls(savef); + rs_write_potions(savef); + rs_write_rings(savef); + rs_write_sticks(savef); + rs_write_misc(savef); + rs_write_int(savef,1234);/*checkpoint*/ + rs_write(savef,whoami,LINELEN); + rs_write_window(savef, cw); + rs_write_window(savef, hw); + rs_write_window(savef, mw); + rs_write_window(savef, msgw); + rs_write_window(savef, stdscr); + rs_write_boolean(savef,pool_teleport); + rs_write_boolean(savef,inwhgt); + rs_write_boolean(savef,after); + rs_write_boolean(savef,waswizard); + rs_write_boolean(savef, playing); /* rogue.h/init.c */ + rs_write_boolean(savef, running); /* rogue.h/init.c */ + rs_write_boolean(savef, wizard); /* rogue.h/init.c */ + rs_write_boolean(savef, notify); /* rogue.h/init.c */ + rs_write_boolean(savef, fight_flush); /* rogue.h/init.c */ + rs_write_boolean(savef, terse); /* rogue.h/init.c */ + rs_write_boolean(savef, auto_pickup); /* rogue.h/init.c */ + rs_write_boolean(savef, def_attr); /* rogue.h/init.c */ + rs_write_boolean(savef, menu_overlay); /* rogue.h/init.c */ + rs_write_boolean(savef, door_stop); /* rogue.h/init.c */ + rs_write_boolean(savef, jump); /* rogue.h/init.c */ + rs_write_boolean(savef, slow_invent); /* rogue.h/init.c */ + rs_write_boolean(savef, firstmove); /* rogue.h/init.c */ + rs_write_boolean(savef, askme); /* rogue.h/init.c */ + rs_write_boolean(savef, in_shell); /* rogue.h/init.c */ + rs_write_boolean(savef, daytime); /* rogue.h/init.c */ + rs_write_boolean(savef, funfont); /* rogue.h/init.c */ + rs_write_levtype(savef,levtype); + rs_write_character_types(savef,char_class,NUM_CHARTYPES); + rs_write_words(savef,abilities,NUMABILITIES); + for(i=0;i<9;i++) + rs_write_coord(savef,&grid[i]); + rs_write_death_types(savef,deaths,DEATHNUM); + rs_write_init_weps(savef,weaps,MAXWEAPONS); + rs_write_init_armor(savef,armors,MAXARMORS); + rs_write_magic_items(savef, things, NUMTHINGS); /* rogue.h/init.c */ + rs_write_magic_items(savef, s_magic, MAXSCROLLS); /* rogue.h/init.c */ + rs_write_magic_items(savef, p_magic, MAXPOTIONS); /* rogue.h/init.c */ + rs_write_magic_items(savef, r_magic, MAXRINGS); /* rogue.h/init.c */ + rs_write_magic_items(savef, ws_magic, MAXSTICKS); /* rogue.h/init.c */ + rs_write_magic_items(savef, m_magic, MAXMM); /* rogue.h/init.c */ + rs_write_magic_items(savef, rel_magic, MAXRELIC); /* rogue.h/init.c */ + rs_write_magic_items(savef, foods, MAXFOODS); /* rogue.h/init.c */ + rs_write_spells(savef,magic_spells,MAXSPELLS); + rs_write_spells(savef,cleric_spells,MAXPRAYERS); + rs_write_spells(savef,druid_spells,MAXCHANTS); + rs_write_spells(savef,quill_scrolls,MAXQUILL); + + rs_write_int(savef,mf_count); /* actions.c */ + rs_write_int(savef,mf_jmpcnt); /* actions.c */ + rs_write_daemons(savef, d_list, MAXDAEMONS); /* daemon.c */ + rs_write_daemons(savef, f_list, MAXFUSES); /* daemon.c */ + rs_write_int(savef,demoncnt); /* daemon.c */ + rs_write_int(savef,fusecnt); /* daemon.c */ + rs_write_int(savef,killed_chance); /* fight.c */ + rs_write_words(savef,rainbow,NCOLORS); /* init.c */ + rs_write_words(savef,sylls,NSYLLS); /* init.c */ + rs_write_words(savef,stones,NSTONES); /* init.c */ + rs_write_words(savef,wood,NWOOD); /* init.c */ + rs_write_words(savef,metal,NMETAL); /* init.c */ + rs_write_monsters(savef,monsters, + sizeof(monsters)/sizeof(struct monster)); /* mons_def.c */ + rs_write_coord(savef,&move_nh); /* move.c */ + return(WRITESTAT); +} + +rs_restore_file(int inf) +{ + int weapon, armor, ring, misc, room = -1,i,checkpoint; + int endian = 0x01020304; + big_endian = ( *((char *)&endian) == 0x01 ); + + rs_read_thing(inf, &player); /* rogue.h */ + rs_read_object_list(inf, &lvl_obj); /* rogue.h/init.c */ + rs_read_monster_list(inf, &mlist); /* rogue.h/init.c */ + rs_read_monster_list(inf, &tlist); /* rogue.h/init.c */ + rs_fix_thing(&player); + rs_fix_monster_list(mlist); + rs_read_traps(inf, traps, MAXTRAPS); + + + rs_read_int(inf, &armor); /* rogue.h */ + cur_armor = get_list_item(player.t_pack,armor); + + for(i = 0; i < NUM_FINGERS; i++) + { + rs_read_int(inf,&ring); + cur_ring[i] = get_list_item(player.t_pack,ring); + } + + for(i = 0; i < NUM_MM; i++) + { + rs_read_int(inf,&misc); + cur_misc[i] = get_list_item(player.t_pack,misc); + } + + for(i=0;i<MAXRELIC;i++) + rs_read_int(inf,&cur_relic[i]); + + rs_read_rooms(inf, rooms, MAXROOMS); + rs_read_int(inf, &room); + + oldrp = &rooms[room]; + + rs_read_int(inf,&weapon); + cur_weapon = get_list_item(player.t_pack,weapon); + + rs_read_int(inf,&char_type); + rs_read_int(inf,&foodlev); + rs_read_int(inf,&ntraps); + rs_read_int(inf,&trader); + rs_read_int(inf,&curprice); + rs_read_int(inf,&seed); + rs_read_int(inf,&max_level); + rs_read_int(inf,&cur_max); + rs_read_int(inf,&prev_max); + rs_read_int(inf,&move_free); + rs_read_int(inf,&mpos); + rs_read_int(inf,&level); + rs_read_long(inf,&purse); + rs_read_int(inf,&inpack); + rs_read_int(inf,&total); + rs_read_int(inf,&no_food); + rs_read_int(inf,&foods_this_level); + rs_read_int(inf,&count); + rs_read_int(inf,&food_left); + rs_read_int(inf,&group); + rs_read_int(inf,&hungry_state); + rs_read_int(inf,&infest_dam); + rs_read_int(inf,&lost_str); + rs_read_int(inf,&lastscore); + rs_read_int(inf,&hold_count); + rs_read_int(inf,&trap_tries); + rs_read_int(inf,&chant_time); + rs_read_int(inf,&pray_time); + rs_read_int(inf,&spell_power); + rs_read_long(inf,&turns); + rs_read_int(inf,&quest_item); + rs_read_int(inf,&cols); + rs_read_int(inf,&lines); + rs_read_int(inf,&nfloors); + rs_read(inf,curpurch,LINELEN); + rs_read_char(inf,&PLAYER); + rs_read_char(inf,&take); + rs_read_int(inf,&checkpoint); + if (checkpoint != 1234){printf("Checkpoint failed");abort();} + rs_read(inf,prbuf,LINELEN*2); + rs_read_int(inf,&checkpoint); + if (checkpoint != 1234){printf("Checkpoint failed");abort();} + rs_read_char(inf,&runch); + rs_read_int(inf,&checkpoint); + if (checkpoint != 1234){printf("Checkpoint failed");abort();} + rs_read_scrolls(inf); + rs_read_potions(inf); + rs_read_rings(inf); + rs_read_sticks(inf); + rs_read_misc(inf); + rs_read_int(inf,&checkpoint); + if (checkpoint != 1234){printf("Checkpoint failed");abort();} + rs_read(inf,whoami,LINELEN); + rs_read_window(inf, cw); + rs_read_window(inf, hw); + rs_read_window(inf, mw); + rs_read_window(inf, msgw); + rs_read_window(inf, stdscr); + rs_read_boolean(inf,&pool_teleport); + rs_read_boolean(inf,&inwhgt); + rs_read_boolean(inf,&after); + rs_read_boolean(inf,&waswizard); + rs_read_boolean(inf, &playing); /* rogue.h/init.c */ + rs_read_boolean(inf, &running); /* rogue.h/init.c */ + rs_read_boolean(inf, &wizard); /* rogue.h/init.c */ + rs_read_boolean(inf, ¬ify); /* rogue.h/init.c */ + rs_read_boolean(inf, &fight_flush); /* rogue.h/init.c */ + rs_read_boolean(inf, &terse); /* rogue.h/init.c */ + rs_read_boolean(inf, &auto_pickup); /* rogue.h/init.c */ + rs_read_boolean(inf, &def_attr); /* rogue.h/init.c */ + rs_read_boolean(inf, &menu_overlay); /* rogue.h/init.c */ + rs_read_boolean(inf, &door_stop); /* rogue.h/init.c */ + rs_read_boolean(inf, &jump); /* rogue.h/init.c */ + rs_read_boolean(inf, &slow_invent); /* rogue.h/init.c */ + rs_read_boolean(inf, &firstmove); /* rogue.h/init.c */ + rs_read_boolean(inf, &askme); /* rogue.h/init.c */ + rs_read_boolean(inf, &in_shell); /* rogue.h/init.c */ + rs_read_boolean(inf, &daytime); /* rogue.h/init.c */ + rs_read_boolean(inf, &funfont); /* rogue.h/init.c */ + rs_read_levtype(inf,&levtype); + rs_read_character_types(inf,char_class,NUM_CHARTYPES); + rs_read_words(inf,abilities,NUMABILITIES); + for(i=0;i<9;i++) + rs_read_coord(inf,&grid[i]); + rs_read_death_types(inf,deaths,DEATHNUM); + rs_read_init_weps(inf,weaps,MAXWEAPONS); + rs_read_init_armor(inf,armors,MAXARMORS); + rs_read_magic_items(inf, things,NUMTHINGS); /* rogue.h/init.c */ + rs_read_magic_items(inf, s_magic,MAXSCROLLS); /* rogue.h/init.c */ + rs_read_magic_items(inf, p_magic,MAXPOTIONS); /* rogue.h/init.c */ + rs_read_magic_items(inf, r_magic,MAXRINGS); /* rogue.h/init.c */ + rs_read_magic_items(inf, ws_magic,MAXSTICKS); /* rogue.h/init.c */ + rs_read_magic_items(inf, m_magic,MAXMM); /* rogue.h/init.c */ + rs_read_magic_items(inf, rel_magic,MAXRELIC); /* rogue.h/init.c */ + rs_read_magic_items(inf, foods,MAXFOODS); /* rogue.h/init.c */ + rs_read_spells(inf,magic_spells,MAXSPELLS); + rs_read_spells(inf,cleric_spells,MAXPRAYERS); + rs_read_spells(inf,druid_spells,MAXCHANTS); + rs_read_spells(inf,quill_scrolls,MAXQUILL); + + rs_read_int(inf,&mf_count); /* actions.c */ + rs_read_int(inf,&mf_jmpcnt); /* actions.c */ + rs_read_daemons(inf, d_list, MAXDAEMONS); /* daemon.c */ + rs_read_daemons(inf, f_list, MAXFUSES); /* daemon.c */ + rs_read_int(inf,&demoncnt); /* daemon.c */ + rs_read_int(inf,&fusecnt); /* daemon.c */ + rs_read_int(inf,&killed_chance); /* fight.c */ + rs_read_words(inf,rainbow,NCOLORS); /* init.c */ + rs_read_words(inf,sylls,NSYLLS); /* init.c */ + rs_read_words(inf,stones,NSTONES); /* init.c */ + rs_read_words(inf,wood,NWOOD); /* init.c */ + rs_read_words(inf,metal,NMETAL); /* init.c */ + + rs_read_monsters(inf,monsters, + sizeof(monsters)/sizeof(struct monster)); /* mons_def.c */ + rs_read_coord(inf,&move_nh); /* move.c */ + + return(READSTAT); +} + +rs_write_scorefile(FILE *savef, struct sc_ent *entries, int count) +{ + int i; + + rs_write_int(savef, count); + for(i = 0; i < count; i++) + { + rs_write_ulong(savef, entries[i].sc_score); + rs_write(savef, entries[i].sc_name, sizeof(entries[i].sc_name)); + rs_write(savef, entries[i].sc_system, sizeof(entries[i].sc_system)); + rs_write(savef, entries[i].sc_login, sizeof(entries[i].sc_login)); + rs_write_short(savef, entries[i].sc_flags); + rs_write_short(savef, entries[i].sc_level); + rs_write_short(savef, entries[i].sc_ctype); + rs_write_short(savef, entries[i].sc_monster); + rs_write_short(savef, entries[i].sc_quest); + } +} + +rs_read_scorefile(FILE *savef, struct sc_ent *entries, int count) +{ + int i,available = 0; + + rs_read_int(fileno(savef), &available); + + if (end_of_file) + return(-1); + + if (available != count) + return(-2); + + for(i = 0; i < count; i++) + { + rs_read_ulong(fileno(savef), &entries[i].sc_score); + rs_read(fileno(savef), entries[i].sc_name, sizeof(entries[i].sc_name)); + rs_read(fileno(savef), entries[i].sc_system, sizeof(entries[i].sc_system)); + rs_read(fileno(savef), entries[i].sc_login, sizeof(entries[i].sc_login)); + rs_read_short(fileno(savef), &entries[i].sc_flags); + rs_read_short(fileno(savef), &entries[i].sc_level); + rs_read_short(fileno(savef), &entries[i].sc_ctype); + rs_read_short(fileno(savef), &entries[i].sc_monster); + rs_read_short(fileno(savef), &entries[i].sc_quest); + } + + return(0); +} + + + +rs_print_thing(FILE *outf, struct thing *thing, char *prefix, int list, int index) +{ + int i; + + fprintf(outf,"%sList Ident : %d\n", prefix, list); + fprintf(outf,"%sList Index : %d\n", prefix, index); + fprintf(outf,"%st_wasshot : %d\n", prefix, thing->t_wasshot); + fprintf(outf,"%st_type : %c\n", prefix, thing->t_type); + fprintf(outf,"%st_disguise : %c\n", prefix, thing->t_disguise); + fprintf(outf,"%st_oldch : %c\n", prefix, thing->t_oldch); + fprintf(outf,"%st_ctype : %d\n", prefix, thing->t_ctype); + fprintf(outf,"%st_index : %d\n", prefix, thing->t_index); + fprintf(outf,"%st_no_move : %d\n", prefix, thing->t_no_move); + fprintf(outf,"%st_quiet : %d\n", prefix, thing->t_quiet); + fprintf(outf,"%st_movement : %d\n", prefix, thing->t_movement); + fprintf(outf,"%st_action : %d\n", prefix, thing->t_action); + fprintf(outf,"%st_artificat: %d\n", prefix, thing->t_artifact); + fprintf(outf,"%st_wand : %d\n", prefix, thing->t_wand); + fprintf(outf,"%st_summon : %d\n", prefix, thing->t_summon); + fprintf(outf,"%st_cast : %d\n", prefix, thing->t_cast); + fprintf(outf,"%st_breathe : %d\n", prefix, thing->t_breathe); + fprintf(outf,"%st_name : %s\n", prefix, (thing->t_name == NULL) ? "none" : + thing->t_name); + fprintf(outf,"%st_doorgoal : %d %d\n", prefix, thing->t_doorgoal.x, thing->t_doorgoal.y); + fprintf(outf,"%st_dest : %p\n", prefix, thing->t_dest); + fprintf(outf,"%st_pos : %d %d (%p)\n", prefix, thing->t_pos.x, thing->t_pos.y,&thing->t_pos); + fprintf(outf,"%st_oldpos : %d %d\n", prefix, thing->t_oldpos.x, thing->t_oldpos.y); + fprintf(outf,"%st_newpos : %d %d\n", prefix, thing->t_newpos.x, thing->t_newpos.y); + fprintf(outf,"%st_flags : ", prefix); + + for(i = 0; i<16; i++) + fprintf(outf,"%X ",thing->t_flags[i]); + fprintf(outf,"\n"); + + fprintf(outf,"%st_pack : %p\n",prefix,thing->t_pack); + fprintf(outf,"%st_using : %p\n",prefix,thing->t_using); + fprintf(outf,"%st_stats : Not Implemented\n",prefix); + fprintf(outf,"%st_maxstats : Not Implemented\n",prefix); + fprintf(outf,"%st_reserved : %d\n",prefix,thing->t_reserved); +} + +rs_print_game_state(FILE *outf) +{ + fprintf(outf, "Player\n"); + + rs_print_thing(outf, &player, " ", 0, 0); +} + +/**** + Machine Dependent Functions + + md_getuid() + md_memused() + md_getusername() + md_gethostname() + md_gethomedir() + md_getroguedir() + md_getshell() + md_shellescape() + md_getpass() + md_crypt() + md_htons() + md_nstoh() + md_unlink() + md_isdir() + md_ntohl() + md_htonl() + +****/ + +int +md_rand(range) +register int range; +{ +#ifdef _WIN32 + return(range <= 0 ? 0 : rand() % range); +#else + return(range <= 0 ? 0 : random() % range); +#endif +} + +int +md_srand(seed) +register int seed; +{ +#ifdef _WIN32 + srand(seed); +#else + srandom(seed); +#endif +} + +void +md_flushinp() +{ + /* ioctl(0,TIOCFLUSH) */ + /* ioctl(_tty_ch,TCFLSH,0) */ + flushinp(); +} + +int +md_getuid() +{ +#ifdef _WIN32 + return(42); +#else + return(getuid()); +#endif +} + +long +md_memused() +{ +#ifdef _WIN32 + MEMORYSTATUS stat; + + GlobalMemoryStatus(&stat); + + return((long)stat.dwTotalPageFile); +#else + return( (long)sbrk(0) ); +#endif +} + +char * +md_getusername() +{ + static char login[80]; + char *l = NULL; +#ifdef _WIN32 + LPSTR mybuffer; + DWORD size = UNLEN + 1; + TCHAR buffer[UNLEN + 1]; + + mybuffer = buffer; + GetUserName(mybuffer,&size); + l = mybuffer; +#endif +#if !defined(_WIN32) && !defined(DJGPP) + struct passwd *pw; + + pw = getpwuid(getuid()); + + l = pw->pw_name; +#endif + + if ((l == NULL) || (*l == '\0')) + if ( (l = getenv("USERNAME")) == NULL ) + if ( (l = getenv("LOGNAME")) == NULL ) + if ( (l = getenv("USER")) == NULL ) + l = "nobody"; + + strncpy(login,l,80); + login[79] = 0; + + return(login); +} + +char * +md_gethomedir() +{ + static char homedir[PATH_MAX]; + char *h = NULL; + size_t len; +#if defined(_WIN32) + TCHAR szPath[MAX_PATH]; +#endif +#if defined(_WIN32) || defined(DJGPP) + char slash = '\\'; +#else + char slash = '/'; + struct passwd *pw; + pw = getpwuid(getuid()); + + h = pw->pw_dir; + + if (strcmp(h,"/") == 0) + h = NULL; +#endif + homedir[0] = 0; + +#ifdef _WIN32 + if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, szPath))) + h = szPath; +#endif + + if ( (h == NULL) || (*h == '\0') ) + if ( (h = getenv("HOME")) == NULL ) + if ( (h = getenv("HOMEDRIVE")) == NULL) + h = ""; + else + { + strncpy(homedir,h,PATH_MAX-1); + homedir[PATH_MAX-1] = 0; + + if ( (h = getenv("HOMEPATH")) == NULL) + h = ""; + } + + + len = strlen(homedir); + strncat(homedir,h,PATH_MAX-len-1); + len = strlen(homedir); + + if ((len > 0) && (homedir[len-1] != slash)) { + homedir[len] = slash; + homedir[len+1] = 0; + } + + return(homedir); +} + +int +directory_exists(char *dirname) +{ + struct stat sb; + + if (stat(dirname, &sb) == 0) /* path exists */ + return (sb.st_mode & S_IFDIR); + + return(0); +} + +char * +md_getroguedir() +{ + static char path[1024]; + char *end,*home; + + if ( (home = getenv("ROGUEHOME")) != NULL) + { + if (*home) + { + strncpy(path, home, PATH_MAX - 20); + + end = &path[strlen(path)-1]; + + + while( (end >= path) && ((*end == '/') || (*end == '\\'))) + *end-- = '\0'; + + if (directory_exists(path)) + return(path); + } + } + + if (directory_exists("/var/games/roguelike")) + return("/var/games/roguelike"); + if (directory_exists("/var/lib/roguelike")) + return("/var/lib/roguelike"); + if (directory_exists("/var/roguelike")) + return("/var/roguelike"); + if (directory_exists("/usr/games/lib")) + return("/usr/games/lib"); + if (directory_exists("/games/roguelik")) + return("/games/roguelik"); + + return(""); +} + +char * +md_getshell() +{ + static char shell[PATH_MAX]; + char *s = NULL; +#ifdef _WIN32 + char *def = "C:\\WINDOWS\\SYSTEM32\\CMD.EXE"; +#elif defined(__DJGPP__) + char *def = "C:\\COMMAND.COM"; +#else + char *def = "/bin/sh"; + struct passwd *pw; + pw = getpwuid(getuid()); + s = pw->pw_shell; +#endif + if ((s == NULL) || (*s == '\0')) + if ( (s = getenv("COMSPEC")) == NULL) + if ( (s = getenv("SHELL")) == NULL) + if ( (s = getenv("SystemRoot")) == NULL) + s = def; + + strncpy(shell,s,PATH_MAX); + shell[PATH_MAX-1] = 0; + + return(shell); +} + +char * +md_gethostname() +{ + static char nodename[80]; + char *n = NULL; +#if !defined(_WIN32) && !defined(__DJGPP__) + struct utsname ourname; + + if (uname(&ourname) == 0) + n = ourname.nodename; +#endif + if ((n == NULL) || (*n == '\0')) + if ( (n = getenv("COMPUTERNAME")) == NULL) + if ( (n = getenv("HOSTNAME")) == NULL) + n = "localhost"; + + strncpy(nodename, n, 80); + nodename[79] = 0; + + return(nodename); +} + +int +md_shellescape() +{ +#if (!defined(_WIN32) && !defined(__DJGPP__)) + int ret_status; + int pid; +#endif + char *sh; + + sh = md_getshell(); + +#if defined(_WIN32) + return(_spawnl(_P_WAIT,sh,"shell",NULL,0)); +#elif defined(__DJGPP__) + return ( spawnl(P_WAIT,sh,"shell",NULL,0) ); +#else + while((pid = fork()) < 0) + sleep(1); + + if (pid == 0) /* Shell Process */ + { + /* + * Set back to original user, just in case + */ + setuid(getuid()); + setgid(getgid()); + execl(sh == NULL ? "/bin/sh" : sh, "shell", "-i", 0); + perror("No shelly"); + _exit(-1); + } + else /* Application */ + { + while (wait(&ret_status) != pid) + continue; + } + + return(ret_status); +#endif +} + +int +md_erasechar() +{ +/* + return(_tty.sg_erase); + return(_tty.c_cc[VERASE]); +*/ + return(erasechar()); +} + +int +md_killchar() +{ +/* + return(_tty.sg_kill); + return(_tty.c_cc[VKILL]); +*/ + return(killchar()); +} + +long +md_ntohl(netlong) +long netlong; +{ + return( ntohl(netlong) ); +} + +long +md_htonl(netlong) +long netlong; +{ + return(htonl(netlong)); +} + +void +md_init() +{ +#ifdef __INTERIX + char *term; + + term = getenv("TERM"); + + if (term == NULL) + setenv("TERM","interix"); +#endif +#if defined(__DJGPP__) || defined(_WIN32) + _fmode = _O_BINARY; +#endif +} + +char * +md_getpass(prompt) +char *prompt; +{ +#ifdef _WIN32 + static char password_buffer[9]; + char *p = password_buffer; + int c, count = 0; + int max_length = 9; + + fflush(stdout); + /* If we can't prompt, abort */ + if (fputs(prompt, stderr) < 0) + { + *p = '\0'; + return NULL; + } + + for(;;) + { + /* Get a character with no echo */ + c = _getch(); + + /* Exit on interrupt (^c or ^break) */ + if (c == '\003' || c == 0x100) + exit(1); + + /* Terminate on end of line or file (^j, ^m, ^d, ^z) */ + if (c == '\r' || c == '\n' || c == '\004' || c == '\032') + break; + + /* Back up on backspace */ + if (c == '\b') + { + if (count) + count--; + else if (p > password_buffer) + p--; + continue; + } + + /* Ignore DOS extended characters */ + if ((c & 0xff) != c) + continue; + + /* Add to password if it isn't full */ + if (p < password_buffer + max_length - 1) + *p++ = c; + else + count++; + } + *p = '\0'; + + fputc('\n', stderr); + + return password_buffer; +#else + return( (char *) getpass(prompt) ); +#endif +} + +#ifdef SIGTSTP + +/* + * handle stop and start signals + */ + +/*UNUSED*/ +void +tstp(a) +int a; +{ + mvcur(0, cols - 1, lines - 1, 0); + fflush(stdout); + kill(0, SIGTSTP); + signal(SIGTSTP, tstp); + crmode(); + noecho(); + clearok(curscr, TRUE); + touchwin(cw); + draw(cw); + flushinp(); +} +#endif + +int +md_setup() +{ +#ifdef SIGTSTP + signal(SIGTSTP, tstp); +#endif +#ifdef SIGHUP + signal(SIGHUP, auto_save); +#endif + signal(SIGTERM, auto_save); + signal(SIGINT, quit); +#ifdef SIGQUIT + signal(SIGQUIT, endit); +#endif +#if defined(__CYGWIN__) || defined(__MSYS__) + ESCDELAY = 250; +#endif + nonl(); + crmode(); /* Cbreak mode */ + noecho(); /* Echo off */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/sticks.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,897 @@ +/* + sticks.c - Functions to implement the various sticks one might find + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" + +/* + * zap a stick and see what happens + */ + +do_zap(zapper, obj, direction, which, flags) +struct thing *zapper; +struct object *obj; +coord *direction; +int which; +int flags; +{ + register struct linked_list *item = NULL; + register struct thing *tp; + register int y = 0, x = 0, bonus; + struct linked_list *nitem; + struct object *nobj; + bool cursed, blessed, is_player = FALSE; + char *mname = NULL; + + cursed = flags & ISCURSED; + blessed = flags & ISBLESSED; + + if (obj && obj->o_type != RELIC) { /* all relics are chargeless */ + if (obj->o_charges < 1) { + msg(nothing); + return; + } + obj->o_charges--; + } + if (which == WS_WONDER) { + switch (rnd(19)) { + case 0: which = WS_ELECT; + when 1: which = WS_FIRE; + when 2: which = WS_COLD; + when 3: which = WS_POLYMORPH; + when 4: which = WS_MISSILE; + when 5: which = WS_SLOW_M; + when 6: which = WS_TELMON; + when 7: which = WS_CANCEL; + when 8: which = WS_CONFMON; + when 9: which = WS_DISINTEGRATE; + when 10: which = WS_PETRIFY; + when 11: which = WS_PARALYZE; + when 12: which = WS_MDEG; + when 13: which = WS_FEAR; + when 14: which = WS_CURING; + when 15: which = WS_LIGHT; + when 16: which = WS_HIT; + when 17: which = WS_DRAIN; + when 18: which = WS_CHARGE; + } + if(ws_magic[which].mi_curse>0 && rnd(100)<=ws_magic[which].mi_curse){ + cursed = TRUE; + blessed = FALSE; + } + } + + tp = NULL; + switch (which) { + case WS_POLYMORPH: + case WS_SLOW_M: + case WS_TELMON: + case WS_CANCEL: + case WS_CONFMON: + case WS_DISINTEGRATE: + case WS_PETRIFY: + case WS_PARALYZE: + case WS_MDEG: + case WS_FEAR: + y = zapper->t_pos.y; + x = zapper->t_pos.x; + + do { + y += direction->y; + x += direction->x; + } + while (shoot_ok(winat(y, x)) && !(y == hero.y && x == hero.x)); + + if (y == hero.y && x == hero.x) + is_player = TRUE; + else if (isalpha(mvwinch(mw, y, x))) { + item = find_mons(y, x); + tp = THINGPTR(item); + runto(tp, &hero); + turn_off(*tp, CANSURPRISE); + mname = monster_name(tp); + is_player = FALSE; + + /* The monster may not like being shot at */ + if ((zapper == &player) && + on(*tp, ISCHARMED) && + save(VS_MAGIC, tp, 0)) { + msg("The eyes of %s turn clear.", prname(mname, FALSE)); + turn_off(*tp, ISCHARMED); + mname = monster_name(tp); + } + } + else { + /* + * if monster misses player because the player dodged then lessen + * the chances he will use the wand again since the player appears + * to be rather dextrous + */ + if (zapper != &player) + zapper->t_wand = zapper->t_wand * 3 / 5; + } + } + switch (which) { + case WS_LIGHT: + /* + * Reddy Kilowat wand. Light up the room + */ + blue_light(blessed, cursed); + when WS_DRAIN: + /* + * Take away 1/2 of hero's hit points, then take it away + * evenly from the monsters in the room or next to hero + * if he is in a passage (but leave the monsters alone + * if the stick is cursed) + */ + if (pstats.s_hpt < 2) { + msg("You are too weak to use it."); + } + else if (cursed) + pstats.s_hpt /= 2; + if (pstats.s_hpt <= 0) { + pstats.s_hpt = -1; + msg("You drain your own life away. --More--"); + death(D_STRENGTH); + } + else + drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1); + + when WS_POLYMORPH: + { + register char oldch; + register struct room *rp; + register struct linked_list *pitem; + coord delta; + + if (tp == NULL) + break; + if (save(VS_MAGIC, tp, 0)) { + msg(nothing); + break; + } + rp = roomin(&tp->t_pos); + check_residue(tp); + delta.x = x; + delta.y = y; + detach(mlist, item); + oldch = tp->t_oldch; + pitem = tp->t_pack; /* save his pack */ + tp->t_pack = NULL; + + if (levtype == OUTSIDE) + new_monster(item,rnd(NUMDINOS)+NUMMONST-NUMDINOS,&delta,FALSE); + else + new_monster(item,rnd(NUMMONST-NUMUNIQUE-NUMDINOS-1)+1,&delta,FALSE); + + if (tp->t_pack != NULL) + o_free_list (tp->t_pack); + tp->t_pack = pitem; + if (isalpha(mvwinch(cw, y, x))) + mvwaddch(cw, y, x, tp->t_type); + tp->t_oldch = oldch; + /* + * should the room light up? + */ + if (on(*tp, HASFIRE)) { + if (rp) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rp->r_fires, fire_item); + rp->r_flags |= HASFIRE; + if (cansee(tp->t_pos.y,tp->t_pos.x) && + next(rp->r_fires) == NULL) light(&hero); + } + } + runto(tp, &hero); + msg(terse ? "A new %s!" + : "You have created a new %s!", + monster_name(tp)); + } + + when WS_PETRIFY: + if (tp == NULL) + break; + if (save(VS_MAGIC, tp, 0)) { + msg(nothing); + break; + } + check_residue(tp); + turn_on(*tp, ISSTONE); + turn_on(*tp, NOSTONE); + turn_off(*tp, ISRUN); + turn_off(*tp, ISINVIS); + turn_off(*tp, CANSURPRISE); + turn_off(*tp, ISDISGUISE); + tp->t_action = A_NIL; + tp->t_no_move = 0; + msg("%s is turned to stone!",prname(mname, TRUE)); + + when WS_TELMON: + { + register int rm; + register struct room *rp; + + if (tp == NULL) + break; + if (save(VS_MAGIC, tp, 0)) { + msg(nothing); + break; + } + rp = NULL; + check_residue(tp); + tp->t_action = A_FREEZE; /* creature is disoriented */ + tp->t_no_move = 2; + if (cursed) { /* Teleport monster to player */ + if ((y == (hero.y + direction->y)) && + (x == (hero.x + direction->x))) + msg(nothing); + else { + tp->t_pos.y = hero.y + direction->y; + tp->t_pos.x = hero.x + direction->x; + } + } + else if (blessed) { /* Get rid of monster */ + killed(item, FALSE, TRUE, TRUE); + return; + } + else { + register int i=0; + + do { /* Move monster to another room */ + rm = rnd_room(); + rnd_pos(&rooms[rm], &tp->t_pos); + }until(winat(tp->t_pos.y,tp->t_pos.x)==FLOOR ||i++>500); + rp = &rooms[rm]; + } + + /* Now move the monster */ + if (isalpha(mvwinch(cw, y, x))) + mvwaddch(cw, y, x, tp->t_oldch); + mvwaddch(mw, y, x, ' '); + mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type); + if (tp->t_pos.y != y || tp->t_pos.x != x) + tp->t_oldch = mvwinch(cw, tp->t_pos.y, tp->t_pos.x); + /* + * check to see if room that creature appears in should + * light up + */ + if (on(*tp, HASFIRE)) { + if (rp) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rp->r_fires, fire_item); + rp->r_flags |= HASFIRE; + if(cansee(tp->t_pos.y, tp->t_pos.x) && + next(rp->r_fires) == NULL) + light(&hero); + } + } + } + when WS_CANCEL: + if (tp == NULL) + break; + if (save(VS_MAGIC, tp, 0)) { + msg(nothing); + break; + } + check_residue(tp); + tp->t_flags[0] &= CANC0MASK; + tp->t_flags[1] &= CANC1MASK; + tp->t_flags[2] &= CANC2MASK; + tp->t_flags[3] &= CANC3MASK; + tp->t_flags[4] &= CANC4MASK; + tp->t_flags[5] &= CANC5MASK; + tp->t_flags[6] &= CANC6MASK; + tp->t_flags[7] &= CANC7MASK; + tp->t_flags[8] &= CANC8MASK; + tp->t_flags[9] &= CANC9MASK; + tp->t_flags[10] &= CANCAMASK; + tp->t_flags[11] &= CANCBMASK; + tp->t_flags[12] &= CANCCMASK; + tp->t_flags[13] &= CANCDMASK; + tp->t_flags[14] &= CANCEMASK; + tp->t_flags[15] &= CANCFMASK; + + when WS_MISSILE: + { + int dice; + static struct object bolt = + { + MISSILE , {0, 0}, 0, "", "1d4 " , NULL, 0, WS_MISSILE, 50, 1 + }; + + if (!obj) + dice = zapper->t_stats.s_lvl; + if (obj->o_type == RELIC) + dice = 15; + else if (EQUAL(ws_type[which], "staff")) + dice = 10; + else + dice = 6; + sprintf(bolt.o_hurldmg, "%dd4", dice); + do_motion(&bolt, direction->y, direction->x, zapper); + if (!hit_monster(unc(bolt.o_pos), &bolt, zapper)) + msg("The missile vanishes with a puff of smoke"); + } + when WS_HIT: + { + register unsigned char ch; + struct object strike; /* don't want to change sticks attributes */ + + direction->y += hero.y; + direction->x += hero.x; + ch = winat(direction->y, direction->x); + if (isalpha(ch)) + { + strike = *obj; + strike.o_hplus = 7; + if (EQUAL(ws_type[which], "staff")) + strcpy(strike.o_damage,"3d8"); + else + strcpy(strike.o_damage,"2d8"); + fight(direction, &strike, FALSE); + } + } + when WS_SLOW_M: + if (is_player) { + add_slow(); + break; + } + if (tp == NULL) + break; + if (cursed) { + if (on(*tp, ISSLOW)) + turn_off(*tp, ISSLOW); + else + turn_on(*tp, ISHASTE); + break; + } + if ((on(*tp,ISUNIQUE) && save(VS_MAGIC,tp,0)) || on(*tp,NOSLOW)) { + msg(nothing); + break; + } + else if (blessed) { + turn_off(*tp, ISRUN); + turn_on(*tp, ISHELD); + } + /* + * always slow in case he breaks free of HOLD + */ + if (on(*tp, ISHASTE)) + turn_off(*tp, ISHASTE); + else + turn_on(*tp, ISSLOW); + + when WS_CHARGE: + if (ws_know[WS_CHARGE] != TRUE && obj) + msg("This is a wand of charging."); + nitem = get_item(pack, "charge", STICK, FALSE, FALSE); + if (nitem != NULL) { + nobj = OBJPTR(nitem); + if ((++(nobj->o_charges) == 1) && (nobj->o_which == WS_HIT)) + fix_stick(nobj); + if (blessed) ++(nobj->o_charges); + if (EQUAL(ws_type[nobj->o_which], "staff")) { + if (nobj->o_charges > 200) + nobj->o_charges = 200; + } + else { + if (nobj->o_charges > 200) + nobj->o_charges = 200; + } + } + when WS_ELECT: + shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT, + "lightning bolt", roll(zapper->t_stats.s_lvl,6)); + + when WS_FIRE: + shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT, + "flame", roll(zapper->t_stats.s_lvl,6)); + + when WS_COLD: + shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT, + "ice", roll(zapper->t_stats.s_lvl,6)); + + when WS_CONFMON: + if (cursed || is_player) { + if (!save(VS_WAND, &player, 0)) { + dsrpt_player(); + confus_player(); + } + else { + if (zapper != &player) zapper->t_wand /= 2; + msg(nothing); + } + } + else { + if (tp == NULL) + break; + if (save(VS_MAGIC, tp, 0) || on(*tp, ISCLEAR)) + msg(nothing); + else + turn_on (*tp, ISHUH); + } + when WS_PARALYZE: + if (is_player || cursed) { + if ((obj && obj->o_type==RELIC) || !save(VS_WAND, &player, 0)){ + player.t_no_move += 2 * movement(&player) * FREEZETIME; + player.t_action = A_FREEZE; + msg("You can't move."); + } + else { + if (zapper != &player) zapper->t_wand /= 2; + msg(nothing); + } + } + else { + if (tp == NULL) + break; + bonus = 0; + if (blessed) bonus = -3; + if (((obj && obj->o_type==RELIC) || !save(VS_WAND,tp,bonus)) && + off(*tp, NOPARALYZE)) { + tp->t_no_move += 2 * movement(tp) * FREEZETIME; + tp->t_action = A_FREEZE; + } + else { + msg(nothing); + } + } + when WS_FEAR: + if (is_player) { + if (!on(player, ISFLEE) || + ISWEARING(R_HEROISM) || + save(VS_WAND, &player, 0)) { + msg(nothing); + zapper->t_wand /= 2; + } + else { + turn_on(player, ISFLEE); + player.t_dest = &zapper->t_pos; + msg("The sight of %s terrifies you.", prname(mname, FALSE)); + } + break; + } + if (tp == NULL) + break; + bonus = 0; + if (blessed) bonus = -3; + if(save(VS_WAND, tp,bonus) || on(*tp,ISUNDEAD) || on(*tp,NOFEAR)){ + msg(nothing); + break; + } + turn_on(*tp, ISFLEE); + turn_on(*tp, WASTURNED); + + /* Stop it from attacking us */ + dsrpt_monster(tp, TRUE, cansee(tp->t_pos.y, tp->t_pos.x)); + + /* If monster was suffocating, stop it */ + if (on(*tp, DIDSUFFOCATE)) { + turn_off(*tp, DIDSUFFOCATE); + extinguish(suffocate); + } + + /* If monster held us, stop it */ + if (on(*tp, DIDHOLD) && (--hold_count == 0)) + turn_off(player, ISHELD); + turn_off(*tp, DIDHOLD); + + /* It is okay to turn tail */ + tp->t_oldpos = tp->t_pos; + + when WS_MDEG: + if (is_player) { + if (save(VS_WAND, &player, 0)) { + msg (nothing); + zapper->t_wand /= 2; + break; + } + pstats.s_hpt /= 2; + if (pstats.s_hpt <= 0) { + pstats.s_hpt = -1; + msg("Your life has been sucked out from you! --More--"); + wait_for(' '); + death(zapper); + } + else + msg("You feel a great drain on your system."); + } + if (tp == NULL) + break; + if (cursed) { + tp->t_stats.s_hpt *= 2; + msg("%s appears to be stronger now!", prname(mname, TRUE)); + } + else if (on(*tp, ISUNIQUE) && save(VS_WAND, tp, 0)) + msg (nothing); + else { + tp->t_stats.s_hpt /= 2; + msg("%s appears to be weaker now", prname(mname, TRUE)); + } + if (tp->t_stats.s_hpt < 1) + killed(item, TRUE, TRUE, TRUE); + when WS_DISINTEGRATE: + if (tp == NULL) + break; + if (cursed) { + register int m1, m2; + coord mp; + struct linked_list *titem; + char ch; + struct thing *th; + + if (on(*tp, ISUNIQUE) || on(*tp, CANSELL)) { + msg (nothing); + break; + } + for (m1=tp->t_pos.x-1 ; m1 <= tp->t_pos.x+1 ; m1++) { + for(m2=tp->t_pos.y-1 ; m2<=tp->t_pos.y+1 ; m2++) { + if (m1 == hero.x && m2 == hero.y) + continue; + ch = winat(m2,m1); + if (shoot_ok(ch)) { + mp.x = m1; /* create it */ + mp.y = m2; + titem = new_item(sizeof(struct thing)); + new_monster(titem,(short)tp->t_index,&mp,FALSE); + th = THINGPTR(titem); + turn_on (*th, ISMEAN); + runto(th,&hero); + if (on(*th, HASFIRE)) { + register struct room *rp; + + rp = roomin(&th->t_pos); + if (rp) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) th; + attach(rp->r_fires, fire_item); + rp->r_flags |= HASFIRE; + if (cansee(th->t_pos.y, th->t_pos.x) && + next(rp->r_fires) == NULL) + light(&hero); + } + } + } + } + } + } + else { /* if its a UNIQUE it might still live */ + if (on(*tp, ISUNIQUE) && save(VS_MAGIC, tp, 0)) { + tp->t_stats.s_hpt /= 2; + if (tp->t_stats.s_hpt < 1) { + killed(item, FALSE, TRUE, TRUE); + msg("You have disintegrated %s", prname(mname, FALSE)); + } + else { + msg("%s appears wounded", prname(mname, TRUE)); + } + } + else { + msg("You have disintegrated %s", prname(mname, FALSE)); + killed (item, FALSE, TRUE, TRUE); + } + } + when WS_CURING: + if (cursed) { + bool sick = FALSE; + if (!save(VS_POISON, &player, 0)) { + msg("You feel extremely sick. "); + sick = TRUE; + pstats.s_hpt -= (pstats.s_hpt/3)+1; + if (pstats.s_hpt == 0) { + pstats.s_hpt = -1; + msg("You die! --More--"); + wait_for(' '); + death (D_POISON); + } + } + if (!save(VS_WAND, &player, 0) && !ISWEARING(R_HEALTH)) { + turn_on(player, HASDISEASE); + turn_on(player, HASINFEST); + turn_on(player, DOROT); + fuse(cure_disease, (VOID *)NULL, roll(HEALTIME,SICKTIME), AFTER); + infest_dam++; + } + else if (sick == FALSE) msg("You feel momentarily sick"); + } + else { + if (on(player, HASDISEASE) || on(player, HASINFEST)) { + extinguish(cure_disease); + turn_off(player, HASINFEST); + infest_dam = 0; + cure_disease(); /* this prints message */ + } + if (on(player, DOROT)) { + msg("You feel your skin returning to normal."); + turn_off(player, DOROT); + } + pstats.s_hpt += roll(pstats.s_lvl, blessed ? 9 : 6); + if (pstats.s_hpt > max_stats.s_hpt) + pstats.s_hpt = max_stats.s_hpt; + msg("You begin to feel %sbetter.", blessed ? "much " : ""); + + } + otherwise: + msg("What a bizarre schtick!"); + } +} + + +/* + * drain: + * Do drain hit points from player shtick + */ + +drain(ymin, ymax, xmin, xmax) +int ymin, ymax, xmin, xmax; +{ + register int i, j, count; + register struct thing *ick; + register struct linked_list *item; + + /* + * First count how many things we need to spread the hit points among + */ + count = 0; + for (i = ymin; i <= ymax; i++) { + if (i < 1 || i > lines - 3) + continue; + for (j = xmin; j <= xmax; j++) { + if (j < 0 || j > cols - 1) + continue; + if (isalpha(mvwinch(mw, i, j))) + count++; + } + } + if (count == 0) + { + msg("You have a tingling feeling."); + return; + } + count = pstats.s_hpt / count; + pstats.s_hpt /= 2; + if (pstats.s_hpt <= 0) { + pstats.s_hpt = -1; + msg("Aarrgghhh!! --More--"); + wait_for(' '); + death(D_STRENGTH); + } + /* + * Now zot all of the monsters + */ + for (i = ymin; i <= ymax; i++) { + if (i < 1 || i > lines - 3) + continue; + for (j = xmin; j <= xmax; j++) { + if (j < 0 || j > cols - 1) + continue; + if (isalpha(mvwinch(mw, i, j)) && + ((item = find_mons(i, j)) != NULL)) { + ick = THINGPTR(item); + if (on(*ick, ISUNIQUE) && save(VS_MAGIC, ick, 0)) + ick->t_stats.s_hpt -= count / 2; + else + ick->t_stats.s_hpt -= count; + if (ick->t_stats.s_hpt < 1) + killed(item, + cansee(i,j)&&(!on(*ick,ISINVIS)||on(player,CANSEE)), + TRUE, TRUE); + else { + runto(ick, &hero); + + /* + * The monster may not like being shot at. Since the + * shot is not aimed directly at the monster, we will + * give him a poorer save. + */ + if (on(*ick, ISCHARMED) && save(VS_MAGIC, ick, -2)) { + msg("The eyes of %s turn clear.", + prname(monster_name(ick), FALSE)); + turn_off(*ick, ISCHARMED); + } + if (cansee(i,j) && (!on(*ick,ISINVIS)||on(player,CANSEE))) + msg("%s appears wounded", + prname(monster_name(ick), TRUE)); + } + } + } + } +} + +/* + * initialize a stick + */ + +fix_stick(cur) +register struct object *cur; +{ + if (EQUAL(ws_type[cur->o_which], "staff")) { + cur->o_weight = 100; + cur->o_charges = 5 + rnd(11); + strcpy(cur->o_damage,"3d4"); + cur->o_hplus = 1; + cur->o_dplus = 0; + switch (cur->o_which) { + case WS_HIT: + cur->o_hplus = 3; + cur->o_dplus = 3; + strcpy(cur->o_damage,"2d8"); + when WS_LIGHT: + cur->o_charges = 15 + rnd(11); + } + } + else { + strcpy(cur->o_damage,"2d3"); + cur->o_weight = 75; + cur->o_hplus = 1; + cur->o_dplus = 0; + cur->o_charges = 5 + rnd(11); + switch (cur->o_which) { + case WS_HIT: + cur->o_hplus = 3; + cur->o_dplus = 3; + strcpy(cur->o_damage,"2d8"); + when WS_LIGHT: + cur->o_charges = 15 + rnd(11); + } + } + strcpy(cur->o_hurldmg,"3d3"); + +} + +/* + * Use the wand that our monster is wielding. + */ + +m_use_wand(monster) +register struct thing *monster; +{ + register struct object *obj; + + /* Make sure we really have it */ + if (monster->t_using) + obj = OBJPTR(monster->t_using); + else { + debug("Stick not set!"); + monster->t_action = A_NIL; + return; + } + + if (obj->o_type != STICK) { + debug("Stick not selected!"); + monster->t_action = A_NIL; + return; + } + /* + * shoot the stick! + * assume all blessed sticks are normal for now. + * Note that we don't get here if the wand is cursed. + */ + msg("%s points a %s at you!", prname(monster_name(monster), TRUE), + ws_type[obj->o_which]); + do_zap(monster, obj, &monster->t_newpos, obj->o_which, NULL); + monster->t_wand /= 2; /* chance lowers with each use */ +} + +bool +need_dir(type, which) +int type, /* type of item, NULL means stick */ + which; /* which item */ +{ + if (type == STICK || type == 0) { + switch (which) { + case WS_LIGHT: + case WS_DRAIN: + case WS_CHARGE: + case WS_CURING: + return(FALSE); + default: + return(TRUE); + } + } + else if (type == RELIC) { + switch (which) { + case MING_STAFF: + case ASMO_ROD: + case EMORI_CLOAK: + return(TRUE); + default: + return(FALSE); + } + } +return (FALSE); /* hope we don't get here */ +} + +/* + * let the player zap a stick and see what happens + */ + +player_zap(which, flag) +int which; +int flag; +{ + register struct linked_list *item; + register struct object *obj; + + obj = NULL; + if (which == 0) { + /* This is a stick. It takes 2 movement periods to zap it */ + if (player.t_action != C_ZAP) { + if ((item = get_item(pack,"zap with",ZAPPABLE,FALSE,FALSE)) == NULL) + return(FALSE); + + obj = OBJPTR(item); + + if (need_dir(obj->o_type, obj->o_which)) { + if (!get_dir(&player.t_newpos)) + return(FALSE); + } + player.t_using = item; /* Remember what it is */ + player.t_action = C_ZAP; /* We are quaffing */ + player.t_no_move = 2 * movement(&player); + return(TRUE); + } + + item = player.t_using; + /* We've waited our time, let's shoot 'em up! */ + player.t_using = NULL; + player.t_action = A_NIL; + + obj = OBJPTR(item); + + /* Handle relics specially here */ + if (obj->o_type == RELIC) { + switch (obj->o_which) { + case ORCUS_WAND: + /* msg(nothing); */ + read_scroll(S_PETRIFY, NULL, FALSE); + return(TRUE); + when MING_STAFF: + which = WS_MISSILE; + when EMORI_CLOAK: + which = WS_PARALYZE; + obj->o_charges = 0; /* one zap/day (whatever that is) */ + fuse(cloak_charge, obj, CLOAK_TIME, AFTER); + when ASMO_ROD: + switch (rnd(3)) { + case 0: which = WS_ELECT; + when 1: which = WS_COLD; + otherwise: which = WS_FIRE; + } + } + } + else { + which = obj->o_which; + ws_know[which] = TRUE; + flag = obj->o_flags; + } + } + do_zap(&player, obj, &player.t_newpos, which, flag); + return(TRUE); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/things.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,952 @@ +/* + things.c - functions for dealing with things like potions and scrolls + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" + +/* + * print out the number of charges on a stick + */ + +char * +charge_str(obj) +register struct object *obj; +{ + static char buf[20]; + + if (!(obj->o_flags & ISKNOW)) + buf[0] = '\0'; + else if (terse) + sprintf(buf, " [%d]", obj->o_charges); + else + sprintf(buf, " [%d charges]", obj->o_charges); + return buf; +} + +/* + * inv_name: + * return the name of something as it would appear in an + * inventory. + */ + +char * +inv_name(obj, drop) +register struct object *obj; +bool drop; +{ + register char *pb; + + pb = prbuf; + pb[0] = '\0'; + switch(obj->o_type) { + case SCROLL: + if (obj->o_count == 1) + sprintf(pb, "A %sscroll ", blesscurse(obj->o_flags)); + else + sprintf(pb, "%d %sscrolls ", + obj->o_count, blesscurse(obj->o_flags)); + pb = &pb[strlen(pb)]; + if (s_know[obj->o_which] || (obj->o_flags & ISPOST)) + sprintf(pb, "of %s", s_magic[obj->o_which].mi_name); + else if (s_guess[obj->o_which]) + sprintf(pb, "named %s", s_guess[obj->o_which]); + else + sprintf(pb, "titled '%s'", s_names[obj->o_which]); + when POTION: + if (obj->o_count == 1) + sprintf(pb, "A %spotion ", blesscurse(obj->o_flags)); + else + sprintf(pb, "%d %spotions ", + obj->o_count, blesscurse(obj->o_flags)); + pb = &pb[strlen(pb)]; + if (p_know[obj->o_which]) + sprintf(pb, "of %s (%s)", p_magic[obj->o_which].mi_name, + p_kind(obj)); + else if (obj->o_flags & ISPOST) + sprintf(pb, "of %s", p_magic[obj->o_which].mi_name); + else if (p_guess[obj->o_which]) + sprintf(pb, "named %s (%s)", p_guess[obj->o_which], + p_colors[obj->o_which]); + else { + pb = prbuf; + if (obj->o_count == 1) + sprintf(pb, "A%s %s potion", + vowelstr(p_colors[obj->o_which]), + p_colors[obj->o_which]); + else + sprintf(pb, "%d %s potions", + obj->o_count, p_colors[obj->o_which]); + } + when FOOD: + if (obj->o_count == 1) + sprintf(pb, "A%s %s", vowelstr(foods[obj->o_which].mi_name), + foods[obj->o_which].mi_name); + else + sprintf(pb, "%d %ss", obj->o_count,foods[obj->o_which].mi_name); + when WEAPON: + if (obj->o_count > 1) + sprintf(pb, "%d ", obj->o_count); + else + strcpy(pb, "A "); + pb = &pb[strlen(pb)]; + if (obj->o_flags & ISKNOW) { + strcat(pb, num(obj->o_hplus, obj->o_dplus)); + strcat (pb, " "); + } + strcat(pb, weaps[obj->o_which].w_name); + if (obj->o_count > 1) + strcat(pb, "s"); + if (obj == cur_weapon) + strcat(pb, " (weapon in hand)"); + if (obj->o_flags & ISPOISON) + strcat(pb, " {Poisoned}"); + when ARMOR: + if (obj->o_flags & ISKNOW) { + strcat(pb, num(armors[obj->o_which].a_class - obj->o_ac, 0)); + strcat(pb, " "); + } + strcat(pb, armors[obj->o_which].a_name); + if (obj == cur_armor) + strcat(pb, " (being worn)"); + when STICK: + sprintf(pb, "A %s%s ", + blesscurse(obj->o_flags), ws_type[obj->o_which]); + pb = &pb[strlen(pb)]; + if (ws_know[obj->o_which] || obj->o_flags & ISKNOW) + sprintf(pb, "of %s%s (%s)", ws_magic[obj->o_which].mi_name, + charge_str(obj), ws_made[obj->o_which]); + else if (obj->o_flags & ISPOST) + sprintf(pb, "of %s", ws_magic[obj->o_which].mi_name); + else if (ws_guess[obj->o_which]) + sprintf(pb, "named %s (%s)", ws_guess[obj->o_which], + ws_made[obj->o_which]); + else { + pb = prbuf; + sprintf(pb, "A %s %s", ws_made[obj->o_which], + ws_type[obj->o_which]); + } + if (obj == cur_weapon) + strcat(prbuf, " (weapon in hand)"); + when RING: + if (r_know[obj->o_which] || obj->o_flags & ISKNOW) + sprintf(pb, "A%s ring of %s (%s)", ring_num(obj), + r_magic[obj->o_which].mi_name, r_stones[obj->o_which]); + else if (obj->o_flags & ISPOST) + sprintf(pb, "A ring of %s", r_magic[obj->o_which].mi_name); + else if (r_guess[obj->o_which]) + sprintf(pb, "A ring named %s (%s)", + r_guess[obj->o_which], r_stones[obj->o_which]); + else + sprintf(pb, "A%s %s ring", vowelstr(r_stones[obj->o_which]), + r_stones[obj->o_which]); + if (obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] || + obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4]) + strcat(pb, " (on left hand)"); + if (obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] || + obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4]) + strcat(pb, " (on right hand)"); + when RELIC: + if (obj->o_flags & ISKNOW) + switch(obj->o_which) { + case QUILL_NAGROM: + sprintf(pb, "%s%s", rel_magic[obj->o_which].mi_name, + charge_str(obj)); + otherwise: + strcpy(pb, rel_magic[obj->o_which].mi_name); + } + else switch(obj->o_which) { + case MUSTY_DAGGER: + strcpy(pb, "Two very fine daggers marked MDDE"); + when EMORI_CLOAK: + strcpy(pb, "A silk cloak"); + when HEIL_ANKH: + strcpy(pb, "A golden ankh"); + when MING_STAFF: + strcpy(pb, "A finely carved staff"); + when ORCUS_WAND: + strcpy(pb, "A sparkling ivory wand"); + when ASMO_ROD: + strcpy(pb, "A glistening ebony rod"); + when YENDOR_AMULET: + strcpy(pb, "A silver amulet"); + when STONEBONES_AMULET: + strcpy(pb, "A stone amulet"); + when BRIAN_MANDOLIN: + strcpy(pb, "A gleaming mandolin"); + when HRUGGEK_MSTAR: + strcpy(pb, "A silvery morning star"); + when AXE_AKLAD: + strcpy(pb, "A jewel encrusted axe"); + when QUILL_NAGROM: + strcpy(pb, "A bright white feather"); + when GERYON_HORN: + strcpy(pb, "A jet black horn"); + when YEENOGHU_FLAIL: + strcpy(pb, "A shimmering flail"); + when SURTUR_RING: + strcpy(pb, "A fiery red ring"); + when ALTERAN_CARD: + strcpy(pb, "A rectangular piece of wood"); + otherwise: + strcpy(pb, "A wholly magical item"); + } + + /* Take care of wielding and wearing */ + switch (obj->o_which) { + case EMORI_CLOAK: + if (cur_armor == NULL && cur_misc[WEAR_CLOAK] == NULL) + strcat(pb, " (being worn)"); + if (obj->o_charges) + strcat(pb, " [charged]"); + else + strcat(pb, " [discharged]"); + when HEIL_ANKH: + if (cur_relic[HEIL_ANKH]) strcat(pb, " (in palm)"); + when EYE_VECNA: + if (cur_relic[EYE_VECNA]) strcat(pb, " (in forehead)"); + when STONEBONES_AMULET: + if (cur_relic[STONEBONES_AMULET]) + strcat(pb, " (in chest)"); + when YENDOR_AMULET: + if (cur_relic[YENDOR_AMULET]) + strcat(pb, " (in chest)"); + when MUSTY_DAGGER: + case HRUGGEK_MSTAR: + case AXE_AKLAD: + case YEENOGHU_FLAIL: + case MING_STAFF: + case ASMO_ROD: + case ORCUS_WAND: + if (cur_weapon == obj) strcat(pb, " (weapon in hand)"); + when SURTUR_RING: + if (cur_relic[SURTUR_RING]) + strcat(pb, " (in nose)"); + } + when MM: + if (m_know[obj->o_which]) + { + misc_name(pb,obj); + } + else { + switch (obj->o_which) { + case MM_JUG: + case MM_BEAKER: + case MM_KEOGHTOM: + strcpy(pb, "A crystalline jar"); + when MM_BOOK: + case MM_SKILLS: + strcpy(pb, "A dusty book"); + when MM_ELF_BOOTS: + case MM_DANCE: + strcpy(pb, "A pair of old boots"); + when MM_BRACERS: + strcpy(pb, "A set of bracers"); + when MM_OPEN: + case MM_HUNGER: + strcpy(pb, "A mysterious chime"); + when MM_DISP: + case MM_R_POWERLESS: + case MM_PROTECT: + strcpy(pb, "A dark looking cloak"); + when MM_DRUMS: + strcpy(pb, "A drum set"); + when MM_DISAPPEAR: + case MM_CHOKE: + strcpy(pb, "A small pouch of dust"); + when MM_G_DEXTERITY: + case MM_G_OGRE: + case MM_FUMBLE: + strcpy(pb, "A set of gauntlets"); + when MM_ADAPTION: + case MM_JEWEL: + case MM_STRANGLE: + strcpy(pb, "A little necklace"); + when MM_CRYSTAL: + strcpy(pb, "An unusual looking rock"); + otherwise: + strcpy(pb, "A magical item"); + } + if (m_guess[obj->o_which]) { + strcat(pb, " named: "); + strcat(pb, m_guess[obj->o_which]); + } + } + if (obj == cur_misc[WEAR_BOOTS] || + obj == cur_misc[WEAR_BRACERS] || + obj == cur_misc[WEAR_CLOAK] || + obj == cur_misc[WEAR_GAUNTLET] || + obj == cur_misc[WEAR_NECKLACE] || + obj == cur_misc[WEAR_JEWEL]) + strcat(pb, " (being worn)"); + when GOLD: + sprintf(pb, "%d Pieces of Gold", obj->o_count); + otherwise: + debug("Picked up something funny"); + sprintf(pb, "Something totally bizarre %s", unctrl(obj->o_type)); + wait_for(' '); + } + + /* Is it marked? */ + if (obj->o_mark[0]) { + pb = &pb[strlen(pb)]; + sprintf(pb, " <%s>", obj->o_mark); + } + + if (obj->o_flags & ISPROT) + strcat(pb, " [protected]"); + if (drop && isupper(prbuf[0])) + prbuf[0] = tolower(prbuf[0]); + else if (!drop && islower(*prbuf)) + *prbuf = toupper(*prbuf); + if (!drop) + strcat(pb, "."); + /* + * Truncate if long. Use cols-4 to offset the "pack letter" of a normal + * inventory listing. + */ + prbuf[cols-4] = '\0'; + return prbuf; +} + +/* + * weap_name: + * Return the name of a weapon. + */ + +char * +weap_name(obj) +register struct object *obj; +{ + switch (obj->o_type) { + case WEAPON: + return(weaps[obj->o_which].w_name); + when MISSILE: + return(ws_magic[obj->o_which].mi_name); + when RELIC: + switch (obj->o_which) { + case MUSTY_DAGGER: + return("daggers"); + when YEENOGHU_FLAIL: + return("flail"); + when AXE_AKLAD: + return("axe"); + when HRUGGEK_MSTAR: + return("morning star"); + when MING_STAFF: + return("staff"); + when ORCUS_WAND: + return("wand"); + when ASMO_ROD: + return("rod"); + } + } + return("weapon"); +} + +/* + * drop: + * put something down + */ + +drop(item) +struct linked_list *item; +{ + register char ch = 0; + register struct linked_list *obj, *nobj; + register struct object *op; + + if (item == NULL) { + /* We charge 2 movement times to drop something */ + if (player.t_action == C_DROP && player.t_using != NULL) { + obj = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + } + + /* t_action == C_DROP always when called from command() */ + else { + if ((obj = get_item(pack, "drop", ALL, FALSE, FALSE)) == NULL) { + player.t_action = A_NIL; + player.t_using = NULL; + return(FALSE); + } + if (player.t_action == C_DROP) { + player.t_using = obj; + player.t_no_move = 2 * movement(&player); + return(FALSE); /* We'll come back after we've waited */ + } + } + + switch(ch = mvwinch(stdscr, hero.y, hero.x)) { + case PASSAGE: + case SCROLL: + case POTION: + case WEAPON: + case FLOOR: + case STICK: + case ARMOR: + case POOL: + case RELIC: + case GOLD: + case FOOD: + case RING: + case MM: + break; + default: + msg("You can't leave it here"); + return(FALSE); + } + } + else { + obj = item; + } + op = OBJPTR(obj); + if (!dropcheck(op)) + return(FALSE); + + /* + * If it is a scare monster scroll, curse it + */ + if (op->o_type == SCROLL && op->o_which == S_SCARE) { + if (op->o_flags & ISBLESSED) + op->o_flags &= ~ISBLESSED; + else op->o_flags |= ISCURSED; + } + + /* + * Take it out of the pack + */ + if (op->o_count >= 2 && op->o_group == 0) + { + nobj = new_item(sizeof *op); + op->o_count--; + op = OBJPTR(nobj); + *op = *(OBJPTR(obj)); + op->o_count = 1; + obj = nobj; + } + else { + detach(pack, obj); + inpack--; + } + if(ch == POOL) { + msg("Gloop... Your %s sinks out of sight. ",inv_name(op,TRUE)); + o_discard(obj); + } + else if (levtype == POSTLEV) { + op->o_pos = hero; /* same place as hero */ + fall(obj,FALSE); + if (item == NULL) /* if item wasn't sold */ + msg("Thanks for your donation to the Fiend's flea market."); + } + else { + /* + * Link it into the level object list + */ + attach(lvl_obj, obj); + mvaddch(hero.y, hero.x, op->o_type); + op->o_pos = hero; + msg("Dropped %s", inv_name(op, TRUE)); + } + updpack(FALSE, &player); + return (TRUE); +} + +/* + * do special checks for dropping or unweilding|unwearing|unringing + */ + +dropcheck(op) +register struct object *op; +{ + int save_max; + + if (op == NULL) + return TRUE; + if (levtype == POSTLEV) { + if ((op->o_flags & ISCURSED) && (op->o_flags & ISKNOW)) { + msg("The trader does not accept shoddy merchandise."); + return(FALSE); + } + } + + /* Player will not drop a relic */ + if (op->o_type == RELIC) { + /* + * There is a 1% cumulative chance per relic that trying to get + * rid of it will cause the relic to turn on the player. + */ + if (rnd(150) < cur_relic[op->o_which]++) { + msg("The artifact turns on you! "); + msg("It crushes your mind!!! --More--"); + pstats.s_hpt = -1; + wait_for (' '); + death(D_RELIC); + } + else { + if (terse) msg("You can't release it."); + else msg("You cannot bring yourself to release it."); + return FALSE; + } + } + + /* If we aren't wearing it, we can drop it */ + if (!is_current(op)) return TRUE; + + /* At this point, we know we are wearing the item */ + if (op->o_flags & ISCURSED) { + msg("You can't. It appears to be cursed."); + return FALSE; + } + if (op->o_type == RING && cur_misc[WEAR_GAUNTLET] != NULL) { + msg ("You have to remove your gauntlets first!"); + return FALSE; + } + cur_null(op); /* set current to NULL */ + if (op->o_type == RING) { + switch (op->o_which) { + case R_ADDSTR: save_max = max_stats.s_str; + chg_str(-op->o_ac); + max_stats.s_str = save_max; + when R_ADDHIT: pstats.s_dext -= op->o_ac; + when R_ADDINTEL: pstats.s_intel -= op->o_ac; + when R_ADDWISDOM: pstats.s_wisdom -= op->o_ac; + when R_SEEINVIS: if (!ISWEARING(R_SEEINVIS) && + find_slot(unsee) == 0) { + turn_off(player, CANSEE); + msg("The tingling feeling leaves your eyes. "); + } + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + when R_WARMTH: if (!ISWEARING(R_WARMTH) && !find_slot(nocold)) + turn_off(player, NOCOLD); + when R_FIRE: if (!ISWEARING(R_FIRE) && + !cur_relic[SURTUR_RING] && + !find_slot(nofire)) + turn_off(player, NOFIRE); + when R_LIGHT: { + if(roomin(&hero) != NULL) { + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + } + } + when R_SEARCH: kill_daemon(ring_search); + when R_TELEPORT: kill_daemon(ring_teleport); + } + } + else if (op->o_type == MM) { + switch (op->o_which) { + case MM_ADAPTION: + turn_off(player, NOGAS); + turn_off(player, NOACID); + + when MM_STRANGLE: + msg("You can breathe again.....whew!"); + kill_daemon(strangle); + + when MM_DANCE: + turn_off(player, ISDANCE); + msg ("Your feet take a break.....whew!"); + + when MM_FUMBLE: + kill_daemon(fumble); + + when MM_G_OGRE: + case MM_G_DEXTERITY: + save_max = max_stats.s_str; + chg_str(-op->o_ac); + max_stats.s_str = save_max; + } + } + return TRUE; +} + +/* + * return a new thing + */ + +struct linked_list * +new_thing(thing_type, allow_curse) +int thing_type; +bool allow_curse; +{ + register struct linked_list *item; + register struct object *cur; + register int j; + register int blesschance, cursechance; + + item = new_item(sizeof *cur); + cur = OBJPTR(item); + cur->o_hplus = cur->o_dplus = 0; + strcpy(cur->o_damage,"0d0"); + strcpy(cur->o_hurldmg,"0d0"); + cur->o_ac = 0; + cur->o_count = 1; + cur->o_group = 0; + cur->contents = NULL; + cur->o_flags = 0; + cur->o_weight = 0; + cur->o_mark[0] = '\0'; + /* + * Decide what kind of object it will be + * If we haven't had food for a while, let it be food. + */ + blesschance = rnd(100); + if (allow_curse) cursechance = rnd(100); + else cursechance = 100; /* No chance of curse */ + + /* Get the type of item (pick one if 'any' is specified) */ + if (thing_type == ALL) j = pick_one(things, NUMTHINGS); + else j = thing_type; + + /* + * make sure he gets his vitamins + */ + if (thing_type == ALL && no_food > 4) + j = 2; + /* + * limit the number of foods on a level because it sometimes + * gets out of hand in the "deep" levels where there is a + * treasure room on most every level with lots of food in it + */ + while (thing_type == ALL && levtype != POSTLEV && foods_this_level > 1 && + j == 2) + j = pick_one(things, NUMTHINGS); /* not too many.... */ + switch (j) + { + case TYP_POTION: + cur->o_type = POTION; + do { + cur->o_which = pick_one(p_magic, MAXPOTIONS); + } while (!allow_curse && p_magic[cur->o_which].mi_curse == 100); + cur->o_weight = things[TYP_POTION].mi_wght; + if (cursechance < p_magic[cur->o_which].mi_curse) + cur->o_flags |= ISCURSED; + else if (blesschance < p_magic[cur->o_which].mi_bless) + cur->o_flags |= ISBLESSED; + + /* If we made a gain ability potion, see what kind it is */ + if (cur->o_which == P_ABIL) cur->o_kind = rnd(NUMABILITIES); + + when TYP_SCROLL: + cur->o_type = SCROLL; + do { + cur->o_which = pick_one(s_magic, MAXSCROLLS); + } while (!allow_curse && s_magic[cur->o_which].mi_curse == 100); + cur->o_weight = things[TYP_SCROLL].mi_wght; + if (cursechance < s_magic[cur->o_which].mi_curse) + cur->o_flags |= ISCURSED; + else if (blesschance < s_magic[cur->o_which].mi_bless) + cur->o_flags |= ISBLESSED; + when TYP_FOOD: + no_food = 0; + cur->o_type = FOOD; + cur->o_weight = things[TYP_FOOD].mi_wght; + cur->o_count += extras(); + foods_this_level += cur->o_count; + cur->o_which = pick_one(foods, MAXFOODS); + when TYP_WEAPON: + cur->o_type = WEAPON; + cur->o_which = rnd(MAXWEAPONS); + init_weapon(cur, cur->o_which); + if (cursechance < 20) + { + + cur->o_flags |= ISCURSED; + cur->o_hplus -= rnd(3) + 1; + cur->o_dplus -= rnd(3) + 1; + } + else if (blesschance < 50) { + + cur->o_hplus += rnd(5) + 1; + cur->o_dplus += rnd(5) + 1; + } + when TYP_ARMOR: + cur->o_type = ARMOR; + for (j = 0; j < MAXARMORS; j++) + if (blesschance < armors[j].a_prob) + break; + if (j == MAXARMORS) + { + debug("Picked a bad armor %d", blesschance); + wait_for(' '); + j = 0; + } + cur->o_which = j; + cur->o_ac = armors[j].a_class; + cur->o_weight = armors[j].a_wght; + if (cursechance < 20) + { + cur->o_flags |= ISCURSED; + cur->o_ac += rnd(4)+1; + } + else if (blesschance < 40) + cur->o_ac -= rnd(3)+1; + when TYP_RING: + cur->o_type = RING; + do { + cur->o_which = pick_one(r_magic, MAXRINGS); + } while (!allow_curse && r_magic[cur->o_which].mi_curse == 100); + cur->o_weight = things[TYP_RING].mi_wght; + if (cursechance < r_magic[cur->o_which].mi_curse) + cur->o_flags |= ISCURSED; + switch (cur->o_which) + { + case R_ADDSTR: + case R_ADDWISDOM: + case R_ADDINTEL: + case R_PROTECT: + case R_ADDHIT: + case R_ADDDAM: + cur->o_ac = rnd(2) + 1; + if (cur->o_flags & ISCURSED) + cur->o_ac = -cur->o_ac; + if (blesschance < r_magic[cur->o_which].mi_bless) + cur->o_ac+=rnd(vlevel/10)+1; + when R_DIGEST: + if (cur->o_flags & ISCURSED) + cur->o_ac = -1; + else if (blesschance < r_magic[cur->o_which].mi_bless) + cur->o_ac = 2; + else cur->o_ac = 1; + } + when TYP_STICK: + cur->o_type = STICK; + do { + cur->o_which = pick_one(ws_magic, MAXSTICKS); + } while (!allow_curse && ws_magic[cur->o_which].mi_curse == 100); + fix_stick(cur); + if (cursechance < ws_magic[cur->o_which].mi_curse) + cur->o_flags |= ISCURSED; + else if (blesschance < ws_magic[cur->o_which].mi_bless) + cur->o_flags |= ISBLESSED; + when TYP_MM: + cur->o_type = MM; + do { + cur->o_which = pick_one(m_magic, MAXMM); + } while (!allow_curse && m_magic[cur->o_which].mi_curse == 100); + cur->o_weight = things[TYP_MM].mi_wght; + if (cursechance < m_magic[cur->o_which].mi_curse) + cur->o_flags |= ISCURSED; + else if (blesschance < m_magic[cur->o_which].mi_bless) + cur->o_flags |= ISBLESSED; + switch (cur->o_which) { + case MM_JUG: + switch(rnd(11)) { + case 0: cur->o_ac = P_PHASE; + when 1: cur->o_ac = P_CLEAR; + when 2: cur->o_ac = P_SEEINVIS; + when 3: cur->o_ac = P_HEALING; + when 4: cur->o_ac = P_MFIND; + when 5: cur->o_ac = P_TFIND; + when 6: cur->o_ac = P_HASTE; + when 7: cur->o_ac = P_RESTORE; + when 8: cur->o_ac = P_FLY; + when 9: cur->o_ac = P_SKILL; + when 10:cur->o_ac = P_FFIND; + } + when MM_HUNGER: + case MM_CHOKE: + cur->o_ac = (2 + rnd(2)) * 3; + when MM_OPEN: + case MM_DRUMS: + case MM_DISAPPEAR: + case MM_KEOGHTOM: + cur->o_ac = (5 + rnd(6)) * 3; + when MM_BRACERS: + if (cur->o_flags & ISCURSED) + cur->o_ac = -(rnd(5)+1); + else + cur->o_ac = rnd(5)+1; + when MM_PROTECT: + if (cur->o_flags & ISCURSED) + cur->o_ac = -(rnd(5)+1); + else + cur->o_ac = rnd(5)+1; + when MM_DISP: + cur->o_ac = 3; + when MM_SKILLS: /* set it to a character class */ + cur->o_ac = rnd(NUM_CHARTYPES-1); + when MM_CRYSTAL: + cur->o_ac = 1; /* Use it just once */ + otherwise: + cur->o_ac = 0; + } + otherwise: + debug("Picked a bad kind of object"); + wait_for(' '); + } + return item; +} + +/* + * provide a new item tailored to specification + */ + +struct linked_list * +spec_item(type, which, hit, damage) +int type, which, hit, damage; +{ + register struct linked_list *item; + register struct object *obj; + + item = new_item(sizeof *obj); + obj = OBJPTR(item); + obj->o_count = 1; + obj->o_group = 0; + obj->contents = NULL; + obj->o_type = type; + obj->o_which = which; + strcpy(obj->o_damage,"0d0"); + strcpy(obj->o_hurldmg,"0d0"); + obj->o_hplus = 0; + obj->o_dplus = 0; + obj->o_flags = 0; + obj->o_mark[0] = '\0'; + obj->o_launch = 0; + obj->o_weight = 0; + + /* Handle special characteristics */ + switch (type) { + case WEAPON: + init_weapon(obj, which); + obj->o_hplus = hit; + obj->o_dplus = damage; + obj->o_ac = 10; + + if (hit < 0 || damage < 0) obj->o_flags |= ISCURSED; + + when ARMOR: + obj->o_ac = armors[which].a_class - hit; + if (hit < 0) obj->o_flags |= ISCURSED; + + when RING: + obj->o_ac = hit; + switch (obj->o_which) { + case R_ADDSTR: + case R_ADDWISDOM: + case R_ADDINTEL: + case R_PROTECT: + case R_ADDHIT: + case R_ADDDAM: + case R_DIGEST: + if (hit < 0) obj->o_flags |= ISCURSED; + } + + when STICK: + fix_stick(obj); + obj->o_charges = hit; + + when GOLD: + obj->o_type = GOLD; + obj->o_count = GOLDCALC; + obj->o_ac = 11; + + when MM: + obj->o_type = MM; + obj->o_ac = hit; + + when RELIC: + /* Handle weight here since these are all created uniquely */ + obj->o_weight = things[TYP_RELIC].mi_wght; + if (obj->o_which == EMORI_CLOAK) + obj->o_charges = 1; + + } + return(item); +} + +/* + * pick an item out of a list of nitems possible magic items + */ + +pick_one(magic, nitems) +register struct magic_item *magic; +int nitems; +{ + register struct magic_item *end; + register int i; + register struct magic_item *start; + + start = magic; + for (end = &magic[nitems], i = rnd(1000); magic < end; magic++) + if (i < magic->mi_prob) + break; + if (magic == end) + { + if (wizard) + { + msg("bad pick_one: %d from %d items", i, nitems); + for (magic = start; magic < end; magic++) + msg("%s: %d%%", magic->mi_name, magic->mi_prob); + } + magic = start; + } + return magic - start; +} + + +/* blesscurse returns whether, according to the flag, the object is + * blessed, cursed, or neither + */ + +char * +blesscurse(flags) +int flags; +{ + if (flags & ISKNOW) { + if (flags & ISCURSED) return("cursed "); + if (flags & ISBLESSED) return("blessed "); + return("normal "); + } + return(""); +} + +/* + * p_kind returns the type of potion for some types of identified potions; + * otherwise, it returns the color. + */ + +char * +p_kind(obj) +struct object *obj; /* We assume that obj points to a potion */ +{ + if (obj->o_which == P_ABIL) return(abilities[obj->o_kind].w_string); + else return(p_colors[obj->o_which]); +} + +/* + * extras: + * Return the number of extra items to be created + */ + +extras() +{ + reg int i; + + i = rnd(100); + if (i < 3) /* 3% for 2 more */ + return (2); + else if (i < 6) /* 6% for 1 more */ + return (1); + else /* otherwise no more */ + return (0); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/trader.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,499 @@ +/* + trader.c - Anything to do with trading posts + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <string.h> +#include "rogue.h" + +/* + * buy_it: + * Buy the item on which the hero stands + */ + +buy_it() +{ + reg int wh; + struct linked_list *item = NULL; + struct object *obj = NULL; + int wasfood = FALSE; + + if (purse <= 0) { + msg("You have no money."); + return; + } + if (curprice < 0) { /* if not yet priced */ + wh = price_it(); + if (!wh) /* nothing to price */ + return; + msg("Do you want to buy it? "); + do { + wh = wgetch(cw); + if (wh == ESC || wh == 'n') { + msg(""); + return; + } + } until(wh == 'y'); + } + mpos = 0; + if (curprice > purse) { + msg("You can't afford it!"); + return; + } + /* + * See if the hero has done all his transacting + */ + if (!open_market()) + return; + /* + * The hero bought the item here + */ + item = find_obj(hero.y, hero.x); + obj = OBJPTR(item); + mpos = 0; + wasfood = ISMULT(obj->o_type); + if (add_pack((struct linked_list *)NULL,TRUE)) {/* try to put it in his pack */ + purse -= curprice; /* take his money */ + ++trader; /* another transaction */ + trans_line(); /* show remaining deals */ + curprice = -1; /* reset stuff */ + curpurch[0] = 0; + if (!wasfood) /* if it was food then the object has been deleted */ + { + whatis (item); /* identify it */ + obj = OBJPTR(item); + obj->o_flags &= ~ISPOST; /* turn off ISPOST */ + obj->o_flags |= ISKNOW; /* he knows the item */ + msg("%s", inv_name(obj, TRUE)); + } + else + msg("a food ration."); + } +} + +/* + * do_post: + * Put a trading post room and stuff on the screen + */ + +do_post(startup) +bool startup; /* True if equipping the player at the beginning of the game */ +{ + coord tp; + reg int i, j = 0, k; + reg struct room *rp; + reg struct object *op; + reg struct linked_list *ll; + + o_free_list(lvl_obj); /* throw old items away */ + + for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) + rp->r_flags = ISGONE; /* kill all rooms */ + + rp = &rooms[0]; /* point to only room */ + rp->r_flags = 0; /* this room NOT gone */ + rp->r_max.x = 40; + rp->r_max.y = 10; /* 10 * 40 room */ + rp->r_pos.x = (cols - rp->r_max.x) / 2; /* center horizontal */ + rp->r_pos.y = 1; /* 2nd line */ + draw_room(rp); /* draw the only room */ + + /* Are we equipping the player? */ + if (startup) { + int wpt; + + /* + * Give the rogue some weaponry. + * Create every kind of weapon there is. + */ + for (wpt=0; wpt<MAXWEAPONS; wpt++) { + ll = spec_item(WEAPON, wpt, rnd(100)/80+1, rnd(121)/60); + attach(lvl_obj, ll); + op = OBJPTR(ll); + op->o_flags |= (ISPOST | ISKNOW); + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* + * Suit of armor. + * Create every kind of armor there is. + */ + for (i=0; i<MAXARMORS; i++) { + ll = spec_item(ARMOR, i, rnd(100)/75, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + op->o_flags |= (ISPOST | ISKNOW); + op->o_weight = armors[i].a_wght; + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* Now create some rods/wands/staffs */ + for (i=rnd(4)+2; i>0; i--) { + if (i == 1 && player.t_ctype != C_FIGHTER) j = WS_HIT; + else if (i == 5 && (player.t_ctype == C_RANGER || + player.t_ctype == C_PALADIN || + player.t_ctype == C_MONK)) j = WS_FEAR; + else switch (rnd(8)) { + case 0: j = WS_SLOW_M; + when 1: j = WS_TELMON; + when 2: j = WS_CONFMON; + when 3: j = WS_PARALYZE; + when 4: j = WS_MDEG; + when 5: j = WS_WONDER; + when 6: j = WS_LIGHT; + when 7: j = WS_CANCEL; + } + ll = spec_item(STICK, j, 0, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + + /* Let clerics and MU'S know what kind they are */ + switch (player.t_ctype) { + case C_MAGICIAN: + case C_CLERIC: + case C_DRUID: + op->o_flags |= (ISPOST | ISKNOW); + otherwise: + op->o_flags |= ISPOST; + } + fix_stick(op); + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* Now let's make some rings */ + for (i=rnd(5)+3; i>0; i--) { + k = 0; + if (i == 6 && player.t_ctype != C_MONK) j = R_HEALTH; + else if (i == 7) j = R_HEROISM; + else switch (rnd(21)) { + case 0: j = R_ADDINTEL; k = roll(1,3); + when 1: j = R_ADDSTR; k = roll(1,3); + when 2: j = R_ADDWISDOM; k = roll(1,3); + when 3: j = R_ADDHIT; k = roll(1,3); + when 4: j = R_ADDDAM; k = roll(1,3); + when 5: j = R_PROTECT; k = roll(1,3); + when 6: j = R_DIGEST; k = 1; + when 7: j = R_SUSABILITY; + when 8: j = R_SEEINVIS; + when 9: j = R_ALERT; + when 10: j = R_FIRE; + when 11: j = R_WARMTH; + when 12: j = R_FREEDOM; + when 13: j = R_STEALTH; + when 14: j = R_CARRY; + when 15: j = R_LIGHT; + when 16: j = R_TELCONTROL; + when 17: j = R_DELUSION; + when 18: j = R_FEAR; + when 19: j = R_AGGR; + when 20: j = R_SEARCH; + } + ll = spec_item(RING, j, k, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + + /* + * Let fighters, thieves, and monks know what kind + * of rings these are. + */ + switch (player.t_ctype) { + case C_FIGHTER: + case C_THIEF: + case C_MONK: + op->o_flags |= (ISPOST | ISKNOW); + otherwise: + op->o_flags |= ISPOST; + } + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* Let's offer some potions */ + for (i=rnd(4)+3; i>0; i--) { + if (i == 1 && player.t_ctype == C_ASSASSIN) j = P_POISON; + else if (i == 6) j = P_PHASE; + else switch (rnd(11)) { + case 0: j = P_CLEAR; + when 1: j = P_HEALING; + when 2: j = P_MFIND; + when 3: j = P_HASTE; + when 4: j = P_RESTORE; + when 5: j = P_FLY; + when 6: j = P_FFIND; + when 7: j = P_SEEINVIS; + when 8: j = P_TFIND; + when 9: j = P_INVIS; + when 10: j = P_SKILL; + } + + /* Make the potion */ + ll = spec_item(POTION, j, 0, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + op->o_flags |= ISPOST; + + /* Place the potion */ + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* Let's offer some scrolls */ + for (i=rnd(4)+3; i>0; i--) { + if (i == 1 && player.t_ctype != C_MONK) j = S_CURING; + else if (i == 6 && player.t_ctype != C_THIEF) j = S_FINDTRAPS; + else switch (rnd(11)) { + case 0: j = S_CONFUSE; + when 1: j = S_MAP; + when 2: j = S_LIGHT; + when 3: j = S_SLEEP; + when 4: j = S_IDENT; + when 5: j = S_GFIND; + when 6: j = S_REMOVE; + when 7: j = S_HOLD; + when 8: j = S_PETRIFY; + when 9: j = S_SCARE; + when 10: j = S_TELEP; + } + + /* Make the scroll */ + ll = spec_item(SCROLL, j, 0, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + op->o_flags |= ISPOST; + + /* Place the scroll */ + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* And finally, let's get some food */ + for (i=rnd(3)+2; i>0; i--) { + ll = spec_item(FOOD, 0, 0, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + op->o_weight = things[TYP_FOOD].mi_wght; + op->o_flags |= ISPOST; + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + } + else { /* in trading post itself */ + i = roll(10, 4); /* 10 to 40 items */ + for (; i > 0 ; i--) { /* place all the items */ + ll = new_thing(ALL, TRUE); /* get something */ + attach(lvl_obj, ll); + op = OBJPTR(ll); + op->o_flags |= ISPOST; /* object in trading post */ + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + } + wmove(cw,12,0); + nofont(cw); + trader = 0; + if (startup) { + waddstr(cw,"Welcome to Friendly Fiend's Equipage\n\r"); + waddstr(cw,"====================================\n\r"); + } + else { + waddstr(cw,"Welcome to Friendly Fiend's Flea Market\n\r"); + waddstr(cw,"=======================================\n\r"); + } + waddstr(cw,"$: Prices object that you stand upon.\n\r"); + waddstr(cw,"#: Buys the object that you stand upon.\n\r"); + waddstr(cw,"%: Trades in something in your pack for gold.\n\r"); + newfont(cw); + trans_line(); +} + +/* + * open_market: + * Retruns TRUE when ok do to transacting + */ + +open_market() +{ + if (trader >= MAXPURCH && !wizard && level != 0) { + msg("The market is closed. The stairs are that-a-way! "); + return FALSE; + } + else { + return TRUE; + } +} + +/* + * price_it: + * Price the object that the hero stands on + */ + +price_it() +{ + reg struct linked_list *item; + reg struct object *obj; + reg int worth; + reg char *str; + + if (!open_market()) /* after buying hours */ + return FALSE; + if ((item = find_obj(hero.y,hero.x)) == NULL) { + debug("Can't find the item"); + return FALSE; + } + obj = OBJPTR(item); + worth = get_worth(obj); + if (worth < 0) { + msg("That's not for sale."); + return FALSE; + } + if (worth < 25) + worth = 25; + + /* Our shopkeeper is affected by the person's charisma */ + if (pstats.s_charisma > 24) /* but don't give it away! */ + worth = (int) ((float) worth * (18. / (float)24)); + else + worth = (int) ((float) worth * (18. / (float)pstats.s_charisma)); + + str = inv_name(obj, TRUE); + msg("%s for only %d pieces of gold", str, worth); + curprice = worth; /* save price */ + strcpy(curpurch,str); /* save item */ + return TRUE; +} + +/* + * sell_it: + * Sell an item to the trading post + */ + +sell_it() +{ + reg struct linked_list *item; + reg struct object *obj; + reg int wo, ch; + + if (!open_market()) /* after selling hours */ + return; + + if ((item = get_item(pack, "sell", ALL, FALSE, FALSE)) == NULL) + return; + obj = OBJPTR(item); + wo = get_worth(obj); + if (wo <= 0) { + mpos = 0; + msg("We don't buy those."); + return; + } + if (wo < 25) + wo = 25; + msg("Your %s is worth %d pieces of gold.",typ_name(obj),wo); + msg("Do you want to sell it? "); + do { + ch = wgetch(cw); + if (ch == ESC || ch == 'n') { + msg(""); + return; + } + } until (ch == 'y'); + mpos = 0; + if (drop(item) == TRUE) { /* drop this item */ + purse += wo; /* give him his money */ + ++trader; /* another transaction */ + wo = obj->o_count; + if (obj->o_group == 0) /* dropped one at a time */ + obj->o_count = 1; + msg("Sold %s",inv_name(obj,TRUE)); + obj->o_count = wo; + trans_line(); /* show remaining deals */ + } +} + +/* + * trans_line: + * Show how many transactions the hero has left + */ + +trans_line() +{ + if (level == 0) + sprintf(prbuf, "You are welcome to spend whatever gold you have."); + else if (!wizard) + sprintf(prbuf,"You have %d transactions remaining.", + MAXPURCH - trader); + else + sprintf(prbuf, + "You have infinite transactions remaining oh great wizard."); + nofont(cw); + mvwaddstr(cw,lines - 4,0,prbuf); + newfont(cw); +} + +/* + * typ_name: + * Return the name for this type of object + */ + +char * +typ_name(obj) +reg struct object *obj; +{ + static char buff[20]; + reg int wh; + + switch (obj->o_type) { + case POTION: wh = TYP_POTION; + when SCROLL: wh = TYP_SCROLL; + when STICK: wh = TYP_STICK; + when RING: wh = TYP_RING; + when ARMOR: wh = TYP_ARMOR; + when WEAPON: wh = TYP_WEAPON; + when MM: wh = TYP_MM; + when FOOD: wh = TYP_FOOD; + when RELIC: wh = TYP_RELIC; + otherwise: wh = -1; + } + if (wh < 0) + strcpy(buff,"unknown"); + else + strcpy(buff,things[wh].mi_name); + return (buff); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/util.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1314 @@ +/* + util.c - all sorts of miscellaneous routines + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" + +/* + * this routine computes the players current AC without dex bonus's + */ + +int +ac_compute(ignoremetal) +bool ignoremetal; +{ + register int ac; + + ac = pstats.s_arm; /* base armor of "skin" */ + if (cur_armor) { + if (!ignoremetal || + (cur_armor->o_which != LEATHER && + cur_armor->o_which != STUDDED_LEATHER && + cur_armor->o_which != PADDED_ARMOR)) + ac -= (10 - cur_armor->o_ac); + } + if (player.t_ctype == C_MONK) + ac -= pstats.s_lvl * 3 / 5; + ac -= ring_value(R_PROTECT); + if (cur_misc[WEAR_BRACERS] != NULL) + ac -= cur_misc[WEAR_BRACERS]->o_ac; + if (cur_misc[WEAR_CLOAK] != NULL) + ac -= cur_misc[WEAR_CLOAK]->o_ac; + + /* If player has the cloak, must be wearing it */ + if (cur_relic[EMORI_CLOAK]) ac -= 15; + + if (ac > 25) + ac = 25; + return(ac); +} + +/* + * aggravate: + * aggravate all the monsters on this level + */ + +aggravate(do_uniques, do_good) +bool do_uniques, do_good; +{ + register struct linked_list *mi; + register struct thing *thingptr; + + for (mi = mlist; mi != NULL; mi = next(mi)) { + thingptr = THINGPTR(mi); + if (do_good == FALSE && off(*thingptr, ISMEAN)) continue; + if (do_uniques || off(*thingptr, ISUNIQUE)) runto(thingptr, &hero); + } +} + +/* + * cansee: + * returns true if the hero can see a certain coordinate. + */ + +cansee(y, x) +register int y, x; +{ + register struct room *rer; + register int radius; + coord tp; + + if (on(player, ISBLIND)) + return FALSE; + + tp.y = y; + tp.x = x; + rer = roomin(&tp); + + /* How far can we see? */ + if (levtype == OUTSIDE) { + if (daytime) radius = 36; + else if (lit_room(rer)) radius = 9; + else radius = 3; + } + else radius = 3; + + /* + * We can only see if the hero in the same room as + * the coordinate and the room is lit or if it is close. + */ + return ((rer != NULL && + levtype != OUTSIDE && + (levtype != MAZELEV || /* Maze level needs direct line */ + maze_view(tp.y, tp.x)) && + rer == roomin(&hero) && + lit_room(rer)) || + DISTANCE(y, x, hero.y, hero.x) < radius); +} + +/* + * check_level: + * Check to see if the guy has gone up a level. + * + * Return points needed to obtain next level. + * + * These are certain beginning experience levels for all players. + * All further experience levels are computed by muliplying by 2 + * up through MAXDOUBLE. Then the cap is added in to compute + * further levels + */ + +long +check_level() +{ + register int i, j, add = 0; + register unsigned long exp; + long retval; /* Return value */ + int nsides; + + pstats.s_lvl -= pstats.s_lvladj; /* correct for level adjustment */ + /* See if we are past the doubling stage */ + exp = char_class[player.t_ctype].cap; + if (pstats.s_exp >= exp) { + i = pstats.s_exp/exp; /* First get amount above doubling area */ + retval = exp + i * exp; /* Compute next higher boundary */ + i += MAXDOUBLE; /* Add in the previous doubled levels */ + } + else { + i = 0; + exp = char_class[player.t_ctype].start_exp; + while (exp <= pstats.s_exp) { + i++; + exp <<= 1; + } + retval = exp; + } + if (++i > pstats.s_lvl) { + nsides = char_class[player.t_ctype].hit_pts; + for (j=0; j<(i-pstats.s_lvl); j++) /* Take care of multi-level jumps */ + add += max(1, roll(1,nsides) + const_bonus()); + max_stats.s_hpt += add; + if ((pstats.s_hpt += add) > max_stats.s_hpt) + pstats.s_hpt = max_stats.s_hpt; + msg("Welcome, %s, to level %d", + cnames[player.t_ctype][min(i-1, NUM_CNAMES-1)], i); + } + pstats.s_lvl = i; + pstats.s_lvl += pstats.s_lvladj; /* correct for level adjustment */ + return(retval); +} + +/* + * Used to modify the players strength + * it keeps track of the highest it has been, just in case + */ + +chg_str(amt) +register int amt; +{ + register int ring_str; /* ring strengths */ + register struct stats *ptr; /* for speed */ + + ptr = &pstats; + ring_str = ring_value(R_ADDSTR); + ptr->s_str -= ring_str; + ptr->s_str += amt; + if (ptr->s_str > MAXATT) ptr->s_str = MAXATT; + if (ptr->s_str > max_stats.s_str) + max_stats.s_str = ptr->s_str; + ptr->s_str += ring_str; + if (ptr->s_str <= 0) { + pstats.s_hpt = -1; + death(D_STRENGTH); + } + updpack(TRUE, &player); +} + +/* + * let's confuse the player + */ + +confus_player() +{ + if (off(player, ISCLEAR)) + { + msg("Wait, what's going on here! Huh? What? Who?"); + if (find_slot(unconfuse)) + lengthen(unconfuse, HUHDURATION); + else + fuse(unconfuse, (VOID *)NULL, HUHDURATION, AFTER); + turn_on(player, ISHUH); + } + else msg("You feel dizzy for a moment, but it quickly passes."); +} + +/* + * this routine computes the players current dexterity + */ + +dex_compute() +{ + if (cur_misc[WEAR_GAUNTLET] != NULL && + cur_misc[WEAR_GAUNTLET]->o_which == MM_G_DEXTERITY) { + if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED) + return (3); + else + return (21); + } + else + return (pstats.s_dext); +} + +/* + * diag_ok: + * Check to see if the move is legal if it is diagonal + */ + +diag_ok(sp, ep, flgptr) +register coord *sp, *ep; +struct thing *flgptr; +{ + register int numpaths = 0; + + /* Horizontal and vertical moves are always ok */ + if (ep->x == sp->x || ep->y == sp->y) + return TRUE; + + /* Diagonal moves are not allowed if there is a horizontal or + * vertical path to the destination + */ + if (step_ok(ep->y, sp->x, MONSTOK, flgptr)) numpaths++; + if (step_ok(sp->y, ep->x, MONSTOK, flgptr)) numpaths++; + return(numpaths != 1); +} + +/* + * pick a random position around the give (y, x) coordinates + */ + +coord * +fallpos(pos, be_clear, range) +register coord *pos; +bool be_clear; +int range; +{ + register int tried, i, j; + register char ch; + static coord ret; + static short masks[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100 }; + +/* + * Pick a spot at random centered on the position given by 'pos' and + * up to 'range' squares away from 'pos' + * + * If 'be_clear' is TRUE, the spot must be either FLOOR or PASSAGE + * inorder to be considered valid + * + * Generate a number from 0 to 8, representing the position to pick. + * Note that this DOES include the positon 'pos' itself + * + * If this position is not valid, mark it as 'tried', and pick another. + * Whenever a position is picked that has been tried before, + * sequentially find the next untried position. This eliminates costly + * random number generation + */ + + tried = 0; + while( tried != 0x1ff ) { + i = rnd(9); + while( tried & masks[i] ) + i = (i + 1) % 9; + + tried |= masks[i]; + + for( j = 1; j <= range; j++ ) { + ret.x = pos->x + j*grid[i].x; + ret.y = pos->y + j*grid[i].y; + + if (ret.x == hero.x && ret.y == hero.y) + continue; /* skip the hero */ + + if (ret.x < 0 || ret.x > cols - 1 || + ret.y < 1 || ret.y > lines - 3) + continue; /* off the screen? */ + + ch = winat(ret.y, ret.x); + + /* + * Check to make certain the spot is valid + */ + switch( ch ) { + case FLOOR: + case PASSAGE: + return( &ret ); + case GOLD: + case SCROLL: + case POTION: + case STICK: + case RING: + case WEAPON: + case ARMOR: + case MM: + case FOOD: + if(!be_clear && levtype != POSTLEV) + return( &ret ); + default: + break; + } + } + } + return( NULL ); +} + +/* + * findmindex: + * Find the index into the monster table of a monster given its name. + */ + +findmindex(name) +char *name; +{ + int which; + + for (which=1; which<NUMMONST; which++) { + if (strcmp(name, monsters[which].m_name) == 0) + break; + } + if (which >= NUMMONST) { + debug("couldn't find monster index"); + which = 1; + } + return(which); +} + +/* + * find_mons: + * Find the monster from his coordinates + */ + +struct linked_list * +find_mons(y, x) +register int y; +register int x; +{ + register struct linked_list *item; + register struct thing *th; + + for (item = mlist; item != NULL; item = next(item)) + { + th = THINGPTR(item); + if (th->t_pos.y == y && th->t_pos.x == x) + return item; + } + return NULL; +} + +/* + * find_obj: + * find the unclaimed object at y, x + */ + +struct linked_list * +find_obj(y, x) +register int y; +register int x; +{ + register struct linked_list *obj; + register struct object *op; + + for (obj = lvl_obj; obj != NULL; obj = next(obj)) + { + op = OBJPTR(obj); + if (op->o_pos.y == y && op->o_pos.x == x) + return obj; + } + return NULL; +} + +/* + * get coordinates from the player using the cursor keys (or mouse) + */ + +coord +get_coordinates() +{ + register int which; + coord c; + + c = hero; + wmove(cw, hero.y, hero.x); + draw(cw); + for (;;) { + which = (wgetch(cw) & 0177); + switch(which) { + case ESC: + c = hero; + wmove(cw, c.y, c.x); + draw(cw); + case '\n': + case '\r': + return(c); + when 'h': + case 'H': + c.x--; + when 'j': + case 'J': + c.y++; + when 'k': + case 'K': + c.y--; + when 'l': + case 'L': + c.x++; + when 'y': + case 'Y': + c.x--; c.y--; + when 'u': + case 'U': + c.x++; c.y--; + when 'b': + case 'B': + c.x--; c.y++; + when 'n': + case 'N': + c.x++; c.y++; + when '*': + mpos = 0; + msg("Use h,j,k,l,y,u,b,n to position cursor, then press enter."); + } + c.y = max(c.y, 1); + c.y = min(c.y, lines - 3); + c.x = max(c.x, 0); + c.x = min(c.x, cols - 1); + wmove(cw, c.y, c.x); + draw(cw); + } +} + +/* + * set up the direction co_ordinate for use in various "prefix" commands + */ + +bool +get_dir(direction) +coord *direction; +{ + register char *prompt; + register bool gotit; + int x,y; + + prompt = terse ? "Direction?" : "Which direction? "; + msg(prompt); + do + { + gotit = TRUE; + switch (wgetch(msgw)) + { + case 'h': case'H': direction->y = 0; direction->x = -1; + when 'j': case'J': direction->y = 1; direction->x = 0; + when 'k': case'K': direction->y = -1; direction->x = 0; + when 'l': case'L': direction->y = 0; direction->x = 1; + when 'y': case'Y': direction->y = -1; direction->x = -1; + when 'u': case'U': direction->y = -1; direction->x = 1; + when 'b': case'B': direction->y = 1; direction->x = -1; + when 'n': case'N': direction->y = 1; direction->x = 1; + when ESC: return (FALSE); + otherwise: + mpos = 0; + msg(prompt); + gotit = FALSE; + } + } until (gotit); + if ((on(player, ISHUH) || on(player, ISDANCE)) && rnd(100) > 20) { + do + { + *direction = grid[rnd(9)]; + } while (direction->y == 0 && direction->x == 0); + } + else if (on(player, ISFLEE)) { + y = hero.y; + x = hero.x; + while (shoot_ok(winat(y, x))) { + y += direction->y; + x += direction->x; + } + if (isalpha(mvwinch(mw, y, x))) { + if (y == player.t_dest->y && x == player.t_dest->x) { + mpos = 0; + msg("You are too frightened to!"); + return(FALSE); + } + } + } + mpos = 0; + return TRUE; +} + + +/* + * get_worth: + * Calculate an objects worth in gold + */ + +long +get_worth(obj) +reg struct object *obj; +{ + reg long worth, wh; + + worth = 0; + wh = obj->o_which; + switch (obj->o_type) { + case FOOD: + worth = 2; + when WEAPON: + if (wh < MAXWEAPONS) { + worth = weaps[wh].w_worth; + worth += s_magic[S_ALLENCH].mi_worth * + (obj->o_hplus + obj->o_dplus); + } + when ARMOR: + if (wh < MAXARMORS) { + worth = armors[wh].a_worth; + worth += s_magic[S_ALLENCH].mi_worth * + (armors[wh].a_class - obj->o_ac); + } + when SCROLL: + if (wh < MAXSCROLLS) + worth = s_magic[wh].mi_worth; + when POTION: + if (wh < MAXPOTIONS) + worth = p_magic[wh].mi_worth; + when RING: + if (wh < MAXRINGS) { + worth = r_magic[wh].mi_worth; + worth += obj->o_ac * 40; + } + when STICK: + if (wh < MAXSTICKS) { + worth = ws_magic[wh].mi_worth; + worth += 20 * obj->o_charges; + } + when MM: + if (wh < MAXMM) { + worth = m_magic[wh].mi_worth; + switch (wh) { + case MM_BRACERS: worth += 40 * obj->o_ac; + when MM_PROTECT: worth += 60 * obj->o_ac; + when MM_DISP: /* ac already figured in price*/ + otherwise: worth += 20 * obj->o_ac; + } + } + when RELIC: + if (wh < MAXRELIC) { + worth = rel_magic[wh].mi_worth; + if (wh == quest_item) worth *= 10; + } + otherwise: + worth = 0; + } + if (obj->o_flags & ISPROT) /* 300% more for protected */ + worth *= 3; + if (obj->o_flags & ISBLESSED) /* 50% more for blessed */ + worth = worth * 3 / 2; + if (obj->o_flags & ISCURSED) /* half for cursed */ + worth /= 2; + if (worth < 0) + worth = 0; + return worth; +} + +/* + * invisible() + */ + +bool +invisible(monst) +register struct thing *monst; +{ + register bool ret_code; + + ret_code = on(*monst, CANSURPRISE); + ret_code &= !ISWEARING(R_ALERT); + ret_code |= (on(*monst, ISINVIS) || + (on(*monst, ISSHADOW) && rnd(100) < 90)) && + off(player, CANSEE); + return( ret_code ); +} + +/* + * see if the object is one of the currently used items + */ + +is_current(obj) +register struct object *obj; +{ + if (obj == NULL) + return FALSE; + if (obj == cur_armor || obj == cur_weapon || + obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] || + obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4] || + obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] || + obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4] || + obj == cur_misc[WEAR_BOOTS] || obj == cur_misc[WEAR_JEWEL] || + obj == cur_misc[WEAR_BRACERS] || obj == cur_misc[WEAR_CLOAK] || + obj == cur_misc[WEAR_GAUNTLET] || obj == cur_misc[WEAR_NECKLACE]) { + + return TRUE; + } + + /* Is it a "current" relic? */ + if (obj->o_type == RELIC) { + switch (obj->o_which) { + case MUSTY_DAGGER: + case EMORI_CLOAK: + case HEIL_ANKH: + case YENDOR_AMULET: + case STONEBONES_AMULET: + case HRUGGEK_MSTAR: + case AXE_AKLAD: + case YEENOGHU_FLAIL: + case SURTUR_RING: + if (cur_relic[obj->o_which]) return TRUE; + } + } + + return FALSE; +} + + +/* + * Look: + * A quick glance all around the player + */ + +look(wakeup, runend) +bool wakeup; /* Should we wake up monsters */ +bool runend; /* At end of a run -- for mazes */ +{ + register int x, y, radius; + register unsigned char ch, och; + register int oldx, oldy; + register bool inpass, horiz, vert, do_light = FALSE, do_blank = FALSE; + register int passcount = 0, curfloorcount = 0, nextfloorcount = 0; + register struct room *rp; + register int ey, ex; + + inpass = ((rp = roomin(&hero)) == NULL); /* Are we in a passage? */ + + /* Are we moving vertically or horizontally? */ + if (runch == 'h' || runch == 'l') horiz = TRUE; + else horiz = FALSE; + if (runch == 'j' || runch == 'k') vert = TRUE; + else vert = FALSE; + + /* How far around himself can the player see? */ + if (levtype == OUTSIDE) { + if (daytime) radius = 9; + else if (lit_room(rp)) radius = 3; + else radius = 1; + } + else radius = 1; + + getyx(cw, oldy, oldx); /* Save current position */ + + /* Blank out the floor around our last position and check for + * moving out of a corridor in a maze. + */ + if (levtype == OUTSIDE) do_blank = !daytime; + else if (oldrp != NULL && !lit_room(oldrp) && off(player, ISBLIND)) + do_blank = TRUE; + + /* Now move around the old position and blank things out */ + ey = player.t_oldpos.y + radius; + ex = player.t_oldpos.x + radius; + for (x = player.t_oldpos.x - radius; x <= ex; x++) + if (x >= 0 && x < cols) + for (y = player.t_oldpos.y - radius; y <= ey; y++) { + struct linked_list *it; + coord here; /* Current <x,y> coordinate */ + unsigned char savech; /* Saves character in monster window */ + bool in_room; /* Are we in a room? */ + + if (y < 1 || y > lines - 3) continue; + + /* See what's there -- ignore monsters, just see what they're on */ + savech = mvwinch(mw, y, x); + waddch(mw, ' '); + ch = show(y, x); + mvwaddch(mw, y, x, savech); /* Restore monster */ + + /* + * If we have a monster that we can't see anymore, make sure + * that we can note that fact. + */ + if (isalpha(savech) && + (y < hero.y - radius || y > hero.y + radius || + x < hero.x - radius || x > hero.x + radius)) { + /* Find the monster */ + it = find_mons(y, x); + } + else it = NULL; + + /* Are we in a room? */ + here.y = y; + here.x = x; + in_room = (roomin(&here) != NULL); + + if ((do_blank || !in_room) && (y != hero.y || x != hero.x)) + switch (ch) { + case DOOR: + case SECRETDOOR: + case PASSAGE: + case STAIRS: + case TRAPDOOR: + case TELTRAP: + case BEARTRAP: + case SLEEPTRAP: + case ARROWTRAP: + case DARTTRAP: + case WORMHOLE: + case MAZETRAP: + case POOL: + case POST: + case VERTWALL: + case HORZWALL: + case WALL: + /* If there was a monster showing, make it disappear */ + if (isalpha(savech)) { + mvwaddch(cw, y, x, ch); + + /* + * If we found it (we should!), set it to + * the right character! + */ + if (it) (THINGPTR(it))->t_oldch = ch; + } + break; + when FLOOR: + case FOREST: + default: + mvwaddch(cw, y, x, in_room ? ' ' : PASSAGE); + + /* If we found a monster, set it to darkness! */ + if (it) (THINGPTR(it))->t_oldch = mvwinch(cw, y, x); + } + + /* Moving out of a corridor? */ + if (levtype == MAZELEV && !ce(hero, player.t_oldpos) && + !running && !isrock(ch) && /* Not running and not a wall */ + ((vert && x != player.t_oldpos.x && y==player.t_oldpos.y) || + (horiz && y != player.t_oldpos.y && x==player.t_oldpos.x))) + do_light = off(player, ISBLIND); + } + + /* Take care of unlighting a corridor */ + if (do_light && lit_room(rp)) light(&player.t_oldpos); + + /* Are we coming or going between a wall and a corridor in a maze? */ + och = show(player.t_oldpos.y, player.t_oldpos.x); + ch = show(hero.y, hero.x); + if (levtype == MAZELEV && + ((isrock(och) && !isrock(ch)) || (isrock(ch) && !isrock(och)))) { + do_light = off(player, ISBLIND); /* Light it up if not blind */ + + /* Unlight what we just saw */ + if (do_light && lit_room(&rooms[0])) light(&player.t_oldpos); + } + + /* Look around the player */ + ey = hero.y + radius; + ex = hero.x + radius; + for (x = hero.x - radius; x <= ex; x++) + if (x >= 0 && x < cols) for (y = hero.y - radius; y <= ey; y++) { + if (y < 1 || y >= lines - 2) + continue; + if (isalpha(mvwinch(mw, y, x))) + { + register struct linked_list *it; + register struct thing *tp; + + if (wakeup) + it = wake_monster(y, x); + else + it = find_mons(y, x); + + if (it) { + tp = THINGPTR(it); + tp->t_oldch = mvinch(y, x); + if (isatrap(tp->t_oldch)) { + register struct trap *trp = trap_at(y, x); + + tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch + : trp->tr_show; + } + if (tp->t_oldch == FLOOR && !lit_room(rp) && + off(player, ISBLIND)) + tp->t_oldch = ' '; + } + } + + /* + * Secret doors show as walls + */ + if ((ch = show(y, x)) == SECRETDOOR) + ch = secretdoor(y, x); + /* + * Don't show room walls if he is in a passage and + * check for maze turns + */ + if (off(player, ISBLIND)) + { + if (y == hero.y && x == hero.x + || (inpass && (ch == HORZWALL || ch == VERTWALL))) + continue; + + /* Did we come to a crossroads in a maze? */ + if (levtype == MAZELEV && + (runend || !ce(hero, player.t_oldpos)) && + !isrock(ch) && /* Not a wall */ + ((vert && x != hero.x && y == hero.y) || + (horiz && y != hero.y && x == hero.x))) + /* Just came to a turn */ + do_light = off(player, ISBLIND); + } + else if (y != hero.y || x != hero.x) + continue; + + wmove(cw, y, x); + waddch(cw, ch); + if (door_stop && !firstmove && running) + { + switch (runch) + { + case 'h': + if (x == hero.x + 1) + continue; + when 'j': + if (y == hero.y - 1) + continue; + when 'k': + if (y == hero.y + 1) + continue; + when 'l': + if (x == hero.x - 1) + continue; + when 'y': + if ((x + y) - (hero.x + hero.y) >= 1) + continue; + when 'u': + if ((y - x) - (hero.y - hero.x) >= 1) + continue; + when 'n': + if ((x + y) - (hero.x + hero.y) <= -1) + continue; + when 'b': + if ((y - x) - (hero.y - hero.x) <= -1) + continue; + } + switch (ch) + { + case DOOR: + if (x == hero.x || y == hero.y) + running = FALSE; + break; + case PASSAGE: + if (x == hero.x || y == hero.y) + passcount++; + break; + case FLOOR: + /* Stop by new passages in a maze (floor next to us) */ + if ((levtype == MAZELEV) && + !(hero.y == y && hero.x == x)) { + if (vert) { /* Moving vertically */ + /* We have a passage on our row */ + if (y == hero.y) curfloorcount++; + + /* Some passage on the next row */ + else if (y != player.t_oldpos.y) + nextfloorcount++; + } + else { /* Moving horizontally */ + /* We have a passage on our column */ + if (x == hero.x) curfloorcount++; + + /* Some passage in the next column */ + else if (x != player.t_oldpos.x) + nextfloorcount++; + } + } + case VERTWALL: + case HORZWALL: + case ' ': + break; + default: + running = FALSE; + break; + } + } + } + + /* Have we passed a side passage, with multiple choices? */ + if (curfloorcount > 0 && nextfloorcount > 0) running = FALSE; + + else if (door_stop && !firstmove && passcount > 1) + running = FALSE; + + /* Do we have to light up the area (just stepped into a new corridor)? */ + if (do_light && !running && lit_room(rp)) light(&hero); + + mvwaddch(cw, hero.y, hero.x, PLAYER); + wmove(cw, oldy, oldx); + if (!ce(player.t_oldpos, hero)) { + player.t_oldpos = hero; /* Don't change if we didn't move */ + oldrp = rp; + } +} + +/* + * Lower a level of experience + */ + +lower_level(who) +short who; +{ + int fewer, nsides; + unsigned long exp; + + msg("You suddenly feel less skillful."); + if (--pstats.s_lvl == 0) { + pstats.s_hpt = -1; + death(who); /* All levels gone */ + } + if (pstats.s_lvladj > 0) { /* lose artificial levels first */ + pstats.s_lvladj--; + return; + } + exp = char_class[player.t_ctype].cap; + if (pstats.s_exp >= exp*2) + pstats.s_exp -= exp; + else + pstats.s_exp /= 2; + + nsides = char_class[player.t_ctype].hit_pts; + fewer = max(1, roll(1,nsides) + const_bonus()); + pstats.s_hpt -= fewer; + max_stats.s_hpt -= fewer; + if (max_stats.s_hpt <= 0) + max_stats.s_hpt = 0; + if (pstats.s_hpt <= 0) { + pstats.s_hpt = -1; + death(who); + } +} + +/* + * print out the name of a monster + */ + +char * +monster_name(tp) +register struct thing *tp; +{ + prbuf[0] = '\0'; + if (on(*tp, ISFLEE) || on(*tp, WASTURNED)) + strcat(prbuf, "terrified "); + if (on(*tp, ISHUH)) + strcat(prbuf, "confused "); + if (on(*tp, ISCHARMED)) + strcat(prbuf, "charmed "); + else if (on(*tp, ISFLY)) + strcat(prbuf, "flying "); + + /* If it is sleeping or stoned, write over any of the above attributes */ + if (off(*tp, ISRUN)) + strcpy(prbuf, "sleeping "); + if (on(*tp, ISSTONE)) + strcpy(prbuf, "petrified "); + + if (tp->t_name) strcat(prbuf, tp->t_name); + else strcat(prbuf, monsters[tp->t_index].m_name); + + return(prbuf); +} + +/* + * move_hero: + * Try to move the hero somplace besides next to where he is. We ask him + * where. There can be restrictions based on why he is moving. + */ + +bool +move_hero(why) +int why; +{ + char *action = NULL; + unsigned char which; + coord c; + + switch (why) { + case H_TELEPORT: + action = "teleport"; + } + + msg("Where do you wish to %s to? (* for help) ", action); + c = get_coordinates(); + mpos = 0; + which = winat(c.y, c.x); + switch (which) { + default: + if (!isrock(which) || off(player, CANINWALL)) break; + + case FLOOR: + case PASSAGE: + case DOOR: + case STAIRS: + case POST: + case GOLD: + case POTION: + case SCROLL: + case FOOD: + case WEAPON: + case ARMOR: + case RING: + case MM: + case RELIC: + case STICK: + hero = c; + return(TRUE); + } + return(FALSE); +} + +/* + * raise_level: + * The guy just magically went up a level. + */ + +raise_level() +{ + unsigned long test; /* Next level -- be sure it is not an overflow */ + + test = check_level(); /* Get next boundary */ + + /* Be sure it is higher than what we have no -- else overflow */ + if (test > pstats.s_exp) pstats.s_exp = test; + check_level(); + + /* Give him a bonus */ + switch (player.t_ctype) { + case C_FIGHTER: + (*add_abil[A_STRENGTH])(1); + when C_RANGER: + case C_PALADIN: + (*add_abil[A_CHARISMA])(1); + when C_MAGICIAN: + (*add_abil[A_INTELLIGENCE])(1); + when C_CLERIC: + case C_DRUID: + (*add_abil[A_WISDOM])(1); + when C_THIEF: + case C_ASSASSIN: + (*add_abil[A_DEXTERITY])(1); + when C_MONK: + (*add_abil[A_CONSTITUTION])(1); + } +} + +/* + * saving throw matrix for character saving throws + * this table is indexed by char type and saving throw type + */ + +static const char st_matrix[NUM_CHARTYPES][5] = { +/* Poison, Petrify, wand, Breath, Magic */ +{ 13, 14, 15, 16, 17 }, +{ 13, 14, 15, 16, 17 }, +{ 13, 14, 15, 16, 17 }, +{ 11, 12, 13, 14, 15 }, +{ 11, 12, 13, 14, 15 }, +{ 12, 13, 14, 15, 16 }, +{ 12, 13, 14, 15, 16 }, +{ 11, 12, 12, 14, 15 }, +{ 12, 13, 14, 15, 16 }, +{ 13, 14, 15, 16, 17 } +}; + +/* + * save: + * See if a creature saves against something + */ + +save(which, who, adj) +int which; /* which type of save */ +struct thing *who; /* who is saving */ +int adj; /* saving throw adjustment */ +{ + register int need, level, protect; + + protect = 0; + level = who->t_stats.s_lvl; + need = st_matrix[who->t_ctype][which]; + switch (who->t_ctype) { + case C_FIGHTER: + case C_RANGER: + case C_PALADIN: + need -= (2 * (level-1) / 5) - 1; /* for level 61; -= 25 */ + when C_THIEF: + case C_ASSASSIN: + case C_MONK: + case C_MONSTER: + need -= (2 * (level-1) / 5) - 3; /* for level 61; -= 27 */ + when C_MAGICIAN: + case C_CLERIC: + case C_DRUID: + need -= (2 * (level-1) / 5) - 5; /* for level 61; -= 29 */ + } + /* + * add in pluses against poison for execeptional constitution + */ + if (which == VS_POISON && who->t_stats.s_const > 18) + need -= (who->t_stats.s_const - 17) / 2; + if (who == &player) { + /* + * does the player have a ring of protection on? + */ + protect += ring_value(R_PROTECT); + /* + * does the player have a cloak of protection on? + */ + if (cur_misc[WEAR_CLOAK]) + protect += cur_misc[WEAR_CLOAK]->o_ac; + + protect = min(protect, 10);/* limit protection to +10 */ + need -= protect; + } + need -= adj; + /* + * always miss or save on a 1 (except for UNIQUEs + */ + if (who == &player || off(*who, ISUNIQUE)) + need = max(need, 2); + need = min(20, need); /* always make our save on a 20 */ + debug("need a %d to save", need); + return (roll(1, 20) >= need); +} + +/* + * secret_door: + * Figure out what a secret door looks like. + */ + +secretdoor(y, x) +register int y, x; +{ + register int i; + register struct room *rp; + register coord *cpp; + static coord cp; + + cp.y = y; + cp.x = x; + cpp = &cp; + for (rp = rooms, i = 0; i < MAXROOMS; rp++, i++) + if (inroom(rp, cpp)) + if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1) + return(HORZWALL); + else + return(VERTWALL); + + return('p'); +} + +/* + * this routine computes the players current strength + */ + +str_compute() +{ + if (cur_misc[WEAR_GAUNTLET] != NULL && + cur_misc[WEAR_GAUNTLET]->o_which == MM_G_OGRE) { + if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED) + return (3); + else + return (21); + } + else + return (pstats.s_str); +} + +/* + * copy string using unctrl for things + */ + +strucpy(s1, s2, len) +register char *s1, *s2; +register int len; +{ + register char *sp; + while (len--) + { + strcpy(s1, (sp = unctrl(*s2))); + s1 += strlen(sp); + s2++; + } + *s1 = '\0'; +} + +/* + * tr_name: + * print the name of a trap + */ + +char * +tr_name(ch) +char ch; +{ + register char *s = NULL; + + switch (ch) + { + case TRAPDOOR: + s = terse ? "A trapdoor." : "You found a trapdoor."; + when BEARTRAP: + s = terse ? "A beartrap." : "You found a beartrap."; + when SLEEPTRAP: + s = terse ? "A sleeping gas trap.":"You found a sleeping gas trap."; + when ARROWTRAP: + s = terse ? "An arrow trap." : "You found an arrow trap."; + when TELTRAP: + s = terse ? "A teleport trap." : "You found a teleport trap."; + when DARTTRAP: + s = terse ? "A dart trap." : "You found a poison dart trap."; + when POOL: + s = terse ? "A shimmering pool." : "You found a shimmering pool"; + when MAZETRAP: + s = terse ? "A maze entrance." : "You found a maze entrance"; + when WORMHOLE: + s = terse ? "A worm hole." : "You found a worm hole entrance"; + } + return s; +} + +/* + * for printfs: if string starts with a vowel, return "n" for an "an" + */ + +char * +vowelstr(str) +register char *str; +{ + switch (*str) + { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + return "n"; + default: + return ""; + } +} + +/* + * wake up a room full (hopefully) of creatures + */ + +wake_room(rp) +register struct room *rp; +{ + register struct linked_list *item; + register struct thing *tp; + + for (item=mlist; item!=NULL; item=next(item)) { + tp = THINGPTR(item); + if (off(*tp,ISRUN) && on(*tp,ISMEAN) && roomin(&tp->t_pos) == rp) + runto(tp, &hero); + } +} + + +/* + * waste_time: + * Do nothing but let other things happen + */ + +waste_time() +{ + if (inwhgt) /* if from wghtchk then done */ + return; + do_daemons(BEFORE); + do_fuses(BEFORE); + do_daemons(AFTER); + do_fuses(AFTER); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/vers.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,21 @@ +/* + vers.c - version number + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +unsigned char encstr[] = "\354\251\243\332A\201|\301\321p\210\251\327\"\257\365t\341%3\271^`~\203z{\341};\f\341\231\222e\234\351]\321"; +char version[] = "@(#)vers.c 8.0.3 - 12/10/2005"; +char *release = "8.0.3";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/weapons.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,429 @@ +/* + weapons.c - Functions for dealing with problems brought about by weapons + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" + +boomerang(ydelta, xdelta, item, tp) +int ydelta, xdelta; +register struct linked_list *item; +register struct thing *tp; +{ + register struct object *obj; + struct thing midpoint; + coord oldpos; + + obj = OBJPTR(item); + oldpos = obj->o_pos; + + /* + * make it appear to fly at the target + */ + do_motion(obj, ydelta, xdelta, tp); + hit_monster(unc(obj->o_pos), obj, tp); + + /* + * Now let's make it fly back to the wielder. We need to + * use midpoint to fool do_motion into thinking the action + * starts there. Do_motion only looks at the t_pos field. + */ + midpoint.t_pos = obj->o_pos; /* Simulate a new start position */ + do_motion(obj, -ydelta, -xdelta, &midpoint); + + obj->o_pos = oldpos; +} + +/* + * do the actual motion on the screen done by an object traveling + * across the room. Note that we should not look at any field in + * tp other than t_pos unless we change boomerang(). + */ + +do_motion(obj, ydelta, xdelta, tp) +register struct object *obj; +register int ydelta, xdelta; +register struct thing *tp; +{ + + /* + * Come fly with us ... + */ + obj->o_pos = tp->t_pos; + for (;;) { + register int ch; + /* + * Erase the old one + */ + if (!ce(obj->o_pos, tp->t_pos) && + cansee(unc(obj->o_pos)) && + mvwinch(cw, obj->o_pos.y, obj->o_pos.x) != ' ') { + mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, show(obj->o_pos.y, obj->o_pos.x)); + } + /* + * Get the new position + */ + obj->o_pos.y += ydelta; + obj->o_pos.x += xdelta; + if (shoot_ok(ch = winat(obj->o_pos.y, obj->o_pos.x)) && ch != DOOR && !ce(obj->o_pos, hero)) { + /* + * It hasn't hit anything yet, so display it + * If it alright. + */ + if (cansee(unc(obj->o_pos)) && + mvwinch(cw, obj->o_pos.y, obj->o_pos.x) != ' ') { + if (obj->o_type == MISSILE) nofont(cw); + mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, obj->o_type); + newfont(cw); + draw(cw); + } + continue; + } + + /* + * Did we stop because of a monster or the hero? If we did + * not, we want to move our position back one because we could + * not actually make it this far. + */ + if (!isalpha(ch) && + !(obj->o_pos.y == hero.y && obj->o_pos.x == hero.x)) { + obj->o_pos.y -= ydelta; + obj->o_pos.x -= xdelta; + } + + break; + } +} + + +/* + * fall: + * Drop an item someplace around here. + */ + +fall(item, pr) +register struct linked_list *item; +bool pr; +{ + register struct object *obj; + register struct room *rp; + register int i; + struct object *tobj; + struct linked_list *titem; + coord *fpos = NULL; + + obj = OBJPTR(item); + /* + * try to drop the item, look up to 3 squares away for now + */ + for (i=1; i<4; i++) { + if ((fpos = fallpos(&obj->o_pos, FALSE, i)) != NULL) + break; + } + + if (fpos != NULL) { + if (obj->o_group) { /* try to add groups together */ + for(titem=lvl_obj; titem!=NULL; titem=next(titem)) { + tobj = OBJPTR(titem); + if (tobj->o_group == obj->o_group && + tobj->o_pos.y == fpos->y && + tobj->o_pos.x == fpos->x) { + tobj->o_count += obj->o_count; + o_discard(item); + return; + } + } + } + mvaddch(fpos->y, fpos->x, obj->o_type); + obj->o_pos = *fpos; + if ((rp = roomin(&hero)) != NULL && + lit_room(rp)) { + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + } + attach(lvl_obj, item); + return; + } + if (pr) { + msg("The %s vanishes as it hits the ground.", + weaps[obj->o_which].w_name); + } + o_discard(item); +} + +/* + * Does the missile hit the monster + */ + +hit_monster(y, x, obj, tp) +register int y, x; +struct object *obj; +register struct thing *tp; +{ + static coord mp; + + mp.y = y; + mp.x = x; + if (tp == &player) { + /* Make sure there is a monster where it landed */ + if (!isalpha(mvwinch(mw, y, x))) { + return(FALSE); + } + + /* Player hits monster */ + return(fight(&mp, obj, TRUE)); + } else { + if (!ce(mp, hero)) { + /* Monster hits monster */ + return(skirmish(tp, &mp, obj, TRUE)); + } + + /* Monster hits player */ + return(attack(tp, obj, TRUE)); + } +} + +/* + * init_weapon: + * Set up the initial goodies for a weapon + */ + +init_weapon(weap, type) +register struct object *weap; +char type; +{ + register struct init_weps *iwp; + + iwp = &weaps[type]; + strcpy(weap->o_damage,iwp->w_dam); + strcpy(weap->o_hurldmg,iwp->w_hrl); + weap->o_launch = iwp->w_launch; + weap->o_flags = iwp->w_flags; + weap->o_weight = iwp->w_wght; + if (weap->o_flags & ISMANY) { + weap->o_count = rnd(8) + 8; + weap->o_group = newgrp(); + } else { + weap->o_count = 1; + } +} + +/* + * missile: + * Fire a missile in a given direction + */ + +missile(ydelta, xdelta, item, tp) +int ydelta, xdelta; +register struct linked_list *item; +register struct thing *tp; +{ + register struct object *obj; + register struct linked_list *nitem; + char ch; + + /* + * Get which thing we are hurling + */ + if (item == NULL) { + return; + } + obj = OBJPTR(item); + if (obj->o_type == RELIC && obj->o_which == AXE_AKLAD) { + boomerang(ydelta, xdelta, item, tp); + return; + } + + if (!dropcheck(obj)) return; /* Can we get rid of it? */ + + if(!(obj->o_flags & ISMISL)) { + for(;;) { + msg(terse ? "Really throw? (y or n): " + : "Do you really want to throw %s? (y or n): ", + inv_name(obj, TRUE)); + mpos = 0; + ch = wgetch(cw); + if (ch == 'n' || ch == ESC) { + after = FALSE; + return; + } + if (ch == 'y') + break; + } + } + /* + * Get rid of the thing. If it is a non-multiple item object, or + * if it is the last thing, just drop it. Otherwise, create a new + * item with a count of one. + */ + if (obj->o_count < 2) { + detach(tp->t_pack, item); + if (tp->t_pack == pack) { + inpack--; + } + } + else { + obj->o_count--; + nitem = (struct linked_list *) new_item(sizeof *obj); + obj = OBJPTR(nitem); + *obj = *(OBJPTR(item)); + obj->o_count = 1; + item = nitem; + } + updpack(FALSE, tp); + do_motion(obj, ydelta, xdelta, tp); + /* + * AHA! Here it has hit something. If it is a wall or a door, + * or if it misses (combat) the monster, put it on the floor + */ + if (!hit_monster(unc(obj->o_pos), obj, tp)) { + fall(item, TRUE); + } + else + o_discard(item); + + mvwaddch(cw, hero.y, hero.x, PLAYER); + +} + +/* + * num: + * Figure out the plus number for armor/weapons + */ + +char * +num(n1, n2) +register int n1, n2; +{ + static char numbuf[LINELEN/2]; + + if (n1 == 0 && n2 == 0) { + return "+0"; + } + if (n2 == 0) { + sprintf(numbuf, "%s%d", n1 < 0 ? "" : "+", n1); + } else { + sprintf(numbuf, "%s%d, %s%d", n1 < 0 ? "" : "+", n1, n2 < 0 ? "" : "+", n2); + } + return(numbuf); +} + +/* + * wield: + * Pull out a certain weapon + */ + +wield() +{ + register struct linked_list *item; + register struct object *obj, *oweapon; + + /* + * It takes 2 movement periods to unwield a weapon and 2 movement + * periods to wield a weapon. + */ + if (player.t_action != C_WIELD) { + player.t_action = C_WIELD; + player.t_using = NULL; /* Make sure this is NULL! */ + if (cur_weapon != NULL) { + player.t_no_move = 2 * movement(&player); + return; + } + } + + if ((oweapon = cur_weapon) != NULL) { + /* At this point we have waited at least 2 units */ + if (!dropcheck(cur_weapon)) { + cur_weapon = oweapon; + player.t_action = A_NIL; + return; + } + if (terse) + addmsg("Was "); + else + addmsg("You were "); + msg("wielding %s", inv_name(oweapon, TRUE)); + } + + /* We we have something picked out? */ + if (player.t_using == NULL) { + /* Now, what does he want to wield? */ + if ((item = get_item(pack, "wield", WIELDABLE, FALSE, FALSE)) == NULL) { + player.t_action = A_NIL; + after = FALSE; + return; + } + player.t_using = item; + player.t_no_move = 2 * movement(&player); + return; + } + + /* We have waited our time, let's wield the weapon */ + item = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + obj = OBJPTR(item); + + if (is_current(obj)) { + msg("Item in use."); + after = FALSE; + return; + } + if (player.t_ctype != C_FIGHTER && + player.t_ctype != C_RANGER && + player.t_ctype != C_PALADIN && + obj->o_type == WEAPON && + obj->o_which == TWOSWORD) { + switch (rnd(3)) { + case 0: + msg("Only fighter types can wield the two-handed sword."); + when 1: + msg("Your hand does not fit the two-handed sword."); + otherwise: + msg("You can not wield the two-handed sword."); + } + return; + } + if (player.t_ctype != C_FIGHTER && + player.t_ctype != C_ASSASSIN && + player.t_ctype != C_THIEF && + player.t_ctype != C_MONK && + obj->o_type == WEAPON && + obj->o_which == BASWORD) { + switch (rnd(3)) { + case 0: + msg("Only thief types can wield the bastard sword."); + when 1: + msg("Your hand does not fit the bastard sword."); + otherwise: + msg("You can not wield the bastard sword."); + } + return; + } + + if (terse) { + addmsg("W"); + } else { + addmsg("You are now w"); + } + msg("ielding %s", inv_name(obj, TRUE)); + cur_weapon = obj; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/wear.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,439 @@ +/* + wear.c - functions for dealing with armor + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <stdlib.h> +#include <curses.h> +#include "rogue.h" + +/* + * take_off: + * Get the armor off of the players back + */ + +take_off() +{ + register struct object *obj; + register struct linked_list *item; + + /* It takes time to take things off */ + if (player.t_action != C_TAKEOFF) { + /* What does player want to take off? */ + if ((item = get_item(pack, "take off", REMOVABLE, FALSE, FALSE))==NULL) + return; + + obj = OBJPTR(item); + if (!is_current(obj)) { + msg("Not wearing %c) %s", pack_char(pack, obj),inv_name(obj, TRUE)); + return; + } + + player.t_using = item; /* Remember what it is */ + player.t_action = C_TAKEOFF; /* We are taking something off */ + + /* Cursed items take almost no time */ + if (obj->o_flags & ISCURSED) player.t_no_move = movement(&player); + else player.t_no_move = dress_units(item) * movement(&player); + return; + } + + /* We have waited our time, let's take off our item */ + item = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + obj = OBJPTR(item); + if (!is_current(obj)) { /* Just to be on the safe side */ + msg("Not wearing %c) %s", pack_char(pack, obj),inv_name(obj, TRUE)); + return; + } + + /* Can the player remove the item? */ + if (!dropcheck(obj)) return; + updpack(TRUE, &player); + + msg("Was wearing %c) %s", pack_char(pack, obj),inv_name(obj,TRUE)); +} + +/* + * wear: + * The player wants to wear something, so let him/her put it on. + */ + +wear() +{ + register struct linked_list *item; + register struct object *obj; + register int i; + + /* It takes time to put things on */ + if (player.t_action != C_WEAR) { + /* What does player want to wear? */ + if ((item = get_item(pack, "wear", WEARABLE, FALSE, FALSE)) == NULL) + return; + + obj = OBJPTR(item); + + switch (obj->o_type) { + case ARMOR: + if (cur_armor != NULL) { + addmsg("You are already wearing armor"); + if (!terse) addmsg(". You'll have to take it off first."); + endmsg(); + after = FALSE; + return; + } + if (player.t_ctype == C_MONK) { + msg("Monks can't wear armor!"); + return; + } + if (cur_misc[WEAR_BRACERS] != NULL) { + msg("You can't wear armor with bracers of defense."); + return; + } + if (cur_misc[WEAR_CLOAK] != NULL || cur_relic[EMORI_CLOAK]) { + msg("You can't wear armor with a cloak."); + return; + } + if (player.t_ctype == C_THIEF && + (obj->o_which != LEATHER && + obj->o_which != STUDDED_LEATHER)) { + if (terse) msg("Thieves can't wear that type of armor."); + else + msg("Thieves can wear leather and studded leather armor."); + return; + } + if (player.t_ctype == C_ASSASSIN && + (obj->o_which != LEATHER && + obj->o_which != STUDDED_LEATHER)) { + if (terse) msg("Assassins can't wear that type of armor."); + else + msg("Assassins can wear leather and studded leather armor."); + return; + } + + when MM: + switch (obj->o_which) { + /* + * when wearing the boots of elvenkind the player will not + * set off any traps + */ + case MM_ELF_BOOTS: + if (cur_misc[WEAR_BOOTS] != NULL) { + msg("Already wearing a pair of boots. "); + return; + } + /* + * when wearing the boots of dancing the player will dance + * uncontrollably + */ + when MM_DANCE: + if (cur_misc[WEAR_BOOTS] != NULL) { + msg("Already wearing a pair of boots."); + return; + } + /* + * bracers give the hero protection in he same way armor does. + * they cannot be used with armor but can be used with cloaks + */ + when MM_BRACERS: + if (cur_misc[WEAR_BRACERS] != NULL) { + msg("Already wearing bracers."); + return; + } + else { + if (cur_armor != NULL) { + msg("You can't wear bracers of defense with armor."); + return; + } + } + + /* + * The robe (cloak) of powerlessness disallows any spell casting + */ + when MM_R_POWERLESS: + /* + * the cloak of displacement gives the hero an extra +2 on AC + * and saving throws. Cloaks cannot be used with armor. + */ + case MM_DISP: + /* + * the cloak of protection gives the hero +n on AC and saving + * throws with a max of +3 on saves + */ + case MM_PROTECT: + if (cur_misc[WEAR_CLOAK] != NULL || + cur_relic[EMORI_CLOAK]) { + msg("%slready wearing a cloak.", terse ? "A" + : "You are a"); + return; + } + else { + if (cur_armor != NULL) { + msg("You can't wear a cloak with armor."); + return; + } + } + /* + * the gauntlets of dexterity and ogre power give the hero + * a dexterity of 21, the gauntlets of fumbling cause the + * hero to drop his weapon. + */ + when MM_G_DEXTERITY: + case MM_G_OGRE: + case MM_FUMBLE: + if (cur_misc[WEAR_GAUNTLET] != NULL) { + msg("Already wearing a pair of gauntlets."); + return; + } + /* + * the jewel of attacks does an aggavate monster + */ + when MM_JEWEL: + if (cur_misc[WEAR_JEWEL] != NULL || + cur_relic[YENDOR_AMULET] || + cur_relic[STONEBONES_AMULET]) { + msg("Already wearing an amulet."); + return; + } + /* + * the necklace of adaption makes the hero immune to + * chlorine gas and acid breath. + */ + when MM_ADAPTION: + if (cur_misc[WEAR_NECKLACE] != NULL) { + msg("Already wearing a necklace."); + return; + } + /* + * the necklace of stragulation will try to strangle the + * hero to death + */ + when MM_STRANGLE: + if (cur_misc[WEAR_NECKLACE] != NULL) { + msg("Already wearing a necklace."); + return; + } + otherwise: + msg("What a strange item you have!"); + return; + } + + when RING: + if (cur_misc[WEAR_GAUNTLET] != NULL) { + msg ("You have to remove your gauntlets first!"); + return; + } + + /* Is there room to put the ring on */ + for (i=0; i<NUM_FINGERS; i++) + if (cur_ring[i] == NULL) { + break; + } + if (i == NUM_FINGERS) { /* Not enough fingers */ + if (terse) msg("Wearing enough rings."); + else msg("You are already wearing eight rings."); + return; + } + } + + player.t_using = item; /* Remember what it is */ + player.t_action = C_WEAR; /* We are taking something off */ + player.t_no_move = dress_units(item) * movement(&player); + return; + } + + /* We have waited our time, let's put on our item */ + item = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + obj = OBJPTR(item); + + switch (obj->o_type) { + case ARMOR: + obj->o_flags |= ISKNOW; + cur_armor = obj; + addmsg(terse ? "W" : "You are now w"); + msg("earing %s.", armors[obj->o_which].a_name); + + when MM: + switch (obj->o_which) { + /* + * when wearing the boots of elvenkind the player will not + * set off any traps + */ + case MM_ELF_BOOTS: + msg("Wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_BOOTS] = obj; + /* + * when wearing the boots of dancing the player will dance + * uncontrollably + */ + when MM_DANCE: + msg("Wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_BOOTS] = obj; + msg("You begin to dance uncontrollably!"); + turn_on(player, ISDANCE); + /* + * bracers give the hero protection in he same way armor does. + * they cannot be used with armor but can be used with cloaks + */ + when MM_BRACERS: + msg("wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_BRACERS] = obj; + + /* + * The robe (cloak) of powerlessness disallows any spell casting + */ + when MM_R_POWERLESS: + /* + * the cloak of displacement gives the hero an extra +2 on AC + * and saving throws. Cloaks cannot be used with armor. + */ + case MM_DISP: + /* + * the cloak of protection gives the hero +n on AC and saving + * throws with a max of +3 on saves + */ + case MM_PROTECT: + msg("wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_CLOAK] = obj; + /* + * the gauntlets of dexterity and ogre power give the hero + * a dexterity of 21, the gauntlets of fumbling cause the + * hero to drop his weapon. + */ + when MM_G_DEXTERITY: + case MM_G_OGRE: + case MM_FUMBLE: + msg("Wearing %s", inv_name(obj,TRUE)); + cur_misc[WEAR_GAUNTLET] = obj; + if (obj->o_which == MM_FUMBLE) + daemon(fumble, (VOID *)NULL, AFTER); + /* + * the jewel of attacks does an aggavate monster + */ + when MM_JEWEL: + msg("Wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_JEWEL] = obj; + aggravate(TRUE, TRUE); /* affect all charactors */ + if (player.t_ctype == C_PALADIN || + player.t_ctype == C_RANGER || player.t_ctype == C_MONK) + msg("A chill runs down your spine! "); + + /* + * the necklace of adaption makes the hero immune to + * chlorine gas and acid + */ + when MM_ADAPTION: + msg("Wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_NECKLACE] = obj; + turn_on(player, NOGAS); + turn_on(player, NOACID); + + /* + * the necklace of stragulation will try to strangle the + * hero to death + */ + when MM_STRANGLE: + msg("Wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_NECKLACE] = obj; + msg("The necklace is beginning to strangle you!"); + daemon(strangle, (VOID *)NULL, AFTER); + otherwise: + msg("What a strange item you have!"); + } + status(FALSE); + if (m_know[obj->o_which] && m_guess[obj->o_which]) { + free(m_guess[obj->o_which]); + m_guess[obj->o_which] = NULL; + } + else if (!m_know[obj->o_which] && + askme && + (obj->o_flags & ISKNOW) == 0 && + m_guess[obj->o_which] == NULL) { + nameitem(item, FALSE); + } + + when RING: + /* If there is room, put on the ring */ + for (i=0; i<NUM_FINGERS; i++) + if (cur_ring[i] == NULL) { + cur_ring[i] = obj; + break; + } + if (i == NUM_FINGERS) { /* Not enough fingers */ + if (terse) msg("Wearing enough rings."); + else msg("You are already wearing eight rings."); + return; + } + + /* Calculate the effect of the ring */ + ring_on(item); + } + updpack(TRUE, &player); +} + +/* + * dress_units: + * How many movements periods does it take to put on or remove the + * given item of "clothing"? + */ + +dress_units(item) +struct linked_list *item; +{ + register struct object *obj; + + obj = OBJPTR(item); + + switch (obj->o_type) { + case ARMOR: + return(10-armors[obj->o_which].a_class); + when RING: + return(2); + when MM: + switch (obj->o_which) { + case MM_ELF_BOOTS: + case MM_DANCE: + /* Boots */ + return(5); + when MM_R_POWERLESS: + case MM_DISP: + case MM_PROTECT: + /* Robes */ + return(4); + when MM_BRACERS: + case MM_G_DEXTERITY: + case MM_G_OGRE: + case MM_FUMBLE: + /* Hand garments */ + return(3); + when MM_JEWEL: + case MM_ADAPTION: + case MM_STRANGLE: + /* Jewelry */ + return(2); + otherwise: + return(1); /* What is it? */ + } + otherwise: + return(1); /* What is it? */ + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/wizard.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,820 @@ +/* + wizard.c - Special wizard commands + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +/* + * Special wizard commands (some of which are also non-wizard commands + * under strange circumstances) + */ + +#include <stdlib.h> +#include <curses.h> +#include <ctype.h> +#include <string.h> +#include "rogue.h" +#include "mach_dep.h" + +/* + * create_obj: + * Create any object for wizard, scroll, magician, or cleric + */ + +create_obj(prompt, which_item, which_type) +bool prompt; +int which_item, which_type; +{ + reg struct linked_list *item; + reg struct object *obj; + reg int wh; + char *pt; + reg int ch, whc, newtype = 0, msz, newitem; + WINDOW *thiswin; + + thiswin = cw; + if (prompt) { + bool nogood = TRUE; + + thiswin = hw; + wclear(hw); + wprintw(hw,"Item\t\t\tKey\n\n"); + wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_RING].mi_name,RING, + things[TYP_STICK].mi_name,STICK); + wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_POTION].mi_name,POTION, + things[TYP_SCROLL].mi_name,SCROLL); + wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_ARMOR].mi_name,ARMOR, + things[TYP_WEAPON].mi_name,WEAPON); + wprintw(hw,"%s\t%c\n",things[TYP_MM].mi_name,MM); + wprintw(hw,"%s\t\t\t%c\n",things[TYP_FOOD].mi_name,FOOD); + if (wizard) { + wprintw(hw,"%s\t\t%c\n",things[TYP_RELIC].mi_name,RELIC); + wprintw(hw,"monster\t\t\tm"); + } + wprintw(hw,"\n\nWhat do you want to create? "); + draw(hw); + do { + ch = wgetch(hw); + if (ch == ESC) { + restscr(cw); + return; + } + switch (ch) { + case RING: + case STICK: + case POTION: + case SCROLL: + case ARMOR: + case WEAPON: + case FOOD: + case MM: + nogood = FALSE; + break; + case RELIC: + case 'm': + if (wizard) + nogood = FALSE; + break; + default: + nogood = TRUE; + } + } while (nogood); + newitem = ch; + } + else + newitem = which_item; + + pt = "those"; + msz = 0; + if(newitem == 'm') { + /* make monster and be done with it */ + wh = makemonster(TRUE, "create"); + if (wh > 0) { + creat_mons (&player, wh, TRUE); + light(&hero); + } + return; + } + if(newitem == GOLD) pt = "gold"; + else if(isatrap(newitem)) pt = "traps"; + + switch(newitem) { + case POTION: whc = TYP_POTION; msz = MAXPOTIONS; + when SCROLL: whc = TYP_SCROLL; msz = MAXSCROLLS; + when WEAPON: whc = TYP_WEAPON; msz = MAXWEAPONS; + when ARMOR: whc = TYP_ARMOR; msz = MAXARMORS; + when RING: whc = TYP_RING; msz = MAXRINGS; + when STICK: whc = TYP_STICK; msz = MAXSTICKS; + when MM: whc = TYP_MM; msz = MAXMM; + when RELIC: whc = TYP_RELIC; msz = MAXRELIC; + when FOOD: whc = TYP_FOOD; msz = MAXFOODS; + otherwise: + if (thiswin == hw) + restscr(cw); + mpos = 0; + msg("Even wizards can't create %s !!",pt); + return; + } + if(msz == 1) { /* if only one type of item */ + ch = 'a'; + } + else if (prompt) { + register struct magic_item *wmi; + char wmn; + register int ii; + int old_prob; + + mpos = 0; + wmi = NULL; + wmn = 0; + switch(newitem) { + case POTION: wmi = &p_magic[0]; + when SCROLL: wmi = &s_magic[0]; + when RING: wmi = &r_magic[0]; + when STICK: wmi = &ws_magic[0]; + when MM: wmi = &m_magic[0]; + when RELIC: wmi = &rel_magic[0]; + when FOOD: wmi = &foods[0]; + when WEAPON: wmn = 1; + when ARMOR: wmn = 2; + } + wclear(hw); + thiswin = hw; + if (wmi != NULL) { + ii = old_prob = 0; + while (ii < msz) { + if(wmi->mi_prob == old_prob && wizard == FALSE) { + msz--; /* can't make a unique item */ + } + else { + mvwaddch(hw,ii % 13,ii > 12 ? cols/2 : 0, ii + 'a'); + waddstr(hw,") "); + waddstr(hw,wmi->mi_name); + ii++; + } + old_prob = wmi->mi_prob; + wmi++; + } + } + else if (wmn != 0) { + for(ii = 0 ; ii < msz ; ii++) { + mvwaddch(hw,ii % 13,ii > 12 ? cols/2 : 0, ii + 'a'); + waddstr(hw,") "); + if(wmn == 1) + waddstr(hw,weaps[ii].w_name); + else + waddstr(hw,armors[ii].a_name); + } + } + sprintf(prbuf,"Which %s? ",things[whc].mi_name); + mvwaddstr(hw,lines - 1, 0, prbuf); + draw(hw); + do { + ch = wgetch(hw); + if (ch == ESC) { + restscr(cw); + msg(""); + return; + } + } until (isalpha(ch)); + if (thiswin == hw) /* restore screen if need be */ + restscr(cw); + newtype = ch - 'a'; + if(newtype < 0 || newtype >= msz) { /* if an illegal value */ + mpos = 0; + msg("There is no such %s",things[whc].mi_name); + return; + } + } + else + newtype = which_type; + item = new_item(sizeof *obj); /* get some memory */ + obj = OBJPTR(item); + obj->o_type = newitem; /* store the new items */ + obj->o_mark[0] = '\0'; + obj->o_which = newtype; + obj->o_group = 0; + obj->contents = NULL; + obj->o_count = 1; + obj->o_flags = 0; + obj->o_dplus = obj->o_hplus = 0; + obj->o_weight = 0; + wh = obj->o_which; + mpos = 0; + if (!wizard) /* users get 0 to +5 */ + whc = rnd(6); + else /* wizard gets to choose */ + whc = getbless(); + if (whc < 0) + obj->o_flags |= ISCURSED; + switch (obj->o_type) { + case WEAPON: + case ARMOR: + if (obj->o_type == WEAPON) { + init_weapon(obj, wh); + obj->o_hplus += whc; + if (!wizard) whc = rnd(6); + obj->o_dplus += whc; + } + else { /* armor here */ + obj->o_weight = armors[wh].a_wght; + obj->o_ac = armors[wh].a_class - whc; + } + when RING: + r_know[wh] = TRUE; + switch(wh) { + case R_ADDSTR: + case R_ADDWISDOM: + case R_ADDINTEL: + case R_PROTECT: + case R_ADDHIT: + case R_ADDDAM: + case R_DIGEST: + obj->o_ac = whc + 2; + break; + default: + obj->o_ac = 0; + } + obj->o_weight = things[TYP_RING].mi_wght; + when MM: + if (whc > 1 && m_magic[wh].mi_bless != 0) + obj->o_flags |= ISBLESSED; + m_know[wh] = TRUE; + switch(wh) { + case MM_JUG: + switch(rnd(11)) { + case 0: obj->o_ac = P_PHASE; + when 1: obj->o_ac = P_CLEAR; + when 2: obj->o_ac = P_SEEINVIS; + when 3: obj->o_ac = P_HEALING; + when 4: obj->o_ac = P_MFIND; + when 5: obj->o_ac = P_TFIND; + when 6: obj->o_ac = P_HASTE; + when 7: obj->o_ac = P_RESTORE; + when 8: obj->o_ac = P_FLY; + when 9: obj->o_ac = P_SKILL; + when 10:obj->o_ac = P_FFIND; + } + when MM_HUNGER: + case MM_CHOKE: + if (whc < 0 ) + whc = -whc; /* cannot be negative */ + obj->o_ac = (whc + 1) * 2; + break; + when MM_OPEN: + case MM_DRUMS: + case MM_DISAPPEAR: + case MM_KEOGHTOM: + if (whc < 0) + whc = -whc; /* these cannot be negative */ + obj->o_ac = (whc + 3) * 5; + break; + when MM_BRACERS: + obj->o_ac = whc + 4; + when MM_DISP: + obj->o_ac = 3; + when MM_PROTECT: + obj->o_ac = whc + 4; + when MM_SKILLS: + if (whc < 2) + obj->o_ac = rnd(NUM_CHARTYPES-1); + else + obj->o_ac = player.t_ctype; + when MM_CRYSTAL: + obj->o_ac = 1; + otherwise: + obj->o_ac = 0; + } + obj->o_weight = things[TYP_MM].mi_wght; + when STICK: + if (whc > 1 && ws_magic[wh].mi_bless != 0) + obj->o_flags |= ISBLESSED; + ws_know[wh] = TRUE; + fix_stick(obj); + when SCROLL: + if (whc > 3 && s_magic[wh].mi_bless != 0) + obj->o_flags |= ISBLESSED; + obj->o_weight = things[TYP_SCROLL].mi_wght; + s_know[wh] = TRUE; + when POTION: + if (whc > 3 && p_magic[wh].mi_bless != 0) + obj->o_flags |= ISBLESSED; + obj->o_weight = things[TYP_POTION].mi_wght; + if (wh == P_ABIL) obj->o_kind = rnd(NUMABILITIES); + p_know[wh] = TRUE; + when RELIC: + obj->o_weight = things[TYP_RELIC].mi_wght; + switch (obj->o_which) { + case QUILL_NAGROM: obj->o_charges = QUILLCHARGES; + when EMORI_CLOAK: obj->o_charges = 1; + otherwise: break; + } + when FOOD: + obj->o_weight = things[TYP_FOOD].mi_wght; + } + mpos = 0; + obj->o_flags |= ISKNOW; + if (add_pack(item, FALSE) == FALSE) { + obj->o_pos = hero; + fall(item, TRUE); + } +} + +/* + * getbless: + * Get a blessing for a wizards object + */ + +int +getbless() +{ + reg char bless; + + msg("Blessing? (+,-,n)"); + bless = wgetch(msgw); + if (bless == '+') + return (15); + else if (bless == '-') + return (-1); + else + return (0); +} + +/* + * get a non-monster death type + */ + +getdeath() +{ + register int i; + int which_death; + char label[80]; + + clear(); + for (i=0; i<DEATHNUM; i++) { + sprintf(label, "[%d] %s", i+1, deaths[i].name); + mvaddstr(i+2, 0, label); + } + mvaddstr(0, 0, "Which death? "); + refresh(); + + /* Get the death */ + for (;;) { + get_str(label, stdscr); + which_death = atoi(label); + if ((which_death < 1 || which_death > DEATHNUM)) { + mvaddstr(0, 0, "Please enter a number in the displayed range -- "); + refresh(); + } + else break; + } + return(deaths[which_death-1].reason); +} + +/* + * make a monster for the wizard + */ + +makemonster(showall, action) +bool showall; /* showall -> show uniques and genocided creatures */ +char *action; +{ + register int i; + register short which_monst; + register int num_monst = NUMMONST, pres_monst=1, num_lines=2*(lines-3); + int max_monster; + char monst_name[40]; + + /* If we're not showing all, subtract UNIQUES, DINOS, and quartermaster */ + if (!showall) num_monst -= NUMUNIQUE + NUMDINOS + 1; + max_monster = num_monst; + + /* Print out the monsters */ + + if (levtype == OUTSIDE) { + num_monst = NUMDINOS; + max_monster = NUMMONST - 1; + pres_monst = (pres_monst + NUMMONST - NUMDINOS - 1); + } + + while (num_monst > 0) { + register int left_limit; + + if (num_monst < num_lines) left_limit = (num_monst+1)/2; + else left_limit = num_lines/2; + + wclear(hw); + touchwin(hw); + + /* Print left column */ + wmove(hw, 2, 0); + for (i=0; i<left_limit; i++) { + sprintf(monst_name, "[%d] %c%s\n", + pres_monst, + (showall || monsters[pres_monst].m_normal) + ? ' ' + : '*', + monsters[pres_monst].m_name); + waddstr(hw, monst_name); + pres_monst++; + } + + /* Print right column */ + for (i=0; i<left_limit && pres_monst<=max_monster; i++) { + sprintf(monst_name, "[%d] %c%s", + pres_monst, + (showall || monsters[pres_monst].m_normal) + ? ' ' + : '*', + monsters[pres_monst].m_name); + wmove(hw, i+2, cols/2); + waddstr(hw, monst_name); + pres_monst++; + } + + if ((num_monst -= num_lines) > 0) { + mvwaddstr(hw, lines-1, 0, morestr); + draw(hw); + wait_for(' '); + } + + else { + mvwaddstr(hw, 0, 0, "Which monster"); + if (!terse) { + waddstr(hw, " do you wish to "); + waddstr(hw, action); + } + waddstr(hw, "? "); + draw(hw); + } + } + +get_monst: + get_str(monst_name, hw); + which_monst = atoi(monst_name); + if (levtype == OUTSIDE) + if ((which_monst < NUMMONST-NUMDINOS || which_monst > max_monster)) { + mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- "); + draw(hw); + goto get_monst; + } + if ((which_monst < 1 || which_monst > max_monster)) { + mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- "); + draw(hw); + goto get_monst; + } + restscr(cw); + return(which_monst); +} + +/* + * passwd: + * see if user knows password + */ + +bool +passwd() +{ + register char *sp, c; + char buf[LINELEN]; + + msg("Wizard's Password:"); + mpos = 0; + sp = buf; + while ((c = wgetch(cw)) != '\n' && c != '\r' && c != '\033') { + if (c == killchar()) + sp = buf; + else if (c == erasechar() && sp > buf) + sp--; + else + *sp++ = c; + } + if (sp == buf) + return FALSE; + *sp = '\0'; + return (strcmp(PASSWD, xcrypt(buf, "mT")) == 0); + + /* don't mess with the password here or elsewhere. + * + * If anyone goes wizard they forfeit being placed in the scorefile. + * So, no need to be secretive about it. Let them have it! + * + * Additionally, you can begin the game as wizard by starting it + * with a null argument, as in: xrogue "" + */ +} + +/* + * teleport: + * Bamf the hero someplace else + */ + +void +teleport() +{ + register struct room *new_rp = NULL, *old_rp = roomin(&hero); + register int rm, which; + coord old; + bool got_position = FALSE; + + /* Disrupt whatever the hero was doing */ + dsrpt_player(); + + /* + * If the hero wasn't doing something disruptable, NULL out his + * action anyway and let him know about it. We don't want him + * swinging or moving into his old place. + */ + if (player.t_action != A_NIL) { + player.t_action = A_NIL; + msg("You feel momentarily disoriented."); + } + + old = hero; + mvwaddch(cw, hero.y, hero.x, mvwinch(stdscr, hero.y, hero.x)); + if (ISWEARING(R_TELCONTROL) || wizard) { + got_position = move_hero(H_TELEPORT); + if (!got_position) + msg("Your attempt fails."); + else { + new_rp = roomin(&hero); + msg("You teleport successfully."); + } + } + if (!got_position) { + do { + rm = rnd_room(); + rnd_pos(&rooms[rm], &hero); + } until(winat(hero.y, hero.x) == FLOOR); + new_rp = &rooms[rm]; + } + player.t_oldpos = old; /* Save last position */ + + /* If hero gets moved, darken old room */ + if (old_rp && old_rp != new_rp) { + old_rp->r_flags |= FORCEDARK; /* Fake darkness */ + light(&old); + old_rp->r_flags &= ~FORCEDARK; /* Restore light state */ + } + + /* Darken where we just came from */ + else if (levtype == MAZELEV) light(&old); + + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + /* if entering a treasure room, wake everyone up......Surprise! */ + if (new_rp->r_flags & ISTREAS) + wake_room(new_rp); + + /* Reset current room and position */ + oldrp = new_rp; /* Used in look() */ + player.t_oldpos = hero; + /* + * make sure we set/unset the ISINWALL on a teleport + */ + which = winat(hero.y, hero.x); + if (isrock(which)) turn_on(player, ISINWALL); + else turn_off(player, ISINWALL); + + /* + * turn off ISHELD in case teleportation was done while fighting + * something that holds you + */ + if (on(player, ISHELD)) { + register struct linked_list *ip, *nip; + register struct thing *mp; + + turn_off(player, ISHELD); + hold_count = 0; + for (ip = mlist; ip; ip = nip) { + mp = THINGPTR(ip); + nip = next(ip); + if (on(*mp, DIDHOLD)) { + turn_off(*mp, DIDHOLD); + turn_on(*mp, CANHOLD); + } + turn_off(*mp, DIDSUFFOCATE); /* Suffocation -- see below */ + } + } + + /* Make sure player does not suffocate */ + extinguish(suffocate); + + count = 0; + running = FALSE; + flushinp(); +} + +/* + * whatis: + * What a certin object is + */ + +whatis(what) +struct linked_list *what; +{ + register struct object *obj; + register struct linked_list *item; + + if (what == NULL) { /* do we need to ask which one? */ + if ((item = get_item(pack, "identify", IDENTABLE, FALSE, FALSE))==NULL) + return; + } + else + item = what; + obj = OBJPTR(item); + switch (obj->o_type) { + case SCROLL: + s_know[obj->o_which] = TRUE; + if (s_guess[obj->o_which]) { + free(s_guess[obj->o_which]); + s_guess[obj->o_which] = NULL; + } + when POTION: + p_know[obj->o_which] = TRUE; + if (p_guess[obj->o_which]) { + free(p_guess[obj->o_which]); + p_guess[obj->o_which] = NULL; + } + when STICK: + ws_know[obj->o_which] = TRUE; + if (ws_guess[obj->o_which]) { + free(ws_guess[obj->o_which]); + ws_guess[obj->o_which] = NULL; + } + when RING: + r_know[obj->o_which] = TRUE; + if (r_guess[obj->o_which]) { + free(r_guess[obj->o_which]); + r_guess[obj->o_which] = NULL; + } + when MM: + /* If it's an identified jug, identify its potion */ + if (obj->o_which == MM_JUG && (obj->o_flags & ISKNOW)) { + if (obj->o_ac != JUG_EMPTY) + p_know[obj->o_ac] = TRUE; + break; + } + + m_know[obj->o_which] = TRUE; + if (m_guess[obj->o_which]) { + free(m_guess[obj->o_which]); + m_guess[obj->o_which] = NULL; + } + otherwise: + break; + } + obj->o_flags |= ISKNOW; + if (what == NULL) + msg(inv_name(obj, FALSE)); +} + +/* + * Choose a quest item + * (if on STARTLEV equipage level = 0) + */ + +choose_qst() +{ + bool doit = TRUE; + bool escp = TRUE; + + /* let wizard in on this too */ + if (waswizard == TRUE || (levtype == POSTLEV && level == 0)) { + wclear(hw); + touchwin(hw); + wmove(hw, 2, 0); + wprintw(hw, "a) Cloak of Emori\n"); + wprintw(hw, "b) Ankh of Heil\n"); + wprintw(hw, "c) Quill of Nagrom\n"); + wprintw(hw, "d) Eye of Vecna\n"); + wprintw(hw, "e) Ring of Surtur\n"); + wprintw(hw, "f) Staff of Ming\n"); + wprintw(hw, "g) Wand of Orcus\n"); + wprintw(hw, "h) Rod of Asmodeus\n"); + wprintw(hw, "i) Amulet of Yendor\n"); + wprintw(hw, "j) Amulet of Stonebones\n"); + wprintw(hw, "k) Mandolin of Brian\n"); + wprintw(hw, "l) Horn of Geryon\n"); + wprintw(hw, "m) Daggers of Musty Doit\n"); + wprintw(hw, "n) Axe of Aklad\n"); + wprintw(hw, "o) Morning Star of Hruggek\n"); + wprintw(hw, "p) Flail of Yeenoghu\n"); + wprintw(hw, "q) Card of Alteran\n"); + mvwaddstr(hw, 0, 0, "Select a quest item: "); /* prompt */ + + if (menu_overlay) /* Print the selections. The longest line is + * Hruggek (26 characters). The prompt is 21. + */ + over_win(cw, hw, 20, 29, 0, 21, NULL); + else + draw(hw); + + while (doit) { + switch (wgetch(cw)) { + case EOF: + case ESC: + escp = FALSE; /* used below */ + doit = FALSE; + when 'a': + quest_item = EMORI_CLOAK; + doit = FALSE; + when 'b': + quest_item = HEIL_ANKH; + doit = FALSE; + when 'c': + quest_item = QUILL_NAGROM; + doit = FALSE; + when 'd': + quest_item = EYE_VECNA; + doit = FALSE; + when 'e': + quest_item = SURTUR_RING; + doit = FALSE; + when 'f': + quest_item = MING_STAFF; + doit = FALSE; + when 'g': + quest_item = ORCUS_WAND; + doit = FALSE; + when 'h': + quest_item = ASMO_ROD; + doit = FALSE; + when 'i': + quest_item = YENDOR_AMULET; + doit = FALSE; + when 'j': + quest_item = STONEBONES_AMULET; + doit = FALSE; + when 'k': + quest_item = BRIAN_MANDOLIN; + doit = FALSE; + when 'l': + quest_item = GERYON_HORN; + doit = FALSE; + when 'm': + quest_item = MUSTY_DAGGER; + doit = FALSE; + when 'n': + quest_item = AXE_AKLAD; + doit = FALSE; + when 'o': + quest_item = HRUGGEK_MSTAR; + doit = FALSE; + when 'p': + quest_item = YEENOGHU_FLAIL; + doit = FALSE; + when 'q': + quest_item = ALTERAN_CARD; + doit = FALSE; + otherwise: + doit = TRUE; + } + } + if (menu_overlay) { + status(FALSE); + touchwin(cw); + if (escp == TRUE) { + msg("Your quest item is the %s. --More--", + rel_magic[quest_item].mi_name); + wait_for(' '); + } + return; + } + else { + if (escp == TRUE) { + wmove(hw, lines-4, 0); + wprintw(hw, "Your quest item is the %s.", + rel_magic[quest_item].mi_name); + } + wmove(hw, lines-1, 0); + wprintw(hw, spacemsg); + draw(hw); + wait_for(' '); + wclear(hw); + draw(hw); + wmove(cw, 0, 0); + wclrtoeol(cw); + status(FALSE); + touchwin(cw); + return; + } + } + else { + msg("You can no longer select a quest item. "); + return; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/xcrypt.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,691 @@ +/* + * FreeSec: libcrypt + * + * Copyright (C) 1994 David Burren + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name(s) of the author(s) nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * This is an original implementation of the DES and the crypt(3) interfaces + * by David Burren <davidb@werj.com.au>. + * + * An excellent reference on the underlying algorithm (and related + * algorithms) is: + * + * B. Schneier, Applied Cryptography: protocols, algorithms, + * and source code in C, John Wiley & Sons, 1994. + * + * Note that in that book's description of DES the lookups for the initial, + * pbox, and final permutations are inverted (this has been brought to the + * attention of the author). A list of errata for this book has been + * posted to the sci.crypt newsgroup by the author and is available for FTP. + * + * NOTE: + * This file has a static version of des_setkey() so that crypt.o exports + * only the crypt() interface. This is required to make binaries linked + * against crypt.o exportable or re-exportable from the USA. + */ + +#include <sys/types.h> +#include <string.h> + +#define _PASSWORD_EFMT1 '_' + +static unsigned char IP[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 +}; + +static unsigned char inv_key_perm[64]; +static unsigned char key_perm[56] = { + 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 +}; + +static unsigned char key_shifts[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +static unsigned char inv_comp_perm[56]; +static unsigned char comp_perm[48] = { + 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 +}; + +/* + * No E box is used, as it's replaced by some ANDs, shifts, and ORs. + */ + +static unsigned char u_sbox[8][64]; +static unsigned char sbox[8][64] = { + { + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 + }, + { + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 + }, + { + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 + }, + { + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 + }, + { + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 + }, + { + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 + }, + { + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 + }, + { + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 + } +}; + +static unsigned char un_pbox[32]; +static unsigned char pbox[32] = { + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 +}; + +static unsigned int bits32[32] = +{ + 0x80000000, 0x40000000, 0x20000000, 0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +static unsigned char bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + +static unsigned int saltbits; +static int old_salt; +static unsigned int *bits28, *bits24; +static unsigned char init_perm[64], final_perm[64]; +static unsigned int en_keysl[16], en_keysr[16]; +static unsigned int de_keysl[16], de_keysr[16]; +static int des_initialised = 0; +static unsigned char m_sbox[4][4096]; +static unsigned int psbox[4][256]; +static unsigned int ip_maskl[8][256], ip_maskr[8][256]; +static unsigned int fp_maskl[8][256], fp_maskr[8][256]; +static unsigned int key_perm_maskl[8][128], key_perm_maskr[8][128]; +static unsigned int comp_maskl[8][128], comp_maskr[8][128]; +static unsigned int old_rawkey0, old_rawkey1; + +static unsigned char ascii64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +/* 0000000000111111111122222222223333333333444444444455555555556666 */ +/* 0123456789012345678901234567890123456789012345678901234567890123 */ + +static __inline int +ascii_to_bin(ch) + char ch; +{ + if (ch > 'z') + return(0); + if (ch >= 'a') + return(ch - 'a' + 38); + if (ch > 'Z') + return(0); + if (ch >= 'A') + return(ch - 'A' + 12); + if (ch > '9') + return(0); + if (ch >= '.') + return(ch - '.'); + return(0); +} + +static void +des_init() +{ + int i, j, b, k, inbit, obit; + unsigned int *p, *il, *ir, *fl, *fr; + + old_rawkey0 = old_rawkey1 = 0; + saltbits = 0; + old_salt = 0; + bits24 = (bits28 = bits32 + 4) + 4; + + /* + * Invert the S-boxes, reordering the input bits. + */ + for (i = 0; i < 8; i++) + for (j = 0; j < 64; j++) { + b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf); + u_sbox[i][j] = sbox[i][b]; + } + + /* + * Convert the inverted S-boxes into 4 arrays of 8 bits. + * Each will handle 12 bits of the S-box input. + */ + for (b = 0; b < 4; b++) + for (i = 0; i < 64; i++) + for (j = 0; j < 64; j++) + m_sbox[b][(i << 6) | j] = + (u_sbox[(b << 1)][i] << 4) | + u_sbox[(b << 1) + 1][j]; + + /* + * Set up the initial & final permutations into a useful form, and + * initialise the inverted key permutation. + */ + for (i = 0; i < 64; i++) { + init_perm[final_perm[i] = IP[i] - 1] = i; + inv_key_perm[i] = 255; + } + + /* + * Invert the key permutation and initialise the inverted key + * compression permutation. + */ + for (i = 0; i < 56; i++) { + inv_key_perm[key_perm[i] - 1] = i; + inv_comp_perm[i] = 255; + } + + /* + * Invert the key compression permutation. + */ + for (i = 0; i < 48; i++) { + inv_comp_perm[comp_perm[i] - 1] = i; + } + + /* + * Set up the OR-mask arrays for the initial and final permutations, + * and for the key initial and compression permutations. + */ + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(il = &ip_maskl[k][i]) = 0; + *(ir = &ip_maskr[k][i]) = 0; + *(fl = &fp_maskl[k][i]) = 0; + *(fr = &fp_maskr[k][i]) = 0; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = init_perm[inbit]) < 32) + *il |= bits32[obit]; + else + *ir |= bits32[obit-32]; + if ((obit = final_perm[inbit]) < 32) + *fl |= bits32[obit]; + else + *fr |= bits32[obit - 32]; + } + } + } + for (i = 0; i < 128; i++) { + *(il = &key_perm_maskl[k][i]) = 0; + *(ir = &key_perm_maskr[k][i]) = 0; + for (j = 0; j < 7; j++) { + inbit = 8 * k + j; + if (i & bits8[j + 1]) { + if ((obit = inv_key_perm[inbit]) == 255) + continue; + if (obit < 28) + *il |= bits28[obit]; + else + *ir |= bits28[obit - 28]; + } + } + *(il = &comp_maskl[k][i]) = 0; + *(ir = &comp_maskr[k][i]) = 0; + for (j = 0; j < 7; j++) { + inbit = 7 * k + j; + if (i & bits8[j + 1]) { + if ((obit=inv_comp_perm[inbit]) == 255) + continue; + if (obit < 24) + *il |= bits24[obit]; + else + *ir |= bits24[obit - 24]; + } + } + } + } + + /* + * Invert the P-box permutation, and convert into OR-masks for + * handling the output of the S-box arrays setup above. + */ + for (i = 0; i < 32; i++) + un_pbox[pbox[i] - 1] = i; + + for (b = 0; b < 4; b++) + for (i = 0; i < 256; i++) { + *(p = &psbox[b][i]) = 0; + for (j = 0; j < 8; j++) { + if (i & bits8[j]) + *p |= bits32[un_pbox[8 * b + j]]; + } + } + + des_initialised = 1; +} + +static void +setup_salt(salt) + int salt; +{ + unsigned int obit, saltbit; + int i; + + if (salt == old_salt) + return; + old_salt = salt; + + saltbits = 0; + saltbit = 1; + obit = 0x800000; + for (i = 0; i < 24; i++) { + if (salt & saltbit) + saltbits |= obit; + saltbit <<= 1; + obit >>= 1; + } +} + +static int +des_setkey(key) + const char *key; +{ + unsigned int k0, k1, rawkey0, rawkey1; + int shifts, round; + + if (!des_initialised) + des_init(); + + rawkey0 = md_ntohl(*(unsigned int *) key); + rawkey1 = md_ntohl(*(unsigned int *) (key + 4)); + + if ((rawkey0 | rawkey1) + && rawkey0 == old_rawkey0 + && rawkey1 == old_rawkey1) { + /* + * Already setup for this key. + * This optimisation fails on a zero key (which is weak and + * has bad parity anyway) in order to simplify the starting + * conditions. + */ + return(0); + } + old_rawkey0 = rawkey0; + old_rawkey1 = rawkey1; + + /* + * Do key permutation and split into two 28-bit subkeys. + */ + k0 = key_perm_maskl[0][rawkey0 >> 25] + | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskl[4][rawkey1 >> 25] + | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f]; + k1 = key_perm_maskr[0][rawkey0 >> 25] + | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskr[4][rawkey1 >> 25] + | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f]; + /* + * Rotate subkeys and do compression permutation. + */ + shifts = 0; + for (round = 0; round < 16; round++) { + unsigned int t0, t1; + + shifts += key_shifts[round]; + + t0 = (k0 << shifts) | (k0 >> (28 - shifts)); + t1 = (k1 << shifts) | (k1 >> (28 - shifts)); + + de_keysl[15 - round] = + en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f] + | comp_maskl[1][(t0 >> 14) & 0x7f] + | comp_maskl[2][(t0 >> 7) & 0x7f] + | comp_maskl[3][t0 & 0x7f] + | comp_maskl[4][(t1 >> 21) & 0x7f] + | comp_maskl[5][(t1 >> 14) & 0x7f] + | comp_maskl[6][(t1 >> 7) & 0x7f] + | comp_maskl[7][t1 & 0x7f]; + + de_keysr[15 - round] = + en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f] + | comp_maskr[1][(t0 >> 14) & 0x7f] + | comp_maskr[2][(t0 >> 7) & 0x7f] + | comp_maskr[3][t0 & 0x7f] + | comp_maskr[4][(t1 >> 21) & 0x7f] + | comp_maskr[5][(t1 >> 14) & 0x7f] + | comp_maskr[6][(t1 >> 7) & 0x7f] + | comp_maskr[7][t1 & 0x7f]; + } + return(0); +} + +static int +do_des(l_in, r_in, l_out, r_out, count) + unsigned int l_in, r_in, *l_out, *r_out; + int count; +{ + /* + * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format. + */ + unsigned int l, r, *kl, *kr, *kl1, *kr1; + unsigned int f = 0, r48l, r48r; + int round; + + if (count == 0) { + return(1); + } else if (count > 0) { + /* + * Encrypting + */ + kl1 = en_keysl; + kr1 = en_keysr; + } else { + /* + * Decrypting + */ + count = -count; + kl1 = de_keysl; + kr1 = de_keysr; + } + + /* + * Do initial permutation (IP). + */ + l = ip_maskl[0][l_in >> 24] + | ip_maskl[1][(l_in >> 16) & 0xff] + | ip_maskl[2][(l_in >> 8) & 0xff] + | ip_maskl[3][l_in & 0xff] + | ip_maskl[4][r_in >> 24] + | ip_maskl[5][(r_in >> 16) & 0xff] + | ip_maskl[6][(r_in >> 8) & 0xff] + | ip_maskl[7][r_in & 0xff]; + r = ip_maskr[0][l_in >> 24] + | ip_maskr[1][(l_in >> 16) & 0xff] + | ip_maskr[2][(l_in >> 8) & 0xff] + | ip_maskr[3][l_in & 0xff] + | ip_maskr[4][r_in >> 24] + | ip_maskr[5][(r_in >> 16) & 0xff] + | ip_maskr[6][(r_in >> 8) & 0xff] + | ip_maskr[7][r_in & 0xff]; + + while (count--) { + /* + * Do each round. + */ + kl = kl1; + kr = kr1; + round = 16; + while (round--) { + /* + * Expand R to 48 bits (simulate the E-box). + */ + r48l = ((r & 0x00000001) << 23) + | ((r & 0xf8000000) >> 9) + | ((r & 0x1f800000) >> 11) + | ((r & 0x01f80000) >> 13) + | ((r & 0x001f8000) >> 15); + + r48r = ((r & 0x0001f800) << 7) + | ((r & 0x00001f80) << 5) + | ((r & 0x000001f8) << 3) + | ((r & 0x0000001f) << 1) + | ((r & 0x80000000) >> 31); + /* + * Do salting for crypt() and friends, and + * XOR with the permuted key. + */ + f = (r48l ^ r48r) & saltbits; + r48l ^= f ^ *kl++; + r48r ^= f ^ *kr++; + /* + * Do sbox lookups (which shrink it back to 32 bits) + * and do the pbox permutation at the same time. + */ + f = psbox[0][m_sbox[0][r48l >> 12]] + | psbox[1][m_sbox[1][r48l & 0xfff]] + | psbox[2][m_sbox[2][r48r >> 12]] + | psbox[3][m_sbox[3][r48r & 0xfff]]; + /* + * Now that we've permuted things, complete f(). + */ + f ^= l; + l = r; + r = f; + } + r = l; + l = f; + } + /* + * Do final permutation (inverse of IP). + */ + *l_out = fp_maskl[0][l >> 24] + | fp_maskl[1][(l >> 16) & 0xff] + | fp_maskl[2][(l >> 8) & 0xff] + | fp_maskl[3][l & 0xff] + | fp_maskl[4][r >> 24] + | fp_maskl[5][(r >> 16) & 0xff] + | fp_maskl[6][(r >> 8) & 0xff] + | fp_maskl[7][r & 0xff]; + *r_out = fp_maskr[0][l >> 24] + | fp_maskr[1][(l >> 16) & 0xff] + | fp_maskr[2][(l >> 8) & 0xff] + | fp_maskr[3][l & 0xff] + | fp_maskr[4][r >> 24] + | fp_maskr[5][(r >> 16) & 0xff] + | fp_maskr[6][(r >> 8) & 0xff] + | fp_maskr[7][r & 0xff]; + return(0); +} + +static int +des_cipher(in, out, salt, count) + const char *in; + char *out; + int salt; + int count; +{ + unsigned int l_out, r_out, rawl, rawr; + unsigned int x[2]; + int retval; + + if (!des_initialised) + des_init(); + + setup_salt(salt); + + memcpy(x, in, sizeof x); + rawl = md_ntohl(x[0]); + rawr = md_ntohl(x[1]); + retval = do_des(rawl, rawr, &l_out, &r_out, count); + + x[0] = md_htonl(l_out); + x[1] = md_htonl(r_out); + memcpy(out, x, sizeof x); + return(retval); +} + +char * +xcrypt(key, setting) + const char *key; + const char *setting; +{ + int i; + unsigned int count, salt, l, r0, r1, keybuf[2]; + unsigned char *p, *q; + static unsigned char output[21]; + + if (!des_initialised) + des_init(); + + /* + * Copy the key, shifting each character up by one bit + * and padding with zeros. + */ + q = (unsigned char *) keybuf; + while ((q - (unsigned char *) keybuf) < sizeof(keybuf)) { + if ((*q++ = *key << 1)) + key++; + } + if (des_setkey((unsigned char *) keybuf)) + return(NULL); + + if (*setting == _PASSWORD_EFMT1) { + /* + * "new"-style: + * setting - underscore, 4 bytes of count, 4 bytes of salt + * key - unlimited characters + */ + for (i = 1, count = 0; i < 5; i++) + count |= ascii_to_bin(setting[i]) << (i - 1) * 6; + + for (i = 5, salt = 0; i < 9; i++) + salt |= ascii_to_bin(setting[i]) << (i - 5) * 6; + + while (*key) { + /* + * Encrypt the key with itself. + */ + if (des_cipher((unsigned char*)keybuf, (unsigned char*)keybuf, 0, 1)) + return(NULL); + /* + * And XOR with the next 8 characters of the key. + */ + q = (unsigned char *) keybuf; + while (((q - (unsigned char *) keybuf) < sizeof(keybuf)) && + *key) + *q++ ^= *key++ << 1; + + if (des_setkey((unsigned char *) keybuf)) + return(NULL); + } + strncpy((char *)output, setting, 9); + + /* + * Double check that we weren't given a short setting. + * If we were, the above code will probably have created + * wierd values for count and salt, but we don't really care. + * Just make sure the output string doesn't have an extra + * NUL in it. + */ + output[9] = '\0'; + p = output + strlen((const char *)output); + } else { + /* + * "old"-style: + * setting - 2 bytes of salt + * key - up to 8 characters + */ + count = 25; + + salt = (ascii_to_bin(setting[1]) << 6) + | ascii_to_bin(setting[0]); + + output[0] = setting[0]; + /* + * If the encrypted password that the salt was extracted from + * is only 1 character long, the salt will be corrupted. We + * need to ensure that the output string doesn't have an extra + * NUL in it! + */ + output[1] = setting[1] ? setting[1] : output[0]; + + p = output + 2; + } + setup_salt(salt); + /* + * Do it. + */ + if (do_des(0, 0, &r0, &r1, count)) + return(NULL); + /* + * Now encode the result... + */ + l = (r0 >> 8); + *p++ = ascii64[(l >> 18) & 0x3f]; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + + l = (r0 << 16) | ((r1 >> 16) & 0xffff); + *p++ = ascii64[(l >> 18) & 0x3f]; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + + l = r1 << 2; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + *p = 0; + + return((char *)output); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/xrogue.sln Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrogue", "xrogue.vcproj", "{ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}.Debug.ActiveCfg = Debug|Win32 + {ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}.Debug.Build.0 = Debug|Win32 + {ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}.Release.ActiveCfg = Release|Win32 + {ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/xrogue.vcproj Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,278 @@ +<?xml version="1.0" encoding = "Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.00" + Name="xrogue" + ProjectGUID="{ABD49D61-EFA9-41BA-9EA1-8DE4B4FA4FF6}" + Keyword="Win32Proj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="1" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + InlineFunctionExpansion="0" + OptimizeForWindowsApplication="TRUE" + AdditionalIncludeDirectories=".." + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;PDC_STATIC_BUILD" + StringPooling="TRUE" + MinimalRebuild="TRUE" + BasicRuntimeChecks="3" + SmallerTypeCheck="TRUE" + RuntimeLibrary="5" + BufferSecurityCheck="TRUE" + EnableFunctionLevelLinking="TRUE" + DisableLanguageExtensions="FALSE" + ForceConformanceInForLoopScope="TRUE" + UsePrecompiledHeader="0" + BrowseInformation="1" + WarningLevel="4" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="4" + CompileAs="1" + DisableSpecificWarnings="4033;4716;4013;4131;4244;4201"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Ws2_32.lib pdcurses.lib" + OutputFile="$(OutDir)/xrogue.exe" + LinkIncremental="2" + SuppressStartupBanner="TRUE" + AdditionalLibraryDirectories=".." + IgnoreAllDefaultLibraries="FALSE" + IgnoreDefaultLibraryNames="LIBC.LIB" + GenerateDebugInformation="TRUE" + ProgramDatabaseFile="$(OutDir)/xrogue.pdb" + SubSystem="1" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="1" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + OmitFramePointers="TRUE" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS" + StringPooling="TRUE" + RuntimeLibrary="4" + EnableFunctionLevelLinking="TRUE" + UsePrecompiledHeader="3" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/xrogue.exe" + LinkIncremental="1" + GenerateDebugInformation="TRUE" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + </Configuration> + </Configurations> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"> + <File + RelativePath="actions.c"> + </File> + <File + RelativePath="bolt.c"> + </File> + <File + RelativePath="chase.c"> + </File> + <File + RelativePath="command.c"> + </File> + <File + RelativePath="daemon.c"> + </File> + <File + RelativePath="daemons.c"> + </File> + <File + RelativePath="eat.c"> + </File> + <File + RelativePath="effects.c"> + </File> + <File + RelativePath="encumb.c"> + </File> + <File + RelativePath="fight.c"> + </File> + <File + RelativePath="help.c"> + </File> + <File + RelativePath="init.c"> + </File> + <File + RelativePath="io.c"> + </File> + <File + RelativePath="list.c"> + </File> + <File + RelativePath="main.c"> + </File> + <File + RelativePath="maze.c"> + </File> + <File + RelativePath="misc.c"> + </File> + <File + RelativePath="mons_def.c"> + </File> + <File + RelativePath="monsters.c"> + </File> + <File + RelativePath="move.c"> + </File> + <File + RelativePath="n_level.c"> + </File> + <File + RelativePath="options.c"> + </File> + <File + RelativePath="outside.c"> + </File> + <File + RelativePath="pack.c"> + </File> + <File + RelativePath="passages.c"> + </File> + <File + RelativePath="player.c"> + </File> + <File + RelativePath="potions.c"> + </File> + <File + RelativePath="rings.c"> + </File> + <File + RelativePath="rip.c"> + </File> + <File + RelativePath="rogue.c"> + </File> + <File + RelativePath="rooms.c"> + </File> + <File + RelativePath="save.c"> + </File> + <File + RelativePath="scrolls.c"> + </File> + <File + RelativePath="state.c"> + </File> + <File + RelativePath="sticks.c"> + </File> + <File + RelativePath="things.c"> + </File> + <File + RelativePath="trader.c"> + </File> + <File + RelativePath="util.c"> + </File> + <File + RelativePath="vers.c"> + </File> + <File + RelativePath="weapons.c"> + </File> + <File + RelativePath="wear.c"> + </File> + <File + RelativePath="wizard.c"> + </File> + <File + RelativePath="xcrypt.c"> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc"> + <File + RelativePath="mach_dep.h"> + </File> + <File + RelativePath="network.h"> + </File> + <File + RelativePath="rogue.h"> + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"> + </Filter> + <File + RelativePath="LICENSE.TXT"> + </File> + <File + RelativePath="Makefile"> + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject>