commit 11cf2fc4fa361a391d9b185e16344c0d1f55d168 Author: Neale Pickett Date: Thu Oct 13 10:59:16 2011 -0500 Import from SourceForge 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";