From 11cf2fc4fa361a391d9b185e16344c0d1f55d168 Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Thu, 13 Oct 2011 10:59:16 -0500 Subject: [PATCH] Import from SourceForge --- Makefile | 113 ++++++++ continue.c | 666 ++++++++++++++++++++++++++++++++++++++++++++ control.c | 273 ++++++++++++++++++ ctlmod.c | 266 ++++++++++++++++++ data.c | 319 +++++++++++++++++++++ edit.c | 577 ++++++++++++++++++++++++++++++++++++++ error.c | 102 +++++++ ether.c | 365 ++++++++++++++++++++++++ find.c | 480 ++++++++++++++++++++++++++++++++ handle.c | 220 +++++++++++++++ inter.c | 471 +++++++++++++++++++++++++++++++ master.c | 400 ++++++++++++++++++++++++++ netmap.c | 196 +++++++++++++ netmisc.c | 231 +++++++++++++++ netprot.c | 529 +++++++++++++++++++++++++++++++++++ netprot.h | 596 +++++++++++++++++++++++++++++++++++++++ netwait.c | 298 ++++++++++++++++++++ netwait.h | 17 ++ network.c | 84 ++++++ network.h | 82 ++++++ packet.c | 486 ++++++++++++++++++++++++++++++++ pipes.c | 489 ++++++++++++++++++++++++++++++++ rcopy.c | 701 ++++++++++++++++++++++++++++++++++++++++++++++ rexec.c | 244 ++++++++++++++++ rinit.c | 439 +++++++++++++++++++++++++++++ rmap.c | 417 +++++++++++++++++++++++++++ rmove.c | 390 ++++++++++++++++++++++++++ ropen.c | 17 ++ rread.c | 181 ++++++++++++ rwrite.c | 805 +++++++++++++++++++++++++++++++++++++++++++++++++++++ sendit.c | 289 +++++++++++++++++++ signal.c | 420 ++++++++++++++++++++++++++++ socket.c | 410 +++++++++++++++++++++++++++ solve.c | 377 +++++++++++++++++++++++++ startup.c | 454 ++++++++++++++++++++++++++++++ system.c | 273 ++++++++++++++++++ terminal.c | 11 + 37 files changed, 12688 insertions(+) create mode 100644 Makefile create mode 100644 continue.c create mode 100644 control.c create mode 100644 ctlmod.c create mode 100644 data.c create mode 100644 edit.c create mode 100644 error.c create mode 100644 ether.c create mode 100644 find.c create mode 100644 handle.c create mode 100644 inter.c create mode 100644 master.c create mode 100644 netmap.c create mode 100644 netmisc.c create mode 100644 netprot.c create mode 100644 netprot.h create mode 100644 netwait.c create mode 100644 netwait.h create mode 100644 network.c create mode 100644 network.h create mode 100644 packet.c create mode 100644 pipes.c create mode 100644 rcopy.c create mode 100644 rexec.c create mode 100644 rinit.c create mode 100644 rmap.c create mode 100644 rmove.c create mode 100644 ropen.c create mode 100644 rread.c create mode 100644 rwrite.c create mode 100644 sendit.c create mode 100644 signal.c create mode 100644 socket.c create mode 100644 solve.c create mode 100644 startup.c create mode 100644 system.c create mode 100644 terminal.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..194afc5 --- /dev/null +++ b/Makefile @@ -0,0 +1,113 @@ +# +# Makefile for network +# @(#)Makefile 4.21 (Berkeley) 02/04/99 +# +HDRS= netprot.h network.h netwait.h +DOBJS= terminal.o rmove.o network.o netprot.o rwrite.o rread.o \ + sendit.o continue.o rinit.o control.o error.o rmap.o edit.o \ + rexec.o master.o handle.o pipes.o packet.o socket.o ether.o \ + netmap.o startup.o solve.o data.o signal.o rcopy.o \ + system.o ctlmod.o +OBJS= $(DOBJS) find.o inter.o +CFILES= terminal.c rmove.c network.c netprot.c rwrite.c rread.c \ + sendit.c continue.c rinit.c control.c error.c rmap.c edit.c \ + rexec.c master.c handle.c pipes.c packet.c socket.c ether.c \ + netmap.c inter.c startup.c solve.c data.c signal.c rcopy.c \ + system.c ctlmod.c find.c +MISC_C= ropen.c netwait.c netmisc.c +MISC= Makefile $(MISC_C) + +DEFS= -DMASTER -DDUMP -DALLSCORES -DUSE_OLD_TTY +CFLAGS= -g $(DEFS) +#CFLAGS= -Bcpp/ -tp -O $(DEFS) +PROFLAGS= -pg -O +#LDFLAGS= -i # For PDP-11's +LDFLAGS= -g # For VAXen +CRLIB= -lncurses +#CRLIB= -lcurses +#CRLIB= libcurses.a + +#SCOREFILE= /usr/public/n_rogue_roll +SCOREFILE= /usr/games/rogue.scores +#SCOREFILE= ./net_hist +SF= -DSCOREFILE='"$(SCOREFILE)"' +NAMELIST= /vmunix +NL= -DNAMELIST='"$(NAMELIST)"' +#MACHDEP= -DMAXLOAD=40 -DLOADAV -DCHECKTIME=4 + +LD= ld +VGRIND= /usr/ucb/vgrind +# for sites without sccs front end, GET= get +GET= sccs get + +# Use ansi flag to gcc +#CC = gcc -ansi +CC = cc + +.DEFAULT: + $(GET) $@ + +a.out: $(HDRS) $(OBJS) + -rm -f a.out + @rm -f x.c + -$(CC) $(LDFLAGS) $(OBJS) $(CRLIB) +# -$(CC) $(LDFLAGS) $(OBJS) $(CRLIB) -ltermlib +# -$(CC) $(LDFLAGS) $(OBJS) $(CRLIB) -lcrypt + size a.out +# @echo -n 'You still have to remove ' # 11/70's +# @size a.out | sed 's/+.*/ 1024 63 * - p/' | dc # 11/70's + +terminal.o: + $(CC) -c $(CFLAGS) terminal.c + +find.o: find.c + $(CC) -c $(CFLAGS) $(SF) $(NL) $(MACHDEP) find.c + +inter.o: inter.c + $(CC) -c $(CFLAGS) $(SF) $(NL) $(MACHDEP) inter.c + +network: newvers a.out + cp a.out network + strip network + +ropen: ropen.c + $(CC) -s -o ropen ropen.c + +netwait: netwait.o netmisc.o terminal.o + $(CC) -s -o netwait terminal.o netwait.o netmisc.o -lcurses + +netmisc.o netwait.o: + $(CC) -O -c $(SF) $*.c + +newvers: + $(GET) -e terminal.c + sccs delta -y terminal.c + +flist: $(HDRS) $(CFILES) $(MISC_C) + -mv flist tags + ctags -u $? + ed - tags < :rofix + sort tags -o flist + rm -f tags + +lint: + /bin/csh -c "lint -hxbc $(DEFS) $(MACHDEP) $(SF) $(NL) $(CFILES) -lcurses > linterrs" + +clean: + rm -f $(OBJS) core a.out p.out network strings ? network.tar vgrind.* x.c x.o xs.c linterrs ropen + +xtar: $(HDRS) $(CFILES) $(MISC) + rm -f network.tar + tar cf network.tar $? :rofix + touch xtar + +vgrind: + @csh $(VGRIND) -t -h "Rogue Version 3.7" $(HDRS) *.c > vgrind.out + @ctags -v $(HDRS) *.c > index + @csh $(VGRIND) -t -x index > vgrind.out.tbl + +wc: + @echo " bytes words lines pages file" + @wc -cwlp $(HDRS) $(CFILES) + +cfiles: $(CFILES) diff --git a/continue.c b/continue.c new file mode 100644 index 0000000..82d60a7 --- /dev/null +++ b/continue.c @@ -0,0 +1,666 @@ +/* + * All the fighting gets done here + * + * @(#)continue.c 4.67 (Berkeley) 09/06/83 + */ + +#include +#include +#include "netprot.h" + +#define EQSTR(a, b) (strcmp(a, b) == 0) + +char *H_names[] = { /* strings for hitting */ + " scored an excellent hit on ", + " hit ", + " have injured ", + " swing and hit ", + " scored an excellent hit on ", + " hit ", + " has injured ", + " swings and hits " +}; + +char *M_names[] = { /* strings for missing */ + " miss", + " swing and miss", + " barely miss", + " don't hit", + " misses", + " swings and misses", + " barely misses", + " doesn't hit", +}; + +/* + * adjustments to hit probabilities due to strength + */ +static int Str_plus[] = { + -7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, +}; + +/* + * adjustments to damage done due to strength + */ +static int Add_dam[] = { + -7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, + 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6 +}; + +/* + * fight: + * The player attacks the monster. + */ +bool +fight(coord *mp, THING *weap, bool thrown) +{ + THING *tp; + bool did_hit = TRUE; + char *mname, ch; + + /* + * Find the monster we want to fight + */ +#ifdef MASTER + if ((tp = moat(mp->y, mp->x)) == NULL) + debug("Fight what @ %d,%d", mp->y, mp->x); +#else + tp = moat(mp->y, mp->x); +#endif + /* + * Since we are fighting, things are not quiet so no healing takes + * place. + */ + Count = 0; + Quiet = 0; + runto(mp); + /* + * Let him know it was really a xeroc (if it was one). + */ + ch = '\0'; + if (tp->t_type == 'X' && tp->t_disguise != 'X' && !on(Player, ISBLIND)) + { + tp->t_disguise = 'X'; + if (on(Player, ISHALU)) { + ch = rnd(26) + 'A'; + mvaddch(tp->t_pos.y, tp->t_pos.x, ch); + } + msg(choose_str("heavy! That's a nasty critter!", + "wait! That's a xeroc!")); + if (!thrown) + return FALSE; + } + mname = set_mname(tp); + did_hit = FALSE; + Has_hit = (Terse && !To_death); + if (roll_em(&Player, tp, weap, thrown)) + { + did_hit = FALSE; + if (thrown) + thunk(weap, mname, Terse); + else + hit((char *) NULL, mname, Terse); + if (on(Player, CANHUH)) + { + did_hit = TRUE; + tp->t_flags |= ISHUH; + Player.t_flags &= ~CANHUH; + endmsg(); + Has_hit = FALSE; + msg("your hands stop glowing %s", pick_color("red")); + } + if (tp->t_stats.s_hpt <= 0) + killed(tp, TRUE); + else if (did_hit && !on(Player, ISBLIND)) + msg("%s appears confused", mname); + did_hit = TRUE; + } + else + if (thrown) + bounce(weap, mname, Terse); + else + miss((char *) NULL, mname, Terse); + return did_hit; +} + +/* + * attack: + * The monster attacks the player + */ +void +attack(THING *mp) +{ + char *mname, ch; + int oldhp; + + /* + * Since this is an attack, stop running and any healing that was + * going on at the time. + */ + Running = FALSE; + Count = 0; + Quiet = 0; + if (To_death && !on(*mp, ISTARGET)) + { + To_death = FALSE; + Kamikaze = FALSE; + } + if (mp->t_type == 'X' && mp->t_disguise != 'X' && !on(Player, ISBLIND)) + { + mp->t_disguise = 'X'; + if (on(Player, ISHALU)) + mvaddch(mp->t_pos.y, mp->t_pos.x, rnd(26) + 'A'); + } + mname = set_mname(mp); + oldhp = Pstats.s_hpt; + if (roll_em(mp, &Player, (THING *) NULL, FALSE)) + { + if (mp->t_type != 'I') + { + if (Has_hit) + addmsg(". "); + hit(mname, (char *) NULL, FALSE); + } + else + if (Has_hit) + endmsg(); + Has_hit = FALSE; + if (Pstats.s_hpt <= 0) + death(mp->t_type); /* Bye bye life ... */ + else if (!Kamikaze) + { + oldhp -= Pstats.s_hpt; + if (oldhp > Max_hit) + Max_hit = oldhp; + if (Pstats.s_hpt <= Max_hit) + To_death = FALSE; + } + if (!on(*mp, ISCANC)) + switch (mp->t_type) + { + when 'A': + /* + * If an aquator hits, you can lose armor class. + */ + rust_armor(Cur_armor); + when 'I': + /* + * The ice monster freezes you + */ + Player.t_flags &= ~ISRUN; + if (!No_command) + { + addmsg("you are frozen"); + if (!Terse) + addmsg(" by the %s", mname); + endmsg(); + } + No_command += rnd(2) + 2; + if (No_command > BORE_LEVEL) + death('h'); + when 'R': + /* + * Rattlesnakes have poisonous bites + */ + if (!save(VS_POISON)) + if (!ISWEARING(R_SUSTSTR)) + { + chg_str(-1); + if (!Terse) + msg("you feel a bite in your leg and now feel weaker"); + else + msg("a bite has weakened you"); + } + else if (!To_death) + if (!Terse) + msg("a bite momentarily weakens you"); + else + msg("bite has no effect"); + when 'W': + case 'V': + /* + * Wraiths might drain energy levels, and Vampires + * can steal Max_hp + */ + if (rnd(100) < (mp->t_type == 'W' ? 15 : 30)) + { + int fewer; + + if (mp->t_type == 'W') + { + if (Pstats.s_exp == 0) + death('W'); /* All levels gone */ + if (--Pstats.s_lvl == 0) + { + Pstats.s_exp = 0; + Pstats.s_lvl = 1; + } + else + Pstats.s_exp = E_levels[Pstats.s_lvl-1]+1; + fewer = roll(1, 10); + } + else + fewer = roll(1, 3); + Pstats.s_hpt -= fewer; + Max_hp -= fewer; + if (Pstats.s_hpt <= 0) + Pstats.s_hpt = 1; + if (Max_hp <= 0) + death(mp->t_type); + msg("you suddenly feel weaker"); + } + when 'F': + /* + * Venus Flytrap stops the poor guy from moving + */ + Player.t_flags |= ISHELD; + sprintf(Monsters['F'-'A'].m_stats.s_dmg,"%dx1", ++Vf_hit); + if (--Pstats.s_hpt <= 0) + death('F'); + when 'L': + { + /* + * Leperachaun steals some gold + */ + long lastpurse; + + lastpurse = Purse; + Purse -= GOLDCALC; + if (!save(VS_MAGIC)) + Purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; + if (Purse < 0) + Purse = 0; + remove_mon(&mp->t_pos, mp, FALSE); + if (Purse != lastpurse) + msg("your purse feels lighter"); + } + when 'N': + { + THING *obj, *steal; + int nobj; + + /* + * Nymph's steal a magic item, look through the pack + * and pick out one we like. + */ + steal = NULL; + for (nobj = 0, obj = Pack; obj != NULL; obj = next(obj)) + if (obj != Cur_armor && obj != Cur_weapon + && obj != Cur_ring[LEFT] && obj != Cur_ring[RIGHT] + && is_magic(obj) && rnd(++nobj) == 0) + steal = obj; + if (steal != NULL) + { + remove_mon(&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE); + leave_pack(steal, FALSE, FALSE); + msg("she stole %s!", inv_name(steal, TRUE)); + discard(steal); + } + } + otherwise: + break; + } + } + else if (mp->t_type != 'I') + { + if (Has_hit) + { + addmsg(". "); + Has_hit = FALSE; + } + if (mp->t_type == 'F') + { + Pstats.s_hpt -= Vf_hit; + if (Pstats.s_hpt <= 0) + death(mp->t_type); /* Bye bye life ... */ + } + miss(mname, (char *) NULL, FALSE); + } + if (Fight_flush && !To_death) + flush_type(); + Count = 0; + status(); +} + +/* + * set_mname: + * return the monster name for the given monster + */ +char * +set_mname(THING *tp) +{ + int ch; + char *mname; + static char tbuf[MAXSTR] = { 't', 'h', 'e', ' ' }; + + if (!see_monst(tp) && !on(Player, SEEMONST)) + return (Terse ? "it" : "something"); + else if (on(Player, ISHALU)) + { + move(tp->t_pos.y, tp->t_pos.x); + ch = toascii(inch()); + if (!isupper(ch)) + ch = rnd(26); + else + ch -= 'A'; + mname = Monsters[ch].m_name; + } + else + mname = Monsters[tp->t_type - 'A'].m_name; + strcpy(&tbuf[4], mname); + return tbuf; +} + +/* + * swing: + * Returns true if the swing hits + */ +bool +swing(int at_lvl, int op_arm, int wplus) +{ + int res = rnd(20); + int need = (20 - at_lvl) - op_arm; + + return (res + wplus >= need); +} + +/* + * roll_em: + * Roll several attacks + */ +bool +roll_em(THING *thatt, THING *thdef, THING *weap, bool hurl) +{ + struct stats *att, *def; + char *cp; + int ndice, nsides, def_arm; + bool did_hit = FALSE; + int hplus; + int dplus; + int damage; + char *index(); + + att = &thatt->t_stats; + def = &thdef->t_stats; + if (weap == NULL) + { + cp = att->s_dmg; + dplus = 0; + hplus = 0; + } + else + { + hplus = (weap == NULL ? 0 : weap->o_hplus); + dplus = (weap == NULL ? 0 : weap->o_dplus); + if (weap == Cur_weapon) + { + if (ISRING(LEFT, R_ADDDAM)) + dplus += Cur_ring[LEFT]->o_arm; + else if (ISRING(LEFT, R_ADDHIT)) + hplus += Cur_ring[LEFT]->o_arm; + if (ISRING(RIGHT, R_ADDDAM)) + dplus += Cur_ring[RIGHT]->o_arm; + else if (ISRING(RIGHT, R_ADDHIT)) + hplus += Cur_ring[RIGHT]->o_arm; + } + cp = weap->o_damage; + if (hurl) + if ((weap->o_flags&ISMISL) && Cur_weapon != NULL && + Cur_weapon->o_which == weap->o_launch) + { + cp = weap->o_hurldmg; + hplus += Cur_weapon->o_hplus; + dplus += Cur_weapon->o_dplus; + } + else if (weap->o_launch < 0) + cp = weap->o_hurldmg; + } + /* + * If the creature being attacked is not running (alseep or held) + * then the attacker gets a plus four bonus to hit. + */ + if (!on(*thdef, ISRUN)) + hplus += 4; + def_arm = def->s_arm; + if (def == &Pstats) + { + if (Cur_armor != NULL) + def_arm = Cur_armor->o_arm; + if (ISRING(LEFT, R_PROTECT)) + def_arm -= Cur_ring[LEFT]->o_arm; + if (ISRING(RIGHT, R_PROTECT)) + def_arm -= Cur_ring[RIGHT]->o_arm; + } + while (cp != NULL && *cp != '\0') + { + ndice = atoi(cp); + if ((cp = index(cp, 'x')) == NULL) + break; + nsides = atoi(++cp); + if (swing(att->s_lvl, def_arm, hplus + Str_plus[att->s_str])) + { + int proll; + + proll = roll(ndice, nsides); +#ifdef MASTER + if (ndice + nsides > 0 && proll <= 0) + debug("Damage for %dx%d came out %d, dplus = %d, Add_dam = %d, def_arm = %d", ndice, nsides, proll, dplus, Add_dam[att->s_str], def_arm); +#endif + damage = dplus + proll + Add_dam[att->s_str]; + def->s_hpt -= max(0, damage); + did_hit = TRUE; + } + if ((cp = index(cp, '/')) == NULL) + break; + cp++; + } + return did_hit; +} + +/* + * prname: + * The print name of a combatant + */ +char * +prname(char *mname, bool upper) +{ + static char tbuf[MAXSTR]; + + *tbuf = '\0'; + if (mname == 0) + strcpy(tbuf, "you"); + else + strcpy(tbuf, mname); + if (upper) + *tbuf = toupper(*tbuf); + return tbuf; +} + +/* + * thunk: + * A missile hits a monster + */ +void +thunk(THING *weap, char *mname, bool noend) +{ + if (To_death) + return; + if (weap->o_type == WEAPON) + addmsg("the %s hits ", Weap_info[weap->o_which].oi_name); + else + addmsg("you hit "); + addmsg("%s", mname); + if (!noend) + endmsg(); +} + +/* + * hit: + * Print a message to indicate a succesful hit + */ +void +hit(char *er, char *ee, bool noend) +{ + int i; + char *s; + extern char *H_names[]; + + if (To_death) + return; + addmsg(prname(er, TRUE)); + if (Terse) + s = " hit"; + else + { + i = rnd(4); + if (er != NULL) + i += 4; + s = H_names[i]; + } + addmsg(s); + if (!Terse) + addmsg(prname(ee, FALSE)); + if (!noend) + endmsg(); +} + +/* + * miss: + * Print a message to indicate a poor swing + */ +void +miss(char *er, char *ee, bool noend) +{ + int i; + extern char *M_names[]; + + if (To_death) + return; + addmsg(prname(er, TRUE)); + if (Terse) + i = 0; + else + i = rnd(4); + if (er != NULL) + i += 4; + addmsg(M_names[i]); + if (!Terse) + addmsg(" %s", prname(ee, FALSE)); + if (!noend) + endmsg(); +} + +/* + * bounce: + * A missile misses a monster + */ +void +bounce(THING *weap, char *mname, bool noend) +{ + if (To_death) + return; + if (weap->o_type == WEAPON) + addmsg("the %s misses ", Weap_info[weap->o_which].oi_name); + else + addmsg("you missed "); + addmsg(mname); + if (!noend) + endmsg(); +} + +/* + * remove_mon: + * Remove a monster from the screen + */ +void +remove_mon(coord *mp, THING *tp, bool waskill) +{ + THING *obj, *nexti; + + for (obj = tp->t_pack; obj != NULL; obj = nexti) + { + nexti = next(obj); + obj->o_pos = tp->t_pos; + detach(tp->t_pack, obj); + if (waskill) + fall(obj, FALSE); + else + discard(obj); + } + moat(mp->y, mp->x) = NULL; + mvaddch(mp->y, mp->x, tp->t_oldch); + detach(Mlist, tp); + if (on(*tp, ISTARGET)) + { + Kamikaze = FALSE; + To_death = FALSE; + if (Fight_flush) + flush_type(); + } + discard(tp); +} + +/* + * killed: + * Called to put a monster to death + */ +void +killed(THING *tp, bool pr) +{ + char *mname; + + Pstats.s_exp += tp->t_stats.s_exp; + + /* + * If the monster was a venus flytrap, un-hold him + */ + switch (tp->t_type) + { + when 'F': + Player.t_flags &= ~ISHELD; + Vf_hit = 0; + strcpy(Monsters['F'-'A'].m_stats.s_dmg, "000x0"); + when 'L': + { + THING *gold; + + if (fallpos(&tp->t_pos, &tp->t_room->r_gold) && Level >= Max_level) + { + gold = new_item(); + gold->o_type = GOLD; + gold->o_goldval = GOLDCALC; + if (save(VS_MAGIC)) + gold->o_goldval += GOLDCALC + GOLDCALC + + GOLDCALC + GOLDCALC; + attach(tp->t_pack, gold); + } + } + } + /* + * Get rid of the monster. + */ + mname = set_mname(tp); + remove_mon(&tp->t_pos, tp, TRUE); + if (pr) + { + if (Has_hit) + { + addmsg(". Defeated "); + Has_hit = FALSE; + } + else + { + if (!Terse) + addmsg("you have "); + addmsg("defeated "); + } + msg(mname); + } + /* + * Do adjustments if he went up a level + */ + check_level(); + if (Fight_flush) + flush_type(); +} diff --git a/control.c b/control.c new file mode 100644 index 0000000..d318023 --- /dev/null +++ b/control.c @@ -0,0 +1,273 @@ +/* + * Various input/output functions + * + * @(#)control.c 4.32 (Berkeley) 02/05/99 + */ + +#include +#include +#include "netprot.h" + +/* + * msg: + * Display a message at the top of the screen. + */ +#define MAXMSG (NUMCOLS - sizeof "--More--") + +static char Msgbuf[MAXMSG+1]; +static int Newpos = 0; + +/* VARARGS1 */ +int +msg(char *fmt, ...) +{ + va_list args; + + /* + * if the string is "", just clear the line + */ + if (*fmt == '\0') + { + move(0, 0); + clrtoeol(); + Mpos = 0; + return ~ESCAPE; + } + /* + * otherwise add to the message and flush it out + */ + va_start(args, fmt); + doadd(fmt, args); + va_end(args); + return endmsg(); +} + +/* + * addmsg: + * Add things to the current message + */ +/* VARARGS1 */ +void +addmsg(char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + doadd(fmt, args); + va_end(args); +} + +/* + * endmsg: + * Display a new msg (giving him a chance to see the previous one + * if it is up there with the --More--) + */ +int +endmsg(void) +{ + char ch; + + if (Save_msg) + strcpy(Huh, Msgbuf); + if (Mpos) + { + look(FALSE); + mvaddstr(0, Mpos, "--More--"); + refresh(); + if (!Msg_esc) + wait_for(' '); + else + { + while ((ch = readchar()) != ' ') + if (ch == ESCAPE) + { + Msgbuf[0] = '\0'; + Mpos = 0; + Newpos = 0; + Msgbuf[0] = '\0'; + return ESCAPE; + } + } + } + /* + * All messages should start with uppercase, except ones that + * start with a pack addressing character + */ + if (islower(Msgbuf[0]) && !Lower_msg && Msgbuf[1] != ')') + Msgbuf[0] = toupper(Msgbuf[0]); + mvaddstr(0, 0, Msgbuf); + clrtoeol(); + Mpos = Newpos; + Newpos = 0; + Msgbuf[0] = '\0'; + refresh(); + return ~ESCAPE; +} + +/* + * doadd: + * Perform an add onto the message buffer + */ +void +doadd(char *fmt, va_list args) +{ + static char buf[MAXSTR]; + + /* + * Do the printf into buf + */ + vsprintf(buf, fmt, args); + if (strlen(buf) + Newpos >= MAXMSG) + endmsg(); + strcat(Msgbuf, buf); + Newpos = strlen(Msgbuf); +} + +/* + * step_ok: + * Returns true if it is ok to step on ch + */ +bool +step_ok(char ch) +{ + switch (ch) + { + case ' ': + case '|': + case '-': + return FALSE; + default: + return (!isalpha(ch)); + } +} + +/* + * readchar: + * Reads and returns a character, checking for gross input errors + */ +int +readchar(void) +{ + int cnt; + static char c; + + cnt = 0; + while (read(0, &c, 1) <= 0) + if (cnt++ > 100) /* if we are getting infinite EOFs */ + auto_save(0); /* save the game */ + return c; +} + +/* + * status: + * Display the important stats line. Keep the cursor where it was. + */ +void +status(void) +{ + int (*print_func)(char *fmt, ...); +# define PRINT_FUNC (*print_func) + int oy, ox, temp; + static int hpwidth = 0; + static int s_hungry; + static int s_lvl; + static int s_pur = -1; + static int s_hp; + static int s_arm; + static str_t s_str; + static long s_exp = 0; + static char *state_name[] = + { + "", "Hungry", "Weak", "Faint" + }; + + /* + * If nothing has changed since the last status, don't + * bother. + */ + temp = (Cur_armor != NULL ? Cur_armor->o_arm : Pstats.s_arm); + if (s_hp == Pstats.s_hpt && s_exp == Pstats.s_exp && s_pur == Purse + && s_arm == temp && s_str == Pstats.s_str && s_lvl == Level + && s_hungry == Hungry_state + && !Stat_msg + ) + return; + + s_arm = temp; + + getyx(stdscr, oy, ox); + if (s_hp != Max_hp) + { + temp = Max_hp; + s_hp = Max_hp; + for (hpwidth = 0; temp; hpwidth++) + temp /= 10; + } + + /* + * Save current status + */ + s_lvl = Level; + s_pur = Purse; + s_hp = Pstats.s_hpt; + s_str = Pstats.s_str; + s_exp = Pstats.s_exp; + s_hungry = Hungry_state; + + if (Stat_msg) + { + print_func = msg; + move(0, 0); + } + else + { + move(STATLINE, 0); + print_func = printw; + } + PRINT_FUNC("Level: %d Gold: %-5d Hp: %*d(%*d) Str: %2d(%d) Arm: %-2d Exp: %d/%ld %s", + Level, Purse, hpwidth, Pstats.s_hpt, hpwidth, Max_hp, Pstats.s_str, + Max_stats.s_str, 10 - s_arm, Pstats.s_lvl, Pstats.s_exp, + state_name[Hungry_state]); + + clrtoeol(); + move(oy, ox); +} + +/* + * wait_for + * Sit around until the guy types the right key + */ +void +wait_for(char ch) +{ + char c; + + if (ch == '\n') + while ((c = readchar()) != '\n' && c != '\r') + continue; + else + while (readchar() != ch) + continue; +} + +/* + * show_win: + * Function used to display a window and wait before returning + */ +void +show_win(char *message) +{ + WINDOW *win; + + win = Hw; + wmove(win, 0, 0); + waddstr(win, message); + touchwin(win); + wmove(win, Hero.y, Hero.x); + wrefresh(win); + wait_for(' '); + clearok(curscr, TRUE); +#ifdef attron + touchwin(stdscr); +#endif attron +} diff --git a/ctlmod.c b/ctlmod.c new file mode 100644 index 0000000..67882cf --- /dev/null +++ b/ctlmod.c @@ -0,0 +1,266 @@ +/* + * Special wizard commands (some of which are also non-wizard commands + * under strange circumstances) + * + * @(#)ctlmod.c 4.30 (Berkeley) 02/05/99 + */ + +#include +#include +#include "netprot.h" + +/* + * whatis: + * What a certin object is + */ +void +whatis(bool insist, int type) +{ + THING *obj; + + if (Pack == NULL) + { + msg("you don't have anything in your pack to identify"); + return; + } + + for (;;) + { + obj = get_item("identify", type); + if (insist) + { + if (N_objs == 0) + return; + else if (obj == NULL) + msg("you must identify something"); + else if (type && obj->o_type != type && + !(type == R_OR_S && obj->o_type == RING || obj->o_type == STICK)) + msg("you must identify a %s", type_name(type)); + else + break; + } + else + break; + } + + if (obj == NULL) + return; + + switch (obj->o_type) + { + when SCROLL: + set_know(obj, Scr_info); + when POTION: + set_know(obj, Pot_info); + when STICK: + set_know(obj, Ws_info); + when WEAPON: + case ARMOR: + obj->o_flags |= ISKNOW; + when RING: + set_know(obj, Ring_info); + } + msg(inv_name(obj, FALSE)); +} + +/* + * set_know: + * Set things up when we really know what a thing is + */ +void +set_know(THING *obj, struct obj_info *info) +{ + char **guess; + + info[obj->o_which].oi_know = TRUE; + obj->o_flags |= ISKNOW; + guess = &info[obj->o_which].oi_guess; + if (*guess) + { + free(*guess); + *guess = NULL; + } +} + +/* + * type_name: + * Return a pointer to the name of the type + */ +char * +type_name(int type) +{ + struct h_list *hp; + static struct h_list tlist[] = { + POTION, "potion", FALSE, + SCROLL, "scroll", FALSE, + FOOD, "food", FALSE, + R_OR_S, "ring, wand or staff", FALSE, + RING, "ring", FALSE, + STICK, "wand or staff", FALSE, + WEAPON, "weapon", FALSE, + ARMOR, "suit of armor", FALSE, + }; + + for (hp = tlist; hp->h_ch; hp++) + if (type == hp->h_ch) + return hp->h_desc; + /* NOTREACHED */ +} + +#ifdef MASTER +/* + * create_obj: + * Wizard command for getting anything he wants + */ +void +create_obj(void) +{ + THING *obj; + char ch, bless; + + obj = new_item(); + msg("type of item: "); + obj->o_type = readchar(); + Mpos = 0; + msg("which %c do you want? (0-f)", obj->o_type); + obj->o_which = (isdigit((ch = readchar())) ? ch - '0' : ch - 'a' + 10); + obj->o_group = 0; + obj->o_count = 1; + Mpos = 0; + if (obj->o_type == WEAPON || obj->o_type == ARMOR) + { + msg("blessing? (+,-,n)"); + bless = readchar(); + Mpos = 0; + if (bless == '-') + obj->o_flags |= ISCURSED; + if (obj->o_type == WEAPON) + { + init_weapon(obj, obj->o_which); + if (bless == '-') + obj->o_hplus -= rnd(3)+1; + if (bless == '+') + obj->o_hplus += rnd(3)+1; + } + else + { + obj->o_arm = A_class[obj->o_which]; + if (bless == '-') + obj->o_arm += rnd(3)+1; + if (bless == '+') + obj->o_arm -= rnd(3)+1; + } + } + else if (obj->o_type == RING) + switch (obj->o_which) + { + case R_PROTECT: + case R_ADDSTR: + case R_ADDHIT: + case R_ADDDAM: + msg("blessing? (+,-,n)"); + bless = readchar(); + Mpos = 0; + if (bless == '-') + obj->o_flags |= ISCURSED; + obj->o_arm = (bless == '-' ? -1 : rnd(2) + 1); + when R_AGGR: + case R_TELEPORT: + obj->o_flags |= ISCURSED; + } + else if (obj->o_type == STICK) + fix_stick(obj); + else if (obj->o_type == GOLD) + { + msg("how much?"); + get_num(&obj->o_goldval, stdscr); + } + add_pack(obj, FALSE); +} +#endif + +/* + * telport: + * Bamf the hero someplace else + */ +void +teleport(void) +{ + int rm; + static coord c; + + mvaddch(Hero.y, Hero.x, floor_at()); + find_floor((struct room *) NULL, &c, FALSE, TRUE); + if (roomin(&c) != Proom) + { + leave_room(&Hero); + Hero = c; + enter_room(&Hero); + } + else + { + Hero = c; + look(TRUE); + } + mvaddch(Hero.y, Hero.x, PLAYER); + /* + * turn off ISHELD in case teleportation was done while fighting + * a Flytrap + */ + if (on(Player, ISHELD)) { + Player.t_flags &= ~ISHELD; + Vf_hit = 0; + strcpy(Monsters['F'-'A'].m_stats.s_dmg, "000x0"); + } + No_move = 0; + Count = 0; + Running = FALSE; + flush_type(); +} + +#ifdef MASTER +/* + * passwd: + * See if user knows password + */ +bool +passwd(void) +{ + char *sp, c; + static char buf[MAXSTR]; + char *crypt(); + + msg("wizard's Password:"); + Mpos = 0; + sp = buf; + while ((c = getchar()) != '\n' && c != '\r' && c != ESCAPE) + *sp++ = c; + if (sp == buf) + return FALSE; + *sp = '\0'; + return (strcmp(PASSWD, crypt(buf, "mT")) == 0); +} + +/* + * show_map: + * Print out the map for the wizard + */ +void +show_map(void) +{ + int y, x, real; + + wclear(Hw); + for (y = 1; y < NUMLINES - 1; y++) + for (x = 0; x < NUMCOLS; x++) + { + if (!(real = flat(y, x) & F_REAL)) + wstandout(Hw); + wmove(Hw, y, x); + waddch(Hw, chat(y, x)); + if (!real) + wstandend(Hw); + } + show_win("---More (level map)---"); +} +#endif diff --git a/data.c b/data.c new file mode 100644 index 0000000..1e70d59 --- /dev/null +++ b/data.c @@ -0,0 +1,319 @@ +/* + * Read a scroll and let it happen + * + * @(#)data.c 4.44 (Berkeley) 02/05/99 + */ + +#include +#include +#include "netprot.h" + +/* + * read_scroll: + * Read a scroll from the pack and do the appropriate thing + */ +void +read_scroll(void) +{ + THING *obj; + PLACE *pp; + int y, x; + char ch; + int i; + bool discardit = FALSE; + struct room *cur_room; + THING *orig_obj; + static coord mp; + + obj = get_item("read", SCROLL); + if (obj == NULL) + return; + if (obj->o_type != SCROLL) + { + if (!Terse) + msg("there is nothing on it to read"); + else + msg("nothing to read"); + return; + } + /* + * Calculate the effect it has on the poor guy. + */ + if (obj == Cur_weapon) + Cur_weapon = NULL; + /* + * Get rid of the thing + */ + discardit = (obj->o_count == 1); + leave_pack(obj, FALSE, FALSE); + orig_obj = obj; + + switch (obj->o_which) + { + when S_CONFUSE: + /* + * Scroll of monster confusion. Give him that power. + */ + Player.t_flags |= CANHUH; + msg("your hands begin to glow %s", pick_color("red")); + when S_ARMOR: + if (Cur_armor != NULL) + { + Cur_armor->o_arm--; + Cur_armor->o_flags &= ~ISCURSED; + msg("your armor glows %s for a moment", pick_color("silver")); + } + when S_HOLD: + /* + * Hold monster scroll. Stop all monsters within two spaces + * from chasing after the hero. + */ + + ch = 0; + for (x = Hero.x - 2; x <= Hero.x + 2; x++) + if (x >= 0 && x < NUMCOLS) + for (y = Hero.y - 2; y <= Hero.y + 2; y++) + if (y >= 0 && y <= NUMLINES - 1) + if ((obj = moat(y, x)) != NULL && on(*obj, ISRUN)) + { + obj->t_flags &= ~ISRUN; + obj->t_flags |= ISHELD; + ch++; + } + if (ch) + { + addmsg("the monster"); + if (ch > 1) + addmsg("s around you"); + addmsg(" freeze"); + if (ch == 1) + addmsg("s"); + endmsg(); + Scr_info[S_HOLD].oi_know = TRUE; + } + else + msg("you feel a strange sense of loss"); + when S_SLEEP: + /* + * Scroll which makes you fall asleep + */ + Scr_info[S_SLEEP].oi_know = TRUE; + No_command += rnd(SLEEPTIME) + 4; + Player.t_flags &= ~ISRUN; + msg("you fall asleep"); + when S_CREATE: + /* + * Create a monster: + * First look in a circle around him, next try his room + * otherwise give up + */ + i = 0; + for (y = Hero.y - 1; y <= Hero.y + 1; y++) + for (x = Hero.x - 1; x <= Hero.x + 1; x++) + /* + * Don't put a monster in top of the player. + */ + if (y == Hero.y && x == Hero.x) + continue; + /* + * Or anything else nasty + */ + else if (step_ok(ch = winat(y, x))) + if (ch == SCROLL + && find_obj(y, x)->o_which == S_SCARE) + continue; + else if (rnd(++i) == 0) + { + mp.y = y; + mp.x = x; + } + if (i == 0) + msg("you hear a faint cry of anguish in the distance"); + else + { + obj = new_item(); + new_monster(obj, randmonster(FALSE), &mp); + } + when S_ID_POTION: + case S_ID_SCROLL: + case S_ID_WEAPON: + case S_ID_ARMOR: + case S_ID_R_OR_S: + { + static char id_type[S_ID_R_OR_S + 1] = + { 0, 0, 0, 0, 0, POTION, SCROLL, WEAPON, ARMOR, R_OR_S }; + /* + * Identify, let him figure something out + */ + Scr_info[obj->o_which].oi_know = TRUE; + msg("this scroll is an %s scroll", Scr_info[obj->o_which].oi_name); + whatis(TRUE, id_type[obj->o_which]); + } + when S_MAP: + /* + * Scroll of magic mapping. + */ + Scr_info[S_MAP].oi_know = TRUE; + msg("oh, now this scroll has a map on it"); + /* + * Take all the things we want to keep hidden out of the window + */ + for (y = 1; y < NUMLINES - 1; y++) + for (x = 0; x < NUMCOLS; x++) + { + pp = INDEX(y, x); + switch (ch = pp->p_ch) + { + case DOOR: + case STAIRS: + break; + + case '-': + case '|': + if (!(pp->p_flags & F_REAL)) + { + ch = pp->p_ch = DOOR; + pp->p_flags |= F_REAL; + } + break; + + case ' ': + if (pp->p_flags & F_REAL) + goto def; + pp->p_flags |= F_REAL; + ch = pp->p_ch = PASSAGE; + /* FALLTHROUGH */ + + case PASSAGE: +pass: + if (!(pp->p_flags & F_REAL)) + pp->p_ch = PASSAGE; + pp->p_flags |= (F_SEEN|F_REAL); + ch = PASSAGE; + break; + + case FLOOR: + if (pp->p_flags & F_REAL) + ch = ' '; + else + { + ch = TRAP; + pp->p_ch = TRAP; + pp->p_flags |= (F_SEEN|F_REAL); + } + break; + + default: +def: + if (pp->p_flags & F_PASS) + goto pass; + ch = ' '; + break; + } + if (ch != ' ') + { + if ((obj = pp->p_monst) != NULL) + obj->t_oldch = ch; + if (obj == NULL || !on(Player, SEEMONST)) + mvaddch(y, x, ch); + } + } + when S_FDET: + /* + * Potion of gold detection + */ + ch = FALSE; + wclear(Hw); + for (obj = Lvl_obj; obj != NULL; obj = next(obj)) + if (obj->o_type == FOOD) + { + ch = TRUE; + wmove(Hw, obj->o_pos.y, obj->o_pos.x); + waddch(Hw, FOOD); + } + if (ch) + { + Scr_info[S_FDET].oi_know = TRUE; + show_win("Your nose tingles and you smell food.--More--"); + } + else + msg("your nose tingles"); + when S_TELEP: + /* + * Scroll of teleportation: + * Make him dissapear and reappear + */ + { + cur_room = Proom; + teleport(); + if (cur_room != Proom) + Scr_info[S_TELEP].oi_know = TRUE; + } + when S_ENCH: + if (Cur_weapon == NULL || Cur_weapon->o_type != WEAPON) + msg("you feel a strange sense of loss"); + else + { + Cur_weapon->o_flags &= ~ISCURSED; + if (rnd(2) == 0) + Cur_weapon->o_hplus++; + else + Cur_weapon->o_dplus++; + msg("your %s glows %s for a moment", + Weap_info[Cur_weapon->o_which].oi_name, pick_color("blue")); + } + when S_SCARE: + /* + * Reading it is a mistake and produces laughter at her + * poor boo boo. + */ + msg("you hear maniacal laughter in the distance"); + when S_REMOVE: + uncurse(Cur_armor); + uncurse(Cur_weapon); + uncurse(Cur_ring[LEFT]); + uncurse(Cur_ring[RIGHT]); + msg(choose_str("you feel in touch with the Universal Onenes", + "you feel as if somebody is watching over you")); + when S_AGGR: + /* + * This scroll aggravates all the monsters on the current + * level and sets them running towards the hero + */ + aggravate(); + msg("you hear a high pitched humming noise"); + when S_PROTECT: + if (Cur_armor != NULL) + { + Cur_armor->o_flags |= ISPROT; + msg("your armor is covered by a shimmering %s shield", + pick_color("gold")); + } + else + msg("you feel a strange sense of loss"); +#ifdef MASTER + otherwise: + msg("what a puzzling scroll!"); + return; +#endif + } + obj = orig_obj; + look(TRUE); /* put the result of the scroll on the screen */ + status(); + + call_it(&Scr_info[obj->o_which]); + + if (discardit) + discard(obj); +} + +/* + * uncurse: + * Uncurse an item + */ +void +uncurse(THING *obj) +{ + if (obj != NULL) + obj->o_flags &= ~ISCURSED; +} diff --git a/edit.c b/edit.c new file mode 100644 index 0000000..ccb5a4c --- /dev/null +++ b/edit.c @@ -0,0 +1,577 @@ +/* + * All sorts of miscellaneous routines + * + * @(#)edit.c 4.66 (Berkeley) 08/06/83 + */ + +#include +#include "netprot.h" +#include + +/* + * look: + * A quick glance all around the player + */ +# undef DEBUG + +void +look(bool wakeup) +{ + int x, y; + int ch; + THING *tp; + PLACE *pp; + struct room *rp; + int ey, ex; + int passcount; + char pfl, *fp, pch; + int sy, sx, sumhero, diffhero; +# ifdef DEBUG + static bool done = FALSE; + + if (done) + return; + done = TRUE; +# endif DEBUG + passcount = 0; + rp = Proom; + if (!ce(Oldpos, Hero)) + { + erase_lamp(&Oldpos, Oldrp); + Oldpos = Hero; + Oldrp = rp; + } + ey = Hero.y + 1; + ex = Hero.x + 1; + sx = Hero.x - 1; + sy = Hero.y - 1; + if (Door_stop && !Firstmove && Running) + { + sumhero = Hero.y + Hero.x; + diffhero = Hero.y - Hero.x; + } + pp = INDEX(Hero.y, Hero.x); + pch = pp->p_ch; + pfl = pp->p_flags; + + for (y = sy; y <= ey; y++) + if (y > 0 && y < NUMLINES - 1) for (x = sx; x <= ex; x++) + { + if (x < 0 || x >= NUMCOLS) + continue; + if (!on(Player, ISBLIND)) + { + if (y == Hero.y && x == Hero.x) + continue; + } + + pp = INDEX(y, x); + ch = pp->p_ch; + if (ch == ' ') /* nothing need be done with a ' ' */ + continue; + fp = &pp->p_flags; + if (pch != DOOR && ch != DOOR) + if ((pfl & F_PASS) != (*fp & F_PASS)) + continue; + if (((*fp & F_PASS) || ch == DOOR) && + ((pfl & F_PASS) || pch == DOOR)) + { + if (Hero.x != x && Hero.y != y && + !step_ok(chat(y, Hero.x)) && !step_ok(chat(Hero.y, x))) + continue; + } + + if ((tp = pp->p_monst) == NULL) + ch = trip_ch(y, x, ch); + else + if (on(Player, SEEMONST) && on(*tp, ISINVIS)) + { + if (Door_stop && !Firstmove) + Running = FALSE; + continue; + } + else + { + if (wakeup) + wake_monster(y, x); + if (see_monst(tp)) + if (on(Player, ISHALU)) + ch = rnd(26) + 'A'; + else + ch = tp->t_disguise; + } + if (on(Player, ISBLIND) && (y != Hero.y || x != Hero.x)) + continue; + + move(y, x); + + if ((Proom->r_flags & ISDARK) && !See_floor && ch == FLOOR) + ch = ' '; + + if (tp != NULL || ch != inch()) + addch(ch); + + if (Door_stop && !Firstmove && Running) + { + switch (Runch) + { + when 'h': + if (x == ex) + continue; + when 'j': + if (y == sy) + continue; + when 'k': + if (y == ey) + continue; + when 'l': + if (x == sx) + continue; + when 'y': + if ((y + x) - sumhero >= 1) + continue; + when 'u': + if ((y - x) - diffhero >= 1) + continue; + when 'n': + if ((y + x) - sumhero <= -1) + continue; + when 'b': + if ((y - x) - diffhero <= -1) + continue; + } + switch (ch) + { + case DOOR: + if (x == Hero.x || y == Hero.y) + Running = FALSE; + break; + case PASSAGE: + if (x == Hero.x || y == Hero.y) + passcount++; + break; + case FLOOR: + case '|': + case '-': + case ' ': + break; + default: + Running = FALSE; + break; + } + } + } + if (Door_stop && !Firstmove && passcount > 1) + Running = FALSE; + if (!Running || !Jump) + mvaddch(Hero.y, Hero.x, PLAYER); +# ifdef DEBUG + done = FALSE; +# endif DEBUG +} + +/* + * trip_ch: + * Return the character appropriate for this space, taking into + * account whether or not the player is tripping. + */ +int +trip_ch(int y, int x, char ch) +{ + if (on(Player, ISHALU) && After) + switch (ch) + { + case FLOOR: + case ' ': + case PASSAGE: + case '-': + case '|': + case DOOR: + case TRAP: + break; + default: + if (y != Stairs.y || x != Stairs.x || !Seenstairs) + ch = rnd_thing(); + break; + } + return ch; +} + +/* + * erase_lamp: + * Erase the area shown by a lamp in a dark room. + */ +void +erase_lamp(coord *pos, struct room *rp) +{ + int y, x, ey, sy, ex; + + if (!(See_floor && (rp->r_flags & (ISGONE|ISDARK)) == ISDARK + && !on(Player,ISBLIND))) + return; + + ey = pos->y + 1; + ex = pos->x + 1; + sy = pos->y - 1; + for (x = pos->x - 1; x <= ex; x++) + for (y = sy; y <= ey; y++) + { + if (y == Hero.y && x == Hero.x) + continue; + move(y, x); + if (inch() == FLOOR) + addch(' '); + } +} + +/* + * show_floor: + * Should we show the floor in her room at this time? + */ +bool +show_floor(void) +{ + if ((Proom->r_flags & (ISGONE|ISDARK)) == ISDARK && !on(Player, ISBLIND)) + return See_floor; + else + return TRUE; +} + +/* + * find_obj: + * Find the unclaimed object at y, x + */ +THING * +find_obj(int y, int x) +{ + THING *obj; + + for (obj = Lvl_obj; obj != NULL; obj = next(obj)) + { + if (obj->o_pos.y == y && obj->o_pos.x == x) + return obj; + } +#ifdef MASTER + msg(sprintf(Prbuf, "Non-object %d,%d", y, x)); + return NULL; +#else + /* NOTREACHED */ +#endif +} + +/* + * eat: + * She wants to eat something, so let her try + */ +void +eat(void) +{ + THING *obj; + + if ((obj = get_item("eat", FOOD)) == NULL) + return; + if (obj->o_type != FOOD) + { + if (!Terse) + msg("ugh, you would get ill if you ate that"); + else + msg("that's Inedible!"); + return; + } + if (Food_left < 0) + Food_left = 0; + if ((Food_left += HUNGERTIME - 200 + rnd(400)) > STOMACHSIZE) + Food_left = STOMACHSIZE; + Hungry_state = 0; + if (obj == Cur_weapon) + Cur_weapon = NULL; + leave_pack(obj, FALSE, FALSE); + if (obj->o_which == 1) + msg("my, that was a yummy %s", Fruit); + else + if (rnd(100) > 70) + { + Pstats.s_exp++; + msg("%s, this food tastes awful", choose_str("bummer", "yuk")); + check_level(); + } + else + msg("%s, that tasted good", choose_str("oh, wow", "yum")); +} + +/* + * check_level: + * Check to see if the guy has gone up a level. + */ +void +check_level(void) +{ + int i, add, olevel; + + for (i = 0; E_levels[i] != 0; i++) + if (E_levels[i] > Pstats.s_exp) + break; + i++; + olevel = Pstats.s_lvl; + Pstats.s_lvl = i; + if (i > olevel) + { + add = roll(i - olevel, 10); + Max_hp += add; + Pstats.s_hpt += add; + msg("welcome to level %d", i); + } +} + +/* + * chg_str: + * Used to modify the playes strength. It keeps track of the + * highest it has been, just in case + */ +void +chg_str(int amt) +{ + auto str_t comp; + + if (amt == 0) + return; + add_str(&Pstats.s_str, amt); + comp = Pstats.s_str; + if (ISRING(LEFT, R_ADDSTR)) + add_str(&comp, -Cur_ring[LEFT]->o_arm); + if (ISRING(RIGHT, R_ADDSTR)) + add_str(&comp, -Cur_ring[RIGHT]->o_arm); + if (comp > Max_stats.s_str) + Max_stats.s_str = comp; +} + +/* + * add_str: + * Perform the actual add, checking upper and lower bound limits + */ +add_str(str_t *sp, int amt) +{ + if ((*sp += amt) < 3) + *sp = 3; + else if (*sp > 31) + *sp = 31; +} + +/* + * add_haste: + * Add a haste to the player + */ +bool +add_haste(bool potion) +{ + if (on(Player, ISHASTE)) + { + No_command += rnd(8); + Player.t_flags &= ~(ISRUN|ISHASTE); + extinguish(nohaste); + msg("you faint from exhaustion"); + return FALSE; + } + else + { + Player.t_flags |= ISHASTE; + if (potion) + fuse(nohaste, 0, rnd(4)+4, AFTER); + return TRUE; + } +} + +/* + * aggravate: + * Aggravate all the monsters on this level + */ +void +aggravate(void) +{ + THING *mp; + + for (mp = Mlist; mp != NULL; mp = next(mp)) + runto(&mp->t_pos); +} + +/* + * vowelstr: + * For printfs: if string starts with a vowel, return "n" for an + * "an". + */ +char * +vowelstr(char *str) +{ + switch (*str) + { + case 'a': case 'A': + case 'e': case 'E': + case 'i': case 'I': + case 'o': case 'O': + case 'u': case 'U': + return "n"; + default: + return ""; + } +} + +/* + * is_current: + * See if the object is one of the currently used items + */ +bool +is_current(THING *obj) +{ + if (obj == NULL) + return FALSE; + if (obj == Cur_armor || obj == Cur_weapon || obj == Cur_ring[LEFT] + || obj == Cur_ring[RIGHT]) + { + if (!Terse) + addmsg("That's already "); + msg("in use"); + return TRUE; + } + return FALSE; +} + +/* + * get_dir: + * Set up the direction co_ordinate for use in varios "prefix" + * commands + */ +bool +get_dir(void) +{ + char *prompt; + bool gotit; + static coord last_delt; + + if (Again && Last_dir != '\0') + { + Delta.y = last_delt.y; + Delta.x = last_delt.x; + Dir_ch = Last_dir; + } + else + { + if (!Terse) + msg(prompt = "which direction? "); + else + prompt = "direction: "; + do + { + gotit = TRUE; + switch (Dir_ch = readchar()) + { + when 'h': case'H': Delta.y = 0; Delta.x = -1; + when 'j': case'J': Delta.y = 1; Delta.x = 0; + when 'k': case'K': Delta.y = -1; Delta.x = 0; + when 'l': case'L': Delta.y = 0; Delta.x = 1; + when 'y': case'Y': Delta.y = -1; Delta.x = -1; + when 'u': case'U': Delta.y = -1; Delta.x = 1; + when 'b': case'B': Delta.y = 1; Delta.x = -1; + when 'n': case'N': Delta.y = 1; Delta.x = 1; + when ESCAPE: Last_dir = '\0'; reset_last(); return FALSE; + otherwise: + Mpos = 0; + msg(prompt); + gotit = FALSE; + } + } until (gotit); + if (isupper(Dir_ch)) + Dir_ch = tolower(Dir_ch); + Last_dir = Dir_ch; + last_delt.y = Delta.y; + last_delt.x = Delta.x; + } + if (on(Player, ISHUH) && rnd(5) == 0) + do + { + Delta.y = rnd(3) - 1; + Delta.x = rnd(3) - 1; + } while (Delta.y == 0 && Delta.x == 0); + Mpos = 0; + return TRUE; +} + +/* + * sign: + * Return the sign of the number + */ +int +sign(int nm) +{ + if (nm < 0) + return -1; + else + return (nm > 0); +} + +/* + * spread: + * Give a spread around a given number (+/- 20%) + */ +int +spread(int nm) +{ + return nm - nm / 20 + rnd(nm / 10); +} + +/* + * call_it: + * Call an object something after use. + */ +void +call_it(struct obj_info *info) +{ + if (info->oi_know) + { + if (info->oi_guess) + { + free(info->oi_guess); + info->oi_guess = NULL; + } + } + else if (!info->oi_guess) + { + msg(Terse ? "call it: " : "what do you want to call it? "); + if (get_str(Prbuf, stdscr) == NORM) + { + if (info->oi_guess != NULL) + free(info->oi_guess); + info->oi_guess = malloc((unsigned int) strlen(Prbuf) + 1); + strcpy(info->oi_guess, Prbuf); + } + } +} + +/* + * rnd_thing: + * Pick a random thing appropriate for this level + */ +int +rnd_thing(void) +{ + int i; + static char thing_list[] = { + POTION, SCROLL, RING, STICK, FOOD, WEAPON, ARMOR, STAIRS, GOLD, AMULET + }; + + if (Level >= AMULETLEVEL) + i = rnd(sizeof thing_list / sizeof (char)); + else + i = rnd(sizeof thing_list / sizeof (char) - 1); + return thing_list[i]; +} + +/* + str str: + * Choose the first or second string depending on whether it the + * player is tripping + */ +char * +choose_str(char *ts, char *ns) +{ + return (on(Player, ISHALU) ? ts : ns); +} diff --git a/error.c b/error.c new file mode 100644 index 0000000..33d7f57 --- /dev/null +++ b/error.c @@ -0,0 +1,102 @@ +/* + * Functions for dealing with linked lists of goodies + * + * @(#)error.c 4.12 (Berkeley) 02/05/99 + */ + +#include +#include "netprot.h" + +#ifdef MASTER +static int Total = 0; /* Total dynamic memory bytes */ +#endif + +/* + * detach: + * Takes an item out of whatever linked list it might be in + */ +void +_detach(THING **list, THING *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 + */ +void +_attach(THING **list, THING *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; +} + +/* + * _free_list: + * Throw the whole blamed thing away + */ +void +_free_list(THING **ptr) +{ + THING *item; + + while (*ptr != NULL) + { + item = *ptr; + *ptr = next(item); + discard(item); + } +} + +/* + * discard: + * Free up an item + */ +void +discard(THING *item) +{ +#ifdef MASTER + Total--; +#endif + free((char *) item); +} + +/* + * new_item + * Get a new item with a specified size + */ +THING * +new_item(void) +{ + THING *item; + +#ifdef MASTER + if ((item = calloc(1, sizeof *item)) == NULL) + msg("ran out of memory after %d items", Total); + else + Total++; +#else + item = calloc(1, sizeof *item); +#endif + item->l_next = NULL; + item->l_prev = NULL; + return item; +} diff --git a/ether.c b/ether.c new file mode 100644 index 0000000..bc3ad65 --- /dev/null +++ b/ether.c @@ -0,0 +1,365 @@ +/* + * Function(s) for dealing with potions + * + * @(#)ether.c 4.46 (Berkeley) 06/07/83 + */ + +#include +#include +#include "netprot.h" + +typedef struct +{ + int pa_flags; + void (*pa_daemon)(void); + int pa_time; + char *pa_high, *pa_straight; +} PACT; + +static PACT P_actions[] = +{ + { ISHUH, unconfuse, HUHDURATION, /* P_CONFUSE */ + "what a tripy feeling!", + "wait, what's going on here. Huh? What? Who?" }, + { ISHALU, come_down, SEEDURATION, /* P_LSD */ + "Oh, wow! Everything seems so cosmic!", + "Oh, wow! Everything seems so cosmic!" }, + { 0, NULL, 0 }, /* P_POISON */ + { 0, NULL, 0 }, /* P_STRENGTH */ + { CANSEE, unsee, SEEDURATION, /* P_SEEINVIS */ + Prbuf, + Prbuf }, + { 0, NULL, 0 }, /* P_HEALING */ + { 0, NULL, 0 }, /* P_MFIND */ + { 0, NULL, 0 }, /* P_TFIND */ + { 0, NULL, 0 }, /* P_RAISE */ + { 0, NULL, 0 }, /* P_XHEAL */ + { 0, NULL, 0 }, /* P_HASTE */ + { 0, NULL, 0 }, /* P_RESTORE */ + { ISBLIND, sight, SEEDURATION, /* P_BLIND */ + "oh, bummer! Everything is dark! Help!", + "a cloak of darkness falls around you" }, + { ISLEVIT, land, HEALTIME, /* P_LEVIT */ + "oh, wow! You're floating in the air!", + "you start to float in the air" } +}; + +/* + * quaff: + * Quaff a potion from the pack + */ +void +quaff(void) +{ + THING *obj, *tp, *mp; + bool discardit = FALSE; + bool show, trip; + + obj = get_item("quaff", POTION); + /* + * Make certain that it is somethings that we want to drink + */ + if (obj == NULL) + return; + if (obj->o_type != POTION) + { + if (!Terse) + msg("yuk! Why would you want to drink that?"); + else + msg("that's undrinkable"); + return; + } + if (obj == Cur_weapon) + Cur_weapon = NULL; + + /* + * Calculate the effect it has on the poor guy. + */ + trip = on(Player, ISHALU); + discardit = (obj->o_count == 1); + leave_pack(obj, FALSE, FALSE); + switch (obj->o_which) + { + when P_CONFUSE: + do_pot(P_CONFUSE, !trip); + when P_POISON: + Pot_info[P_POISON].oi_know = TRUE; + if (ISWEARING(R_SUSTSTR)) + msg("you feel momentarily sick"); + else + { + chg_str(-(rnd(3) + 1)); + msg("you feel very sick now"); + come_down(); + } + when P_HEALING: + Pot_info[P_HEALING].oi_know = TRUE; + if ((Pstats.s_hpt += roll(Pstats.s_lvl, 4)) > Max_hp) + Pstats.s_hpt = ++Max_hp; + sight(); + msg("you begin to feel better"); + when P_STRENGTH: + Pot_info[P_STRENGTH].oi_know = TRUE; + chg_str(1); + msg("you feel stronger, now. What bulging muscles!"); + when P_MFIND: + Player.t_flags |= SEEMONST; + fuse(turn_see, TRUE, HUHDURATION, AFTER); + if (!turn_see(FALSE)) + msg("you have a %s feeling for a moment, then it passes", + choose_str("normal", "strange")); + when P_TFIND: + /* + * Potion of magic detection. Show the potions and scrolls + */ + show = FALSE; + if (Lvl_obj != NULL) + { + wclear(Hw); + for (tp = Lvl_obj; tp != NULL; tp = next(tp)) + { + if (is_magic(tp)) + { + show = TRUE; + wmove(Hw, tp->o_pos.y, tp->o_pos.x); + waddch(Hw, MAGIC); + Pot_info[P_TFIND].oi_know = TRUE; + } + } + for (mp = Mlist; mp != NULL; mp = next(mp)) + { + for (tp = mp->t_pack; tp != NULL; tp = next(tp)) + { + if (is_magic(tp)) + { + show = TRUE; + wmove(Hw, mp->t_pos.y, mp->t_pos.x); + waddch(Hw, MAGIC); + } + } + } + } + if (show) + { + Pot_info[P_TFIND].oi_know = TRUE; + show_win("You sense the presence of magic on this level.--More--"); + } + else + msg("you have a %s feeling for a moment, then it passes", + choose_str("normal", "strange")); + when P_LSD: + if (!trip) + { + if (on(Player, SEEMONST)) + turn_see(FALSE); + start_daemon(visuals, 0, BEFORE); + Seenstairs = seen_stairs(); + } + do_pot(P_LSD, TRUE); + when P_SEEINVIS: + sprintf(Prbuf, "this potion tastes like %s juice", Fruit); + show = on(Player, CANSEE); + do_pot(P_SEEINVIS, FALSE); + if (!show) + invis_on(); + sight(); + when P_RAISE: + Pot_info[P_RAISE].oi_know = TRUE; + msg("you suddenly feel much more skillful"); + raise_level(); + when P_XHEAL: + Pot_info[P_XHEAL].oi_know = TRUE; + if ((Pstats.s_hpt += roll(Pstats.s_lvl, 8)) > Max_hp) + { + if (Pstats.s_hpt > Max_hp + Pstats.s_lvl + 1) + ++Max_hp; + Pstats.s_hpt = ++Max_hp; + } + sight(); + come_down(); + msg("you begin to feel much better"); + when P_HASTE: + Pot_info[P_HASTE].oi_know = TRUE; + After = FALSE; + if (add_haste(TRUE)) + msg("you feel yourself moving much faster"); + when P_RESTORE: + if (ISRING(LEFT, R_ADDSTR)) + add_str(&Pstats.s_str, -Cur_ring[LEFT]->o_arm); + if (ISRING(RIGHT, R_ADDSTR)) + add_str(&Pstats.s_str, -Cur_ring[RIGHT]->o_arm); + if (Pstats.s_str < Max_stats.s_str) + Pstats.s_str = Max_stats.s_str; + if (ISRING(LEFT, R_ADDSTR)) + add_str(&Pstats.s_str, Cur_ring[LEFT]->o_arm); + if (ISRING(RIGHT, R_ADDSTR)) + add_str(&Pstats.s_str, Cur_ring[RIGHT]->o_arm); + msg("hey, this tastes great. It make you feel warm all over"); + when P_BLIND: + do_pot(P_BLIND, TRUE); + when P_LEVIT: + do_pot(P_LEVIT, TRUE); +#ifdef MASTER + otherwise: + msg("what an odd tasting potion!"); + return; +#endif + } + status(); + /* + * Throw the item away + */ + + call_it(&Pot_info[obj->o_which]); + + if (discardit) + discard(obj); + return; +} + +/* + * is_magic: + * Returns true if an object radiates magic + */ +bool +is_magic(THING *obj) +{ + switch (obj->o_type) + { + case ARMOR: + return (obj->o_flags&ISPROT) || obj->o_arm != A_class[obj->o_which]; + case WEAPON: + return obj->o_hplus != 0 || obj->o_dplus != 0; + case POTION: + case SCROLL: + case STICK: + case RING: + case AMULET: + return TRUE; + } + return FALSE; +} + +/* + * invis_on: + * Turn on the ability to see invisible + */ +void +invis_on(void) +{ + THING *mp; + + Player.t_flags |= CANSEE; + for (mp = Mlist; mp != NULL; mp = next(mp)) + if (on(*mp, ISINVIS) && see_monst(mp) && !on(Player, ISHALU)) + mvaddch(mp->t_pos.y, mp->t_pos.x, mp->t_disguise); +} + +/* + * turn_see: + * Put on or off seeing monsters on this level + */ +bool +turn_see(bool turn_off) +{ + THING *mp; + bool can_see, add_new; + + add_new = FALSE; + for (mp = Mlist; mp != NULL; mp = next(mp)) + { + move(mp->t_pos.y, mp->t_pos.x); + can_see = see_monst(mp); + if (turn_off) + { + if (!can_see) + addch(mp->t_oldch); + } + else + { + if (!can_see) + standout(); + if (!on(Player, ISHALU)) + addch(mp->t_type); + else + addch(rnd(26) + 'A'); + if (!can_see) + { + standend(); + add_new++; + } + } + } + if (turn_off) + Player.t_flags &= ~SEEMONST; + else + Player.t_flags |= SEEMONST; + return add_new; +} + +/* + * seen_stairs: + * Return TRUE if the player has seen the stairs + */ +bool +seen_stairs(void) +{ + THING *tp; + + move(Stairs.y, Stairs.x); + if (inch() == STAIRS) /* it's on the map */ + return TRUE; + if (ce(Hero, Stairs)) /* It's under him */ + return TRUE; + + /* + * if a monster is on the stairs, this gets hairy + */ + if ((tp = moat(Stairs.y, Stairs.x)) != NULL) + { + if (see_monst(tp) && on(*tp, ISRUN)) /* if it's visible and awake */ + return TRUE; /* it must have moved there */ + + if (on(Player, SEEMONST) /* if she can detect monster */ + && tp->t_oldch == STAIRS) /* and there once were stairs */ + return TRUE; /* it must have moved there */ + } + return FALSE; +} + +/* + * raise_level: + * The guy just magically went up a level. + */ +void +raise_level(void) +{ + Pstats.s_exp = E_levels[Pstats.s_lvl-1] + 1L; + check_level(); +} + +/* + * do_pot: + * Do a potion with standard setup. This means it uses a fuse and + * turns on a flag + */ +void +do_pot(int type, bool knowit) +{ + PACT *pp; + int t; + + pp = &P_actions[type]; + if (!Pot_info[type].oi_know) + Pot_info[type].oi_know = knowit; + t = spread(pp->pa_time); + if (!on(Player, pp->pa_flags)) + { + Player.t_flags |= pp->pa_flags; + fuse(pp->pa_daemon, 0, t, AFTER); + look(FALSE); + } + else + lengthen(pp->pa_daemon, t); + msg(choose_str(pp->pa_high, pp->pa_straight)); +} diff --git a/find.c b/find.c new file mode 100644 index 0000000..3673daa --- /dev/null +++ b/find.c @@ -0,0 +1,480 @@ +/* + * Various installation dependent routines + * + * @(#)find.c 4.37 (Berkeley) 05/23/83 + */ + +/* + * The various tuneable defines are: + * + * SCOREFILE Where/if the score file should live. + * ALLSCORES Score file is top ten scores, not top ten + * players. This is only useful when only a few + * people will be playing; otherwise the score file + * gets hogged by just a few people. + * NUMSCORES Number of scores in the score file (default 10). + * NUMNAME String version of NUMSCORES (first character + * should be capitalized) (default "Ten"). + * MAXLOAD What (if any) the maximum load average should be + * when people are playing. Since it is divided + * by 10, to specify a load limit of 4.0, MAXLOAD + * should be "40". If defined, then + * LOADAV Should it use it's own routine to get + * the load average? + * NAMELIST If so, where does the system namelist + * hide? + * MAXUSERS What (if any) the maximum user count should be + * when people are playing. If defined, then + * UCOUNT Should it use it's own routine to count + * users? + * UTMP If so, where does the user list hide? + * CHECKTIME How often/if it should check during the game + * for high load average. + */ + +#include +#include "network.h" +#include +#include +#include +#include + +#include + +#ifdef SCOREFILE + +static char *Lockfile = "/tmp/.fredlock"; + +# ifndef NUMSCORES +# define NUMSCORES 10 +# define NUMNAME "Ten" +# endif + +unsigned int numscores = NUMSCORES; +char *Numname = NUMNAME; + +# ifdef ALLSCORES +bool Allscore = TRUE; +# else ALLSCORES +bool Allscore = FALSE; +# endif ALLSCORES + +#endif SCOREFILE + +#ifdef CHECKTIME +static int Num_checks; /* times we've gone over in checkout() */ +#endif CHECKTIME + +/* + * init_check: + * Check out too see if it is proper to play the game now + */ +void +init_check(void) +{ +#if defined(MAXLOAD) || defined(MAXUSERS) + if (too_much()) + { + printf("Sorry, %s, but the system is too loaded now.\n", Whoami); + printf("Try again later. Meanwhile, why not enjoy a%s %s?\n", + vowelstr(Fruit), Fruit); + if (author()) + printf("However, since you're a good guy, it's up to you\n"); + else + exit(1); + } +#endif +} + +/* + * open_score: + * Open up the score file for future use, and then + * setuid(getuid()) in case we are running setuid. + */ +void +open_score(void) +{ +#ifdef SCOREFILE + Fd = open(SCOREFILE, O_RDWR); +#else + Fd = -1; +#endif + setuid(getuid()); + setgid(getgid()); +} + +/* + * setup: + * Get starting setup for all games + */ +void +setup(void) +{ +#ifdef CHECKTIME + int checkout(); +#endif + + signal(SIGHUP, auto_save); +#ifndef DUMP + signal(SIGILL, auto_save); + signal(SIGTRAP, auto_save); + signal(SIGIOT, auto_save); + signal(SIGEMT, auto_save); + signal(SIGFPE, auto_save); + signal(SIGBUS, auto_save); + signal(SIGSEGV, auto_save); + signal(SIGSYS, auto_save); + signal(SIGTERM, auto_save); +#endif + + signal(SIGINT, quit); +#ifndef DUMP + signal(SIGQUIT, endit); +#endif +#ifdef CHECKTIME + signal(SIGALRM, checkout); + alarm(CHECKTIME * 60); + Num_checks = 0; +#endif + crmode(); /* Cbreak mode */ + noecho(); /* Echo off */ +#ifdef TIOCGLTC + getltchars(); /* get the local tty chars */ +#endif +} + +/* + * getltchars: + * Get the local tty chars for later use + */ +void +getltchars(void) +{ +#ifdef TIOCGLTC + ioctl(1, TIOCGLTC, &Ltc); + Got_ltc = TRUE; + Orig_dsusp = Ltc.t_dsuspc; + Ltc.t_dsuspc = Ltc.t_suspc; + ioctl(1, TIOCSLTC, &Ltc); +#endif +} + +/* + * resetltchars: + * Reset the local tty chars to original values. + */ +void +resetltchars(void) +{ +#ifdef TIOCGLTC + if (Got_ltc) { + Ltc.t_dsuspc = Orig_dsusp; + ioctl(1, TIOCSLTC, &Ltc); + } +#endif +} + +/* + * playltchars: + * Set local tty chars to the values we use when playing. + */ +void +playltchars(void) +{ +#ifdef TIOCGLTC + if (Got_ltc) { + Ltc.t_dsuspc = Ltc.t_suspc; + ioctl(1, TIOCSLTC, &Ltc); + } +#endif +} + +/* + * start_score: + * Start the scoring sequence + */ +void +start_score(void) +{ +#ifdef CHECKTIME + signal(SIGALRM, SIG_IGN); +#endif +} + +/* + * is_symlink: + * See if the file has a symbolic link + */ +bool +is_symlink(char *sp) +{ +#ifdef S_IFLNK + struct stat sbuf2; + + if (lstat(sp, &sbuf2) < 0) + return FALSE; + else + return ((sbuf2.st_mode & S_IFMT) != S_IFREG); +#else + return FALSE; +#endif +} + +#if defined(MAXLOAD) || defined(MAXUSERS) +/* + * too_much: + * See if the system is being used too much for this game + */ +bool +too_much(void) +{ +#ifdef MAXLOAD + double avec[3]; +#else + int cnt; +#endif + +#ifdef MAXLOAD + loadav(avec); + if (avec[1] > (MAXLOAD / 10.0)) + return TRUE; +#endif +#ifdef MAXUSERS + if (ucount() > MAXUSERS) + return TRUE; +#endif + return FALSE; +} + +/* + * author: + * See if a user is an author of the program + */ +bool +author(void) +{ +#ifdef MASTER + if (Wizard) + return TRUE; +#endif + switch (getuid()) + { + case -1: + return TRUE; + default: + return FALSE; + } +} +#endif + +#ifdef CHECKTIME +/* + * checkout: + * Check each CHECKTIME seconds to see if the load is too high + */ +void +checkout(int sig) +{ + static char *msgs[] = { + "The load is too high to be playing. Please leave in %0.1f minutes", + "Please save your game. You have %0.1f minutes", + "Last warning. You have %0.1f minutes to leave", + }; + int checktime; + + signal(SIGALRM, checkout); + if (too_much()) + { + if (author()) + { + Num_checks = 1; + chmsg("The load is rather high, O exaulted one"); + } + else if (Num_checks++ == 3) + fatal("Sorry. You took too long. You are dead\n"); + checktime = (CHECKTIME * 60) / Num_checks; + alarm(checktime); + chmsg(msgs[Num_checks - 1], ((double) checktime / 60.0)); + } + else + { + if (Num_checks) + { + Num_checks = 0; + chmsg("The load has dropped back down. You have a reprieve"); + } + alarm(CHECKTIME * 60); + } +} + +/* + * chmsg: + * checkout()'s version of msg. If we are in the middle of a + * shell, do a printf instead of a msg to avoid the refresh. + */ +/* VARARGS1 */ +void +chmsg(char *fmt, int arg) +{ + if (!In_shell) + msg(fmt, arg); + else + { + printf(fmt, arg); + putchar('\n'); + fflush(stdout); + } +} +#endif + +#ifdef LOADAV +/* + * loadav: + * Looking up load average in core (for system where the loadav() + * system call isn't defined + */ + +#include + +struct nlist avenrun = { + "_avenrun" +}; + +void +loadav(double *avg) +{ + int kmem; + + if ((kmem = open("/dev/kmem", 0)) < 0) + goto bad; + nlist(NAMELIST, &avenrun); + if (avenrun.n_type == 0) + { + close(kmem); +bad: + avg[0] = 0.0; + avg[1] = 0.0; + avg[2] = 0.0; + return; + } + + lseek(kmem, (long) avenrun.n_value, 0); + read(kmem, (char *) avg, 3 * sizeof (double)); + close(kmem); +} +#endif + +#ifdef UCOUNT +/* + * ucount: + * Count number of users on the system + */ +#include + +struct utmp buf; + +int +ucount(void) +{ + struct utmp *up; + FILE *utmp; + int count; + + if ((utmp = fopen(UTMP, "r")) == NULL) + return 0; + + up = &buf; + count = 0; + + while (fread(up, 1, sizeof (*up), utmp) > 0) + if (buf.ut_name[0] != '\0') + count++; + fclose(utmp); + return count; +} +#endif + +/* + * lock_sc: + * lock the score file. If it takes too long, ask the user if + * they care to wait. Return TRUE if the lock is successful. + */ +bool +lock_sc(void) +{ +#ifdef SCOREFILE + int cnt; + static struct stat sbuf; + time_t time(); + +over: + close(8); /* just in case there are no files left */ + if (creat(Lockfile, 0000) >= 0) + return TRUE; + for (cnt = 0; cnt < 5; cnt++) + { + sleep(1); + if (creat(Lockfile, 0000) >= 0) + return TRUE; + } + if (stat(Lockfile, &sbuf) < 0) + { + creat(Lockfile, 0000); + return TRUE; + } + if (time(NULL) - sbuf.st_mtime > 10) + { + if (unlink(Lockfile) < 0) + return FALSE; + goto over; + } + else + { + printf("The score file is very busy. Do you want to wait longer\n"); + printf("for it to become free so your score can get posted?\n"); + printf("If so, type \"y\"\n"); + fgets(Prbuf, MAXSTR, stdin); + if (Prbuf[0] == 'y') + for (;;) + { + if (creat(Lockfile, 0000) >= 0) + return TRUE; + if (stat(Lockfile, &sbuf) < 0) + { + creat(Lockfile, 0000); + return TRUE; + } + if (time(NULL) - sbuf.st_mtime > 10) + { + if (unlink(Lockfile) < 0) + return FALSE; + } + sleep(1); + } + else + return FALSE; + } +#endif +} + +/* + * unlock_sc: + * Unlock the score file + */ +void +unlock_sc(void) +{ +#ifdef SCOREFILE + unlink(Lockfile); +#endif +} + +/* + * flush_type: + * Flush typeahead for traps, etc. + */ +void +flush_type(void) +{ + crmode(); +} diff --git a/handle.c b/handle.c new file mode 100644 index 0000000..1dc30e6 --- /dev/null +++ b/handle.c @@ -0,0 +1,220 @@ +#include +#include "netprot.h" + +#define TREAS_ROOM 20 /* one chance in TREAS_ROOM for a treasure room */ +#define MAXTREAS 10 /* maximum number of treasures in a treasure room */ +#define MINTREAS 2 /* minimum number of treasures in a treasure room */ + +/* + * new_level: + * Dig and draw a new level + * + * @(#)handle.c 4.38 (Berkeley) 02/05/99 + */ +void +new_level(void) +{ + THING *tp; + PLACE *pp; + char *sp; + int i; + + Player.t_flags &= ~ISHELD; /* unhold when you go down just in case */ + if (Level > Max_level) + Max_level = Level; + /* + * Clean things off from last level + */ + for (pp = Places; pp < &Places[MAXCOLS*MAXLINES]; pp++) + { + pp->p_ch = ' '; + pp->p_flags = F_REAL; + pp->p_monst = NULL; + } + clear(); + /* + * Free up the monsters on the last level + */ + for (tp = Mlist; tp != NULL; tp = next(tp)) + free_list(tp->t_pack); + free_list(Mlist); + /* + * Throw away stuff left on the previous level (if anything) + */ + free_list(Lvl_obj); + do_rooms(); /* Draw rooms */ + do_passages(); /* Draw passages */ + No_food++; + put_things(); /* Place objects (if any) */ + /* + * Place the traps + */ + if (rnd(10) < Level) + { + Ntraps = rnd(Level / 4) + 1; + if (Ntraps > MAXTRAPS) + Ntraps = MAXTRAPS; + i = Ntraps; + while (i--) + { + /* + * not only wouldn't it be NICE to have traps in mazes + * (not that we care about being nice), since the trap + * number is stored where the passage number is, we + * can't actually do it. + */ + do + { + find_floor((struct room *) NULL, &Stairs, FALSE, FALSE); + } while (chat(Stairs.y, Stairs.x) != FLOOR); + sp = &flat(Stairs.y, Stairs.x); + *sp &= ~F_REAL; + *sp |= rnd(NTRAPS); + } + } + /* + * Place the staircase down. + */ + find_floor((struct room *) NULL, &Stairs, FALSE, FALSE); + chat(Stairs.y, Stairs.x) = STAIRS; + Seenstairs = FALSE; + + for (tp = Mlist; tp != NULL; tp = next(tp)) + tp->t_room = roomin(&tp->t_pos); + + find_floor((struct room *) NULL, &Hero, FALSE, TRUE); + enter_room(&Hero); + mvaddch(Hero.y, Hero.x, PLAYER); + if (on(Player, SEEMONST)) + turn_see(FALSE); + if (on(Player, ISHALU)) + visuals(); +} + +/* + * rnd_room: + * Pick a room that is really there + */ +int +rnd_room(void) +{ + int rm; + + do + { + rm = rnd(MAXROOMS); + } while (Rooms[rm].r_flags & ISGONE); + return rm; +} + +/* + * put_things: + * Put potions and scrolls on this level + */ +void +put_things(void) +{ + int i; + THING *obj; + + /* + * Once you have found the amulet, the only way to get new stuff is + * go down into the dungeon. + */ + if (Amulet && Level < Max_level) + return; + /* + * check for treasure rooms, and if so, put it in. + */ + if (rnd(TREAS_ROOM) == 0) + treas_room(); + /* + * Do MAXOBJ attempts to put things on a level + */ + for (i = 0; i < MAXOBJ; i++) + if (rnd(100) < 36) + { + /* + * Pick a new object and link it in the list + */ + obj = new_thing(); + attach(Lvl_obj, obj); + /* + * Put it somewhere + */ + find_floor((struct room *) NULL, &obj->o_pos, FALSE, FALSE); + chat(obj->o_pos.y, obj->o_pos.x) = obj->o_type; + } + /* + * If he is really deep in the dungeon and he hasn't found the + * amulet yet, put it somewhere on the ground + */ + if (Level >= AMULETLEVEL && !Amulet) + { + obj = new_item(); + attach(Lvl_obj, obj); + obj->o_hplus = 0; + obj->o_dplus = 0; + obj->o_damage = obj->o_hurldmg = "0x0"; + obj->o_arm = 11; + obj->o_type = AMULET; + /* + * Put it somewhere + */ + find_floor((struct room *) NULL, &obj->o_pos, FALSE, FALSE); + chat(obj->o_pos.y, obj->o_pos.x) = AMULET; + } +} + +/* + * treas_room: + * Add a treasure room + */ +#define MAXTRIES 10 /* max number of tries to put down a monster */ + +void +treas_room(void) +{ + int nm; + THING *tp; + struct room *rp; + int spots, num_monst; + static coord mp; + + rp = &Rooms[rnd_room()]; + spots = (rp->r_max.y - 2) * (rp->r_max.x - 2) - MINTREAS; + if (spots > (MAXTREAS - MINTREAS)) + spots = (MAXTREAS - MINTREAS); + num_monst = nm = rnd(spots) + MINTREAS; + while (nm--) + { + find_floor(rp, &mp, 2 * MAXTRIES, FALSE); + tp = new_thing(); + tp->o_pos = mp; + attach(Lvl_obj, tp); + chat(mp.y, mp.x) = tp->o_type; + } + + /* + * fill up room with monsters from the next level down + */ + + if ((nm = rnd(spots) + MINTREAS) < num_monst + 2) + nm = num_monst + 2; + spots = (rp->r_max.y - 2) * (rp->r_max.x - 2); + if (nm > spots) + nm = spots; + Level++; + while (nm--) + { + spots = 0; + if (find_floor(rp, &mp, MAXTRIES, TRUE)) + { + tp = new_item(); + new_monster(tp, randmonster(FALSE), &mp); + tp->t_flags |= ISMEAN; /* no sloughers in THIS room */ + give_pack(tp); + } + } + Level--; +} diff --git a/inter.c b/inter.c new file mode 100644 index 0000000..8d3f683 --- /dev/null +++ b/inter.c @@ -0,0 +1,471 @@ +/* + * File for the fun ends + * Death or a total win + * + * @(#)inter.c 4.57 (Berkeley) 02/05/99 + */ + +#include +#ifdef attron +#include +#endif attron +#include +#include +#include +#include +#include +#include "netprot.h" +#include "netwait.h" + +#include + +#ifdef attron +int _putchar(char c); +# define _puts(s) tputs(s, 0, _putchar); +# define SO enter_standout_mode +# define SE exit_standout_mode +#endif + +static char *Rip[] = { +" __________\n", +" / \\\n", +" / REST \\\n", +" / IN \\\n", +" / PEACE \\\n", +" / \\\n", +" | |\n", +" | |\n", +" | killed by a |\n", +" | |\n", +" | 1980 |\n", +" *| * * * | *\n", +" ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______\n", + 0 +}; + +/* + * score: + * Figure score and post it. + */ +/* VARARGS2 */ +void +score(int amount, int flags, char monst) +{ + SCORE *scp; + int i; + SCORE *sc2; + SCORE *top_ten, *endp; + FILE *outf; +# ifdef MASTER + int prflags = 0; +# endif + void (*fp)(int); + int uid; + static char *reason[] = { + "killed", + "quit", + "A total winner", + "killed with Amulet" + }; + + start_score(); + + if (flags >= 0) + { + endwin(); + resetltchars(); + /* + * free up space to "guarantee" there is space for the top_ten + */ + delwin(stdscr); + delwin(curscr); + if (Hw != NULL) + delwin(Hw); + } + + if (Fd >= 0) + outf = fdopen(Fd, "w"); + else + return; + + top_ten = (SCORE *) malloc(numscores * sizeof (SCORE)); + endp = &top_ten[numscores]; + for (scp = top_ten; scp < endp; scp++) + { + scp->sc_score = 0; + for (i = 0; i < MAXSTR; i++) + scp->sc_name[i] = rnd(255); + scp->sc_flags = RN; + scp->sc_level = RN; + scp->sc_monster = RN; + scp->sc_uid = RN; + } + + signal(SIGINT, SIG_DFL); + if (flags >= 0 +#ifdef MASTER + || Wizard +#endif + ) + { + printf("[Press return to continue]"); + fflush(stdout); + fgets(Prbuf,10,stdin); + } +#ifdef MASTER + if (Wizard) + if (strcmp(Prbuf, "names") == 0) + prflags = 1; + else if (strcmp(Prbuf, "edit") == 0) + prflags = 2; +#endif + rd_score(top_ten, Fd); + fclose(outf); + close(Fd); + Fd = open(SCOREFILE, O_RDWR); + outf = fdopen(Fd, "w"); + /* + * Insert her in list if need be + */ + sc2 = NULL; + if (!Noscore) + { + uid = getuid(); + for (scp = top_ten; scp < endp; scp++) + if (amount > scp->sc_score) + break; + else if (!Allscore && /* only one score per nowin uid */ + flags != 2 && scp->sc_uid == uid && scp->sc_flags != 2) + scp = endp; + if (scp < endp) + { + if (flags != 2 && !Allscore) + { + for (sc2 = scp; sc2 < endp; sc2++) + { + if (sc2->sc_uid == uid && sc2->sc_flags != 2) + break; + } + if (sc2 >= endp) + sc2 = endp - 1; + } + else + sc2 = endp - 1; + while (sc2 > scp) + { + *sc2 = sc2[-1]; + sc2--; + } + scp->sc_score = amount; + strncpy(scp->sc_name, Whoami, MAXSTR); + scp->sc_flags = flags; + if (flags == 2) + scp->sc_level = Max_level; + else + scp->sc_level = Level; + scp->sc_monster = monst; + scp->sc_uid = uid; + sc2 = scp; + } + } + /* + * Print the list + */ + if (flags != -1) + putchar('\n'); + printf("Top %s %s:\n", Numname, Allscore ? "Scores" : "Rogueists"); + printf("Rank\tScore\tName\n"); + for (scp = top_ten; scp < endp; scp++) + { + if (scp->sc_score) { + if (sc2 == scp && SO) + _puts(SO); + printf("%d\t%d\t%s: %s on level %d", scp - top_ten + 1, + scp->sc_score, scp->sc_name, reason[scp->sc_flags], + scp->sc_level); + if (scp->sc_flags == 0 || scp->sc_flags == 3) + printf(" by %s", killname((char) scp->sc_monster, TRUE)); +# ifdef MASTER + if (prflags == 1) + { + struct passwd *pp, *getpwuid(); + + if ((pp = getpwuid(scp->sc_uid)) == NULL) + printf(" (%d)", scp->sc_uid); + else + printf(" (%s)", pp->pw_name); + putchar('\n'); + } + else if (prflags == 2) + { + fflush(stdout); + fgets(Prbuf,10,stdin); + if (Prbuf[0] == 'd') + { + for (sc2 = scp; sc2 < endp - 1; sc2++) + *sc2 = *(sc2 + 1); + sc2 = endp - 1; + sc2->sc_score = 0; + for (i = 0; i < MAXSTR; i++) + sc2->sc_name[i] = rnd(255); + sc2->sc_flags = RN; + sc2->sc_level = RN; + sc2->sc_monster = RN; + scp--; + } + } + else +# endif MASTER + printf(".\n"); + if (sc2 == scp && SE) + _puts(SE); + } + else + break; + } + fseek(outf, 0L, SEEK_SET); + /* + * Update the list file + */ + if (sc2 != NULL) + { + if (lock_sc()) + { + fp = signal(SIGINT, SIG_IGN); + wr_score(top_ten, outf); + unlock_sc(); + signal(SIGINT, fp); + } + } + fclose(outf); +} + +/* + * death: + * Do something really fun when he dies + */ +void +death(char monst) +{ + char **dp, *killer; + struct tm *lt; + static time_t date; + struct tm *localtime(); + + signal(SIGINT, SIG_IGN); + Purse -= Purse / 10; + signal(SIGINT, leave); + clear(); + killer = killname(monst, FALSE); + if (!Tombstone) + { + mvprintw(LINES - 2, 0, "Killed by "); + killer = killname(monst, FALSE); + if (monst != 's' && monst != 'h') + printw("a%s ", vowelstr(killer)); + printw("%s with %d gold", killer, Purse); + } + else + { + time(&date); + lt = localtime(&date); + move(8, 0); + dp = Rip; + while (*dp) + addstr(*dp++); + mvaddstr(17, center(killer), killer); + if (monst == 's' || monst == 'h') + mvaddch(16, 32, ' '); + else + mvaddstr(16, 33, vowelstr(killer)); + mvaddstr(14, center(Whoami), Whoami); + sprintf(Prbuf, "%d Au", Purse); + move(15, center(Prbuf)); + addstr(Prbuf); + sprintf(Prbuf, "%2d", lt->tm_year); + mvaddstr(18, 28, Prbuf); + } + move(LINES - 1, 0); + refresh(); + score(Purse, Amulet ? 3 : 0, monst); + my_exit(0); +} + +/* + * center: + * Return the index to center the given string + */ +int +center(char *str) +{ + return 28 - ((strlen(str) + 1) / 2); +} + +/* + * total_winner: + * Code for a winner + */ +void +total_winner(void) +{ + THING *obj; + struct obj_info *op; + int worth; + int oldpurse; + + clear(); + standout(); + addstr(" \n"); + addstr(" @ @ @ @ @ @@@ @ @ \n"); + addstr(" @ @ @@ @@ @ @ @ @ \n"); + addstr(" @ @ @@@ @ @ @ @ @ @@@ @@@@ @@@ @ @@@ @ \n"); + addstr(" @@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ \n"); + addstr(" @ @ @ @ @ @ @ @@@@ @ @ @@@@@ @ @ @ \n"); + addstr(" @ @ @ @ @ @@ @ @ @ @ @ @ @ @ @ @ \n"); + addstr(" @@@ @@@ @@ @ @ @ @@@@ @@@@ @@@ @@@ @@ @ \n"); + addstr(" \n"); + addstr(" Congratulations, you have made it to the light of day! \n"); + standend(); + addstr("\nYou have joined the elite ranks of those who have escaped the\n"); + addstr("Dungeons of Doom alive. You journey home and sell all your loot at\n"); + addstr("a great profit and are admitted to the Fighters' Guild.\n"); + mvaddstr(LINES - 1, 0, "--Press space to continue--"); + refresh(); + wait_for(' '); + clear(); + mvaddstr(0, 0, " Worth Item\n"); + oldpurse = Purse; + for (obj = Pack; obj != NULL; obj = next(obj)) + { + switch (obj->o_type) + { + when FOOD: + worth = 2 * obj->o_count; + when WEAPON: + worth = Weap_info[obj->o_which].oi_worth; + worth *= 3 * (obj->o_hplus + obj->o_dplus) + obj->o_count; + obj->o_flags |= ISKNOW; + when ARMOR: + worth = Arm_info[obj->o_which].oi_worth; + worth += (9 - obj->o_arm) * 100; + worth += (10 * (A_class[obj->o_which] - obj->o_arm)); + obj->o_flags |= ISKNOW; + when SCROLL: + worth = Scr_info[obj->o_which].oi_worth; + worth *= obj->o_count; + op = &Scr_info[obj->o_which]; + if (!op->oi_know) + worth /= 2; + op->oi_know = TRUE; + when POTION: + worth = Pot_info[obj->o_which].oi_worth; + worth *= obj->o_count; + op = &Pot_info[obj->o_which]; + if (!op->oi_know) + worth /= 2; + op->oi_know = TRUE; + when RING: + op = &Ring_info[obj->o_which]; + worth = op->oi_worth; + if (obj->o_which == R_ADDSTR || obj->o_which == R_ADDDAM || + obj->o_which == R_PROTECT || obj->o_which == R_ADDHIT) + if (obj->o_arm > 0) + worth += obj->o_arm * 100; + else + worth = 10; + if (!(obj->o_flags & ISKNOW)) + worth /= 2; + obj->o_flags |= ISKNOW; + op->oi_know = TRUE; + when STICK: + op = &Ws_info[obj->o_which]; + worth = op->oi_worth; + worth += 20 * obj->o_charges; + if (!(obj->o_flags & ISKNOW)) + worth /= 2; + obj->o_flags |= ISKNOW; + op->oi_know = TRUE; + when AMULET: + worth = 1000; + } + if (worth < 0) + worth = 0; + printw("%c) %5d %s\n", obj->o_packch, worth, inv_name(obj, FALSE)); + Purse += worth; + } + printw(" %5d Gold Pieces ", oldpurse); + refresh(); + score(Purse, 2, ' '); + my_exit(0); +} + +/* + * killname: + * Convert a code to a monster name + */ +char * +killname(char monst, bool doart) +{ + struct h_list *hp; + char *sp; + bool article; + static struct h_list nlist[] = { + 'a', "arrow", TRUE, + 'b', "bolt", TRUE, + 'd', "dart", TRUE, + 'h', "hypothermia", FALSE, + 's', "starvation", FALSE, + '\0' + }; + + if (isupper(monst)) + { + sp = Monsters[monst-'A'].m_name; + article = TRUE; + } + else + { + sp = "Wally the Wonder Badger"; + article = FALSE; + for (hp = nlist; hp->h_ch; hp++) + if (hp->h_ch == monst) + { + sp = hp->h_desc; + article = hp->h_print; + break; + } + } + if (doart && article) + sprintf(Prbuf, "a%s ", vowelstr(sp)); + else + Prbuf[0] = '\0'; + strcat(Prbuf, sp); + return Prbuf; +} + +/* + * death_monst: + * Return a monster appropriate for a random death. + */ +char +death_monst(void) +{ + static char poss[] = + { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'h', 'd', 's', + ' ' /* This is provided to generate the "Wally the Wonder Badger" + message for killer */ + }; + + return poss[rnd(sizeof poss / sizeof (char))]; +} + +#ifdef attron +int +_putchar(char c) +{ + putchar(c); +} +#endif attron diff --git a/master.c b/master.c new file mode 100644 index 0000000..e35a3ce --- /dev/null +++ b/master.c @@ -0,0 +1,400 @@ +/* + * Hero movement commands + * + * @(#)master.c 4.49 (Berkeley) 02/05/99 + */ + +#include +#include +#include "netprot.h" + +/* + * Used to hold the new Hero position + */ + +coord nh; + +/* + * do_run: + * Start the hero running + */ +void +do_run(char ch) +{ + Running = TRUE; + After = FALSE; + Runch = ch; +} + +/* + * do_move: + * Check to see that a move is legal. If it is handle the + * consequences (fighting, picking up, etc.) + */ +void +do_move(int dy, int dx) +{ + char ch, fl; + + Firstmove = FALSE; + if (No_move) + { + No_move--; + msg("you are still stuck in the bear trap"); + return; + } + /* + * Do a confused move (maybe) + */ + if (on(Player, ISHUH) && rnd(5) != 0) + { + nh = *rndmove(&Player); + if (ce(nh, Hero)) + { + After = FALSE; + Running = FALSE; + To_death = FALSE; + return; + } + } + else + { +over: + nh.y = Hero.y + dy; + nh.x = Hero.x + dx; + } + + /* + * Check if he tried to move off the screen or make an illegal + * diagonal move, and stop him if he did. + */ + if (nh.x < 0 || nh.x >= NUMCOLS || nh.y <= 0 || nh.y >= NUMLINES - 1) + goto hit_bound; + if (!diag_ok(&Hero, &nh)) + { + After = FALSE; + Running = FALSE; + return; + } + if (Running && ce(Hero, nh)) + After = Running = FALSE; + fl = flat(nh.y, nh.x); + ch = winat(nh.y, nh.x); + if (!(fl & F_REAL) && ch == FLOOR) + { + if (!on(Player, ISLEVIT)) + { + chat(nh.y, nh.x) = ch = TRAP; + flat(nh.y, nh.x) |= F_REAL; + } + } + else if (on(Player, ISHELD) && ch != 'F') + { + msg("you are being held"); + return; + } + switch (ch) + { + case ' ': + case '|': + case '-': +hit_bound: + if (Passgo && Running && (Proom->r_flags & ISGONE) + && !on(Player, ISBLIND)) + { + bool b1, b2; + + switch (Runch) + { + case 'h': + case 'l': + b1 = (Hero.y != 1 && turn_ok(Hero.y - 1, Hero.x)); + b2 = (Hero.y != NUMLINES - 2 && turn_ok(Hero.y + 1, Hero.x)); + if (!(b1 ^ b2)) + break; + if (b1) + { + Runch = 'k'; + dy = -1; + } + else + { + Runch = 'j'; + dy = 1; + } + dx = 0; + turnref(); + goto over; + case 'j': + case 'k': + b1 = (Hero.x != 0 && turn_ok(Hero.y, Hero.x - 1)); + b2 = (Hero.x != NUMCOLS - 1 && turn_ok(Hero.y, Hero.x + 1)); + if (!(b1 ^ b2)) + break; + if (b1) + { + Runch = 'h'; + dx = -1; + } + else + { + Runch = 'l'; + dx = 1; + } + dy = 0; + turnref(); + goto over; + } + } + Running = FALSE; + After = FALSE; + break; + case DOOR: + Running = FALSE; + if (flat(Hero.y, Hero.x) & F_PASS) + enter_room(&nh); + goto move_stuff; + case TRAP: + ch = be_trapped(&nh); + if (ch == T_DOOR || ch == T_TELEP) + return; + goto move_stuff; + case PASSAGE: + /* + * when you're in a corridor, you don't know if you're in + * a maze room or not, and there ain't no way to find out + * if you're leaving a maze room, so it is necessary to + * always recalculate Proom. + */ + Proom = roomin(&Hero); + goto move_stuff; + case FLOOR: + if (!(fl & F_REAL)) + be_trapped(&Hero); + goto move_stuff; + case STAIRS: + Seenstairs = TRUE; + /* FALLTHROUGH */ + default: + Running = FALSE; + if (isupper(ch) || moat(nh.y, nh.x)) + fight(&nh, Cur_weapon, FALSE); + else + { + if (ch != STAIRS) + Take = ch; +move_stuff: + mvaddch(Hero.y, Hero.x, floor_at()); + if ((fl & F_PASS) && chat(Oldpos.y, Oldpos.x) == DOOR) + leave_room(&nh); + Hero = nh; + } + } +} + +/* + * turn_ok: + * Decide whether it is legal to turn onto the given space + */ +bool +turn_ok(int y, int x) +{ + PLACE *pp; + + pp = INDEX(y, x); + return (pp->p_ch == DOOR + || (pp->p_flags & (F_REAL|F_PASS)) == (F_REAL|F_PASS)); +} + +/* + * turnref: + * Decide whether to refresh at a passage turning or not + */ +void +turnref(void) +{ + PLACE *pp; + + pp = INDEX(Hero.y, Hero.x); + if (!(pp->p_flags & F_SEEN)) + { + if (Jump) + { + leaveok(stdscr, TRUE); + refresh(); + leaveok(stdscr, FALSE); + } + pp->p_flags |= F_SEEN; + } +} + +/* + * door_open: + * Called to illuminate a room. If it is dark, remove anything + * that might move. + */ +void +door_open(struct room *rp) +{ + THING *mp; + int y, x; + + if (!(rp->r_flags & ISGONE)) + for (y = rp->r_pos.y; y < rp->r_pos.y + rp->r_max.y; y++) + for (x = rp->r_pos.x; x < rp->r_pos.x + rp->r_max.x; x++) + if (isupper(winat(y, x))) + wake_monster(y, x); +} + +/* + * be_trapped: + * The guy stepped on a trap.... Make him pay. + */ +char +be_trapped(coord *tc) +{ + PLACE *pp; + THING *arrow; + char tr; + + if (on(Player, ISLEVIT)) + return T_RUST; /* anything that's not a door or teleport */ + Running = FALSE; + Count = FALSE; + pp = INDEX(tc->y, tc->x); + pp->p_ch = TRAP; + tr = pp->p_flags & F_TMASK; + pp->p_flags |= F_SEEN; + switch (tr) + { + when T_DOOR: + Level++; + new_level(); + msg("you fell into a trap!"); + when T_BEAR: + No_move += BEARTIME; + msg("you are caught in a bear trap"); + when T_SLEEP: + No_command += SLEEPTIME; + Player.t_flags &= ~ISRUN; + msg("a strange white mist envelops you and you fall asleep"); + when T_ARROW: + if (swing(Pstats.s_lvl - 1, Pstats.s_arm, 1)) + { + Pstats.s_hpt -= roll(1, 6); + if (Pstats.s_hpt <= 0) + { + msg("an arrow killed you"); + death('a'); + } + else + msg("oh no! An arrow shot you"); + } + else + { + arrow = new_item(); + init_weapon(arrow, ARROW); + arrow->o_count = 1; + arrow->o_pos = Hero; + fall(arrow, FALSE); + msg("an arrow shoots past you"); + } + when T_TELEP: + /* + * since the hero's leaving, look() won't put a TRAP + * down for us, so we have to do it ourself + */ + teleport(); + mvaddch(tc->y, tc->x, TRAP); + when T_DART: + if (!swing(Pstats.s_lvl+1, Pstats.s_arm, 1)) + msg("a small dart whizzes by your ear and vanishes"); + else + { + Pstats.s_hpt -= roll(1, 4); + if (Pstats.s_hpt <= 0) + { + msg("a poisoned dart killed you"); + death('d'); + } + if (!ISWEARING(R_SUSTSTR) && !save(VS_POISON)) + chg_str(-1); + msg("a small dart just hit you in the shoulder"); + } + when T_RUST: + msg("a gush of water hits you on the head"); + rust_armor(Cur_armor); + } + flush_type(); + return tr; +} + +/* + * rndmove: + * Move in a random direction if the monster/person is confused + */ +coord * +rndmove(THING *who) +{ + THING *obj; + int x, y; + char ch; + coord ret; /* what we will be returning */ + + y = ret.y = who->t_pos.y + rnd(3) - 1; + x = ret.x = who->t_pos.x + rnd(3) - 1; + /* + * Now check to see if that's a legal move. If not, don't move. + * (I.e., bump into the wall or whatever) + */ + if (y == who->t_pos.y && x == who->t_pos.x) + return &ret; + if (!diag_ok(&who->t_pos, &ret)) + goto bad; + else + { + ch = winat(y, x); + if (!step_ok(ch)) + goto bad; + if (ch == SCROLL) + { + for (obj = Lvl_obj; obj != NULL; obj = next(obj)) + if (y == obj->o_pos.y && x == obj->o_pos.x) + break; + if (obj != NULL && obj->o_which == S_SCARE) + goto bad; + } + } + return &ret; + +bad: + ret = who->t_pos; + return &ret; +} + +/* + * rust_armor: + * Rust the given armor, if it is a legal kind to rust, and we + * aren't wearing a magic ring. + */ +void +rust_armor(THING *arm) +{ + if (arm == NULL || arm->o_type != ARMOR || arm->o_which == LEATHER || + arm->o_arm >= 9) + return; + + if ((arm->o_flags & ISPROT) || ISWEARING(R_SUSTARM)) + { + if (!To_death) + msg("the rust vanishes instantly"); + } + else + { + arm->o_arm++; + if (!Terse) + msg("your armor appears to be weaker now. Oh my!"); + else + msg("your armor weakens"); + } +} diff --git a/netmap.c b/netmap.c new file mode 100644 index 0000000..44ce2e8 --- /dev/null +++ b/netmap.c @@ -0,0 +1,196 @@ +#include +#include "netprot.h" + +/* + * Routines dealing specifically with rings + * + * @(#)netmap.c 4.19 (Berkeley) 05/29/83 + */ + +/* + * ring_on: + * Put a ring on a hand + */ +void +ring_on(void) +{ + THING *obj; + int ring; + + obj = get_item("put on", RING); + /* + * Make certain that it is somethings that we want to wear + */ + if (obj == NULL) + return; + if (obj->o_type != RING) + { + if (!Terse) + msg("it would be difficult to wrap that around a finger"); + else + msg("not a ring"); + return; + } + + /* + * find out which hand to put it on + */ + if (is_current(obj)) + return; + + if (Cur_ring[LEFT] == NULL && Cur_ring[RIGHT] == NULL) + { + if ((ring = gethand()) < 0) + return; + } + else if (Cur_ring[LEFT] == NULL) + ring = LEFT; + else if (Cur_ring[RIGHT] == NULL) + ring = RIGHT; + else + { + if (!Terse) + msg("you already have a ring on each hand"); + else + msg("wearing two"); + return; + } + Cur_ring[ring] = obj; + + /* + * Calculate the effect it has on the poor guy. + */ + switch (obj->o_which) + { + case R_ADDSTR: + chg_str(obj->o_arm); + break; + case R_SEEINVIS: + invis_on(); + break; + case R_AGGR: + aggravate(); + break; + } + + if (!Terse) + addmsg("you are now wearing "); + msg("%s (%c)", inv_name(obj, TRUE), obj->o_packch); +} + +/* + * ring_off: + * Take off a ring + */ +void +ring_off(void) +{ + int ring; + THING *obj; + + if (Cur_ring[LEFT] == NULL && Cur_ring[RIGHT] == NULL) + { + if (Terse) + msg("no rings"); + else + msg("you aren't wearing any rings"); + return; + } + else if (Cur_ring[LEFT] == NULL) + ring = RIGHT; + else if (Cur_ring[RIGHT] == NULL) + ring = LEFT; + else + if ((ring = gethand()) < 0) + return; + Mpos = 0; + obj = Cur_ring[ring]; + if (obj == NULL) + { + msg("not wearing such a ring"); + return; + } + if (dropcheck(obj)) + msg("was wearing %s (%c)", inv_name(obj, TRUE), obj->o_packch); +} + +/* + * gethand: + * Which hand is the hero interested in? + */ +int +gethand(void) +{ + int c; + + for (;;) + { + if (Terse) + msg("left or right ring? "); + else + msg("left hand or right hand? "); + if ((c = readchar()) == ESCAPE) + return -1; + Mpos = 0; + if (c == 'l' || c == 'L') + return LEFT; + else if (c == 'r' || c == 'R') + return RIGHT; + if (Terse) + msg("L or R"); + else + msg("please type L or R"); + } +} + +/* + * ring_eat: + * How much food does this ring use up? + */ +int +ring_eat(int hand) +{ + THING *ring; + int eat; + static int uses[] = { + 1, /* R_PROTECT */ 1, /* R_ADDSTR */ + 1, /* R_SUSTSTR */ -3, /* R_SEARCH */ + -5, /* R_SEEINVIS */ 0, /* R_NOP */ + 0, /* R_AGGR */ -3, /* R_ADDHIT */ + -3, /* R_ADDDAM */ 2, /* R_REGEN */ + -2, /* R_DIGEST */ 0, /* R_TELEPORT */ + 1, /* R_STEALTH */ 1 /* R_SUSTARM */ + }; + + if ((ring = Cur_ring[hand]) == NULL) + return 0; + if ((eat = uses[ring->o_which]) < 0) + eat = (rnd(-eat) == 0); + if (ring->o_which == R_DIGEST) + eat = -eat; + return eat; +} + +/* + * ring_num: + * Print ring bonuses + */ +char * +ring_num(THING *obj) +{ + static char buf[10]; + + if (!(obj->o_flags & ISKNOW)) + return ""; + switch (obj->o_which) + { + when R_PROTECT: + case R_ADDSTR: + case R_ADDDAM: + case R_ADDHIT: + sprintf(buf, " [%s]", num(obj->o_arm, 0, RING)); + otherwise: + return ""; + } + return buf; +} diff --git a/netmisc.c b/netmisc.c new file mode 100644 index 0000000..3de73d5 --- /dev/null +++ b/netmisc.c @@ -0,0 +1,231 @@ +/* + * copies of several routines needed for netwait + * + * @(#)netmisc.c 4.7 (Berkeley) 02/05/99 + */ + +# include +# include +# include +# include + +# define TRUE 1 +# define FALSE 0 +# define MAXSTR 80 +# define bool char +# define when break;case +# define otherwise break;default + +typedef struct { + char *m_name; +} MONST; + +char *s_vowelstr(); + +extern char encstr[], frob; + +char *lockfile = "/tmp/.fredlock"; + +char Prbuf[MAXSTR]; /* Buffer for sprintfs */ + +MONST Monsters[] = { + { "aquator" }, { "bat" }, { "centaur" }, { "dragon" }, { "emu" }, + { "venus flytrap" }, { "griffin" }, { "hobgoblin" }, { "ice monster" }, + { "jabberwock" }, { "kobold" }, { "leprechaun" }, { "medusa" }, + { "nymph" }, { "orc" }, { "phantom" }, { "quasit" }, { "rattlesnake" }, + { "snake" }, { "troll" }, { "ur-vile" }, { "vampire" }, { "wraith" }, + { "xeroc" }, { "yeti" }, { "zombie" } +}; + +/* + * s_lock_sc: + * lock the score file. If it takes too long, ask the user if + * they care to wait. Return TRUE if the lock is successful. + */ +bool +s_lock_sc(void) +{ + int cnt; + static struct stat sbuf; + time_t time(); + +over: + close(8); /* just in case there are no files left */ + if (creat(lockfile, 0000) >= 0) + return TRUE; + for (cnt = 0; cnt < 5; cnt++) + { + sleep(1); + if (creat(lockfile, 0000) >= 0) + return TRUE; + } + if (stat(lockfile, &sbuf) < 0) + { + creat(lockfile, 0000); + return TRUE; + } + if (time(NULL) - sbuf.st_mtime > 10) + { + if (unlink(lockfile) < 0) + return FALSE; + goto over; + } + else + { + printf("The score file is very busy. Do you want to wait longer\n"); + printf("for it to become free so your score can get posted?\n"); + printf("If so, type \"y\"\n"); + fgets(Prbuf, MAXSTR, stdin); + if (Prbuf[0] == 'y') + for (;;) + { + if (creat(lockfile, 0000) >= 0) + return TRUE; + if (stat(lockfile, &sbuf) < 0) + { + creat(lockfile, 0000); + return TRUE; + } + if (time(NULL) - sbuf.st_mtime > 10) + { + if (unlink(lockfile) < 0) + return FALSE; + } + sleep(1); + } + else + return FALSE; + } +} + +/* + * s_unlock_sc: + * Unlock the score file + */ +void +s_unlock_sc(void) +{ + unlink(lockfile); +} + +/* + * s_encwrite: + * Perform an encrypted write + */ +void +s_encwrite(char *start, unsigned int size, FILE *outf) +{ + char *e1, *e2, fb; + int temp; + extern char statlist[]; + + e1 = encstr; + e2 = statlist; + fb = frob; + + while (size--) + { + putc(*start++ ^ *e1 ^ *e2 ^ fb, outf); + temp = *e1++; + fb += temp * *e2++; + if (*e1 == '\0') + e1 = encstr; + if (*e2 == '\0') + e2 = statlist; + } +} + +/* + * s_encread: + * Perform an encrypted read + */ +void +s_encread(char *start, unsigned int size, int inf) +{ + char *e1, *e2, fb; + int temp; + int read_size; + extern char statlist[]; + + fb = frob; + + if ((read_size = read(inf, start, size)) == 0 || read_size == -1) + return; + + e1 = encstr; + e2 = statlist; + + while (size--) + { + *start++ ^= *e1 ^ *e2 ^ fb; + temp = *e1++; + fb += temp * *e2++; + if (*e1 == '\0') + e1 = encstr; + if (*e2 == '\0') + e2 = statlist; + } +} + +/* + * s_killname: + * Convert a code to a monster name + */ +char * +s_killname(char monst, bool doart) +{ + char *sp; + bool article; + + article = TRUE; + switch (monst) + { + when 'a': + sp = "arrow"; + when 'b': + sp = "bolt"; + when 'd': + sp = "dart"; + when 's': + sp = "starvation"; + article = FALSE; + when 'h': + sp = "hypothermia"; + article = FALSE; + otherwise: + if (isupper(monst)) + sp = Monsters[monst-'A'].m_name; + else + { + sp = "God"; + article = FALSE; + } + } + if (doart && article) + sprintf(Prbuf, "a%s ", s_vowelstr(sp)); + else + Prbuf[0] = '\0'; + strcat(Prbuf, sp); + return Prbuf; +} + +/* + * s_vowelstr: + * For printfs: if string starts with a vowel, return "n" for an + * "an". + */ +char * +s_vowelstr(char *str) +{ + switch (*str) + { + case 'a': case 'A': + case 'e': case 'E': + case 'i': case 'I': + case 'o': case 'O': + case 'u': case 'U': + return "n"; + default: + return ""; + } +} diff --git a/netprot.c b/netprot.c new file mode 100644 index 0000000..3e31905 --- /dev/null +++ b/netprot.c @@ -0,0 +1,529 @@ +/* + * Code for one creature to chase another + * + * @(#)netprot.c 4.57 (Berkeley) 02/05/99 + */ + +#include +#include "netprot.h" + +#define DRAGONSHOT 5 /* one chance in DRAGONSHOT that a dragon will flame */ + +static coord Ch_ret; /* Where chasing takes you */ + +/* + * runners: + * Make all the running monsters move. + */ +void +runners(void) +{ + THING *tp; + THING *next; + bool wastarget; + static coord orig_pos; + + for (tp = Mlist; tp != NULL; tp = next) + { + /* remember this in case the monster's "next" is changed */ + next = next(tp); + + if (!on(*tp, ISHELD) && on(*tp, ISRUN)) + { + orig_pos = tp->t_pos; + wastarget = on(*tp, ISTARGET); + move_monst(tp); + if (on(*tp, ISFLY) && dist_cp(&Hero, &tp->t_pos) >= 3) + move_monst(tp); + if (wastarget && !ce(orig_pos, tp->t_pos)) + { + tp->t_flags &= ~ISTARGET; + To_death = FALSE; + } + } + } + if (Has_hit) + { + endmsg(); + Has_hit = FALSE; + } +} + +/* + * move_monst: + * Execute a single turn of running for a monster + */ +void +move_monst(THING *tp) +{ + if (!on(*tp, ISSLOW) || tp->t_turn) + do_chase(tp); + if (on(*tp, ISHASTE)) + do_chase(tp); + tp->t_turn ^= TRUE; +} + +/* + * relocate: + * Make the monster's new location be the specified one, updating + * all the relevant state. + */ +void +relocate(THING *th, coord *new_loc) +{ + struct room *oroom; + + if (!ce(*new_loc, th->t_pos)) + { + mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch); + th->t_room = roomin(new_loc); + set_oldch(th, new_loc); + oroom = th->t_room; + moat(th->t_pos.y, th->t_pos.x) = NULL; + + if (oroom != th->t_room) + th->t_dest = find_dest(th); + th->t_pos = *new_loc; + moat(new_loc->y, new_loc->x) = th; + } + move(new_loc->y, new_loc->x); + if (see_monst(th)) + addch(th->t_disguise); + else if (on(Player, SEEMONST)) + { + standout(); + addch(th->t_type); + standend(); + } +} + +/* + * do_chase: + * Make one thing chase another. + */ +void +do_chase(THING *th) +{ + coord *cp; + struct room *rer, *ree; /* room of chaser, room of chasee */ + int mindist = 32767, curdist; + bool stoprun = FALSE; /* TRUE means we are there */ + bool door; + THING *obj; + static coord this; /* Temporary destination for chaser */ + + rer = th->t_room; /* Find room of chaser */ + if (on(*th, ISGREED) && rer->r_goldval == 0) + th->t_dest = &Hero; /* If gold has been taken, run after hero */ + if (th->t_dest == &Hero) /* Find room of chasee */ + ree = Proom; + else + ree = roomin(th->t_dest); + /* + * We don't count doors as inside rooms for this routine + */ + door = (chat(th->t_pos.y, th->t_pos.x) == DOOR); + /* + * If the object of our desire is in a different room, + * and we are not in a corridor, run to the door nearest to + * our goal. + */ +over: + if (rer != ree) + { + for (cp = rer->r_exit; cp < &rer->r_exit[rer->r_nexits]; cp++) + { + curdist = dist_cp(th->t_dest, cp); + if (curdist < mindist) + { + this = *cp; + mindist = curdist; + } + } + if (door) + { + rer = &Passages[flat(th->t_pos.y, th->t_pos.x) & F_PNUM]; + door = FALSE; + goto over; + } + } + else + { + this = *th->t_dest; + /* + * For dragons check and see if (a) the hero is on a straight + * line from it, and (b) that it is within shooting distance, + * but outside of striking range. + */ + if (th->t_type == 'D' && (th->t_pos.y == Hero.y || th->t_pos.x == Hero.x + || abs(th->t_pos.y - Hero.y) == abs(th->t_pos.x - Hero.x)) + && dist_cp(&th->t_pos, &Hero) <= BOLT_LENGTH * BOLT_LENGTH + && !on(*th, ISCANC) && rnd(DRAGONSHOT) == 0) + { + Delta.y = sign(Hero.y - th->t_pos.y); + Delta.x = sign(Hero.x - th->t_pos.x); + if (Has_hit) + endmsg(); + fire_bolt(&th->t_pos, &Delta, "flame"); + Running = FALSE; + Count = 0; + Quiet = 0; + if (To_death && !on(*th, ISTARGET)) + { + To_death = FALSE; + Kamikaze = FALSE; + } + return; + } + } + /* + * This now contains what we want to run to this time + * so we run to it. If we hit it we either want to fight it + * or stop running + */ + if (!chase(th, &this)) + { + if (ce(this, Hero)) + { + attack(th); + return; + } + else if (ce(this, *th->t_dest)) + { + for (obj = Lvl_obj; obj != NULL; obj = next(obj)) + if (th->t_dest == &obj->o_pos) + { + detach(Lvl_obj, obj); + attach(th->t_pack, obj); + chat(obj->o_pos.y, obj->o_pos.x) = + (th->t_room->r_flags & ISGONE) ? PASSAGE : FLOOR; + th->t_dest = find_dest(th); + break; + } + if (th->t_type != 'F') + stoprun = TRUE; + } + } + else + { + if (th->t_type == 'F') + return; + } + relocate(th, &Ch_ret); + /* + * And stop running if need be + */ + if (stoprun && ce(th->t_pos, *(th->t_dest))) + th->t_flags &= ~ISRUN; +} + +/* + * set_oldch: + * Set the oldch character for the monster + */ +void +set_oldch(THING *tp, coord *cp) +{ + char sch; + + if (ce(tp->t_pos, *cp)) + return; + + sch = tp->t_oldch; + tp->t_oldch = mvinch(cp->y, cp->x); + if (!on(Player, ISBLIND)) + if ((sch == FLOOR || tp->t_oldch == FLOOR) && + (tp->t_room->r_flags & ISDARK)) + tp->t_oldch = ' '; + else if (dist_cp(cp, &Hero) <= LAMPDIST && See_floor) + tp->t_oldch = chat(cp->y, cp->x); +} + +/* + * see_monst: + * Return TRUE if the hero can see the monster + */ +bool +see_monst(THING *mp) +{ + int y, x; + + if (on(Player, ISBLIND)) + return FALSE; + if (on(*mp, ISINVIS) && !on(Player, CANSEE)) + return FALSE; + y = mp->t_pos.y; + x = mp->t_pos.x; + if (dist(y, x, Hero.y, Hero.x) < LAMPDIST) + { + if (y != Hero.y && x != Hero.x && + !step_ok(chat(y, Hero.x)) && !step_ok(chat(Hero.y, x))) + return FALSE; + return TRUE; + } + if (mp->t_room != Proom) + return FALSE; + return (!(mp->t_room->r_flags & ISDARK)); +} + +/* + * runto: + * Set a monster running after the hero. + */ +void +runto(coord *runner) +{ + THING *tp; + + /* + * If we couldn't find him, something is funny + */ +#ifdef MASTER + if ((tp = moat(runner->y, runner->x)) == NULL) + msg("couldn't find monster in runto at (%d,%d)", runner->y, runner->x); +#else + tp = moat(runner->y, runner->x); +#endif + /* + * Start the beastie running + */ + tp->t_flags |= ISRUN; + tp->t_flags &= ~ISHELD; + tp->t_dest = find_dest(tp); +} + +/* + * chase: + * Find the spot for the chaser(er) to move closer to the + * chasee(ee). Returns TRUE if we want to keep on chasing later + * FALSE if we reach the goal. + */ +bool +chase(THING *tp, coord *ee) +{ + THING *obj; + int x, y; + int curdist, thisdist; + coord *er = &tp->t_pos; + char ch; + int plcnt = 1; + static coord tryp; + + /* + * If the thing is confused, let it move randomly. Invisible + * Stalkers are slightly confused all of the time, and bats are + * quite confused all the time + */ + if ((on(*tp, ISHUH) && rnd(5) != 0) || (tp->t_type == 'P' && rnd(5) == 0) + || (tp->t_type == 'B' && rnd(2) == 0)) + { + /* + * get a valid random move + */ + Ch_ret = *rndmove(tp); + curdist = dist_cp(&Ch_ret, ee); + /* + * Small chance that it will become un-confused + */ + if (rnd(20) == 0) + tp->t_flags &= ~ISHUH; + } + /* + * Otherwise, find the empty spot next to the chaser that is + * closest to the chasee. + */ + else + { + int ey, ex; + /* + * This will eventually hold where we move to get closer + * If we can't find an empty spot, we stay where we are. + */ + curdist = dist_cp(er, ee); + Ch_ret = *er; + + ey = er->y + 1; + if (ey >= NUMLINES - 1) + ey = NUMLINES - 2; + ex = er->x + 1; + if (ex >= NUMCOLS) + ex = NUMCOLS - 1; + + for (x = er->x - 1; x <= ex; x++) + { + if (x < 0) + continue; + tryp.x = x; + for (y = er->y - 1; y <= ey; y++) + { + tryp.y = y; + if (!diag_ok(er, &tryp)) + continue; + ch = winat(y, x); + if (step_ok(ch)) + { + /* + * If it is a scroll, it might be a scare monster scroll + * so we need to look it up to see what type it is. + */ + if (ch == SCROLL) + { + for (obj = Lvl_obj; obj != NULL; obj = next(obj)) + { + if (y == obj->o_pos.y && x == obj->o_pos.x) + break; + } + if (obj != NULL && obj->o_which == S_SCARE) + continue; + } + /* + * It can also be a Xeroc, which we shouldn't step on + */ + if ((obj = moat(y, x)) != NULL && obj->t_type == 'X') + continue; + /* + * If we didn't find any scrolls at this place or it + * wasn't a scare scroll, then this place counts + */ + thisdist = dist(y, x, ee->y, ee->x); + if (thisdist < curdist) + { + plcnt = 1; + Ch_ret = tryp; + curdist = thisdist; + } + else if (thisdist == curdist && rnd(++plcnt) == 0) + { + Ch_ret = tryp; + curdist = thisdist; + } + } + } + } + } + return (curdist != 0 && !ce(Ch_ret, Hero)); +} + +/* + * roomin: + * Find what room some coordinates are in. NULL means they aren't + * in any room. + */ +struct room * +roomin(coord *cp) +{ + struct room *rp; + char *fp; + + + fp = &flat(cp->y, cp->x); + if (*fp & F_PASS) + return &Passages[*fp & F_PNUM]; + + for (rp = Rooms; rp < &Rooms[MAXROOMS]; rp++) + if (cp->x <= rp->r_pos.x + rp->r_max.x && rp->r_pos.x <= cp->x + && cp->y <= rp->r_pos.y + rp->r_max.y && rp->r_pos.y <= cp->y) + return rp; + + msg("in some bizarre place (%d, %d)", unc(*cp)); +#ifdef MASTER + abort(); + /* NOTREACHED */ +#else + return NULL; +#endif +} + +/* + * diag_ok: + * Check to see if the move is legal if it is diagonal + */ +bool +diag_ok(coord *sp, coord *ep) +{ + if (ep->x < 0 || ep->x >= NUMCOLS || ep->y <= 0 || ep->y >= NUMLINES - 1) + return FALSE; + if (ep->x == sp->x || ep->y == sp->y) + return TRUE; + return (step_ok(chat(ep->y, sp->x)) && step_ok(chat(sp->y, ep->x))); +} + +/* + * cansee: + * Returns true if the hero can see a certain coordinate. + */ +bool +cansee(int y, int x) +{ + struct room *rer; + static coord tp; + + if (on(Player, ISBLIND)) + return FALSE; + if (dist(y, x, Hero.y, Hero.x) < LAMPDIST) + { + if (flat(y, x) & F_PASS) + if (y != Hero.y && x != Hero.x && + !step_ok(chat(y, Hero.x)) && !step_ok(chat(Hero.y, x))) + return FALSE; + return TRUE; + } + /* + * We can only see if the hero in the same room as + * the coordinate and the room is lit or if it is close. + */ + tp.y = y; + tp.x = x; + return ((rer = roomin(&tp)) == Proom && !(rer->r_flags & ISDARK)); +} + +/* + * find_dest: + * find the proper destination for the monster + */ +coord * +find_dest(THING *tp) +{ + THING *obj; + int prob; + + if ((prob = Monsters[tp->t_type - 'A'].m_carry) <= 0 || tp->t_room == Proom + || see_monst(tp)) + return &Hero; + for (obj = Lvl_obj; obj != NULL; obj = next(obj)) + { + if (obj->o_type == SCROLL && obj->o_which == S_SCARE) + continue; + if (roomin(&obj->o_pos) == tp->t_room && rnd(100) < prob) + { + for (tp = Mlist; tp != NULL; tp = next(tp)) + if (tp->t_dest == &obj->o_pos) + break; + if (tp == NULL) + return &obj->o_pos; + } + } + return &Hero; +} + +/* + * dist: + * Calculate the "distance" between to points. Actually, + * this calculates d^2, not d, but that's good enough for + * our purposes, since it's only used comparitively. + */ +int +dist(int y1, int x1, int y2, int x2) +{ + return ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); +} + +/* + * dist_cp: + * Call dist() with appropriate arguments for coord pointers + */ +int +dist_cp(coord *c1, coord *c2) +{ + return dist(c1->y, c1->x, c2->y, c2->x); +} diff --git a/netprot.h b/netprot.h new file mode 100644 index 0000000..6bb1545 --- /dev/null +++ b/netprot.h @@ -0,0 +1,596 @@ +/* + * Rogue definitions and variable declarations + * + * @(#)netprot.h 5.42 (Berkeley) 08/06/83 + */ + +#include "network.h" +#include + +/* + * Maximum number of different things + */ +#define MAXROOMS 9 +#define MAXTHINGS 9 +#define MAXOBJ 9 +#define MAXPACK 23 +#define MAXTRAPS 10 +#define AMULETLEVEL 26 +#define NUMTHINGS 7 /* number of types of things */ +#define MAXPASS 13 /* upper limit on number of passages */ +#define NUMLINES 24 +#define NUMCOLS 80 +#define STATLINE (NUMLINES - 1) +#define BORE_LEVEL 50 + +/* + * return values for get functions + */ +#define NORM 0 /* normal exit */ +#define QUIT 1 /* quit option setting */ +#define MINUS 2 /* back up one option */ + +/* + * inventory types + */ +#define INV_OVER 0 +#define INV_SLOW 1 +#define INV_CLEAR 2 + +/* + * All the fun defines + */ +#define when break;case +#define otherwise break;default +#define until(expr) while(!(expr)) +#define next(ptr) (*ptr).l_next +#define prev(ptr) (*ptr).l_prev +#define winat(y,x) (moat(y,x) != NULL ? moat(y,x)->t_disguise : chat(y,x)) +#define ce(a,b) ((a).x == (b).x && (a).y == (b).y) +#define Hero Player.t_pos +#define Pstats Player.t_stats +#define Pack Player.t_pack +#define Proom Player.t_room +#define Max_hp Player.t_stats.s_maxhp +#define attach(a,b) _attach(&a,b) +#define detach(a,b) _detach(&a,b) +#define free_list(a) _free_list(&a) +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define on(thing,flag) (((thing).t_flags & (flag)) != 0) +#define GOLDCALC (rnd(50 + 10 * Level) + 2) +#define ISRING(h,r) (Cur_ring[h] != NULL && Cur_ring[h]->o_which == r) +#define ISWEARING(r) (ISRING(LEFT, r) || ISRING(RIGHT, r)) +#define ISMULT(type) (type == POTION || type == SCROLL || type == FOOD) +#define INDEX(y,x) (&Places[((x) << 5) + (y)]) +#define chat(y,x) (Places[((x) << 5) + (y)].p_ch) +#define flat(y,x) (Places[((x) << 5) + (y)].p_flags) +#define moat(y,x) (Places[((x) << 5) + (y)].p_monst) +#define unc(cp) (cp).y, (cp).x +#ifdef MASTER +#define debug if (Wizard) msg +#endif + +/* + * Things that appear on the screens + */ +#define PASSAGE '#' +#define DOOR '+' +#define FLOOR '.' +#define PLAYER '@' +#define TRAP '^' +#define STAIRS '%' +#define GOLD '*' +#define POTION '!' +#define SCROLL '?' +#define MAGIC '$' +#define FOOD ':' +#define WEAPON ')' +#define ARMOR ']' +#define AMULET ',' +#define RING '=' +#define STICK '/' +#define CALLABLE -1 +#define R_OR_S -2 + +/* + * Various constants + */ +#define BEARTIME spread(3) +#define SLEEPTIME spread(5) +#define HOLDTIME spread(2) +#define WANDERTIME spread(70) +#define BEFORE spread(1) +#define AFTER spread(2) +#define HEALTIME 30 +#define HUHDURATION 20 +#define SEEDURATION 850 +#define HUNGERTIME 1300 +#define MORETIME 150 +#define STOMACHSIZE 2000 +#define STARVETIME 850 +#define ESCAPE 27 +#define LEFT 0 +#define RIGHT 1 +#define BOLT_LENGTH 6 +#define LAMPDIST 3 +#ifdef MASTER +#define PASSWD "mTsdVv0Uvy4xY" +#endif + +/* + * Save against things + */ +#define VS_POISON 00 +#define VS_PARALYZATION 00 +#define VS_DEATH 00 +#define VS_BREATH 02 +#define VS_MAGIC 03 + +/* + * Various flag bits + */ +/* flags for rooms */ +#define ISDARK 0000001 /* room is dark */ +#define ISGONE 0000002 /* room is gone (a corridor) */ +#define ISMAZE 0000004 /* room is gone (a corridor) */ + +/* flags for objects */ +#define ISCURSED 000001 /* object is cursed */ +#define ISKNOW 0000002 /* player knows details about the object */ +#define ISMISL 0000004 /* object is a missile type */ +#define ISMANY 0000010 /* object comes in groups */ +/* ISFOUND 0000020 ...is used for both objects and creatures */ +#define ISPROT 0000040 /* armor is permanently protected */ + +/* flags for creatures */ +#define CANHUH 0000001 /* creature can confuse */ +#define CANSEE 0000002 /* creature can see invisible creatures */ +#define ISBLIND 0000004 /* creature is blind */ +#define ISCANC 0000010 /* creature has special qualities cancelled */ +#define ISLEVIT 0000010 /* hero is levitating */ +#define ISFOUND 0000020 /* creature has been seen (used for objects) */ +#define ISGREED 0000040 /* creature runs to protect gold */ +#define ISHASTE 0000100 /* creature has been hastened */ +#define ISTARGET 000200 /* creature is the target of an 'f' command */ +#define ISHELD 0000400 /* creature has been held */ +#define ISHUH 0001000 /* creature is confused */ +#define ISINVIS 0002000 /* creature is invisible */ +#define ISMEAN 0004000 /* creature can wake when player enters room */ +#define ISHALU 0004000 /* hero is on acid trip */ +#define ISREGEN 0010000 /* creature can regenerate */ +#define ISRUN 0020000 /* creature is running at the player */ +#define SEEMONST 040000 /* hero can detect unseen monsters */ +#define ISFLY 0040000 /* creature can fly */ +#define ISSLOW 0100000 /* creature has been slowed */ + +/* + * Flags for level map + */ +#define F_PASS 0x80 /* is a passageway */ +#define F_SEEN 0x40 /* have seen this spot before */ +#define F_DROPPED 0x20 /* object was dropped here */ +#define F_LOCKED 0x20 /* door is locked */ +#define F_REAL 0x10 /* what you see is what you get */ +#define F_PNUM 0x0f /* passage number mask */ +#define F_TMASK 0x07 /* trap number mask */ + +/* + * Trap types + */ +#define T_DOOR 00 +#define T_ARROW 01 +#define T_SLEEP 02 +#define T_BEAR 03 +#define T_TELEP 04 +#define T_DART 05 +#define T_RUST 06 +#define NTRAPS 7 + +/* + * Potion types + */ +#define P_CONFUSE 0 +#define P_LSD 1 +#define P_POISON 2 +#define P_STRENGTH 3 +#define P_SEEINVIS 4 +#define P_HEALING 5 +#define P_MFIND 6 +#define P_TFIND 7 +#define P_RAISE 8 +#define P_XHEAL 9 +#define P_HASTE 10 +#define P_RESTORE 11 +#define P_BLIND 12 +#define P_LEVIT 13 +#define MAXPOTIONS 14 + +/* + * Scroll types + */ +#define S_CONFUSE 0 +#define S_MAP 1 +#define S_HOLD 2 +#define S_SLEEP 3 +#define S_ARMOR 4 +#define S_ID_POTION 5 +#define S_ID_SCROLL 6 +#define S_ID_WEAPON 7 +#define S_ID_ARMOR 8 +#define S_ID_R_OR_S 9 +#define S_SCARE 10 +#define S_FDET 11 +#define S_TELEP 12 +#define S_ENCH 13 +#define S_CREATE 14 +#define S_REMOVE 15 +#define S_AGGR 16 +#define S_PROTECT 17 +#define MAXSCROLLS 18 + +/* + * Weapon types + */ +#define MACE 0 +#define SWORD 1 +#define BOW 2 +#define ARROW 3 +#define DAGGER 4 +#define TWOSWORD 5 +#define DART 6 +#define SHIRAKEN 7 +#define SPEAR 8 +#define FLAME 9 /* fake entry for dragon breath (ick) */ +#define MAXWEAPONS 9 /* this should equal FLAME */ + +/* + * Armor types + */ +#define LEATHER 0 +#define RING_MAIL 1 +#define STUDDED_LEATHER 2 +#define SCALE_MAIL 3 +#define CHAIN_MAIL 4 +#define SPLINT_MAIL 5 +#define BANDED_MAIL 6 +#define PLATE_MAIL 7 +#define MAXARMORS 8 + +/* + * Ring types + */ +#define R_PROTECT 0 +#define R_ADDSTR 1 +#define R_SUSTSTR 2 +#define R_SEARCH 3 +#define R_SEEINVIS 4 +#define R_NOP 5 +#define R_AGGR 6 +#define R_ADDHIT 7 +#define R_ADDDAM 8 +#define R_REGEN 9 +#define R_DIGEST 10 +#define R_TELEPORT 11 +#define R_STEALTH 12 +#define R_SUSTARM 13 +#define MAXRINGS 14 + +/* + * Rod/Wand/Staff types + */ +#define WS_LIGHT 0 +#define WS_INVIS 1 +#define WS_ELECT 2 +#define WS_FIRE 3 +#define WS_COLD 4 +#define WS_POLYMORPH 5 +#define WS_MISSILE 6 +#define WS_HASTE_M 7 +#define WS_SLOW_M 8 +#define WS_DRAIN 9 +#define WS_NOP 10 +#define WS_TELAWAY 11 +#define WS_TELTO 12 +#define WS_CANCEL 13 +#define MAXSTICKS 14 + +/* + * Now we define the structures and types + */ + +/* + * Help list + */ +struct h_list { + char h_ch; + char *h_desc; + bool h_print; +}; + +/* + * Coordinate data type + */ +typedef struct { + int y; + int x; +} coord; + +typedef unsigned int str_t; + +/* + * Stuff about objects + */ +struct obj_info { + char *oi_name; + int oi_prob; + short oi_worth; + char *oi_guess; + bool oi_know; +}; + +/* + * Room structure + */ +struct room { + coord r_pos; /* Upper left corner */ + coord r_max; /* Size of room */ + coord r_gold; /* Where the gold is */ + int r_goldval; /* How much the gold is worth */ + short r_flags; /* Info about the room */ + int r_nexits; /* Number of exits */ + coord r_exit[12]; /* Where the exits are */ +}; + +/* + * Structure describing a fighting being + */ +struct stats { + str_t s_str; /* Strength */ + long s_exp; /* Experience */ + int s_lvl; /* Level of mastery */ + int s_arm; /* Armor class */ + short s_hpt; /* Hit points */ + char s_dmg[13]; /* String describing damage done */ + short s_maxhp; /* Max hit points */ +}; + +/* + * Structure for monsters and player + */ +union thing { + struct { + union thing *_l_next, *_l_prev; /* Next pointer in link */ + coord _t_pos; /* Position */ + bool _t_turn; /* If slowed, is it a turn to move */ + char _t_type; /* What it is */ + char _t_disguise; /* What mimic looks like */ + char _t_oldch; /* Character that was where it was */ + coord *_t_dest; /* Where it is running to */ + short _t_flags; /* State word */ + struct stats _t_stats; /* Physical description */ + struct room *_t_room; /* Current room for thing */ + union thing *_t_pack; /* What the thing is carrying */ + } _t; + struct { + union thing *_l_next, *_l_prev; /* Next pointer in link */ + int _o_type; /* What kind of object it is */ + coord _o_pos; /* Where it lives on the screen */ + char *_o_text; /* What it says if you read it */ + char _o_launch; /* What you need to launch it */ + char _o_packch; /* What character it is in the pack */ + char *_o_damage; /* Damage if used like sword */ + char *_o_hurldmg; /* Damage if thrown */ + int _o_count; /* Count for plural objects */ + int _o_which; /* Which object of a type it is */ + int _o_hplus; /* Plusses to hit */ + int _o_dplus; /* Plusses to damage */ + short _o_arm; /* Armor protection */ + short _o_flags; /* Information about objects */ + int _o_group; /* Group number for this object */ + char *_o_label; /* Label for object */ + } _o; +}; + +typedef union thing THING; + +#define l_next _t._l_next +#define l_prev _t._l_prev +#define t_pos _t._t_pos +#define t_turn _t._t_turn +#define t_type _t._t_type +#define t_disguise _t._t_disguise +#define t_oldch _t._t_oldch +#define t_dest _t._t_dest +#define t_flags _t._t_flags +#define t_stats _t._t_stats +#define t_pack _t._t_pack +#define t_room _t._t_room +#define o_type _o._o_type +#define o_pos _o._o_pos +#define o_text _o._o_text +#define o_launch _o._o_launch +#define o_packch _o._o_packch +#define o_damage _o._o_damage +#define o_hurldmg _o._o_hurldmg +#define o_count _o._o_count +#define o_which _o._o_which +#define o_hplus _o._o_hplus +#define o_dplus _o._o_dplus +#define o_arm _o._o_arm +#define o_charges o_arm +#define o_goldval o_arm +#define o_flags _o._o_flags +#define o_group _o._o_group +#define o_label _o._o_label + +/* + * describe a place on the level map + */ +typedef struct { + char p_ch; + char p_flags; + THING *p_monst; +} PLACE; + +/* + * Array containing information on all the various types of monsters + */ +struct monster { + char *m_name; /* What to call the monster */ + int m_carry; /* Probability of carrying something */ + short m_flags; /* Things about the monster */ + struct stats m_stats; /* Initial stats */ +}; + +/* + * External variables + */ + +extern bool After, Again, Allscore, Amulet, Door_stop, Fight_flush, + Firstmove, Has_hit, Inv_describe, Jump, Kamikaze, + Lower_msg, Move_on, Msg_esc, Noscore, Pack_used[], + Passgo, Playing, Q_comm, Running, Save_msg, See_floor, + Seenstairs, Stat_msg, Terse, To_death, Tombstone; + +extern char Dir_ch, File_name[], Home[], Huh[], *Inv_t_name[], + L_last_comm, L_last_dir, Last_comm, Last_dir, *Numname, + Outbuf[], *P_colors[], *R_stones[], *Release, Runch, + *S_names[], Take, *Tr_name[], *Ws_made[], *Ws_type[]; + +extern int A_class[], Count, Food_left, Hungry_state, Inpack, + Inv_type, Lastscore, Level, Max_hit, Max_level, Mpos, + N_objs, No_command, No_food, No_move, Ntraps, Purse, + Quiet, Vf_hit; + +extern unsigned int numscores; + +extern long Dnum, E_levels[], Seed; + +extern WINDOW *Hw; + +extern coord Delta, Oldpos, Stairs; + +extern PLACE Places[]; + +extern THING *Cur_armor, *Cur_ring[], *Cur_weapon, *L_last_pick, + *Last_pick, *Lvl_obj, *Mlist, Player; + +extern struct h_list Helpstr[]; + +extern struct room *Oldrp, Passages[], Rooms[]; + +extern struct stats Max_stats; + +extern struct monster Monsters[]; + +extern struct obj_info Arm_info[], Pot_info[], Ring_info[], + Scr_info[], Things[], Ws_info[], Weap_info[]; + +/* + * Function types + */ +void accnt_maze(int y, int x, int ny, int nx); +void badcheck(char *name, struct obj_info *info, int bound); +void bounce(THING *weap, char *mname, bool noend); +void call(void); +void check_level(void); +void conn(int r1, int r2); +void current(THING *cur, char *how, char *where); +void d_level(void); +void dig(int y, int x); +void discard(THING *item); +void do_chase(THING *th); +void do_maze(struct room *rp); +void do_motion(THING *obj, int ydelta, int xdelta); +void do_pot(int type, bool knowit); +void doadd(char *fmt, va_list args); +void door(struct room *rm, coord *cp); +void drain(void); +void draw_room(struct room *rp); +void encwrite(char *start, unsigned int size, FILE *outf); +void erase_lamp(coord *pos, struct room *rp); +void fall(THING *obj, bool pr); +void fire_bolt(coord *start, coord *dir, char *name); +void help(void); +void hit(char *er, char *ee, bool noend); +void horiz(struct room *rp, int starty); +void identify(void); +void illcom(char ch); +void invis_on(void); +void killed(THING *tp, bool pr); +void miss(char *er, char *ee, bool noend); +void money(int value); +void move_monst(THING *tp); +void move_msg(THING *obj); +void nameit(THING *obj, char *type, char *which, struct obj_info *op, char *(*prfunc)(THING *)); +void numpass(int y, int x); +void passnum(void); +void pr_spec(struct obj_info *info, int nitems); +void put_bool(void *b); +void put_inv_t(void *ip); +void put_str(void *str); +void put_things(void); +void putpass(coord *cp); +void raise_level(void); +void relocate(THING *th, coord *new_loc); +void remove_mon(coord *mp, THING *tp, bool waskill); +void reset_last(void); +void rust_armor(THING *arm); +void save_file(FILE *savef); +void search(void); +void set_know(THING *obj, struct obj_info *info); +void set_oldch(THING *tp, coord *cp); +void strucpy(char *s1, char *s2, int len); +void thunk(THING *weap, char *mname, bool noend); +void treas_room(void); +void turnref(void); +void u_level(void); +void uncurse(THING *obj); +void vert(struct room *rp, int startx); +void wait_for(char ch); +void waste_time(void); + +bool chase(THING *tp, coord *ee); +bool diag_ok(coord *sp, coord *ep); +bool dropcheck(THING *obj); +bool fallpos(coord *pos, coord *newpos); +bool find_floor(struct room *rp, coord *cp, int limit, bool monst); +bool is_magic(THING *obj); +bool levit_check(void); +bool pack_room(bool from_floor, THING *obj); +bool roll_em(THING *thatt, THING *thdef, THING *weap, bool hurl); +bool see_monst(THING *mp); +bool seen_stairs(void); +bool turn_ok(int y, int x); +bool turn_see(bool turn_off); + +char be_trapped(coord *tc); +char floor_ch(void); +char pack_char(void); + +char *charge_str(THING *obj); +char *choose_str(char *ts, char *ns); +char *inv_name(THING *obj, bool drop); +char *nullstr(THING *ignored); +char *num(int n1, int n2, char type); +char *ring_num(THING *obj); +char *set_mname(THING *tp); +char *vowelstr(char *str); + +int get_bool(void *vp, WINDOW *win); +int get_inv_t(void *vp, WINDOW *win); +int get_num(void *vp, WINDOW *win); +int get_sf(void *vp, WINDOW *win); +int get_str(void *vopt, WINDOW *win); +int trip_ch(int y, int x, char ch); + +coord *find_dest(THING *tp); +coord *rndmove(THING *who); + +THING *find_obj(int y, int x); +THING *get_item(char *purpose, int type); +THING *leave_pack(THING *obj, bool newobj, bool all); +THING *new_item(void); +THING *new_thing(void); + +struct room *roomin(coord *cp); diff --git a/netwait.c b/netwait.c new file mode 100644 index 0000000..05f1a55 --- /dev/null +++ b/netwait.c @@ -0,0 +1,298 @@ +/* + * score editor + * + * @(#)netwait.c 4.6 (Berkeley) 02/05/99 + */ + +# include +# include +# include +# include +# include + +# define TRUE 1 +# define FALSE 0 +# define bool char +# define RN (((Seed = Seed*11109+13849) >> 16) & 0xffff) + +# define MAXSTR 80 + +# include "netwait.h" + +SCORE Top_ten[10]; + +char frob, + Buf[BUFSIZ], + *Reason[] = { + "killed", + "quit", + "A total winner", + "killed with Amulet", + }; + +int Seed, + Inf; + +struct passwd *getpwnam(); + +int +main(ac, av) +int ac; +char **av; +{ + char *scorefile; + FILE *outf; + + if (ac == 1) + scorefile = SCOREFILE; + else + scorefile = av[1]; + Seed = getpid(); + + if ((Inf = open(scorefile, 2)) < 0) { + perror(scorefile); + exit(1); + } + frob = 0; + s_encread((char *) Top_ten, sizeof Top_ten, Inf); + + while (do_comm()) + continue; + + exit(0); +} + +/* + * do_comm: + * Get and execute a command + */ +bool +do_comm(void) +{ + char *sp; + SCORE *scp; + struct passwd *pp; + static FILE *outf = NULL; + static bool written = TRUE; + + printf("\nCommand: "); + while (isspace(Buf[0] = getchar()) || Buf[0] == '\n') + continue; + fgets(&Buf[1], BUFSIZ, stdin); + Buf[strlen(Buf) - 1] = '\0'; + switch (Buf[0]) { + case 'w': + if (strncmp(Buf, "write", strlen(Buf))) + goto def; + lseek(Inf, 0L, 0); + if (outf == NULL && (outf = fdopen(Inf, "w")) == NULL) { + perror("fdopen"); + exit(1); + } + fseek(outf, 0L, 0); + if (s_lock_sc()) + { + int (*fp)(); + + fp = signal(SIGINT, SIG_IGN); + frob = 0; + s_encwrite((char *) Top_ten, sizeof Top_ten, outf); + s_unlock_sc(); + signal(SIGINT, fp); + written = TRUE; + } + break; + + case 'a': + if (strncmp(Buf, "add", strlen(Buf))) + goto def; + add_score(); + written = FALSE; + break; + + case 'd': + if (strncmp(Buf, "delete", strlen(Buf))) + goto def; + del_score(); + written = FALSE; + break; + + case 'p': + if (strncmp(Buf, "print", strlen(Buf))) + goto def; + printf("\nTop Ten Rogueists:\nRank\tScore\tName\n"); + for (scp = Top_ten; scp < &Top_ten[10]; scp++) + if (!pr_score(scp, TRUE)) + break; + break; + + case 'q': + if (strncmp(Buf, "quit", strlen(Buf))) + goto def; + if (!written) { + printf("No write\n"); + written = TRUE; + } + else + return FALSE; + break; + + default: +def: + printf("Unkown command: \"%s\"\n", Buf); + } + return TRUE; +} + +/* + * add_score: + * Add a score to the score file + */ +void +add_score(void) +{ + SCORE *scp; + struct passwd *pp; + int i; + static SCORE new; + + printf("Name: "); + fgets(new.sc_name, MAXSTR, stdin); + new.sc_name[strlen(new.sc_name) - 1] = '\0'; + do { + printf("Reason: "); + if ((new.sc_flags = getchar()) < '0' || new.sc_flags > '2') { + for (i = 0; i < 3; i++) + printf("%d: %s\n", i, Reason[i]); + ungetc(new.sc_flags, stdin); + } + while (getchar() != '\n') + continue; + } while (new.sc_flags < '0' || new.sc_flags > '2'); + new.sc_flags -= '0'; + do { + printf("User: "); + fgets(Buf, BUFSIZ, stdin); + Buf[strlen(Buf) - 1] = '\0'; + if ((pp = getpwnam(Buf)) == NULL) + printf("who (%s)?\n", Buf); + } while (pp == NULL); + new.sc_uid = pp->pw_uid; + do { + printf("Monster: "); + if (!isalpha(new.sc_monster = getchar())) { + printf("type A-Za-z [%s]\n", unctrl(new.sc_monster)); + ungetc(new.sc_monster, stdin); + } + while (getchar() != '\n') + continue; + } while (!isalpha(new.sc_monster)); + printf("Score: "); + scanf("%d", &new.sc_score); + printf("Level: "); + scanf("%d", &new.sc_level); + while (getchar() != '\n') + continue; + pr_score(&new, FALSE); + printf("Really add it? "); + if (getchar() != 'y') + return; + while (getchar() != '\n') + continue; + insert_score(&new); +} + +/* + * pr_score: + * Print out a score entry. Return FALSE if last entry. + */ +void +pr_score(SCORE *scp, bool num) +{ + struct passwd *pp; + + if (scp->sc_score) { + if (num) + printf("%d", scp - Top_ten + 1); + printf("\t%d\t%s: %s on level %d", scp->sc_score, scp->sc_name, + Reason[scp->sc_flags], scp->sc_level); + if (scp->sc_flags == 0) + printf(" by %s", s_killname((char) scp->sc_monster, TRUE)); + if ((pp = getpwuid(scp->sc_uid)) == NULL) + printf(" (%d)", scp->sc_uid); + else + printf(" (%s)", pp->pw_name); + putchar('\n'); + } + return scp->sc_score; +} + +/* + * insert_score: + * Insert a score into the top ten list + */ +void +insert_score(SCORE *new) +{ + SCORE *scp, *sc2; + int flags, uid, amount; + + flags = new->sc_flags; + uid = new->sc_uid; + amount = new->sc_score; + + for (scp = Top_ten; scp < &Top_ten[10]; scp++) + if (amount > scp->sc_score) + break; + else if (flags != 2 && scp->sc_uid == uid && scp->sc_flags != 2) + scp = &Top_ten[10]; + if (scp < &Top_ten[10]) { + if (flags != 2) + for (sc2 = scp; sc2 < &Top_ten[10]; sc2++) { + if (sc2->sc_uid == uid && sc2->sc_flags != 2) + break; + } + else + sc2 = &Top_ten[9]; + while (sc2 > scp) { + *sc2 = sc2[-1]; + sc2--; + } + *scp = *new; + sc2 = scp; + } +} + +/* + * del_score: + * Delete a score from the score list. + */ +void +del_score(void) +{ + SCORE *scp; + int i; + int num; + + for (;;) { + printf("Which score? "); + fgets(Buf, BUFSIZ, stdin); + if (Buf[0] == '\n') + return; + sscanf(Buf, "%d", &num); + if (num < 1 || num > 10) + printf("range is 1-10\n"); + else + break; + } + num--; + for (scp = &Top_ten[num]; scp < &Top_ten[9]; scp++) + *scp = scp[1]; + Top_ten[9].sc_score = 0; + for (i = 0; i < MAXSTR; i++) + Top_ten[9].sc_name[i] = RN; + Top_ten[9].sc_flags = RN; + Top_ten[9].sc_level = RN; + Top_ten[9].sc_monster = RN; + Top_ten[9].sc_uid = RN; +} diff --git a/netwait.h b/netwait.h new file mode 100644 index 0000000..7a4706c --- /dev/null +++ b/netwait.h @@ -0,0 +1,17 @@ +/* + * Score file structure + * + * @(#)netwait.h 4.6 (Berkeley) 02/05/99 + */ + +struct sc_ent { + unsigned int sc_uid; + unsigned short sc_score; + unsigned int sc_flags; + unsigned short sc_monster; + char sc_name[MAXSTR]; + unsigned short sc_level; + long sc_time; +}; + +typedef struct sc_ent SCORE; diff --git a/network.c b/network.c new file mode 100644 index 0000000..9fc6a27 --- /dev/null +++ b/network.c @@ -0,0 +1,84 @@ +/* + * This file contains misc functions for dealing with armor + * + * @(#)network.c 4.14 (Berkeley) 02/05/99 + */ + +#include +#include "netprot.h" + +/* + * wear: + * The player wants to wear something, so let him/her put it on. + */ +void +wear(void) +{ + THING *obj; + char *sp; + + if ((obj = get_item("wear", ARMOR)) == NULL) + return; + if (Cur_armor != NULL) + { + addmsg("you are already wearing some"); + if (!Terse) + addmsg(". You'll have to take it off first"); + endmsg(); + After = FALSE; + return; + } + if (obj->o_type != ARMOR) + { + msg("you can't wear that"); + return; + } + waste_time(); + obj->o_flags |= ISKNOW; + sp = inv_name(obj, TRUE); + Cur_armor = obj; + if (!Terse) + addmsg("you are now "); + msg("wearing %s", sp); +} + +/* + * take_off: + * Get the armor off of the players back + */ +void +take_off(void) +{ + THING *obj; + + if ((obj = Cur_armor) == NULL) + { + After = FALSE; + if (Terse) + msg("not wearing armor"); + else + msg("you aren't wearing any armor"); + return; + } + if (!dropcheck(Cur_armor)) + return; + Cur_armor = NULL; + if (Terse) + addmsg("was"); + else + addmsg("you used to be"); + msg(" wearing %c) %s", obj->o_packch, inv_name(obj, TRUE)); +} + +/* + * waste_time: + * Do nothing but let other things happen + */ +void +waste_time(void) +{ + do_daemons(BEFORE); + do_fuses(BEFORE); + do_daemons(AFTER); + do_fuses(AFTER); +} diff --git a/network.h b/network.h new file mode 100644 index 0000000..4b188d9 --- /dev/null +++ b/network.h @@ -0,0 +1,82 @@ +/* + * Defines for things used in find.c + * + * @(#)network.h 4.35 (Berkeley) 02/05/99 + */ + +/* + * Don't change the constants, since they are used for sizes in many + * places in the program. + */ + +#include + +#undef SIGTSTP + +#define MAXSTR 1024 /* maximum length of strings */ +#define MAXLINES 32 /* maximum number of screen lines used */ +#define MAXCOLS 80 /* maximum number of screen columns used */ + +#define RN (((Seed = Seed*11109+13849) >> 16) & 0xffff) +#ifdef CTRL +#undef CTRL +#endif +#define CTRL(c) (c & 037) + +/* + * Now all the global variables + */ + +extern bool Got_ltc, In_shell, Wizard; + +extern char Fruit[], Orig_dsusp, Prbuf[], Whoami[]; + +extern int Fd; + +#ifdef TIOCGLTC +extern struct ltchars Ltc; +#endif TIOCGLTC + +/* + * Function types + */ + +#include +#include + +void auto_save(int sig); +void come_down(void); +void doctor(void); +void end_line(void); +void endit(int sig); +void fatal(char *s); +void getltchars(void); +void land(void); +void leave(int sig); +void my_exit(int st); +void nohaste(void); +void playit(void); +void playltchars(void); +void print_disc(char type); +void quit(int sig); +void resetltchars(void); +void rollwand(void); +void runners(void); +void set_order(short *order, int numthings); +void sight(void); +void stomach(void); +void swander(void); +void tstp(int ignored); +void unconfuse(void); +void unsee(void); +void visuals(void); + +char add_line(char *fmt, char *arg); + +char *killname(char monst, bool doart); +char *nothing(char type); +char *type_name(int type); + +#ifdef CHECKTIME +void checkout(int sig); +#endif diff --git a/packet.c b/packet.c new file mode 100644 index 0000000..2ef7c53 --- /dev/null +++ b/packet.c @@ -0,0 +1,486 @@ +#include +#include +#include "netprot.h" + +/* + * Routines to deal with the pack + * + * @(#)packet.c 4.40 (Berkeley) 02/05/99 + */ + +/* + * add_pack: + * Pick up an object and add it to the pack. If the argument is + * non-null use it as the linked_list pointer instead of gettting + * it off the ground. + */ +void +add_pack(THING *obj, bool silent) +{ + THING *op, *lp; + bool from_floor; + + from_floor = FALSE; + if (obj == NULL) + { + if ((obj = find_obj(Hero.y, Hero.x)) == NULL) + return; + from_floor = TRUE; + } + + /* + * Check for and deal with scare monster scrolls + */ + if (obj->o_type == SCROLL && obj->o_which == S_SCARE) + if (obj->o_flags & ISFOUND) + { + detach(Lvl_obj, obj); + mvaddch(Hero.y, Hero.x, floor_ch()); + chat(Hero.y, Hero.x) = (Proom->r_flags & ISGONE) ? PASSAGE : FLOOR; + discard(obj); + msg("the scroll turns to dust as you pick it up"); + return; + } + + if (Pack == NULL) + { + Pack = obj; + obj->o_packch = pack_char(); + Inpack++; + } + else + { + lp = NULL; + for (op = Pack; op != NULL; op = next(op)) + { + if (op->o_type != obj->o_type) + lp = op; + else + { + while (op->o_type == obj->o_type && op->o_which != obj->o_which) + { + lp = op; + if (next(op) == NULL) + break; + else + op = next(op); + } + if (op->o_type == obj->o_type && op->o_which == obj->o_which) + if (ISMULT(op->o_type)) + { + if (!pack_room(from_floor, obj)) + return; + op->o_count++; +dump_it: + discard(obj); + obj = op; + lp = NULL; + goto out; + } + else if (obj->o_group) + { + lp = op; + while (op->o_type == obj->o_type + && op->o_which == obj->o_which + && op->o_group != obj->o_group) + { + lp = op; + if (next(op) == NULL) + break; + else + op = next(op); + } + if (op->o_type == obj->o_type + && op->o_which == obj->o_which + && op->o_group == obj->o_group) + { + op->o_count += obj->o_count; + Inpack--; + if (!pack_room(from_floor, obj)) + return; + goto dump_it; + } + } + else + lp = op; +out: + break; + } + } + + if (lp != NULL) + if (!pack_room(from_floor, obj)) + return; + else + { + obj->o_packch = pack_char(); + next(obj) = next(lp); + prev(obj) = lp; + if (next(lp) != NULL) + prev(next(lp)) = obj; + next(lp) = obj; + } + } + + obj->o_flags |= ISFOUND; + + /* + * If this was the object of something's desire, that monster will + * get mad and run at the hero. + */ + for (op = Mlist; op != NULL; op = next(op)) + if (op->t_dest = &obj->o_pos) + op->t_dest = &Hero; + + if (obj->o_type == AMULET) + Amulet = TRUE; + /* + * Notify the user + */ + if (!silent) + { + if (!Terse) + addmsg("you now have "); + msg("%s (%c)", inv_name(obj, !Terse), obj->o_packch); + } +} + +/* + * pack_room: + * See if there's room in the pack. If not, print out an + * appropriate message + */ +bool +pack_room(bool from_floor, THING *obj) +{ + if (++Inpack > MAXPACK) + { + if (!Terse) + addmsg("there's "); + addmsg("no room"); + if (!Terse) + addmsg(" in your pack"); + endmsg(); + if (from_floor) + move_msg(obj); + Inpack = MAXPACK; + return FALSE; + } + + if (from_floor) + { + detach(Lvl_obj, obj); + mvaddch(Hero.y, Hero.x, floor_ch()); + chat(Hero.y, Hero.x) = (Proom->r_flags & ISGONE) ? PASSAGE : FLOOR; + } + + return TRUE; +} + +/* + * leave_pack: + * Take an item out of the pack + */ +THING * +leave_pack(THING *obj, bool newobj, bool all) +{ + THING *nobj; + + Inpack--; + nobj = obj; + if (obj->o_count > 1 && !all) + { + Last_pick = obj; + obj->o_count--; + if (obj->o_group) + Inpack++; + if (newobj) + { + nobj = new_item(); + *nobj = *obj; + next(nobj) = NULL; + prev(nobj) = NULL; + nobj->o_count = 1; + } + } + else + { + Last_pick = NULL; + Pack_used[obj->o_packch - 'a'] = FALSE; + detach(Pack, obj); + } + return nobj; +} + +/* + * pack_char: + * Return the next unused pack character. + */ +char +pack_char(void) +{ + bool *bp; + + for (bp = Pack_used; *bp; bp++) + continue; + *bp = TRUE; + return (bp - Pack_used) + 'a'; +} + +/* + * inventory: + * List what is in the pack. Return TRUE if there is something of + * the given type. + */ +bool +inventory(THING *list, int type) +{ + static char inv_temp[MAXSTR]; + + N_objs = 0; + for (; list != NULL; list = next(list)) + { + if (type && type != list->o_type && !(type == CALLABLE && + list->o_type != FOOD && list->o_type != AMULET) && + !(type == R_OR_S && (list->o_type == RING || list->o_type == STICK))) + continue; + N_objs++; +#ifdef MASTER + if (!list->o_packch) + strcpy(inv_temp, "%s"); + else +#endif + sprintf(inv_temp, "%c) %%s", list->o_packch); + Msg_esc = TRUE; + if (add_line(inv_temp, inv_name(list, FALSE)) == ESCAPE) + { + Msg_esc = FALSE; + msg(""); + return TRUE; + } + Msg_esc = FALSE; + } + if (N_objs == 0) + { + if (Terse) + msg(type == 0 ? "empty handed" : + "nothing appropriate"); + else + msg(type == 0 ? "you are empty handed" : + "you don't have anything appropriate"); + return FALSE; + } + end_line(); + return TRUE; +} + +/* + * pick_up: + * Add something to characters pack. + */ +void +pick_up(char ch) +{ + THING *obj; + + if (on(Player, ISLEVIT)) + return; + + obj = find_obj(Hero.y, Hero.x); + if (Move_on) + move_msg(obj); + else + switch (ch) + { + case GOLD: + if (obj == NULL) + return; + money(obj->o_goldval); + detach(Lvl_obj, obj); + discard(obj); + Proom->r_goldval = 0; + break; + default: +#ifdef MASTER + debug("Where did you pick a '%s' up???", unctrl(ch)); +#endif + case ARMOR: + case POTION: + case FOOD: + case WEAPON: + case SCROLL: + case AMULET: + case RING: + case STICK: + add_pack((THING *) NULL, FALSE); + break; + } +} + +/* + * move_msg: + * Print out the message if you are just moving onto an object + */ +void +move_msg(THING *obj) +{ + if (!Terse) + addmsg("you "); + msg("moved onto %s", inv_name(obj, TRUE)); +} + +/* + * picky_inven: + * Allow player to inventory a single item + */ +void +picky_inven(void) +{ + THING *obj; + char mch; + + if (Pack == NULL) + msg("you aren't carrying anything"); + else if (next(Pack) == NULL) + msg("a) %s", inv_name(Pack, FALSE)); + else + { + msg(Terse ? "item: " : "which item do you wish to inventory: "); + Mpos = 0; + if ((mch = readchar()) == ESCAPE) + { + msg(""); + return; + } + for (obj = Pack; obj != NULL; obj = next(obj)) + if (mch == obj->o_packch) + { + msg("%c) %s", mch, inv_name(obj, FALSE)); + return; + } + msg("'%s' not in pack", unctrl(mch)); + } +} + +/* + * get_item: + * Pick something out of a pack for a purpose + */ +THING * +get_item(char *purpose, int type) +{ + THING *obj; + char ch; + + if (Pack == NULL) + msg("you aren't carrying anything"); + else if (Again) + if (Last_pick) + return Last_pick; + else + msg("you ran out"); + else + { + for (;;) + { + if (!Terse) + addmsg("which object do you want to "); + addmsg(purpose); + if (Terse) + addmsg(" what"); + msg("? (* for list): "); + ch = readchar(); + Mpos = 0; + /* + * Give the poor player a chance to abort the command + */ + if (ch == ESCAPE) + { + reset_last(); + After = FALSE; + msg(""); + return NULL; + } + N_objs = 1; /* normal case: person types one char */ + if (ch == '*') + { + Mpos = 0; + if (inventory(Pack, type) == 0) + { + After = FALSE; + return NULL; + } + continue; + } + for (obj = Pack; obj != NULL; obj = next(obj)) + if (obj->o_packch == ch) + break; + if (obj == NULL) + { + msg("that's not a valid item"); + continue; + } + else + return obj; + } + } + return NULL; +} + +/* + * money: + * Add or subtract gold from the pack + */ +void +money(int value) +{ + Purse += value; + mvaddch(Hero.y, Hero.x, floor_ch()); + chat(Hero.y, Hero.x) = (Proom->r_flags & ISGONE) ? PASSAGE : FLOOR; + if (value > 0) + { + if (!Terse) + addmsg("you found "); + msg("%d gold pieces", value); + } +} + +/* + * floor_ch: + * Return the appropriate floor character for her room + */ +char +floor_ch(void) +{ + if (Proom->r_flags & ISGONE) + return PASSAGE; + return (show_floor() ? FLOOR : ' '); +} + +/* + * floor_at: + * Return the character at hero's position, taking See_floor + * into account + */ +char +floor_at(void) +{ + char ch; + + ch = chat(Hero.y, Hero.x); + if (ch == FLOOR) + ch = floor_ch(); + return ch; +} + +/* + * reset_last: + * Reset the last command when the current one is aborted + */ +void +reset_last(void) +{ + Last_comm = L_last_comm; + Last_dir = L_last_dir; + Last_pick = L_last_pick; +} diff --git a/pipes.c b/pipes.c new file mode 100644 index 0000000..cfa39cf --- /dev/null +++ b/pipes.c @@ -0,0 +1,489 @@ +/* + * This file has all the code for the option command. I would rather + * this command were not necessary, but it is the only way to keep the + * wolves off of my back. + * + * @(#)pipes.c 4.24 (Berkeley) 05/10/83 + */ + +#include +#include +#include "netprot.h" + +#define EQSTR(a, b, c) (strncmp(a, b, c) == 0) + +#define NUM_OPTS (sizeof optlist / sizeof (OPTION)) + +#ifndef attron +# define erasechar() _tty.sg_erase +# define killchar() _tty.sg_kill +#endif + +/* + * description of an option and what to do with it + */ +struct optstruct { + char *o_name; /* option name */ + char *o_prompt; /* prompt for interactive entry */ + void *o_opt; /* pointer to thing to set */ + /* function to print value */ + void (*o_putfunc)(void *opt); + /* function to get value interactively */ + int (*o_getfunc)(void *opt, WINDOW *win); +}; + +typedef struct optstruct OPTION; + +void pr_optname(OPTION *op); + +OPTION optlist[] = { + {"terse", "Terse output", + (int *) &Terse, put_bool, get_bool }, + {"flush", "Flush typeahead during battle", + (int *) &Fight_flush, put_bool, get_bool }, + {"jump", "Show position only at end of run", + (int *) &Jump, put_bool, get_bool }, + {"seefloor", "Show the lamp-illuminated floor", + (int *) &See_floor, put_bool, get_sf }, + {"passgo", "Follow turnings in passageways", + (int *) &Passgo, put_bool, get_bool }, + {"tombstone", "Print out tombstone when killed", + (int *) &Tombstone, put_bool, get_bool }, + {"inven", "Inventory style", + (int *) &Inv_type, put_inv_t, get_inv_t }, + {"name", "Name", + (int *) Whoami, put_str, get_str }, + {"fruit", "Fruit", + (int *) Fruit, put_str, get_str }, + {"file", "Save file", + (int *) File_name, put_str, get_str } +}; + +/* + * option: + * Print and then set options from the terminal + */ +void +option(void) +{ + OPTION *op; + int retval; + + wclear(Hw); + /* + * Display current values of options + */ + for (op = optlist; op < &optlist[NUM_OPTS]; op++) + { + pr_optname(op); + (*op->o_putfunc)(op->o_opt); + waddch(Hw, '\n'); + } + /* + * Set values + */ + wmove(Hw, 0, 0); + for (op = optlist; op < &optlist[NUM_OPTS]; op++) + { + pr_optname(op); + if ((retval = (*op->o_getfunc)(op->o_opt, Hw))) + if (retval == QUIT) + break; + else if (op > optlist) { /* MINUS */ + wmove(Hw, (op - optlist) - 1, 0); + op -= 2; + } + else /* trying to back up beyond the top */ + { + putchar('\007'); + wmove(Hw, 0, 0); + op--; + } + } + /* + * Switch back to original screen + */ + wmove(Hw, LINES - 1, 0); + waddstr(Hw, "--Press space to continue--"); + wrefresh(Hw); + wait_for(' '); + clearok(curscr, TRUE); +#ifdef attron + touchwin(stdscr); +#endif + After = FALSE; +} + +/* + * pr_optname: + * Print out the option name prompt + */ +void +pr_optname(OPTION *op) +{ + wprintw(Hw, "%s (\"%s\"): ", op->o_prompt, op->o_name); +} + +/* + * put_bool + * Put out a boolean + */ +void +put_bool(void *b) +{ + waddstr(Hw, *(bool *) b ? "True" : "False"); +} + +/* + * put_str: + * Put out a string + */ +void +put_str(void *str) +{ + waddstr(Hw, (char *) str); +} + +/* + * put_inv_t: + * Put out an inventory type + */ +void +put_inv_t(void *ip) +{ + waddstr(Hw, Inv_t_name[*(int *) ip]); +} + +/* + * get_bool: + * Allow changing a boolean option and print it out + */ +int +get_bool(void *vp, WINDOW *win) +{ + bool *bp = (bool *) vp; + int oy, ox; + bool op_bad; + + op_bad = TRUE; + getyx(win, oy, ox); + waddstr(win, *bp ? "True" : "False"); + while (op_bad) + { + wmove(win, oy, ox); + wrefresh(win); + switch (readchar()) + { + case 't': + case 'T': + *bp = TRUE; + op_bad = FALSE; + break; + case 'f': + case 'F': + *bp = FALSE; + op_bad = FALSE; + break; + case '\n': + case '\r': + op_bad = FALSE; + break; + case ESCAPE: + return QUIT; + case '-': + return MINUS; + default: + wmove(win, oy, ox + 10); + waddstr(win, "(T or F)"); + } + } + wmove(win, oy, ox); + waddstr(win, *bp ? "True" : "False"); + waddch(win, '\n'); + return NORM; +} + +/* + * get_sf: + * Change value and handle transition problems from See_floor to + * !See_floor. + */ +int +get_sf(void *vp, WINDOW *win) +{ + bool *bp = (bool *) vp; + bool was_sf; + int retval; + + was_sf = See_floor; + retval = get_bool(bp, win); + if (retval == QUIT) return(QUIT); + if (was_sf != See_floor) + { + if (!See_floor) { + See_floor = TRUE; + erase_lamp(&Hero, Proom); + See_floor = FALSE; + } + else + look(FALSE); + } + return(NORM); +} + +/* + * get_str: + * Set a string option + */ +#define MAXINP 50 /* max string to read from terminal or environment */ + +int +get_str(void *vopt, WINDOW *win) +{ + char *opt = (char *) vopt; + char *sp; + int c, oy, ox; + int i; + static char buf[MAXSTR]; + + getyx(win, oy, ox); + wrefresh(win); + /* + * loop reading in the string, and put it in a temporary buffer + */ + for (sp = buf; (c = readchar()) != '\n' && c != '\r' && c != ESCAPE; + wclrtoeol(win), wrefresh(win)) + { + if (c == -1) + continue; + else if (c == erasechar()) /* process erase character */ + { + if (sp > buf) + { + sp--; + for (i = strlen(unctrl(*sp)); i; i--) + waddch(win, '\b'); + } + continue; + } + else if (c == killchar()) /* process kill character */ + { + sp = buf; + wmove(win, oy, ox); + continue; + } + else if (sp == buf) + { + if (c == '-' && win != stdscr) + break; + else if (c == '~') + { + strcpy(buf, Home); + waddstr(win, Home); + sp += strlen(Home); + continue; + } + } + if (sp >= &buf[MAXINP] || !(isprint(c) || c == ' ')) + putchar(CTRL('G')); + else + { + *sp++ = c; + waddstr(win, unctrl(c)); + } + } + *sp = '\0'; + if (sp > buf) /* only change option if something has been typed */ + strucpy(opt, buf, strlen(buf)); + mvwprintw(win, oy, ox, "%s\n", opt); + wrefresh(win); + if (win == stdscr) + Mpos += sp - buf; + if (c == '-') + return MINUS; + else if (c == ESCAPE) + return QUIT; + else + return NORM; +} + +/* + * get_inv_t + * Get an inventory type name + */ +int +get_inv_t(void *vp, WINDOW *win) +{ + int *ip = (int *) vp; + int oy, ox; + bool op_bad; + + op_bad = TRUE; + getyx(win, oy, ox); + waddstr(win, Inv_t_name[*ip]); + while (op_bad) + { + wmove(win, oy, ox); + wrefresh(win); + switch (readchar()) + { + case 'o': + case 'O': + *ip = INV_OVER; + op_bad = FALSE; + break; + case 's': + case 'S': + *ip = INV_SLOW; + op_bad = FALSE; + break; + case 'c': + case 'C': + *ip = INV_CLEAR; + op_bad = FALSE; + break; + case '\n': + case '\r': + op_bad = FALSE; + break; + case ESCAPE: + return QUIT; + case '-': + return MINUS; + default: + wmove(win, oy, ox + 15); + waddstr(win, "(O, S, or C)"); + } + } + mvwprintw(win, oy, ox, "%s\n", Inv_t_name[*ip]); + return NORM; +} + + +#ifdef MASTER +/* + * get_num: + * Get a numeric option + */ +int +get_num(void *vp, WINDOW *win) +{ + short *opt = (short *) vp; + int i; + static char buf[MAXSTR]; + + if ((i = get_str(buf, win)) == NORM) + *opt = atoi(buf); + return i; +} +#endif + +/* + * 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; + OPTION *op; + int len; + char **i; + char *start; + + while (*str) + { + /* + * Get option name + */ + 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) /* if option is a boolean */ + *(bool *)op->o_opt = TRUE; /* NOSTRICT */ + else /* string option */ + { + /* + * Skip to start of string value + */ + for (str = sp + 1; *str == '='; str++) + continue; + if (*str == '~') + { + strcpy((char *) op->o_opt, Home); /* NOSTRICT */ + start = (char *) op->o_opt + strlen(Home);/* NOSTRICT */ + while (*++str == '/') + continue; + } + else + start = (char *) op->o_opt; /* NOSTRICT */ + /* + * Skip to end of string value + */ + for (sp = str + 1; *sp && *sp != ','; sp++) + continue; + /* + * check for type of inventory + */ + if (op->o_putfunc == put_inv_t) + { + if (islower(*str)) + *str = toupper(*str); + for (i = Inv_t_name; i <= &Inv_t_name[INV_CLEAR]; i++) + if (strncmp(str, *i, sp - str) == 0) + { + Inv_type = i - Inv_t_name; + break; + } + } + else + strucpy(start, str, sp - str); + } + break; + } + /* + * check for "noname" for booleans + */ + else if (op->o_putfunc == put_bool + && EQSTR(str, "no", 2) && EQSTR(str + 2, op->o_name, len - 2)) + { + *(bool *)op->o_opt = FALSE; /* NOSTRICT */ + break; + } + + /* + * skip to start of next option name + */ + while (*sp && !isalpha(*sp)) + sp++; + str = sp; + } +} + +/* + * strucpy: + * Copy string using unctrl for things + */ +void +strucpy(char *s1, char *s2, int len) +{ + if (len > MAXINP) + len = MAXINP; + while (len--) + { + if (isprint(*s2) || *s2 == ' ') + *s1++ = *s2; + s2++; + } + *s1 = '\0'; +} diff --git a/rcopy.c b/rcopy.c new file mode 100644 index 0000000..cc86d10 --- /dev/null +++ b/rcopy.c @@ -0,0 +1,701 @@ +/* + * Contains functions for dealing with things like potions, scrolls, + * and other items. + * + * @(#)rcopy.c 4.53 (Berkeley) 02/05/99 + */ + +#include +#ifdef attron +#include +#endif attron +#include +#include "netprot.h" + +/* + * inv_name: + * Return the name of something as it would appear in an + * inventory. + */ +char * +inv_name(THING *obj, bool drop) +{ + char *pb; + struct obj_info *op; + char *sp; + int which; + + pb = Prbuf; + which = obj->o_which; + switch (obj->o_type) + { + when POTION: + nameit(obj, "potion", P_colors[which], &Pot_info[which], nullstr); + when RING: + nameit(obj, "ring", R_stones[which], &Ring_info[which], ring_num); + when STICK: + nameit(obj, Ws_type[which], Ws_made[which], &Ws_info[which], charge_str); + when SCROLL: + if (obj->o_count == 1) + { + strcpy(pb, "A scroll "); + pb = &Prbuf[9]; + } + else + { + sprintf(pb, "%d scrolls ", obj->o_count); + pb = &Prbuf[strlen(Prbuf)]; + } + op = &Scr_info[which]; + if (op->oi_know) + sprintf(pb, "of %s", op->oi_name); + else if (op->oi_guess) + sprintf(pb, "called %s", op->oi_guess); + else + sprintf(pb, "titled '%s'", S_names[which]); + when FOOD: + if (which == 1) + if (obj->o_count == 1) + sprintf(pb, "A%s %s", vowelstr(Fruit), Fruit); + else + sprintf(pb, "%d %ss", obj->o_count, Fruit); + else + if (obj->o_count == 1) + strcpy(pb, "Some food"); + else + sprintf(pb, "%d rations of food", obj->o_count); + when WEAPON: + sp = Weap_info[which].oi_name; + if (obj->o_count > 1) + sprintf(pb, "%d ", obj->o_count); + else + sprintf(pb, "A%s ", vowelstr(sp)); + pb = &Prbuf[strlen(Prbuf)]; + if (obj->o_flags & ISKNOW) + sprintf(pb, "%s %s", num(obj->o_hplus,obj->o_dplus,WEAPON), sp); + else + sprintf(pb, "%s", sp); + if (obj->o_count > 1) + strcat(pb, "s"); + if (obj->o_label != NULL) + { + pb = &Prbuf[strlen(Prbuf)]; + sprintf(pb, " called %s", obj->o_label); + } + when ARMOR: + sp = Arm_info[which].oi_name; + if (obj->o_flags & ISKNOW) + { + sprintf(pb, "%s %s [", + num(A_class[which] - obj->o_arm, 0, ARMOR), sp); + if (!Terse) + strcat(pb, "protection "); + pb = &Prbuf[strlen(Prbuf)]; + sprintf(pb, "%d]", 10 - obj->o_arm); + } + else + sprintf(pb, "%s", sp); + if (obj->o_label != NULL) + { + pb = &Prbuf[strlen(Prbuf)]; + sprintf(pb, " called %s", obj->o_label); + } + when AMULET: + strcpy(pb, "The Amulet of Yendor"); + when GOLD: + sprintf(Prbuf, "%d Gold pieces", obj->o_goldval); +#ifdef MASTER + otherwise: + debug("Picked up something funny %s", unctrl(obj->o_type)); + sprintf(pb, "Something bizarre %s", unctrl(obj->o_type)); +#endif + } + if (Inv_describe) + { + if (obj == Cur_armor) + strcat(pb, " (being worn)"); + if (obj == Cur_weapon) + strcat(pb, " (weapon in hand)"); + if (obj == Cur_ring[LEFT]) + strcat(pb, " (on left hand)"); + else if (obj == Cur_ring[RIGHT]) + strcat(pb, " (on right hand)"); + } + if (drop && isupper(Prbuf[0])) + Prbuf[0] = tolower(Prbuf[0]); + else if (!drop && islower(*Prbuf)) + *Prbuf = toupper(*Prbuf); + Prbuf[MAXSTR-1] = '\0'; + return Prbuf; +} + +/* + * drop: + * Put something down + */ +void +drop(void) +{ + char ch; + THING *obj; + + ch = chat(Hero.y, Hero.x); + if (ch != FLOOR && ch != PASSAGE) + { + After = FALSE; + msg("there is something there already"); + return; + } + if ((obj = get_item("drop", 0)) == NULL) + return; + if (!dropcheck(obj)) + return; + obj = leave_pack(obj, TRUE, !ISMULT(obj->o_type)); + /* + * Link it into the level object list + */ + attach(Lvl_obj, obj); + chat(Hero.y, Hero.x) = obj->o_type; + flat(Hero.y, Hero.x) |= F_DROPPED; + obj->o_pos = Hero; + if (obj->o_type == AMULET) + Amulet = FALSE; + msg("dropped %s", inv_name(obj, TRUE)); +} + +/* + * dropcheck: + * Do special checks for dropping or unweilding|unwearing|unringing + */ +bool +dropcheck(THING *obj) +{ + if (obj == NULL) + return TRUE; + if (obj != Cur_armor && obj != Cur_weapon + && obj != Cur_ring[LEFT] && obj != Cur_ring[RIGHT]) + return TRUE; + if (obj->o_flags & ISCURSED) + { + msg("you can't. It appears to be cursed"); + return FALSE; + } + if (obj == Cur_weapon) + Cur_weapon = NULL; + else if (obj == Cur_armor) + { + waste_time(); + Cur_armor = NULL; + } + else + { + Cur_ring[obj == Cur_ring[LEFT] ? LEFT : RIGHT] = NULL; + switch (obj->o_which) + { + case R_ADDSTR: + chg_str(-obj->o_arm); + break; + case R_SEEINVIS: + unsee(); + extinguish(unsee); + break; + } + } + return TRUE; +} + +/* + * new_thing: + * Return a new thing + */ +THING * +new_thing(void) +{ + THING *cur; + int r; + + cur = new_item(); + cur->o_hplus = 0; + cur->o_dplus = 0; + cur->o_damage = cur->o_hurldmg = "0x0"; + cur->o_arm = 11; + cur->o_count = 1; + cur->o_group = 0; + cur->o_flags = 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 ? 2 : pick_one(Things, NUMTHINGS)) + { + when 0: + cur->o_type = POTION; + cur->o_which = pick_one(Pot_info, MAXPOTIONS); + when 1: + cur->o_type = SCROLL; + cur->o_which = pick_one(Scr_info, MAXSCROLLS); + when 2: + cur->o_type = FOOD; + No_food = 0; + if (rnd(10) != 0) + cur->o_which = 0; + else + cur->o_which = 1; + when 3: + init_weapon(cur, pick_one(Weap_info, MAXWEAPONS)); + if ((r = rnd(100)) < 10) + { + cur->o_flags |= ISCURSED; + cur->o_hplus -= rnd(3) + 1; + } + else if (r < 15) + cur->o_hplus += rnd(3) + 1; + when 4: + cur->o_type = ARMOR; + cur->o_which = pick_one(Arm_info, MAXARMORS); + cur->o_arm = A_class[cur->o_which]; + if ((r = rnd(100)) < 20) + { + cur->o_flags |= ISCURSED; + cur->o_arm += rnd(3) + 1; + } + else if (r < 28) + cur->o_arm -= rnd(3) + 1; + when 5: + cur->o_type = RING; + cur->o_which = pick_one(Ring_info, MAXRINGS); + switch (cur->o_which) + { + when R_ADDSTR: + case R_PROTECT: + case R_ADDHIT: + case R_ADDDAM: + if ((cur->o_arm = rnd(3)) == 0) + { + cur->o_arm = -1; + cur->o_flags |= ISCURSED; + } + when R_AGGR: + case R_TELEPORT: + cur->o_flags |= ISCURSED; + } + when 6: + cur->o_type = STICK; + cur->o_which = pick_one(Ws_info, MAXSTICKS); + fix_stick(cur); +#ifdef MASTER + otherwise: + debug("Picked a bad kind of object"); + wait_for(' '); +#endif + } + return cur; +} + +/* + * pick_one: + * Pick an item out of a list of nitems possible objects + */ +int +pick_one(struct obj_info *info, int nitems) +{ + struct obj_info *end; + struct obj_info *start; + int i; + + start = info; + for (end = &info[nitems], i = rnd(100); info < end; info++) + if (i < info->oi_prob) + break; + if (info == end) + { +#ifdef MASTER + if (Wizard) + { + msg("bad pick_one: %d from %d items", i, nitems); + for (info = start; info < end; info++) + msg("%s: %d%%", info->oi_name, info->oi_prob); + } +#endif + info = start; + } + return info - start; +} + +/* + * discovered: + * list what the player has discovered in this game of a certain type + */ +static int Line_cnt = 0; + +static bool Newpage = FALSE; + +static char *Lastfmt, *Lastarg; + +void +discovered(void) +{ + char ch; + bool disc_list; + + do { + disc_list = FALSE; + if (!Terse) + addmsg("for "); + addmsg("what type"); + if (!Terse) + addmsg(" of object do you want a list"); + msg("? (* for all)"); + ch = readchar(); + switch (ch) + { + case ESCAPE: + msg(""); + return; + case POTION: + case SCROLL: + case RING: + case STICK: + case '*': + disc_list = TRUE; + break; + default: + if (Terse) + msg("Not a type"); + else + msg("Please type one of %c%c%c%c (ESCAPE to quit)", POTION, SCROLL, RING, STICK); + } + } while (!disc_list); + if (ch == '*') + { + print_disc(POTION); + add_line("", NULL); + print_disc(SCROLL); + add_line("", NULL); + print_disc(RING); + add_line("", NULL); + print_disc(STICK); + end_line(); + } + else + { + print_disc(ch); + end_line(); + } +} + +/* + * print_disc: + * Print what we've discovered of type 'type' + */ + +#define MAX4(a,b,c,d) (a > b ? (a > c ? (a > d ? a : d) : (c > d ? c : d)) : (b > c ? (b > d ? b : d) : (c > d ? c : d))) + +void +print_disc(char type) +{ + struct obj_info *info; + int i, maxnum, num_found; + static THING obj; + static short order[MAX4(MAXSCROLLS, MAXPOTIONS, MAXRINGS, MAXSTICKS)]; + + switch (type) + { + case SCROLL: + maxnum = MAXSCROLLS; + info = Scr_info; + break; + case POTION: + maxnum = MAXPOTIONS; + info = Pot_info; + break; + case RING: + maxnum = MAXRINGS; + info = Ring_info; + break; + case STICK: + maxnum = MAXSTICKS; + info = Ws_info; + break; + } + set_order(order, maxnum); + obj.o_count = 1; + obj.o_flags = 0; + num_found = 0; + for (i = 0; i < maxnum; i++) + if (info[order[i]].oi_know || info[order[i]].oi_guess) + { + obj.o_type = type; + obj.o_which = order[i]; + add_line("%s", inv_name(&obj, FALSE)); + num_found++; + } + if (num_found == 0) + add_line(nothing(type), NULL); +} + +/* + * set_order: + * Set up order for list + */ +void +set_order(short *order, int numthings) +{ + int i, r, t; + + for (i = 0; i< numthings; i++) + order[i] = i; + + for (i = numthings; i > 0; i--) + { + r = rnd(i); + t = order[i - 1]; + order[i - 1] = order[r]; + order[r] = t; + } +} + +/* + * add_line: + * Add a line to the list of discoveries + */ +/* VARARGS1 */ +char +add_line(char *fmt, char *arg) +{ + WINDOW *tw, *sw; + int x, y; + char *prompt = "--Press space to continue--"; + static int maxlen = -1; + + if (Line_cnt == 0) + { + wclear(Hw); + if (Inv_type == INV_SLOW) + Mpos = 0; + } + if (Inv_type == INV_SLOW) + { + if (*fmt != '\0') + if (msg(fmt, arg) == ESCAPE) + return ESCAPE; + Line_cnt++; + } + else + { + if (maxlen < 0) + maxlen = strlen(prompt); + if (Line_cnt >= LINES - 1 || fmt == NULL) + { + if (Inv_type == INV_OVER && fmt == NULL && !Newpage) + { + msg(""); + refresh(); + tw = newwin(Line_cnt + 1, maxlen + 2, 0, COLS - maxlen - 3); + sw = subwin(tw, Line_cnt + 1, maxlen + 1, 0, COLS - maxlen - 2); + for (y = 0; y <= Line_cnt; y++) + { + wmove(sw, y, 0); + for (x = 0; x <= maxlen; x++) + waddch(sw, mvwinch(Hw, y, x)); + } + wmove(tw, Line_cnt, 1); + waddstr(tw, prompt); + /* + * if there are lines below, use 'em + */ + if (LINES > NUMLINES) + if (NUMLINES + Line_cnt > LINES) + mvwin(tw, LINES - (Line_cnt + 1), COLS - maxlen - 3); + else + mvwin(tw, NUMLINES, 0); + touchwin(tw); + wrefresh(tw); + wait_for(' '); +#ifndef attron + if (CE) +#else attron + if (clr_eol) +#endif attron + { + werase(tw); + leaveok(tw, TRUE); + wrefresh(tw); + } + delwin(tw); + touchwin(stdscr); + } + else + { + wmove(Hw, LINES - 1, 0); + waddstr(Hw, prompt); + wrefresh(Hw); + wait_for(' '); + clearok(curscr, TRUE); + wclear(Hw); +#ifdef attron + touchwin(stdscr); +#endif attron + } + Newpage = TRUE; + Line_cnt = 0; + maxlen = strlen(prompt); + } + if (fmt != NULL && !(Line_cnt == 0 && *fmt == '\0')) + { + mvwprintw(Hw, Line_cnt++, 0, fmt, arg); + getyx(Hw, y, x); + if (maxlen < x) + maxlen = x; + Lastfmt = fmt; + Lastarg = arg; + } + } + return ~ESCAPE; +} + +/* + * end_line: + * End the list of lines + */ +void +end_line(void) +{ + if (Inv_type != INV_SLOW) + if (Line_cnt == 1 && !Newpage) + { + Mpos = 0; + msg(Lastfmt, Lastarg); + } + else + add_line((char *) NULL, NULL); + Line_cnt = 0; + Newpage = FALSE; +} + +/* + * nothing: + * Set up Prbuf so that message for "nothing found" is there + */ +char * +nothing(char type) +{ + char *sp, *tystr; + + if (Terse) + sprintf(Prbuf, "Nothing"); + else + sprintf(Prbuf, "Haven't discovered anything"); + if (type != '*') + { + sp = &Prbuf[strlen(Prbuf)]; + switch (type) + { + when POTION: tystr = "potion"; + when SCROLL: tystr = "scroll"; + when RING: tystr = "ring"; + when STICK: tystr = "stick"; + } + sprintf(sp, " about any %ss", tystr); + } + return Prbuf; +} + +/* + * nameit: + * Give the proper name to a potion, stick, or ring + */ +void +nameit(THING *obj, char *type, char *which, struct obj_info *op, + char *(*prfunc)(THING *)) +{ + char *pb; + + if (op->oi_know || op->oi_guess) + { + if (obj->o_count == 1) + sprintf(Prbuf, "A %s ", type); + else + sprintf(Prbuf, "%d %ss ", obj->o_count, type); + pb = &Prbuf[strlen(Prbuf)]; + if (op->oi_know) + sprintf(pb, "of %s%s(%s)", op->oi_name, (*prfunc)(obj), which); + else if (op->oi_guess) + sprintf(pb, "called %s%s(%s)", op->oi_guess, (*prfunc)(obj), which); + } + else if (obj->o_count == 1) + sprintf(Prbuf, "A%s %s %s", vowelstr(which), which, type); + else + sprintf(Prbuf, "%d %s %ss", obj->o_count, which, type); +} + +/* + * nullstr: + * Return a pointer to a null-length string + */ +char * +nullstr(THING *ignored) +{ + return ""; +} + +# ifdef MASTER +/* + * pr_list: + * List possible potions, scrolls, etc. for wizard. + */ +void +pr_list(void) +{ + int ch; + + if (!Terse) + addmsg("for "); + addmsg("what type"); + if (!Terse) + addmsg(" of object do you want a list"); + msg("? "); + ch = readchar(); + switch (ch) + { + when POTION: + pr_spec(Pot_info, MAXPOTIONS); + when SCROLL: + pr_spec(Scr_info, MAXSCROLLS); + when RING: + pr_spec(Ring_info, MAXRINGS); + when STICK: + pr_spec(Ws_info, MAXSTICKS); + when ARMOR: + pr_spec(Arm_info, MAXARMORS); + when WEAPON: + pr_spec(Weap_info, MAXWEAPONS); + otherwise: + return; + } +} + +/* + * pr_spec: + * Print specific list of possible items to choose from + */ +void +pr_spec(struct obj_info *info, int nitems) +{ + struct obj_info *endp; + int i, lastprob; + + endp = &info[nitems]; + lastprob = 0; + for (i = '0'; info < endp; i++) + { + if (i == '9' + 1) + i = 'a'; + sprintf(Prbuf, "%c: %%s (%d%%%%)", i, info->oi_prob - lastprob); + lastprob = info->oi_prob; + add_line(Prbuf, info->oi_name); + info++; + } + end_line(); +} +# endif MASTER diff --git a/rexec.c b/rexec.c new file mode 100644 index 0000000..a17eb60 --- /dev/null +++ b/rexec.c @@ -0,0 +1,244 @@ +/* + * File with various monster functions in it + * + * @(#)rexec.c 4.46 (Berkeley) 02/05/99 + */ + +#include +#include "netprot.h" +#include + +/* + * List of monsters in rough order of vorpalness + */ +static char Lvl_mons[] = { + 'K', 'E', 'B', 'S', 'H', 'I', 'R', 'O', 'Z', 'L', 'C', 'Q', 'A', + 'N', 'Y', 'F', 'T', 'W', 'P', 'X', 'U', 'M', 'V', 'G', 'J', 'D' +}; + +static char Wand_mons[] = { + 'K', 'E', 'B', 'S', 'H', 0, 'R', 'O', 'Z', 0, 'C', 'Q', 'A', + 0, 'Y', 0, 'T', 'W', 'P', 0, 'U', 'M', 'V', 'G', 'J', 0 +}; + +/* + * randmonster: + * Pick a monster to show up. The lower the level, + * the meaner the monster. + */ +char +randmonster(bool wander) +{ + int d; + char *mons; + + mons = (wander ? Wand_mons : Lvl_mons); + do + { + d = Level + (rnd(10) - 6); + if (d < 0) + d = rnd(5); + if (d > 25) + d = rnd(5) + 21; + } while (mons[d] == 0); + return mons[d]; +} + +/* + * new_monster: + * Pick a new monster and add it to the list + */ +void +new_monster(THING *tp, char type, coord *cp) +{ + struct monster *mp; + int lev_add; + + if ((lev_add = Level - AMULETLEVEL) < 0) + lev_add = 0; + attach(Mlist, tp); + tp->t_type = type; + tp->t_disguise = type; + tp->t_pos = *cp; + move(cp->y, cp->x); + tp->t_oldch = inch(); + tp->t_room = roomin(cp); + moat(cp->y, cp->x) = tp; + mp = &Monsters[tp->t_type-'A']; + tp->t_stats.s_lvl = mp->m_stats.s_lvl + lev_add; + tp->t_stats.s_maxhp = tp->t_stats.s_hpt = roll(tp->t_stats.s_lvl, 8); + tp->t_stats.s_arm = mp->m_stats.s_arm - lev_add; + strcpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg); + tp->t_stats.s_str = mp->m_stats.s_str; + tp->t_stats.s_exp = mp->m_stats.s_exp + lev_add * 10 + exp_add(tp); + tp->t_flags = mp->m_flags; + if (Level > 29) + tp->t_flags |= ISHASTE; + tp->t_turn = TRUE; + tp->t_pack = NULL; + if (ISWEARING(R_AGGR)) + runto(cp); + if (type == 'X') + tp->t_disguise = rnd_thing(); +} + +/* + * expadd: + * Experience to add for this monster's level/hit points + */ +int +exp_add(THING *tp) +{ + int mod; + + if (tp->t_stats.s_lvl == 1) + mod = tp->t_stats.s_maxhp / 8; + else + mod = tp->t_stats.s_maxhp / 6; + if (tp->t_stats.s_lvl > 9) + mod *= 20; + else if (tp->t_stats.s_lvl > 6) + mod *= 4; + return mod; +} + +/* + * wanderer: + * Create a new wandering monster and aim it at the player + */ +void +wanderer(void) +{ + int i; + struct room *rp; + THING *tp; + static coord cp; + + tp = new_item(); + do + { + find_floor((struct room *) NULL, &cp, FALSE, TRUE); + } while (roomin(&cp) == Proom); + new_monster(tp, randmonster(TRUE), &cp); + if (on(Player, SEEMONST)) + { + standout(); + if (!on(Player, ISHALU)) + addch(tp->t_type); + else + addch(rnd(26) + 'A'); + standend(); + } + runto(&tp->t_pos); +#ifdef MASTER + if (Wizard) + msg("started a wandering %s", Monsters[tp->t_type-'A'].m_name); +#endif +} + +/* + * wake_monster: + * What to do when the hero steps next to a monster + */ +THING * +wake_monster(int y, int x) +{ + THING *tp; + struct room *rp; + char ch, *mname; + +#ifdef MASTER + if ((tp = moat(y, x)) == NULL) + msg("can't find monster in wake_monster"); +#else + tp = moat(y, x); + if (tp == NULL) + endwin(), abort(); +#endif + ch = tp->t_type; + /* + * Every time he sees mean monster, it might start chasing him + */ + if (!on(*tp, ISRUN) && rnd(3) != 0 && on(*tp, ISMEAN) && !on(*tp, ISHELD) + && !ISWEARING(R_STEALTH) && !on(Player, ISLEVIT)) + { + tp->t_dest = &Hero; + tp->t_flags |= ISRUN; + } + if (ch == 'M' && !on(Player, ISBLIND) && !on(Player, ISHALU) + && !on(*tp, ISFOUND) && !on(*tp, ISCANC) && on(*tp, ISRUN)) + { + rp = Proom; + if ((rp != NULL && !(rp->r_flags & ISDARK)) + || dist(y, x, Hero.y, Hero.x) < LAMPDIST) + { + tp->t_flags |= ISFOUND; + if (!save(VS_MAGIC)) + { + if (on(Player, ISHUH)) + lengthen(unconfuse, spread(HUHDURATION)); + else + fuse(unconfuse, 0, spread(HUHDURATION), AFTER); + Player.t_flags |= ISHUH; + mname = set_mname(tp); + addmsg("%s", mname); + if (strcmp(mname, "it") != 0) + addmsg("'"); + msg("s gaze has confused you"); + } + } + } + /* + * Let greedy ones guard gold + */ + if (on(*tp, ISGREED) && !on(*tp, ISRUN)) + { + tp->t_flags |= ISRUN; + if (Proom->r_goldval) + tp->t_dest = &Proom->r_gold; + else + tp->t_dest = &Hero; + } + return tp; +} + +/* + * give_pack: + * Give a pack to a monster if it deserves one + */ +void +give_pack(THING *tp) +{ + if (Level >= Max_level && rnd(100) < Monsters[tp->t_type-'A'].m_carry) + attach(tp->t_pack, new_thing()); +} + +/* + * save_throw: + * See if a creature save against something + */ +int +save_throw(int which, THING *tp) +{ + int need; + + need = 14 + which - tp->t_stats.s_lvl / 2; + return (roll(1, 20) >= need); +} + +/* + * save: + * See if he saves against various nasty things + */ +int +save(int which) +{ + if (which == VS_MAGIC) + { + if (ISRING(LEFT, R_PROTECT)) + which -= Cur_ring[LEFT]->o_arm; + if (ISRING(RIGHT, R_PROTECT)) + which -= Cur_ring[RIGHT]->o_arm; + } + return save_throw(which, &Player); +} diff --git a/rinit.c b/rinit.c new file mode 100644 index 0000000..9d6daf7 --- /dev/null +++ b/rinit.c @@ -0,0 +1,439 @@ +/* + * global variable initializaton + * + * @(#)rinit.c 4.31 (Berkeley) 02/05/99 + */ + +#include +#include +#include "netprot.h" + +/* + * init_player: + * Roll her up + */ +void +init_player(void) +{ + THING *obj; + + Pstats = Max_stats; + Food_left = HUNGERTIME; + /* + * Give him some food + */ + obj = new_item(); + obj->o_type = FOOD; + obj->o_count = 1; + add_pack(obj, TRUE); + /* + * And his suit of armor + */ + obj = new_item(); + obj->o_type = ARMOR; + obj->o_which = RING_MAIL; + obj->o_arm = A_class[RING_MAIL] - 1; + obj->o_flags |= ISKNOW; + obj->o_count = 1; + Cur_armor = obj; + add_pack(obj, TRUE); + /* + * Give him his weaponry. First a mace. + */ + obj = new_item(); + init_weapon(obj, MACE); + obj->o_hplus = 1; + obj->o_dplus = 1; + obj->o_flags |= ISKNOW; + add_pack(obj, TRUE); + Cur_weapon = obj; + /* + * Now a +1 bow + */ + obj = new_item(); + init_weapon(obj, BOW); + obj->o_hplus = 1; + obj->o_flags |= ISKNOW; + add_pack(obj, TRUE); + /* + * Now some arrows + */ + obj = new_item(); + init_weapon(obj, ARROW); + obj->o_count = rnd(15) + 25; + obj->o_flags |= ISKNOW; + add_pack(obj, TRUE); +} + +/* + * Contains defintions and functions for dealing with things like + * potions and scrolls + */ + +static char *Rainbow[] = { + "amber", + "aquamarine", + "black", + "blue", + "brown", + "clear", + "crimson", + "cyan", + "ecru", + "gold", + "green", + "grey", + "magenta", + "orange", + "pink", + "plaid", + "purple", + "red", + "silver", + "tan", + "tangerine", + "topaz", + "turquoise", + "vermilion", + "violet", + "white", + "yellow", +}; + +#define NCOLORS (sizeof Rainbow / sizeof (char *)) + +static char *Sylls[] = { + "a", "ab", "ag", "aks", "ala", "an", "app", "arg", "arze", "ash", + "bek", "bie", "bit", "bjor", "blu", "bot", "bu", "byt", "comp", + "con", "cos", "cre", "dalf", "dan", "den", "do", "e", "eep", "el", + "eng", "er", "ere", "erk", "esh", "evs", "fa", "fid", "fri", "fu", + "gan", "gar", "glen", "gop", "gre", "ha", "hyd", "i", "ing", "ip", + "ish", "it", "ite", "iv", "jo", "kho", "kli", "klis", "la", "lech", + "mar", "me", "mi", "mic", "mik", "mon", "mung", "mur", "nej", + "nelg", "nep", "ner", "nes", "nes", "nih", "nin", "o", "od", "ood", + "org", "orn", "ox", "oxy", "pay", "ple", "plu", "po", "pot", + "prok", "re", "rea", "rhov", "ri", "ro", "rog", "rok", "rol", "sa", + "san", "sat", "sef", "seh", "shu", "ski", "sna", "sne", "snik", + "sno", "so", "sol", "sri", "sta", "sun", "ta", "tab", "tem", + "ther", "ti", "tox", "trol", "tue", "turs", "u", "ulk", "um", "un", + "uni", "ur", "val", "viv", "vly", "vom", "wah", "wed", "werg", + "wex", "whon", "wun", "xo", "y", "yot", "yu", "zant", "zeb", "zim", + "zok", "zon", "zum", +}; + +typedef struct { + char *st_name; + int st_value; +} STONE; + +static STONE Stones[] = { + { "agate", 25}, + { "alexandrite", 40}, + { "amethyst", 50}, + { "carnelian", 40}, + { "diamond", 300}, + { "emerald", 300}, + { "germanium", 225}, + { "granite", 5}, + { "garnet", 50}, + { "jade", 150}, + { "kryptonite", 300}, + { "lapis lazuli", 50}, + { "moonstone", 50}, + { "obsidian", 15}, + { "onyx", 60}, + { "opal", 200}, + { "pearl", 220}, + { "peridot", 63}, + { "ruby", 350}, + { "sapphire", 285}, + { "stibotantalite", 200}, + { "tiger eye", 50}, + { "topaz", 60}, + { "turquoise", 70}, + { "taaffeite", 300}, + { "zircon", 80}, +}; + +#define NSTONES (sizeof Stones / sizeof (STONE)) + +static char *Wood[] = { + "avocado wood", + "balsa", + "bamboo", + "banyan", + "birch", + "cedar", + "cherry", + "cinnibar", + "cypress", + "dogwood", + "driftwood", + "ebony", + "elm", + "eucalyptus", + "fall", + "hemlock", + "holly", + "ironwood", + "kukui wood", + "mahogany", + "manzanita", + "maple", + "oaken", + "persimmon wood", + "pecan", + "pine", + "poplar", + "redwood", + "rosewood", + "spruce", + "teak", + "walnut", + "zebrawood", +}; + +#define NWOOD (sizeof Wood / sizeof (char *)) + +static char *Metal[] = { + "aluminum", + "beryllium", + "bone", + "brass", + "bronze", + "copper", + "electrum", + "gold", + "iron", + "lead", + "magnesium", + "mercury", + "nickel", + "pewter", + "platinum", + "steel", + "silver", + "silicon", + "tin", + "titanium", + "tungsten", + "zinc", +}; + +#define NMETAL (sizeof Metal / sizeof (char *)) + +#define MAX3(a,b,c) (a > b ? (a > c ? a : c) : (b > c ? b : c)) + +static bool Used[MAX3(NCOLORS, NSTONES, NWOOD)]; + +/* + * init_colors: + * Initialize the potion color scheme for this time + */ +void +init_colors(void) +{ + int i, j; + + for (i = 0; i < NCOLORS; i++) + Used[i] = FALSE; + for (i = 0; i < MAXPOTIONS; i++) + { + do + j = rnd(NCOLORS); + until (!Used[j]); + Used[j] = TRUE; + P_colors[i] = Rainbow[j]; + } +} + +/* + * init_names: + * Generate the names of the various scrolls + */ +#define MAXNAME 40 /* Max number of characters in a name */ + +void +init_names(void) +{ + int nsyl; + char *cp, *sp; + int i, nwords; + + for (i = 0; i < MAXSCROLLS; i++) + { + cp = Prbuf; + nwords = rnd(3) + 2; + while (nwords--) + { + nsyl = rnd(3) + 1; + while (nsyl--) + { + sp = Sylls[rnd((sizeof Sylls) / (sizeof (char *)))]; + if (&cp[strlen(sp)] > &Prbuf[MAXNAME]) + break; + while (*sp) + *cp++ = *sp++; + } + *cp++ = ' '; + } + *--cp = '\0'; + S_names[i] = (char *) malloc((unsigned) strlen(Prbuf)+1); + strcpy(S_names[i], Prbuf); + } +} + +/* + * init_stones: + * Initialize the ring stone setting scheme for this time + */ +void +init_stones(void) +{ + int i, j; + + for (i = 0; i < NSTONES; i++) + Used[i] = FALSE; + for (i = 0; i < MAXRINGS; i++) + { + do + j = rnd(NSTONES); + until (!Used[j]); + Used[j] = TRUE; + R_stones[i] = Stones[j].st_name; + Ring_info[i].oi_worth += Stones[j].st_value; + } +} + +/* + * init_materials: + * Initialize the construction materials for wands and staffs + */ +void +init_materials(void) +{ + int i, j; + char *str; + static bool metused[NMETAL]; + + for (i = 0; i < NWOOD; i++) + Used[i] = FALSE; + for (i = 0; i < NMETAL; i++) + metused[i] = FALSE; + for (i = 0; i < MAXSTICKS; i++) + { + for (;;) + if (rnd(2) == 0) + { + j = rnd(NMETAL); + if (!metused[j]) + { + Ws_type[i] = "wand"; + str = Metal[j]; + metused[j] = TRUE; + break; + } + } + else + { + j = rnd(NWOOD); + if (!Used[j]) + { + Ws_type[i] = "staff"; + str = Wood[j]; + Used[j] = TRUE; + break; + } + } + Ws_made[i] = str; + } +} + +#ifdef MASTER +# define NT NUMTHINGS, "things" +# define MP MAXPOTIONS, "potions" +# define MS MAXSCROLLS, "scrolls" +# define MR MAXRINGS, "rings" +# define MWS MAXSTICKS, "sticks" +# define MW MAXWEAPONS, "weapons" +# define MA MAXARMORS, "armor" +#else +# define NT NUMTHINGS +# define MP MAXPOTIONS +# define MS MAXSCROLLS +# define MR MAXRINGS +# define MWS MAXSTICKS +# define MW MAXWEAPONS +# define MA MAXARMORS +#endif + +/* + * sumprobs: + * Sum up the probabilities for items appearing + */ +void +sumprobs(struct obj_info *info, int bound +#ifdef MASTER + , char *name +#endif +) +{ + struct obj_info *last, *endp, *start; + + start = info; + endp = info + bound; + while (++info < endp) + info->oi_prob += (info - 1)->oi_prob; +#ifdef MASTER + badcheck(name, start, bound); +#endif +} + +/* + * init_probs: + * Initialize the probabilities for the various items + */ +void +init_probs(void) +{ + sumprobs(Things, NT); + sumprobs(Pot_info, MP); + sumprobs(Scr_info, MS); + sumprobs(Ring_info, MR); + sumprobs(Ws_info, MWS); + sumprobs(Weap_info, MW); + sumprobs(Arm_info, MA); +} + +#ifdef MASTER +/* + * badcheck: + * Check to see if a series of probabilities sums to 100 + */ +void +badcheck(char *name, struct obj_info *info, int bound) +{ + struct obj_info *end; + + if (info[bound - 1].oi_prob == 100) + return; + printf("\nBad percentages for %s (bound = %d):\n", name, bound); + for (end = &info[bound]; info < end; info++) + printf("%3d%% %s\n", info->oi_prob, info->oi_name); + printf("[hit RETURN to continue]"); + fflush(stdout); + while (getchar() != '\n') + continue; +} +#endif + +/* + * pick_color: + * If he is halucinating, pick a random color name and return it, + * otherwise return the given color. + */ +char * +pick_color(char *col) +{ + return (on(Player, ISHALU) ? Rainbow[rnd(NCOLORS)] : col); +} diff --git a/rmap.c b/rmap.c new file mode 100644 index 0000000..93ce8b5 --- /dev/null +++ b/rmap.c @@ -0,0 +1,417 @@ +/* + * Exploring the dungeons of doom + * Copyright (C) 1981 by Michael Toy, Ken Arnold, and Glenn Wichman + * All rights reserved + * + * @(#)rmap.c 4.22 (Berkeley) 02/05/99 + */ + +#include +#ifdef attron +#include +#endif attron +#include +#include +#include "netprot.h" + +/* + * main: + * The main program, of course + */ +int +main(int argc, char **argv, char **envp) +{ + char *env; + struct passwd *pw; + int lowtime; + +#ifndef DUMP + signal(SIGQUIT, exit); + signal(SIGILL, exit); + signal(SIGTRAP, exit); + signal(SIGIOT, exit); + signal(SIGEMT, exit); + signal(SIGFPE, exit); + signal(SIGBUS, exit); + signal(SIGSEGV, exit); + signal(SIGSYS, exit); +#endif + +#ifdef MASTER + /* + * Check to see if he is a wizard + */ + if (argc >= 2 && argv[1][0] == '\0') + if (strcmp(PASSWD, crypt(getpass("Wizard's password: "), "mT")) == 0) + { + Wizard = TRUE; + Player.t_flags |= SEEMONST; + argv++; + argc--; + } +#endif + + /* + * get Home and options from environment + */ + if ((env = getenv("HOME")) != NULL) + strcpy(Home, env); + else if ((pw = getpwuid(getuid())) != NULL) + strcpy(Home, pw->pw_dir); + strcat(Home, "/"); + + strcpy(File_name, Home); + strcat(File_name, "rogue.save"); + + if ((env = getenv("ROGUEOPTS")) != NULL) + parse_opts(env); + if (env == NULL || Whoami[0] == '\0') + if ((pw = getpwuid(getuid())) == NULL) + { + printf("Say, who the hell are you?\n"); + exit(1); + } + else + strucpy(Whoami, pw->pw_name, strlen(pw->pw_name)); + +#ifdef MASTER + if (Wizard && getenv("SEED") != NULL) + Dnum = atoi(getenv("SEED")); + else +#endif + Dnum = lowtime + getpid(); + Seed = Dnum; + + /* + * check for print-score option + */ + open_score(); + if (argc == 2) + if (strcmp(argv[1], "-s") == 0) + { + Noscore = TRUE; + score(0, -1); + exit(0); + } + else if (strcmp(argv[1], "-d") == 0) + { + Dnum = rnd(100); /* throw away some rnd()s to break patterns */ + while (--Dnum) + rnd(100); + Purse = rnd(100) + 1; + Level = rnd(100) + 1; + initscr(); + getltchars(); + death(death_monst()); + exit(0); + } + + init_check(); /* check for legal startup */ + if (argc == 2) + if (!restore(argv[1], envp)) /* Note: restore will never return */ + my_exit(1); + lowtime = (int) time(NULL); +#ifdef MASTER + if (Wizard) + printf("Hello %s, welcome to dungeon #%d", Whoami, Dnum); + else +#endif + printf("Hello %s, just a moment while I dig the dungeon...", Whoami); + fflush(stdout); + + initscr(); /* Start up cursor package */ + init_probs(); /* Set up prob tables for objects */ + init_player(); /* Set up initial Player stats */ + init_names(); /* Set up names of scrolls */ + init_colors(); /* Set up colors of potions */ + init_stones(); /* Set up stone settings of rings */ + init_materials(); /* Set up materials of wands */ + setup(); + + /* + * The screen must be at least NUMLINES x NUMCOLS + */ + if (LINES < NUMLINES || COLS < NUMCOLS) + { + printf("\nSorry, the screen must be at least %dx%d\n", NUMLINES, NUMCOLS); + endwin(); + my_exit(1); + } + + /* + * Set up windows + */ + Hw = newwin(LINES, COLS, 0, 0); +#ifdef attron + idlok(stdscr, TRUE); + idlok(Hw, TRUE); +#endif attron +#ifdef MASTER + Noscore = Wizard; +#endif + new_level(); /* Draw current level */ + /* + * Start up daemons and fuses + */ + start_daemon(runners, 0, AFTER); + start_daemon(doctor, 0, AFTER); + fuse(swander, 0, WANDERTIME, AFTER); + start_daemon(stomach, 0, AFTER); + playit(); +} + +/* + * endit: + * Exit the program abnormally. + */ +void +endit(int sig) +{ + fatal("Okay, bye bye!\n"); +} + +/* + * fatal: + * Exit the program, printing a message. + */ +void +fatal(char *s) +{ + mvaddstr(LINES - 2, 0, s); + refresh(); + endwin(); + my_exit(0); +} + +/* + * rnd: + * Pick a very random number. + */ +int +rnd(int range) +{ + return range == 0 ? 0 : abs((int) RN) % range; +} + +/* + * roll: + * Roll a number of dice + */ +int +roll(int number, int sides) +{ + int dtotal = 0; + + while (number--) + dtotal += rnd(sides)+1; + return dtotal; +} + +#ifdef SIGTSTP +/* + * tstp: + * Handle stop and start signals + */ +void +tstp(int ignored) +{ + int y, x; + int oy, ox; + + /* + * leave nicely + */ + getyx(curscr, oy, ox); + mvcur(0, COLS - 1, LINES - 1, 0); + endwin(); + resetltchars(); + fflush(stdout); + kill(0, SIGTSTP); /* send actual signal and suspend process */ + + /* + * start back up again + */ + signal(SIGTSTP, tstp); + crmode(); + noecho(); + playltchars(); + clearok(curscr, TRUE); + wrefresh(curscr); + getyx(curscr, y, x); + mvcur(y, x, oy, ox); + fflush(stdout); + curscr->_cury = oy; + curscr->_curx = ox; +} +#endif + +/* + * playit: + * The main loop of the program. Loop until the game is over, + * refreshing things and looking at the proper times. + */ +void +playit(void) +{ + char *opts; + + /* + * set up defaults for slow terminals + */ + +#ifndef attron + if (_tty.sg_ospeed <= B1200) +#else attron + if (baudrate() <= 1200) +#endif attron + { + Terse = TRUE; + Jump = TRUE; + See_floor = FALSE; + } +#ifndef attron + if (!CE) +#else attron + if (clr_eol) +#endif attron + Inv_type = INV_CLEAR; + + /* + * parse environment declaration of options + */ + if ((opts = getenv("ROGUEOPTS")) != NULL) + parse_opts(opts); + + + Oldpos = Hero; + Oldrp = roomin(&Hero); + while (Playing) + command(); /* Command execution */ + endit(0); +} + +/* + * quit: + * Have player make certain, then exit. + */ +void +quit(int sig) +{ + int oy, ox; + + /* + * Reset the signal in case we got here via an interrupt + */ + if (!Q_comm) + Mpos = 0; + getyx(curscr, oy, ox); + msg("really quit?"); + if (readchar() == 'y') + { + signal(SIGINT, leave); + clear(); + mvprintw(LINES - 2, 0, "You quit with %d gold pieces", Purse); + move(LINES - 1, 0); + refresh(); + score(Purse, 1); + my_exit(0); + } + else + { + move(0, 0); + clrtoeol(); + status(); + move(oy, ox); + refresh(); + Mpos = 0; + Count = 0; + To_death = FALSE; + } +} + +/* + * leave: + * Leave quickly, but curteously + */ +void +leave(int sig) +{ + static char buf[BUFSIZ]; + + setbuf(stdout, buf); /* throw away pending output */ +#ifndef attron + if (!_endwin) + { + mvcur(0, COLS - 1, LINES - 1, 0); + endwin(); + } +#else attron + endwin(); +#endif attron + putchar('\n'); + my_exit(0); +} + +/* + * shell: + * Let them escape for a while + */ +void +shell(void) +{ + int pid; + char *sh; + int ret_status; + + /* + * Set the terminal back to original mode + */ + move(LINES-1, 0); + refresh(); + endwin(); + resetltchars(); + putchar('\n'); + In_shell = TRUE; + After = FALSE; + sh = getenv("SHELL"); + fflush(stdout); + /* + * Fork and do a shell + */ + while ((pid = fork()) < 0) + sleep(1); + if (pid == 0) + { + execl(sh == NULL ? "/bin/sh" : sh, "shell", "-i", 0); + perror("No shelly"); + exit(-1); + } + else + { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + while (wait(&ret_status) != pid) + continue; + signal(SIGINT, quit); + signal(SIGQUIT, endit); + printf("\n[Press return to continue]"); + fflush(stdout); + noecho(); + crmode(); + playltchars(); + In_shell = FALSE; + wait_for('\n'); + clearok(stdscr, TRUE); + } +} + +/* + * my_exit: + * Leave the process properly + */ +void +my_exit(int st) +{ + resetltchars(); + exit(st); +} diff --git a/rmove.c b/rmove.c new file mode 100644 index 0000000..d2a750a --- /dev/null +++ b/rmove.c @@ -0,0 +1,390 @@ +/* + * global variable initializaton + * + * @(#)rmove.c 4.82 (Berkeley) 02/05/99 + */ + +#include +#include "netprot.h" + +bool After; /* True if we want after daemons */ +bool Again; /* Repeating the last command */ +bool Noscore; /* Was a wizard sometime */ +bool Seenstairs; /* Have seen the stairs (for lsd) */ +bool Amulet = FALSE; /* He found the amulet */ +bool Door_stop = FALSE; /* Stop running when we pass a door */ +bool Fight_flush = FALSE; /* True if toilet input */ +bool Firstmove = FALSE; /* First move after setting Door_stop */ +bool Got_ltc = FALSE; /* We have gotten the local tty chars */ +bool Has_hit = FALSE; /* Has a "hit" message pending in msg */ +bool In_shell = FALSE; /* True if executing a shell */ +bool Inv_describe = TRUE; /* Say which way items are being used */ +bool Jump = FALSE; /* Show running as series of jumps */ +bool Kamikaze = FALSE; /* To_death really to DEATH */ +bool Lower_msg = FALSE; /* Messages should start w/lower case */ +bool Move_on = FALSE; /* Next move shouldn't pick up items */ +bool Msg_esc = FALSE; /* Check for ESC from msg's --More-- */ +bool Passgo = FALSE; /* Follow passages */ +bool Playing = TRUE; /* True until he quits */ +bool Q_comm = FALSE; /* Are we executing a 'Q' command? */ +bool Running = FALSE; /* True if player is running */ +bool Save_msg = TRUE; /* Remember last msg */ +bool See_floor = TRUE; /* Show the lamp illuminated floor */ +bool Stat_msg = FALSE; /* Should status() print as a msg() */ +bool Terse = FALSE; /* True if we should be short */ +bool To_death = FALSE; /* Fighting is to the death! */ +bool Tombstone = TRUE; /* Print out tombstone at end */ +#ifdef MASTER +bool Wizard = FALSE; /* True if allows wizard commands */ +#endif +bool Pack_used[26] = { /* Is the character used in the pack? */ + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE +}; + +char Dir_ch; /* Direction from last get_dir() call */ +char File_name[MAXSTR]; /* Save file name */ +char Huh[MAXSTR]; /* The last message printed */ +char *P_colors[MAXPOTIONS]; /* Colors of the potions */ +char Prbuf[2*MAXSTR]; /* Buffer for sprintfs */ +char *R_stones[MAXRINGS]; /* Stone settings of the rings */ +char *Release; /* Release number of program */ +char Runch; /* Direction player is Running */ +char *S_names[MAXSCROLLS]; /* Names of the scrolls */ +char Take; /* Thing she is taking */ +char Whoami[MAXSTR]; /* Name of player */ +char *Ws_made[MAXSTICKS]; /* What sticks are made of */ +char *Ws_type[MAXSTICKS]; /* Is it a wand or a staff */ +#ifdef TIOCSLTC +char Orig_dsusp; /* Original dsusp char */ +#endif +char Fruit[MAXSTR] = /* Favorite fruit */ + { 's', 'l', 'i', 'm', 'e', '-', 'm', 'o', 'l', 'd', '\0' }; +char Home[MAXSTR] = { '\0' }; /* User's home directory */ +char *Inv_t_name[] = { + "Overwrite", + "Slow", + "Clear" +}; +char L_last_comm = '\0'; /* Last Last_comm */ +char L_last_dir = '\0'; /* Last Last_dir */ +char Last_comm = '\0'; /* Last command typed */ +char Last_dir = '\0'; /* Last direction given */ +char *Tr_name[] = { /* Names of the traps */ + "a trapdoor", + "an arrow trap", + "a sleeping gas trap", + "a beartrap", + "a teleport trap", + "a poison dart trap", + "a rust trap", +}; + + +int N_objs; /* # items listed in inventory() call */ +int Ntraps; /* Number of traps on this level */ +int Hungry_state = 0; /* How hungry is he */ +int Inpack = 0; /* Number of things in pack */ +int Inv_type = 0; /* Type of inventory to use */ +int Level = 1; /* What level she is on */ +int Max_hit; /* Max damage done to her in To_death */ +int Max_level; /* Deepest player has gone */ +int Mpos = 0; /* Where cursor is on top line */ +int No_food = 0; /* Number of levels without food */ +int A_class[MAXARMORS] = { /* Armor class for each armor type */ + 8, /* LEATHER */ + 7, /* RING_MAIL */ + 7, /* STUDDED_LEATHER */ + 6, /* SCALE_MAIL */ + 5, /* CHAIN_MAIL */ + 4, /* SPLINT_MAIL */ + 4, /* BANDED_MAIL */ + 3, /* PLATE_MAIL */ +}; + +int Count = 0; /* Number of times to repeat command */ +int Fd; /* File descriptor for score file */ +int Food_left; /* Amount of food in hero's stomach */ +int Lastscore = -1; /* Score before this turn */ +int No_command = 0; /* Number of turns asleep */ +int No_move = 0; /* Number of turns held in place */ +int Purse = 0; /* How much gold he has */ +int Quiet = 0; /* Number of quiet turns */ +int Vf_hit = 0; /* Number of time flytrap has hit */ + +long Dnum; /* Dungeon number */ +long Seed; /* Random number seed */ +long E_levels[] = { + 10L, + 20L, + 40L, + 80L, + 160L, + 320L, + 640L, + 1300L, + 2600L, + 5200L, + 13000L, + 26000L, + 50000L, + 100000L, + 200000L, + 400000L, + 800000L, + 2000000L, + 4000000L, + 8000000L, + 0L +}; + +coord Delta; /* Change indicated to get_dir() */ +coord Oldpos; /* Position before last look() call */ +coord Stairs; /* Location of staircase */ + +PLACE Places[MAXLINES*MAXCOLS]; /* Level map */ + +THING *Cur_armor; /* What he is wearing */ +THING *Cur_ring[2]; /* Which rings are being worn */ +THING *Cur_weapon; /* Which weapon he is weilding */ +THING *L_last_pick = NULL; /* Last Last_pick */ +THING *Last_pick = NULL; /* Last object picked in get_item() */ +THING *Lvl_obj = NULL; /* List of objects on this level */ +THING *Mlist = NULL; /* List of monsters on the level */ +THING Player; /* His stats */ + /* restart of game */ + +WINDOW *Hw = NULL; /* Used as a scratch window */ + +#define INIT_STATS { 16, 0, 1, 10, 12, "1x4", 12 } + +struct stats Max_stats = INIT_STATS; /* The maximum for the player */ + +struct room *Oldrp; /* Roomin(&Oldpos) */ +struct room Rooms[MAXROOMS]; /* One for each room -- A level */ +struct room Passages[MAXPASS] = /* One for each passage */ +{ + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 }, + { {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, 0 } +}; + +#define ___ 1 +#define XX 10 +struct monster Monsters[26] = + { +/* Name CARRY FLAG str, exp, lvl, amr, hpt, dmg */ +{ "aquator", 0, ISMEAN, { XX, 20, 5, 2, ___, "0x0/0x0" } }, +{ "bat", 0, ISFLY, { XX, 1, 1, 3, ___, "1x2" } }, +{ "centaur", 15, 0, { XX, 17, 4, 4, ___, "1x2/1x5/1x5" } }, +{ "dragon", 100, ISMEAN, { XX,5000, 10, -1, ___, "1x8/1x8/3x10" } }, +{ "emu", 0, ISMEAN, { XX, 2, 1, 7, ___, "1x2" } }, +{ "venus flytrap", 0, ISMEAN, { XX, 80, 8, 3, ___, "%%%x0" } }, + /* NOTE: the damage is %%% so that xstr won't merge this */ + /* string with others, since it is written on in the program */ +{ "griffin", 20, ISMEAN|ISFLY|ISREGEN, { XX,2000, 13, 2, ___, "4x3/3x5" } }, +{ "hobgoblin", 0, ISMEAN, { XX, 3, 1, 5, ___, "1x8" } }, +{ "ice monster", 0, 0, { XX, 5, 1, 9, ___, "0x0" } }, +{ "jabberwock", 70, 0, { XX,3000, 15, 6, ___, "2x12/2x4" } }, +{ "kestrel", 0, ISMEAN|ISFLY, { XX, 1, 1, 7, ___, "1x4" } }, +{ "leprechaun", 0, 0, { XX, 10, 3, 8, ___, "1x1" } }, +{ "medusa", 40, ISMEAN, { XX,200, 8, 2, ___, "3x4/3x4/2x5" } }, +{ "nymph", 100, 0, { XX, 37, 3, 9, ___, "0x0" } }, +{ "orc", 15, ISGREED,{ XX, 5, 1, 6, ___, "1x8" } }, +{ "phantom", 0, ISINVIS,{ XX,120, 8, 3, ___, "4x4" } }, +{ "quagga", 0, ISMEAN, { XX, 15, 3, 3, ___, "1x5/1x5" } }, +{ "rattlesnake", 0, ISMEAN, { XX, 9, 2, 3, ___, "1x6" } }, +{ "snake", 0, ISMEAN, { XX, 2, 1, 5, ___, "1x3" } }, +{ "troll", 50, ISREGEN|ISMEAN,{ XX, 120, 6, 4, ___, "1x8/1x8/2x6" } }, +{ "black unicorn", 0, ISMEAN, { XX,190, 7, -2, ___, "1x9/1x9/2x9" } }, +{ "vampire", 20, ISREGEN|ISMEAN,{ XX,350, 8, 1, ___, "1x10" } }, +{ "wraith", 0, 0, { XX, 55, 5, 4, ___, "1x6" } }, +{ "xeroc", 30, 0, { XX,100, 7, 7, ___, "4x4" } }, +{ "yeti", 30, 0, { XX, 50, 4, 6, ___, "1x6/1x6" } }, +{ "zombie", 0, ISMEAN, { XX, 6, 2, 8, ___, "1x8" } } + }; +#undef ___ +#undef XX + +struct obj_info Things[NUMTHINGS] = { + { 0, 26 }, /* potion */ + { 0, 36 }, /* scroll */ + { 0, 16 }, /* food */ + { 0, 7 }, /* weapon */ + { 0, 7 }, /* armor */ + { 0, 4 }, /* ring */ + { 0, 4 }, /* stick */ +}; + +struct obj_info Arm_info[MAXARMORS] = { + { "leather armor", 20, 20, NULL, FALSE }, + { "ring mail", 15, 25, NULL, FALSE }, + { "studded leather armor", 15, 20, NULL, FALSE }, + { "scale mail", 13, 30, NULL, FALSE }, + { "chain mail", 12, 75, NULL, FALSE }, + { "splint mail", 10, 80, NULL, FALSE }, + { "banded mail", 10, 90, NULL, FALSE }, + { "plate mail", 5, 150, NULL, FALSE }, +}; +struct obj_info Pot_info[MAXPOTIONS] = { + { "confusion", 7, 5, NULL, FALSE }, + { "hallucination", 8, 5, NULL, FALSE }, + { "poison", 8, 5, NULL, FALSE }, + { "gain strength", 13, 150, NULL, FALSE }, + { "see invisible", 3, 100, NULL, FALSE }, + { "healing", 13, 130, NULL, FALSE }, + { "monster detection", 6, 130, NULL, FALSE }, + { "magic detection", 6, 105, NULL, FALSE }, + { "raise level", 2, 250, NULL, FALSE }, + { "extra healing", 5, 200, NULL, FALSE }, + { "haste self", 5, 190, NULL, FALSE }, + { "restore strength", 13, 130, NULL, FALSE }, + { "blindness", 5, 5, NULL, FALSE }, + { "levitation", 6, 75, NULL, FALSE }, +}; +struct obj_info Ring_info[MAXRINGS] = { + { "protection", 9, 400, NULL, FALSE }, + { "add strength", 9, 400, NULL, FALSE }, + { "sustain strength", 5, 280, NULL, FALSE }, + { "searching", 10, 420, NULL, FALSE }, + { "see invisible", 10, 310, NULL, FALSE }, + { "adornment", 1, 10, NULL, FALSE }, + { "aggravate monster", 10, 10, NULL, FALSE }, + { "dexterity", 8, 440, NULL, FALSE }, + { "increase damage", 8, 400, NULL, FALSE }, + { "regeneration", 4, 460, NULL, FALSE }, + { "slow digestion", 9, 240, NULL, FALSE }, + { "teleportation", 5, 30, NULL, FALSE }, + { "stealth", 7, 470, NULL, FALSE }, + { "maintain armor", 5, 380, NULL, FALSE }, +}; +struct obj_info Scr_info[MAXSCROLLS] = { + { "monster confusion", 7, 140, NULL, FALSE }, + { "magic mapping", 4, 150, NULL, FALSE }, + { "hold monster", 2, 180, NULL, FALSE }, + { "sleep", 3, 5, NULL, FALSE }, + { "enchant armor", 7, 160, NULL, FALSE }, + { "identify potion", 10, 80, NULL, FALSE }, + { "identify scroll", 10, 80, NULL, FALSE }, + { "identify weapon", 6, 80, NULL, FALSE }, + { "identify armor", 7, 100, NULL, FALSE }, + { "identify ring, wand or staff", 10, 115, NULL, FALSE }, + { "scare monster", 3, 200, NULL, FALSE }, + { "food detection", 2, 60, NULL, FALSE }, + { "teleportation", 5, 165, NULL, FALSE }, + { "enchant weapon", 8, 150, NULL, FALSE }, + { "create monster", 4, 75, NULL, FALSE }, + { "remove curse", 7, 105, NULL, FALSE }, + { "aggravate monsters", 3, 20, NULL, FALSE }, + { "protect armor", 2, 250, NULL, FALSE }, +}; +struct obj_info Weap_info[MAXWEAPONS + 1] = { + { "mace", 11, 8, NULL, FALSE }, + { "long sword", 11, 15, NULL, FALSE }, + { "short bow", 12, 15, NULL, FALSE }, + { "arrow", 12, 1, NULL, FALSE }, + { "dagger", 8, 3, NULL, FALSE }, + { "two handed sword", 10, 75, NULL, FALSE }, + { "dart", 12, 2, NULL, FALSE }, + { "shuriken", 12, 5, NULL, FALSE }, + { "spear", 12, 5, NULL, FALSE }, + { NULL, 0 }, /* DO NOT REMOVE: fake entry for dragon's breath */ +}; +struct obj_info Ws_info[MAXSTICKS] = { + { "light", 12, 250, NULL, FALSE }, + { "invisibility", 6, 5, NULL, FALSE }, + { "lightning", 3, 330, NULL, FALSE }, + { "fire", 3, 330, NULL, FALSE }, + { "cold", 3, 330, NULL, FALSE }, + { "polymorph", 15, 310, NULL, FALSE }, + { "magic missile", 10, 170, NULL, FALSE }, + { "haste monster", 10, 5, NULL, FALSE }, + { "slow monster", 11, 350, NULL, FALSE }, + { "drain life", 9, 300, NULL, FALSE }, + { "nothing", 1, 5, NULL, FALSE }, + { "teleport away", 6, 340, NULL, FALSE }, + { "teleport to", 6, 50, NULL, FALSE }, + { "cancellation", 5, 280, NULL, FALSE }, +}; + +struct h_list Helpstr[] = { + '?', " prints help", TRUE, + '/', " identify object", TRUE, + 'h', " left", TRUE, + 'j', " down", TRUE, + 'k', " up", TRUE, + 'l', " right", TRUE, + 'y', " up & left", TRUE, + 'u', " up & right", TRUE, + 'b', " down & left", TRUE, + 'n', " down & right", TRUE, + 'H', " run left", FALSE, + 'J', " run down", FALSE, + 'K', " run up", FALSE, + 'L', " run right", FALSE, + 'Y', " run up & left", FALSE, + 'U', " run up & right", FALSE, + 'B', " run down & left", FALSE, + 'N', " run down & right", FALSE, + CTRL('H'), " run left until adjacent", FALSE, + CTRL('J'), " run down until adjacent", FALSE, + CTRL('K'), " run up until adjacent", FALSE, + CTRL('L'), " run right until adjacent", FALSE, + CTRL('Y'), " run up & left until adjacent", FALSE, + CTRL('U'), " run up & right until adjacent", FALSE, + CTRL('B'), " run down & left until adjacent", FALSE, + CTRL('N'), " run down & right until adjacent", FALSE, + '\0', " : run that way", TRUE, + '\0', " : run till adjacent", TRUE, + 'f', " fight till death or near death", TRUE, + 't', " throw something", TRUE, + 'm', " move onto without picking up", TRUE, + 'z', " zap a wand in a direction", TRUE, + '^', " identify trap type", TRUE, + 's', " search for trap/secret door", TRUE, + '>', " go down a staircase", TRUE, + '<', " go up a staircase", TRUE, + '.', " rest for a turn", TRUE, + 'i', " inventory", TRUE, + 'I', " inventory single item", TRUE, + 'q', " quaff potion", TRUE, + 'r', " read scroll", TRUE, + 'e', " eat food", TRUE, + 'w', " wield a weapon", TRUE, + 'W', " wear armor", TRUE, + 'T', " take armor off", TRUE, + 'P', " put on ring", TRUE, + 'R', " remove ring", TRUE, + 'd', " drop object", TRUE, + 'c', " call object", TRUE, + 'a', " repeat last command", TRUE, + ')', " print current weapon", TRUE, + ']', " print current armor", TRUE, + '=', " print current rings", TRUE, + '@', " print current stats", TRUE, + 'D', " recall what's been discovered", TRUE, + 'o', " examine/set options", TRUE, + CTRL('R'), " redraw screen", TRUE, + CTRL('P'), " repeat last message", TRUE, + ESCAPE, " cancel command", TRUE, + 'S', " save game", TRUE, + 'Q', " quit", TRUE, + '!', " shell escape", TRUE, + 'F', " fight till either of you dies", TRUE, + 'v', " print version number", TRUE, + 0, NULL +}; + +#ifdef TIOCGLTC +struct ltchars Ltc; /* needed to change ^Y to not be suspchar */ +#endif TIOCGLTC diff --git a/ropen.c b/ropen.c new file mode 100644 index 0000000..482b612 --- /dev/null +++ b/ropen.c @@ -0,0 +1,17 @@ +/* + * print out an encrypted password on the standard output + * + * @(#)ropen.c 1.4 (Berkeley) 02/05/99 + */ +#include + +int +main(void) +{ + static char buf[80]; + + fprintf(stderr, "Password: "); + fgets(buf, 80, stdin); + buf[strlen(buf) - 1] = '\0'; + printf("%s\n", crypt(buf, "mT")); +} diff --git a/rread.c b/rread.c new file mode 100644 index 0000000..b8f5e04 --- /dev/null +++ b/rread.c @@ -0,0 +1,181 @@ +/* + * Contains functions for dealing with things that happen in the + * future. + * + * @(#)rread.c 4.7 (Berkeley) 02/05/99 + */ + +#include +#include "netprot.h" + +#define EMPTY 0 +#define DAEMON -1 +#define MAXDAEMONS 20 + +#define _X_ { EMPTY } + +struct delayed_action { + int d_type; + void (*d_func)(int); + int d_arg; + int d_time; +} d_list[MAXDAEMONS] = { + _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, + _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, +}; + +/* + * d_slot: + * Find an empty slot in the daemon/fuse list + */ +struct delayed_action * +d_slot(void) +{ + struct delayed_action *dev; + + for (dev = d_list; dev < &d_list[MAXDAEMONS]; dev++) + if (dev->d_type == EMPTY) + return dev; +#ifdef MASTER + debug("Ran out of fuse slots"); +#endif + return NULL; +} + +/* + * find_slot: + * Find a particular slot in the table + */ +struct delayed_action * +find_slot(void (*func)(int)) +{ + struct delayed_action *dev; + + for (dev = d_list; dev < &d_list[MAXDAEMONS]; dev++) + if (dev->d_type != EMPTY && func == dev->d_func) + return dev; + return NULL; +} + +/* + * start_daemon: + * Start a daemon, takes a function. + */ +void +start_daemon(void (*func)(int), int arg, int type) +{ + struct delayed_action *dev; + + dev = d_slot(); + dev->d_type = type; + dev->d_func = func; + dev->d_arg = arg; + dev->d_time = DAEMON; +} + +/* + * kill_daemon: + * Remove a daemon from the list + */ +void +kill_daemon(void (*func)(int)) +{ + struct delayed_action *dev; + + if ((dev = find_slot(func)) == NULL) + return; + /* + * Take it out of the list + */ + dev->d_type = EMPTY; +} + +/* + * do_daemons: + * Run all the daemons that are active with the current flag, + * passing the argument to the function. + */ +void +do_daemons(flag) +int flag; +{ + 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_type == flag && dev->d_time == DAEMON) + (*dev->d_func)(dev->d_arg); +} + +/* + * fuse: + * Start a fuse to go off in a certain number of turns + */ +void +fuse(void (*func)(int), int arg, int tm, int type) +{ + struct delayed_action *wire; + + wire = d_slot(); + wire->d_type = type; + wire->d_func = func; + wire->d_arg = arg; + wire->d_time = tm; +} + +/* + * lengthen: + * Increase the time until a fuse goes off + */ +void +lengthen(void (*func)(int), int xtime) +{ + struct delayed_action *wire; + + if ((wire = find_slot(func)) == NULL) + return; + wire->d_time += xtime; +} + +/* + * extinguish: + * Put out a fuse + */ +void +extinguish(void (*func)(int)) +{ + struct delayed_action *wire; + + if ((wire = find_slot(func)) == NULL) + return; + wire->d_type = EMPTY; +} + +/* + * do_fuses: + * Decrement counters and start needed fuses + */ +void +do_fuses(int flag) +{ + 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 (flag == wire->d_type && wire->d_time > 0 && --wire->d_time == 0) + { + wire->d_type = EMPTY; + (*wire->d_func)(wire->d_arg); + } +} diff --git a/rwrite.c b/rwrite.c new file mode 100644 index 0000000..90028d6 --- /dev/null +++ b/rwrite.c @@ -0,0 +1,805 @@ +/* + * Read and execute the user commands + * + * @(#)rwrite.c 4.73 (Berkeley) 08/06/83 + */ + +#include +#include +#include "netprot.h" + +/* + * command: + * Process the user commands + */ +void +command(void) +{ + char ch; + int ntimes = 1; /* Number of player moves */ + char *fp; + THING *mp; + static char countch, direction, newcount = FALSE; + + if (on(Player, ISHASTE)) + ntimes++; + /* + * Let the daemons start up + */ + do_daemons(BEFORE); + do_fuses(BEFORE); + while (ntimes--) + { + Again = FALSE; + if (Has_hit) + { + endmsg(); + Has_hit = FALSE; + } + /* + * these are illegal things for the player to be, so if any are + * set, someone's been poking in memeory + */ + if (on(Player, ISSLOW|ISGREED|ISINVIS|ISREGEN|ISTARGET)) + exit(1); + + look(TRUE); + if (!Running) + Door_stop = FALSE; + status(); + Lastscore = Purse; + move(Hero.y, Hero.x); + if (!((Running || Count) && Jump)) + refresh(); /* Draw screen */ + Take = 0; + After = TRUE; + /* + * Read command or continue run + */ +#ifdef MASTER + if (Wizard) + Noscore = TRUE; +#endif + if (!No_command) + { + if (Running || To_death) + ch = Runch; + else if (Count) + ch = countch; + else + { + ch = readchar(); + Move_on = FALSE; + if (Mpos != 0) /* Erase message if its there */ + msg(""); + } + } + else + ch = '.'; + if (No_command) + { + if (--No_command == 0) + { + Player.t_flags |= ISRUN; + msg("you can move again"); + } + } + else + { + /* + * check for prefixes + */ + newcount = FALSE; + if (isdigit(ch)) + { + Count = 0; + newcount = TRUE; + while (isdigit(ch)) + { + Count = Count * 10 + (ch - '0'); + ch = readchar(); + } + countch = ch; + /* + * turn off Count for commands which don't make sense + * to repeat + */ + switch (ch) + { + case CTRL('B'): case CTRL('H'): case CTRL('J'): + case CTRL('K'): case CTRL('L'): case CTRL('N'): + case CTRL('U'): case CTRL('Y'): + case '.': case 'a': case 'b': case 'h': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'q': + case 'r': case 's': case 't': case 'u': case 'y': + case 'z': case 'B': case 'C': case 'H': case 'I': + case 'J': case 'K': case 'L': case 'N': case 'U': + case 'Y': +#ifdef MASTER + case CTRL('D'): case CTRL('A'): +#endif + break; + default: + Count = 0; + } + } + /* + * execute a command + */ + if (Count && !Running) + Count--; + if (ch != 'a' && ch != ESCAPE && !(Running || Count || To_death)) + { + L_last_comm = Last_comm; + L_last_dir = Last_dir; + L_last_pick = Last_pick; + Last_comm = ch; + Last_dir = '\0'; + Last_pick = NULL; + } +over: + switch (ch) + { + when ',': { + THING *obj = NULL; + int found = 0; + for (obj = Lvl_obj; obj != NULL; obj = next(obj)) + { + if (obj->o_pos.y == Hero.y && obj->o_pos.x == Hero.x) + { + found=1; + break; + } + } + + if (found) { + if (levit_check()) + ; + else + pick_up(obj->o_type); + } + else { + if (!Terse) + addmsg("you are "); + msg("not standing on any object"); + } + } + when '!': shell(); + when 'h': do_move(0, -1); + when 'j': do_move(1, 0); + when 'k': do_move(-1, 0); + when 'l': do_move(0, 1); + when 'y': do_move(-1, -1); + when 'u': do_move(-1, 1); + when 'b': do_move(1, -1); + when 'n': do_move(1, 1); + when 'H': do_run('h'); + when 'J': do_run('j'); + when 'K': do_run('k'); + when 'L': do_run('l'); + when 'Y': do_run('y'); + when 'U': do_run('u'); + when 'B': do_run('b'); + when 'N': do_run('n'); + when CTRL('H'): case CTRL('J'): case CTRL('K'): case CTRL('L'): + case CTRL('Y'): case CTRL('U'): case CTRL('B'): case CTRL('N'): + { + if (!on(Player, ISBLIND)) + { + Door_stop = TRUE; + Firstmove = TRUE; + } + if (Count && !newcount) + ch = direction; + else + { + ch += ('A' - CTRL('A')); + direction = ch; + } + goto over; + } + when 'F': + Kamikaze = TRUE; + /* FALLTHROUGH */ + case 'f': + if (!get_dir()) + { + After = FALSE; + break; + } + Delta.y += Hero.y; + Delta.x += Hero.x; + if (((mp = moat(Delta.y, Delta.x)) == NULL + || (!see_monst(mp)) && !on(Player, SEEMONST))) + { + if (!Terse) + addmsg("I see "); + msg("no monster there"); + After = FALSE; + } + else if (diag_ok(&Hero, &Delta)) + { + To_death = TRUE; + Max_hit = 0; + mp->t_flags |= ISTARGET; + Runch = ch = Dir_ch; + goto over; + } + when 't': + if (!get_dir()) + After = FALSE; + else + missile(Delta.y, Delta.x); + when 'a': + if (Last_comm == '\0') + { + msg("you haven't typed a command yet"); + After = FALSE; + } + else + { + ch = Last_comm; + Again = TRUE; + goto over; + } + when 'q': quaff(); + when 'Q': + After = FALSE; + Q_comm = TRUE; + quit(0); + Q_comm = FALSE; + when 'i': After = FALSE; inventory(Pack, 0); + when 'I': After = FALSE; picky_inven(); + when 'd': drop(); + when 'r': read_scroll(); + when 'e': eat(); + when 'w': wield(); + when 'W': wear(); + when 'T': take_off(); + when 'P': ring_on(); + when 'R': ring_off(); + when 'o': option(); After = FALSE; + when 'c': call(); After = FALSE; + when '>': After = FALSE; d_level(); + when '<': After = FALSE; u_level(); + when '?': After = FALSE; help(); + when '/': After = FALSE; identify(); + when 's': search(); + when 'z': + if (get_dir()) + do_zap(); + else + After = FALSE; + when 'D': After = FALSE; discovered(); + when CTRL('P'): After = FALSE; msg(Huh); + when CTRL('R'): + After = FALSE; + clearok(curscr,TRUE); + wrefresh(curscr); + when 'v': + After = FALSE; + msg("version %s. (mctesq was here)", Release); + when 'S': + After = FALSE; + save_game(); + when '.': ; /* Rest command */ + when ' ': After = FALSE; /* "Legal" illegal command */ + when '^': + After = FALSE; + if (get_dir()) { + Delta.y += Hero.y; + Delta.x += Hero.x; + fp = &flat(Delta.y, Delta.x); + if (chat(Delta.y, Delta.x) != TRAP) + msg("no trap there"); + else if (on(Player, ISHALU)) + msg(Tr_name[rnd(NTRAPS)]); + else { + msg(Tr_name[*fp & F_TMASK]); + *fp |= F_SEEN; + } + } +#ifdef MASTER + when '+': + After = FALSE; + if (Wizard) + { + Wizard = FALSE; + turn_see(TRUE); + msg("not wizard any more"); + } + else + { +/* if (Wizard = passwd()) */ + if (Wizard = 1) + { + Noscore = TRUE; + turn_see(FALSE); + msg("you are suddenly as smart as Ken Arnold in dungeon #%d", Dnum); + } + else + msg("sorry"); + } +#endif + when ESCAPE: /* Escape */ + Door_stop = FALSE; + Count = 0; + After = FALSE; + Again = FALSE; + when 'm': + Move_on = TRUE; + if (!get_dir()) + After = FALSE; + else + { + ch = Dir_ch; + countch = Dir_ch; + goto over; + } + when ')': current(Cur_weapon, "wielding", NULL); + when ']': current(Cur_armor, "wearing", NULL); + when '=': + current(Cur_ring[LEFT], "wearing", + Terse ? "(L)" : "on left hand"); + current(Cur_ring[RIGHT], "wearing", + Terse ? "(R)" : "on right hand"); + when '@': + Stat_msg = TRUE; + status(); + Stat_msg = FALSE; + After = FALSE; + otherwise: + After = FALSE; +#ifdef MASTER + if (Wizard) switch (ch) + { + when '|': msg("@ %d,%d", Hero.y, Hero.x); + when 'C': create_obj(); + when '$': msg("Inpack = %d", Inpack); + when CTRL('G'): inventory(Lvl_obj, 0); + when CTRL('W'): whatis(FALSE, 0); + when CTRL('D'): Level++; new_level(); + when CTRL('A'): Level--; new_level(); + when CTRL('F'): show_map(); + when CTRL('T'): teleport(); + when CTRL('E'): msg("food left: %d", Food_left); + when CTRL('C'): add_pass(); + when CTRL('X'): turn_see(on(Player, SEEMONST)); + when CTRL('~'): + { + THING *item; + + if ((item = get_item("charge", STICK)) != NULL) + item->o_charges = 10000; + } + when CTRL('I'): + { + int i; + THING *obj; + + for (i = 0; i < 9; i++) + raise_level(); + /* + * Give him a sword (+1,+1) + */ + obj = new_item(); + init_weapon(obj, TWOSWORD); + obj->o_hplus = 1; + obj->o_dplus = 1; + add_pack(obj, TRUE); + Cur_weapon = obj; + /* + * And his suit of armor + */ + obj = new_item(); + obj->o_type = ARMOR; + obj->o_which = PLATE_MAIL; + obj->o_arm = -5; + obj->o_flags |= ISKNOW; + obj->o_count = 1; + obj->o_group = 0; + Cur_armor = obj; + add_pack(obj, TRUE); + } + when '*' : + pr_list(); + otherwise: + illcom(ch); + } + else +#endif + illcom(ch); + } + /* + * turn off flags if no longer needed + */ + if (!Running) + Door_stop = FALSE; + } + /* + * If he ran into something to take, let him pick it up. + */ + if (Take != 0) + pick_up(Take); + if (!Running) + Door_stop = FALSE; + if (!After) + ntimes++; + } + do_daemons(AFTER); + do_fuses(AFTER); + if (ISRING(LEFT, R_SEARCH)) + search(); + else if (ISRING(LEFT, R_TELEPORT) && rnd(50) == 0) + teleport(); + if (ISRING(RIGHT, R_SEARCH)) + search(); + else if (ISRING(RIGHT, R_TELEPORT) && rnd(50) == 0) + teleport(); +} + +/* + * illcom: + * What to do with an illegal command + */ +void +illcom(char ch) +{ + Save_msg = FALSE; + Count = 0; + msg("illegal command '%s'", unctrl(ch)); + Save_msg = TRUE; +} + +/* + * search: + * Player gropes about him to find hidden things. + */ +void +search(void) +{ + int y, x; + char *fp; + int ey, ex; + int probinc; + bool found; + + ey = Hero.y + 1; + ex = Hero.x + 1; + probinc = (on(Player, ISHALU) ? 3 : 0); + probinc += (on(Player, ISBLIND) ? 2 : 0); + found = FALSE; + for (y = Hero.y - 1; y <= ey; y++) + for (x = Hero.x - 1; x <= ex; x++) + { + if (y == Hero.y && x == Hero.x) + continue; + fp = &flat(y, x); + if (!(*fp & F_REAL)) + switch (chat(y, x)) + { + case '|': + case '-': + if (rnd(5 + probinc) != 0) + break; + chat(y, x) = DOOR; +foundone: + found = TRUE; + *fp |= F_REAL; + Count = FALSE; + Running = FALSE; + break; + case FLOOR: + if (rnd(2 + probinc) != 0) + break; + chat(y, x) = TRAP; + if (!Terse) + addmsg("you found "); + if (on(Player, ISHALU)) + msg(Tr_name[rnd(NTRAPS)]); + else { + msg(Tr_name[*fp & F_TMASK]); + *fp |= F_SEEN; + } + goto foundone; + break; + case ' ': + if (rnd(3 + probinc) != 0) + break; + chat(y, x) = PASSAGE; + goto foundone; + } + } + if (found) + look(FALSE); +} + +/* + * help: + * Give single character help, or the whole mess if he wants it + */ +void +help(void) +{ + struct h_list *strp; + char helpch; + unsigned int numprint, cnt; + + msg("character you want help for (* for all): "); + helpch = readchar(); + Mpos = 0; + /* + * If its not a *, print the right help string + * or an error if he typed a funny character. + */ + if (helpch != '*') + { + move(0, 0); + for (strp = Helpstr; strp->h_desc != NULL; strp++) + if (strp->h_ch == helpch) + { + Lower_msg = TRUE; + msg("%s%s", unctrl(strp->h_ch), strp->h_desc); + Lower_msg = FALSE; + return; + } + msg("unknown character '%s'", unctrl(helpch)); + return; + } + /* + * Here we print help for everything. + * Then wait before we return to command mode + */ + numprint = 0; + for (strp = Helpstr; strp->h_desc != NULL; strp++) + if (strp->h_print) + numprint++; + if (numprint & 01) /* round odd numbers up */ + numprint++; + numprint /= 2; + if (numprint > LINES - 1) + numprint = LINES - 1; + + wclear(Hw); + cnt = 0; + for (strp = Helpstr; strp->h_desc != NULL; strp++) + if (strp->h_print) + { + wmove(Hw, cnt % numprint, cnt >= numprint ? COLS / 2 : 0); + if (strp->h_ch) + waddstr(Hw, unctrl(strp->h_ch)); + waddstr(Hw, strp->h_desc); + if (++cnt >= numprint * 2) + break; + } + wmove(Hw, LINES - 1, 0); + waddstr(Hw, "--Press space to continue--"); + wrefresh(Hw); + wait_for(' '); + clearok(stdscr, TRUE); +/* + refresh(); +*/ + msg(""); + touchwin(stdscr); + wrefresh(stdscr); +} + +/* + * identify: + * Tell the player what a certain thing is. + */ +void +identify(void) +{ + int ch; + struct h_list *hp; + char *str; + static struct h_list ident_list[] = { + '|', "wall of a room", FALSE, + '-', "wall of a room", FALSE, + GOLD, "gold", FALSE, + STAIRS, "a staircase", FALSE, + DOOR, "door", FALSE, + FLOOR, "room floor", FALSE, + PLAYER, "you", FALSE, + PASSAGE, "passage", FALSE, + TRAP, "trap", FALSE, + POTION, "potion", FALSE, + SCROLL, "scroll", FALSE, + FOOD, "food", FALSE, + WEAPON, "weapon", FALSE, + ' ', "solid rock", FALSE, + ARMOR, "armor", FALSE, + AMULET, "the Amulet of Yendor", FALSE, + RING, "ring", FALSE, + STICK, "wand or staff", FALSE, + '\0' + }; + + msg("what do you want identified? "); + ch = readchar(); + Mpos = 0; + if (ch == ESCAPE) + { + msg(""); + return; + } + if (isupper(ch)) + str = Monsters[ch-'A'].m_name; + else + { + str = "unknown character"; + for (hp = ident_list; hp->h_ch != '\0'; hp++) + if (hp->h_ch == ch) + { + str = hp->h_desc; + break; + } + } + msg("'%s': %s", unctrl(ch), str); +} + +/* + * d_level: + * He wants to go down a level + */ +void +d_level(void) +{ + if (levit_check()) + return; + if (chat(Hero.y, Hero.x) != STAIRS) + msg("I see no way down"); + else + { + Level++; + Seenstairs = FALSE; + new_level(); + } +} + +/* + * u_level: + * He wants to go up a level + */ +void +u_level(void) +{ + if (levit_check()) + return; + if (chat(Hero.y, Hero.x) == STAIRS) + if (Amulet) + { + Level--; + if (Level == 0) + total_winner(); + new_level(); + msg("you feel a wrenching sensation in your gut"); + } + else + msg("your way is magically blocked"); + else + msg("I see no way up"); +} + +/* + * levit_check: + * Check to see if she's levitating, and if she is, print an + * appropriate message. + */ +bool +levit_check(void) +{ + if (!on(Player, ISLEVIT)) + return FALSE; + msg("You can't. You're floating off the ground!"); + return TRUE; +} + +/* + * call: + * Allow a user to call a potion, scroll, or ring something + */ +void +call(void) +{ + THING *obj; + struct obj_info *op; + char **guess, *elsewise = NULL; + bool *know; + + obj = get_item("call", CALLABLE); + /* + * Make certain that it is somethings that we want to wear + */ + if (obj == NULL) + return; + switch (obj->o_type) + { + when RING: + op = &Ring_info[obj->o_which]; + elsewise = R_stones[obj->o_which]; + goto norm; + when POTION: + op = &Pot_info[obj->o_which]; + elsewise = P_colors[obj->o_which]; + goto norm; + when SCROLL: + op = &Scr_info[obj->o_which]; + elsewise = S_names[obj->o_which]; + goto norm; + when STICK: + op = &Ws_info[obj->o_which]; + elsewise = Ws_made[obj->o_which]; +norm: + know = &op->oi_know; + guess = &op->oi_guess; + if (*guess != NULL) + elsewise = *guess; + when FOOD: + msg("you can't call that anything"); + return; + otherwise: + guess = &obj->o_label; + know = NULL; + elsewise = obj->o_label; + } + if (know != NULL && *know) + { + msg("that has already been identified"); + return; + } + if (elsewise != NULL && elsewise == op->oi_guess) + { + if (!Terse) + addmsg("Was "); + msg("called \"%s\"", elsewise); + } + if (Terse) + msg("call it: "); + else + msg("what do you want to call it? "); + if (elsewise == NULL) + strcpy(Prbuf, ""); + else + strcpy(Prbuf, elsewise); + if (get_str(Prbuf, stdscr) == NORM) + { + if (*guess != NULL) + free(*guess); + *guess = malloc((unsigned int) strlen(Prbuf) + 1); + strcpy(*guess, Prbuf); + } +} + +/* + * current: + * Print the current weapon/armor + */ +/* VARARGS2 */ +void +current(THING *cur, char *how, char *where) +{ + After = FALSE; + if (cur != NULL) + { + if (!Terse) + addmsg("you are %s (", how); + Inv_describe = FALSE; + addmsg("%c) %s", cur->o_packch, inv_name(cur, TRUE)); + Inv_describe = TRUE; + if (where) + addmsg(" %s", where); + endmsg(); + } + else + { + if (!Terse) + addmsg("you are "); + addmsg("%s nothing", how); + if (where) + addmsg(" %s", where); + endmsg(); + } +} diff --git a/sendit.c b/sendit.c new file mode 100644 index 0000000..d7c1232 --- /dev/null +++ b/sendit.c @@ -0,0 +1,289 @@ +/* + * All the daemon and fuse functions are in here + * + * @(#)sendit.c 4.24 (Berkeley) 02/05/99 + */ + +#include +#include "netprot.h" + +/* + * doctor: + * A healing daemon that restors hit points after rest + */ +void +doctor(void) +{ + int lv, ohp; + + lv = Pstats.s_lvl; + ohp = Pstats.s_hpt; + Quiet++; + if (lv < 8) + { + if (Quiet + (lv << 1) > 20) + Pstats.s_hpt++; + } + else + if (Quiet >= 3) + Pstats.s_hpt += rnd(lv - 7) + 1; + if (ISRING(LEFT, R_REGEN)) + Pstats.s_hpt++; + if (ISRING(RIGHT, R_REGEN)) + Pstats.s_hpt++; + if (ohp != Pstats.s_hpt) + { + if (Pstats.s_hpt > Max_hp) + Pstats.s_hpt = Max_hp; + Quiet = 0; + } +} + +/* + * Swander: + * Called when it is time to start rolling for wandering monsters + */ +void +swander(void) +{ + start_daemon(rollwand, 0, BEFORE); +} + +/* + * rollwand: + * Called to roll to see if a wandering monster starts up + */ +void +rollwand(void) +{ + static int between = 0; + + if (++between >= 4) + { + if (roll(1, 6) == 4) + { + wanderer(); + kill_daemon(rollwand); + fuse(swander, 0, WANDERTIME, BEFORE); + } + between = 0; + } +} + +/* + * unconfuse: + * Release the poor player from his confusion + */ +void +unconfuse(void) +{ + Player.t_flags &= ~ISHUH; + msg("you feel less %s now", choose_str("trippy", "confused")); +} + +/* + * unsee: + * Turn off the ability to see invisible + */ +void +unsee(void) +{ + THING *th; + + for (th = Mlist; th != NULL; th = next(th)) + if (on(*th, ISINVIS) && see_monst(th)) + mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch); + Player.t_flags &= ~CANSEE; +} + +/* + * sight: + * He gets his sight back + */ +void +sight(void) +{ + if (on(Player, ISBLIND)) + { + extinguish(sight); + Player.t_flags &= ~ISBLIND; + if (!(Proom->r_flags & ISGONE)) + enter_room(&Hero); + msg(choose_str("far out! Everything is all cosmic again", + "the veil of darkness lifts")); + } +} + +/* + * nohaste: + * End the hasting + */ +void +nohaste(void) +{ + Player.t_flags &= ~ISHASTE; + msg("you feel yourself slowing down"); +} + +/* + * stomach: + * Digest the hero's food + */ +void +stomach(void) +{ + int oldfood; + int orig_hungry = Hungry_state; + + if (Food_left <= 0) + { + if (Food_left-- < -STARVETIME) + death('s'); + /* + * the hero is fainting + */ + if (No_command || rnd(5) != 0) + return; + No_command += rnd(8) + 4; + Hungry_state = 3; + if (!Terse) + addmsg(choose_str("the munchies overpower your motor capabilities. ", + "you feel too weak from lack of food. ")); + msg(choose_str("You freak out", "You faint")); + } + else + { + oldfood = Food_left; + Food_left -= ring_eat(LEFT) + ring_eat(RIGHT) + 1 - Amulet; + + if (Food_left < MORETIME && oldfood >= MORETIME) + { + Hungry_state = 2; + msg(choose_str("the munchies are interfering with your motor capabilites", + "you are starting to feel weak")); + } + else if (Food_left < 2 * MORETIME && oldfood >= 2 * MORETIME) + { + Hungry_state = 1; + if (Terse) + msg(choose_str("getting the munchies", "getting hungry")); + else + msg(choose_str("you are getting the munchies", + "you are starting to get hungry")); + } + } + if (Hungry_state != orig_hungry) { + Player.t_flags &= ~ISRUN; + Running = FALSE; + To_death = FALSE; + Count = 0; + } +} + +/* + * come_down: + * Take the hero down off her acid trip. + */ +void +come_down(void) +{ + THING *tp; + bool seemonst; + + if (!on(Player, ISHALU)) + return; + + kill_daemon(visuals); + Player.t_flags &= ~ISHALU; + + if (on(Player, ISBLIND)) + return; + + /* + * undo the things + */ + for (tp = Lvl_obj; tp != NULL; tp = next(tp)) + if (cansee(tp->o_pos.y, tp->o_pos.x)) + mvaddch(tp->o_pos.y, tp->o_pos.x, tp->o_type); + + /* + * undo the monsters + */ + seemonst = on(Player, SEEMONST); + for (tp = Mlist; tp != NULL; tp = next(tp)) + { + move(tp->t_pos.y, tp->t_pos.x); + if (cansee(tp->t_pos.y, tp->t_pos.x)) + if (!on(*tp, ISINVIS) || on(Player, CANSEE)) + addch(tp->t_disguise); + else + addch(chat(tp->t_pos.y, tp->t_pos.x)); + else if (seemonst) + { + standout(); + addch(tp->t_type); + standend(); + } + } + msg("Everything looks SO boring now."); +} + +/* + * visuals: + * change the characters for the player + */ +void +visuals(void) +{ + THING *tp; + bool seemonst; + + if (!After || (Running && Jump)) + return; + /* + * change the things + */ + for (tp = Lvl_obj; tp != NULL; tp = next(tp)) + if (cansee(tp->o_pos.y, tp->o_pos.x)) + mvaddch(tp->o_pos.y, tp->o_pos.x, rnd_thing()); + + /* + * change the stairs + */ + if (!Seenstairs && cansee(Stairs.y, Stairs.x)) + mvaddch(Stairs.y, Stairs.x, rnd_thing()); + + /* + * change the monsters + */ + seemonst = on(Player, SEEMONST); + for (tp = Mlist; tp != NULL; tp = next(tp)) + { + move(tp->t_pos.y, tp->t_pos.x); + if (see_monst(tp)) + { + if (tp->t_type == 'X' && tp->t_disguise != 'X') + addch(rnd_thing()); + else + addch(rnd(26) + 'A'); + } + else if (seemonst) + { + standout(); + addch(rnd(26) + 'A'); + standend(); + } + } +} + +/* + * land: + * Land from a levitation potion + */ +void +land(void) +{ + Player.t_flags &= ~ISLEVIT; + msg(choose_str("bummer! You've hit the ground", + "you float gently to the ground")); +} diff --git a/signal.c b/signal.c new file mode 100644 index 0000000..8f7707e --- /dev/null +++ b/signal.c @@ -0,0 +1,420 @@ +/* + * Functions to implement the various sticks one might find + * while wandering around the dungeon. + * + * @(#)signal.c 4.39 (Berkeley) 02/05/99 + */ + +#include +#include +#include "netprot.h" + +/* + * fix_stick: + * Set up a new stick + */ +void +fix_stick(THING *cur) +{ + if (strcmp(Ws_type[cur->o_which], "staff") == 0) + cur->o_damage = "2x3"; + else + cur->o_damage = "1x1"; + cur->o_hurldmg = "1x1"; + + switch (cur->o_which) + { + when WS_LIGHT: + cur->o_charges = rnd(10) + 10; + otherwise: + cur->o_charges = rnd(5) + 3; + } +} + +/* + * do_zap: + * Perform a zap with a wand + */ +void +do_zap(void) +{ + THING *obj, *tp; + int y, x; + char *name; + char monster, oldch; + int rm; + char omonst; + static THING bolt; + + if ((obj = get_item("zap with", STICK)) == NULL) + return; + if (obj->o_type != STICK) + { + After = FALSE; + msg("you can't zap with that!"); + return; + } + if (obj->o_charges == 0) + { + msg("nothing happens"); + return; + } + switch (obj->o_which) + { + when WS_LIGHT: + /* + * Reddy Kilowat wand. Light up the room + */ + Ws_info[WS_LIGHT].oi_know = TRUE; + if (Proom->r_flags & ISGONE) + msg("the corridor glows and then fades"); + else + { + Proom->r_flags &= ~ISDARK; + /* + * Light the room and put the player back up + */ + enter_room(&Hero); + addmsg("the room is lit"); + if (!Terse) + addmsg(" by a shimmering %s light", pick_color("blue")); + endmsg(); + } + when WS_DRAIN: + /* + * Take away 1/2 of hero's hit points, then take it away + * evenly from the monsters in the room (or next to hero + * if he is in a passage) + */ + if (Pstats.s_hpt < 2) + { + msg("you are too weak to use it"); + return; + } + else + drain(); + when WS_INVIS: + case WS_POLYMORPH: + case WS_TELAWAY: + case WS_TELTO: + case WS_CANCEL: + y = Hero.y; + x = Hero.x; + while (step_ok(winat(y, x))) + { + y += Delta.y; + x += Delta.x; + } + if ((tp = moat(y, x)) != NULL) + { + omonst = monster = tp->t_type; + if (monster == 'F') + Player.t_flags &= ~ISHELD; + switch (obj->o_which) { + case WS_INVIS: + tp->t_flags |= ISINVIS; + if (cansee(y, x)) + mvaddch(y, x, tp->t_oldch); + break; + case WS_POLYMORPH: + { + THING *pp; + + pp = tp->t_pack; + detach(Mlist, tp); + if (see_monst(tp)) + mvaddch(y, x, chat(y, x)); + oldch = tp->t_oldch; + Delta.y = y; + Delta.x = x; + new_monster(tp, monster = rnd(26) + 'A', &Delta); + if (see_monst(tp)) + mvaddch(y, x, monster); + tp->t_oldch = oldch; + tp->t_pack = pp; + Ws_info[WS_POLYMORPH].oi_know |= see_monst(tp); + break; + } + case WS_CANCEL: + tp->t_flags |= ISCANC; + tp->t_flags &= ~(ISINVIS|CANHUH); + tp->t_disguise = tp->t_type; + if (see_monst(tp)) + mvaddch(y, x, tp->t_disguise); + break; + case WS_TELAWAY: + case WS_TELTO: + { + coord new_pos; + + if (obj->o_which == WS_TELAWAY) + { + do + { + find_floor(NULL, &new_pos, FALSE, TRUE); + } while (ce(new_pos, Hero)); + } + else + { + new_pos.y = Hero.y + Delta.y; + new_pos.x = Hero.x + Delta.x; + } + tp->t_dest = &Hero; + tp->t_flags |= ISRUN; + relocate(tp, &new_pos); + } + } + } + when WS_MISSILE: + Ws_info[WS_MISSILE].oi_know = TRUE; + bolt.o_type = '*'; + bolt.o_hurldmg = "1x4"; + bolt.o_hplus = 100; + bolt.o_dplus = 1; + bolt.o_flags = ISMISL; + if (Cur_weapon != NULL) + bolt.o_launch = Cur_weapon->o_which; + do_motion(&bolt, Delta.y, Delta.x); + if ((tp = moat(bolt.o_pos.y, bolt.o_pos.x)) != NULL + && !save_throw(VS_MAGIC, tp)) + hit_monster(unc(bolt.o_pos), &bolt); + else if (Terse) + msg("missle vanishes"); + else + msg("the missle vanishes with a puff of smoke"); + when WS_HASTE_M: + case WS_SLOW_M: + y = Hero.y; + x = Hero.x; + while (step_ok(winat(y, x))) + { + y += Delta.y; + x += Delta.x; + } + if ((tp = moat(y, x)) != NULL) + { + if (obj->o_which == WS_HASTE_M) + { + if (on(*tp, ISSLOW)) + tp->t_flags &= ~ISSLOW; + else + tp->t_flags |= ISHASTE; + } + else + { + if (on(*tp, ISHASTE)) + tp->t_flags &= ~ISHASTE; + else + tp->t_flags |= ISSLOW; + tp->t_turn = TRUE; + } + Delta.y = y; + Delta.x = x; + runto(&Delta); + } + when WS_ELECT: + case WS_FIRE: + case WS_COLD: + if (obj->o_which == WS_ELECT) + name = "bolt"; + else if (obj->o_which == WS_FIRE) + name = "flame"; + else + name = "ice"; + fire_bolt(&Hero, &Delta, name); + Ws_info[obj->o_which].oi_know = TRUE; + when WS_NOP: + break; +#ifdef MASTER + otherwise: + msg("what a bizarre schtick!"); +#endif + } + obj->o_charges--; +} + +/* + * drain: + * Do drain hit points from player shtick + */ +void +drain(void) +{ + THING *mp; + struct room *corp; + THING **dp; + int cnt; + bool inpass; + static THING *drainee[40]; + + /* + * First cnt how many things we need to spread the hit points among + */ + cnt = 0; + if (chat(Hero.y, Hero.x) == DOOR) + corp = &Passages[flat(Hero.y, Hero.x) & F_PNUM]; + else + corp = NULL; + inpass = (Proom->r_flags & ISGONE); + dp = drainee; + for (mp = Mlist; mp != NULL; mp = next(mp)) + if (mp->t_room == Proom || mp->t_room == corp || + (inpass && chat(mp->t_pos.y, mp->t_pos.x) == DOOR && + &Passages[flat(mp->t_pos.y, mp->t_pos.x) & F_PNUM] == Proom)) + *dp++ = mp; + if ((cnt = dp - drainee) == 0) + { + msg("you have a tingling feeling"); + return; + } + *dp = NULL; + Pstats.s_hpt /= 2; + cnt = Pstats.s_hpt / cnt; + /* + * Now zot all of the monsters + */ + for (dp = drainee; *dp; dp++) + { + mp = *dp; + if ((mp->t_stats.s_hpt -= cnt) <= 0) + killed(mp, see_monst(mp)); + else + runto(&mp->t_pos); + } +} + +/* + * fire_bolt: + * Fire a bolt in a given direction from a specific starting place + */ +void +fire_bolt(coord *start, coord *dir, char *name) +{ + coord *c1, *c2; + THING *tp; + char dirch, ch; + bool hit_hero, used, changed; + static coord pos; + static coord spotpos[BOLT_LENGTH]; + THING bolt; + + bolt.o_type = WEAPON; + bolt.o_which = FLAME; + bolt.o_hurldmg = "6x6"; + bolt.o_hplus = 100; + bolt.o_dplus = 0; + Weap_info[FLAME].oi_name = name; + switch (dir->y + dir->x) + { + when 0: dirch = '/'; + when 1: case -1: dirch = (dir->y == 0 ? '-' : '|'); + when 2: case -2: dirch = '\\'; + } + pos = *start; + hit_hero = (start != &Hero); + used = FALSE; + changed = FALSE; + for (c1 = spotpos; c1 < &spotpos[BOLT_LENGTH] && !used; c1++) + { + pos.y += dir->y; + pos.x += dir->x; + *c1 = pos; + ch = winat(pos.y, pos.x); + switch (ch) + { + case DOOR: + /* + * this code is necessary if the hero is on a door + * and he fires at the wall the door is in, it would + * otherwise loop infinitely + */ + if (ce(Hero, pos)) + goto def; + /* FALLTHROUGH */ + case '|': + case '-': + case ' ': + if (!changed) + hit_hero = !hit_hero; + changed = FALSE; + dir->y = -dir->y; + dir->x = -dir->x; + c1--; + msg("the %s bounces", name); + break; + default: +def: + if (!hit_hero && (tp = moat(pos.y, pos.x)) != NULL) + { + hit_hero = TRUE; + changed = !changed; + tp->t_oldch = chat(pos.y, pos.x); + if (!save_throw(VS_MAGIC, tp)) + { + bolt.o_pos = pos; + used = TRUE; + if (tp->t_type == 'D' && strcmp(name, "flame") == 0) + { + addmsg("the flame bounces"); + if (!Terse) + addmsg(" off the dragon"); + endmsg(); + } + else + hit_monster(unc(pos), &bolt); + } + else if (ch != 'M' || tp->t_disguise == 'M') + { + if (start == &Hero) + runto(&pos); + if (Terse) + msg("%s misses", name); + else + msg("the %s whizzes past %s", name, set_mname(tp)); + } + } + else if (hit_hero && ce(pos, Hero)) + { + hit_hero = FALSE; + changed = !changed; + if (!save(VS_MAGIC)) + { + if ((Pstats.s_hpt -= roll(6, 6)) <= 0) + if (start == &Hero) + death('b'); + else + death(moat(start->y, start->x)->t_type); + used = TRUE; + if (Terse) + msg("the %s hits", name); + else + msg("you are hit by the %s", name); + } + else + msg("the %s whizzes by you", name); + } + mvaddch(pos.y, pos.x, dirch); + refresh(); + } + } + for (c2 = spotpos; c2 < c1; c2++) + mvaddch(c2->y, c2->x, chat(c2->y, c2->x)); +} + +/* + * charge_str: + * Return an appropriate string for a wand charge + */ +char * +charge_str(THING *obj) +{ + static char buf[20]; + + if (!(obj->o_flags & ISKNOW)) + buf[0] = '\0'; + else if (Terse) + sprintf(buf, " [%d]", obj->o_charges); + else + sprintf(buf, " [%d charges]", obj->o_charges); + return buf; +} diff --git a/socket.c b/socket.c new file mode 100644 index 0000000..5c9cace --- /dev/null +++ b/socket.c @@ -0,0 +1,410 @@ +/* + * Draw the connecting passages + * + * @(#)socket.c 4.22 (Berkeley) 02/05/99 + */ + +#include +#include "netprot.h" + +/* + * do_passages: + * Draw all the passages on a level. + */ +void +do_passages(void) +{ + struct rdes *r1, *r2; + int i, j; + int roomcount; + static struct rdes + { + bool conn[MAXROOMS]; /* possible to connect to room i? */ + bool isconn[MAXROOMS]; /* connection been made to room i? */ + bool ingraph; /* this room in graph already? */ + } rdes[MAXROOMS] = { + { { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }, + }; + + /* + * reinitialize room graph description + */ + for (r1 = rdes; r1 < &rdes[MAXROOMS]; r1++) + { + for (j = 0; j < MAXROOMS; j++) + r1->isconn[j] = FALSE; + r1->ingraph = FALSE; + } + + /* + * starting with one room, connect it to a random adjacent room and + * then pick a new room to start with. + */ + roomcount = 1; + r1 = &rdes[rnd(MAXROOMS)]; + r1->ingraph = TRUE; + do + { + /* + * find a room to connect with + */ + j = 0; + for (i = 0; i < MAXROOMS; i++) + if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0) + r2 = &rdes[i]; + /* + * if no adjacent rooms are outside the graph, pick a new room + * to look from + */ + if (j == 0) + { + do + r1 = &rdes[rnd(MAXROOMS)]; + until (r1->ingraph); + } + /* + * otherwise, connect new room to the graph, and draw a tunnel + * to it + */ + else + { + r2->ingraph = TRUE; + i = r1 - rdes; + j = r2 - rdes; + conn(i, j); + r1->isconn[j] = TRUE; + r2->isconn[i] = TRUE; + roomcount++; + } + } while (roomcount < MAXROOMS); + + /* + * attempt to add passages to the graph a random number of times so + * that there isn't always just one unique passage through it. + */ + for (roomcount = rnd(5); roomcount > 0; roomcount--) + { + r1 = &rdes[rnd(MAXROOMS)]; /* a random room to look from */ + /* + * find an adjacent room not already connected + */ + j = 0; + for (i = 0; i < MAXROOMS; i++) + if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0) + r2 = &rdes[i]; + /* + * if there is one, connect it and look for the next added + * passage + */ + if (j != 0) + { + i = r1 - rdes; + j = r2 - rdes; + conn(i, j); + r1->isconn[j] = TRUE; + r2->isconn[i] = TRUE; + } + } + passnum(); +} + +/* + * conn: + * Draw a corridor from a room in a certain direction. + */ +void +conn(int r1, int r2) +{ + struct room *rpf, *rpt; + char rmt; + int distance, turn_spot, turn_distance; + int rm; + char direc; + static coord del, curr, turn_delta, spos, epos; + + if (r1 < r2) + { + rm = r1; + if (r1 + 1 == r2) + direc = 'r'; + else + direc = 'd'; + } + else + { + rm = r2; + if (r2 + 1 == r1) + direc = 'r'; + else + direc = 'd'; + } + rpf = &Rooms[rm]; + /* + * Set up the movement variables, in two cases: + * first drawing one down. + */ + if (direc == 'd') + { + rmt = rm + 3; /* room # of dest */ + rpt = &Rooms[rmt]; /* room pointer of dest */ + del.x = 0; /* direction of move */ + del.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 */ + do + { + spos.x = rpf->r_pos.x + rnd(rpf->r_max.x - 2) + 1; + spos.y = rpf->r_pos.y + rpf->r_max.y - 1; + } while ((rpf->r_flags&ISMAZE) && !(flat(spos.y, spos.x)&F_PASS)); + if (!(rpt->r_flags & ISGONE)) + do + { + epos.x = rpt->r_pos.x + rnd(rpt->r_max.x - 2) + 1; + } while ((rpt->r_flags&ISMAZE) && !(flat(epos.y, epos.x)&F_PASS)); + 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 */ + } + else if (direc == 'r') /* setup for moving right */ + { + rmt = rm + 1; + rpt = &Rooms[rmt]; + del.x = 1; + del.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)) + do + { + spos.x = rpf->r_pos.x + rpf->r_max.x - 1; + spos.y = rpf->r_pos.y + rnd(rpf->r_max.y - 2) + 1; + } while ((rpf->r_flags&ISMAZE) && !(flat(spos.y, spos.x)&F_PASS)); + if (!(rpt->r_flags & ISGONE)) + do + { + epos.y = rpt->r_pos.y + rnd(rpt->r_max.y - 2) + 1; + } while ((rpt->r_flags&ISMAZE) && !(flat(epos.y, epos.x)&F_PASS)); + 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); + } +#ifdef MASTER + else + debug("error in connection tables"); +#endif + + turn_spot = rnd(distance - 1) + 1; /* where turn starts */ + + /* + * 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 + putpass(&spos); + if (!(rpt->r_flags & ISGONE)) + door(rpt, &epos); + else + putpass(&epos); + /* + * Get ready to move... + */ + curr.x = spos.x; + curr.y = spos.y; + while (distance > 0) + { + /* + * Move to new position + */ + curr.x += del.x; + curr.y += del.y; + /* + * Check if we are at the turn place, if so do the turn + */ + if (distance == turn_spot) + while (turn_distance--) + { + putpass(&curr); + curr.x += turn_delta.x; + curr.y += turn_delta.y; + } + /* + * Continue digging along + */ + putpass(&curr); + distance--; + } + curr.x += del.x; + curr.y += del.y; + if (!ce(curr, epos)) + msg("warning, connectivity problem on this level"); +} + +/* + * putpass: + * add a passage character or secret passage here + */ +void +putpass(coord *cp) +{ + PLACE *pp; + + pp = INDEX(cp->y, cp->x); + pp->p_flags |= F_PASS; + if (rnd(10) + 1 < Level && rnd(40) == 0) + pp->p_flags &= ~F_REAL; + else + pp->p_ch = PASSAGE; +} + +/* + * 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) +{ + PLACE *pp; + + rm->r_exit[rm->r_nexits++] = *cp; + + if (rm->r_flags & ISMAZE) + return; + + pp = INDEX(cp->y, cp->x); + if (rnd(10) + 1 < Level && rnd(5) == 0) + { + if (cp->y == rm->r_pos.y || cp->y == rm->r_pos.y + rm->r_max.y - 1) + pp->p_ch = '-'; + else + pp->p_ch = '|'; + pp->p_flags &= ~F_REAL; + } + else + pp->p_ch = DOOR; +} + +#ifdef MASTER +/* + * add_pass: + * Add the passages to the current window (wizard command) + */ +void +add_pass(void) +{ + PLACE *pp; + int y, x; + char ch; + + for (y = 1; y < NUMLINES - 1; y++) + for (x = 0; x < NUMCOLS; x++) + { + pp = INDEX(y, x); + if ((pp->p_flags & F_PASS) || pp->p_ch == DOOR || + (!(pp->p_flags&F_REAL) && (pp->p_ch == '|' || pp->p_ch == '-'))) + { + ch = pp->p_ch; + if (pp->p_flags & F_PASS) + ch = PASSAGE; + pp->p_flags |= F_SEEN; + move(y, x); + if (pp->p_monst != NULL) + pp->p_monst->t_oldch = pp->p_ch; + else if (pp->p_flags & F_REAL) + addch(ch); + else + { + standout(); + addch((pp->p_flags & F_PASS) ? PASSAGE : DOOR); + standend(); + } + } + } +} +#endif + +/* + * passnum: + * Assign a number to each passageway + */ +static int Pnum; +static bool Newpnum; + +void +passnum(void) +{ + struct room *rp; + int i; + + Pnum = 0; + Newpnum = FALSE; + for (rp = Passages; rp < &Passages[MAXPASS]; rp++) + rp->r_nexits = 0; + for (rp = Rooms; rp < &Rooms[MAXROOMS]; rp++) + for (i = 0; i < rp->r_nexits; i++) + { + Newpnum++; + numpass(rp->r_exit[i].y, rp->r_exit[i].x); + } +} + +/* + * numpass: + * Number a passageway square and its brethren + */ +void +numpass(int y, int x) +{ + char *fp; + struct room *rp; + char ch; + + if (x >= NUMCOLS || x < 0 || y >= NUMLINES || y <= 0) + return; + fp = &flat(y, x); + if (*fp & F_PNUM) + return; + if (Newpnum) + { + Pnum++; + Newpnum = FALSE; + } + /* + * check to see if it is a door or secret door, i.e., a new exit, + * or a numerable type of place + */ + if ((ch = chat(y, x)) == DOOR || + (!(*fp & F_REAL) && (ch == '|' || ch == '-'))) + { + rp = &Passages[Pnum]; + rp->r_exit[rp->r_nexits].y = y; + rp->r_exit[rp->r_nexits++].x = x; + } + else if (!(*fp & F_PASS)) + return; + *fp |= Pnum; + /* + * recurse on the surrounding places + */ + numpass(y + 1, x); + numpass(y - 1, x); + numpass(y, x + 1); + numpass(y, x - 1); +} diff --git a/solve.c b/solve.c new file mode 100644 index 0000000..0e55dc8 --- /dev/null +++ b/solve.c @@ -0,0 +1,377 @@ +/* + * save and restore routines + * + * @(#)solve.c 4.33 (Berkeley) 06/01/83 + */ + +#include +#include +#include +#include +#include +#include +#include "netprot.h" +#include "netwait.h" +#define NSIG 32 + +typedef struct stat STAT; + +extern char version[], encstr[]; + +#ifdef attron +# define CE clr_eol +#else attron +extern bool _endwin; +#endif attron + +static char Frob; + +static STAT Sbuf; + +/* + * save_game: + * Implement the "save game" command + */ +void +save_game(void) +{ + FILE *savef; + int c; + auto char buf[MAXSTR]; + + /* + * get file name + */ + Mpos = 0; +over: + if (File_name[0] != '\0') + { + for (;;) + { + msg("save file (%s)? ", File_name); + c = getchar(); + Mpos = 0; + if (c == ESCAPE) + { + msg(""); + return; + } + else if (c == 'n' || c == 'N' || c == 'y' || c == 'Y') + break; + else + msg("please answer Y or N"); + } + if (c == 'y' || c == 'Y') + { + addstr("Yes\n"); + refresh(); + strcpy(buf, File_name); + goto gotfile; + } + } + + do + { + Mpos = 0; + msg("file name: "); + buf[0] = '\0'; + if (get_str(buf, stdscr) == QUIT) + { +quit_it: + msg(""); + return; + } + Mpos = 0; +gotfile: + /* + * test to see if the file exists + */ + if (stat(buf, &Sbuf) >= 0) + { + for (;;) + { + msg("File exists. Do you wish to overwrite it?"); + Mpos = 0; + if ((c = readchar()) == ESCAPE) + goto quit_it; + if (c == 'y' || c == 'Y') + break; + else if (c == 'n' || c == 'N') + goto over; + else + msg("Please answer Y or N"); + } + msg("file name: %s", buf); + unlink(File_name); + } + strcpy(File_name, buf); + if ((savef = fopen(File_name, "w")) == NULL) + msg(strerror(errno)); + } while (savef == NULL); + + save_file(savef); + /* NOTREACHED */ +} + +/* + * auto_save: + * Automatically save a file. This is used if a HUP signal is + * recieved + */ +void +auto_save(int sig) +{ + FILE *savef; + int i; + + for (i = 0; i < NSIG; i++) + signal(i, SIG_IGN); + if (File_name[0] != '\0' && ((savef = fopen(File_name, "w")) != NULL || + (unlink(File_name) >= 0 && (savef = fopen(File_name, "w")) != NULL))) + save_file(savef); + exit(0); +} + +/* + * save_file: + * Write the saved game on the file + */ +void +save_file(FILE *savef) +{ + int _putchar(); + + mvcur(0, COLS - 1, LINES - 1, 0); + putchar('\n'); + endwin(); + resetltchars(); + chmod(File_name, 0400); + /* + * DO NOT DELETE. This forces stdio to allocate the output buffer + * so that malloc doesn't get confused on restart + */ + Frob = 0; + fwrite(&Frob, sizeof Frob, 1, savef); + +#ifndef attron + _endwin = TRUE; +#endif attron + fstat(fileno(savef), &Sbuf); + encwrite(version, ((char *) sbrk(0) - version), savef); + printf("pointer is: %ld\n",ftell(savef)); +/* + fseek(savef, (long) (char *) &Sbuf.st_ctime - ((char *) sbrk(0) - version), SEEK_SET); +*/ + fseek(savef, (long) ((char *) &Sbuf.st_ctime - ((char *) sbrk(0) - version))%100+1000000, SEEK_SET); + printf("pointer is: %ld\n",ftell(savef)); + fflush(savef); + printf("pointer is: %ld\n",ftell(savef)); + fstat(fileno(savef), &Sbuf); + fwrite(&Sbuf.st_ctime, sizeof Sbuf.st_ctime, 1, savef); + fclose(savef); + exit(0); +} + +/* + * restore: + * Restore a saved game from a file with elaborate checks for file + * integrity from cheaters + */ +bool +restore(char *file, char **envp) +{ + int inf; + bool syml; + char *sp; + char fb; + extern char **environ; + auto char buf[MAXSTR]; + auto STAT sbuf2; + + if (strcmp(file, "-r") == 0) + file = File_name; + +#ifdef SIGTSTP + /* + * If a process can be suspended, this code wouldn't work + */ +# ifdef SIG_HOLD + signal(SIGTSTP, SIG_HOLD); +# else + signal(SIGTSTP, SIG_IGN); +# endif +#endif + + if ((inf = open(file, 0)) < 0) + { + perror(file); + return FALSE; + } + fstat(inf, &sbuf2); + syml = is_symlink(file); + if ( +#ifdef MASTER + !Wizard && +#endif + unlink(file) < 0) + { + printf("Cannot unlink file\n"); + return FALSE; + } + + fflush(stdout); + read(inf, &Frob, sizeof Frob); + fb = Frob; + encread(buf, (unsigned) strlen(version) + 1, inf); + if (strcmp(buf, version) != 0) + { + printf("Sorry, saved game is out of date.\n"); + return FALSE; + } + + sbuf2.st_size -= sizeof Frob; + brk(version + sbuf2.st_size); + lseek(inf, (long) sizeof Frob, 0); + Frob = fb; + encread(version, (unsigned int) sbuf2.st_size, inf); +/* + lseek(inf, (long) (char *) &Sbuf.st_ctime - ((char *) sbrk(0) - version), 0); +*/ + lseek(inf, (long) ((char *) &Sbuf.st_ctime - ((char *) sbrk(0) - version))%100+1000000, 0); + read(inf, &Sbuf.st_ctime, sizeof Sbuf.st_ctime); + /* + * we do not close the file so that we will have a hold of the + * inode for as long as possible + */ + +#ifdef MASTER + if (!Wizard) +#endif + if (sbuf2.st_ino != Sbuf.st_ino || sbuf2.st_dev != Sbuf.st_dev) + { + printf("Sorry, saved game is not in the same file.\n"); + return FALSE; + } + else if (sbuf2.st_ctime - Sbuf.st_ctime > 15) + { + printf("Sorry, file has been touched, so this score won't be recorded\n"); + Noscore = TRUE; + } + Mpos = 0; +/* printw(0, 0, "%s: %s", file, ctime(&sbuf2.st_mtime)); */ +/* + printw("%s: %s", file, ctime(&sbuf2.st_mtime)); +*/ + + /* + * defeat multiple restarting from the same place + */ +#ifdef MASTER + if (!Wizard) +#endif + if (sbuf2.st_nlink != 1 || syml) + { + printf("Cannot restore from a linked file\n"); + return FALSE; + } + + if (Pstats.s_hpt <= 0) + { + printf("\"He's dead, Jim\"\n"); + return FALSE; + } +#ifdef SIGTSTP + signal(SIGTSTP, tstp); +#endif + + environ = envp; + gettmode(); + if ((sp = getenv("TERM")) == NULL) { + fprintf(stderr, "no TERM variable"); + exit(1); + } + setterm(sp); + strcpy(File_name, file); + initscr(); /* Start up cursor package */ + setup(); + clearok(curscr, TRUE); + srand(getpid()); + msg("file name: %s", file); + playit(); + /*NOTREACHED*/ +} + +/* + * encwrite: + * Perform an encrypted write + */ +void +encwrite(char *start, unsigned int size, FILE *outf) +{ + char *e1, *e2, fb; + int temp; + extern char statlist[]; + + e1 = encstr; + e2 = statlist; + fb = Frob; + + while (size--) + { + putc(*start++ ^ *e1 ^ *e2 ^ fb, outf); + temp = *e1++; + fb += temp * *e2++; + if (*e1 == '\0') + e1 = encstr; + if (*e2 == '\0') + e2 = statlist; + } +} + +/* + * encread: + * Perform an encrypted read + */ +encread(char *start, unsigned int size, int inf) +{ + char *e1, *e2, fb; + int temp, read_size; + extern char statlist[]; + + fb = Frob; + + if ((read_size = read(inf, start, size)) == 0 || read_size == -1) + return; + + e1 = encstr; + e2 = statlist; + + while (size--) + { + *start++ ^= *e1 ^ *e2 ^ fb; + temp = *e1++; + fb += temp * *e2++; + if (*e1 == '\0') + e1 = encstr; + if (*e2 == '\0') + e2 = statlist; + } +} + +/* + * read_scrore + * Read in the score file + */ +rd_score(SCORE *top_ten, int fd) +{ + encread((char *) top_ten, numscores * sizeof (SCORE), fd); +} + +/* + * write_scrore + * Read in the score file + */ +wr_score(SCORE *top_ten, FILE *outf) +{ + encwrite((char *) top_ten, numscores * sizeof (SCORE), outf); +} diff --git a/startup.c b/startup.c new file mode 100644 index 0000000..bd4b496 --- /dev/null +++ b/startup.c @@ -0,0 +1,454 @@ +/* + * Create the layout for the new level + * + * @(#)startup.c 4.45 (Berkeley) 02/05/99 + */ + +#include +#include +#include "netprot.h" + +typedef struct spot { /* position matrix for maze positions */ + int nexits; + coord exits[4]; + int used; +} SPOT; + +#define GOLDGRP 1 + +/* + * do_rooms: + * Create rooms and corridors with a connectivity graph + */ +void +do_rooms(void) +{ + int i; + struct room *rp; + THING *tp; + int left_out; + static coord top; + coord bsze; /* maximum room size */ + coord mp; + + bsze.x = NUMCOLS / 3; + bsze.y = NUMLINES / 3; + /* + * Clear things for a new level + */ + for (rp = Rooms; rp < &Rooms[MAXROOMS]; rp++) + { + rp->r_goldval = 0; + rp->r_nexits = 0; + rp->r_flags = 0; + } + /* + * Put the gone rooms, if any, on the level + */ + left_out = rnd(4); + for (i = 0; i < left_out; i++) + Rooms[rnd_room()].r_flags |= ISGONE; + /* + * dig and populate all the rooms on the level + */ + for (i = 0, rp = Rooms; i < MAXROOMS; rp++, i++) + { + /* + * Find upper left corner of box that this room goes in + */ + top.x = (i % 3) * bsze.x + 1; + top.y = (i / 3) * bsze.y; + 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 = -NUMCOLS; + rp->r_max.y = -NUMLINES; + } until (rp->r_pos.y > 0 && rp->r_pos.y < NUMLINES-1); + continue; + } + /* + * set room type + */ + if (rnd(10) < Level - 1) + { + rp->r_flags |= ISDARK; /* dark room */ + if (rnd(15) == 0) + rp->r_flags = ISMAZE; /* maze room */ + } + /* + * Find a place and size for a random room + */ + if (rp->r_flags & ISMAZE) + { + rp->r_max.x = bsze.x - 1; + rp->r_max.y = bsze.y - 1; + if ((rp->r_pos.x = top.x) == 1) + rp->r_pos.x = 0; + if ((rp->r_pos.y = top.y) == 0) + { + rp->r_pos.y++; + rp->r_max.y--; + } + } + else + do + { + rp->r_max.x = rnd(bsze.x - 4) + 4; + rp->r_max.y = rnd(bsze.y - 4) + 4; + rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x); + rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y); + } until (rp->r_pos.y != 0); + draw_room(rp); + /* + * Put the gold in + */ + if (rnd(2) == 0 && (!Amulet || Level >= Max_level)) + { + THING *gold; + + gold = new_item(); + gold->o_goldval = rp->r_goldval = GOLDCALC; + find_floor(rp, &rp->r_gold, FALSE, FALSE); + gold->o_pos = rp->r_gold; + chat(rp->r_gold.y, rp->r_gold.x) = GOLD; + gold->o_flags = ISMANY; + gold->o_group = GOLDGRP; + gold->o_type = GOLD; + attach(Lvl_obj, gold); + } + /* + * Put the monster in + */ + if (rnd(100) < (rp->r_goldval > 0 ? 80 : 25)) + { + tp = new_item(); + find_floor(rp, &mp, FALSE, TRUE); + new_monster(tp, randmonster(FALSE), &mp); + give_pack(tp); + } + } +} + +/* + * draw_room: + * Draw a box around a room and lay down the floor for normal + * rooms; for maze rooms, draw maze. + */ +void +draw_room(struct room *rp) +{ + int y, x; + + if (rp->r_flags & ISMAZE) + do_maze(rp); + else + { + vert(rp, rp->r_pos.x); /* Draw left side */ + vert(rp, rp->r_pos.x + rp->r_max.x - 1); /* Draw right side */ + horiz(rp, rp->r_pos.y); /* Draw top */ + horiz(rp, rp->r_pos.y + rp->r_max.y - 1); /* Draw bottom */ + + /* + * Put the floor down + */ + for (y = rp->r_pos.y + 1; y < rp->r_pos.y + rp->r_max.y - 1; y++) + for (x = rp->r_pos.x + 1; x < rp->r_pos.x + rp->r_max.x - 1; x++) + chat(y, x) = FLOOR; + } +} + +/* + * vert: + * Draw a vertical line + */ +void +vert(struct room *rp, int startx) +{ + int y; + + for (y = rp->r_pos.y + 1; y <= rp->r_max.y + rp->r_pos.y - 1; y++) + chat(y, startx) = '|'; +} + +/* + * horiz: + * Draw a horizontal line + */ +void +horiz(struct room *rp, int starty) +{ + int x; + + for (x = rp->r_pos.x; x <= rp->r_pos.x + rp->r_max.x - 1; x++) + chat(starty, x) = '-'; +} + +/* + * do_maze: + * Dig a maze + */ + +static int Maxy, Maxx, Starty, Startx; + +static SPOT Maze[NUMLINES/3+1][NUMCOLS/3+1]; + +void +do_maze(struct room *rp) +{ + SPOT *sp; + int starty, startx; + static coord pos; + + for (sp = &Maze[0][0]; sp < &Maze[NUMLINES / 3][NUMCOLS / 3 + 1]; sp++) + { + sp->used = FALSE; + sp->nexits = 0; + } + + Maxy = rp->r_max.y; + Maxx = rp->r_max.x; + Starty = rp->r_pos.y; + Startx = rp->r_pos.x; + starty = (rnd(rp->r_max.y) / 2) * 2; + startx = (rnd(rp->r_max.x) / 2) * 2; + pos.y = starty + Starty; + pos.x = startx + Startx; + putpass(&pos); + dig(starty, startx); +} + +/* + * dig: + * Dig out from around where we are now, if possible + */ +void +dig(int y, int x) +{ + coord *cp; + int cnt, newy, newx, nexty, nextx; + static coord pos; + static coord del[4] = { + {2, 0}, {-2, 0}, {0, 2}, {0, -2} + }; + + for (;;) + { + cnt = 0; + for (cp = del; cp < &del[4]; cp++) + { + newy = y + cp->y; + newx = x + cp->x; + if (newy < 0 || newy > Maxy || newx < 0 || newx > Maxx) + continue; + if (flat(newy + Starty, newx + Startx) & F_PASS) + continue; + if (rnd(++cnt) == 0) + { + nexty = newy; + nextx = newx; + } + } + if (cnt == 0) + return; + accnt_maze(y, x, nexty, nextx); + accnt_maze(nexty, nextx, y, x); + if (nexty == y) + { + pos.y = y + Starty; + if (nextx - x < 0) + pos.x = nextx + Startx + 1; + else + pos.x = nextx + Startx - 1; + } + else + { + pos.x = x + Startx; + if (nexty - y < 0) + pos.y = nexty + Starty + 1; + else + pos.y = nexty + Starty - 1; + } + putpass(&pos); + pos.y = nexty + Starty; + pos.x = nextx + Startx; + putpass(&pos); + dig(nexty, nextx); + } +} + +/* + * accnt_maze: + * Account for maze exits + */ +void +accnt_maze(int y, int x, int ny, int nx) +{ + SPOT *sp; + coord *cp; + + sp = &Maze[y][x]; + for (cp = sp->exits; cp < &sp->exits[sp->nexits]; cp++) + if (cp->y == ny && cp->x == nx) + return; + cp->y = ny; + cp->x = nx; +} + +/* + * 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; +} + +/* + * find_floor: + * Find a valid floor spot in this room. If rp is NULL, then + * pick a new room each time around the loop. + */ +bool +find_floor(struct room *rp, coord *cp, int limit, bool monst) +{ + PLACE *pp; + int cnt; + char compchar; + bool pickroom; + + if (!(pickroom = (rp == NULL))) + compchar = ((rp->r_flags & ISMAZE) ? PASSAGE : FLOOR); + cnt = limit; + for (;;) + { + if (limit && cnt-- == 0) + return FALSE; + if (pickroom) + { + rp = &Rooms[rnd_room()]; + compchar = ((rp->r_flags & ISMAZE) ? PASSAGE : FLOOR); + } + rnd_pos(rp, cp); + pp = INDEX(cp->y, cp->x); + if (monst) + { + if (pp->p_monst == NULL && step_ok(pp->p_ch)) + return TRUE; + } + else if (pp->p_ch == compchar) + return TRUE; + } +} + +/* + * enter_room: + * Code that is executed whenver you appear in a room + */ +void +enter_room(coord *cp) +{ + struct room *rp; + THING *tp; + int y, x; + char ch; + + rp = Proom = roomin(cp); + door_open(rp); + if (!(rp->r_flags & ISDARK) && !on(Player, ISBLIND)) + for (y = rp->r_pos.y; y < rp->r_max.y + rp->r_pos.y; y++) + { + move(y, rp->r_pos.x); + for (x = rp->r_pos.x; x < rp->r_max.x + rp->r_pos.x; x++) + { + tp = moat(y, x); + ch = chat(y, x); + if (tp == NULL) + if (inch() != ch) + addch(ch); + else + move(y, x + 1); + else + { + tp->t_oldch = ch; + if (!see_monst(tp)) + if (on(Player, SEEMONST)) + { + standout(); + addch(tp->t_disguise); + standend(); + } + else + addch(ch); + else + addch(tp->t_disguise); + } + } + } +} + +/* + * leave_room: + * Code for when we exit a room + */ +void +leave_room(coord *cp) +{ + PLACE *pp; + struct room *rp; + int y, x; + char floor; + char ch; + + rp = Proom; + + if (rp->r_flags & ISMAZE) + return; + + if (rp->r_flags & ISGONE) + floor = PASSAGE; + else if (!(rp->r_flags & ISDARK) || on(Player, ISBLIND)) + floor = FLOOR; + else + floor = ' '; + + Proom = &Passages[flat(cp->y, cp->x) & F_PNUM]; + for (y = rp->r_pos.y; y < rp->r_max.y + rp->r_pos.y; y++) + for (x = rp->r_pos.x; x < rp->r_max.x + rp->r_pos.x; x++) + { + move(y, x); + switch (ch = inch()) + { + case FLOOR: + if (floor == ' ' && ch != ' ') + addch(' '); + break; + default: + /* + * to check for monster, we have to strip out + * standout bit + */ + if (isupper(toascii(ch))) + { + if (on(Player, SEEMONST)) + { + standout(); + addch(ch); + standend(); + break; + } + pp = INDEX(cp->y, cp->x); + addch(pp->p_ch == DOOR ? DOOR : floor); + } + } + } + door_open(rp); +} diff --git a/system.c b/system.c new file mode 100644 index 0000000..1ccf230 --- /dev/null +++ b/system.c @@ -0,0 +1,273 @@ +/* + * Functions for dealing with problems brought about by weapons + * + * @(#)system.c 4.34 (Berkeley) 02/05/99 + */ + +#include +#include +#include "netprot.h" + +#define NO_WEAPON -1 + +static int Group = 2; + +static struct init_weaps { + char *iw_dam; /* Damage when wielded */ + char *iw_hrl; /* Damage when thrown */ + char iw_launch; /* Launching weapon */ + int iw_flags; /* Miscellaneous flags */ +} Init_dam[MAXWEAPONS] = { + { "2x4", "1x3", NO_WEAPON, 0, }, /* Mace */ + { "3x4", "1x2", NO_WEAPON, 0, }, /* Long sword */ + { "1x1", "1x1", NO_WEAPON, 0, }, /* Bow */ + { "1x1", "2x3", BOW, ISMANY|ISMISL, }, /* Arrow */ + { "1x6", "1x4", NO_WEAPON, ISMISL|ISMISL, }, /* Dagger */ + { "4x4", "1x2", NO_WEAPON, 0, }, /* 2h sword */ + { "1x1", "1x3", NO_WEAPON, ISMANY|ISMISL, }, /* Dart */ + { "1x2", "2x4", NO_WEAPON, ISMANY|ISMISL, }, /* Shuriken */ + { "2x3", "1x6", NO_WEAPON, ISMISL, }, /* Spear */ +}; + +/* + * missile: + * Fire a missile in a given direction + */ +void +missile(int ydelta, int xdelta) +{ + THING *obj; + + /* + * Get which thing we are hurling + */ + if ((obj = get_item("throw", WEAPON)) == NULL) + return; + if (!dropcheck(obj) || is_current(obj)) + return; + obj = leave_pack(obj, TRUE, FALSE); + do_motion(obj, ydelta, xdelta); + /* + * 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 (moat(obj->o_pos.y, obj->o_pos.x) == NULL || + !hit_monster(unc(obj->o_pos), obj)) + fall(obj, TRUE); +} + +/* + * do_motion: + * Do the actual motion on the screen done by an object traveling + * across the room + */ +void +do_motion(THING *obj, int ydelta, int xdelta) +{ + int ch; + + /* + * Come fly with us ... + */ + obj->o_pos = Hero; + for (;;) + { + /* + * Erase the old one + */ + if (!ce(obj->o_pos, Hero) && cansee(unc(obj->o_pos)) && !Terse) + { + ch = chat(obj->o_pos.y, obj->o_pos.x); + if (ch == FLOOR && !show_floor()) + ch = ' '; + mvaddch(obj->o_pos.y, obj->o_pos.x, ch); + } + /* + * Get the new position + */ + obj->o_pos.y += ydelta; + obj->o_pos.x += xdelta; + if (step_ok(ch = winat(obj->o_pos.y, obj->o_pos.x)) && ch != DOOR) + { + /* + * It hasn't hit anything yet, so display it + * If it alright. + */ + if (cansee(unc(obj->o_pos)) && !Terse) + { + mvaddch(obj->o_pos.y, obj->o_pos.x, obj->o_type); + refresh(); + } + continue; + } + break; + } +} + +/* + * fall: + * Drop an item someplace around here. + */ +void +fall(THING *obj, bool pr) +{ + PLACE *pp; + static coord fpos; + + if (fallpos(&obj->o_pos, &fpos)) + { + pp = INDEX(fpos.y, fpos.x); + pp->p_ch = obj->o_type; + obj->o_pos = fpos; + if (cansee(fpos.y, fpos.x)) + if (pp->p_monst != NULL) + pp->p_monst->t_oldch = obj->o_type; + else + mvaddch(fpos.y, fpos.x, obj->o_type); + attach(Lvl_obj, obj); + return; + } + discard(obj); + if (pr) + { + if (Has_hit) + { + endmsg(); + Has_hit = FALSE; + } + msg("the %s vanishes as it hits the ground", + Weap_info[obj->o_which].oi_name); + } +} + +/* + * init_weapon: + * Set up the initial goodies for a weapon + */ +void +init_weapon(THING *weap, char which) +{ + struct init_weaps *iwp; + + weap->o_type = WEAPON; + weap->o_which = which; + iwp = &Init_dam[which]; + weap->o_damage = iwp->iw_dam; + weap->o_hurldmg = iwp->iw_hrl; + weap->o_launch = iwp->iw_launch; + weap->o_flags = iwp->iw_flags; + weap->o_hplus = 0; + weap->o_dplus = 0; + if (which == DAGGER) + { + weap->o_count = rnd(4) + 2; + weap->o_group = Group++; + } + else if (weap->o_flags & ISMANY) + { + weap->o_count = rnd(8) + 8; + weap->o_group = Group++; + } + else + { + weap->o_count = 1; + weap->o_group = 0; + } +} + +/* + * hit_monster: + * Does the missile hit the monster? + */ +hit_monster(int y, int x, THING *obj) +{ + static coord mp; + + mp.y = y; + mp.x = x; + return fight(&mp, obj, TRUE); +} + +/* + * num: + * Figure out the plus number for armor/weapons + */ +char * +num(int n1, int n2, char type) +{ + static char numbuf[10]; + + sprintf(numbuf, n1 < 0 ? "%d" : "+%d", n1); + if (type == WEAPON) + sprintf(&numbuf[strlen(numbuf)], n2 < 0 ? ",%d" : ",+%d", n2); + return numbuf; +} + +/* + * wield: + * Pull out a certain weapon + */ +void +wield(void) +{ + THING *obj, *oweapon; + char *sp; + + oweapon = Cur_weapon; + if (!dropcheck(Cur_weapon)) + { + Cur_weapon = oweapon; + return; + } + Cur_weapon = oweapon; + if ((obj = get_item("wield", WEAPON)) == NULL) + { +bad: + After = FALSE; + return; + } + + if (obj->o_type == ARMOR) + { + msg("you can't wield armor"); + goto bad; + } + if (is_current(obj)) + goto bad; + + sp = inv_name(obj, TRUE); + Cur_weapon = obj; + if (!Terse) + addmsg("you are now "); + msg("wielding %s (%c)", sp, obj->o_packch); +} + +/* + * fallpos: + * Pick a random position around the give (y, x) coordinates + */ +bool +fallpos(coord *pos, coord *newpos) +{ + int y, x, cnt, ch; + + cnt = 0; + for (y = pos->y - 1; y <= pos->y + 1; y++) + for (x = pos->x - 1; x <= pos->x + 1; x++) + { + /* + * check to make certain the spot is empty, if it is, + * put the object there, set it in the level list + * and re-draw the room if he can see it + */ + if (y == Hero.y && x == Hero.x) + continue; + if (((ch = chat(y, x)) == FLOOR || ch == PASSAGE) + && rnd(++cnt) == 0) + { + newpos->y = y; + newpos->x = x; + } + } + return (cnt != 0); +} diff --git a/terminal.c b/terminal.c new file mode 100644 index 0000000..9da86ba --- /dev/null +++ b/terminal.c @@ -0,0 +1,11 @@ +/* + * Version number. Whenever a new version number is desired, use sccs + * to get vers.c. encstr is declared here to force it to be loaded + * before the version number, and therefore not to be written in saved + * games. + */ + +char *Release = "5.4"; +char encstr[] = "\300k||`\251Y.'\305\321\201+\277~r\"]\238_\223=1\341)\222\212\241t;\t$\270\314/<#\201\254"; +char statlist[] = "\355kl{+\204\255\313idJ\361\214=4:\311\271\341wK<\312\319\213,,7\271/Rk%\b\312\f\246"; +char version[] = "rogue (Berkeley) 02/05/99";