# HG changeset patch # User John "Elwin" Edwards # Date 1431481179 14400 # Node ID 6b5fbd7c3ece55c7c118ecbdd36ceabc75477a4d # Parent 66b0263af4247cc0be79928abd42c2bdfe835420# Parent cc5148bdf345d2717969e36ea2b5e81910890e21 Merge arogue7 and xrogue trees. diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/LICENSE.TXT --- /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. diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/Makefile --- /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 diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/README.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. diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/actions.c --- /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 +#include +#include +#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; it_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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/bolt.c --- /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 +#include +#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; +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/chase.c --- /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 +#include +#include +#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= 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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/command.c --- /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 +#include +#include +#include +#include +#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? "); /* 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); + } +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/daemon.c --- /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 +#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()); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/daemons.c --- /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 +#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= 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) + { + 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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/eat.c --- /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 +#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; + } +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/effects.c --- /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 +#include +#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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/encumb.c --- /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 +#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; io_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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/fight.c --- /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 +#include +#include +#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; +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/help.c --- /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 +#include +#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', " 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', " Throw something", + 'T', " Take off something", + 'v', " Print program version", + 'w', " Wield a weapon", + 'W', " Wear something", + 'X', " Sense for traps", + 'z', " 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'), " 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); +} + + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/init.c --- /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 +#include +#include +#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 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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/io.c --- /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 +#include +#include +#include +#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 4) { + *error = 1; + return(0L); + } + + for (i=0; i 4) return(0); + + for (i=0; i> (8 * i)) & 0xff); + putc(outc, stream); + } + return(size); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/list.c --- /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 +#include +#include +#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; +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/mach_dep.h --- /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 diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/main.c --- /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 +#include +#include +#include +#include + +#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 +#include +#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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/misc.c --- /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 +#include +#include +#include +#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! */ + /* 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)); + + 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) { + 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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/mons_def.c --- /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 +#include +#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"}}, +}; + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/monsters.c --- /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 +#include +#include +#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; im_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; it_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)); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/move.c --- /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 +#include +#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; ir_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= 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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/n_level.c --- /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 +#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; it_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; jr_max.y-1; j++) + for (i=1; ir_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; + } +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/network.h --- /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(); + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/options.c --- /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 +#include +#include +#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; io_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; +} diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/outside.c --- /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 +#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 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; + * { + * } + */ + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/pack.c --- /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 +#include +#include +#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; io_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; io_pos = tp->t_pos; + attach(tp->t_pack, item); + } +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/passages.c --- /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 +#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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/player.c --- /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 +#include +#include +#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)); + + 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) { + 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; + } +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/potions.c --- /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 +#include +#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 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); +} diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/rings.c --- /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 +#include +#include +#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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/rip.c --- /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 +#include +#include +#include +#include +#include +#include +#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; isc_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); +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/rogue.c --- /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 +#include +#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" +} +}; + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/rogue.h --- /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 +#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]; + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/rooms.c --- /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 +#include +#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; jy, 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); + } +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/save.c --- /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 +#include +#include +#include +#include +#include +#include +#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; +} + diff -r 66b0263af424 -r 6b5fbd7c3ece xrogue/scrolls.c --- /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 +#include +#include +#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