#include <ctype.h>
#include "advent.h"
-#include "database.h"
#include "linenoise/linenoise.h"
-#include "newdb.h"
+#include "dungeon.h"
+
+const char new_advent_to_ascii[] = {
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', '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', '\0', '\0', '\0', '\0', '\0',
+};
+
+const char new_ascii_to_advent[] = {
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+};
char* xstrdup(const char* s)
{
va_end(ap);
}
-bool GETIN(FILE *input,
- long *pword1, long *pword1x,
- long *pword2, long *pword2x)
-/* Get a command from the adventurer. Snarf out the first word, pad it with
- * blanks, and return it in WORD1. Chars 6 thru 10 are returned in WORD1X, in
- * case we need to print out the whole word in an error message. Any number of
- * blanks may follow the word. If a second word appears, it is returned in
- * WORD2 (chars 6 thru 10 in WORD2X), else WORD2 is -1. */
-{
- long junk;
-
- for (;;) {
- if (game.blklin)
- fputc('\n', stdout);;
- if (!MAPLIN(input))
- return false;
- *pword1 = GETTXT(true, true, true);
- if (game.blklin && *pword1 < 0)
- continue;
- *pword1x = GETTXT(false, true, true);
- do {
- junk = GETTXT(false, true, true);
- } while
- (junk > 0);
- *pword2 = GETTXT(true, true, true);
- *pword2x = GETTXT(false, true, true);
- do {
- junk = GETTXT(false, true, true);
- } while
- (junk > 0);
- if (GETTXT(true, true, true) <= 0)
- return true;
- rspeak(TWO_WORDS);
- }
-}
-
void echo_input(FILE* destination, char* input_prompt, char* input)
{
size_t len = strlen(input_prompt) + strlen(input) + 1;
return (outcome);
}
-/* Line-parsing routines (GETTXT, MAKEWD, PUTTXT, SHFTXT) */
-
-long GETTXT(bool skip, bool onewrd, bool upper)
-/* Take characters from an input line and pack them into 30-bit words.
- * Skip says to skip leading blanks. ONEWRD says stop if we come to a
- * blank. UPPER says to map all letters to uppercase. If we reach the
- * end of the line, the word is filled up with blanks (which encode as 0's).
- * If we're already at end of line when TEXT is called, we return -1. */
-{
- long text;
- static long splitting = -1;
-
- if (LNPOSN != splitting)
- splitting = -1;
- text = -1;
- while (true) {
- if (LNPOSN > LNLENG)
- return (text);
- if ((!skip) || INLINE[LNPOSN] != 0)
- break;
- ++LNPOSN;
- }
-
- text = 0;
- for (int I = 1; I <= TOKLEN; I++) {
- text = text * 64;
- if (LNPOSN > LNLENG || (onewrd && INLINE[LNPOSN] == 0))
- continue;
- char current = INLINE[LNPOSN];
- if (current < ascii_to_advent['%']) {
- splitting = -1;
- if (upper && current >= ascii_to_advent['a'])
- current = current - 26;
- text = text + current;
- ++LNPOSN;
- continue;
- }
- if (splitting != LNPOSN) {
- text = text + ascii_to_advent['%'];
- splitting = LNPOSN;
- continue;
- }
-
- text = text + current - ascii_to_advent['%'];
- splitting = -1;
- ++LNPOSN;
- }
-
- return text;
-}
-
-token_t MAKEWD(long letters)
-/* Combine TOKLEN (currently 5) uppercase letters (represented by
- * pairs of decimal digits in lettrs) to form a 30-bit value matching
- * the one that GETTXT would return given those characters plus
- * trailing blanks. Caution: lettrs will overflow 31 bits if
- * 5-letter word starts with V-Z. As a kludgey workaround, you can
- * increment a letter by 5 by adding 50 to the next pair of
- * digits. */
-{
- long i = 1, word = 0;
-
- for (long k = letters; k != 0; k = k / 100) {
- word = word + i * (MOD(k, 50) + 10);
- i = i * 64;
- if (MOD(k, 100) > 50)word = word + i * 5;
- }
- i = 64L * 64L * 64L * 64L * 64L / i;
- word = word * i;
- return word;
-}
-
/* Data structure routines */
-long vocab(long id, long init)
-/* Look up ID in the vocabulary (ATAB) and return its "definition" (KTAB), or
- * -1 if not found. If INIT is positive, this is an initialisation call setting
- * up a keyword variable, and not finding it constitutes a bug. It also means
- * that only KTAB values which taken over 1000 equal INIT may be considered.
- * (Thus "STEPS", which is a motion verb as well as an object, may be located
- * as an object.) And it also means the KTAB value is taken modulo 1000. */
-{
- long lexeme;
-
- for (long i = 1; i <= TABSIZ; i++) {
- if (KTAB[i] == -1) {
- lexeme = -1;
- if (init < 0)
- return (lexeme);
- BUG(REQUIRED_VOCABULARY_WORD_NOT_FOUND); // LCOV_EXCL_LINE
- }
- if (init >= 0 && KTAB[i] / 1000 != init)
- continue;
- if (ATAB[i] == id) {
- lexeme = KTAB[i];
- if (init >= 0)
- lexeme = MOD(lexeme, 1000);
- return (lexeme);
- }
- }
- BUG(RAN_OFF_END_OF_VOCABULARY_TABLE); // LCOV_EXCL_LINE
-}
-
int get_motion_vocab_id(const char* word)
// Return the first motion number that has 'word' as one of its words.
{
return range * get_next_lcg_value() / game.lcg_m;
}
-long rndvoc(long second, long force)
-/* Searches the vocabulary ATAB for a word whose second character is
- * char, and changes that word such that each of the other four
- * characters is a random letter. If force is non-zero, it is used
- * as the new word. Returns the new word. */
-{
- long rnd = force;
-
- if (rnd == 0) {
- for (int i = 1; i <= 5; i++) {
- long j = 11 + randrange(26);
- if (i == 2)
- j = second;
- rnd = rnd * 64 + j;
- }
- }
-
- long div = 64L * 64L * 64L;
- for (int i = 1; i <= TABSIZ; i++) {
- if (MOD(ATAB[i] / div, 64L) == second) {
- ATAB[i] = rnd;
- break;
- }
- }
-
- return rnd;
-}
-
void make_zzword(char zzword[6])
{
for (int i = 0; i < 5; ++i)
zzword[5] = '\0';
}
-/* Machine dependent routines (MAPLIN, SAVEIO) */
-
-bool MAPLIN(FILE *fp)
-{
- bool eof;
-
- /* Read a line of input, from the specified input source.
- * This logic is complicated partly because it has to serve
- * several cases with different requirements and partly because
- * of a quirk in linenoise().
- *
- * The quirk shows up when you paste a test log from the clipboard
- * to the program's command prompt. While fgets (as expected)
- * consumes it a line at a time, linenoise() returns the first
- * line and discards the rest. Thus, there needs to be an
- * editline (-s) option to fall back to fgets while still
- * prompting. Note that linenoise does behave properly when
- * fed redirected stdin.
- *
- * The logging is a bit of a mess because there are two distinct cases
- * in which you want to echo commands. One is when shipping them to
- * a log under the -l option, in which case you want to suppress
- * prompt generation (so test logs are unadorned command sequences).
- * On the other hand, if you redirected stdin and are feeding the program
- * a logfile, you *do* want prompt generation - it makes checkfiles
- * easier to read when the commands are marked by a preceding prompt.
- */
- do {
- if (!editline) {
- if (prompt)
- fputs("> ", stdout);
- IGNORE(fgets(rawbuf, sizeof(rawbuf) - 1, fp));
- eof = (feof(fp));
- } else {
- char *cp = linenoise("> ");
- eof = (cp == NULL);
- if (!eof) {
- strncpy(rawbuf, cp, sizeof(rawbuf) - 1);
- linenoiseHistoryAdd(rawbuf);
- strncat(rawbuf, "\n", sizeof(rawbuf) - strlen(rawbuf) - 1);
- linenoiseFree(cp);
- }
- }
- } while
- (!eof && rawbuf[0] == '#');
- if (eof) {
- if (logfp && fp == stdin)
- fclose(logfp);
- return false;
- } else {
- FILE *efp = NULL;
- if (logfp && fp == stdin)
- efp = logfp;
- else if (!isatty(0))
- efp = stdout;
- if (efp != NULL) {
- if (prompt && efp == stdout)
- fputs("> ", efp);
- IGNORE(fputs(rawbuf, efp));
- }
- strcpy(INLINE + 1, rawbuf);
- /* translate the chars to integers in the range 0-126 and store
- * them in the common array "INLINE". Integer values are as follows:
- * 0 = space [ASCII CODE 40 octal, 32 decimal]
- * 1-2 = !" [ASCII 41-42 octal, 33-34 decimal]
- * 3-10 = '()*+,-. [ASCII 47-56 octal, 39-46 decimal]
- * 11-36 = upper-case letters
- * 37-62 = lower-case letters
- * 63 = percent (%) [ASCII 45 octal, 37 decimal]
- * 64-73 = digits, 0 through 9
- * Remaining characters can be translated any way that is convenient;
- * The above mappings are required so that certain special
- * characters are known to fit in 6 bits and/or can be easily spotted.
- * Array elements beyond the end of the line should be filled with 0,
- * and LNLENG should be set to the index of the last character.
- *
- * If the data file uses a character other than space (e.g., tab) to
- * separate numbers, that character should also translate to 0.
- *
- * This procedure may use the map1,map2 arrays to maintain
- * static data for he mapping. MAP2(1) is set to 0 when the
- * program starts and is not changed thereafter unless the
- * routines in this module choose to do so. */
- LNLENG = 0;
- for (long i = 1; i <= (long)sizeof(INLINE) && INLINE[i] != 0; i++) {
- long val = INLINE[i];
- INLINE[i] = ascii_to_advent[val];
- if (INLINE[i] != 0)
- LNLENG = i;
- }
- LNPOSN = 1;
- return true;
- }
-}
-
void datime(long* d, long* t)
{
struct timeval tv;