# HG changeset patch # User John "Elwin" Edwards # Date 1431481179 14400 # Node ID 6b5fbd7c3ece55c7c118ecbdd36ceabc75477a4d # Parent 66b0263af4247cc0be79928abd42c2bdfe835420# Parent cc5148bdf345d2717969e36ea2b5e81910890e21 Merge arogue7 and xrogue trees. diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/LICENSE.TXT --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/LICENSE.TXT Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,179 @@ +Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T +Portions Copyright (C) 1984 Robert D. Kindelberger +Portions Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman +Portions Copyright (C) 2005 Nicholas J. Kisseberth +Portions Copyright (C) 1994 David Burren +All rights reserved. + +=========================================================================== + +Advanced Rogue +Copyright (C) 1984, 1985, 1986 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 Robert D. Kindelberger. +Used under license: + +Super-Rogue +Copyright (C) 1984 Robert D. Kindelberger +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 "Super-Rogue" 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 "Super-Rogue", + nor may "Super-Rogue" 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 (state.c, mdport.c) are based on the work +of Nicholas J. Kisseberth. Used under license: + +Copyright (C) 2005 Nicholas J. Kisseberth +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 (xcrypt.c) 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/Makefile Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,193 @@ +# +# Makefile for rogue +# +# Advanced Rogue +# Copyright (C) 1984, 1985, 1986 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. +# + +# +# Makefile for rogue +# + + +DISTNAME=arogue7.7.1 +PROGRAM=arogue77 + +O=o + +HDRS= rogue.h mach_dep.h network.h + +OBJS1 = vers.$(O) actions.$(O) chase.$(O) command.$(O) daemon.$(O) \ + daemons.$(O) eat.$(O) effects.$(O) encumb.$(O) fight.$(O) init.$(O) \ + io.$(O) list.$(O) main.$(O) maze.$(O) mdport.$(O) misc.$(O) \ + monsters.$(O) +OBJS2 = move.$(O) new_level.$(O) options.$(O) outside.$(O) pack.$(O) \ + passages.$(O) player.$(O) potions.$(O) rings.$(O) rip.$(O) rogue.$(O) \ + rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) things.$(O) \ + trader.$(O) util.$(O) weapons.$(O) wear.$(O) wizard.$(O) xcrypt.$(O) +OBJS = $(OBJS1) $(OBJS2) + +CFILES= vers.c actions.c chase.c command.c daemon.c \ + daemons.c eat.c effects.c encumb.c fight.c init.c \ + io.c list.c main.c maze.c mdport.c misc.c monsters.c \ + move.c new_level.c options.c outside.c pack.c \ + passages.c player.c potions.c rings.c rip.c rogue.c \ + rooms.c save.c scrolls.c state.c sticks.c things.c \ + trader.c util.c weapons.c wear.c wizard.c xcrypt.c +MISC_C= +DOCSRC= aguide.mm +DOCS = $(PROGRAM).doc $(PROGRAM).html +MISC = Makefile $(MISC_C) LICENSE.TXT $(PROGRAM).sln $(PROGRAM).vcproj $(DOCS)\ + $(DOCSRC) + +CC = gcc +ROPTS = +COPTS = -O3 +CFLAGS= $(COPTS) $(ROPTS) +LIBS = -lcurses +RM = rm -f + +.SUFFIXES: .obj + +.c.obj: + $(CC) $(CFLAGS) /c $*.c + +$(PROGRAM): $(HDRS) $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ + +clean: + $(RM) $(OBJS1) + $(RM) $(OBJS2) + $(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe $(PROGRAM).lck + $(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip + +dist.src: + make clean + tar cf $(DISTNAME)-src.tar $(CFILES) $(HDRS) $(MISC) + gzip -f $(DISTNAME)-src.tar + +doc.nroff: + tbl aguide.mm | nroff -mm | colcrt - > arogue77.doc + +doc.groff: + groff -P-c -t -mm -Tascii aguide.mm | sed -e 's/.\x08//g' > arogue77.doc + groff -t -mm -Thtml aguide.mm > arogue77.ht + +dist.irix: + make clean + make CC=cc COPTS="-woff 1116 -O3" $(PROGRAM) + tar cf $(DISTNAME)-irix.tar $(PROGRAM) LICENSE.TXT $(DOCS) + gzip -f $(DISTNAME)-irix.tar + +dist.aix: + make clean + make CC=xlc COPTS="-qmaxmem=16768 -O3 -qstrict" $(PROGRAM) + tar cf $(DISTNAME)-aix.tar $(PROGRAM) LICENSE.TXT $(DOCS) + gzip -f $(DISTNAME)-aix.tar + +dist.linux: + make clean + make $(PROGRAM) + tar cf $(DISTNAME)-linux.tar $(PROGRAM) LICENSE.TXT $(DOCS) + gzip -f $(DISTNAME)-linux.tar + +dist.interix: + @$(MAKE) clean + @$(MAKE) COPTS="-ansi" $(PROGRAM) + tar cf $(DISTNAME)-interix.tar $(PROGRAM) LICENSE.TXT $(DOCS) + gzip -f $(DISTNAME)-interix.tar + +dist.cygwin: + @$(MAKE) --no-print-directory clean + @$(MAKE) --no-print-directory $(PROGRAM) + tar cf $(DISTNAME)-cygwin.tar $(PROGRAM).exe LICENSE.TXT $(DOCS) + gzip -f $(DISTNAME)-cygwin.tar + +# +# Use MINGW32-MAKE to build this target +# +dist.mingw32: + @$(MAKE) --no-print-directory RM="cmd /c del" clean + @$(MAKE) --no-print-directory LIBS="-lpdcurses" $(PROGRAM) + cmd /c del $(DISTNAME)-mingw32.zip + zip $(DISTNAME)-mingw32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS) + +dist.msys: + @$(MAKE) --no-print-directory clean + @$(MAKE) --no-print-directory LIBS="-lcurses" $(PROGRAM) + tar cf $(DISTNAME)-msys.tar $(PROGRAM).exe LICENSE.TXT $(DOCS) + gzip -f $(DISTNAME)-msys.tar + +dist.djgpp: + @$(MAKE) --no-print-directory clean + @$(MAKE) --no-print-directory LDFLAGS="-L$(DJDIR)/LIB" \ + LIBS="-lpdcurses" $(PROGRAM) + rm -f $(DISTNAME)-djgpp.zip + zip $(DISTNAME)-djgpp.zip $(PROGRAM).exe LICENSE.TXT $(DOCS) + +# +# Use NMAKE to build this targer +# +dist.win32: + @$(MAKE) /NOLOGO O="obj" RM="-del" clean + @$(MAKE) /NOLOGO O="obj" CC="CL" \ + LIBS="..\pdcurses\pdcurses.lib shfolder.lib user32.lib Advapi32.lib" \ + COPTS="-nologo -I..\pdcurses \ + -Ox -wd4033 -wd4716" $(PROGRAM) + -del $(DISTNAME)-win32.zip + zip $(DISTNAME)-win32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS) + + +actions.o: rogue.h +chase.o: rogue.h +command.o: rogue.h +command.o: mach_dep.h +daemon.o: rogue.h +daemons.o: rogue.h +eat.o: rogue.h +edit.o: mach_dep.h +edit.o: rogue.h +effects.o: rogue.h +encumb.o: rogue.h +fight.o: rogue.h +init.o: rogue.h +init.o: mach_dep.h +io.o: rogue.h +list.o: rogue.h +main.o: mach_dep.h +main.o: network.h +main.o: rogue.h +maze.o: rogue.h +misc.o: rogue.h +monsters.o: rogue.h +move.o: rogue.h +new_level.o: rogue.h +options.o: rogue.h +outside.o: rogue.h +pack.o: rogue.h +passages.o: rogue.h +player.o: rogue.h +potions.o: rogue.h +rings.o: rogue.h +rip.o: mach_dep.h +rip.o: network.h +rip.o: rogue.h +rogue.o: rogue.h +rooms.o: rogue.h +save.o: rogue.h +save.o: mach_dep.h +scrolls.o: rogue.h +sticks.o: rogue.h +things.o: rogue.h +trader.o: rogue.h +util.o: rogue.h +weapons.o: rogue.h +wear.o: rogue.h +wizard.o: rogue.h diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/actions.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/actions.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,982 @@ +/* + * actions.c - functions for dealing with monster actions + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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 "curses.h" +#include "rogue.h" +#define MAXINT INT_MAX +#define MININT INT_MIN +/* + * 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 anyway */ + if (action == C_CAST) + spell_power += magic_spells[which].s_cost; + else if (action == C_PRAY) + pray_time += cleric_spells[which].s_cost; + else if (action == C_CHANT) + chant_time += druid_spells[which].s_cost; + } + 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(10)+1); + purse -= obj->o_count; + obj->o_pos = hero; + fall(item, FALSE); + } while (purse > 0 && rnd(10) != 1); + } + } + when C_EAT: + msg("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("Oww....You decide to stop searching."); + count = 0; /* don't search again */ + + when C_SETTRAP: + msg("Oww....You can't get a trap set."); + + when A_NIL: + default: + return; + } + player.t_no_move = movement(&player); /* disoriented for a while */ + player.t_action = A_NIL; + player.t_selection = 0; + player.t_using = NULL; +} + +/* + * 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 player still next to us? */ + if (ce(tp->t_newpos, hero)) sell(tp); + + /* The darned player 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))) + 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); + } + + /* 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; + + 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 -- sets "monst_dead" if it kills someone */ + shoot_bolt(tp, tp->t_pos, tp->t_newpos, FALSE, + tp->t_index, breath, damage); + + running = FALSE; + if (fight_flush) md_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 = MININT; + int mindist = MAXINT, maxdist = MININT; + 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 = CCHAR( 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) + dch = CCHAR( 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 = CCHAR( 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 == MININT) { + /* 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 = NULL; /* No more door goal */ + } + + /* Indicate that we do not want to flee from the door */ + if (dist != MININT) flee = FALSE; + } + else th->t_doorgoal = 0; /* 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; + static 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 = 150; + if (save(VS_BREATH, &player, -3)) + damage /= 2; + msg ("%s's sonic blast hits you", prname(monster_name(tp), TRUE)); + if ((pstats.s_hpt -= damage) <= 0) + death(tp->t_index); + + running = FALSE; + if (fight_flush) md_flushinp(); + dsrpt_player(); +} + +/* + * m_spell: + * The monster casts a spell. Currently this is limited to + * magic missile. + */ +m_spell(tp) +register struct thing *tp; +{ + static 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) md_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; + struct linked_list *weapon; + 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 (on(*prey, ISINWALL) || + ((shoot_dir = can_shoot(er, ee)) == 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, er, ee, dist, shoot_dir)) { + return(TRUE); + } + + /* From now on, we must have a direct shot at the prey */ + if (shoot_dir == NULL) 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) && + (weapon = get_hurl(tp))) { + tp->t_newpos = *shoot_dir; /* Save the direction */ + tp->t_action = A_THROW; /* We're going to throw something */ + tp->t_using = weapon; /* 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); + +} + +/* + * 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; + register 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 = next(item)) { + tp = THINGPTR(item); + turn_on(*tp, ISREADY); + } + + for (;;) { + + for (item = mlist; item != NULL; item = next(item)) { + tp = THINGPTR(item); + + if (on(*tp, ISREADY)) + break; + } + + if (item == NULL) + break; + + turn_off(*tp, ISREADY); + + /* 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)); + } + + /* Too bad -- try again later */ + else 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, monst_pos, defend_pos, dist, shoot_dir) +register struct thing *monster; +register coord *monst_pos, *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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/aguide.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/aguide.mm Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,799 @@ +.\" +.\" aguide.mm +.\" +.\" Advanced Rogue +.\" Copyright (C) 1984, 1985, 1986 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. +.\" +.tr ~ +.nr Pt 1 +.ds HF 3 2 2 2 2 2 2 +.TL +The Dungeons of Doom +.AF Toolchest +.AU " " +.AS 1 +.P +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. +.P +The version of Rogue described in this guide has been expanded to include +over 110 monsters with many new capabilities. +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. +The player chooses a character class at the beginning of the game which +defines the player's abilities. +Experience, rather than gold, decides the player's score. +.AE +.MT 4 +.H 1 INTRODUCTION +Rogue is a screen-oriented fantasy game set in the ever-changing +\fIDungeons of Doom\fR. +The game comes complete with monsters, spells, weapons, armor, potions, +and other magical items. +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. +.P +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 items found +in the dungeon. +To make things interesting, the player has a quest to return one of +several unique artifacts, rumored to lie deep in the dungeon's bowels. +Returning with this artifact brings great glory and the title of +\fIComplete Winner\fR. +But even after finding the artifact, the player may wish to continue +further to match wits with an \fIarch-devil\fR, \fIdemon prince\fR, or even a +\fIdeity\fR found far down in the dungeon. +Defeating such a creature will gain the player many experience points, +the basis for scoring in Rogue. +.P +It is very difficult to return from the \fIDungeons of Doom\fR. +Few people ever make it out alive. +Should this unlikely event occur, the player would be proclaimed a +complete winner and handsomely rewarded for any booty removed from the +dungeon. +.H 1 "CHARACTER CLASSES" +Before placing the player in the dungeon, the game requests the player +to select what type of character they would like to be:~ a fighter, a magic user, a cleric, +a druid, a thief, a paladin, a ranger, a monk, or an assassin. +.H 2 "The Fighter" +A fighter is very strong and will have a high strength rating. +This great strength gives a fighter the best odds of +winning a battle with a monster. +At high experience levels the \fIfighter\fR also gets to attack +multiple times in a single turn. +This obviously further increases his chances at winning battles. +Intrinsic to the fighter class is a robustness which results in +1 to 12 extra hit points for every new experience +level. +.H 2 "The Magician" +A Magician is able to "cast" spells. +The number and variety of spells increases as +the magician gains experience and intelligence. +Magic users are not as hearty as fighters; +they receive 1 to 6 extra hit +points for every new experience level. +.H 2 "The Cleric" +A cleric is able to "pray" to his god for help. +The number and variety of prayers which the gods are willing to grant to +a cleric increase as the cleric gains experience and wisdom. +.P +Because of their religious nature, clerics can also affect the "undead" +beings, like \fIzombies\fR and \fIghouls\fR, which became monsters after they +died. +If an "undead" creature is next to a cleric, the cleric may try +to turn it and cause it to flee. +If the cleric is sufficiently powerful relative to the monster, +the cleric will destroy it. +This ability increases as the character gains experience levels. +.P +Clerics can gain from 1 to 8 extra hit points on +reaching a new experience level. +.H 2 "The Druid" +The druid is a cleric of sorts but worships nature rather than a god. +The druid is able to "chant" and thereby recieve certain types +of spells. Most of the chants are targeted more towards the +elements and nature. +.P +Druids gain from 1 to 8 hit points when they gain an experience level. +.H 2 "The Thief" +A thief is exceptionally dextrous and has a good chance to +set a trap or rob a monster. +.P +By their nature, thieves can automatically detect all the gold on the +current level of the dungeon. +They are also good at detecting hidden traps. +Because thieves slink along, they are not as likely as other characters +to wake sleeping monsters. +If a \fIthief\fR manages to sneak up on a creature without waking it, he +will get a chance to \fIbackstab\fR the monster. When this is done, +the damage done by the \fIthief\fR greatly increases based on his experience +level. +.P +Thieves gain from 1 to 6 extra hit points from a new experience level. +.H 2 "The Paladin" +The paladin is a type of holy warrior. Somewhat of a cross between a +fighter and a cleric. He is able to pray and turn undead as a cleric, +(but to a lesser degree) but fights as a fighter. He is on the side of +all that is good and righteous. Therefore he would never attack a +creature that would not attack him first. If he does kill a non-violent +creature inadvertantly he will feel "uneasy" and his god may retaliate +by making him a mere fighter. +.P +Paladins gain 1 to 10 hit points per experience level. +.H 2 "The Ranger" +The ranger is somewhat of a cross between a druid and a fighter. He +too is on the side of righteousness and good. Therefore, the same +same restrictions apply to his as they do to a paladin. The ranger +can "chant" and "cast" but to a lesser degree than the druid and +magician. +.P +Rangers gain 1 to 8 hit points per experience level. +.H 2 "The Monk" +The Monk is a martial arts expert. He wears no armor but has +an effective armor class based on his ability to dodge attacks. +He does not need a weapon in combat for his hands and feet are +a formidable weapon. His ability to dodge and use his hands +as weapons increases as he gains in level. +.P +Monks gain 1 to 6 hit points per experience level. +.H 2 "The Assassin" +The assassin is a person trained in the art of killing people +by surprise. He has most of the abilities of the thief except +the "backstab". Instead, the assassin has the chance to kill +an opponent outright with one strike. He is also a ruthless +character and trained in the use of poison. He can recognize +poison on sight and can coat his weapon with it thereby making +his next attack an exceptionally lethal one. +.P +Assassins gain 1 to 6 hit points per experience level. +.H 1 "ATTRIBUTES" +.H 2 "Intelligence" +Intelligence is the primary attribute associated with casting +spells. With higher intelligence comes the knowledge of more +spells, the ability to cast more spells, and faster recovery +of spells that have been cast. +.H 2 "Strength" +This is, of course, the measure of a character's physical strength. +With higher strength a character can carry more, cause more damage +when striking, have a better chance to strike an opponent, and +move about more quickly when carrying a load. +.H 2 "Wisdom" +Wisdom is the primary attribute associated with Praying +to a god. With higher wisdom comes the knowledge of more +prayers, the ability to pray more often, and faster recovery +of prayer ability. +.H 2 "Dexterity" +Dexterity is a measure of a character's agility. With higher dexterity +a character is harder to hit, can hit a opponent more easily, and +can move about more quickly when carrying a load. +.H 2 Constitution +Every character has a constitution rating. +A character with an exceptionally good constitution will gain more than +the normal amount of hit points associated with the character's class +when the character reaches a new experience level. Exceptional constitution +also provides better protection versus poison-based attacks and diseases. +.H 2 "Charisma" +Charisma is a measure of a characters looks and general likeableness. +It effects transactions when trying to purchase things. +.H 2 "Experience Levels" +Characters gain experience for killing monsters, stealing from monsters, +and turning monsters. +Each character class has a set of thresholds associated with it. +When a character reaches a threshold, the character attains the next +experience level. +This new level brings extra hit points and a greater chance of success +in performing the abilities associated with the character's class. +For example, magicians receive new spells, and clerics receive new prayers. +.P +.H 2 "Allocating Attributes" +The player starts with 72 "attribute points" to create a character and +can distribute them in any manner among the six attributes described +above. +When prompting the player for each attribute, the game displays the +minimum and maximum allowable values for that attribute. +The player can type a backspace (control-H) to go back and change +a value; typing an escape (ESC) sets the remaining attributes to +the maximum value possible given the remaining attribute points. +.H 1 "THE SCREEN" +During the normal course of play, the screen consists of three separate +sections:~ the top line of the terminal, the bottom two lines of the +terminal, and the remaining middle lines. +The top line reports actions which occur during the game, the middle +section depicts the dungeon, and the bottom lines describe the player's +current condition. +.H 2 "The Top Line" +Whenever anything happens to the player, such as finding a scroll or +hitting or being hit by a monster, a short report of the occurrence +appears on the top line of the screen. +When such reports occur quickly, one right after another, +the game displays the notice followed by the prompt '\(emMore\(em.'~ +After reading this notice, the player can press a space to display +the next message. +At such a point, the game ignores all commands until the player presses +a space. +.H 2 "The Dungeon Section" +The large middle section of the screen displays the player's surroundings using +the following symbols: +.tr ~~ +.VL 10 +.LI | +A wall of a room. +.LI - +A wall of a room. +.LI * +A pile of gold. +.LI % +A way to the next level. +.LI + +A doorway. +.LI . +The floor in a room. +.LI @ +The player. +.LI _ +The player, when invisible. +.LI # +The floor in a passageway. +.LI ! +A flask containing a potion. +.LI ? +A sealed scroll. +.LI : +Some food. +.LI ) +A weapon. +.LI \ +Solid rock (denoted by a space). +.LI ] +Some armor. +.LI ; +A miscellaneous magic item +.LI , +An artifact +.LI = +A ring. +.LI / +A wand or a staff. +.LI ^ +The entrance to a trading post +.LI > +A trapdoor leading to the next level +.LI { +An arrow trap +.LI $ +A sleeping gas trap +.LI } +A beartrap +.LI ~ +A trap that teleports you somewhere else +.LI \` +A poison dart trap +.LI \fR"\fR +A shimmering magic pool +.LI \' +An entrance to a maze +.LI $ +Any magical item. (During magic detection) +.LI > +A blessed magical item. (During magic detection) +.LI < +A cursed magical item. (During magic detection) +.LI A\ letter +A monster. +Note that a given letter may signify multiple monsters, +depending on the level of the dungeon. +The player can always identify a current monster by using +the identify command ('\fB/\fR'). +.LE +.tr ~ +.H 2 "The Status Section" +The bottom two lines of the screen describe the player's current status. +The first line gives the player's characteristics: +.BL +.LI +Intelligence (\fBInt\fR) +.LI +Strength (\fBStr\fR) +.LI +Wisdom (\fBWis\fR) +.LI +Dexterity (\fBDxt\fR) +.LI +Constitution (\fBConst\fR) +.LI +Charisma (\fBChar\fR) +.LI +Encumberance (\fBCarry\fR) +.LE +.P +Intelligence, strength, wisdom, dexterity, charisma, and constitution have a +normal maximum of 25, but can be higher when 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 causes you to use more food. +.P +The second status line provides the following information: +.BL +.LI +The current level (\fBLvl\fR) in the dungeon. This number increases as the +player goes further down. +.LI +The player's current number of hit points (\fBHp\fR), followed in parentheses +by the player's current maximum number of hit points. +Hit points express the player's health. +As a player heals by resting, the player's current hit points gradually +increase until reaching the current maximum. +This maximum increases each time a player attains a new experience level. +If the player's current hit points reach 0, the player dies. +.LI +The player's armor class (\fBAc\fR). +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. +The protection level increases as the armor class decreases. +.LI +The player's current experience level (\fBExp\fR) followed by the player's +experience points. +The player can gain experience points by killing monsters, successfully +stealing from monsters, and turning monsters. +When a player gains enough experience points to surpass a threshold that +depends on the player's character type, the player reaches a new +experience level. +A new experience level brings extra hit points and possibly added +abilities, such as a new spell for a magician or a new prayer for +a cleric. +.LI +A description of the player's character. +This description depends on the player's character type and experience +level. +.LE +.H 1 COMMANDS +A player can invoke most Rogue commands by typing a single character. +Some commands, however, require a direction, in which case the player +types the command character followed by a directional command. +Many commands can be prefaced by a number, indicating how many times +the command should be executed. +.P +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 should then type the letter associated with the item, as +displayed by the \fBinventory\fR command. +Typing a '*' at this point produces a list of the eligible items. +.P +Rogue understands the following commands:~ +.VL 4 +.LI ? +Preceding a command by a '\fB?\fR' produces a brief explanation of the command. +The command '\fB?*\fR' gives an explanation of all the commands. +.LI / +Preceding a symbol by a '\fB/\fR' identifies the symbol. +.LI = +Clarify. +After typing an '\fB=\fR' 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, Rogue will +identify whatever is at that space. +Examples include a \fIsleeping giant rat\fR, a \fIblue potion\fR, and a \fIfood +ration\fR. +.LI h +Move one position to the left. +.LI j +Move one position down. +.LI k +Move one position up. +.LI l +Move one position to the right. +.LI y +Move one position to the top left. +.LI u +Move one position to the top right. +.LI b +Move one position to the bottom left. +.LI n +Move one position to the bottom right. +.LI H +Run to the left until reaching something interesting. +.LI J +Run down until reaching something interesting. +.LI K +Run up until reaching something interesting. +.LI L +Run to the right until reaching something interesting. +.LI Y +Run to the top left until reaching something interesting. +.LI U +Run to the top right until reaching something interesting. +.LI B +Run to the bottom left until reaching something interesting. +.LI N +Run to the bottom right until reaching something interesting. +.LI t +This command prompts for an object from the players pack. +The player then \fBt\fRhrows the object in the specified direction. +.LI f +When this command precedes a directional command, the player moves +in the specified direction until passing something interesting. +.LI z +This command prompts for a wand or staff from the player's pack and +\fBz\fRaps it in the specified direction. +.LI > +Go down to the next level. +.LI < +Go up to the next level. +.LI s +\fBS\fRearch for a secret door or a trap in the circle surrounding the player. +.LI . +This command (a dot) causes the player to rest a turn. +.LI i +Display an \fBi\fRnventory of the player's pack. +.LI I +This command prompts for an item from the player's pack and displays +the \fBi\fRnventory information for that item. +.LI q +\fBQ\fRuaff a potion from the player's pack. +.LI r +\fBR\fRead a scroll from the player's pack. +.LI e +\fBE\fRat some food from the player's pack. +.LI w +\fBW\fRield a weapon from the player's pack. +.LI W +\fBW\fRear some armor, ring, or miscellaneous magic item from the player's pack. +The player can wear a maximum of eight rings. +.LI T +\fBT\fRake off whatever the player is wearing. +.LI ^U +\fBU\fRse a magic item in the player's pack. +.LI d +\fBD\fRrop an item from the player's pack. +.LI P +\fBP\fRick up the items currently under the player. +.LI ^N +When the player types this command, Rogue prompts for a monster or an item +from the player's pack and a one-line \fBn\fRame. +For monsters, the player can use the movement keys to position the cursor +over the desired monster, and Rogue will use the given \fBn\fRame to refer +to that monster. +For items, Rogue gives all similar items (such as all the blue potions) +the specified \fBn\fRame. +.LI m +When the player types this command, Rogue prompts for an item from the +player's pack and a one-line name. +Rogue then \fBm\fRarks the specified item with the given name. +.LI o +Typing this command causes Rogue to display all the settable \fBo\fRptions. +The player can then merely examine the options or change any or all of them. +.LI C +This command, restricted to magicians and rangers +produces a listing of the current supply of spells. +The player can select one of the displayed spells and, if the player's +energy level is sufficiently high, \fBC\fRast it. +The more complicated the spell, the more energy it takes. +.LI c +This command, restricted to druids and rangers +produces a listing of the current supply of chants. +The player can select one of the displayed chants and, if the player's +energy level is sufficiently high, \fBc\fRhant it. +The more complicated the spell, the more energy it takes. +.LI p +This command, restricted to clerics and paladins, +produces a listing of the character's known \fBp\fRrayers. +The player can then offer one of these prayers to the character's deity. +Deities are not known for favoring characters which continually pray +to them, and they are most likely to answer the least "ambitious" prayers. +.LI a +This command is restricted to clerics and paladins +must be followed by a directional command. +If there is an "undead" monster standing next to the player in the +specified direction, there is a chance the player will \fBa\fRffect the +monster by causing it to flee or possibly even destroying it. +.LI * +Count the gold in the player's pack. +.LI ^ +This command sets a trap and is limited to thieves and assassins. +If the character is successful, Rogue prompts the player for a type of trap +and sets it where the player is standing. +.LI G +This command is restricted to thieves and assassins. +It causes Rogue to display all the gold on the current level. +.LI D +\fBD\fRip something into a magic pool. +.LI ^T +This command is restricted to thieves and assassins. +It must be followed by a directional command. +If there is a monster standing next to the player in the specified direction, +the player tries to \fBs\fRteal an item from the monster's pack. +If the player is successful, the monster does not notice anything, but if +the player is unsuccessful, there is a chance the monster will wake up. +.LI ^L +Redraw the screen. +.LI ^R +\fBR\fRepeat the last message that was displayed on the top line of the screen. +.LI ^[ +Typing an escape will usually cause Rogue to cancel the current command. +.LI v +Print the current Rogue \fBv\fRersion number. +.LI ! +Escape to the shell. +.LI S +Quit and \fBs\fRave the game for resumption at a later time. +.LI Q +\fBQ\fRuit without saving the game. +.LE +.H 1 "IMPLICIT COMMANDS" +There is no "attack" command. +If a player wishes to attack a monster, the player simply tries to +move onto the spot where the monster is standing. +The game then assumes that the player wishes to attack the monster +with whatever weapon the player is wielding. +.P +When the player moves onto an item, the game automatically places the +object into the player's pack. +If there is no room left in the pack, the game announces that fact and +leaves the item on the floor. +.H 1 TIME +All actions except for purely 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 a space varies with the type +of armor worn. +Movement is always faster when flying. +.P +Since actions take time, 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. +Of course, the same rule applies when the player hits a monster. +.P +Magical hasting (or slowing) will decrease (or increase) the time it takes +to perform an action. +.H 1 LIGHT +Some rooms in the dungeon possess a natural light source. +In other rooms and in corridors the player can see only those things +within a one space radius from the player. +These dark rooms can be lit with magical light or by a \fIfire beetle\fR. +.H 1 "WEAPONS AND ARMOR" +The player can wield exactly one weapon at a time. +When the player attacks a monster, the amount of damage depends on the +particular weapon the player 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. +.P +A weapon may be cursed or blessed, affecting the likelihood of hitting a +monster with the weapon and the damage the weapon will inflict on the monster. +If the player has identified a weapon, the "to hit" and "to damage" bonuses +appear in that order before the weapon's name in an inventory listing. +A positive bonus indicates a blessed weapon, and a negative bonus usually +indicates a cursed weapon. +The player cannot release a cursed weapon. +.P +Without any armor the player has an armor class of 10. +The lower the player's armor class, the harder it is for a monster to hit +the player, so +wearing armor can improve the player's armor class. +A cursed suit of armor, however, offers poor protection and may sometimes be +worse than no armor at all. +.P +After the player has identified a suit of armor, the protection bonus appears +before the armor's name in an inventory listing. +If the bonus is positive the armor is blessed, and if it is negative, the +armor is usually cursed. +The player cannot remove a cursed suit of armor. +.P +Some monsters can corrode armor when they hit it. +If such a monster hits the player when the player is wearing metal armor, +the armor loses some of its protection value, but the corrosion does not +curse the armor. +This corrosive property can also apply to weapons when the player hits +such a monster. +.H 1 "POTIONS AND SCROLLS" +The player can frequently find potions and scrolls in the dungeon. +In any given dungeon, the player can distinguish among the different types +of potions by a potion's color and among the different types of scrolls +by a scroll's name. +Quaffing a potion or reading a scroll usually causes some magical occurrence. +Most potions and scrolls may be cursed or blessed. +.H 1 RINGS +The player can wear a maximum of eight rings, and +they 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. +Many rings can be cursed or blessed, and the player cannot remove a +cursed ring. +The player can distinguish among different types of rings by a ring's jewel. +.H 1 "WANDS AND STAVES" +Wands and staves affect the player's environment. +The player can zap a wand or staff at something and perhaps shoot a bolt +of lightning at it or teleport it away. +All wands or staves of the same type are constructed with the same type of wood. +Some wands and staves may be cursed or blessed. +.H 1 FOOD +The player must be careful not to run out of food since moving through the +dungeon fighting monsters consumes a lot of energy. +Starving results in the player's fainting for increasingly longer periods +of time, during which any nearby monster can attack the player freely. +.P +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. +.H 1 GOLD +Gold has one use in a dungeon:~ buying things. +One can buy things in two ways, either in a \fItrading post\fR or from a +\fIquartermaster\fR. +A trading post is a place that sometimes occurs "between levels" of the +dungeon and can be entered by stepping on the entrance. +A quartermaster is a person who will sometimes appear and +will try to sell the player some of his wares. +These wares are never cursed and frequently blessed, though blessed goods +cost more than normal goods. +If the player chooses to buy one of the quartermaster's items, the +quartermaster trades the item for the specified amount of gold and +disappears. +Attacking a quartermaster causes him to vanish without offering +a trade. +.P +The player starts the game in a trading post with a class-dependent allotment +of gold. +Although there are restrictions on the use of some items (eg. only fighters, +paladins, and rangers can wield two-handed swords), the market will happily +sell the player anything that he can afford. + +.H 1 "MISCELLANEOUS MAGIC ITEMS" +Miscellaneous items such as a pair of boots or a book may be found within the +dungeon. +These items can usually be used to the 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. +.H 1 "ARTIFACTS" +Some monsters down in the depths of the dungeon carry unique artifacts. +The game begins as a quest to retrieve one of these items. +Each artifact appears only on its owner's person. +These items also can usually be used to the player's advantage. However, +care must be taken when handling them for they are intelligent and will +reject mishandling or abuse. These items consume food and merely carrying +them will result in increased food use. +.H 1 TRAPS +A variety of traps, including trap doors, bear traps, and sleeping traps, are +hidden in the dungeon. +They remain hidden until sprung by a monster or the player. +A sprung trap continues to function, but since it is visible, an intelligent +monster is not likely to tread on it. +.H 1 "THE MONSTERS" +Each monster except for the merchant \fIquartermaster\fR appears in +a limited range of dungeon levels. +All monsters of the same type share the same abilities; +all \fIgiant rats\fR, for example, can give the player a disease, and +all \fIjackalweres\fR can put the player to sleep. +Monsters of the same type can vary, however, such that one \fIkobold\fR +may be much more difficult to kill than another one. +In general, the more difficult it is to kill a monster, the more +experience points the monster is worth. +.P +Most monsters attack by biting and clawing, but some monsters carry +weapons, including such projectile weapons as short bows and crossbows, +and some monsters have breath weapons. +Some monsters even use magical items, such as wands. +Monsters with distance weapons or magic can attack the player from across a room +or down a corridor. +.P +Some monsters are more intelligent than others, and the more intelligent +a monster, the more likely that the monster will run away if it is about +to die. +A fleeing monster will not attack the player unless cornered. +.P +It is sometimes possible to enlist a monster's aid. +Reading a \fIcharm monster\fR scroll, for example, or singing a \fIcharm +monster\fR chant can make a monster believe the player is its friend. +A charmed monster will fight hostile monsters for the player as long as they are +not of its race. +.P +As the player moves down in the dungeon, the monsters get more powerful. +Deep down in the dungeon there exist some one-of-a-kind monsters. +These monsters are greatly feared. +However, once a "unique monster" is killed, the player will not find +another in the current dungeon. +.H 1 OPTIONS +Rogue has several options which may be set by the player:~ +.VL 7 +.LI \fBterse\fR +Setting this Boolean option results in shorter messages appearing on +the top line of the screen. +.LI \fBjump\fR +Setting this Boolean option results in waiting until the player has +finished running to draw the player's path. +Otherwise the game always displays the path one step at a time. +.LI \fBstep\fR +Setting this Boolean option results in most listings, such as an inventory, +appearing one item at a time on the top line of the screen. +When this option is not set, the game clears the screen, displays the +list, and then redraws the dungeon. +.LI \fBflush\fR +Setting this Boolean option results in flushing all typeahead (pending) commands +when the player encounters a monster. +.LI \fBaskme\fR +Setting this Boolean option results in the game prompting the player for a +name upon encountering a new type of scroll, potion, ring, staff, or wand. +.LI \fBpickup\fR +This option specifys whether items should be picked up automatically as the +rogue steps over them. +In the non-automatic mode, the player may still pick up items via the +pickup (P) command. +The option defaults to true. +.LI \fBname\fR +This string is the player's name and defaults to the player's account name. +.LI \fBfile\fR +This string, which defaults to rogue.save, specifies the file to use for +saving the game. +.LI \fBscore\fR +This string identifies the top-twenty score file to use for the game. +.LI \fBclass\fR +This option specifies the character class of the rogue. +It can be set only in the ROGUEOPTS environment variable. +.LI \fBquested~item\fR +.br +This option is set by the game at the start and cannot be reset by the player. +It is merely listed to remind the player of his quest. +.LE +.P +The player can set options at the beginning of a game via the ROGUEOPTS +environment variable. +Naming a Boolean option sets it, and preceding the Boolean option name by +"no" clears it. +The syntax "stringoption=name" sets a string option to "name."~ +So setting ROGUEOPTS to +"terse, jump, nostep, flush, askme, name=Ivan~the~Terrible" +would set the \fIterse, jump, flush\fR, and \fIaskme\fR Boolean options, +clear the \fIstep\fR Boolean option, set the player's +\fIname\fR to "Ivan the Terrible," and use the defaults for +the \fIsave file\fR and the \fIscore file\fR. +.P +The player may change an option at any time during the game +via the \fBoption\fR command, which results in a listing of +the current options. +Typing a new value changes the option, a RETURN moves to the +next option, a '-' moves to the previous option, and an ESCAPE +returns the player to the dungeon. +.H 1 SCORING +The player receives experience points for stealing items from +monsters, turning monsters (a clerical ability), and killing +monsters. +When the player gets killed, the player's score equals the player's +experience points. +A player who quits gets a score equal to the player's experience +points and gold. +If the player makes it back up out of the dungeon, the player's +score equals the player's experience points plus the gold the +player carried and the gold received from selling the player's +possessions. +.P +Rogue maintains a list of the top twenty scores to date, together +with the name of the player obtaining the score, the level where +the player finished, and the manner in which the player ended the +game. +As an installation option, the game may record only one entry per +character type and login; +this restriction encourages a greater number of different players +in the scorechart. +.H 1 ACKNOWLEDGEMENTS +This version of Rogue is based on a version developed at the +University of California. diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/arogue77.doc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/arogue77.doc Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1122 @@ + + + + + + + The Dungeons of Doom + + Toolchest + + + + + + + 1. INTRODUCTION + + Rogue is a screen-oriented fantasy game set in the + ever-changing Dungeons of Doom. The game comes complete + with monsters, spells, weapons, armor, potions, and other + magical items. 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 + items found in the dungeon. To make things interesting, the + player has a quest to return one of several unique + artifacts, rumored to lie deep in the dungeon's bowels. + Returning with this artifact brings great glory and the + title of Complete Winner. But even after finding the + artifact, the player may wish to continue further to match + wits with an arch-devil, demon prince, or even a deity found + far down in the dungeon. Defeating such a creature will + gain the player many experience points, the basis for + scoring in Rogue. + + It is very difficult to return from the Dungeons of + Doom. Few people ever make it out alive. Should this + unlikely event occur, the player would be proclaimed a + complete winner and handsomely rewarded for any booty + removed from the dungeon. + + + 2. CHARACTER CLASSES + + Before placing the player in the dungeon, the game + requests the player to select what type of character they + would like to be: a fighter, a magic user, a cleric, a + druid, a thief, a paladin, a ranger, a monk, or an assassin. + + 2.1 The Fighter + + A fighter is very strong and will have a high strength + rating. This great strength gives a fighter the best odds + of winning a battle with a monster. At high experience + + + + + + + + + - 2 - + + + + levels the fighter also gets to attack multiple times in a + single turn. This obviously further increases his chances + at winning battles. Intrinsic to the fighter class is a + robustness which results in 1 to 12 extra hit points for + every new experience level. + + 2.2 The Magician + + A Magician is able to "cast" spells. The number and + variety of spells increases as the magician gains experience + and intelligence. Magic users are not as hearty as + fighters; they receive 1 to 6 extra hit points for every new + experience level. + + 2.3 The Cleric + + A cleric is able to "pray" to his god for help. The + number and variety of prayers which the gods are willing to + grant to a cleric increase as the cleric gains experience + and wisdom. + + Because of their religious nature, clerics can also + affect the "undead" beings, like zombies and ghouls, which + became monsters after they died. If an "undead" creature is + next to a cleric, the cleric may try to turn it and cause it + to flee. If the cleric is sufficiently powerful relative to + the monster, the cleric will destroy it. This ability + increases as the character gains experience levels. + + Clerics can gain from 1 to 8 extra hit points on + reaching a new experience level. + + 2.4 The Druid + + The druid is a cleric of sorts but worships nature + rather than a god. The druid is able to "chant" and thereby + recieve certain types of spells. Most of the chants are + targeted more towards the elements and nature. + + Druids gain from 1 to 8 hit points when they gain an + experience level. + + 2.5 The Thief + + A thief is exceptionally dextrous and has a good chance + to set a trap or rob a monster. + + By their nature, thieves can automatically detect all + the gold on the current level of the dungeon. They are also + good at detecting hidden traps. Because thieves slink + along, they are not as likely as other characters to wake + sleeping monsters. If a thief manages to sneak up on a + creature without waking it, he will get a chance to backstab + the monster. When this is done, the damage done by the thief + + + + + + + + + - 3 - + + + + greatly increases based on his experience level. + + Thieves gain from 1 to 6 extra hit points from a new + experience level. + + 2.6 The Paladin + + The paladin is a type of holy warrior. Somewhat of a + cross between a fighter and a cleric. He is able to pray and + turn undead as a cleric, (but to a lesser degree) but fights + as a fighter. He is on the side of all that is good and + righteous. Therefore he would never attack a creature that + would not attack him first. If he does kill a non-violent + creature inadvertantly he will feel "uneasy" and his god may + retaliate by making him a mere fighter. + + Paladins gain 1 to 10 hit points per experience level. + + 2.7 The Ranger + + The ranger is somewhat of a cross between a druid and a + fighter. He too is on the side of righteousness and good. + Therefore, the same same restrictions apply to his as they + do to a paladin. The ranger can "chant" and "cast" but to a + lesser degree than the druid and magician. + + Rangers gain 1 to 8 hit points per experience level. + + 2.8 The Monk + + The Monk is a martial arts expert. He wears no armor + but has an effective armor class based on his ability to + dodge attacks. He does not need a weapon in combat for his + hands and feet are a formidable weapon. His ability to dodge + and use his hands as weapons increases as he gains in level. + + Monks gain 1 to 6 hit points per experience level. + + 2.9 The Assassin + + The assassin is a person trained in the art of killing + people by surprise. He has most of the abilities of the + thief except the "backstab". Instead, the assassin has the + chance to kill an opponent outright with one strike. He is + also a ruthless character and trained in the use of poison. + He can recognize poison on sight and can coat his weapon + with it thereby making his next attack an exceptionally + lethal one. + + Assassins gain 1 to 6 hit points per experience level. + + + 3. ATTRIBUTES + + + + + + + + + + - 4 - + + + + 3.1 Intelligence + + Intelligence is the primary attribute associated with + casting spells. With higher intelligence comes the knowledge + of more spells, the ability to cast more spells, and faster + recovery of spells that have been cast. + + 3.2 Strength + + This is, of course, the measure of a character's + physical strength. With higher strength a character can + carry more, cause more damage when striking, have a better + chance to strike an opponent, and move about more quickly + when carrying a load. + + 3.3 Wisdom + + Wisdom is the primary attribute associated with Praying + to a god. With higher wisdom comes the knowledge of more + prayers, the ability to pray more often, and faster recovery + of prayer ability. + + 3.4 Dexterity + + Dexterity is a measure of a character's agility. With + higher dexterity a character is harder to hit, can hit a + opponent more easily, and can move about more quickly when + carrying a load. + + 3.5 Constitution + + Every character has a constitution rating. A character + with an exceptionally good constitution will gain more than + the normal amount of hit points associated with the + character's class when the character reaches a new + experience level. Exceptional constitution also provides + better protection versus poison-based attacks and diseases. + + 3.6 Charisma + + Charisma is a measure of a characters looks and general + likeableness. It effects transactions when trying to + purchase things. + + 3.7 Experience Levels + + Characters gain experience for killing monsters, + stealing from monsters, and turning monsters. Each + character class has a set of thresholds associated with it. + When a character reaches a threshold, the character attains + the next experience level. This new level brings extra hit + points and a greater chance of success in performing the + abilities associated with the character's class. For + example, magicians receive new spells, and clerics receive + + + + + + + + + - 5 - + + + + new prayers. + + 3.8 Allocating Attributes + + The player starts with 72 "attribute points" to create + a character and can distribute them in any manner among the + six attributes described above. When prompting the player + for each attribute, the game displays the minimum and + maximum allowable values for that attribute. The player can + type a backspace (control-H) to go back and change a value; + typing an escape (ESC) sets the remaining attributes to the + maximum value possible given the remaining attribute points. + + + 4. THE SCREEN + + During the normal course of play, the screen consists + of three separate sections: the top line of the terminal, + the bottom two lines of the terminal, and the remaining + middle lines. The top line reports actions which occur + during the game, the middle section depicts the dungeon, and + the bottom lines describe the player's current condition. + + 4.1 The Top Line + + Whenever anything happens to the player, such as + finding a scroll or hitting or being hit by a monster, a + short report of the occurrence appears on the top line of + the screen. When such reports occur quickly, one right + after another, the game displays the notice followed by the + prompt '--More--.' After reading this notice, the player + can press a space to display the next message. At such a + point, the game ignores all commands until the player + presses a space. + + 4.2 The Dungeon Section + + The large middle section of the screen displays the + player's surroundings using the following symbols: + + | A wall of a room. + + - A wall of a room. + + * A pile of gold. + + % A way to the next level. + + + A doorway. + + . The floor in a room. + + @ The player. + + + + + + + + + + - 6 - + + + + _ The player, when invisible. + + # The floor in a passageway. + + ! A flask containing a potion. + + ? A sealed scroll. + + : Some food. + + ) A weapon. + + Solid rock (denoted by a space). + + ] Some armor. + + ; A miscellaneous magic item + + , An artifact + + = A ring. + + / A wand or a staff. + + ^ The entrance to a trading post + + > 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) + + A letter A monster. Note that a given letter may signify + multiple monsters, depending on the level of the + dungeon. The player can always identify a current + monster by using the identify command ('/'). + + + + + + + + + + + - 7 - + + + + 4.3 The Status Section + + The bottom two lines of the screen describe the + player's current status. The first line gives the player's + characteristics: + + o Intelligence (Int) + + o Strength (Str) + + o Wisdom (Wis) + + o Dexterity (Dxt) + + o Constitution (Const) + + o Charisma (Char) + + o Encumberance (Carry) + + Intelligence, strength, wisdom, dexterity, charisma, + and constitution have a normal maximum of 25, but can be + higher when 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 causes you to use more food. + + The second status line provides the following + information: + + o The current level (Lvl) in the dungeon. This number + increases as the player goes further down. + + o The player's current number of hit points (Hp), + followed in parentheses by the player's current maximum + number of hit points. Hit points express the player's + health. As a player heals by resting, the player's + current hit points gradually increase until reaching + the current maximum. This maximum increases each time + a player attains a new experience level. If the + player's current hit points reach 0, the player dies. + + o The player's armor class (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. The protection + level increases as the armor class decreases. + + o The player's current experience level (Exp) followed by + the player's experience points. The player can gain + experience points by killing monsters, successfully + stealing from monsters, and turning monsters. When a + player gains enough experience points to surpass a + + + + + + + + + - 8 - + + + + threshold that depends on the player's character type, + the player reaches a new experience level. A new + experience level brings extra hit points and possibly + added abilities, such as a new spell for a magician or + a new prayer for a cleric. + + o A description of the player's character. This + description depends on the player's character type and + experience level. + + + 5. COMMANDS + + A player can invoke most Rogue commands by typing a + single character. Some commands, however, require a + direction, in which case the player types the command + character followed by a directional command. 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 should then type the + letter associated with the item, as displayed by the + inventory command. Typing a '*' at this point produces a + list of the eligible items. + + Rogue understands the following commands: + + ? Preceding a command by a '?' produces a brief + explanation of the command. The command '?*' gives an + explanation of all the commands. + + / 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, Rogue will identify whatever is + at that space. Examples include a sleeping giant rat, a + blue potion, and a food ration. + + 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. + + + + + + + + + + - 9 - + + + + 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. + + t This command prompts for an object from the players + pack. The player then throws the object in the + specified direction. + + f When this command precedes a directional command, the + player moves in the specified direction until passing + something interesting. + + z This command prompts for a wand or staff from the + player's pack and zaps it in the specified direction. + + > Go down to the next level. + + < Go up to the next level. + + s Search for a secret door or a trap in the circle + surrounding the player. + + . This command (a dot) causes the player to rest a turn. + + 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. + + q Quaff a potion from the player's pack. + + r Read a scroll from the player's pack. + + + + + + + + + + + - 10 - + + + + e Eat some food from the player's pack. + + w Wield a weapon from the player's pack. + + W Wear some armor, ring, or miscellaneous magic item from + the player's pack. The player can wear a maximum of + eight rings. + + T Take off whatever the player is wearing. + + ^U Use a magic item in the player's pack. + + d Drop an item from the player's pack. + + P Pick up the items currently under the player. + + ^N When the player types this command, Rogue prompts for a + monster or an item from the player's pack and a one-line + name. For monsters, the player can use the movement + keys to position the cursor over the desired monster, + and Rogue will use the given name to refer to that + monster. For items, Rogue gives all similar items (such + as all the blue potions) the specified name. + + m When the player types this command, Rogue prompts for an + item from the player's pack and a one-line name. Rogue + then marks the specified item with the given name. + + o Typing this command causes Rogue to display all the + settable options. The player can then merely examine + the options or change any or all of them. + + C This command, restricted to magicians and rangers + produces a listing of the current supply of 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 + takes. + + c This command, restricted to druids and rangers produces + a listing of the current supply of 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 + takes. + + p This command, restricted to clerics and paladins, + produces a listing of the character's known prayers. + The player can then offer one of these prayers to the + character's deity. Deities are not known for favoring + characters which continually pray to them, and they are + most likely to answer the least "ambitious" prayers. + + + + + + + + + + + - 11 - + + + + a This command is restricted to clerics and paladins must + be followed by a directional command. If there is an + "undead" monster standing next to the player in the + specified direction, there is a chance the player will + affect the monster by causing it to flee or possibly + even destroying it. + + * Count the gold in the player's pack. + + ^ This command sets a trap and is limited to thieves and + assassins. If the character is successful, Rogue + prompts the player for a type of trap and sets it where + the player is standing. + + G This command is restricted to thieves and assassins. It + causes Rogue to display all the gold on the current + level. + + D Dip something into a magic pool. + + ^T This command is restricted to thieves and assassins. It + must be followed by a directional command. If there is + a monster standing next to the player in the specified + direction, the player tries to steal an item from the + monster's pack. If the player is successful, the + monster does not notice anything, but if the player is + unsuccessful, there is a chance the monster will wake + up. + + ^L Redraw the screen. + + ^R Repeat the last message that was displayed on the top + line of the screen. + + ^[ Typing an escape will usually cause Rogue to cancel the + current command. + + v Print the current Rogue version number. + + ! Escape to the shell. + + S Quit and save the game for resumption at a later time. + + Q Quit without saving the game. + + + 6. IMPLICIT COMMANDS + + There is no "attack" command. If a player wishes to + attack a monster, the player simply tries to move onto the + spot where the monster is standing. The game then assumes + that the player wishes to attack the monster with whatever + weapon the player is wielding. + + + + + + + + + + - 12 - + + + + When the player moves onto an item, the game + automatically places the object into the player's pack. If + there is no room left in the pack, the game announces that + fact and leaves the item on the floor. + + + 7. TIME + + All actions except for purely 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 a space varies with the type of armor worn. + Movement is always faster when flying. + + Since actions take time, 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. Of course, + the same rule applies when the player hits a monster. + + Magical hasting (or slowing) will decrease (or + increase) the time it takes to perform an action. + + + 8. LIGHT + + Some rooms in the dungeon possess a natural light + source. In other rooms and in corridors the player can see + only those things within a one space radius from the player. + These dark rooms can be lit with magical light or by a fire + beetle. + + + 9. WEAPONS AND ARMOR + + The player can wield exactly one weapon at a time. + When the player attacks a monster, the amount of damage + depends on the particular weapon the player 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, affecting the + likelihood of hitting a monster with the weapon and the + damage the weapon will inflict on the monster. If the + player has identified a weapon, the "to hit" and "to damage" + bonuses appear in that order before the weapon's name in an + inventory listing. A positive bonus indicates a blessed + weapon, and a negative bonus usually indicates a cursed + weapon. The player cannot release a cursed weapon. + + + + + + + + + - 13 - + + + + Without any armor the player has an armor class of 10. + The lower the player's armor class, the harder it is for a + monster to hit the player, so wearing armor can improve the + player's armor class. A cursed suit of armor, however, + offers poor protection and may sometimes be worse than no + armor at all. + + After the player has identified a suit of armor, the + protection bonus appears before the armor's name in an + inventory listing. If the bonus is positive the armor is + blessed, and if it is negative, the armor is usually cursed. + The player cannot remove a cursed suit of armor. + + Some monsters can corrode armor when they hit it. If + such a monster hits the player when the player is wearing + metal armor, the armor loses some of its protection value, + but the corrosion does not curse the armor. This corrosive + property can also apply to weapons when the player hits such + a monster. + + + 10. POTIONS AND SCROLLS + + The player can frequently find potions and scrolls in + the dungeon. In any given dungeon, the player can + distinguish among the different types of potions by a + potion's color and among the different types of scrolls by a + scroll's name. Quaffing a potion or reading a scroll + usually causes some magical occurrence. Most potions and + scrolls may be cursed or blessed. + + + 11. RINGS + + The player can wear a maximum of eight rings, and they + 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. Many rings can + be cursed or blessed, and the player cannot remove a cursed + ring. The player can distinguish among different types of + rings by a ring's jewel. + + + 12. WANDS AND STAVES + + Wands and staves affect the player's environment. The + player can zap a wand or staff at something and perhaps + shoot a bolt of lightning at it or teleport it away. All + wands or staves of the same type are constructed with the + same type of wood. Some wands and staves may be cursed or + blessed. + + + + + + + + + + + + - 14 - + + + + 13. FOOD + + The player must be careful not to run out of food since + moving through the dungeon fighting monsters consumes a lot + of energy. Starving results in the player's fainting for + increasingly longer periods of time, during which any nearby + monster can attack the player freely. + + 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. + + + 14. GOLD + + Gold has one use in a dungeon: buying things. One can + buy things in two ways, either in a trading post or from a + quartermaster. A trading post is a place that sometimes + occurs "between levels" of the dungeon and can be entered by + stepping on the entrance. A quartermaster is a person who + will sometimes appear and will try to sell the player some + of his wares. These wares are never cursed and frequently + blessed, though blessed goods cost more than normal goods. + If the player chooses to buy one of the quartermaster's + items, the quartermaster trades the item for the specified + amount of gold and disappears. Attacking a quartermaster + causes him to vanish without offering a trade. + + The player starts the game in a trading post with a + class-dependent allotment of gold. Although there are + restrictions on the use of some items (eg. only fighters, + paladins, and rangers can wield two-handed swords), the + market will happily sell the player anything that he can + afford. + + + + 15. MISCELLANEOUS MAGIC ITEMS + + Miscellaneous items such as a pair of boots or a book + may be found within the dungeon. These items can usually be + used to the 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. + + + 16. ARTIFACTS + + Some monsters down in the depths of the dungeon carry + unique artifacts. The game begins as a quest to retrieve + one of these items. Each artifact appears only on its + owner's person. These items also can usually be used to the + player's advantage. However, care must be taken when + handling them for they are intelligent and will reject + + + + + + + + + - 15 - + + + + mishandling or abuse. These items consume food and merely + carrying them will result in increased food use. + + + 17. TRAPS + + A variety of traps, including trap doors, bear traps, + and sleeping traps, are hidden in the dungeon. They remain + hidden until sprung by a monster or the player. A sprung + trap continues to function, but since it is visible, an + intelligent monster is not likely to tread on it. + + + 18. THE MONSTERS + + Each monster except for the merchant 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 can vary, however, such that one kobold may be + much more difficult to kill than another one. 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, including such projectile weapons as + short bows and crossbows, and some monsters have breath + weapons. Some monsters even use magical items, such as + wands. Monsters with distance weapons or magic can attack + the player from across a room or down a corridor. + + Some monsters are more intelligent than others, and the + more intelligent a monster, the more likely that the monster + will run away if it is about to die. A fleeing monster will + not attack the player unless cornered. + + It is sometimes possible to enlist a monster's aid. + Reading a charm monster scroll, for example, or singing a + charm monster chant can make a monster believe the player is + its friend. A charmed monster will fight hostile monsters + for the player as long as they are not of its race. + + As the player moves down in the dungeon, the monsters + get more powerful. Deep down in the dungeon there exist + some one-of-a-kind monsters. These monsters are greatly + feared. However, once a "unique monster" is killed, the + player will not find another in the current dungeon. + + + 19. OPTIONS + + Rogue has several options which may be set by the + player: + + + + + + + + + - 16 - + + + + terse Setting this Boolean option results in shorter + messages appearing on the top line of the screen. + + jump Setting this Boolean option results in waiting until + the player has finished running to draw the player's + path. Otherwise the game always displays the path + one step at a time. + + step Setting this Boolean option results in most listings, + such as an inventory, appearing one item at a time on + the top line of the screen. When this option is not + set, the game clears the screen, displays the list, + and then redraws the dungeon. + + flush Setting this Boolean option results in flushing all + typeahead (pending) commands when the player + encounters a monster. + + askme Setting this Boolean option results in the game + prompting the player for a name upon encountering a + new type of scroll, potion, ring, staff, or wand. + + pickup This option specifys whether items should be picked + up automatically as the rogue steps over them. In + the non-automatic mode, the player may still pick up + items via the pickup (P) command. The option + defaults to true. + + name This string is the player's name and defaults to the + player's account name. + + file This string, which defaults to rogue.save, specifies + the file to use for saving the game. + + score This string identifies the top-twenty score file to + use for the game. + + class This option specifies the character class of the + rogue. It can be set only in the ROGUEOPTS + environment variable. + + quested item + This option is set by the game at the start and + cannot be reset by the player. It is merely listed + to remind the player of his quest. + + The player can set options at the beginning of a game + via the ROGUEOPTS environment variable. Naming a Boolean + option sets it, and preceding the Boolean option name by + "no" clears it. The syntax "stringoption=name" sets a + string option to "name." So setting ROGUEOPTS to "terse, + jump, nostep, flush, askme, name=Ivan the Terrible" would + set the terse, jump, flush, and askme Boolean options, clear + the step Boolean option, set the player's name to "Ivan the + + + + + + + + + - 17 - + + + + Terrible," and use the defaults for the save file and the + score file. + + The player may change an option at any time during the + game via the option command, which results in a listing of + the current options. Typing a new value changes the option, + a RETURN moves to the next option, a '-' moves to the + previous option, and an ESCAPE returns the player to the + dungeon. + + + 20. SCORING + + The player receives experience points for stealing + items from monsters, turning monsters (a clerical ability), + and killing monsters. When the player gets killed, the + player's score equals the player's experience points. A + player who quits gets a score equal to the player's + experience points and gold. If the player makes it back up + out of the dungeon, the player's score equals the player's + experience points plus the gold the player carried and the + gold received from selling the player's possessions. + + Rogue maintains a list of the top twenty scores to + date, together with the name of the player obtaining the + score, the level where the player finished, and the manner + in which the player ended the game. As an installation + option, the game may record only one entry per character + type and login; this restriction encourages a greater number + of different players in the scorechart. + + + 21. ACKNOWLEDGEMENTS + + This version of Rogue is based on a version developed + at the University of California. + + + + + + + + + + + + + + + + + + + + + + + diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/arogue77.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/arogue77.html Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1328 @@ + + + + + + + + + + + + + +

The Dungeons of Doom

+
+

Toolchest

+

http://roguelike.sourceforge.net/arogue77

+
+ + + + + + + +
+ Advanced Rogue
+ Copyright (C) 1984, 1985, 1986 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.

+ +

1. Introduction

+ +

+ Rogue is a screen-oriented fantasy game set in the + ever-changing Dungeons of Doom. The game comes complete + with monsters, spells, weapons, armor, potions, and other + magical items. 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 + items found in the dungeon. To make things interesting, the + player has a quest to return one of several unique + artifacts, rumored to lie deep in the dungeon's bowels. + Returning with this artifact brings great glory and the + title of Complete Winner. But even after finding the + artifact, the player may wish to continue further to match + wits with an arch-devil, demon prince, or even a deity found + far down in the dungeon. Defeating such a creature will + gain the player many experience points, the basis for + scoring in Rogue. +

+ +

+ It is very difficult to return from the Dungeons of + Doom. Few people ever make it out alive. Should this + unlikely event occur, the player would be proclaimed a + complete winner and handsomely rewarded for any booty + removed from the dungeon. +

+ +

2. Character Classes

+ +

+ Before placing the player in the dungeon, the game + requests the player to select what type of character they + would like to be: a fighter, a magic user, a cleric, a + druid, a thief, a paladin, a ranger, a monk, or an assassin. +

+ +

2.1 The Fighter

+ +

+ A fighter is very strong and will have a high strength + rating. This great strength gives a fighter the best odds + of winning a battle with a monster. At high experience + levels the fighter also gets to attack multiple times in a + single turn. This obviously further increases his chances + at winning battles. Intrinsic to the fighter class is a + robustness which results in 1 to 12 extra hit points for + every new experience level. +

+ +

2.2 The Magician

+ +

+ A Magician is able to "cast" spells. The number and + variety of spells increases as the magician gains experience + and intelligence. Magic users are not as hearty as + fighters; they receive 1 to 6 extra hit points for every new + experience level.

+ +

2.3 The Cleric

+ +

+ A cleric is able to "pray" to his god for help. The + number and variety of prayers which the gods are willing to + grant to a cleric increase as the cleric gains experience + and wisdom. +

+ +

+ Because of their religious nature, clerics can also + affect the "undead" beings, like zombies and ghouls, which + became monsters after they died. If an "undead" creature is + next to a cleric, the cleric may try to turn it and cause it + to flee. If the cleric is sufficiently powerful relative to + the monster, the cleric will destroy it. This ability + increases as the character gains experience levels. +

+ +

+ Clerics can gain from 1 to 8 extra hit points on + reaching a new experience level.

+ +

2.4 The Druid

+ +

+ The druid is a cleric of sorts but worships nature + rather than a god. The druid is able to "chant" and thereby + recieve certain types of spells. Most of the chants are + targeted more towards the elements and nature. +

+ +

+ Druids gain from 1 to 8 hit points when they gain an + experience level. +

+ +

2.5 The Thief

+ +

+ A thief is exceptionally dextrous and has a good chance + to set a trap or rob a monster. +

+ +

+ By their nature, thieves can automatically detect all + the gold on the current level of the dungeon. They are also + good at detecting hidden traps. Because thieves slink + along, they are not as likely as other characters to wake + sleeping monsters. If a thief manages to sneak up on a + creature without waking it, he will get a chance to backstab + the monster. When this is done, the damage done by the thief + greatly increases based on his experience level. +

+ +

+ Thieves gain from 1 to 6 extra hit points from a new + experience level. +

+ +

2.6 The Paladin

+ +

+ The paladin is a type of holy warrior. Somewhat of a + cross between a fighter and a cleric. He is able to pray and + turn undead as a cleric, (but to a lesser degree) but fights + as a fighter. He is on the side of all that is good and + righteous. Therefore he would never attack a creature that + would not attack him first. If he does kill a non-violent + creature inadvertantly he will feel "uneasy" and his god may + retaliate by making him a mere fighter. +

+ +

+ Paladins gain 1 to 10 hit points per experience level. +

+ +

2.7 The Ranger

+ +

+ The ranger is somewhat of a cross between a druid and a + fighter. He too is on the side of righteousness and good. + Therefore, the same same restrictions apply to his as they + do to a paladin. The ranger can "chant" and "cast" but to a + lesser degree than the druid and magician. +

+ +

+ Rangers gain 1 to 8 hit points per experience level. +

+ +

2.8 The Monk

+ +

+ The Monk is a martial arts expert. He wears no armor + but has an effective armor class based on his ability to + dodge attacks. He does not need a weapon in combat for his + hands and feet are a formidable weapon. His ability to dodge + and use his hands as weapons increases as he gains in level. +

+ +

+ Monks gain 1 to 6 hit points per experience level. +

+ +

2.9 The Assassin

+ +

+ The assassin is a person trained in the art of killing + people by surprise. He has most of the abilities of the + thief except the "backstab". Instead, the assassin has the + chance to kill an opponent outright with one strike. He is + also a ruthless character and trained in the use of poison. + He can recognize poison on sight and can coat his weapon + with it thereby making his next attack an exceptionally + lethal one. +

+ +

+ Assassins gain 1 to 6 hit points per experience level. +

+ +

3. ATTRIBUTES

+ +

3.1 Intelligence

+ +

Intelligence is the primary attribute associated with + casting spells. With higher intelligence comes the knowledge + of more spells, the ability to cast more spells, and faster + recovery of spells that have been cast. + +

+ +

3.2 Strength

+

This is, of course, the measure of a character's + physical strength. With higher strength a character can + carry more, cause more damage when striking, have a better + chance to strike an opponent, and move about more quickly + when carrying a load. + +

+

3.3 Wisdom

+

Wisdom is the primary attribute associated with Praying + to a god. With higher wisdom comes the knowledge of more + prayers, the ability to pray more often, and faster recovery + of prayer ability. + +

+

3.4 Dexterity

+

Dexterity is a measure of a character's agility. With + higher dexterity a character is harder to hit, can hit a + opponent more easily, and can move about more quickly when + carrying a load. + +

+

3.5 Constitution

+

Every character has a constitution rating. A character + with an exceptionally good constitution will gain more than + the normal amount of hit points associated with the + character's class when the character reaches a new + experience level. Exceptional constitution also provides + better protection versus poison-based attacks and diseases. + +

+

3.6 Charisma

+

Charisma is a measure of a characters looks and general + likeableness. It effects transactions when trying to + purchase things.

+ +

3.7 Experience Levels

+ +

+Characters gain experience for killing monsters, +stealing from monsters, and turning monsters. Each +character class has a set of thresholds associated with it. +When a character reaches a threshold, the character attains +the next experience level. This new level brings extra hit +points and a greater chance of success in performing the +abilities associated with the character's class. For +example, magicians receive new spells, and clerics receive +new prayers. +

+ +

+ +3.8 Allocating Attributes +

+

+The player starts with 72 "attribute points" to create +a character and can distribute them in any manner among the +six attributes described above. When prompting the player +for each attribute, the game displays the minimum and +maximum allowable values for that attribute. The player can +type a backspace (control-H) to go back and change a value; +typing an escape (ESC) sets the remaining attributes to the +maximum value possible given the remaining attribute points. +

+ +

+4.0 +THE SCREEN

+

+During the normal course of play, the screen consists +of three separate sections: the top line of the terminal, +the bottom two lines of the terminal, and the remaining +middle lines. The top line reports actions which occur +during the game, the middle section depicts the dungeon, and +the bottom lines describe the player's current condition. +

+ +

4.1 The Top Line + +

+Whenever anything happens to the player, such as +finding a scroll or hitting or being hit by a monster, a +short report of the occurrence appears on the top line of +the screen. When such reports occur quickly, one right +after another, the game displays the notice followed by the +prompt '--More--.' After reading this notice, the player +can press a space to display the next message. At such a +point, the game ignores all commands until the player +presses a space. +

+ +

+4.2 The Dungeon Section

+The large middle section of the screen displays the +player's surroundings using the following symbols: +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
|     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 player.
_ The player, when invisible.
# The floor in a passageway
! A flask containing a potion.
? A sealed scroll.
: Some food.
) A weapon.
  Solid rock (denoted by a space)
] Some armor.
; A miscellaneous magic item.
, An artifact.
= A ring.
/ A wand or a staff.
^ The entrance to a trading post.
> 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. (Duriing magic detection)
< A cursed magical item. (During magic detection)
A letter A monster. Note that a given letter may signify
+ multiple monsters, depending on the level of the
+ dungeon. The player can always identify a current
+ monster by using the identify command ('/').
+

+ +

4.3 The Status Section

+ +

+The bottom two lines of the screen describe the +player's current status. The first line gives the player's +characteristics: +

+ +
    +
  • +

    Intelligence (Int)

  • +
  • +

    Strength (Str)

  • +
  • +

    Wisdom (Wis)

  • +
  • +

    Dexterity (Dxt)

  • +
  • +

    Constitution (Const)

  • +
  • +

    Charisma (Char)

  • +
  • +

    Encumberance (Carry)

  • +
+ +

+Intelligence, strength, wisdom, dexterity, charisma, +and constitution have a normal maximum of 25, but can be +higher when 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 causes you to use more food. +

+ +

+The second status line provides the following +information: +

+ +
    +
  • +

    The current level (Lvl) in the dungeon. This number +increases as the player goes further down. +

  • +
  • +

    The player's current number of hit points (Hp), +followed in parentheses by the player's current maximum +number of hit points. Hit points express the player's +health. As a player heals by resting, the player's +current hit points gradually increase until reaching +the current maximum. This maximum increases each time +a player attains a new experience level. If the +player's current hit points reach 0, the player dies. +

  • +
  • +

    The player's armor class (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. The protection +level increases as the armor class decreases. +

  • +
  • +

    The player's current experience level (Exp) followed by +the player's experience points. The player can gain +experience points by killing monsters, successfully +stealing from monsters, and turning monsters. When a +player gains enough experience points to surpass a +threshold that depends on the player's character type, +the player reaches a new experience level. A new +experience level brings extra hit points and possibly +added abilities, such as a new spell for a magician or +a new prayer for a cleric. +

  • +
  • +

    A description of the player's character. This +description depends on the player's character type and +experience level. +

  • +
+ +

5.0 COMMANDS

+ +

+A player can invoke most Rogue commands by typing a +single character. Some commands, however, require a +direction, in which case the player types the command +character followed by a directional command. 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 should then type the +letter associated with the item, as displayed by the +inventory command. Typing a '*' at this point produces a +list of the eligible items. +

+ +

Rogue understands the following commands:

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
?   Preceding a command by a '?' produces a brief explanation of the + command. The command '?*' gives an explanation of all the commands.
/ 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, Rogue will identify + whatever is at that space. Examples include a sleeping giant rat, a blue + potion, and a food ration.
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
t This command prompts for an object from the players pack. The player +then throws the object in the specified direction.
f When this command is preceded with a directional command, the player + moves in the specified direction until passing something interesting.
z This command prompts for a wand or staff from the player's pack and + zaps +it in the specified direction.
> Go down to the next level.
< Go up to the next level.
s Search for a secret door or a trap in the circle surrounding the + player.
. This command (a dot) causes the player to rest a turn.
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.
q Quaff a potion from the player's pack.
r Read a scroll from the player's pack.
e Eat some food from the player's pack.
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.
T Take off whatever the player is wearing.
^U Use a magic item in the player's pack.
d Drop an item from the player's pack.
P Pick up the items currently under the player.
^N When the player types this command, Rogue prompts for a monster or + an item from the player's pack and a one-line name. For monsters, the + player can use the movement keys to position the cursor over the desired + monster, and Rogue will use the given name to refer to that
+ monster. For items, Rogue gives all similar items (such as all the blue + potions) the specified name.
m When the player types this command, Rogue prompts for an item from + the player's pack and a one-line name. Rogue then marks the specified + item with the given name..
o Typing this command causes Rogue to display all the settable + options. The player can then merely examine the options or change any or + all of them.
C This command, restricted to magicians and rangers produces a listing + of the current supply of 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 takes.
c This command, restricted to druids and rangers produces a listing of + the current supply of 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 takes.
p This command, restricted to clerics and paladins, produces a listing + of the character's known prayers. The player can then offer one of these + prayers to the character's deity. Deities are not known for favoring + characters which continually pray to them, and they are most likely to + answer the least "ambitious" prayers.
a This command is restricted to clerics and paladins must be followed + by a directional command. If there is an "undead" monster standing next + to the player in the specified direction, there is a chance the player + will affect the monster by causing it to flee or possibly even + destroying it.
* Count the gold in the player's pack.
^ This command sets a trap and is limited to thieves and assassins. If + the character is successful, Rogue prompts the player for a type of trap + and sets it where the player is standing.
G This command is restricted to thieves and assassins. It causes Rogue + to display all the gold on the current level.
D Dip something into a magic pool.
^T This command is restricted to thieves and assassins. It + must be followed by a directional command. If there is a monster + standing next to the player in the specified direction, the player tries + to steal an item from the monster's pack. If the player is successful, + the monster does not notice anything, but if the player is unsuccessful, + there is a chance the monster will wake up.
^L Redraw the screen.
^R Repeat the last message that was displayed on the top line of the + screen.
Escape (^[) Typing an escape will usually cause Rogue to cancel the current + command.
v Print the current Rogue version number.
! Escape to the shell level.
S Quit and save the game for resumption at a later time.
Q Quit without saving the game.
+

+ +

6. IMPLICIT COMMANDS

+ +

+There is no "attack" command. If a player wishes to +attack a monster, the player simply tries to move onto the +spot where the monster is standing. The game then assumes +that the player wishes to attack the monster with whatever +weapon the player is wielding. +

+ +

+When the player moves onto an item, the game +automatically places the object into the player's pack. If +there is no room left in the pack, the game announces that +fact and leaves the item on the floor. +

+ +

7. TIME

+ +

+All actions except for purely 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 a space varies with the type of armor worn. +Movement is always faster when flying. +

+ +

+Since actions take time, 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. Of course, +the same rule applies when the player hits a monster. +

+ +

+Magical hasting (or slowing) will decrease (or +increase) the time it takes to perform an action. +

+ +

8.0 LIGHT

+ +

+Some rooms in the dungeon possess a natural light +source. In other rooms and in corridors the player can see +only those things within a one space radius from the player. +These dark rooms can be lit with magical light or by a fire +beetle. +

+ +

9. WEAPONS AND ARMOR

+ +

+The player can wield exactly one weapon at a time. +When the player attacks a monster, the amount of damage +depends on the particular weapon the player 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, affecting the +likelihood of hitting a monster with the weapon and the +damage the weapon will inflict on the monster. If the +player has identified a weapon, the "to hit" and "to damage" +bonuses appear in that order before the weapon's name in an +inventory listing. A positive bonus indicates a blessed +weapon, and a negative bonus usually indicates a cursed +weapon. The player cannot release a cursed weapon. +

+ +

+Without any armor the player has an armor class of 10. +The lower the player's armor class, the harder it is for a +monster to hit the player, so wearing armor can improve the +player's armor class. A cursed suit of armor, however, +offers poor protection and may sometimes be worse than no +armor at all. +

+ +

+After the player has identified a suit of armor, the +protection bonus appears before the armor's name in an +inventory listing. If the bonus is positive the armor is +blessed, and if it is negative, the armor is usually cursed. +The player cannot remove a cursed suit of armor. +

+ +

+Some monsters can corrode armor when they hit it. If +such a monster hits the player when the player is wearing +metal armor, the armor loses some of its protection value, +but the corrosion does not curse the armor. This corrosive +property can also apply to weapons when the player hits such +a monster. +

+ + +

10. POTIONS AND SCROLLS

+ +

+The player can frequently find potions and scrolls in +the dungeon. In any given dungeon, the player can +distinguish among the different types of potions by a +potion's color and among the different types of scrolls by a +scroll's name. Quaffing a potion or reading a scroll +usually causes some magical occurrence. Most potions and +scrolls may be cursed or blessed. +

+ +

11. RINGS

+ +

+The player can wear a maximum of eight rings, and they +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. Many rings can +be cursed or blessed, and the player cannot remove a cursed +ring. The player can distinguish among different types of +rings by a ring's jewel. +

+ +

12. WANDS AND STAVES

+ +

+Wands and staves affect the player's environment. The +player can zap a wand or staff at something and perhaps +shoot a bolt of lightning at it or teleport it away. All +wands or staves of the same type are constructed with the +same type of wood. Some wands and staves may be cursed or +blessed. +

+ +

13. FOOD

+ +

+The player must be careful not to run out of food since +moving through the dungeon fighting monsters consumes a lot +of energy. Starving results in the player's fainting for +increasingly longer periods of time, during which any nearby +monster can attack the player freely. +

+ +

+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. +

+ +

14. GOLD

+ +

+Gold has one use in a dungeon: buying things. One can +buy things in two ways, either in a trading post or from a +quartermaster. A trading post is a place that sometimes +occurs "between levels" of the dungeon and can be entered by +stepping on the entrance. A quartermaster is a person who +will sometimes appear and will try to sell the player some +of his wares. These wares are never cursed and frequently +blessed, though blessed goods cost more than normal goods. +If the player chooses to buy one of the quartermaster's +items, the quartermaster trades the item for the specified +amount of gold and disappears. Attacking a quartermaster +causes him to vanish without offering a trade. +

+ +

+The player starts the game in a trading post with a +class-dependent allotment of gold. Although there are +restrictions on the use of some items (eg. only fighters, +paladins, and rangers can wield two-handed swords), the +market will happily sell the player anything that he can +afford. +

+ +

15. MISCELLANEOUS MAGIC ITEMS

+ +

+Miscellaneous items such as a pair of boots or a book +may be found within the dungeon. These items can usually be +used to the 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. +

+ +

16. ARTIFACTS

+ +

+Some monsters down in the depths of the dungeon carry +unique artifacts. The game begins as a quest to retrieve +one of these items. Each artifact appears only on its +owner's person. These items also can usually be used to the +player's advantage. However, care must be taken when +handling them for they are intelligent and will reject +mishandling or abuse. These items consume food and merely +carrying them will result in increased food use. +

+ +

17. TRAPS

+ +

+A variety of traps, including trap doors, bear traps, +and sleeping traps, are hidden in the dungeon. They remain +hidden until sprung by a monster or the player. A sprung +trap continues to function, but since it is visible, an +intelligent monster is not likely to tread on it. +

+ +

18. THE MONSTERS

+ +

+Each monster except for the merchant 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 can vary, however, such that one kobold may be +much more difficult to kill than another one. 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, including such projectile weapons as +short bows and crossbows, and some monsters have breath +weapons. Some monsters even use magical items, such as +wands. Monsters with distance weapons or magic can attack +the player from across a room or down a corridor. +

+ +

+Some monsters are more intelligent than others, and the +more intelligent a monster, the more likely that the monster +will run away if it is about to die. A fleeing monster will +not attack the player unless cornered. +

+ +

+It is sometimes possible to enlist a monster's aid. +Reading a charm monster scroll, for example, or singing a +charm monster chant can make a monster believe the player is +its friend. A charmed monster will fight hostile monsters +for the player as long as they are not of its race. +

+ +

+As the player moves down in the dungeon, the monsters +get more powerful. Deep down in the dungeon there exist +some one-of-a-kind monsters. These monsters are greatly +feared. However, once a "unique monster" is killed, the +player will not find another in the current dungeon. +

+ + +

19. OPTIONS

+ +

+Rogue has several options which may be set by the player: +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
terse  Setting this Boolean option results in shorter messages appearing on + the top line of the screen.
jump Setting this Boolean option results in waiting until the player has + finished running to draw the player's path. Otherwise the game always + displays the path one step at a time.
step Setting this Boolean option results in most listings, such as an + inventory, appearing one item at a time on the top line of the screen. + When this option is not set, the game clears the screen, displays the + list, and then redraws the dungeon.
flush Setting this Boolean option results in flushing all typeahead + (pending) commands when the player encounters a monster.
askme Setting this Boolean option results in the game prompting the + player for a name upon encountering a + new type of scroll, potion, ring, staff, or wand.
pickup This option specifies whether items should be picked up automatically + as the rogue steps over them. In the non-automatic mode, the player may + still pick up items via the pickup (P) command. The option defaults to + true.
name This string is the player's name and defaults to the player's + account name.
file This string, which defaults to arogue77.sav, specifies the file to + use for saving the game.
score This string identifies the top-twenty score file to use for the + game.
class This option specifies the character class of the rogue. It can be + set only in the ROGUEOPTS
+ environment variable.
quested item This option is set by the game at the start and cannot be reset by + the player. It is merely listed
+ to remind the player of his quest.
+

+ +

+The player can set options at the beginning of a game via the +ROGUEOPTS environment variable. Naming a Boolean option sets it, and preceding +the Boolean option name by "no" clears it. The syntax "stringoption=name" sets a +string option to "name." So setting ROGUEOPTS to "terse, jump, nostep, flush, +askme, name=Ivan the Terrible" would set the terse, jump, flush, and askme +Boolean options, clear the step Boolean option, set the player's name to "Ivan +the Terrible," and use the defaults for the save file and the score file. +

+ +

+The player may change an option at any time during the game via the option +command, which results in a listing of the current options. Typing a new value +changes the option, a RETURN moves to the next option, a '-' moves to the +previous option, and an ESCAPE returns the player to the dungeon. +

+ +

20. SCORING

+ +

+The player receives experience points for stealing items from monsters, +turning monsters (a clerical ability), +and killing monsters. When the player gets killed, the player's score equals the +player's experience points. A +player who quits gets a score equal to the player's experience points and gold. +If the player makes it back up +out of the dungeon, the player's score equals the player's experience points +plus the gold the player carried and the gold received from selling the player's +possessions. +

+ +

+Rogue maintains a list of the top twenty scores to date, together with the name +of the player obtaining the score, the level where the player finished, and the manner in which the player +ended the game. As an installation option, the game may record only one entry per character type and login; this +restriction encourages a greater number of different players in the scorechart. +

+ +

21. ACKNOWLEDGEMENTS

+ +

+This version of Rogue is based on a version developed +at the University of California. +

diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/arogue77.sln --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/arogue77.sln Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "arogue77", "arogue77.vcproj", "{D95CFDAC-E66E-47D3-87B7-F76149F6A51D}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {D95CFDAC-E66E-47D3-87B7-F76149F6A51D}.Debug.ActiveCfg = Debug|Win32 + {D95CFDAC-E66E-47D3-87B7-F76149F6A51D}.Debug.Build.0 = Debug|Win32 + {D95CFDAC-E66E-47D3-87B7-F76149F6A51D}.Release.ActiveCfg = Release|Win32 + {D95CFDAC-E66E-47D3-87B7-F76149F6A51D}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/arogue77.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/arogue77.vcproj Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/chase.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/chase.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,928 @@ +/* + * chase.c - Code for one object to chase another + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Code for one object to chase another + * + */ + +#include +#include +#include "curses.h" +#include "rogue.h" +#define MAXINT INT_MAX +#define MININT INT_MIN + + +/* + * 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) { + 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 = CCHAR( 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 = CCHAR( 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. + */ + +coord * +can_shoot(er, ee) +register coord *er, *ee; +{ + static coord 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) + return(NULL); + + /* Do we have a straight shot? */ + if (!straight_shot(er->y, er->x, ee->y, ee->x, &shoot_dir)) return(NULL); + else return(&shoot_dir); +} + +/* + * 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 = MAXINT; + register coord *er = &tp->t_pos; + struct thing *prey; /* What we are chasing */ + coord ch_ret; /* Where chasing takes you */ + 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 = MININT; /* 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 : MAXINT; + 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 = CCHAR( 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 = CCHAR( 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, 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 = MAXINT; + 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 < MAXINT) + 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 < MAXINT && + 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 != MININT && /* It is possible to move back */ + ((flee && dist == 0) || /* No other possible moves */ + (!flee && dist == MAXINT))) { + /* 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(NULL, tp); + if (tp->t_using == NULL) + tp->t_no_move += weap_move(tp, 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 */ + 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(player, ISBLIND) && + cansee(unc(th->t_pos)) && + !invisible(th)) + 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(NULL, th); + /* + * add in rest of time + */ + if (th->t_using == NULL) + th->t_no_move += weap_move(th, 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 = CCHAR( 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 = CCHAR( mvwinch(cw, ch_ret.y, ch_ret.x) ); /* What player sees */ + rch = CCHAR( 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 == '|' || rch == '-')) { + char nch; /* The new look to the tunnel */ + + if (rch == WALL) nch = PASSAGE; + else if (levtype == MAZELEV) 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 == '|' || rch == '-') { + 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) md_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 = CCHAR( 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 */ + 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 = CCHAR( winat(ery, erx) )) { + case '|': + case '-': + 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/command.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/command.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1223 @@ +/* + * command.c - Read and execute the user commands + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Read and execute the user commands + * + */ + +#include "curses.h" +#include +#include +#include +#include +#include "mach_dep.h" +#include "rogue.h" +#ifdef PC7300 +#include "sys/window.h" +extern struct uwdata wdata; +#endif + +/* + * command: + * Process the user commands + */ + +command() +{ + unsigned char ch; + struct linked_list *item; + unsigned char countch, direction, 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("The sun rises above the horizon"); + else msg("The sun sinks below 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 = (char) 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 = CCHAR( 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 = readchar(); + if (mpos != 0 && !running) /* Erase message if its there */ + msg(""); + } + + /* + * check for prefixes + */ + if (isdigit(ch)) + { + count = 0; + newcount = TRUE; + while (isdigit(ch)) + { + count = count * 10 + (ch - '0'); + if (count > 255) + count = 255; + ch = readchar(); + } + 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 = readchar(); + 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(); + 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_PICKUP: + player.t_action = A_NIL; + if (add_pack(NULL, FALSE, NULL)) { + char tch; + + tch = CCHAR( 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_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_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 'Q' : after = FALSE; quit(0); + when 'i' : after = FALSE; inventory(pack, ALL); + when 'I' : after = FALSE; picky_inven(); + when C_DROP : player.t_action = C_DROP; drop(NULL); + when '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 C_COUNT : count_gold(); + when C_QUAFF : quaff(-1, NULL, NULL, TRUE); + when C_READ : read_scroll(-1, NULL, TRUE); + when C_EAT : eat(); + when C_WIELD : wield(); + when C_WEAR : wear(); + when C_TAKEOFF : take_off(); + when 'o' : option(); + when CTRL('N') : nameit(); + when '=' : after = FALSE; display(); + when 'm' : nameitem(NULL, TRUE); + when '>' : after = FALSE; d_level(); + when '<' : after = FALSE; u_level(); + when '?' : after = FALSE; help(); + when '/' : after = FALSE; identify(NULL); + when C_USE : use_mm(-1); + 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 C_DIP : dip_it(); + when 'G' : + if (player.t_action == A_NIL) { + player.t_action = 'G'; + player.t_no_move = movement(&player); + } + else { + gsense(); + player.t_action = A_NIL; + } + 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 = 5 * movement(&player); + } + else { + search(FALSE, FALSE); + player.t_action = A_NIL; + } + when C_ZAP : if (!player_zap(NULL, FALSE)) + after=FALSE; + when C_PRAY : pray(); + when C_CHANT : chant(); + when C_CAST : cast(); + when 'a' : + if (player.t_action == A_NIL) { + if (get_dir(&player.t_newpos)) { + player.t_action = 'a'; + player.t_no_move = 2 * movement(&player); + } + else + after = FALSE; + } + else { + affect(); + player.t_action = A_NIL; + } + when 'v' : after = FALSE; + msg("Advanced Rogue Version %s.", + release); + when CTRL('L') : after = FALSE; clearok(curscr, TRUE); + touchwin(cw); /* MMMMMMMMMM */ + when CTRL('R') : after = FALSE; msg(huh); + when 'S' : + after = FALSE; + if (save_game()) + { + wclear(cw); + draw(cw); + endwin(); +#ifdef PC7300 + endhardwin(); +#endif + exit(0); + } + when '.' : + player.t_no_move = movement(&player); /* Rest */ + player.t_action = A_NIL; + when ' ' : after = FALSE; /* Do Nothing */ +#ifdef WIZARD + when CTRL('P') : + after = FALSE; + if (wizard) + { + wizard = FALSE; + trader = 0; + msg("Not wizard any more"); + } + else + { + if (waswizard || passwd()) + { + msg("Welcome, oh mighty wizard."); + wizard = waswizard = TRUE; + } + else + msg("Sorry"); + } +#endif + when ESCAPE : /* 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; + otherwise : + after = FALSE; +#ifdef WIZARD + if (wizard) switch (ch) + { + case 'M' : create_obj(TRUE, 0, 0); + when CTRL('W') : wanderer(); + when CTRL('I') : inventory(lvl_obj, ALL); + when CTRL('Z') : whatis(NULL); + when CTRL('D') : level++; new_level(NORMLEV); + when CTRL('F') : overlay(stdscr,cw); + when CTRL('X') : overlay(mw,cw); + when CTRL('J') : teleport(); + when CTRL('E') : msg("food left: %d\tfood level: %d", + food_left, foodlev); + when CTRL('A') : activity(); + when CTRL('C') : + { + int tlev; + prbuf[0] = 0; + msg("Which level? "); + if(get_str(prbuf,msgw) == NORM) { + tlev = atoi(prbuf); + if(tlev < 1) { + mpos = 0; + msg("Illegal level."); + } + else if (tlev > 199) { + levtype = MAZELEV; + level = tlev - 200 + 1; + } + else if (tlev > 99) { + levtype = POSTLEV; + level = tlev - 100 + 1; + } + else { + levtype = NORMLEV; + level = tlev; + } + new_level(levtype); + } + } + 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; + 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) { + item = spec_item(WEAPON, TWOSWORD, 5, 5); + add_pack(item, TRUE, NULL); + cur_weapon = OBJPTR(item); + (OBJPTR(item))->o_flags |= (ISKNOW|ISPROT); + } + /* + * And his suit of armor + */ + if (player.t_ctype != C_MONK) { + item = spec_item(ARMOR, PLATE_ARMOR, 10, 0); + obj = OBJPTR(item); + if (player.t_ctype == C_THIEF) + obj->o_which = STUDDED_LEATHER; + obj->o_flags |= (ISKNOW | ISPROT); + obj->o_weight = armors[PLATE_ARMOR].a_wght; + cur_armor = obj; + add_pack(item, TRUE, NULL); + } + purse += 20000; + } + otherwise : + msg("Illegal command '%s'.", unctrl(ch)); + count = 0; + } + else +#endif + { + 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)) { + if ((pstats.s_hpt -= infest_dam) <= 0) death(D_INFESTATION); + } + + /* + * The eye of Vecna is a constant drain on the player + */ + if (cur_relic[EYE_VECNA]) { + if ((--pstats.s_hpt) <= 0) death(D_RELIC); + } + + /* + * if player has body rot then take off five hits + */ + if (on(player, DOROT)) { + if ((pstats.s_hpt -= 5) <= 0) 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); + +#ifdef NEEDLOOK + /* Shall we take a look? */ + if (player.t_no_move <= 1 && + !((running || count) && jump)) + look(FALSE, FALSE); +#endif + + if (++segment > 10) segment = 1; + t_free_list(monst_dead); + } +} + +/* + * 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. + */ + +void +quit(sig) +int sig; +{ + /* + * Reset the signal in case we got here via an interrupt + */ + if (signal(SIGINT, quit) != quit) + mpos = 0; + msg("Really quit? "); + 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); +#ifdef PC7300 + endhardwin(); +#endif + exit(0); + } + else + { + signal(SIGINT, quit); + wmove(cw, 0, 0); + wclrtoeol(cw); + status(FALSE); + draw(cw); + mpos = 0; + count = 0; + running = FALSE; + } +} + +/* + * bugkill: + * killed by a program bug instead of voluntarily. + */ + +void +bugkill(sig) +int sig; +{ + signal(sig, quit); /* If we get it again, give up */ + 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) */ + 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; + + /* Mch and ch will be the same unless there is a monster here */ + mch = CCHAR( winat(y, x) ); + ch = CCHAR( mvwinch(stdscr, y, x) ); + sch = CCHAR( 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) md_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; + } + } + } + } +} + + +/* + * help: + * Give single character help, or the whole mess if he wants it + */ + +help() +{ + register struct h_list *strp = helpstr; +#ifdef WIZARD + struct h_list *wizp = wiz_help; +#endif + register char helpch; + register int cnt; + + msg("Character you want help for (* for all): "); + helpch = readchar(); + mpos = 0; + /* + * If its not a *, print the right help string + * or an error if he typed a funny character. + */ + if (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++; + } +#ifdef WIZARD + if (wizard) { + while (wizp->h_ch) { + if (wizp->h_ch == helpch) { + msg("%s%s", unctrl(wizp->h_ch), wizp->h_desc); + return; + } + wizp++; + } + } +#endif + + msg("Unknown character '%s'", unctrl(helpch)); + return; + } + /* + * Here we print help for everything. + * Then wait before we return to command mode + */ + 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; + } + } +#ifdef WIZARD + 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; + } + } + } +#endif + 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 char ch; +{ + register char *str; + + if (ch == 0) { + msg("What do you want identified? "); + ch = readchar(); + mpos = 0; + if (ch == ESCAPE) + { + msg(""); + return; + } + } + if (isalpha(ch)) + str = monsters[id_monst(ch)].m_name; + else switch(ch) + { + case '|': + case '-': + str = (levtype == OUTSIDE) ? "boundary of sector" + : "wall of a room"; + when GOLD: str = "gold"; + when STAIRS : str = (levtype == OUTSIDE) ? "entrance to a dungeon" + : "passage leading down"; + when DOOR: str = "door"; + when FLOOR: str = (levtype == OUTSIDE) ? "meadow" : "room floor"; + when VPLAYER: str = "the hero of the game ---> you"; + when IPLAYER: str = "you (but invisible)"; + when PASSAGE: str = "passage"; + when POST: str = "trading post"; + when POOL: str = (levtype == OUTSIDE) ? "lake" + : "a shimmering pool"; + when TRAPDOOR: str = "trapdoor"; + 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 FOREST: str = "forest"; + when POTION: str = "potion"; + when SCROLL: str = "scroll"; + when FOOD: str = "food"; + when WEAPON: str = "weapon"; + when ' ' : str = "solid rock"; + when ARMOR: str = "armor"; + when MM: str = "miscellaneous magic"; + when RING: str = "ring"; + when STICK: str = "wand or staff"; + when SECRETDOOR:str = "secret door"; + when RELIC: str = "artifact"; + otherwise: str = "unknown character"; + } + msg("'%s' : %s", unctrl(ch), str); +} + +/* + * d_level: + * He wants to go down a level + */ + +d_level() +{ + bool no_phase=FALSE; + char position = CCHAR( winat(hero.y, hero.x) ); + + + /* If we are on a trading post, go to a trading post level. */ + if (position == POST) { + new_level(POSTLEV); + 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; + } + + /* 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++; + 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; + struct thing *tp; + struct object *obj; + + 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 (level == 0) { + 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) new_level(NORMLEV); + else { + level = -1; /* Indicate that we are new to the outside */ + msg("You emerge into the %s", daytime ? "light" : "night"); + new_level(OUTSIDE); /* Leaving the dungeon */ + } + + if (no_phase) unphase(); +} + +/* + * Let him escape for a while + */ + +shell() +{ + register char *sh; + + /* + * Set the terminal back to original mode + */ + sh = getenv("SHELL"); + wclear(hw); + wmove(hw, lines-1, 0); + draw(hw); + endwin(); + in_shell = TRUE; + fflush(stdout); + /* + * Fork and do a shell + */ + + md_shellescape(); + + printf(retstr); + noecho(); + raw(); + keypad(cw,1); + keypad(msgw,1); + in_shell = FALSE; + wait_for('\n'); + clearok(cw, TRUE); + touchwin(cw); +} + +/* + * see what we want to name -- an item or a monster. + */ +nameit() +{ + char answer; + + msg("Name monster or item (m or i)? "); + answer = readchar(); + mpos = 0; + + while (answer != 'm' && answer != 'i' && answer != ESCAPE) { + mpos = 0; + msg("Please specify m or i, for monster or item - "); + answer = readchar(); + } + + switch (answer) { + case 'm': namemonst(); + when 'i': nameitem(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, *elsewise; + 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(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 */ + player.t_no_move = (purse/300 + 1) * movement(&player); + return; + } + if (purse > 100) + msg("You think you have about %d gold pieces.", purse); + else + msg("You have %d gold pieces.", purse); + player.t_action = A_NIL; +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/daemon.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/daemon.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,252 @@ +/* + * daemon.c - functions for dealing with things that happen in the future. + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Contains functions for dealing with things that happen in the + * future. + * + */ + +#include "curses.h" +#include "rogue.h" + +#define EMPTY 0 +#define DAEMON -1 +#define MAXDAEMONS 10 +#define MAXFUSES 20 + +#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(func, arg, type) +reg int arg, type, (*func)(); +{ + reg struct delayed_action *dev; + + dev = d_slot(); + if (dev != NULL) { + dev->d_type = type; + dev->d_func = func; + dev->d_.arg = arg; + dev->d_time = DAEMON; + demoncnt += 1; /* update count */ + } +} + + +/* + * kill_daemon: + * Remove a daemon from the list + */ +kill_daemon(func) +reg int (*func)(); +{ + reg struct delayed_action *dev; + reg int i; + + for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++) { + if (dev->d_type != EMPTY && func == 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 = 0; + 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; +{ + reg struct delayed_action *dev; + + /* + * Loop through the devil list + */ + for (dev = d_list; dev <= &d_list[MAXDAEMONS-1]; dev++) + /* + * Executing each one, giving it the proper arguments + */ + if (dev->d_type == flag && dev->d_time == DAEMON) + (*dev->d_func)(dev->d_.arg); +} + + +/* + * fuse: + * Start a fuse to go off in a certain number of turns + */ +fuse(func, arg, time, type) +reg int (*func)(), arg, time, type; +{ + reg struct delayed_action *wire; + + wire = f_slot(); + if (wire != NULL) { + wire->d_type = type; + wire->d_func = func; + wire->d_.arg = arg; + wire->d_time = time; + fusecnt += 1; /* update count */ + } +} + + +/* + * lengthen: + * Increase the time until a fuse goes off + */ +lengthen(func, xtime) +reg int (*func)(), xtime; +{ + reg struct delayed_action *wire; + + if ((wire = find_slot(func)) == NULL) + return; + wire->d_time += xtime; +} + + +/* + * extinguish: + * Put out a fuse + */ +extinguish(func) +reg int (*func)(); +{ + reg struct delayed_action *wire; + + if ((wire = find_slot(func)) == NULL) + return; + wire->d_type = EMPTY; + wire->d_func = NULL; + wire->d_.arg = 0; + wire->d_time = 0; + fusecnt -= 1; +} + + +/* + * do_fuses: + * Decrement counters and start needed fuses + */ +do_fuses(flag) +reg int flag; +{ + reg struct delayed_action *wire; + + /* + * Step though the list + */ + for (wire = f_list; wire <= &f_list[MAXFUSES-1]; wire++) { + /* + * 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); + 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(0)); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/daemons.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/daemons.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,663 @@ +/* + * daemon.c - All the daemon and fuse functions are in here + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * All the daemon and fuse functions are in here + * + */ + +#include "curses.h" +#include "rogue.h" + +/* + * doctor: + * A healing daemon that restors hit points after rest + */ + +doctor(tp) +register struct thing *tp; +{ + register int ohp; + register int limit, new_points; + register struct stats *curp; /* current stats pointer */ + register struct stats *maxp; /* max stats pointer */ + + curp = &(tp->t_stats); + maxp = &(tp->maxstats); + if (curp->s_hpt == maxp->s_hpt) { + tp->t_quiet = 0; + return; + } + tp->t_quiet++; + switch (tp->t_ctype) { + case C_MAGICIAN: + limit = 8 - curp->s_lvl; + new_points = curp->s_lvl - 3; + when C_THIEF: + case C_ASSASIN: + case C_MONK: + limit = 8 - curp->s_lvl; + new_points = curp->s_lvl - 2; + when C_CLERIC: + case C_DRUID: + limit = 8 - curp->s_lvl; + new_points = curp->s_lvl - 3; + when C_FIGHTER: + case C_RANGER: + case C_PALADIN: + limit = 16 - curp->s_lvl*2; + new_points = curp->s_lvl - 5; + when C_MONSTER: + limit = 16 - curp->s_lvl; + new_points = curp->s_lvl - 6; + 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, 0, 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_ASSASIN) || + (rnd(30) >= dex_compute()))) { + if (levtype != POSTLEV) + wanderer(); + kill_daemon(rollwand); + fuse(swander, 0, 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)) death(D_PETRIFY); +} + +/* + * land: + * Player can no longer fly + */ + +land() +{ + turn_off(player, ISFLY); + msg("You regain your normal weight"); + running = FALSE; +} + +/* + * 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 + */ + +void +res_strength(howmuch) +int 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); +} + +/* + * 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() +{ + 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) > 20) + return; + if (hungry_state == F_FAINT && rnd(20) == 7) /*must have fainted once*/ + death(D_STARVATION); + player.t_action = A_FREEZE; + player.t_no_move = movement(&player) * (rnd(8) + 4); + if (!terse) + addmsg("You feel too weak from lack of food. "); + msg("You faint"); + running = FALSE; + if (fight_flush) md_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) md_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; + 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 + */ + +undance() +{ + turn_off(player, ISDANCE); + msg ("Your feet take a break.....whew!"); +} + +/* + * if he has our favorite necklace of strangulation then take damage every turn + */ +strangle() +{ + if ((pstats.s_hpt -= 6) <= 0) 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 + */ +ring_search() +{ + search(FALSE, FALSE); +} +/* + * this is called each turn the hero has the ring of teleportation on + */ +ring_teleport() +{ + if (rnd(100) < 2) teleport(); +} +/* + * this is called to charge up the quill of Nagrom + */ +quill_charge() +{ + register struct object *tobj; + 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, 0, 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 + */ + +cloak_charge(obj) +register struct object *obj; +{ + if (obj->o_charges < 1) + obj->o_charges = 1; +} + +/* + * 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 looses its bluish tint"); +} +/* + * eat_gold: + * an artifact eats gold + */ +eat_gold(obj) +register struct object *obj; +{ + if (purse == 1) + msg("%s demand you find more gold", inv_name(obj, FALSE)); + if (purse == 0) { + if (--pstats.s_hpt <= 0) + 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, 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, 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, NULL, time, AFTER); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/eat.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/eat.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,130 @@ +/* + * eat.c - Functions for dealing with digestion + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "curses.h" +#include "rogue.h" + +/* + * eat: + * He wants to eat something, so let him try + */ + +eat() +{ + register struct linked_list *item; + int which; + unsigned long temp; + + if (player.t_action != C_EAT) { + if ((item = get_item(pack, "eat", FOOD, FALSE, FALSE)) == NULL) + return; + + player.t_using = item; /* Remember what it is */ + player.t_action = C_EAT; /* We are eating */ + which = (OBJPTR(item))->o_which; + player.t_no_move = max(foods[which].mi_food/100, 1) * movement(&player); + return; + } + + /* We have waited our time, let's eat the food */ + item = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + which = (OBJPTR(item))->o_which; + if ((food_left += foods[which].mi_food) > STOMACHSIZE) + food_left = STOMACHSIZE; + del_pack(item); + if (hungry_state == F_SATIATED && food_left == STOMACHSIZE && rnd(4) == 1) { + pstats.s_hpt = 0; + msg ("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 all that food down."); + msg ("Your stomach feels like its about to burst!"); + } + else { + hungry_state = F_OKAY; + switch (rnd(3)) { + case 0: msg("My, that was a yummy %s", foods[which].mi_name); + when 1: msg("Mmmm, that was a tasty %s", foods[which].mi_name); + when 2: msg("Wow, that was a scrumptious %s", foods[which].mi_name); + } + } + updpack(TRUE, &player); + switch(which) { + case E_WHORTLEBERRY: + add_abil[A_INTELLIGENCE](1); + + when E_SWEETSOP: + add_abil[A_DEXTERITY](1); + + when E_SOURSOP: + add_abil[A_STRENGTH](1); + + when E_SAPODILLA: + add_abil[A_WISDOM](1); + + when E_RAMBUTAN: + add_abil[A_CONSTITUTION](1); + + when E_PEACH: + add_abil[A_CHARISMA](1); + + when E_STRAWBERRY: + temp = pstats.s_exp/100; + pstats.s_exp += temp; + if (temp > 0) + msg("You feel slightly more experienced now"); + check_level(); + + when E_PITANGA: + max_stats.s_hpt++; + pstats.s_hpt++; + if (terse) + msg("You feel a bit tougher now"); + else + msg("You feel a bit tougher now. Go get 'em!"); + + when E_HAGBERRY: + pstats.s_arm--; + msg("Your skin feels more resilient now"); + + when E_DEWBERRY: + if (chant_time > 0) { + chant_time -= 50; + if (chant_time < 0) + chant_time = 0; + msg("You feel you have more chant ability"); + } + if (pray_time > 0) { + pray_time -= 50; + if (pray_time < 0) + pray_time = 0; + msg("You feel you have more prayer ability"); + } + if (spell_power > 0) { + spell_power -= 50; + if (spell_power < 0) + spell_power = 0; + msg("You feel you have more spell casting ability"); + } + + otherwise: /* all the foods don't have to do something */ + break; + } +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/effects.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/effects.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,700 @@ +/* + * effects.c - functions for dealing with appllying effects to monsters + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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 "curses.h" +#include "rogue.h" + +/* + * effect: + * Check for effects of one thing hitting another thing. Return + * the reason code if the defender is killed. Otherwise return 0. + */ +effect(att, def, weap, thrown, see_att, see_def) +register struct thing *att, *def; +struct object *weap; +bool thrown; +register bool see_att, see_def; +{ + register bool att_player, def_player; + char attname[LINELEN+1], defname[LINELEN+1]; + + /* See if the attacker or defender is the player */ + att_player = (att == &player); + def_player = (def == &player); + + /* + * If the player could see the attacker or defender, they can't + * surprise anymore (don't bother checking if they could). + */ + if (see_att) turn_off(*att, CANSURPRISE); + if (see_def) turn_off(*def, CANSURPRISE); + + /* What are the attacker and defender names? */ + if (att_player) strcpy(attname, "you"); + else { + if (see_att) strcpy(attname, monster_name(att)); + else strcpy(attname, "something"); + } + + if (def_player) strcpy(defname, "you"); + else { + if (see_def) strcpy(defname, monster_name(def)); + else strcpy(defname, "something"); + } + + /* + * See what happens to the attacker first. We can skip this + * whole section, however, if the defender is the player. + * Nothing happens (yet) to anyone just for hitting the player. + */ + if (!def_player) { + if (!thrown) { /* Some things require a direct hit. */ + /* + * If the attacker hits a rusting monster, The weapon + * may be damaged + */ + if (on(*def, CANRUST) && weap && + weap->o_type != RELIC && (weap->o_flags & ISMETAL) && + !(weap->o_flags & ISPROT)) { + if ((weap->o_hplus < 1 && weap->o_dplus < 1) || + roll(1,20) < weap->o_hplus+weap->o_dplus+10) { + if (rnd(100) < 50) weap->o_hplus--; + else weap->o_dplus--; + if (att_player) + msg(terse ? "Your %s weakens!" + : "Your %s appears to be weaker now!", + weaps[weap->o_which].w_name); + } + } + } + + /* If the attacker hit something that shrieks, wake the dungeon */ + if (on(*def, CANSHRIEK)) { + turn_off(*def, CANSHRIEK); + if (see_def) + msg("%s emits a piercing shriek.", prname(defname, TRUE)); + else msg("You hear a piercing shriek."); + 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 <= 0) + 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 stop glowing red."); + 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("You feel your life force being drawn from 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 you against itself.", + prname(attname, TRUE)); + else if (see_att) + msg("%s squeezes 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 you"); + else { + chg_str(-1); + msg(terse ? "A sting has weakened you" : + "You feel a sting in your arm and now 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 turned to 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 (see_def) + msg("%s turns to stone.", prname(defname, TRUE)); + else if (cansee(unc(def->t_pos))) + msg("A new statue appears!"); + } + } + 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.", 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 skillfull.", 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.", 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.", + prname(attname, FALSE)); + if (on(player, HASSTINK)) lengthen(unstink, STINKTIME); + else { + turn_on(player, HASSTINK); + fuse(unstink, 0, 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, 0, 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. + */ + 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_MONK) { + msg("The wound heals quickly."); + } + else { + turn_on(*def, HASDISEASE); + fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER); + msg(terse ? "You have been diseased." + : "You have contracted a 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 appears to be weaker now. Oh my!"); + 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 and fall off!"); + 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 dissolve. Oh my!"); + 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. + */ + if (on(*att, CANINFEST) && + rnd(def->t_stats.s_const) < att->t_stats.s_lvl) { + if (ISWEARING(R_HEALTH) || + player.t_ctype == C_PALADIN || + 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, 0, 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) < 25 && + (find_slot(suffocate) == 0)) { + turn_on(*att, DIDSUFFOCATE); + msg("%s is beginning to suffocate you.", prname(attname, TRUE)); + fuse(suffocate, 0, 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)) + msg("You smell an unpleasant odor."); + 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, 0, 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. + */ + if (on(*att, CANROT)) { + if (!ISWEARING(R_HEALTH) && + player.t_ctype != C_PALADIN && + player.t_ctype != C_MONK && + !save(VS_POISON, def, 0) && + off(*def, DOROT)) { + turn_on(*def, DOROT); + msg("You feel your skin starting to rot 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 + GOLDCALC; + if (!save(VS_MAGIC, def, att->t_stats.s_lvl/10)) { + if (on(*att, ISUNIQUE)) + purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; + purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; + } + if (purse < 0) + purse = 0; + if (purse != lastpurse) { + msg("Your purse feels lighter"); + + /* 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; + strncpy(obj->o_damage, "0d0", sizeof(obj->o_damage)); + strncpy(obj->o_hurldmg, "0d0", sizeof(obj->o_hurldmg)); + 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/encumb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/encumb.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,207 @@ +/* + * encumb.c - Stuff to do with encumberence + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Stuff to do with encumberence + * + */ + +#include "curses.h" +#include "rogue.h" + +/* + * updpack: + * Update his pack weight and adjust fooduse accordingly + */ +updpack(getmax, tp) +int getmax; +struct thing *tp; +{ + + reg int topcarry, curcarry; + + if (getmax) + tp->t_stats.s_carry = totalenc(tp); /* get total encumb */ + curcarry = packweight(tp); /* get pack weight */ + + /* Only update food use for the player (for now) */ + if (tp == &player) { + topcarry = tp->t_stats.s_carry / 5; /* 20% of total carry */ + if(curcarry > 4 * topcarry) { + if(rnd(100) < 80) + foodlev = 3; /* > 80% of pack */ + } else if(curcarry > 3 * topcarry) { + if(rnd(100) < 60) + foodlev = 2; /* > 60% of pack */ + } else + foodlev = 1; /* <= 60% of pack */ + } + tp->t_stats.s_pack = curcarry; /* update pack weight */ +} + + +/* + * packweight: + * Get the total weight of the hero's pack + */ +packweight(tp) +register struct thing *tp; +{ + reg struct object *obj; + reg struct linked_list *pc; + reg int weight; + + weight = 0; + for (pc = tp->t_pack ; pc != NULL ; pc = next(pc)) { + obj = OBJPTR(pc); + weight += itemweight(obj); + } + if (weight < 0) /* in case of amulet */ + weight = 0; + + /* If this is the player, is he wearing a ring of carrying? */ + if (tp == &player && ISWEARING(R_CARRY)) { + register int temp, i; + + temp = 0; + for (i=0; io_which == R_CARRY) { + if (cur_ring[i]->o_flags & ISCURSED) temp--; + else temp++; + } + } + 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 = CCHAR( mvwinch(stdscr, hero.y, hero.x) ); + if((ch != FLOOR && ch != PASSAGE)) { + extinguish(wghtchk); + fuse(wghtchk,TRUE,1,AFTER); + inwhgt = FALSE; + return; + } + extinguish(wghtchk); + msg("Your pack is too heavy for you"); + do { + dropchk = drop(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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/fight.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/fight.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1496 @@ +/* + * fight.c - All the fighting gets done here + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * All the fighting gets done here + * + */ + +#include "curses.h" +#include +#include +#include "rogue.h" + +int hit(struct object *weapon, bool see_att, bool see_def, char *er, char *ee, bool back_stab, bool thrown, bool short_msg); +#define CONF_DAMAGE -1 +#define PARAL_DAMAGE -2 +#define DEST_DAMAGE -3 +#define DRAIN_DAMAGE -4 + +/* + * 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_ASSASIN) && + !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_ASSASIN) { + 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 affect on %s", + prname(mname, FALSE)); + } + else { + hit(thrown ? 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 ? NULL : weap, + TRUE, see_def, + thrown ? weap_name(weap) : 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, NULL, FALSE, thrown, terse); + msg("Your amulet seems to absorb the magic missile"); + } + else { + hit(weapon, see_att, TRUE, mname, 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) 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, NULL, thrown, terse); + } + if (fight_flush) md_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; + register int ndice, nsides, nplus, def_arm; + 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) { + static char dmgbuf[20]; + + /* + * monks damage grows with level + */ + if (att == &pstats && player.t_ctype == C_MONK) { + sprintf(dmgbuf, "%dd4", att->s_lvl/3+1); + cp = dmgbuf; + } + else + cp = att->s_dmg; + } + else if (weap->o_type == RELIC) { + switch (weap->o_which) { + case MUSTY_DAGGER: cp = "1d4+1/1d4+1"; + when YEENOGHU_FLAIL: cp = "3d6/paralyze/confuse"; + when HRUGGEK_MSTAR: cp = "3d10"; + when MING_STAFF: cp = "1d8"; + when ASMO_ROD: cp = "2d8+1"; + when ORCUS_WAND: cp = "destroy"; + when AXE_AKLAD: if (hurl) cp = "1d6/drain"; + else cp = "3d6/drain"; + } + } + 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) + { + strncpy(weap->o_damage, "1d6", sizeof(weap->o_damage)); + 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 < 22 && + ((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 < 22) { + 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", 7) == 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, 0, 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) + msg("The artifact warms 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) 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 */ + msg("You feel a tug at your life force."); + if (!save(VS_MAGIC, &player, -4)) { + msg("The wand devours your soul."); + def->s_hpt = 0; + } + } + /* Player hits monster */ + else if (!save(VS_MAGIC, def_er, -4)) { + if (att == &pstats) + msg("The artifact draws energy."); + + /* Give the attacker half the monster's hits */ + att->s_hpt += def->s_hpt/2; + if (att->s_hpt > att_er->maxstats.s_hpt) + att->s_hpt = att_er->maxstats.s_hpt; + + /* 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) + 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_ASSASIN) + 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; + } + 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; + 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_ASSASIN) + s = (er == 0 ? " assassinate!" : " assassinates!"); + else + s = (er == 0 ? " backstab!" : " backstabs!"); + } + else + s = " hit."; + } + else { + if (back_stab) { + if (player.t_ctype == C_ASSASIN) + 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; + 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; + + 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; +} + +#ifdef THUNK +/* + * thunk: + * A missile hits a monster + */ + +thunk(weap, tp, mname) +register struct object *weap; +register struct thing *tp; /* Defender */ +register char *mname; +{ + char *def_name; /* Name of defender */ + + /* What do we call the defender? */ + if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp)) + def_name = "something"; + else def_name = prname(mname, FALSE); + + if (weap->o_type == WEAPON) + msg("The %s hits %s.", weaps[weap->o_which].w_name, def_name); + else if (weap->o_type == MISSILE) + msg("The %s hits %s.",ws_magic[weap->o_which].mi_name, def_name); + else + msg("You hit %s.", def_name); +} + +/* + * mthunk: + * A missile from a monster hits the player + */ + +m_thunk(weap, tp, mname) +register struct object *weap; +register struct thing *tp; +register char *mname; +{ + char *att_name; /* Name of attacker */ + + /* What do we call the attacker? */ + if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp)) + att_name = "Something"; + else att_name = prname(mname, TRUE); + + if (weap->o_type == WEAPON) + msg("%s's %s hits you.", att_name, weaps[weap->o_which].w_name); + else if (weap->o_type == MISSILE) + msg("%s's %s hits you.", att_name, ws_magic[weap->o_which].mi_name); + else + msg("%s hits you.", att_name); +} + +/* + * bounce: + * A missile misses a monster + */ + +bounce(weap, tp, mname) +register struct object *weap; +register struct thing *tp; /* Defender */ +register char *mname; +{ + char *def_name; /* Name of defender */ + + /* What do we call the defender? */ + if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp)) + def_name = "something"; + else def_name = prname(mname, FALSE); + + if (weap->o_type == WEAPON) + msg("The %s misses %s.",weaps[weap->o_which].w_name, def_name); + else if (weap->o_type == MISSILE) + msg("The %s misses %s.",ws_magic[weap->o_which].mi_name, def_name); + else + msg("You missed %s.", def_name); +} + +/* + * m_bounce: + * A missle from a monster misses the player + */ + +m_bounce(weap, tp, mname) +register struct object *weap; +register struct thing *tp; +register char *mname; +{ + char *att_name; /* Name of attacker */ + + /* What do we call the attacker? */ + if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp)) + att_name = "Something"; + else att_name = prname(mname, TRUE); + + if (weap->o_type == WEAPON) + msg("%s's %s misses you.", att_name, weaps[weap->o_which].w_name); + else if (weap->o_type == MISSILE) + msg("%s's %s misses you.", att_name, ws_magic[weap->o_which].mi_name); + else + msg("%s misses you.", att_name); +} +#endif + + +/* + * 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 + */ + +int chance = 0;/* cumulative chance for goodies to loose it */ + +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; + + 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) { + if ((off(*tp, ISMEAN) || on(*tp, ISFRIENDLY)) && + (player.t_ctype == C_RANGER || player.t_ctype == C_PALADIN)) { + if (tp->t_stats.s_exp > pstats.s_exp) + pstats.s_exp = 0; + else + pstats.s_exp -= tp->t_stats.s_exp; + if (roll(1,100) < chance++) + changeclass(C_FIGHTER); + else + 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(tp->t_pack); + (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(monst_dead,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, /* 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. WE STILL NEED TO FIGURE OUT HOW + * WE WANT THIS TO WORK. + */ + if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/10)) && + (rnd(25) < 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/init.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/init.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,625 @@ +/* + * init.c - global variable initializaton + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * global variable initializaton + * + */ + +#include "curses.h" +#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 = "You no longer fall into trading posts. They are \ +now entered like going down the stairs."; + +char *rainbow[] = { + +"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", +}; +#define NCOLORS (sizeof rainbow / sizeof(char *)) +int cNCOLORS = NCOLORS; + +static char *sylls[] = { + "a", "ab", "ag", "aks", "ala", "an", "ankh", "app", "arg", "arze", + "ash", "ban", "bar", "bat", "bek", "bie", "bin", "bit", "bjor", + "blu", "bot", "bu", "byt", "comp", "con", "cos", "cre", "dalf", + "dan", "den", "do", "e", "eep", "el", "eng", "er", "ere", "erk", + "esh", "evs", "fa", "fid", "for", "fri", "fu", "gan", "gar", + "glen", "gop", "gre", "ha", "he", "hyd", "i", "ing", "ion", "ip", + "ish", "it", "ite", "iv", "jo", "kho", "kli", "klis", "la", "lech", + "man", "mar", "me", "mi", "mic", "mik", "mon", "mung", "mur", + "nej", "nelg", "nep", "ner", "nes", "net", "nih", "nin", "o", "od", + "ood", "org", "orn", "ox", "oxy", "pay", "pet", "ple", "plu", "po", + "pot", "prok", "re", "rea", "rhov", "ri", "ro", "rog", "rok", "rol", + "sa", "san", "sat", "see", "sef", "seh", "shu", "ski", "sna", + "sne", "snik", "sno", "so", "sol", "sri", "sta", "sun", "ta", + "tab", "tem", "ther", "ti", "tox", "trol", "tue", "turs", "u", + "ulk", "um", "un", "uni", "ur", "val", "viv", "vly", "vom", "wah", + "wed", "werg", "wex", "whon", "wun", "xo", "y", "yot", "yu", + "zant", "zap", "zeb", "zim", "zok", "zon", "zum", +}; + +char *stones[] = { + "agate", "alexandrite", "amethyst", + "azurite", "bloodstone", "cairngorm", + "carnelian", "chalcedony", "chrysoberyl", + "chrysolite", "chrysoprase", "citrine", + "coral", "diamond", "emerald", + "garnet", "heliotrope", "hematite", + "hyacinth", "jacinth", "jade", + "jargoon", "jasper", "kryptonite", + "lapus lazuli", "malachite", "mocca stone", + "moonstone", "obsidian", "olivine", + "onyx", "opal", "pearl", + "peridot", "quartz", "rhodochrosite", + "rhodolite", "ruby", "sapphire", + "sardonyx", "serpintine", "spinel", + "tiger eye", "topaz", "tourmaline", + "turquoise", "zircon", +}; +#define NSTONES (sizeof stones / sizeof(char *)) +int cNSTONES = NSTONES; + +char *wood[] = { + "avocado wood", "balsa", "banyan", "birch", + "cedar", "cherry", "cinnibar", "dogwood", + "driftwood", "ebony", "eucalyptus", "hemlock", + "ironwood", "mahogany", "manzanita", "maple", + "oak", "pine", "redwood", "rosewood", + "teak", "walnut", "zebra wood", "persimmon wood", +}; +#define NWOOD (sizeof wood / sizeof(char *)) +int cNWOOD = NWOOD; + +char *metal[] = { + "aluminium", "bone", "brass", "bronze", + "copper", "chromium", "iron", "lead", + "magnesium", "pewter", "platinum", "silver", + "steel", "tin", "titanium", "zinc", +}; +#define NMETAL (sizeof metal / sizeof(char *)) +int cNMETAL = NMETAL; +#define MAX3(a,b,c) (a > b ? (a > c ? a : c) : (b > c ? b : c)) + +static bool used[MAX3(NCOLORS, NSTONES, NWOOD)]; + + +/* + * 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, j; + + for (i = 0; i < NCOLORS; i++) + used[i] = FALSE; + + for (i = 0 ; i < MAXPOTIONS ; i++) + { + do + j = rnd(NCOLORS); + until (!used[j]); + used[j] = TRUE; + p_colors[i] = rainbow[j]; + 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, j; + register char *str; + static bool metused[NMETAL]; + + for (i = 0; i < NWOOD; i++) + used[i] = FALSE; + for (i = 0; i < NMETAL; i++) + metused[i] = FALSE; + + for (i = 0 ; i < MAXSTICKS ; i++) + { + for (;;) + if (rnd(100) > 50) + { + j = rnd(NMETAL); + if (!metused[j]) + { + ws_type[i] = "wand"; + str = metal[j]; + metused[j] = TRUE; + break; + } + } + else + { + j = rnd(NWOOD); + if (!used[j]) + { + ws_type[i] = "staff"; + str = wood[j]; + used[j] = TRUE; + break; + } + } + + 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(3)+1; + while(nsyl--) + { + sp = sylls[rnd((sizeof sylls) / (sizeof (char *)))]; + 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, minimum, maximum, ch, i, j; + short do_escape, *our_stats[NUMABILITIES-1]; + struct linked_list *weap_item, *armor_item; + struct object *obj; + + weap_item = armor_item = NULL; + + if (char_type == -1) { + /* 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 = 2700; + switch (player.t_ctype) { + case C_FIGHTER: + purse += 1800; + when C_THIEF: + case C_ASSASIN: + purse += 600; + } +#ifdef WIZARD + /* + * allow me to describe a super character + */ + if (wizard && strcmp(getenv("SUPER"),"YES") == 0) { + pstats.s_str = 25; + pstats.s_intel = 25; + pstats.s_wisdom = 25; + pstats.s_dext = 25; + pstats.s_const = 25; + pstats.s_charisma = 25; + pstats.s_exp = 10000000L; + pstats.s_lvladj = 0; + pstats.s_lvl = 1; + pstats.s_hpt = 500; + pstats.s_carry = totalenc(&player); + strncpy(pstats.s_dmg, "3d4", sizeof(pstats.s_dmg)); + check_level(); + mpos = 0; + if (player.t_ctype == C_FIGHTER || + player.t_ctype == C_RANGER || + player.t_ctype == C_PALADIN) + weap_item = spec_item(WEAPON, TWOSWORD, 5, 5); + else + weap_item = spec_item(WEAPON, SWORD, 5, 5); + obj = OBJPTR(weap_item); + obj->o_flags |= ISKNOW; + add_pack(weap_item, TRUE, NULL); + cur_weapon = obj; + if (player.t_ctype != C_MONK) { + j = PLATE_ARMOR; + if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASIN) + j = STUDDED_LEATHER; + armor_item = spec_item(ARMOR, j, 10, 0); + obj = OBJPTR(armor_item); + obj->o_flags |= (ISKNOW | ISPROT); + obj->o_weight = armors[j].a_wght; + add_pack(armor_item, TRUE, NULL); + cur_armor = obj; + } + purse += 10000; + } + else +#endif + + { + switch(player.t_ctype) { + case C_MAGICIAN:round = A_INTELLIGENCE; + when C_FIGHTER: round = A_STRENGTH; + when C_RANGER: round = A_STRENGTH; + when C_PALADIN: round = A_STRENGTH; + when C_CLERIC: round = A_WISDOM; + when C_DRUID: round = A_WISDOM; + when C_THIEF: round = A_DEXTERITY; + when C_ASSASIN: round = A_DEXTERITY; + when C_MONK: round = A_DEXTERITY; + } + + 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; + strncpy(pstats.s_dmg, "1d4", sizeof(pstats.s_dmg)); + 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: %d", purse); + + mvwaddstr(hw, 0, 0, "Is this character okay? "); + draw(hw); + } while(wgetch(hw) != 'y'); + } + + pstats.s_arm = 10; + max_stats = pstats; + + /* Set up the initial movement rate */ + player.t_action = A_NIL; + player.t_movement = 6; + player.t_no_move = 0; + player.t_using = NULL; +} + + + + + + +/* + * init_stones: + * Initialize the ring stone setting scheme for this time + */ + +init_stones() +{ + register int i, j; + + for (i = 0; i < NSTONES; i++) + used[i] = FALSE; + + for (i = 0 ; i < MAXRINGS ; i++) + { + do + j = rnd(NSTONES); + until (!used[j]); + used[j] = TRUE; + r_stones[i] = stones[j]; + 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/io.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/io.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,540 @@ +/* + * io.c - Various input/output functions + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Various input/output functions + */ + +#include "curses.h" +#include +#include +#include +#include "rogue.h" + +/* + * msg: + * Display a message at the top of the screen. + */ + +static char msgbuf[BUFSIZ]; +static int newpos = 0; + +/*VARARGS1*/ +msg(char *fmt, ...) +{ + va_list ap; + /* + * if the string is "", just clear the line + */ + if (*fmt == '\0') + { + 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 + */ +addmsg(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + doadd(fmt, ap); + va_end(ap); +} + +/* + * 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; + + strcpy(huh, msgbuf); + 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) + 2 < cols) { + wmove(msgw, 0, mpos + 2); + newpos += mpos + 2; + } + else { + wmove(msgw, 0, mpos); + waddstr(msgw, morestr); + draw(cw); + draw(msgw); + wait_for(' '); + overwrite(cw,msgw); + wmove(msgw, 0, 0); + touchwin(cw); + } + } + else { + overwrite(cw,msgw); + wmove(msgw, 0, 0); + } + waddstr(msgw, msgbuf); + getyx(msgw, y, x); + mpos = newpos; + newpos = 0; + wmove(msgw, y, x); + draw(cw); + clearok(msgw, FALSE); + draw(msgw); +} + +doadd(char *fmt, va_list ap) +{ + + /* + * Do the printf into buf + */ + vsprintf(&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; + char ch; + + /* What is here? Don't check monster window if MONSTOK is set */ + if (can_on_monst == MONSTOK) ch = CCHAR( mvinch(y, x) ); + else ch = CCHAR( 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 '|': + case '-': + case SECRETDOOR: + if (flgptr && on(*flgptr, CANINWALL)) return(TRUE); + return FALSE; + when SCROLL: + if (can_on_monst == MONSTOK) return(TRUE); /* Not a real obstacle */ + /* + * 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) { + item = find_obj(y, x); + if (item != NULL && + (OBJPTR(item))->o_which==S_SCARE && + (flgptr == NULL || flgptr->t_stats.s_intel < 16)) + return(FALSE); /* All but smart ones are scared */ + } + return(TRUE); + otherwise: + return (!isalpha(ch)); + } + return(FALSE); +} +/* + * shoot_ok: + * returns true if it is ok for type to shoot over ch + */ + +shoot_ok(ch) +{ + switch (ch) + { + case ' ': + case '|': + case '-': + case SECRETDOOR: + case FOREST: + return FALSE; + default: + return (!isalpha(ch)); + } +} + +/* + * readchar: + * flushes stdout so that screen is up to date and then returns + * getchar. + */ + +readchar() +{ + int ch; + + ch = md_readchar(cw); + + if ((ch == 3) || (ch == 0)) + { + quit(0); + return(27); + } + + return(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, ox, temp; + register char *pb; + static 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; + + 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 ) 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); + wmove(cw, oy, ox); +} + +/* + * wait_for + * Sit around until the guy types the right key + */ +wait_for(ch) +register char ch; +{ + register char c; + + 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; +{ + static 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/list.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/list.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,226 @@ +/* + * list.c - Functions for dealing with linked lists of goodies + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Functions for dealing with linked lists of goodies + * + */ + +#include "curses.h" +#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_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); + 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; + 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); + static char errbuf[LINELEN]; + + if (space == NULL) { + sprintf(errbuf,"Rogue ran out of memory (used = %d, wanted = %d).", + md_memused(), size); + fatal(errbuf); + } + total++; + return space; +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/mach_dep.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/mach_dep.h Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,84 @@ +/* + * mach_dep.h - machine dependicies + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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 that the wizard commands exist + */ +#define WIZARD 0 + +/* + * define if you want to limit scores to one per class per userid + */ +#undef LIMITSCORE /* 1 */ + +/* + * define that rogue should "nice()" itself + */ +#undef NICE /* 1 */ + +#ifdef NICE +#define FUDGE_TIME 70 /* fudge factor allowed in time for saved game*/ +#else +#define FUDGE_TIME 50 /* fudge factor allowed in time for saved game*/ +#endif + +#undef DUMP /* 1 */ /* dump core rather than catch the signal */ +#undef NOCHECKACCESS /* 1 */ /* If set, then don't check time on save file */ + + +/* + * where scorefile should live + */ +#ifndef SCOREFILE +#define SCOREFILE "arogue7.scr" +#endif + +/* + * Variables for checking to make sure the system isn't too loaded + * for people to play + */ + +#if u370 +# define MAXUSERS 40 /* max number of users for this game */ +# define MAXPROCESSES 140 /* number processes including system */ + /* processes but not including gettys*/ +#endif +#if uts +# define MAXUSERS 45 /* max number of users for this game */ +# define MAXPROCESSES 150 /* number processes including system */ + /* processes but not including gettys*/ +#endif +#if vax +# define MAXUSERS 17 /* max number of users for this game */ +# define MAXPROCESSES 85 /* number processes including system */ + /* processes but not including gettys*/ +#endif +#if u3b +# define MAXUSERS 14 /* max number of users for this game */ +# define MAXPROCESSES 75 /* number processes including system */ + /* processes but not including gettys*/ +#endif + +#undef MAXUSERS +#undef MAXPROCESSES + +#undef CHECKTIME /* 15 *//* number of minutes between load checks */ + /* if not defined checks are only on startup */ +#define UTMP "/etc/utmp" /* where utmp file lives */ +/* + * define the current author user id of the program for "special handling" + */ +#ifndef AUTHOR +#define AUTHOR 0 +#endif diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/main.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,756 @@ +/* + * main.c - setup code + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "curses.h" +#include +#include +#include +#ifdef BSD +#include +#else +#include +#endif +#include "mach_dep.h" +#include "network.h" +#include "rogue.h" +#ifdef PC7300 +#include "sys/window.h" +#include +extern struct uwdata wdata, oldwin; +extern char oldtext[WTXTNUM][WTXTLEN]; +#endif + +#define SAVEDIR "." + +main(argc, argv, envp) +char **argv; +char **envp; +{ + register char *env; + int lowtime; + time_t now; +#ifdef PC7300 + int hardwindow; /* Do we have a hardware window? */ +#endif + + md_init(); + + /* + * get home and options from environment + */ + + strncpy(home, md_gethomedir(), LINELEN); + + /* Get default save file */ + strcpy(file_name, home); + strcat(file_name, "arogue77.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,"arogue77.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.ar7sav", 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(0, SCOREIT, 0); + exit(0); + } + +#ifdef NUMNET + /* + * Check for a network update + */ + if (argc == 2 && strcmp(argv[1], "-u") == 0) { + unsigned long netread(); + 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(1); + else { + score(amount, UPDATE, monster); + exit(0); + } + } +#endif + +#ifdef WIZARD + /* + * Check to see if he is a wizard + */ + if (argc >= 2 && argv[1][0] == '\0') + if (strcmp(PASSWD, md_crypt(md_getpass("Wizard's password: "), "mT")) == 0) + { + wizard = TRUE; + argv++; + argc--; + } +#endif + + if (!wizard && !author() && !holiday()) { + printf("Sorry, %s, but you can't play during working hours.\n", whoami); + printf("Try again later.\n"); + exit(1); + } + if (!wizard && !author() && too_much()) { + printf("Sorry, %s, but the system is too loaded now.\n", whoami); + printf("Try again later.\n"); + exit(1); + } + +#if NICE + if (!wizard) + nice(19); /* nice the max amount */ +#endif + + if (use_savedir) + { + if (!restore(file_name, envp)) + exit(1); + } + if (argc == 2) + if (!restore(argv[1], envp)) /* Note: restore will never return */ + exit(1); + lowtime = (int) time(&now); + dnum = (wizard && getenv("SEED") != NULL ? + atoi(getenv("SEED")) : + lowtime + getpid()); + if (wizard) + printf("Hello %s, welcome to dungeon #%d", whoami, dnum); + else + printf("Hello %s, just a moment while I dig the dungeon...", whoami); + fflush(stdout); + seed = dnum; + md_srand(seed); + +#ifdef PC7300 + /* Store static window parameters */ + hardwindow = ioctl(0, WIOCGETD, &wdata); + if (hardwindow >= 0) { /* We have a hardware window */ + extern char **environ; + + /* Make sure our window is the right size */ + oldwin = wdata; + if ((wdata.uw_height / wdata.uw_vs) < 23 || + (wdata.uw_width / wdata.uw_hs) < 75) { + wdata.uw_width = 80 * wdata.uw_hs; + wdata.uw_height = 24 * wdata.uw_vs; + wdata.uw_x = 0; + wdata.uw_y = wdata.uw_vs; + wdata.uw_uflags = NBORDER; + + /* Make the change */ + if (ioctl(1, WIOCSETD, &wdata) >= 0 && environ) { + char **eptr, *tptr, *nptr, *newenv, *lptr = 0, *cptr = 0; + int i, nlines = -1, ncols = -1, nlindig = 0, ncoldig = 0; + struct utdata labelbuf; + + /* Save and change window-associated text */ + for (i=0; i 85) cols = 85; + if (lines > 24) lines = 24; + if (lines < 23 || cols < 75) { /* give player a break if larger font used */ + printf("\nERROR: screen size too small for rogue\n"); + byebye(0); + } + + /* + * Now that we have cols and lines, we can update our window + * structure for non-hardware windows. + */ +#ifdef PC7300 + if (hardwindow < 0) { + wdata.uw_x = 0; + wdata.uw_y = 0; + wdata.uw_width = COLS; + wdata.uw_height = LINES; + wdata.uw_uflags = 0; + wdata.uw_hs = 1; + wdata.uw_vs = 1; + wdata.uw_baseline = 0; + } +#endif + 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); + keypad(cw,TRUE); + keypad(msgw,TRUE); + + init_player(); /* Roll up the rogue */ + waswizard = wizard; + +#ifdef WIZARD + /* A super wizard doesn't have to get equipped */ + if (wizard && strcmp(getenv("SUPER"),"YES") == 0) { + level = 1; + new_level(NORMLEV); + } + else +#endif + new_level(STARTLEV); /* Draw current level */ + /* + * Start up daemons and fuses + */ + daemon(doctor, &player, AFTER); + fuse(swander, 0, WANDERTIME, AFTER); + if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_RANGER) + fuse(spell_recovery, 0, SPELLTIME, AFTER); + if (player.t_ctype == C_DRUID || player.t_ctype == C_RANGER) + fuse(chant_recovery, 0, SPELLTIME, AFTER); + if (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN) + fuse(prayer_recovery, 0, SPELLTIME, AFTER); + daemon(stomach, 0, AFTER); + if (player.t_ctype == C_THIEF || + player.t_ctype == C_ASSASIN || + player.t_ctype == C_MONK) + daemon(trap_look, 0, AFTER); + + /* Does this character have any special knowledge? */ + switch (player.t_ctype) { + case C_ASSASIN: + /* Assassins automatically recognize poison */ + p_know[P_POISON] = TRUE; + } + + /* Choose a quest item */ + quest_item = rnd(MAXRELIC); + 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. + */ + +void +endit(sig) +int 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); + endwin(); +#ifdef PC7300 + endhardwin(); +#endif + printf("\n"); /* So the curser doesn't stop at the end of the line */ + exit(0); +} + +/* + * rnd: + * Pick a very random number. + */ +rnd(range) +register int range; +{ + return(range <= 0 ? 0 : 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; +} +# ifdef SIGTSTP +/* + * handle stop and start signals + */ +void +tstp(sig) +int sig; +{ + mvcur(0, cols - 1, lines - 1, 0); + endwin(); + fflush(stdout); + kill(0, SIGTSTP); + signal(SIGTSTP, tstp); + raw(); + noecho(); + keypad(cw,1); + keypad(msgw,1); + clearok(curscr, TRUE); + touchwin(cw); + draw(cw); + md_flushinp(); +} +# endif + +setup() +{ +#ifdef CHECKTIME + int checkout(); + + if (!author()) { + signal(SIGALRM, checkout); + alarm(CHECKTIME * 60); + } +#endif +/* +#ifndef DUMP + signal(SIGILL, bugkill); +#ifdef SIGTRAP + signal(SIGTRAP, bugkill); +#endif +#ifdef SIGIOT + signal(SIGIOT, bugkill); +#endif +#ifdef SIGEMT + signal(SIGEMT, bugkill); +#endif + signal(SIGFPE, bugkill); +#ifdef SIGBUS + signal(SIGBUS, bugkill); +#endif + signal(SIGSEGV, bugkill); +#ifdef SIGSYS + signal(SIGSYS, bugkill); +#endif +#ifdef SIGPIPE + signal(SIGPIPE, bugkill); +#endif +#endif +*/ +#ifdef SIGTSTP + signal(SIGTSTP, tstp); +#endif + +#ifdef SIGHUP + signal(SIGHUP, auto_save); +#endif + signal(SIGTERM, auto_save); + signal(SIGINT, quit); +#ifdef SIGQUIT + signal(SIGQUIT, endit); +#endif + raw(); /* Cbreak mode */ + noecho(); /* Echo off */ + nonl(); +} + +/* + * 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(0); +} + +/* + * see if the system is being used too much for this game + */ +too_much() +{ +#if MAXPROCESSES + if (loadav() > MAXPROCESSES) + return(TRUE); +#endif +#if MAXUSERS + if (ucount() > MAXUSERS) + return(TRUE); +#endif + return(FALSE); +} + +/* + * author: + * See if a user is an author of the program + */ +author() +{ + switch (md_getuid()) { +#if AUTHOR + case AUTHOR: +#endif + case 0: /* always OK for root to play */ + return TRUE; + default: + return FALSE; + } +} + + +#if CHECKTIME +static int num_checks = 0; /* times we've gone over in checkout() */ + +checkout() +{ + static char *msgs[] = { + "The system is too loaded for games. Please leave in %d minutes", + "Please save your game. You have %d minutes", + "This is your last chance. You had better leave in %d minutes", + }; + int checktime; + + signal(SIGALRM, checkout); + if (!holiday() && !author()) { + msg("Game time is over. Your game is being saved.\n\n"); + auto_save(); /* NO RETURN */ + } + if (too_much()) { + if (num_checks >= 3) + fatal("You didn't listen, so now you are DEAD !!\n"); + checktime = CHECKTIME / (num_checks + 1); + chmsg(msgs[num_checks++], checktime); + alarm(checktime * 60); + } + else { + if (num_checks) { + chmsg("The load has dropped. You have a reprieve."); + num_checks = 0; + } + alarm(CHECKTIME * 60); + } +} + +/* + * checkout()'s version of msg. If we are in the middle of a shell, do a + * printf instead of a msg to avoid the refresh. + */ +chmsg(fmt, arg) +char *fmt; +int arg; +{ + if (in_shell) { + printf(fmt, arg); + putchar('\n'); + fflush(stdout); + } + else + msg(fmt, arg); +} +#endif + +#ifdef MAXPROCESSES + +#include + +loadav() +{ + char *sarcmd = "sar -v | cut -c17-20 | tail -2"; + char *gettycmd = "grep getty /etc/inittab | wc -l"; + char sysbuffer[BUFSIZ]; + char tempfile[50]; + char inbuf[BUFSIZ]; + int fd, nprocess, ngetty; + + sprintf(tempfile, "/tmp/rg%d", getpid()); + sprintf(sysbuffer, "%s > %s", sarcmd, tempfile); + if (system(sysbuffer) != 0) { + debug ("system() call failed"); + return (MAXPROCESSES - 1); + } + if ((fd = open(tempfile, O_RDONLY)) == -1) { + debug ("open() call failed"); + return (MAXPROCESSES - 1); + } + if (read(fd, inbuf, BUFSIZ) == -1) { + debug ("read() call failed"); + return (MAXPROCESSES - 1); + } + close(fd); + sscanf(inbuf, "%d", &nprocess); + sprintf(sysbuffer, "%s > %s", gettycmd, tempfile); + if (system(sysbuffer) != 0) { + debug ("system() call failed"); + return (MAXPROCESSES - 1); + } + if ((fd = open(tempfile, O_RDONLY)) == -1) { + debug ("open() call failed"); + return (MAXPROCESSES - 1); + } + if (read(fd, inbuf, BUFSIZ) == -1) { + debug ("read() call failed"); + return (MAXPROCESSES - 1); + } + close(fd); + sscanf(inbuf, "%d", &ngetty); + unlink(tempfile); + return(nprocess - ngetty); +} +#endif + +#ifdef MAXUSERS +/* + * ucount: + * Count the number of people on the system + */ +#include +#include +struct utmp buf; +ucount() +{ + reg struct utmp *up; + reg FILE *utmp; + reg int count; + + if ((utmp = fopen(UTMP, "r")) == NULL) + return 0; + + up = &buf; + count = 0; + while (fread(up, 1, sizeof (*up), utmp) > 0) +#ifdef BSD + if (buf.ut_line[0] == 't') /* On a tty */ +#else + if (buf.ut_type == USER_PROCESS) +#endif + count++; + fclose(utmp); + return count; +} +#endif + +/* + * holiday: + * Returns TRUE when it is a good time to play rogue + */ +holiday() +{ +#ifdef CHECKTIME + long now; + struct tm *localtime(); + reg struct tm *ntime; + + + time(&now); /* get the current time */ + ntime = localtime(&now); + if(ntime->tm_wday == 0 || ntime->tm_wday == 6) + return TRUE; /* OK on Sat & Sun */ + if(ntime->tm_hour < 8 || ntime->tm_hour >= 18) + return TRUE; /* OK before 8AM & after 6PM */ + if(ntime->tm_yday <= 7 || ntime->tm_yday >= 350) + return TRUE; /* OK during Christmas */ + return FALSE; /* All other times are bad */ +#else + return TRUE; +#endif +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/maze.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/maze.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,368 @@ +/* + * maze.c - functions for dealing with mazes + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "curses.h" +#include +#include "rogue.h" + +struct cell { + char y_pos; + char x_pos; +}; +struct bordercells { + char num_pos; /* number of frontier cells next to you */ + struct cell conn[4]; /* the y,x position of above cell */ +} border_cells; + + +static char *frontier, + *bits; +static int maze_lines, + maze_cols; +char *moffset(), + *foffset(); + + +/* + * crankout: + * Does actual drawing of maze to window + */ +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('-'); + else if(x==0 || x==cols-2) /* left | right side */ + addch('|'); + else if (y % 2 == 0 && x % 2 == 0) { + if(*moffset(y, x-1) || *moffset(y, x+1)) + addch('-'); + else + addch('|'); + } + else if (y % 2 == 0) + addch('-'); + else + addch('|'); + } + 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(5) + 5); /* add in one large hunk */ + attach(lvl_obj, item); + cnt = 0; + do { + rnd_pos(rp, &tp); + } until (mvinch(tp.y, tp.x) == FLOOR || cnt++ > 5000); + 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++ > 5000); + mvaddch(tp.y, tp.x, FOOD); + obj->o_pos = tp; + if (rnd(100) < 40) { /* treasure type maze */ + treas = TRUE; + least = 10; + debug("treasure maze"); + } + else { /* normal maze level */ + least = 5; + treas = FALSE; + } + genmonsters(least, treas); +} + + +/* + * draw_maze: + * Generate and draw the maze on the screen + */ +draw_maze() +{ + reg int i, j, more; + reg char *ptr; + + maze_lines = (lines - 3) / 2; + maze_cols = (cols - 1) / 2; + bits = ALLOC((lines - 3) * (cols - 1)); + frontier = ALLOC(maze_lines * maze_cols); + ptr = frontier; + while (ptr < (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(frontier); + FREE(bits); +} + +/* + * findcells: + * Figure out cells to open up + */ +findcells(y,x) +reg int x, y; +{ + reg int rtpos, i; + + *foffset(y, x) = FALSE; + border_cells.num_pos = 0; + if (y < maze_lines - 1) { /* look below */ + if (*foffset(y + 1, x)) { + border_cells.conn[border_cells.num_pos].y_pos = y + 1; + border_cells.conn[border_cells.num_pos].x_pos = x; + border_cells.num_pos += 1; + } + } + if (y > 0) { /* look above */ + if (*foffset(y - 1, x)) { + border_cells.conn[border_cells.num_pos].y_pos = y - 1; + border_cells.conn[border_cells.num_pos].x_pos = x; + border_cells.num_pos += 1; + + } + } + if (x < maze_cols - 1) { /* look right */ + if (*foffset(y, x + 1)) { + border_cells.conn[border_cells.num_pos].y_pos = y; + border_cells.conn[border_cells.num_pos].x_pos = x + 1; + border_cells.num_pos += 1; + } + } + if (x > 0) { /* look left */ + if (*foffset(y, x - 1)) { + border_cells.conn[border_cells.num_pos].y_pos = y; + border_cells.conn[border_cells.num_pos].x_pos = x - 1; + border_cells.num_pos += 1; + + } + } + if (border_cells.num_pos == 0) /* no neighbors available */ + return 0; + else { + i = rnd(border_cells.num_pos); + rtpos = border_cells.num_pos - 1; + rmwall(border_cells.conn[i].y_pos, border_cells.conn[i].x_pos, y, x); + return rtpos; + } +} + +/* + * foffset: + * Calculate memory address for frontier + */ +char * +foffset(y, x) +int y, x; +{ + + return (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, xcheck, 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 '|': + case '-': + 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 '|': + case '-': + 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 '|': + case '-': + 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; + switch (winat(ycheck, xcheck)) { + case '|': + case '-': + case WALL: + case DOOR: + case SECRETDOOR: + return(FALSE); + } + start += delta; + } + return(TRUE); +} + + +/* + * moffset: + * Calculate memory address for bits + */ +char * +moffset(y, x) +int y, x; +{ + + return (bits + (y * (cols - 1)) + x); +} + + + + +/* + * rmwall: + * Removes appropriate walls from the maze + */ +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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/mdport.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/mdport.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1196 @@ +/* + mdport.c - Machine Dependent Code for Porting Unix/Curses games + + Copyright (C) 2005 Nicholas J. Kisseberth + 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. +*/ + +#if defined(_WIN32) +#include +#include +#include +#include +#include +#include +#undef MOUSE_MOVED +#elif defined(__DJGPP__) +#include +#else +#include +#include +#include +#endif + +#include + +#if defined(_WIN32) && !defined(__MINGW32__) +#define PATH_MAX _PATH_MAX +#endif + +#include + +#if defined(__INTERIX) || defined(__MSYS__) +#include +#else +#ifdef NCURSES_VERSION +#include +#endif +#endif + +#include +#include +#include +#include +#include +#include + +#define MOD_MOVE(c) (toupper(c) ) + +void +md_init() +{ +#ifdef __INTERIX + char *term; + + term = getenv("TERM"); + + if (term == NULL) + setenv("TERM","interix"); +#endif +#if defined(__DJGPP__) || defined(_WIN32) + _fmode = _O_BINARY; +#endif +#if defined(__CYGWIN__) || defined(__MSYS__) + ESCDELAY=250; +#endif +} + +int +md_hasclreol() +{ +#ifndef attron + return(!CE); +#elif !defined(__PDCURSES__) + return(clr_eol != NULL); +#else + return(TRUE); +#endif +} + +#ifdef attron +# define _puts(s) tputs(s, 0, md_putchar); +# define SO enter_standout_mode +# define SE exit_standout_mode +#endif + +int +md_putchar(int c) +{ + putchar(c); +} + +static int md_standout_mode = 0; + +int +md_raw_standout() +{ +#ifdef _WIN32 + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + HANDLE hStdout; + int fgattr,bgattr; + + if (md_standout_mode == 0) + { + hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hStdout, &csbiInfo); + fgattr = (csbiInfo.wAttributes & 0xF); + bgattr = (csbiInfo.wAttributes & 0xF0); + SetConsoleTextAttribute(hStdout,(fgattr << 4) | (bgattr >> 4)); + md_standout_mode = 1; + } +#elif !defined(__PDCURSES__) + _puts(SO); + fflush(stdout); +#endif +} + +int +md_raw_standend() +{ +#ifdef _WIN32 + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + HANDLE hStdout; + int fgattr,bgattr; + + if (md_standout_mode == 1) + { + hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hStdout, &csbiInfo); + fgattr = (csbiInfo.wAttributes & 0xF); + bgattr = (csbiInfo.wAttributes & 0xF0); + SetConsoleTextAttribute(hStdout,(fgattr << 4) | (bgattr >> 4)); + md_standout_mode = 0; + } +#elif !defined(__PDCURSES__) + _puts(SE); + fflush(stdout); +#endif +} + +int +md_unlink_open_file(char *file, int inf) +{ +#ifdef _WIN32 + close(inf); + chmod(file, 0600); + return( _unlink(file) ); +#else + return(unlink(file)); +#endif +} + +int +md_unlink(char *file) +{ +#ifdef _WIN32 + chmod(file, 0600); + return( _unlink(file) ); +#else + return(unlink(file)); +#endif +} + +int +md_creat(char *file, int mode) +{ + int fd; +#ifdef _WIN32 + mode = _S_IREAD | _S_IWRITE; +#endif + fd = open(file,O_CREAT | O_EXCL | O_WRONLY, mode); + + return(fd); +} + + +int +md_normaluser() +{ +#ifndef _WIN32 + setuid(getuid()); + setgid(getgid()); +#endif +} + +int +md_getuid() +{ +#ifndef _WIN32 + return( getuid() ); +#else + return(42); +#endif +} + +char * +md_getusername() +{ + static char login[80]; + char *l = NULL; +#ifdef _WIN32 + LPSTR mybuffer; + DWORD size = UNLEN + 1; + TCHAR buffer[UNLEN + 1]; + + mybuffer = buffer; + GetUserName(mybuffer,&size); + l = mybuffer; +#endif +#if !defined(_WIN32) && !defined(DJGPP) + struct passwd *pw; + + pw = getpwuid(getuid()); + + l = pw->pw_name; +#endif + + if ((l == NULL) || (*l == '\0')) + if ( (l = getenv("USERNAME")) == NULL ) + if ( (l = getenv("LOGNAME")) == NULL ) + if ( (l = getenv("USER")) == NULL ) + l = "nobody"; + + strncpy(login,l,80); + login[79] = 0; + + return(login); +} + +char * +md_gethomedir() +{ + static char homedir[PATH_MAX]; + char *h = NULL; + size_t len; +#if defined(_WIN32) + TCHAR szPath[PATH_MAX]; +#endif +#if defined(_WIN32) || defined(DJGPP) + char slash = '\\'; +#else + char slash = '/'; + struct passwd *pw; + pw = getpwuid(getuid()); + + h = pw->pw_dir; + + if (strcmp(h,"/") == 0) + h = NULL; +#endif + homedir[0] = 0; +#ifdef _WIN32 + if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, szPath))) + h = szPath; +#endif + + if ( (h == NULL) || (*h == '\0') ) + if ( (h = getenv("HOME")) == NULL ) + if ( (h = getenv("HOMEDRIVE")) == NULL) + h = ""; + else + { + strncpy(homedir,h,PATH_MAX-1); + homedir[PATH_MAX-1] = 0; + + if ( (h = getenv("HOMEPATH")) == NULL) + h = ""; + } + + + len = strlen(homedir); + strncat(homedir,h,PATH_MAX-len-1); + len = strlen(homedir); + + if ((len > 0) && (homedir[len-1] != slash)) { + homedir[len] = slash; + homedir[len+1] = 0; + } + + return(homedir); +} + +int +md_sleep(int s) +{ +#ifdef _WIN32 + _sleep(s); +#else + sleep(s); +#endif +} + +char * +md_getshell() +{ + static char shell[PATH_MAX]; + char *s = NULL; +#ifdef _WIN32 + char *def = "C:\\WINDOWS\\SYSTEM32\\CMD.EXE"; +#elif defined(__DJGPP__) + char *def = "C:\\COMMAND.COM"; +#else + char *def = "/bin/sh"; + struct passwd *pw; + pw = getpwuid(getuid()); + s = pw->pw_shell; +#endif + if ((s == NULL) || (*s == '\0')) + if ( (s = getenv("COMSPEC")) == NULL) + if ( (s = getenv("SHELL")) == NULL) + if ( (s = getenv("SystemRoot")) == NULL) + s = def; + + strncpy(shell,s,PATH_MAX); + shell[PATH_MAX-1] = 0; + + return(shell); +} + +int +md_shellescape() +{ +#if (!defined(_WIN32) && !defined(__DJGPP__)) + int ret_status; + int pid; + void (*myquit)(int); + void (*myend)(int); +#endif + char *sh; + + sh = md_getshell(); + +#if defined(_WIN32) + return((int)_spawnl(_P_WAIT,sh,"shell",NULL,0)); +#elif defined(__DJGPP__) + return ( spawnl(P_WAIT,sh,"shell",NULL,0) ); +#else + while((pid = fork()) < 0) + sleep(1); + + if (pid == 0) /* Shell Process */ + { + /* + * Set back to original user, just in case + */ + setuid(getuid()); + setgid(getgid()); + execl(sh == NULL ? "/bin/sh" : sh, "shell", "-i", 0); + perror("No shelly"); + _exit(-1); + } + else /* Application */ + { + myend = signal(SIGINT, SIG_IGN); +#ifdef SIGQUIT + myquit = signal(SIGQUIT, SIG_IGN); +#endif + while (wait(&ret_status) != pid) + continue; + + signal(SIGINT, myquit); +#ifdef SIGQUIT + signal(SIGQUIT, myend); +#endif + } + + return(ret_status); +#endif +} + +int +directory_exists(char *dirname) +{ + struct stat sb; + + if (stat(dirname, &sb) == 0) /* path exists */ + return (sb.st_mode & S_IFDIR); + + return(0); +} + +char * +md_getroguedir() +{ + static char path[1024]; + char *end,*home; + + if ( (home = getenv("ROGUEHOME")) != NULL) + { + if (*home) + { + strncpy(path, home, PATH_MAX - 20); + + end = &path[strlen(path)-1]; + + while( (end >= path) && ((*end == '/') || (*end == '\\'))) + *end-- = '\0'; + + if (directory_exists(path)) + return(path); + } + } + + if (directory_exists("/var/games/roguelike")) + return("/var/games/roguelike"); + if (directory_exists("/var/lib/roguelike")) + return("/var/lib/roguelike"); + if (directory_exists("/var/roguelike")) + return("/var/roguelike"); + if (directory_exists("/usr/games/lib")) + return("/usr/games/lib"); + if (directory_exists("/games/roguelik")) + return("/games/roguelik"); + + return(""); +} + +char * +md_getrealname(int uid) +{ + static char uidstr[20]; +#if !defined(_WIN32) && !defined(DJGPP) + struct passwd *pp; + + if ((pp = getpwuid(uid)) == NULL) + { + sprintf(uidstr,"%d", uid); + return(uidstr); + } + else + return(pp->pw_name); +#else + sprintf(uidstr,"%d", uid); + return(uidstr); +#endif +} + +extern char *xcrypt(char *key, char *salt); + +char * +md_crypt(char *key, char *salt) +{ + return( xcrypt(key,salt) ); +} + +char * +md_getpass(prompt) +char *prompt; +{ +#ifdef _WIN32 + static char password_buffer[9]; + char *p = password_buffer; + int c, count = 0; + int max_length = 9; + + fflush(stdout); + /* If we can't prompt, abort */ + if (fputs(prompt, stderr) < 0) + { + *p = '\0'; + return NULL; + } + + for(;;) + { + /* Get a character with no echo */ + c = _getch(); + + /* Exit on interrupt (^c or ^break) */ + if (c == '\003' || c == 0x100) + exit(1); + + /* Terminate on end of line or file (^j, ^m, ^d, ^z) */ + if (c == '\r' || c == '\n' || c == '\004' || c == '\032') + break; + + /* Back up on backspace */ + if (c == '\b') + { + if (count) + count--; + else if (p > password_buffer) + p--; + continue; + } + + /* Ignore DOS extended characters */ + if ((c & 0xff) != c) + continue; + + /* Add to password if it isn't full */ + if (p < password_buffer + max_length - 1) + *p++ = c; + else + count++; + } + *p = '\0'; + + fputc('\n', stderr); + + return password_buffer; +#else + return( (char *) getpass(prompt) ); +#endif +} + + +int md_endian = 0x01020304; + +unsigned long int +md_ntohl(unsigned long int x) +{ +#ifdef _WIN32 + if ( *((char *)&md_endian) == 0x01 ) + return(x); + else + return( ((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24) ); +#else + return( ntohl(x) ); +#endif +} + +unsigned long int +md_htonl(unsigned long int x) +{ +#ifdef _WIN32 + if ( *((char *)&md_endian) == 0x01 ) + return(x); + else + return( ((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24) ); +#else + return( htonl(x) ); +#endif +} + +int +md_rand() +{ +#ifdef _WIN32 + return(rand()); +#else + return(random()); +#endif +} + +int +md_srand(seed) +register int seed; +{ +#ifdef _WIN32 + srand(seed); +#else + srandom(seed); +#endif +} + +long +md_memused() +{ +#ifdef _WIN32 + MEMORYSTATUS stat; + + GlobalMemoryStatus(&stat); + + return((long)stat.dwTotalPageFile); +#else + return( (long)sbrk(0) ); +#endif +} + +char * +md_gethostname() +{ + static char nodename[80]; + char *n = NULL; +#if !defined(_WIN32) && !defined(__DJGPP__) + struct utsname ourname; + + if (uname(&ourname) == 0) + n = ourname.nodename; +#endif + if ((n == NULL) || (*n == '\0')) + if ( (n = getenv("COMPUTERNAME")) == NULL) + if ( (n = getenv("HOSTNAME")) == NULL) + n = "localhost"; + + strncpy(nodename, n, 80); + nodename[79] = 0; + + return(nodename); +} + +int +md_erasechar() +{ +#ifdef BSD + return(_tty.sg_erase); /* process erase character */ +#elif defined(USG5_0) + return(_tty.c_cc[VERASE]); /* process erase character */ +#else /* USG5_2 .... curses */ + return( erasechar() ); /* process erase character */ +#endif +} + +int +md_killchar() +{ +#ifdef BSD + return(_tty.sg_kill); +#elif defined(USG5_0) + return(_tty.c_cc[VKILL]); +#else /* USG5_2 ..... curses */ + return( killchar() ); +#endif +} + +/* + * unctrl: + * Print a readable version of a certain character + */ + +char * +md_unctrl(ch) +char ch; +{ +#if USG5_0 + extern char *_unctrl[]; /* Defined in curses library */ + + return _unctrl[ch&0177]; +#else + return( unctrl(ch) ); +#endif +} + +void +md_flushinp() +{ +#ifdef BSD + ioctl(0, TIOCFLUSH); +#elif defined(USG5_0) + ioctl(_tty_ch,TCFLSH,0) +#else /* USG5_2.... curses */ + flushinp(); +#endif +} + +/* + Cursor/Keypad Support + + Sadly Cursor/Keypad support is less straightforward than it should be. + + The various terminal emulators/consoles choose to differentiate the + cursor and keypad keys (with modifiers) in different ways (if at all!). + Furthermore they use different code set sequences for each key only + a subset of which the various curses libraries recognize. Partly due + to incomplete termcap/terminfo entries and partly due to inherent + limitations of those terminal capability databases. + + I give curses first crack at decoding the sequences. If it fails to decode + it we check for common ESC-prefixed sequences. + + All cursor/keypad results are translated into standard rogue movement + commands. + + Unmodified keys are translated to walk commands: hjklyubn + Modified (shift,control,alt) are translated to run commands: HJKLYUBN + + Console and supported (differentiated) keys + Interix: Cursor Keys, Keypad, Ctl-Keypad + Cygwin: Cursor Keys, Keypad, Alt-Cursor Keys + MSYS: Cursor Keys, Keypad, Ctl-Cursor Keys, Ctl-Keypad + Win32: Cursor Keys, Keypad, Ctl/Shift/Alt-Cursor Keys, Ctl/Alt-Keypad + DJGPP: Cursor Keys, Keypad, Ctl/Shift/Alt-Cursor Keys, Ctl/Alt-Keypad + + Interix Console (raw, ncurses) + ============================== + normal shift ctrl alt + ESC [D, ESC F^, ESC [D, ESC [D /# Left #/ + ESC [C, ESC F$, ESC [C, ESC [C /# Right #/ + ESC [A, ESC F-, local win, ESC [A /# Up #/ + ESC [B, ESC F+, local win, ESC [B /# Down #/ + ESC [H, ESC [H, ESC [H, ESC [H /# Home #/ + ESC [S, local win, ESC [S, ESC [S /# Page Up #/ + ESC [T, local win, ESC [T, ESC [T /# Page Down #/ + ESC [U, ESC [U, ESC [U, ESC [U /# End #/ + ESC [D, ESC F^, ESC [D, O /# Keypad Left #/ + ESC [C, ESC F$, ESC [C, O /# Keypad Right #/ + ESC [A, ESC [A, ESC [-1, O /# Keypad Up #/ + ESC [B, ESC [B, ESC [-2, O /# Keypad Down #/ + ESC [H, ESC [H, ESC [-263, O /# Keypad Home #/ + ESC [S, ESC [S, ESC [-19, O /# Keypad PgUp #/ + ESC [T, ESC [T, ESC [-20, O /# Keypad PgDn #/ + ESC [U, ESC [U, ESC [-21, O /# Keypad End #/ + nothing, nothing, nothing, O /# Kaypad 5 #/ + + Interix Console (term=interix, ncurses) + ============================== + KEY_LEFT, ESC F^, KEY_LEFT, KEY_LEFT /# Left #/ + KEY_RIGHT, ESC F$, KEY_RIGHT, KEY_RIGHT /# Right #/ + KEY_UP, 0x146, local win, KEY_UP /# Up #/ + KEY_DOWN, 0x145, local win, KEY_DOWN /# Down #/ + ESC [H, ESC [H, ESC [H, ESC [H /# Home #/ + KEY_PPAGE, local win, KEY_PPAGE, KEY_PPAGE /# Page Up #/ + KEY_NPAGE, local win, KEY_NPAGE, KEY_NPAGE /# Page Down #/ + KEY_LL, KEY_LL, KEY_LL, KEY_LL /# End #/ + KEY_LEFT, ESC F^, ESC [-4, O /# Keypad Left #/ + KEY_RIGHT, ESC F$, ESC [-3, O /# Keypad Right #/ + KEY_UP, KEY_UP, ESC [-1, O /# Keypad Up #/ + KEY_DOWN, KEY_DOWN, ESC [-2, O /# Keypad Down #/ + ESC [H, ESC [H, ESC [-263, O /# Keypad Home #/ + KEY_PPAGE, KEY_PPAGE, ESC [-19, O /# Keypad PgUp #/ + KEY_NPAGE, KEY_NPAGE, ESC [-20, O /# Keypad PgDn #/ + KEY_LL, KEY_LL, ESC [-21, O /# Keypad End #/ + nothing, nothing, nothing, O /# Keypad 5 #/ + + Cygwin Console (raw, ncurses) + ============================== + normal shift ctrl alt + ESC [D, ESC [D, ESC [D, ESC ESC [D /# Left #/ + ESC [C, ESC [C, ESC [C, ESC ESC [C /# Rght #/ + ESC [A, ESC [A, ESC [A, ESC ESC [A /# Up #/ + ESC [B, ESC [B, ESC [B, ESC ESC [B /# Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC ESC [1~ /# Home #/ + ESC [5~, ESC [5~, ESC [5~, ESC ESC [5~ /# Page Up #/ + ESC [6~, ESC [6~, ESC [6~, ESC ESC [6~ /# Page Down #/ + ESC [4~, ESC [4~, ESC [4~, ESC ESC [4~ /# End #/ + ESC [D, ESC [D, ESC [D, ESC ESC [D,O /# Keypad Left #/ + ESC [C, ESC [C, ESC [C, ESC ESC [C,O /# Keypad Right #/ + ESC [A, ESC [A, ESC [A, ESC ESC [A,O /# Keypad Up #/ + ESC [B, ESC [B, ESC [B, ESC ESC [B,O /# Keypad Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC ESC [1~,O /# Keypad Home #/ + ESC [5~, ESC [5~, ESC [5~, ESC ESC [5~,O /# Keypad PgUp #/ + ESC [6~, ESC [6~, ESC [6~, ESC ESC [6~,O /# Keypad PgDn #/ + ESC [4~, ESC [4~, ESC [4~, ESC ESC [4~,O /# Keypad End #/ + ESC [-71, nothing, nothing, O /# Keypad 5 #/ + + Cygwin Console (term=cygwin, ncurses) + ============================== + KEY_LEFT, KEY_LEFT, KEY_LEFT, ESC-260 /# Left #/ + KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, ESC-261 /# Rght #/ + KEY_UP, KEY_UP, KEY_UP, ESC-259 /# Up #/ + KEY_DOWN, KEY_DOWN, KEY_DOWN, ESC-258 /# Down #/ + KEY_HOME, KEY_HOME, KEY_HOME, ESC-262 /# Home #/ + KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, ESC-339 /# Page Up #/ + KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, ESC-338 /# Page Down #/ + KEY_END, KEY_END, KEY_END, ESC-360 /# End #/ + KEY_LEFT, KEY_LEFT, KEY_LEFT, ESC-260,O /# Keypad Left #/ + KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, ESC-261,O /# Keypad Right #/ + KEY_UP, KEY_UP, KEY_UP, ESC-259,O /# Keypad Up #/ + KEY_DOWN, KEY_DOWN, KEY_DOWN, ESC-258,O /# Keypad Down #/ + KEY_HOME, KEY_HOME, KEY_HOME, ESC-262,O /# Keypad Home #/ + KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, ESC-339,O /# Keypad PgUp #/ + KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, ESC-338,O /# Keypad PgDn #/ + KEY_END, KEY_END, KEY_END, ESC-360,O /# Keypad End #/ + ESC [G, nothing, nothing, O /# Keypad 5 #/ + + MSYS Console (raw, ncurses) + ============================== + normal shift ctrl alt + ESC OD, ESC [d, ESC Od nothing /# Left #/ + ESC OE, ESC [e, ESC Oe, nothing /# Right #/ + ESC OA, ESC [a, ESC Oa, nothing /# Up #/ + ESC OB, ESC [b, ESC Ob, nothing /# Down #/ + ESC [7~, ESC [7$, ESC [7^, nothing /# Home #/ + ESC [5~, local window, ESC [5^, nothing /# Page Up #/ + ESC [6~, local window, ESC [6^, nothing /# Page Down #/ + ESC [8~, ESC [8$, ESC [8^, nothing /# End #/ + ESC OD, ESC [d, ESC Od O /# Keypad Left #/ + ESC OE, ESC [c, ESC Oc, O /# Keypad Right #/ + ESC OA, ESC [a, ESC Oa, O /# Keypad Up #/ + ESC OB, ESC [b, ESC Ob, O /# Keypad Down #/ + ESC [7~, ESC [7$, ESC [7^, O /# Keypad Home #/ + ESC [5~, local window, ESC [5^, O /# Keypad PgUp #/ + ESC [6~, local window, ESC [6^, O /# Keypad PgDn #/ + ESC [8~, ESC [8$, ESC [8^, O /# Keypad End #/ + 11, 11, 11, O /# Keypad 5 #/ + + MSYS Console (term=rxvt, ncurses) + ============================== + normal shift ctrl alt + KEY_LEFT, KEY_SLEFT, 514 nothing /# Left #/ + KEY_RIGHT, KEY_SRIGHT, 516, nothing /# Right #/ + KEY_UP, 518, 519, nothing /# Up #/ + KEY_DOWN, 511, 512, nothing /# Down #/ + KEY_HOME, KEY_SHOME, ESC [7^, nothing /# Home #/ + KEY_PPAGE, local window, ESC [5^, nothing /# Page Up #/ + KEY_NPAGE, local window, ESC [6^, nothing /# Page Down #/ + KEY_END, KEY_SEND, KEY_EOL, nothing /# End #/ + KEY_LEFT, KEY_SLEFT, 514 O /# Keypad Left #/ + KEY_RIGHT, KEY_SRIGHT, 516, O /# Keypad Right #/ + KEY_UP, 518, 519, O /# Keypad Up #/ + KEY_DOWN, 511, 512, O /# Keypad Down #/ + KEY_HOME, KEY_SHOME, ESC [7^, O /# Keypad Home #/ + KEY_PPAGE, local window, ESC [5^, O /# Keypad PgUp #/ + KEY_NPAGE, local window, ESC [6^, O /# Keypad PgDn #/ + KEY_END, KEY_SEND, KEY_EOL, O /# Keypad End #/ + 11, 11, 11, O /# Keypad 5 #/ + + Win32 Console (raw, pdcurses) + DJGPP Console (raw, pdcurses) + ============================== + normal shift ctrl alt + 260, 391, 443, 493 /# Left #/ + 261, 400, 444, 492 /# Right #/ + 259, 547, 480, 490 /# Up #/ + 258, 548, 481, 491 /# Down #/ + 262, 388, 447, 524 /# Home #/ + 339, 396, 445, 526 /# Page Up #/ + 338, 394, 446, 520 /# Page Down #/ + 358, 384, 448, 518 /# End #/ + 452, 52('4'), 511, 521 /# Keypad Left #/ + 454, 54('6'), 513, 523 /# Keypad Right #/ + 450, 56('8'), 515, 525 /# Keypad Up #/ + 456, 50('2'), 509, 519 /# Keypad Down #/ + 449, 55('7'), 514, 524 /# Keypad Home #/ + 451, 57('9'), 516, 526 /# Keypad PgUp #/ + 457, 51('3'), 510, 520 /# Keypad PgDn #/ + 455, 49('1'), 508, 518 /# Keypad End #/ + 453, 53('5'), 512, 522 /# Keypad 5 #/ + + Win32 Console (pdcurses, MSVC/MingW32) + DJGPP Console (pdcurses) + ============================== + normal shift ctrl alt + KEY_LEFT, KEY_SLEFT, CTL_LEFT, ALT_LEFT /# Left #/ + KEY_RIGHT, KEY_SRIGHT, CTL_RIGHT, ALT_RIGHT /# Right #/ + KEY_UP, KEY_SUP, CTL_UP, ALT_UP /# Up #/ + KEY_DOWN, KEY_SDOWN, CTL_DOWN, ALT_DOWN /# Down #/ + KEY_HOME, KEY_SHOME, CTL_HOME, ALT_HOME /# Home #/ + KEY_PPAGE, KEY_SPREVIOUS, CTL_PGUP, ALT_PGUP /# Page Up #/ + KEY_NPAGE, KEY_SNEXTE, CTL_PGDN, ALT_PGDN /# Page Down #/ + KEY_END, KEY_SEND, CTL_END, ALT_END /# End #/ + KEY_B1, 52('4'), CTL_PAD4, ALT_PAD4 /# Keypad Left #/ + KEY_B3, 54('6'), CTL_PAD6, ALT_PAD6 /# Keypad Right #/ + KEY_A2, 56('8'), CTL_PAD8, ALT_PAD8 /# Keypad Up #/ + KEY_C2, 50('2'), CTL_PAD2, ALT_PAD2 /# Keypad Down #/ + KEY_A1, 55('7'), CTL_PAD7, ALT_PAD7 /# Keypad Home #/ + KEY_A3, 57('9'), CTL_PAD9, ALT_PAD9 /# Keypad PgUp #/ + KEY_C3, 51('3'), CTL_PAD3, ALT_PAD3 /# Keypad PgDn #/ + KEY_C1, 49('1'), CTL_PAD1, ALT_PAD1 /# Keypad End #/ + KEY_B2, 53('5'), CTL_PAD5, ALT_PAD5 /# Keypad 5 #/ + + Windows Telnet (raw) + ============================== + normal shift ctrl alt + ESC [D, ESC [D, ESC [D, ESC [D /# Left #/ + ESC [C, ESC [C, ESC [C, ESC [C /# Right #/ + ESC [A, ESC [A, ESC [A, ESC [A /# Up #/ + ESC [B, ESC [B, ESC [B, ESC [B /# Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Home #/ + ESC [5~, ESC [5~, ESC [5~, ESC [5~ /# Page Up #/ + ESC [6~, ESC [6~, ESC [6~, ESC [6~ /# Page Down #/ + ESC [4~, ESC [4~, ESC [4~, ESC [4~ /# End #/ + ESC [D, ESC [D, ESC [D, ESC [D /# Keypad Left #/ + ESC [C, ESC [C, ESC [C, ESC [C /# Keypad Right #/ + ESC [A, ESC [A, ESC [A, ESC [A /# Keypad Up #/ + ESC [B, ESC [B, ESC [B, ESC [B /# Keypad Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Keypad Home #/ + ESC [5~, ESC [5~, ESC [5~, ESC [5~ /# Keypad PgUp #/ + ESC [6~, ESC [6~, ESC [6~, ESC [6~ /# Keypad PgDn #/ + ESC [4~, ESC [4~, ESC [4~, ESC [4~ /# Keypad End #/ + nothing, nothing, nothing, nothing /# Keypad 5 #/ + + Windows Telnet (term=xterm) + ============================== + normal shift ctrl alt + KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT /# Left #/ + KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, KEY_RIGHT /# Right #/ + KEY_UP, KEY_UP, KEY_UP, KEY_UP /# Up #/ + KEY_DOWN, KEY_DOWN, KEY_DOWN, KEY_DOWN /# Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Home #/ + KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, KEY_PPAGE /# Page Up #/ + KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, KEY_NPAGE /# Page Down #/ + ESC [4~, ESC [4~, ESC [4~, ESC [4~ /# End #/ + KEY_LEFT, KEY_LEFT, KEY_LEFT, O /# Keypad Left #/ + KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, O /# Keypad Right #/ + KEY_UP, KEY_UP, KEY_UP, O /# Keypad Up #/ + KEY_DOWN, KEY_DOWN, KEY_DOWN, O /# Keypad Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Keypad Home #/ + KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, KEY_PPAGE /# Keypad PgUp #/ + KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, KEY_NPAGE /# Keypad PgDn #/ + ESC [4~, ESC [4~, ESC [4~, O /# Keypad End #/ + ESC [-71, nothing, nothing, O /# Keypad 5 #/ + + PuTTY + ============================== + normal shift ctrl alt + ESC [D, ESC [D, ESC OD, ESC [D /# Left #/ + ESC [C, ESC [C, ESC OC, ESC [C /# Right #/ + ESC [A, ESC [A, ESC OA, ESC [A /# Up #/ + ESC [B, ESC [B, ESC OB, ESC [B /# Down #/ + ESC [1~, ESC [1~, local win, ESC [1~ /# Home #/ + ESC [5~, local win, local win, ESC [5~ /# Page Up #/ + ESC [6~, local win, local win, ESC [6~ /# Page Down #/ + ESC [4~, ESC [4~, local win, ESC [4~ /# End #/ + ESC [D, ESC [D, ESC [D, O /# Keypad Left #/ + ESC [C, ESC [C, ESC [C, O /# Keypad Right #/ + ESC [A, ESC [A, ESC [A, O /# Keypad Up #/ + ESC [B, ESC [B, ESC [B, O /# Keypad Down #/ + ESC [1~, ESC [1~, ESC [1~, O /# Keypad Home #/ + ESC [5~, ESC [5~, ESC [5~, O /# Keypad PgUp #/ + ESC [6~, ESC [6~, ESC [6~, O /# Keypad PgDn #/ + ESC [4~, ESC [4~, ESC [4~, O /# Keypad End #/ + nothing, nothing, nothing, O /# Keypad 5 #/ + + PuTTY + ============================== + normal shift ctrl alt + KEY_LEFT, KEY_LEFT, ESC OD, ESC KEY_LEFT /# Left #/ + KEY_RIGHT KEY_RIGHT, ESC OC, ESC KEY_RIGHT /# Right #/ + KEY_UP, KEY_UP, ESC OA, ESC KEY_UP /# Up #/ + KEY_DOWN, KEY_DOWN, ESC OB, ESC KEY_DOWN /# Down #/ + ESC [1~, ESC [1~, local win, ESC ESC [1~ /# Home #/ + KEY_PPAGE local win, local win, ESC KEY_PPAGE /# Page Up #/ + KEY_NPAGE local win, local win, ESC KEY_NPAGE /# Page Down #/ + ESC [4~, ESC [4~, local win, ESC ESC [4~ /# End #/ + ESC Ot, ESC Ot, ESC Ot, O /# Keypad Left #/ + ESC Ov, ESC Ov, ESC Ov, O /# Keypad Right #/ + ESC Ox, ESC Ox, ESC Ox, O /# Keypad Up #/ + ESC Or, ESC Or, ESC Or, O /# Keypad Down #/ + ESC Ow, ESC Ow, ESC Ow, O /# Keypad Home #/ + ESC Oy, ESC Oy, ESC Oy, O /# Keypad PgUp #/ + ESC Os, ESC Os, ESC Os, O /# Keypad PgDn #/ + ESC Oq, ESC Oq, ESC Oq, O /# Keypad End #/ + ESC Ou, ESC Ou, ESC Ou, O /# Keypad 5 #/ +*/ + +#define M_NORMAL 0 +#define M_ESC 1 +#define M_KEYPAD 2 +#define M_TRAIL 3 + +int +md_readchar(WINDOW *win) +{ + int ch = 0; + int lastch = 0; + int mode = M_NORMAL; + int mode2 = M_NORMAL; + + while(1) + { + ch = wgetch(win); + + if (ch == ERR) /* timed out waiting for valid sequence */ + { /* flush input so far and start over */ + mode = M_NORMAL; + nocbreak(); + raw(); + ch = 27; + break; + } + + if (mode == M_TRAIL) + { + if (ch == '^') /* msys console : 7,5,6,8: modified*/ + ch = MOD_MOVE( toupper(lastch) ); + + if (ch == '~') /* cygwin console: 1,5,6,4: normal */ + ch = tolower(lastch); /* windows telnet: 1,5,6,4: normal */ + /* msys console : 7,5,6,8: normal */ + + if (mode2 == M_ESC) /* cygwin console: 1,5,6,4: modified*/ + ch = MOD_MOVE( toupper(ch) ); + + break; + } + + if (mode == M_ESC) + { + if (ch == 27) + { + mode2 = M_ESC; + continue; + } + + if ((ch == 'F') || (ch == 'O') || (ch == '[')) + { + mode = M_KEYPAD; + continue; + } + + + switch(ch) + { + /* Cygwin Console */ + /* PuTTY */ + case KEY_LEFT : ch = MOD_MOVE('H'); break; + case KEY_RIGHT: ch = MOD_MOVE('L'); break; + case KEY_UP : ch = MOD_MOVE('K'); break; + case KEY_DOWN : ch = MOD_MOVE('J'); break; + case KEY_HOME : ch = MOD_MOVE('Y'); break; + case KEY_PPAGE: ch = MOD_MOVE('U'); break; + case KEY_NPAGE: ch = MOD_MOVE('N'); break; + case KEY_END : ch = MOD_MOVE('B'); break; + + default: break; + } + + break; + } + + if (mode == M_KEYPAD) + { + switch(ch) + { + /* ESC F - Interix Console codes */ + case '^': ch = MOD_MOVE('H'); break; /* Shift-Left */ + case '$': ch = MOD_MOVE('L'); break; /* Shift-Right */ + + /* ESC [ - Interix Console codes */ + case 'H': ch = 'y'; break; /* Home */ + case 1: ch = MOD_MOVE('K'); break; /* Ctl-Keypad Up */ + case 2: ch = MOD_MOVE('J'); break; /* Ctl-Keypad Down */ + case 3: ch = MOD_MOVE('L'); break; /* Ctl-Keypad Right */ + case 4: ch = MOD_MOVE('H'); break; /* Ctl-Keypad Left */ + case 263: ch = MOD_MOVE('Y'); break; /* Ctl-Keypad Home */ + case 19: ch = MOD_MOVE('U'); break; /* Ctl-Keypad PgUp */ + case 20: ch = MOD_MOVE('N'); break; /* Ctl-Keypad PgDn */ + case 21: ch = MOD_MOVE('B'); break; /* Ctl-Keypad End */ + + /* ESC [ - Cygwin Console codes */ + case 'G': ch = '.'; break; /* Keypad 5 */ + case '7': lastch = 'Y'; mode=M_TRAIL; break; /* Ctl-Home */ + case '5': lastch = 'U'; mode=M_TRAIL; break; /* Ctl-PgUp */ + case '6': lastch = 'N'; mode=M_TRAIL; break; /* Ctl-PgDn */ + + /* ESC [ - Win32 Telnet, PuTTY */ + case '1': lastch = 'y'; mode=M_TRAIL; break; /* Home */ + case '4': lastch = 'b'; mode=M_TRAIL; break; /* End */ + + /* ESC O - PuTTY */ + case 'D': ch = MOD_MOVE('H'); break; + case 'C': ch = MOD_MOVE('L'); break; + case 'A': ch = MOD_MOVE('K'); break; + case 'B': ch = MOD_MOVE('J'); break; + case 't': ch = 'h'; break; + case 'v': ch = 'l'; break; + case 'x': ch = 'k'; break; + case 'r': ch = 'j'; break; + case 'w': ch = 'y'; break; + case 'y': ch = 'u'; break; + case 's': ch = 'n'; break; + case 'q': ch = 'b'; break; + case 'u': ch = '.'; break; + } + + if (mode != M_KEYPAD) + continue; + } + + if (ch == 27) + { + halfdelay(1); + mode = M_ESC; + continue; + } + + switch(ch) + { + case KEY_LEFT : ch = 'h'; break; + case KEY_DOWN : ch = 'j'; break; + case KEY_UP : ch = 'k'; break; + case KEY_RIGHT : ch = 'l'; break; + case KEY_HOME : ch = 'y'; break; + case KEY_PPAGE : ch = 'u'; break; + case KEY_END : ch = 'b'; break; +#ifdef KEY_LL + case KEY_LL : ch = 'b'; break; +#endif + case KEY_NPAGE : ch = 'n'; break; + +#ifdef KEY_B1 + case KEY_B1 : ch = 'h'; break; + case KEY_C2 : ch = 'j'; break; + case KEY_A2 : ch = 'k'; break; + case KEY_B3 : ch = 'l'; break; +#endif + case KEY_A1 : ch = 'y'; break; + case KEY_A3 : ch = 'u'; break; + case KEY_C1 : ch = 'b'; break; + case KEY_C3 : ch = 'n'; break; + /* next should be '.', but for problem with putty/linux */ + case KEY_B2 : ch = 'u'; break; + +#ifdef KEY_SLEFT + case KEY_SRIGHT : ch = MOD_MOVE('L'); break; + case KEY_SLEFT : ch = MOD_MOVE('H'); break; +#ifdef KEY_SUP + case KEY_SUP : ch = MOD_MOVE('K'); break; + case KEY_SDOWN : ch = MOD_MOVE('J'); break; +#endif + case KEY_SHOME : ch = MOD_MOVE('Y'); break; + case KEY_SPREVIOUS:ch = MOD_MOVE('U'); break; + case KEY_SEND : ch = MOD_MOVE('B'); break; + case KEY_SNEXT : ch = MOD_MOVE('N'); break; +#endif + case 0x146 : ch = MOD_MOVE('K'); break; /* Shift-Up */ + case 0x145 : ch = MOD_MOVE('J'); break; /* Shift-Down */ + +#ifdef CTL_RIGHT + case CTL_RIGHT : ch = MOD_MOVE('L'); break; + case CTL_LEFT : ch = MOD_MOVE('H'); break; + case CTL_UP : ch = MOD_MOVE('K'); break; + case CTL_DOWN : ch = MOD_MOVE('J'); break; + case CTL_HOME : ch = MOD_MOVE('Y'); break; + case CTL_PGUP : ch = MOD_MOVE('U'); break; + case CTL_END : ch = MOD_MOVE('B'); break; + case CTL_PGDN : ch = MOD_MOVE('N'); break; +#endif +#ifdef KEY_EOL + case KEY_EOL : ch = MOD_MOVE('B'); break; +#endif + +#ifndef CTL_PAD1 + /* MSYS rxvt console */ + case 511 : ch = MOD_MOVE('J'); break; /* Shift Dn */ + case 512 : ch = MOD_MOVE('J'); break; /* Ctl Down */ + case 514 : ch = MOD_MOVE('H'); break; /* Ctl Left */ + case 516 : ch = MOD_MOVE('L'); break; /* Ctl Right*/ + case 518 : ch = MOD_MOVE('K'); break; /* Shift Up */ + case 519 : ch = MOD_MOVE('K'); break; /* Ctl Up */ +#endif + +#ifdef CTL_PAD1 + case CTL_PAD1 : ch = MOD_MOVE('B'); break; + case CTL_PAD2 : ch = MOD_MOVE('J'); break; + case CTL_PAD3 : ch = MOD_MOVE('N'); break; + case CTL_PAD4 : ch = MOD_MOVE('H'); break; + case CTL_PAD5 : ch = '.'; break; + case CTL_PAD6 : ch = MOD_MOVE('L'); break; + case CTL_PAD7 : ch = MOD_MOVE('Y'); break; + case CTL_PAD8 : ch = MOD_MOVE('K'); break; + case CTL_PAD9 : ch = MOD_MOVE('U'); break; +#endif + +#ifdef ALT_RIGHT + case ALT_RIGHT : ch = MOD_MOVE('L'); break; + case ALT_LEFT : ch = MOD_MOVE('H'); break; + case ALT_DOWN : ch = MOD_MOVE('J'); break; + case ALT_HOME : ch = MOD_MOVE('Y'); break; + case ALT_PGUP : ch = MOD_MOVE('U'); break; + case ALT_END : ch = MOD_MOVE('B'); break; + case ALT_PGDN : ch = MOD_MOVE('N'); break; +#endif + +#ifdef ALT_PAD1 + case ALT_PAD1 : ch = MOD_MOVE('B'); break; + case ALT_PAD2 : ch = MOD_MOVE('J'); break; + case ALT_PAD3 : ch = MOD_MOVE('N'); break; + case ALT_PAD4 : ch = MOD_MOVE('H'); break; + case ALT_PAD5 : ch = '.'; break; + case ALT_PAD6 : ch = MOD_MOVE('L'); break; + case ALT_PAD7 : ch = MOD_MOVE('Y'); break; + case ALT_PAD8 : ch = MOD_MOVE('K'); break; + case ALT_PAD9 : ch = MOD_MOVE('U'); break; +#endif + } + + break; + } + + nocbreak(); /* disable halfdelay mode if on */ + raw(); + + return(ch & 0x7F); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/misc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/misc.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1203 @@ +/* + * misc.c - routines dealing specifically with miscellaneous magic + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "curses.h" +#include +#include +#include "rogue.h" +#ifdef PC7300 +#include "menu.h" +#endif + +/* + * routines dealing specifically with miscellaneous magic + */ + +/* + * changeclass: + * Change the player's class to the specified one. + */ + +changeclass(newclass) +int 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 feel like a whole new person!"); + + /* + * if he becomes a thief he has to have leather armor + */ + if ((newclass == C_THIEF || newclass == C_ASSASIN) && + cur_armor != NULL && + cur_armor->o_which != LEATHER && + cur_armor->o_which != STUDDED_LEATHER ) + cur_armor->o_which = STUDDED_LEATHER; + /* + * if he becomes a monk he can't wear armor + */ + 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 | ISMETAL); + cur_misc[WEAR_CLOAK] = cur_armor; + cur_armor = NULL; + } + /* + * 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_RANGER) + 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, 0, SPELLTIME, AFTER); + if (newclass == C_DRUID || newclass == C_RANGER) + fuse(chant_recovery, 0, SPELLTIME, AFTER); + if ((newclass==C_CLERIC || newclass==C_PALADIN) && !cur_misc[HEIL_ANKH]) + fuse(prayer_recovery, 0, SPELLTIME, AFTER); + /* + * if he's changing from a fighter then may have to change + * his sword since only fighter can use two-handed + * and bastard swords + */ + 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) && + !(newclass == C_ASSASIN && + cur_weapon->o_which == BASWORD)) + cur_weapon->o_which = SWORD; + + /* + * if he was a thief then take out the trap_look() daemon + */ + if (player.t_ctype == C_THIEF || + player.t_ctype == C_MONK || + player.t_ctype == C_ASSASIN) + kill_daemon(trap_look); + + /* + * if he becomes a thief then add the trap_look() daemon + */ + if (newclass == C_THIEF || newclass == C_ASSASIN || newclass == C_MONK) + daemon(trap_look, 0, AFTER); + 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 -= pstats.s_exp/10; + check_level(); + if (pstats.s_hpt > save) /* don't add to current hits */ + pstats.s_hpt = save; + } +} + +/* + * 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, NULL)) + put_contents(bag, item); +} + + +do_bag(item) +register struct linked_list *item; +{ + + register struct linked_list *titem; + 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 (readchar()) { + case EOF: + case ESCAPE: + 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"); + } + waddstr(hw,"[ESC]\tLeave this menu\n"); + mvwaddstr(hw, lines-1, 0, spacemsg); + draw(hw); + wait_for (' '); + clearok(cw, TRUE); + touchwin(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 || + (!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) < 50) { + 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 + */ +char * +misc_name(obj) +register struct object *obj; +{ + static char buf[LINELEN]; + char buf1[LINELEN]; + + buf[0] = '\0'; + buf1[0] = '\0'; + if (!(obj->o_flags & ISKNOW)) + return (m_magic[obj->o_which].mi_name); + switch (obj->o_which) { + case MM_BRACERS: + case MM_PROTECT: + strcat(buf, num(obj->o_ac, 0)); + strcat(buf, " "); + } + 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(buf, "cursed "); + } + strcat(buf, 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 (buf, buf1); + return buf; +} + +use_emori() +{ + char selection; /* Cloak function */ + int state = 0; /* Menu state */ + + msg("What do you want to do? (* for a list): "); + do { + selection = tolower(readchar()); + 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 ESCAPE: + if (state == 1) { + clearok(cw, TRUE); /* Set up for redraw */ + touchwin(cw); + } + msg(""); + + after = FALSE; + return; + + when '1': + case '2': + case '3': + case '4': + if (state == 1) { /* In prompt window */ + clearok(cw, TRUE); /* Set up for redraw */ + touchwin(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(); + } + } +} + +#ifdef PC7300 +static menu_t Display; /* The menu structure */ +static mitem_t Dispitems[MAXQUILL+1]; /* Info for each line */ +static char Displines[MAXQUILL+1][LINELEN+1]; /* The lines themselves */ +#endif +/* + * 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, + dummy; + 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) (readchar() - 'a'); + if (which_scroll == (int) ESCAPE - (int) 'a') { + mpos = 0; + msg(""); + 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) (ESCAPE - '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= 0) { + if (Display.m_selcnt == 0) { + /* Menu was cancelled */ + after = FALSE; + return FALSE; /* all done if abort */ + } + else which_scroll = (int) Display.m_curi->mi_val; + goto got_scroll; + } +#endif + /* Should we overlay? */ + if (menu_overlay && MAXQUILL + 3 < lines / 2) { + over_win(cw, hw, MAXQUILL + 5, maxlen + 3, 0, curlen, NULL); + } + else draw(hw); + } + + if (!nohw) { + which_scroll = (int) (readchar() - 'a'); + while (which_scroll < 0 || which_scroll >= MAXQUILL) { + if (which_scroll == (int) ESCAPE - (int) 'a') { + after = FALSE; + + /* Restore the screen */ + touchwin(cw); + if (MAXQUILL + 3 < lines / 2) clearok(cw, FALSE); + else { + msg(""); + clearok(cw, TRUE); + } + 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 / 2) { + over_win(cw, hw, MAXQUILL + 5, maxlen + 3, + 0, curlen, NULL); + } + else draw(hw); + + which_scroll = (int) (readchar() - 'a'); + } + } + + /* Now restore the screen if we have to */ + if (!nohw) { + touchwin(cw); + if (MAXQUILL + 3 < lines / 2) clearok(cw, FALSE); + else { + msg(""); + clearok(cw, TRUE); + } + } + else msg(""); + + +#ifdef PC7300 +got_scroll: +#endif + /* 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, NULL) == FALSE) { + (OBJPTR(item))->o_pos = hero; + fall(item, TRUE); + } +} + +use_mm(which) +int which; +{ + register struct object *obj; + register struct linked_list *item; + bool cursed, blessed, is_mm; + + cursed = FALSE; + 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); + cursed = (obj->o_flags & ISCURSED) != 0; + blessed = (obj->o_flags & ISBLESSED) != 0; + which = obj->o_which; + } + + if (obj->o_type == POTION) { /* An 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 HEIL_ANKH: + case YENDOR_AMULET: + case STONEBONES_AMULET: + /* Nothing happens by this mode */ + msg("Nothing happens."); + when EYE_VECNA: + msg("The pain subsides..."); + when SURTUR_RING: + /* Panic fire giants */ + do_panic(findmindex("fire giant")); + } + } + 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 cracked!"); + break; + } + obj->o_charges--; + if (food_left >= MORETIME + 5) { + food_left = MORETIME + 5; + msg(terse? "Getting hungry" : "You are starting to get hungry"); + hungry_state = F_HUNGRY; + } + 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); + /* + * 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--; + msg("aaAAACHOOOooo. Cough. Cough. Sneeze. Sneeze."); + if (!find_slot(dust_appear)) { + turn_on(player, ISINVIS); + fuse(dust_appear, 0, 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--; + msg("aaAAACHOOOooo. Cough. Cough. Sneeze. Sneeze."); + if (!cur_relic[SURTUR_RING] && !save(VS_POISON, &player, 0)) { + msg ("You choke to death!!! --More--"); + pstats.s_hpt = -1; /* in case he hangs up the phone */ + wait_for(' '); + death(D_CHOKE); + } + else { + msg("You begin to cough and choke uncontrollably"); + if (find_slot(unchoke)) + lengthen(unchoke, DUSTTIME); + else + fuse(unchoke, 0, 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); + + 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) + 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 QUILL_NAGROM: units = 2; + when EMORI_CLOAK: units = 2; + when BRIAN_MANDOLIN:units = 4; + when GERYON_HORN: units = 3; + when HEIL_ANKH: + case YENDOR_AMULET: + case STONEBONES_AMULET: + units = 2; + when EYE_VECNA: + /* Do some effects right away! */ + units = 6; + + /* The eye will do nothing other than give a headache */ + pstats.s_hpt -= 35; + msg("You feel a sudden shooting pain in your eye!"); + if (pstats.s_hpt < 0) { + msg ("The pain is too much for you! -- More --"); + wait_for(' '); + death(D_RELIC); + } + when SURTUR_RING: + units = 3; + msg("Your nose tickles a bit."); + } + 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 = 3; + when MM_BEAKER: + case MM_BOOK: + /* This is a strange case because it can go forever */ + units = 1; + when MM_OPEN: + case MM_HUNGER: + /* Chimes */ + units = 3; + when MM_DRUMS: + units = 3; + when MM_DISAPPEAR: + case MM_CHOKE: + /* Dust */ + units = 3; + 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; + otherwise: + /* What is it? */ + units = -1; + } + otherwise: units = -1; + } + + return (units); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/monsters.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/monsters.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,827 @@ +/* + * monsters.c - File with various monster functions in it + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * File with various monster functions in it + * + */ + +#include "curses.h" +#include "rogue.h" +#include +#include + + +/* + * 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 < level + least; i++) { + if (!treas && rnd(100) < 50) /* 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; + + result = NLEVMONS*vlevel; + if (result > NUMMONST) result = NUMMONST; + + 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 = 0; + tp->t_quiet = 0; + tp->t_dest = NULL; + tp->t_name = NULL; + tp->t_pos = tp->t_oldpos = *cp; + tp->t_oldch = CCHAR( 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.s_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.s_lvl; + tp->t_stats.s_arm = mp->m_stats.s_arm; + strncpy(tp->t_stats.s_dmg, mp->m_stats.s_dmg, sizeof(tp->t_stats.s_dmg)); + tp->t_stats.s_str = mp->m_stats.s_str; + tp->t_stats.s_dext = mp->m_stats.s_dex; + tp->t_movement = mp->m_stats.s_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.s_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(4); + tp->t_stats.s_const = 8 + rnd(4); + tp->t_stats.s_charisma = 8 + rnd(4); + + /* 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 = 75; /* base chance of breathing */ + tp->t_artifact = 90; /* base chance of using artifact */ + tp->t_summon = 40; /* base chance of summoning */ + tp->t_cast = 75; /* 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) < 20) + 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) < (22 + 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); + + strncpy(cur->o_damage, "0d0", sizeof(cur->o_damage)); + strncpy(cur->o_hurldmg, "0d0", sizeof(cur->o_hurldmg)); + strncpy(cur1->o_damage, "0d0", sizeof(cur1->o_damage)); + strncpy(cur1->o_hurldmg, "0d0", sizeof(cur1->o_hurldmg)); + + 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 < 10) { + 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; + + 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/4) + return NUMMONST; + + cur_level = vlevel; + range = 4*NLEVMONS; + i = 0; + do + { + if (i++ > range*10) { /* just in case all have be genocided */ + i = 0; + if (--cur_level <= 0) + fatal("Rogue could not find a monster to make"); + } + d = NLEVMONS*(cur_level - 1) + (rnd(range) - (range - 1 - NLEVMONS)); + if (d < 1) + d = rnd(NLEVMONS) + 1; + if (d > NUMMONST - NUMUNIQUE - 1) { + if (no_unique) + d = rnd(range) + (NUMMONST - NUMUNIQUE - 1) - (range - 1); + else if (d > NUMMONST - 1) + d = rnd(range+NUMUNIQUE) + (NUMMONST-1) - (range+NUMUNIQUE-1); + } + } + 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 int 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 monst_dead. + */ + 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 %d 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; + + } + + /* Remove the POST flag that we used for get_item() */ + obj->o_flags &= ~ISPOST; + + if (add_pack(item, FALSE, NULL) == 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) > 33 && + (!is_stealth(&player) || (on(*tp, ISUNIQUE) && rnd(100) > 50)) && + (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, 0, 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 slightly 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, 0, 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 < 0) + 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/move.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/move.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1874 @@ +/* + * move.c - Hero movement commands + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Hero movement commands + * + */ + +#include "curses.h" +#include +#include "rogue.h" +#ifdef PC7300 +#include "menu.h" +#endif + +/* + * Used to hold the new hero position + */ + +static coord 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; + register bool is_player = (th == &player), + can_see; + register struct linked_list *mitem; + register struct thing *mp; + + + /* Can the player see the creature? */ + can_see = (cansee(tc->y, tc->x) && (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 into a trap!"); + if (pstats.s_hpt <= 0) death(D_FALL); + 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)); + } + } + 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) { + msg("A strange white mist envelops you."); + if (!ISWEARING(R_ALERT)) { + msg("You fall asleep."); + player.t_no_move += movement(&player) * SLEEPTIME; + player.t_action = A_FREEZE; + } + } + 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, 6)) <= 0) { + msg("The arrow killed you."); + death(D_ARROW); + } + } + else { + if (can_see) + msg("An arrow shot %s.", prname(mname, FALSE)); + if ((th->t_stats.s_hpt -= roll(1, 6)) <= 0) { + 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(3) - 1; + arrow->o_dplus = rnd(3) - 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 = CCHAR( 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 in the shoulder."); + if ((pstats.s_hpt -= roll(1, 4)) <= 0) { + msg("The dart killed you."); + 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 == 0) death(D_POISON); + } + else if (!ISWEARING(R_SUSABILITY)) + chg_str(-1); + } + } + else { + if (can_see) + msg("A small dart just hit %s in the shoulder.", + prname(mname, FALSE)); + if ((th->t_stats.s_hpt -= roll(1,4)) <= 0) { + 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; + if (th->t_stats.s_hpt <= 0) { + 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 < 30) { + teleport(); /* teleport away */ + pool_teleport = TRUE; + } + else if((i < 45) && level > 2) { + level -= rnd(2) + 1; + cur_max = level; + new_level(NORMLEV); + pool_teleport = TRUE; + msg("You here a faint groan from below."); + } + else if(i < 70) { + level += rnd(4) + 1; + new_level(NORMLEV); + pool_teleport = TRUE; + msg("You find yourself in strange surroundings."); + } + else if(i > 95) { + msg("Oh no!!! You drown in the pool!!! --More--"); + wait_for(' '); + death(D_DROWN); + } + } + } + else { + if (i < 60) { + if (can_see) { + /* Drowns */ + if (i < 30) + 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++; + msg("You fell through a trap door!"); + if (pstats.s_hpt <= 0) death(D_FALL); + new_level(MAZELEV); + msg("You are surrounded by twisty passages!"); + } + else { + if (can_see) msg("%s fell into a 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); + + md_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)) + 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"); + if (!terse) + 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, locx; /* Hold delta of chosen location */ + + /* New position */ + nh.y = hero.y + dy; + nh.x = hero.x + dx; + + /* If it is a legal move, just return */ + if (nh.x >= 0 && nh.x < cols && nh.y > 0 && nh.y < lines - 2) { + + switch (winat(nh.y, nh.x)) { + case WALL: + case '|': + case '-': + break; + default: + if (diag_ok(&hero, &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 '|': + case '-': + break; + default: + nh.y = y; + nh.x = x; + if (diag_ok(&hero, &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); + switch(ob->o_type) { + case WEAPON: + if(i < 50) { /* 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 < 70) { /* 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 < 50) { /* 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(8) + 1; + if(i < 50) { /* 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 < 65) { /* 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 < 50) { /* 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 < 80) { /* 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 < 50) { /* 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 < 80) { /* 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 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 char ch; + struct linked_list *item; + register struct thing *tp; + 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) < 80) || + (ISWEARING(R_DELUSION) && rnd(100) < 25))) + /* Get a random move */ + nh = *rndmove(&player); + else { + nh.y = hero.y + dy; + 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 (nh.x < 0 || nh.x > cols-1 || nh.y < 1 || nh.y >= lines - 2 + || !diag_ok(&hero, &nh, &player)) + { + after = running = FALSE; + player.t_action = A_NIL; + return; + } + if (running && ce(hero, nh)) + after = running = FALSE; + ch = CCHAR( winat(nh.y, nh.x) ); + + /* Take care of hero trying to move close to something frightening */ + if (on(player, ISFLEE)) { + if (rnd(100) < 10) { + turn_off(player, ISFLEE); + msg("You regain your composure."); + } + else if (DISTANCE(nh.y, 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(nh.y, 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 = CCHAR( winat(nh.y, 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 = NULL; + + /* 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 '|': + case '-': + if (levtype == OUTSIDE) { + hero = 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(&nh); + running = FALSE; + break; + } + case MAZETRAP: + if (levtype == OUTSIDE) { + running = FALSE; + break; + } + case TRAPDOOR: + case TELTRAP: + case BEARTRAP: + case SLEEPTRAP: + case ARROWTRAP: + case DARTTRAP: + ch = be_trapped(&player, &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(nh.y, 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/9 + 1; + when C_PALADIN: num_hits = player.t_stats.s_lvl/12 + 1; + when C_RANGER: num_hits = player.t_stats.s_lvl/13 + 1; + when C_MONK: if(cur_weapon) num_hits= 1; + else num_hits= player.t_stats.s_lvl/5 + 1; + otherwise: num_hits = 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 = 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 = 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 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 = CCHAR( winat(old_hero.y + 1, old_hero.x) ); + if (!isrock(wall_check)) call_light = TRUE; + } + if (old_hero.y - 1 > 0) { + wall_check = CCHAR( 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 = CCHAR( winat(old_hero.y, old_hero.x + 1) ); + if (!isrock(wall_check)) call_light = TRUE; + } + if (old_hero.x - 1 >= 0) { + wall_check = CCHAR( 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 = CCHAR( 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 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 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 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 = CCHAR( winat(hero.y, hero.x) ); + if (isrock(ch)) see_radius = 2; + ch = CCHAR( 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, see_before; + + /* 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 = '-'; + else + ch = '|'; + } + /* 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 = CCHAR( 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 '-': + case '|': + 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 = CCHAR( mvwinch(cw, y, x) ); /* What's seen */ + rch = CCHAR( mvinch(y, x) ); /* What's really there */ + switch (rch) { + case DOOR: + case SECRETDOOR: + case STAIRS: + case TRAPDOOR: + case TELTRAP: + case BEARTRAP: + case SLEEPTRAP: + case ARROWTRAP: + case DARTTRAP: + case MAZETRAP: + case POOL: + case POST: + case '|': + case '-': + 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 STUDDED_LEATHER: + case SCALE_MAIL: + case PADDED_ARMOR: + diff += 1; + when CHAIN_MAIL: + 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; + static coord ret; /* what we will be returning */ + static 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 3 of these */ + +static char *trap_types[TRAPTYPES] = { + "Trap Door", + "Bear Trap", + "Sleep Trap", + "Arrow Trap", + "Teleport Trap", + "Dart Trap", + "Magic pool", + "Maze Trap", + "Trading Post" +}; + +#ifdef PC7300 +#define TRAPWIDTH 13 /* Length of longest named trap from above list */ +#define TRAPPREFIX 4 /* Length of prefix (eg. "[9] ") */ +static menu_t Display; /* The menu structure */ +static mitem_t Dispitems[TRAPTYPES+1]; /* Info for each line */ +static char Displines[TRAPTYPES+1][TRAPWIDTH+TRAPPREFIX+1]; +#endif + +/* + * 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 char ch, och; + int thief_bonus = 0; + int s_dext; + + if (is_player && player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) { + msg("Only thieves and assassins can set traps."); + return; + } + switch (och = CCHAR( 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_using = NULL; + 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 = tolower(readchar()); + switch (selection) { + case '*': + if (state != 1) { +#ifdef PC7300 + for (i=0; i= 0) { + if (Display.m_selcnt == 0) { + /* Cancelled menu */ + msg(""); + + trap_tries--; /* Don't count this one */ + after = FALSE; + return; + } + selection = Display.m_curi->mi_val; + state = 2; + break; + } +#endif + + 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); + + switch ((player.t_selection = selection)) { + case '1': units = 20; /* Trap door */ + when '2': units = 5; /* Bear trap */ + when '3': units = 6; /* Sleeping gas trap */ + when '4': units = 5; /* Arrow trap */ + when '5': units = 8; /* Teleport trap */ + when '6': units = 5; /* Dart trap */ + otherwise: units = 10; /* Unknown trap */ + } + player.t_no_move = units * movement(&player); + player.t_action = C_SETTRAP; + player.t_using = NULL; + return; + } + } + + if (is_player && player.t_ctype == C_THIEF) thief_bonus = 30; + if (is_player && player.t_ctype == C_ASSASIN) thief_bonus = 20; + + s_dext = (tp == &player) ? dex_compute() : tp->t_stats.s_dext; + + if (ntraps >= MAXTRAPS || ++trap_tries >= MAXTRPTRY || levtype == POSTLEV || + 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 = POST; + } + + 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 char ch = CCHAR( 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 = CCHAR( mvwinch(stdscr, y, x) ); /* Invisible */ + } + else if (on(*tp, CANINWALL)) { + if (isrock(mvwinch(stdscr, y, x))) ch = CCHAR( 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/network.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/network.h Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,36 @@ +/* + * network.h - networking setup + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * 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. + */ + +/* #define NETCOMMAND "uux - -n '%s!%s -u' >/dev/null 2>&1" */ + +/* Networking information -- should not vary among networking machines */ +#define SYSLEN 9 +#define LOGLEN 8 +#undef NUMNET /* 1 */ +struct network { + char *system; + char *rogue; +}; +extern struct network Network[]; + +/* This system's name -- should not be defined if uname() is available */ +#undef SYSTEM /* "ihesa" */ diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/new_level.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/new_level.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,628 @@ +/* + * new_level.c - Dig and draw a new level + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "curses.h" +#include "rogue.h" +#define TERRASAVE 3 + +/* + * new_level: + * Dig and draw a new level + * + */ + +new_level(ltype) +LEVTYPE ltype; /* designates type of level to create */ +{ + register int rm, i, cnt; + register 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, startx, deltay, deltax; + bool fresh=TRUE, vert, top; + struct room *rp; + struct linked_list *nitem, *savmonst=NULL, *savitems=NULL; + coord stairs; + + if (wizard) { + msg("Turns: %d", 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+10 + rnd(11); + + 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) == '-') vert = TRUE; + else vert = FALSE; + + if (level == -1) { + fresh = TRUE; + starty = 2; + startx = 1; + deltay = deltax = 1; + level = 0; /* Restore the level */ + } + else { /* Copy several lines of the terrain to the other end */ + char cch; /* Copy character */ + + /* 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; + + 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) 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(monst_dead); + 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 */ + if (ltype == POSTLEV || ltype == STARTLEV) { + if (ltype == POSTLEV) do_post(FALSE); /* Trading post */ + else do_post(TRUE); /* Equippage */ + levtype = ltype = POSTLEV; + } + else if (ltype == MAZELEV) { + do_maze(); + no_food++; + put_things(ltype); /* Place objects (if any) */ + } + else if (ltype == OUTSIDE) { + 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, 4) == 4) { + cnt = 0; + do { + rm = rnd_room(); + rnd_pos(&rooms[rm], &stairs); + } until (mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 5000); + addch(STAIRS); + } + /* + * maybe add a trading post + */ + if (level > 5 && rnd(11) == 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++ > 5000); + 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++ > 5000 || 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 = CCHAR( 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; + } + turn_off(*tp,ISELSEWHERE); + detach(tlist, item); + 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 = CCHAR( 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)+1; + 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++ > 5000); + + traps[i].tr_flags = 0; + + /* If we are at the bottom, we can't set a trap door */ + if (level >= nfloors) ch = (char) rnd(7) + 1; + else ch = (char) rnd(8); + + 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; + } + 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 = 5000; + do { + rm = rnd_room(); + 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); + + /* + * 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; + + 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; + coord tp, *exit; + + /* + * The only way to get new stuff is to go down into the dungeon. + */ + if (level <= cur_max) + return; + + /* + * There is a chance that there is a treasure room on this level + */ + if (ltype != MAZELEV && rnd(HARDER) < level - 10) { + register 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) && + 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 + * and paladin. + */ + while (TRUE) { + 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) + 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; + } + } + } + + /* + * Do MAXOBJ attempts to put things on a level + * put more things in a maze to entice player to navigate them + */ + for (i = 0; i < MAXOBJ; i++) + if (ltype == MAZELEV || rnd(100) < 45) { + /* + * 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 { + rm = rnd_room(); + rnd_pos(&rooms[rm], &tp); + } until (winat(tp.y, tp.x) == FLOOR || cnt++ > 500); + mvaddch(tp.y, tp.x, cur->o_type); + cur->o_pos = tp; + } +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/options.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/options.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,501 @@ +/* + * options.c - This file has all the code for the option command + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * This file has all the code for the option command. + * I would rather this command were not necessary, but + * it is the only way to keep the wolves off of my back. + * + */ + +#include "curses.h" +#include +#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(); + +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 class: ", + (int *)&char_type, put_abil, get_abil }, + {"quest", "Quest item: ", + (int *) &quest_item, put_quest, get_quest } +}; + +/* + * The ability 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 == md_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 == md_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 += (int)(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-1]; 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-1]; op++) + { + waddstr(hw, op->o_prompt); + if ((retval = (*op->o_getfunc)(op->o_opt, hw))) + if (retval == QUIT) + break; + else if (op > optlist) { /* MINUS */ + wmove(hw, (int)(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(' '); + clearok(cw, TRUE); + touchwin(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; + + while (*str) + { + /* + * Get option name + */ + for (sp = str; isalpha(*sp); sp++) + continue; + len = (int)(sp - str); + /* + * Look it up and deal with it + */ + for (op = optlist; op <= &optlist[NUM_OPTS-1]; 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++) + 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++) + continue; + strucpy(start, str, sp - str); + + /* Put the value into the option field */ + if (op->o_putfunc != put_abil) + { + if (allowchange(op)) + strcpy((char *)op->o_opt, (char *)value); + } + + else if (*op->o_opt == -1) { /* Only init ability once */ + register int len = strlen(value); + register int i; + + if (isupper(value[0])) value[0] = tolower(value[0]); + 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 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/outside.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/outside.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,213 @@ +/* + * outside.c - functions for dealing with the "outside" level + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "curses.h" +#include "rogue.h" + +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 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 = CCHAR( mvinch(cury, left_pos) ); + top_left = CCHAR( mvinch(top_pos, left_pos) ); + top = CCHAR( mvinch(top_pos, curx) ); + top_right = CCHAR( 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; + } + genmonsters(5, (bool) 0); +} + + +/* + * 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); + + /* Forest is most likely */ + if (chance < 60) return(FOREST); + + /* Next comes meadow */ + if (chance < 90) return(FLOOR); + + /* Then comes lakes */ + if (chance < 97) 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 + */ + +void +lake_check(place) +coord *place; +{ +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/pack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/pack.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1549 @@ +/* + * pack.c - Routines to deal with the pack. + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "curses.h" +#include +#include +#include "rogue.h" +#ifdef PC7300 +#include "menu.h" +#endif + +/* + * Routines to deal with the pack + */ + +/* + * 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, packret) +register struct linked_list *item, **packret; +bool silent; +{ + register struct linked_list *ip, *lp, *ap; + register struct object *obj, *op; + register bool exact, from_floor; + + if (packret != NULL) + *packret = NULL; + + 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 can 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, 0, SPELLTIME, 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); + + /* 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 pulsing.", inv_name(obj, TRUE)); + msg("It fades away.... -- More --"); + wait_for(' '); + death(D_RELIC); + } + msg("The %s welds itself into your chest.",inv_name(obj,TRUE)); + + /* The eye must be inserted in eye socket */ + when EYE_VECNA: + msg("The eye forces you to jam it into your eye socket!"); + pstats.s_hpt -= 75; + if (pstats.s_hpt < 0) { + msg ("The pain is too much for you! -- More --"); + wait_for(' '); + death(D_RELIC); + } + waste_time(); + msg("The excrutiating pain slowly turns into a dull throb."); + + when QUILL_NAGROM: + fuse(quill_charge,0,player.t_ctype==C_MAGICIAN ? 4 : 8,AFTER); + + /* Weapons will insist on being wielded. */ + when MUSTY_DAGGER: + case HRUGGEK_MSTAR: + case YEENOGHU_FLAIL: + case AXE_AKLAD: + /* For the daggers start a fuse to change player to a thief. */ + /* and set a daemon to eat gold. */ + if (obj->o_which == MUSTY_DAGGER) { + fuse(changeclass, C_THIEF, roll(20, 20), AFTER); + 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); + } + /* For the axe start a fuse to change player to a fighter. */ + if (obj->o_which == AXE_AKLAD) + fuse(changeclass, C_FIGHTER, roll(20, 20), 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; + + when SURTUR_RING: + msg("The ring forces itself through your nose!"); + pstats.s_hpt -= 22; + if (pstats.s_hpt < 0) { + msg ("The pain is too much for you! -- More --"); + wait_for(' '); + death(D_RELIC); + } + waste_time(); + turn_on(player, NOFIRE); + msg("The pain slowly subsides."); + otherwise: + break; + } + cur_relic[obj->o_which]++; /* Note that we have it */ + } + + updpack(FALSE, &player); + if (packret != NULL) + *packret = item; + return(TRUE); +} + +#ifdef PC7300 +static menu_t Display; /* The menu structure */ +static mitem_t Dispitems[MAXPACK+1]; /* Info for each line */ +static char Displines[MAXPACK+1][LINELEN+1]; /* The lines themselves */ +#endif + +/* + * 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, 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 */ + +#ifdef PC7300 + /* Put it into the PC menu display */ + strcpy(Displines[0], inv_temp); + Dispitems[0].mi_name = Displines[0]; + Dispitems[0].mi_flags = 0; + Dispitems[0].mi_val = 0; +#endif + } + /* + * 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); +#ifdef PC7300 + /* Put it into the PC menu display */ + strcpy(Displines[n_objs-1], inv_temp); + Displines[n_objs-1][curx] = '\0'; /* Strip newline */ + Dispitems[n_objs-1].mi_name = Displines[n_objs-1]; + Dispitems[n_objs-1].mi_flags = 0; + Dispitems[n_objs-1].mi_val = 0; +#endif + } + } + } + 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) + { +#ifdef PC7300 + /* Place an end marker for the items */ + Dispitems[n_objs].mi_name = 0; + + /* Set up the main menu structure */ + Display.m_label = "Inventory"; + Display.m_title = "Pack Contents"; + Display.m_prompt = "Press Cancl to continue."; + Display.m_curptr = '\0'; + Display.m_markptr = '\0'; + Display.m_flags = 0; + Display.m_selcnt = 0; + Display.m_items = Dispitems; + Display.m_curi = 0; + + /* + * Try to display the menu. If we don't have a local terminal, + * the call will fail and we will just continue with the + * normal mode. + */ + if (menu(&Display) >= 0) return TRUE; +#endif + 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 / 2 + 2) { + over_win(cw, hw, n_objs + 2, maxx + 3, n_objs, curx, ' '); + return TRUE; + } + + draw(hw); + wait_for(' '); + clearok(cw, TRUE); + touchwin(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 = readchar()) == ESCAPE) + { + 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, NULL, mch, FALSE, FALSE) == NULL) { + if (terse) msg("None in pack."); + 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; + char description[2*LINELEN+1]; + char cost[LINELEN/2]; +#ifdef PC7300 + int menucount = 0; + int usemenu = 1; +#endif + + /* + * 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) < 75) + 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); + while(TRUE) { + if (purpose) { /* Should we prompt the player? */ + msg("%s what (* for the item)?",purpose); + ch = tolower(readchar()); + } + 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 == ESCAPE) { + 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); + + } + } + while (TRUE) { + if (!askfirst && purpose) { + msg("%s what? (* for list): ",purpose); + ch = readchar(); + } + else ch = '*'; + + mpos = 0; + if (ch == ESCAPE) { /* 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, "[%d] ", 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; +#ifdef PC7300 + if (usemenu) { + /* Put it into the PC menu display */ + strcpy(Displines[menucount], description); + Displines[menucount][curx] = '\0'; /* Strip newline */ + Dispitems[menucount].mi_name = Displines[menucount]; + Dispitems[menucount].mi_flags = 0; + Dispitems[menucount++].mi_val = (int) item; + } +#endif + 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? ", purpose); + else strcpy(description, spacemsg); + waddstr(hw, description); + curx = strlen(description); + if (maxx < curx) maxx = curx; + +#ifdef PC7300 + if (usemenu) { + /* Place an end marker for the items */ + Dispitems[menucount].mi_name = 0; + + /* Set up the main menu structure */ + Display.m_label = "Sub-Inventory"; + if (purpose) { + Display.m_title = description; + Display.m_prompt = + "Select an item or press Cancl for no selection."; + Display.m_selcnt = 1; + } + else { + Display.m_title = 0; + Display.m_prompt = "Press Cancl to continue."; + Display.m_selcnt = 0; + } + Display.m_curptr = '\0'; + Display.m_markptr = '\0'; + Display.m_flags = 0; + Display.m_items = Dispitems; + Display.m_curi = 0; + + /* + * Try to display the menu. If we don't have a local terminal, + * the call will fail and we will just continue with the + * normal mode. + */ + if (menu(&Display) >= 0) { + msg(""); + if (Display.m_selcnt == 0) { + /* Menu was cancelled */ + if (purpose) { + after = FALSE; + return NULL; /* all done if abort */ + } + else return saveitem; + } + else return (struct linked_list *) Display.m_curi->mi_val; + } + else { + usemenu = 0; /* Can't use the menu facilities */ + } + } +#endif + /* Write the screen */ + if ((menu_overlay && cnt < lines / 2 + 2) || 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 = tolower(readchar()); + } until (isalpha(ch) || ch == ESCAPE); + } + 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 */ + } + else restscr(cw); + + if(ch == ESCAPE) { + 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: + 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: + return (TRUE); + } + } + else if (obj->o_type == POTION) { + /* + * only assassins can use poison + */ + if (player.t_ctype == C_ASSASIN && 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 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) { + item = spec_item(FOOD, NULL, 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 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 an extra blank line at the bottom and 3 blank columns + * to he right. + */ + if (menu_overlay && num_there < lines / 2 + 2) { + 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 = tolower(readchar()); + } until (isalpha(ch) || ch == '*' || ch == ESCAPE); + + /* Redraw original screen */ + if (pagecnt < 0) { + clearok(cw, FALSE); /* Setup to redraw current screen */ + touchwin(cw); /* clearing first */ + } + else restscr(cw); + + if (ch == ESCAPE) { + 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 he right. + */ + if (menu_overlay && num_there < lines / 2 + 2) { + 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, NULL)) { + /* + * 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, nitems, i; + + /* Select the items */ + nitems = rnd(6) + 5; + + switch (rnd(9)) { + /* Armor */ + case 0: + case 1: + turn_on(*tp, CARRYARMOR); + sell_type = TYP_ARMOR; + break; + + /* Weapon */ + case 2: + case 3: + turn_on(*tp, CARRYWEAPON); + sell_type = TYP_WEAPON; + break; + + /* Staff or wand */ + case 4: + turn_on(*tp, CARRYSTICK); + sell_type = TYP_STICK; + break; + + /* Ring */ + case 5: + turn_on(*tp, CARRYRING); + sell_type = TYP_RING; + break; + + /* scroll */ + case 6: + turn_on(*tp, CARRYSCROLL); + sell_type = TYP_SCROLL; + break; + + /* potions */ + case 7: + turn_on(*tp, CARRYPOTION); + sell_type = TYP_POTION; + break; + + /* Miscellaneous magic */ + case 8: + turn_on(*tp, CARRYMISC); + sell_type = TYP_MM; + break; + } + for (i=0; io_pos = tp->t_pos; + attach(tp->t_pack, item); + } +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/passages.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/passages.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,366 @@ +/* + * passages.c - Draw the connecting passages + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Draw the connecting passages + * + * @(#)passages.c 3.4 (Berkeley) 6/15/81 + */ + +#include "curses.h" +#include "rogue.h" + +/* + * do_passages: + * Draw all the passages on a level. + */ + +do_passages() +{ + register struct rdes *r1, *r2; + 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 (r1 = rdes; r1 <= &rdes[MAXROOMS-1]; r1++) + { + 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 = (int)(r1 - rdes); + j = (int)(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 = (int)(r1 - rdes); + j = (int)(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; + register char rmt; + register int distance, max_diag, offset, i; + register int rm; + int turns[3], turn_dist[3]; + register char direc; + coord delta, curr, turn_delta, spos, epos; + + 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); + addch((rnd(10) < level - 1 && rnd(100) < 20) ? SECRETDOOR : 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/player.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/player.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,812 @@ +/* + * player.c - This file contains functions for dealing with special player + * abilities + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * This file contains functions for dealing with special player abilities + */ + +#include +#include "curses.h" +#include "rogue.h" +#ifdef PC7300 +#include "menu.h" +#endif + + +/* + * 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)) == NULL) { + 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 magic user is going to try and cast a spell + */ +cast() +{ + 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; + } + spell_ability = pstats.s_lvl * pstats.s_intel; + if (player.t_ctype != C_MAGICIAN) + spell_ability /= 3; + + 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 - 15; + num_spells += pstats.s_lvl; + if (player.t_ctype != C_MAGICIAN) + num_spells /= 3; + if (num_spells > MAXSPELLS) + num_spells = MAXSPELLS; + if (num_spells < 1) { + msg("You are not allowed to cast spells yet."); + return; + } + 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_using = NULL; + 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_RANGER) { + 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; + if (player.t_ctype != C_DRUID) + chant_ability /= 3; + + 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 - 15) / 2; + + num_chants += pstats.s_lvl; + + if (player.t_ctype != C_DRUID) + num_chants /= 3; + + 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_using = NULL; + 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 > 6 && pstats.s_const <= 14) + bonus = 0; + else if (pstats.s_const > 14) + bonus = pstats.s_const-14; + else if (pstats.s_const > 3) + bonus = -1; + else + bonus = -2; + switch(player.t_ctype) { + case C_FIGHTER: bonus = min(bonus, 11); + when C_MAGICIAN: bonus = min(bonus, 4); + when C_CLERIC: bonus = min(bonus, 4); + when C_THIEF: bonus = min(bonus, 4); + when C_RANGER: bonus = min(bonus, 6); + when C_PALADIN: bonus = min(bonus, 8); + when C_ASSASIN: bonus = min(bonus, 4); + when C_MONK: bonus = min(bonus, 6); + when C_DRUID: bonus = min(bonus, 4); + otherwise: bonus = min(bonus, 4); + } + return(bonus); +} + + +/* Routines for thieves */ + +/* + * gsense: + * Sense gold + */ + +gsense() +{ + /* Only thieves can do this */ + if (player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) { + msg("You seem to have no gold sense."); + return; + } + + read_scroll(S_GFIND, NULL, FALSE); +} + +/* + * 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; + if (player.t_ctype != C_CLERIC) + prayer_ability /= 3; + + if (cur_relic[HEIL_ANKH]) prayer_ability *= 2; + + 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 - 15) / 2; + + num_prayers += pstats.s_lvl; + if (cur_relic[HEIL_ANKH]) num_prayers += 3; + + if (player.t_ctype != C_CLERIC) + num_prayers /= 3; + + 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_using = NULL; + 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; +} + + + +/* + * 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; + + if (player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) { + 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 (isinvisible = invisible(tp)) mname = "creature"; + else mname = monster_name(tp); + + /* Can player steal something unnoticed? */ + if (player.t_ctype == C_THIEF) thief_bonus = 10; + if (player.t_ctype == C_ASSASIN) thief_bonus = 0; + 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, NULL) == 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(35) >= 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); + } + } +} + +#ifdef PC7300 +/* Use MAXSPELLS or whatever is the biggest number of spells/prayers/etc */ +static menu_t Display; /* The menu structure */ +static mitem_t Dispitems[MAXSPELLS+1]; /* Info for each line */ +static char Displines[MAXSPELLS+1][LINELEN+1]; /* The lines themselves */ +#endif + +/* + * 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 */ +char *prompt; /* prompt for spell list */ +char *type; /* type of thing--> spell, prayer, chant */ +{ + bool nohw = FALSE; + register int i; + int curlen, + maxlen, + dummy, + which_spell, + spell_left; +#ifdef PC7300 + char label[LINELEN], /* For menu label */ + title[LINELEN]; /* For menu title */ +#endif + + 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) (readchar() - 'a'); + msg(""); /* Get rid of the prompt */ + if (which_spell == (int) ESCAPE - (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) (ESCAPE - 'a')) { + mpos = 0; + msg(""); + after = FALSE; + return(FALSE); + } + } + else { + /* Now display the possible spells */ + wclear(hw); + touchwin(hw); + wmove(hw, 2, 0); + *type = toupper(*type); + wprintw(hw, " Cost %s", type); + *type = tolower(*type); + mvwaddstr(hw, 3, 0, + "-----------------------------------------------"); + maxlen = 47; /* Maximum width of header */ + + for (i=0; i= 0) { + if (Display.m_selcnt == 0) { + /* Menu was cancelled */ + after = FALSE; + return FALSE; /* all done if abort */ + } + else which_spell = (int) Display.m_curi->mi_val; + goto got_spell; + } +#endif + /* Should we overlay? */ + if (menu_overlay && num_spells + 3 < lines / 2) { + over_win(cw, hw, num_spells + 5, maxlen + 3, 0, curlen, NULL); + } + else draw(hw); + } + + if (!nohw) { + which_spell = (int) (readchar() - 'a'); + while (which_spell < 0 || which_spell >= num_spells) { + if (which_spell == (int) ESCAPE - (int) 'a') { + after = FALSE; + + /* Restore the screen */ + touchwin(cw); + if (num_spells + 3 < lines / 2) clearok(cw, FALSE); + else clearok(cw, TRUE); + 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 / 2) { + over_win(cw, hw, num_spells + 5, maxlen + 3, + 0, curlen, NULL); + } + else draw(hw); + + which_spell = (int) (readchar() - 'a'); + } + } + + /* Now restore the screen if we have to */ + if (!nohw) { + touchwin(cw); + if (num_spells + 3 < lines / 2) clearok(cw, FALSE); + else clearok(cw, TRUE); + } + +#ifdef PC7300 +got_spell: +#endif + 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_using = NULL; + player.t_no_move = (which_spell/3 + 1) * movement(&player); + return(TRUE); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/potions.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/potions.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,981 @@ +/* + * potions.c - Function(s) for dealing with potions + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Function(s) for dealing with potions + */ + +#include +#include "curses.h" +#include "rogue.h" + + +/* + * add_abil is an array of functions used to change attributes. It must be + * ordered according to the attribute definitions in rogue.h. + */ + +void (*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. + */ + +void (*res_abil[NUMABILITIES])() = { + res_intelligence, res_strength, res_wisdom, res_dexterity, + res_constitution, res_charisma +}; + +/* + * Increase player's constitution + */ + +void +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 <= 0) + death(D_CONSTITUTION); + } + else { + msg("You feel healthier now."); + pstats.s_const = min(pstats.s_const + change, 25); + } + + /* Adjust the maximum */ + if (max_stats.s_const < pstats.s_const) + max_stats.s_const = pstats.s_const; +} + +/* + * Increase player's charisma + */ + +void +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 > 25) pstats.s_charisma = 25; + 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; +} + +/* + * Increase player's dexterity + */ + +void +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 > 25) pstats.s_dext = 25; + 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; +} + +/* + * 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, 0, roll(hasttime, hasttime), AFTER); + } +} + +/* + * Increase player's intelligence + */ +void +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 > 25) pstats.s_intel = 25; + 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; +} + +/* + * 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, 0, roll(HASTETIME,HASTETIME), AFTER); + } + } +} + +/* + * Increase player's strength + */ + +void +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); + } +} + +/* + * Increase player's wisdom + */ + +void +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 > 25) pstats.s_wisdom = 25; + 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; +} + +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, 0, 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 <= 0) + death(D_POISON); + } + 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; + 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; + + msg("You begin to sense the presence of monsters."); + 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); + } + waddstr(msgw, morestr); + clearok(msgw, FALSE); + draw(msgw); + overlay(hw, cw); + draw(cw); + wait_for(' '); + msg(""); + 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; + msg("You sense the presence of magic on this level."); + waddstr(msgw, morestr); + clearok(msgw, FALSE); + draw(msgw); + overlay(hw,cw); + draw(cw); + wait_for(' '); + msg(""); + 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, 0, SEEDURATION, AFTER); + light(&hero); + } + else + lengthen(sight, SEEDURATION); + } + else { + if (off(player, CANSEE)) { + turn_on(player, CANSEE); + msg("Your eyes begin to tingle."); + fuse(unsee, 0, blessed ? SEEDURATION*3 :SEEDURATION, AFTER); + light(&hero); + } + else if (find_slot(unsee) != 0) + 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, 0, 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, 0, 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(); + 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 ? 2 : 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, 0, 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 (show) { + if (is_potion) p_know[P_FFIND] = TRUE; + msg("Your nose tingles."); + msg("You sense the presence of food on this level."); + waddstr(msgw, morestr); + clearok(msgw, FALSE); + draw(msgw); + overlay(hw,cw); + draw(cw); + wait_for(' '); + msg(""); + } + 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, 0, 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) death(D_POTION); + } + else { + int adjust; + + msg("You feel more skillful."); + + /* Get the adjustment */ + adjust = blessed ? 3 : 2; + + /* Does he currently have an artifical skill? */ + if (!find_slot(unskill)) { + pstats.s_lvladj = adjust; + pstats.s_lvl += pstats.s_lvladj; + fuse(unskill, 0, + 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 = 3; + else duration = 1; + + if (on(player, NOFIRE)) { + if (find_slot(nofire)) + lengthen(nofire, duration*FIRETIME); + else { + msg("Nothing happens."); /* has on a ring */ + say_message = FALSE; + } + } + else { + fuse(nofire, 0, 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 = 3; + else duration = 1; + + if (on(player, NOCOLD)) { + if (find_slot(nocold)) + lengthen(nocold, duration*COLDTIME); + else { + msg("Nothing happens."); /* has on a ring */ + say_message = FALSE; + } + } + else { + fuse(nocold, 0, 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 = 3; + else duration = 1; + + if (on(player, NOBOLT)) { + if (find_slot(nobolt)) + lengthen(nobolt, duration*BOLTTIME); + } + else { + fuse(nobolt, 0, duration*BOLTTIME, AFTER); + turn_on(player, NOBOLT); + } + if (say_message) + 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 / 4); + } + if (pstats.s_const <= 0 || pstats.s_hpt <= 0) + 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 + */ + +void +res_dexterity(howmuch) +int howmuch; +{ + short save_max; + int ring_str; + + if (howmuch < 0) return; + + /* 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; + } +} + + +/* + * res_intelligence: + * Restore player's intelligence + */ + +void +res_intelligence(howmuch) +int howmuch; +{ + short save_max; + int ring_str; + + if (howmuch <= 0) return; + + /* 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; + } +} + +/* + * res_wisdom: + * Restore player's wisdom + */ + +void +res_wisdom(howmuch) +int howmuch; +{ + short save_max; + int ring_str; + + if (howmuch <= 0) return; + + /* 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; + } +} + +/* + * res_constitution: + * Restore the players constitution. + */ + +void +res_constitution(howmuch) +int howmuch; +{ + if (howmuch > 0) + pstats.s_const = min(pstats.s_const + howmuch, max_stats.s_const); +} + +/* + * res_charisma: + * Restore the players charisma. + */ + +void +res_charisma(howmuch) +int howmuch; +{ + if (howmuch > 0) + pstats.s_charisma = + min(pstats.s_charisma + howmuch, max_stats.s_charisma); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/rings.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/rings.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,162 @@ +/* + * rings.c - routines dealing specifically with rings + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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 "curses.h" +#include "rogue.h" + +/* + * routines dealing specifically with rings + */ + + +/* + * how much food does this ring use up? + */ +ring_eat(hand) +register int hand; +{ + if (cur_ring[hand] == NULL) + return 0; + switch (cur_ring[hand]->o_which) { + case R_VAMPREGEN: + return 3; + case R_REGEN: + return 2; + case R_HEALTH: + case R_SUSABILITY: + return 1; + case R_SEARCH: + case R_SEEINVIS: + return (rnd(100) < 33); + 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: + turn_on(player, CANSEE); + msg("Your eyes begin to tingle"); + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + when R_AGGR: + aggravate(TRUE, TRUE); + when R_WARMTH: + turn_on(player, NOCOLD); + when R_FIRE: + 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, 0, AFTER); + when R_TELEPORT: + daemon(ring_teleport, 0, 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/rip.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/rip.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,937 @@ +/* + * rip.c - File for the fun ends Death or a total win + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* Print flags for scoring */ +#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 "arogue7.log" + +#define NAMELEN 80 + +/* + * File for the fun ends + * Death or a total win + * + */ + +#include "curses.h" +#ifdef BSD +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include "mach_dep.h" +#include "network.h" +#include "rogue.h" +#ifdef PC7300 +#include "sys/window.h" +extern struct uwdata wdata, oldwin; +extern char oldtext[WTXTNUM][WTXTLEN]; +#endif + +#ifdef NUMNET +/* Network machines (for mutual score keeping) */ +static struct network Network[NUMNET] = { + { "ihwpt", "/t1/michael/bin/rg" }, +}; +#endif + +/* + * If you change this structure, change the compatibility routines + * scoreout() and scorein() to reflect the change. Also update SCORELEN. + */ +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; +}; +#define SCORELEN \ + (sizeof(unsigned long) + NAMELEN + SYSLEN + LOGLEN + 5*sizeof(short)) + +static char *rip[] = { +" __________", +" / \\", +" / REST \\", +" / IN \\", +" / PEACE \\", +" / \\", +" | |", +" | |", +" | killed by |", +" | |", +" | 1984 |", +" *| * * * | *", +" ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______", + 0 +}; + +char *killname(); + + + + + +void +byebye(sig) +int sig; +{ + if (!isendwin()) { + clear(); + endwin(); + } +#ifdef PC7300 + endhardwin(); +#endif + printf("\n"); + exit(0); +} + + +/* + * 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(); + + 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, 26, (sprintf(prbuf, "%4d", 1900+lt->tm_year), prbuf)); + move(lines-1, 0); + refresh(); + writelog(pstats.s_exp, KILLED, monst); + score(pstats.s_exp, KILLED, monst); + endwin(); +#ifdef PC7300 + endhardwin(); +#endif + exit(0); +} + +#ifdef PC7300 +/* + * Restore window characteristics on a hard window terminal (PC7300). + */ +endhardwin() +{ + register int i; + struct utdata labelbuf; + + /* Restore the old window size */ + if (oldwin.uw_width) ioctl(1, WIOCSETD, &oldwin); + + /* Restore the old window text */ + for (i=0; i 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; + /* 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; +short monst; +{ + static struct sc_ent top_ten[NUMSCORE]; + register struct sc_ent *scp; + register int i; + register struct sc_ent *sc2; + register int outfd; + register char *killer; + register int prflags = 0; + register int fd; + short upquest, wintype, uplevel, uptype; /* For network updating */ + char upsystem[SYSLEN], uplogin[LOGLEN]; + char *thissys; /* Holds the name of this system */ + char *compatstr=NULL; /* Holds scores for writing compatible score files */ + char scoreline[100]; +#define REASONLEN 3 + static char *reason[] = { + "killed", + "quit", + "A total winner", + "somehow left", + }; + char *packend; + + signal(SIGINT, byebye); + if (flags != WINNER && flags != SCOREIT && flags != UPDATE) { + if (flags == CHICKEN) + packend = "when you quit"; + 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 ((fd = open(score_file, O_RDWR | O_CREAT, 0666)) < 0) return; + outfd = fd; + +#ifndef SYSTEM + thissys = md_gethostname(); +#else + thissys = SYSTEM; +#endif + + for (scp = top_ten; scp <= &top_ten[NUMSCORE-1]; scp++) + { + scp->sc_score = 0L; + for (i = 0; i < NAMELEN; i++) + scp->sc_name[i] = rnd(255); + scp->sc_quest= RN; + scp->sc_flags = RN; + scp->sc_level = RN; + scp->sc_monster = RN; + scp->sc_ctype = 0; + strncpy(scp->sc_system, thissys, SYSLEN); + scp->sc_login[0] = '\0'; + } + + /* + * If this is a SCOREIT optin (rogue -s), don't call byebye. The + * endwin() call in byebye() will result 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; +#ifdef WIZARD + 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 */ + } + } +#endif + + /* Read the score and convert it to a compatible format */ + for(i = 0; i < NUMSCORE; i++) + { + encread(top_ten[i].sc_name, NAMELEN, fd); + encread(top_ten[i].sc_system, SYSLEN, fd); + encread(top_ten[i].sc_login, LOGLEN, fd); + encread(scoreline, 100, fd); + sscanf(scoreline, " %lu %hd %hd %hd %hd %hd \n", + &top_ten[i].sc_score, &top_ten[i].sc_flags, + &top_ten[i].sc_level, &top_ten[i].sc_ctype, + &top_ten[i].sc_monster, &top_ten[i].sc_quest + ); + } + + /* Get some values if this is an update */ + if (flags == UPDATE) { + unsigned long netread(); + 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) { + close(outfd); + free(compatstr); + return; + } + } + + /* + * Insert player in list if need be + */ + if (!waswizard) { + char *login; + + if (flags != UPDATE) { + login = md_getusername(); + } + + if (flags == UPDATE) + (void) update(top_ten, amount, upquest, whoami, wintype, + uplevel, monst, uptype, upsystem, uplogin); + else { +#ifdef WIZARD + 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, "Editing", "choose"); + } while (scp->sc_monster < 0); /* Force a choice */ + else scp->sc_monster = getdeath(); + clear(); + refresh(); + } + } + else printf("\n"); + } + } + if ((flags != SCOREIT) && (flags != UPDATE)) { + printf("\n[Press return to exit]"); + fflush(stdout); + fgets(prbuf,80,stdin); + } +/* if (prflags == EDITSCORE) endwin();*/ /* End editing windowing */ + } + lseek(outfd, 0L, 0); + /* + * Update the list file + */ + + for(i = 0; i < NUMSCORE; i++) + { + memset(scoreline,0,100); + encwrite(top_ten[i].sc_name, NAMELEN, outfd); + encwrite(top_ten[i].sc_system, SYSLEN, outfd); + encwrite(top_ten[i].sc_login, LOGLEN, outfd); + sprintf(scoreline, " %lu %hd %hd %hd %hd %hd \n", + top_ten[i].sc_score, top_ten[i].sc_flags, + top_ten[i].sc_level, top_ten[i].sc_ctype, + top_ten[i].sc_monster, top_ten[i].sc_quest); + encwrite(scoreline,100,outfd); + } + + close(outfd); +} + +/* + * scorein: + * Convert a character string that has been translated from a + * score file by scoreout() back to a score file structure. + */ +scorein(input, scores, num_bytes) +unsigned char *input; +struct sc_ent scores[]; +int num_bytes; /* Number of bytes of input that we want to convert */ +{ + register int i, j; + unsigned long *lptr; + unsigned short *sptr; + unsigned char *cptr; + + /* Convert a maximum of NUMSCORE entries */ + for (i=0; num_bytes > 0 && i < NUMSCORE; num_bytes -= SCORELEN, i++) { + /* The long fields are first -- ordered low to high byte in input */ + lptr = &scores[i].sc_score; + *lptr = ((unsigned long) *input++) & 0x000000ffL; + *lptr |= (((unsigned long) *input++) << 8) & 0x0000ff00L; + *lptr |= (((unsigned long) *input++) << 16) & 0x00ff0000L; + *lptr |= (((unsigned long) *input++) << 24) & 0xff000000L; + + /* The short fields are next -- ordered low to high byte in input */ + sptr = (unsigned short *) &scores[i].sc_flags; + *sptr = ((unsigned short) *input++) & 0xff; + *sptr |= (((unsigned short) *input++) << 8) & 0xff00; + + sptr = (unsigned short *) &scores[i].sc_level; + *sptr = ((unsigned short) *input++) & 0xff; + *sptr |= (((unsigned short) *input++) << 8) & 0xff00; + + sptr = (unsigned short *) &scores[i].sc_ctype; + *sptr = ((unsigned short) *input++) & 0xff; + *sptr |= (((unsigned short) *input++) << 8) & 0xff00; + + sptr = (unsigned short *) &scores[i].sc_monster; + *sptr = ((unsigned short) *input++) & 0xff; + *sptr |= (((unsigned short) *input++) << 8) & 0xff00; + + sptr = (unsigned short *) &scores[i].sc_quest; + *sptr = ((unsigned short) *input++) & 0xff; + *sptr |= (((unsigned short) *input++) << 8) & 0xff00; + + /* Finally comes the char fields -- they're easy */ + cptr = (unsigned char *) scores[i].sc_name; + for (j = 0; j < NAMELEN; j++) *cptr++ = *input++; + + cptr = (unsigned char *) scores[i].sc_system; + for (j = 0; j < SYSLEN; j++) *cptr++ = *input++; + + cptr = (unsigned char *) scores[i].sc_login; + for (j = 0; j < LOGLEN; j++) *cptr++ = *input++; + } +} + +/* + * scoreout: + * Convert a score file structure to a character string. We do + * this for compatibility sake since some machines write out fields in + * different orders. + */ +scoreout(scores, output) +struct sc_ent scores[]; +unsigned char *output; +{ + register int i, j; + unsigned long *lptr; + unsigned short *sptr; + unsigned char *cptr; + + for (i=0; i> 8*j) & 0xff); + + /* The short fields are next -- ordered low to high byte in input */ + sptr = (unsigned short *) &scores[i].sc_flags; + *output++ = (unsigned char) (*sptr & 0xff); + *output++ = (unsigned char) ((*sptr >> 8) & 0xff); + + sptr = (unsigned short *) &scores[i].sc_level; + *output++ = (unsigned char) (*sptr & 0xff); + *output++ = (unsigned char) ((*sptr >> 8) & 0xff); + + sptr = (unsigned short *) &scores[i].sc_ctype; + *output++ = (unsigned char) (*sptr & 0xff); + *output++ = (unsigned char) ((*sptr >> 8) & 0xff); + + sptr = (unsigned short *) &scores[i].sc_monster; + *output++ = (unsigned char) (*sptr & 0xff); + *output++ = (unsigned char) ((*sptr >> 8) & 0xff); + + sptr = (unsigned short *) &scores[i].sc_quest; + *output++ = (unsigned char) (*sptr & 0xff); + *output++ = (unsigned char) ((*sptr >> 8) & 0xff); + + /* Finally comes the char fields -- they're easy */ + cptr = (unsigned char *) scores[i].sc_name; + for (j = 0; j < NAMELEN; j++) *output++ = *cptr++; + + cptr = (unsigned char *) scores[i].sc_system; + for (j = 0; j < SYSLEN; j++) *output++ = *cptr++; + + cptr = (unsigned char *) scores[i].sc_login; + for (j = 0; j < LOGLEN; j++) *output++ = *cptr++; + } +} + +/* + * 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,"--- %d Gold Pieces ---",purse); + refresh(); +} + +total_winner() +{ + register struct linked_list *item; + register struct object *obj; + register int worth; + register char c; + register int 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 leader of a "); + switch (player.t_ctype) { + case C_MAGICIAN:addstr("magic user's guild.\n"); + when C_FIGHTER: addstr("fighter's guild.\n"); + when C_RANGER: addstr("ranger's guild.\n"); + when C_CLERIC: addstr("monastery.\n"); + when C_PALADIN: addstr("monastery.\n"); + when C_MONK: addstr("monastery.\n"); + when C_DRUID: addstr("monastery.\n"); + when C_THIEF: addstr("thief's guild.\n"); + when C_ASSASIN: addstr("assassin's guild.\n"); + otherwise: addstr("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) %6d %s", c, worth, inv_name(obj, FALSE)); + purse += worth; + } + mvprintw(c - 'a' + 1, 0," %5d Gold Pieces ", oldpurse); + refresh(); + writelog(pstats.s_exp + (long) purse, WINNER, '\0'); + score(pstats.s_exp + (long) purse, WINNER, '\0'); + endwin(); +#ifdef PC7300 + endhardwin(); +#endif + exit(0); +} + +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; +{ + register struct sc_ent *scp, *sc2; + int retval=0; /* 1 if a change, 0 otherwise */ + + for (scp = top_ten; scp < &top_ten[NUMSCORE]; scp++) { + if (amount >= scp->sc_score) + break; + +#ifdef LIMITSCORE /* Limits player to one entry per class per uid */ + /* If this good score is the same class and uid, then forget it */ + if (strncmp(scp->sc_login, login, LOGLEN) == 0 && + scp->sc_ctype == ctype && + strncmp(scp->sc_system, system, SYSLEN) == 0) return(0); +#endif + } + + if (scp < &top_ten[NUMSCORE]) + { + retval = 1; + +#ifdef LIMITSCORE /* Limits player to one entry per class per uid */ + /* If a lower scores exists for the same login and class, delete it */ + for (sc2 = scp ;sc2 < &top_ten[NUMSCORE]; sc2++) { + if (sc2->sc_score == 0L) break; /* End of useful scores */ + + if (strncmp(sc2->sc_login, login, LOGLEN) == 0 && + sc2->sc_ctype == ctype && + strncmp(sc2->sc_system, system, SYSLEN) == 0) { + /* We want to delete this entry */ + while (sc2 < &top_ten[NUMSCORE-1]) { + *sc2 = *(sc2+1); + sc2++; + } + sc2->sc_score = 0L; + } + } +#endif + + for (sc2 = &top_ten[NUMSCORE-1]; sc2 > scp; sc2--) + *sc2 = *(sc2-1); + scp->sc_score = amount; + scp->sc_quest = quest; + strncpy(scp->sc_name, whoami, NAMELEN); + scp->sc_flags = flags; + scp->sc_level = level; + scp->sc_monster = monst; + scp->sc_ctype = ctype; + strncpy(scp->sc_system, system, SYSLEN); + strncpy(scp->sc_login, login, LOGLEN); + } + + return(retval); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/rogue.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/rogue.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1690 @@ +/* + * rogue.c - Global game variables + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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 "curses.h" +#include "rogue.h" +#ifdef PC7300 +#include +#endif + +#ifdef BSD +char +tolower(c) +{ + if (isupper(c)) return(_tolower(c)); + else return(c); +} +char +toupper(c) +{ + if (islower(c)) return(_toupper(c)); + else return(c); +} +#endif + +/* + * 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 *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 dnum; /* Dungeon number */ +int max_level; /* Deepest player has gone ever */ +int cur_max; /* Deepest player has gone currently */ +int mpos = 0; +int level = 0; +int 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; +int 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 */ +char 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 outbuf[BUFSIZ]; /* Output buffer for stdout */ +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 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 */ +bool playing = TRUE; +bool running = FALSE; +bool wizard = FALSE; +bool notify = TRUE; +bool fight_flush = FALSE; +bool terse = FALSE; +bool auto_pickup = TRUE; +bool menu_overlay = TRUE; +bool door_stop = FALSE; +bool jump = FALSE; +bool slow_invent = FALSE; +bool firstmove = FALSE; +bool askme = FALSE; +bool in_shell = FALSE; +bool daytime = TRUE; +bool use_savedir = FALSE; +LEVTYPE levtype; /* type of level i'm on */ + +char *nothing = "Nothing seems to happen."; +char *spacemsg = "--Press space to continue--"; +char *morestr = "-- More --"; +char *retstr = "[Press return to continue]"; +#ifdef PC7300 +struct uwdata wdata, oldwin; /* Static window information */ +char oldtext[WTXTNUM][WTXTLEN]; /* Saved window text */ +#endif + +/* + * 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", 80, 1310720, 12, 10, 30, 2, 1, 2 }, +{ "ranger", 140, 2293760, 8, 10, 20, 2, 1, 2 }, +{ "paladin", 120, 1966080, 10, 10, 23, 2, 1, 2 }, +{ "magic user", 130, 2129920, 6, 9, 18, 2, 1, 5 }, +{ "cleric", 110, 1802240, 8, 10, 19, 2, 1, 3 }, +{ "thief", 75, 1228800, 6, 10, 25, 2, 1, 4 }, +{ "assassin", 85, 1392640, 6, 10, 25, 2, 1, 4 }, +{ "druid", 100, 1638400, 8, 10, 19, 2, 1, 3 }, +{ "monk", 95, 1556480, 6, 10, 25, 2, 1, 3 }, +{ "monster", 0, 0, 8, 7, 30, 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. + */ + +char *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"}, +}; + + +/* + * weapons and their attributes + */ +struct init_weps weaps[MAXWEAPONS] = { + { "mace", "2d4", "1d3", NONE, ISMETAL, 3, 100, 8 }, + { "long sword", "1d12", "1d2", NONE, ISMETAL, 4, 60, 18 }, + { "short bow", "1d1", "1d1", NONE, 0, 6, 40, 15 }, + { "arrow", "1d1", "1d6", BOW, ISMANY|ISMISL, 1, 5, 1 }, + { "dagger", "1d6", "1d4", NONE, ISMETAL|ISMISL|ISMANY,1,7,2}, + { "rock", "1d2", "1d4", SLING, ISMANY|ISMISL, 1, 5, 1 }, + { "two-handed sword","3d6", "1d2", NONE, ISMETAL, 5, 250, 40 }, + { "sling", "0d0", "0d0", NONE, 0, 1, 5, 1 }, + { "dart", "1d1", "1d3", NONE, ISMANY|ISMISL, 1, 5, 1 }, + { "crossbow", "1d1", "1d1", NONE, 0, 6, 100, 15 }, + { "crossbow bolt", "1d2", "1d12", CROSSBOW,ISMANY|ISMISL, 1, 7, 1 }, + { "spear", "1d8", "2d6", NONE, ISMANY|ISMETAL|ISMISL,2,20,8}, + { "trident", "3d4", "1d4", NONE, ISMETAL, 4, 50, 20 }, + { "spetum", "2d6", "1d3", NONE, ISMETAL, 4, 50, 20 }, + { "bardiche", "3d4", "1d2", NONE, ISMETAL, 4, 125, 20 }, + { "pike", "1d12", "1d8", NONE, ISMETAL, 4, 80, 18 }, + { "bastard sword", "2d8", "1d2", NONE, ISMETAL, 5, 100, 30 }, + { "halberd", "2d6", "1d3", NONE, ISMETAL, 4, 175, 10 }, + { "battle axe", "1d8", "1d3", NONE, ISMETAL, 3, 80, 10 }, +}; + +struct init_armor armors[MAXARMORS] = { + { "leather armor", 11, 8, 70, 100 }, + { "ring mail", 22, 7, 50, 250 }, + { "studded leather armor", 33, 7, 50, 200 }, + { "scale mail", 45, 6, 70, 250 }, + { "padded armor", 57, 6, 150, 150 }, + { "chain mail", 69, 5, 100, 300 }, + { "splint mail", 80, 4, 150, 350 }, + { "banded mail", 90, 4, 150, 350 }, + { "plate mail", 96, 3, 400, 400 }, + { "plate armor", 100, 2, 650, 450 }, +}; + +struct magic_item things[NUMTHINGS] = { + { "potion", 260, 10 }, /* potion */ + { "scroll", 260, 30 }, /* scroll */ + { "food", 180, 20 }, /* food */ + { "weapon", 80, 0 }, /* weapon */ + { "armor", 80, 0 }, /* armor */ + { "ring", 50, 5 }, /* ring */ + { "stick", 60, 0 }, /* stick */ + { "miscellaneous magic", 30, 50 }, /* miscellaneous magic */ + { "artifact", 0, 10 }, /* artifact */ +}; + +struct magic_item s_magic[MAXSCROLLS] = { + { "monster confusion", 50, 125, 0, 0 }, + { "magic mapping", 50, 150, 0, 0 }, + { "light", 70, 100, 21, 15 }, + { "hold monster", 30, 200, 33, 20 }, + { "sleep", 20, 150, 20, 0 }, + { "enchantment", 170, 200, 9, 9 }, + { "identify", 200, 100, 0, 25 }, + { "scare monster", 40, 250, 27, 21 }, + { "gold detection", 30, 110, 0, 0 }, + { "teleportation", 60, 165, 10, 20 }, + { "create monster", 30, 75, 0, 0 }, + { "remove curse", 70, 120, 9, 15 }, + { "petrification", 10, 185, 0, 0 }, + { "genocide", 10, 300, 0, 0 }, + { "cure disease", 80, 160, 0, 0 }, + { "acquirement", 10, 700, 0, 0 }, + { "protection", 30, 190, 20, 0 }, + { "trap finding", 10, 180, 0, 0 }, + { "runes", 10, 50, 0, 0 }, + { "charm monster", 20, 275, 0, 15 }, +}; + +struct magic_item p_magic[MAXPOTIONS] = { + { "clear thought", 50, 180, 27, 10 }, + { "gain ability", 160, 210, 15, 15 }, + { "see invisible", 50, 150, 25, 15 }, + { "healing", 160, 130, 27, 27 }, + { "monster detection", 60, 120, 0, 0 }, + { "magic detection", 60, 105, 0, 0 }, + { "raise level", 10, 450, 11, 10 }, + { "haste self", 90, 180, 30, 5 }, + { "restore abilities", 140, 140, 0, 10 }, + { "phasing", 50, 210, 21, 20 }, + { "invisibility", 50, 230, 0, 15 }, + { "flying", 40, 130, 0, 20 }, + { "food detection", 10, 150, 0, 0 }, + { "skill", 10, 200, 20, 10 }, + { "fire resistance", 10, 250, 0, 10 }, + { "cold resistance", 10, 250, 0, 10 }, + { "lightning protection", 10, 250, 0, 10 }, + { "poison", 30, 205, 0, 0 }, +}; + +struct magic_item r_magic[MAXRINGS] = { + { "protection", 50, 200, 33, 25 }, + { "add strength", 60, 200, 33, 25 }, + { "sustain ability", 50, 500, 0, 0 }, + { "searching", 50, 400, 0, 0 }, + { "extra sight", 40, 350, 0, 0 }, + { "alertness", 40, 380, 0, 0 }, + { "aggravate monster", 30, 100, 100, 0 }, + { "dexterity", 60, 220, 33, 25 }, + { "increase damage", 60, 220, 33, 25 }, + { "regeneration", 40, 600, 0, 0 }, + { "slow digestion", 40, 240, 15, 15 }, + { "teleportation", 20, 100, 100, 0 }, + { "stealth", 30, 300, 0, 0 }, + { "add intelligence", 60, 240, 33, 25 }, + { "increase wisdom", 60, 220, 33, 25 }, + { "sustain health", 80, 500, 0, 0 }, + { "carrying", 20, 100, 100, 0 }, + { "illumination", 30, 520, 0, 0 }, + { "delusion", 20, 100, 75, 0 }, + { "fear", 20, 100, 100, 0}, + { "heroism", 30, 390, 0, 0 }, + { "fire resistance", 40, 400, 0, 0 }, + { "warmth", 40, 400, 0, 0 }, + { "vampiric regeneration", 10,1000, 0, 0}, + { "free action", 10, 370, 0, 0}, + { "teleport control", 10, 700, 0, 0}, +}; + +struct magic_item ws_magic[MAXSTICKS] = { + { "light", 90, 120, 20, 20 }, + { "striking", 60, 115, 0, 0 }, + { "lightning", 35, 200, 0, 0 }, + { "fire", 35, 200, 0, 0 }, + { "cold", 35, 200, 0, 0 }, + { "polymorph", 80, 150, 0, 0 }, + { "magic missile", 80, 170, 0, 0 }, + { "slow", 80, 220, 25, 20 }, + { "drain life", 80, 210, 20, 0 }, + { "charging", 70, 400, 0, 0 }, + { "teleport", 90, 140, 25, 20 }, + { "cancellation", 40, 130, 0, 0 }, + { "confusion", 35, 100, 15, 0}, + { "disintegration", 10, 300, 33, 0}, + { "petrification", 30, 240, 0, 0}, + { "paralyzation", 30, 180, 15, 0}, + { "degeneration", 30, 250, 30, 0}, + { "curing", 10, 250, 25, 0}, + { "wonder", 50, 110, 0, 0}, + { "fear", 30, 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", 140, 100, 15, 0}, + { "chime of opening", 50, 250, 0, 0}, + { "chime of hunger", 50, 100,100, 0}, + { "cloak of displacement", 60, 500, 0, 0}, + { "cloak of protection", 70, 200, 15, 0}, + { "drums of panic", 40, 350, 0, 0}, + { "dust of disappearance", 40, 300, 0, 0}, + { "dust of choking", 30, 100,100, 0}, + { "gauntlets of dexterity", 30, 600, 25, 0}, + { "gauntlets of ogre power", 30, 600, 25, 0}, + { "jewel of attacks", 40, 150,100, 0}, + { "keoghtoms ointment", 50, 200, 0, 0}, + { "robe of powerlessness", 30, 100,100, 0}, + { "gauntlets of fumbling", 30, 100,100, 0}, + { "necklace of adaptation", 20, 500, 0, 0}, + { "necklace of strangulation",30, 110,100, 0}, + { "boots of dancing", 30, 120,100, 0}, + { "book of skills", 20, 650, 0, 0}, +}; + + +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}, +}; +/* + * food and fruits that you get + */ +struct magic_item foods[MAXFOODS] = { + { "food ration", 800, 50, 750, 0}, + { "apple", 10, 20, 300, 0}, + { "banana", 10, 20, 300, 0}, + { "blueberry", 10, 20, 300, 0}, + { "candleberry", 10, 20, 300, 0}, + { "caprifig", 10, 20, 300, 0}, + { "dewberry", 10, 20, 300, 0}, + { "elderberry", 10, 20, 300, 0}, + { "gooseberry", 10, 20, 300, 0}, + { "guanabana", 10, 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}, +}; + +/* + * these are the spells that a magic user 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, 7, TYP_SCROLL, 0 }, + { S_CONFUSE, 10, TYP_SCROLL, 0 }, + { WS_MISSILE, 15, TYP_STICK, 0 }, + { S_TELEP, 20, TYP_SCROLL, 0 }, + { S_SLEEP, 20, TYP_SCROLL, 0 }, + { P_FLY, 20, TYP_POTION, 0 }, + { P_SEEINVIS, 20, TYP_POTION, 0 }, + { WS_COLD, 25, TYP_STICK, 0 }, + { WS_ELECT, 25, TYP_STICK, 0 }, + { WS_FIRE, 25, TYP_STICK, 0 }, + { P_HASTE, 30, TYP_POTION, 0 }, + { WS_CANCEL, 30, TYP_STICK, 0 }, + { P_PHASE, 40, TYP_POTION, 0 }, + { S_HOLD, 50, TYP_SCROLL, 0 }, + { WS_CHARGE, 55, TYP_STICK, ISBLESSED }, + { S_PROTECT, 60, TYP_SCROLL, 0 }, + { S_ALLENCH, 70, TYP_SCROLL, 0 }, +}; + +/* + * these are the spells that a cleric can cast + */ +struct spells cleric_spells[MAXPRAYERS] = { + { P_MFIND, 3, TYP_POTION, 0 }, + { P_TFIND, 7, TYP_POTION, 0 }, + { S_LIGHT, 10, TYP_SCROLL, ISBLESSED }, + { S_REMOVE, 15, TYP_SCROLL, 0 }, + { P_HEALING, 20, TYP_POTION, 0 }, + { P_FFIND, 24, TYP_POTION, 0 }, + { S_FINDTRAPS, 26, TYP_SCROLL, 0 }, + { S_CURING, 27, TYP_SCROLL, 0 }, + { WS_PARALYZE, 30, TYP_STICK, ISBLESSED }, + { S_MAP, 31, TYP_SCROLL, 0 }, + { P_CLEAR, 32, TYP_POTION, 0 }, + { WS_FEAR, 33, TYP_STICK, ISBLESSED }, + { P_SEEINVIS, 35, TYP_POTION, 0 }, + { P_RESTORE, 40, TYP_POTION, 0 }, + { P_PHASE, 43, TYP_POTION, 0 }, + { S_TELEP, 45, TYP_SCROLL, 0 }, + { WS_CURING, 50, TYP_STICK, ISBLESSED }, + { WS_DRAIN, 50, TYP_STICK, 0 }, +}; + +/* + * these are the spells that a druid can chant + */ +struct spells druid_spells[MAXCHANTS] = { + { P_TFIND, 3, TYP_POTION, 0 }, + { P_MFIND, 3, TYP_POTION, 0 }, + { S_LIGHT, 7, TYP_SCROLL, ISBLESSED }, + { S_CONFUSE, 10, TYP_SCROLL, 0 }, + { S_MAP, 10, TYP_SCROLL, 0 }, + { P_FFIND, 15, TYP_POTION, 0 }, + { P_HEALING, 20, TYP_POTION, 0 }, + { S_CURING, 25, TYP_SCROLL, 0 }, + { P_FLY, 27, TYP_POTION, ISBLESSED }, + { P_FIRE, 30, TYP_POTION, ISBLESSED }, + { P_COLD, 30, TYP_POTION, ISBLESSED }, + { P_LIGHTNING, 30, TYP_POTION, ISBLESSED }, + { S_HOLD, 35, TYP_SCROLL, 0 }, + { WS_CURING, 40, TYP_STICK, ISBLESSED }, + { P_PHASE, 45, TYP_POTION, 0 }, + { S_CHARM, 50, TYP_SCROLL, ISBLESSED }, +}; + + +/* + * these are the scrolls that a quill can write + */ +struct quill quill_scrolls[MAXQUILL] = { + { S_GFIND, 4, }, + { S_IDENT, 5, }, + { S_LIGHT, 6, }, + { S_REMOVE, 7, }, + { S_MAP, 10, }, + { S_SLEEP, 20, }, + { S_TELEP, 30, }, + { S_CONFUSE, 40, }, + { S_CURING, 50, }, + { S_HOLD, 70, }, + { S_PROTECT, 90, }, + { S_SCARE, 110, }, + { S_ALLENCH, 130, }, +}; + +char *cnames[NUM_CHARTYPES-1][NUM_CNAMES] = { +{ "Veteran", "Warrior", /* Fighter */ + "Swordsman", "Hero", + "Swashbuckler", "Myrmidon", + "Champion", "Superhero", + "Lord", "Lord", + "Lord", "Lord", + "Lord", "Lord", + "Lord", "Lord", + "Lord" +}, +{ "Runner", "Strider", /* Ranger */ + "Scout", "Courser", + "Tracker", "Guide", + "Pathfinder", "Ranger", + "Ranger Knight", "Ranger Lord", + "Ranger Lord", "Ranger Lord", + "Ranger Lord", "Ranger Lord", + "Ranger Lord", "Ranger Lord", + "Ranger Lord" +}, +{ "Gallant", "Keeper", /* Paladin */ + "Protector", "Defender", + "Warder", "Guardian", + "Chevalier", "Justiciar", + "Paladin", "Paladin", + "Paladin", "Paladin", + "Paladin", "Paladin", + "Paladin", "Paladin", + "Paladin" +}, +{ "Prestidigitator", "Evoker", /* Magic User */ + "Conjurer", "Theurgist", + "Thaumaturgist", "Magician", + "Enchanter", "Warlock", + "Sorcerer", "Necromancer", + "Wizard I", "Wizard II", + "Wizard III", "Wizard IV", + "Wizard V", "Wizard VI", + "High Wizard" +}, +{ "Acolyte", "Adept", /* Cleric */ + "Priest", "Curate", + "Prefect", "Canon", + "Lama", "Patriarch", + "High Priest", "High Priest", + "High Priest", "High Priest", + "High Priest", "High Priest", + "High Priest", "High Priest", + "High Priest" +}, +{ "Rogue", "Footpad", /* Thief */ + "Cutpurse", "Robber", + "Burglar", "Filcher", + "Sharper", "Magsman", + "Thief", "Master Thief", + "Master Thief", "Master Thief", + "Master Thief", "Master Thief", + "Master Thief", "Master Thief", + "Master Thief" +}, +{ "Bravo", "Rutterkin", /* Assassin */ + "Waghalter", "Murderer", + "Thug", "Killer", + "Cutthroat", "Executioner", + "Assassin", "Expert Assassin", + "Senior Assassin", "Chief Assassin", + "Prime Assassin", "Guildmaster Assassin", + "Grandfather Assassin", "Grandfather Assassin", + "Grandfather Assassin" +}, +{ "Aspirant", "Ovate", /* Druid */ + "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", "Druid", + "Archdruid", "The Great Druid", + "The Great Druid", "The Great Druid", + "The Great Druid", +}, +{ "Novice", "Initiate", /* Monk */ + "Brother", "Disciple", + "Immaculate", "Master", + "Superior Master", "Master of Dragons", + "Master of North Wind", "Master of West Wind", + "Master of South Wind", "Master of East Wind", + "Master of Winter", "Master of Autumn", + "Master of Summer", "Master of Spring", + "Grand Master" +} +} ; + +struct h_list helpstr[] = { + '?', " prints help", + '/', " identify object", + '=', " identify screen character", + 'h', " left", + 'j', " down", + 'k', " up", + 'l', " right", + 'y', " up & left", + 'u', " up & right", + 'b', " down & left", + 'n', " down & 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", + 't', " throw something", + 'f', " forward until find something", + 'z', " zap a wand or staff", + '>', " go down a staircase", + '<', " go up a staircase", + 's', " search for trap/secret door", + '.', " rest for a while", + 'i', " inventory", + 'I', " inventory single item", + 'q', " quaff potion", + 'r', " read paper", + 'e', " eat food", + 'w', " wield a weapon", + 'W', " wear something", + 'T', " take off something", + 'd', " drop object", + 'P', " pick up object(s)", + CTRL('N'), " name object or monster", + 'm', " mark object (specific)", + 'o', " examine/set options", + 'c', " chant", + 'C', " cast a spell", + 'p', " pray", + 'a', " affect the undead", + '^', " set a trap", + 'G', " sense gold", + 'D', " dip something (into a pool)", + '*', " count up gold pieces", + CTRL('T'), " take (steal) from (direction)", + CTRL('U'), " use miscellaneous magic item", + CTRL('L'), " redraw screen", + CTRL('R'), " repeat last message", + ESCAPE, " cancel command", + 'v', " print program version number", + '!', " shell escape", + 'S', " save game", + 'Q', " quit", + 0, 0 +} ; + +struct h_list wiz_help[] = { + CTRL('A'), " system activity", + CTRL('C'), " move to another dungeon level", + CTRL('D'), " down 1 dungeon level", + CTRL('E'), " food remaining", + CTRL('F'), " display entire level", + CTRL('H'), " jump 9 experience levels", + CTRL('I'), " inventory of level", + CTRL('J'), " teleport", + CTRL('M'), " recharge staff", + CTRL('P'), " toggle wizard status", + CTRL('U'), " up 1 dungeon level", + CTRL('X'), " detect monsters", + CTRL('Z'), " identify", + 'M', " make object", + 0, 0 +}; + + +#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, 0, HPT(""), + ""}}, +{"giant rat", + 0, TRUE, TRUE, 'R', "2-4", + {ISMEAN, CANDISEASE}, + 0, 0, + 1, + {10, 10, 6, 7, 1, 7, HPT("1d4"), + "1d3"}}, +{"kobold", + 10, TRUE, TRUE, 'K', "8", + {ISMEAN, CANSHOOT, CARRYWEAPON}, + 0, 0, + 1, + {9, 10, 6, 5, 1, 7, HPT("1d4"), + "1d4"}}, +{"gnome", + 10, TRUE, FALSE, 'G', "11-12", + {CANSHOOT, CARRYPOTION, CARRYWEAPON}, + 0, 0, + 1, + {10, 10, 6, 8, 1, 5, HPT("1d6"), + "1d6"}}, +{"bat", + 0, TRUE, TRUE, 'b', "2-4", + {ISMEAN, CANDISEASE, ISFLY, AREMANY}, + 0, 0, + 0, + {10, 10, 6, 5, 1, 10, HPT("1d4"), + "1d1"}}, +{"halfling", + 10, TRUE, FALSE, 'H', "11-12", + {CANSHOOT, CARRYPOTION, CARRYWEAPON}, + 0, 0, + 1, + {8, 10, 6, 9, 1, 4, HPT("1d6"), + "1d6"}}, +{"dwarf", + 15, TRUE, FALSE, 'D', "11-12", + {CANSHOOT, CARRYPOTION, CARRYWEAPON}, + 0, 0, + 1, + {10, 10, 6, 10, 1, 4, HPT("1d8"), + "1d8"}}, +{"orc", + 15, TRUE, TRUE, 'O', "8", + {ISMEAN, CANSHOOT, CARRYGOLD, CARRYWEAPON}, + 0, 0, + 1, + {12, 10, 6, 10, 1, 6, HPT("1d8"), + "1d8"}}, +{"xvart", + 100, TRUE, TRUE, 'x', "14-15", + {ISMEAN, CARRYDAGGER, AREMANY}, + 0, 0, + 1, + {8, 10, 6, 7, 1, 7, HPT("1d4"), + "1d4"}}, +{"manes", + 0, TRUE, TRUE, 'M', "2-4", + {ISMEAN, MAGICHIT, ISUNDEAD, TURNABLE}, + 0, 0, + 1, + {10, 10, 6, 18, 1, 7, HPT("1d8"), + "1d2/1d2/1d4"}}, +{"elf", + 50, TRUE, FALSE, 'E', "13-20", + {CANSHOOT, CARRYPOTION, CARRYSCROLL, CARRYWEAPON}, + 0, 0, + 2, + {12, 10, 6, 20, 1, 5, HPT("1d8+1"), + "1d10"}}, +{"hobgoblin", + 10, TRUE, TRUE, 'h', "8-10", + {ISMEAN, CANSHOOT, CARRYWEAPON}, + 0, 0, + 2, + {14, 10, 6, 20, 1, 5, HPT("1d8+1"), + "1d8"}}, +{"fire beetle", + 0, TRUE, TRUE, 'B', "0", + {ISMEAN, HASFIRE}, + 0, 0, + 2, + {10, 10, 6, 20, 1, 4, HPT("1d8+2"), + "2d4"}}, +{"giant ant", + 0, TRUE, TRUE, 'A', "1", + {ISMEAN, CANPOISON}, + 0, 0, + 3, + {10, 10, 6, 40, 2, 3, HPT("2d8"), + "1d6/1d6"}}, +{"zombie", + 0, TRUE, TRUE, 'Z', "0", + {ISMEAN, ISUNDEAD, TURNABLE}, + 0, 0, + 2, + {10, 10, 6, 20, 2, 8, HPT("2d8"), + "1d8"}}, +{"ear seeker", + 0, TRUE, TRUE, 'e', "0", + {ISMEAN, CANINFEST, AREMANY, CANSURPRISE}, + 0, 0, + 0, + {10, 10, 6, 5, 1, 9, HPT("1d1"), + "1d1"}}, +{"shrieker", + 0, TRUE, FALSE, 'S', "0", + {CANSHRIEK, NOMOVE, NOSTAB}, + 0, 0, + 1, + {10, 10, 6, 10, 3, 7, HPT("3d8"), + "0d0"}}, +{"stirge", + 0, TRUE, TRUE, 's', "1", + {ISMEAN, CANDRAW, ISFLY}, + 0, 0, + 2, + {10, 10, 6, 36, 4, 8, HPT("1d8+1"), + "1d3"}}, +{"gas spore", + 0, TRUE, FALSE, 'a', "0", + {ISMEAN, CANEXPLODE, CANINFEST, ISFLY}, + 0, 0, + 5, + {10, 10, 18, 90, 1, 9, HPT("1d1"), + "1d1"}}, +{"troglodyte", + 5, TRUE, TRUE, 'T', "5-7", + {ISMEAN, CANSMELL, CANSHOOT, CARRYGOLD, CARRYWEAPON}, + 0, 0, + 2, + {10, 10, 6, 36, 2, 5, HPT("2d8"), + "1d3/1d3/2d5"}}, +{"lemure", + 0, TRUE, FALSE, 'L', "2-4", + {ISMEAN, ISREGEN, MAGICHIT, ISUNDEAD, TURNABLE}, + 0, 0, + 3, + {10, 10, 9, 65, 3, 7, HPT("3d8"), + "1d3"}}, +{"bugbear", + 5, TRUE, TRUE, 'b', "5-8", + {ISMEAN, CANSHOOT, CANSURPRISE, CARRYGOLD, CARRYPOTION, + CARRYWEAPON}, + 0, 0, + 4, + {16, 10, 6, 135, 3, 5, HPT("3d8+1"), + "2d4"}}, +{"wererat", + 20, TRUE, TRUE, 'r', "11-12", + {ISMEAN, MAGICHIT, CARRYFOOD, CANSUMMON}, + "giant rat", 2, + 4, + {10, 10, 6, 150, 3, 6, HPT("3d8+1"), + "1d8"}}, +{"ghoul", + 0, TRUE, TRUE, 'g', "5-7", + {ISMEAN, CANPARALYZE, ISUNDEAD, TURNABLE}, + 0, 0, + 2, + {10, 10, 6, 65, 2, 6, HPT("2d8"), + "1d3/1d3/1d6"}}, +{"leprechaun", + 100, TRUE, FALSE, 'l', "15-16", + {CARRYGOLD, STEALGOLD}, + 0, 0, + 1, + {10, 10, 3, 80, 6, 3, HPT("1d4+1"), + "0d0"}}, +{"gray ooze", + 50, TRUE, FALSE, 'o', "1", + {ISMEAN, CANRUST, ISSCAVENGE, NOCOLD, NOFIRE, NOSTAB,CARRYFOOD}, + 0, 0, + 5, + {10, 10, 10, 200, 3, 8, HPT("3d8+3"), + "2d8"}}, +{"giant tick", + 0, TRUE, TRUE, 't', "0", + {ISMEAN, CANDRAW, CANDISEASE}, + 0, 0, + 2, + {10, 10, 9, 105, 3, 3, HPT("3d8"), + "1d4"}}, +{"ogre", + 50, TRUE, TRUE, 'O', "5-7", + {ISMEAN, CARRYGOLD, CARRYWEAPON}, + 0, 0, + 5, + {18, 10, 7, 90, 4, 5, HPT("4d8+1"), + "1d10"}}, +{"very young dragon", + 10, TRUE, FALSE, 'd', "15-16", + {ISMEAN, CANBRANDOM, ISGREED, CARRYGOLD}, + 0, 0, + 9, + {10, 10, 6, 100, 9, -1, HPT("9d1"), + "1d4/1d4/2d4"}}, +{"centaur", + 15, TRUE, FALSE, 'C', "5-10", + {CANSHOOT, CARRYPOTION, CARRYGOLD, CARRYWEAPON}, + 0, 0, + 4, + {10, 10, 2, 85, 4, 4, HPT("4d8"), + "1d6/1d6"}}, +{"nymph", + 100, TRUE, FALSE, 'N', "15-16", + {STEALMAGIC, CARRYSCROLL, CARRYPOTION, CARRYSTICK}, + 0, 0, + 3, + {10, 10, 6, 350, 4, 9, HPT("3d8"), + "0d0"}}, +{"violet fungi", + 0, TRUE, FALSE, 'F', "0", + {ISMEAN, CANHOLD, NOMOVE, CANROT, NOSTAB}, + 0, 0, + 4, + {10, 10, 6, 135, 3, 7, HPT("3d8"), + "5d1"}}, +{"gelatinous cube", + 90, TRUE, TRUE, 'c', "0", + {ISMEAN, ISSCAVENGE, CANPARALYZE, NOSTAB, CARRYFOOD}, + 0, 0, + 4, + {10, 10, 8, 150, 4, 8, HPT("4d8"), + "2d4"}}, +{"fire toad", + 0, TRUE, TRUE, 'f', "5-7", + {ISMEAN, CANBFIRE, NOFIRE}, + 0, 0, + 4, + {10, 10, 6, 150, 4, 10, HPT("4d8+1"), + "2d4"}}, +{"blink dog", + 0, TRUE, TRUE, 'B', "8-10", + {ISMEAN, CANBLINK}, + 0, 0, + 5, + {10, 10, 6, 170, 4, 5, HPT("4d8"), + "1d6"}}, +{"rust monster", + 0, TRUE, TRUE, 'R', "1", + {ISMEAN, CANRUST}, + 0, 0, + 4, + {10, 10, 6, 185, 5, 2, HPT("3d8"), + "0d0/0d0"}}, +{"ghast", + 0, TRUE, TRUE, 'G', "11-12", + {CANPARALYZE, CANSTINK, ISMEAN, ISUNDEAD, TURNABLE}, + 0, 0, + 4, + {10, 10, 6, 190, 4, 4, HPT("4d8"), + "1d4/1d4/1d8"}}, +{"blindheim", + 0, TRUE, FALSE, 'b', "1", + {CANBLIND, ISMEAN}, + 0, 0, + 4, + {8, 10, 6, 200, 2, 1, HPT("4d8+2"), + "1d8"}}, +{"shadow", + 0, TRUE, TRUE, 'S', "5-7", + {ISSHADOW, ISMEAN, CANCHILL, ISUNDEAD, TURNABLE}, + 0, 0, + 4, + {10, 10, 6, 255, 3, 7, HPT("3d8+3"), + "1d4+1"}}, +{"gargoyle", + 5, TRUE, TRUE, 'g', "5-7", + {ISMEAN, MAGICHIT}, + 0, 0, + 5, + {10, 10, 6, 165, 4, 5, HPT("4d8+4"), + "1d3/1d3/1d6/1d4"}}, +{"quasit", + 30, TRUE, TRUE, 'Q', "5-7", + {ISMEAN, ISREGEN, MAGICHIT, CANSURPRISE, CANITCH, CARRYSTICK, + CARRYSCROLL, CARRYGOLD, CARRYPOTION, NOCOLD, NOFIRE, NOBOLT}, + 0, 0, + 3, + {10, 10, 6, 325, 7, 2, HPT("3d8"), + "1d2/1d2/1d4"}}, +{"imp", + 25, TRUE, TRUE, 'I', "8-10", + {ISMEAN, ISREGEN, MAGICHIT, CANPOISON, CANSURPRISE, + CANTELEPORT, CARRYRING, CARRYSTICK, NOCOLD, NOBOLT, NOFIRE}, + 0, 0, + 3, + {10, 10, 6, 275, 2, 2, HPT("2d8+2"), + "1d4"}}, +{"su-monster", 10, TRUE, TRUE, 's', "8-10", + {ISMEAN, CARRYSCROLL, CARRYGOLD, CARRYFOOD}, + 0, 0, + 6, + {10, 10, 5, 225, 5, 6, HPT("5d8+5"), + "4d4/2d4"}}, +{"owlbear", + 5, TRUE, TRUE, 'O', "5-7", + {ISMEAN, CANHUG, CARRYRING, CARRYFOOD}, + 0, 0, + 8, + {10, 10, 8, 225, 5, 5, HPT("5d8+2"), + "1d6/1d6/2d6"}}, +{"doppleganger", + 0, TRUE, TRUE, 'D', "11-12", + {ISMEAN, CANSURPRISE}, + 0, 0, + 4, + {10, 10, 6, 330, 10, 5, HPT("4d8"), + "1d12"}}, +{"yeti", + 30, TRUE, TRUE, 'Y', "8-10", + {ISMEAN, CANPARALYZE, CANHUG, NOCOLD, CANSURPRISE, + CARRYGOLD, CARRYPOTION}, + 0, 0, + 8, + {13, 10, 6, 500, 6, 6, HPT("4d8+4"), + "1d6/1d6"}}, +{"leucrotta", + 0, TRUE, FALSE, 'L', "8-10", + {ISMEAN}, + 0, 0, + 8, + {10, 10, 2, 475, 6, 4, HPT("6d8+1"), + "3d6/1d6/1d6"}}, +{"cockatrice", + 0, TRUE, TRUE, 'C', "1", + {ISMEAN, TOUCHSTONE}, + 0, 0, + 5, + {10, 10, 5, 315, 5, 6, HPT("5d8"), + "1d3"}}, +{"wight", + 0, TRUE, TRUE, 'W', "8-10", + {ISMEAN, CANDRAIN, MAGICHIT, ISUNDEAD, TURNABLE}, + 0, 0, + 5, + {10, 10, 6, 540, 4, 5, HPT("4d8+3"), + "1d4"}}, +{"troll", + 50, TRUE, FALSE, 'T', "5-7", + {ISMEAN, ISREGEN, CARRYFOOD, CARRYGOLD}, + 0, 0, + 8, + {18, 10, 8, 600, 6, 4, HPT("6d8+6"), + "1d4+4/1d4+4/2d6"}}, +{"jackalwere", + 50, TRUE, TRUE, 'J', "11-12", + {ISMEAN, CANSHOOT, CANSNORE, MAGICHIT, CARRYFOOD, CARRYGOLD, + CARRYSCROLL}, + 0, 0, + 4, + {10, 10, 6, 800, 4, 4, HPT("4d8"), + "2d4"}}, +{"wraith", + 0, TRUE, TRUE, 'w', "11-12", + {ISMEAN, CANDRAIN, MAGICHIT, ISUNDEAD, TURNABLE}, + 0, 0, + 6, + {10, 10, 6, 575, 5, 4, HPT("5d8+3"), + "1d6"}}, +{"mimic", + 20, TRUE, FALSE, 'M', "2-10", + {ISMEAN, ISDISGUISE, NODETECT, CANHOLD, CARRYFOOD, CARRYRING, + CARRYGOLD, NOMOVE}, + 0, 0, + 12, + {10, 10, 6, 1300, 9, 7, HPT("10d8"), + "3d4"}}, +{"erinyes", + 25, TRUE, TRUE, 'E', "8-10", + {ISMEAN, CANFRIGHTEN, CANSUMMON, TURNABLE, CANPAIN, CANSEE, + NOFIRE, CANTELEPORT, CARRYRING, CARRYSTICK}, + "ghoul", 3, + 8, + {10, 10, 6, 875, 7, 2, HPT("6d8+6"), + "2d4"}}, +{"lava child", + 0, TRUE, TRUE, 'l', "8-10", + {ISMEAN, NOMETAL}, + 0, 0, + 8, + {10, 10, 6, 950, 5, 4, HPT("5d8+1"), + "1d6/1d6/2d12"}}, +{"basilisk", + 0, TRUE, FALSE, 'B', "1", + {ISMEAN, LOOKSTONE}, + 0, 0, + 8, + {10, 10, 6, 1000, 6, 4, HPT("6d8+1"), + "1d10"}}, +{"mummy", + 20, TRUE, FALSE, 'm', "5-7", + {ISMEAN,CANINFEST, MAGICHIT, CANFRIGHTEN, HALFDAMAGE, ISUNDEAD, + TURNABLE, CARRYRING}, + 0, 0, + 8, + {10, 10, 6, 1150, 6, 3, HPT("6d8+3"), + "1d12"}}, +{"otyugh", + 0, TRUE, TRUE, 'o', "5-10", + {ISMEAN, CANDISEASE}, + 0, 0, + 8, + {10, 10, 6, 700, 7, 3, HPT("7d8"), + "1d8/1d8/1d4+1"}}, +{"adult dragon", + 30, TRUE, FALSE, 'd', "15-16", + {ISMEAN, CANBRANDOM, ISGREED, CANFRIGHTEN, CARRYGOLD, + CARRYPOTION}, + 0, 0, + 9, + {10, 10, 6, 1000, 9, -1, HPT("45d1"), + "1d6/1d6/2d6"}}, +{"invisible stalker", + 0, TRUE, TRUE, 'i', "13-14", + {ISMEAN, ISINVIS}, + 0, 0, + 10, + {10, 10, 4, 1090, 8, 3, HPT("8d8"), + "4d4"}}, +{"xorn", + 0, TRUE, TRUE, 'X', "8-10", + {ISMEAN, CANINWALL, NOCOLD, NOFIRE, CANSURPRISE, NOBOLT}, + 0, 0, + 10, + {10, 10, 6, 1275, 7, -2, HPT("7d8+7"), + "1d3/1d3/1d3/4d6"}}, +{"chimera", + 0, TRUE, FALSE, 'c', "2-4", + {ISMEAN, CANBFIRE, NOFIRE}, + 0, 0, + 12, + {10, 10, 6, 1000, 9, 6, HPT("9d8"), + "1d3/1d3/1d4/1d4/2d4/3d4"}}, +{"horned devil", + 5, TRUE, TRUE, 'H', "13-14", + {ISMEAN, CANFRIGHTEN, CANINFEST, CANPOISON, MAGICHIT, CANSUMMON, + NOFIRE, CANTELEPORT, CARRYGOLD, CARRYRING, CARRYSTICK}, + "wight", 2, + 6, + {10, 10, 6, 1320, 7, -3, HPT("5d8+5"), + "1d4/1d4/1d4+1/1d3"}}, +{"specter", + 0, TRUE, TRUE, 'S', "13-14", + {ISMEAN, DOUBLEDRAIN, ISUNDEAD, TURNABLE}, + 0, 0, + 10, + {10, 10, 6, 1650, 7, 2, HPT("7d8+3"), + "1d8"}}, +{"will-o-wisp", 100, TRUE, FALSE, 'W', "15-16", + {ISMEAN, CANSURPRISE, ISFLY, CARRYGOLD, CARRYMISC, NOBOLT}, + 0, 0, + 12, + {10, 10, 5, 2000, 9, -8, HPT("9d8"), + "2d8"}}, +{"lamia", + 0, TRUE, TRUE, 'L', "13-14", + {ISMEAN, TAKEWISDOM}, + 0, 0, + 9, + {10, 10, 2, 1500, 9, 3, HPT("9d8"), + "1d4/1d4"}}, +{"neo-otyugh", + 0, TRUE, TRUE, 'N', "10-12", + {ISMEAN, CANDISEASE}, + 0, 0, + 10, + {12, 10, 6, 1500, 10, 0, HPT("12d8"), + "2d6/2d6/1d3"}}, +{"barbed devil", + 0, TRUE, TRUE, 'B', "11-12", + {TOUCHFEAR, CANSUMMON, ISMEAN, CANHOLD, TURNABLE, NOFIRE, + CANTELEPORT}, + "ghast", 4, + 10, + {10, 10, 6, 1425, 8, 0, HPT("8d8"), + "2d4/2d4/3d4"}}, +{"vrock", + 10, TRUE, TRUE, 'V', "5-7", + {ISMEAN, CANSUMMON, CANSEE, TURNABLE, CANTELEPORT, CARRYGOLD, + CARRYRING, CARRYSTICK}, + "erinyes", 2, + 10, + {10, 10, 6, 1500, 8, 0, HPT("8d8"), + "1d4/1d4/1d8/1d8/1d6"}}, +{"shambling mound", + 25, TRUE, TRUE, 's', "5-7", + {ISMEAN, CANSUFFOCATE, NOCOLD, NOFIRE, CANHOLD, CARRYGOLD, + CARRYFOOD, CARRYRING}, + 0, 0, + 10, + {10, 10, 7, 1800, 9, 0, HPT("9d8"), + "2d8/2d8"}}, +{"umber hulk", + 40, TRUE, TRUE, 'U', "8-10", + {ISMEAN, CANHUH, CANINWALL, CANTUNNEL, CARRYSCROLL, + CARRYPOTION, CARRYFOOD}, + 0, 0, + 12, + {10, 10, 6, 1700, 8, 2, HPT("8d8+8"), + "3d4/3d4/2d5"}}, +{"ettin", + 0, TRUE, TRUE, 'e', "5-7", + {ISMEAN, CANSHOOT, AREMANY}, + 0, 0, + 14, + {10, 10, 6, 1950, 10, 3, HPT("10d8"), + "2d8/3d6"}}, +{"black pudding", + 30, TRUE, FALSE, 'P', "0", + {ISMEAN, CANRUST, NOCOLD, BOLTDIVIDE, BLOWDIVIDE, ISSCAVENGE, + NOSTAB, CARRYSCROLL, CARRYPOTION, CARRYRING}, + 0, 0, + 14, + {10, 10, 6, 2000, 10, 6, HPT("10d8"), + "3d8"}}, +{"hezrou", + 15, TRUE, TRUE, 'h', "5-7", + {ISMEAN, CANFRIGHTEN, CANSEE, CANSUMMON, TURNABLE, CANTELEPORT, + CARRYPOTION, CARRYRING, CARRYSTICK}, + "wight", 3, + 12, + {10, 10, 6, 2000, 9, -2, HPT("9d8"), + "1d3/1d3/4d4"}}, +{"glabrezu", + 25, TRUE, FALSE, 'G', "8-10", + {ISMEAN, CANFRIGHTEN, CANSEE, CANSUMMON, TURNABLE, CANTELEPORT, + CARRYSCROLL, CARRYPOTION, CARRYGOLD}, + "wraith", 3, + 14, + {10, 10, 6, 2400, 10, -4, HPT("10d8"), + "2d6/2d6/1d3/1d3/1d4+1"}}, +{"bone devil", + 0, TRUE, TRUE, 'b', "11-12", + {ISMEAN, CANFRIGHTEN, CANSEE, CANSUMMON, CANSURPRISE, CANCHILL, + TURNABLE, NOFIRE, NOCOLD, CANTELEPORT}, + "ghast", 3, + 12, + {10, 10, 6, 2800, 9, -1, HPT("9d8"), + "2d4"}}, +{"white pudding", + 30, TRUE, FALSE, 'w', "0", + {ISMEAN, CANDISSOLVE, NOCOLD, BOLTDIVIDE, BLOWDIVIDE, + ISSCAVENGE, NOSTAB, CARRYRING, CARRYSCROLL, + CARRYPOTION}, + 0, 0, + 14, + {10, 10, 6, 2200, 9, 8, HPT("10d8"), + "7d4"}}, +{"vampire", + 20, TRUE, TRUE, 'v', "15-16", + {ISMEAN, ISREGEN, CANSUCK, ISUNDEAD, TURNABLE, CARRYMISC}, + 0, 0, + 12, + {20, 10, 6, 3800, 8, 1, HPT("8d8+3"), + "1d6+4"}}, +{"ghost", + 20, TRUE, FALSE, 'g', "13-14", + {ISMEAN, CANFRIGHTEN, CANAGE, ISUNDEAD, TURNABLE, CARRYMISC, + CMAGICHIT, CANINWALL}, + 0, 0, + 10, + {13, 10, 5, 5000, 12, 0, HPT("10d8"), + "1d12"}}, +{"intellect devourer", + 0, TRUE, FALSE, 'D', "11-12", + {ISMEAN, TAKEINTEL, CMAGICHIT, HALFDAMAGE, CANSURPRISE, NOFIRE, + NOCOLD}, + 0, 0, + 9, + {10, 10, 4, 5000, 7, 4, HPT("6d8+6"), + "1d4/1d4/1d4/1d4"}}, +{"ice devil", + 30, TRUE, FALSE, 'I', "13-14", + {ISMEAN, CANSEE, ISREGEN, CANFRIGHTEN, CANSUMMON, CANBICE, + NOCOLD, NOFIRE, TOUCHSLOW, CANTELEPORT, CARRYSCROLL, CARRYRING, + CARRYSTICK}, + "bone devil", 2, + 16, + {20, 10, 6, 4400, 11, -4, HPT("11d8"), + "1d4/1d4/2d4/3d4"}}, +{"purple worm", + 70, TRUE, TRUE, 'p', "0", + {ISMEAN, CANPOISON, CANINWALL, CANTUNNEL, CARRYFOOD, CARRYGOLD}, + 0, 0, + 20, + {10, 10, 6, 4900, 15, 6, HPT("15d8"), + "2d12/2d4"}}, +{"ancient brass dragon", + 70, TRUE, FALSE, 'r', "13-14", + {CANBSGAS, CANBFGAS, ISGREED, CANSEE, NOSLEEP, NOFEAR, + CARRYGOLD, CARRYRING}, + 0, 0, + 50, + {10, 10, 6, 10000, 8, 2, HPT("0d8+64"), + "1d4/1d4/4d4"}}, +{"pit fiend", + 100, TRUE, TRUE, 'f', "15-16", + {ISMEAN, CANSEE, BMAGICHIT, CANFRIGHTEN, CANHOLD, CANSUMMON, + CANBFIRE, NOFIRE, CANTELEPORT, CARRYSTICK, HASFIRE, ISFLY}, + "barbed devil", 3, + 18, + {22, 10, 6, 10000, 13, -3, HPT("13d8"), + "1d4+4/1d6+6"}}, +{"ancient white dragon", + 70, TRUE, TRUE, 'W', "8-9", + {ISMEAN, CANBICE, ISGREED, CANSEE, NOCOLD, CARRYGOLD, + CARRYRING}, + 0, 0, + 50, + {10, 10, 6, 15000, 7, 3, HPT("0d8+56"), + "1d4/1d4/2d8"}}, +{"ancient black dragon", + 70, TRUE, TRUE, 'a', "8-10", + {ISMEAN, CANBACID, NOACID, ISGREED, CANSEE, CARRYGOLD, + CARRYSTICK}, + 0, 0, + 50, + {10, 10, 6, 20000, 8, 3, HPT("0d8+64"), + "1d4/1d4/3d6"}}, +{"lich", + 60, TRUE, TRUE, 'l', "19-20", + {ISMEAN, CANDRAIN, CANSEE, CANPARALYZE, CANFRIGHTEN, MAGICHIT, + ISUNDEAD, TURNABLE, NOBOLT, CANMISSILE, CANSUMMON, CARRYGOLD, + CARRYSCROLL, CARRYPOTION, CARRYRING, CARRYSTICK}, + "specter", 2, + 16, + {10, 10, 6, 20000, 17, 0, HPT("11d8"), + "1d10"}}, +{"titan", + 80, TRUE, FALSE, 't', "17-20", + {ISMEAN, ISSHADOW, CANSEE, CANMISSILE, CARRYRING, CARRYSTICK, + CANTELEPORT}, + 0, 0, + 30, + {13, 10, 5, 20000, 19, -3, HPT("22d8"), + "8d6"}}, +{"ancient copper dragon", + 70, TRUE, FALSE, 'c', "13-14", + {CANBACID, NOACID, CANBSLGAS, ISGREED, CANSEE, NOSLOW, + CARRYGOLD, CARRYSTICK}, + 0, 0, + 50, + {10, 10, 6, 20000, 9, 1, HPT("0d8+72"), + "1d4/1d4/5d4"}}, +{"ancient green dragon", + 50, TRUE, TRUE, 'E', "10-12", + {ISMEAN, CANBGAS, ISGREED, CANSEE, NOGAS, CARRYGOLD, + CARRYRING, CARRYSTICK}, + 0, 0, + 50, + {10, 10, 6, 20000, 9, 2, HPT("0d8+72"), + "1d6/1d6/2d10"}}, +{"ancient bronze dragon", + 50, TRUE, FALSE, 'L', "15-16", + {CANBCGAS, CANBBOLT, CANBFGAS, ISGREED, CANSEE, NOFEAR, NOBOLT, + ISCLEAR, CARRYGOLD, CARRYRING, CARRYSTICK}, + 0, 0, + 50, + {10, 10, 6, 20000, 10, 0, HPT("0d8+80"), + "1d6/1d6/4d6"}}, +{"ancient blue dragon", + 50, TRUE, TRUE, 'u', "12-14", + {ISMEAN, CANBBOLT, ISGREED, CANSEE, NOBOLT, CARRYGOLD, + CARRYSCROLL, CARRYRING, CARRYSTICK}, + 0, 0, + 50, + {10, 10, 6, 20000, 10, 2, HPT("0d8+80"), + "1d6/1d6/3d8"}}, +{"ancient silver dragon", + 40, TRUE, FALSE, 'S', "15-16", + {CANBICE, CANBPGAS, ISGREED, CANSEE, CANMISSILE, NOCOLD, + NOPARALYZE, CARRYGOLD, CARRYSCROLL, CARRYRING, CARRYSTICK}, + 0, 0, + 50, + {10, 10, 6, 20000, 11, -1, HPT("0d8+88"), + "1d6/1d6/5d6"}}, +{"frost giant", + 50, TRUE, TRUE, 'F', "5-10", + {ISMEAN, NOCOLD, CARRYGOLD, AREMANY}, + 0, 0, + 40, + {25, 10, 5, 20000, 15, 4, HPT("10d8+4"), + "4d6"}}, +{"ancient red dragon", + 40, TRUE, TRUE, 'R', "15-16", + {ISMEAN, CANBFIRE, ISGREED, CANSEE, NOFIRE, CARRYGOLD, + CARRYPOTION, CARRYRING, CARRYSTICK}, + 0, 0, + 50, + {10, 10, 6, 20000, 11, -1, HPT("0d8+88"), + "1d8/1d8/3d10"}}, +{"ancient gold dragon", + 50, TRUE, FALSE, 'G', "17-18", + {CANBFIRE, CANBGAS, ISGREED, CANSEE, CANMISSILE, NOFIRE, NOGAS, + CARRYGOLD, CARRYPOTION, CARRYRING, CARRYSTICK, CANTELEPORT}, + 0, 0, + 50, + {10, 10, 6, 20000, 12, -2, HPT("0d8+96"), + "1d8/1d8/6d6"}}, +{"fire giant", + 30, TRUE, TRUE, 'f', "6-10", + {ISMEAN, CARRYGOLD, NOFIRE, AREMANY}, + 0, 0, + 45, + {27, 10, 5, 26000, 15, 4, HPT("11d8+5"), + "5d6"}}, +{"storm giant", + 30, TRUE, TRUE, 's', "8-10", + {ISMEAN, NOBOLT, CANBBOLT, CARRYRING}, + 0, 0, + 50, + {30, 10, 5, 30000, 15, 2, HPT("15d8+8"), + "7d6"}}, +{"dwarven thief (Musty Doit)", + 50, TRUE, TRUE, 'm', "16", + {ISMEAN, ISUNIQUE, ISINVIS, NOFIRE, NOGAS, NOSTAB, STEALGOLD, + STEALMAGIC, CANPAIN, ISFLY, CARRYGOLD, CANSURPRISE, CANSEE, + CARRYMDAGGER, CARRYMISC, CARRYPOTION, CANBSTAB, ISSCAVENGE, + NODETECT}, + 0, 0, + 0, + {9, 18, 8, 300000, 22, -5, HPT("0d8+95"), + "6d4+70/6d4+70"}}, +{"demon prince (Jubilex)", + 100, TRUE, FALSE, 'J', "18", + {ISMEAN, ISUNIQUE, CANFRIGHTEN, ISREGEN, BMAGICHIT, ISSHADOW, + CANHOLD, CANDISEASE, CANSUMMON, CANSEE, CANROT, CANINFEST, + CANRUST, NOSTAB, CANTELEPORT, CARRYMISC, CANSMELL, CANSTINK, + NOFIRE}, + "black pudding", 4, + 0, + {18, 18, 5, 100000, 20, -7, HPT("0d8+88"), + "4d10"}}, +{"arch devil (Geryon)", + 100, TRUE, FALSE, 'g', "16", + {ISMEAN, ISUNIQUE, BMAGICHIT, CANSEE, ISSHADOW, CANFRIGHTEN, + CANHUH, CANPOISON, CANSUMMON, NOFIRE, CANTELEPORT, NOFIRE, + CARRYMISC, CARRYHORN}, + "ice devil", 5, + 0, + {18, 18, 5, 110000, 30, -3, HPT("0d8+133"), + "3d6/3d6/2d4"}}, +{"arch devil (Dispater)", + 100, TRUE, FALSE, 'd', "18", + {ISMEAN, ISUNIQUE, CANSEE, CANFRIGHTEN, CANHUH, BMAGICHIT, + CANSUMMON, CARRYSTICK, NOFIRE, CANTELEPORT, CARRYMISC}, + "ghost", 9, + 0, + {18, 18, 5, 120000, 36, -2, HPT("0d8+144"), + "4d6"}}, +{"demon prince (Yeenoghu)", + 100, TRUE, FALSE, 'Y', "16", + {ISMEAN, ISREGEN, ISUNIQUE, MAGICHIT, CANSEE, ISSHADOW, CANHOLD, + CARRYFLAIL, CANFRIGHTEN, CANPARALYZE, CANSUMMON, CANHUH, + CANMISSILE, CANTELEPORT, CARRYMISC, NOFIRE}, + "lich", 5, + 0, + {18, 18, 5, 130000, 23, -5, HPT("0d8+100"), + "3d6/3d6"}}, +{"witch (Emori)", + 50, TRUE, TRUE, 'w', "18", + {ISMEAN, CANMISSILE, ISINVIS, CANBBOLT, CANBFIRE, CANBICE, + CANSEE, CANSUMMON, ISUNIQUE, CANSNORE, ISFLY, TAKEINTEL, + CANDANCE, CANDISEASE, NOBOLT, NOCOLD, NOFIRE, CARRYCLOAK, + ISCLEAR, CARRYSCROLL, CARRYSTICK, CANTELEPORT, CANSLOW}, + "shambling mound", 7, + 0, + {21, 12, 6, 140000, 25, 0, HPT("0d8+102"), + "1d4/1d4"}}, +{"cleric of Thoth (Heil)", + 100, TRUE, TRUE, 'h', "16", + {ISMEAN, CANSEE, NOFEAR, ISREGEN, CANHOLD, CANBFIRE, ISUNIQUE, + DOUBLEDRAIN, CANSUMMON, NOFIRE, TOUCHFEAR, CANDISEASE, CANSUCK, + CANSEE, TAKEWISDOM, CARRYANKH, CARRYRING, ISINVIS, ISFLY}, + "vampire", 9, + 0, + {25, 15, 6, 150000, 25, -8, HPT("0d8+116"), + "0d6+11"}}, +{"magician (Tsoming Zen)", + 80, TRUE, FALSE, 'z', "18", + {ISMEAN, ISUNIQUE, ISINVIS, ISREGEN, CANBFIRE, CANBICE, + CANBBOLT, CANMISSILE, NOFIRE, CANHOLD, CANFRIGHTEN, CANDISEASE, + CANPAIN, CANSUMMON, CANSEE, ISFLY, CANTELEPORT, + CARRYSTAFF, CARRYSTICK, NOSLOW, NOBOLT, NOCOLD}, + "ancient black dragon", 5, + 0, + {18, 16, 6, 160000, 21, -4, HPT("0d8+125"), + "2d4+1/2d4+1/2d4+1/2d4+1"}}, +{"poet (Brian)", + 80, TRUE, TRUE, 'p', "16", + {ISMEAN, ISUNIQUE, STEALGOLD, ISSHADOW, CANSUMMON, ISREGEN, + CANDISEASE, NOCOLD, NOBOLT, NOFIRE, NOFEAR, CANTUNNEL, CANSEE, + CANINWALL, ISCLEAR, CARRYMANDOLIN, CARRYPOTION, CARRYRING}, + "umber hulk", 6, + 0, + {19, 18, 5, 170000, 20, -2, HPT("0d8+156"), + "8d8+48/4d4+36"}}, +{"lesser god (Hruggek)", + 100, TRUE, FALSE, 'H', "17", + {ISMEAN, CANSEE, ISUNIQUE, CANSUMMON, ISREGEN, CANFRIGHTEN, + CANTELEPORT, CARRYMISC, CARRYMSTAR, CANSMELL, CANBLINK}, + "purple worm", 6, + 0, + {19, 18, 5, 180000, 25, 0, HPT("0d8+221"), + "2d8/2d8"}}, +{"lesser god (Kurtulmak)", + 100, TRUE, TRUE, 'K', "19", + {ISMEAN, CANFRIGHTEN, CANPOISON, CANSEE, ISUNIQUE, CANSUMMON, + CANTELEPORT, CARRYMISC, CANBLINK}, + "lich", 3, + 0, + {19, 18, 5, 190000, 27, 0, HPT("0d8+219"), + "2d12/1d6"}}, +{"demigod (Vaprak \"The Destroyer\")", + 100, TRUE, TRUE, 'v', "18", + {ISMEAN, ISUNIQUE, ISREGEN, MAGICHIT, CANSEE, CANSUMMON, + CANTELEPORT, CARRYMISC, CANSMELL}, + "troll", 9, + 0, + {18, 18, 5, 200000, 26, 0, HPT("0d8+198"), + "2d10/2d10/1d12"}}, +{"hero (Aklad)", + 100, TRUE, FALSE, 'k', "16", + {ISMEAN, ISUNIQUE, CANSUMMON, ISREGEN, NOCOLD, NOBOLT, NOFIRE, + NOPARALYZE, NOFEAR, CANSEE, ISCLEAR, CARRYAXE, CARRYRING, + CARRYMISC, CANBLINK}, + "ancient green dragon", 4, + 0, + {25, 16, 4, 210000, 25, -10, HPT("0d8+196"), + "2d8+23/2d8+23/1d6+19/1d6+19"}}, +{"magician/thief (Nagrom)", + 100, TRUE, TRUE, 'N', "19", + {ISMEAN, ISUNIQUE, STEALMAGIC, ISINVIS, CANSUMMON, ISREGEN, + CANMISSILE, CANSEE, CARRYQUILL, CARRYSCROLL, CARRYRING, ISFLY, + CANBSTAB, CANBFIRE, CANBBOLT, CANBICE, NOCOLD, NOBOLT, NOFIRE, + CANSURPRISE, NODETECT, CANTELEPORT, CANSLOW, + CARRYSTICK}, + "ancient blue dragon", 5, + 0, + {18, 18, 8, 220000, 26, -2, HPT("0d8+150"), + "1d10+3/1d4+3"}}, +{"platinum dragon (Bahamut)", + 100, TRUE, FALSE, 'P', "20", + {ISUNIQUE, CANBICE, CANBGAS, CANBBOLT, CANBRANDOM, CANSEE, + NOCOLD, NOBOLT, NOGAS, NOFIRE, NOFEAR, NOSLEEP, NOSLOW, + NOPARALYZE, CANMISSILE, CANSONIC, CANFRIGHTEN, CANSUMMON, + CARRYMISC, CANTELEPORT, ISFLY}, + "ancient gold dragon", 4, + 0, + {18, 18, 5, 230000, 38, -3, HPT("0d8+168"), + "2d6/2d6/6d8"}}, +{"arch devil (Baalzebul)", + 100, TRUE, FALSE, 'B', "18", + {ISMEAN, ISSHADOW, ISUNIQUE, BMAGICHIT, CANHOLD, CANPOISON, + CANFRIGHTEN, CANHUH, CANSUMMON, CANSEE, NOFIRE, CANTELEPORT, + CARRYMISC, CARRYSTICK, CANDRAIN}, + "ice devil", 9, + 0, + {18, 18, 5, 240000, 37, -5, HPT("0d8+166"), + "2d6"}}, +{"chromatic dragon (Tiamat)", + 100, TRUE, FALSE, 'C', "18", + {ISMEAN, ISUNIQUE, CANBFIRE, CANBACID, CANBBOLT, CANBICE, + CANBGAS, CANBRANDOM, CANSEE, NOFIRE, NOBOLT, NOCOLD, NOACID, + NOGAS, CANSUMMON, CANMISSILE, CANFRIGHTEN, CARRYMISC, + CARRYRING, CANTELEPORT, ISFLY}, + "ancient red dragon", 6, + 0, + {18, 18, 5, 250000, 29, 0, HPT("0d8+128"), + "2d8/3d6/2d10/3d8/3d10/1d6"}}, +{"demon prince (Orcus)", + 100, TRUE, FALSE, 'O', "20", + {ISMEAN, ISUNIQUE, BMAGICHIT, CANPOISON, CANFRIGHTEN, CANSEE, + CANBBOLT, CANSUMMON, NOBOLT, CANTELEPORT, CARRYWAND, NOFIRE, + CARRYMISC, ISFLY, CARRYSTICK}, + "vampire", 9, + 0, + {18, 18, 5, 260000, 27, -6, HPT("0d8+120"), + "1d10+3/2d4"}}, +{"arch devil (Asmodeus)", + 100, TRUE, FALSE, 'A', "20", + {ISMEAN, ISUNIQUE, CANSEE, ISSHADOW, CANHOLD, BMAGICHIT, + CANFRIGHTEN, CANHUH, TOUCHSLOW, CANSUMMON, NOFIRE, + CANTELEPORT, CARRYROD, CARRYMISC, CARRYSTICK, CANDRAIN}, + "pit fiend", 5, + 0, + {18, 18, 5, 270000, 45, -7, HPT("0d8+199"), + "1d10+4"}}, +{"demon prince (Demogorgon)", + 100, TRUE, FALSE, 'D', "20", + {ISMEAN, CANHUH, BMAGICHIT, DOUBLEDRAIN, CANINFEST, CANSEE, + CANFRIGHTEN, ISUNIQUE, CANSUMMON, CANROT, CANTELEPORT, NOFIRE, + CANDISEASE, CARRYMISC, CANSUCK, CARRYSTICK}, + "pit fiend", 9, + 0, + {18, 18, 5, 280000, 45, -8, HPT("0d8+200"), + "1d6/1d6"}}, +{"greater god (Maglubiyet)", + 100, TRUE, FALSE, 'M', "19", + {ISMEAN, ISUNIQUE, CMAGICHIT, CANSEE, ISREGEN, CANSUMMON, + CANTELEPORT, CARRYMISC, CANFRIGHTEN, CARRYSTICK}, + "lich", 6, + 0, + {19, 18, 5, 290000, 45, -1, HPT("0d8+350"), + "2d10/2d10"}}, +{"greater god (Gruumsh)", + 100, TRUE, FALSE, 'G', "19", + {ISMEAN, ISUNIQUE, CMAGICHIT, CANSEE, ISREGEN, CANSUMMON, + CANTELEPORT, CARRYMISC, CANFRIGHTEN, CARRYSTICK}, + "lich", 9, + 0, + {19, 18, 5, 300000, 45, -1, HPT("0d8+350"), + "3d10/3d10"}}, +{"lesser god (Thrym)", + 100, TRUE, FALSE, 'T', "16", + {ISMEAN, NOCOLD, ISUNIQUE, ISREGEN, CMAGICHIT, CANSEE, + CANSUMMON, CARRYMISC, CANTELEPORT, CANFRIGHTEN, CARRYSTICK}, + "frost giant", 9, + 0, + {25, 18, 5, 310000, 45, -2, HPT("0d8+360"), + "4d10/4d10"}}, +{"lesser god (Surtur)", + 100, TRUE, FALSE, 't', "19", + {ISMEAN, NOFIRE, ISUNIQUE, ISREGEN, CMAGICHIT, CANSEE, + CANFRIGHTEN, CANSUMMON, CANMISSILE, CANTELEPORT, CARRYMISC, + CARRYSTICK, CARRYFOOD, CARRYSURTURRING}, + "fire giant", 9, + 0, + {25, 18, 5, 320000, 45, -2, HPT("0d8+380"), + "5d10/5d10"}}, +{"lesser god (Skoraeus Stonebones)", + 100, TRUE, FALSE, 'b', "19", + {ISMEAN, ISUNIQUE, ISREGEN, CMAGICHIT, CANSEE, CANSUMMON, ISFLY, + CANMISSILE, CANINWALL, CANTELEPORT, CARRYMISC, CARRYSTICK, + CANFRIGHTEN, CARRYBAMULET}, + "storm giant", 9, + 0, + {25, 25, 6, 330000, 45, -1, HPT("0d8+380"), + "6d10/6d10"}}, +{"ruler of greater titans (Yendor)", + 100, TRUE, TRUE, 'y', "25", + {ISMEAN, CANINWALL, ISUNIQUE, ISREGEN, CMAGICHIT,ISFLY, + CANSUMMON, CANMISSILE, CANFRIGHTEN, CANBFIRE, NOFIRE, + CANHOLD, CARRYYAMULET, CANSEE, CANDANCE, ISSHADOW, + CANTELEPORT, CARRYMISC, CARRYRING, CARRYSTICK}, + "titan", 15, + 0, + {25, 25, 6, 340000, 45, -6, HPT("0d8+400"), + "7d10/7d10"}}, +{"the creator of liches (Vecna)", + 100, TRUE, TRUE, 'V', "25", + {ISMEAN, CANINWALL, ISUNIQUE, ISREGEN, CMAGICHIT, CANSNORE, + CANSUMMON, CANMISSILE, CANFRIGHTEN, CANBFIRE, NOFIRE, ISFLY, + CANHOLD, CARRYEYE, CANSEE, CANDANCE, ISINVIS, HALFDAMAGE, + CANTELEPORT, CARRYMISC, CARRYRING, CARRYSTICK, LOOKSTONE, + CANSLOW, CANBLIND}, + "lich", 15, + 0, + {25, 25, 6, 350000, 47, -8, HPT("0d8+450"), + "6d10/6d10"}}, +{"quartermaster", + 0, FALSE, TRUE, 'q', "18", + {CANSELL, ISCLEAR, CANTELEPORT, ISFLY, CANSEE, STEALMAGIC, + NOFEAR, CANBSTAB}, + 0, 0, + 50, + {25, 18, 12, 20, 1, -4, HPT("1d8+1"), + "1d10"}}, +}; diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/rogue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/rogue.h Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1299 @@ +/* + * rogue.h - Rogue definitions and variable declarations + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Rogue definitions and variable declarations + * + */ + +#define reg register +#undef lines /* AIX's term.h defines this, causing a conflict */ +#ifdef BSD +#undef tolower(c) +#define _tolower(c) ((c)-'A'+'a') +extern char tolower(); +#undef toupper(c) +#define _toupper(c) ((c)-'a'+'A') +extern char toupper(); +#define strchr index + +#define exfork vfork /* Better way to do a fork followed by an exec */ +#else +#define exfork fork /* Standard fork with no paging available */ +#endif + +/* + * Maximum number of different things + */ +#define MAXDAEMONS 10 +#define MAXFUSES 20 +#define MAXROOMS 9 +#define MAXTHINGS 9 +#define MAXOBJ 9 +#define MAXSTATS 72 /* max total of all stats at startup */ +#define MAXPACK 23 +#define MAXDOUBLE 14 /* Maximum number of times exppts is doubled */ +#define MAXCONTENTS 10 +#define MAXENCHANT 10 /* max number of enchantments on an item */ +#define MAXTREAS 15 /* number monsters/treasure in treasure room */ +#define MAXTRAPS 25 +#define MAXTRPTRY 8 /* 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 18 /* Maximum number of prayers for cleric */ +#define MAXSPELLS 20 /* Maximum number of spells (for magician) */ +#define MAXQUILL 13 /* scrolls the Quill of Nagrom can write */ +#define QUILLCHARGES 160 /* max num of charges in the Quill of Nagrom */ +#define NUMMONST 125 /* Current number of monsters */ +#define NUM_CNAMES 17 /* number of names per character level */ +#define NUMUNIQUE 27 /* number of UNIQUE creatures */ +#define NLEVMONS 3 /* Number of new monsters per level */ +#define NUMSCORE 10 /* number of entries in score file */ +#define HARDER 35 /* 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) /* # of purchases at post */ + +/* 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 1500 /* 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_ASSASIN 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 + +/* + * 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 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) +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif +#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) + +#undef CTRL +#define CTRL(ch) (ch & 037) + +#define ALLOC(x) calloc((unsigned int) x,1) +#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 == '-') || (ch == '|') || (ch == SECRETDOOR)) +#define invisible(monst) \ + (((on(*monst, ISINVIS) || \ + (on(*monst, ISSHADOW) && rnd(100) < 90)) && \ + off(player, CANSEE)) || \ + (on(*monst, CANSURPRISE) && !ISWEARING(R_ALERT))) +#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 DEATHNUM 20 /* number of ways to die */ + +/* + * Things that appear on the screens + */ +#define WALL ' ' +#define PASSAGE '#' +#define DOOR '+' +#define FLOOR '.' +#define VPLAYER '@' +#define IPLAYER '_' +#define POST '^' +#define TRAPDOOR '>' +#define ARROWTRAP '{' +#define SLEEPTRAP '$' +#define BEARTRAP '}' +#define TELTRAP '~' +#define DARTTRAP '`' +#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 + */ +#define PASSWD "mTdNfNGDrwAZ." +#define FIGHTBASE 10 +#define SPELLTIME ((max(30-pstats.s_lvl,5))) +#define BEARTIME 17 +#define CLOAK_TIME (roll(20,20)) +#define SLEEPTIME 7 +#define FREEZETIME 11 +#define PAINTIME (roll(2, 12)) +#define HEALTIME 30 +#define CHILLTIME (roll(20, 4)) +#define SMELLTIME 20 +#define STONETIME (roll(10,2)) +#define HASTETIME 11 +#define SICKTIME 25 +#define WANDERTIME (max(5, (HARDER*2)-rnd(vlevel))) +#define BEFORE 1 +#define AFTER 2 +#define HUHDURATION (50+rnd(30)) +#define SEEDURATION 850 +#define SKILLDURATION (100+rnd(50)) +#define CLRDURATION 50 +#define GONETIME 200 +#define FIRETIME (200+roll(5,5)) +#define COLDTIME (200+roll(5,5)) +#define BOLTTIME (200+roll(5,5)) +#define FLYTIME 300 +#define DUSTTIME (30+roll(5,10)) +#define PHASEDURATION 300 +#define MORETIME 100 +#define STINKTIME 16 +#define STOMACHSIZE 1500 +#define ESCAPE 27 +#define BOLT_LENGTH 10 +#define MARKLEN 20 +#define DAYLENGTH 400 +#define ALCHEMYTIME (400+rnd(150)) + +/* + * 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 /* clorine 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 */ + + +#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 ISCHARMED 0x50080000 /* is the monster charmed? */ +#define ISFRIENDLY 0x50080000 /* monster friendly for any reason? */ + +#define ISREADY 0x60000001 +#define ISDEAD 0x60000002 +#define ISELSEWHERE 0x60000004 + +/* 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 ( 0 ) +#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 MAXFOODS 21 +/* + * 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 MAXMM 22 + +/* + * 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 MAXRELIC 16 + + +#define LEVEL 600 +#define vlevel max(level, turns/LEVEL + 1) +/* + * Now we 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 level */ + STARTLEV /* beginning of the game */ +} LEVTYPE; + +/* + * Help list + */ + +struct h_list { + char h_ch; + char *h_desc; +}; + +/* + * Coordinate data type + */ +typedef struct { + int x; + int y; +} coord; + +/* + * structure for the ways to die + */ +struct death_type { + int reason; + char *name; +}; + + +/* + * 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; + 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 { + char tr_type; /* What kind of trap */ + 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 s_str; /* Strength */ + short s_dex; /* dexterity */ + short s_move; /* movement rate */ + unsigned long s_exp; /* Experience */ + short s_lvl; /* Level of mastery */ + short s_arm; /* Armor class */ + char *s_hpt; /* Hit points */ + char *s_dmg; /* String describing damage done */ +}; + +/* + * Structure for monsters and player + */ +struct thing { + bool t_wasshot; /* Was character shot last round? */ + char t_type; /* What it is */ + char t_disguise; /* What mimic looks like */ + 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; +}; + +/* + * Array containing information on all the various types of monsters + */ +struct monster { + char *m_name; /* 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; /* Intelligence range */ + long m_flags[MAXFLAGS]; /* Things about the monster */ + char *m_typesum; /* 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_text; /* What it says if you read it */ + 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 */ + char o_mark[MARKLEN]; /* Mark the specific object */ +}; +/* + * weapon structure + */ +struct init_weps { + char *w_name; /* name of weapon */ + char *w_dam; /* hit damage */ + char *w_hrl; /* 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; /* 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 quill { + short s_which; /* which scroll to write */ + short s_cost; /* cost of writing it */ +}; + +struct delayed_action { + int d_type; + int (*d_func)(); + union { + int arg; + void *varg; + } d_; + int d_time; +} ; + +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 *malloc(), *getenv(), *tr_name(), *new(), *sprintf(), */ +char *getenv(), *tr_name(), *new(), + *vowelstr(), *inv_name(), *strcpy(), *strcat(); +char *num(), *ring_num(), *misc_num(), *blesscurse(), *p_kind(), + *typ_name(), *prname(), *monster_name(), *weap_name(), *misc_name(); +coord *rndmove(), *can_shoot(), *fallpos(), *doorway(), get_coordinates(); +short randmonster(), id_monst(), movement(); +void quit(int), auto_save(int), bugkill(int), endit(int), tstp(int), + byebye(int); +int 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(); +bool blue_light(), can_blink(), creat_mons(), add_pack(), + straight_shot(), maze_view(), lit_room(), getdelta(), save_file(), + save_game(), m_use_it(), m_use_pack(), get_dir(), need_dir(); +long lseek(), check_level(); +void genmonsters(), + add_intelligence(), add_strength(), add_wisdom(), add_dexterity(), + add_constitution(), add_charisma(), res_intelligence(), res_strength(int), + res_wisdom(), res_dexterity(), res_constitution(), res_charisma(); + +void writelog(unsigned long amount, int flags, short monst); + +#ifdef CHECKTIME +int checkout(); +#endif + + +/* + * Now all the global variables + */ + +extern struct trap traps[]; +extern struct h_list helpstr[]; +extern struct h_list wiz_help[]; +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 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 magic users */ +extern struct spells cleric_spells[]; /* spells for clerics */ +extern struct spells druid_spells[]; /* spells for druids */ +extern struct quill quill_scrolls[]; /* scrolls for quill */ +extern char *cnames[][17]; /* Character level names */ +extern char *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 char 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 int 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 dnum; /* Dungeon number */ +extern int max_level; /* Deepest player has gone */ +extern int cur_max; /* Deepest player has gone currently */ +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 int 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 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; /* Are savefiles in SAVEDIR */ +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 coord oldpos; /* Position before last look() call */ +extern coord grid[]; /* used for random pos generation */ +extern char *nothing; /* "nothing happens" msg */ +extern char *spacemsg; +extern char *morestr; +extern char *retstr; +extern LEVTYPE levtype; +extern void (*add_abil[NUMABILITIES])(); /* Functions to change abilities */ +extern void (*res_abil[NUMABILITIES])(); /* Functions to change abilities */ +extern int cNCOLORS, cNWOOD, cNMETAL, cNSTONES; +extern char *rainbow[], *stones[], *wood[], *metal[]; +extern int land(), wghtchk(), undance(), cloak_charge(struct object *); +extern struct delayed_action d_list[MAXDAEMONS]; +extern struct delayed_action f_list[MAXFUSES]; +extern int demoncnt, fusecnt, between, chance; +#define CCHAR(x) ( (char) (x & A_CHARTEXT) ) +extern char *md_gethostname(), *md_getusername(), *md_gethomedir(), *md_getroguedir(), *md_crypt(); diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/rooms.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/rooms.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,296 @@ +/* + * rooms.c - Draw the nine rooms on the screen + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Draw the nine rooms on the screen + * + */ + +#include +#include "curses.h" +#include "rogue.h" + +do_rooms() +{ + register int i; + register struct room *rp; + register struct linked_list *item; + register struct thing *tp; + int left_out; + int num_monsters; + int which_monster; + int j; + coord top; + coord bsze; + coord mp; + coord *np; + + /* + * bsze is the maximum room size + */ + bsze.x = cols/3; + bsze.y = (lines-2)/3; + /* + * Clear things for a new level + */ + for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) { + rp->r_flags = 0; + rp->r_fires = NULL; + } + /* + * 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.x = -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) < 50 && 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('-'); +} + +/* + * 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('|'); + } +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/save.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/save.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,321 @@ +/* + * save.c - save and restore routines + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * save and restore routines + * + */ + +#include "curses.h" +#include +#include +#include +#include +#include +#include +#include "rogue.h" +#include +#include +#include "mach_dep.h" +#ifdef PC7300 +#include "sys/window.h" +extern struct uwdata wdata; +#endif + +#if u370 || uts +#define ENCREAD(b,n,fd) read(fd,b,n) +#define ENCWRITE(b,n,fd) write(fd,b,n) +#endif +#ifndef ENCREAD +#define ENCREAD encread +#define ENCWRITE encwrite +#endif + +typedef struct stat STAT; + +extern char version[], encstr[]; +/* extern bool _endwin; */ +extern int errno; + +STAT sbuf; + +bool +save_game() +{ + register int savefd; + 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 = readchar(); + if (c == ESCAPE) 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; + } + } + + 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 ((savefd = open(file_name, O_WRONLY|O_CREAT|O_TRUNC,0666)) < 0) + { + msg(strerror(errno)); /* fake perror() */ + if (use_savedir) + return FALSE; + } + } while (savefd < 0); + + /* + * write out encrpyted file (after a stat) + */ + if (save_file(savefd) == FALSE) { + msg("Cannot create save file."); + unlink(file_name); + return(FALSE); + } + else return(TRUE); +} + +/* + * automatically save a file. This is used if a HUP signal is + * recieved + */ +void +auto_save(sig) +int sig; +{ + register int savefd; + register int i; + + for (i = 0; i < NSIG; i++) + signal(i, SIG_IGN); + if (file_name[0] != '\0' && + pstats.s_hpt > 0 && + (savefd = open(file_name, O_WRONLY|O_CREAT|O_TRUNC, 0600)) >= 0) + save_file(savefd); + endwin(); +#ifdef PC7300 + endhardwin(); +#endif + exit(1); +} + +/* + * write the saved game on the file + */ +bool +save_file(savefd) +register int savefd; +{ + register unsigned num_to_write, num_written; + FILE *savef; + int ret; + + wmove(cw, lines-1, 0); + draw(cw); + lseek(savefd, 0L, 0); + fstat(savefd, &sbuf); + num_to_write = strlen(version) + 1; + num_written = ENCWRITE(version, num_to_write, savefd); + sprintf(prbuf,"%d x %d\n", LINES, COLS); + ENCWRITE(prbuf,80,savefd); + savef = (FILE *) fdopen(savefd,"wb"); + ret = rs_save_file(savef); + fclose(savef); + if (num_to_write == num_written && ret == 0) return(TRUE); + else return(FALSE); +} + +restore(file, envp) +register char *file; +char **envp; +{ + register int inf; + extern char **environ; + char buf[LINELEN]; + STAT sbuf2; + int oldcol, oldline; /* Old number of columns and lines */ + + if (strcmp(file, "-r") == 0) + file = file_name; + if ((inf = open(file, 0)) < 0) + { + if (use_savedir && errno == ENOENT) + { + 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; + } + + /* + * Get the lines and columns from the previous game + */ + + ENCREAD(buf, 80, inf); + sscanf(buf, "%d x %d\n", &oldline, &oldcol); + fstat(inf, &sbuf2); + fflush(stdout); + + initscr(); + + if (COLS < oldcol || LINES < oldline) { + endwin(); + printf("Cannot restart the game on a smaller screen.\n"); + return FALSE; + } + + 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); + + keypad(cw,1); + keypad(msgw,1); + + if (rs_restore_file(inf) != 0) + { + printf("Cannot restore file\n"); + close(inf); + return(FALSE); + } + + cols = COLS; + lines = LINES; + if (cols > 85) cols = 85; + if (lines > 24) lines = 24; + + mpos = 0; + mvwprintw(msgw, 0, 0, "%s: %s", file, ctime(&sbuf2.st_mtime)); + + /* + * defeat multiple restarting from the same place + */ + if (!wizard && md_unlink_open_file(file, inf) < 0) { + printf("Cannot unlink file\n"); + return FALSE; + } + + environ = envp; + strcpy(file_name, file); + setup(); + clearok(curscr, TRUE); + touchwin(cw); + srand(getpid()); + playit(); + /*NOTREACHED*/ + return(0); +} + +#define ENCWBSIZ 1024 +/* + * perform an encrypted write + */ +encwrite(start, size, outf) +register char *start; +register unsigned size; +register int outf; +{ + register char *ep; + register int i = 0; + int num_written = 0; + auto char buf[ENCWBSIZ]; + + ep = encstr; + + while (size--) + { + buf[i++] = *start++ ^ *ep++ ; + if (*ep == '\0') + ep = encstr; + + if (i == ENCWBSIZ || size == 0) { + if (write(outf, buf, (unsigned)i) < i) + return(num_written); + else { + num_written += i; + i = 0; + } + } + } + return(num_written); +} + +/* + * perform an encrypted read + */ +encread(start, size, inf) +register char *start; +register unsigned size; +register int inf; +{ + register char *ep; + register int read_size; + + if ((read_size = read(inf, start, size)) == -1 || read_size == 0) + return read_size; + + ep = encstr; + + size = read_size; + while (size--) + { + *start++ ^= *ep++; + if (*ep == '\0') + ep = encstr; + } + return read_size; +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/scrolls.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/scrolls.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,842 @@ +/* + * scrolls.c - Functions for dealing with scrolls + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Read a scroll and let it happen + * + */ + +#include "curses.h" +#include +#include +#include "rogue.h" + +/* + * let the hero get rid of some type of monster (but not a UNIQUE!) + */ +genocide() +{ + register struct linked_list *ip; + register struct thing *mp; + register struct linked_list *nip; + register int num_monst = NUMMONST-NUMUNIQUE-1, /* cannot genocide uniques */ + pres_monst=1, + num_lines=2*(lines-3); + register int which_monst; + + which_monst = makemonster(FALSE, "Genocide", "wipe out"); + if (which_monst <= 0) { + 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, *nobj; + register struct linked_list *item, *nitem; + register int i,j; + register 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) != 0; + blessed = (obj->o_flags & ISBLESSED) != 0; + + which = obj->o_which; + } + else { + cursed = flag & ISCURSED; + blessed = flag & ISBLESSED; + } + + + switch (which) { + case S_CONFUSE: + /* + * Scroll of monster confusion. Give him that power. + */ + msg("Your hands begin to glow red"); + 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 again."); + 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 + */ + aggravate(TRUE, TRUE); + msg("You hear a high pitched humming noise."); + } + 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); + } + 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); + } + } + } + } + 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(NULL); + } + if (is_scroll) s_know[S_IDENT] = TRUE; + when S_MAP: + /* + * Scroll of magic mapping. + */ + if (is_scroll && s_know[S_MAP] != TRUE) { + msg("Oh, now this scroll has a map on it."); + s_know[S_MAP] = TRUE; + } + overwrite(stdscr, hw); + /* + * Take all the things we want to keep hidden out of the window + */ + for (i = 1; i < lines-2; i++) + for (j = 0; j < cols; j++) + { + switch (nch = ch = CCHAR( mvwinch(hw, i, j) )) + { + case SECRETDOOR: + nch = secretdoor (i, j); + break; + case '-': + case '|': + case DOOR: + case PASSAGE: + case ' ': + case STAIRS: + if (mvwinch(mw, i, j) != ' ') + { + register struct thing *it; + + it = THINGPTR(find_mons(i, j)); + if (it && it->t_oldch == ' ') + it->t_oldch = nch; + } + break; + default: + nch = ' '; + } + if (nch != ch) + waddch(hw, nch); + } + /* + * Copy in what he has discovered + */ + overlay(cw, hw); + /* + * And set up for display + */ + overwrite(hw, cw); + when S_GFIND: + /* + * Scroll of gold detection + */ + { + int gtotal = 0; + + wclear(hw); + for (nitem = lvl_obj; nitem != NULL; nitem = next(nitem)) { + nobj = OBJPTR(nitem); + if (nobj->o_type == GOLD) { + gtotal += nobj->o_count; + mvwaddch(hw, nobj->o_pos.y, nobj->o_pos.x, GOLD); + } + } + for (nitem = mlist; nitem != NULL; nitem = next(nitem)) { + register struct linked_list *gitem; + register struct thing *th; + + th = THINGPTR(nitem); + if (on(*th, NODETECT)) continue; + for(gitem = th->t_pack; gitem != NULL; gitem = next(gitem)){ + nobj = OBJPTR(gitem); + if (nobj->o_type == GOLD) { + gtotal += nobj->o_count; + mvwaddch(hw, th->t_pos.y, th->t_pos.x, GOLD); + } + } + } + if (gtotal) { + if (is_scroll) s_know[S_GFIND] = TRUE; + msg("You begin to feel greedy and you sense gold."); + waddstr(msgw, morestr); + clearok(msgw, FALSE); + draw(msgw); + overlay(hw, cw); + draw(cw); + wait_for(' '); + msg(""); + break; + } + } + msg("You begin to feel a pull downward"); + when S_TELEP: + /* + * Scroll of teleportation: + * Make him disappear and reappear + */ + if (cursed) { + int old_max = cur_max; + + turns = (vlevel * 3) * LEVEL; + level = nfloors; + new_level(NORMLEV); + status(TRUE); + mpos = 0; + msg("You are banished to the lower regions."); + if (old_max == cur_max) /* if he's been here, make it harder */ + aggravate(TRUE, TRUE); + } + else if (blessed) { + int old_level, + much = rnd(4) - 4; + + old_level = level; + if (much != 0) { + level += much; + if (level < 1) + level = 1; + mpos = 0; + cur_max = level; + turns += much*LEVEL; + if (turns < 0) + turns = 0; + new_level(NORMLEV); /* change levels */ + if (level == old_level) + status(TRUE); + msg("You are whisked away to another region."); + } + } + else { + teleport(); + } + if (is_scroll) s_know[S_TELEP] = TRUE; + when S_SCARE: + /* + * A monster will refuse to step on a scare monster scroll + * if it is dropped. Thus reading it is a mistake and produces + * laughter at the poor rogue's boo boo. + */ + msg("You hear maniacal laughter in the distance."); + when S_REMOVE: + if (cursed) { /* curse all player's possessions */ + for (nitem = pack; nitem != NULL; nitem = next(nitem)) { + nobj = OBJPTR(nitem); + if (nobj->o_flags & ISBLESSED) + nobj->o_flags &= ~ISBLESSED; + else + nobj->o_flags |= ISCURSED; + } + msg("The smell of fire and brimstone fills the air."); + } + else if (blessed) { + for (nitem = pack; nitem != NULL; nitem = next(nitem)) { + nobj = OBJPTR(nitem); + nobj->o_flags &= ~ISCURSED; + } + msg("Your pack glistens brightly"); + } + else { + nitem = get_item(pack, "remove the curse on",ALL,FALSE,FALSE); + if (nitem != NULL) { + nobj = OBJPTR(nitem); + nobj->o_flags &= ~ISCURSED; + msg("Removed the curse from %s",inv_name(nobj,TRUE)); + } + } + if (is_scroll) s_know[S_REMOVE] = TRUE; + when S_PETRIFY: + switch (mvinch(hero.y, hero.x)) { + case TRAPDOOR: + case DARTTRAP: + case TELTRAP: + case ARROWTRAP: + case SLEEPTRAP: + case BEARTRAP: + { + register int i; + + /* Find the right trap */ + for (i=0; io_type) { /* ruin it completely */ + case RING: if (lb->o_ac > 0) { + if (is_current(lb)) { + switch (lb->o_which) { + case R_ADDWISDOM: + pstats.s_wisdom -= lb->o_ac; + when R_ADDINTEL: + pstats.s_intel -= lb->o_ac; + when R_ADDSTR: + pstats.s_str -= lb->o_ac; + when R_ADDHIT: + pstats.s_dext -= lb->o_ac; + } + } + did_it = TRUE; + lb->o_ac = 0; + } + when ARMOR: if (lb->o_ac > 10) { + did_it = TRUE; + lb->o_ac = 10; + } + when STICK: if (lb->o_charges > 0) { + did_it = TRUE; + lb->o_charges = 0; + } + when WEAPON:if (lb->o_hplus > 0) { + did_it = TRUE; + lb->o_hplus = 0; + } + if (lb->o_dplus > 0) { + did_it = TRUE; + lb->o_dplus = 0; + } + } + if (lb->o_flags & ISPROT) { + did_it = TRUE; + lb->o_flags &= ~ISPROT; + } + if (lb->o_flags & ISBLESSED) { + did_it = TRUE; + lb->o_flags &= ~ISBLESSED; + } + if (did_it) + msg("Your %s glows red for a moment",inv_name(lb,TRUE)); + else { + msg(nothing); + break; + } + } + else { + lb->o_flags |= ISPROT; + msg("Protected %s.",inv_name(lb,TRUE)); + } + } + if (is_scroll) s_know[S_PROTECT] = TRUE; + } + when S_MAKEIT: + msg("You have been endowed with the power of creation."); + if (is_scroll) s_know[S_MAKEIT] = TRUE; + create_obj(TRUE, 0, 0); + when S_ALLENCH: { + struct linked_list *ll; + struct object *lb; + int howmuch, flags; + if (is_scroll && s_know[S_ALLENCH] == FALSE) { + msg("You are granted the power of enchantment."); + msg("You may enchant anything(weapon,ring,armor,scroll,potion)"); + } + if ((ll = get_item(pack, "enchant", ALL, FALSE, FALSE)) != NULL) { + lb = OBJPTR(ll); + lb->o_flags &= ~ISCURSED; + if (blessed) { + howmuch = 2; + flags = ISBLESSED; + } + else if (cursed) { + howmuch = -1; + flags = ISCURSED; + } + else { + howmuch = 1; + flags = ISBLESSED; + } + switch(lb->o_type) { + case RING: + if (lb->o_ac + howmuch > MAXENCHANT) { + msg("The enchantment doesn't seem to work!"); + break; + } + lb->o_ac += howmuch; + if (lb==cur_ring[LEFT_1] || lb==cur_ring[LEFT_2] || + lb==cur_ring[LEFT_3] || lb==cur_ring[LEFT_4] || + lb==cur_ring[RIGHT_1] || lb==cur_ring[RIGHT_2] || + lb==cur_ring[RIGHT_3] || lb==cur_ring[RIGHT_4]) { + switch (lb->o_which) { + case R_ADDWISDOM: pstats.s_wisdom += howmuch; + when R_ADDINTEL: pstats.s_intel += howmuch; + when R_ADDSTR: pstats.s_str += howmuch; + when R_ADDHIT: pstats.s_dext += howmuch; + } + } + msg("Enchanted %s.",inv_name(lb,TRUE)); + when ARMOR: + if ((armors[lb->o_which].a_class - lb->o_ac) + + howmuch > MAXENCHANT) { + msg("The enchantment doesn't seem to work!"); + break; + } + else + lb->o_ac -= howmuch; + msg("Enchanted %s.",inv_name(lb,TRUE)); + when STICK: + lb->o_charges += (howmuch * 10) + rnd(5); + if (lb->o_charges < 0) + lb->o_charges = 0; + if (EQUAL(ws_type[lb->o_which], "staff")) { + if (lb->o_charges > 100) + lb->o_charges = 100; + } + else { + if (lb->o_charges > 50) + lb->o_charges = 50; + } + msg("Enchanted %s.",inv_name(lb,TRUE)); + when WEAPON: + if(lb->o_hplus+lb->o_dplus+howmuch > MAXENCHANT * 2){ + msg("The enchantment doesn't seem to work!"); + break; + } + if (rnd(100) < 50) + lb->o_hplus += howmuch; + else + lb->o_dplus += howmuch; + msg("Enchanted %s.",inv_name(lb,TRUE)); + when MM: + switch (lb->o_which) { + case MM_BRACERS: + if (lb->o_ac + howmuch > MAXENCHANT) { + msg("The enchantment doesn't seem to work!"); + break; + } + else lb->o_ac += howmuch; + msg("Enchanted %s.",inv_name(lb,TRUE)); + when MM_PROTECT: + if (lb->o_ac + howmuch > MAXENCHANT/2) { + msg("The enchantment doesn't seem to work!"); + break; + } + else lb->o_ac += howmuch; + msg("Enchanted %s.",inv_name(lb,TRUE)); + } + lb->o_flags |= flags; + when POTION: + case SCROLL: + default: + lb->o_flags |= flags; + msg("Enchanted %s.",inv_name(lb,TRUE)); + } + } + if (is_scroll) s_know[S_ALLENCH] = TRUE; + if (!is_scroll) { + pstats.s_const--; + max_stats.s_const--; + if (pstats.s_const <= 0) + death(D_CONSTITUTION); + msg("You feel less healthy now"); + } + } + when S_FINDTRAPS: + for (i=0; i 0) { + msg("You sense the presence of traps"); + if (is_scroll) s_know[S_FINDTRAPS] = TRUE; + } + else + msg(nothing); + + when S_RUNES: + { + register struct linked_list *sitem; + + msg("The scroll explodes in a ball of fire!"); + if (on(player, NOFIRE)) { + msg("The fire does not seem to affect you"); + break; + } + explode(&player); + if (pstats.s_hpt <= 0) + death(D_SCROLL); + for (sitem = pack; sitem != NULL; sitem = nitem) { + nitem = next(sitem); /* in case we delete it */ + nobj = OBJPTR(sitem); + /* + * check for loss of all scrolls and give them + * a save versus fire + */ + if (nobj->o_type == SCROLL && roll(1,20) < 19) { + msg("%s burns up!", inv_name(nobj, TRUE)); + inpack--; + detach(pack, sitem); + o_discard(sitem); + } + } + } + + when S_CHARM: + { + bool spots[9]; + int x, y, spot, count, numcharmed, something, bonus; + struct linked_list *item; + register struct thing *tp; + + /* Initialize the places where we look around us */ + for (i=0; i<9; i++) spots[i] = FALSE; + count = 0; /* No spots tried yet */ + numcharmed = 0; /* Nobody charmed yet */ + something = 0; /* Nothing has been seen yet */ + bonus = 0; /* no bonus yet */ + + /* Now look around us randomly for a charmee */ + while (count < 9) { + do { + spot = rnd(9); + } while (spots[spot] == TRUE); + + /* We found a place */ + count++; + spots[spot] = TRUE; + y = hero.y - 1 + (spot / 3); + x = hero.x - 1 + (spot % 3); + + /* Be sure to stay on the board! */ + if (x < 0 || x >= cols || (y < 1) || (y >= lines - 2)) + continue; + + /* Is there a monster here? */ + if (!isalpha(mvwinch(mw, y, x))) continue; + + /* What kind is it? */ + item = find_mons(y, x); + if (item == NULL) continue; + + tp = THINGPTR(item); + if (on(*tp,ISCHARMED) || on(*tp,ISUNIQUE) || on(*tp,ISUNDEAD)) + continue; + + /* Will the monster be charmed? */ + if (blessed) bonus -= 3; + bonus -= (pstats.s_charisma - 13) / 3; + if ((player.t_ctype==C_PALADIN || player.t_ctype==C_RANGER) && + off(*tp, ISMEAN)) + bonus -= 3; + if (save(VS_MAGIC, tp, bonus)) continue; + + /* We got him! */ + numcharmed++; + + /* Let the player know (maybe) */ + if ((off(*tp, ISINVIS) || on(player, CANSEE)) && + (off(*tp, ISSHADOW) || on(player, CANSEE)) && + cansee(y, x)) { + if (on(*tp, CANSURPRISE)) { + turn_off(*tp, CANSURPRISE); + msg("Woah!"); + } + msg("The eyes of %s glaze over!", + prname(monster_name(tp), FALSE)); + something++; + } + + /* Charm him and turn off any side effects */ + turn_on(*tp, ISCHARMED); + runto(tp, &hero); + tp->t_action = A_NIL; + + /* If monster was suffocating us, stop it */ + if (on(*tp, DIDSUFFOCATE)) { + turn_off(*tp, DIDSUFFOCATE); + extinguish(suffocate); + } + + /* If monster held us, stop it */ + if (on(*tp, DIDHOLD) && (--hold_count == 0)) + turn_off(player, ISHELD); + turn_off(*tp, DIDHOLD); + + /* If frightened of this monster, stop */ + if (on(player, ISFLEE) && + player.t_dest == &tp->t_pos) turn_off(player, ISFLEE); + + if ((blessed && numcharmed >= 2) || numcharmed > 0) break; + } + + if (something == 0) msg(nothing); + } + + otherwise: + msg("What a puzzling scroll!"); + return; + } + look(TRUE, FALSE); /* put the result of the scroll on the screen */ + status(FALSE); + if (is_scroll && item && s_know[which] && s_guess[which]) + { + free(s_guess[which]); + s_guess[which] = NULL; + } + else if (is_scroll && + !s_know[which] && + item && + askme && + (obj->o_flags & ISKNOW) == 0 && + (obj->o_flags & ISPOST) == 0 && + s_guess[which] == NULL) { + nameitem(item, FALSE); + } + if (item != NULL) o_discard(item); + updpack(TRUE, &player); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/state.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/state.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,2675 @@ +/* + state.c - Portable Rogue Save State Code + + Copyright (C) 1999, 2000, 2005 Nicholas J. Kisseberth + 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. +*/ + +/************************************************************************/ +/* Save State Code */ +/************************************************************************/ + +#define RSID_STATS 0xABCD0001 +#define RSID_MSTATS 0xABCD0002 +#define RSID_THING 0xABCD0003 +#define RSID_OBJECT 0xABCD0004 +#define RSID_MAGICITEMS 0xABCD0005 +#define RSID_KNOWS 0xABCD0006 +#define RSID_GUESSES 0xABCD0007 +#define RSID_OBJECTLIST 0xABCD0008 +#define RSID_BAGOBJECT 0xABCD0009 +#define RSID_MONSTERLIST 0xABCD000A +#define RSID_MONSTERSTATS 0xABCD000B +#define RSID_MONSTERS 0xABCD000C +#define RSID_TRAP 0xABCD000D +#define RSID_WINDOW 0xABCD000E +#define RSID_DAEMONS 0xABCD000F +#define RSID_STICKS 0xABCD0010 +#define RSID_IARMOR 0xABCD0011 +#define RSID_SPELLS 0xABCD0012 +#define RSID_ILIST 0xABCD0013 +#define RSID_HLIST 0xABCD0014 +#define RSID_DEATHTYPE 0xABCD0015 +#define RSID_CTYPES 0XABCD0016 +#define RSID_COORDLIST 0XABCD0017 +#define RSID_ROOMS 0XABCD0018 + +#include +#include +#include +#include +#include "rogue.h" + +#define READSTAT (format_error || read_error ) +#define WRITESTAT (write_error) + +static int read_error = FALSE; +static int write_error = FALSE; +static int format_error = FALSE; +static int endian = 0x01020304; +#define big_endian ( *((char *)&endian) == 0x01 ) + +int +rs_write(FILE *savef, void *ptr, size_t size) +{ + if (write_error) + return(WRITESTAT); + + if (encwrite(ptr, size, fileno(savef)) != size) + write_error = 1; + + return(WRITESTAT); +} + +int +rs_read(int inf, void *ptr, size_t size) +{ + if (read_error || format_error) + return(READSTAT); + + if (encread(ptr, size, inf) != size) + read_error = 1; + + return(READSTAT); +} + +int +rs_write_uchar(FILE *savef, unsigned char c) +{ + if (write_error) + return(WRITESTAT); + + rs_write(savef, &c, 1); + + return(WRITESTAT); +} + +int +rs_read_uchar(int inf, unsigned char *c) +{ + if (read_error || format_error) + return(READSTAT); + + rs_read(inf, c, 1); + + return(READSTAT); +} + +int +rs_write_char(FILE *savef, char c) +{ + if (write_error) + return(WRITESTAT); + + rs_write(savef, &c, 1); + + return(WRITESTAT); +} + +int +rs_read_char(int inf, char *c) +{ + if (read_error || format_error) + return(READSTAT); + + rs_read(inf, c, 1); + + return(READSTAT); +} + +int +rs_write_chars(FILE *savef, char *c, int count) +{ + if (write_error) + return(WRITESTAT); + + rs_write_int(savef, count); + rs_write(savef, c, count); + + return(WRITESTAT); +} + +int +rs_read_chars(int inf, char *i, int count) +{ + int value = 0; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf, &value); + + if (value != count) + format_error = TRUE; + + rs_read(inf, i, count); + + return(READSTAT); +} + +int +rs_write_int(FILE *savef, int c) +{ + unsigned char bytes[4]; + unsigned char *buf = (unsigned char *) &c; + + if (write_error) + return(WRITESTAT); + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + rs_write(savef, buf, 4); + + return(WRITESTAT); +} + +int +rs_read_int(int inf, int *i) +{ + unsigned char bytes[4]; + int input = 0; + unsigned char *buf = (unsigned char *)&input; + + if (read_error || format_error) + return(READSTAT); + + rs_read(inf, &input, 4); + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + *i = *((int *) buf); + + return(READSTAT); +} + +int +rs_write_ints(FILE *savef, int *c, int count) +{ + int n = 0; + + if (write_error) + return(WRITESTAT); + + rs_write_int(savef, count); + + for(n = 0; n < count; n++) + if( rs_write_int(savef,c[n]) != 0) + break; + + return(WRITESTAT); +} + +int +rs_read_ints(int inf, int *i, int count) +{ + int n, value; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf,&value); + + if (value != count) + format_error = TRUE; + + for(n = 0; n < count; n++) + if (rs_read_int(inf, &i[n]) != 0) + break; + + return(READSTAT); +} + +int +rs_write_boolean(FILE *savef, bool c) +{ + unsigned char buf = (c == 0) ? 0 : 1; + + if (write_error) + return(WRITESTAT); + + rs_write(savef, &buf, 1); + + return(WRITESTAT); +} + +int +rs_read_boolean(int inf, bool *i) +{ + unsigned char buf = 0; + + if (read_error || format_error) + return(READSTAT); + + rs_read(inf, &buf, 1); + + *i = (buf != 0); + + return(READSTAT); +} + +int +rs_write_booleans(FILE *savef, bool *c, int count) +{ + int n = 0; + + if (write_error) + return(WRITESTAT); + + rs_write_int(savef, count); + + for(n = 0; n < count; n++) + if (rs_write_boolean(savef, c[n]) != 0) + break; + + return(WRITESTAT); +} + +int +rs_read_booleans(int inf, bool *i, int count) +{ + int n = 0, value = 0; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf,&value); + + if (value != count) + format_error = TRUE; + + for(n = 0; n < count; n++) + if (rs_read_boolean(inf, &i[n]) != 0) + break; + + return(READSTAT); +} + +int +rs_write_short(FILE *savef, short c) +{ + unsigned char bytes[2]; + unsigned char *buf = (unsigned char *) &c; + + if (write_error) + return(WRITESTAT); + + if (big_endian) + { + bytes[1] = buf[0]; + bytes[0] = buf[1]; + buf = bytes; + } + + rs_write(savef, buf, 2); + + return(WRITESTAT); +} + +int +rs_read_short(int inf, short *i) +{ + unsigned char bytes[2]; + short input; + unsigned char *buf = (unsigned char *)&input; + + if (read_error || format_error) + return(READSTAT); + + rs_read(inf, &input, 2); + + if (big_endian) + { + bytes[1] = buf[0]; + bytes[0] = buf[1]; + buf = bytes; + } + + *i = *((short *) buf); + + return(READSTAT); +} + +int +rs_write_shorts(FILE *savef, short *c, int count) +{ + int n = 0; + + if (write_error) + return(WRITESTAT); + + rs_write_int(savef, count); + + for(n = 0; n < count; n++) + if (rs_write_short(savef, c[n]) != 0) + break; + + return(WRITESTAT); +} + +int +rs_read_shorts(int inf, short *i, int count) +{ + int n = 0, value = 0; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf,&value); + + if (value != count) + format_error = TRUE; + + for(n = 0; n < value; n++) + if (rs_read_short(inf, &i[n]) != 0) + break; + + return(READSTAT); +} + +int +rs_write_ushort(FILE *savef, unsigned short c) +{ + unsigned char bytes[2]; + unsigned char *buf = (unsigned char *) &c; + + if (write_error) + return(WRITESTAT); + + if (big_endian) + { + bytes[1] = buf[0]; + bytes[0] = buf[1]; + buf = bytes; + } + + rs_write(savef, buf, 2); + + return(WRITESTAT); +} + +int +rs_read_ushort(int inf, unsigned short *i) +{ + unsigned char bytes[2]; + unsigned short input; + unsigned char *buf = (unsigned char *)&input; + + if (read_error || format_error) + return(READSTAT); + + rs_read(inf, &input, 2); + + if (big_endian) + { + bytes[1] = buf[0]; + bytes[0] = buf[1]; + buf = bytes; + } + + *i = *((unsigned short *) buf); + + return(READSTAT); +} + +int +rs_write_uint(FILE *savef, unsigned int c) +{ + unsigned char bytes[4]; + unsigned char *buf = (unsigned char *) &c; + + if (write_error) + return(WRITESTAT); + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + rs_write(savef, buf, 4); + + return(WRITESTAT); +} + +int +rs_read_uint(int inf, unsigned int *i) +{ + unsigned char bytes[4]; + int input; + unsigned char *buf = (unsigned char *)&input; + + if (read_error || format_error) + return(READSTAT); + + rs_read(inf, &input, 4); + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + *i = *((unsigned int *) buf); + + return(READSTAT); +} + +int +rs_write_long(FILE *savef, long c) +{ + int c2; + unsigned char bytes[4]; + unsigned char *buf = (unsigned char *)&c; + + if (write_error) + return(WRITESTAT); + + if (sizeof(long) == 8) + { + c2 = c; + buf = (unsigned char *) &c2; + } + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + rs_write(savef, buf, 4); + + return(WRITESTAT); +} + +int +rs_read_long(int inf, long *i) +{ + unsigned char bytes[4]; + long input; + unsigned char *buf = (unsigned char *) &input; + + if (read_error || format_error) + return(READSTAT); + + rs_read(inf, &input, 4); + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + *i = *((long *) buf); + + return(READSTAT); +} + +int +rs_write_longs(FILE *savef, long *c, int count) +{ + int n = 0; + + if (write_error) + return(WRITESTAT); + + rs_write_int(savef,count); + + for(n = 0; n < count; n++) + rs_write_long(savef, c[n]); + + return(WRITESTAT); +} + +int +rs_read_longs(int inf, long *i, int count) +{ + int n = 0, value = 0; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf,&value); + + if (value != count) + format_error = TRUE; + + for(n = 0; n < value; n++) + if (rs_read_long(inf, &i[n]) != 0) + break; + + return(READSTAT); +} + +int +rs_write_ulong(FILE *savef, unsigned long c) +{ + unsigned int c2; + unsigned char bytes[4]; + unsigned char *buf = (unsigned char *)&c; + + if (write_error) + return(WRITESTAT); + + if ( (sizeof(long) == 8) && (sizeof(int) == 4) ) + { + c2 = c; + buf = (unsigned char *) &c2; + } + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + rs_write(savef, buf, 4); + + return(WRITESTAT); +} + +int +rs_read_ulong(int inf, unsigned long *i) +{ + unsigned char bytes[4]; + unsigned long input; + unsigned char *buf = (unsigned char *) &input; + + if (read_error || format_error) + return(READSTAT); + + rs_read(inf, &input, 4); + + if (big_endian) + { + bytes[3] = buf[0]; + bytes[2] = buf[1]; + bytes[1] = buf[2]; + bytes[0] = buf[3]; + buf = bytes; + } + + *i = *((unsigned long *) buf); + + return(READSTAT); +} + +int +rs_write_ulongs(FILE *savef, unsigned long *c, int count) +{ + int n = 0; + + if (write_error) + return(WRITESTAT); + + rs_write_int(savef,count); + + for(n = 0; n < count; n++) + if (rs_write_ulong(savef,c[n]) != 0) + break; + + return(WRITESTAT); +} + +int +rs_read_ulongs(int inf, unsigned long *i, int count) +{ + int n = 0, value = 0; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf,&value); + + if (value != count) + format_error = TRUE; + + for(n = 0; n < count; n++) + if (rs_read_ulong(inf, &i[n]) != 0) + break; + + return(READSTAT); +} + +int +rs_write_marker(FILE *savef, int id) +{ + if (write_error) + return(WRITESTAT); + + rs_write_int(savef, id); + + return(WRITESTAT); +} + +int +rs_read_marker(int inf, int id) +{ + int nid; + + if (read_error || format_error) + return(READSTAT); + + if (rs_read_int(inf, &nid) == 0) + if (id != nid) + format_error = 1; + + return(READSTAT); +} + + + +/******************************************************************************/ + +int +rs_write_string(FILE *savef, char *s) +{ + int len = 0; + + if (write_error) + return(WRITESTAT); + + len = (s == NULL) ? 0 : (int) strlen(s) + 1; + + rs_write_int(savef, len); + rs_write_chars(savef, s, len); + + return(WRITESTAT); +} + +int +rs_read_string(int inf, char *s, int max) +{ + int len = 0; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf, &len); + + if (len > max) + format_error = TRUE; + + rs_read_chars(inf, s, len); + + return(READSTAT); +} + +int +rs_read_new_string(int inf, char **s) +{ + int len=0; + char *buf=0; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf, &len); + + if (len == 0) + buf = NULL; + else + { + buf = malloc(len); + + if (buf == NULL) + read_error = TRUE; + } + + rs_read_chars(inf, buf, len); + + *s = buf; + + return(READSTAT); +} + +int +rs_write_strings(FILE *savef, char *s[], int count) +{ + int n = 0; + + if (write_error) + return(WRITESTAT); + + rs_write_int(savef, count); + + for(n = 0; n < count; n++) + if (rs_write_string(savef, s[n]) != 0) + break; + + return(WRITESTAT); +} + +int +rs_read_strings(int inf, char **s, int count, int max) +{ + int n = 0; + int value = 0; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf, &value); + + if (value != count) + format_error = TRUE; + + for(n = 0; n < count; n++) + if (rs_read_string(inf, s[n], max) != 0) + break; + + return(READSTAT); +} + +int +rs_read_new_strings(int inf, char **s, int count) +{ + int n = 0; + int value = 0; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf, &value); + + if (value != count) + format_error = TRUE; + + for(n = 0; n < count; n++) + if (rs_read_new_string(inf, &s[n]) != 0) + break; + + return(READSTAT); +} + +int +rs_write_string_index(FILE *savef, char *master[], int max, const char *str) +{ + int i; + + if (write_error) + return(WRITESTAT); + + for(i = 0; i < max; i++) + if (str == master[i]) + return( rs_write_int(savef, i) ); + + return( rs_write_int(savef,-1) ); +} + +int +rs_read_string_index(int inf, char *master[], int maxindex, char **str) +{ + int i; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf, &i); + + if (i > maxindex) + format_error = TRUE; + else if (i >= 0) + *str = master[i]; + else + *str = NULL; + + return(READSTAT); +} + +int +rs_write_coord(FILE *savef, coord c) +{ + if (write_error) + return(WRITESTAT); + + rs_write_int(savef, c.x); + rs_write_int(savef, c.y); + + return(WRITESTAT); +} + +int +rs_read_coord(int inf, coord *c) +{ + coord in; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf,&in.x); + rs_read_int(inf,&in.y); + + if (READSTAT == 0) + { + c->x = in.x; + c->y = in.y; + } + + return(READSTAT); +} + +int +rs_write_coord_list(FILE *savef, struct linked_list *l) +{ + rs_write_marker(savef, RSID_COORDLIST); + rs_write_int(savef, list_size(l)); + + while (l != NULL) + { + rs_write_coord(savef, *(coord *) l->l_data); + l = l->l_next; + } + + return(WRITESTAT); +} + +int +rs_read_coord_list(int inf, struct linked_list **list) +{ + int i, cnt; + struct linked_list *l = NULL, *previous = NULL, *head = NULL; + + rs_read_marker(inf, RSID_COORDLIST); + + if (rs_read_int(inf,&cnt) != 0) + return(READSTAT); + + for (i = 0; i < cnt; i++) + { + l = new_item(sizeof(coord)); + l->l_prev = previous; + + if (previous != NULL) + previous->l_next = l; + + rs_read_coord(inf,(coord *) l->l_data); + + if (previous == NULL) + head = l; + + previous = l; + } + + if (l != NULL) + l->l_next = NULL; + + *list = head; + + return(READSTAT); +} + +int +rs_write_window(FILE *savef, WINDOW *win) +{ + int row,col,height,width; + + if (write_error) + return(WRITESTAT); + + width = getmaxx(win); + height = getmaxy(win); + + rs_write_marker(savef,RSID_WINDOW); + rs_write_int(savef,height); + rs_write_int(savef,width); + + for(row=0;rowl_next) + if (count == i) + return(l->l_data); + + return(NULL); +} + +int +find_list_ptr(struct linked_list *l, void *ptr) +{ + int count; + + for(count = 0; l != NULL; count++, l = l->l_next) + if (l->l_data == ptr) + return(count); + + return(-1); +} + +int +list_size(struct linked_list *l) +{ + int count; + + for(count = 0; l != NULL; count++, l = l->l_next) + ; + + return(count); +} + +/******************************************************************************/ + +int +rs_write_levtype(FILE *savef, LEVTYPE c) +{ + int lt; + + switch(c) + { + case NORMLEV: lt = 1; break; + case POSTLEV: lt = 2; break; + case MAZELEV: lt = 3; break; + case OUTSIDE: lt = 4; break; + case STARTLEV: lt = 5; break; + default: lt = -1; break; + } + + rs_write_int(savef,lt); + + return(WRITESTAT); +} + +int +rs_read_levtype(int inf, LEVTYPE *l) +{ + int lt; + + rs_read_int(inf, <); + + switch(lt) + { + case 1: *l = NORMLEV; break; + case 2: *l = POSTLEV; break; + case 3: *l = MAZELEV; break; + case 4: *l = OUTSIDE; break; + case 5: *l = STARTLEV; break; + default: *l = NORMLEV; break; + } + + return(READSTAT); +} + +int +rs_write_stats(FILE *savef, struct stats *s) +{ + if (write_error) + return(WRITESTAT); + + rs_write_marker(savef, RSID_STATS); + rs_write_short(savef, s->s_str); + rs_write_short(savef, s->s_intel); + rs_write_short(savef, s->s_wisdom); + rs_write_short(savef, s->s_dext); + rs_write_short(savef, s->s_const); + rs_write_short(savef, s->s_charisma); + rs_write_ulong(savef, s->s_exp); + rs_write_int(savef, s->s_lvladj); + rs_write_int(savef, s->s_lvl); + rs_write_int(savef, s->s_arm); + rs_write_int(savef, s->s_hpt); + rs_write_int(savef, s->s_pack); + rs_write_int(savef, s->s_carry); + rs_write(savef, s->s_dmg, sizeof(s->s_dmg)); + + return(WRITESTAT); +} + +int +rs_read_stats(int inf, struct stats *s) +{ + if (read_error || format_error) + return(READSTAT); + + rs_read_marker(inf, RSID_STATS); + rs_read_short(inf,&s->s_str); + rs_read_short(inf,&s->s_intel); + rs_read_short(inf,&s->s_wisdom); + rs_read_short(inf,&s->s_dext); + rs_read_short(inf,&s->s_const); + rs_read_short(inf,&s->s_charisma); + rs_read_ulong(inf,&s->s_exp); + rs_read_int(inf,&s->s_lvladj); + rs_read_int(inf,&s->s_lvl); + rs_read_int(inf,&s->s_arm); + rs_read_int(inf,&s->s_hpt); + rs_read_int(inf,&s->s_pack); + rs_read_int(inf,&s->s_carry); + rs_read(inf,s->s_dmg,sizeof(s->s_dmg)); + + return(READSTAT); +} + +int +rs_write_magic_items(FILE *savef, struct magic_item *i, int count) +{ + int n; + + rs_write_marker(savef, RSID_MAGICITEMS); + rs_write_int(savef, count); + + for(n=0;n count) + format_error = TRUE; + + for(i=0; i < count; i++) + { + func = 0; + rs_read_int(inf, &d_list[i].d_type); + rs_read_int(inf, &func); + + switch(func) + { + case 1: d_list[i].d_func = rollwand; + break; + case 2: d_list[i].d_func = doctor; + break; + case 3: d_list[i].d_func = stomach; + break; + case 4: d_list[i].d_func = trap_look; + break; + case 5: d_list[i].d_func = eat_gold; + break; + case 6: d_list[i].d_func = ring_search; + break; + case 7: d_list[i].d_func = ring_teleport; + break; + case 8: d_list[i].d_func = fumble; + break; + case 9: d_list[i].d_func = strangle; + break; + case 10: d_list[i].d_func = unconfuse; + break; + case 11: d_list[i].d_func = swander; + break; + case 12: d_list[i].d_func = spell_recovery; + break; + case 13: d_list[i].d_func = chant_recovery; + break; + case 14: d_list[i].d_func = prayer_recovery; + break; + case 15: d_list[i].d_func = cure_disease; + break; + case 16: d_list[i].d_func = unstink; + break; + case 17: d_list[i].d_func = (int (*)()) res_strength; + break; + case 18: d_list[i].d_func = undance; + break; + case 19: d_list[i].d_func = suffocate; + break; + case 20: d_list[i].d_func = wghtchk; + break; + case 21: d_list[i].d_func = dust_appear; + break; + case 22: d_list[i].d_func = unchoke; + break; + case 23: d_list[i].d_func = sight; + break; + case 24: d_list[i].d_func = changeclass; + break; + case 25: d_list[i].d_func = cloak_charge; + break; + case 26: d_list[i].d_func = quill_charge; + break; + case 27: d_list[i].d_func = nohaste; + break; + case 28: d_list[i].d_func = noslow; + break; + case 29: d_list[i].d_func = unclrhead; + break; + case 30: d_list[i].d_func = unsee; + break; + case 31: d_list[i].d_func = unphase; + break; + case 32: d_list[i].d_func = land; + break; + case 33: d_list[i].d_func = appear; + break; + case 34: d_list[i].d_func = unskill; + break; + case 35: d_list[i].d_func = nofire; + break; + case 36: d_list[i].d_func = nocold; + break; + case 37: d_list[i].d_func = nobolt; + break; + case 0: + case -1: + default: d_list[i].d_func = NULL; + break; + } + + if (d_list[i].d_func == doctor) + { + rs_read_int(inf, &dummy); + d_list[i].d_.varg = &player; + } + else if (d_list[i].d_func == eat_gold) + { + rs_read_int(inf, &dummy); + d_list[i].d_.varg = get_list_item(player.t_pack, dummy); + if (d_list[i].d_.varg == NULL) + d_list[i].d_type = 0; + } + else if (d_list[i].d_func == changeclass) + { + rs_read_int(inf, &d_list[i].d_.arg); + } + else if (d_list[i].d_func == cloak_charge) + { + rs_read_int(inf, &dummy); + d_list[i].d_.varg = get_list_item(player.t_pack,dummy); + + if (d_list[i].d_.varg == NULL) + d_list[i].d_type = 0; + } + else + rs_read_int(inf, &d_list[i].d_.arg); + + rs_read_int(inf, &d_list[i].d_time); + + if (d_list[i].d_func == NULL) + { + d_list[i].d_time = 0; + d_list[i].d_.varg = NULL; + d_list[i].d_type = 0; + } + + } + + return(READSTAT); +} + +int +rs_write_room(FILE *savef, struct room *r) +{ + struct linked_list *l; + int i; + + if (write_error) + return(WRITESTAT); + + rs_write_coord(savef, r->r_pos); + rs_write_coord(savef, r->r_max); + rs_write_long(savef, r->r_flags); + + l = r->r_fires; + i = list_size(l); + + rs_write_int(savef, i); + + if (i >0) + while (l != NULL) + { + i = find_list_ptr(mlist, l->l_data); + rs_write_int(savef,i); + l = l->l_next; + } + + rs_write_coord_list(savef, r->r_exit); + + return(WRITESTAT); +} + +int +rs_read_room(int inf, struct room *r) +{ + int value = 0, n = 0, i = 0, index = 0, id = 0; + struct linked_list *fires=NULL, *item = NULL; + + if (read_error || format_error) + return(READSTAT); + + rs_read_coord(inf,&r->r_pos); + rs_read_coord(inf,&r->r_max); + rs_read_long(inf,&r->r_flags); + + rs_read_int(inf, &i); + fires = NULL; + + while (i>0) + { + rs_read_int(inf,&index); + + if (index >= 0) + { + void *data; + data = get_list_item(mlist,index); + item = creat_item(); + item->l_data = data; + if (fires == NULL) + fires = item; + else + attach(fires,item); + } + i--; + } + + r->r_fires=fires; + + rs_read_coord_list(inf, &r->r_exit); + + return(READSTAT); +} + +int +rs_write_rooms(FILE *savef, struct room r[], int count) +{ + int n = 0; + + if (write_error) + return(WRITESTAT); + + rs_write_int(savef, count); + + for(n = 0; n < count; n++) + rs_write_room(savef, &r[n]); + + return(WRITESTAT); +} + +int +rs_read_rooms(int inf, struct room *r, int count) +{ + int value = 0, n = 0; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf,&value); + + if (value > count) + format_error = TRUE; + + for(n = 0; n < value; n++) + rs_read_room(inf,&r[n]); + + return(READSTAT); +} + +int +rs_write_room_reference(FILE *savef, struct room *rp) +{ + int i, room = -1; + + if (write_error) + return(WRITESTAT); + + for (i = 0; i < MAXROOMS; i++) + if (&rooms[i] == rp) + room = i; + + rs_write_int(savef, room); + + return(WRITESTAT); +} + +int +rs_read_room_reference(int inf, struct room **rp) +{ + int i; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf, &i); + + *rp = &rooms[i]; + + return(READSTAT); +} + +int +rs_write_door_reference(FILE *savef, coord *exit) +{ + int i, idx; + + for (i = 0; i < MAXROOMS; i++) + { + idx = find_list_ptr(rooms[i].r_exit, exit); + + if (idx != -1) + break; + } + + if (i >= MAXROOMS) + { + rs_write_int(savef,-1); + rs_write_int(savef,-1); + if (exit != NULL) + abort(); + } + else + { + rs_write_int(savef,i); + rs_write_int(savef,idx); + } + + return(WRITESTAT); +} + +int +rs_read_door_reference(int inf, coord **exit) +{ + int i, idx; + + rs_read_int(inf, &i); + rs_read_int(inf, &idx); + + if ( (i == -1) || (idx == -1) ) + *exit = NULL; + else + *exit = get_list_item(rooms[i].r_exit, idx); + + return(READSTAT); +} + +int +rs_write_traps(FILE *savef, struct trap *trap,int count) +{ + int n; + + rs_write_int(savef, RSID_TRAP); + rs_write_int(savef, count); + + for(n=0; no_type); + rs_write_coord(savef, o->o_pos); + rs_write_char(savef, o->o_launch); + rs_write(savef, o->o_damage, sizeof(o->o_damage)); + rs_write(savef, o->o_hurldmg, sizeof(o->o_hurldmg)); + rs_write_object_list(savef, o->contents); + rs_write_int(savef, o->o_count); + rs_write_int(savef, o->o_which); + rs_write_int(savef, o->o_hplus); + rs_write_int(savef, o->o_dplus); + rs_write_int(savef, o->o_ac); + rs_write_long(savef, o->o_flags); + rs_write_int(savef, o->o_group); + rs_write_int(savef, o->o_weight); + rs_write(savef, o->o_mark, MARKLEN); + + + return(WRITESTAT); +} + +int +rs_read_object(int inf, struct object *o) +{ + if (read_error || format_error) + return(READSTAT); + + rs_read_marker(inf, RSID_OBJECT); + rs_read_int(inf, &o->o_type); + rs_read_coord(inf, &o->o_pos); + rs_read_char(inf, &o->o_launch); + rs_read(inf, o->o_damage, sizeof(o->o_damage)); + rs_read(inf, o->o_hurldmg, sizeof(o->o_hurldmg)); + rs_read_object_list(inf,&o->contents); + rs_read_int(inf, &o->o_count); + rs_read_int(inf, &o->o_which); + rs_read_int(inf, &o->o_hplus); + rs_read_int(inf, &o->o_dplus); + rs_read_int(inf, &o->o_ac); + rs_read_long(inf,&o->o_flags); + rs_read_int(inf, &o->o_group); + rs_read_int(inf, &o->o_weight); + rs_read(inf, o->o_mark, MARKLEN); + + return(READSTAT); +} + +int +rs_write_object_list(FILE *savef, struct linked_list *l) +{ + if (write_error) + return(WRITESTAT); + + rs_write_marker(savef, RSID_OBJECTLIST); + rs_write_int(savef, list_size(l)); + + for( ;l != NULL; l = l->l_next) + rs_write_object(savef, OBJPTR(l)); + + return(WRITESTAT); +} + +int +rs_read_object_list(int inf, struct linked_list **list) +{ + int i, cnt; + struct linked_list *l = NULL, *previous = NULL, *head = NULL; + + if (read_error || format_error) + return(READSTAT); + + rs_read_marker(inf, RSID_OBJECTLIST); + rs_read_int(inf, &cnt); + + for (i = 0; i < cnt; i++) + { + l = new_item(sizeof(struct object)); + + l->l_prev = previous; + + if (previous != NULL) + previous->l_next = l; + + rs_read_object(inf,OBJPTR(l)); + + if (previous == NULL) + head = l; + + previous = l; + } + + if (l != NULL) + l->l_next = NULL; + + *list = head; + + return(READSTAT); +} + +int +rs_write_object_reference(FILE *savef, struct linked_list *list, struct object *item) +{ + int i; + + if (write_error) + return(WRITESTAT); + + i = find_list_ptr(list, item); + + rs_write_int(savef, i); + + return(WRITESTAT); +} + +int +rs_read_object_reference(int inf, struct linked_list *list, struct object **item) +{ + int i; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf, &i); + + *item = get_list_item(list,i); + + return(READSTAT); +} + +int +find_thing_coord(struct linked_list *monlist, coord *c) +{ + struct linked_list *mitem; + struct thing *tp; + int i = 0; + + for(mitem = monlist; mitem != NULL; mitem = mitem->l_next) + { + tp = THINGPTR(mitem); + + if (c == &tp->t_pos) + return(i); + + i++; + } + + return(-1); +} + +int +find_object_coord(struct linked_list *objlist, coord *c) +{ + struct linked_list *oitem; + struct object *obj; + int i = 0; + + for(oitem = objlist; oitem != NULL; oitem = oitem->l_next) + { + obj = OBJPTR(oitem); + + if (c == &obj->o_pos) + return(i); + + i++; + } + + return(-1); +} + +int +rs_write_thing(FILE *savef, struct thing *t) +{ + int i = -1; + + if (write_error) + return(WRITESTAT); + + rs_write_marker(savef, RSID_THING); + + if (t == NULL) + { + rs_write_int(savef, 0); + return(WRITESTAT); + } + + rs_write_int(savef, 1); + rs_write_boolean(savef,t->t_wasshot); + rs_write_char(savef, t->t_type); + rs_write_char(savef, t->t_disguise); + rs_write_char(savef, t->t_oldch); + rs_write_short(savef, t->t_ctype); + rs_write_short(savef, t->t_index); + rs_write_short(savef, t->t_no_move); + rs_write_short(savef, t->t_quiet); + rs_write_short(savef, t->t_movement); + rs_write_short(savef, t->t_action); + rs_write_short(savef, t->t_artifact); + rs_write_short(savef, t->t_wand); + rs_write_short(savef, t->t_summon); + rs_write_short(savef, t->t_cast); + rs_write_short(savef, t->t_breathe); + + rs_write_string(savef,t->t_name); + rs_write_door_reference(savef, t->t_doorgoal); + + if (t->t_dest == &hero) + { + rs_write_int(savef,0); + rs_write_int(savef,1); + } + else if (t->t_dest != NULL) + { + i = find_thing_coord(mlist, t->t_dest); + + if (i >= 0) + { + rs_write_int(savef,1); + rs_write_int(savef,i); + } + else + { + i = find_object_coord(lvl_obj, t->t_dest); + + if (i >= 0) + { + rs_write_int(savef,2); + rs_write_int(savef,i); + } + else + { + rs_write_int(savef,0); + rs_write_int(savef,1); /* chase the hero anyway */ + } + } + } + else + { + rs_write_int(savef,0); + rs_write_int(savef,0); + } + + rs_write_coord(savef, t->t_pos); + rs_write_coord(savef, t->t_oldpos); + rs_write_coord(savef, t->t_newpos); + rs_write_ulongs(savef, t->t_flags, 16); + rs_write_object_list(savef, t->t_pack); + i = -1; + if (t->t_using != NULL) + i = find_list_ptr(t->t_pack, t->t_using->l_data); + rs_write_int(savef, i); + rs_write_int(savef, t->t_selection); + rs_write_stats(savef, &t->t_stats); + rs_write_stats(savef, &t->maxstats); + + return(WRITESTAT); +} + +int +rs_read_thing(int inf, struct thing *t) +{ + int listid = 0, index = -1; + + if (read_error || format_error) + return(READSTAT); + + rs_read_marker(inf, RSID_THING); + + rs_read_int(inf, &index); + + if (index == 0) + return(READSTAT); + + rs_read_boolean(inf, &t->t_wasshot); + rs_read_char(inf, &t->t_type); + rs_read_char(inf, &t->t_disguise); + rs_read_char(inf, &t->t_oldch); + rs_read_short(inf, &t->t_ctype); + rs_read_short(inf, &t->t_index); + rs_read_short(inf, &t->t_no_move); + rs_read_short(inf, &t->t_quiet); + rs_read_short(inf, &t->t_movement); + rs_read_short(inf, &t->t_action); + rs_read_short(inf, &t->t_artifact); + rs_read_short(inf, &t->t_wand); + rs_read_short(inf, &t->t_summon); + rs_read_short(inf, &t->t_cast); + rs_read_short(inf, &t->t_breathe); + rs_read_new_string(inf,&t->t_name); + rs_read_door_reference(inf,&t->t_doorgoal); + + rs_read_int(inf,&listid); + rs_read_int(inf,&index); + t->t_reserved = -1; + if (listid == 0) + { + if (index == 1) + t->t_dest = &hero; + else + t->t_dest = NULL; + } + else if (listid == 1) + { + t->t_dest = NULL; + t->t_reserved = index; + } + else if (listid == 2) + { + struct object *obj; + obj = get_list_item(lvl_obj,index); + if (obj != NULL) + { + t->t_dest = &obj->o_pos; + } + } + else + t->t_dest = NULL; + + rs_read_coord(inf,&t->t_pos); + rs_read_coord(inf,&t->t_oldpos); + rs_read_coord(inf,&t->t_newpos); + rs_read_ulongs(inf,t->t_flags,16); + rs_read_object_list(inf,&t->t_pack); + rs_read_int(inf,&index); + t->t_using = get_list_item(t->t_pack, index); + rs_read_int(inf, &t->t_selection); + rs_read_stats(inf,&t->t_stats); + rs_read_stats(inf,&t->maxstats); + + return(READSTAT); +} + +int +rs_fix_thing(struct thing *t) +{ + struct thing *tp; + + if (t->t_reserved < 0) + return; + + tp = get_list_item(mlist,t->t_reserved); + + if (tp != NULL) + { + t->t_dest = &tp->t_pos; + } +} + +int +rs_write_thing_list(FILE *savef, struct linked_list *l) +{ + int cnt = 0; + + if (write_error) + return(WRITESTAT); + + rs_write_marker(savef, RSID_MONSTERLIST); + + cnt = list_size(l); + + rs_write_int(savef, cnt); + + if (cnt < 1) + return(WRITESTAT); + + while (l != NULL) { + rs_write_thing(savef, (struct thing *)l->l_data); + l = l->l_next; + } + + return(WRITESTAT); +} + +int +rs_read_thing_list(int inf, struct linked_list **list) +{ + int i, cnt; + struct linked_list *l = NULL, *previous = NULL, *head = NULL; + + if (read_error || format_error) + return(READSTAT); + + rs_read_marker(inf, RSID_MONSTERLIST); + + rs_read_int(inf, &cnt); + + for (i = 0; i < cnt; i++) + { + l = new_item(sizeof(struct thing)); + + l->l_prev = previous; + + if (previous != NULL) + previous->l_next = l; + + rs_read_thing(inf,THINGPTR(l)); + + if (previous == NULL) + head = l; + + previous = l; + } + + if (l != NULL) + l->l_next = NULL; + + *list = head; + + return(READSTAT); +} + +int +rs_fix_thing_list(struct linked_list *list) +{ + struct linked_list *item; + + for(item = list; item != NULL; item = item->l_next) + rs_fix_thing(THINGPTR(item)); +} + +int +rs_write_thing_reference(FILE *savef, struct linked_list *list, struct thing *item) +{ + int i; + + if (write_error) + return(WRITESTAT); + + if (item == NULL) + rs_write_int(savef,-1); + else + { + i = find_list_ptr(list, item); + + rs_write_int(savef, i); + } + + return(WRITESTAT); +} + +int +rs_read_thing_reference(int inf, struct linked_list *list, struct thing **item) +{ + int i; + + if (read_error || format_error) + return(READSTAT); + + rs_read_int(inf, &i); + + if (i == -1) + *item = NULL; + else + *item = get_list_item(list,i); + + return(READSTAT); +} + +int +rs_write_thing_references(FILE *savef, struct linked_list *list, struct thing *items[], int count) +{ + int i; + + if (write_error) + return(WRITESTAT); + + for(i = 0; i < count; i++) + rs_write_thing_reference(savef,list,items[i]); + + return(WRITESTAT); +} + +int +rs_read_thing_references(int inf, struct linked_list *list, struct thing *items[], int count) +{ + int i; + + if (read_error || format_error) + return(READSTAT); + + for(i = 0; i < count; i++) + rs_read_thing_reference(inf,list,&items[i]); + + return(WRITESTAT); +} + +int +rs_save_file(FILE *savef) +{ + int i; + + if (write_error) + return(WRITESTAT); + + rs_write_object_list(savef, lvl_obj); + rs_write_thing(savef, &player); + rs_write_thing_list(savef, mlist); + rs_write_thing_list(savef, tlist); + rs_write_thing_list(savef, monst_dead); + + rs_write_traps(savef, traps, MAXTRAPS); + rs_write_rooms(savef, rooms, MAXROOMS); + rs_write_room_reference(savef,oldrp); + + rs_write_object_reference(savef, player.t_pack, cur_armor); + + for (i = 0; i < NUM_FINGERS; i++) + rs_write_object_reference(savef, player.t_pack, cur_ring[i]); + + for (i = 0; i < NUM_MM; i++) + rs_write_object_reference(savef, player.t_pack, cur_misc[i]); + + rs_write_ints(savef, cur_relic, MAXRELIC); + + rs_write_object_reference(savef, player.t_pack, cur_weapon); + + rs_write_int(savef,char_type); + rs_write_int(savef,foodlev); + rs_write_int(savef,ntraps); + rs_write_int(savef,trader); + rs_write_int(savef,curprice); + rs_write_int(savef,seed); + rs_write_int(savef,dnum); + rs_write_int(savef,max_level); + rs_write_int(savef,cur_max); + rs_write_int(savef,mpos); + rs_write_int(savef,level); + rs_write_int(savef,purse); + rs_write_int(savef,inpack); + rs_write_int(savef,total); + rs_write_int(savef,no_food); + rs_write_int(savef,foods_this_level); + rs_write_int(savef,count); + rs_write_int(savef,food_left); + rs_write_int(savef,group); + rs_write_int(savef,hungry_state); + rs_write_int(savef,infest_dam); + rs_write_int(savef,lost_str); + rs_write_int(savef,lastscore); + rs_write_int(savef,hold_count); + rs_write_int(savef,trap_tries); + rs_write_int(savef,chant_time); + rs_write_int(savef,pray_time); + rs_write_int(savef,spell_power); + rs_write_int(savef,turns); + rs_write_int(savef,quest_item); + rs_write_int(savef,cols); + rs_write_int(savef,lines); + rs_write_char(savef,nfloors); + rs_write(savef,curpurch,LINELEN); + rs_write_char(savef,PLAYER); + rs_write_char(savef,take); + rs_write(savef,prbuf,LINELEN*2); + rs_write(savef,outbuf,BUFSIZ); + rs_write_char(savef,runch); + rs_write_scrolls(savef); + rs_write_potions(savef); + rs_write_rings(savef); + rs_write_sticks(savef); + rs_write_misc(savef); + rs_write(savef,whoami,LINELEN); + rs_write(savef,huh,LINELEN); + rs_write(savef,file_name,LINELEN); + rs_write(savef,score_file,LINELEN); + rs_write(savef,home,LINELEN); + rs_write_window(savef, cw); + rs_write_window(savef, hw); + rs_write_window(savef, mw); + rs_write_window(savef, msgw); + rs_write_window(savef, stdscr); + rs_write_boolean(savef, pool_teleport); + rs_write_boolean(savef, inwhgt); + rs_write_boolean(savef, after); + rs_write_boolean(savef, waswizard); + rs_write_boolean(savef, playing); + rs_write_boolean(savef, running); + rs_write_boolean(savef, wizard); + rs_write_boolean(savef, notify); + rs_write_boolean(savef, fight_flush); + rs_write_boolean(savef, terse); + rs_write_boolean(savef, auto_pickup); + rs_write_boolean(savef, menu_overlay); + rs_write_boolean(savef, door_stop); + rs_write_boolean(savef, jump); + rs_write_boolean(savef, slow_invent); + rs_write_boolean(savef, firstmove); + rs_write_boolean(savef, askme); + rs_write_boolean(savef, in_shell); + rs_write_boolean(savef, daytime); + rs_write_levtype(savef, levtype); + rs_write_magic_items(savef, things, MAXTHINGS); + rs_write_magic_items(savef, s_magic, MAXSCROLLS); + rs_write_magic_items(savef, p_magic, MAXPOTIONS); + rs_write_magic_items(savef, r_magic, MAXRINGS); + rs_write_magic_items(savef, ws_magic, MAXSTICKS); + rs_write_magic_items(savef, m_magic, MAXMM); + rs_write_magic_items(savef, rel_magic, MAXRELIC); + rs_write_magic_items(savef, foods, MAXFOODS); + + rs_write_monsters(savef, monsters, NUMMONST+1); + + rs_write_daemons(savef, d_list, MAXDAEMONS); + rs_write_daemons(savef, f_list, MAXFUSES); + rs_write_int(savef, demoncnt); + rs_write_int(savef, fusecnt); + + rs_write_int(savef, between); + + rs_write_int(savef, chance); + + return(WRITESTAT); +} + +int +rs_restore_file(int inf) +{ + int i; + + if (read_error || format_error) + return(READSTAT); + + rs_read_object_list(inf, &lvl_obj); + rs_read_thing(inf, &player); + rs_read_thing_list(inf, &mlist); + rs_read_thing_list(inf, &tlist); + rs_read_thing_list(inf, &monst_dead); + + rs_fix_thing(&player); + rs_fix_thing_list(mlist); + rs_fix_thing_list(tlist); + rs_fix_thing_list(monst_dead); + + rs_read_traps(inf, traps, MAXTRAPS); + rs_read_rooms(inf, rooms, MAXROOMS); + rs_read_room_reference(inf,&oldrp); + + rs_read_object_reference(inf, player.t_pack, &cur_armor); + + for(i = 0; i < NUM_FINGERS; i++) + rs_read_object_reference(inf, player.t_pack, &cur_ring[i]); + + for(i = 0; i < NUM_MM; i++) + rs_read_object_reference(inf, player.t_pack, &cur_misc[i]); + + rs_read_ints(inf, cur_relic, MAXRELIC); + + rs_read_object_reference(inf, player.t_pack, &cur_weapon); + + rs_read_int(inf,&char_type); + rs_read_int(inf,&foodlev); + rs_read_int(inf,&ntraps); + rs_read_int(inf,&trader); + rs_read_int(inf,&curprice); + rs_read_int(inf,&seed); + rs_read_int(inf,&dnum); + rs_read_int(inf,&max_level); + rs_read_int(inf,&cur_max); + rs_read_int(inf,&mpos); + rs_read_int(inf,&level); + rs_read_int(inf,&purse); + rs_read_int(inf,&inpack); + rs_read_int(inf,&total); + rs_read_int(inf,&no_food); + rs_read_int(inf,&foods_this_level); + rs_read_int(inf,&count); + rs_read_int(inf,&food_left); + rs_read_int(inf,&group); + rs_read_int(inf,&hungry_state); + rs_read_int(inf,&infest_dam); + rs_read_int(inf,&lost_str); + rs_read_int(inf,&lastscore); + rs_read_int(inf,&hold_count); + rs_read_int(inf,&trap_tries); + rs_read_int(inf,&chant_time); + rs_read_int(inf,&pray_time); + rs_read_int(inf,&spell_power); + rs_read_int(inf,&turns); + rs_read_int(inf,&quest_item); + rs_read_int(inf,&cols); + rs_read_int(inf,&lines); + rs_read_char(inf,&nfloors); + rs_read(inf,curpurch,LINELEN); + rs_read_char(inf,&PLAYER); + rs_read_char(inf,&take); + rs_read(inf,prbuf,LINELEN*2); + rs_read(inf,outbuf,BUFSIZ); + rs_read_char(inf,&runch); + rs_read_scrolls(inf); + rs_read_potions(inf); + rs_read_rings(inf); + rs_read_sticks(inf); + rs_read_misc(inf); + rs_read(inf,whoami,LINELEN); + rs_read(inf,huh,LINELEN); + rs_read(inf,file_name,LINELEN); + rs_read(inf,score_file,LINELEN); + rs_read(inf,home,LINELEN); + rs_read_window(inf, cw); + rs_read_window(inf, hw); + rs_read_window(inf, mw); + rs_read_window(inf, msgw); + rs_read_window(inf, stdscr); + rs_read_boolean(inf, &pool_teleport); + rs_read_boolean(inf, &inwhgt); + rs_read_boolean(inf, &after); + rs_read_boolean(inf, &waswizard); + rs_read_boolean(inf, &playing); + rs_read_boolean(inf, &running); + rs_read_boolean(inf, &wizard); + rs_read_boolean(inf, ¬ify); + rs_read_boolean(inf, &fight_flush); + rs_read_boolean(inf, &terse); + rs_read_boolean(inf, &auto_pickup); + rs_read_boolean(inf, &menu_overlay); + rs_read_boolean(inf, &door_stop); + rs_read_boolean(inf, &jump); + rs_read_boolean(inf, &slow_invent); + rs_read_boolean(inf, &firstmove); + rs_read_boolean(inf, &askme); + rs_read_boolean(inf, &in_shell); + rs_read_boolean(inf, &daytime); + rs_read_levtype(inf, &levtype); + rs_read_magic_items(inf, things, MAXTHINGS); + rs_read_magic_items(inf, s_magic, MAXSCROLLS); + rs_read_magic_items(inf, p_magic, MAXPOTIONS); + rs_read_magic_items(inf, r_magic, MAXRINGS); + rs_read_magic_items(inf, ws_magic, MAXSTICKS); + rs_read_magic_items(inf, m_magic, MAXMM); + rs_read_magic_items(inf, rel_magic, MAXRELIC); + rs_read_magic_items(inf, foods, MAXFOODS); + rs_read_monsters(inf, monsters, NUMMONST + 1); + + rs_read_daemons(inf, d_list, MAXDAEMONS); + rs_read_daemons(inf, f_list, MAXFUSES); + rs_read_int(inf, &demoncnt); + rs_read_int(inf, &fusecnt); + + rs_read_int(inf, &between); + + rs_read_int(inf, &chance); + + return(READSTAT); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/sticks.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/sticks.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1248 @@ +/* + * sticks.c - Functions to implement the various sticks one might find + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Functions to implement the various sticks one might find + * while wandering around the dungeon. + */ + +#include "curses.h" +#include +#include +#include "rogue.h" + + +/* + * zap a stick and see what happens + */ +do_zap(zapper, obj, direction, which, flags) +struct thing *zapper; +struct object *obj; +coord *direction; +int which; +int flags; +{ + register struct linked_list *item; + register struct thing *tp; + register int y, x, bonus; + struct linked_list *nitem; + struct object *nobj; + bool cursed, blessed, is_player; + char *mname; + + cursed = flags & ISCURSED; + blessed = flags & ISBLESSED; + + if (obj && obj->o_type != RELIC) { /* all relics are chargeless */ + if (obj->o_charges < 1) { + msg(nothing); + return; + } + obj->o_charges--; + } + if (which == WS_WONDER) { + switch (rnd(14)) { + case 0: which = WS_ELECT; + when 1: which = WS_FIRE; + when 2: which = WS_COLD; + when 3: which = WS_POLYMORPH; + when 4: which = WS_MISSILE; + when 5: which = WS_SLOW_M; + when 6: which = WS_TELMON; + when 7: which = WS_CANCEL; + when 8: which = WS_CONFMON; + when 9: which = WS_DISINTEGRATE; + when 10: which = WS_PETRIFY; + when 11: which = WS_PARALYZE; + when 12: which = WS_MDEG; + when 13: which = WS_FEAR; + } + if(ws_magic[which].mi_curse>0 && rnd(100)<=ws_magic[which].mi_curse){ + cursed = TRUE; + blessed = FALSE; + } + } + + tp = NULL; + switch (which) { + case WS_POLYMORPH: + case WS_SLOW_M: + case WS_TELMON: + case WS_CANCEL: + case WS_CONFMON: + case WS_DISINTEGRATE: + case WS_PETRIFY: + case WS_PARALYZE: + case WS_MDEG: + case WS_FEAR: + y = zapper->t_pos.y; + x = zapper->t_pos.x; + + do { + y += direction->y; + x += direction->x; + } + while (shoot_ok(winat(y, x)) && !(y == hero.y && x == hero.x)); + + if (y == hero.y && x == hero.x) + is_player = TRUE; + else if (isalpha(mvwinch(mw, y, x))) { + item = find_mons(y, x); + tp = THINGPTR(item); + runto(tp, &hero); + turn_off(*tp, CANSURPRISE); + mname = monster_name(tp); + is_player = FALSE; + + /* The monster may not like being shot at */ + if ((zapper == &player) && + on(*tp, ISCHARMED) && + save(VS_MAGIC, tp, 0)) { + msg("The eyes of %s turn clear.", prname(mname, FALSE)); + turn_off(*tp, ISCHARMED); + mname = monster_name(tp); + } + } + else { + /* + * if monster misses player because the player dodged then lessen + * the chances he will use the wand again since the player appears + * to be rather dextrous + */ + if (zapper != &player) + zapper->t_wand = zapper->t_wand * 3 / 4; + } + } + switch (which) { + case WS_LIGHT: + /* + * Reddy Kilowat wand. Light up the room + */ + blue_light(blessed, cursed); + when WS_DRAIN: + /* + * Take away 1/2 of hero's hit points, then take it away + * evenly from the monsters in the room or next to hero + * if he is in a passage (but leave the monsters alone + * if the stick is cursed) + */ + if (pstats.s_hpt < 2) { + msg("You are too weak to use it."); + } + else if (cursed) + pstats.s_hpt /= 2; + else + drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1); + + when WS_POLYMORPH: + { + register char oldch; + register struct room *rp; + register struct linked_list *pitem; + coord delta; + + if (tp == NULL) + break; + if (save(VS_MAGIC, tp, 0)) { + msg(nothing); + break; + } + rp = roomin(&tp->t_pos); + check_residue(tp); + delta.x = x; + delta.y = y; + detach(mlist, item); + oldch = tp->t_oldch; + pitem = tp->t_pack; /* save his pack */ + tp->t_pack = NULL; + new_monster(item,rnd(NUMMONST-NUMUNIQUE-1)+1,&delta,FALSE); + if (tp->t_pack != NULL) + o_free_list (tp->t_pack); + tp->t_pack = pitem; + if (isalpha(mvwinch(cw, y, x))) + mvwaddch(cw, y, x, tp->t_type); + tp->t_oldch = oldch; + /* + * should the room light up? + */ + if (on(*tp, HASFIRE)) { + if (rp) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rp->r_fires, fire_item); + rp->r_flags |= HASFIRE; + if (cansee(tp->t_pos.y,tp->t_pos.x) && + next(rp->r_fires) == NULL) light(&hero); + } + } + runto(tp, &hero); + msg(terse ? "A new %s!" + : "You have created a new %s!", + monster_name(tp)); + } + + when WS_PETRIFY: + if (tp == NULL) + break; + if (save(VS_MAGIC, tp, 0)) { + msg(nothing); + break; + } + check_residue(tp); + turn_on(*tp, ISSTONE); + turn_on(*tp, NOSTONE); + turn_off(*tp, ISRUN); + turn_off(*tp, ISINVIS); + turn_off(*tp, CANSURPRISE); + turn_off(*tp, ISDISGUISE); + tp->t_action = A_NIL; + tp->t_no_move = 0; + msg("%s is turned to stone!",prname(mname, TRUE)); + + when WS_TELMON: + { + register int rm; + register struct room *rp; + + if (tp == NULL) + break; + if (save(VS_MAGIC, tp, 0)) { + msg(nothing); + break; + } + rp = NULL; + check_residue(tp); + tp->t_action = A_FREEZE; /* creature is disoriented */ + tp->t_no_move = 2; + if (cursed) { /* Teleport monster to player */ + if ((y == (hero.y + direction->y)) && + (x == (hero.x + direction->x))) + msg(nothing); + else { + tp->t_pos.y = hero.y + direction->y; + tp->t_pos.x = hero.x + direction->x; + } + } + else if (blessed) { /* Get rid of monster */ + killed(item, FALSE, TRUE, TRUE); + return; + } + else { + register int i=0; + + do { /* Move monster to another room */ + rm = rnd_room(); + rnd_pos(&rooms[rm], &tp->t_pos); + }until(winat(tp->t_pos.y,tp->t_pos.x)==FLOOR ||i++>500); + rp = &rooms[rm]; + } + + /* Now move the monster */ + if (isalpha(mvwinch(cw, y, x))) + mvwaddch(cw, y, x, tp->t_oldch); + mvwaddch(mw, y, x, ' '); + mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type); + if (tp->t_pos.y != y || tp->t_pos.x != x) + tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) ); + /* + * check to see if room that creature appears in should + * light up + */ + if (on(*tp, HASFIRE)) { + if (rp) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rp->r_fires, fire_item); + rp->r_flags |= HASFIRE; + if(cansee(tp->t_pos.y, tp->t_pos.x) && + next(rp->r_fires) == NULL) + light(&hero); + } + } + } + when WS_CANCEL: + if (tp == NULL) + break; + if (save(VS_MAGIC, tp, 0)) { + msg(nothing); + break; + } + check_residue(tp); + tp->t_flags[0] &= CANC0MASK; + tp->t_flags[1] &= CANC1MASK; + tp->t_flags[2] &= CANC2MASK; + tp->t_flags[3] &= CANC3MASK; + tp->t_flags[4] &= CANC4MASK; + tp->t_flags[5] &= CANC5MASK; + tp->t_flags[6] &= CANC6MASK; + tp->t_flags[7] &= CANC7MASK; + tp->t_flags[8] &= CANC8MASK; + tp->t_flags[9] &= CANC9MASK; + tp->t_flags[10] &= CANCAMASK; + tp->t_flags[11] &= CANCBMASK; + tp->t_flags[12] &= CANCCMASK; + tp->t_flags[13] &= CANCDMASK; + tp->t_flags[14] &= CANCEMASK; + tp->t_flags[15] &= CANCFMASK; + + when WS_MISSILE: + { + int dice; + static struct object bolt = + { + MISSILE , {0, 0}, "", 0, "", "1d4 " , NULL, 0, WS_MISSILE, 50, 1 + }; + + if (!obj) + dice = zapper->t_stats.s_lvl; + if (obj->o_type == RELIC) + dice = 15; + else if (EQUAL(ws_type[which], "staff")) + dice = 10; + else + dice = 6; + sprintf(bolt.o_hurldmg, "%dd4", dice); + do_motion(&bolt, direction->y, direction->x, zapper); + if (!hit_monster(unc(bolt.o_pos), &bolt, zapper)) + msg("The missile vanishes with a puff of smoke"); + } + when WS_HIT: + { + register char ch; + struct object strike; /* don't want to change sticks attributes */ + + direction->y += hero.y; + direction->x += hero.x; + ch = CCHAR( winat(direction->y, direction->x) ); + if (isalpha(ch)) + { + strike = *obj; + strike.o_hplus = 6; + if (EQUAL(ws_type[which], "staff")) + strncpy(strike.o_damage,"3d8",sizeof(strike.o_damage)); + else + strncpy(strike.o_damage,"2d8",sizeof(strike.o_damage)); + fight(direction, &strike, FALSE); + } + } + when WS_SLOW_M: + if (is_player) { + add_slow(); + break; + } + if (tp == NULL) + break; + if (cursed) { + if (on(*tp, ISSLOW)) + turn_off(*tp, ISSLOW); + else + turn_on(*tp, ISHASTE); + break; + } + if ((on(*tp,ISUNIQUE) && save(VS_MAGIC,tp,0)) || on(*tp,NOSLOW)) { + msg(nothing); + break; + } + else if (blessed) { + turn_off(*tp, ISRUN); + turn_on(*tp, ISHELD); + } + /* + * always slow in case he breaks free of HOLD + */ + if (on(*tp, ISHASTE)) + turn_off(*tp, ISHASTE); + else + turn_on(*tp, ISSLOW); + + when WS_CHARGE: + if (ws_know[WS_CHARGE] != TRUE && obj) + msg("This is a wand of charging."); + nitem = get_item(pack, "charge", STICK, FALSE, FALSE); + if (nitem != NULL) { + nobj = OBJPTR(nitem); + if ((++(nobj->o_charges) == 1) && (nobj->o_which == WS_HIT)) + fix_stick(nobj); + if (blessed) ++(nobj->o_charges); + if (EQUAL(ws_type[nobj->o_which], "staff")) { + if (nobj->o_charges > 100) + nobj->o_charges = 100; + } + else { + if (nobj->o_charges > 50) + nobj->o_charges = 50; + } + } + when WS_ELECT: + shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT, + "lightning bolt", roll(zapper->t_stats.s_lvl,6)); + + when WS_FIRE: + shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT, + "flame", roll(zapper->t_stats.s_lvl,6)); + + when WS_COLD: + shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT, + "ice", roll(zapper->t_stats.s_lvl,6)); + + when WS_CONFMON: + if (cursed || is_player) { + if (!save(VS_WAND, &player, 0)) { + dsrpt_player(); + confus_player(); + } + else { + if (zapper != &player) zapper->t_wand /= 2; + msg(nothing); + } + } + else { + if (tp == NULL) + break; + if (save(VS_MAGIC, tp, 0) || on(*tp, ISCLEAR)) + msg(nothing); + else + turn_on (*tp, ISHUH); + } + when WS_PARALYZE: + if (is_player || cursed) { + if ((obj && obj->o_type==RELIC) || !save(VS_WAND, &player, 0)){ + player.t_no_move += 2 * movement(&player) * FREEZETIME; + player.t_action = A_FREEZE; + msg("You can't move."); + } + else { + if (zapper != &player) zapper->t_wand /= 2; + msg(nothing); + } + } + else { + if (tp == NULL) + break; + bonus = 0; + if (blessed) bonus = -3; + if (((obj && obj->o_type==RELIC) || !save(VS_WAND,tp,bonus)) && + off(*tp, NOPARALYZE)) { + tp->t_no_move += 2 * movement(tp) * FREEZETIME; + tp->t_action = A_FREEZE; + } + else { + msg(nothing); + } + } + when WS_FEAR: + if (is_player) { + if (!on(player, ISFLEE) || + ISWEARING(R_HEROISM) || + save(VS_WAND, &player, 0)) { + msg(nothing); + zapper->t_wand /= 2; + } + else { + turn_on(player, ISFLEE); + player.t_dest = &zapper->t_pos; + msg("The sight of %s terrifies you.", prname(mname, FALSE)); + } + break; + } + if (tp == NULL) + break; + bonus = 0; + if (blessed) bonus = -3; + if(save(VS_WAND, tp,bonus) || on(*tp,ISUNDEAD) || on(*tp,NOFEAR)){ + msg(nothing); + break; + } + turn_on(*tp, ISFLEE); + turn_on(*tp, WASTURNED); + + /* Stop it from attacking us */ + dsrpt_monster(tp, TRUE, cansee(tp->t_pos.y, tp->t_pos.x)); + + /* If monster was suffocating, stop it */ + if (on(*tp, DIDSUFFOCATE)) { + turn_off(*tp, DIDSUFFOCATE); + extinguish(suffocate); + } + + /* If monster held us, stop it */ + if (on(*tp, DIDHOLD) && (--hold_count == 0)) + turn_off(player, ISHELD); + turn_off(*tp, DIDHOLD); + + /* It is okay to turn tail */ + tp->t_oldpos = tp->t_pos; + + when WS_MDEG: + if (is_player) { + if (save(VS_WAND, &player, 0)) { + msg (nothing); + zapper->t_wand /= 2; + break; + } + pstats.s_hpt /= 2; + if (pstats.s_hpt <= 0) { + msg("Your life has been sucked from you -- More --"); + wait_for(' '); + death(zapper); + } + else + msg("You feel a great drain on your system"); + } + if (tp == NULL) + break; + if (cursed) { + tp->t_stats.s_hpt *= 2; + msg("%s appears to be stronger now!", prname(mname, TRUE)); + } + else if (on(*tp, ISUNIQUE) && save(VS_WAND, tp, 0)) + msg (nothing); + else { + tp->t_stats.s_hpt /= 2; + msg("%s appears to be weaker now", prname(mname, TRUE)); + } + if (tp->t_stats.s_hpt < 1) + killed(item, TRUE, TRUE, TRUE); + when WS_DISINTEGRATE: + if (tp == NULL) + break; + if (cursed) { + register int m1, m2; + coord mp; + struct linked_list *titem; + char ch; + struct thing *th; + + if (on(*tp, ISUNIQUE)) { + msg (nothing); + break; + } + for (m1=tp->t_pos.x-1 ; m1 <= tp->t_pos.x+1 ; m1++) { + for(m2=tp->t_pos.y-1 ; m2<=tp->t_pos.y+1 ; m2++) { + if (m1 == hero.x && m2 == hero.y) + continue; + ch = CCHAR( winat(m2,m1) ); + if (shoot_ok(ch)) { + mp.x = m1; /* create it */ + mp.y = m2; + titem = new_item(sizeof(struct thing)); + new_monster(titem,(short)tp->t_index,&mp,FALSE); + th = THINGPTR(titem); + turn_on (*th, ISMEAN); + runto(th,&hero); + if (on(*th, HASFIRE)) { + register struct room *rp; + + rp = roomin(&th->t_pos); + if (rp) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) th; + attach(rp->r_fires, fire_item); + rp->r_flags |= HASFIRE; + if (cansee(th->t_pos.y, th->t_pos.x) && + next(rp->r_fires) == NULL) + light(&hero); + } + } + } + } + } + } + else { /* if its a UNIQUE it might still live */ + if (on(*tp, ISUNIQUE) && save(VS_MAGIC, tp, 0)) { + tp->t_stats.s_hpt /= 2; + if (tp->t_stats.s_hpt < 1) { + killed(item, FALSE, TRUE, TRUE); + msg("You have disintegrated %s", prname(mname, FALSE)); + } + else { + msg("%s appears wounded", prname(mname, TRUE)); + } + } + else { + msg("You have disintegrated %s", prname(mname, FALSE)); + killed (item, FALSE, TRUE, TRUE); + } + } + when WS_CURING: + if (cursed) { + if (!save(VS_POISON, &player, 0)) { + msg("You feel extremely sick now"); + pstats.s_hpt /=2; + if (pstats.s_hpt == 0) death (D_POISON); + } + if (!save(VS_WAND, &player, 0) && !ISWEARING(R_HEALTH)) { + turn_on(player, HASDISEASE); + turn_on(player, HASINFEST); + turn_on(player, DOROT); + fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER); + infest_dam++; + } + else msg("You fell momentarily sick"); + } + else { + if (on(player, HASDISEASE) || on(player, HASINFEST)) { + extinguish(cure_disease); + turn_off(player, HASINFEST); + infest_dam = 0; + cure_disease(); /* this prints message */ + } + if (on(player, DOROT)) { + msg("You feel your skin returning to normal."); + turn_off(player, DOROT); + } + pstats.s_hpt += roll(pstats.s_lvl, blessed ? 6 : 4); + if (pstats.s_hpt > max_stats.s_hpt) + pstats.s_hpt = max_stats.s_hpt; + msg("You begin to feel %sbetter.", blessed ? "much " : ""); + + } + otherwise: + msg("What a bizarre schtick!"); + } +} + + +/* + * drain: + * Do drain hit points from player shtick + */ + +drain(ymin, ymax, xmin, xmax) +int ymin, ymax, xmin, xmax; +{ + register int i, j, count; + register struct thing *ick; + register struct linked_list *item; + + /* + * First count how many things we need to spread the hit points among + */ + count = 0; + for (i = ymin; i <= ymax; i++) { + if (i < 1 || i > lines - 3) + continue; + for (j = xmin; j <= xmax; j++) { + if (j < 0 || j > cols - 1) + continue; + if (isalpha(mvwinch(mw, i, j))) + count++; + } + } + if (count == 0) + { + msg("You have a tingling feeling"); + return; + } + count = pstats.s_hpt / count; + pstats.s_hpt /= 2; + /* + * Now zot all of the monsters + */ + for (i = ymin; i <= ymax; i++) { + if (i < 1 || i > lines - 3) + continue; + for (j = xmin; j <= xmax; j++) { + if (j < 0 || j > cols - 1) + continue; + if (isalpha(mvwinch(mw, i, j)) && + ((item = find_mons(i, j)) != NULL)) { + ick = THINGPTR(item); + if (on(*ick, ISUNIQUE) && save(VS_MAGIC, ick, 0)) + ick->t_stats.s_hpt -= count / 2; + else + ick->t_stats.s_hpt -= count; + if (ick->t_stats.s_hpt < 1) + killed(item, + cansee(i,j)&&(!on(*ick,ISINVIS)||on(player,CANSEE)), + TRUE, TRUE); + else { + runto(ick, &hero); + + /* + * The monster may not like being shot at. Since the + * shot is not aimed directly at the monster, we will + * give him a poorer save. + */ + if (on(*ick, ISCHARMED) && save(VS_MAGIC, ick, -2)) { + msg("The eyes of %s turn clear.", + prname(monster_name(ick), FALSE)); + turn_off(*ick, ISCHARMED); + } + if (cansee(i,j) && (!on(*ick,ISINVIS)||on(player,CANSEE))) + msg("%s appears wounded", + prname(monster_name(ick), TRUE)); + } + } + } + } +} + +/* + * initialize a stick + */ +fix_stick(cur) +register struct object *cur; +{ + if (EQUAL(ws_type[cur->o_which], "staff")) { + cur->o_weight = 100; + cur->o_charges = 5 + rnd(10); + strncpy(cur->o_damage, "2d3", sizeof(cur->o_damage)); + cur->o_hplus = 1; + cur->o_dplus = 0; + switch (cur->o_which) { + case WS_HIT: + cur->o_hplus = 3; + cur->o_dplus = 3; + strncpy(cur->o_damage, "2d8", sizeof(cur->o_damage)); + when WS_LIGHT: + cur->o_charges = 20 + rnd(10); + } + } + else { + strncpy(cur->o_damage, "1d3", sizeof(cur->o_damage)); + cur->o_weight = 60; + cur->o_hplus = 1; + cur->o_dplus = 0; + cur->o_charges = 3 + rnd(5); + switch (cur->o_which) { + case WS_HIT: + cur->o_hplus = 3; + cur->o_dplus = 3; + strncpy(cur->o_damage, "1d8", sizeof(cur->o_damage)); + when WS_LIGHT: + cur->o_charges = 10 + rnd(10); + } + } + strncpy(cur->o_hurldmg, "1d1", sizeof(cur->o_hurldmg)); + +} + +/* + * Use the wand that our monster is wielding. + */ +m_use_wand(monster) +register struct thing *monster; +{ + register struct object *obj; + + /* Make sure we really have it */ + if (monster->t_using) + obj = OBJPTR(monster->t_using); + else { + debug("Stick not set!"); + monster->t_action = A_NIL; + return; + } + + if (obj->o_type != STICK) { + debug("Stick not selected!"); + monster->t_action = A_NIL; + return; + } + /* + * shoot the stick! + * assume all blessed sticks are normal for now. + * Note that we don't get here if the wand is cursed. + */ + msg("%s points a %s at you!", prname(monster_name(monster), TRUE), + ws_type[obj->o_which]); + do_zap(monster, obj, &monster->t_newpos, obj->o_which, NULL); + monster->t_wand /= 2; /* chance lowers with each use */ +} + +bool +need_dir(type, which) +int type, /* type of item, NULL means stick */ + which; /* which item */ +{ + if (type == STICK || type == 0) { + switch (which) { + case WS_LIGHT: + case WS_DRAIN: + case WS_CHARGE: + case WS_CURING: + return(FALSE); + default: + return(TRUE); + } + } + else if (type == RELIC) { + switch (which) { + case MING_STAFF: + case ASMO_ROD: + case EMORI_CLOAK: + return(TRUE); + default: + return(FALSE); + } + } +return (FALSE); /* hope we don't get here */ +} +/* + * let the player zap a stick and see what happens + */ +player_zap(which, flag) +int which; +int flag; +{ + register struct linked_list *item; + register struct object *obj; + + obj = NULL; + if (which == 0) { + /* This is a stick. It takes 2 movement periods to zap it */ + if (player.t_action != C_ZAP) { + if ((item = get_item(pack,"zap with",ZAPPABLE,FALSE,FALSE)) == NULL) + return(FALSE); + + obj = OBJPTR(item); + + if (need_dir(obj->o_type, obj->o_which)) { + if (!get_dir(&player.t_newpos)) + return(FALSE); + } + player.t_using = item; /* Remember what it is */ + player.t_action = C_ZAP; /* We are quaffing */ + player.t_no_move = 2 * movement(&player); + return(TRUE); + } + + item = player.t_using; + /* We've waited our time, let's shoot 'em up! */ + player.t_using = NULL; + player.t_action = A_NIL; + + obj = OBJPTR(item); + + /* Handle relics specially here */ + if (obj->o_type == RELIC) { + switch (obj->o_which) { + case ORCUS_WAND: + msg(nothing); + return(TRUE); + when MING_STAFF: + which = WS_MISSILE; + when EMORI_CLOAK: + which = WS_PARALYZE; + obj->o_charges = 0; /* one zap/day(whatever that is) */ + fuse(cloak_charge, obj, CLOAK_TIME, AFTER); + when ASMO_ROD: + switch (rnd(3)) { + case 0: which = WS_ELECT; + when 1: which = WS_COLD; + otherwise: which = WS_FIRE; + } + } + } + else { + which = obj->o_which; + ws_know[which] = TRUE; + flag = obj->o_flags; + } + } + do_zap(&player, obj, &player.t_newpos, which, flag); + return(TRUE); +} + + +/* + * 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; +{ + register char dirch, ch; + register bool used, change; + register 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 */ + for (y = 0; y < BOLT_LENGTH && !used; y++) + { + ch = CCHAR( winat(pos.y, pos.x) ); + spotpos[y].place = pos; + spotpos[y].oldch = CCHAR( mvwinch(cw, pos.y, pos.x) ); + + /* Are we at hero? */ + if (ce(pos, hero)) goto at_hero; + + switch (ch) + { + case SECRETDOOR: + case '|': + case '-': + case ' ': + if (dirch == '-' || dirch == '|') { + dir.y = -dir.y; + dir.x = -dir.x; + } + else { + char chx = CCHAR( mvinch(pos.y-dir.y, pos.x) ), + chy = CCHAR( mvinch(pos.y, pos.x-dir.x) ); + bool anychange = FALSE; /* Did we change anthing */ + + if (chy == WALL || chy == SECRETDOOR || + chy == '-' || chy == '|') { + dir.y = -dir.y; + change ^= TRUE; /* Change at least one direction */ + anychange = TRUE; + } + if (chx == WALL || chx == SECRETDOOR || + chx == '-' || chx == '|') { + 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; + register struct thing *tp; + register char *mname; + bool see_monster = cansee(pos.y, pos.x); + + item = find_mons(unc(pos)); + 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) || on(*tp, ISUNDEAD))) || + (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 { + bool see_him; + + see_him = + 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)); + + /* 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,"sleeping gas")&&ISWEARING(R_ALERT))){ + msg("The %s has no affect", 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 affect", 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, 0, + 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))) + 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 */ + 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 cc5148bdf345 -r 6b5fbd7c3ece arogue7/things.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/things.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,931 @@ +/* + * things.c - functions for dealing with things like potions and scrolls + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Contains functions for dealing with things like + * potions and scrolls + * + */ + +#include "curses.h" +#include +#include +#include "rogue.h" + +/* + * print out the number of charges on a stick + */ +char * +charge_str(obj) +register struct object *obj; +{ + static char buf[20]; + + if (!(obj->o_flags & ISKNOW)) + buf[0] = '\0'; + else if (terse) + sprintf(buf, " [%d]", obj->o_charges); + else + sprintf(buf, " [%d charges]", obj->o_charges); + return buf; +} +/* + * inv_name: + * return the name of something as it would appear in an + * inventory. + */ +char * +inv_name(obj, drop) +register struct object *obj; +bool drop; +{ + register char *pb; + + pb = prbuf; + pb[0] = '\0'; + switch(obj->o_type) { + case SCROLL: + if (obj->o_count == 1) + sprintf(pb, "A %sscroll ", blesscurse(obj->o_flags)); + else + sprintf(pb, "%d %sscrolls ", + obj->o_count, blesscurse(obj->o_flags)); + pb = &pb[strlen(pb)]; + if (s_know[obj->o_which] || (obj->o_flags & ISPOST)) + sprintf(pb, "of %s", s_magic[obj->o_which].mi_name); + else if (s_guess[obj->o_which]) + sprintf(pb, "named %s", s_guess[obj->o_which]); + else + sprintf(pb, "titled '%s'", s_names[obj->o_which]); + when POTION: + if (obj->o_count == 1) + sprintf(pb, "A %spotion ", blesscurse(obj->o_flags)); + else + sprintf(pb, "%d %spotions ", + obj->o_count, blesscurse(obj->o_flags)); + pb = &pb[strlen(pb)]; + if (p_know[obj->o_which]) + sprintf(pb, "of %s (%s)", p_magic[obj->o_which].mi_name, + p_kind(obj)); + else if (obj->o_flags & ISPOST) + sprintf(pb, "of %s", p_magic[obj->o_which].mi_name); + else if (p_guess[obj->o_which]) + sprintf(pb, "named %s (%s)", p_guess[obj->o_which], + p_colors[obj->o_which]); + else { + pb = prbuf; + if (obj->o_count == 1) + sprintf(pb, "A%s %s potion", + vowelstr(p_colors[obj->o_which]), + p_colors[obj->o_which]); + else + sprintf(pb, "%d %s potions", + obj->o_count, p_colors[obj->o_which]); + } + when FOOD: + if (obj->o_count == 1) + sprintf(pb, "A%s %s", vowelstr(foods[obj->o_which].mi_name), + foods[obj->o_which].mi_name); + else + sprintf(pb, "%d %ss", obj->o_count,foods[obj->o_which].mi_name); + when WEAPON: + if (obj->o_count > 1) + sprintf(pb, "%d ", obj->o_count); + else + strcpy(pb, "A "); + pb = &pb[strlen(pb)]; + if (obj->o_flags & ISKNOW) { + strcat(pb, num(obj->o_hplus, obj->o_dplus)); + strcat (pb, " "); + } + strcat(pb, weaps[obj->o_which].w_name); + if (obj->o_count > 1) + strcat(pb, "s"); + if (obj == cur_weapon) + strcat(pb, " (weapon in hand)"); + if (obj->o_flags & ISPOISON) + strcat(pb, " {Poisoned}"); + when ARMOR: + if (obj->o_flags & ISKNOW) { + strcat(pb, num(armors[obj->o_which].a_class - obj->o_ac, 0)); + strcat(pb, " "); + } + strcat(pb, armors[obj->o_which].a_name); + if (obj == cur_armor) + strcat(pb, " (being worn)"); + when STICK: + sprintf(pb, "A %s%s ", + blesscurse(obj->o_flags), ws_type[obj->o_which]); + pb = &pb[strlen(pb)]; + if (ws_know[obj->o_which] || obj->o_flags & ISKNOW) + sprintf(pb, "of %s%s (%s)", ws_magic[obj->o_which].mi_name, + charge_str(obj), ws_made[obj->o_which]); + else if (obj->o_flags & ISPOST) + sprintf(pb, "of %s", ws_magic[obj->o_which].mi_name); + else if (ws_guess[obj->o_which]) + sprintf(pb, "named %s (%s)", ws_guess[obj->o_which], + ws_made[obj->o_which]); + else { + pb = prbuf; + sprintf(pb, "A %s %s", ws_made[obj->o_which], + ws_type[obj->o_which]); + } + if (obj == cur_weapon) + strcat(prbuf, " (weapon in hand)"); + when RING: + if (r_know[obj->o_which] || obj->o_flags & ISKNOW) + sprintf(pb, "A%s ring of %s (%s)", ring_num(obj), + r_magic[obj->o_which].mi_name, r_stones[obj->o_which]); + else if (obj->o_flags & ISPOST) + sprintf(pb, "A ring of %s", r_magic[obj->o_which].mi_name); + else if (r_guess[obj->o_which]) + sprintf(pb, "A ring named %s (%s)", + r_guess[obj->o_which], r_stones[obj->o_which]); + else + sprintf(pb, "A%s %s ring", vowelstr(r_stones[obj->o_which]), + r_stones[obj->o_which]); + if (obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] || + obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4]) + strcat(pb, " (on left hand)"); + if (obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] || + obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4]) + strcat(pb, " (on right hand)"); + when RELIC: + if (obj->o_flags & ISKNOW) + switch(obj->o_which) { + case QUILL_NAGROM: + sprintf(pb, "%s%s", rel_magic[obj->o_which].mi_name, + charge_str(obj)); + otherwise: + strcpy(pb, rel_magic[obj->o_which].mi_name); + } + else switch(obj->o_which) { + case MUSTY_DAGGER: + strcpy(pb, "Two very fine daggers marked MDDE"); + when EMORI_CLOAK: + strcpy(pb, "A silk cloak"); + when HEIL_ANKH: + strcpy(pb, "A golden ankh"); + when MING_STAFF: + strcpy(pb, "A finely carved staff"); + when ORCUS_WAND: + strcpy(pb, "A sparkling ivory wand"); + when ASMO_ROD: + strcpy(pb, "A glistening ebony rod"); + when YENDOR_AMULET: + strcpy(pb, "A silver amulet"); + when STONEBONES_AMULET: + strcpy(pb, "A stone amulet"); + when BRIAN_MANDOLIN: + strcpy(pb, "A gleaming mandolin"); + when HRUGGEK_MSTAR: + strcpy(pb, "A huge morning star"); + when AXE_AKLAD: + strcpy(pb, "A jewel encrusted axe"); + when QUILL_NAGROM: + strcpy(pb, "A bright white feather"); + when GERYON_HORN: + strcpy(pb, "A jet black horn"); + when YEENOGHU_FLAIL: + strcpy(pb, "A shimmering flail"); + when SURTUR_RING: + strcpy(pb, "A fiery red ring"); + otherwise: + strcpy(pb, "A magical item"); + } + + /* Take care of wielding and wearing */ + switch (obj->o_which) { + case EMORI_CLOAK: + if (cur_armor == NULL && cur_misc[WEAR_CLOAK] == NULL) + strcat(pb, " (being worn)"); + if (obj->o_charges) + strcat(pb, " [charged]"); + else + strcat(pb, " [discharged]"); + when HEIL_ANKH: + if (cur_relic[HEIL_ANKH]) strcat(pb, " (in hand)"); + when EYE_VECNA: + if (cur_relic[EYE_VECNA]) strcat(pb, " (in eye socket)"); + when STONEBONES_AMULET: + if (cur_relic[STONEBONES_AMULET]) + strcat(pb, " (in chest)"); + when YENDOR_AMULET: + if (cur_relic[YENDOR_AMULET]) + strcat(pb, " (in chest)"); + when MUSTY_DAGGER: + case HRUGGEK_MSTAR: + case AXE_AKLAD: + case YEENOGHU_FLAIL: + case MING_STAFF: + case ASMO_ROD: + case ORCUS_WAND: + if (cur_weapon == obj) strcat(pb, " (weapon in hand)"); + when SURTUR_RING: + if (cur_relic[SURTUR_RING]) + strcat(pb, " (in nose)"); + } + when MM: + if (m_know[obj->o_which]) + strcpy(pb, misc_name(obj)); + else { + switch (obj->o_which) { + case MM_JUG: + case MM_BEAKER: + strcpy(pb, "A bottle"); + when MM_KEOGHTOM: + strcpy(pb, "A jar"); + when MM_JEWEL: + strcpy(pb, "An amulet"); + when MM_BOOK: + case MM_SKILLS: + strcpy(pb, "A book"); + when MM_ELF_BOOTS: + case MM_DANCE: + strcpy(pb, "A pair of boots"); + when MM_BRACERS: + strcpy(pb, "A pair of bracers"); + when MM_OPEN: + case MM_HUNGER: + strcpy(pb, "A chime"); + when MM_DISP: + case MM_R_POWERLESS: + case MM_PROTECT: + strcpy(pb, "A cloak"); + when MM_DRUMS: + strcpy(pb, "A set of drums"); + when MM_DISAPPEAR: + case MM_CHOKE: + strcpy(pb, "A pouch of dust"); + when MM_G_DEXTERITY: + case MM_G_OGRE: + case MM_FUMBLE: + strcpy(pb, "A pair of gauntlets"); + when MM_ADAPTION: + case MM_STRANGLE: + strcpy(pb, "A necklace"); + otherwise: + strcpy(pb, "A magical item"); + } + if (m_guess[obj->o_which]) { + strcat(pb, " named: "); + strcat(pb, m_guess[obj->o_which]); + } + } + if (obj == cur_misc[WEAR_BOOTS] || + obj == cur_misc[WEAR_BRACERS] || + obj == cur_misc[WEAR_CLOAK] || + obj == cur_misc[WEAR_GAUNTLET] || + obj == cur_misc[WEAR_NECKLACE] || + obj == cur_misc[WEAR_JEWEL]) + strcat(pb, " (being worn)"); + when GOLD: + sprintf(pb, "%d Pieces of Gold", obj->o_count); + otherwise: + debug("Picked up something funny"); + sprintf(pb, "Something bizarre %s", unctrl(obj->o_type)); + } + + /* Is it marked? */ + if (obj->o_mark[0]) { + pb = &pb[strlen(pb)]; + sprintf(pb, " <%s>", obj->o_mark); + } + + if (obj->o_flags & ISPROT) + strcat(pb, " [protected]"); + if (drop && isupper(prbuf[0])) + prbuf[0] = tolower(prbuf[0]); + else if (!drop && islower(*prbuf)) + *prbuf = toupper(*prbuf); + if (!drop) + strcat(pb, "."); + /* + * Truncate if long. Use cols-4 to offset the "pack letter" of a normal + * inventory listing. + */ + prbuf[cols-4] = '\0'; + return prbuf; +} + +/* + * weap_name: + * Return the name of a weapon. + */ +char * +weap_name(obj) +register struct object *obj; +{ + switch (obj->o_type) { + case WEAPON: + return(weaps[obj->o_which].w_name); + when MISSILE: + return(ws_magic[obj->o_which].mi_name); + when RELIC: + switch (obj->o_which) { + case MUSTY_DAGGER: + return("daggers"); + when YEENOGHU_FLAIL: + return("flail"); + when AXE_AKLAD: + return("axe"); + when HRUGGEK_MSTAR: + return("morning star"); + when MING_STAFF: + return("staff"); + when ORCUS_WAND: + return("wand"); + when ASMO_ROD: + return("rod"); + } + } + return("weapon"); +} + +/* + * drop: + * put something down + */ +drop(item) +struct linked_list *item; +{ + register char ch; + register struct linked_list *obj, *nobj; + register struct object *op; + + if (item == NULL) { + /* We charge 2 movement times to drop something */ + if (player.t_action == C_DROP && player.t_using != NULL) { + obj = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + } + + /* t_action == C_DROP always when called from command() */ + else { + if ((obj = get_item(pack, "drop", ALL, FALSE, FALSE)) == NULL) { + player.t_action = A_NIL; + player.t_using = NULL; + return(FALSE); + } + if (player.t_action == C_DROP) { + player.t_using = obj; + player.t_no_move = 2 * movement(&player); + return(FALSE); /* We'll come back after we've waited */ + } + } + + switch(ch = CCHAR(mvwinch(stdscr, hero.y, hero.x))) { + case PASSAGE: + case SCROLL: + case POTION: + case WEAPON: + case FLOOR: + case STICK: + case ARMOR: + case POOL: + case RELIC: + case GOLD: + case FOOD: + case RING: + case MM: + break; + default: + msg("Can't leave it here"); + return(FALSE); + } + } + else { + obj = item; + } + op = OBJPTR(obj); + if (!dropcheck(op)) + return(FALSE); + + /* + * If it is a scare monster scroll, curse it + */ + if (op->o_type == SCROLL && op->o_which == S_SCARE) { + if (op->o_flags & ISBLESSED) + op->o_flags &= ~ISBLESSED; + else op->o_flags |= ISCURSED; + } + + /* + * Take it out of the pack + */ + if (op->o_count >= 2 && op->o_group == 0) + { + nobj = new_item(sizeof *op); + op->o_count--; + op = OBJPTR(nobj); + *op = *(OBJPTR(obj)); + op->o_count = 1; + obj = nobj; + } + else { + detach(pack, obj); + inpack--; + } + if(ch == POOL) { + msg("Your %s sinks out of sight.",inv_name(op,TRUE)); + o_discard(obj); + } + else if (levtype == POSTLEV) { + op->o_pos = hero; /* same place as hero */ + fall(obj,FALSE); + if (item == NULL) /* if item wasn't sold */ + msg("Thanks for your donation to the fiend's flea market."); + } + else { + /* + * Link it into the level object list + */ + attach(lvl_obj, obj); + mvaddch(hero.y, hero.x, op->o_type); + op->o_pos = hero; + msg("Dropped %s", inv_name(op, TRUE)); + } + updpack(FALSE, &player); + return (TRUE); +} + +/* + * do special checks for dropping or unweilding|unwearing|unringing + */ +dropcheck(op) +register struct object *op; +{ + int save_max; + + if (op == NULL) + return TRUE; + if (levtype == POSTLEV) { + if ((op->o_flags & ISCURSED) && (op->o_flags & ISKNOW)) { + msg("The trader does not accept your shoddy merchandise"); + return(FALSE); + } + } + + /* Player will not drop a relic */ + if (op->o_type == RELIC) { + /* + * There is a 1% cumulative chance per relic that trying to get + * rid of it will cause the relic to turn on the player. + */ + if (rnd(100) < cur_relic[op->o_which]++) { + msg("The artifact turns on you."); + msg("It crushes your mind!!! -- More --"); + pstats.s_hpt = -1; + wait_for (' '); + death(D_RELIC); + } + else { + if (terse) msg("Can't release it."); + else msg("You cannot bring yourself to release it."); + return FALSE; + } + } + + /* If we aren't wearing it, we can drop it */ + if (!is_current(op)) return TRUE; + + /* At this point, we know we are wearing the item */ + if (op->o_flags & ISCURSED) { + msg("You can't. It appears to be cursed."); + return FALSE; + } + if (op->o_type == RING && cur_misc[WEAR_GAUNTLET] != NULL) { + msg ("You have to remove your gauntlets first!"); + return FALSE; + } + cur_null(op); /* set current to NULL */ + if (op->o_type == RING) { + switch (op->o_which) { + case R_ADDSTR: save_max = max_stats.s_str; + chg_str(-op->o_ac); + max_stats.s_str = save_max; + when R_ADDHIT: pstats.s_dext -= op->o_ac; + when R_ADDINTEL: pstats.s_intel -= op->o_ac; + when R_ADDWISDOM: pstats.s_wisdom -= op->o_ac; + when R_SEEINVIS: if (!ISWEARING(R_SEEINVIS) && + find_slot(unsee) == 0) { + turn_off(player, CANSEE); + msg("The tingling feeling leaves your eyes"); + } + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + when R_WARMTH: if (!ISWEARING(R_WARMTH) && !find_slot(nocold)) + turn_off(player, NOCOLD); + when R_FIRE: if (!ISWEARING(R_FIRE) && + !cur_relic[SURTUR_RING] && + !find_slot(nofire)) + turn_off(player, NOFIRE); + when R_LIGHT: { + if(roomin(&hero) != NULL) { + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + } + } + when R_SEARCH: kill_daemon(ring_search); + when R_TELEPORT: kill_daemon(ring_teleport); + } + } + else if (op->o_type == MM) { + switch (op->o_which) { + case MM_ADAPTION: + turn_off(player, NOGAS); + + when MM_STRANGLE: + msg("You can breathe again.....whew!"); + kill_daemon(strangle); + + when MM_DANCE: + turn_off(player, ISDANCE); + msg ("Your feet take a break.....whew!"); + + when MM_FUMBLE: + kill_daemon(fumble); + } + } + return TRUE; +} + +/* + * return a new thing + */ +struct linked_list * +new_thing(thing_type, allow_curse) +int thing_type; +bool allow_curse; +{ + register struct linked_list *item; + register struct object *cur; + register int j; + register int blesschance, cursechance; + + item = new_item(sizeof *cur); + cur = OBJPTR(item); + cur->o_hplus = cur->o_dplus = 0; + strncpy(cur->o_damage, "0d0", sizeof(cur->o_damage)); + strncpy(cur->o_hurldmg, "0d0", sizeof(cur->o_hurldmg)); + cur->o_ac = 0; + cur->o_count = 1; + cur->o_group = 0; + cur->contents = NULL; + cur->o_flags = 0; + cur->o_weight = 0; + cur->o_mark[0] = '\0'; + /* + * Decide what kind of object it will be + * If we haven't had food for a while, let it be food. + */ + blesschance = rnd(100); + if (allow_curse) cursechance = rnd(100); + else cursechance = 100; /* No chance of curse */ + + /* Get the type of item (pick one if 'any' is specified) */ + if (thing_type == ALL) j = pick_one(things, NUMTHINGS); + else j = thing_type; + + /* + * make sure he gets his vitamins + */ + if (thing_type == ALL && no_food > 3) + j = 2; + /* + * limit the number of foods on a level because it sometimes + * gets out of hand in the "deep" levels where there is a + * treasure room on most every level with lots of food in it + */ + while (thing_type == ALL && levtype != POSTLEV && foods_this_level > 2 && + j == 2) + j = pick_one(things, NUMTHINGS); /* not too many.... */ + switch (j) + { + case TYP_POTION: + cur->o_type = POTION; + do { + cur->o_which = pick_one(p_magic, MAXPOTIONS); + } while (!allow_curse && p_magic[cur->o_which].mi_curse == 100); + cur->o_weight = things[TYP_POTION].mi_wght; + if (cursechance < p_magic[cur->o_which].mi_curse) + cur->o_flags |= ISCURSED; + else if (blesschance < p_magic[cur->o_which].mi_bless) + cur->o_flags |= ISBLESSED; + + /* If we made a gain ability potion, see what kind it is */ + if (cur->o_which == P_ABIL) cur->o_kind = rnd(NUMABILITIES); + + when TYP_SCROLL: + cur->o_type = SCROLL; + do { + cur->o_which = pick_one(s_magic, MAXSCROLLS); + } while (!allow_curse && s_magic[cur->o_which].mi_curse == 100); + cur->o_weight = things[TYP_SCROLL].mi_wght; + if (cursechance < s_magic[cur->o_which].mi_curse) + cur->o_flags |= ISCURSED; + else if (blesschance < s_magic[cur->o_which].mi_bless) + cur->o_flags |= ISBLESSED; + when TYP_FOOD: + no_food = 0; + cur->o_type = FOOD; + cur->o_weight = things[TYP_FOOD].mi_wght; + cur->o_count += extras(); + foods_this_level += cur->o_count; + cur->o_which = pick_one(foods, MAXFOODS); + when TYP_WEAPON: + cur->o_type = WEAPON; + cur->o_which = rnd(MAXWEAPONS); + init_weapon(cur, cur->o_which); + if (cursechance < 20) + { + + cur->o_flags |= ISCURSED; + cur->o_hplus -= rnd(2) + 1; + cur->o_dplus -= rnd(2) + 1; + } + else if (blesschance < 50) { + + cur->o_hplus += rnd(5) + 1; + cur->o_dplus += rnd(5) + 1; + } + when TYP_ARMOR: + cur->o_type = ARMOR; + for (j = 0; j < MAXARMORS; j++) + if (blesschance < armors[j].a_prob) + break; + if (j == MAXARMORS) + { + debug("Picked a bad armor %d", blesschance); + j = 0; + } + cur->o_which = j; + cur->o_ac = armors[j].a_class; + cur->o_weight = armors[j].a_wght; + if (cursechance < 20) + { + cur->o_flags |= ISCURSED; + cur->o_ac += rnd(3)+1; + } + else if (blesschance < 35) + cur->o_ac -= rnd(3)+1; + when TYP_RING: + cur->o_type = RING; + do { + cur->o_which = pick_one(r_magic, MAXRINGS); + } while (!allow_curse && r_magic[cur->o_which].mi_curse == 100); + cur->o_weight = things[TYP_RING].mi_wght; + if (cursechance < r_magic[cur->o_which].mi_curse) + cur->o_flags |= ISCURSED; + else if (blesschance < r_magic[cur->o_which].mi_bless) + cur->o_flags |= ISBLESSED; + switch (cur->o_which) + { + case R_ADDSTR: + case R_ADDWISDOM: + case R_ADDINTEL: + case R_PROTECT: + case R_ADDHIT: + case R_ADDDAM: + cur->o_ac = rnd(2) + 1; /* From 1 to 3 */ + if (cur->o_flags & ISCURSED) + cur->o_ac = -cur->o_ac; + if (cur->o_flags & ISBLESSED) cur->o_ac++; + when R_DIGEST: + if (cur->o_flags & ISCURSED) cur->o_ac = -1; + else if (cur->o_flags & ISBLESSED) cur->o_ac = 2; + else cur->o_ac = 1; + } + when TYP_STICK: + cur->o_type = STICK; + do { + cur->o_which = pick_one(ws_magic, MAXSTICKS); + } while (!allow_curse && ws_magic[cur->o_which].mi_curse == 100); + fix_stick(cur); + if (cursechance < ws_magic[cur->o_which].mi_curse) + cur->o_flags |= ISCURSED; + else if (blesschance < ws_magic[cur->o_which].mi_bless) + cur->o_flags |= ISBLESSED; + when TYP_MM: + cur->o_type = MM; + do { + cur->o_which = pick_one(m_magic, MAXMM); + } while (!allow_curse && m_magic[cur->o_which].mi_curse == 100); + cur->o_weight = things[TYP_MM].mi_wght; + if (cursechance < m_magic[cur->o_which].mi_curse) + cur->o_flags |= ISCURSED; + else if (blesschance < m_magic[cur->o_which].mi_bless) + cur->o_flags |= ISBLESSED; + switch (cur->o_which) { + case MM_JUG: + switch(rnd(11)) { + case 0: cur->o_ac = P_PHASE; + when 1: cur->o_ac = P_CLEAR; + when 2: cur->o_ac = P_SEEINVIS; + when 3: cur->o_ac = P_HEALING; + when 4: cur->o_ac = P_MFIND; + when 5: cur->o_ac = P_TFIND; + when 6: cur->o_ac = P_HASTE; + when 7: cur->o_ac = P_RESTORE; + when 8: cur->o_ac = P_FLY; + when 9: cur->o_ac = P_SKILL; + when 10:cur->o_ac = P_FFIND; + } + when MM_OPEN: + cur->o_ac = (4 + rnd(5)) * 5; + when MM_HUNGER: + case MM_DRUMS: + case MM_DISAPPEAR: + case MM_CHOKE: + case MM_KEOGHTOM: + cur->o_ac = 3 + (rnd(3)+1) * 3; + when MM_BRACERS: + if (cur->o_flags & ISCURSED) + cur->o_ac = -(rnd(3)+1); + else + cur->o_ac = rnd(8)+1; + when MM_PROTECT: + if (cur->o_flags & ISCURSED) + cur->o_ac = -(rnd(3)+1); + else + cur->o_ac = rnd(5)+1; + when MM_DISP: + cur->o_ac = 2; + when MM_SKILLS: /* set it to a character class */ + cur->o_ac = rnd(NUM_CHARTYPES-1); + otherwise: + cur->o_ac = 0; + } + otherwise: + debug("Picked a bad kind of object"); + wait_for(' '); + } + return item; +} + +/* + * provide a new item tailored to specification + */ +struct linked_list * +spec_item(type, which, hit, damage) +int type, which, hit, damage; +{ + register struct linked_list *item; + register struct object *obj; + + item = new_item(sizeof *obj); + obj = OBJPTR(item); + obj->o_count = 1; + obj->o_group = 0; + obj->contents = NULL; + obj->o_type = type; + obj->o_which = which; + strncpy(obj->o_damage, "0d0", sizeof(obj->o_damage)); + strncpy(obj->o_hurldmg, "0d0", sizeof(obj->o_hurldmg)); + obj->o_hplus = 0; + obj->o_dplus = 0; + obj->o_flags = 0; + obj->o_mark[0] = '\0'; + obj->o_text = NULL; + obj->o_launch = 0; + obj->o_weight = 0; + + /* Handle special characteristics */ + switch (type) { + case WEAPON: + init_weapon(obj, which); + obj->o_hplus = hit; + obj->o_dplus = damage; + obj->o_ac = 10; + + if (hit > 0 || damage > 0) obj->o_flags |= ISBLESSED; + else if (hit < 0 || damage < 0) obj->o_flags |= ISCURSED; + + when ARMOR: + obj->o_ac = armors[which].a_class - hit; + if (hit > 0) obj->o_flags |= ISBLESSED; + else if (hit < 0) obj->o_flags |= ISCURSED; + + when RING: + obj->o_ac = hit; + switch (obj->o_which) { + case R_ADDSTR: + case R_ADDWISDOM: + case R_ADDINTEL: + case R_PROTECT: + case R_ADDHIT: + case R_ADDDAM: + case R_DIGEST: + if (hit > 1) obj->o_flags |= ISBLESSED; + else if (hit < 0) obj->o_flags |= ISCURSED; + } + + when STICK: + fix_stick(obj); + obj->o_charges = hit; + + when GOLD: + obj->o_type = GOLD; + obj->o_count = GOLDCALC; + obj->o_ac = 11; + + when MM: + obj->o_type = MM; + obj->o_ac = hit; + + when RELIC: + /* Handle weight here since these are all created uniquely */ + obj->o_weight = things[TYP_RELIC].mi_wght; + if (obj->o_which == EMORI_CLOAK) + obj->o_charges = 1; + + } + return(item); +} + +/* + * pick an item out of a list of nitems possible magic items + */ +pick_one(magic, nitems) +register struct magic_item *magic; +int nitems; +{ + register struct magic_item *end; + register int i; + register struct magic_item *start; + + start = magic; + for (end = &magic[nitems], i = rnd(1000); magic < end; magic++) + if (i < magic->mi_prob) + break; + if (magic == end) + { + if (wizard) + { + msg("bad pick_one: %d from %d items", i, nitems); + for (magic = start; magic < end; magic++) + msg("%s: %d%%", magic->mi_name, magic->mi_prob); + } + magic = start; + } + return (int) (magic - start); +} + + +/* blesscurse returns whether, according to the flag, the object is + * blessed, cursed, or neither + */ + +char * +blesscurse(flags) +int flags; +{ + if (flags & ISKNOW) { + if (flags & ISCURSED) return("cursed "); + if (flags & ISBLESSED) return("blessed "); + return("normal "); + } + return(""); +} + +/* + * p_kind returns the type of potion for some types of identified potions; + * otherwise, it returns the color. + */ + +char * +p_kind(obj) +struct object *obj; /* We assume that obj points to a potion */ +{ + if (obj->o_which == P_ABIL) return(abilities[obj->o_kind]); + else return(p_colors[obj->o_which]); +} + +/* + * extras: + * Return the number of extra items to be created + */ +extras() +{ + reg int i; + + i = rnd(100); + if (i < 4) /* 4% for 2 more */ + return (2); + else if (i < 11) /* 7% for 1 more */ + return (1); + else /* otherwise no more */ + return (0); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/trader.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/trader.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,539 @@ +/* + * trader.c - Anything to do with trading posts + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Anything to do with trading posts + */ + +#include "curses.h" +#include "rogue.h" + + + + + +/* + * buy_it: + * Buy the item on which the hero stands + */ +buy_it() +{ + reg int wh; + struct linked_list *item; + + if (purse <= 0) { + msg("You have no money."); + return; + } + if (curprice < 0) { /* if not yet priced */ + wh = price_it(); + if (!wh) /* nothing to price */ + return; + msg("Do you want to buy it? "); + do { + wh = tolower(readchar()); + if (wh == ESCAPE || wh == 'n') { + msg(""); + return; + } + } until(wh == 'y'); + } + mpos = 0; + if (curprice > purse) { + msg("You can't afford to buy that %s !",curpurch); + return; + } + /* + * See if the hero has done all his transacting + */ + if (!open_market()) + return; + /* + * The hero bought the item here + */ + item = find_obj(hero.y, hero.x); + mpos = 0; + if (add_pack(NULL, TRUE, &item)) { /* try to put it in his pack */ + purse -= curprice; /* take his money */ + ++trader; /* another transaction */ + trans_line(); /* show remaining deals */ + curprice = -1; /* reset stuff */ + curpurch[0] = 0; + whatis (item); /* identify it after purchase */ + (OBJPTR(item))->o_flags &= ~ISPOST; /* turn off ISPOST */ + msg("%s", inv_name(OBJPTR(item), TRUE)); + } +} + +/* + * do_post: + * Put a trading post room and stuff on the screen + */ +do_post(startup) +bool startup; /* True if equipping the player at the beginning of the game */ +{ + coord tp; + reg int i, j, k; + reg struct room *rp; + reg struct object *op; + reg struct linked_list *ll; + + o_free_list(lvl_obj); /* throw old items away */ + + for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) + rp->r_flags = ISGONE; /* kill all rooms */ + + rp = &rooms[0]; /* point to only room */ + rp->r_flags = 0; /* this room NOT gone */ + rp->r_max.x = 40; + rp->r_max.y = 10; /* 10 * 40 room */ + rp->r_pos.x = (cols - rp->r_max.x) / 2; /* center horizontal */ + rp->r_pos.y = 1; /* 2nd line */ + draw_room(rp); /* draw the only room */ + + /* Are we equipping the player? */ + if (startup) { + int wpt; + + /* + * Give the rogue some weaponry. + */ + for (wpt=0; wpto_flags |= (ISPOST | ISKNOW); + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* + * And his suit of armor....... + * Thieves can only wear leather armor, + * so make sure some is available for them. + */ + for (i=0; io_flags |= (ISPOST | ISKNOW); + op->o_weight = armors[i].a_wght; + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* Now create some wands */ + for (i=rnd(4)+2; i>0; i--) { + switch (rnd(8)) { + case 0: j = WS_SLOW_M; + when 1: j = WS_TELMON; + when 2: j = WS_CONFMON; + when 3: j = WS_PARALYZE; + when 4: j = WS_MDEG; + when 5: j = WS_WONDER; + when 6: j = WS_FEAR; + when 7: j = WS_LIGHT; + } + ll = spec_item(STICK, j, 0, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + + /* Let clerics and MU'S know what kind they are */ + switch (player.t_ctype) { + case C_MAGICIAN: + case C_CLERIC: + case C_DRUID: + op->o_flags |= (ISPOST | ISKNOW); + otherwise: + op->o_flags |= ISPOST; + } + fix_stick(op); + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* Now let's make some rings */ + for (i=rnd(4)+3; i>0; i--) { + k = 0; + switch (rnd(15)) { + case 0: j = R_PROTECT; k = roll(1,2); + when 1: j = R_ADDSTR; k = roll(1,3); + when 2: j = R_ADDHIT; k = roll(1,3); + when 3: j = R_ADDDAM; k = roll(1,3); + when 4: j = R_DIGEST; k = 1; + when 5: j = R_ADDINTEL; k = roll(1,3); + when 6: j = R_ADDWISDOM;k = roll(1,3); + when 7: j = R_SUSABILITY; + when 8: j = R_SEEINVIS; + when 9: j = R_ALERT; + when 10:j = R_HEALTH; + when 11:j = R_HEROISM; + when 12:j = R_FIRE; + when 13:j = R_WARMTH; + when 14:j = R_FREEDOM; + } + ll = spec_item(RING, j, k, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + + /* + * Let fighters, assassins, monks, and thieves know what kind + * of rings these are. + */ + switch (player.t_ctype) { + case C_FIGHTER: + case C_THIEF: + case C_ASSASIN: + case C_MONK: + op->o_flags |= (ISPOST | ISKNOW); + otherwise: + op->o_flags |= ISPOST; + } + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* Let's offer some potions */ + for (i=rnd(3)+1; i>0; i--) { + /* Choose the type of potion */ + if (i == 1 && player.t_ctype == C_ASSASIN) j = P_POISON; + else switch (rnd(8)) { + case 0: j = P_CLEAR; + when 1: j = P_HEALING; + when 2: j = P_MFIND; + when 3: j = P_TFIND; + when 4: j = P_HASTE; + when 5: j = P_RESTORE; + when 6: j = P_FLY; + when 7: j = P_FFIND; + } + + /* Make the potion */ + ll = spec_item(POTION, j, 0, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + op->o_flags |= ISPOST; + + /* Place the potion */ + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* Let's offer some scrolls */ + for (i=rnd(3)+1; i>0; i--) { + /* Choose the type of scrolls */ + switch (rnd(8)) { + case 0: j = S_CONFUSE; + when 1: j = S_MAP; + when 2: j = S_LIGHT; + when 3: j = S_SLEEP; + when 4: j = S_IDENT; + when 5: j = S_GFIND; + when 6: j = S_REMOVE; + when 7: j = S_CURING; + } + + /* Make the scroll */ + ll = spec_item(SCROLL, j, 0, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + op->o_flags |= ISPOST; + + /* Place the scroll */ + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + + /* And finally, let's get some food */ + for (i=rnd(3)+1; i>0; i--) { + ll = spec_item(FOOD, 0, 0, 0); + attach(lvl_obj, ll); + op = OBJPTR(ll); + op->o_weight = things[TYP_FOOD].mi_wght; + op->o_flags |= ISPOST; + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + } + else { + i = roll(10, 4); /* 10 to 40 items */ + for (; i > 0 ; i--) { /* place all the items */ + ll = new_thing(ALL, TRUE); /* get something */ + attach(lvl_obj, ll); + op = OBJPTR(ll); + op->o_flags |= ISPOST; /* object in trading post */ + do { + rnd_pos(rp,&tp); + } until (mvinch(tp.y, tp.x) == FLOOR); + op->o_pos = tp; + mvaddch(tp.y,tp.x,op->o_type); + } + } + wmove(cw,12,0); + trader = 0; + if (startup) { + waddstr(cw,"Welcome to Friendly Fiend's Equipage\n\r"); + waddstr(cw,"====================================\n\r"); + } + else { + waddstr(cw,"Welcome to Friendly Fiend's Flea Market\n\r"); + waddstr(cw,"=======================================\n\r"); + } + waddstr(cw,"$: Prices object that you stand upon.\n\r"); + waddstr(cw,"#: Buys the object that you stand upon.\n\r"); + waddstr(cw,"%: Trades in something in your pack for gold.\n\r"); + trans_line(); +} + + +/* + * get_worth: + * Calculate an objects worth in gold + */ +get_worth(obj) +reg struct object *obj; +{ + reg int worth, wh; + + worth = 0; + wh = obj->o_which; + switch (obj->o_type) { + case FOOD: + worth = 2; + when WEAPON: + if (wh < MAXWEAPONS) { + worth = weaps[wh].w_worth; + worth += s_magic[S_ALLENCH].mi_worth * + (obj->o_hplus + obj->o_dplus); + } + when ARMOR: + if (wh < MAXARMORS) { + worth = armors[wh].a_worth; + worth += s_magic[S_ALLENCH].mi_worth * + (armors[wh].a_class - obj->o_ac); + } + when SCROLL: + if (wh < MAXSCROLLS) + worth = s_magic[wh].mi_worth; + when POTION: + if (wh < MAXPOTIONS) + worth = p_magic[wh].mi_worth; + when RING: + if (wh < MAXRINGS) { + worth = r_magic[wh].mi_worth; + worth += obj->o_ac * 40; + } + when STICK: + if (wh < MAXSTICKS) { + worth = ws_magic[wh].mi_worth; + worth += 20 * obj->o_charges; + } + when MM: + if (wh < MAXMM) { + worth = m_magic[wh].mi_worth; + switch (wh) { + case MM_BRACERS: worth += 40 * obj->o_ac; + when MM_PROTECT: worth += 60 * obj->o_ac; + when MM_DISP: /* ac already figured in price*/ + otherwise: worth += 20 * obj->o_ac; + } + } + when RELIC: + if (wh < MAXRELIC) { + worth = rel_magic[wh].mi_worth; + if (wh == quest_item) worth *= 10; + } + otherwise: + worth = 0; + } + if (obj->o_flags & ISPROT) /* 300% more for protected */ + worth *= 3; + if (obj->o_flags & ISBLESSED) /* 50% more for blessed */ + worth = worth * 3 / 2; + if (obj->o_flags & ISCURSED) /* half for cursed */ + worth /= 2; + if (worth < 0) + worth = 0; + return worth; +} + +/* + * open_market: + * Retruns TRUE when ok do to transacting + */ +open_market() +{ + if (trader >= MAXPURCH && !wizard && level != 0) { + msg("The market is closed. The stairs are that-a-way."); + return FALSE; + } + else { + return TRUE; + } +} + +/* + * price_it: + * Price the object that the hero stands on + */ +price_it() +{ + reg struct linked_list *item; + reg struct object *obj; + reg int worth; + reg char *str; + + if (!open_market()) /* after buying hours */ + return FALSE; + if ((item = find_obj(hero.y,hero.x)) == NULL) { + debug("Can't find the item"); + return FALSE; + } + obj = OBJPTR(item); + worth = get_worth(obj); + if (worth < 0) { + msg("That's not for sale."); + return FALSE; + } + if (worth < 25) + worth = 25; + + /* Our shopkeeper is affected by the person's charisma */ + worth = (int) ((float) worth * (17. / (float)pstats.s_charisma)); + str = inv_name(obj, TRUE); + msg("%s for only %d pieces of gold", str, worth); + curprice = worth; /* save price */ + strcpy(curpurch,str); /* save item */ + return TRUE; +} + + + +/* + * sell_it: + * Sell an item to the trading post + */ +sell_it() +{ + reg struct linked_list *item; + reg struct object *obj; + reg int wo, ch; + + if (!open_market()) /* after selling hours */ + return; + + if ((item = get_item(pack, "sell", ALL, FALSE, FALSE)) == NULL) + return; + obj = OBJPTR(item); + wo = get_worth(obj); + if (wo <= 0) { + mpos = 0; + msg("We don't buy those."); + return; + } + if (wo < 25) + wo = 25; + msg("Your %s is worth %d pieces of gold.",typ_name(obj),wo); + msg("Do you want to sell it? "); + do { + ch = tolower(readchar()); + if (ch == ESCAPE || ch == 'n') { + msg(""); + return; + } + } until (ch == 'y'); + mpos = 0; + if (drop(item) == TRUE) { /* drop this item */ + purse += wo; /* give him his money */ + ++trader; /* another transaction */ + wo = obj->o_count; + if (obj->o_group == 0) /* dropped one at a time */ + obj->o_count = 1; + msg("Sold %s",inv_name(obj,TRUE)); + obj->o_count = wo; + trans_line(); /* show remaining deals */ + } +} + +/* + * trans_line: + * Show how many transactions the hero has left + */ +trans_line() +{ + if (level == 0) + sprintf(prbuf, "You are welcome to spend whatever you have."); + else if (!wizard) + sprintf(prbuf,"You have %d transactions remaining.", + MAXPURCH - trader); + else + sprintf(prbuf, + "You have infinite transactions remaining oh great wizard."); + mvwaddstr(cw,lines - 3,0,prbuf); +} + + + +/* + * typ_name: + * Return the name for this type of object + */ +char * +typ_name(obj) +reg struct object *obj; +{ + static char buff[20]; + reg int wh; + + switch (obj->o_type) { + case POTION: wh = TYP_POTION; + when SCROLL: wh = TYP_SCROLL; + when STICK: wh = TYP_STICK; + when RING: wh = TYP_RING; + when ARMOR: wh = TYP_ARMOR; + when WEAPON: wh = TYP_WEAPON; + when MM: wh = TYP_MM; + when FOOD: wh = TYP_FOOD; + when RELIC: wh = TYP_RELIC; + otherwise: wh = -1; + } + if (wh < 0) + strcpy(buff,"unknown"); + else + strcpy(buff,things[wh].mi_name); + return (buff); +} + + diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/util.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,1284 @@ +/* + * util.c - all sorts of miscellaneous routines + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "curses.h" +#include "rogue.h" +#include +#include +#ifdef PC7300 +#include +#include +#include +extern struct uwdata wdata; +#endif + +/* + * all sorts of miscellaneous routines + * + */ + + + + +/* + * this routine computes the players current AC without dex bonus's + */ +int +ac_compute(ignoremetal) +bool ignoremetal; +{ + register int ac; + + ac = pstats.s_arm; /* base armor of "skin" */ + if (cur_armor) { + if (!ignoremetal || + (cur_armor->o_which != LEATHER && + cur_armor->o_which != STUDDED_LEATHER && + cur_armor->o_which != PADDED_ARMOR)) + ac -= (10 - cur_armor->o_ac); + } + if (player.t_ctype == C_MONK) + ac -= pstats.s_lvl * 2 / 3; + ac -= ring_value(R_PROTECT); + if (cur_misc[WEAR_BRACERS] != NULL) + ac -= cur_misc[WEAR_BRACERS]->o_ac; + if (cur_misc[WEAR_CLOAK] != NULL) + ac -= cur_misc[WEAR_CLOAK]->o_ac; + + /* If player has the cloak, must be wearing it */ + if (cur_relic[EMORI_CLOAK]) ac -= 5; + + if (ac > 10) + ac = 10; + return(ac); +} + +/* + * aggravate: + * aggravate all the monsters on this level + */ + +aggravate(do_uniques, do_good) +bool do_uniques, do_good; +{ + register struct linked_list *mi; + register struct thing *thingptr; + + for (mi = mlist; mi != NULL; mi = next(mi)) { + thingptr = THINGPTR(mi); + if (do_good == FALSE && off(*thingptr, ISMEAN)) continue; + if (do_uniques || off(*thingptr, ISUNIQUE)) runto(thingptr, &hero); + } +} + +/* + * cansee: + * returns true if the hero can see a certain coordinate. + */ + +cansee(y, x) +register int y, x; +{ + register struct room *rer; + register int radius; + coord tp; + + if (on(player, ISBLIND)) + return FALSE; + + tp.y = y; + tp.x = x; + rer = roomin(&tp); + + /* How far can we see? */ + if (levtype == OUTSIDE) { + if (daytime) radius = 36; + else if (lit_room(rer)) radius = 9; + else radius = 3; + } + else radius = 3; + + /* + * We can only see if the hero in the same room as + * the coordinate and the room is lit or if it is close. + */ + return ((rer != NULL && + levtype != OUTSIDE && + (levtype != MAZELEV || /* Maze level needs direct line */ + maze_view(tp.y, tp.x)) && + rer == roomin(&hero) && + lit_room(rer)) || + DISTANCE(y, x, hero.y, hero.x) < radius); +} + +/* + * check_level: + * Check to see if the guy has gone up a level. + * + * Return points needed to obtain next level. + * + * These are certain beginning experience levels for all players. + * All further experience levels are computed by muliplying by 2 + * up through MAXDOUBLE. Then the cap is added in to compute + * further levels + */ +long +check_level() +{ + register int i, j, add = 0; + register unsigned long exp; + long retval; /* Return value */ + int nsides; + + pstats.s_lvl -= pstats.s_lvladj; /* correct for level adjustment */ + /* See if we are past the doubling stage */ + exp = char_class[player.t_ctype].cap; + if (pstats.s_exp >= exp) { + i = pstats.s_exp/exp; /* First get amount above doubling area */ + retval = exp + i * exp; /* Compute next higher boundary */ + i += MAXDOUBLE; /* Add in the previous doubled levels */ + } + else { + i = 0; + exp = char_class[player.t_ctype].start_exp; + while (exp <= pstats.s_exp) { + i++; + exp <<= 1; + } + retval = exp; + } + if (++i > pstats.s_lvl) { + nsides = char_class[player.t_ctype].hit_pts; + for (j=0; j<(i-pstats.s_lvl); j++) /* Take care of multi-level jumps */ + add += max(1, roll(1,nsides) + const_bonus()); + max_stats.s_hpt += add; + if ((pstats.s_hpt += add) > max_stats.s_hpt) + pstats.s_hpt = max_stats.s_hpt; + msg("Welcome, %s, to level %d", + cnames[player.t_ctype][min(i-1, NUM_CNAMES-1)], i); + } + pstats.s_lvl = i; + pstats.s_lvl += pstats.s_lvladj; /* correct for level adjustment */ + return(retval); +} + +/* + * Used to modify the players strength + * it keeps track of the highest it has been, just in case + */ + +chg_str(amt) +register int amt; +{ + register int ring_str; /* ring strengths */ + register struct stats *ptr; /* for speed */ + + ptr = &pstats; + ring_str = ring_value(R_ADDSTR); + ptr->s_str -= ring_str; + ptr->s_str += amt; + if (ptr->s_str > 25) + ptr->s_str = 25; + if (ptr->s_str > max_stats.s_str) + max_stats.s_str = ptr->s_str; + ptr->s_str += ring_str; + if (ptr->s_str <= 0) + death(D_STRENGTH); + updpack(TRUE, &player); +} + +/* + * let's confuse the player + */ +confus_player() +{ + if (off(player, ISCLEAR)) + { + msg("Wait, what's going on here. Huh? What? Who?"); + if (find_slot(unconfuse)) + lengthen(unconfuse, HUHDURATION); + else + fuse(unconfuse, 0, HUHDURATION, AFTER); + turn_on(player, ISHUH); + } + else msg("You feel dizzy for a moment, but it quickly passes."); +} + +/* + * this routine computes the players current dexterity + */ +dex_compute() +{ + if (cur_misc[WEAR_GAUNTLET] != NULL && + cur_misc[WEAR_GAUNTLET]->o_which == MM_G_DEXTERITY) { + if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED) + return (3); + else + return (18); + } + else + return (pstats.s_dext); +} + +/* + * diag_ok: + * Check to see if the move is legal if it is diagonal + */ + +diag_ok(sp, ep, flgptr) +register coord *sp, *ep; +struct thing *flgptr; +{ + register int numpaths = 0; + + /* Horizontal and vertical moves are always ok */ + if (ep->x == sp->x || ep->y == sp->y) + return TRUE; + + /* Diagonal moves are not allowed if there is a horizontal or + * vertical path to the destination + */ + if (step_ok(ep->y, sp->x, MONSTOK, flgptr)) numpaths++; + if (step_ok(sp->y, ep->x, MONSTOK, flgptr)) numpaths++; + return(numpaths != 1); +} + +/* + * pick a random position around the give (y, x) coordinates + */ +coord * +fallpos(pos, be_clear, range) +register coord *pos; +bool be_clear; +int range; +{ + register int tried, i, j; + register char ch; + static coord ret; + static short masks[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100 }; + +/* + * Pick a spot at random centered on the position given by 'pos' and + * up to 'range' squares away from 'pos' + * + * If 'be_clear' is TRUE, the spot must be either FLOOR or PASSAGE + * inorder to be considered valid + * + * + * Generate a number from 0 to 8, representing the position to pick. + * Note that this DOES include the positon 'pos' itself + * + * If this position is not valid, mark it as 'tried', and pick another. + * Whenever a position is picked that has been tried before, + * sequentially find the next untried position. This eliminates costly + * random number generation + */ + + tried = 0; + while( tried != 0x1ff ) { + i = rnd(9); + while( tried & masks[i] ) + i = (i + 1) % 9; + + tried |= masks[i]; + + for( j = 1; j <= range; j++ ) { + ret.x = pos->x + j*grid[i].x; + ret.y = pos->y + j*grid[i].y; + + if (ret.x == hero.x && ret.y == hero.y) + continue; /* skip the hero */ + + if (ret.x < 0 || ret.x > cols - 1 || + ret.y < 1 || ret.y > lines - 3) + continue; /* off the screen? */ + + ch = CCHAR( winat(ret.y, ret.x) ); + + /* + * Check to make certain the spot is valid + */ + switch( ch ) { + case FLOOR: + case PASSAGE: + return( &ret ); + case GOLD: + case SCROLL: + case POTION: + case STICK: + case RING: + case WEAPON: + case ARMOR: + case MM: + case FOOD: + if(!be_clear && levtype != POSTLEV) + return( &ret ); + default: + break; + } + } + } + return( NULL ); +} + + +/* + * findmindex: + * Find the index into the monster table of a monster given its name. + */ + +findmindex(name) +char *name; +{ + int which; + + for (which=1; which= NUMMONST) { + debug("couldn't find monster index"); + which = 1; + } + return(which); +} + +/* + * find_mons: + * Find the monster from his coordinates + */ + +struct linked_list * +find_mons(y, x) +register int y; +register int x; +{ + register struct linked_list *item; + register struct thing *th; + + for (item = mlist; item != NULL; item = next(item)) + { + th = THINGPTR(item); + if (th->t_pos.y == y && th->t_pos.x == x) + return item; + } + return NULL; +} + +/* + * find_obj: + * find the unclaimed object at y, x + */ + +struct linked_list * +find_obj(y, x) +register int y; +register int x; +{ + register struct linked_list *obj; + register struct object *op; + + for (obj = lvl_obj; obj != NULL; obj = next(obj)) + { + op = OBJPTR(obj); + if (op->o_pos.y == y && op->o_pos.x == x) + return obj; + } + return NULL; +} + +/* + * get coordinates from the player using the cursor keys (or mouse) + */ +coord +get_coordinates() +{ + register int which; + coord c; +#ifdef PC7300 + struct umdata startmouse, listenmouse; /* Mouse parameters */ + int xmouse, /* x-position of mouse */ + ymouse, /* y-position of mouse */ + bmouse, /* button value of mouse */ + rmouse; /* reason for mouse change */ +#endif + + c = hero; + wmove(cw, hero.y, hero.x); + draw(cw); +#ifdef PC7300 + keypad(0, 1); /* Turn on escape sequences */ + ioctl(0, WIOCGETMOUSE, &startmouse); /* Get current mouse parameters */ + listenmouse = startmouse; /* Make a copy */ + listenmouse.um_flags |= MSDOWN; /* Enable detection of button down */ + ioctl(0, WIOCSETMOUSE, &listenmouse); /* Make the change */ +#endif + for (;;) { +#ifdef PC7300 + which = wgetc(0); +#else + which = (getchar() & 0177); +#endif + switch(which) { +#ifdef PC7300 + case Home: + c.x = 0; c.y = 1; + when Beg: + c.x = 0; + when End: + c.x = cols - 1; + when Mouse: + case ESCAPE: + case Cancl: + case s_Cancl: + if (which == Mouse) { + if (wreadmouse(0,&xmouse,&ymouse,&bmouse,&rmouse) != 0 || + (rmouse & MSDOWN) == 0) + break; + c.y = ymouse / wdata.uw_vs; + c.x = xmouse / wdata.uw_hs; + c.y = max(c.y, 1); + c.y = min(c.y, lines - 3); + c.x = max(c.x, 0); + c.x = min(c.x, cols - 1); + } + else c = hero; + wmove(cw, c.y, c.x); + draw(cw); + case '\n': + case '\c': + keypad(0, 0); /* Turn off escape interpretation */ + ioctl(0, WIOCSETMOUSE, &startmouse); /* No mouse tracking */ + return(c); + when 'h': + case 'H': + case Back: + case s_Back: + c.x--; + when 'j': + case 'J': + case Down: + case RollDn: + c.y++; + when 'k': + case 'K': + case Up: + case RollUp: + c.y--; + when 'l': + case 'L': + case Forward: + case s_Forward: + c.x++; + when 'y': + case 'Y': + case Prev: + c.x--; c.y--; + when 'u': + case 'U': + case Next: + c.x++; c.y--; + when 'b': + case 'B': + case s_Prev: + c.x--; c.y++; + when 'n': + case 'N': + case s_Next: + c.x++; c.y++; + when '*': + msg("Select location via mouse, or"); + msg("Use cursor keys,h,j,k,l,y,u,b,or n, then hit return."); +#else + case ESCAPE: + c = hero; + wmove(cw, c.y, c.x); + draw(cw); + case '\n': + case '\r': + return(c); + when 'h': + case 'H': + c.x--; + when 'j': + case 'J': + c.y++; + when 'k': + case 'K': + c.y--; + when 'l': + case 'L': + c.x++; + when 'y': + case 'Y': + c.x--; c.y--; + when 'u': + case 'U': + c.x++; c.y--; + when 'b': + case 'B': + c.x--; c.y++; + when 'n': + case 'N': + c.x++; c.y++; + when '*': + msg("Use h,j,k,l,y,u,b,n to position cursor, then hit return."); +#endif + } + c.y = max(c.y, 1); + c.y = min(c.y, lines - 3); + c.x = max(c.x, 0); + c.x = min(c.x, cols - 1); + wmove(cw, c.y, c.x); + draw(cw); + } +} + +/* + * set up the direction co_ordinate for use in various "prefix" commands + */ +bool +get_dir(direction) +coord *direction; +{ + register char *prompt; + register bool gotit; + int x,y; + + prompt = terse ? "Direction?" : "Which direction? "; + msg(prompt); + do + { + gotit = TRUE; + switch (md_readchar(msgw)) + { + case 'h': case'H': direction->y = 0; direction->x = -1; + when 'j': case'J': direction->y = 1; direction->x = 0; + when 'k': case'K': direction->y = -1; direction->x = 0; + when 'l': case'L': direction->y = 0; direction->x = 1; + when 'y': case'Y': direction->y = -1; direction->x = -1; + when 'u': case'U': direction->y = -1; direction->x = 1; + when 'b': case'B': direction->y = 1; direction->x = -1; + when 'n': case'N': direction->y = 1; direction->x = 1; + case 0: + when 3: quit(0); + return(FALSE); + when ESCAPE: return (FALSE); + otherwise: + mpos = 0; + msg(prompt); + gotit = FALSE; + } + } until (gotit); + if ((on(player, ISHUH) || on(player, ISDANCE)) && rnd(100) > 20) { + do + { + *direction = grid[rnd(9)]; + } while (direction->y == 0 && direction->x == 0); + } + else if (on(player, ISFLEE)) { + y = hero.y; + x = hero.x; + while (shoot_ok(winat(y, x))) { + y += direction->y; + x += direction->x; + } + if (isalpha(mvwinch(mw, y, x))) { + if (y == player.t_dest->y && x == player.t_dest->x) { + mpos = 0; + msg("You are too frightened to!"); + return(FALSE); + } + } + } + mpos = 0; + return TRUE; +} + +/* + * see if the object is one of the currently used items + */ +is_current(obj) +register struct object *obj; +{ + if (obj == NULL) + return FALSE; + if (obj == cur_armor || obj == cur_weapon || + obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] || + obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4] || + obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] || + obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4] || + obj == cur_misc[WEAR_BOOTS] || obj == cur_misc[WEAR_JEWEL] || + obj == cur_misc[WEAR_BRACERS] || obj == cur_misc[WEAR_CLOAK] || + obj == cur_misc[WEAR_GAUNTLET] || obj == cur_misc[WEAR_NECKLACE]) { + + return TRUE; + } + + /* Is it a "current" relic? */ + if (obj->o_type == RELIC) { + switch (obj->o_which) { + case MUSTY_DAGGER: + case EMORI_CLOAK: + case HEIL_ANKH: + case YENDOR_AMULET: + case STONEBONES_AMULET: + case HRUGGEK_MSTAR: + case AXE_AKLAD: + case YEENOGHU_FLAIL: + case SURTUR_RING: + if (cur_relic[obj->o_which]) return TRUE; + } + } + + return FALSE; +} + + +/* + * Look: + * A quick glance all around the player + */ + +look(wakeup, runend) +bool wakeup; /* Should we wake up monsters */ +bool runend; /* At end of a run -- for mazes */ +{ + register int x, y, radius; + register char ch, och; + register int oldx, oldy; + register bool inpass, horiz, vert, do_light = FALSE, do_blank = FALSE; + register int passcount = 0, curfloorcount = 0, nextfloorcount = 0; + register struct room *rp; + register int ey, ex; + + inpass = ((rp = roomin(&hero)) == NULL); /* Are we in a passage? */ + + /* Are we moving vertically or horizontally? */ + if (runch == 'h' || runch == 'l') horiz = TRUE; + else horiz = FALSE; + if (runch == 'j' || runch == 'k') vert = TRUE; + else vert = FALSE; + + /* How far around himself can the player see? */ + if (levtype == OUTSIDE) { + if (daytime) radius = 6; + else if (lit_room(rp)) radius = 3; + else radius = 1; + } + else radius = 1; + + getyx(cw, oldy, oldx); /* Save current position */ + + /* Blank out the floor around our last position and check for + * moving out of a corridor in a maze. + */ + if (levtype == OUTSIDE) do_blank = !daytime; + else if (oldrp != NULL && !lit_room(oldrp) && off(player, ISBLIND)) + do_blank = TRUE; + + /* Now move around the old position and blank things out */ + ey = player.t_oldpos.y + radius; + ex = player.t_oldpos.x + radius; + for (x = player.t_oldpos.x - radius; x <= ex; x++) + if (x >= 0 && x < cols) + for (y = player.t_oldpos.y - radius; y <= ey; y++) { + struct linked_list *it; + coord here; /* Current coordinate */ + char savech; /* Saves character in monster window */ + bool in_room; /* Are we in a room? */ + + if (y < 1 || y > lines - 3) continue; + + /* See what's there -- ignore monsters, just see what they're on */ + savech = CCHAR( mvwinch(mw, y, x) ); + waddch(mw, ' '); + ch = show(y, x); + mvwaddch(mw, y, x, savech); /* Restore monster */ + + /* + * If we have a monster that we can't see anymore, make sure + * that we can note that fact. + */ + if (isalpha(savech) && + (y < hero.y - radius || y > hero.y + radius || + x < hero.x - radius || x > hero.x + radius)) { + /* Find the monster */ + it = find_mons(y, x); + } + else it = NULL; + + /* Are we in a room? */ + here.y = y; + here.x = x; + in_room = (roomin(&here) != NULL); + + if ((do_blank || !in_room) && (y != hero.y || x != hero.x)) + switch (ch) { + case DOOR: + case SECRETDOOR: + case PASSAGE: + case STAIRS: + case TRAPDOOR: + case TELTRAP: + case BEARTRAP: + case SLEEPTRAP: + case ARROWTRAP: + case DARTTRAP: + case MAZETRAP: + case POOL: + case POST: + case '|': + case '-': + case WALL: + /* If there was a monster showing, make it disappear */ + if (isalpha(savech)) { + mvwaddch(cw, y, x, ch); + + /* + * If we found it (we should!), set it to + * the right character! + */ + if (it) (THINGPTR(it))->t_oldch = ch; + } + break; + when FLOOR: + case FOREST: + default: + mvwaddch(cw, y, x, in_room ? ' ' : PASSAGE); + + /* If we found a monster, set it to darkness! */ + if (it) (THINGPTR(it))->t_oldch = CCHAR( mvwinch(cw, y, x) ); + } + + /* Moving out of a corridor? */ + if (levtype == MAZELEV && !ce(hero, player.t_oldpos) && + !running && !isrock(ch) && /* Not running and not a wall */ + ((vert && x != player.t_oldpos.x && y==player.t_oldpos.y) || + (horiz && y != player.t_oldpos.y && x==player.t_oldpos.x))) + do_light = off(player, ISBLIND); + } + + /* Take care of unlighting a corridor */ + if (do_light && lit_room(rp)) light(&player.t_oldpos); + + /* Are we coming or going between a wall and a corridor in a maze? */ + och = show(player.t_oldpos.y, player.t_oldpos.x); + ch = show(hero.y, hero.x); + if (levtype == MAZELEV && + ((isrock(och) && !isrock(ch)) || (isrock(ch) && !isrock(och)))) { + do_light = off(player, ISBLIND); /* Light it up if not blind */ + + /* Unlight what we just saw */ + if (do_light && lit_room(&rooms[0])) light(&player.t_oldpos); + } + + /* Look around the player */ + ey = hero.y + radius; + ex = hero.x + radius; + for (x = hero.x - radius; x <= ex; x++) + if (x >= 0 && x < cols) for (y = hero.y - radius; y <= ey; y++) { + if (y < 1 || y >= lines - 2) + continue; + if (isalpha(mvwinch(mw, y, x))) + { + register struct linked_list *it; + register struct thing *tp; + + if (wakeup) + it = wake_monster(y, x); + else + it = find_mons(y, x); + + if (it) { + tp = THINGPTR(it); + tp->t_oldch = CCHAR( mvinch(y, x) ); + if (isatrap(tp->t_oldch)) { + register struct trap *trp = trap_at(y, x); + + tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch + : trp->tr_show; + } + if (tp->t_oldch == FLOOR && !lit_room(rp) && + off(player, ISBLIND)) + tp->t_oldch = ' '; + } + } + + /* + * Secret doors show as walls + */ + if ((ch = show(y, x)) == SECRETDOOR) + ch = secretdoor(y, x); + /* + * Don't show room walls if he is in a passage and + * check for maze turns + */ + if (off(player, ISBLIND)) + { + if (y == hero.y && x == hero.x + || (inpass && (ch == '-' || ch == '|'))) + continue; + + /* Did we come to a crossroads in a maze? */ + if (levtype == MAZELEV && + (runend || !ce(hero, player.t_oldpos)) && + !isrock(ch) && /* Not a wall */ + ((vert && x != hero.x && y == hero.y) || + (horiz && y != hero.y && x == hero.x))) + /* Just came to a turn */ + do_light = off(player, ISBLIND); + } + else if (y != hero.y || x != hero.x) + continue; + + wmove(cw, y, x); + waddch(cw, ch); + if (door_stop && !firstmove && running) + { + switch (runch) + { + case 'h': + if (x == hero.x + 1) + continue; + when 'j': + if (y == hero.y - 1) + continue; + when 'k': + if (y == hero.y + 1) + continue; + when 'l': + if (x == hero.x - 1) + continue; + when 'y': + if ((x + y) - (hero.x + hero.y) >= 1) + continue; + when 'u': + if ((y - x) - (hero.y - hero.x) >= 1) + continue; + when 'n': + if ((x + y) - (hero.x + hero.y) <= -1) + continue; + when 'b': + if ((y - x) - (hero.y - hero.x) <= -1) + continue; + } + switch (ch) + { + case DOOR: + if (x == hero.x || y == hero.y) + running = FALSE; + break; + case PASSAGE: + if (x == hero.x || y == hero.y) + passcount++; + break; + case FLOOR: + /* Stop by new passages in a maze (floor next to us) */ + if ((levtype == MAZELEV) && + !(hero.y == y && hero.x == x)) { + if (vert) { /* Moving vertically */ + /* We have a passage on our row */ + if (y == hero.y) curfloorcount++; + + /* Some passage on the next row */ + else if (y != player.t_oldpos.y) + nextfloorcount++; + } + else { /* Moving horizontally */ + /* We have a passage on our column */ + if (x == hero.x) curfloorcount++; + + /* Some passage in the next column */ + else if (x != player.t_oldpos.x) + nextfloorcount++; + } + } + case '|': + case '-': + case ' ': + break; + default: + running = FALSE; + break; + } + } + } + + /* Have we passed a side passage, with multiple choices? */ + if (curfloorcount > 0 && nextfloorcount > 0) running = FALSE; + + else if (door_stop && !firstmove && passcount > 1) + running = FALSE; + + /* Do we have to light up the area (just stepped into a new corridor)? */ + if (do_light && !running && lit_room(rp)) light(&hero); + + mvwaddch(cw, hero.y, hero.x, PLAYER); + wmove(cw, oldy, oldx); + if (!ce(player.t_oldpos, hero)) { + player.t_oldpos = hero; /* Don't change if we didn't move */ + oldrp = rp; + } +} + +/* + * Lower a level of experience + */ + +lower_level(who) +short who; +{ + int fewer, nsides; + unsigned int exp; + + msg("You suddenly feel less skillful."); + if (--pstats.s_lvl == 0) + death(who); /* All levels gone */ + if (pstats.s_lvladj > 0) { /* lose artificial levels first */ + pstats.s_lvladj--; + return; + } + exp = char_class[player.t_ctype].cap; + if (pstats.s_exp >= exp*2) + pstats.s_exp -= exp; + else + pstats.s_exp /= 2; + + nsides = char_class[player.t_ctype].hit_pts; + fewer = max(1, roll(1,nsides) + const_bonus()); + pstats.s_hpt -= fewer; + max_stats.s_hpt -= fewer; + if (pstats.s_hpt < 1) + pstats.s_hpt = 1; + if (max_stats.s_hpt < 1) + death(who); +} + +/* + * print out the name of a monster + */ +char * +monster_name(tp) +register struct thing *tp; +{ + prbuf[0] = '\0'; + if (on(*tp, ISFLEE) || on(*tp, WASTURNED)) + strcat(prbuf, "terrified "); + if (on(*tp, ISHUH)) + strcat(prbuf, "confused "); + if (on(*tp, ISCHARMED)) + strcat(prbuf, "charmed "); + else if (on(*tp, ISFLY)) + strcat(prbuf, "flying "); + + /* If it is sleeping or stoned, write over any of the above attributes */ + if (off(*tp, ISRUN)) + strcpy(prbuf, "sleeping "); + if (on(*tp, ISSTONE)) + strcpy(prbuf, "petrified "); + + if (tp->t_name) strcat(prbuf, tp->t_name); + else strcat(prbuf, monsters[tp->t_index].m_name); + + return(prbuf); +} + +/* + * move_hero: + * Try to move the hero somplace besides next to where he is. We ask him + * where. There can be restrictions based on why he is moving. + */ + +bool +move_hero(why) +int why; +{ + char *action; + char which; + coord c; + + switch (why) { + case H_TELEPORT: + action = "teleport"; + } + + msg("Where do you wish to %s to? (* for help) ", action); + c = get_coordinates(); + mpos = 0; + which = CCHAR( winat(c.y, c.x) ); + switch (which) { + default: + if (!isrock(which) || off(player, CANINWALL)) break; + + case FLOOR: + case PASSAGE: + case DOOR: + case STAIRS: + case POST: + case GOLD: + case POTION: + case SCROLL: + case FOOD: + case WEAPON: + case ARMOR: + case RING: + case MM: + case RELIC: + case STICK: + hero = c; + return(TRUE); + } + return(FALSE); +} + +/* + * raise_level: + * The guy just magically went up a level. + */ + +raise_level() +{ + unsigned long test; /* Next level -- be sure it is not an overflow */ + + test = check_level(); /* Get next boundary */ + + /* Be sure it is higher than what we have no -- else overflow */ + if (test > pstats.s_exp) pstats.s_exp = test; + check_level(); +} + +/* + * saving throw matrix for character saving throws + * this table is indexed by char type and saving throw type + */ +static int st_matrix[NUM_CHARTYPES][5] = { +/* Poison, Petrify, wand, Breath, Magic */ +{ 14, 15, 16, 16, 17 }, +{ 14, 15, 16, 16, 17 }, +{ 14, 15, 16, 16, 17 }, +{ 14, 13, 11, 15, 12 }, +{ 10, 13, 14, 16, 15 }, +{ 13, 12, 14, 16, 15 }, +{ 13, 12, 14, 16, 15 }, +{ 10, 13, 14, 16, 15 }, +{ 13, 12, 14, 16, 15 }, +{ 14, 15, 16, 16, 17 } +}; + +/* + * save: + * See if a creature saves against something + */ +save(which, who, adj) +int which; /* which type of save */ +struct thing *who; /* who is saving */ +int adj; /* saving throw adjustment */ +{ + register int need, level, protect; + + protect = 0; + level = who->t_stats.s_lvl; + need = st_matrix[who->t_ctype][which]; + switch (who->t_ctype) { + case C_FIGHTER: + case C_RANGER: + case C_PALADIN: + case C_MONSTER: + need -= (level-1) / 2; + when C_MAGICIAN: + need -= 2 * (level-1) / 5; + when C_CLERIC: + case C_DRUID: + need -= (level-1) / 3; + when C_THIEF: + case C_ASSASIN: + case C_MONK: + need -= 2 * (level-1) / 4; + } + /* + * add in pluses against poison for execeptional constitution + */ + if (which == VS_POISON && who->t_stats.s_const > 18) + need -= (who->t_stats.s_const - 17) / 2; + if (who == &player) { + /* + * does the player have a ring of protection on? + */ + protect += ring_value(R_PROTECT); + /* + * does the player have a cloak of protection on? + */ + if (cur_misc[WEAR_CLOAK]) + protect += cur_misc[WEAR_CLOAK]->o_ac; + + protect = min(protect, 4);/* no more than a +4 bonus */ + need -= protect; + } + need -= adj; + /* + * always miss or save on a 1 (except for UNIQUEs + */ + if (who == &player || off(*who, ISUNIQUE)) + need = max(need, 2); + need = min(20, need); /* always make our save on a 20 */ + debug("need a %d to save", need); + return (roll(1, 20) >= need); +} + + +/* + * secret_door: + * Figure out what a secret door looks like. + */ + +secretdoor(y, x) +register int y, x; +{ + register int i; + register struct room *rp; + register coord *cpp; + static coord cp; + + cp.y = y; + cp.x = x; + cpp = &cp; + for (rp = rooms, i = 0; i < MAXROOMS; rp++, i++) + if (inroom(rp, cpp)) + if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1) + return('-'); + else + return('|'); + + return('p'); +} + +/* + * this routine computes the players current strength + */ +str_compute() +{ + if (cur_misc[WEAR_GAUNTLET] != NULL && + cur_misc[WEAR_GAUNTLET]->o_which == MM_G_OGRE) { + if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED) + return (3); + else + return (18); + } + else + return (pstats.s_str); +} + +/* + * copy string using unctrl for things + */ +strucpy(s1, s2, len) +register char *s1, *s2; +register int len; +{ + register char *sp; + + while (len--) + { + strcpy(s1, (sp = unctrl(*s2++))); + s1 += strlen(sp); + } + *s1 = '\0'; +} + +/* + * tr_name: + * print the name of a trap + */ + +char * +tr_name(ch) +char ch; +{ + register char *s; + + switch (ch) + { + case TRAPDOOR: + s = terse ? "A trapdoor." : "You found a trapdoor."; + when BEARTRAP: + s = terse ? "A beartrap." : "You found a beartrap."; + when SLEEPTRAP: + s = terse ? "A sleeping gas trap.":"You found a sleeping gas trap."; + when ARROWTRAP: + s = terse ? "An arrow trap." : "You found an arrow trap."; + when TELTRAP: + s = terse ? "A teleport trap." : "You found a teleport trap."; + when DARTTRAP: + s = terse ? "A dart trap." : "You found a poison dart trap."; + when POOL: + s = terse ? "A shimmering pool." : "You found a shimmering pool"; + when MAZETRAP: + s = terse ? "A maze entrance." : "You found a maze entrance"; + } + return s; +} + +/* + * for printfs: if string starts with a vowel, return "n" for an "an" + */ +char * +vowelstr(str) +register char *str; +{ + switch (*str) + { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + return "n"; + default: + return ""; + } +} + +/* + * wake up a room full (hopefully) of creatures + */ +wake_room(rp) +register struct room *rp; +{ + register struct linked_list *item; + register struct thing *tp; + + for (item=mlist; item!=NULL; item=next(item)) { + tp = THINGPTR(item); + if (off(*tp,ISRUN) && on(*tp,ISMEAN) && roomin(&tp->t_pos) == rp) + runto(tp, &hero); + } +} + + +/* + * waste_time: + * Do nothing but let other things happen + */ + +waste_time() +{ + if (inwhgt) /* if from wghtchk then done */ + return; + do_daemons(BEFORE); + do_fuses(BEFORE); + do_daemons(AFTER); + do_fuses(AFTER); +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/vers.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/vers.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,24 @@ +/* + * vers.c - version number + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * version number. Whenever a new version number is desired, use + * sccs to get vers.c. Environ and encstr are declared here to + * force them to be loaded before the version number, and therefore + * not to be written in saved games. + */ + +char encstr[] = "\354\251\243\332A\201|\301\321p\210\251\327\"\257\365t\341%3\271^`~\203z{\341};\f\341\231\222e\234\351]\321\234"; +char version[] = "@(#)vers.c 7.7 (Bell Labs) 07/07/86"; +char *release = "7.7.1"; diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/weapons.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/weapons.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,403 @@ +/* + * weapons.c - Functions for dealing with problems brought about by weapons + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * Functions for dealing with problems brought about by weapons + * + */ + +#include "curses.h" +#include +#include +#include "rogue.h" + +boomerang(ydelta, xdelta, item, tp) +int ydelta, xdelta; +register struct linked_list *item; +register struct thing *tp; +{ + register struct object *obj; + struct thing midpoint; + coord oldpos; + + obj = OBJPTR(item); + oldpos = obj->o_pos; + + /* + * make it appear to fly at the target + */ + do_motion(obj, ydelta, xdelta, tp); + hit_monster(unc(obj->o_pos), obj, tp); + + /* + * Now let's make it fly back to the wielder. We need to + * use midpoint to fool do_motion into thinking the action + * starts there. Do_motion only looks at the t_pos field. + */ + midpoint.t_pos = obj->o_pos; /* Simulate a new start position */ + do_motion(obj, -ydelta, -xdelta, &midpoint); + + obj->o_pos = oldpos; +} + +/* + * do the actual motion on the screen done by an object traveling + * across the room. Note that we should not look at any field in + * tp other than t_pos unless we change boomerang(). + */ +do_motion(obj, ydelta, xdelta, tp) +register struct object *obj; +register int ydelta, xdelta; +register struct thing *tp; +{ + + /* + * Come fly with us ... + */ + obj->o_pos = tp->t_pos; + for (; ;) { + register int ch; + /* + * Erase the old one + */ + if (!ce(obj->o_pos, tp->t_pos) && + cansee(unc(obj->o_pos)) && + mvwinch(cw, obj->o_pos.y, obj->o_pos.x) != ' ') { + mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, show(obj->o_pos.y, obj->o_pos.x)); + } + /* + * Get the new position + */ + obj->o_pos.y += ydelta; + obj->o_pos.x += xdelta; + if (shoot_ok(ch = winat(obj->o_pos.y, obj->o_pos.x)) && ch != DOOR && !ce(obj->o_pos, hero)) { + /* + * It hasn't hit anything yet, so display it + * If it alright. + */ + if (cansee(unc(obj->o_pos)) && + mvwinch(cw, obj->o_pos.y, obj->o_pos.x) != ' ') { + mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, obj->o_type); + draw(cw); + } + continue; + } + + /* + * Did we stop because of a monster or the hero? If we did + * not, we want to move our position back one because we could + * not actually make it this far. + */ + if (!isalpha(ch) && + !(obj->o_pos.y == hero.y && obj->o_pos.x == hero.x)) { + obj->o_pos.y -= ydelta; + obj->o_pos.x -= xdelta; + } + + break; + } +} + + +/* + * fall: + * Drop an item someplace around here. + */ + +fall(item, pr) +register struct linked_list *item; +bool pr; +{ + register struct object *obj; + register struct room *rp; + register int i; + struct object *tobj; + struct linked_list *titem; + coord *fpos; + + obj = OBJPTR(item); + /* + * try to drop the item, look up to 3 squares away for now + */ + for (i=1; i<4; i++) { + if ((fpos = fallpos(&obj->o_pos, FALSE, i)) != NULL) + break; + } + + if (fpos != NULL) { + if (obj->o_group) { /* try to add groups together */ + for(titem=lvl_obj; titem!=NULL; titem=next(titem)) { + tobj = OBJPTR(titem); + if (tobj->o_group == obj->o_group && + tobj->o_pos.y == fpos->y && + tobj->o_pos.x == fpos->x) { + tobj->o_count += obj->o_count; + o_discard(item); + return; + } + } + } + mvaddch(fpos->y, fpos->x, obj->o_type); + obj->o_pos = *fpos; + if ((rp = roomin(&hero)) != NULL && + lit_room(rp)) { + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + } + attach(lvl_obj, item); + return; + } + if (pr) { + msg("The %s vanishes as it hits the ground.", + weaps[obj->o_which].w_name); + } + o_discard(item); +} + + +/* + * Does the missile hit the monster + */ + +hit_monster(y, x, obj, tp) +register int y, x; +struct object *obj; +register struct thing *tp; +{ + static coord mp; + + mp.y = y; + mp.x = x; + if (tp == &player) { + /* Make sure there is a monster where it landed */ + if (!isalpha(mvwinch(mw, y, x))) { + return(FALSE); + } + + /* Player hits monster */ + return(fight(&mp, obj, TRUE)); + } else { + if (!ce(mp, hero)) { + /* Monster hits monster */ + return(skirmish(tp, &mp, obj, TRUE)); + } + + /* Monster hits player */ + return(attack(tp, obj, TRUE)); + } +} + +/* + * init_weapon: + * Set up the initial goodies for a weapon + */ + +init_weapon(weap, type) +register struct object *weap; +char type; +{ + register struct init_weps *iwp; + + iwp = &weaps[type]; + strncpy(weap->o_damage, iwp->w_dam, sizeof(weap->o_damage)); + strncpy(weap->o_hurldmg, iwp->w_hrl, sizeof(weap->o_hurldmg)); + weap->o_launch = iwp->w_launch; + weap->o_flags = iwp->w_flags; + weap->o_weight = iwp->w_wght; + if (weap->o_flags & ISMANY) { + weap->o_count = rnd(8) + 8; + weap->o_group = newgrp(); + } else { + weap->o_count = 1; + } +} + +/* + * missile: + * Fire a missile in a given direction + */ + +missile(ydelta, xdelta, item, tp) +int ydelta, xdelta; +register struct linked_list *item; +register struct thing *tp; +{ + register struct object *obj; + register struct linked_list *nitem; + char ch; + + /* + * Get which thing we are hurling + */ + if (item == NULL) { + return; + } + obj = OBJPTR(item); + if (obj->o_type == RELIC && obj->o_which == AXE_AKLAD) { + boomerang(ydelta, xdelta, item, tp); + return; + } + + if (!dropcheck(obj)) return; /* Can we get rid of it? */ + + if(!(obj->o_flags & ISMISL)) { + while (TRUE) { + msg(terse ? "Really throw? (y or n): " + : "Do you really want to throw %s? (y or n): ", + inv_name(obj, TRUE)); + mpos = 0; + ch = readchar(); + if (ch == 'n' || ch == ESCAPE) { + after = FALSE; + return; + } + if (ch == 'y') + break; + } + } + /* + * Get rid of the thing. If it is a non-multiple item object, or + * if it is the last thing, just drop it. Otherwise, create a new + * item with a count of one. + */ + if (obj->o_count < 2) { + detach(tp->t_pack, item); + if (tp->t_pack == pack) { + inpack--; + } + } + else { + obj->o_count--; + nitem = (struct linked_list *) new_item(sizeof *obj); + obj = OBJPTR(nitem); + *obj = *(OBJPTR(item)); + obj->o_count = 1; + item = nitem; + } + updpack(FALSE, tp); + do_motion(obj, ydelta, xdelta, tp); + /* + * AHA! Here it has hit something. If it is a wall or a door, + * or if it misses (combat) the monster, put it on the floor + */ + if (!hit_monster(unc(obj->o_pos), obj, tp)) { + fall(item, TRUE); + } + mvwaddch(cw, hero.y, hero.x, PLAYER); +} + +/* + * num: + * Figure out the plus number for armor/weapons + */ + +char * +num(n1, n2) +register int n1, n2; +{ + static char numbuf[LINELEN]; + + if (n1 == 0 && n2 == 0) { + return "+0"; + } + if (n2 == 0) { + sprintf(numbuf, "%s%d", n1 < 0 ? "" : "+", n1); + } else { + sprintf(numbuf, "%s%d, %s%d", n1 < 0 ? "" : "+", n1, n2 < 0 ? "" : "+", n2); + } + return(numbuf); +} + +/* + * wield: + * Pull out a certain weapon + */ + +wield() +{ + register struct linked_list *item; + register struct object *obj, *oweapon; + + /* + * It takes 2 movement periods to unwield a weapon and 2 movement + * periods to wield a weapon. + */ + if (player.t_action != C_WIELD) { + player.t_action = C_WIELD; + player.t_using = NULL; /* Make sure this is NULL! */ + if (cur_weapon != NULL) { + player.t_no_move = 2 * movement(&player); + return; + } + } + + if ((oweapon = cur_weapon) != NULL) { + /* At this point we have waited at least 2 units */ + if (!dropcheck(cur_weapon)) { + cur_weapon = oweapon; + player.t_action = A_NIL; + return; + } + if (terse) + addmsg("Was "); + else + addmsg("You were "); + msg("wielding %s", inv_name(oweapon, TRUE)); + } + + /* We we have something picked out? */ + if (player.t_using == NULL) { + /* Now, what does he want to wield? */ + if ((item = get_item(pack, "wield", WIELDABLE, FALSE, FALSE)) == NULL) { + player.t_action = A_NIL; + after = FALSE; + return; + } + player.t_using = item; + player.t_no_move = 2 * movement(&player); + return; + } + + /* We have waited our time, let's wield the weapon */ + item = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + obj = OBJPTR(item); + + if (is_current(obj)) { + msg("Item in use."); + after = FALSE; + return; + } + if (player.t_ctype != C_FIGHTER && + player.t_ctype != C_RANGER && + player.t_ctype != C_PALADIN && + obj->o_type == WEAPON && + (obj->o_which == TWOSWORD || + (obj->o_which == BASWORD && + player.t_ctype != C_ASSASIN))) { + msg("Only fighter types can wield a %s", + weaps[obj->o_which].w_name); + return; + } + if (terse) { + addmsg("W"); + } else { + addmsg("You are now w"); + } + msg("ielding %s", inv_name(obj, TRUE)); + cur_weapon = obj; +} + diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/wear.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/wear.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,432 @@ +/* + * wear.c - functions for dealing with armor + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 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. + */ + +/* + * This file contains misc functions for dealing with armor + */ + +#include +#include "curses.h" +#include "rogue.h" + + +/* + * take_off: + * Get the armor off of the players back + */ + +take_off() +{ + register struct object *obj; + register struct linked_list *item; + + /* It takes time to take things off */ + if (player.t_action != C_TAKEOFF) { + /* What does player want to take off? */ + if ((item = get_item(pack, "take off", REMOVABLE, FALSE, FALSE))==NULL) + return; + + obj = OBJPTR(item); + if (!is_current(obj)) { + msg("Not wearing %c) %s", pack_char(pack, obj),inv_name(obj, TRUE)); + return; + } + + player.t_using = item; /* Remember what it is */ + player.t_action = C_TAKEOFF; /* We are taking something off */ + + /* Cursed items take almost no time */ + if (obj->o_flags & ISCURSED) player.t_no_move = movement(&player); + else player.t_no_move = dress_units(item) * movement(&player); + return; + } + + /* We have waited our time, let's take off our item */ + item = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + obj = OBJPTR(item); + if (!is_current(obj)) { /* Just to be on the safe side */ + msg("Not wearing %c) %s", pack_char(pack, obj),inv_name(obj, TRUE)); + return; + } + + /* Can the player remove the item? */ + if (!dropcheck(obj)) return; + updpack(TRUE, &player); + + msg("Was wearing %c) %s", pack_char(pack, obj),inv_name(obj,TRUE)); +} + +/* + * wear: + * The player wants to wear something, so let him/her put it on. + */ + +wear() +{ + register struct linked_list *item; + register struct object *obj; + register int i; + + /* It takes time to put things on */ + if (player.t_action != C_WEAR) { + /* What does player want to wear? */ + if ((item = get_item(pack, "wear", WEARABLE, FALSE, FALSE)) == NULL) + return; + + obj = OBJPTR(item); + + switch (obj->o_type) { + case ARMOR: + if (cur_armor != NULL) { + addmsg("You are already wearing armor"); + if (!terse) addmsg(". You'll have to take it off first."); + endmsg(); + after = FALSE; + return; + } + if (player.t_ctype == C_MONK) { + msg("Monks can't wear armor!"); + return; + } + if (cur_misc[WEAR_BRACERS] != NULL) { + msg("You can't wear armor with bracers of defense."); + return; + } + if (cur_misc[WEAR_CLOAK] != NULL || cur_relic[EMORI_CLOAK]) { + msg("You can't wear armor with a cloak."); + return; + } + if (player.t_ctype == C_THIEF && + (obj->o_which != LEATHER && + obj->o_which != STUDDED_LEATHER)) { + if (terse) msg("Thieves can't wear that type of armor"); + else + msg("Thieves can only wear leather or studded leather armor"); + return; + } + if (player.t_ctype == C_ASSASIN && + (obj->o_which != LEATHER && + obj->o_which != STUDDED_LEATHER)) { + if (terse) msg("Assassins can't wear that type of armor"); + else + msg("Assassins can only wear leather or studded leather armor"); + return; + } + + when MM: + switch (obj->o_which) { + /* + * when wearing the boots of elvenkind the player will not + * set off any traps + */ + case MM_ELF_BOOTS: + if (cur_misc[WEAR_BOOTS] != NULL) { + msg("Already wearing a pair of boots"); + return; + } + /* + * when wearing the boots of dancing the player will dance + * uncontrollably + */ + when MM_DANCE: + if (cur_misc[WEAR_BOOTS] != NULL) { + msg("Already wearing a pair of boots"); + return; + } + /* + * bracers give the hero protection in he same way armor does. + * they cannot be used with armor but can be used with cloaks + */ + when MM_BRACERS: + if (cur_misc[WEAR_BRACERS] != NULL) { + msg("Already wearing bracers"); + return; + } + else { + if (cur_armor != NULL) { + msg("You can't wear bracers of defense with armor."); + return; + } + } + + /* + * The robe (cloak) of powerlessness disallows any spell casting + */ + when MM_R_POWERLESS: + /* + * the cloak of displacement gives the hero an extra +2 on AC + * and saving throws. Cloaks cannot be used with armor. + */ + case MM_DISP: + /* + * the cloak of protection gives the hero +n on AC and saving + * throws with a max of +3 on saves + */ + case MM_PROTECT: + if (cur_misc[WEAR_CLOAK] != NULL || + cur_relic[EMORI_CLOAK]) { + msg("%slready wearing a cloak.", terse ? "A" + : "You are a"); + return; + } + else { + if (cur_armor != NULL) { + msg("You can't wear a cloak with armor."); + return; + } + } + /* + * the gauntlets of dexterity give the hero a dexterity of 18 + * the gauntlets of ogre power give the hero a strength of 18 + * the gauntlets of fumbling cause the hero to drop his weapon + */ + when MM_G_DEXTERITY: + case MM_G_OGRE: + case MM_FUMBLE: + if (cur_misc[WEAR_GAUNTLET] != NULL) { + msg("Already wearing a pair of gauntlets."); + return; + } + /* + * the jewel of attacks does an aggavate monster + */ + when MM_JEWEL: + if (cur_misc[WEAR_JEWEL] != NULL || + cur_relic[YENDOR_AMULET] || + cur_relic[STONEBONES_AMULET]) { + msg("Already wearing an amulet."); + return; + } + /* + * the necklace of adaption makes the hero immune to + * chlorine gas + */ + when MM_ADAPTION: + if (cur_misc[WEAR_NECKLACE] != NULL) { + msg("Already wearing a necklace"); + return; + } + /* + * the necklace of stragulation will try to strangle the + * hero to death + */ + when MM_STRANGLE: + if (cur_misc[WEAR_NECKLACE] != NULL) { + msg("Already wearing a necklace"); + return; + } + otherwise: + msg("what a strange item you have!"); + return; + } + + when RING: + if (cur_misc[WEAR_GAUNTLET] != NULL) { + msg ("You have to remove your gauntlets first!"); + return; + } + + /* Is there room to put the ring on */ + for (i=0; io_type) { + case ARMOR: + obj->o_flags |= ISKNOW; + cur_armor = obj; + addmsg(terse ? "W" : "You are now w"); + msg("earing %s.", armors[obj->o_which].a_name); + + when MM: + switch (obj->o_which) { + /* + * when wearing the boots of elvenkind the player will not + * set off any traps + */ + case MM_ELF_BOOTS: + msg("Wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_BOOTS] = obj; + /* + * when wearing the boots of dancing the player will dance + * uncontrollably + */ + when MM_DANCE: + msg("Wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_BOOTS] = obj; + msg("You begin to dance uncontrollably!"); + turn_on(player, ISDANCE); + /* + * bracers give the hero protection in he same way armor does. + * they cannot be used with armor but can be used with cloaks + */ + when MM_BRACERS: + msg("wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_BRACERS] = obj; + + /* + * The robe (cloak) of powerlessness disallows any spell casting + */ + when MM_R_POWERLESS: + /* + * the cloak of displacement gives the hero an extra +2 on AC + * and saving throws. Cloaks cannot be used with armor. + */ + case MM_DISP: + /* + * the cloak of protection gives the hero +n on AC and saving + * throws with a max of +3 on saves + */ + case MM_PROTECT: + msg("wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_CLOAK] = obj; + /* + * the gauntlets of dexterity give the hero a dexterity of 18 + * the gauntlets of ogre power give the hero a strength of 18 + * the gauntlets of fumbling cause the hero to drop his weapon + */ + when MM_G_DEXTERITY: + case MM_G_OGRE: + case MM_FUMBLE: + msg("Wearing %s", inv_name(obj,TRUE)); + cur_misc[WEAR_GAUNTLET] = obj; + if (obj->o_which == MM_FUMBLE) + daemon(fumble, 0, AFTER); + /* + * the jewel of attacks does an aggavate monster + */ + when MM_JEWEL: + msg("Wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_JEWEL] = obj; + aggravate(TRUE, TRUE); + /* + * the necklace of adaption makes the hero immune to + * chlorine gas + */ + when MM_ADAPTION: + msg("Wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_NECKLACE] = obj; + turn_on(player, NOGAS); + /* + * the necklace of stragulation will try to strangle the + * hero to death + */ + when MM_STRANGLE: + msg("Wearing %s",inv_name(obj,TRUE)); + cur_misc[WEAR_NECKLACE] = obj; + msg("The necklace is beginning to strangle you!"); + daemon(strangle, 0, AFTER); + otherwise: + msg("What a strange item you have!"); + } + status(FALSE); + if (m_know[obj->o_which] && m_guess[obj->o_which]) { + free(m_guess[obj->o_which]); + m_guess[obj->o_which] = NULL; + } + else if (!m_know[obj->o_which] && + askme && + (obj->o_flags & ISKNOW) == 0 && + m_guess[obj->o_which] == NULL) { + nameitem(item, FALSE); + } + + when RING: + /* If there is room, put on the ring */ + for (i=0; io_type) { + case ARMOR: + return(10-armors[obj->o_which].a_class); + when RING: + return(2); + when MM: + switch (obj->o_which) { + case MM_ELF_BOOTS: + case MM_DANCE: + /* Boots */ + return(4); + when MM_R_POWERLESS: + case MM_DISP: + case MM_PROTECT: + /* Robes */ + return(4); + when MM_BRACERS: + case MM_G_DEXTERITY: + case MM_G_OGRE: + case MM_FUMBLE: + /* Hand garments */ + return(3); + when MM_JEWEL: + case MM_ADAPTION: + case MM_STRANGLE: + /* Jewelry */ + return(2); + otherwise: + return(1); /* What is it? */ + } + otherwise: + return(1); /* What is it? */ + } +} diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/wizard.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/wizard.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,697 @@ +/* + * wizard.c - Special wizard commands + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +/* + * Special wizard commands (some of which are also non-wizard commands + * under strange circumstances) + */ + +#include "curses.h" +#include +#include +#include "rogue.h" +#ifdef PC7300 +#include "menu.h" +#endif + + +/* + * create_obj: + * Create any object for wizard, scroll, magician, or cleric + */ +create_obj(prompt, which_item, which_type) +bool prompt; +int which_item, which_type; +{ + reg struct linked_list *item; + reg struct object *obj; + reg int wh; + reg char ch, newitem, newtype, whc, msz, *pt; + WINDOW *thiswin; + + thiswin = cw; + if (prompt) { + bool nogood = TRUE; + + thiswin = hw; + wclear(hw); + wprintw(hw,"Item\t\t\tKey\n\n"); + wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_RING].mi_name,RING, + things[TYP_STICK].mi_name,STICK); + wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_POTION].mi_name,POTION, + things[TYP_SCROLL].mi_name,SCROLL); + wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_ARMOR].mi_name,ARMOR, + things[TYP_WEAPON].mi_name,WEAPON); + wprintw(hw,"%s\t%c\n",things[TYP_MM].mi_name,MM); + wprintw(hw,"%s\t\t\t%c\n",things[TYP_FOOD].mi_name,FOOD); + if (wizard) { + wprintw(hw,"%s\t\t%c\n",things[TYP_RELIC].mi_name,RELIC); + waddstr(hw,"monster\t\t\tm"); + } + wprintw(hw,"\n\nWhat do you want to create? "); + draw(hw); + do { + ch = wgetch(hw); + if (ch == ESCAPE) { + restscr(cw); + return; + } + switch (ch) { + case RING: + case STICK: + case POTION: + case SCROLL: + case ARMOR: + case WEAPON: + case FOOD: + case MM: + nogood = FALSE; + break; + case RELIC: + case 'm': + if (wizard) + nogood = FALSE; + break; + default: + nogood = TRUE; + } + } while (nogood); + newitem = ch; + } + else + newitem = which_item; + + pt = "those"; + msz = 0; + if(newitem == 'm') { + /* make monster and be done with it */ + wh = makemonster(TRUE, "Creation", "create"); + if (wh > 0) { + creat_mons (&player, wh, TRUE); + light(&hero); + } + return; + } + if(newitem == GOLD) + pt = "gold"; + /* else if(isatrap(newitem)) + pt = "traps"; + */ + switch(newitem) { + case POTION: whc = TYP_POTION; msz = MAXPOTIONS; + when SCROLL: whc = TYP_SCROLL; msz = MAXSCROLLS; + when WEAPON: whc = TYP_WEAPON; msz = MAXWEAPONS; + when ARMOR: whc = TYP_ARMOR; msz = MAXARMORS; + when RING: whc = TYP_RING; msz = MAXRINGS; + when STICK: whc = TYP_STICK; msz = MAXSTICKS; + when MM: whc = TYP_MM; msz = MAXMM; + when RELIC: whc = TYP_RELIC; msz = MAXRELIC; + when FOOD: whc = TYP_FOOD; msz = MAXFOODS; + otherwise: + if (thiswin == hw) + restscr(cw); + mpos = 0; + msg("Even wizards can't create %s !!",pt); + return; + } + if(msz == 1) { /* if only one type of item */ + ch = 'a'; + } + else if (prompt) { + register struct magic_item *wmi; + char wmn; + register int ii; + int old_prob; + + mpos = 0; + wmi = NULL; + wmn = 0; + switch(newitem) { + case POTION: wmi = &p_magic[0]; + when SCROLL: wmi = &s_magic[0]; + when RING: wmi = &r_magic[0]; + when STICK: wmi = &ws_magic[0]; + when MM: wmi = &m_magic[0]; + when RELIC: wmi = &rel_magic[0]; + when FOOD: wmi = &foods[0]; + when WEAPON: wmn = 1; + when ARMOR: wmn = 2; + } + wclear(hw); + thiswin = hw; + if (wmi != NULL) { + ii = old_prob = 0; + while (ii < msz) { + if(wmi->mi_prob == old_prob && wizard == FALSE) { + msz--; /* can't make a unique item */ + } + else { + mvwaddch(hw,ii % 13,ii > 12 ? cols/2 : 0, ii + 'a'); + waddstr(hw,") "); + waddstr(hw,wmi->mi_name); + ii++; + } + old_prob = wmi->mi_prob; + wmi++; + } + } + else if (wmn != 0) { + for(ii = 0 ; ii < msz ; ii++) { + mvwaddch(hw,ii % 13,ii > 12 ? cols/2 : 0, ii + 'a'); + waddstr(hw,") "); + if(wmn == 1) + waddstr(hw,weaps[ii].w_name); + else + waddstr(hw,armors[ii].a_name); + } + } + sprintf(prbuf,"Which %s? ",things[whc].mi_name); + mvwaddstr(hw,lines - 1, 0, prbuf); + draw(hw); + do { + ch = wgetch(hw); + if (ch == ESCAPE) { + restscr(cw); + msg(""); + return; + } + } until (isalpha(ch)); + if (thiswin == hw) /* restore screen if need be */ + restscr(cw); + newtype = tolower(ch) - 'a'; + if(newtype < 0 || newtype >= msz) { /* if an illegal value */ + mpos = 0; + msg("There is no such %s",things[whc].mi_name); + return; + } + } + else + newtype = which_type; + item = new_item(sizeof *obj); /* get some memory */ + obj = OBJPTR(item); + obj->o_type = newitem; /* store the new items */ + obj->o_mark[0] = '\0'; + obj->o_which = newtype; + obj->o_group = 0; + obj->contents = NULL; + obj->o_count = 1; + obj->o_flags = 0; + obj->o_dplus = obj->o_hplus = 0; + obj->o_weight = 0; + wh = obj->o_which; + mpos = 0; + if (!wizard) /* users get 0 to +3 */ + whc = rnd(4); + else /* wizard gets to choose */ + whc = getbless(); + if (whc < 0) + obj->o_flags |= ISCURSED; + switch (obj->o_type) { + case WEAPON: + case ARMOR: + if (obj->o_type == WEAPON) { + init_weapon(obj, wh); + obj->o_hplus += whc; + obj->o_dplus += whc; + } + else { /* armor here */ + obj->o_weight = armors[wh].a_wght; + obj->o_ac = armors[wh].a_class - whc; + } + when RING: + if (whc > 1 && r_magic[wh].mi_bless != 0) + obj->o_flags |= ISBLESSED; + r_know[wh] = TRUE; + switch(wh) { + case R_ADDSTR: + case R_ADDWISDOM: + case R_ADDINTEL: + case R_PROTECT: + case R_ADDHIT: + case R_ADDDAM: + case R_DIGEST: + obj->o_ac = whc + 1; + break; + default: + obj->o_ac = 0; + } + obj->o_weight = things[TYP_RING].mi_wght; + when MM: + if (whc > 1 && m_magic[wh].mi_bless != 0) + obj->o_flags |= ISBLESSED; + m_know[wh] = TRUE; + switch(wh) { + case MM_JUG: + switch(rnd(11)) { + case 0: obj->o_ac = P_PHASE; + when 1: obj->o_ac = P_CLEAR; + when 2: obj->o_ac = P_SEEINVIS; + when 3: obj->o_ac = P_HEALING; + when 4: obj->o_ac = P_MFIND; + when 5: obj->o_ac = P_TFIND; + when 6: obj->o_ac = P_HASTE; + when 7: obj->o_ac = P_RESTORE; + when 8: obj->o_ac = P_FLY; + when 9: obj->o_ac = P_SKILL; + when 10:obj->o_ac = P_FFIND; + } + when MM_OPEN: + case MM_HUNGER: + case MM_DRUMS: + case MM_DISAPPEAR: + case MM_CHOKE: + case MM_KEOGHTOM: + if (whc < 0) + whc = -whc; /* these cannot be negative */ + obj->o_ac = (whc + 1) * 5; + break; + when MM_BRACERS: + obj->o_ac = whc * 2 + 1; + when MM_DISP: + obj->o_ac = 2; + when MM_PROTECT: + obj->o_ac = whc; + when MM_SKILLS: + if (wizard && whc != 0) + obj->o_ac = rnd(NUM_CHARTYPES-1); + else + obj->o_ac = player.t_ctype; + otherwise: + obj->o_ac = 0; + } + obj->o_weight = things[TYP_MM].mi_wght; + when STICK: + if (whc > 1 && ws_magic[wh].mi_bless != 0) + obj->o_flags |= ISBLESSED; + ws_know[wh] = TRUE; + fix_stick(obj); + when SCROLL: + if (whc > 1 && s_magic[wh].mi_bless != 0) + obj->o_flags |= ISBLESSED; + obj->o_weight = things[TYP_SCROLL].mi_wght; + s_know[wh] = TRUE; + when POTION: + if (whc > 1 && p_magic[wh].mi_bless != 0) + obj->o_flags |= ISBLESSED; + obj->o_weight = things[TYP_POTION].mi_wght; + if (wh == P_ABIL) obj->o_kind = rnd(NUMABILITIES); + p_know[wh] = TRUE; + when RELIC: + obj->o_weight = things[TYP_RELIC].mi_wght; + switch (obj->o_which) { + case QUILL_NAGROM: obj->o_charges = QUILLCHARGES; + when EMORI_CLOAK: obj->o_charges = 1; + otherwise: break; + } + when FOOD: + obj->o_weight = things[TYP_FOOD].mi_wght; + } + mpos = 0; + obj->o_flags |= ISKNOW; + if (add_pack(item, FALSE, NULL) == FALSE) { + obj->o_pos = hero; + fall(item, TRUE); + } +} + +/* + * getbless: + * Get a blessing for a wizards object + */ +getbless() +{ + reg char bless; + + msg("Blessing? (+,-,n)"); + bless = wgetch(msgw); + if (bless == '+') + return (rnd(3) + 2); + else if (bless == '-') + return (-rnd(3) - 1); + else + return (0); +} + +/* + * get a non-monster death type + */ +getdeath() +{ + register int i; + int which_death; + char label[80]; + + clear(); + for (i=0; i DEATHNUM)) { + mvaddstr(0, 0, "Please enter a number in the displayed range -- "); + refresh(); + } + else break; + } + return(deaths[which_death-1].reason); +} + +#ifdef PC7300 +static menu_t Display; /* The menu structure */ +static mitem_t Dispitems[NUMMONST+1]; /* Info for each line */ +static char Displines[NUMMONST+1][LINELEN+1]; /* The lines themselves */ +#endif + +/* + * make a monster for the wizard + */ +makemonster(showall, label, action) +bool showall; /* showall -> show uniques and genocided creatures */ +char *label, *action; +{ +#ifdef PC7300 + register int nextmonst; +#endif + register int i; + register short which_monst; + register int num_monst = NUMMONST, pres_monst=1, num_lines=2*(lines-3); + int max_monster; + char monst_name[40]; + + /* If we're not showing all, subtract out the UNIQUES and quartermaster */ + if (!showall) num_monst -= NUMUNIQUE + 1; + max_monster = num_monst; + +#ifdef PC7300 + nextmonst = 0; + for (i=1; i<=num_monst; i++) { + /* Only display existing monsters if we're not showing them all */ + if (showall || monsters[i].m_normal) { + strcpy(Displines[nextmonst], monsters[i]); + Dispitems[nextmonst].mi_name = Displines[nextmonst]; + Dispitems[nextmonst].mi_flags = 0; + Dispitems[nextmonst++].mi_val = i; + } + } + + /* Place an end marker for the items */ + Dispitems[nextmonst].mi_name = 0; + + /* Set up the main menu structure */ + Display.m_label = label; + Display.m_title = "Monster Listing"; + Display.m_prompt = "Select a monster or press Cancl."; + Display.m_curptr = '\0'; + Display.m_markptr = '\0'; + Display.m_flags = 0; + Display.m_selcnt = 1; + Display.m_items = Dispitems; + Display.m_curi = 0; + + /* + * Try to display the menu. If we don't have a local terminal, + * the call will fail and we will just continue with the + * normal mode. + */ + if (menu(&Display) >= 0) { + restscr(cw); + touchwin(cw); + return(Display.m_selcnt == 1 ? Display.m_curi->mi_val : -1); + } +#endif + + /* Print out the monsters */ + while (num_monst > 0) { + register left_limit; + + if (num_monst < num_lines) left_limit = (num_monst+1)/2; + else left_limit = num_lines/2; + + wclear(hw); + touchwin(hw); + + /* Print left column */ + wmove(hw, 2, 0); + for (i=0; i 0) { + mvwaddstr(hw, lines-1, 0, morestr); + draw(hw); + wait_for(' '); + } + + else { + mvwaddstr(hw, 0, 0, "Which monster"); + if (!terse) { + waddstr(hw, " do you wish to "); + waddstr(hw, action); + } + waddstr(hw, "? "); + draw(hw); + } + } + +get_monst: + get_str(monst_name, hw); + which_monst = atoi(monst_name); + if ((which_monst < 1 || which_monst > max_monster)) { + mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- "); + draw(hw); + goto get_monst; + } + restscr(cw); + touchwin(cw); + return(which_monst); +} + +/* + * passwd: + * see if user knows password + */ + +passwd() +{ + register char *sp, c; + char buf[LINELEN], *crypt(); + + msg("Wizard's Password:"); + mpos = 0; + sp = buf; + while ((c = readchar()) != '\n' && c != '\r' && c != '\033') + if (c == md_killchar()) + sp = buf; + else if (c == md_erasechar() && sp > buf) + sp--; + else + *sp++ = c; + if (sp == buf) + return FALSE; + *sp = '\0'; + return (strcmp(PASSWD, md_crypt(buf, "mT")) == 0); +} + + +/* + * teleport: + * Bamf the hero someplace else + */ + +teleport() +{ + register struct room *new_rp, *old_rp = roomin(&hero); + register int rm, which; + coord old; + bool got_position = FALSE; + + /* Disrupt whatever the hero was doing */ + dsrpt_player(); + + /* + * If the hero wasn't doing something disruptable, NULL out his + * action anyway and let him know about it. We don't want him + * swinging or moving into his old place. + */ + if (player.t_action != A_NIL) { + player.t_action = A_NIL; + msg("You feel momentarily disoriented."); + } + + old = hero; + mvwaddch(cw, hero.y, hero.x, mvwinch(stdscr, hero.y, hero.x)); + if (ISWEARING(R_TELCONTROL) || wizard) { + got_position = move_hero(H_TELEPORT); + if (!got_position) + msg("Your attempt fails."); + else { + new_rp = roomin(&hero); + msg("You teleport successfully."); + } + } + if (!got_position) { + do { + rm = rnd_room(); + rnd_pos(&rooms[rm], &hero); + } until(winat(hero.y, hero.x) == FLOOR); + new_rp = &rooms[rm]; + } + player.t_oldpos = old; /* Save last position */ + + /* If hero gets moved, darken old room */ + if (old_rp && old_rp != new_rp) { + old_rp->r_flags |= FORCEDARK; /* Fake darkness */ + light(&old); + old_rp->r_flags &= ~FORCEDARK; /* Restore light state */ + } + + /* Darken where we just came from */ + else if (levtype == MAZELEV) light(&old); + + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + /* if entering a treasure room, wake everyone up......Surprise! */ + if (new_rp->r_flags & ISTREAS) + wake_room(new_rp); + + /* Reset current room and position */ + oldrp = new_rp; /* Used in look() */ + player.t_oldpos = hero; + /* + * make sure we set/unset the ISINWALL on a teleport + */ + which = winat(hero.y, hero.x); + if (isrock(which)) turn_on(player, ISINWALL); + else turn_off(player, ISINWALL); + + /* + * turn off ISHELD in case teleportation was done while fighting + * something that holds you + */ + if (on(player, ISHELD)) { + register struct linked_list *ip, *nip; + register struct thing *mp; + + turn_off(player, ISHELD); + hold_count = 0; + for (ip = mlist; ip; ip = nip) { + mp = THINGPTR(ip); + nip = next(ip); + if (on(*mp, DIDHOLD)) { + turn_off(*mp, DIDHOLD); + turn_on(*mp, CANHOLD); + } + turn_off(*mp, DIDSUFFOCATE); /* Suffocation -- see below */ + } + } + + /* Make sure player does not suffocate */ + extinguish(suffocate); + + count = 0; + running = FALSE; + md_flushinp(); + return rm; +} + +/* + * whatis: + * What a certin object is + */ + +whatis(what) +struct linked_list *what; +{ + register struct object *obj; + register struct linked_list *item; + + if (what == NULL) { /* do we need to ask which one? */ + if ((item = get_item(pack, "identify", IDENTABLE, FALSE, FALSE))==NULL) + return; + } + else + item = what; + obj = OBJPTR(item); + switch (obj->o_type) { + case SCROLL: + s_know[obj->o_which] = TRUE; + if (s_guess[obj->o_which]) { + free(s_guess[obj->o_which]); + s_guess[obj->o_which] = NULL; + } + when POTION: + p_know[obj->o_which] = TRUE; + if (p_guess[obj->o_which]) { + free(p_guess[obj->o_which]); + p_guess[obj->o_which] = NULL; + } + when STICK: + ws_know[obj->o_which] = TRUE; + if (ws_guess[obj->o_which]) { + free(ws_guess[obj->o_which]); + ws_guess[obj->o_which] = NULL; + } + when RING: + r_know[obj->o_which] = TRUE; + if (r_guess[obj->o_which]) { + free(r_guess[obj->o_which]); + r_guess[obj->o_which] = NULL; + } + when MM: + /* If it's an identified jug, identify its potion */ + if (obj->o_which == MM_JUG && (obj->o_flags & ISKNOW)) { + if (obj->o_ac != JUG_EMPTY) + p_know[obj->o_ac] = TRUE; + break; + } + + m_know[obj->o_which] = TRUE; + if (m_guess[obj->o_which]) { + free(m_guess[obj->o_which]); + m_guess[obj->o_which] = NULL; + } + otherwise: + break; + } + obj->o_flags |= ISKNOW; + if (what == NULL) + msg(inv_name(obj, FALSE)); +} + diff -r cc5148bdf345 -r 6b5fbd7c3ece arogue7/xcrypt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/xcrypt.c Tue May 12 21:39:39 2015 -0400 @@ -0,0 +1,694 @@ +/* + * FreeSec: libcrypt + * + * Copyright (C) 1994 David Burren + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name(s) of the author(s) nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * This is an original implementation of the DES and the crypt(3) interfaces + * by David Burren . + * + * An excellent reference on the underlying algorithm (and related + * algorithms) is: + * + * B. Schneier, Applied Cryptography: protocols, algorithms, + * and source code in C, John Wiley & Sons, 1994. + * + * Note that in that book's description of DES the lookups for the initial, + * pbox, and final permutations are inverted (this has been brought to the + * attention of the author). A list of errata for this book has been + * posted to the sci.crypt newsgroup by the author and is available for FTP. + * + * NOTE: + * This file has a static version of des_setkey() so that crypt.o exports + * only the crypt() interface. This is required to make binaries linked + * against crypt.o exportable or re-exportable from the USA. + */ + +#include +#include + +#ifdef MASTER +# include +#endif +#define _PASSWORD_EFMT1 '_' + +static unsigned char IP[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 +}; + +static unsigned char inv_key_perm[64]; +static unsigned char key_perm[56] = { + 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 +}; + +static unsigned char key_shifts[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +static unsigned char inv_comp_perm[56]; +static unsigned char comp_perm[48] = { + 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 +}; + +/* + * No E box is used, as it's replaced by some ANDs, shifts, and ORs. + */ + +static unsigned char u_sbox[8][64]; +static unsigned char sbox[8][64] = { + { + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 + }, + { + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 + }, + { + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 + }, + { + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 + }, + { + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 + }, + { + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 + }, + { + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 + }, + { + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 + } +}; + +static unsigned char un_pbox[32]; +static unsigned char pbox[32] = { + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 +}; + +static unsigned int bits32[32] = +{ + 0x80000000, 0x40000000, 0x20000000, 0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +static unsigned char bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + +static unsigned int saltbits; +static int old_salt; +static unsigned int *bits28, *bits24; +static unsigned char init_perm[64], final_perm[64]; +static unsigned int en_keysl[16], en_keysr[16]; +static unsigned int de_keysl[16], de_keysr[16]; +static int des_initialised = 0; +static unsigned char m_sbox[4][4096]; +static unsigned int psbox[4][256]; +static unsigned int ip_maskl[8][256], ip_maskr[8][256]; +static unsigned int fp_maskl[8][256], fp_maskr[8][256]; +static unsigned int key_perm_maskl[8][128], key_perm_maskr[8][128]; +static unsigned int comp_maskl[8][128], comp_maskr[8][128]; +static unsigned int old_rawkey0, old_rawkey1; + +static unsigned char ascii64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +/* 0000000000111111111122222222223333333333444444444455555555556666 */ +/* 0123456789012345678901234567890123456789012345678901234567890123 */ + +static __inline int +ascii_to_bin(ch) + char ch; +{ + if (ch > 'z') + return(0); + if (ch >= 'a') + return(ch - 'a' + 38); + if (ch > 'Z') + return(0); + if (ch >= 'A') + return(ch - 'A' + 12); + if (ch > '9') + return(0); + if (ch >= '.') + return(ch - '.'); + return(0); +} + +static void +des_init() +{ + int i, j, b, k, inbit, obit; + unsigned int *p, *il, *ir, *fl, *fr; + + old_rawkey0 = old_rawkey1 = 0; + saltbits = 0; + old_salt = 0; + bits24 = (bits28 = bits32 + 4) + 4; + + /* + * Invert the S-boxes, reordering the input bits. + */ + for (i = 0; i < 8; i++) + for (j = 0; j < 64; j++) { + b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf); + u_sbox[i][j] = sbox[i][b]; + } + + /* + * Convert the inverted S-boxes into 4 arrays of 8 bits. + * Each will handle 12 bits of the S-box input. + */ + for (b = 0; b < 4; b++) + for (i = 0; i < 64; i++) + for (j = 0; j < 64; j++) + m_sbox[b][(i << 6) | j] = + (u_sbox[(b << 1)][i] << 4) | + u_sbox[(b << 1) + 1][j]; + + /* + * Set up the initial & final permutations into a useful form, and + * initialise the inverted key permutation. + */ + for (i = 0; i < 64; i++) { + init_perm[final_perm[i] = IP[i] - 1] = i; + inv_key_perm[i] = 255; + } + + /* + * Invert the key permutation and initialise the inverted key + * compression permutation. + */ + for (i = 0; i < 56; i++) { + inv_key_perm[key_perm[i] - 1] = i; + inv_comp_perm[i] = 255; + } + + /* + * Invert the key compression permutation. + */ + for (i = 0; i < 48; i++) { + inv_comp_perm[comp_perm[i] - 1] = i; + } + + /* + * Set up the OR-mask arrays for the initial and final permutations, + * and for the key initial and compression permutations. + */ + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(il = &ip_maskl[k][i]) = 0; + *(ir = &ip_maskr[k][i]) = 0; + *(fl = &fp_maskl[k][i]) = 0; + *(fr = &fp_maskr[k][i]) = 0; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = init_perm[inbit]) < 32) + *il |= bits32[obit]; + else + *ir |= bits32[obit-32]; + if ((obit = final_perm[inbit]) < 32) + *fl |= bits32[obit]; + else + *fr |= bits32[obit - 32]; + } + } + } + for (i = 0; i < 128; i++) { + *(il = &key_perm_maskl[k][i]) = 0; + *(ir = &key_perm_maskr[k][i]) = 0; + for (j = 0; j < 7; j++) { + inbit = 8 * k + j; + if (i & bits8[j + 1]) { + if ((obit = inv_key_perm[inbit]) == 255) + continue; + if (obit < 28) + *il |= bits28[obit]; + else + *ir |= bits28[obit - 28]; + } + } + *(il = &comp_maskl[k][i]) = 0; + *(ir = &comp_maskr[k][i]) = 0; + for (j = 0; j < 7; j++) { + inbit = 7 * k + j; + if (i & bits8[j + 1]) { + if ((obit=inv_comp_perm[inbit]) == 255) + continue; + if (obit < 24) + *il |= bits24[obit]; + else + *ir |= bits24[obit - 24]; + } + } + } + } + + /* + * Invert the P-box permutation, and convert into OR-masks for + * handling the output of the S-box arrays setup above. + */ + for (i = 0; i < 32; i++) + un_pbox[pbox[i] - 1] = i; + + for (b = 0; b < 4; b++) + for (i = 0; i < 256; i++) { + *(p = &psbox[b][i]) = 0; + for (j = 0; j < 8; j++) { + if (i & bits8[j]) + *p |= bits32[un_pbox[8 * b + j]]; + } + } + + des_initialised = 1; +} + +static void +setup_salt(salt) + int salt; +{ + unsigned int obit, saltbit; + int i; + + if (salt == old_salt) + return; + old_salt = salt; + + saltbits = 0; + saltbit = 1; + obit = 0x800000; + for (i = 0; i < 24; i++) { + if (salt & saltbit) + saltbits |= obit; + saltbit <<= 1; + obit >>= 1; + } +} + +static int +des_setkey(key) + const char *key; +{ + unsigned int k0, k1, rawkey0, rawkey1; + int shifts, round; + + if (!des_initialised) + des_init(); + + rawkey0 = md_ntohl(*(unsigned int *) key); + rawkey1 = md_ntohl(*(unsigned int *) (key + 4)); + + if ((rawkey0 | rawkey1) + && rawkey0 == old_rawkey0 + && rawkey1 == old_rawkey1) { + /* + * Already setup for this key. + * This optimisation fails on a zero key (which is weak and + * has bad parity anyway) in order to simplify the starting + * conditions. + */ + return(0); + } + old_rawkey0 = rawkey0; + old_rawkey1 = rawkey1; + + /* + * Do key permutation and split into two 28-bit subkeys. + */ + k0 = key_perm_maskl[0][rawkey0 >> 25] + | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskl[4][rawkey1 >> 25] + | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f]; + k1 = key_perm_maskr[0][rawkey0 >> 25] + | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskr[4][rawkey1 >> 25] + | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f]; + /* + * Rotate subkeys and do compression permutation. + */ + shifts = 0; + for (round = 0; round < 16; round++) { + unsigned int t0, t1; + + shifts += key_shifts[round]; + + t0 = (k0 << shifts) | (k0 >> (28 - shifts)); + t1 = (k1 << shifts) | (k1 >> (28 - shifts)); + + de_keysl[15 - round] = + en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f] + | comp_maskl[1][(t0 >> 14) & 0x7f] + | comp_maskl[2][(t0 >> 7) & 0x7f] + | comp_maskl[3][t0 & 0x7f] + | comp_maskl[4][(t1 >> 21) & 0x7f] + | comp_maskl[5][(t1 >> 14) & 0x7f] + | comp_maskl[6][(t1 >> 7) & 0x7f] + | comp_maskl[7][t1 & 0x7f]; + + de_keysr[15 - round] = + en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f] + | comp_maskr[1][(t0 >> 14) & 0x7f] + | comp_maskr[2][(t0 >> 7) & 0x7f] + | comp_maskr[3][t0 & 0x7f] + | comp_maskr[4][(t1 >> 21) & 0x7f] + | comp_maskr[5][(t1 >> 14) & 0x7f] + | comp_maskr[6][(t1 >> 7) & 0x7f] + | comp_maskr[7][t1 & 0x7f]; + } + return(0); +} + +static int +do_des(l_in, r_in, l_out, r_out, count) + unsigned int l_in, r_in, *l_out, *r_out; + int count; +{ + /* + * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format. + */ + unsigned int l, r, *kl, *kr, *kl1, *kr1; + unsigned int f = 0, r48l, r48r; + int round; + + if (count == 0) { + return(1); + } else if (count > 0) { + /* + * Encrypting + */ + kl1 = en_keysl; + kr1 = en_keysr; + } else { + /* + * Decrypting + */ + count = -count; + kl1 = de_keysl; + kr1 = de_keysr; + } + + /* + * Do initial permutation (IP). + */ + l = ip_maskl[0][l_in >> 24] + | ip_maskl[1][(l_in >> 16) & 0xff] + | ip_maskl[2][(l_in >> 8) & 0xff] + | ip_maskl[3][l_in & 0xff] + | ip_maskl[4][r_in >> 24] + | ip_maskl[5][(r_in >> 16) & 0xff] + | ip_maskl[6][(r_in >> 8) & 0xff] + | ip_maskl[7][r_in & 0xff]; + r = ip_maskr[0][l_in >> 24] + | ip_maskr[1][(l_in >> 16) & 0xff] + | ip_maskr[2][(l_in >> 8) & 0xff] + | ip_maskr[3][l_in & 0xff] + | ip_maskr[4][r_in >> 24] + | ip_maskr[5][(r_in >> 16) & 0xff] + | ip_maskr[6][(r_in >> 8) & 0xff] + | ip_maskr[7][r_in & 0xff]; + + while (count--) { + /* + * Do each round. + */ + kl = kl1; + kr = kr1; + round = 16; + while (round--) { + /* + * Expand R to 48 bits (simulate the E-box). + */ + r48l = ((r & 0x00000001) << 23) + | ((r & 0xf8000000) >> 9) + | ((r & 0x1f800000) >> 11) + | ((r & 0x01f80000) >> 13) + | ((r & 0x001f8000) >> 15); + + r48r = ((r & 0x0001f800) << 7) + | ((r & 0x00001f80) << 5) + | ((r & 0x000001f8) << 3) + | ((r & 0x0000001f) << 1) + | ((r & 0x80000000) >> 31); + /* + * Do salting for crypt() and friends, and + * XOR with the permuted key. + */ + f = (r48l ^ r48r) & saltbits; + r48l ^= f ^ *kl++; + r48r ^= f ^ *kr++; + /* + * Do sbox lookups (which shrink it back to 32 bits) + * and do the pbox permutation at the same time. + */ + f = psbox[0][m_sbox[0][r48l >> 12]] + | psbox[1][m_sbox[1][r48l & 0xfff]] + | psbox[2][m_sbox[2][r48r >> 12]] + | psbox[3][m_sbox[3][r48r & 0xfff]]; + /* + * Now that we've permuted things, complete f(). + */ + f ^= l; + l = r; + r = f; + } + r = l; + l = f; + } + /* + * Do final permutation (inverse of IP). + */ + *l_out = fp_maskl[0][l >> 24] + | fp_maskl[1][(l >> 16) & 0xff] + | fp_maskl[2][(l >> 8) & 0xff] + | fp_maskl[3][l & 0xff] + | fp_maskl[4][r >> 24] + | fp_maskl[5][(r >> 16) & 0xff] + | fp_maskl[6][(r >> 8) & 0xff] + | fp_maskl[7][r & 0xff]; + *r_out = fp_maskr[0][l >> 24] + | fp_maskr[1][(l >> 16) & 0xff] + | fp_maskr[2][(l >> 8) & 0xff] + | fp_maskr[3][l & 0xff] + | fp_maskr[4][r >> 24] + | fp_maskr[5][(r >> 16) & 0xff] + | fp_maskr[6][(r >> 8) & 0xff] + | fp_maskr[7][r & 0xff]; + return(0); +} + +static int +des_cipher(in, out, salt, count) + const char *in; + char *out; + int salt; + int count; +{ + unsigned int l_out, r_out, rawl, rawr; + unsigned int x[2]; + int retval; + + if (!des_initialised) + des_init(); + + setup_salt(salt); + + memcpy(x, in, sizeof x); + rawl = md_ntohl(x[0]); + rawr = md_ntohl(x[1]); + retval = do_des(rawl, rawr, &l_out, &r_out, count); + + x[0] = md_htonl(l_out); + x[1] = md_htonl(r_out); + memcpy(out, x, sizeof x); + return(retval); +} + +char * +xcrypt(key, setting) + const char *key; + const char *setting; +{ + int i; + unsigned int count, salt, l, r0, r1, keybuf[2]; + unsigned char *p, *q; + static unsigned char output[21]; + + if (!des_initialised) + des_init(); + + /* + * Copy the key, shifting each character up by one bit + * and padding with zeros. + */ + q = (unsigned char *) keybuf; + while ((q - (unsigned char *) keybuf) < sizeof(keybuf)) { + if ((*q++ = *key << 1)) + key++; + } + if (des_setkey((unsigned char *) keybuf)) + return(NULL); + + if (*setting == _PASSWORD_EFMT1) { + /* + * "new"-style: + * setting - underscore, 4 bytes of count, 4 bytes of salt + * key - unlimited characters + */ + for (i = 1, count = 0; i < 5; i++) + count |= ascii_to_bin(setting[i]) << (i - 1) * 6; + + for (i = 5, salt = 0; i < 9; i++) + salt |= ascii_to_bin(setting[i]) << (i - 5) * 6; + + while (*key) { + /* + * Encrypt the key with itself. + */ + if (des_cipher((unsigned char*)keybuf, (unsigned char*)keybuf, 0, 1)) + return(NULL); + /* + * And XOR with the next 8 characters of the key. + */ + q = (unsigned char *) keybuf; + while (((q - (unsigned char *) keybuf) < sizeof(keybuf)) && + *key) + *q++ ^= *key++ << 1; + + if (des_setkey((unsigned char *) keybuf)) + return(NULL); + } + strncpy((char *)output, setting, 9); + + /* + * Double check that we weren't given a short setting. + * If we were, the above code will probably have created + * wierd values for count and salt, but we don't really care. + * Just make sure the output string doesn't have an extra + * NUL in it. + */ + output[9] = '\0'; + p = output + strlen((const char *)output); + } else { + /* + * "old"-style: + * setting - 2 bytes of salt + * key - up to 8 characters + */ + count = 25; + + salt = (ascii_to_bin(setting[1]) << 6) + | ascii_to_bin(setting[0]); + + output[0] = setting[0]; + /* + * If the encrypted password that the salt was extracted from + * is only 1 character long, the salt will be corrupted. We + * need to ensure that the output string doesn't have an extra + * NUL in it! + */ + output[1] = setting[1] ? setting[1] : output[0]; + + p = output + 2; + } + setup_salt(salt); + /* + * Do it. + */ + if (do_des(0, 0, &r0, &r1, count)) + return(NULL); + /* + * Now encode the result... + */ + l = (r0 >> 8); + *p++ = ascii64[(l >> 18) & 0x3f]; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + + l = (r0 << 16) | ((r1 >> 16) & 0xffff); + *p++ = ascii64[(l >> 18) & 0x3f]; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + + l = r1 << 2; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + *p = 0; + + return((char *)output); +}