Import UltraRogue from the Roguelike Restoration Project (r1490)

This commit is contained in:
John "Elwin" Edwards 2017-01-31 19:56:04 -05:00
parent c346921c68
commit 11c74c273d
59 changed files with 42044 additions and 0 deletions

138
urogue/LICENSE.TXT Normal file
View file

@ -0,0 +1,138 @@
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
Portions Copyright (C) 1985 Michael Morgan, Ken Dalka
Portions Copyright (C) 1981 Michael Toy, Ken Arnold and Glenn Wichman
Portions Copyright (C) 1993, 1995 Nicholas J. Kisseberth
All rights reserved.
===========================================================================
UltaRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
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 "UltraRogue" and "urogue" 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 "UltraRogue" or
"urogue", nor may "UltraRogue" or "urogue" appear in their name,
without prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
===========================================================================
Portions of this software are based on the work of Michael Morgan and
Ken Dalka. Used under license:
Advanced Rogue
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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 are based on the work of Michael Toy, Ken Arnold
and Glenn Wichman. Used under license:
Rogue: Exploring the Dungeons of Doom
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
===========================================================================
Portions of this software (save/restore game state) are based on the work
of Nicholas J. Kisseberth. Used under license:
Copyright (C) 1993, 1995 Nicholas J. Kisseberth
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

167
urogue/Makefile Normal file
View file

@ -0,0 +1,167 @@
# UltraRogue: The Ultimate Adventure in the Dungeons of Doom
# Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
# All rights reserved.
#
# See the file LICENSE.TXT for full copyright and licensing information.
#
# Makefile for urogue
#
DISTNAME=urogue1.0.7
HDRS = dict.h dictutil.h rogue.h
OBJS = armor.o \
artifact.o \
bag.o \
chase.o \
command.o \
daemon.o \
daemons.o \
dict.o \
dictutil.o \
encumb.o \
fight.o \
getplay.o \
ident.o \
init.o \
io.o \
list.o \
magic.o \
main.o \
maze.o \
memory.o \
misc.o \
monsdata.o \
monsters.o \
move.o \
newlvl.o \
options.o \
pack.o \
passages.o \
player.o \
potions.o \
random.o \
rings.o \
rip.o \
rooms.o \
save.o \
scrolls.o \
state.o \
status.o \
sticks.o \
things.o \
trader.o \
verify.o \
vers.o \
weapons.o \
wizard.o
PROGRAM = ur
CFILES = armor.c \
artifact.c \
bag.c \
chase.c \
command.c \
daemon.c \
daemons.c \
dict.c \
dictutil.c \
encumb.c \
fight.c \
getplay.c \
ident.c \
init.c \
io.c \
list.c \
magic.c \
main.c \
maze.c \
memory.c \
misc.c \
monsdata.c \
monsters.c \
move.c \
newlvl.c \
options.c \
pack.c \
passages.c \
player.c \
potions.c \
random.c \
rings.c \
rip.c \
rooms.c \
save.c \
scrolls.c \
state.c \
status.c \
sticks.c \
things.c \
trader.c \
verify.c \
vers.c \
weapons.c \
wizard.c
MISC= Makefile README LICENSE.TXT history.txt TODO
CC = gcc
CFLAGS= -O3
CRLIB = -lcurses
RM = rm -f
TAR = tar
urogue: $(OBJS) $(MAKEFILE)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(CRLIB) -o $@
clean:
rm -f $(OBJS) urogue a.out core *.map urogue.exe urogue.cat
dist.src:
make clean
tar cf $(DISTNAME)-src.tar $(CFILES) $(HDRS) $(MISC)
gzip -f $(DISTNAME)-src.tar
dist.irix:
make clean
make CC=cc CFLAGS="-woff 1116 -O3" urogue
nroff -man urogue.6 | colcrt - > urogue.cat
tar cf $(DISTNAME)-irix.tar urogue urogue.cat README LICENSE.TXT
gzip -f $(DISTNAME)-irix.tar
dist.aix:
make clean
make CC=xlc CFLAGS="-qmaxmem=16768 -O3 -qstrict" urogue
nroff -man urogue.6 | colcrt - > urogue.cat
tar cf $(DISTNAME)-aix.tar urogue urogue.cat README LICENSE.TXT
gzip -f $(DISTNAME)-aix.tar
dist.linux:
make clean
make urogue
groff -man urogue.6 | sed -e 's/.\x08//g' > urogue.cat
tar cf $(DISTNAME)-linux.tar urogue urogue.cat README LICENSE.TXT
gzip -f $(DISTNAME)-linux.tar
dist.interix:
make clean
make urogue
groff -P-b -P-u -man -Tascii urogue.6 > urogue.cat
tar cf $(DISTNAME)-interix.tar urogue urogue.cat README LICENSE.TXT
gzip -f $(DISTNAME)-interix.tar
dist.cygwin:
make clean
make urogue
groff -P-c -man -Tascii urogue.6 | sed -e 's/.\x08//g' > urogue.cat
tar cf $(DISTNAME)-cygwin.tar urogue.exe urogue.cat README LICENSE.TXT
gzip -f $(DISTNAME)-cygwin.tar
dist.djgpp:
make clean
make LDFLAGS="-L$(DJDIR)/LIB" CRLIB="-lpdcurses" urogue
groff -man -Tascii urogue.6 | sed -e 's/.\x08//g' > urogue.cat
rm -f $(DISTNAME)-djgpp.zip
zip $(DISTNAME)-djgpp.zip urogue.exe urogue.cat README LICENSE.TXT

74
urogue/README Normal file
View file

@ -0,0 +1,74 @@
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
There are 8 different treasures to be picked up in this version of rogue.
The first is on level 25 and is relatively easy to pick up. The last is
on level 100 and is very difficult to get. Carrying any one of the
unique treasures allows the rogue to go up the stairs, but one has to
be very careful. To be a total winner, yu must pick up all 8 and
return to the surface again.
(note: the above may be incorrect, i think the number of levels is
reduced to 50 and you have to get all 8 artifacts to go back up)
The environment variable UROGUE is used to set up the default things
for a player. The options that can be set are:
terse: short output messages
flush: flush typeahead when fighting
jump: show position only at the end of running
inven: inventory style
askme: ask about unidentified things
stopdoor: stop running when next to something interesting
name: the rogue's name (string)
fruit: the funny fruit used by the rogue (string)
file: default savefile name (string)
score: default scorefile name (string)
class: default player class (string)
Something like
setenv UROGUE "name=George of the Jungle,fruit=peach,noterse,jump"
does the obvious. The "score" option is ignored unless you start
urogue in wizard mode. The class option string can have the following
values: "fighter", "illus", "paladin", "ranger", "cleric", "magic",
"assasin", "druid", "ninja", and "thief" and is initialized only at
startup time. The "inven" option can take the values "slow", "clear",
and "overwrite".
About the Author
================
Herb Chong is currently freelance writing and doing some teaching.
If you pick up a copy of Windows Sources Magazine, you can usually
find something he has written. Starting in October (1993) he will
have a regular column. Herb has also just started teaching Adult Ed
and undergraduate classes at Mercy College, a small and not very well
known college in Westchester, NY.
Acknowledgements
================
The source code for Rogue 3.6 (by Michael Toy, Ken Arnold and Glenn
Wichman) was used as the original basis for this game. A thousand
thanks go out to them and their classic adventure game of the early 1980s.
Modifications of a long forgotten and bastardized nature were taken
from Advanced Rogue 1.0 and/or SuperRogue. We believe that the flea market,
pools, and maze levels had their origin somewhere around here.
Chief Architect : Herb Chong
Major Contributers: Carlton Hommel Mike Cooper Mike Laman
Jason Venner Nick Kisseberth
Other Contributers: Nick Flor Henry Chai Pat Place
Michael Maudlin dan@ciprico edjames@ucbshadow
Web Dove Tim Haapanen tecot@cmu-cs-k.arpa
Any omissions or errors are purely unintentional. The above list was
compiled by Nick Kisseberth from the change log in UltraRogue through
1987 and from correspondense with Herb Chong.

23
urogue/TODO Normal file
View file

@ -0,0 +1,23 @@
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1993, 1995 Herb Chong
All rights reserved.
%W% %G%
add_pack() calls ur_free() on the linked list pointer passed
to it. Need to go through code and look for cases where we
use that pointer after calling add_pack(). Electric
fence in guard-free() mode should help.
Similary throw_away(), discard(), discard_pack() free items...
there will be more like this...
Bug in genocide scroll: don't request list, type letter, etc...
Implement potion of true sight.
Bug: apparently when creating a new familiar after a player level
change, something isn't begin reset because ur SEGVs when running
through the monster list in do_chase() right after the new
familiar is created. It appears that the familiar isn't being removed
from the monster list.

207
urogue/armor.c Normal file
View file

@ -0,0 +1,207 @@
/*
armor.c - functions for dealing with armor
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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 "rogue.h"
/*
wear()
The player wants to wear something, so let him/her put it on.
*/
void
wear(void)
{
struct object *obj;
if (cur_armor != NULL)
{
msg("You are already wearing some.");
after = FALSE;
return;
}
/* What does player want to wear? */
if ((obj = get_object(pack, "wear", ARMOR, NULL)) == NULL)
return;
wear_ok(&player, obj, MESSAGE);
waste_time();
cur_armor = obj;
obj->o_flags |= ISKNOW;
msg("You are now wearing %s.", inv_name(obj, TRUE));
return;
}
/*
take_off()
Get the armor off of the players back
*/
void
take_off(void)
{
struct object *obj;
if ((obj = cur_armor) == NULL)
{
msg("You aren't wearing armor!");
return;
}
if (!dropcheck(cur_armor))
return;
msg("You were wearing %c%c) %s.", ARMOR, print_letters[get_ident(obj)],
inv_name(obj, LOWERCASE));
cur_armor = NULL;
if (on(player, STUMBLER))
{
msg("Your foot feels a lot better now.");
turn_off(player, STUMBLER);
}
}
/*
wear_ok()
enforce player class armor restrictions
*/
int
wear_ok(struct thing *wearee, struct object *obj, int print_message)
{
int which = obj->o_which;
int ret_val = TRUE;
int class_type = wearee->t_ctype;
if (obj->o_type != ARMOR)
return(FALSE);
else
switch (class_type)
{
case C_MAGICIAN: /* cannot wear metal */
case C_ILLUSION:
switch (which)
{
case RING_MAIL:
case SCALE_MAIL:
case PADDED_ARMOR:
case CHAIN_MAIL:
case BRIGANDINE:
case SPLINT_MAIL:
case GOOD_CHAIN:
case PLATE_MAIL:
case PLATE_ARMOR:
ret_val = FALSE;
break;
default:
break;
}
case C_THIEF: /* cannot clank around */
case C_ASSASIN:
case C_NINJA:
switch (which)
{
case CHAIN_MAIL:
case BRIGANDINE:
case SPLINT_MAIL:
case GOOD_CHAIN:
case PLATE_MAIL:
case PLATE_ARMOR:
ret_val = FALSE;
break;
default:
break;
}
case C_CLERIC: /* cannot wear plate */
case C_DRUID:
switch (which)
{
case PLATE_MAIL:
case PLATE_ARMOR:
case MITHRIL:
ret_val = FALSE;
break;
default:
break;
}
case C_FIGHTER: /* wear anything */
case C_RANGER:
break;
case C_PALADIN: /* cannot wear common stuff */
switch (which)
{
case SOFT_LEATHER:
case CUIRBOLILLI:
case HEAVY_LEATHER:
case STUDDED_LEATHER:
case PADDED_ARMOR:
case BRIGANDINE:
ret_val = FALSE;
break;
default:
break;
}
case C_MONSTER:
break;
default: /* Unknown class */
debug("Unknown class %d.", class_type);
break;
}
if (ret_val == FALSE && print_message == MESSAGE)
switch (class_type)
{
case C_MAGICIAN:
case C_ILLUSION:
msg("You cannot regenerate spell points while wearing that!");
break;
case C_THIEF:
case C_ASSASIN:
case C_NINJA:
msg("Don't expect to be stealthy while wearing that!");
break;
case C_CLERIC:
case C_DRUID:
case C_PALADIN:
msg("Your god strongly disapproves of your wearing that!");
break;
case C_FIGHTER:
case C_RANGER:
case C_MONSTER:
break;
}
return(ret_val);
}

1922
urogue/artifact.c Normal file

File diff suppressed because it is too large Load diff

448
urogue/bag.c Normal file
View file

@ -0,0 +1,448 @@
/*
bag.c - functions for dealing with bags
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* new bag functions
*
* This is a simple version of bag.c that uses linked lists to perform the bag
* functions. The bag is just a linked list of objects (struct object) to be
* specific, but most of that is supposed to be hidden from the user, who
* should access the bag only through the functions presented here.
*/
#include <stdlib.h>
#include "rogue.h"
/*
* apply_to_bag
*
* This is the general bag manipulation routine. The bag is subjected to
* selection criteria and those objects which pass are processed by an action
* routine. The two criteria are type and filter function. The filter
* function returns TRUE if the object passes and FALSE otherwise. The filter
* function is passed the object and the user-supplied argument. This gives
* the user plenty of flexibility in determining which items will be
* processed. The action routine is passed the object, the id, and the
* user-supplied argument given to apply_to_bag. Specifying NULL for either
* the type or filter function means that criterion always selects. A NULL
* action routine means no processing is done and the first object which
* passes the filter is returned to the user. The action routine returns TRUE
* if processing should continue or FALSE if the current item should be
* returned to the caller.
*
* Returns NULL if the bag is empty or if nothing qualified.
*
* linked_list *bag_p; // linked list of objects
* int type; // what is its type (ARMOR, ...)
* int (*bff_p)(); // bag filter function
* int (*baf_p)(); // bag action routine
* long user_arg; // user argument for filter, action
*
*/
struct object *
apply_to_bag(struct linked_list *bag_p,
int type,
int (*bff_p)(struct object *obj, bag_arg *user_arg),
int (*baf_p)(struct object *obj, bag_arg *user_arg, int id),
void *user_arg)
{
struct object *bag_obj_p = NULL; /* qualifying object */
struct object *cur_obj_p; /* current object */
bag_arg arg;
arg.varg = user_arg;
if (bag_p == NULL)
return (NULL);
for (; bag_p != NULL; bag_p = next(bag_p))
{
cur_obj_p = OBJPTR(bag_p);
if (type != 0 && type != cur_obj_p->o_type)
continue;
if (bff_p != NULL && !(*bff_p)(cur_obj_p, &arg))
continue;
/*
* At this point, we have an object which qualifies for
* processing
*/
bag_obj_p = cur_obj_p; /* in case the user wants it */
if (baf_p != NULL && (*baf_p)(cur_obj_p, &arg, identifier(bag_obj_p)))
continue;
/*
* We have an object which qualifies, quit now!
*/
break;
}
if (bag_p == NULL)
return (NULL);
return (bag_obj_p);
}
/*
count_bag()
Counts up all bag items which meet the selection criteria
*/
int
count_bag(linked_list *bag_p,
int type,
int (*bff_p)(struct object *obj, bag_arg *junk))
{
int cnt = 0;
apply_to_bag(bag_p, type, bff_p, baf_increment, &cnt);
return(cnt);
}
/*
del_bag()
Removes an object from a bag and throws it away.
*/
void
del_bag(linked_list *bag_p, object *obj_p)
{
pop_bag(&bag_p, obj_p); /* get the thing from the bag */
ur_free(obj_p); /* release the memory */
}
/*
pop_bag()
Removes an item from a bag and returns it to the user. If the item is
not in the bag, return NULL.
*/
struct object *
pop_bag(linked_list **bag_pp, object *obj_p)
{
linked_list *item_p;
for (item_p = *bag_pp; item_p != NULL && OBJPTR(item_p) != obj_p;
item_p = next(item_p));
if (item_p == NULL)
return (NULL);
_detach(bag_pp, item_p);
return (obj_p);
}
/*
push_bag()
stuff another item into the bag
*/
void
push_bag(linked_list **bag_pp, object *obj_p)
{
struct linked_list *item_p = NULL;
struct linked_list *new_p = NULL;
struct linked_list *best_p = NULL;
new_p = new_list();
new_p->data.obj = obj_p; /* attach our object */
identifier(obj_p) = get_ident(obj_p); /* tag this object for */
/* inventory */
/*
* Find a place in the bag - try to match the type, then sort by
* identifier
*/
for (item_p = *bag_pp; item_p != NULL; item_p = next(item_p))
{
if ((OBJPTR(item_p))->o_type == obj_p->o_type)
{
if (best_p == NULL)
best_p = item_p;
else if (identifier((OBJPTR(item_p))) >
identifier((OBJPTR(best_p))) &&
identifier((OBJPTR(item_p))) <
identifier(obj_p))
best_p = item_p;
}
}
_attach_after(bag_pp, best_p, new_p); /* stuff it in the list */
return;
}
/*
scan_bag()
Gets the object from the bag that matches the type and id. The object
is not removed from the bag.
*/
struct object *
scan_bag(linked_list *bag_p, int type, int id)
{
object *obj_p = NULL;
for (; bag_p != NULL; bag_p = next(bag_p))
{
obj_p = OBJPTR(bag_p);
if (obj_p->o_type == type && identifier(obj_p) == id)
break;
}
if (bag_p == NULL)
return(NULL);
return(obj_p);
}
/*
baf_decrement_test()
Assumes the argument is a pointer to int and it just decrements it.
Returns TRUE, except when the count goes to zero.
*/
int
baf_decrement_test(struct object *obj_p, bag_arg *count_p, int id)
{
NOOP(obj_p);
NOOP(id);
if (*count_p->iarg > 0)
return(TRUE);
return(FALSE);
}
/*
baf_identify()
Bag action function to identify an object. This is needed to conform
to bag action routine calling conventions and to put the linked list
structure on top of the object before calling whatis()
*/
int
baf_identify(struct object *obj_p, bag_arg *junk, int id)
{
linked_list l;
linked_list *lp = &l;
NOOP(junk);
NOOP(id);
lp->data.obj = obj_p; /* stuff object in the right place */
whatis(lp);
return(TRUE);
}
/*
baf_increment()
Assumes the argument is a pointer to int and it just increments it and
returns TRUE
*/
int
baf_increment(object *obj_p, bag_arg *count_p, int id)
{
NOOP(obj_p);
NOOP(id);
(*count_p->iarg)++;
return(TRUE);
}
/*
baf_print_item()
Bag action function to print a single item, inventory style.
*/
int
baf_print_item(struct object *obj_p, bag_arg *type, int id)
{
char inv_temp[3 * LINELEN]; /* plenty of space for paranoid programmers */
if (*type->iarg == 0)
sprintf(inv_temp, "%c%c) %s", obj_p->o_type,
print_letters[id], inv_name(obj_p, LOWERCASE), FALSE);
else
sprintf(inv_temp, "%c) %s", print_letters[id],
inv_name(obj_p, LOWERCASE), FALSE);
add_line(inv_temp);
return(TRUE);
}
/*
bff_group()
This bag filter function checks to see if two items can be combined by
adjusting the count. Grouped items can be combined if the group numbers
match. The only other item that is allowed to have a count is food, and
there an exact match is required.
*/
int
bff_group(struct object *obj_p, bag_arg *arg)
{
struct object *new_obj_p = arg->obj;
if (new_obj_p->o_group > 0 && new_obj_p->o_group == obj_p->o_group)
return(TRUE);
if (new_obj_p->o_type == FOOD &&
obj_p->o_type == new_obj_p->o_type &&
obj_p->o_which == new_obj_p->o_which)
return(TRUE);
return(FALSE);
}
/*
bff_callable
Figures out which items can be callable: current rules are:
potions, scrolls, staffs, and rings.
*/
int
bff_callable(struct object *obj_p, bag_arg *junk)
{
NOOP(junk);
if (obj_p->o_type == POTION || obj_p->o_type == RING ||
obj_p->o_type == STICK || obj_p->o_type == SCROLL)
return(TRUE);
return(FALSE);
}
/*
bff_markable()
Selects which items can be marked. Current rules exclude only gold.
*/
int
bff_markable(struct object *obj_p, bag_arg *junk)
{
NOOP(junk);
if (obj_p->o_type == GOLD)
return(FALSE);
return(TRUE);
}
/*
bffron()
returns TRUE if hero is wearing this ring
*/
int
bffron(object *obj_p, bag_arg *junk)
{
NOOP(junk);
return(cur_ring[LEFT_1] == obj_p || cur_ring[LEFT_2] == obj_p ||
cur_ring[LEFT_3] == obj_p || cur_ring[LEFT_4] == obj_p ||
cur_ring[LEFT_5] ||
cur_ring[RIGHT_1] == obj_p || cur_ring[RIGHT_2] == obj_p ||
cur_ring[RIGHT_3] == obj_p || cur_ring[RIGHT_4] == obj_p ||
cur_ring[RIGHT_5]);
}
/*
bff_zappable()
Selects which items can be zapped. This includes both sticks and
magically enhanced weapons with lightning ability.
*/
int
bff_zappable(struct object *obj_p, bag_arg *junk)
{
NOOP(junk);
if (obj_p->o_type == STICK)
return(TRUE);
if (obj_p->o_type == WEAPON && obj_p->o_flags & ISZAPPED)
return(TRUE);
return (FALSE);
}
/*
baf_curse()
Curse all non-artifact items in the player's pack
*/
int
baf_curse(struct object *obj_p, bag_arg *junk, int id)
{
NOOP(junk);
NOOP(id);
if (obj_p->o_type != ARTIFACT && rnd(8) == 0)
{
obj_p->o_flags |= ISCURSED;
obj_p->o_flags &= ~ISBLESSED;
}
return(TRUE);
}
/*
bafcweapon()
bag action routine to fetch the current weapon
*/
int
bafcweapon(struct object *obj_p, bag_arg *junk, int id)
{
NOOP(junk);
NOOP(id);
if (obj_p == cur_weapon)
return(FALSE); /* found what we wanted - stop and return it */
return(TRUE);
}
/*
bafcarmor()
bag action routine to fetch the current armor
*/
int
bafcarmor(struct object *obj_p, bag_arg *junk, int id)
{
NOOP(junk);
NOOP(id);
if (obj_p == cur_armor)
return(FALSE); /* found what we wanted - stop and return it */
return(TRUE);
}

1326
urogue/chase.c Normal file

File diff suppressed because it is too large Load diff

1383
urogue/command.c Normal file

File diff suppressed because it is too large Load diff

327
urogue/daemon.c Normal file
View file

@ -0,0 +1,327 @@
/*
daemon.c - functions for dealing with things that happen in the future
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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.
*/
/*
Needs to be rewritten again to work on a per creature basis.
Either each monster will have a list of effect, or each
fuse will take a creature pointer and multiple entries
for each fuse will be allowed. I tend to want to attach
the effects to the creature.
*/
#include "rogue.h"
int demoncnt;
struct daemon daemons[DAEMON_MAX] =
{
{ DAEMON_NULL, NULL },
{ DAEMON_DOCTOR, doctor },
{ DAEMON_ROLLWAND, rollwand },
{ DAEMON_STOMACH, stomach },
{ DAEMON_RUNNERS, runners }
};
struct fuse fuses[FUSE_MAX] =
{
{ FUSE_NULL, NULL },
{ FUSE_SWANDER, swander },
{ FUSE_UNCONFUSE, unconfuse },
{ FUSE_UNSCENT, unscent },
{ FUSE_SCENT, scent },
{ FUSE_UNHEAR, unhear },
{ FUSE_HEAR, hear },
{ FUSE_UNSEE, unsee },
{ FUSE_UNSTINK, unstink },
{ FUSE_UNCLRHEAD, unclrhead },
{ FUSE_UNPHASE, unphase },
{ FUSE_SIGHT, sight },
{ FUSE_RES_STRENGTH, res_strength },
{ FUSE_NOHASTE, nohaste },
{ FUSE_NOSLOW, noslow },
{ FUSE_SUFFOCATE, suffocate },
{ FUSE_CURE_DISEASE, cure_disease },
{ FUSE_UNITCH, un_itch },
{ FUSE_APPEAR, appear },
{ FUSE_UNELECTRIFY, unelectrify },
{ FUSE_UNBHERO, unbhero },
{ FUSE_UNSHERO, unshero },
{ FUSE_UNXRAY, NULL },
{ FUSE_UNDISGUISE, undisguise },
{ FUSE_SHERO, shero },
{ FUSE_WGHTCHK, wghtchk },
{ FUSE_UNSUMMON, unsummon },
{ FUSE_UNGAZE, ungaze },
{ FUSE_UNCOLD, uncold },
{ FUSE_UNHOT, unhot },
{ FUSE_UNFLY, unfly },
{ FUSE_UNBREATHE, unbreathe },
{ FUSE_UNREGEN, unregen },
{ FUSE_UNSUPEREAT, unsupereat },
{ FUSE_UNSHIELD, unshield },
{ FUSE_UNMSHIELD, unmshield },
{ FUSE_UNTRUESEE, untruesee }
};
/*
d_slot()
Find an empty slot in the daemon/fuse list
*/
struct delayed_action *
d_slot(void)
{
int i;
struct delayed_action *dev;
for (i = 0, dev = d_list; i < MAXDAEMONS; 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(int type, int id)
{
int i;
struct delayed_action *dev;
for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++)
if ( (dev->d_type == type) && (id == dev->d_id) )
return(dev);
return(NULL);
}
/*
daemon()
Start a daemon, takes a function.
*/
void
start_daemon(int id, void *arg, int whendo)
{
struct delayed_action *dev;
dev = d_slot();
if (dev != NULL)
{
dev->d_type = DAEMON;
dev->d_when = whendo;
dev->d_id = id;
dev->d_arg = arg;
dev->d_time = 1;
demoncnt += 1; /* update count */
}
}
/*
kill_daemon()
Remove a daemon from the list
*/
void
kill_daemon(int id)
{
struct delayed_action *dev;
if ((dev = find_slot(DAEMON, id)) == NULL)
return;
/* Take it out of the list */
dev->d_type = EMPTY;
demoncnt -= 1; /* update count */
return;
}
/*
do_daemons()
Run all the daemons that are active with the current flag,
passing the argument to the function.
*/
void
do_daemons(int now)
{
struct delayed_action *dev;
/* Loop through the devil list */
for (dev = d_list; dev < &d_list[MAXDAEMONS]; dev++)
/* Executing each one, giving it the proper arguments */
if ( (dev->d_when == now) && (dev->d_type == DAEMON))
{
if ((dev->d_id < 1) || (dev->d_id >= DAEMON_MAX))
printf("Bad daemon id %d\n", dev->d_id);
else if (daemons[dev->d_id].func == NULL)
printf("No action for daemon %d!!!\n", dev->d_id);
else
{
daemon_arg arg;
arg.varg = dev->d_arg;
daemons[dev->d_id].func(&arg);
}
}
}
/*
fuse()
Start a fuse to go off in a certain number of turns
*/
void
light_fuse(int id, void *arg, int time, int whendo)
{
struct delayed_action *wire;
wire = d_slot();
if (wire != NULL)
{
wire->d_type = FUSE;
wire->d_when = whendo;
wire->d_id = id;
wire->d_arg = arg;
wire->d_time = time;
demoncnt += 1; /* update count */
}
}
/*
lengthen()
Increase the time until a fuse goes off
*/
void
lengthen_fuse(int id, int xtime)
{
struct delayed_action *wire;
if ((wire = find_slot(FUSE,id)) == NULL)
return;
wire->d_time += xtime;
return;
}
/*
extinguish()
Put out a fuse
*/
void
extinguish_fuse(int id)
{
struct delayed_action *wire;
if ((wire = find_slot(FUSE,id)) == NULL)
return;
wire->d_type = EMPTY;
demoncnt -= 1;
return;
}
/*
do_fuses()
Decrement counters and start needed fuses
*/
void
do_fuses(int now)
{
struct delayed_action *wire;
/* Step though the list */
for (wire = d_list; wire < &d_list[MAXDAEMONS]; wire++)
{
/*
* Decrementing counters and starting things we want. We
* also need to remove the fuse from the list once it has
* gone off.
*/
if( (wire->d_type == FUSE) && (wire->d_when == now) )
{
if (--wire->d_time <= 0)
{
fuse_arg arg;
arg.varg = wire->d_arg;
wire->d_type = EMPTY;
fuses[wire->d_id].func(&arg);
demoncnt -= 1;
}
}
}
return;
}
/*
activity()
Show wizard number of demaons and memory blocks used
*/
void
activity(void)
{
msg("Daemons = %d : Memory Items = %d ", demoncnt, total);
return;
}
/*
waste_time()
Do nothing but let other things happen
*/
void
waste_time(void)
{
if (inwhgt) /* if from wghtchk then done */
return;
do_daemons(BEFORE);
do_fuses(BEFORE);
do_daemons(AFTER);
do_fuses(AFTER);
}

999
urogue/daemons.c Normal file
View file

@ -0,0 +1,999 @@
/*
daemons.c - All the daemon and fuse functions are in here
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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 "rogue.h"
/*
doctor()
A healing daemon that restors spell and hit points after rest
*/
void
doctor(daemon_arg *who)
{
struct thing *tp = who->thingptr;
long ohp; /* turn off ISFLEE? */
struct stats *curp; /* current stats pointer */
struct stats *maxp; /* max stats pointer */
int turns_quiet, new_points;
curp = &(tp->t_stats);
maxp = &(tp->maxstats);
if (on(*tp, ISINWALL))
{
tp->t_rest_hpt = 0;
return;
}
/* Check for regenerating spell points first */
doctor_spell_points(tp);
if (curp->s_hpt == maxp->s_hpt)
{
tp->t_rest_hpt = 0;
return;
}
tp->t_rest_hpt++;
switch (tp->t_ctype)
{
case C_MAGICIAN:
case C_ILLUSION:
turns_quiet = 24 - curp->s_lvl;
new_points = curp->s_lvl / 2 - 4;
break;
case C_THIEF:
case C_ASSASIN:
case C_NINJA:
turns_quiet = 16 - curp->s_lvl;
new_points = curp->s_lvl / 2 - 1;
break;
case C_CLERIC:
case C_DRUID:
turns_quiet = 16 - curp->s_lvl;
new_points = curp->s_lvl / 2 - 2;
break;
case C_FIGHTER:
case C_RANGER:
case C_PALADIN:
turns_quiet = 8 - curp->s_lvl / 2;
new_points = curp->s_lvl / 2 - 1;
break;
case C_MONSTER:
turns_quiet = 16 - curp->s_lvl;
new_points = curp->s_lvl / 2 - 6;
break;
default:
debug("What a strange character you are!");
return;
}
ohp = curp->s_hpt;
if (off(*tp, HASDISEASE))
{
if (curp->s_lvl < 8)
{
if (tp->t_rest_hpt > turns_quiet)
curp->s_hpt++;
}
else if (tp->t_rest_hpt >= 15)
curp->s_hpt += rnd(new_points) + 1;
}
if (tp == &player)
{
if (curp->s_lvl > 10)
turns_quiet = 2;
else
turns_quiet = rnd(turns_quiet / 6) + 1;
if (is_wearing(R_REGEN))
curp->s_hpt += ring_value(R_REGEN);
}
if (on(*tp, ISREGEN))
curp->s_hpt += curp->s_lvl / 5 + 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 */
}
}
tp->t_rest_hpt = 0;
}
return;
}
/*
doctor_spell_points()
A healing daemon that restors spell points
*/
void
doctor_spell_points(struct thing *tp)
{
int turns_quiet, new_points;
struct stats *curp; /* current stats pointer */
struct stats *maxp; /* max stats pointer */
int opower; /* current power */
curp = &(tp->t_stats);
maxp = &(tp->maxstats);
opower = curp->s_power;
/* The right ring will let you regenerate while wearing bad armor */
if (off(*tp, CANCAST) ||
((tp == &player) &&
(cur_armor && wear_ok(tp, cur_armor, NOMESSAGE) == FALSE) &&
!(is_wearing(R_WIZARD) || is_wearing(R_PIETY))))
{
tp->t_rest_pow = 0;
return;
}
tp->t_rest_pow++;
switch (tp->t_ctype)
{
case C_MAGICIAN:
case C_ILLUSION:
turns_quiet = 18 - curp->s_lvl / 2;
new_points = curp->s_lvl / 2;
break;
case C_CLERIC:
case C_DRUID:
turns_quiet = 24 - curp->s_lvl;
new_points = curp->s_lvl / 2 - 2;
break;
case C_THIEF:
case C_ASSASIN:
case C_NINJA:
turns_quiet = 32 - curp->s_lvl;
new_points = curp->s_lvl / 3 - 3;
break;
case C_FIGHTER:
case C_RANGER:
case C_PALADIN:
turns_quiet = 32 - curp->s_lvl;
new_points = curp->s_lvl / 3 - 4;
break;
case C_MONSTER:
turns_quiet = 24 - curp->s_lvl;
new_points = curp->s_lvl - 6;
break;
default:
return;
}
if (curp->s_lvl < 8)
{
if (tp->t_rest_pow > turns_quiet)
curp->s_power++;
}
else if (tp->t_rest_pow >= 15)
curp->s_power += rnd(new_points) + 1;
if (tp == &player && (is_wearing(R_WIZARD) || is_wearing(R_PIETY)))
curp->s_power += ring_value(R_WIZARD) + ring_value(R_PIETY);
curp->s_power = min(max(0, curp->s_power), maxp->s_power);
if (curp->s_power != opower)
tp->t_rest_pow = 0;
return;
}
/*
rollwand()
called to roll to see if a wandering monster starts up
*/
daemon
rollwand(daemon_arg *arg)
{
NOOP(arg);
if ((rnd(6) == 0) && (player.t_ctype != C_THIEF ||
(rnd(30) >= pstats.s_dext)))
{
wanderer();
kill_daemon(DAEMON_ROLLWAND);
light_fuse(FUSE_SWANDER, 0, WANDERTIME, BEFORE);
}
return;
}
/*
stomach()
digest the hero's food
*/
daemon
stomach(daemon_arg *arg)
{
int oldfood, old_hunger;
int amount;
int power_scale;
NOOP(arg);
old_hunger = hungry_state;
if (food_left <= 0)
{
/* the hero is fainting */
if (no_command || rnd(100) > 20)
return;
no_command = rnd(8) + 4;
running = FALSE;
count = 0;
hungry_state = F_FAINT;
feed_me(hungry_state);
}
else
{
oldfood = food_left;
amount = ring_eat(LEFT_1) + ring_eat(LEFT_2) +
ring_eat(LEFT_3) + ring_eat(LEFT_4) +
ring_eat(RIGHT_1) + ring_eat(RIGHT_2) +
ring_eat(RIGHT_3) + ring_eat(RIGHT_4) +
foodlev;
if (on(player, SUPEREAT)) /* artifact or regeneration munchies */
amount *= 2;
if (on(player, POWEREAT)) /* Used an artifact power */
{
amount += 40;
turn_off(player, POWEREAT);
}
power_scale = (on(player, POWERDEXT) + on(player, POWERSTR) +
on(player, POWERWISDOM) + on(player, POWERINTEL) +
on(player, POWERCONST) + 1);
food_left -= amount * power_scale;
if (food_left < MORETIME && oldfood >= MORETIME)
{
hungry_state = F_WEAK;
running = FALSE;
feed_me(hungry_state);
}
else if (food_left < 2 * MORETIME && oldfood >= 2 * MORETIME)
{
hungry_state = F_HUNGRY;
running = FALSE;
feed_me(hungry_state);
}
}
if (old_hunger != hungry_state)
updpack();
wghtchk(NULL);
}
/*
runners()
Make all the running monsters move. with monsters now fighting
each other, this routine have been enhanced and may need more work yet
*/
daemon
runners(daemon_arg *arg)
{
struct linked_list *item;
struct thing *tp;
NOOP(arg);
for (item = mlist; item != NULL; item = next_mons)
{
curr_mons = item;
next_mons = next(curr_mons);
tp = THINGPTR(item);
if (on(*tp, ISHELD) && rnd(tp->t_stats.s_str +
tp->t_stats.s_lvl) > 10 + rnd(50))
{
turn_off(*tp, ISHELD);
turn_off(*tp, ISDISGUISE);
turn_on(*tp, ISRUN);
tp->t_ischasing = TRUE;
tp->t_chasee = &player;
tp->t_horde = NULL;
if (tp->t_stats.s_hpt < rnd(tp->maxstats.s_hpt))
turn_on(*tp, ISFLEE);
if (cansee(tp->t_pos.y, tp->t_pos.x))
msg("The %s breaks free!", monsters[tp->t_index].m_name);
}
if (off(*tp, ISHELD) && on(*tp, ISRUN))
{
int flee = FALSE;
flee = on(*tp, ISFLEE) ||
( (tp->t_chasee == &player) &&
on(player, ISINWALL) &&
off(*tp, CANINWALL) && off(*tp, ISFAMILIAR) );
if (off(*tp, ISSLOW) || tp->t_turn)
{
daemon_arg targ;
targ.thingptr = tp;
doctor(&targ);
do_chase(tp, flee);
}
if (curr_mons && (on(*tp, ISHASTE) ||
((on(*tp, CANFLY) || on(*tp, ISFAST)) &&
DISTANCE(hero, tp->t_pos) >= 4)))
{
daemon_arg targ;
targ.thingptr = tp;
doctor(&targ);
do_chase(tp, flee);
}
if (curr_mons)
{
tp->t_turn ^= TRUE;
tp->t_wasshot ^= FALSE; /* Not shot anymore */
}
}
}
curr_mons = next_mons = NULL;
return;
}
/*
swander()
called when it is time to start rolling for wandering monsters
*/
fuse
swander(fuse_arg *arg)
{
NOOP(arg);
start_daemon(DAEMON_ROLLWAND, 0, BEFORE);
return;
}
/*
unconfuse
release the poor player from his confusion
*/
fuse
unconfuse(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, ISHUH);
msg("You feel less confused now.");
return;
}
/*
unscent()
turn of extra smelling ability
*/
fuse
unscent(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, CANSCENT);
msg("The smell of monsters goes away.");
}
/*
scent
give back the players sense of smell
*/
fuse
scent(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, ISUNSMELL);
msg("You begin to smell the damp dungeon air again.");
}
/*
unhear
player doesn't have extra hearing any more
*/
fuse
unhear(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, CANHEAR);
msg("The sounds of monsters fades away.");
}
/*
hear()
return the players sense of hearing
*/
fuse
hear(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, ISDEAF);
msg("You can hear again.");
}
/*
unsee
He lost his see invisible power
Need to make monsters invisible again? This
was done in Rogue 5.2
for (th = mlist; th != NULL; th = next(th))
if (on(*th, ISINVIS) && see_monst(th))
{
move(th->t_pos.y, th->t_pos.x);
addch(th->t_oldch);
}
*/
fuse
unsee(fuse_arg *arg)
{
NOOP(arg);
if (!is_wearing(R_SEEINVIS))
{
turn_off(player, CANSEE);
msg("The tingling feeling leaves your eyes.");
}
}
/*
unstink()
Remove to-hit handicap from player
*/
fuse
unstink(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, HASSTINK);
}
/*
unclrhead
Player is no longer immune to confusion
*/
fuse
unclrhead(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, ISCLEAR);
msg("The blue aura about your head fades away.");
}
/*
unphase()
Player can no longer walk through walls
*/
fuse
unphase(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, CANINWALL);
msg("Your dizzy feeling leaves you.");
if (!step_ok(hero.y, hero.x, NOMONST, &player))
death(D_PETRIFY);
}
/*
sight()
He gets his sight back
*/
fuse
sight(fuse_arg *arg)
{
NOOP(arg);
if (on(player, ISBLIND))
{
extinguish_fuse(FUSE_SIGHT);
turn_off(player, ISBLIND);
light(&hero);
msg("The veil of darkness lifts.");
}
}
/*
res_strength()
Restore player's strength
*/
fuse
res_strength(fuse_arg *arg)
{
NOOP(arg);
if (lost_str)
{
chg_str(lost_str, FALSE, FALSE);
lost_str = 0;
}
else
pstats.s_str = max_stats.s_str + ring_value(R_ADDSTR) +
(on(player, POWERSTR) ? 10 : 0) +
(on(player, SUPERHERO) ? 10 : 0);
updpack();
}
/*
nohaste()
End the hasting
*/
fuse
nohaste(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, ISHASTE);
msg("You feel yourself slowing down.");
}
/*
noslow()
End the slowing
*/
fuse
noslow(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, ISSLOW);
msg("You feel yourself speeding up.");
}
/*
suffocate()
If this gets called, the player has suffocated
*/
fuse
suffocate(fuse_arg *arg)
{
NOOP(arg);
death(D_SUFFOCATION);
}
/*
cure_disease()
daemon for curing the diseased
*/
fuse
cure_disease(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, HASDISEASE);
if (off(player, HASINFEST))
msg("You begin to feel yourself improving again.");
}
/*
un_itch()
daemon for adding back dexterity
*/
fuse
un_itch(fuse_arg *arg)
{
NOOP(arg);
if (lost_dext)
{
chg_dext(lost_dext, FALSE, FALSE);
lost_dext = 0;
turn_off(player, HASITCH);
}
}
/*
appear()
Become visible again
*/
fuse
appear(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, ISINVIS);
PLAYER = VPLAYER;
msg("The tingling feeling leaves your body.");
light(&hero);
}
/*
unelectrify()
stop shooting off sparks
*/
fuse
unelectrify(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, ISELECTRIC);
msg("The sparks and violet glow from your body fade away.");
light(&hero);
}
/*
unshero()
super heroism wears off, now do nasty effects
*/
fuse
unshero(fuse_arg *arg)
{
NOOP(arg);
msg("Your feeling of invulnerability goes away.");
turn_off(player, SUPERHERO);
chg_str(-11, FALSE, FALSE);
chg_dext(-6, FALSE, FALSE);
food_left -= HEROTIME + rnd(HEROTIME);
no_command += 5 + rnd(5);
msg("You fall asleep.");
}
/*
unbhero()
blessed super heroism wears off, no bad effects
*/
fuse
unbhero(fuse_arg *arg)
{
NOOP(arg);
msg("Your feeling of invincibility goes away.");
turn_off(player, SUPERHERO);
chg_str(-10, FALSE, FALSE);
chg_dext(-5, FALSE, FALSE);
}
/*
undisguise()
player stops looking like a monster
*/
fuse
undisguise(fuse_arg *arg)
{
NOOP(arg);
msg("Your skin feels itchy for a moment.");
turn_off(player, ISDISGUISE);
PLAYER = VPLAYER;
light(&hero);
}
/*
unsummon()
Unsummon a monster
*/
void
unsummon(fuse_arg *monny)
{
struct linked_list *monst = monny->ll;
struct linked_list *sum_monst = (struct linked_list *) monst;
struct thing *tp = THINGPTR(sum_monst);
char *mname = monsters[tp->t_index].m_name;
turn_off(*tp, WASSUMMONED);
turn_off(player, HASSUMMONED);
msg("Goodbye, master.");
msg("The summoned %s phases out of existence", mname);
killed(NULL, sum_monst, NOMESSAGE, NOPOINTS);
mons_summoned--;
}
/*
ungaze()
Turn off gaze reflection
*/
fuse
ungaze(fuse_arg *arg)
{
NOOP(arg);
msg("The shiny particles swirl to the floor.");
turn_off(player, CANREFLECT);
}
/*
shero()
restore lost abilities from cursed potion of shero
*/
fuse
shero(fuse_arg *arg)
{
NOOP(arg);
msg("You feel normal again.");
chg_str(2, FALSE, TRUE);
chg_dext(2, FALSE, TRUE);
turn_off(player, ISUNHERO);
}
/*
wghtchk()
check that the pack weight is OK
*/
fuse
wghtchk(fuse_arg *arg)
{
int dropchk, err = TRUE;
char ch;
NOOP(arg);
inwhgt = TRUE;
if (pstats.s_pack > pstats.s_carry)
{
ch = CCHAR( mvwinch(stdscr, hero.y, hero.x) );
if ((ch != FLOOR && ch != PASSAGE))
{
extinguish_fuse(FUSE_WGHTCHK);
light_fuse(FUSE_WGHTCHK, (void *)TRUE, 1, AFTER);
inwhgt = FALSE;
return;
}
extinguish_fuse(FUSE_WGHTCHK);
msg("Your pack is too heavy for you.");
do
{
dropchk = drop(NULL);
if (dropchk == FALSE)
{
mpos = 0;
msg("You must drop something.");
}
if (dropchk == TRUE)
err = FALSE;
}
while (err);
}
inwhgt = FALSE;
}
/*
uncold()
He lost his cold resistance power
*/
fuse
uncold(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, NOCOLD);
if (!is_wearing(R_COLDRESIST))
msg("You feel a slight chill in the air.");
}
/*
unhot()
He lost his fire resistance power
*/
fuse
unhot(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, NOFIRE);
if (!is_wearing(R_FIRERESIST))
msg("You feel a flush of warmth.");
}
/*
unfly()
He stopped flying
*/
fuse
unfly(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, CANFLY);
if (!is_wearing(R_LEVITATION))
msg("You float gently to the ground.");
}
/*
unbreathe()
He started needing oxygen
*/
fuse
unbreathe(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, HASOXYGEN);
if (!is_wearing(R_BREATHE))
msg("You start huffing and puffing.");
}
/*
unregen()
He stops being regenerative
*/
fuse
unregen(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, ISREGEN);
if (!is_wearing(R_REGEN))
msg("Your metabolism slows down.");
}
/*
unsupereat()
He stops being excessively hungry
*/
fuse
unsupereat(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, SUPEREAT);
msg("You stop feeling so hungry.");
}
/*
unshield()
He stops having his AC helped by magic
*/
fuse
unshield(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, HASSHIELD);
pstats.s_arm -= pstats.s_acmod;
pstats.s_acmod = 0;
msg("Your skin feels normal.");
}
/*
unmshield()
He stops ignoring thrown weapons
*/
fuse
unmshield(fuse_arg *arg)
{
NOOP(arg);
turn_off(player, HASMSHIELD);
msg("The fog dissapates.");
}
/*
untrue()
He lost his true sight power
*/
void
untruesee(fuse_arg *arg)
{
NOOP(arg);
if (!is_wearing(R_TRUESEE))
{
turn_off(player, CANTRUESEE);
msg("Your sensory perceptions return to normal.");
}
}

1160
urogue/dict.c Normal file

File diff suppressed because it is too large Load diff

216
urogue/dict.h Normal file
View file

@ -0,0 +1,216 @@
/*
dict.h
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
/*-----------------
Change history:
(AK:04/03/95) - Added hook for extensions to dictionary structure.
(AK:04/04/95) - Added dictionary signature, table of contents and parameter
structure defintions and fields in DICTIONARY structure
-------------------*/
#ifndef dict_h_included
#define dict_h_included
static char dict_sccsid[] = "%W% %G%";
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define DICT_NONE 0x00000000 /* no flags set */
#define DICT_VALIDATE 0xdeadbeef /* look for this in every dictionary structure */
#define DICT_ENTRY_NONE -1 /* index of invalid entry */
typedef unsigned char BOOLEANC;
/*------------------
string table entry
------------------*/
typedef struct string_entry {
long string_offset; /* offset in string array */
long count; /* number of occurrences of string */
long next; /* offset of next in hash chain */
void *any_ptr; /* free pointer */
unsigned long flags; /* user definable flag value for string */
unsigned long hash_value; /* hash value of string using hash function */
} STRING_ENTRY;
/*--------------------
Dictionary signature (AK:04/04/95)
--------------------*/
typedef struct dict_sig_ { /* Dictionary signature */
unsigned long check_value; /* 0xdeadbeef */
int toc_size; /* # of entries in Table of Contents */
long nparms; /* # of parameters */
unsigned long checksum; /* Checksum for TOC */
} DICT_SIG;
/*----------------------------------
Dictionary table of contents entry (AK:04/04/95)
----------------------------------*/
typedef struct TOC_entry_ { /* Dictionary table of contents entry */
char id[5]; /* Field identifier: */
long offset; /* Offset (bytes) of entry in file */
long size; /* Size (bytes) of entry */
void *ptr; /* Where entry is stored in memory */
unsigned long checksum; /* Checksum of entry */
int type; /* 0=ordinary ; 1=EVECTOR ; 2=NULL */
} DICT_TOC_ENTRY;
/*--------------------------------
Dictionary parameter table entry (AK:04/04/95)
--------------------------------*/
typedef struct dict_parm_entry_ { /* Dictionary parameter table entry */
char id[13]; /* Parameter identifier */
unsigned long value; /* Parameter value */
} DICT_PARM_ENTRY;
/*---------------------------
Hash dictionary information
---------------------------*/
typedef struct dictionary {
unsigned long check_value; /* check validation value */
unsigned long flags; /* flag values */
long entry_count; /* number of used entries in each table */
char *string_array; /* storage for strings */
long array_size; /* number of bytes allocated */
long array_used; /* number of bytes occupied */
int array_growth_count; /* number of times grown */
STRING_ENTRY *string_table; /* string table */
long string_max; /* max number of entries in string table */
long scan_string_index; /* current index into string table for scan */
int string_growth_count; /* number of times had to grow string table */
long *chains; /* vector of array indices to hash entries */
int longest_chain_length; /* longest chain length in hash table */
int allowable_chain_length; /* chain lengths always < this */
long table_size; /* number of elements in hash entries vector */
unsigned long hash_mask; /* mask for doing mod() function */
int hash_growth_count; /* number of times had to grow hash table */
void *ext; /* Hook for extensions to the dictionary (AK:04/03/95) */
DICT_SIG *sig; /* Signature (AK:04/04/95) */
DICT_TOC_ENTRY *toc; /* Table of contents (AK:04/04/95) */
DICT_PARM_ENTRY *parm; /* Parameters (AK:04/04/95) */
} DICTIONARY;
/*--------------------------------------------------------------
dict_create: create a dictionary and initialize its structures
--------------------------------------------------------------*/
extern DICTIONARY *dict_create(
const long toc_size,
const long initial_string_count,
const long initial_hash_entries,
const long max_chain_length );
/*-------------------------------------------------
dict_delete: deletes an entry from the dictionary
-------------------------------------------------*/
extern BOOLEANC dict_delete(
const DICTIONARY *dict,
const char *s,
const long count );
/*---------------------------------------------------
dict_destroy: discard a dictionary and its contents
---------------------------------------------------*/
extern BOOLEANC dict_destroy(
DICTIONARY *dict );
/*------------------------------------------------
dict_export: write a dictionary to an ASCII file
------------------------------------------------*/
extern BOOLEANC dict_export(
DICTIONARY *dict,
const char *fname );
/*-------------------------------------------------
dict_import: read a dictionary from an ASCII file
-------------------------------------------------*/
extern DICTIONARY *dict_import(
const char *dict_fname,
const long initial_string_count,
const long initial_hash_entries,
const long max_chain_length );
/*------------------------------------------------------------------
dict_insert: add entries into the dictionary, growing as necessary
------------------------------------------------------------------*/
extern STRING_ENTRY *dict_insert(
DICTIONARY *dict,
char *s,
const long occurences,
const unsigned long flags,
void *any_ptr,
long *number );
/*----------------------------------------------------
dict_load: read a dictionary from a file into memory
----------------------------------------------------*/
extern DICTIONARY *dict_load(
const char *fname );
/*-----------------------------------------------------------------
dict_merge: merges the contents of a dictionary into another one,
updating the contents of the destination
-----------------------------------------------------------------*/
extern BOOLEANC dict_merge(
const DICTIONARY *dst,
const DICTIONARY *src,
const BOOLEANC move );
/*----------------------------------------------------
dict_save: save a dictionary from memory into a file
----------------------------------------------------*/
extern BOOLEANC dict_save(
DICTIONARY *dict,
const char *fname );
/*-----------------------------------------------
dict_scan_begin: begin a scan of the dictionary
-----------------------------------------------*/
extern BOOLEANC dict_scan_begin(
DICTIONARY *dict );
/*--------------------------------------------
dict_scan_next: get the next entry in a scan
--------------------------------------------*/
extern STRING_ENTRY *dict_scan_next(
DICTIONARY *dict );
/*-----------------------------------------------
dict_search: look for entries in the dictionary
-----------------------------------------------*/
extern STRING_ENTRY *dict_search(
const DICTIONARY *dict,
const char *s,
long *number );
/*----------------------------------------------------------------------
dict_string_by_number: return string pointer for a given string number
----------------------------------------------------------------------*/
extern STRING_ENTRY *dict_string_by_number(
const DICTIONARY *dict,
const long number );
/*----------------------------------------------------------
dict_union: merges contents of 2 dictionaries into a third
----------------------------------------------------------*/
extern DICTIONARY *dict_union(
const DICTIONARY *dict1,
const DICTIONARY *dict2 );
#endif /* dict_h_included */

438
urogue/dictutil.c Normal file
View file

@ -0,0 +1,438 @@
/*
dictutil.c
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
/*************************************************************************
** Utilities for Dictionary Maintenence Functions
*************************************************************************/
static char sccsid[] = "%W% %G%";
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if !defined(OS2) && !defined(_WIN32)
#include <unistd.h>
#else
#include <io.h>
#include <fcntl.h>
#endif
#include "dict.h"
#include "dictutil.h"
#include "rogue.h"
int trace;
FILE *ft;
/***********
** Read 'count' characters into 'buffer' at 'offset' in a binary file
** Return 0 on success; -1 on failure;
***********/
int block_read( FILE *fi , char *buffer , size_t count , long offset )
{
if ( fseek(fi,offset,SEEK_SET) == -1 )
return( -1 );
if ( fread(buffer,1,count,fi) != count )
return( -1 );
return( 0 );
}
/***********
** Write 'count' characters from 'buffer' to a binary file.
** Return -1 on failure; 0 on success.
***********/
int block_write( FILE *fo , char *buffer , size_t count )
{
if ( fwrite(buffer,1,count,fo) != count )
return( -1 );
return( 0 );
}
/***********
** Load a dictionary table entry with id TOC_id into memory pointed to by block.
** Update the dictionary TOC.
** If *block=NULL, allocate the block of memory.
** Return 0 on success; -1 on failure.
** Set dt_entry->ptr to where the block is stored.
***********/
void *dict_load_block( DICTIONARY *dict , char *toc_id ,
FILE *fi , void *block )
{ DICT_TOC_ENTRY *dt_entry;
static void *ptr;
int index, ret_code;
index = dict_toc_index( dict , toc_id );
if ( index != -1 ) { /* Found the id */
dt_entry = &(dict->toc[index]);
} else {
signal_error( "dict_load_block: could not find TOC_id" , toc_id , 1 );
return( NULL );
} /* endif */
if ( block == NULL ) {
ptr = malloc( dt_entry->size );
if ( trace > 3 ) {
fprintf( ft , "\ndict_load_block allocates %lx bytes at location %p\n" ,
dt_entry->size , ptr );
} /* endif */
} else {
ptr = block;
if ( trace > 3 ) {
fprintf( ft , "\ndict_load_block uses memory at location %p\n" , ptr );
} /* endif */
} /* endif */
if ( ptr == NULL ) {
signal_error( "dict_load_block: alloc failed " , toc_id , 1 );
return( NULL );
} /* endif */
ret_code = block_read( fi ,
(char*)ptr ,
dt_entry->size ,
dt_entry->offset );
if ( ret_code == -1 )
return( NULL );
if ( dt_entry->checksum !=
compute_checksum( dt_entry->size , (char*)ptr ) ) {
signal_error( "dict_load_block: invalid checksum ", toc_id, 1);
return( NULL );
} /* endif */
dt_entry->ptr = ptr;
if ( trace > 3 ) {
fprintf( ft , "\nLoaded block\nTOC entry: id:%s offset:%lx size:%lx ptr:%p checksum:%lx type:%d\n" ,
dict->toc[index].id , dict->toc[index].offset ,
dict->toc[index].size , dict->toc[index].ptr ,
dict->toc[index].checksum , dict->toc[index].type );
} /* endif */
return( ptr );
}
/***********
** Save a dictionary table entry.
** Update the dictionary TOC entry offset and checksum fields.
** Return 0 on success, -1 on failure.
** Note: It is assumed that the size and pointer fields in TOC entry are
** already up to date; i.e., that they are consistent with the current
** location and size of the block being written. This is essential
** because the table of contents must have already been written
** into the file.
***********/
BOOLEANC dict_save_block( DICTIONARY *dict , char *toc_id , FILE *fo )
{ DICT_TOC_ENTRY *dt_entry;
int index, ret_code;
char *block;
index = dict_toc_index( dict , toc_id );
if ( index == -1 ) {
signal_error( "dict_save_block: id not found " , toc_id , 1 );
return( FALSE );
} /* endif */
dt_entry = &(dict->toc[index]);
block = (char*)(dt_entry->ptr);
if ( block == NULL ) {
signal_error( "dict_save_block: NULL block " , toc_id , 1 );
return( FALSE );
} /* endif */
/* dt_entry->offset = fseek( fo , 0 , SEEK_END ); */
dt_entry->checksum = compute_checksum( dt_entry->size , block );
ret_code = block_write( fo , dt_entry->ptr , dt_entry->size );
if ( ret_code == -1 ) {
signal_error( "dict_save_block: block_write failed " , toc_id , 1 );
return( FALSE );
} /* endif */
if ( trace > 3 ) {
fprintf( ft , "\nStored block\nTOC entry: id:%s offset:%lx size:%lx ptr:%p checksum:%lx type:%d\n" ,
dict->toc[index].id , dict->toc[index].offset ,
dict->toc[index].size , dict->toc[index].ptr ,
dict->toc[index].checksum , dict->toc[index].type );
} /* endif */
return( TRUE );
}
/***********
** Look up and id in the table of contents.
** Return its index (-1 on failure).
***********/
int dict_toc_index( DICTIONARY *dict , char *toc_id )
{ int index;
for ( index = 0 ; index < dict->sig->toc_size ; index++ ) {
if ( strcmp(dict->toc[index].id,toc_id) == 0 )
return( index );
} /* endfor */
return( -1 );
}
/***********
** Compute a block checksum.
** (Currently just returns 0.)
***********/
unsigned long compute_checksum( size_t size , char *block )
{
NOOP(size);
NOOP(block);
return( 0 );
}
/***********
** Create a dictionary paramter entry.
***********/
DICT_PARM_ENTRY *dict_make_parm_entry( char *id , unsigned long value )
{ static DICT_PARM_ENTRY *entry;
entry = (DICT_PARM_ENTRY *) malloc( sizeof(DICT_PARM_ENTRY) );
if ( entry == NULL )
return(NULL);
strncpy( entry->id , id , 13 );
entry->value = value;
return( entry );
}
/***********
** Look up and id in the parameter array.
** Return its index (-1 on failure).
***********/
int dict_parm_index( DICTIONARY *dict , char *parm_id )
{ long index;
for ( index = 0 ; index < dict->sig->nparms ; index++ ) {
if ( strcmp( dict->parm[index].id , parm_id ) == 0 )
return( (int) index );
} /* endfor */
return( -1 );
}
/***********
** Reset table of contents offsets and checksums
** in preparation for dict_save().
***********/
BOOLEANC dict_reset_toc_offsets( DICTIONARY *dict )
{ int i;
long offset;
offset = sizeof(DICT_SIG)
+ dict->sig->toc_size * sizeof(DICT_TOC_ENTRY);
for ( i = 0 ; i < dict->sig->toc_size ; i++ ) {
dict->toc[i].offset = offset;
offset += dict->toc[i].size;
dict->toc[i].checksum =
compute_checksum( dict->toc[i].size , dict->toc[i].ptr );
} /* endfor */
return( TRUE );
}
/***********
** Load the names of the dictionary parameters.
** 14 parms
***********/
BOOLEANC dict_set_parm_ids( DICTIONARY *dict )
{
if ( dict==NULL || dict->sig == NULL ) {
signal_error( "dict_set_parm_ids: Allocate dict and signature first." , "" , 0 );
return( FALSE );
}
dict->sig->nparms = 14;
strcpy( dict->parm[0].id , "FLAGS_______" );
strcpy( dict->parm[1].id , "ENTRY_COUNT_" );
strcpy( dict->parm[2].id , "ARRAY_SIZE__" );
strcpy( dict->parm[3].id , "ARRAY_USED__" );
strcpy( dict->parm[4].id , "ARR_GROW_CT_" );
strcpy( dict->parm[5].id , "STRING_MAX__" );
strcpy( dict->parm[6].id , "STR_GROW_CT_" );
strcpy( dict->parm[7].id , "LONG_CHAIN__" );
strcpy( dict->parm[8].id , "ALLOW_CHAIN_" );
strcpy( dict->parm[9].id , "HASH_TAB_SIZ" );
strcpy( dict->parm[10].id , "HASH_MASK___" );
strcpy( dict->parm[11].id , "HASH_GROW_CT" );
strcpy( dict->parm[12].id , "CHECK_VALUE_" );
strcpy( dict->parm[13].id , "SCAN_STR_IX_" );
return( TRUE );
}
/***********
** Set the dictionary parm structure from the values in the dict structure.
** 14 parms
***********/
BOOLEANC dict_set_parm_values( DICTIONARY *dict )
{ int index;
if ( (index=dict_parm_index(dict,"FLAGS_______")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->flags;
if ( (index=dict_parm_index(dict,"ENTRY_COUNT_")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->entry_count;
if ( (index=dict_parm_index(dict,"ARRAY_SIZE__")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->array_size;
if ( (index=dict_parm_index(dict,"ARRAY_USED__")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->array_used;
if ( (index=dict_parm_index(dict,"ARR_GROW_CT_")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->array_growth_count;
if ( (index=dict_parm_index(dict,"STRING_MAX__")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->string_max;
if ( (index=dict_parm_index(dict,"STR_GROW_CT_")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->string_growth_count;
if ( (index=dict_parm_index(dict,"LONG_CHAIN__")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->longest_chain_length;
if ( (index=dict_parm_index(dict,"ALLOW_CHAIN_")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->allowable_chain_length;
if ( (index=dict_parm_index(dict,"HASH_TAB_SIZ")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->table_size;
if ( (index=dict_parm_index(dict,"HASH_MASK___")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->hash_mask;
if ( (index=dict_parm_index(dict,"HASH_GROW_CT")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->hash_growth_count;
if ( (index=dict_parm_index(dict,"CHECK_VALUE_")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->check_value;
if ( (index=dict_parm_index(dict,"SCAN_STR_IX_")) == -1 )
return( FALSE );
dict->parm[index].value = (unsigned long)dict->scan_string_index;
return( TRUE );
}
/***********
** Set the values in the dict structure from the dictionary parm structure.
** 14 parms
***********/
BOOLEANC dict_set_parm_variables( DICTIONARY *dict )
{ int index;
if ( (index=dict_parm_index(dict,"FLAGS_______")) == -1 )
return( FALSE );
dict->flags = (unsigned long)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"ENTRY_COUNT_")) == -1 )
return( FALSE );
dict->entry_count = (long)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"ARRAY_SIZE__")) == -1 )
return( FALSE );
dict->array_size = (long)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"ARRAY_USED__")) == -1 )
return( FALSE );
dict->array_used = (long)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"ARR_GROW_CT_")) == -1 )
return( FALSE );
dict->array_growth_count = (int)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"STRING_MAX__")) == -1 )
return( FALSE );
dict->string_max = (long)dict->parm[index].value ;
if ( (index=dict_parm_index(dict,"STR_GROW_CT_")) == -1 )
return( FALSE );
dict->string_growth_count = (int)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"LONG_CHAIN__")) == -1 )
return( FALSE );
dict->longest_chain_length = (int)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"ALLOW_CHAIN_")) == -1 )
return( FALSE );
dict->allowable_chain_length = (int)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"HASH_TAB_SIZ")) == -1 )
return( FALSE );
dict->table_size = (long)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"HASH_MASK___")) == -1 )
return( FALSE );
dict->hash_mask = (unsigned long)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"HASH_GROW_CT")) == -1 )
return( FALSE );
dict->hash_growth_count = (int)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"CHECK_VALUE_")) == -1 )
return( FALSE );
dict->check_value = (unsigned long)dict->parm[index].value;
if ( (index=dict_parm_index(dict,"SCAN_STR_IX_")) == -1 )
return( FALSE );
dict->scan_string_index = (long)dict->parm[index].value;
return( TRUE );
}
/***********
** If trace (global) > 0 , signal an error
** If severity > 0 , abort
***********/
void signal_error( char *header , char *message , int severity )
{
FILE *fpe;
if ( trace > 0 ) {
printf( "%s: %s\n" , header , message );
fpe = fopen( "ERROR.FIL" , "a" );
fprintf( fpe , "\n%s: %s\n" , header , message );
fclose( fpe );
} /* endif */
if ( severity > 0 )
abort();
}

116
urogue/dictutil.h Normal file
View file

@ -0,0 +1,116 @@
/*
dictutil.h
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
/****************************************************************/
/* HEADERS FOR DICTIONARY MAINTENENCE ROUTINE UTILITIES */
/****************************************************************/
#ifndef dictutil_h_included
#define dictutil_h_included
static char dictutil_sccsid[] = "%W% %G%";
#include <stdio.h>
#include "dict.h"
/*-------------------------------
Binary read of a block of bytes
-------------------------------*/
extern int block_read(
FILE *fi,
char *buffer,
size_t count,
long offset );
/*--------------------------------
Binary write of a block of bytes
--------------------------------*/
extern int block_write(
FILE *fo,
char *buffer,
size_t count );
/*--------------------------------------
Compute a checksum of a block of bytes
--------------------------------------*/
extern unsigned long compute_checksum(
size_t size,
char *block );
/*-----------------------------------------------------------------
Load a block of bytes from a compiled dictionary file into memory
-----------------------------------------------------------------*/
extern void *dict_load_block(
DICTIONARY *dict,
char *toc_id,
FILE *fi,
void *block );
/*-----------------------------------
Create a dictionary parameter entry
-----------------------------------*/
extern DICT_PARM_ENTRY *dict_make_parm_entry(
char *id,
unsigned long value );
/*------------------------------------
Look up an id in the parameter array
------------------------------------*/
extern int dict_parm_index(
DICTIONARY *dict,
char *parm_id );
/*-------------------------------
Reset table of contents offsets
-------------------------------*/
extern BOOLEANC dict_reset_toc_offsets(
DICTIONARY *dict );
/*-----------------------------------------------------------------
Save a block of bytes from memory into a compiled dictionary file
-----------------------------------------------------------------*/
extern BOOLEANC dict_save_block(
DICTIONARY *dict,
char *toc_id,
FILE *fo );
/*--------------------------------------------------------------------
Set the dictionary parm values from the values in the dict structure
--------------------------------------------------------------------*/
extern BOOLEANC dict_set_parm_values(
DICTIONARY *dict );
/*--------------------------------------------------------------------
Set the values in the dict structure from the dictionary parm values
--------------------------------------------------------------------*/
extern BOOLEANC dict_set_parm_variables(
DICTIONARY *dict );
/*---------------------------
Set the dictionary parm ids
---------------------------*/
extern BOOLEANC dict_set_parm_ids(
DICTIONARY *dict );
/*--------------------------------------
Look up an id in the table of contents
--------------------------------------*/
extern int dict_toc_index(
DICTIONARY *dict,
char *toc_id );
/*------------------------------------
Record and error and abort if needed
------------------------------------*/
extern void signal_error(
char *header,
char *message,
int severity );
#endif

185
urogue/encumb.c Normal file
View file

@ -0,0 +1,185 @@
/*
encumb.c - Stuff to do with encumberance
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "rogue.h"
/*
updpack()
Update his pack weight and adjust fooduse accordingly
*/
void
updpack(void)
{
int curcarry = packweight();
pstats.s_carry = totalenc(); /* update max encumb */
if (is_carrying(TR_PURSE))
pstats.s_carry += 1000;
foodlev = 0;
switch ((curcarry * 5) / pstats.s_carry) /* % of total capacity */
{
case 5: /* 100 % */
foodlev++;
case 4: /* 80 % */
if (rnd(100) < 80)
foodlev++;
case 3: /* 60 % */
if (rnd(100) < 60)
foodlev++;
case 2: /* 40 % */
if (rnd(100) < 40)
foodlev++;
case 1: /* 20 % */
if (rnd(100) < 20)
foodlev++;
case 0: /* 0 % */
foodlev++;
}
pstats.s_pack = curcarry; /* update pack weight */
if (is_carrying(TR_PURSE)) /* makes pack lighter */
foodlev--;
}
/*
packweight()
Get the total weight of the hero's pack
*/
int
packweight(void)
{
struct linked_list *pc;
int weight = 0;
for (pc = pack; pc != NULL; pc = next(pc))
{
struct object *obj = OBJPTR(pc);
weight += itemweight(obj) * obj->o_count;
}
if (weight < 0) /* caused by artifacts or blessed items */
weight = 0;
return (weight);
}
/*
itemweight()
Get the weight of an object
*/
int
itemweight(struct object *wh)
{
int weight = wh->o_weight; /* get base weight */
int ac;
switch (wh->o_type)
{
case ARMOR: /* 10% for each plus or minus*/
ac = armors[wh->o_which].a_class - wh->o_ac;
weight *= (10 - ac) / 10;
break;
case WEAPON:
if ((wh->o_hplus + wh->o_dplus) > 0)
weight /= 2;
}
if (wh->o_flags & ISCURSED)
weight += weight / 2; /* +50% for cursed */
else if (wh->o_flags & ISBLESSED)
weight -= weight / 5; /* -20% for blessed */
if (weight < 0)
weight = 0;
return (weight);
}
/*
playenc()
Get hero's carrying ability above norm 50 units per point of STR
over 10, 300 units per plus on R_CARRYING 1000 units for TR_PURSE
*/
int
playenc(void)
{
int ret_val = (pstats.s_str - 10) * 50;
if (is_wearing(R_CARRYING))
ret_val += ring_value(R_CARRYING) * 300;
return (ret_val);
}
/*
totalenc()
Get total weight that the hero can carry
*/
int
totalenc(void)
{
int wtotal = 1400 + playenc();
switch (hungry_state)
{
case F_OK:
case F_HUNGRY: /* no change */
break;
case F_WEAK:
wtotal -= wtotal / 4; /* 25% off weak */
break;
case F_FAINT:
wtotal /= 2; /* 50% off faint */
break;
}
return (wtotal);
}
/*
hitweight()
Gets the fighting ability according to current weight This
returns a +2 hit for very light pack weight, +1 hit
for light pack weight, 0 hit for medium pack weight, -1 hit for heavy
pack weight, -2 hit for very heavy pack weight
*/
int
hitweight(void)
{
return(3 - foodlev);
}

2175
urogue/fight.c Normal file

File diff suppressed because it is too large Load diff

350
urogue/getplay.c Normal file
View file

@ -0,0 +1,350 @@
/*
getplay.c - Procedures for saving and retrieving a characters starting
attributes, armour, and weapon.
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
/* 11/08/83 ???, S.A. Hester */
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"
#define I_STR 0
#define I_INTEL 1
#define I_WISDOM 2
#define I_DEXT 3
#define I_CONST 4
#define I_CHARISMA 5
#define I_HPT 6
#define I_POWER 7
#define I_CTYPE 8
#define MAXPATT 9 /* Total Number of above defines. */
#define MAXPDEF 10 /* Maximum number of pre-defined chars */
static int def_array[MAXPDEF][MAXPATT]; /* Pre-def'd chars */
static void get_chr_filename(char *filename, int size)
{
const char *home;
home = getenv("HOME");
if (home) {
if ((int)strlen(home) < (size - 12) )
{
strcpy(filename, home);
strcat(filename,"/urogue.chr");
}
else
strncpy(filename,"urogue.chr",size);
}
else
strcpy(filename, "urogue.chr");
}
int
geta_player(void)
{
int i;
FILE *fd;
char pbuf[2 * LINELEN];
char filename[200];
get_chr_filename(filename, sizeof(filename));
if ((fd = fopen(filename, "r")) == NULL)
return(FALSE);
fread(def_array, sizeof(def_array), 1, fd);
fclose(fd);
wclear(hw);
touchwin(hw);
print_stored();
mvwaddstr(hw, 0, 0, "Do you wish to select a character? ");
wrefresh(hw);
if (readcharw(hw) != 'y')
return FALSE;
do
{
wmove(hw, LINES - 1, 0);
wclrtoeol(hw);
mvwaddstr(hw, 0, 0, "Enter the number of a pre-defined character: ");
wclrtoeol(hw);
wrefresh(hw);
get_string(pbuf, hw);
i = atoi(pbuf) - 1;
if (i < 0 || i > MAXPDEF - 1)
{
wstandout(hw);
mvwaddstr(hw, 1, 0, "Please use the range 1 to");
wprintw(hw, " %d.", MAXPDEF);
wstandend(hw);
wclrtoeol(hw);
wrefresh(hw);
}
else if (def_array[i][I_STR] == 0)
{
wstandout(hw);
mvwaddstr(hw,1,0,"Please enter the number of a known character: ");
wstandend(hw);
wclrtoeol(hw);
}
else
{
mvwaddstr(hw, 1, 0, "");
wclrtoeol(hw);
}
}
while (i < 0 || i > MAXPDEF - 1 || (def_array[i][I_STR] == 0));
pstats.s_str = def_array[i][I_STR];
pstats.s_intel = def_array[i][I_INTEL];
pstats.s_wisdom = def_array[i][I_WISDOM];
pstats.s_dext = def_array[i][I_DEXT];
pstats.s_const = def_array[i][I_CONST];
pstats.s_charisma = def_array[i][I_CHARISMA];
pstats.s_hpt = def_array[i][I_HPT];
pstats.s_power = def_array[i][I_POWER];
player.t_ctype = char_type = def_array[i][I_CTYPE];
max_stats = pstats;
return(TRUE);
}
void
puta_player(void)
{
FILE *fd;
char pbuf[2 * LINELEN];
char filename[200];
int i;
char *class = which_class(player.t_ctype);
sprintf(pbuf, "You have a %s with the following attributes:", class);
mvwaddstr(hw, 2, 0, pbuf);
wclrtoeol(hw);
sprintf(pbuf,
"Int: %d Str: %d Wis: %d Dex: %d Con: %d Cha: %d Pow: %d Hpt: %d",
pstats.s_intel,
pstats.s_str,
pstats.s_wisdom,
pstats.s_dext,
pstats.s_const,
pstats.s_charisma,
pstats.s_power,
pstats.s_hpt );
mvwaddstr(hw, 3, 0, "");
wclrtoeol(hw);
mvwaddstr(hw, 4, 0, pbuf);
wclrtoeol(hw);
mvwaddstr(hw, 5, 0, "");
wclrtoeol(hw);
mvwaddstr(hw, 0, 0, "Would you like to save this character?");
wclrtoeol(hw);
wrefresh(hw);
if ((readcharw(hw) & 0177) != 'y')
return;
do
{
mvwaddstr(hw, 0, 0, "Overwrite which number? ");
wclrtoeol(hw);
wrefresh(hw);
get_string(pbuf, hw);
i = atoi(pbuf) - 1;
if (i < 0 || i > MAXPDEF - 1)
{
wstandout(hw);
mvwaddstr(hw, 1, 0, "Use the range 1 to");
wprintw(hw, " %d!", MAXPDEF);
wstandend(hw);
wclrtoeol(hw);
wrefresh(hw);
}
}
while (i < 0 || i > MAXPDEF - 1);
/* Set some global stuff */
def_array[i][I_STR] = pstats.s_str;
def_array[i][I_INTEL] = pstats.s_intel;
def_array[i][I_WISDOM] = pstats.s_wisdom;
def_array[i][I_DEXT] = pstats.s_dext;
def_array[i][I_CONST] = pstats.s_const;
def_array[i][I_CHARISMA] = pstats.s_charisma;
def_array[i][I_HPT] = pstats.s_hpt;
def_array[i][I_POWER] = pstats.s_power;
def_array[i][I_CTYPE] = player.t_ctype;
/* OK. Now let's write this stuff out! */
get_chr_filename(filename, sizeof(filename));
if ((fd = fopen(filename, "w")) == NULL)
{
sprintf(pbuf, "I can't seem to open/create urogue.chr.");
mvwaddstr(hw, 5, 5, pbuf);
mvwaddstr(hw, 6, 5, "However I'll let you play it anyway!");
mvwaddstr(hw, LINES - 1, 0, spacemsg);
wrefresh(hw);
wait_for(' ');
return;
}
fwrite(def_array, sizeof(def_array), 1, fd);
fclose(fd);
return;
}
void
do_getplayer(void)
{
print_stored();
if (char_type == C_NOTSET)
do
{
/* See what type character will be */
mvwaddstr(hw, 3, 0, "[a] Fighter\t"
"[b] Paladin\t"
"[c] Ranger\n"
"[d] Cleric\t"
"[e] Druid\t"
"[f] Magician\n"
"[g] Illusionist\t"
"[h] Thief\t"
"[i] Assasin\t"
"[j] Ninja");
mvwaddstr(hw, 0, 0, "What character class do you desire? ");
wrefresh(hw);
char_type = readcharw(hw) - 'a';
if (char_type < C_FIGHTER || char_type >= C_MONSTER)
{
wstandout(hw);
mvwaddstr(hw, 1, 0, "Please enter a letter from a - j");
wstandend(hw);
wclrtoeol(hw);
wrefresh(hw);
}
else
{
mvwaddstr(hw, 1, 0, "");
wclrtoeol(hw);
}
}
while (char_type < C_FIGHTER || char_type >= C_MONSTER);
player.t_ctype = char_type;
}
void
print_stored(void)
{
int i;
char *class;
char pbuf[2 * LINELEN];
wstandout(hw);
mvwaddstr(hw, 9, 0, "YOUR CURRENT CHARACTERS:");
wstandend(hw);
wclrtoeol(hw);
for (i = 0; i < MAXPDEF; i++)
{
if (def_array[i][I_STR])
{
class = which_class(def_array[i][I_CTYPE]);
sprintf(pbuf,
"%2d. (%s): Int: %d Str: %d Wis: %d Dex: %d Con: %d Cha: %d"
" Pow: %d Hpt: %d",
i + 1,
class,
def_array[i][I_INTEL],
def_array[i][I_STR],
def_array[i][I_WISDOM],
def_array[i][I_DEXT],
def_array[i][I_CONST],
def_array[i][I_CHARISMA],
def_array[i][I_POWER],
def_array[i][I_HPT]);
mvwaddstr(hw, 11 + i, 0, pbuf);
}
else
{
sprintf(pbuf, "%2d. ### NONE ###", i + 1);
mvwaddstr(hw, 11 + i, 0, pbuf);
}
}
}
char *
which_class(int c_class)
{
char *class;
switch (c_class)
{
case C_FIGHTER:
class = "Fighter";
break;
case C_MAGICIAN:
class = "Magician";
break;
case C_CLERIC:
class = "Cleric";
break;
case C_THIEF:
class = "Thief";
break;
case C_PALADIN:
class = "Paladin";
break;
case C_RANGER:
class = "Ranger";
break;
case C_DRUID:
class = "Druid";
break;
case C_ILLUSION:
class = "Illusionist";
break;
case C_ASSASIN:
class = "Assasin";
break;
case C_NINJA:
class = "Ninja";
break;
default:
class = "Monster";
break;
}
return (class);
}

1469
urogue/history.txt Normal file

File diff suppressed because it is too large Load diff

136
urogue/ident.c Normal file
View file

@ -0,0 +1,136 @@
/*
ident.c - routines to associate an identifier with an object
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1986, 1991, 1993, 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* ident
*
* This file contains routines to associate an identifier with an object. The
* identifiers are organized by type. Once an identifier is attached to an
* object, it remains with that object until the object is removed from the
* game. The identifiers are small integers, and they are assigned merely by
* counting objects of the same type. Allocation picks the next available
* integer.
*
* It is required that the linked list be sorted within types so that gaps can
* easily be detected.
*/
#include "rogue.h"
/*
* Index of 0 is invalid (unused state)
*/
char print_letters[] = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
linked_list *ident_list = NULL; /* master list of all items */
/*
get_ident()
Gets the identifier for the given object. If an identifier exists, it is
returned. If not, one is allocated and returned to the user. The
identifier remains constant as long as the object is in the game.
*/
int
get_ident(struct object *obj_p)
{
int obj_type = obj_p->o_type;
linked_list *list_p; /* pointer into ident_list */
int new_id = 1; /* in case we have to allocate */
struct object *tmp_obj_p;
struct linked_list *new_place_p = NULL;
if (identifier(obj_p) != 0)
return (identifier(obj_p));
/* no identifier - must allocate one */
for (list_p = ident_list; list_p != NULL; list_p = next(list_p))
{
tmp_obj_p = OBJPTR(list_p);
if (tmp_obj_p->o_type == obj_type)
{
if (identifier(tmp_obj_p) == new_id)
{
/* if this id is taken, try next */
new_place_p = list_p;
new_id++;
}
}
}
/*
* If we get here, the object is not in the list, and we need to add
* it. The proper id is in new_id, and the place to put it is right
* after new_place_p.
*/
list_p = new_list();
_attach_after(&ident_list, new_place_p, list_p);
identifier(obj_p) = new_id;
list_p->data.obj = obj_p;
return(new_id);
}
/*
free_ident()
Frees up an identifier by removing the list entry that contains that item.
If the item isn't found, nothing is done.
*/
void
free_ident(struct object *obj_p)
{
linked_list *list_p;
for (list_p = ident_list; list_p != NULL; list_p = next(list_p))
{
if (obj_p == OBJPTR(list_p))
{
_detach(&ident_list, list_p); /* unlink it from the list */
ur_free(list_p); /* release link structure */
break;
}
}
}
/*
unprint_id()
Converts a printable id from print_letters to the real thing by getting the
index.
*/
int
unprint_id(char *print_id)
{
char *id_p;
for (id_p = print_letters; id_p != NULL; id_p++)
if (*id_p == *print_id)
break;
return( (int) (id_p - print_letters) );
}
/*
max_print()
returns the size of the print list
*/
int
max_print(void)
{
return(sizeof(print_letters) - 2); /* 1 for blank and 1 for EOS string */
}

1075
urogue/init.c Normal file

File diff suppressed because it is too large Load diff

471
urogue/io.c Normal file
View file

@ -0,0 +1,471 @@
/*
io.c - Various input/output functions
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include "rogue.h"
char prbuf[2 * LINELEN]; /* Buffer for sprintfs */
static char mbuf[2*LINELEN]; /* Current message buffer */
static int newpos = 0; /* index in mbuf to end of msg */
int mpos = 0; /* 0 = Overwrite existing message */
/* >0 = print --More-- at this pos */
/* and wait for key */
int line_cnt = 0;
int newpage = FALSE;
/*
msg()
Display a message at the top of the screen.
*/
void
msg(const char *fmt, ...)
{
va_list ap;
/* if the string is "", just clear the line */
if (*fmt == '\0')
{
wmove(cw, 0, 0);
wclrtoeol(cw);
mpos = 0;
return;
}
/* otherwise add to the message and flush it out */
va_start(ap, fmt);
doadd(fmt, ap);
va_end(ap);
endmsg();
}
void
vmsg(const char *fmt, va_list ap)
{
/* if the string is "", just clear the line */
if (*fmt == '\0')
{
wmove(cw, 0, 0);
wclrtoeol(cw);
mpos = 0;
return;
}
/* otherwise add to the message and flush it out */
doadd(fmt, ap);
endmsg();
}
/*
addmsg()
add things to the current message
*/
void
addmsg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
doadd(fmt,ap);
va_end(ap);
}
/*
endmsg()
Display a new msg (giving him a chance to see the previous one
if it is up there with the --More--)
*/
void
endmsg(void)
{
strcpy(msgbuf[msg_index], mbuf);
msg_index = ++msg_index % 10;
if (mpos)
{
wmove(cw, 0, mpos);
wprintw(cw, (char *) morestr);
wrefresh(cw);
wait_for(' ');
}
mvwprintw(cw, 0, 0, mbuf);
wclrtoeol(cw);
mpos = newpos;
newpos = 0;
wrefresh(cw);
}
void
doadd(const char *fmt, va_list ap)
{
vsprintf(&mbuf[newpos], fmt, ap);
newpos = (int) strlen(mbuf);
}
/*
status()
Display the important stats line. Keep the cursor where it was.
*/
void
status(int display)
{
static char buf[1024]; /* Temporary buffer */
struct stats *stat_ptr, *max_ptr;
int oy, ox;
stat_ptr = &pstats;
max_ptr = &max_stats;
getyx(cw, oy, ox);
sprintf(buf,
"Int:%d(%d) Str:%d(%d) Wis:%d(%d) Dex:%d(%d) Con:%d(%d) Carry:%d(%d) %d",
stat_ptr->s_intel, max_ptr->s_intel,
stat_ptr->s_str, max_ptr->s_str,
stat_ptr->s_wisdom, max_ptr->s_wisdom,
stat_ptr->s_dext, max_ptr->s_dext,
stat_ptr->s_const, max_ptr->s_const,
stat_ptr->s_pack / 10, stat_ptr->s_carry / 10, foodlev );
mvwaddstr(cw, LINES - 2, 0, buf);
wclrtoeol(cw);
sprintf(buf, "Lvl:%d Au:%d Hpt:%3d(%3d) Pow:%d(%d) Ac:%d Exp:%d+%ld %s",
level,
purse,
stat_ptr->s_hpt, max_ptr->s_hpt,
stat_ptr->s_power, max_ptr->s_power,
(cur_armor != NULL ? (cur_armor->o_ac - 10 + stat_ptr->s_arm)
: stat_ptr->s_arm) - ring_value(R_PROTECT),
stat_ptr->s_lvl,
stat_ptr->s_exp,
cnames[player.t_ctype][min(stat_ptr->s_lvl - 1, 14)]);
mvwaddstr(cw, LINES - 1, 0, buf);
switch(hungry_state)
{
case F_OK: break;
case F_HUNGRY: waddstr(cw, " Hungry");
break;
case F_WEAK: waddstr(cw, " Weak");
break;
case F_FAINT: waddstr(cw, " Fainting");
break;
}
wclrtoeol(cw);
wmove(cw, oy, ox);
if (display)
wrefresh(cw);
}
/*
* readchar:
* Flushes stdout so that screen is up to date and then returns
* getchar().
*/
char
readcharw(WINDOW *win)
{
char ch;
ch = (char) md_readchar(win);
if ((ch == 3) || (ch == 0))
{
quit();
return(27);
}
return(ch);
}
char
readchar()
{
return( readcharw(cw) );
}
/*
wait_for()
Sit around until the guy types the right key
*/
void
w_wait_for(WINDOW *w, int ch)
{
char c;
if (ch == '\n')
while ((c = readcharw(w)) != '\n' && c != '\r')
continue;
else
while (readcharw(w) != ch)
continue;
}
void
wait_for(int ch)
{
w_wait_for(cw, ch);
}
/*
show_win()
function used to display a window and wait before returning
*/
void
show_win(WINDOW *scr, char *message)
{
mvwaddstr(scr, 0, 0, message);
touchwin(scr);
wmove(scr, hero.y, hero.x);
wrefresh(scr);
wait_for(' ');
clearok(cw, TRUE);
touchwin(cw);
}
/*
restscr()
Restores the screen to the terminal
*/
void
restscr(WINDOW *scr)
{
clearok(scr, TRUE);
touchwin(scr);
}
/*
add_line()
Add a line to the list of discoveries
*/
void
add_line(const char *fmt, ...)
{
WINDOW *tw;
va_list ap;
va_start(ap, fmt);
if (line_cnt == 0)
{
wclear(hw);
if (inv_type == INV_SLOW)
mpos = 0;
}
if (inv_type == INV_SLOW)
{
if ( (fmt != NULL) && (*fmt != '\0') )
vmsg(fmt, ap);
line_cnt++;
}
else
{
if ( (line_cnt >= LINES - 2) || (fmt == NULL)) /* end 'o page */
{
if (fmt == NULL && !newpage && inv_type == INV_OVER)
{
tw = newwin(line_cnt + 2, COLS, 0, 0);
overwrite(hw, tw);
wstandout(tw);
mvwaddstr(tw, line_cnt, 0, spacemsg);
wstandend(tw);
touchwin(tw);
wrefresh(tw);
wait_for(' ');
delwin(tw);
touchwin(cw);
}
else
{
wstandout(hw);
mvwaddstr(hw, LINES - 1, 0, spacemsg);
wstandend(hw);
wrefresh(hw);
w_wait_for(hw, ' ');
touchwin(cw);
wclear(hw);
}
newpage = TRUE;
line_cnt = 0;
}
/* draw line */
if (fmt != NULL && !(line_cnt == 0 && *fmt == '\0'))
{
static char tmpbuf[1024];
vsprintf(tmpbuf, fmt, ap);
mvwprintw(hw, line_cnt++, 0, tmpbuf);
}
}
}
/*
end_line()
End the list of lines
*/
void
end_line(void)
{
if (inv_type != INV_SLOW)
add_line(NULL);
line_cnt = 0;
newpage = FALSE;
}
/*
hearmsg()
Call msg() only if you are not deaf
*/
void
hearmsg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (off(player, ISDEAF))
vmsg(fmt, ap);
else if (wizard)
{
msg("Couldn't hear: ");
vmsg(fmt, ap);
}
va_end(ap);
}
/*
seemsg()
Call msg() only if you are not blind
*/
void
seemsg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (off(player, ISBLIND))
vmsg(fmt, ap);
else if (wizard)
{
msg("Couldn't see: ");
vmsg(fmt, ap);
}
va_end(ap);
}
int
get_string(char *buffer, WINDOW *win)
{
char *sp, c;
int oy, ox;
char buf[2 * LINELEN];
wrefresh(win);
getyx(win, oy, ox);
/* loop reading in the string, and put it in a temporary buffer */
for (sp = buf; (c = readcharw(win)) != '\n' &&
c != '\r' &&
c != '\033' &&
c != '\007' &&
sp < &buf[LINELEN - 1];
wclrtoeol(win), wrefresh(win))
{
if ((c == '\b') || (c == 0x7f))
{
if (sp > buf)
{
size_t i;
sp--;
for (i = strlen(unctrl(*sp)); i; i--)
waddch(win, '\b');
}
continue;
}
else if (c == '\0')
{
sp = buf;
wmove(win, oy, ox);
continue;
}
else if (sp == buf && c == '-' && win == hw)
break;
*sp++ = c;
waddstr(win, unctrl(c));
}
*sp = '\0';
if (sp > buf) /* only change option if something has been typed */
strncpy(buffer, buf, strlen(buf)+1);
wmove(win, oy, ox);
waddstr(win, buffer);
waddch(win, '\n');
wrefresh(win);
if (win == cw)
mpos += (int)(sp - buf);
if (c == '-')
return(MINUS);
else if (c == '\033' || c == '\007')
return(QUIT);
else
return(NORM);
}

69
urogue/lint-curses.h Normal file
View file

@ -0,0 +1,69 @@
/*
lint-curses.h
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1993, 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
/* Sufficient info to pass lint */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define getyx(win,y,x) y = win->_cury, x = win->_curx
struct screen { int opque_data_type; };
typedef struct { int _cury; int _curx; } WINDOW;
extern WINDOW *stdscr;
extern WINDOW *curscr;
extern int LINES;
extern int COLS;
extern char *unctrl(char c);
extern void initscr(void);
extern int wmove(WINDOW *window, int Line, int Column);
extern int move(int Line, int Column);
extern int addch(char c);
extern int mvaddch(int y, int x, char c);
extern int waddch(WINDOW *window, char c);
extern int mvwaddch(WINDOW *window, int y, int x, char c);
extern int mvwinch(WINDOW *window, int y, int x);
extern int winch(WINDOW *window);
extern int mvinch(int y, int x);
extern int getch(void);
extern int wgetch(WINDOW *window);
extern void clear(void);
extern void wclear(WINDOW *window);
extern void refresh(void);
extern void wrefresh(WINDOW *window);
extern void clearok(WINDOW *window, int flag);
extern void endwin(void);
extern void touchwin(WINDOW *window);
extern void overlay(WINDOW *w1, WINDOW *w2);
extern void wclrtoeol(WINDOW *window);
extern void wprintw(WINDOW *window, const char *fmt, ...);
extern void mvprintw(int line, int col, char *fmt, ...);
extern void mvwprintw(WINDOW *window, int line, int col, char *fmt, ...);
extern int mvwaddstr(WINDOW *window, int y, int x, const char *str);
extern int mvaddstr(int y, int x, char *str);
extern int waddstr(WINDOW *window, char *str);
extern int addstr(char *str);
extern void standout(void);
extern void wstandout(WINDOW *window);
extern void standend(void);
extern void wstandend(WINDOW *window);
extern void noecho(void);
extern void cbreak(void);
extern void crmode(void);
extern void nonl(void);
extern void nl(void);
extern int wgetch(WINDOW *window);
extern WINDOW *newwin(int lines, int cols, int y, int x);
extern void overwrite(WINDOW *w1, WINDOW *w2);
extern void delwin(WINDOW *window);
extern void printw(char *fmt, ...);

222
urogue/list.c Normal file
View file

@ -0,0 +1,222 @@
/*
list.c - Functions for dealing with linked lists of goodies
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "rogue.h"
static char errbuf[2 * LINELEN];
/*
ur_alloc()
ur_free()
These are just calls to the system alloc and free, and they also adjust
the totals. The buffer is cleared out because idents need to be zero
before going into the pack, or they will be used as indices!
*/
void *
ur_alloc(size_t size)
{
char *buf_p;
total++;
buf_p = mem_malloc(size);
if (buf_p == NULL)
return(NULL);
memset(buf_p,0,size);
return(buf_p);
}
void
ur_free(void *buf_p)
{
mem_free(buf_p);
total--;
}
/*
detach()
Takes an item out of whatever linked list it might be in
.... function needs to be renamed....
*/
void
_detach(struct linked_list **list, struct linked_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
... this needs to be renamed as well ...
*/
void
_attach(struct linked_list **list, struct linked_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;
}
/*
_attach_after()
Attaches the given item after the supplied one in the list. If the listed
item is NULL, the new item is attached at the head of the list.
*/
void
_attach_after(linked_list **list_pp, linked_list *list_p, linked_list *new_p)
{
if (list_p == NULL)
{
_attach(list_pp, new_p); /* stuff it at the beginning */
return;
}
if (next(list_p) != NULL) /* something after this one? */
{
new_p->l_next = next(list_p);
list_p->l_next->l_prev = new_p;
}
else
new_p->l_next = NULL;
list_p->l_next = new_p;
new_p->l_prev = list_p;
}
/*
_free_list()
Throw the whole blamed thing away
*/
void
_free_list(linked_list **ptr)
{
linked_list *item;
while(*ptr != NULL)
{
item = *ptr;
*ptr = next(item);
discard(item);
}
}
/*
discard()
free up an item
*/
void
discard(struct linked_list *item)
{
throw_away(item->data.obj);
ur_free(item);
}
/*
throw_away()
toss out something (like discard, but without the link_list)
*/
void
throw_away(struct object *ptr)
{
free_ident(ptr);
ur_free(ptr);
}
/*
new_item()
get a new item with a specified size
*/
struct linked_list *
new_item(int size)
{
struct linked_list *item;
if ((item = new_list()) == NULL)
msg("Ran out of memory for header after %d items.", total);
if ((item->data.l_data = new_alloc(size)) == NULL)
msg("Ran out of memory for data after %d items.", total);
item->l_next = item->l_prev = NULL;
return(item);
}
void *
new_alloc(size_t size)
{
void *space = ur_alloc(size);
if (space == NULL)
{
sprintf(errbuf, "Rogue ran out of memory.");
fatal(errbuf);
}
return(space);
}
struct linked_list *
new_list(void)
{
union /* ugly_lint_hack */
{
struct linked_list *ll;
void *vptr;
} newp;
newp.vptr = mem_malloc(sizeof(struct linked_list));
memset(newp.vptr,0,sizeof(struct linked_list));
return(newp.ll);
}

878
urogue/magic.c Normal file
View file

@ -0,0 +1,878 @@
/*
magic.c - This file contains functions for casting magic spells
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "rogue.h"
/*
Cost for each level of spells level:
*/
static const int spell_cost[] = {1, 5, 17, 29, 53, 91, 159, 247, 396};
static struct spells monst_spells[] =
{
{5, S_SELFTELEP, SCR_MAGIC},
{4, P_HEALING, POT_MAGIC | _TWO_},
{3, P_REGENERATE, POT_MAGIC},
{2, P_HEALING, POT_MAGIC},
{4, P_HASTE, POT_MAGIC},
{2, P_SEEINVIS, POT_MAGIC},
{3, P_SHERO, POT_MAGIC},
{5, P_PHASE, POT_MAGIC},
{4, P_INVIS, POT_MAGIC},
{4, WS_CANCEL, ZAP_MAGIC},
/* In reverse order of damage ability */
{6, WS_ELECT, ZAP_MAGIC | _TWO_},
{6, WS_FIRE, ZAP_MAGIC | _TWO_},
{6, WS_COLD, ZAP_MAGIC | _TWO_},
{6, WS_MISSILE, ZAP_MAGIC | _TWO_},
{5, WS_ELECT, ZAP_MAGIC},
{5, WS_FIRE, ZAP_MAGIC},
{5, WS_COLD, ZAP_MAGIC},
{4, WS_ELECT, ZAP_MAGIC | ISCURSED},
{4, WS_FIRE, ZAP_MAGIC | ISCURSED},
{4, WS_COLD, ZAP_MAGIC | ISCURSED},
{3, WS_MISSILE, ZAP_MAGIC},
{1, WS_MISSILE, ZAP_MAGIC | ISCURSED},
{-1, -1, 0}
};
/*
Spells that a player can cast Non-mus only know ISKNOW spells until found
in the dungeon. Special classes know their spells one level lower, and
blessed one above.
*/
static struct spells player_spells[] =
{
{1, WS_KNOCK, ZAP_MAGIC | ISKNOW},
{1, S_SUMFAMILIAR, SCR_MAGIC | SP_DRUID | SP_MAGIC | SP_CLERIC, SP_ILLUSION },
{1, S_GFIND, SCR_MAGIC | ISKNOW},
{1, P_MONSTDET, POT_MAGIC | ISKNOW | SP_DRUID},
{1, P_TREASDET, POT_MAGIC | ISKNOW | SP_MAGIC},
{1, S_FOODDET, SCR_MAGIC | ISKNOW | SP_CLERIC},
{1, S_LIGHT, SCR_MAGIC | ISKNOW | SP_ILLUSION},
{2, WS_CLOSE, ZAP_MAGIC | ISKNOW},
{2, S_IDENTIFY, SCR_MAGIC | ISKNOW},
{2, WS_HIT, ZAP_MAGIC | ISKNOW | SP_PRAYER},
{2, P_SHIELD, POT_MAGIC | ISKNOW | SP_MAGIC},
{2, P_COLDRESIST, POT_MAGIC | SP_WIZARD},
{2, P_SEEINVIS, POT_MAGIC | SP_ILLUSION},
{2, S_CONFUSE, SCR_MAGIC | SP_CLERIC},
{2, P_SMELL, POT_MAGIC | SP_DRUID},
{2, WS_MISSILE, ZAP_MAGIC | SP_MAGIC},
{2, P_HEAR, POT_MAGIC},
{3, P_CLEAR, POT_MAGIC | ISKNOW},
{3, P_HEALING, POT_MAGIC | ISKNOW | SP_PRAYER},
{3, S_CURING, SCR_MAGIC | ISKNOW | SP_PRAYER},
{3, WS_MONSTELEP, ZAP_MAGIC | SP_MAGIC},
{3, WS_CANCEL, ZAP_MAGIC | SP_WIZARD},
{3, S_SELFTELEP, SCR_MAGIC | SP_WIZARD},
{3, P_FIRERESIST, POT_MAGIC | SP_WIZARD | SP_DRUID},
{3, S_MAP, SCR_MAGIC | SP_ILLUSION | SP_DRUID},
{3, S_REMOVECURSE, SCR_MAGIC | SP_PRAYER},
{3, S_HOLD, SCR_MAGIC | SP_CLERIC},
{3, S_SLEEP, SCR_MAGIC | SP_DRUID},
{3, P_HASOXYGEN, POT_MAGIC | SP_DRUID},
{3, WS_XENOHEALING, ZAP_MAGIC | SP_DRUID},
{3, P_RESTORE, POT_MAGIC},
{4, S_MSHIELD, SCR_MAGIC | ISKNOW | SP_ILLUSION},
{4, P_INVIS, POT_MAGIC | SP_ILLUSION},
{4, S_REFLECT, SCR_MAGIC | SP_ILLUSION},
{4, P_TRUESEE, POT_MAGIC | SP_ILLUSION},
{4, P_REGENERATE, POT_MAGIC | SP_CLERIC},
{4, WS_DRAIN, ZAP_MAGIC | SP_CLERIC},
{4, P_HASTE, POT_MAGIC | SP_ILLUSION | SP_CLERIC},
{4, P_LEVITATION, POT_MAGIC | SP_WIZARD | SP_DRUID},
{4, WS_WEB, ZAP_MAGIC | SP_MAGIC},
{4, P_PHASE, POT_MAGIC},
{5, P_SHERO, POT_MAGIC | ISKNOW},
{5, S_PETRIFY, SCR_MAGIC | SP_MAGIC},
{5, S_SCARE, SCR_MAGIC | _TWO_ | SP_PRAYER},
{5, WS_COLD, ZAP_MAGIC | SP_DRUID},
{5, WS_FIRE, ZAP_MAGIC | SP_CLERIC},
{5, WS_ELECT, ZAP_MAGIC | SP_WIZARD},
{5, WS_ANTIMATTER, ZAP_MAGIC | SP_ILLUSION},
{5, S_ELECTRIFY, SCR_MAGIC | SP_ILLUSION},
{6, WS_DISINTEGRATE, ZAP_MAGIC | ISKNOW},
{6, S_OWNERSHIP, SCR_MAGIC | SP_ALL},
{7, S_ENCHANT, SCR_MAGIC | SP_MAGIC},
{-1, -1, 0}
};
/*
incant()
Cast a spell
*/
void
incant(struct thing *caster, coord dir)
{
int i;
struct stats *curp;
struct stats *maxp;
int is_player = (caster == &player);
int points_casters;
char *casters_name = (on(player, ISBLIND)) ? "it" :
monsters[caster->t_index].m_name;
struct spells *sp;
char *cast_name; /* = spell_name(sp) */
char *spell_type; /* spell or prayer */
int casting_cost; /* from spell_cost[] */
int spell_roll; /* sucess/fail 1D100 die roll */
int fumble_chance; /* Spell fumble chance */
int num_fumbles = 0; /* for fumble_spell() */
int bless_or_curse = ISNORMAL; /* blessed or cursed? */
int message_flags = CAST_NORMAL; /* which message to print out */
int class_casters; /* For determining ISKNOW */
int stat_casters; /* s_intel or s_wisdom */
int level_casters; /* spellcasting level */
char buf[2 * LINELEN];
struct spells sorted_spells[MAX_SPELLS];
char spellbuf[2 * LINELEN];
char spellbuf2[2 * LINELEN];
curp = &(caster->t_stats);
maxp = &(caster->maxstats);
points_casters = curp->s_power;
if (points_casters <= 0)
{
if (is_player)
msg("You don't have any spell points.");
return;
}
/*
* Paladins, Rangers, ringwearers, and monsters cast at 4 levels
* below. Other non-specialists at 8 below
*/
level_casters = curp->s_lvl;
switch (caster->t_ctype)
{
case C_PALADIN:
level_casters -= 4;
/* fallthrough */
case C_CLERIC:
class_casters = SP_CLERIC;
stat_casters = curp->s_wisdom;
break;
case C_RANGER:
level_casters -= 4;
/* fallthrough */
case C_DRUID:
class_casters = SP_DRUID;
stat_casters = curp->s_wisdom;
break;
case C_MAGICIAN:
class_casters = SP_WIZARD;
stat_casters = curp->s_intel;
break;
case C_ILLUSION:
class_casters = SP_ILLUSION;
stat_casters = curp->s_intel;
break;
case C_MONSTER:
if (off(*caster, ISUNIQUE))
level_casters -= 4;
class_casters = 0x0;
stat_casters = curp->s_intel;
break;
default:
if (is_wearing(R_WIZARD))
{
level_casters -= 4;
class_casters = (rnd(4) ? SP_WIZARD : SP_ILLUSION);
stat_casters = curp->s_intel;
}
else if (is_wearing(R_PIETY))
{
level_casters -= 4;
class_casters = (rnd(4) ? SP_CLERIC : SP_DRUID);
stat_casters = curp->s_wisdom;
}
else
{
level_casters -= 8;
class_casters = 0x0;
stat_casters = (rnd(2) ? curp->s_wisdom : curp->s_intel);
}
}
/* Bug - What about when WIS == INT? */
spell_type = (stat_casters == curp->s_intel) ? "spell" : "prayer";
if (!is_player && (sp = pick_monster_spell(caster)) == NULL)
return;
else if (is_player)
{
int num_spells = -1; /* num of spells cheap enough */
sorted_spells[0].sp_cost = -1;
for (sp = player_spells; sp->sp_level != -1; sp++)
{
if (sp->sp_flags & class_casters) /* Does class know spell? */
{
int rnd_number = rnd(2 * sp->sp_level) - sp->sp_level;
/* Knows normal spell one level below others */
casting_cost = spell_cost[sp->sp_level - 1] + rnd_number;
if (points_casters >= casting_cost)
{
sorted_spells[++num_spells] = *sp;
sorted_spells[num_spells].sp_cost = casting_cost;
sorted_spells[num_spells].sp_level = sp->sp_level - 1;
}
/* Knows blessed spell one level above others */
casting_cost = spell_cost[sp->sp_level + 1] + rnd_number;
if (points_casters >= casting_cost)
{
sorted_spells[++num_spells] = *sp;
sorted_spells[num_spells].sp_level = sp->sp_level + 1;
sorted_spells[num_spells].sp_cost = casting_cost;
sorted_spells[num_spells].sp_flags |= ISBLESSED;
}
} /* If class doesn't know spell, see if its a ISKNOW */
else if (sp->sp_flags & ISKNOW)
{
int rnd_number = rnd(4 * sp->sp_level) - sp->sp_level;
casting_cost = spell_cost[sp->sp_level] + rnd_number;
if (points_casters >= casting_cost)
{
sorted_spells[++num_spells] = *sp;
sorted_spells[num_spells].sp_cost = casting_cost;
}
}
/* else this spell is unknown */
}
if (sorted_spells[0].sp_cost == -1)
{
msg("You don't have enough %s points.", spell_type);
after = FALSE;
return;
}
qsort(sorted_spells,num_spells + 1,sizeof(struct spells),sort_spells);
do /* Prompt for spells */
{
struct spells *which_spell = NULL;
buf[0] = '\0';
msg("");/* Get rid of --More-- */
msg("Which %s are you casting [%d points left] (* for list)? ",
spell_type, points_casters);
switch(get_string(buf, cw))
{
case NORM: break;
case QUIT: return; /* ESC - lose turn */
default: continue;
}
if (buf[0] == '*') /* print list */
{
add_line("Cost Abbreviation Full Name");
for (i = 0; i <= num_spells; i++)
{
sp = &sorted_spells[i];
sprintf(buf, "[%3d] %-12s\t%s",
sp->sp_cost, spell_abrev(sp,spellbuf2),
spell_name(sp,spellbuf));
add_line(buf);
}
end_line();
sp = NULL;
continue;
}
if (isupper(buf[0])) /* Uppercase Abbreviation */
{
for (i = 0; i <= num_spells; i++)
{
sp = &sorted_spells[i];
if ((strcmp(spell_abrev(sp,spellbuf2), buf) == 0))
{
which_spell = sp;
break;
}
}
}
else /* Full Spell Name */
{
for (i = 0; i <= num_spells; i++)
{
sp = &sorted_spells[i];
if ((strcmp(spell_name(sp,spellbuf), buf) == 0))
{
which_spell = sp;
break;
}
}
}
sp = which_spell;
}
while (sp == NULL);
}
/* Common monster and player code */
cast_name = spell_name(sp,spellbuf);
fumble_chance = (10 * sp->sp_level / 4 - 10 * level_casters / 13) * 5;
if (cur_weapon != NULL && wield_ok(caster, cur_weapon, FALSE) == FALSE)
{
switch (caster->t_ctype)
{
case C_MAGICIAN:
case C_ILLUSION:
msg("You should have both hands free.");
fumble_chance += rnd(level_casters) * 5;
break;
case C_CLERIC:
case C_DRUID:
case C_PALADIN:
msg("Your god looks askance at the weapon you wield.");
fumble_chance += rnd(level_casters) * 5;
break;
default:
break;
}
}
if (fumble_chance >= MAX_FUMBLE_CHANCE)
fumble_chance = MAX_FUMBLE_CHANCE;
else if (fumble_chance <= MIN_FUMBLE_CHANCE + sp->sp_level)
fumble_chance = MIN_FUMBLE_CHANCE + sp->sp_level;
if (fumble_chance > (30 + rnd(50)))
{
if (is_player)
{
int answer;
msg("Are you sure you want to try for that hard a %s? [n]",
spell_type);
answer = readchar();
if (tolower(answer) != 'y')
{
after = FALSE;
return;
}
else
msg("Here goes...");
}
else /* Only if the monster is desperate */
{
if (curp->s_hpt > maxp->s_hpt / 2)
return;
}
}
/* casting costs food energy */
food_left -= sp->sp_cost;
spell_roll = rnd(100);
debug("%s(%d) cast '%s' fumble %%%d (rolled %d) ",
monsters[caster->t_index].m_name, curp->s_power, cast_name,
fumble_chance, spell_roll);
caster->t_rest_hpt = caster->t_rest_pow = 0;
if (!is_player) /* Stop running. */
{
running = FALSE;
msg("The %s is casting '%s'.", casters_name, cast_name);
}
/* The Crown of Might insures that your spells never fumble */
if (spell_roll < fumble_chance)
{
if (is_carrying(TR_CROWN))
message_flags |= CAST_CROWN;
else
{
message_flags |= CAST_CURSED;
curp->s_power -= min(curp->s_power,
(2 * sp->sp_cost)); /* 2x cost */
num_fumbles = rnd(((fumble_chance - spell_roll) / 10)
+ 1) + rnd(sp->sp_level) + rnd(curp->s_lvl);
num_fumbles = min(10, max(0, num_fumbles));
if (num_fumbles >= 6 && rnd(1) == 0)
bless_or_curse = ISCURSED;
else if (num_fumbles < 4)
{
if (is_player)
msg("Your %s fails.", spell_type);
return;
}
}
}
else if (spell_roll > MAX_FUMBLE_CHANCE)
{
if (is_player)
{
message_flags |= CAST_BLESSED;
pstats.s_exp += 3 * sp->sp_cost * curp->s_lvl;
check_level();
}
maxp->s_power += sp->sp_cost;
bless_or_curse = ISBLESSED;
}
else
{
if (is_player) /* extra exp for sucessful spells */
{
if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_ILLUSION)
{
pstats.s_exp += sp->sp_cost * curp->s_lvl;
check_level();
}
}
bless_or_curse = sp->sp_flags & ISBLESSED;
curp->s_power -= sp->sp_cost;
}
/* The Sceptre of Might blesses all your spells */
if (is_player && ((bless_or_curse & ISBLESSED) == 0) &&
is_carrying(TR_SCEPTRE))
{
message_flags |= CAST_SEPTRE;
bless_or_curse = ISBLESSED;
}
if (sp->sp_flags & POT_MAGIC)
quaff(caster, sp->sp_which, bless_or_curse);
else if (sp->sp_flags & SCR_MAGIC)
read_scroll(caster, sp->sp_which, bless_or_curse);
else if (sp->sp_flags & ZAP_MAGIC)
{
if (is_player)
{
do /* Must pick a direction */
{
msg("Which direction?");
}
while (get_dir() == FALSE);
}
else
{
delta.x = dir.x;
delta.y = dir.y;
}
do_zap(caster, sp->sp_which, bless_or_curse);
}
else
msg("What a strange %s!", spell_type);
/*
* Print messages and take fumbles *after* spell has gone off. This
* makes ENCHANT, etc more dangerous
*/
if (is_player)
{
if (message_flags & CAST_SEPTRE)
msg("The Sceptre enhanced your %s.", spell_type);
if (message_flags & CAST_CROWN)
msg("The Crown wordlessly corrected your %s.",
spell_type);
switch (message_flags & 0x1)
{
case CAST_CURSED:
msg("You botched your '%s' %s.", cast_name,
spell_type);
fumble_spell(caster, num_fumbles);
break;
case CAST_NORMAL:
msg("You sucessfully cast your '%s' %s.",
cast_name, spell_type);
break;
case CAST_BLESSED:
msg("Your '%s' %s went superbly.", cast_name,
spell_type);
break;
}
}
}
/*
spell_name()
returns pointer to spell name
*/
char *
spell_name(struct spells *sp, char *buf)
{
if (buf == NULL)
return("UltraRogue Bug #105");
if (sp->sp_flags & POT_MAGIC)
strcpy(buf, p_magic[sp->sp_which].mi_name);
else if (sp->sp_flags & SCR_MAGIC)
strcpy(buf, s_magic[sp->sp_which].mi_name);
else if (sp->sp_flags & ZAP_MAGIC)
strcpy(buf, ws_magic[sp->sp_which].mi_name);
else
strcpy(buf, "unknown spell type");
if (sp->sp_flags & ISBLESSED)
strcat(buf, " 2");
return(buf);
}
/*
spell_abrev()
returns pointer to capital letter spell abbreviation
*/
char *
spell_abrev(struct spells *sp, char *buf)
{
if (buf == NULL)
return("UltraRogue Bug #106");
if (sp->sp_flags & POT_MAGIC)
strcpy(buf, p_magic[sp->sp_which].mi_abrev);
else if (sp->sp_flags & SCR_MAGIC)
strcpy(buf, s_magic[sp->sp_which].mi_abrev);
else if (sp->sp_flags & ZAP_MAGIC)
strcpy(buf, ws_magic[sp->sp_which].mi_abrev);
else
strcpy(buf, "?????");
if (sp->sp_flags & ISBLESSED)
strcat(buf, " 2");
return(buf);
}
/*
fumble_spell()
he blew it. Make him pay
*/
void
fumble_spell(struct thing *caster, int num_fumbles)
{
struct stats *curp = &(caster->t_stats);
struct stats *maxp = &(caster->maxstats);
int is_player = (caster == &player);
debug("Taking %d fumbles.", num_fumbles);
switch (num_fumbles)
{
case 10: /* Lose ability */
if (rnd(5) == 0)
quaff(caster, P_GAINABIL, ISCURSED);
break;
case 9: /* Lose max spell points */
if (rnd(4) == 0)
{
maxp->s_power -= rnd(10);
if (maxp->s_power <= 5)
maxp->s_power = 5;
}
break;
case 8: /* Lose all current spell points */
if (rnd(3) == 0)
curp->s_power = 0;
else
curp->s_power /= 2;
break;
case 7: /* Freeze */
if (rnd(2) == 0)
{
if (is_player)
no_command++;
else
caster->t_no_move++;
}
break;
case 6: /* Cast a cursed spell - see below */
break;
case 5: /* Become dazed and confused */
if (rnd(5) == 0)
quaff(caster, P_CLEAR, ISCURSED);
break;
case 4: /* Lose hit points */
if (is_player)
feel_message();
if ((curp->s_hpt -= rnd(10)) <= 0)
{
if (is_player)
death(D_SPELLFUMBLE);
else
killed(caster, find_mons(caster->t_pos.y, caster->t_pos.x),
NOMESSAGE, NOPOINTS);
return;
}
break;
case 3: /* Spell fails */
break;
case 2: /* Freeze */
if (is_player)
no_command++;
else
caster->t_no_move++;
break;
default:
case 1: /* Take double spell points - handled in incant() */
break;
}
}
/*
learn_new_spells()
go through player_spells and ISKNOW identified potions,
scrolls, and sticks
*/
void
learn_new_spells(void)
{
struct spells *sp;
int kludge = 0;
char spellbuf[2*LINELEN];
for (sp = player_spells; sp->sp_level != -1; sp++)
{
if (sp->sp_flags & POT_MAGIC)
kludge = TYP_POTION;
else if (sp->sp_flags & SCR_MAGIC)
kludge = TYP_SCROLL;
else if (sp->sp_flags & ZAP_MAGIC)
kludge = TYP_STICK;
if (know_items[kludge][sp->sp_which])
{
if ((sp->sp_flags & ISKNOW) == FALSE)
debug("Learned new spell '%s'", spell_name(sp,spellbuf));
sp->sp_flags |= ISKNOW;
}
}
}
/*
pick_monster_spell()
decide which spell from monst_spells will be cast
returns pointer to spell in monst_spells
*/
struct spells *
pick_monster_spell(struct thing *caster)
{
struct spells *sp = NULL;
struct stats *curp = &(caster->t_stats);
int points_casters = curp->s_power;
/* Discover castable spells */
for (sp = monst_spells; sp->sp_level != -1; sp++)
{
int rnd_number = rnd(2 * sp->sp_level) - sp->sp_level;
int casting_cost = spell_cost[sp->sp_level] + rnd_number;
if (points_casters >= casting_cost)
sp->sp_flags |= ISKNOW;
}
/* Decide which spell to cast */
if (curp->s_hpt < rnd(caster->maxstats.s_hpt)) /* think defense */
{
int i;
static const int run_or_heal[NUM_RUN] =
{ M_SELFTELEP, M_HLNG2, M_HLNG, M_REGENERATE };
for (i = 0; i < NUM_RUN; i++)
{
sp = &monst_spells[run_or_heal[i]];
if ((sp->sp_flags & ISKNOW) && rnd(1))
return(sp);
}
}
if (on(*caster, ISSLOW)) /* cancel a slow */
{
sp = &monst_spells[M_HASTE];
if (sp->sp_flags & ISKNOW)
return (sp);
}
if (on(*caster, ISFLEE)) /* stop running away */
{
sp = &monst_spells[M_SHERO];
if (sp->sp_flags & ISKNOW)
return (sp);
}
if (on(player, ISINVIS) || on(player, ISDISGUISE))
{
if (off(*caster, CANSEE)) /* look for him */
{
sp = &monst_spells[M_SEEINVIS];
if (sp->sp_flags & ISKNOW)
return (sp);
}
else if (off(*caster, ISINVIS)) /* go invisible */
{
sp = &monst_spells[M_INVIS];
if (sp->sp_flags & ISKNOW)
return (sp);
}
}
if (on(player, CANINWALL) && (off(*caster, CANINWALL)) &&
(rnd(5) == 0))
{
sp = &monst_spells[M_PHASE];
if (sp->sp_flags & ISKNOW)
return (sp);
}
if (rnd(5) == 0 && has_defensive_spell(player))
{
sp = &monst_spells[M_CANCEL];
if (sp->sp_flags & ISKNOW)
return (sp);
}
/* Cast an offensive spell */
for (sp = &monst_spells[M_OFFENSE]; sp->sp_level != 1; sp++)
{
if ((rnd(3) == 0) && (sp->sp_flags & ISKNOW))
return (sp);
if ((rnd(3) == 0) && (sp->sp_flags & ISKNOW))
{
if (sp->sp_which != WS_MISSILE &&
DISTANCE(caster->t_pos, hero) > BOLT_LENGTH)
continue;
else
return(sp);
}
}
return(NULL);
}
/*
sort_spells()
called by qsort()
*/
int
sort_spells(const void *a, const void *b)
{
struct spells *sp1, *sp2;
int diff;
char spellbuf[2 * LINELEN];
char spellbuf2[2 * LINELEN];
union /* hack to prevent 'lint' from complaining */
{
struct spells *s;
const void *vptr;
} s1,s2;
s1.vptr = a;
s2.vptr = b;
sp1 = s1.s;
sp2 = s2.s;
diff = sp1->sp_cost - sp2->sp_cost;
if (diff != 0)
return(diff);
else
return(strcmp(spell_name(sp1,spellbuf), spell_name(sp1,spellbuf2)));
}

278
urogue/main.c Normal file
View file

@ -0,0 +1,278 @@
/*
main.c - setup code
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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 _ALL_SOURCE
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include "rogue.h"
FILE *fd_score = NULL;
/* Command line options */
int prscore; /* Print scores */
int prversion; /* Print version info */
int
main(int argc, char *argv[])
{
int x;
char *env;
time_t lowtime;
time_t now;
int rflag = 0;
char *nm;
float scale;
for (x = 1; x < argc; x++)
{
if (argv[x][0] != '-')
break;
switch (argv[x][1])
{
case 's':
prscore = TRUE;
break;
case 'v':
prversion = TRUE;
break;
case 'r':
rflag = TRUE;
break;
default:
fprintf(stderr,"%s: Unknown option '%c'.\n",argv[0],argv[x][1]);
exit(1);
}
}
if (!rflag)
{
argc -= (x - 1);
argv += (x - 1);
}
/* Get default score file */
strcpy(score_file, "urogue.scr");
fd_score = fopen(score_file, "r+");
if (fd_score == NULL)
fd_score = fopen(score_file, "a+");
if ((env = getenv("OPTIONS")) != NULL)
parse_opts(env);
nm = getenv("USER");
if (nm != NULL)
strcpy(whoami,nm);
else
strcpy(whoami,"anonymous");
lowtime = time(&now);
dnum = (wizard && getenv("SEED") != NULL ? atoi( getenv("SEED")) : (int)lowtime);
ur_srandom(dnum);
if (env == NULL || fruit[0] == '\0')
{
static const char *funfruit[] =
{
"candleberry", "caprifig", "dewberry", "elderberry",
"gooseberry", "guanabana", "hagberry", "ilama", "imbu",
"jaboticaba", "jujube", "litchi", "mombin", "pitanga",
"prickly pear", "rambutan", "sapodilla", "soursop",
"sweetsop", "whortleberry"
};
strcpy(fruit, funfruit[rnd(sizeof(funfruit) / sizeof(funfruit[0]))]);
}
/* put a copy of fruit in the right place */
fd_data[1].mi_name = md_strdup(fruit);
/* print scores */
if (prscore)
{
waswizard = TRUE;
score(0L, 0, SCOREIT, 0);
exit(0);
}
/* check for version option */
if (prversion)
{
printf("UltraRogue Version %s.\n", release);
exit(0);
}
if (wizard)
printf("Hello %s, welcome to dungeon #%d", whoami, dnum);
else
printf("Hello %s, just a moment while I dig the dungeon...", whoami);
mem_debug(2);
mem_tracking(1);
fflush(stdout);
init_things(); /* Set up probabilities of things */
init_fd(); /* Set up food probabilities */
init_colors(); /* Set up colors of potions */
init_stones(); /* Set up stone settings of rings */
init_materials(); /* Set up materials of wands */
initscr(); /* Start up cursor package */
refresh();
init_names(); /* Set up names of scrolls */
cbreak();
crmode(); /* Cbreak mode */
noecho(); /* Echo off */
nonl();
scale = (float) (LINES * COLS) / (80.0F * 25.0F); /* get food right for */
/* different screen sizes */
food_left = (int) (food_left * scale);
/* Set up windows */
cw = newwin(LINES, COLS, 0, 0);
mw = newwin(LINES, COLS, 0, 0);
hw = newwin(LINES, COLS, 0, 0);
if (argc == 2 && argv[1][0] != '\0' && !restore(argv[1]))
/* Note: restore returns on error only */
exit(1);
waswizard = wizard; /* set wizard flags */
init_player(); /* look up things and outfit pack */
resurrect = pstats.s_const;
init_exp(); /* set first experience level change */
init_flags(); /* set initial flags */
wclear(hw);
wrefresh(hw);
new_level(POSTLEV,0); /* Draw current level */
/* Start up daemons and fuses */
start_daemon(DAEMON_DOCTOR, &player, AFTER);
light_fuse(FUSE_SWANDER, 0, WANDERTIME, AFTER);
start_daemon(DAEMON_STOMACH, 0, AFTER);
start_daemon(DAEMON_RUNNERS, 0, AFTER);
char_type = player.t_ctype;
player.t_oldpos = hero;
oldrp = roomin(hero);
after = TRUE;
signal(SIGINT, quit_handler);
while(playing)
{
do_daemons(BEFORE);
do_fuses(BEFORE);
command(); /* Command execution */
if (after)
do_after_effects();
}
fatal("");
return(0);
}
/*
fatal()
Exit the program, printing a message.
*/
void
fatal(char *s)
{
clear();
move(LINES - 2, 0);
printw("%s", s);
wrefresh(stdscr);
endwin();
printf("\n"); /* So the cursor doesn't stop at the end of the line */
exit(100);
}
/*
rnd()
Pick a very random number.
*/
unsigned char
ucrnd(unsigned char range)
{
return (unsigned char)(range <= 0 ? 0 : (ur_random() & 0x7fffffffL) % range);
}
short
srnd(short range)
{
return (short)(range <= 0 ? 0 : (ur_random() & 0x7fffffffL) % range);
}
int
rnd(int range)
{
return (range <= 0 ? 0 : (ur_random() & 0x7fffffffL) % range);
}
unsigned long
ulrnd(unsigned long range)
{
return(range <= 0 ? 0 : (ur_random() & 0x7fffffffL) % range);
}
/*
roll()
roll a number of dice
*/
int
roll(int number, int sides)
{
int dtotal = 0;
while (number--)
dtotal += rnd(sides) + 1;
return(dtotal);
}

333
urogue/maze.c Normal file
View file

@ -0,0 +1,333 @@
/*
maze.c - functions for dealing with armor
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdlib.h>
#include "rogue.h"
static char *frontier;
static char *bits;
static int urlines;
static int urcols;
/*
domaze()
Draw the maze on this level.
*/
void
do_maze(void)
{
int i, least;
struct room *rp;
struct linked_list *item;
struct object *obj;
struct thing *mp;
int treas;
coord tp;
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
{
rp->r_nexits = 0; /* no exits */
rp->r_flags = ISGONE; /* kill all rooms */
rp->r_fires = 0; /* 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, 0, 0, 0);
obj = OBJPTR(item);
obj->o_count *= (rnd(10) + 5); /* add in one large hunk */
do
{
rnd_pos(rp, &tp);
}
while( mvwinch(stdscr, tp.y, tp.x) != FLOOR);
obj->o_pos = tp;
add_obj(item, tp.y, tp.x);
/* add in some food to make sure he has enough */
item = spec_item(FOOD, 0, 0, 0);
obj = OBJPTR(item);
do
{
rnd_pos(rp, &tp);
}
while( mvwinch(stdscr, tp.y, tp.x) != FLOOR);
obj->o_pos = tp;
add_obj(item, tp.y, tp.x);
if (rnd(100) < 5) /* 5% for treasure maze level */
{
treas = TRUE;
least = 20;
debug("Treasure maze.");
}
else /* normal maze level */
{
least = 1;
treas = FALSE;
}
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);
}
while(mvwinch(stdscr, tp.y, tp.x) != FLOOR);
new_monster(item, randmonster(NOWANDER, NOGRAB), &tp, NOMAXSTATS);
/* See if we want to give it a treasure to carry around. */
if (rnd(100) < monsters[mp->t_index].m_carry)
attach(mp->t_pack, new_thing());
/* If it carries gold, give it some */
if (on(*mp, CARRYGOLD))
{
item = spec_item(GOLD, 0, 0, 0);
obj = OBJPTR(item);
obj->o_count = GOLDCALC + GOLDCALC + GOLDCALC;
obj->o_pos = mp->t_pos;
attach(mp->t_pack, item);
}
}
}
/*
draw_maze()
Generate and draw the maze on the screen
*/
void
draw_maze(void)
{
int i, j, more;
char *ptr;
urlines = (LINES - 3) / 2;
urcols = (COLS - 1) / 2;
bits = ur_alloc((unsigned int) ((LINES - 3) * (COLS - 1)));
frontier = ur_alloc((unsigned int) (urlines * urcols));
ptr = frontier;
while (ptr < (frontier + (urlines * urcols)))
*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 < urlines; i++)
{
for (j = 0; j < urcols; j++)
{
do
more = findcells(i, j);
while (more != 0);
}
}
crankout();
ur_free(frontier);
ur_free(bits);
}
/*
moffset()
Calculate memory address for bits
*/
char *
moffset(int y, int x)
{
return (bits + (y * (COLS - 1)) + x);
}
/*
foffset()
Calculate memory address for frontier
*/
char *
foffset(int y, int x)
{
return (frontier + (y * urcols) + x);
}
/*
findcells()
Figure out cells to open up
*/
int
findcells(int y, int x)
{
int rtpos, i;
struct
{
int num_pos; /* number of frontier cells next to you */
struct
{
int y_pos;
int x_pos;
} conn[4]; /* the y,x position of above cell */
} mborder;
*foffset(y, x) = FALSE;
mborder.num_pos = 0;
if (y < urlines - 1) { /* look below */
if (*foffset(y + 1, x))
{
mborder.conn[mborder.num_pos].y_pos = y + 1;
mborder.conn[mborder.num_pos].x_pos = x;
mborder.num_pos += 1;
}
}
if (y > 0) /* look above */
{
if (*foffset(y - 1, x))
{
mborder.conn[mborder.num_pos].y_pos = y - 1;
mborder.conn[mborder.num_pos].x_pos = x;
mborder.num_pos += 1;
}
}
if (x < urcols - 1) /* look right */
{
if (*foffset(y, x + 1))
{
mborder.conn[mborder.num_pos].y_pos = y;
mborder.conn[mborder.num_pos].x_pos = x + 1;
mborder.num_pos += 1;
}
}
if (x > 0) /* look left */
{
if (*foffset(y, x - 1))
{
mborder.conn[mborder.num_pos].y_pos = y;
mborder.conn[mborder.num_pos].x_pos = x - 1;
mborder.num_pos += 1;
}
}
if (mborder.num_pos == 0)/* no neighbors available */
return(0);
else
{
i = rnd(mborder.num_pos);
rtpos = mborder.num_pos - 1;
rmwall(mborder.conn[i].y_pos, mborder.conn[i].x_pos, y, x);
return(rtpos);
}
}
/*
rmwall()
Removes appropriate walls from the maze
*/
void
rmwall(int newy, int newx, int oldy, int oldx)
{
int xdif, ydif;
xdif = newx - oldx;
ydif = newy - oldy;
*moffset((oldy * 2) + ydif + 1, (oldx * 2) + xdif + 1) = FALSE;
findcells(newy, newx);
}
/*
crankout()
Does actual drawing of maze to window
*/
void
crankout(void)
{
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);
}
}
}

1270
urogue/mdport.c Normal file

File diff suppressed because it is too large Load diff

420
urogue/memory.c Normal file
View file

@ -0,0 +1,420 @@
/*
memory.c
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdio.h>
#include <stdlib.h>
#include "dict.h"
#include "memory.h"
#include "rogue.h"
static char sccsid[] = "%W%\t%G%";
/* Debugging memory allocation code that tries to trap common memory problems
like overwriting storage and stepping on memory pointer chains. If code
doesn't use malloc, free, and realloc a lot, these routines can be left in
as added protection against undetected storage bugs.
*/
/* FENCE_SIZE should be a multiple of sizeof(size_t) to prevent alignment problems.
The code assumes that malloc and realloc return pointers aligned at least on size_t
sized boundaries and that a pointer needs alignment no more strict than that of an
object needed to hold a size_t.
*/
#define FENCE_SIZE (sizeof(size_t) * 1024)
static int memdebug_level = 0;
static DICTIONARY *allocations = NULL;
static FILE *trace_file = NULL;
/* set the debug level */
void mem_debug(const int level)
{
memdebug_level = level;
if (trace_file == NULL)
trace_file = fopen("trace", "w");
/* all except 0, 1, and unknown fall through */
switch(memdebug_level) {
case 2:
fprintf(trace_file, "+++ Memory tracking possible, ");
case 1:
fprintf(trace_file, "+++ Memory debugging enabled, ");
break;
case 0:
fprintf(trace_file, "+++ Memory debugging disabled, ");
break;
default:
fprintf(trace_file, "!!! Unknown memory debug level set, enabling level 1, ");
memdebug_level = 1;
break;
}
fprintf(trace_file, "fence size = %d\n", FENCE_SIZE);
}
/* set memory tracking on or off */
/* turning it off deletes all tracking data */
void mem_tracking(int flag)
{
/* do nothing if debuglevel is too low */
if (memdebug_level < 2)
return;
/* turn on tracking */
if (flag > 0) {
if (allocations != NULL) {
dict_destroy(allocations);
allocations = NULL;
}
allocations = dict_create(8, 100, 4, 20);
if (allocations == NULL) {
fprintf(trace_file, "!!! Unable to allocate tracking table!\n");
abort();
}
}
/* turn off tracking */
else if (allocations != NULL) {
dict_destroy(allocations);
allocations = NULL;
}
}
/* go through all pointers and see if they are OK, aborting if not */
/* always returns 1 if not aborting so that it can be included in */
/* if statement boolean expressions */
int mem_check(char *fname, int linenum)
{
STRING_ENTRY *se;
/* scan of a NULL dictionary always succeeds */
if (allocations == NULL)
return TRUE;
if (!dict_scan_begin(allocations)) {
fprintf(trace_file, "!!! Dictionary scan initialization failed!\n");
abort();
}
fprintf(trace_file, "\n+++ --- Starting pointer scan\n");
fprintf(trace_file, "+++ --- At %s, %d\n", fname, linenum);
/* mem_validate aborts if there is a problem */
while((se = dict_scan_next(allocations)) != NULL)
mem_validate(se->any_ptr);
fprintf(trace_file, "+++ --- Done pointer scan\n\n");
/* always return a good value if execution arrives here */
return 1;
}
/* allocate some memory and initialize header and trailer */
void *mem_malloc(const size_t bytes)
{
char *mem_temp;
size_t real_size = bytes + (FENCE_SIZE << 1);
/* allocate including guard bytes to detect some ways of overwriting of memory areas */
mem_temp = (void *)malloc(real_size);
if (memdebug_level > 0) {
fprintf(trace_file, "+++ Requested size of %ld bytes\n", bytes);
fprintf(trace_file, "+++ Actual malloc of %ld bytes located at %p\n", real_size, mem_temp);
}
/* if allocation succeeded, set management data */
if (mem_temp != NULL) {
size_t i;
char *end;
/* do beginning marker bytes */
for (i = 0; i < FENCE_SIZE - sizeof(size_t); i++)
*mem_temp++ = 145;
/* save size in header too */
if (memdebug_level > 0)
fprintf(trace_file, "*** Requested memory size stored at %p\n", mem_temp);
*(size_t *)mem_temp = bytes;
/* finally, point to storage we are going to hand out */
mem_temp += sizeof(size_t);
/* now, point to trailer bytes and do them */
end = mem_temp + bytes;
for (i = 0; i < FENCE_SIZE; i++)
*end++ = 145;
/* now zap contents to zero */
for (i = 0; i < bytes; i++)
mem_temp[i] = 0;
}
/* track pointer if needed */
if (memdebug_level > 1 && allocations != NULL) {
char key[16];
long temp;
sprintf(key, "%p", mem_temp);
if (dict_insert(allocations, key, 1, (const unsigned long) bytes, mem_temp, &temp) == NULL) {
fprintf(trace_file, "!!! Insert of pointer tracking info failed\n");
abort();
}
}
/* allow caller to do error handling */
if (memdebug_level > 0) {
fprintf(trace_file, "--- Returning pointer of %p\n", mem_temp);
fflush(trace_file);
}
return (void *)mem_temp;
}
/* release some memory, making sure that it was properly allocated */
void mem_free(const void *ptr)
{
char *mem_temp;
size_t mem_size;
size_t i;
if (memdebug_level > 0)
fprintf(trace_file, "+++ Free of memory located at %p\n", ptr);
if (ptr == NULL) {
if (memdebug_level > 0) {
fprintf(trace_file, "!!! Freeing NULL pointer\n");
fflush(trace_file);
}
abort();
}
mem_validate(ptr); /* doesn't return on error */
/* get location of size of area */
mem_temp = (char *)ptr - sizeof(size_t);
/* get and calculate real size */
mem_size = *(size_t *)mem_temp + (FENCE_SIZE << 1);
/* if doing memory tracking */
if (memdebug_level > 1 && allocations != NULL) {
char key[16];
STRING_ENTRY *se;
long temp;
sprintf(key, "%p", ptr);
if ((se = dict_search(allocations, key, &temp)) == NULL) {
fprintf(trace_file, "!!! Deleting pointer not found in tracking info\n");
abort();
}
if (se->count == 0) {
fprintf(trace_file, "!!! Freeing a pointer that has already been freed!\n");
abort();
}
else if (se->flags != mem_size - (FENCE_SIZE << 1)) {
fprintf(trace_file, "!!! Stored size different from tracking size!\n");
abort();
}
/* remember deleted stuff by zeroing the allocation count */
se->count = 0;
se->flags = 0;
}
/* zap bytes being freed */
for (i = 0, mem_temp = (char *)ptr - FENCE_SIZE; i < mem_size; i++, mem_temp++)
*mem_temp = 243;
if (memdebug_level > 0)
fflush(trace_file);
mem_temp = (char *)ptr - FENCE_SIZE;
free((void *)mem_temp);
}
/* reallocate some memory, making sure that it was properly allocated */
void *mem_realloc(const void *ptr, const size_t new_size)
{
char *mem_temp = (char *)ptr;
size_t real_size = new_size + (FENCE_SIZE << 1);
size_t mem_size;
long i;
if (memdebug_level > 0) {
fprintf(trace_file, "+++ Requested size of %ld bytes\n", new_size);
fprintf(trace_file, "+++ Actual realloc of %ld bytes located at %p\n", real_size, mem_temp);
}
if (ptr == NULL) {
if (memdebug_level > 0) {
fprintf(trace_file, "!!! Reallocating NULL pointer\n");
fflush(trace_file);
}
abort();
}
mem_validate(ptr); /* doesn't return on error */
/* if doing memory tracking */
if (memdebug_level > 1 && allocations != NULL) {
char key[16];
STRING_ENTRY *se;
long temp;
sprintf(key, "%p", ptr);
if ((se = dict_search(allocations, key, &temp)) == NULL) {
fprintf(trace_file, "!!! Deleting a pointer not found in tracking info!\n");
abort();
}
/* point to size bytes */
mem_temp = (char *)ptr - sizeof(size_t);
/* get user size */
mem_size = *(size_t *)mem_temp;
if (se->count == 0) {
fprintf(trace_file, "!!! Freeing a pointer that has already been freed!\n");
abort();
}
else if (se->flags != mem_size) {
fprintf(trace_file, "!!! Stored size different from tracking size!\n");
abort();
}
/* remember deleted stuff by zeroing the allocation count */
se->count = 0;
se->flags = 0;
}
/* header marker bytes will be copied by the realloc */
mem_temp = (char *)ptr - FENCE_SIZE;
mem_temp = realloc((void *)mem_temp, real_size);
if (mem_temp != NULL) {
char *end;
/* save size in header too */
mem_temp += FENCE_SIZE - sizeof(size_t);
if (memdebug_level > 0)
fprintf(trace_file, "*** Requested memory size stored at %p\n", mem_temp);
*(size_t *)mem_temp = new_size;
/* finally, point to storage we are going to hand out */
mem_temp += sizeof(size_t);
/* now, point to trailer bytes and do them */
end = mem_temp + new_size;
for (i = 0; i < FENCE_SIZE; i++)
*end++ = 145;
}
if (memdebug_level > 1 && allocations != NULL) {
char key[16];
long temp;
sprintf(key, "%p", mem_temp);
if (dict_insert(allocations, key, 1, (const unsigned long)new_size, mem_temp, &temp) == NULL) {
fprintf(trace_file, "!!! Insert of pointer tracking info failed\n");
abort();
}
}
if (memdebug_level > 0) {
fprintf(trace_file, "--- Returning pointer of %p\n", mem_temp);
fflush(trace_file);
}
return (void *)mem_temp;
}
/* check a pointer to be sure all check bytes are OK. abort if not */
/* always returns 1 if not aborting so that it can be included in */
/* if statement boolean expressions */
int mem_validate(void *ptr)
{
unsigned char *mem_temp = (unsigned char *)ptr;
size_t mem_size;
size_t i;
/* NULL pointers are always valid */
if (ptr == NULL)
return 1;
if (memdebug_level > 0)
fprintf(trace_file, "+++ Checking %p as pointer\n", ptr);
if (memdebug_level > 1 && allocations != NULL) {
char key[16];
STRING_ENTRY *se;
long temp;
sprintf(key, "%p", ptr);
if ((se = dict_search(allocations, key, &temp)) == NULL) {
fprintf(trace_file, "!!! Pointer not found in tracking info!\n");
abort();
}
/* point to size bytes */
mem_temp = (unsigned char *)ptr - sizeof(size_t);
/* get user size */
mem_size = *(size_t *)mem_temp;
if (se->count == 0) {
fprintf(trace_file, "!!! Checking pointer has been freed!\n");
abort();
}
else if (se->flags != mem_size) {
fprintf(trace_file, "!!! Stored size different from tracking size!\n");
abort();
}
}
/* check the header bytes */
mem_temp = (unsigned char *) ptr - FENCE_SIZE;
if (memdebug_level > 0)
fprintf(trace_file, "+++ Real pointer at %p\n", mem_temp);
for (i = 0; i < FENCE_SIZE - sizeof(size_t); i++)
if (*mem_temp++ != 145) {
if (memdebug_level > 0) {
fprintf(trace_file, "!!! The user pointer at %p has been overwritten\n", ptr);
fprintf(trace_file, "!!! Header offset %ld has been changed\n", i - 1);
fflush(trace_file);
}
abort();
}
/* check size */
i = *(size_t *)mem_temp;
if (memdebug_level > 0)
fprintf(trace_file, "*** Stored memory size of %ld bytes in header\n", i);
/* now point to where trailer should be */
mem_temp = (unsigned char *)ptr + i;
for (i = 0; i < FENCE_SIZE; i++)
if (*mem_temp++ != 145) {
if (memdebug_level > 0) {
fprintf(trace_file, "!!! The user pointer at %p has been overwritten\n", ptr);
fprintf(trace_file, "!!! Trailer offset %ld has been changed\n", i - 1);
fflush(trace_file);
}
abort();
}
if (memdebug_level > 0)
fflush(trace_file);
return 1;
}

1208
urogue/misc.c Normal file

File diff suppressed because it is too large Load diff

2878
urogue/monsdata.c Normal file

File diff suppressed because it is too large Load diff

1497
urogue/monsters.c Normal file

File diff suppressed because it is too large Load diff

1837
urogue/move.c Normal file

File diff suppressed because it is too large Load diff

676
urogue/newlvl.c Normal file
View file

@ -0,0 +1,676 @@
/*
newlvl.c - Dig and draw a new level
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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.
*/
/*
Notes
Add treasure room code from Rogue 5.2,
put in #ifdef 0/#endif bracket at end of code
*/
#include "rogue.h"
/*
new_level()
Dig and draw a new level
*/
void
new_level(LEVTYPE ltype, int special)
{
int rm, i, cnt;
struct linked_list *item, *nitem;
struct thing *tp;
struct linked_list *fpack = NULL;
int going_down = TRUE;
coord stairs;
/* Start player off right */
turn_off(player, ISHELD);
turn_off(player, ISFLEE);
extinguish_fuse(FUSE_SUFFOCATE);
hold_count = 0;
trap_tries = 0;
no_food++;
if (level >= max_level)
max_level = level;
else
going_down = FALSE;
/* Free up the monsters on the last level */
if (fam_ptr != NULL) /* save what familiar is carrying */
{
fpack = (THINGPTR(fam_ptr))->t_pack;
(THINGPTR(fam_ptr))->t_pack = NULL;
fam_ptr = NULL; /* just in case */
}
for (i = 1; i <= mons_summoned; i++)
extinguish_fuse(FUSE_UNSUMMON);
mons_summoned = 0;
for (item = mlist; item != NULL; item = nitem)
{
tp = THINGPTR(item);
nitem = next(item);
if (on(*tp, ISUNIQUE)) /* Put alive UNIQUE on next level */
monsters[tp->t_index].m_normal = TRUE;
killed(NULL, item, NOMESSAGE, NOPOINTS);
}
free_list(lvl_obj); /* Free up previous objects (if any) */
wclear(cw);
wclear(mw);
clear();
refresh();
levtype = ltype;
switch (ltype)
{
case THRONE:
do_throne(special); /* do monster throne stuff */
break;
case MAZELEV:
do_maze();
break;
case POSTLEV:
do_post();
levtype = ltype = NORMLEV;
level++;
default:
do_rooms(); /* Draw rooms */
do_passages(); /* Draw passages */
break;
}
/* Place the staircase down. */
cnt = 0;
do
{
rm = rnd_room();
rnd_pos(&rooms[rm], &stairs);
}
while (!(mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 5000));
addch(STAIRS);
put_things(ltype); /* Place objects (if any) */
if (has_artifact && level == 1)
create_lucifer(&stairs);
/* Place the traps */
ntraps = 0; /* No traps yet */
if (levtype == NORMLEV)
{
if (rnd(10) < level)
{
char ch = 0;
i = ntraps = min(MAXTRAPS, rnd(level / 2) + 1);
/* maybe a lair */
if (level > 35 && ltype == NORMLEV && rnd(wizard ? 3 : 10) == 0)
{
cnt = 0;
do
{
rm = rnd_room();
if (rooms[rm].r_flags & ISTREAS)
continue;
rnd_pos(&rooms[rm], &stairs);
}
while (!(mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 5000));
addch(LAIR);
i--;
traps[i].tr_flags = 0;
traps[i].tr_type = LAIR;
traps[i].tr_show = FLOOR;
traps[i].tr_pos = stairs;
}
while (i--)
{
cnt = 0;
do
{
rm = rnd_room();
if (rooms[rm].r_flags & ISTREAS)
continue;
rnd_pos(&rooms[rm], &stairs);
}
while (!(mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 5000));
traps[i].tr_flags = 0;
switch (rnd(11))
{
case 0:
ch = TRAPDOOR;
break;
case 1:
ch = BEARTRAP;
break;
case 2:
ch = SLEEPTRAP;
break;
case 3:
ch = ARROWTRAP;
break;
case 4:
ch = TELTRAP;
break;
case 5:
ch = DARTTRAP;
break;
case 6:
ch = POOL;
if (rnd(10))
traps[i].tr_flags = ISFOUND;
break;
case 7:
ch = MAZETRAP;
break;
case 8:
ch = FIRETRAP;
break;
case 9:
ch = POISONTRAP;
break;
case 10:
ch = RUSTTRAP;
break;
}
addch(ch);
traps[i].tr_type = ch;
traps[i].tr_show = FLOOR;
traps[i].tr_pos = stairs;
}
}
}
do /* Position hero */
{
rm = rnd_room();
if (levtype != THRONE && (rooms[rm].r_flags & ISTREAS))
continue;
rnd_pos(&rooms[rm], &hero);
}
while(!(winat(hero.y, hero.x) == FLOOR &&
DISTANCE(hero, stairs) > 16));
oldrp = &rooms[rm]; /* Set the current room */
player.t_oldpos = player.t_pos; /* Set the current position */
if (levtype != POSTLEV && levtype != THRONE)
{
if (on(player, BLESSMAP) && rnd(5) == 0)
{
read_scroll(&player, S_MAP, ISNORMAL);
if (rnd(3) == 0)
turn_off(player, BLESSMAP);
}
if (player.t_ctype == C_THIEF || on(player, BLESSGOLD) && rnd(5) == 0)
{
read_scroll(&player, S_GFIND, ISNORMAL);
if (rnd(3) == 0)
turn_off(player, BLESSGOLD);
}
if (player.t_ctype == C_RANGER || on(player, BLESSFOOD) && rnd(5) == 0)
{
read_scroll(&player, S_FOODDET, ISNORMAL);
if (rnd(3) == 0)
turn_off(player, BLESSFOOD);
}
if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_ILLUSION ||
on(player, BLESSMAGIC) && rnd(5) == 0)
{
quaff(&player, P_TREASDET, ISNORMAL);
if (rnd(3) == 0)
turn_off(player, BLESSMAGIC);
}
if (player.t_ctype == C_DRUID || on(player, BLESSMONS) && rnd(5) == 0)
{
quaff(&player, P_MONSTDET, ISNORMAL);
if (rnd(3) == 0)
turn_off(player, BLESSMONS);
}
else if (player.t_ctype == C_CLERIC ||
player.t_ctype == C_PALADIN || is_wearing(R_PIETY))
undead_sense();
}
if (is_wearing(R_AGGR))
aggravate();
if (is_wearing(R_ADORNMENT) ||
cur_armor != NULL && cur_armor->o_which == MITHRIL)
{
int greed = FALSE;
for (item = mlist; item != NULL; item = next(item))
{
tp = THINGPTR(item);
if (on(*tp, ISGREED))
{
turn_on(*tp, ISRUN);
turn_on(*tp, ISMEAN);
tp->t_ischasing = TRUE;
tp->t_chasee = &player;
greed = TRUE;
}
}
if (greed)
msg("An uneasy feeling comes over you.");
}
if (is_carrying(TR_PALANTIR)) /* Palantir shows all */
{
msg("The Palantir reveals all!");
overlay(stdscr, cw); /* Wizard mode 'f' command */
overlay(mw, cw); /* followed by 'm' command */
}
if (is_carrying(TR_PHIAL)) /* Phial lights your way */
{
if (!is_carrying(TR_PALANTIR))
msg("The Phial banishes the darkness!");
for (i = 0; i < MAXROOMS; i++)
rooms[i].r_flags &= ~ISDARK;
}
if (is_carrying(TR_AMULET)) /* Amulet describes the level */
{
level_eval();
}
wmove(cw, hero.y, hero.x);
waddch(cw, PLAYER);
light(&hero);
/* Summon familiar if player has one */
if (on(player, HASFAMILIAR))
{
summon_monster((short) fam_type, FAMILIAR, MESSAGE);
if (fam_ptr != NULL) /* add old pack to new */
{
tp = THINGPTR(fam_ptr);
if (tp->t_pack == NULL)
tp->t_pack = fpack;
else if (fpack != NULL)
{
for (item = tp->t_pack; item->l_next != NULL;item = next(item))
;
item->l_next = fpack;
debug("new_level: l_prev = %p",item);
fpack->l_prev = item;
}
}
else
free_list(fpack);
}
mem_check(__FILE__,__LINE__);
status(TRUE);
}
/*
put_things()
put potions and scrolls on this level
*/
void
put_things(LEVTYPE ltype)
{
int i, rm, cnt;
struct linked_list *item;
struct object *cur;
int got_unique = FALSE;
int length, width, maxobjects;
coord tp;
/*
* Once you have found an artifact, the only way to get new stuff is
* go down into the dungeon.
*/
if (has_artifact && level < max_level && ltype != THRONE)
return;
/*
* There is a chance that there is a treasure room on this level
* Increasing chance after level 10
*/
if (ltype != MAZELEV && rnd(50) < level - 10)
{
int n, j;
struct room *rp;
/* Count the number of free spaces */
n = 0; /* 0 tries */
do
{
rp = &rooms[rnd_room()];
width = rp->r_max.y - 2;
length = rp->r_max.x - 2;
}
while(!((width * length <= MAXTREAS) || (n++ > MAXROOMS * 4)));
/* Mark the room as a treasure room */
rp->r_flags |= ISTREAS;
/* Make all the doors secret doors */
for (n = 0; n < rp->r_nexits; n++)
{
move(rp->r_exit[n].y, rp->r_exit[n].x);
addch(SECRETDOOR);
}
/* Put in the monsters and treasures */
for (j = 1; j < rp->r_max.y - 1; j++)
for (n = 1; n < rp->r_max.x - 1; n++)
{
coord trp;
trp.y = rp->r_pos.y + j;
trp.x = rp->r_pos.x + n;
/* Monsters */
if ((rnd(100) < (MAXTREAS * 100) /
(width * length)) &&
(mvwinch(mw, rp->r_pos.y + j,
rp->r_pos.x + n) == ' '))
{
struct thing *th;
/* Make a monster */
item = new_item(sizeof *th);
th = THINGPTR(item);
/*
* Put it there and aggravate it
* (unless it can escape) only put
* one UNIQUE per treasure room at
* most
*/
if (got_unique)
new_monster(item, randmonster(NOWANDER, GRAB), &trp,
NOMAXSTATS);
else
{
new_monster(item, randmonster(NOWANDER, NOGRAB), &trp,
NOMAXSTATS);
if (on(*th, ISUNIQUE))
got_unique = TRUE;
}
turn_off(*th, ISFRIENDLY);
turn_on(*th, ISMEAN);
if (off(*th, CANINWALL))
{
th->t_ischasing = TRUE;
th->t_chasee = &player;
turn_on(*th, ISRUN);
}
}
/* Treasures */
if ((rnd(100) < (MAXTREAS * 100) /
(width * length)) &&
(mvinch(rp->r_pos.y + j,
rp->r_pos.x + n) == FLOOR))
{
item = new_thing();
cur = OBJPTR(item);
cur->o_pos = trp;
add_obj(item, trp.y, trp.x);
}
}
}
/* Do MAXOBJ attempts to put things on a level, maybe */
maxobjects = (ltype == THRONE) ? rnd(3 * MAXOBJ) + 35 : MAXOBJ;
for (i = 0; i < maxobjects; i++)
if (rnd(100) < 40 || ltype == THRONE)
{
/* Pick a new object and link it in the list */
item = new_thing();
cur = OBJPTR(item);
/* Put it somewhere */
cnt = 0;
do
{
rm = rnd_room();
rnd_pos(&rooms[rm], &tp);
}
while(!(winat(tp.y, tp.x) == FLOOR || cnt++ > 500));
cur->o_pos = tp;
add_obj(item, tp.y, tp.x);
}
/*
* If he is really deep in the dungeon and he hasn't found an
* artifact yet, put it somewhere on the ground
*/
if (make_artifact())
{
item = new_item(sizeof *cur);
cur = OBJPTR(item);
new_artifact(-1, cur);
cnt = 0;
do
{
rm = rnd_room();
rnd_pos(&rooms[rm], &tp);
}
while(!(winat(tp.y, tp.x) == FLOOR || cnt++ > 500));
cur->o_pos = tp;
add_obj(item, tp.y, tp.x);
}
}
/*
do_throne()
Put a monster's throne room and monsters on the screen
*/
void
do_throne(int special)
{
coord mp;
int save_level;
int i;
struct room *rp;
struct thing *tp;
struct linked_list *item;
int throne_monster;
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
{
rp->r_nexits = 0; /* no exits */
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 = 3; /* 2nd line */
draw_room(rp); /* draw the only room */
save_level = level;
level = max(2 * level, level + roll(4, 6));
if (special == 0) /* Who has he offended? */
do
throne_monster = nummonst - roll(1, NUMSUMMON);
while(!monsters[throne_monster].m_normal);
else
throne_monster = special;
/* Create summoning monster */
item = new_item(sizeof *tp);
tp = THINGPTR(item);
do
{
rnd_pos(rp, &mp);
}
while(mvwinch(stdscr, mp.y, mp.x) != FLOOR);
new_monster(item, throne_monster, &mp, MAXSTATS);
turn_on(*tp, CANSEE);
turn_off(*tp, ISFRIENDLY);
if (on(*tp, CANSUMMON)) /* summon his helpers */
summon_help(tp, FORCE);
else
{
for (i = roll(4, 10); i >= 0; i--)
{
item = new_item(sizeof *tp);
tp = THINGPTR(item);
do
{
rnd_pos(rp, &mp);
}
while(mvwinch(stdscr, mp.y, mp.x) != FLOOR);
new_monster(item, randmonster(NOWANDER, NOGRAB), &mp, MAXSTATS);
turn_on(*tp, CANSEE);
turn_off(*tp, ISFRIENDLY);
}
}
level = save_level + roll(2, 3); /* send the hero down */
aggravate();
}
/*
create_lucifer()
special surprise on the way back up create Lucifer
with more than the usual god abilities
*/
void
create_lucifer(coord *stairs)
{
struct linked_list *item = new_item(sizeof(struct thing));
struct thing *tp = THINGPTR(item);
new_monster(item, nummonst + 1, stairs, MAXSTATS);
turn_on(*tp, CANINWALL);
turn_on(*tp, CANHUH);
turn_on(*tp, CANBLINK);
turn_on(*tp, CANSNORE);
turn_on(*tp, CANDISEASE);
turn_on(*tp, NOCOLD);
turn_on(*tp, TOUCHFEAR);
turn_on(*tp, BMAGICHIT);
turn_on(*tp, NOFIRE);
turn_on(*tp, NOBOLT);
turn_on(*tp, CANBLIND);
turn_on(*tp, CANINFEST);
turn_on(*tp, CANSMELL);
turn_on(*tp, CANPARALYZE);
turn_on(*tp, CANSTINK);
turn_on(*tp, CANCHILL);
turn_on(*tp, CANFRIGHTEN);
turn_on(*tp, CANHOLD);
turn_on(*tp, CANBRANDOM);
}

519
urogue/options.c Normal file
View file

@ -0,0 +1,519 @@
/*
options.c - This file has all the code for the option command
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <string.h>
#include <ctype.h>
#include "rogue.h"
#define NUM_OPTS (sizeof optlist / sizeof (OPTION))
#define EQSTR(a, b, c) (strncmp(a, b, c) == 0)
/* description of an option and what to do with it */
static OPTION optlist[] =
{
{"jump","Show position only at end of run (jump): ", &jump,put_bool,get_bool},
{"inven","Style of inventories (inven): ", &inv_type, put_inv, get_inv},
{"askme","Ask me about unidentified things (askme): ",&askme,put_bool,get_bool},
{"doorstop","Stop running when adjacent (doorstop): ",&doorstop,put_bool,get_bool},
{"name", "Name (name): ", &whoami, put_str, get_str},
{"fruit", "Fruit (fruit): ", &fruit, put_str, get_str},
{"file", "Save file (file): ", &file_name, put_str, get_str},
{"score", "Score file (score): ", &score_file, put_str, get_str},
{"class", "Character class (class): ",&char_type, put_abil, get_abil}
};
/*
option()
print and then set options from the terminal
*/
void
option(void)
{
OPTION *op;
int retval;
wclear(hw);
touchwin(hw);
/* Display current values of options */
for (op = optlist; op < &optlist[NUM_OPTS]; op++)
{
waddstr(hw, op->o_prompt);
(*op->o_putfunc)(&op->o_opt, hw);
waddch(hw, '\n');
}
/* Set values */
wmove(hw, 0, 0);
for (op = optlist; op < &optlist[NUM_OPTS]; op++)
{
waddstr(hw, op->o_prompt);
retval = (*op->o_getfunc)(&op->o_opt, hw);
if (retval)
if (retval == QUIT)
break;
else if (op > optlist) /* MINUS */
{
wmove(hw, (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);
wrefresh(hw);
wait_for(' ');
clearok(cw, TRUE);
touchwin(cw);
}
/*
put_bool()
put out a boolean
*/
void
put_bool(opt_arg *opt, WINDOW *win)
{
waddstr(win, *opt->iarg ? "True" : "False");
}
/*
put_str()
put out a string
*/
void
put_str(opt_arg *opt, WINDOW *win)
{
waddstr(win, opt->str);
}
/*
put_abil()
print the character type
*/
void
put_abil(opt_arg *opt, WINDOW *win)
{
char *abil;
switch(*opt->iarg)
{
case C_FIGHTER:
abil = "Fighter";
break;
case C_MAGICIAN:
abil = "Magic User";
break;
case C_CLERIC:
abil = "Cleric";
break;
case C_THIEF:
abil = "Thief";
break;
case C_PALADIN:
abil = "Paladin";
break;
case C_RANGER:
abil = "Ranger";
break;
case C_ILLUSION:
abil = "Illusionist";
break;
case C_ASSASIN:
abil = "Assasin";
break;
case C_NINJA:
abil = "Ninja";
break;
case C_DRUID:
abil = "Druid";
break;
default:
abil = "(unknown)";
}
waddstr(win, abil);
}
/*
get_bool()
allow changing a boolean option and print it out
*/
int
get_bool(opt_arg *opt, WINDOW *win)
{
int oy, ox;
int op_bad;
op_bad = TRUE;
getyx(win, oy, ox);
waddstr(win, *opt->iarg ? "True" : "False");
while(op_bad)
{
wmove(win, oy, ox);
wrefresh(win);
switch (readcharw(win))
{
case 't':
case 'T':
*opt->iarg = TRUE;
op_bad = FALSE;
break;
case 'f':
case 'F':
*opt->iarg = 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, *opt->iarg ? "True" : "False");
waddch(win, '\n');
return(NORM);
}
/*
get_str()
set a string option
*/
int
get_str(opt_arg *opt, WINDOW *win)
{
return( get_string(opt->str, win) );
}
/*
get_abil()
The ability field is read-only
*/
int
get_abil(opt_arg *opt, WINDOW *win)
{
int oy, ox, ny, nx;
int op_bad;
op_bad = TRUE;
getyx(win, oy, ox);
put_abil(opt, win);
getyx(win, ny, nx);
while(op_bad)
{
wmove(win, oy, ox);
wrefresh(win);
switch(readcharw(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);
}
/*
parse_opts()
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.
*/
void
parse_opts(char *str)
{
char *sp;
const OPTION *op;
size_t len;
while (*str)
{
for (sp = str; isalpha(*sp); sp++)
continue;
len = sp - str;
/* Look it up and deal with it */
for (op = optlist; op < &optlist[NUM_OPTS]; op++)
if (EQSTR(str, op->o_name, len))
{
if (op->o_putfunc == put_bool)
*op->o_opt.iarg = TRUE;
else /* string option */
{
char *start;
char value[80];
/* Skip to start of string value */
for (str = sp + 1; *str == '='; str++)
continue;
start = (char *) value;
/* Skip to end of string value */
for (sp = str + 1; *sp && *sp != ','; sp++)
continue;
strncpy(start, str, sp - str);
/* Put the value into the option field */
if (op->o_putfunc != put_abil &&
op->o_putfunc != put_inv)
strcpy(op->o_opt.str, value);
if (op->o_putfunc == put_inv)
{
int *opt = op->o_opt.iarg;
len = strlen(value);
if (isupper(value[0]))
value[0] = (char) tolower(value[0]);
if (EQSTR(value, "overwrite",len))
*opt = INV_OVER;
if (EQSTR(value, "slow", len))
*opt = INV_SLOW;
if (EQSTR(value, "clear", len))
*opt = INV_CLEAR;
}
else if (*op->o_opt.iarg == -1)
{
int *opt = op->o_opt.iarg;
len = strlen(value);
if (isupper(value[0]))
value[0] = (char) tolower(value[0]);
if (EQSTR(value, "fighter", len))
*opt = C_FIGHTER;
else if (EQSTR(value, "magic", min(len, 5)))
*opt = C_MAGICIAN;
else if (EQSTR(value, "illus", min(len, 5)))
*opt = C_ILLUSION;
else if (EQSTR(value, "cleric", len))
*opt = C_CLERIC;
else if (EQSTR(value, "thief", len))
*opt = C_THIEF;
else if (EQSTR(value, "paladin", len))
*opt = C_PALADIN;
else if (EQSTR(value, "ranger", len))
*opt = C_RANGER;
else if (EQSTR(value, "assasin", len))
*opt = C_ASSASIN;
else if (EQSTR(value, "druid", len))
*opt = C_DRUID;
else if (EQSTR(value, "ninja", len))
*opt = C_NINJA;
}
}
break;
}
else if (op->o_putfunc == put_bool
&& EQSTR(str, "no", 2) &&
EQSTR(str + 2, op->o_name, len - 2))
{
*op->o_opt.iarg = FALSE;
break;
}
/* skip to start of next option name */
while (*sp && !isalpha(*sp))
sp++;
str = sp;
}
}
/*
put_inv()
print the inventory type
*/
void
put_inv(opt_arg *opt, WINDOW *win)
{
char *style;
switch(*opt->iarg)
{
case INV_OVER:
style = "Overwrite";
break;
case INV_SLOW:
style = "Slow";
break;
case INV_CLEAR:
style = "Clear Screen";
break;
default:
style = "(unknown)";
}
waddstr(win, style);
}
/*
get_inv()
The inventory field.
*/
int
get_inv(opt_arg *opt, WINDOW *win)
{
int oy, ox, ny, nx;
int op_bad;
op_bad = TRUE;
getyx(win, oy, ox);
put_inv(opt, win);
getyx(win, ny, nx);
while(op_bad)
{
wmove(win, oy, ox);
wrefresh(win);
switch(readcharw(win))
{
case '\n':
case '\r':
op_bad = FALSE;
break;
case '\033':
case '\007':
return(QUIT);
case '-':
return(MINUS);
case 'O':
case 'o':
*opt->iarg = INV_OVER;
op_bad = FALSE;
break;
case 'S':
case 's':
*opt->iarg = INV_SLOW;
op_bad = FALSE;
break;
case 'C':
case 'c':
*opt->iarg = INV_CLEAR;
op_bad = FALSE;
break;
default:
mvwaddstr(win, ny, nx + 5, "(Use: o, s, or c)");
}
}
wmove(win, oy, ox);
wclrtoeol(win);
switch(*opt->iarg)
{
case INV_SLOW:
waddstr(win, "Slow\n");
break;
case INV_CLEAR:
waddstr(win, "Clear Screen\n");
break;
case INV_OVER:
waddstr(win, "Overwrite\n");
break;
default:
waddstr(win, "Unknown\n");
break;
}
return(NORM);
}

683
urogue/pack.c Normal file
View file

@ -0,0 +1,683 @@
/*
pack.c - Routines to deal with the pack.
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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.
*/
/*
Notes
The new pack is implemented through the use of bags,
and items are classed by their types (see rogue.h) which also
happen to be their display character.
*/
#include <stdlib.h>
#include <ctype.h>
#include "rogue.h"
#define ESCAPE_EXIT(x) if (x == ESCAPE) {after = FALSE; msg(""); return(NULL);}
#define BAD_NEWS -1
#define BAD_LIST ((struct linked_list *) BAD_NEWS)
#define GOOD_NEWS 0
static char type_list[] = "!?])/=:,"; /* things to inventory */
/*
swap_top()
Takes an stacked object and exchanges places with the top
object. <node> must belong to the <top>'s stacked object list.
*/
void
swap_top(struct linked_list *top, struct linked_list *node)
{
struct object *obt, *obn;
obt = OBJPTR(top);
obn = OBJPTR(node);
detach((obt->next_obj), node); /* Take it out of the stack */
attach(lvl_obj, node); /* and put it into the level */
detach(lvl_obj, top); /* Remove item from level */
obn->next_obj = obt->next_obj;
if (obn->next_obj)
obn->next_obj->l_prev = NULL;
attach((obn->next_obj), top);
}
/*
get_all()
Get as many stacked items as possible.
*/
void
get_all(struct linked_list *top)
{
struct linked_list *node;
struct object *obt;
while (top)
{
obt = OBJPTR(top);
node = obt->next_obj;
rem_obj(top, FALSE);
if (!add_pack(top, FALSE))
return;
top = node;
}
}
/*
get_stack()
Allows the user to chose from a stack of items.
*/
struct linked_list *
get_stack(struct linked_list *item)
{
struct object *obj;
char buf[2 * LINELEN];
int i = 0, j;
struct linked_list *ll;
mpos = 0;
obj = OBJPTR(item);
ll = obj->next_obj;
sprintf(buf, "You are standing on top of the following items: ");
add_line(buf);
sprintf(buf, "%d) -- %s", i, inv_name(obj, TRUE));
add_line(buf);
while (ll)
{
i++;
obj = OBJPTR(ll);
sprintf(buf, "%d) -- %s", i, inv_name(obj, TRUE));
add_line(buf);
ll = next(ll);
}
end_line();
msg("Which one do you want to pick up? [* for all] ");
switch(get_string(buf, cw))
{
case NORM:
break;
case QUIT: /* pick up nothing */
msg("");
return (NULL);
}
if (buf[0] == '*')
{
get_all(item);
msg("");
return(NULL);
}
else
{
i = atoi(buf);
if (i)
{
obj = OBJPTR(item);
ll = obj->next_obj;
j = 1;
while (ll && (j != i))
{
ll = next(ll);
j++;
}
if (ll)
{
swap_top(item, ll);
return(ll);
}
else
{
debug("Got past last item while picking up.");
return(item);
}
}
else
return (item);
}
}
/*
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 getting it off the
ground.
*/
int
add_pack(struct linked_list *item, int print_message)
{
struct object *obj, *op;
int from_floor;
if (item == NULL)
{
from_floor = TRUE;
if ((item = find_obj(hero.y, hero.x)) == NULL)
{
msg("Nothing to pick up.");
return(FALSE);
}
}
else
from_floor = FALSE;
if (from_floor)
{
item = get_stack(item);
if (!item)
return(FALSE);
}
obj = OBJPTR(item);
/* If it is gold, just add its value to rogue's purse and get rid of */
if (obj->o_type == GOLD)
{
struct linked_list *mitem;
struct thing *tp;
if (print_message)
{
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_horde==obj)
{
tp->t_ischasing = TRUE;
tp->t_chasee = &player;
tp->t_horde = NULL;
}
}
/*
* This will cause problems if people are able to drop and
* pick up gold, or when GOLDSTEAL monsters are killed.
*/
/* Thieves get EXP for gold they pick up */
if (player.t_ctype == C_THIEF)
{
pstats.s_exp += obj->o_count / 4;
check_level();
}
purse += obj->o_count;
if (from_floor)
rem_obj(item, TRUE); /* Remove object from the level */
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.");
if (print_message)
{
msg("%s onto %s", terse ? "Moved" : "You moved",
inv_name(obj, LOWERCASE));
}
return(FALSE);
}
/*
* Link it into the pack. If the item can be grouped, try to find its
* neighbors and bump the count. A special case is food, which can't
* be grouped, but an exact match allows the count to get
* incremented.
*/
if ((op = apply_to_bag(pack, obj->o_type, bff_group, NULL, obj)) != NULL)
{
op->o_count += obj->o_count; /* add it to the rest */
if (from_floor)
rem_obj(item, FALSE);
pack_report(op, print_message, "You now have ");
return(TRUE);
}
/* 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.");
rem_obj(item, TRUE);
return(TRUE);
}
/* Check if there is room */
if (count_bag(pack, obj->o_type, NULL) == max_print())
{
msg("You have no room for more %s.", name_type(obj->o_type));
if (print_message)
{
obj = OBJPTR(item);
msg("%s onto %s.", terse ? "Moved" : "You moved",
inv_name(obj, LOWERCASE));
}
return(FALSE);
}
/*
* finally, add the new item to the bag, and free up the linked list
* on top of it.
*/
if (from_floor)
rem_obj(item, FALSE);
push_bag(&pack, obj);
pack_report(obj, print_message, "You now have ");
ur_free(item);
return(TRUE); /* signal success */
}
/*
pack_report()
Notify the user about the results of the pack operation and do some
post processing.
*/
void
pack_report(object *obj, int print_message, char *message)
{
/* Notify the user */
if (print_message)
{
if (!terse)
addmsg(message);
msg("(%c%c) %s.", obj->o_type, print_letters[get_ident(obj)],
inv_name(obj, !terse));
}
if (obj->o_type == ARTIFACT)
{
has_artifact |= (1 << obj->o_which);
picked_artifact |= (1 << obj->o_which);
if (!(obj->ar_flags & ISUSED))
{
obj->ar_flags |= ISUSED;
pstats.s_exp += arts[obj->o_which].ar_worth / 10;
check_level();
}
}
updpack();
return;
}
/*
inventory()
list what is in the pack
*/
void
inventory(struct linked_list *container, int type)
{
int cnt;
if (type == 0)
{
msg("What kind of item <%s> to inventory (* for all)?", type_list);
type = readchar();
if (type == ESCAPE)
{
after = FALSE;
msg("");
return;
}
}
/*
* Get a list of items to print out. If the user selects '*', list
* them all.
*/
if (type == '*')
type = 0; /* no type passed ->use them all */
mpos = 0;
if ((cnt = count_bag(container, type, NULL)) == 0)
msg("You don't have any %s.", name_type(type));
else
{
apply_to_bag(container, type, NULL, baf_print_item, &type);
end_line();
msg("");
}
return;
}
/*
pick_up()
Add something to characters pack.
*/
void
pick_up(char ch)
{
switch(ch)
{
default:
debug("Where did you pick that up???");
break;
case GOLD:
case ARMOR:
case POTION:
case FOOD:
case WEAPON:
case SCROLL:
case ARTIFACT:
case RING:
case STICK:
add_pack(NULL, MESSAGE);
break;
}
}
/*
get_object()
Pick something out of a pack for a purpose. The basic idea is to
list all the possibilities, let the user select one, get that item
from the container, and pass it back to the calling routine.
*/
struct object *
get_object(struct linked_list *container, char *purpose, int type, int (*bff_p)(struct object *obj, bag_arg *junk))
/* char *container; what container has what we want */
/* char *purpose; a message (verb) to print if we cant find any */
/* char type; type (o_type) to pick out (NULL = any) */
/* int (*bff_p) (); bag filter function to test item */
{
struct object *obj_p = NULL;
char sel_id; /* selected type and id */
int sel_type;
char response;
if (container == NULL)
{
msg("There isn't anything in there.");
after = FALSE;
return(NULL);
}
/* Make sure we have at least one item that qualifies! */
if (apply_to_bag(container, type, bff_p, NULL, NULL) == NULL)
{
msg("You seem to have nothing to %s.", purpose);
after = FALSE;
return(NULL);
}
while (obj_p == NULL)
{
if (type == 0)
{
msg("What kind of item <%s> do you want to %s (* for list)?", type_list, purpose);
response = readchar();
ESCAPE_EXIT(response);
msg("");
if (response == '*')
{
add_line("! Potion");
add_line("? Scroll");
add_line("= Ring");
add_line("/ Stick");
add_line("] Armor");
add_line(") Weapon");
add_line(": Food");
end_line();
continue;
}
if (!is_member(type_list, response)) { beep();
continue; }
if (count_bag(container, response, NULL) == 0)
{
msg("You don't have any %s.", name_type(response));
continue;
}
type = response;
}
while(obj_p == NULL)
{
msg("What item do you want to %s (* for list)?", purpose);
response = readchar();
msg("");
ESCAPE_EXIT(response);
if (response == '*')
{
mpos = 0;
apply_to_bag(container, type, bff_p, baf_print_item, &type);
end_line();
continue;
}
sel_type = type;
sel_id = response;
obj_p = scan_bag(container, sel_type,unprint_id(&sel_id));
}
}
mpos = 0;
msg("");
return(obj_p);
}
/*
get_item()
This is only an interim function that serves as an interface to
the old function get_item and its replacement get_object. It
assumes a NULL action routine and allocates a linked_list
structure on top of the object pointer.
*/
struct linked_list *
get_item(char *purpose, int type)
{
struct object *obj_p;
if ((obj_p = get_object(pack, purpose, type, NULL)) == NULL)
return(NULL);
return(make_item(obj_p));
}
/*
del_pack()
Take something out of the hero's pack and throw it away.
*/
void
del_pack(struct linked_list *what)
{
rem_pack(OBJPTR(what));
discard(what);
}
/*
discard_pack
take an object from the pack and throw it away (like del_pack,
but without the linked_list structure)
*/
void
discard_pack(struct object *obj_p)
{
rem_pack(obj_p);
throw_away(obj_p);
}
/*
rem_pack()
Removes an item from the pack.
*/
void
rem_pack(struct object *obj_p)
{
cur_null(obj_p); /* check for current stuff */
pop_bag(&pack, obj_p);
updpack();
return; /* tell caller an item has been removed */
}
/*
cur_null()
This updates cur_weapon etc for dropping things
*/
void
cur_null(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[LEFT_5])
cur_ring[LEFT_5] = 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_ring[RIGHT_5])
cur_ring[RIGHT_5] = NULL;
}
/*
idenpack()
Identify all the items in the pack
*/
void
idenpack(void)
{
apply_to_bag(pack, 0, NULL, baf_identify, NULL);
}
/*
show_floor()
Print out the item on the floor. Used by the move command.
*/
void
show_floor(void)
{
struct linked_list *item;
struct object *obj;
item = find_obj(hero.y, hero.x);
if (item != NULL)
{
addmsg("%s onto ", terse ? "Moved" : "You moved");
obj = OBJPTR(item);
if (obj->next_obj != NULL)
msg("a stack of things.");
else if (obj->o_type == GOLD)
msg("%d gold pieces.", obj->o_count);
else
{
addmsg(inv_name(obj, TRUE));
addmsg(".");
endmsg();
}
}
}

320
urogue/passages.c Normal file
View file

@ -0,0 +1,320 @@
/*
passages.c - Draw the connecting passages
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdlib.h>
#include "rogue.h"
#define cmov(xy) move((xy).y, (xy).x)
/*
do_passages()
Draw all the passages on a level.
*/
void
do_passages(void)
{
struct rdes *r1, *r2 = NULL;
int i, j;
int roomcount;
static struct rdes 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]; 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
{
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)];
}
while (!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.
*/
void
conn(int r1, int r2)
{
struct room *rpf, *rpt = NULL;
int rmt;
int distance = 0, turn_spot = 0, turn_distance = 0;
int rm;
char direc;
coord delt = {0,0}, curr, turn_delta = {0,0}, spos = {0,0}, epos = {0,0};
if (r1 < r2)
{
rm = r1;
if (r1 + 1 == r2)
direc = 'r';
else
direc = 'd';
}
else
{
rm = r2;
if (r2 + 1 == r1)
direc = 'r';
else
direc = 'd';
}
rpf = &rooms[rm];
/*
* Set up the movement variables, in two cases: first drawing one
* down.
*/
if (direc == 'd')
{
rmt = rm + 3; /* room # of dest */
rpt = &rooms[rmt]; /* room pointer of dest */
delt.x = 0; /* direction of move */
delt.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);
turn_distance = abs(spos.x - epos.x); /* how far to turn */
turn_spot = rnd(distance - 1) + 1; /* where turn starts */
}
else if (direc == 'r') /* setup for moving right */
{
rmt = rm + 1;
rpt = &rooms[rmt];
delt.x = 1;
delt.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;
turn_distance = abs(spos.y - epos.y);
turn_spot = rnd(distance - 1) + 1;
}
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('#');
}
/* Get ready to move... */
curr.x = spos.x;
curr.y = spos.y;
while (distance)
{
/* Move to new position */
curr.x += delt.x;
curr.y += delt.y;
/* Check if we are at the turn place, if so do the turn */
if (distance == turn_spot && turn_distance > 0)
while (turn_distance--)
{
cmov(curr);
addch(PASSAGE);
curr.x += turn_delta.x;
curr.y += turn_delta.y;
}
/* Continue digging along */
cmov(curr);
addch(PASSAGE);
distance--;
}
curr.x += delt.x;
curr.y += delt.y;
if (!ce(curr, epos))
msg("Warning, connectivity problem on this level.");
}
/*
door()
Add a door or possibly a secret door also enters the door in the exits
array of the room.
*/
void
door(struct room *rm, coord *cp)
{
char a_door;
cmov(*cp);
a_door = (rnd(10)<level - 1 && rnd(100) < 20) ? SECRETDOOR : DOOR;
addch(a_door);
rm->r_exit[rm->r_nexits++] = *cp;
}

538
urogue/player.c Normal file
View file

@ -0,0 +1,538 @@
/*
player.c - functions for dealing with special player abilities
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdlib.h>
#include <ctype.h>
#include "rogue.h"
/*
* Pray to a deity
*
* 00-10 Good stuff happens
* 11-40 A good deity answers
* 41-60 Nothing happens
* 61-90 A bad deity answers, but with good results
* 91-99 You were better off before
*/
void
prayer(void)
{
int chance, i, times;
char num_str[20];
int ch;
struct linked_list *item;
struct thing *tp;
int is_godly;
if (player.t_praycnt > pstats.s_lvl)
{
msg("Are you sure you want to bother the gods?");
ch = readchar();
if (tolower(ch) != 'y')
{
after = FALSE;
return;
}
else
msg("Here goes...");
}
msg("You are surrounded by orange smoke...");
if (rnd(3) == 0)
luck--;
if (is_wearing(R_PIETY) || (rnd(luck) == 0 &&
(player.t_ctype == C_DRUID || player.t_ctype == C_CLERIC ||
((player.t_ctype == C_PALADIN || player.t_ctype == C_RANGER)
&& pstats.s_lvl > 8))))
is_godly = ISBLESSED;
else
is_godly = ISNORMAL;
if (is_wearing(R_PIETY))
player.t_praycnt += rnd(2);
else
player.t_praycnt++;
if (wizard)
{
msg("What roll?[0..%d] ", 99);
ch = get_string(num_str, cw);
if (ch == QUIT)
{
msg("");
return;
}
chance = atoi(num_str);
}
else
{
chance = rnd(100) + roll(10, luck) - 5;
if (player.t_praycnt > pstats.s_lvl)
chance += 50;
if (is_godly)
chance -= 50;
}
chance = max(0, min(chance, 100));
if (chance == 0)
{
msg("The heavens open and glorious radiance surrounds you!");
pstats.s_hpt = max_stats.s_hpt;
pstats.s_power = max_stats.s_power;
if (is_godly)
times = 8;
else
times = 1;
/*
* kill all monsters surrounding the hero except unique ones
* This will change when I implement the deity option. If
* The deity is "stronger" than the unique monster, then the
* monster will be killed.
*/
for (i = 0; i < times; i++)
{
item = f_mons_a(player.t_pos.y, player.t_pos.x, TRUE);
if (item)
{
tp = THINGPTR(item);
msg("A bolt of eldritch energy strikes down the %s!",
monsters[tp->t_index].m_name);
killed(NULL, item, NOMESSAGE, POINTS);
}
}
}
else if (chance == 2)
{
msg("Aule, Lord of Crafts, hears your call.");
read_scroll(&player, S_MAKEITEMEM, is_godly);
}
/* Save 3-9 for other wonderful stuff */
else if (chance < 15)
{
msg("Orome, Lord of Forests, hears your call.");
read_scroll(&player, S_SUMMON, is_godly);
}
else if (chance < 20)
{
msg("Hermes, the Winged Messenger, hears your call.");
quaff(&player, P_HASTE, is_godly);
}
else if (chance < 25)
{
msg("Lorien, Master of Dreams, hears your call.");
read_scroll(&player, S_SLEEP, is_godly);
}
else if (chance < 30)
{
msg("Este, Lady of Healing, hears your call.");
quaff(&player, P_RESTORE, is_godly);
quaff(&player, P_HEALING, is_godly);
}
else if (chance < 35)
{
msg("Thor, God of Thunder, hears your call.");
msg("A bolt of lighting strikes you!");
read_scroll(&player, S_ELECTRIFY, is_godly);
}
else if (chance < 40)
{
msg("Lorien, Master of Illusion, hears your call.");
quaff(&player, P_DISGUISE, is_godly);
}
else if (chance < 60) /* Nothing happens */
{
msg("Boccob, the Uncaring, ignores you.");
}
/* You don't really want one of these gods answering your call */
else if (chance < 65)
{
msg("Jubilex, Master of Slimes and Oozes, hears your call.");
read_scroll(&player, S_HOLD, is_godly);
luck++;
}
else if (chance < 70)
{
msg("Sauron, Lord of the Ring, hears your call.");
quaff(&player, P_INVIS, is_godly);
luck++;
}
else if (chance < 75)
{
msg("Orcus, Lord of Undead, hears your call.");
quaff(&player, P_PHASE, is_godly);
luck++;
}
else if (chance < 80)
{
msg("Incabulos, God of Evil Sendings, hears your call.");
quaff(&player, P_CLEAR, is_godly);
luck++;
}
else if (chance < 85)
{
msg("Raxivort, Night Flutterer, hears your call.");
quaff(&player, P_SEEINVIS, is_godly);
luck++;
}
else if (chance < 90)
{
msg("Morgoth, Lord of Fire, hears your call.");
quaff(&player, P_FIRERESIST, is_godly);
luck++;
}
else if (chance < 100) /* You are in for it now! */
{
msg("You fall into a horrible trance-like state.");
no_command += SLEEPTIME;
}
if (chance == 100)
{
msg("The heavens open - but wait!");
msg("A bolt of eldritch energy strikes you!");
if (pstats.s_hpt > 1)
pstats.s_hpt /= 2;
msg("The gods must be angry with you.");
}
}
/* Routines for thieves */
/*
gsense()
Sense gold returns TRUE if gold was detected
*/
int
gsense(void)
{
if (lvl_obj != NULL)
{
struct linked_list *gitem;
struct object *cur;
int gtotal = 0;
wclear(hw);
for (gitem = lvl_obj; gitem != NULL; gitem = next(gitem))
{
cur = OBJPTR(gitem);
if (cur->o_type == GOLD)
{
gtotal += cur->o_count;
mvwaddch(hw, cur->o_pos.y, cur->o_pos.x, GOLD);
}
}
if (gtotal)
{
msg("You sense gold!");
overlay(hw, cw);
return(TRUE);
}
}
nothing_message(ISNORMAL);
return(FALSE);
}
/*
is_stealth()
is player quiet about something
*/
int
is_stealth(struct thing *tp)
{
return (rnd(25) < tp->t_stats.s_dext ||
(tp == &player && is_wearing(R_STEALTH)));
}
/*
steal()
Steal in direction given in delta
*/
void
steal(void)
{
struct linked_list *item;
struct thing *tp;
coord new_pos;
short thief_bonus;
char *unsuccess = "";
char *gain = "";
char *notice = "is not";
new_pos.y = hero.y + delta.y;
new_pos.x = hero.x + delta.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("There is no one to steal from.");
return;
}
if ((item = find_mons(new_pos.y, new_pos.x)) == NULL)
return;
tp = THINGPTR(item);
/* Can player steal something unnoticed? */
if (player.t_ctype == C_THIEF || player.t_ctype == C_NINJA)
thief_bonus = 10;
else
thief_bonus = -50;
if (rnd(50) >= 3 * pstats.s_dext + thief_bonus)
{
chase_it(&new_pos, &player);
turn_off(*tp, ISFRIENDLY);
notice = "is";
}
if (rnd(100) <
(thief_bonus + 2 * pstats.s_dext + 5 * pstats.s_lvl -
5 * (tp->t_stats.s_lvl - 3)))
{
struct linked_list *s_item, *pack_ptr;
int cnt = 0;
s_item = NULL; /* Start stolen goods out as nothing */
/* Find a good item to take */
if (tp->t_pack != NULL)
{
/* Count up the number of items in the monster's pack */
for (pack_ptr = tp->t_pack; pack_ptr != NULL; pack_ptr = next(pack_ptr))
cnt++;
/* Pick one */
cnt = rnd(cnt);
/* Take it from the monster */
for (pack_ptr = tp->t_pack; --cnt == 0; pack_ptr = next(pack_ptr))
;
s_item = pack_ptr;
detach(tp->t_pack, s_item);
/* Give it to player */
if (add_pack(s_item, MESSAGE) == FALSE)
{
(OBJPTR(s_item))->o_pos = hero;
fall(&player, s_item, TRUE, FALSE);
}
/* Get points for stealing from unfriendly monsters */
if (off(*tp, ISFRIENDLY))
{
if (player.t_ctype == C_THIEF)
pstats.s_exp += 2 * tp->t_stats.s_exp / 3;
else
pstats.s_exp += tp->t_stats.s_exp / min(pstats.s_lvl, 10);
check_level();
}
}
else
{
gain = " gains you nothing and";
}
}
else
{
unsuccess = " unsuccessful";
}
msg("Your%s attempt%s %s noticed.", unsuccess, gain, notice);
}
/*
affect()
cleric affecting undead
*/
void
affect(void)
{
struct linked_list *item;
struct thing *tp;
char *mname;
coord new_pos;
int is_godly;
int effective_level;
if (player.t_ctype != C_CLERIC && player.t_ctype != C_PALADIN &&
!is_wearing(R_PIETY))
{
msg("Only clerics and paladins can affect undead.");
return;
}
is_godly = (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN);
if (is_godly && is_wearing(R_PIETY))
effective_level = 2 * pstats.s_lvl;
else
effective_level = pstats.s_lvl;
new_pos.y = hero.y + delta.y;
new_pos.x = hero.x + delta.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 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 = monsters[tp->t_index].m_name;
if (off(*tp, ISUNDEAD))
{
msg("Your holy symbol has no effect on the %s.", mname);
goto annoy;
}
if (on(*tp, WASTURNED))
{
msg("Your holy symbol merely enrages the %s.", mname);
goto annoy;
}
/* Can cleric destroy it? */
if (effective_level >= 3 * tp->t_stats.s_lvl)
{
msg("You have destroyed the %s.", mname);
killed(&player, item, NOMESSAGE, POINTS);
return;
}
/* Can cleric turn it? */
if (rnd(100) + 1 >
(100 * ((2 * tp->t_stats.s_lvl) - effective_level)) /
effective_level)
{
msg("You have turned the %s.", mname);
turn_on(*tp, WASTURNED); /* One turn per monster */
turn_on(*tp, ISRUN);
turn_on(*tp, ISFLEE);
/* If monster was suffocating, stop it */
if (on(*tp, DIDSUFFOCATE))
{
turn_off(*tp, DIDSUFFOCATE);
extinguish_fuse(FUSE_SUFFOCATE);
}
/* If monster held us, stop it */
if (on(*tp, DIDHOLD) && (--hold_count == 0))
turn_off(player, ISHELD);
turn_off(*tp, DIDHOLD);
return;
}
msg("The %s momentarily recoils from your holy symbol.", mname);
annoy:
if (off(*tp, WASTURNED))
chase_it(&new_pos, &player);
}
/*
undead_sense()
cleric or paladin finding the ungodly
*/
void
undead_sense(void)
{
struct linked_list *item;
struct thing *tp;
int showit = FALSE;
wclear(hw);
for (item = mlist; item != NULL; item = next(item))
{
tp = THINGPTR(item);
if (on(*tp, ISUNDEAD))
{
mvwaddch(hw, tp->t_pos.y, tp->t_pos.x, '&');
showit = TRUE;
}
}
if (showit)
{
msg("You feel the presense of the ungodly.");
overlay(hw, cw);
wrefresh(cw);
wclear(hw);
}
}

1516
urogue/potions.c Normal file

File diff suppressed because it is too large Load diff

23
urogue/random.c Normal file
View file

@ -0,0 +1,23 @@
/*
random.c - random and associated routines
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1992, 1993, 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "rogue.h"
void
ur_srandom(unsigned x)
{
md_srandom(x);
}
long
ur_random(void)
{
return( md_random() );
}

354
urogue/rings.c Normal file
View file

@ -0,0 +1,354 @@
/*
rings.c - Routines dealing specificaly with rings
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <string.h>
#include <stdlib.h>
#include "rogue.h"
void
ring_on(void)
{
struct object *obj;
struct linked_list *item;
int ring;
char buf[2 * LINELEN];
if ((item = get_item("put on", RING)) == NULL)
return;
obj = OBJPTR(item);
if (obj->o_type != RING)
{
msg("You can't put that on!");
return;
}
/* find out which hand to put it on */
if (is_current(obj))
{
msg("Already wearing that!");
return;
}
if (cur_ring[LEFT_1] == NULL)
ring = LEFT_1;
else if (cur_ring[LEFT_2] == NULL)
ring = LEFT_2;
else if (cur_ring[LEFT_3] == NULL)
ring = LEFT_3;
else if (cur_ring[LEFT_4] == NULL)
ring = LEFT_4;
else if (cur_ring[LEFT_5] == NULL)
ring = LEFT_5;
else if (cur_ring[RIGHT_1] == NULL)
ring = RIGHT_1;
else if (cur_ring[RIGHT_2] == NULL)
ring = RIGHT_2;
else if (cur_ring[RIGHT_3] == NULL)
ring = RIGHT_3;
else if (cur_ring[RIGHT_4] == NULL)
ring = RIGHT_4;
else if (cur_ring[RIGHT_5] == NULL)
ring = RIGHT_5;
else
{
msg("You already have on ten rings.");
return;
}
cur_ring[ring] = obj;
/* Calculate the effect it has on the poor guy. */
switch (obj->o_which)
{
case R_ADDSTR:
pstats.s_str += obj->o_ac;
break;
case R_ADDHIT:
pstats.s_dext += obj->o_ac;
break;
case R_ADDINTEL:
pstats.s_intel += obj->o_ac;
break;
case R_ADDWISDOM:
pstats.s_wisdom += obj->o_ac;
break;
case R_FREEDOM:
turn_off(player, ISHELD);
hold_count = 0;
break;
case R_TRUESEE:
if (off(player, PERMBLIND))
{
turn_on(player, CANTRUESEE);
msg("You become more aware of your surroundings.");
sight(NULL);
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
break;
case R_SEEINVIS:
if (off(player, PERMBLIND))
{
turn_on(player, CANTRUESEE);
msg("Your eyes begin to tingle.");
sight(NULL);
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
break;
case R_AGGR:
aggravate();
break;
case R_CARRYING:
updpack();
break;
case R_LEVITATION:
msg("You begin to float in the air!");
break;
case R_LIGHT:
if (roomin(hero) != NULL)
{
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
}
status(FALSE);
if (know_items[TYP_RING][obj->o_which] &&
guess_items[TYP_RING][obj->o_which])
{
mem_free(guess_items[TYP_RING][obj->o_which]);
guess_items[TYP_RING][obj->o_which] = NULL;
}
else if (!know_items[TYP_RING][obj->o_which] &&
askme &&
(obj->o_flags & ISKNOW) == 0 &&
guess_items[TYP_RING][obj->o_which] == NULL)
{
mpos = 0;
msg("What do you want to call it? ");
if (get_string(buf, cw) == NORM)
{
guess_items[TYP_RING][obj->o_which] =
new_alloc(strlen(buf) + 1);
strcpy(guess_items[TYP_RING][obj->o_which], buf);
}
msg("");
}
}
void
ring_off(void)
{
struct object *obj;
struct linked_list *item;
if (cur_ring[LEFT_1] == NULL && cur_ring[LEFT_2] == NULL &&
cur_ring[LEFT_3] == NULL && cur_ring[LEFT_4] == NULL &&
cur_ring[LEFT_5] == NULL &&
cur_ring[RIGHT_1] == NULL && cur_ring[RIGHT_2] == NULL &&
cur_ring[RIGHT_3] == NULL && cur_ring[RIGHT_4] == NULL &&
cur_ring[RIGHT_5] == NULL)
{
msg("You aren't wearing any rings.");
return;
}
else if ((item = get_item("remove", RING)) == NULL)
return;
mpos = 0;
obj = OBJPTR(item);
if ((obj = OBJPTR(item)) == NULL)
msg("You are not wearing that!");
if (dropcheck(obj))
{
switch (obj->o_which)
{
case R_SEEINVIS:
msg("Your eyes stop tingling.");
break;
case R_CARRYING:
updpack();
break;
case R_LEVITATION:
msg("You float gently to the ground.");
break;
case R_LIGHT:
if (roomin(hero) != NULL)
{
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
break;
case R_TRUESEE:
msg("Your sensory perceptions return to normal.");
break;
}
msg("Was wearing %s.", inv_name(obj, LOWERCASE));
}
}
/*
ring_eat()
how much food does this ring use up?
*/
int
ring_eat(int hand)
{
int ret_val = 0;
int ac;
if (cur_ring[hand] != NULL)
{
switch (cur_ring[hand]->o_which)
{
case R_REGEN:
case R_VREGEN:
ret_val = rnd(pstats.s_lvl > 10 ? 10 : pstats.s_lvl);
case R_DIGEST:
ac = cur_ring[hand]->o_ac;
if (ac < 0 && rnd(1 - (ac / 3)) == 0)
ret_val = -ac + 1;
else if (rnd((ac / 2) + 2) == 0)
ret_val = -1 - ac;
break;
case R_SEARCH:
ret_val = rnd(100) < 33;
break;
default:
ret_val = 1;
}
}
ret_val += rnd(luck);
return(ret_val);
}
/*
ring_num()
print ring bonuses
*/
char *
ring_num(struct object *obj, char *buf)
{
char buffer[1024];
if (buf == NULL)
return("A bug in UltraRogue #101");
buf[0] = 0;
if (obj->o_flags & ISKNOW)
{
switch (obj->o_which)
{
case R_SEARCH:
case R_PROTECT:
case R_ADDSTR:
case R_ADDDAM:
case R_ADDHIT:
case R_ADDINTEL:
case R_ADDWISDOM:
case R_CARRYING:
case R_VREGEN:
case R_RESURRECT:
case R_TELCONTROL:
case R_REGEN:
case R_PIETY:
case R_WIZARD:
buf[0] = ' ';
strcpy(&buf[1], num(obj->o_ac, 0,buffer));
break;
case R_DIGEST:
buf[0] = ' ';
strcpy(&buf[1], num(obj->o_ac < 0 ?
obj->o_ac : obj->o_ac - 1, 0, buffer));
break;
default:
if (obj->o_flags & ISCURSED)
strcpy(buf, " cursed");
break;
}
}
return(buf);
}
/*
ring_value()
Return the effect of the specified ring
*/
#define ISRING(h, r) (cur_ring[h] != NULL && cur_ring[h]->o_which == r)
int
ring_value(int 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(LEFT_5, type))
result += cur_ring[LEFT_5]->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;
if (ISRING(RIGHT_5, type))
result += cur_ring[RIGHT_5]->o_ac;
return(result);
}

661
urogue/rip.c Normal file
View file

@ -0,0 +1,661 @@
/*
rip.c - File for the fun ends Death or a total win
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include "rogue.h"
static struct sc_ent
{
int sc_lvl;
long sc_score;
char sc_name[76];
long sc_gold;
int sc_flags;
int sc_level;
int sc_artifacts;
int sc_monster;
} top_ten[10];
static const char *rip[] =
{
" __________",
" / \\",
" / REST \\",
" / IN \\",
" / PEACE \\",
" / \\",
" | |",
" | |",
" | killed by |",
" | |",
" | 1993 |",
" *| * * * | *",
" ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______",
0
};
/*
death()
Do something really fun when he dies
*/
void
death(int monst)
{
char **dp = (char **) rip, *killer;
struct tm *lt;
time_t date;
char buf[80];
int c;
if (is_wearing(R_RESURRECT) || rnd(wizard ? 3 : 67) == 0)
{
int die = TRUE;
if (resurrect-- == 0)
msg("You've run out of lives.");
else if (!save_resurrect(ring_value(R_RESURRECT)))
msg("Your attempt to return from the grave fails.");
else
{
struct linked_list *item;
struct linked_list *next_item;
struct object *obj;
int rm, flags;
coord pos;
die = FALSE;
msg("You feel a sudden warmth and then nothingness.");
teleport();
if (ring_value(R_RESURRECT) > 1 && rnd(10))
{
pstats.s_hpt = 2 * pstats.s_const;
pstats.s_const = max(pstats.s_const - 1, 3);
}
else
{
for (item = pack; item != NULL; item = next_item)
{
obj = OBJPTR(item);
if (obj->o_flags & ISOWNED || obj->o_flags & ISPROT)
{
next_item = next(item);
continue;
}
flags = obj->o_flags;
obj->o_flags &= ~ISCURSED;
dropcheck(obj);
obj->o_flags = flags;
next_item = next(item);
rem_pack(obj);
if (obj->o_type == ARTIFACT)
has_artifact &= ~(1 << obj->o_which);
do
{
rm = rnd_room();
rnd_pos(&rooms[rm], &pos);
}
while(winat(pos.y, pos.x) != FLOOR);
obj->o_pos = pos;
add_obj(item, obj->o_pos.y, obj->o_pos.x);
}
pstats.s_hpt = pstats.s_const;
pstats.s_const = max(pstats.s_const - roll(2, 2), 3);
}
chg_str(roll(1, 4), TRUE, FALSE);
pstats.s_lvl = max(pstats.s_lvl, 1);
no_command += 2 + rnd(4);
if (on(player, ISHUH))
lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
else
light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
turn_on(player, ISHUH);
light(&hero);
}
if (die)
{
wmove(cw, mpos, 0);
waddstr(cw, morestr);
wrefresh(cw);
wait_for(' ');
}
else
return;
}
time(&date);
lt = localtime(&date);
clear();
wclear(cw);
move(8, 0);
while (*dp)
printw("%s\n", *dp++);
mvaddstr(14, 28 - ((int)(strlen(whoami) + 1) / 2), whoami);
sprintf(buf, "%d+%ld Points", pstats.s_lvl, pstats.s_exp);
mvaddstr(15, 28 - ((int)(strlen(buf) + 1) / 2), buf);
killer = killname(monst,buf);
mvaddstr(17, 28 - ((int)(strlen(killer) + 1) / 2), killer);
mvaddstr(18, 28, (sprintf(prbuf, "%2d", lt->tm_year), prbuf));
move(LINES - 1, 0);
mvaddstr(LINES - 1, 0, retstr);
while ((c = readcharw(stdscr)) != '\n' && c != '\r')
continue;
idenpack();
wrefresh(cw);
refresh();
score(pstats.s_exp, pstats.s_lvl, KILLED, monst);
byebye();
}
/*
score()
figure score and post it.
*/
void
score(long amount, int lvl, int flags, int monst) /*ARGSUSED*/
{
struct sc_ent *scp=NULL, *sc2=NULL;
int i;
char *killer;
char buf[1024];
static const char *reason[] =
{
"killed",
"quit",
"a winner",
"a total winner"
};
char *packend;
if (flags != WINNER && flags != TOTAL && flags != SCOREIT)
{
if (flags == CHICKEN)
packend = "when you quit";
else
packend = "at your untimely demise";
noecho();
nl();
refresh();
showpack(packend);
}
/* Open file and read list */
if (fd_score == NULL)
{
printf("No score file opened\n");
return;
}
for (scp = top_ten; scp < &top_ten[10]; scp++)
{
scp->sc_lvl = 0L;
scp->sc_score = 0L;
for (i = 0; i < 76; i++)
scp->sc_name[i] = ucrnd(255);
scp->sc_gold = 0L;
scp->sc_flags = rnd(10);
scp->sc_level = rnd(10);
scp->sc_monster = srnd(10);
scp->sc_artifacts = 0;
}
if (flags != SCOREIT)
{
mvaddstr(LINES - 1, 0, retstr);
refresh();
fflush(stdout);
wait_for('\n');
}
fseek(fd_score, 0L, SEEK_SET);
fread(top_ten, sizeof(top_ten), 1, fd_score);
/* Insert player in list if need be */
if (!waswizard)
{
for (scp = top_ten; scp < &top_ten[10]; scp++)
{
if (lvl > scp->sc_lvl)
break;
if (lvl == scp->sc_lvl && amount > scp->sc_score)
break;
}
if (scp < &top_ten[10])
{
if (flags == WINNER)
sc2 = &top_ten[9]; /* LAST WINNER ALWAYS MAKES IT */
while (sc2 > scp)
{
*sc2 = sc2[-1];
sc2--;
}
scp->sc_lvl = lvl;
scp->sc_gold = purse;
scp->sc_score = amount;
strcpy(scp->sc_name, whoami);
strcat(scp->sc_name,", ");
strcat(scp->sc_name, which_class(player.t_ctype));
scp->sc_flags = flags;
if (flags == WINNER)
scp->sc_level = max_level;
else
scp->sc_level = level;
scp->sc_monster = monst;
scp->sc_artifacts = has_artifact;
sc2 = scp;
}
}
if (flags != SCOREIT)
{
clear();
refresh();
endwin();
}
/* Print the list */
printf("\nTop Ten Adventurers:\n%4s %15s %10s %s\n",
"Rank", "Score", "Gold", "Name");
for (scp = top_ten; scp < &top_ten[10]; scp++)
{
if (scp->sc_score)
{
char lev[20];
sprintf(lev, "%ld+%ld", scp->sc_lvl, scp->sc_score);
printf("%4d %15s %10ld %s:", scp - top_ten + 1,
lev,
scp->sc_gold,
scp->sc_name);
if (scp->sc_artifacts)
{
char thangs[80];
int n;
int first = TRUE;
thangs[0] = '\0';
for (n = 0; n <= maxartifact; n++)
{
if (scp->sc_artifacts & (1 << n))
{
if (strlen(thangs))
strcat(thangs, ", ");
if (first)
{
strcat(thangs, "retrieved ");
first = FALSE;
}
if (45 - strlen(thangs) < strlen(arts[n].ar_name))
{
printf("%s\n%32s", thangs," ");
thangs[0] = '\0';
}
strcat(thangs, arts[n].ar_name);
}
}
if (strlen(thangs))
printf("%s,", thangs);
printf("\n%32s"," ");
}
printf("%s on level %d",reason[scp->sc_flags],scp->sc_level);
if (scp->sc_flags == 0)
{
printf(" by \n%32s"," ");
killer = killname(scp->sc_monster, buf);
printf(" %s", killer);
}
putchar('\n');
}
}
if (sc2 != NULL)
{
fseek(fd_score, 0L, SEEK_SET);
/* Update the list file */
fwrite(top_ten, sizeof(top_ten), 1, fd_score);
}
fclose(fd_score);
}
void
total_winner(void)
{
struct linked_list *item;
struct object *obj;
int worth, oldpurse;
char c;
struct linked_list *bag = NULL;
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 \n");
addstr("escaped the Dungeons of Doom alive. You journey home \n");
addstr("and sell all your loot at a great profit.\n");
addstr("The White Council approves the recommendation of\n");
if (player.t_ctype == C_FIGHTER)
addstr("the fighters guild and appoints you Lord Protector\n");
else if (player.t_ctype == C_ASSASIN)
addstr("the assassins guild and appoints you Master Murderer\n");
else if (player.t_ctype == C_NINJA)
addstr("the ninja guild and appoints you Master of the Wind\n");
else if (player.t_ctype == C_ILLUSION)
addstr("the illusionists guild and appoints you Master Wizard\n");
else if (player.t_ctype == C_MAGICIAN)
addstr("the magicians guild and appoints you Master Wizard\n");
else if (player.t_ctype == C_CLERIC)
addstr("the temple priests and appoints you Master of the Flowers\n");
else if (player.t_ctype == C_DRUID)
addstr("the temple priests and appoints you Master of the Flowers\n");
else if (player.t_ctype == C_RANGER)
addstr("the rangers guild and appoints you Master Ranger\n");
else if (player.t_ctype == C_PALADIN)
addstr("the paladins guild and appoints you Master Paladin\n");
else if (player.t_ctype == C_THIEF)
{
addstr("the thieves guild under protest and appoints you\n");
addstr("Master of the Highways\n");
}
addstr("of the Land Between the Mountains.\n");
mvaddstr(LINES - 1, 0, spacemsg);
refresh();
wait_for(' ');
clear();
idenpack();
oldpurse = purse;
mvaddstr(0, 0, " Worth Item");
for (c = 'a', item = pack; item != NULL; c++, item = next(item))
{
obj = OBJPTR(item);
worth = get_worth(obj);
purse += worth;
if (obj->o_type == ARTIFACT && obj->o_which == TR_PURSE)
bag = obj->o_bag;
mvprintw(c - 'a' + 1, 0, "%c) %8d %s", c,
worth, inv_name(obj, UPPERCASE));
}
if (bag != NULL)
{
mvaddstr(LINES - 1, 0, morestr);
refresh();
wait_for(' ');
clear();
mvprintw(0, 0, "Contents of the Magic Purse of Yendor:\n");
for (c = 'a', item = bag; item != NULL; c++, item = next(item))
{
obj = OBJPTR(item);
worth = get_worth(obj);
whatis(item);
purse += worth;
mvprintw(c - 'a' + 1, 0, "%c) %8d %s\n", c,
worth, inv_name(obj, UPPERCASE));
}
}
mvprintw(c - 'a' + 1, 0, " %6d Gold Pieces ", oldpurse);
refresh();
if (has_artifact == 255)
score(pstats.s_exp, pstats.s_lvl, TOTAL, 0);
else
score(pstats.s_exp, pstats.s_lvl, WINNER, 0);
byebye();
}
char *
killname(int monst, char *buf)
{
if (buf == NULL)
return("A bug in UltraRogue #102");
if (monst >= 0)
{
switch (monsters[monst].m_name[0])
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
sprintf(buf, "an %s", monsters[monst].m_name);
break;
default:
sprintf(buf, "a %s", monsters[monst].m_name);
}
return(buf);
}
else
switch(monst)
{
case D_ARROW:
strcpy(buf, "an arrow"); break;
case D_DART:
strcpy(buf, "a dart"); break;
case D_BOLT:
strcpy(buf, "a bolt"); break;
case D_POISON:
strcpy(buf, "poison"); break;
case D_POTION:
strcpy(buf, "a cursed potion"); break;
case D_PETRIFY:
strcpy(buf, "petrification"); break;
case D_SUFFOCATION:
strcpy(buf, "suffocation"); break;
case D_INFESTATION:
strcpy(buf, "a parasite"); break;
case D_DROWN:
strcpy(buf, "drowning"); break;
case D_FALL:
strcpy(buf, "falling"); break;
case D_FIRE:
strcpy(buf, "slow boiling in oil"); break;
case D_SPELLFUMBLE:
strcpy(buf, "a botched spell"); break;
case D_DRAINLIFE:
strcpy(buf, "a drain life spell"); break;
case D_ARTIFACT:
strcpy(buf, "an artifact of the gods"); break;
case D_GODWRATH:
strcpy(buf, "divine retribution"); break;
case D_CLUMSY:
strcpy(buf, "excessive clumsyness"); break;
default:
strcpy(buf, "stupidity"); break;
}
return(buf);
}
/*
showpack()
Display the contents of the hero's pack
*/
void
showpack(char *howso)
{
char *iname;
unsigned int worth;
int cnt, ch, oldpurse;
struct linked_list *item;
struct object *obj;
struct linked_list *bag = NULL;
cnt = 1;
clear();
mvprintw(0, 0, "Contents of your pack %s:\n", howso);
ch = 0;
oldpurse = purse;
purse = 0;
for (item = pack; item != NULL; item = next(item))
{
obj = OBJPTR(item);
worth = get_worth(obj);
whatis(item);
purse += worth;
if (obj->o_type == ARTIFACT && obj->o_which == TR_PURSE)
bag = obj->o_bag;
iname = inv_name(obj, UPPERCASE);
mvprintw(cnt, 0, "%d) %s\n", ch, iname);
ch += 1;
if (++cnt > LINES - 5 && next(item) != NULL)
{
cnt = 1;
mvaddstr(LINES - 1, 0, morestr);
refresh();
wait_for(' ');
clear();
}
}
if (bag != NULL)
{
mvaddstr(LINES - 1, 0, morestr);
refresh();
wait_for(' ');
clear();
cnt = 1;
ch = 0;
mvprintw(0, 0, "Contents of the Magic Purse of Yendor %s:\n", howso);
for (item = bag; item != NULL; item = next(item))
{
obj = OBJPTR(item);
worth = get_worth(obj);
whatis(item);
purse += worth;
mvprintw(cnt, 0, "%d) %s\n", ch, inv_name(obj, UPPERCASE));
ch += 1;
if (++cnt > LINES - 5 && next(item) != NULL)
{
cnt = 1;
mvaddstr(LINES - 1, 0, morestr);
refresh();
wait_for(' ');
clear();
}
}
}
mvprintw(cnt + 1, 0, "Carrying %d gold pieces", oldpurse);
mvprintw(cnt + 2, 0, "Carrying objects worth %d gold pieces", purse);
purse += oldpurse;
refresh();
}
void
byebye(void)
{
endwin();
printf("\n");
exit(0);
}
/*
save_resurrect()
chance of resurrection according to modifed D&D probabilities
*/
int
save_resurrect(int bonus)
{
int need, adjust;
adjust = pstats.s_const + bonus - luck;
if (adjust > 17)
return(TRUE);
else if (adjust < 14)
need = 5 * (adjust + 5);
else
need = 90 + 2 * (adjust - 13);
return(roll(1, 100) < need);
}

1815
urogue/rogue.h Normal file

File diff suppressed because it is too large Load diff

315
urogue/rooms.c Normal file
View file

@ -0,0 +1,315 @@
/*
rooms.c - Draw the nine rooms on the screen
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdlib.h>
#include "rogue.h"
void
do_rooms(void)
{
int i;
struct room *rp;
struct linked_list *item;
struct thing *tp;
int left_out;
coord top;
coord bsze;
coord mp;
/* 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_nexits = rp->r_flags = rp->r_fires = 0;
/* Put the gone rooms, if any, on the level */
left_out = rnd(3);
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++)
{
int 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;
}
while (rp->r_pos.y < 1 || rp->r_pos.y > LINES - 3);
continue;
}
if (rnd(40) < level - 5)
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);
}
while (rp->r_pos.y == 0);
/* Draw the room */
draw_room(rp);
/* Put the gold in */
if (rnd(10) < 3 && (!has_artifact || level >= max_level))
{
struct linked_list *itm;
struct object *cur;
coord tpos;
has_gold = TRUE; /* This room has gold in it */
itm = spec_item(GOLD, 0, 0, 0);
cur = OBJPTR(itm);
/* Put it somewhere */
rnd_pos(rp, &tpos);
cur->o_pos = tpos;
/* Put the gold into the level list of items */
add_obj(itm, tpos.y, tpos.x);
if (roomin(tpos) != rp)
{
endwin();
abort();
}
}
/* Put the monster in */
if (rnd(100) < (has_gold ? 80 : 40))
{
int which;
int n, cnt;
item = new_item(sizeof *tp);
tp = THINGPTR(item);
do
rnd_pos(rp, &mp);
while (mvwinch(stdscr, mp.y, mp.x) != FLOOR);
which = randmonster(NOWANDER, NOGRAB);
new_monster(item, which, &mp, NOMAXSTATS);
/* See if we want to give it a treasure to carry around. */
if (rnd(100) < monsters[tp->t_index].m_carry)
attach(tp->t_pack, new_thing());
/* If it has a fire, mark it */
if (on(*tp, HASFIRE))
{
rp->r_flags |= HASFIRE;
rp->r_fires++;
}
/* If it carries gold, give it some */
if (on(*tp, CARRYGOLD))
{
struct object *cur;
item = spec_item(GOLD, 0, 0, 0);
cur = OBJPTR(item);
cur->o_count = GOLDCALC + GOLDCALC + GOLDCALC;
cur->o_pos = tp->t_pos;
attach(tp->t_pack, item);
}
n = rnd(7);
if (on(*tp, ISSWARM) && n < 5)
cnt = roll(2, 4);
else if (on(*tp, ISFLOCK) && n < 5)
cnt = roll(1, 4);
else
cnt = 0;
for (n = 1; n <= cnt; n++)
{
coord pos;
if (place_mons(mp.y, mp.x, &pos)!= FALSE)
{
struct linked_list *nitem;
nitem = new_item(sizeof(struct thing));
new_monster(nitem, which, &pos, NOMAXSTATS);
/* If the monster is on a trap, trap it */
if (isatrap(mvinch(pos.y, pos.x)))
be_trapped(THINGPTR(nitem), mp);
if (on(*tp, ISFRIENDLY))
turn_on(*(THINGPTR(nitem)), ISFRIENDLY);
else
turn_off(*(THINGPTR(nitem)), ISFRIENDLY);
}
}
if (cnt > 0)
{
int boost = rnd(3) + 1;
if (on(*tp, LOWCAST) || on(*tp, MEDCAST) || on(*tp, HIGHCAST))
turn_on(*tp, CANCAST);
tp->t_stats.s_hpt += 3 * boost;
tp->t_stats.s_arm -= 2 * boost;
tp->t_stats.s_lvl += 2 * boost;
tp->t_stats.s_str += 2 * boost;
tp->t_stats.s_intel += 2 * boost;
tp->t_stats.s_exp += 4 * boost * monsters[which].m_add_exp;
}
}
}
}
/*
draw_room()
Draw a box around a room
*/
void
draw_room(struct room *rp)
{
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
*/
void
horiz(int cnt)
{
while(cnt--)
addch('-');
}
/*
vert()
draw a vertical line
*/
void
vert(int cnt)
{
int x, y;
getyx(stdscr, y, x);
x--;
while(cnt--)
{
move(++y, x);
addch('|');
}
}
/*
rnd_pos()
pick a random spot in a room
*/
void
rnd_pos(struct room *rp, 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;
}
/*
rnd_room()
Pick a room that is really there
*/
int
rnd_room(void)
{
int rm;
if (levtype != NORMLEV)
rm = 0;
else
do
{
rm = rnd(MAXROOMS);
}
while (rooms[rm].r_flags & ISGONE);
return(rm);
}

135
urogue/save.c Normal file
View file

@ -0,0 +1,135 @@
/*
save.c - save and restore routines
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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 _ALL_SOURCE /* need to remove need for this AIXism */
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "rogue.h"
int
save_game(void)
{
FILE *savefd;
char buf[2 * LINELEN];
char oldfile[2*LINELEN];
/* get file name */
strcpy(oldfile,file_name);
do
{
mpos = 0;
if (oldfile[0] != '\0')
msg("Save file [%s]: ", file_name);
else
msg("Save file as: ");
mpos = 0;
buf[0] = '\0';
if (get_string(buf, cw) == QUIT)
{
msg("");
return(FALSE);
}
if ( (buf[0] == 0) && (oldfile[0] != 0) )
strcpy(file_name, oldfile);
else if (buf[0] != 0)
strcpy(file_name, buf);
else
{
msg("");
return(FALSE);
}
wclear(hw);
wmove(hw, LINES - 1, 0);
wrefresh(hw);
if ((savefd = fopen(file_name, "w")) == NULL)
msg(strerror(errno)); /* fake perror() */
}
while (savefd == NULL);
/* write out [compressed?] file */
save_file(savefd);
return(TRUE);
}
int
restore(char *file)
{
FILE *infd;
char *sp;
if (strcmp(file, "-r") == 0)
file = file_name;
if ((infd = fopen(file, "r")) == NULL)
{
perror(file);
return(FALSE);
}
if ( restore_file(infd) == FALSE )
return(FALSE);
/*
* we do not close the file so that we will have a hold of the inode
* for as long as possible
*/
if (remove(file) < 0)
{
printf("Cannot unlink file\n");
return(FALSE);
}
if ((sp = getenv("OPTIONS")) != NULL)
parse_opts(sp);
strcpy(file_name, file);
clearok(cw, TRUE);
touchwin(cw);
noecho();
nonl();
while(playing)
{
do_daemons(BEFORE);
do_fuses(BEFORE);
command(); /* Command execution */
if (after)
do_after_effects();
}
fatal("");
return(FALSE);
}

1491
urogue/scrolls.c Normal file

File diff suppressed because it is too large Load diff

1445
urogue/state.c Normal file

File diff suppressed because it is too large Load diff

52
urogue/status.c Normal file
View file

@ -0,0 +1,52 @@
/*
status.c - functions for complex status determination of monsters/objects
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1992, 1993, 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "rogue.h"
/*
has_defensive_spell()
has monster cast a defensive spell.
Any flags added here must also be in player_powers[].
*/
int
has_defensive_spell(struct thing th)
{
if (on(th, HASOXYGEN))
return(TRUE);
if (on(th, CANFLY))
return(TRUE);
if (on(th, CANINWALL))
return(TRUE);
if (on(th, CANREFLECT))
return(TRUE);
if (on(th, CANSEE))
return(TRUE);
if (on(th, HASMSHIELD))
return(TRUE);
if (on(th, HASSHIELD))
return(TRUE);
if (on(th, ISHASTE))
return(TRUE);
if (on(th, ISREGEN))
return(TRUE);
if (on(th, ISDISGUISE))
return(TRUE);
if (on(th, ISINVIS))
return(TRUE);
if (on(th, NOCOLD))
return(TRUE);
if (on(th, NOFIRE))
return(TRUE);
if (on(th, ISELECTRIC))
return(TRUE);
return(FALSE);
}

1796
urogue/sticks.c Normal file

File diff suppressed because it is too large Load diff

935
urogue/things.c Normal file
View file

@ -0,0 +1,935 @@
/*
things.c - functions for dealing with things like potions and scrolls
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <string.h>
#include <ctype.h>
#include "rogue.h"
/*
inv_name()
return the name of something as it would appear in an inventory.
*/
char *
inv_name(struct object *obj, int lowercase)
{
char *pb;
char buf[1024];
switch(obj->o_type)
{
case SCROLL:
if (obj->o_count == 1)
sprintf(prbuf, "A %s%sscroll ",
obj->o_flags & CANRETURN ? "claimed " : "",
blesscurse(obj->o_flags));
else
sprintf(prbuf, "%d %s%sscrolls ",
obj->o_count,
obj->o_flags & CANRETURN ? "claimed " : "",
blesscurse(obj->o_flags));
pb = &prbuf[strlen(prbuf)];
if (know_items[TYP_SCROLL][obj->o_which])
sprintf(pb, "of %s", s_magic[obj->o_which].mi_name);
else if (guess_items[TYP_SCROLL][obj->o_which])
sprintf(pb, "called %s", guess_items[TYP_SCROLL][obj->o_which]);
else
sprintf(pb, "titled '%s'", s_names[obj->o_which]);
break;
case POTION:
if (obj->o_count == 1)
sprintf(prbuf, "A %s%spotion ",
obj->o_flags & CANRETURN ? "claimed " : "",
blesscurse(obj->o_flags));
else
sprintf(prbuf, "%d %s%spotions ",
obj->o_count,
obj->o_flags & CANRETURN ? "claimed " : "",
blesscurse(obj->o_flags));
pb = &prbuf[strlen(prbuf)];
if (know_items[TYP_POTION][obj->o_which])
sprintf(pb, "of %s(%s)", p_magic[obj->o_which].mi_name,
p_colors[obj->o_which]);
else if (guess_items[TYP_POTION][obj->o_which])
sprintf(pb, "called %s(%s)", guess_items[TYP_POTION][obj->o_which],
p_colors[obj->o_which]);
else
{
if (obj->o_count == 1)
sprintf(prbuf, "A%s %s potion",
obj->o_flags & CANRETURN ? " claimed" :
(char *) vowelstr(p_colors[obj->o_which]),
p_colors[obj->o_which]);
else
sprintf(prbuf, "%d %s%s potions",
obj->o_count,
obj->o_flags & CANRETURN ? "claimed " : "",
(char *) p_colors[obj->o_which]);
}
break;
case FOOD:
if (obj->o_count == 1)
sprintf(prbuf, "A%s %s",
obj->o_flags & CANRETURN ? " claimed" :
(char *) vowelstr(fd_data[obj->o_which].mi_name),
fd_data[obj->o_which].mi_name);
else
sprintf(prbuf, "%d %s%ss", obj->o_count,
obj->o_flags & CANRETURN ? "claimed " : "",
fd_data[obj->o_which].mi_name);
break;
case WEAPON:
if (obj->o_count > 1)
sprintf(prbuf, "%d ", obj->o_count);
else if ((obj->o_flags & (ISZAPPED | CANRETURN | ISPOISON | ISSILVER | ISTWOH)) ||
((obj->o_flags & (ISKNOW | ISZAPPED)) == (ISKNOW | ISZAPPED)))
strcpy(prbuf, "A ");
else
sprintf(prbuf, "A%s ", vowelstr(weaps[obj->o_which].w_name));
pb = &prbuf[strlen(prbuf)];
if ((obj->o_flags & ISKNOW) && (obj->o_flags & ISZAPPED))
sprintf(pb, "charged%s ", charge_str(obj,buf));
pb = &prbuf[strlen(prbuf)];
if (obj->o_flags & CANRETURN)
sprintf(pb, "claimed ");
pb = &prbuf[strlen(prbuf)];
if (obj->o_flags & ISPOISON)
sprintf(pb, "poisoned ");
pb = &prbuf[strlen(prbuf)];
if (obj->o_flags & ISSILVER)
sprintf(pb, "silver ");
if (obj->o_flags & ISTWOH)
sprintf(pb, "two-handed ");
pb = &prbuf[strlen(prbuf)];
if (obj->o_flags & ISKNOW)
sprintf(pb, "%s %s", num(obj->o_hplus, obj->o_dplus, buf),
weaps[obj->o_which].w_name);
else
sprintf(pb, "%s", weaps[obj->o_which].w_name);
if (obj->o_count > 1)
strcat(prbuf, "s");
break;
case ARMOR:
if (obj->o_flags & ISKNOW)
sprintf(prbuf, "%s%s %s",
obj->o_flags & CANRETURN ? "claimed " : "",
num(armors[obj->o_which].a_class - obj->o_ac, 0, buf),
armors[obj->o_which].a_name);
else
sprintf(prbuf, "%s%s",
obj->o_flags & CANRETURN ? "claimed " : "",
armors[obj->o_which].a_name);
break;
case ARTIFACT:
sprintf(prbuf, "the %s", arts[obj->o_which].ar_name);
if (obj->o_flags & CANRETURN)
strcat(prbuf, " (claimed)");
break;
case STICK:
sprintf(prbuf, "A %s%s%s ",
obj->o_flags & CANRETURN ? "claimed " : "",
blesscurse(obj->o_flags), ws_type[obj->o_which]);
pb = &prbuf[strlen(prbuf)];
if (know_items[TYP_STICK][obj->o_which])
sprintf(pb, "of %s%s(%s)", ws_magic[obj->o_which].mi_name,
charge_str(obj,buf), ws_made[obj->o_which]);
else if (guess_items[TYP_STICK][obj->o_which])
sprintf(pb, "called %s(%s)", guess_items[TYP_STICK][obj->o_which],
ws_made[obj->o_which]);
else
sprintf(&prbuf[2], "%s%s %s",
obj->o_flags & CANRETURN ? "claimed " : "",
ws_made[obj->o_which],
ws_type[obj->o_which]);
break;
case RING:
if (know_items[TYP_RING][obj->o_which])
sprintf(prbuf, "A%s%s ring of %s(%s)",
obj->o_flags & CANRETURN ? " claimed" : "", ring_num(obj,buf),
r_magic[obj->o_which].mi_name, r_stones[obj->o_which]);
else if (guess_items[TYP_RING][obj->o_which])
sprintf(prbuf, "A %sring called %s(%s)",
obj->o_flags & CANRETURN ? "claimed " : "",
guess_items[TYP_RING][obj->o_which], r_stones[obj->o_which]);
else
sprintf(prbuf, "A%s %s ring",
obj->o_flags & CANRETURN ? "claimed " :
(char *)vowelstr(r_stones[obj->o_which]),
r_stones[obj->o_which]);
break;
case GOLD:
sprintf(prbuf, "%d gold pieces", obj->o_count);
break;
default:
debug("Picked up something funny.");
sprintf(prbuf, "Something bizarre %s", unctrl(obj->o_type));
break;
}
/* Is it marked? */
if (obj->o_mark[0])
{
pb = &prbuf[strlen(prbuf)];
sprintf(pb, " <%s>", obj->o_mark);
}
if (obj == cur_armor)
strcat(prbuf, " (being worn)");
if (obj == cur_weapon)
strcat(prbuf, " (weapon in hand)");
if (obj == cur_ring[LEFT_1])
strcat(prbuf, " (on left hand)");
else if (obj == cur_ring[LEFT_2])
strcat(prbuf, " (on left hand)");
else if (obj == cur_ring[LEFT_3])
strcat(prbuf, " (on left hand)");
else if (obj == cur_ring[LEFT_4])
strcat(prbuf, " (on left hand)");
else if (obj == cur_ring[LEFT_5])
strcat(prbuf, " (on left hand)");
else if (obj == cur_ring[RIGHT_1])
strcat(prbuf, " (on right hand)");
else if (obj == cur_ring[RIGHT_2])
strcat(prbuf, " (on right hand)");
else if (obj == cur_ring[RIGHT_3])
strcat(prbuf, " (on right hand)");
else if (obj == cur_ring[RIGHT_4])
strcat(prbuf, " (on right hand)");
else if (obj == cur_ring[RIGHT_5])
strcat(prbuf, " (on right hand)");
if (obj->o_flags & ISPROT)
strcat(prbuf, " [protected]");
if (lowercase && isupper(prbuf[0]))
prbuf[0] = (char) tolower(prbuf[0]);
else if (!lowercase && islower(*prbuf))
*prbuf = (char) toupper(*prbuf);
if (!lowercase)
strcat(prbuf, ".");
return(prbuf);
}
/*
rem_obj()
Remove an object from the level.
*/
void
rem_obj(struct linked_list *item, int dis)
{
struct linked_list *llptr;
struct object *objptr, *op;
int x, y;
if (item == NULL)
return;
detach(lvl_obj, item);
objptr = OBJPTR(item);
if ( (llptr = objptr->next_obj) != NULL )
{
detach((objptr->next_obj), llptr);
attach(lvl_obj, llptr);
op = OBJPTR(llptr);
op->next_obj = objptr->next_obj;
if (op->next_obj)
objptr->next_obj->l_prev = NULL;
y = op->o_pos.y;
x = op->o_pos.x;
if (cansee(y, x))
mvwaddch(cw, y, x, op->o_type);
mvaddch(y, x, op->o_type);
}
else
{
y = objptr->o_pos.y;
x = objptr->o_pos.x;
/* problems if dropped in rock */
mvaddch(y,x,(roomin((objptr->o_pos)) == NULL ? PASSAGE : FLOOR));
}
if (dis)
discard(item);
}
/*
add_obj()
adds an object to the level
*/
void
add_obj(struct linked_list *item, int y, int x)
{
struct linked_list *llptr;
struct object*objptr;
llptr = find_obj(y, x);
if (llptr)
{
objptr = OBJPTR(llptr);
attach((objptr->next_obj), item);
}
else
{
attach(lvl_obj, item);
objptr = OBJPTR(item);
objptr->next_obj = NULL;
objptr->o_pos.y = y;
objptr->o_pos.x = x;
mvaddch(y, x, objptr->o_type);
}
}
/*
drop()
put something down
*/
int
drop(struct linked_list *item)
{
char ch = CCHAR( mvwinch(stdscr, hero.y, hero.x) );
struct object *obj;
switch (ch)
{
case GOLD:
case POTION:
case SCROLL:
case FOOD:
case WEAPON:
case ARMOR:
case RING:
case STICK:
case FLOOR:
case PASSAGE:
case POOL:
case ARTIFACT:
if (item == NULL && (item = get_item("drop", 0)) == NULL)
return(FALSE);
break;
default:
msg("You can't drop something here.");
return(FALSE);
}
obj = OBJPTR(item);
if (!dropcheck(obj))
return(FALSE);
/* Curse a dropped scare monster scroll */
if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
{
if (obj->o_flags & ISBLESSED)
obj->o_flags &= ~ISBLESSED;
else
obj->o_flags |= ISCURSED;
}
/* Take it out of the pack */
if (obj->o_count >= 2 && obj->o_group == 0)
{
struct linked_list *nitem = new_item(sizeof *obj);
obj->o_count--;
obj = OBJPTR(nitem);
*obj = *(OBJPTR(item));
obj->o_count = 1;
item = nitem;
}
else
rem_pack(obj);
if (ch == POOL)
{
msg("The pool bubbles briefly as your %s sinks out of sight.",
inv_name(obj, TRUE));
discard(item);
item = NULL;
}
else /* Link it into the level object list */
{
add_obj(item, hero.y, hero.x);
mvaddch(hero.y, hero.x, obj->o_type);
}
if (obj->o_type == ARTIFACT)
has_artifact &= ~(1 << obj->o_which);
updpack();
return(TRUE);
}
/*
dropcheck()
do special checks for dropping or unweilding|unwearing|unringing
*/
int
dropcheck(struct object *op)
{
if (op == NULL)
return(TRUE);
if (op != cur_armor && op != cur_weapon &&
op != cur_ring[LEFT_1] && op != cur_ring[LEFT_2] &&
op != cur_ring[LEFT_3] && op != cur_ring[LEFT_4] &&
op != cur_ring[LEFT_5] &&
op != cur_ring[RIGHT_1] && op != cur_ring[RIGHT_2] &&
op != cur_ring[RIGHT_3] && op != cur_ring[RIGHT_4] &&
op != cur_ring[RIGHT_5])
return(TRUE);
if (op->o_flags & ISCURSED)
{
msg("You can't. It appears to be cursed.");
return(FALSE);
}
if (op == cur_weapon)
cur_weapon = NULL;
else if (op == cur_armor)
{
waste_time();
cur_armor = NULL;
}
else if (op == cur_ring[LEFT_1] || op == cur_ring[LEFT_2] ||
op == cur_ring[LEFT_3] || op == cur_ring[LEFT_4] ||
op == cur_ring[LEFT_5] ||
op == cur_ring[RIGHT_1] || op == cur_ring[RIGHT_2] ||
op == cur_ring[RIGHT_3] || op == cur_ring[RIGHT_4] ||
op == cur_ring[RIGHT_5])
{
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[LEFT_5])
cur_ring[LEFT_5] = 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_ring[RIGHT_5])
cur_ring[RIGHT_5] = NULL;
switch (op->o_which)
{
case R_ADDSTR:
chg_str(-op->o_ac, FALSE, FALSE);
break;
case R_ADDHIT:
chg_dext(-op->o_ac, FALSE, FALSE);
break;
case R_ADDINTEL:
pstats.s_intel -= op->o_ac;
break;
case R_ADDWISDOM:
pstats.s_wisdom -= op->o_ac;
break;
case R_SEEINVIS:
if (find_slot(FUSE_UNSEE,FUSE) == NULL)
{
turn_off(player, CANSEE);
msg("The tingling feeling leaves your eyes.");
}
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
break;
case R_LIGHT:
if (roomin(hero) != NULL)
{
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
break;
}
}
return(TRUE);
}
/*
new_thing()
return a new thing
*/
struct linked_list *
new_thing(void)
{
int j, k;
struct linked_list *item;
struct object *cur;
short blesschance = srnd(100);
short cursechance = srnd(100);
item = new_item(sizeof *cur);
cur = OBJPTR(item);
cur->o_hplus = cur->o_dplus = 0;
cur->o_damage = cur->o_hurldmg = "0d0";
cur->o_ac = 11;
cur->o_count = 1;
cur->o_group = 0;
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.
*/
switch (no_food > 3 ? TYP_FOOD : pick_one(things, numthings))
{
case TYP_POTION:
cur->o_type = POTION;
cur->o_which = pick_one(p_magic, maxpotions);
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;
break;
case TYP_SCROLL:
cur->o_type = SCROLL;
cur->o_which = pick_one(s_magic, maxscrolls);
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;
break;
case TYP_FOOD:
no_food = 0;
cur->o_type = FOOD;
cur->o_which = pick_one(fd_data, maxfoods);
cur->o_weight = 2;
cur->o_count += extras();
break;
case TYP_WEAPON:
cur->o_type = WEAPON;
cur->o_which = rnd(maxweapons);
init_weapon(cur, cur->o_which);
if (cursechance < 10)
{
short bad = (rnd(10) < 1) ? 2 : 1;
cur->o_flags |= ISCURSED;
cur->o_hplus -= bad;
cur->o_dplus -= bad;
}
else if (blesschance < 15)
{
short good = (rnd(10) < 1) ? 2 : 1;
cur->o_hplus += good;
cur->o_dplus += good;
}
break;
case 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;
if (((k = rnd(100)) < 20) && j != MITHRIL)
{
cur->o_flags |= ISCURSED;
cur->o_ac += rnd(3) + 1;
}
else if (k < 28 || j == MITHRIL)
cur->o_ac -= rnd(3) + 1;
if (j == MITHRIL)
cur->o_flags |= ISPROT;
cur->o_weight = armors[j].a_wght;
break;
case TYP_RING:
cur->o_type = RING;
cur->o_which = pick_one(r_magic, maxrings);
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:
case R_CARRYING:
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++;
break;
case R_RESURRECT:
case R_TELCONTROL:
case R_VREGEN:
case R_REGEN:
case R_PIETY:
case R_WIZARD:
cur->o_ac = 0;
if (cur->o_flags & ISCURSED)
cur->o_ac = -1;
if (cur->o_flags & ISBLESSED)
cur->o_ac = 1;
break;
case 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;
break;
default:
cur->o_ac = 0;
break;
}
break;
case TYP_STICK:
cur->o_type = STICK;
cur->o_which = pick_one(ws_magic, maxsticks);
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;
break;
default:
debug("Picked a bad kind of object");
wait_for(' ');
}
return(item);
}
/*
spec_item()
provide a new item tailored to specification
*/
struct linked_list *
spec_item(char type, int which, int hitp, int damage)
{
struct linked_list *item;
struct object *obj;
item = new_item(sizeof *obj);
obj = OBJPTR(item);
obj->o_count = 1;
obj->o_group = 0;
obj->o_type = type;
obj->o_which = which;
obj->o_damage = obj->o_hurldmg = "0d0";
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;
switch(type) /* Handle special characteristics */
{
case WEAPON:
init_weapon(obj, which);
obj->o_hplus = hitp;
obj->o_dplus = damage;
obj->o_ac = 10;
break;
case ARMOR:
obj->o_ac = armors[which].a_class - hitp;
break;
case RING:
obj->o_ac = hitp;
break;
case STICK:
fix_stick(obj);
obj->o_charges = hitp;
break;
case GOLD:
obj->o_type = GOLD;
obj->o_count = GOLDCALC;
obj->o_ac = 11;
break;
}
if (hitp > 0 || damage > 0)
obj->o_flags |= ISBLESSED;
else if (hitp < 0 || damage < 0)
obj->o_flags |= ISCURSED;
return(item);
}
/*
pick_one()
pick an item out of a list of nitems possible magic items
*/
int
pick_one(struct magic_item *magic, int nitems)
{
int i;
struct magic_item *end;
struct magic_item *start = magic;
for (end = &magic[nitems], i = rnd(1000); magic < end; magic++)
if (i <= magic->mi_prob)
break;
if (magic == end)
{
if (wizard)
{
add_line("Bad pick_one: %d from %d items", i, nitems);
for (magic = start; magic < end; magic++)
add_line("%s: %d%%", magic->mi_name, magic->mi_prob);
end_line();
}
magic = start;
}
return((int)(magic - start));
}
/*
blesscurse()
returns whether the object is blessed or cursed
*/
char *
blesscurse(long flags)
{
if (flags & ISKNOW)
{
if (flags & ISCURSED)
return("cursed ");
if (flags & ISBLESSED)
return("blessed ");
return("normal ");
}
return("");
}
/*
extras()
Return the number of extra food items to be created
*/
int
extras(void)
{
int i = rnd(100);
if (i < 10)
return(2);
else if (i < 20)
return(1);
else
return(0);
}
/*
name_type()
Returns a string identifying a pack item's type
*/
char *
name_type(int type)
{
switch(type)
{
case ARMOR:
return ("armor");
case WEAPON:
return ("weapons");
case SCROLL:
return ("scrolls");
case RING:
return ("rings");
case STICK:
return ("staffs");
case POTION:
return ("potions");
case FOOD:
return ("food");
case GOLD:
return ("gold");
default:
return ("items");
}
}
/*
make_item()
adds a linked_list structure to the top of an object for interfacing
with other routines
*/
linked_list *
make_item(object *obj_p)
{
linked_list *item_p = new_list();
item_p->l_next = item_p->l_prev = NULL;
item_p->data.obj = obj_p;
return(item_p);
}
/*
is_member()
Checks to see if a character is a member of an array
*/
int
is_member(char *list_p, int member)
{
while (*list_p != 0)
{
if (*list_p++ == member)
return(TRUE);
}
return(FALSE);
}

808
urogue/trader.c Normal file
View file

@ -0,0 +1,808 @@
/*
trader.c - Anything to do with trading posts
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "rogue.h"
#define EFFECTIVE_PURSE ((player.t_ctype==C_PALADIN)?(9 * purse / 10) : purse)
/*
do_post()
Buy and sell things in a trading post
*/
void
display_postinfo(void)
{
wclear(hw);
wstandout(hw);
mvwaddstr(hw, 0, COLS / 2 - 30,
"Welcome to Friendly Fiend's Flea Market" );
wstandend(hw);
wclrtoeol(hw);
trans_line();
}
void
do_post(void)
{
int bad_letter = FALSE;
player.t_trans = 0;
for (;;)
{
if (!open_market())
return;
display_postinfo();
if (bad_letter)
{
bad_letter = FALSE;
wstandout(hw);
mvwaddstr(hw, 7, 0, "Type 'i' or 'I' to inventory, "
"'l' to leave, 'b' to buy, or 's' to sell");
wstandend(hw);
}
mvwaddstr(hw, 6, 0, "Do you wish to buy, sell, inventory, or leave?");
wrefresh(hw);
switch(readcharw(hw))
{
case 'b':
mvwaddstr(hw, 7, 0,
"Lets go into the buying section of the store...");
touchwin(hw);
wrefresh(hw);
buy_it('\0', ISNORMAL);
break;
case 's':
mvwaddstr(hw, 7, 0,
"Lets go into the selling section of the store...");
touchwin(hw);
wrefresh(hw);
sell_it();
break;
case 'i':
inventory(pack, '*');
break;
case 'I':
wclear(hw);
wrefresh(hw);
inventory(pack, 0);
msg(" ");
msg("");
break;
case 'l':
wclear(hw);
wrefresh(hw);
return;
default:
bad_letter = TRUE;
break;
}
}
}
void
buy_it(char itemtype, int flags)
{
int i;
int blessed = flags & ISBLESSED;
int cursed = flags & ISCURSED;
int is_spell = flags & SCR_MAGIC;
int array_size; /* # of items within type */
int which_type = 0; /* Which type to buy */
int which_one; /* Which one within type */
int plus_or_minus = 0; /* for magic items */
const struct magic_item *magic_array = NULL;
struct linked_list *item;
struct object *obj;
char buf[2 * LINELEN];
buy_more:
display_postinfo();
do
{
array_size = 0;
if (itemtype == '\0')
{
mpos = 0;
wmove(hw,10,0);
wclrtoeol(hw);
mvwaddstr(hw, 11, 0, "WHAT\tTYPE\n! Potion\n? Scroll\n"
"= Ring\n/ Stick\n] Armor\n) Weapon\n: Food");
if (wizard)
mvwaddstr(hw, 19, 0, ", Artifact");
mvwaddstr(hw, 9, 0, "What type of item do you want? ");
wclrtoeol(hw);
touchwin(hw);
wrefresh(hw);
itemtype = readcharw(hw);
}
switch(itemtype)
{
case POTION:
which_type = TYP_POTION;
array_size = maxpotions;
magic_array = p_magic;
break;
case SCROLL:
which_type = TYP_SCROLL;
array_size = maxscrolls;
magic_array = s_magic;
break;
case FOOD:
which_type = TYP_FOOD;
array_size = maxfoods;
magic_array = fd_data;
break;
case WEAPON:
which_type = TYP_WEAPON;
array_size = maxweapons;
break;
case ARMOR:
which_type = TYP_ARMOR;
array_size = maxarmors;
break;
case RING:
which_type = TYP_RING;
array_size = maxrings;
magic_array = r_magic;
break;
case STICK:
which_type = TYP_STICK;
array_size = maxsticks;
magic_array = ws_magic;
break;
case ARTIFACT:
if (!wizard)
{
itemtype = '\0';
continue;
}
which_type = TYP_ARTIFACT;
array_size = maxartifact;
break;
case ESCAPE:
return;
default:
wstandout(hw);
mvwaddstr(hw, 10, 0, "We don't stock any of those.");
wstandend(hw);
itemtype = '\0';
continue;
}
}
while (array_size == 0);
which_one = array_size;
do
{
const struct magic_item *m_item;
display_postinfo();
mpos = 0;
sprintf(buf, "Which kind of %s do you wish to have (* for list)? ",
things[which_type].mi_name);
mvwaddstr(hw, 9, 0, buf);
touchwin(hw);
wrefresh(hw);
buf[0] = '\0';
switch (get_string(buf, hw))
{
case QUIT:
case ESCAPE:
itemtype = '\0';
goto buy_more;
}
if (buf[0] == '*') /* print list */
{
add_line(" ID BASECOST NAME");
switch (which_type)
{
case TYP_RING:
case TYP_POTION:
case TYP_STICK:
case TYP_SCROLL:
case TYP_FOOD:
for(i=0,m_item=magic_array; i < array_size; i++, m_item++)
if (!is_spell && m_item->mi_worth > 0)
{
sprintf(buf, "%3d) %8d %s", i, m_item->mi_worth,
m_item->mi_name);
add_line(buf);
}
break;
case TYP_ARMOR:
for (i = 0; i < array_size; i++)
if (!is_spell && armors[i].a_worth > 0)
{
sprintf(buf, "%3d) %8d %s", i, armors[i].a_worth,
armors[i].a_name);
add_line(buf);
}
break;
case TYP_WEAPON:
for (i = 0; i < array_size; i++)
if (!is_spell && weaps[i].w_worth > 0)
{
sprintf(buf, "%3d) %8d %s", i, weaps[i].w_worth,
weaps[i].w_name);
add_line(buf);
}
break;
case TYP_ARTIFACT:
for (i = 0; i < array_size; i++)
{
sprintf(buf, "%3d) %8d %s", i, arts[i].ar_worth,
arts[i].ar_name);
add_line(buf);
}
break;
default:
add_line("What a strange type.");
}
end_line();
touchwin(hw);
wrefresh(hw);
continue;
}
if (isdigit(buf[0]))
which_one = atoi(buf);
else
switch (which_type)
{
case TYP_RING:
case TYP_POTION:
case TYP_STICK:
case TYP_SCROLL:
case TYP_FOOD:
for (i=0,m_item=magic_array; i < array_size; i++, m_item++)
if (strcmp(buf, m_item->mi_name) == 0)
which_one = i;
break;
case TYP_ARMOR:
for (i = 0; i < array_size; i++)
if (strcmp(buf, armors[i].a_name) == 0)
which_one = i;
break;
case TYP_WEAPON:
for (i = 0; i < array_size; i++)
if (strcmp(buf, weaps[i].w_name) == 0)
which_one = i;
break;
case TYP_ARTIFACT:
for (i = 0; i < array_size; i++)
if (strcmp(buf, arts[i].ar_name) == 0)
which_one = i;
break;
default:
msg("What a strange type.");
}
if (which_one < 0 || which_one >= array_size)
{
wstandout(hw);
mvwaddstr(hw, 10, 0, "Type the name or an ID number.");
wstandend(hw);
}
}
while (which_one < 0 || which_one >= array_size);
item = new_item(sizeof *obj);
obj = OBJPTR(item);
if (which_type == TYP_ARTIFACT)
{
new_artifact(which_one, obj);
add_pack(item, NOMESSAGE);
itemtype = '\0';
goto buy_more;
}
obj->o_type = itemtype;
obj->o_which = which_one;
obj->o_mark[0] = '\0';
obj->o_group = 0;
obj->o_count = 1;
obj->o_weight = 0;
obj->o_dplus = obj->o_hplus = 0;
obj->o_worth = 0;
if (!is_spell)
{
plus_or_minus = -100;
do
{
mvwaddstr(hw, 10, 0, "Do you want the cursed, blessed, or normal"
" version? (c, b, n) [n]");
touchwin(hw);
wrefresh(hw);
blessed = cursed = FALSE;
switch (readcharw(hw))
{
case ESCAPE:
discard(item);
itemtype = '\0';
goto buy_more;
case 'c':
cursed = TRUE;
plus_or_minus = 0;
break;
case 'b':
blessed = TRUE;
plus_or_minus = 0;
break;
case 'n':
case ' ':
plus_or_minus = 0;
break;
default:
wstandout(hw);
mvwaddstr(hw,11,0,"Type 'c' for cursed, 'b' for blessed, "
"or 'n' for normal");
wstandend(hw);
}
}
while (plus_or_minus == -100);
}
/* else used blessed, cursed from flags parameter */
if (which_type == TYP_WEAPON)
init_weapon(obj, which_one);
obj->o_flags |= ISKNOW;
if (cursed)
{
plus_or_minus = -(rnd(2) + 1);
obj->o_flags |= ISCURSED;
}
else if (blessed)
{
plus_or_minus = (rnd(3) + 1);
obj->o_flags |= ISBLESSED;
}
else
{
plus_or_minus = 0;
obj->o_flags |= ISNORMAL;
}
switch (which_type)
{
case TYP_WEAPON:
obj->o_hplus += plus_or_minus;
obj->o_dplus += plus_or_minus;
break;
case TYP_ARMOR:
obj->o_weight = armors[which_one].a_wght;
obj->o_ac = armors[which_one].a_class - plus_or_minus;
break;
case TYP_STICK:
fix_stick(obj);
break;
case TYP_RING:
obj->o_ac = plus_or_minus;
break;
case TYP_SCROLL:
case TYP_POTION:
obj->o_weight = things[which_type].mi_wght;
break;
case TYP_FOOD:
break;
default:
msg("That's a strange thing to try to own.");
discard(item);
itemtype = '\0';
goto buy_more;
}
obj->o_worth = get_worth(obj) * (luck + level / 15 + 1);
describe_it(obj);
if (!wizard && obj->o_worth > EFFECTIVE_PURSE)
{
wstandout(hw);
mvwaddstr(hw, 12, 0, "Unfortunately, you can't afford it.");
wstandend(hw);
wclrtoeol(hw);
touchwin(hw);
wrefresh(hw);
wait_for(' ');
discard(item);
itemtype = '\0';
goto buy_more;
}
mvwaddstr(hw, 12, 0, "Do you want it? [y] ");
wclrtoeol(hw);
touchwin(hw);
wrefresh(hw);
switch (readcharw(hw))
{
case ESCAPE:
case 'n':
msg("");
discard(item);
itemtype = '\0';
goto buy_more;
}
/* The hero bought the item here */
mpos = 0;
if (add_pack(item, NOMESSAGE) && !is_spell)
{
if (!wizard)
{
purse -= obj->o_worth; /* take his money */
++player.t_trans;
}
trans_line(); /* show remaining deals */
switch(which_type)
{
case TYP_RING:
case TYP_STICK:
case TYP_SCROLL:
case TYP_POTION:
know_items[which_type][which_one] = TRUE;
}
}
}
/*
sell_it()
Sell an item to the trading post
*/
void
sell_it(void)
{
struct object *obj;
struct linked_list *item;
char buf[2 * LINELEN];
wclear(cw);
if ((item = get_item("sell", 0)) == NULL)
return;
obj = OBJPTR(item);
msg("");
display_postinfo();
touchwin(hw);
wrefresh(hw);
if ((obj->o_type == ARTIFACT) || (obj->o_worth = get_worth(obj)) == 0)
{
mpos = 0;
msg("We don't buy those.");
if (is_wearing(R_ADORNMENT) && rnd(10) < 4)
msg("How about that %s ring instead?", r_stones[R_ADORNMENT]);
return;
}
describe_it(obj);
mvwaddstr(hw, 12, 0, "Do you want to sell it? [n] ");
touchwin(hw);
wrefresh(hw);
switch( readcharw(hw) )
{
case 'y':
break;
default:
msg("");
if (is_wearing(R_ADORNMENT))
msg("How about that %s ring instead?",
r_stones[R_ADORNMENT]);
return;
}
rem_pack(obj);
purse += obj->o_worth; /* give him his money */
++player.t_trans;
sprintf(buf, "Sold %s. Hit space to continue.",
inv_name(obj, LOWERCASE));
discard(item);
mvwaddstr(hw, 13, 0, buf);
touchwin(hw);
wrefresh(hw);
wait_for(' ');
}
/*
describe_it()
Laud or condemn the object
*/
extern char *inv_name();
void
describe_it(struct object *obj)
{
static char *cursed_d[] =
{
"worthless hunk of junk",
"shoddy piece of trash",
"piece of rusty garbage",
"example of terrible workmanship",
"cheap hack"
};
static char *normal_d[] =
{
"journeyman's piece",
"fine deal",
"great bargain",
"good find",
"real value",
"piece of honest workmanship",
"steal",
"purchase worth making",
"inexpensive product"
};
static char *blessed_d[] =
{
"magnificant masterpiece",
"quality product",
"exceptional find",
"unbeatable value",
"rare beauty",
"superior product",
"well-crafted item"
};
char *charp;
char buf[2 * LINELEN];
if (obj->o_flags & ISBLESSED)
charp = blessed_d[rnd(sizeof(blessed_d) / sizeof(char *))];
else if (obj->o_flags & ISCURSED)
charp = cursed_d[rnd(sizeof(cursed_d) / sizeof(char *))];
else
charp = normal_d[rnd(sizeof(normal_d) / sizeof(char *))];
sprintf(buf, "It's a%s %s worth %d pieces of gold.",
vowelstr(charp), charp, obj->o_worth);
mvwaddstr(hw, 10, 0, inv_name(obj, TRUE));
mvwaddstr(hw, 11, 0, buf);
wclrtoeol(hw);
}
/*
open_market()
Retruns TRUE when ok do to transacting
*/
int
open_market(void)
{
int maxtrans = is_wearing(R_ADORNMENT) ? MAXPURCH + 4 : MAXPURCH;
if (wizard || player.t_trans < maxtrans || (level == 0))
return(TRUE);
else
{
msg("The market is closed. The stairs are that-a-way.");
return(FALSE);
}
}
/*
get_worth()
Calculate an objects worth in gold
*/
int
get_worth(struct object *obj)
{
long worth = 0;
int wh = obj->o_which;
int blessed = obj->o_flags & ISBLESSED;
int cursed = obj->o_flags & ISCURSED;
switch (obj->o_type)
{
case FOOD:
if (wh < maxfoods)
{
worth = obj->o_count * fd_data[wh].mi_worth;
if (blessed)
worth *= 2;
}
break;
case WEAPON:
if (wh < maxweapons)
{
worth = weaps[wh].w_worth;
worth *= obj->o_count * (2 +
(4 * obj->o_hplus +
4 * obj->o_dplus));
if (obj->o_flags & ISSILVER)
worth *= 2;
if (obj->o_flags & ISPOISON)
worth *= 2;
if (obj->o_flags & ISZAPPED)
worth += 20 * obj->o_charges;
}
break;
case ARMOR:
if (wh < maxarmors)
{
int plusses = armors[wh].a_class - obj->o_ac;
worth = armors[wh].a_worth;
if (plusses > 0)
worth *= (1 + (10 *
(armors[wh].a_class - obj->o_ac)));
}
break;
case SCROLL:
if (wh < maxscrolls)
worth = s_magic[wh].mi_worth;
break;
case POTION:
if (wh < maxpotions)
worth = p_magic[wh].mi_worth;
break;
case RING:
if (wh < maxrings)
{
worth = r_magic[wh].mi_worth;
worth += obj->o_ac * 40;
}
break;
case STICK:
if (wh < maxsticks)
{
worth = ws_magic[wh].mi_worth;
worth += 20 * obj->o_charges;
}
break;
case ARTIFACT:
if (wh < maxartifact)
worth = arts[wh].ar_worth;
break;
default:
worth = 0;
}
if (obj->o_flags & ISPROT) /* 300% more for protected */
worth *= 3;
if (blessed) /* 250% more for blessed */
worth = 5 * worth / 2;
else if (cursed) /* half for cursed */
worth /= 2;
if (obj->o_flags & (CANRETURN | ISOWNED))
worth *= 4;
else if (obj->o_flags & CANRETURN)
worth *= 2;
else if (obj->o_flags & ISLOST)
worth /= 3;
return(max(0, worth)); /* anything is worth at least one gold piece */
}
/*
trans_line()
Show how many transactions the hero has left
*/
void
trans_line(void)
{
char buf[2 * LINELEN];
int adorned = is_wearing(R_ADORNMENT);
if (level == 0 && purse > 0)
sprintf(buf, "You still have %d pieces of gold left.", purse);
else if (purse == 0)
sprintf(buf, "You have no money left.");
else if (!wizard)
sprintf(buf, "You have %d transactions and %d gold pieces remaining.",
max(0, (adorned ? MAXPURCH + 4 : MAXPURCH) - player.t_trans),
EFFECTIVE_PURSE);
else
sprintf(buf, "You have infinite transactions remaining.");
mvwaddstr(hw, LINES - 2, 0, buf);
}

288
urogue/urogue.6 Normal file
View file

@ -0,0 +1,288 @@
.\"
.\" Last Modified: 06/16/86
.\"
.TH UROGUE 6 "1.03 Draft"
.SH NAME
urogue \- UltraRogue \- Exploring the dungeons of doom.
.SH SYNTAX
.B urogue
[
.I save-file
]
[
.B \-k
]
[
.B \-s
]
[
.B \-n
]
[
.B \-v
]
[
.B \-r
]
.SH DESCRIPTION
.PP
.I UltraRogue
is a advanced version of one of the more standard rogue games.
It is much more difficult and interesting to play than the
original version on which it is based (Advanced Rogue 2.0).
Some of it's unique features include 10 player character classes,
several hundred monsters, charmable monsters, etc.
.PP
To win the game
you must locate 8 artifacts which start appearing from level 25
down. You must then bring all artifacts back up out of the dungeon.
These artifacts also may be
.I applied
to use some of their great powers! Be warned, though, sometimes these
powers back-fire on you.
.SH ENVIRONMENT
The environment variable
.B $UROGUE
(the person installing
.I UltraRogue
may have changed this for your site)
is checked to set certain default options for
.I UltraRogue.
The following may be set in the
.B $UROGUE:
.IP "\fBterse\fR (\fIboolean\fR)"
Short output messages.
.IP "\fBflush\fR (\fIboolean\fR)"
Flush typeahead when fighting.
.IP "\fBjump\fR (\fIboolean\fR)"
Show position only at the end of running.
.IP "\fBinven\fR (\fIstring\fR)"
Inventory style.
.IP "\fBaskme\fR (\fIboolean\fR)"
Ask about unidentified things.
.IP "\fBstopdoor\fR (\fIboolean\fR)"
Stop running when next to something interesting.
.IP "\fBname\fR (\fIstring\fR)"
The rogue's name.
.IP "\fBfruit\fR (\fIstring\fR)"
The funny fruit used by the rogue.
.IP "\fBfile\fR (\fIstring\fR)"
Default savefile name.
.IP "\fBscore\fR (\fIstring\fR)"
Default scorefile name.
.IP "\fBclass\fR (\fIstring\fR)"
Default player class.
.sp
.PP
Something like
.nf
.sp
.in +.5in
setenv UROGUE "name=VAX Killer,fruit=Peach,noterse,jump"
.in -.5in
.sp
.fi
does the obvious. The ``score'' option is ignored unless you start
urogue in wizard mode. The class option string can have the following
values: ``fighter'', ``illus'', ``paladin'', ``ranger'', ``cleric'', ``magic'',
``assasin'', ``druid'', ``ninja'', and ``thief'' and is initialized only at
startup time. The ``inven'' option can take the values ``slow'', ``clear'',
and ``overwrite''.
.PP
You may change most of these values while playing with the
.B ``o''
command.
.SH OPTIONS
.PP
If a
.I save_file
is specified,
urogue will be restored from the specified saved game file.
If the save file is named ``-r'', the default saved game file of
.I ~/rogue.save
is restored.
The other options are:
.IP \-k
Place the terminal's kaypad into
.I auxilary
or
.I applications
mode. Once this is done, the keypad may be used for movement instead
of the normal letter movement keys.
The directions are ``1'' move left and down, ``2'' move down, ``3'' move
right and down, ``6'' move right, ``9'' move right and up, ``8'' move up,
``7'' move up, and ``4'' move left. If the user hits the <RUN> key
(key ``5'') and then a direction, then the rogue will run in the specified
direction.
When the game ends the keypad is restored
to normal
.I numeric
mode if \-k was specified. The user may also place the keypad into
.I auxilary
or
.I applications
mode manually and then may use the keypad without specifing the
\-k option.
.IP \-s
Display the list of scores.
.IP \-n
Display the urogue news file.
This is a file containing information on currently known bugs,
changes, fixes, and enhancements to look for from the last version.
.IP \-v
Display the urogue version information.
.SH COMMANDS
The following is a list of commands for
.I UltraRogue.
You may see a similiar list during a
.I UltraRogue
game by using the
.B ``?''
command.
A
.I <direction>
is one of
\fB``h'', ``j'', ``k'', ``l'', ``y'', ``u'', ``b'', \fRor\fB
``n''.\fR
.IP \fB?\fR
Print out a list of commands.
.IP \fB/\fR
Identify objects.
.IP \fBh\fR
Move left.
.IP \fBj\fR
Move down.
.IP \fBk\fR
Move up.
.IP \fBl\fR
Move right.
.IP \fBy\fR
Move up and left.
.IP \fBu\fR
Move up and right.
.IP \fBb\fR
Move down and left.
.IP \fBn\fR
Move down and right.
.IP \fB<SHIFT><direction>\fR
Run in
.I <direction>.
.IP \fBm<direction>\fR
Move in
.I <direction>
without picking anything up.
.IP \fBt<direction>\fR
Throw something in
.I <direction>.
.IP \fBz<direction>\fR
Zap a wand or staff in
.I <direction>.
.IP \fB>\fR
Go down a staircase.
.IP \fB<\fR
Go up a staircase.
You must possess at least one Artifact to go up a staircase.
.IP \fBs\fR
Search for a trap/secrect door.
.IP \fB.\fR
Rest (do nothing) for one turn.
.IP \fBi\fR
General inventory.
.IP \fBI\fR
Inventory a single item.
.IP \fBq\fR
Quaff a potion.
.IP \fBr\fR
Read paper.
.IP \fBe\fR
Eat one ration of food.
.IP \fBw\fR
Wield a weapon.
.IP \fBW\fR
Wear armor.
.IP \fBT\fR
Take armor off.
.IP \fBP\fR
Put on a ring.
.IP \fBR\fR
Remove a ring.
.IP \fBA\fR
Apply an Artifact.
.IP \fBd\fR
Drop an object.
.IP \fBc\fR
Call object (generic).
.IP \fBM\fR
Mark object (specific).
.IP \fBo\fR
Examine/set options.
.IP \fBC\fR
Cast a spell/say a prayer.
.IP \fBp\fR
Pray to a deity.
.IP \fBa\fR
Affect the undead.
.IP \fB^\fR
Set a trap.
.IP \fBD\fR
Dip something in a pool.
.IP \fB^T\fR
Take (steal) from
.I <direction>.
.IP \fB^R\fR
Redraw screen.
.IP \fB^P\fR
Print last message.
May go up to the last 10 messages.
.IP \fB<ESCAPE>\fR
Cancel current command.
.IP \fBv\fR
Print
.I UltraRogue
version information.
.IP \fB!\fR
Create a shell. Uses $SHELL if present in your environment.
.IP \fBS\fR
Save the current game.
.IP \fBQ\fR
Quit the current game.
.IP \fB=\fR
Listen for monsters.
.IP \fBf<direction>\fR
Fight monster in
.I <direction>.
.IP \fBF<direction>\fR
Fight monster to death in
.I <direction>.
.IP \fB#\fR
Buy the object the rogue is standing on.
Used when in Friendly Fiend's Flea Market.
.IP \fB$\fR
Price the object the rogue is standing on.
Used when in Friendly Fiend's Flea Market.
.IP \fB%\fR
Sell an object from the rogue's pack.
Used when in Friendly Fiend's Flea Market.
.SH FILES
.DT
.ta \w'/usr/games/lib/urogue/scorefile\ \ \ 'u
/usr/games/lib/urogue/scorefile \- Score file
.br
.ta \w'/usr/games/lib/urogue/motd\ \ \ 'u
/usr/games/lib/urogue/motd \- Message of the day
.br
.ta \w'/usr/games/lib/urogue/news\ \ \ 'u
/usr/games/lib/urogue/news \- News file
.br
\fB~\fP/rogue.save \- Default save file
.ST
.SH SEE ALSO
rogue(6),
.br
.I "A Guide to the Dungeons of Doom."
.SH COPYRIGHT
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
.br
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
.br
All rights reserved.

20
urogue/urogue.sln Normal file
View file

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual C++ Express 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "urogue", "urogue.vcproj", "{A428D711-A9BE-4A4E-9013-3AC25A18502D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A428D711-A9BE-4A4E-9013-3AC25A18502D}.Debug|Win32.ActiveCfg = Debug|Win32
{A428D711-A9BE-4A4E-9013-3AC25A18502D}.Debug|Win32.Build.0 = Debug|Win32
{A428D711-A9BE-4A4E-9013-3AC25A18502D}.Release|Win32.ActiveCfg = Release|Win32
{A428D711-A9BE-4A4E-9013-3AC25A18502D}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

440
urogue/urogue.vcproj Normal file
View file

@ -0,0 +1,440 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="urogue"
ProjectGUID="{A428D711-A9BE-4A4E-9013-3AC25A18502D}"
RootNamespace="urogue"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
InlineFunctionExpansion="0"
AdditionalIncludeDirectories="../pdcurses"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;SCOREFILE;ALLSCORES"
StringPooling="true"
MinimalRebuild="true"
ExceptionHandling="0"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
BrowseInformation="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
CompileAs="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib pdcurses.lib advapi32.lib shfolder.lib user32.lib"
OutputFile="$(OutDir)/rogue54.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="../pdcurses"
IgnoreDefaultLibraryNames="LIBC.LIB"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/rogue54.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
OmitFramePointers="true"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/rogue54.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
>
<File
RelativePath="armor.c"
>
</File>
<File
RelativePath=".\artifact.c"
>
</File>
<File
RelativePath=".\bag.c"
>
</File>
<File
RelativePath="chase.c"
>
</File>
<File
RelativePath="command.c"
>
</File>
<File
RelativePath="daemon.c"
>
</File>
<File
RelativePath="daemons.c"
>
</File>
<File
RelativePath=".\dict.c"
>
</File>
<File
RelativePath=".\dictutil.c"
>
</File>
<File
RelativePath=".\encumb.c"
>
</File>
<File
RelativePath="fight.c"
>
</File>
<File
RelativePath=".\getplay.c"
>
</File>
<File
RelativePath=".\ident.c"
>
</File>
<File
RelativePath="init.c"
>
</File>
<File
RelativePath="io.c"
>
</File>
<File
RelativePath="list.c"
>
</File>
<File
RelativePath=".\magic.c"
>
</File>
<File
RelativePath="main.c"
>
</File>
<File
RelativePath=".\maze.c"
>
</File>
<File
RelativePath=".\mdport.c"
>
</File>
<File
RelativePath=".\memory.c"
>
</File>
<File
RelativePath="misc.c"
>
</File>
<File
RelativePath=".\monsdata.c"
>
</File>
<File
RelativePath="monsters.c"
>
</File>
<File
RelativePath="move.c"
>
</File>
<File
RelativePath=".\newlvl.c"
>
</File>
<File
RelativePath="options.c"
>
</File>
<File
RelativePath="pack.c"
>
</File>
<File
RelativePath="passages.c"
>
</File>
<File
RelativePath=".\player.c"
>
</File>
<File
RelativePath="potions.c"
>
</File>
<File
RelativePath=".\random.c"
>
</File>
<File
RelativePath="rings.c"
>
</File>
<File
RelativePath="rip.c"
>
</File>
<File
RelativePath="rooms.c"
>
</File>
<File
RelativePath="save.c"
>
</File>
<File
RelativePath="scrolls.c"
>
</File>
<File
RelativePath="state.c"
>
</File>
<File
RelativePath=".\status.c"
>
</File>
<File
RelativePath="sticks.c"
>
</File>
<File
RelativePath="things.c"
>
</File>
<File
RelativePath=".\trader.c"
>
</File>
<File
RelativePath=".\verify.c"
>
</File>
<File
RelativePath="vers.c"
>
</File>
<File
RelativePath="weapons.c"
>
</File>
<File
RelativePath="wizard.c"
>
</File>
<File
RelativePath=".\xcrypt.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc"
>
<File
RelativePath=".\dict.h"
>
</File>
<File
RelativePath=".\dictutil.h"
>
</File>
<File
RelativePath=".\lint-curses.h"
>
</File>
<File
RelativePath="rogue.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
>
</Filter>
<File
RelativePath=".\history.txt"
>
</File>
<File
RelativePath="LICENSE.TXT"
>
</File>
<File
RelativePath="Makefile"
>
</File>
<File
RelativePath=".\README"
>
</File>
<File
RelativePath=".\TODO"
>
</File>
<File
RelativePath=".\urogue.6"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

19
urogue/verify.c Normal file
View file

@ -0,0 +1,19 @@
/*
verify.c - exiting functions
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1995 Herb Chong
All rights reserved.
*/
static char sccsid[] = "%W% %G%";
#include "rogue.h"
void verify_function(const char *file, const int line)
{
char s[80];
sprintf(s, "Verify failure in %s at line %d\n", file, line);
fatal(s);
}

21
urogue/vers.c Normal file
View file

@ -0,0 +1,21 @@
/*
vers.c - version number
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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.
*/
const char *save_format = "UltraRogue Portable Save File Release 001\04";
const char *version = "UltraRogue 1.06a October 1995";
const char *release = "1.06 Alpha (October 1995)";

556
urogue/weapons.c Normal file
View file

@ -0,0 +1,556 @@
/*
weapons.c - Functions for dealing with problems brought about by weapons
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <ctype.h>
#include <string.h>
#include "rogue.h"
/*
missile()
Fire a missile in a given direction
*/
void
missile(int ydelta, int xdelta, struct linked_list *item, struct thing *tp)
{
struct object *obj;
struct linked_list *nitem;
if (item == NULL) /* Get which thing we are hurling */
return;
obj = OBJPTR(item);
if (!dropcheck(obj) || is_current(obj))
return;
/*
* 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)
{
if (tp->t_pack == pack)
rem_pack(obj);
else
detach(tp->t_pack, item);
}
else
{
obj->o_count--;
nitem = (struct linked_list *) new_item(sizeof *obj);
obj = OBJPTR(nitem);
*obj = *(OBJPTR(item));
obj->o_count = 1;
item = nitem;
}
switch (obj->o_type)
{
case ARTIFACT:
has_artifact &= ~(1 << obj->o_which);
break;
case SCROLL:
if (obj->o_which == S_SCARE && obj->o_flags & ISBLESSED)
obj->o_flags &= ~ISBLESSED;
else
obj->o_flags |= ISCURSED;
}
updpack();
obj->o_pos = do_motion(obj->o_type, 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(obj->o_pos.y, obj->o_pos.x, obj, tp))
{
if (obj->o_type == WEAPON && obj->o_which == GRENADE)
{
hearmsg("BOOOM!");
aggravate();
if (ntraps + 1 < 2 * MAXTRAPS &&
fallpos(obj->o_pos, &traps[ntraps].tr_pos))
{
mvaddch(traps[ntraps].tr_pos.y, traps[ntraps].tr_pos.x,
TRAPDOOR);
traps[ntraps].tr_type = TRAPDOOR;
traps[ntraps].tr_flags = ISFOUND;
traps[ntraps].tr_show = TRAPDOOR;
ntraps++;
light(&hero);
}
discard(item);
}
else if (obj->o_flags & ISLOST)
{
if (obj->o_type == WEAPON)
addmsg("The %s", weaps[obj->o_which].w_name);
else
addmsg(inv_name(obj, LOWERCASE));
msg(" vanishes in a puff of greasy smoke.");
discard(item);
}
else
{
fall(&player, item, TRUE, TRUE);
if (obj->o_flags & CANRETURN)
msg("You have %s.", inv_name(obj, LOWERCASE));
}
}
else if (obj->o_flags & ISOWNED)
{
add_pack(item, NOMESSAGE);
msg("You have %s.", inv_name(obj, LOWERCASE));
}
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
/*
do_motion()
do the actual motion on the screen done by an object
traveling across the room
*/
coord
do_motion(int ob, int ydelta, int xdelta, struct thing *tp)
{
coord pos;
/* Come fly with us ... */
pos = tp->t_pos;
for (;;)
{
int ch;
/* Erase the old one */
if (!ce(pos, tp->t_pos) &&
cansee(pos.y, pos.x) &&
mvwinch(cw, pos.y, pos.x) != ' ')
{
mvwaddch(cw, pos.y, pos.x, show(pos.y, pos.x));
}
/* Get the new position */
pos.y += ydelta;
pos.x += xdelta;
if (shoot_ok(ch = winat(pos.y, pos.x)) &&
ch != DOOR && !ce(pos, hero))
{
/* It hasn't hit anything yet, so display it if it alright. */
if (cansee(pos.y, pos.x) &&
mvwinch(cw, pos.y, pos.x) != ' ')
{
mvwaddch(cw, pos.y, pos.x, ob);
wrefresh(cw);
}
continue;
}
break;
}
return(pos);
}
/*
fall()
Drop an item someplace around here.
*/
void
fall(struct thing *tp, struct linked_list *item, int pr, int player_owned)
{
struct object *obj;
struct room *rp;
coord fpos;
obj = OBJPTR(item);
rp = roomin(tp->t_pos);
if (player_owned && obj->o_flags & CANRETURN)
{
add_pack(item, NOMESSAGE);
msg("You have %s.", inv_name(obj, LOWERCASE));
return;
}
else if (fallpos(obj->o_pos, &fpos))
{
if (obj->o_flags & CANBURN && obj->o_type == WEAPON
&& obj->o_which == MOLOTOV
&& ntraps + 1 < 2 * MAXTRAPS)
{
mvaddch(fpos.y, fpos.x, FIRETRAP);
traps[ntraps].tr_type = FIRETRAP;
traps[ntraps].tr_flags = ISFOUND;
traps[ntraps].tr_show = FIRETRAP;
traps[ntraps].tr_pos = fpos;
ntraps++;
if (rp != NULL)
rp->r_flags &= ~ISDARK;
}
else
{
obj->o_pos = fpos;
add_obj(item, fpos.y, fpos.x);
}
if (rp != NULL &&
(!(rp->r_flags & ISDARK) ||
(rp->r_flags & HASFIRE)))
{
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
}
return;
}
/* get here only if there isn't a place to put it */
if (pr)
{
if (cansee(obj->o_pos.y, obj->o_pos.x))
{
if (obj->o_type == WEAPON)
addmsg("The %s", weaps[obj->o_which].w_name);
else
addmsg(inv_name(obj, LOWERCASE));
msg(" vanishes as it hits the ground.");
}
}
discard(item);
}
/*
init_weapon()
Set up the initial goodies for a weapon
*/
void
init_weapon(struct object *weap, int type)
{
struct init_weps *iwp = &weaps[type];
weap->o_damage = iwp->w_dam;
weap->o_hurldmg = iwp->w_hrl;
weap->o_launch = iwp->w_launch;
weap->o_flags = iwp->w_flags;
weap->o_weight = iwp->w_wght;
if (weap->o_flags & ISMANY)
{
weap->o_count = rnd(8) + 8;
weap->o_group = ++group;
}
else
weap->o_count = 1;
}
/*
hit_monster()
does the missile hit the target?
*/
int
hit_monster(int y, int x, struct object *weapon, struct thing *thrower)
{
struct linked_list *mon;
coord target;
target.y = y;
target.x = x;
if (thrower == &player)
return(fight(&target, weapon, THROWN));
if (ce(target, hero))
{
if (good_monster(*thrower))
{
if (on(*thrower, ISFAMILIAR))
msg("Please get out of the way, Master! I nearly hit you.");
else
msg("Get out of the way %s!", whoami);
return(FALSE);
}
return(attack(thrower, weapon, THROWN));
}
if ((mon = find_mons(y, x)) != NULL)
return(mon_mon_attack(thrower, mon, weapon, THROWN));
else
return(FALSE);
}
/*
num()
Figure out the plus number for armor/weapons
*/
char *
num(int n1, int n2, char *buf)
{
if (buf == NULL)
return("UltraRogue Error #104");
if (n1 == 0 && n2 == 0)
{
strcpy(buf,"+0");
return(buf);
}
if (n2 == 0)
sprintf(buf, "%s%d", n1 < 0 ? "" : "+", n1);
else
sprintf(buf, "%s%d, %s%d", n1 < 0 ? "" : "+",
n1, n2 < 0 ? "" : "+", n2);
return(buf);
}
/*
wield()
Pull out a certain weapon
*/
void
wield(void)
{
struct linked_list *item;
struct object *obj, *oweapon;
oweapon = cur_weapon;
if (!dropcheck(cur_weapon))
{
cur_weapon = oweapon;
return;
}
cur_weapon = oweapon;
if ((item = get_item("wield", WEAPON)) == NULL)
{
after = FALSE;
return;
}
obj = OBJPTR(item);
if (is_current(obj))
{
after = FALSE;
return;
}
wield_ok(&player, obj, TRUE);
msg("You are now wielding %s.", inv_name(obj, LOWERCASE));
cur_weapon = obj;
}
/*
fallpos()
pick a random position around the given (y, x) coordinates
*/
int
fallpos(coord pos, coord *newpos) /*ARGSUSED*/
{
int y, x, cnt;
coord places[9];
cnt = 0;
/* look for all the places that qualify */
for (y = pos.y - 1; y <= pos.y + 1; y++)
{
for (x = pos.x - 1; x <= pos.x + 1; x++)
{
switch(CCHAR(mvwinch(stdscr,y,x)))
{
case GOLD:
case POTION:
case SCROLL:
case FOOD:
case WEAPON:
case ARMOR:
case RING:
case STICK:
case FLOOR:
case PASSAGE:
case ARTIFACT:
places[cnt].y = y;
places[cnt].x = x;
cnt++;
}
}
}
/* now, pick one of the places, if there are any */
if (cnt > 0)
{
int which = rnd(cnt);
newpos->y = places[which].y;
newpos->x = places[which].x;
debug("Dropping object at %d, %d", newpos->y, newpos->x);
}
return(cnt);
}
/*
wield_ok()
enforce player class weapons restrictions
*/
int
wield_ok(struct thing *wieldee, struct object *obj, int print_message)
{
int ret_val = TRUE;
int class_type = wieldee->t_ctype;
if (obj->o_type != WEAPON)
{
ret_val = FALSE;
return(ret_val);
}
else
switch (class_type)
{
case C_MAGICIAN: /* need one hand free */
case C_ILLUSION:
if (obj->o_flags & ISTWOH)
ret_val = FALSE;
break;
case C_THIEF: /* need portable weapon */
case C_ASSASIN:
case C_NINJA:
if (obj->o_flags & ISTWOH)
ret_val = FALSE;
break;
case C_CLERIC: /* No sharp weapons */
if (obj->o_flags & ISSHARP)
ret_val = FALSE;
break;
case C_DRUID: /* No non-silver metal weapons */
if (obj->o_flags & ISMETAL && !(obj->o_flags & ISSILVER))
ret_val = FALSE;
break;
case C_PALADIN: /* must wield sharp stuff */
if ((obj->o_flags & ISSHARP) == FALSE)
ret_val = FALSE;
break;
case C_FIGHTER: /* wield anything */
case C_RANGER:
case C_MONSTER:
break;
default: /* Unknown class */
debug("Unknown class %d.", class_type);
break;
}
if (itemweight(obj) > 18 * pstats.s_str)
{
if (wieldee == &player && print_message == TRUE)
msg("That is too heavy for you to swing effectively!");
ret_val = FALSE;
return(ret_val);
}
if (ret_val == FALSE && print_message == MESSAGE)
switch (class_type)
{
case C_MAGICIAN:
case C_ILLUSION:
msg("You'll find it hard to cast spells while wielding that!");
break;
case C_THIEF:
case C_ASSASIN:
case C_NINJA:
msg("Don't expect to backstab anyone while wielding that!");
break;
case C_CLERIC:
case C_DRUID:
case C_PALADIN:
msg("Your god strongly disapproves of your wielding that!");
break;
case C_FIGHTER:
case C_RANGER:
case C_MONSTER:
break;
}
return(ret_val);
}
/*
shoot_ok()
returns true if it is ok for type to shoot over ch
*/
int
shoot_ok(int ch)
{
switch(ch)
{
case ' ':
case '|':
case '-':
case SECRETDOOR:
return(FALSE);
default:
return(!isalpha(ch));
}
}

238
urogue/wizard.c Normal file
View file

@ -0,0 +1,238 @@
/*
wizard.c - Special wizard commands
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
All rights reserved.
Based on "Advanced Rogue"
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
All rights reserved.
Based on "Rogue: Exploring the Dungeons of Doom"
Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <string.h>
#include <stdlib.h>
#include "rogue.h"
/*
whatis()
What a certain object is
*/
void
whatis(struct linked_list *what)
{
struct object *obj;
int kludge;
int print_message = FALSE;
if (what == NULL)
{
print_message = TRUE;
while ((what = get_item("identify", 0)) == NULL)
;
}
obj = OBJPTR(what);
obj->o_flags |= ISKNOW;
switch (obj->o_type)
{
case SCROLL: kludge = TYP_SCROLL; break;
case POTION: kludge = TYP_POTION; break;
case STICK: kludge = TYP_STICK; break;
case RING: kludge = TYP_RING; break;
case WEAPON:
case ARMOR:
default: kludge = -1; break;
}
if (kludge != -1)
{
know_items[kludge][obj->o_which] = TRUE;
if (guess_items[kludge][obj->o_which])
{
ur_free(guess_items[kludge][obj->o_which]);
guess_items[kludge][obj->o_which] = NULL;
}
}
if (print_message)
msg(inv_name(obj, UPPERCASE));
}
/*
teleport()
Bamf the hero someplace else
*/
void
teleport(void)
{
struct room *new_rp = NULL, *old_rp = roomin(hero);
int rm, which;
coord c;
int is_lit = FALSE; /* For saving room light state */
int rand_position = TRUE;
c = hero;
mvwaddch(cw, hero.y, hero.x, mvwinch(stdscr, hero.y, hero.x));
if (is_wearing(R_TELCONTROL))
{
msg("Where do you wish to teleport to? (* for help)");
wmove(cw, hero.y, hero.x);
wrefresh(cw);
which = (short) (readchar() & 0177);
while (which != (short) ESCAPE && which != (short) LINEFEED
&& which != (short) CARRIAGE_RETURN)
{
switch(which)
{
case 'h': c.x--; break;
case 'j': c.y++; break;
case 'k': c.y--; break;
case 'l': c.x++; break;
case 'y': c.x--;
c.y--; break;
case 'u': c.x++;
c.y--; break;
case 'b': c.x--;
c.y++; break;
case 'n': c.x++;
c.y++; break;
case '*':
msg("Use h,j,k,l,y,u,b,n to position cursor, then hit"
"return.");
}
c.y = max(c.y, 1);
c.y = min(c.y, LINES - 3);
c.x = max(c.x, 1);
c.x = min(c.x, COLS - 1);
wmove(cw, c.y, c.x);
wrefresh(cw);
which = (short) (readchar() & 0177);
}
which = winat(c.y, c.x);
if ((which == FLOOR || which == PASSAGE || which == DOOR) &&
((ring_value(R_TELCONTROL) == 0 && rnd(10) < 6)
|| (ring_value(R_TELCONTROL) > 0 && rnd(10) < 9)))
{
rand_position = FALSE;
msg("You attempt succeeds.");
hero = c;
new_rp = roomin(hero);
}
else
msg("Your attempt fails.");
}
if (rand_position)
{
do
{
rm = rnd_room();
rnd_pos(&rooms[rm], &hero);
}
while (winat(hero.y, hero.x) != FLOOR);
new_rp = &rooms[rm];
}
/* If hero gets moved, darken old room */
if (old_rp && old_rp != new_rp)
{
if (!(old_rp->r_flags & ISDARK))
is_lit = TRUE;
old_rp->r_flags |= ISDARK; /* Fake darkness */
light(&c);
if (is_lit)
old_rp->r_flags &= ~ISDARK; /* Restore light state */
}
light(&hero);
mvwaddch(cw, hero.y, hero.x, PLAYER);
/* turn off ISHELD in case teleportation was done while fighting */
if (on(player, ISHELD))
{
struct linked_list *ip, *nip;
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);
}
}
extinguish_fuse(FUSE_SUFFOCATE);
player.t_no_move = 0; /* not trapped anymore */
count = 0;
running = FALSE;
return;
}
/*
passwd()
see if user knows password
*/
int
passwd(void)
{
char *sp, c;
char buf[2 * LINELEN];
msg("Wizard's Password:");
mpos = 0;
sp = buf;
while ((c = (readchar() & 0177)) != '\n' && c != '\r' && c != '\033')
{
if (c == '\0')
sp = buf;
else if (c == '\b' && sp > buf)
sp--;
else
*sp++ = c;
}
if (sp == buf)
return(FALSE);
*sp = '\0';
return(TRUE);
}

685
urogue/xcrypt.c Normal file
View file

@ -0,0 +1,685 @@
/*
* FreeSec: libcrypt
*
* Copyright (C) 1994 David Burren
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name(s) of the author(s) nor the names of other contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
* This is an original implementation of the DES and the crypt(3) interfaces
* by David Burren <davidb@werj.com.au>.
*
* An excellent reference on the underlying algorithm (and related
* algorithms) is:
*
* B. Schneier, Applied Cryptography: protocols, algorithms,
* and source code in C, John Wiley & Sons, 1994.
*
* Note that in that book's description of DES the lookups for the initial,
* pbox, and final permutations are inverted (this has been brought to the
* attention of the author). A list of errata for this book has been
* posted to the sci.crypt newsgroup by the author and is available for FTP.
*
* NOTE:
* This file has a static version of des_setkey() so that crypt.o exports
* only the crypt() interface. This is required to make binaries linked
* against crypt.o exportable or re-exportable from the USA.
*/
#include <sys/types.h>
#include <string.h>
extern unsigned long int md_ntohl(unsigned long int x);
extern unsigned long int md_htonl(unsigned long int x);
#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(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 j, b, k, inbit, obit;
unsigned int *p, *il, *ir, *fl, *fr;
unsigned char i;
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(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(const unsigned 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(unsigned int l_in, unsigned int r_in, unsigned int *l_out,
unsigned int *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(const unsigned char *in, unsigned 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(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);
}