Rog-O-Matic XIV (part 04 of 10)
Michael Mauldin
mlm at cmu-cs-cad.ARPA
Sat Feb 2 02:28:35 AEST 1985
#!/bin/sh
#
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# @ Here is part of your new automatic Rogue player, Rog-O-Matic XIV! @
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#
# [Note: this is a Beta-Test release of version XIV, and almost
# certainly contains bugs. A new version will be made available
# soon. If you experience any problems with this version, please
# contact Michael Mauldin as soon as possible, so your input can be
# included in the new release]
#
# Rog-O-Matic XIV is shipped via mail in pieces, files rgm14.01, rgm14.02,
# ..., rgm14.nn. Each piece contains some number of smaller files. To
# retrieve them, run each file through the shell 'sh', as follows:
#
# sh <rgm14.01
# sh <rgm14.02
# ...
# sh <rgm14.nn
#
# or do it all at once:
#
# cat rgm14.* | sh
#
# The README file contains all necessary information to edit the "install.h"
# file, after which "make" will build the rogomatic and player binary files.
# Please note that file 'Bugreport' contains modifications you may wish to
# make to the code BEFORE you compile it. You can safely install ALL of
# them; depending on your version of Rogue, you may HAVE to install SOME of
# them.
#
# Rog-O-Matic is copyrighted, but permission is given to copy and modify the
# source provided that (1) it is not used for profit (2) all authorship and
# copyright notices remain intact and (3) any person or site with a copy has
# notified Michael Mauldin either by electronic mail or US Post that they
# have Rog-O-Matic XIV.
#
# We would appreciate hearing about any interesting additions or modifi-
# cations, and would especially like to know how well the program plays
# against your Rogue. And we really, really want to know if Rog-O-Matic
# becomes a "Total Winner" against Rogue 5.2 or Rogue 5.3 again.
#
# Michael Mauldin (Fuzzy)
# Department of Computer Science
# Carnegie-Mellon University
# Pittsburgh, PA 15213
# (412) 578-3065, mauldin at cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 04 of 10:'
echo 'x - io.c'
sed 's/^X//' > io.c << '/'
X/*
X * io.c: Rog-O-Matic XIV (CMU) Thu Jan 31 18:19:29 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains all of the functions which deal with the real world.
X */
X
X# include <curses.h>
X# include <ctype.h>
X
X# include "install.h"
X
X# ifdef BSD41
X# include <time.h>
X# else
X# include <sys/time.h>
X# endif
X
X# include "types.h"
X# include "globals.h"
X# include "termtokens.h"
X
X# define READ 0
X
X/*
X * Charonscreen returns the current character on the screen (using
X * curses(3)). This macro is based on the winch(win) macro.
X */
X# define charonscreen(X,Y) (stdscr->_y[X][Y])
X
Xchar *month[] =
X{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
X
Xstatic char screen00 = ' ';
X
X/* Constants */
X
X# define SENDQ 256
X
X/* The command queue */
X
Xchar queue[SENDQ]; /* To Rogue */
Xint head = 0, tail = 0;
X
X/*
X * Getrogue: Sensory interface.
X *
X * Handle grungy low level terminal I/O. Getrogue reads tokens from the
X * Rogue process and interprets them, making the screen array an image of
X * the rogue level. Getrogue returns when the string waitstr has been read
X * and either the cursor is on the Rogue '@' or some other condition
X * implies that we have synchronized with Rogue.
X */
X
Xgetrogue (waitstr, onat)
Xchar *waitstr; /* String to synchronize with */
Xint onat; /* 0 ==> Wait for waitstr
X 1 ==> Cursor on @ sufficient
X 2 ==> [1] + send ';' when ever
X we eat a --More-- message */
X{ int botprinted = 0, wasmapped = didreadmap, r, c, pending ();
X register int i, j;
X char ch, *s, *m, *q, *d, *call, getroguetoken();
X int *doors;
X static moved = 0;
X
X domonster(); /* LGCH */
X
X newdoors = doorlist; /* no new doors found yet */
X atrow0 = atrow; atcol0 = atcol; /* Save our current posistion */
X s = waitstr; /* FSM to check for the wait msg */
X m = "More--"; /* FSM to check for '--More--' */
X call = "Call it:"; /* FSM to check for 'Call it:' */
X q = "(* for list): "; /* FSM to check for prompt */
X d = ")______"; /* FSM to check for tombstone grass */
X
X if (moved) /* If we moved last time, put any */
X { sleepmonster (); moved = 0; } /* Old monsters to sleep */
X
X /* While we have not reached the end of the Rogue input, read */
X /* characters from Rogue and figure out what they mean. */
X while ((*s) ||
X ((!hasted || version != RV36A) && onat && screen[row][col] != '@'))
X { ch = getroguetoken ();
X
X /* If message ends in "(* for list): ", call terpmes */
X if (ch == *q) { if (*++q == 0) terpmes (); }
X else q = "(* for list): ";
X
X /* Rogomatic now keys off of the grass under the Tombstone to */
X /* detect that it has been killed. This was done because the */
X /* "Press return" prompt only happens if there is a score file */
X /* Available on that system. Hopefully the grass is the same */
X /* in all versions of Rogue! */
X if (ch == *d) { if (0 == *++d) { addch (ch); deadrogue (); return;} }
X else d = ")_______";
X
X /* If the message has a more, strip it off and call terpmes */
X if (ch == *m)
X { if (*++m == 0)
X { /* More than 50 messages since last command ==> start logging */
X if (++morecount > 50 && !logging)
X { toggleecho (); dwait (D_WARNING, "Started logging --More-- loop."); }
X
X /* More than 100 messages since last command ==> infinite loop */
X if (++morecount > 100) dwait (D_FATAL, "Caught in --More-- loop.");
X
X /* Send a space (and possibly a semicolon) to clear the message */
X if (onat == 2) sendnow (" ;");
X else sendnow (" ");
X
X /* Clear the --More-- of the end of the message */
X for (i = col - 7; i < col; screen[0][i++] = ' ');
X
X terpmes (); /* Interpret the message */
X
X /* This code gets rid of the "Studded leather arm" bug */
X /* But it causes other problems. MLM */
X /* sprintf (&screen[0][col - 7], "--More--"); */
X }
X }
X else m = "More--";
X
X /* If the message is 'Call it:', cancel the request */
X if (ch == *call)
X { if (*++call == 0)
X { /* Send an escape (and possibly a semicolon) to clear the message */
X if (onat == 2) sendnow ("%c;", ESC);
X else sendnow ("%c", ESC);
X }
X }
X else call = "Call it:";
X
X /* Check to see whether we have read the synchronization string */
X if (*s) { if (ch == *s) s++; else s = waitstr; }
X
X /* Now figure out what the token means */
X switch (ch)
X { case BS_TOK:
X col--;
X break;
X
X case CE_TOK:
X if (row && row < 23)
X for (i = col; i < 80; i++)
X { updatepos (' ', row, i);
X screen[row][i] = ' ';
X }
X else
X for (i = col; i < 80; i++)
X screen[row][i] = ' ';
X
X if (row) { at (row, col); clrtoeol (); }
X else if (col == 0) screen00 = ' ';
X break;
X
X case CL_TOK:
X clearscreen ();
X break;
X
X case CM_TOK:
X screen00 = screen[0][0];
X break;
X
X case CR_TOK:
X /* Handle missing '--more--' between inventories MLM 24-Jun-83 */
X if (row==0 && screen[0][1]==')' && screen[0][col-1] != '-')
X terpmes ();
X col = 0;
X break;
X
X case DO_TOK:
X row++;
X break;
X
X case ER_TOK:
X break;
X
X case LF_TOK:
X row++;
X col = 0;
X break;
X
X case ND_TOK:
X col++;
X break;
X
X case SE_TOK:
X revvideo = 0;
X standend ();
X break;
X
X case SO_TOK:
X revvideo = 1;
X standout ();
X break;
X
X case TA_TOK:
X col = 8 * (1 + col / 8);
X break;
X
X case EOF:
X if (interrupted) return;
X if (!replaying || !logdigested) { playing = 0; return; }
X saynow ("End of game log, type 'Q' to exit.");
X return;
X break;
X
X case UP_TOK:
X row--;
X break;
X
X default:
X if (ch < ' ')
X { saynow ("Unknown character '\\%o'--more--", ch);
X waitforspace ();
X }
X else if (row)
X { at (row, col);
X if (!emacs && !terse) addch (ch);
X if (row == 23) botprinted = 1;
X else updatepos (ch, row, col);
X }
X else if (col == 0)
X { screen00 = screen[0][0]; }
X else if (col == 1 && ch == 'l' && screen[0][0] == 'I')
X { screen[0][0] = screen00;
X if (screen00 != ' ') terpmes ();
X screen[0][0] = 'I';
X }
X screen[row][col++] = ch;
X break;
X }
X }
X
X if (botprinted) terpbot ();
X
X if (atrow != atrow0 || atcol != atcol0)
X { updateat (); /* Changed position, record the move */
X moved = 1; /* Indicate that we moved */
X wakemonster (8); /* Wake up adjacent mean monsters */
X currentrectangle(); /* Keep current rectangle up to date. LGCH */
X }
X
X if (!usesynch && !pending ())
X { usesynch = 1;
X lastobj = NONE;
X resetinv();
X }
X
X if (version < RV53A && checkrange && !pending ())
X { command (T_OTHER, "Iz"); checkrange = 0; }
X
X donemonster (); /* LGCH */
X
X /* If mapping status has changed */
X if (wasmapped != didreadmap)
X { dwait (D_CONTROL | D_SEARCH, "wasmapped: %d didreadmap: %d",
X wasmapped, didreadmap);
X
X mapinfer ();
X }
X
X if (didreadmap != Level)
X { doors = doorlist;
X while (doors != newdoors)
X { r = *doors++; c = *doors++;
X dwait (D_INFORM, "new door at %d, %d", r, c);
X inferhall (r, c);
X }
X }
X
X if (!blinded)
X for (i = atrow-1; i <= atrow+1; i++) /* For blanks around the */
X for (j = atcol-1; j <= atcol+1; j++) /* rogue... */
X if (seerc(' ',i,j) && onrc(CANGO,i,j)) /* CANGO+BLANK impossible */
X { unsetrc (CANGO | SAFE, i, j); /* Infer cant go and... */
X setnewgoal (); /* invalidate the map. */
X }
X
X at (row, col);
X if (!emacs && !terse) refresh ();
X}
X
X/*
X * terpbot: Read the Rogue status line and set the various status
X * variables. This routine depends on the value of version to decide what
X * the status line looks like.
X */
X
Xterpbot ()
X{ char sstr[30], modeline[256];
X int oldlev = Level, oldgold = Gold, oldhp = Hp, Str18 = 0;
X extern int geneid;
X register int i, oldstr = Str, oldAc = Ac, oldExp = Explev;
X
X /* Since we use scanf to read this field, it must not be left blank */
X if (screen[23][78] == ' ') screen[23][78] = 'X';
X
X /* Read the bottom line, there are three versions of the status line */
X if (version < RV52A) /* Rogue 3.6, Rogue 4.7? */
X { sscanf (screen[23],
X " Level: %d Gold: %d Hp: %d(%d) Str: %s Ac: %d Exp: %d/%d %s",
X &Level, &Gold, &Hp, &Hpmax, sstr, &Ac, &Explev, &Exp, Ms);
X sscanf (sstr, "%d/%d", &Str, &Str18);
X Str = Str * 100 + Str18;
X if (Str > Strmax) Strmax = Str;
X }
X else if (version < RV53A) /* Rogue 5.2 (versions A and B) */
X { sscanf (screen[23],
X " Level: %d Gold: %d Hp: %d(%d) Str: %d(%d) Ac: %d Exp: %d/%d %s",
X &Level, &Gold, &Hp, &Hpmax, &Str, &Strmax, &Ac, &Explev, &Exp, Ms);
X
X Str = Str * 100; Strmax = Strmax * 100;
X }
X else /* Rogue 5.3 (and beyond???) */
X { sscanf (screen[23],
X " Level: %d Gold: %d Hp: %d(%d) Str: %d(%d) Arm: %d Exp: %d/%d %s",
X &Level, &Gold, &Hp, &Hpmax, &Str, &Strmax, &Ac, &Explev, &Exp, Ms);
X
X Str = Str * 100; Strmax = Strmax * 100; Ac = 10 - Ac;
X }
X
X /* Monitor changes in some variables */
X if (screen[23][78] == 'X') screen[23][78] = ' '; /* Restore blank */
X if (oldlev != Level) newlevel ();
X if (Level > MaxLevel) MaxLevel = Level;
X if (oldgold < Gold) deletestuff (atrow, atcol);
X if (oldhp < Hp) newring = 1;
X
X lastdamage = max (0, oldhp - Hp);
X
X /*
X * Insert code here to monitor changes in attributes due to special
X * attacks MLM October 26, 1983.
X */
X
X setbonuses ();
X
X /*
X * If in special output modes, generate output line
X */
X
X if ((oldlev != Level || oldgold != Gold || oldstr != Str ||
X oldAc != Ac || oldExp != Explev))
X {
X /* Stuff the new values into the argument space (for ps command) */
X sprintf (modeline, "Rgm %d: Id%d L%d %d %d(%d) s%d a%d e%d ",
X rogpid, geneid, Level, Gold, Hp, Hpmax, Str / 100, 10-Ac, Explev);
X modeline[arglen-1] = '\0';
X strcpy (parmstr, modeline);
X
X /* Handle Emacs and Terse mode */
X if (emacs || terse)
X { /* Skip backward over blanks and nulls */
X for (i = 79; screen[23][i] == ' ' || screen[23][i] == '\0'; i--);
X screen[23][++i] = '\0';
X
X if (emacs)
X { sprintf (modeline, " %s (%%b)", screen[23]);
X if (strlen (modeline) > 72) sprintf (modeline, " %s", screen[23]);
X fprintf (realstdout, "%s", modeline);
X fflush (realstdout);
X }
X else if (terse && oldlev != Level)
X { fprintf (realstdout, "%s\n", screen[23]);
X fflush (realstdout);
X }
X }
X }
X}
X
X/*
X * dumpwalls: Dump the current screen map
X */
X
Xdumpwalls ()
X{ register int r, c, S;
X char ch;
X
X printexplored ();
X
X for (r = 1; r < 23; r++)
X { for (c = 0; c < 80; c++)
X { S=scrmap[r][c];
X ch = (ARROW&S) ? 'a' :
X (TELTRAP&S) ? 't' :
X (TRAPDOR&S) ? 'v' :
X (GASTRAP&S) ? 'g' :
X (BEARTRP&S) ? 'b' :
X (DARTRAP&S) ? 's' :
X (WATERAP&S) ? 'w' :
X (TRAP&S) ? '^' :
X (STAIRS&S) ? '>' :
X (RUNOK&S) ? '%' :
X ((DOOR+BEEN&S)==DOOR+BEEN) ? 'D' :
X (DOOR&S) ? 'd' :
X ((BOUNDARY+BEEN&S)==BOUNDARY+BEEN) ? 'B' :
X ((ROOM+BEEN&S)==ROOM+BEEN) ? 'R' :
X (BEEN&S) ? ':' :
X (HALL&S) ? '#' :
X ((BOUNDARY+WALL&S)==BOUNDARY+WALL) ? 'W' :
X (BOUNDARY&S) ? 'b' :
X (ROOM&S) ? 'r' :
X (CANGO&S) ? '.' :
X (WALL&S) ? 'W' :
X (S) ? 'X' : '\0';
X if (ch) mvaddch (r, c, ch);
X }
X }
X
X at (row, col);
X}
X
X/*
X * sendnow: Send a string to the Rogue process.
X */
X
Xsendnow (f, a1, a2, a3, a4)
Xchar *f;
Xint a1, a2, a3, a4;
X{ char cmd[128];
X register char *s = cmd;
X
X sprintf (cmd, f, a1, a2, a3, a4);
X
X while (*s) sendcnow (*s++);
X}
X
X/*
X * sendcnow: send a character to the Rogue process. This routine also does
X * the logging of characters in echo mode.
X */
X
Xsendcnow (c)
Xchar c;
X{ if (replaying) return;
X if (logging)
X { if (cecho)
X { fprintf (fecho, "\nC: \"%c", c); cecho = !cecho; }
X else
X fprintf (fecho, "%c", c);
X }
X fprintf (trogue, "%c", c);
X}
X
X/*
X * send: add a string to the queue of commands to be sent to Rogue. The
X * commands are sent one at a time by the resend routine.
X */
X
X# define bump(p,sizeq) (p)=((p)+1)%sizeq
X
Xsend (f, a1, a2, a3, a4)
Xchar *f;
Xint a1, a2, a3, a4;
X{ char cmd[128];
X register char *s = cmd;
X
X sprintf (s, f, a1, a2, a3, a4);
X
X for (; *s; bump (tail, SENDQ))
X queue[tail] = *(s++);
X
X /* Appends null, so resend will treat as a unit */
X queue[tail] = '\0';
X bump (tail, SENDQ);
X}
X
X/*
X * resend: Send next block of characters from the queue
X */
X
Xresend ()
X{ register char *l=lastcmd; /* Ptr into last command */
X
X morecount = 0; /* Clear message count */
X if (head == tail) return (0); /* Fail if no commands */
X
X /* Send all queued characters until the next queued NULL */
X while (queue[head])
X { sendcnow (*l++ = queue[head]); bump (head, SENDQ); }
X bump (head, SENDQ);
X *l = '\0';
X
X return (1); /* Return success */
X}
X
X/*
X * pending: Return true if there is a command in the queue to be sent to
X * Rogue.
X */
X
Xpending ()
X{ return (head != tail);
X}
X
X/*
X * getroguetoken: get a command from Rogue (either a character or a
X * cursor motion sequence).
X */
X
Xchar getroguetoken ()
X{ char ch;
X char getlogtoken();
X
X if (replaying)
X return (getlogtoken());
X
X ch = GETROGUECHAR;
X
X /* Convert escape sequences into tokens (negative numbers) */
X if (ch == ESC)
X { switch (ch = GETROGUECHAR)
X
X { case CE_CHR: ch = CE_TOK; break;
X case CL_CHR: ch = CL_TOK; break;
X case CM_CHR: ch = CM_TOK; break;
X case DO_CHR: ch = DO_TOK; break;
X case ND_CHR: ch = ND_TOK; break;
X case SE_CHR: ch = SE_TOK; break;
X case SO_CHR: ch = SO_TOK; break;
X case UP_CHR: ch = UP_TOK; break;
X default: saynow ("Unknown sequence ESC-%s --More--", unctrl(ch));
X waitforspace ();
X ch = ER_TOK;
X }
X }
X
X /* Get arguments for cursor addressing */
X if ((int) ch == CM_TOK)
X { row = (int) GETROGUECHAR - 32; col = (int) GETROGUECHAR - 32; }
X
X /* Log the tokens */
X if (logging)
X { if (!cecho) { fprintf (fecho, "\"\nR: "); cecho = !cecho; }
X if (ISPRT (ch)) fprintf (fecho, "%c", ch);
X else switch (ch)
X { case BS_TOK: fprintf (fecho, "{bs}"); break;
X case CE_TOK: fprintf (fecho, "{ce}"); break;
X case CL_TOK: fprintf (fecho, "{ff}"); break;
X case CM_TOK: fprintf (fecho, "{cm(%d,%d)}", row, col); break;
X case CR_TOK: fprintf (fecho, "{cr}"); break;
X case DO_TOK: fprintf (fecho, "{do}"); break;
X case LF_TOK: fprintf (fecho, "{nl}"); break;
X case ND_TOK: fprintf (fecho, "{nd}"); break;
X case SE_TOK: fprintf (fecho, "{se}"); break;
X case SO_TOK: fprintf (fecho, "{so}"); break;
X case TA_TOK: fprintf (fecho, "{ta}"); break;
X case UP_TOK: fprintf (fecho, "{up}"); break;
X case ER_TOK: fprintf (fecho, "{ERRESC}", ch); break;
X default: fprintf (fecho, "{ERR%o}", ch);
X ch = ER_TOK;
X }
X fflush (fecho);
X }
X
X return (ch);
X}
X
X/*
X * at: move the cursor. Now just a call to move();
X */
X
Xat (r, c)
Xint r, c;
X{ move (r, c);
X}
X
X/*
X * deadrogue: Called when we have been killed, it reads the tombstone
X * to see how much we had when we died and who killed us. It then
X * calls quitrogue to handle the termination handshaking and log the
X * game.
X */
X
X# define GOLDROW 15
X# define KILLROW 17
X# define TOMBCOL 19
X
Xdeadrogue ()
X{ int mh;
X char *killer, *killend;
X
X printw ("\n\nOops...");
X refresh ();
X
X sscanf (&screen[GOLDROW][TOMBCOL], "%18d", &Gold);
X
X killer = &screen[KILLROW][TOMBCOL];
X killend = killer+17;
X while (*killer==' ') ++killer;
X while (*killend==' ') *(killend--) = '\0';
X
X /* Record the death blow if killed by a monster */
X if ((mh = findmonster (killer)) != NONE)
X { addprob (&monhist[mh].theyhit, SUCCESS);
X addstat (&monhist[mh].damage, Hp);
X }
X
X quitrogue (killer, Gold, DIED);
X}
X
X/*
X * quitrogue: we are going to quit. Log the game and send a \n to
X * the Rogue process, then wait for it to die before returning.
X */
X
Xquitrogue (reason, gold, terminationtype)
Xchar *reason; /* A reason string for the summary line */
Xint gold; /* What is the final score */
Xint terminationtype; /* SAVED, FINSISHED, or DIED */
X{ struct tm *localtime(), *ts;
X long clock;
X char *k, *r;
X
X /* Save the killer and score */
X for (k=ourkiller, r=reason; *r && *r != ' '; ++k, ++r) *k = *r;
X *k = '\0';
X ourscore = gold;
X
X /* Dont need to make up any more commands */
X if (!replaying || !logdigested)
X playing = 0;
X
X /* Now get the current time, so we can date the score */
X clock = time(&clock);
X ts = localtime(&clock);
X
X /* Build a summary line */
X sprintf (sumline, "%3s %2d, %4d %-8.8s %7d%s%-17.17s %3d %3d ",
X month[ts -> tm_mon], ts -> tm_mday, 1900 + ts -> tm_year,
X getname (), gold, cheat ? "*" : " ", reason, MaxLevel, Hpmax);
X
X if (Str % 100)
X sprintf (sumline, "%s%2d.%2d", sumline, Str/100, Str%100);
X else
X sprintf (sumline, "%s %2d ", sumline, Str/100);
X
X sprintf (sumline, "%s %2d %2d/%-6d %d",
X sumline, Ac, Explev, Exp, ltm.gamecnt);
X
X /* Now write the summary line to the log file */
X at (23, 0); clrtoeol (); refresh ();
X
X /* 22 is index of score in sumline */
X if (!replaying)
X add_score (sumline, versionstr, (terse || emacs || noterm));
X
X /* Restore interrupt status */
X reset_int ();
X
X /* Set the termination message based on the termination method */
X if (stlmatch (reason, "total winner"))
X termination = "victorius";
X else if (stlmatch (reason, "user typing quit"))
X termination = "abortivus";
X else if (stlmatch (reason, "gave up"))
X termination = "inops consilii";
X else if (stlmatch (reason, "quit (scoreboard)"))
X termination = "callidus";
X else if (stlmatch (reason, "saved"))
X termination = "suspendus";
X
X /* Send the requisite handshaking to Rogue */
X if (terminationtype == DIED)
X sendnow ("\n");
X else if (terminationtype == FINISHED)
X sendnow ("Qy\n");
X else
X sendnow ("Syy"); /* Must send two yesses, R5.2 MLM */
X
X /* Wait for Rogue to die */
X wait (0);
X}
X
X/*
X * waitfor: snarf characters from Rogue until a string is found.
X * The characters are echoed to the users screen.
X *
X * The string must not contain a valid prefix of itself
X * internally.
X *
X * MLM 8/27/82
X */
X
Xwaitfor (mess)
Xchar *mess;
X{ register char *m = mess;
X
X while (*m)
X { if (getroguetoken () == *m) m++;
X else m = mess;
X }
X}
X
X/*
X * say: Display a messsage on the top line. Restore cursor to Rogue.
X */
X
Xsay (s, a1, a2, a3, a4, a5, a6, a7, a8)
Xchar *s;
Xint a1, a2, a3, a4, a5, a6, a7, a8;
X{ char buf[BUFSIZ], *b;
X
X if (!emacs && !terse)
X { sprintf (buf, s, a1, a2, a3, a4, a5, a6, a7, a8);
X at (0,0);
X for (b=buf; *b; b++) printw ("%s", unctrl (*b));
X clrtoeol ();
X at (row, col);
X }
X}
X
X/*
X * saynow: Display a messsage on the top line. Restore cursor to Rogue,
X * and refresh the screen.
X */
X
Xsaynow (s, a1, a2, a3, a4, a5, a6, a7, a8)
Xchar *s;
Xint a1, a2, a3, a4, a5, a6, a7, a8;
X{ if (!emacs && !terse)
X { say (s, a1, a2, a3, a4, a5, a6, a7, a8);
X refresh ();
X }
X}
X
X/*
X * waitforspace: Wait for the user to type a space.
X * Be sure to interpret a snapshot command, if given.
X */
X
Xwaitforspace ()
X{ char ch;
X
X refresh ();
X
X if (!noterm)
X while ((ch = fgetc (stdin)) != ' ')
X if (ch == '/') dosnapshot ();
X
X at (row, col);
X}
X
X/*
X * givehelp: Each time a ? is pressed, this routine prints the next
X * help message in a sequence of help messages. Nexthelp is an
X */
X
Xchar *nexthelp[] =
X{ "Rgm commands: t=toggle run mode, e=logging, i=inventory, -=status [?]",
X "Rgm commands: <ret>=singlestep, `=summary, /=snapshot, R=replay [?]",
X "Rogue cmds: S=Save, Q=Quit, h j k l H J K L b n u y N B U Y f s < > [?]",
X "Wizard: d=debug, !=show items, @=show monsters, #=show level flags [?]",
X "Wizard: ~=version, ^=bowrank, %%=armorrank, $=weaponrank, ==ringrank [?]",
X "Wizard: (=database, )=cycles, +=possible secret doors, :=chicken [?]",
X "Wizard: [=weapstat, r=resetinv, &=object count, *=toggle blind [?]",
X "Wizard: C=toggle cosmic, M=mazedoor, m=monster, A=attempt, {=flags",
X NULL
X};
X
Xchar **helpline = nexthelp;
X
Xgivehelp ()
X{
X if (*helpline == NULL) helpline = nexthelp;
X saynow (*helpline++);
X}
X
X/*
X * pauserogue: Wait for the user to type a space and then redraw the
X * screen. Now uses the stored image and passes it to
X * curses rather than sending a form feed to Rogue. MLM
X */
X
Xpauserogue ()
X{
X at (23, 0);
X addstr ("--press space to continue--");
X clrtoeol ();
X refresh ();
X
X waitforspace ();
X
X redrawscreen ();
X}
X
X/*
X * getrogver: Read the output of the Rogue version command
X * and set version. RV36B = 362 (3.6 with wands)
X * and RV52A = 521 (5.2). Note that RV36A is
X * infered when we send a "//" command to identify
X * wands.
X */
X
Xgetrogver ()
X{ char *vstr = versionstr, ch;
X
X if (replaying) /* Use default version */
X { sprintf (versionstr, DEFVER); }
X
X else /* Execute the version command */
X { sendnow ("v");
X waitfor ("ersion ");
X
X while ((ch = getroguetoken ()) != ' ') *(vstr++) = ch;
X *--vstr = '\0';
X }
X
X if (stlmatch (versionstr, "3.6")) version = RV36B;
X else if (stlmatch (versionstr, "5.2")) version = RV52A;
X else if (stlmatch (versionstr, "5.3")) version = RV53A;
X else saynow ("What a strange version of Rogue! ");
X}
X
X/*
X * charsavail: How many characters are there at the terminal? If any
X * characters are found, 'noterm' is reset, since there is obviously
X * a terminal around if the user is typing at us.
X */
X
Xcharsavail ()
X{ long n;
X int retc;
X
X if (retc = ioctl (READ, FIONREAD, &n))
X { saynow ("Ioctl returns %d, n=%ld.\n", retc, n);
X n=0;
X }
X
X if (n > 0) noterm = 0;
X return ((int) n);
X}
X
X/*
X * redrawscreen: Make the users screen look like the Rogue screen (screen).
X */
X
Xredrawscreen ()
X{ register int i, j;
X char ch;
X
X clear ();
X
X for (i = 1; i < 24; i++) for (j = 0; j < 80; j++)
X if ((ch = screen[i][j]) > ' ') mvaddch(i, j, ch);
X
X at (row, col);
X
X refresh ();
X}
X
X/*
X * toggleecho: toggle the I/O echo feature. If first time, open the
X * roguelog file.
X */
X
Xtoggleecho ()
X{ if (replaying) return;
X logging = !logging;
X if (logging)
X { if ((fecho = wopen (ROGUELOG, "w")) == NULL)
X { logging = !logging;
X saynow ("can't open %s", ROGUELOG);
X }
X else
X { fprintf (fecho, "Rogomatic Game Log\n\n");
X saynow ("Logging to file %s", ROGUELOG);
X cecho = 1;
X }
X }
X else
X { if (cecho)
X fprintf (fecho, "\n");
X else
X fprintf (fecho, "\"\n");
X fclose (fecho);
X
X if (playing) saynow ("File %s closed", ROGUELOG);
X }
X if (playing)
X { at (row, col); refresh (); }
X}
X
X/*
X * clearsendqueue: Throw away queued Rogue commands.
X */
X
Xclearsendqueue ()
X{ head = tail;
X}
X
X/*
X * startreplay: Open the log file to replay.
X */
X
Xstartreplay (logfile, logfilename)
XFILE **logfile;
Xchar *logfilename;
X{ if ((*logfile = fopen (logfilename, "r")) == NULL)
X { fprintf (stderr, "Can't open '%s'.\n", logfilename);
X exit(1);
X }
X}
X
X/*
X * putn: Put 'n' copies of character 'c' on file 'f'.
X */
X
Xputn (c, f, n)
Xregister char c;
Xregister FILE *f;
Xregister int n;
X{
X while (n--)
X putc (c, f);
X}
X
X/*
X * printsnap: print a snapshot to file f.
X */
X
Xprintsnap (f)
XFILE *f;
X{ register int i, j, length;
X struct tm *localtime(), *ts;
X char *statusline();
X long clock;
X
X /* Now get the current time, so we can date the snapshot */
X clock = time(&clock);
X ts = localtime(&clock);
X
X /* Print snapshot timestamp */
X fprintf (f, "\nSnapshot taken on %s %d, %d at %02d:%02d:%02d:\n\n",
X month[ts -> tm_mon], ts -> tm_mday, 1900 + ts -> tm_year,
X ts -> tm_hour, ts -> tm_min, ts -> tm_sec);
X
X /* Print the current map */
X putn ('-', f, 79);
X fprintf (f, "\n");
X for (i = 0; i < 24; i++)
X { for (length = 79; length >= 0 && charonscreen(i,length) == ' '; length--);
X for (j=0; j <= length; j++) fprintf (f, "%c", charonscreen(i,j));
X fprintf (f, "\n");
X }
X putn ('-', f, 79);
X
X /* Print status variables */
X fprintf (f, "\n\n%s\n\n", statusline ());
X
X /* Print the inventory */
X
X dumpinv (f);
X fprintf (f, "\n");
X putn ('-', f, 79);
X fprintf (f, "\n");
X}
X
X/*
X * getlogtoken: routine to retrieve a rogue token from the log file.
X * This allows us to replay a game with all the diagnostic commands of
X * Rog-O-Matic at our disposal. LGCH.
X */
X
Xchar getlogtoken()
X{ int acceptline;
X char ch = GETLOGCHAR;
X char ch1, ch2, dig;
X
X while (ch == NEWLINE)
X { acceptline = 0;
X if ((ch = GETLOGCHAR) == 'R')
X if ((ch = GETLOGCHAR) == ':')
X if ((ch = GETLOGCHAR) == ' ')
X { ch = GETLOGCHAR;
X acceptline = 1;
X }
X if (!acceptline)
X while ((int) ch != NEWLINE && (int) ch != EOF)
X ch = GETLOGCHAR;
X }
X
X if (ch == '{')
X { ch1 = GETLOGCHAR;
X ch2 = GETLOGCHAR;
X ch = GETLOGCHAR; /* Ignore the closing '}' */
X switch (ch1)
X { case 'b': ch = BS_TOK; break;
X case 'c':
X switch (ch2)
X { case 'e': ch = CE_TOK; break;
X case 'm':
X ch = CM_TOK;
X row = 0;
X while ((dig = GETLOGCHAR) != ',')
X { row = row * 10 + dig - '0';
X }
X col = 0;
X while ((dig = GETLOGCHAR) != ')')
X { col = col * 10 + dig - '0'; }
X GETLOGCHAR; /* Ignore '}' */
X break;
X case 'r': ch = CR_TOK;
X }
X break;
X case 'd': ch = DO_TOK; break;
X case 'f': ch = CL_TOK; break;
X
X case 'n':
X if (ch2 == 'l')
X ch = LF_TOK;
X else
X ch = ND_TOK;
X break;
X case 's':
X if (ch2 == 'e')
X ch = SE_TOK;
X else
X ch = SO_TOK;
X break;
X case 't': ch = TA_TOK; break;
X case 'u': ch = UP_TOK; break;
X case 'E':
X while (GETLOGCHAR != '}')
X ;
X ch = ER_TOK;
X break;
X }
X }
X return (ch);
X}
X
X/*
X * getoldcommand: retrieve the old command from a logfile we are replaying.
X */
X
Xgetoldcommand (s)
Xregister char *s;
X{ register int charcount = 0;
X char ch = ' ', term = '"', *startpat = "\nC: ";
X
X while (*startpat && (int) ch != EOF)
X { if ((ch = GETLOGCHAR) != *(startpat++)) startpat = "\nC: "; }
X
X if ((int) ch != EOF)
X { term = ch = GETLOGCHAR;
X while ((ch = GETLOGCHAR) != term && (int) ch != EOF && charcount++ < 128)
X { *(s++) = ch;
X }
X }
X
X *s = '\0';
X}
X
X/*
X * dosnapshot: add a snapshot to the SHAPSHOT file.
X */
X
Xdosnapshot ()
X{
X if ((snapshot = wopen (SNAPSHOT, "a")) == NULL)
X saynow ("Cannot write file %s.", SNAPSHOT);
X else
X { printsnap (snapshot);
X fclose (snapshot);
X saynow ("Snapshot added to %s.", SNAPSHOT);
X }
X}
X
X/*
X * clearscreen: Done whenever a {ff} is sent by Rogue. This code is
X * separate so it can be called from replay(), since there is an implicit
X * formfeed not recorded in the log file. MLM
X */
X
Xclearscreen ()
X{ register int i, j;
X
X row = col = 0;
X clear ();
X screen00 = ' ';
X for (i = 0; i < 24; i++)
X for (j = 0; j < 80; j++)
X { screen[i][j] = ' ';
X unsetrc (STUFF, i, j);
X }
X initstufflist ();
X mlistlen = 0; /* initmonsterlist (); temp hack MLM */
X}
X
X/*
X * statusline: Write all about our current status into a string.
X * Returns a pointer to a static area. MLM
X */
X
Xchar *
Xstatusline ()
X{ static char staticarea[256];
X register char *s=staticarea;
X
X sprintf (s, "Status: ");
X
X if (aggravated) strcat (s, "aggravated, ");
X if (beingheld) strcat (s, "being held, ");
X if (blinded) strcat (s, "blind, ");
X if (confused) strcat (s, "confused, ");
X if (cosmic) strcat (s, "cosmic, ");
X if (cursedarmor) strcat (s, "cursed armor, ");
X if (cursedweapon) strcat (s, "cursed weapon, ");
X if (doublehasted) strcat (s, "perm hasted, ");
X if (droppedscare) strcat (s, "dropped scare, ");
X if (floating) strcat (s, "floating, ");
X if (hasted) strcat (s, "hasted, ");
X if (protected) strcat (s, "protected, ");
X if (redhands) strcat (s, "red hands, ");
X if (Level == didreadmap) strcat (s, "mapped, ");
X
X if (*genocided) sprintf (s, "genocided '%s', ", s, genocided);
X
X sprintf (s, "%s%d food%s, %d missile%s, %d turn%s, (%d,%d %d,%d) bonus",
X s, larder, plural(larder), ammo, plural(ammo), turns,
X plural(turns), gplushit, gplusdam, wplushit, wplusdam);
X
X return (s);
X}
/
echo 'x - pack.c'
sed 's/^X//' > pack.c << '/'
X/*
X * pack.c: Rog-O-Matic XIV (CMU) Thu Jan 31 15:04:23 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains functions which mess with Rog-O-Matics pack
X */
X
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
Xstatic char *stuffmess [] = {
X "strange object", "food", "potion", "scroll",
X "wand", "ring", "hitter", "thrower",
X "missile", "armor", "amulet", "gold",
X "none" };
X
X/*
X * itemstr: print the inventory message for a single item.
X */
X
Xchar *itemstr (i)
Xregister int i;
X{ static char ispace[128];
X register char *item = ispace;
X
X if (i < 0 || i >= MAXINV)
X { sprintf (item, "%d out of bounds", i); }
X else if (inven[i].count < 1)
X { sprintf (item, "%c) nothing", LETTER(i)); }
X else
X { sprintf (item, "%c) %4d %d*%s:", LETTER(i), worth(i),
X inven[i].count, stuffmess[(int)inven[i].type]);
X
X if (inven[i].phit != UNKNOWN && inven[i].pdam == UNKNOWN)
X sprintf (item, "%s (%d)", item, inven[i].phit);
X else if (inven[i].phit != UNKNOWN)
X sprintf (item, "%s (%d,%d)", item, inven[i].phit, inven[i].pdam);
X
X if (inven[i].charges != UNKNOWN)
X sprintf (item, "%s [%d]", item, inven[i].charges);
X
X sprintf (item, "%s %s%s%s%s%s%s%s%s%s.", /* DR UTexas */
X item, inven[i].str,
X (itemis (i, KNOWN) ? "" : ", unknown"),
X (used (inven[i].str) ? ", tried" : ""),
X (itemis (i, CURSED) ? ", cursed" : ""),
X (itemis (i, UNCURSED) ? ", uncursed" : ""),
X (itemis (i, ENCHANTED) ? ", enchanted" : ""),
X (itemis (i, PROTECTED) ? ", protected" : ""),
X (itemis (i, WORTHLESS) ? ", useless" : ""),
X (!itemis (i, INUSE) ? "" :
X (inven[i].type == armor || inven[i].type == ring) ?
X ", being worn" : ", in hand"));
X }
X
X return (item);
X}
X
X/*
X * dumpinv: print the inventory. calls itemstr.
X */
X
Xdumpinv (f)
Xregister FILE *f;
X{ register int i;
X
X if (f == NULL)
X at (1,0);
X
X for (i=0; i<MAXINV; i++)
X { if (inven[i].count == 0) /* No item here */
X ;
X else if (f != NULL) /* Write to a file */
X { fprintf (f, "%s\n", itemstr (i)); }
X else /* Dump on the screen */
X { printw ("%s\n", itemstr (i)); }
X }
X}
X
X/*
X * removeinv: remove an item from the inventory.
X */
X
Xremoveinv (pos)
Xint pos;
X{
X if (--(inven[pos].count) == 0)
X { clearpack (pos); /* Assure nothing at that spot DR UT */
X rollpackup (pos); /* Close up the hole */
X }
X
X countpack ();
X checkrange = 1;
X}
X
X/*
X * deleteinv: delete an item from the inventory. Note: this function
X * is used when we drop rather than throw or use, since bunches of
X * things can be dropped all at once.
X */
X
Xdeleteinv (pos)
Xint pos;
X{
X if (--(inven[pos].count) == 0 || inven[pos].type == missile)
X { clearpack (pos); /* Assure nothing at that spot DR UT */
X rollpackup (pos); /* Close up the hole */
X }
X
X countpack ();
X checkrange = 1;
X}
X
X/*
X * clearpack: zero out slot in pack. DR UTexas 01/05/84
X */
X
Xclearpack (pos)
Xint pos;
X{
X if (pos >= MAXINV) return;
X inven[pos].count = 0;
X inven[pos].str[0] = '\0';
X inven[pos].phit = UNKNOWN;
X inven[pos].pdam = UNKNOWN;
X inven[pos].charges = UNKNOWN;
X forget (pos, (KNOWN | CURSED | ENCHANTED | PROTECTED | UNCURSED |
X INUSE | WORTHLESS));
X
X}
X
X/*
X * rollpackup: We have deleted an item, move up the objects behind it in
X * the pack.
X */
X
Xrollpackup (pos)
Xregister int pos;
X{ register char *savebuf;
X register int i;
X
X if (version >= RV53A) return;
X
X if (pos < currentarmor) currentarmor--;
X else if (pos == currentarmor) currentarmor = NONE;
X
X if (pos < currentweapon) currentweapon--;
X else if (pos == currentweapon) currentweapon = NONE;
X
X if (pos < leftring) leftring--;
X else if (pos == leftring) leftring = NONE;
X
X if (pos < rightring) rightring--;
X else if (pos == rightring) rightring = NONE;
X
X savebuf = inven[pos].str;
X for (i=pos; i+1<invcount; i++)
X inven[i] = inven[i+1];
X
X inven[--invcount].str = savebuf;
X}
X
X/*
X * rollpackdown: Open up a new spot in the pack, and move down the
X * objects behind that position.
X */
X
Xrollpackdown (pos)
Xregister int pos;
X{ register char *savebuf;
X register int i;
X
X if (version >= RV53A) return;
X
X savebuf = inven[invcount].str;
X for (i=invcount; i>pos; --i)
X { inven[i] = inven[i-1];
X if (i-1 == currentarmor) currentarmor++;
X if (i-1 == currentweapon) currentweapon++;
X if (i-1 == leftring) leftring++;
X if (i-1 == rightring) rightring++;
X }
X inven[pos].str = savebuf;
X
X if (++invcount > MAXINV)
X usesynch = 0;
X}
X
X/*
X * resetinv: send an inventory command. The actual work is done by
X * doresetinv, which is called by a demon in the command handler.
X */
X
Xresetinv()
X{
X if (!replaying) command (T_OTHER, "i");
X}
X
X/*
X * doresetinv: reset the inventory. DR UTexas 01/05/84
X */
X
Xdoresetinv ()
X{ int i;
X static char space[MAXINV][80];
X
X usesynch = 1;
X checkrange = 0;
X
X for(i=0; i<MAXINV; ++i)
X { inven[i].str = space[i];
X clearpack (i);
X }
X
X invcount = objcount = urocnt = 0;
X currentarmor = currentweapon = leftring = rightring = NONE;
X
X if (version >= RV53A) invcount = MAXINV;
X}
X
X/*
X * inventory: parse an item message.
X */
X
X# define xtr(w,b,e,k) {what=(w);xbeg=mess+(b);xend=mend-(e);xknow|=(k);}
X
Xinventory (msgstart, msgend)
Xchar *msgstart, *msgend;
X{ register char *p, *q, *mess = msgstart, *mend = msgend;
X char objname[100], *realname();
X int n, ipos, xknow = 0, newitem = 0, inuse = 0;
X int plushit = UNKNOWN, plusdam = UNKNOWN, charges = UNKNOWN;
X stuff what;
X char *xbeg, *xend;
X
X xbeg = xend = "";
X dwait (D_PACK, "inventory: message %s", mess);
X
X /* Rip surrounding garbage from the message */
X
X if (mess[1] == ')')
X { ipos= DIGIT(*mess); mess+=3;}
X else
X { ipos= DIGIT(mend[-2]); mend -= 4;
X deletestuff (atrow, atcol);
X unsetrc (USELESS, atrow, atcol);
X newitem = 1; }
X
X if (ISDIGIT(*mess))
X { n=atoi(mess); mess += 2+(n>9); }
X else
X { n=1;
X if (*mess == 'a') mess++; /* Eat the determiner A/An/The */
X if (*mess == 'n') mess++;
X if (*mess == 't') mess++;
X if (*mess == 'h') mess++;
X if (*mess == 'e') mess++;
X if (*mess == ' ') mess++; } /* Eat the space after the determiner */
X
X /* Read the plus to hit */
X if (*mess=='+' || *mess=='-')
X { plushit = atoi(mess++);
X while (ISDIGIT (*mess)) mess++;
X xknow = KNOWN;}
X
X /* Eat any comma separating two modifiers */
X if (*mess==',') mess++;
X
X /* Read the plus damage */
X if (*mess=='+' || *mess=='-')
X { plusdam = atoi(mess++);
X while (ISDIGIT (*mess)) mess++;
X xknow = KNOWN;}
X
X while (*mess==' ') mess++; /* Eat any separating spaces */
X while (mend[-1]==' ') mend--; /* Remove trailing blanks */
X while (mend[-1]=='.') mend--; /* Remove trailing periods */
X
X /* Read any parenthesized strings at the end of the message */
X while (mend[-1]==')')
X { while (*--mend != '(') ; /* on exit mend -> '(' */
X if (stlmatch(mend,"(being worn)") )
X { currentarmor = ipos; inuse = INUSE; }
X else if (stlmatch(mend,"(weapon in hand)") )
X { currentweapon = ipos; inuse = INUSE; }
X else if (stlmatch(mend,"(on left hand)") )
X { leftring = ipos; inuse = INUSE; }
X else if (stlmatch(mend,"(on right hand)") )
X { rightring = ipos; inuse = INUSE; }
X
X while (mend[-1]==' ') mend--;
X }
X
X /* Read the charges on a wand (or armor class or ring bonus) */
X if (mend[-1] == ']')
X { while (*--mend != '['); /* on exit mend -> '[' */
X if (mend[1] == '+') charges = atoi(mend+2);
X else charges = atoi(mend+1);
X xknow = KNOWN;
X }
X
X /* Undo plurals by removing trailing 's' */
X while (mend[-1] == ' ') mend--;
X if (mend[-1]=='s') mend--;
X
X /* Now find what we have picked up: */
X if (stlmatch(mend-4,"food")) {what=food;xknow=KNOWN;}
X else if (stlmatch(mess,"amulet")) xtr(amulet,0,0,KNOWN)
X else if (stlmatch(mess,"potion of ")) xtr(potion,10,0,KNOWN)
X else if (stlmatch(mess,"potions of ")) xtr(potion,11,0,KNOWN)
X else if (stlmatch(mess,"scroll of ")) xtr(scroll,10,0,KNOWN)
X else if (stlmatch(mess,"scrolls of ")) xtr(scroll,11,0,KNOWN)
X else if (stlmatch(mess,"staff of ")) xtr(wand,9,0,KNOWN)
X else if (stlmatch(mess,"wand of ")) xtr(wand,8,0,KNOWN)
X else if (stlmatch(mess,"ring of ")) xtr(ring,8,0,KNOWN)
X else if (stlmatch(mend-4,"mail")) xtr(armor,0,0,0)
X else if (stlmatch(mend-6,"potion")) xtr(potion,0,7,0)
X else if (stlmatch(mess,"scroll titled '")) xtr(scroll,15,1,0)
X else if (stlmatch(mess,"scrolls titled '")) xtr(scroll,16,1,0)
X else if (stlmatch(mend-5,"staff")) xtr(wand,0,6,0)
X else if (stlmatch(mend-4,"wand")) xtr(wand,0,5,0)
X else if (stlmatch(mend-4,"ring")) xtr(ring,0,5,0)
X else if (stlmatch(mess,"apricot")) xtr(food,0,0,KNOWN)
X else if (stlmatch(mend-5,"sword")) xtr(hitter,0,0,0)
X else if (stlmatch(mend-4,"mace")) xtr(hitter,0,0,0)
X else if (stlmatch(mend-6,"dagger")) xtr(missile,0,0,0)
X else if (stlmatch(mend-5,"spear")) xtr(missile,0,0,0)
X else if (stlmatch(mend-5,"armor")) xtr(armor,0,0,0)
X else if (stlmatch(mend-3,"arm")) xtr(armor,0,0,0)
X else if (stlmatch(mend-3,"bow")) xtr(thrower,0,0,0)
X else if (stlmatch(mend-5,"sling")) xtr(thrower,0,0,0)
X else if (stlmatch(mend-5,"arrow")) xtr(missile,0,0,0)
X else if (stlmatch(mend-4,"dart")) xtr(missile,0,0,0)
X else if (stlmatch(mend-4,"rock")) xtr(missile,0,0,0)
X else if (stlmatch(mend-4,"bolt")) xtr(missile,0,0,0)
X else if (stlmatch(mend-8,"shuriken")) xtr(missile,0,0,0)
X else xtr(strange,0,0,0)
X
X /* Copy the name of the object into a string */
X
X for (p = objname, q = xbeg; q < xend; p++, q++) *p = *q;
X *p = '\0';
X
X dwait (D_PACK, "inv: %s '%s', hit %d, dam %d, chg %d, knw %d",
X stuffmess[(int) what], objname, plushit, plusdam, charges, xknow);
X
X /* Ring bonus is printed differently in Rogue 5.3 */
X if (version >= RV53A && what == ring && charges != UNKNOWN)
X { plushit = charges; charges = UNKNOWN; }
X
X /* If the name of the object matches something in the database, */
X /* slap the real name into the slot and mark it as known */
X
X if ((what == potion || what == scroll || what == wand) && !xknow)
X { char *dbname = realname (objname);
X if (*dbname)
X { strcpy (objname, dbname);
X xknow = KNOWN;
X if (newitem)
X { at (0,0);
X
X if (n == 1) printw ("a ");
X else printw ("%d ", n);
X
X printw ("%s%s of %s (%c)",
X what == potion ? "potion" :
X what == scroll ? "scroll" :
X what == ring ? "ring" :
X "wand",
X (n == 1) ? "" : "s",
X objname,
X LETTER(ipos));
X
X clrtoeol ();
X at (row, col);
X refresh ();
X }
X else
X say (msgstart);
X }
X }
X
X /* If new item, record the change */
X if (newitem && what == armor)
X newarmor = 1;
X else if (newitem && what == ring)
X newring = 1;
X else if (newitem && what == food)
X { newring = 1; lastfoodlevel = Level; }
X else if (newitem && (what == hitter || what == missile || what == wand))
X newweapon = 1;
X
X /* If the object is an old object, set its count, else allocate */
X /* a new object and roll the other objects down */
X
X if (n > 1 && ipos < invcount && inven[ipos].type == what &&
X n == inven[ipos].count+1 &&
X stlmatch(objname, inven[ipos].str) &&
X inven[ipos].phit == plushit &&
X inven[ipos].pdam == plusdam)
X inven[ipos].count = n;
X
X /* New item, in older Rogues, open up a spot in the pack */
X else
X { if (version < RV53A) rollpackdown (ipos);
X
X /*
X * Use retained info to determine cursed attributes when identifying
X * or protected status for armor. DR UTexas 01/05/84
X */
X
X if (inven[ipos].type == what && stlmatch (objname, inven[ipos].str))
X { if (xknow != itemis (ipos, KNOWN) &&
X !itemis (ipos, (UNCURSED | ENCHANTED)) &&
X ((plushit != UNKNOWN && plushit < 0) ||
X (plusdam != UNKNOWN && plusdam < 0)))
X remember (ipos, CURSED);
X if (newitem || what != armor ) forget (ipos, PROTECTED);
X }
X
X inven[ipos].type = what;
X inven[ipos].count = n;
X inven[ipos].phit = plushit;
X inven[ipos].pdam = plusdam;
X inven[ipos].charges = charges;
X remember (ipos, inuse | xknow);
X if (!xknow) ++urocnt;
X }
X
X /* Forget enchanted status if item known. DR UTexas 31 Jan 84 */
X if (itemis (ipos, KNOWN)) forget (ipos, ENCHANTED);
X
X /* Set the name of the object */
X if (inven[ipos].str != NULL)
X strcpy (inven[ipos].str, objname);
X else if (!replaying)
X dwait (D_ERROR, "terpmess: null inven[%d].str, invcount %d.",
X ipos, invcount);
X
X /* Set cursed attribute for weapon and armor */
X if (cursedarmor && ipos == currentarmor) remember (ipos, CURSED);
X if (cursedweapon && ipos == currentweapon) remember (ipos, CURSED);
X
X /* Keep track of whether we are wielding a trap arrow */
X if (ipos == currentweapon) usingarrow = (what == missile);
X
X countpack ();
X
X /* If we picked up a useless thing, note that fact */
X if (newitem && on (USELESS)) remember (ipos, WORTHLESS);
X else if (newitem) forget (ipos, WORTHLESS);
X
X checkrange = 1;
X}
X
X/*
X * countpack: Count objects, missiles, and food in the pack.
X */
X
Xcountpack ()
X{ register int i, cnt;
X
X for (objcount=0, larder=0, ammo=0, i=0; i<invcount; i++)
X { if (! (cnt = inven[i].count)) ; /* No object here */
X else if (inven[i].type == missile) { objcount++; ammo += cnt; }
X else if (inven[i].type == food) { objcount += cnt; larder += cnt; }
X else { objcount += cnt; }
X }
X}
/
echo 'Part 04 of Rog-O-Matic XIV complete.'
exit
More information about the Comp.sources.unix
mailing list