home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk1.iso / altsrc / articles / 11241 < prev    next >
Text File  |  1994-09-11  |  48KB  |  1,952 lines

  1. Path: wupost!kuhub.cc.ukans.edu!nrlvx1.nrl.navy.mil!ra!news.pop.psu.edu!news.cac.psu.edu!howland.reston.ans.net!europa.eng.gtefsd.com!MathWorks.Com!news.duke.edu!godot.cc.duq.edu!newsfeed.pitt.edu!uunet!news.sprintlink.net!demon!hunting2.demon.co.uk!zondo
  2. Newsgroups: alt.sources
  3. Subject: Wander: puzzle game (2 of 6)
  4. Message-ID: <778924803snz@hunting2.demon.co.uk>
  5. From: zondo@hunting2.demon.co.uk (Zondo Pillock)
  6. Date: Wed, 7 Sep 1994 08:00:03 +0000
  7. Reply-To: zondo@hunting2.demon.co.uk
  8. Sender: usenet@demon.co.uk
  9. Organization: Hunting Engineering Limited
  10. X-Newsreader: Demon Internet Simple News v1.29
  11. Lines: 1939
  12.  
  13. This is wander, version 1.0.
  14.  
  15. Wander is a game where you wander around the screen collecting
  16. treasures, solving puzzles and avoiding the nasty monsters.  It's
  17. really a new version of an old game called 'wanderer', written by
  18. Steven Shipway back in 1988.  Ah, wanderer... excellent game, shame
  19. about the source code.  I loved the game so much I rewrote it to
  20. (hopefully) make it more slick and expandable.  See the file CHANGES
  21. for the main differences between this version and the old one.
  22.  
  23. Wander uses curses and has been tested on a DECstation 5000 (ULTRIX)
  24. and SGI Indigo (IRIX).
  25.  
  26.                                                                __o
  27.                                 zondo@hunting2.demon.co.uk   _`\<,_
  28.                                 ............................(_)/ (_)
  29.  
  30.  
  31. Submitted-by: zondo@hunting2.demon.co.uk
  32. Archive-name: wander/part02
  33.  
  34. ---- Cut Here and feed the following to sh ----
  35. #!/bin/sh
  36. # This is part 02 of wander.
  37. touch -am 1231235999 $$.touch >/dev/null 2>&1
  38. if test ! -f 1231235999 && test -f $$.touch; then
  39.   shar_touch=touch
  40. else
  41.   shar_touch=:
  42.   echo 'WARNING: not restoring timestamps'
  43. fi
  44. rm -f 1231235999 $$.touch
  45. #
  46. # ============= move.c ==============
  47. if test -f 'move.c' && test X"$1" != X"-c"; then
  48.   echo 'x - skipping move.c (File already exists)'
  49. else
  50.   echo 'x - extracting move.c (text)'
  51.   sed 's/^X//' << 'SHAR_EOF' > 'move.c' &&
  52. /*
  53. X *  Wander version 1.0, Copyright (C) 1994 G. Hutchings
  54. X *  Wander comes with ABSOLUTELY NO WARRANTY.
  55. X *  This is free software, and you are welcome to redistribute it
  56. X *  under certain conditions; see the file COPYING for details.
  57. X */
  58. X
  59. /* Object movement stuff */
  60. X
  61. #ifndef lint
  62. static char rcsid[] = "$Id: move.c,v 1.24 1994/06/16 13:17:28 glen Exp $";
  63. #endif
  64. X
  65. #include <stdio.h>
  66. #include "defs.h"
  67. #include "data.h"
  68. #include "proto.h"
  69. #include "config.h"
  70. X
  71. struct {
  72. X    int line, col;        /* Position to move */
  73. X    int moved;            /* Has it been moved? */
  74. } movelist[MAXWIDTH*MAXHEIGHT];
  75. X
  76. int nummoves = 0;        /* No. of entries in move list */
  77. X
  78. /* Return whether player can move in a direction */
  79. int
  80. canmove(int dir)
  81. {
  82. X    int line = curpos->pline;
  83. X    int col = curpos->pcol;
  84. X    struct loc next, into;
  85. X
  86. X    /* Can't move at all if you're dead */
  87. X    if (curpos->dead) return 0;
  88. X
  89. X    /* Can always do nothing */
  90. X    if (dir == NONE) return 1;
  91. X
  92. X    /* Can only move onto exit if you have all the diamonds */
  93. X    /* (or you're wizard) */
  94. X    into = moveto(line, col, dir);
  95. X    if (into.type == EXIT) {
  96. X    if (!testlevel) {
  97. X        return (curpos->diamonds == 0 || wizard);
  98. X    } else {
  99. X        message("You can't leave a level you're testing");
  100. X        beep();
  101. X        return 0;
  102. X    }
  103. X    }
  104. X
  105. X    /* Can't move into something that blocks */
  106. X    if (obj[into.type].block) return 0;
  107. X
  108. X    if (obj[into.type].push) {
  109. X    /* Can't push if next space isn't free */
  110. X    next = moveto(into.line, into.col, dir);
  111. X    if (next.type != BLANK) return 0;
  112. X
  113. X    /* Can't push if going 'against the grain' */
  114. X    switch (obj[into.type].movedir) {
  115. X    case NORTH:
  116. X        if (dir == SOUTH) return 0;
  117. X        break;
  118. X    case SOUTH:
  119. X        if (dir == NORTH) return 0;
  120. X        break;
  121. X    case EAST:
  122. X        if (dir == WEST) return 0;
  123. X        break;
  124. X    case WEST:
  125. X        if (dir == EAST) return 0;
  126. X        break;
  127. X    }
  128. X    }
  129. X
  130. X    return 1;
  131. }
  132. X
  133. /* Move player */
  134. void
  135. domove(int dir)
  136. {
  137. X    int lastscore, pl, pc, plnew, pcnew, teleported = 0;
  138. X    struct loc new, next;
  139. X    int lpush, cpush;
  140. X
  141. X    /* Remove 'future' positions (if any) */
  142. X    removepos();
  143. X
  144. X    /* Copy current position */
  145. X    curpos = copypos(curpos);
  146. X    curpos->dir = dir;
  147. X
  148. X    /* Do the move */
  149. X    if (dir != NONE) {
  150. X    pl = curpos->pline;
  151. X    pc = curpos->pcol;
  152. X    new = moveto(pl, pc, dir);
  153. X    plnew = new.line;
  154. X    pcnew = new.col;
  155. X
  156. X    /* Check for being killed */
  157. X    if (obj[new.type].kill) {
  158. X        switch (new.type) {
  159. X        case BABY:
  160. X        case MONSTER:
  161. X        doeffect(plnew, pcnew, EATEN);
  162. X        die("You've been munched by a hungry monster!");
  163. X        break;
  164. X        case LANDMINE:
  165. X        doeffect(plnew, pcnew, BLOWNUP);
  166. X        die("You've been blown up by a landmine!");
  167. X        break;
  168. X        default:
  169. X        die("Oh dear, you're dead.  Not sure what killed you, though");
  170. X        }
  171. X    }
  172. X
  173. X    /* Check for pushing something */
  174. X    if (obj[new.type].push) {
  175. X        next = moveto(plnew, pcnew, dir);
  176. X        lpush = next.line;
  177. X        cpush = next.col;
  178. X        curpos->data[lpush][cpush] = curpos->data[plnew][pcnew];
  179. X    }
  180. X
  181. X    /* Check for eating something */
  182. X    if (obj[new.type].eat) {
  183. X        curpos->score += obj[new.type].score;
  184. X
  185. X        switch (new.type) {
  186. X        case CAPSULE:
  187. X        if (curpos->nmoves > 0)
  188. X            curpos->nmoves += CAPSULEMOVES;
  189. X        break;
  190. X        case TREASURE:
  191. X        curpos->diamonds--;
  192. X        break;
  193. X        }
  194. X    }
  195. X
  196. X    /* Check for teleport */
  197. X    if (new.type == TELEPORT) {
  198. X        curpos->data[pl][pc] = BLANK;
  199. X        curpos->data[plnew][pcnew] = PLAYER;
  200. X        doeffect(plnew, pcnew, VANISH);
  201. X        curpos->data[plnew][pcnew] = BLANK;
  202. X        moveinto(plnew, pcnew);
  203. X        plnew = tline;
  204. X        pcnew = tcol;
  205. X        teleported = 1;
  206. X    }
  207. X
  208. X    /* Check for escape */
  209. X    if (new.type == EXIT) {
  210. X        curpos->data[pl][pc] = BLANK;
  211. X        curpos->data[plnew][pcnew] = PLAYER;
  212. X        doeffect(plnew, pcnew, VANISH);
  213. X        curpos->data[plnew][pcnew] = BLANK;
  214. X        exited = 1;
  215. X
  216. X        /* Add moves left as a bonus */
  217. X        if (curpos->nmoves > 0)
  218. X        curpos->score += curpos->nmoves;
  219. X
  220. X        /* Get last score for this level (if any) */
  221. X        lastscore = getscore(myuid, level);
  222. X
  223. X        /* Update score for this level */
  224. X        while (1) {
  225. X        if (lockscores()) {
  226. X            readscores();
  227. X            updatescore(myuid, level, curpos->score);
  228. X            writescores();
  229. X            unlockscores();
  230. X            break;
  231. X        }
  232. X        }
  233. X
  234. X        /* Report on success */
  235. X        if (level == maxlevel) {
  236. X        message("Well done!  Type %c to go to level %d, %c to save",
  237. X            NEXTLEVEL, level+1, SAVE);
  238. X        } else if (curpos->score > lastscore) {
  239. X        message("You beat your last score on this level by %d points",
  240. X            curpos->score-lastscore);
  241. X        } else {
  242. X        message("You didn't beat your last score of %d points",
  243. X            lastscore);
  244. X        }
  245. X
  246. X        beep();
  247. X    }
  248. X
  249. X    /* Set final player position */
  250. X    if (curpos->data[pl][pc] == PLAYER)
  251. X        curpos->data[pl][pc] = BLANK;
  252. X    curpos->pline = plnew;
  253. X    curpos->pcol = pcnew;
  254. X
  255. X    if (teleported) {
  256. X        recentre();
  257. X        doeffect(plnew, pcnew, APPEAR);
  258. X
  259. X        /* Check you didn't appear inside a monster! */
  260. X        if (findmonster(plnew, pcnew) != NULL) {
  261. X        doeffect(plnew, pcnew, BLOWNUP);
  262. X        die("You materialized inside a monster!  Yuck!");
  263. X        }
  264. X    }
  265. X
  266. X    curpos->data[plnew][pcnew] = PLAYER;
  267. X
  268. X    /* Check for things moving */
  269. X    vacate(pl, pc);
  270. X    moveinto(plnew, pcnew);
  271. X    }
  272. X
  273. X    /* Move objects affected by you */
  274. X    moveobjects();
  275. X
  276. X    /* Move the nasty evil monsters */
  277. X    movemonsters();
  278. X
  279. X    /* Move objects affected by monsters */
  280. X    moveobjects();
  281. X
  282. X    /* Decrement moves left */
  283. X    if (curpos->nmoves > 0) curpos->nmoves--;
  284. X    if (curpos->nmoves == 0) {
  285. X    doeffect(curpos->pline, curpos->pcol, TIMEUP);
  286. X    die("You ran out of time!");
  287. X    }
  288. X
  289. X    /* Add new position to stack */
  290. X    addpos(curpos);
  291. }
  292. X
  293. /* Check for things moving when something moves next to them */
  294. void
  295. moveinto(int line, int col)
  296. {
  297. X    /* Try to move objects in the four adjacent squares */
  298. X    addmove(line-1, col  );
  299. X    addmove(line  , col-1);
  300. X    addmove(line  , col+1);
  301. X    addmove(line+1, col  );
  302. }
  303. X
  304. /* Check for things moving after a square has been vacated */
  305. void
  306. vacate(int line, int col)
  307. {
  308. X    /* Check all surrounding squares for objects which */
  309. X    /* might move into or through the vacated one */
  310. X    checkmove(line-1, col,   line, col);
  311. X    checkmove(line  , col-1, line, col);
  312. X    checkmove(line  , col+1, line, col);
  313. X    checkmove(line+1, col  , line, col);
  314. X    checkmove(line-1, col-1, line, col);
  315. X    checkmove(line-1, col+1, line, col);
  316. X    checkmove(line+1, col-1, line, col);
  317. X    checkmove(line+1, col+1, line, col);
  318. }
  319. X
  320. /* Check if an object moves into a vacated square */
  321. void
  322. checkmove(int line, int col, int lastline, int lastcol)
  323. {
  324. X    struct loc locs[2];
  325. X    int nlocs, i;
  326. X
  327. X    /* Would it move at all? */
  328. X    if ((nlocs = wouldmove(line, col, locs)) == 0) return;
  329. X
  330. X    /* If so, would it move into or through the vacated square? */
  331. X    for (i = 0; i < nlocs; i++) {
  332. X    if (locs[i].line == lastline &&
  333. X        locs[i].col == lastcol)
  334. X        addmove(line, col);
  335. X    }
  336. }
  337. X
  338. /* Returns whether an object would move if given the */
  339. /* chance, and the path it would take to get there */
  340. int
  341. wouldmove(int line, int col, struct loc locs[2])
  342. {
  343. X    struct loc l, next, lsloc[2], rsloc[2];
  344. X    int dir, sdir, nlocs = 0, nls = 0, nrs = 0;
  345. X
  346. X    /* Everything stops when you die */
  347. X    if (curpos->dead) return 0;
  348. X
  349. X    l = curloc(curpos, line, col);
  350. X    dir = obj[l.type].movedir;
  351. X    if (dir == NONE) return 0;
  352. X    next = moveto(line, col, dir);
  353. X
  354. X    switch (next.type) {
  355. X    case BLANK:
  356. X    locs[nlocs++] = next;
  357. X    break;
  358. X    case LSLOPE:
  359. X    case RSLOPE:
  360. X    sdir = (next.type == LSLOPE ?
  361. X        slopes[dir].lsdir :
  362. X        slopes[dir].rsdir);
  363. X    next = moveto(line, col, sdir);
  364. X    if (next.type == BLANK) {
  365. X        locs[nlocs++] = next;
  366. X        next = moveto(next.line, next.col, dir);
  367. X        if (next.type == BLANK) {
  368. X        locs[nlocs++] = next;
  369. X        } else {
  370. X        nlocs = 0;
  371. X        }
  372. X    }
  373. X    break;
  374. X    default:
  375. X    if (obj[next.type].sloped) {
  376. X        lsloc[nls++] = moveto(line, col, slopes[dir].lsdir);
  377. X        if (lsloc[0].type == BLANK) {
  378. X        lsloc[nls++] = moveto(lsloc[0].line, lsloc[0].col, dir);
  379. X        if (lsloc[1].type != BLANK) nls = 0;
  380. X        }
  381. X
  382. X        rsloc[nrs++] = moveto(line, col, slopes[dir].rsdir);
  383. X        if (rsloc[0].type == BLANK) {
  384. X        rsloc[nrs++] = moveto(rsloc[0].line, rsloc[0].col, dir);
  385. X        if (rsloc[1].type != BLANK) nrs = 0;
  386. X        }
  387. X
  388. X        if (nls == 2 && nrs < 2) {
  389. X        nlocs = nls;
  390. X        locs[0] = lsloc[0];
  391. X        locs[1] = lsloc[1];
  392. X        } else if (nrs == 2 && nls < 2) {
  393. X        nlocs = nrs;
  394. X        locs[0] = rsloc[0];
  395. X        locs[1] = rsloc[1];
  396. X        }
  397. X    }
  398. X
  399. X    break;
  400. X    }
  401. X
  402. X    return nlocs;
  403. }
  404. X
  405. /* Move an object */
  406. void
  407. moveobject(int line, int col)
  408. {
  409. X    int nlocs, lnew, cnew, type, dir;
  410. X    struct loc locs[2], next, l;
  411. X
  412. X    l = curloc(curpos, line, col);
  413. X    type = l.type;
  414. X    dir = obj[type].movedir;
  415. X
  416. X    while ((nlocs = wouldmove(line, col, locs)) > 0) {
  417. X    /* Move it */
  418. X    lnew = locs[nlocs-1].line;
  419. X    cnew = locs[nlocs-1].col;
  420. X    curpos->data[line][col] = BLANK;
  421. X    curpos->data[lnew][cnew] = type;
  422. X    drawpos(curpos);
  423. X
  424. X    /* Check for things moving into the space it left */
  425. X    vacate(line, col);
  426. X    line = lnew;
  427. X    col = cnew;
  428. X    moveinto(line, col);
  429. X
  430. X    /* Check for bashing things */
  431. X    next = moveto(line, col, dir);
  432. X    switch (next.type) {
  433. X    case PLAYER:
  434. X        switch (type) {
  435. X        case BOULDER:
  436. X        doeffect(next.line, next.col, SQUASHED);
  437. X        die("A boulder just squashed you flat!");
  438. X        break;
  439. X        case LARROW:
  440. X        case RARROW:
  441. X        doeffect(next.line, next.col, SHOT);
  442. X        die("You've been shot by a giant arrow!");
  443. X        break;
  444. X        case ROCKET:
  445. X        doeffect(next.line, next.col, BLOWNUP);
  446. X        die("You've been blown up by a rocket!");
  447. X        break;
  448. X        default:
  449. X        die("Oh dear, you're dead.  Not sure what killed you, though");
  450. X        break;
  451. X        }
  452. X
  453. X        break;
  454. X    case MONSTER:
  455. X        switch (type) {
  456. X        case BOULDER:
  457. X        doeffect(next.line, next.col, SQUASHED);
  458. X        killmonster(next.line, next.col);
  459. X        break;
  460. X        case LARROW:
  461. X        case RARROW:
  462. X        doeffect(next.line, next.col, SHOT);
  463. X        killmonster(next.line, next.col);
  464. X        break;
  465. X        case ROCKET:
  466. X        doeffect(next.line, next.col, BLOWNUP);
  467. X        killmonster(next.line, next.col);
  468. X        break;
  469. X        default:
  470. X        killmonster(next.line, next.col);
  471. X        break;
  472. X        }
  473. X
  474. X        break;
  475. X    }
  476. X    }
  477. }
  478. X
  479. /* Add an object to the move list */
  480. void
  481. addmove(int line, int col)
  482. {
  483. X    int i;
  484. X
  485. X    for (i = 0; i < nummoves; i++) {
  486. X    if (movelist[i].moved) break;
  487. X    }
  488. X
  489. X    movelist[i].line = line;
  490. X    movelist[i].col = col;
  491. X    movelist[i].moved = 0;
  492. X
  493. X    if (i == nummoves) nummoves++;
  494. }
  495. X
  496. /* Move all the objects in the move list */
  497. void
  498. moveobjects()
  499. {
  500. X    int i, priority, p, line, col;
  501. X    struct loc l;
  502. X
  503. X    while (1) {
  504. X    /* Find highest movement priority */
  505. X    for (priority = 0, i = 0; i < nummoves; i++) {
  506. X        if (!movelist[i].moved) {
  507. X        line = movelist[i].line;
  508. X        col = movelist[i].col;
  509. X        l = curloc(curpos, line, col);
  510. X        if ((p = obj[l.type].movepri) == 0) continue;
  511. X        if (priority == 0 || p < priority) priority = p;
  512. X        }
  513. X    }
  514. X
  515. X    /* If nothing else to move, that's it */
  516. X    if (priority == 0) break;
  517. X
  518. X    /* Move all objects of that priority */
  519. X    for (i = 0; i < nummoves; i++) {
  520. X        if (!movelist[i].moved) {
  521. X        line = movelist[i].line;
  522. X        col = movelist[i].col;
  523. X        l = curloc(curpos, line, col);
  524. X        p = obj[l.type].movepri;
  525. X        if (p == priority) {
  526. X            moveobject(line, col);
  527. X            movelist[i].moved = 1;
  528. X        }
  529. X        }
  530. X    }
  531. X    }
  532. X
  533. X    /* Clear move list */
  534. X    nummoves = 0;
  535. }
  536. X
  537. /* Hahahaha, you're dead! */
  538. void
  539. die(char *msg)
  540. {
  541. X    curpos->dead = 1;
  542. X    beep();
  543. X    message(msg);
  544. }
  545. SHAR_EOF
  546.   $shar_touch -am 0706083194 'move.c' &&
  547.   chmod 0444 'move.c' ||
  548.   echo 'restore of move.c failed'
  549.   shar_count="`wc -c < 'move.c'`"
  550.   test 11194 -eq "$shar_count" ||
  551.     echo "move.c: original size 11194, current size $shar_count"
  552. fi
  553. # ============= score.c ==============
  554. if test -f 'score.c' && test X"$1" != X"-c"; then
  555.   echo 'x - skipping score.c (File already exists)'
  556. else
  557.   echo 'x - extracting score.c (text)'
  558.   sed 's/^X//' << 'SHAR_EOF' > 'score.c' &&
  559. /*
  560. X *  Wander version 1.0, Copyright (C) 1994 G. Hutchings
  561. X *  Wander comes with ABSOLUTELY NO WARRANTY.
  562. X *  This is free software, and you are welcome to redistribute it
  563. X *  under certain conditions; see the file COPYING for details.
  564. X */
  565. X
  566. /* Scoring routines */
  567. X
  568. #ifndef lint
  569. static char rcsid[] = "$Id: score.c,v 1.11 1994/06/15 13:47:52 glen Exp $";
  570. #endif
  571. X
  572. #include <stdio.h>
  573. #include <string.h>
  574. #include "defs.h"
  575. #include "data.h"
  576. #include "proto.h"
  577. #include "config.h"
  578. X
  579. /* Field separator in score file */
  580. #define FIELDSEP    ":"
  581. X
  582. struct score {
  583. X    char *name;            /* Player name */
  584. X    int uid;            /* UID */
  585. X    int hide;            /* Hide score from other players? */
  586. X    int level;            /* Max. level */
  587. X    int *score;            /* Current scores per level */
  588. X    struct score *next;        /* Next in list */
  589. };
  590. X
  591. static struct score *scores = NULL; /* Score list */
  592. X
  593. char *getenv(char *name);
  594. X
  595. /* Return player's user name */
  596. char *
  597. playername()
  598. {
  599. X    static char buf[BUFSIZ];
  600. X
  601. X    /* Get name from variable */
  602. X    if (getenv("WANDERNAME") != NULL) {
  603. X    strcpy(buf, getenv("WANDERNAME"));
  604. X    } else if (getenv("USER") != NULL) {
  605. X    strcpy(buf, getenv("USER"));
  606. X    } else {
  607. X    fatal("WANDERNAME or USER environment variables must be set");
  608. X    }
  609. X
  610. X    /* Check it for validity */
  611. X    if (strlen(buf) == 0)
  612. X    fatal("WANDERNAME or USER must not be set to a null string");
  613. X    if (strstr(buf, FIELDSEP) != NULL)
  614. X    fatal("%s must not contain any '%c' characters", buf, FIELDSEP);
  615. X
  616. X    return buf;
  617. }
  618. X
  619. /* Add a new player to the score list */
  620. static struct score *
  621. addscore()
  622. {
  623. X    struct score *new;
  624. X    int i;
  625. X
  626. X    new = ALLOC(struct score, 1);
  627. X    if (new == NULL)
  628. X    fatal("Out of memory");
  629. X
  630. X    new->name = NULL;
  631. X    new->score = ALLOC(int, nlevels);
  632. X    for (i = 0; i < nlevels; i++) new->score[i] = 0;
  633. X    new->next = scores;
  634. X    scores = new;
  635. X
  636. X    return new;
  637. }
  638. X
  639. /* Read the score file */
  640. void
  641. readscores()
  642. {
  643. X    char buf[BUFSIZ], *file = scorefile(), *tok;
  644. X    struct score *s;
  645. X    FILE *fp;
  646. X    int i;
  647. X
  648. X    if ((fp = fopen(file, "r")) == NULL)
  649. X    fatal("Can't open %s", file);
  650. X
  651. X    /* Free old score list (if any) */
  652. X    while (scores != NULL) {
  653. X    s = scores->next;
  654. X    DEALLOC(scores->name);
  655. X    DEALLOC(scores->score);
  656. X    DEALLOC(scores);
  657. X    scores = s;
  658. X    }
  659. X
  660. X    while (fgets(buf, BUFSIZ, fp) != NULL) {
  661. X    /* Add new score */
  662. X    s = addscore();
  663. X
  664. X    /* First field is player name */
  665. X    if ((tok = strtok(buf, FIELDSEP)) == NULL)
  666. X        fatal("%s: corrupted score file", file);
  667. X    s->name = ALLOC(char, strlen(tok)+1);
  668. X    strcpy(s->name, tok);
  669. X
  670. X    /* Second field is UID */
  671. X    if ((tok = strtok(NULL, FIELDSEP)) == NULL)
  672. X        fatal("%s: corrupted score file", file);
  673. X    s->uid = atoi(tok);
  674. X
  675. X    /* Third field is whether to hide score */
  676. X    if ((tok = strtok(NULL, FIELDSEP)) == NULL)
  677. X        fatal("%s: corrupted score file", file);
  678. X    s->hide = atoi(tok);
  679. X
  680. X    /* Fourth field is level */
  681. X    if ((tok = strtok(NULL, FIELDSEP)) == NULL)
  682. X        fatal("%s: corrupted score file", file);
  683. X    s->level = atoi(tok);
  684. X
  685. X    /* Following fields are scores per level */
  686. X    for (i = 0; i < s->level-1; i++) {
  687. X        if ((tok = strtok(NULL, FIELDSEP)) == NULL)
  688. X        fatal("%s: corrupted score file", file);
  689. X        s->score[i] = atoi(tok);
  690. X    }
  691. X    }
  692. X
  693. X    fclose(fp);
  694. }
  695. X
  696. /* Write the score file */
  697. void
  698. writescores()
  699. {
  700. X    char *file = scorefile();
  701. X    struct score *s;
  702. X    FILE *fp;
  703. X    int i;
  704. X
  705. X    fp = fopen(file, "w");
  706. X
  707. X    for (s = scores; s != NULL; s = s->next) {
  708. X    fprintf(fp, "%s%s%d%s%d%s%d",
  709. X        s->name, FIELDSEP,
  710. X        s->uid, FIELDSEP,
  711. X        s->hide, FIELDSEP,
  712. X        s->level);
  713. X
  714. X    for (i = 0; i < s->level-1; i++) {
  715. X        fprintf(fp, "%s%d", FIELDSEP, s->score[i]);
  716. X    }
  717. X
  718. X    fprintf(fp, "\n");
  719. X    }
  720. X
  721. X    fclose(fp);
  722. }
  723. X
  724. /* Look up a player in the score list */
  725. static struct score *
  726. findscore(int uid)
  727. {
  728. X    struct score *s;
  729. X
  730. X    for (s = scores; s != NULL; s = s->next) {
  731. X    if (s->uid == uid) return s;
  732. X    }
  733. X
  734. X    return NULL;
  735. }
  736. X
  737. /* Update a player's score */
  738. void
  739. updatescore(int uid, int level, int score)
  740. {
  741. X    struct score *s = findscore(uid);
  742. X    extern char myname[];
  743. X
  744. X    if (s == NULL) {
  745. X    s = addscore();
  746. X    s->uid = uid;
  747. X    }
  748. X
  749. X    if (s->name != NULL) DEALLOC(s->name);
  750. X    s->name = ALLOC(char, strlen(myname)+1);
  751. X    strcpy(s->name, myname);
  752. X    s->hide = hidescore;
  753. X
  754. X    s->level = level+1;
  755. X    s->score[level-1] = score;
  756. }
  757. X
  758. /* Display the score list */
  759. void
  760. showscores()
  761. {
  762. X    struct score *s;
  763. X    int i, totalscore, title = 0;
  764. X
  765. X    for (s = scores; s != NULL; s = s->next) {
  766. X    if (s->hide && s->uid != myuid) continue;
  767. X
  768. X    if (!title) {
  769. X        printf("\n          W A N D E R   S C O R E S\n\n");
  770. X        printf("%-30s  %5s  %5s\n\n", "Name", "Level", "Score");
  771. X        title = 1;
  772. X    }
  773. X
  774. X    for (i = 0, totalscore = 0; i < s->level-1; i++)
  775. X        totalscore += s->score[i];
  776. X
  777. X    printf("%-30s  %3d    %5d\n", s->name, s->level, totalscore);
  778. X    }
  779. X
  780. X    if (title)
  781. X    printf("\n");
  782. X    else
  783. X    printf("No scores recorded\n");
  784. }
  785. X
  786. /* Display your scores per level */
  787. void
  788. showlevels(int uid)
  789. {
  790. X    struct score *s = findscore(uid);
  791. X    int i;
  792. X
  793. X    if (s == NULL || s->level == 1) {
  794. X    printf("You haven't finished any levels yet\n");
  795. X    } else {
  796. X    printf("Level   Score\n");
  797. X    for (i = 0; i < s->level-1; i++) {
  798. X        printf("%3d     %5d\n", i+1, s->score[i]);
  799. X    }
  800. X    }
  801. }
  802. X
  803. /* Return player's biggest level */
  804. int
  805. getlevel(int uid)
  806. {
  807. X    struct score *s = findscore(uid);
  808. X
  809. X    return (s != NULL ? s->level : 1);
  810. }
  811. X
  812. /* Return a player's score for a level */
  813. int
  814. getscore(int uid, int level)
  815. {
  816. X    struct score *s = findscore(uid);
  817. X
  818. X    return (s != NULL ? s->score[level-1] : 0);
  819. }
  820. SHAR_EOF
  821.   $shar_touch -am 0615144994 'score.c' &&
  822.   chmod 0444 'score.c' ||
  823.   echo 'restore of score.c failed'
  824.   shar_count="`wc -c < 'score.c'`"
  825.   test 5452 -eq "$shar_count" ||
  826.     echo "score.c: original size 5452, current size $shar_count"
  827. fi
  828. # ============= save.c ==============
  829. if test -f 'save.c' && test X"$1" != X"-c"; then
  830.   echo 'x - skipping save.c (File already exists)'
  831. else
  832.   echo 'x - extracting save.c (text)'
  833.   sed 's/^X//' << 'SHAR_EOF' > 'save.c' &&
  834. /*
  835. X *  Wander version 1.0, Copyright (C) 1994 G. Hutchings
  836. X *  Wander comes with ABSOLUTELY NO WARRANTY.
  837. X *  This is free software, and you are welcome to redistribute it
  838. X *  under certain conditions; see the file COPYING for details.
  839. X */
  840. X
  841. /* Level saving functions */
  842. X
  843. #ifndef lint
  844. static char rcsid[] = "$Id: save.c,v 1.11 1994/06/29 14:27:43 glen Exp $";
  845. #endif
  846. X
  847. #include <stdio.h>
  848. #include "defs.h"
  849. #include "data.h"
  850. #include "proto.h"
  851. #include "config.h"
  852. X
  853. #define MEMSIZE        100    /* Default memory allocation size */
  854. #define LINESIZE    60    /* Moves per line */
  855. #define DELAY        0.3    /* Default replay frame delay (sec) */
  856. #define WAIT        1000L    /* Wait delay (msec) */
  857. X
  858. struct path {
  859. X    int level;            /* Level */
  860. X    int score;            /* Score gained */
  861. X    char *moves;        /* Moves made to do it */
  862. };
  863. X
  864. /* Return the move path of the current level */
  865. static struct path *
  866. movepath()
  867. {
  868. X    struct pos *p;
  869. X    struct path *new = ALLOC(struct path, 1);
  870. X    int msize = MEMSIZE, nmoves = 0;
  871. X
  872. X    if (new == NULL) fatal("Out of memory");
  873. X
  874. X    new->level = (testlevel ? 0 : level);
  875. X    new->score = lastpos->score;
  876. X    new->moves = ALLOC(char, msize);
  877. X
  878. X    for (p = firstpos->next; p != NULL; p = p->next) {
  879. X    if        (p->dir == NORTH) {
  880. X        new->moves[nmoves++] = 'N';
  881. X    } else if (p->dir == EAST) {
  882. X        new->moves[nmoves++] = 'E';
  883. X    } else if (p->dir == SOUTH) {
  884. X        new->moves[nmoves++] = 'S';
  885. X    } else if (p->dir == WEST) {
  886. X        new->moves[nmoves++] = 'W';
  887. X    } else if (p->dir == NONE) {
  888. X        new->moves[nmoves++] = '.';
  889. X    } else {
  890. X        new->moves[nmoves++] = '?';
  891. X    }
  892. X
  893. X    if (nmoves == msize) {
  894. X        msize += MEMSIZE;
  895. X        new->moves = REALLOC(new->moves, char, msize);
  896. X    }
  897. X    }
  898. X
  899. X    new->moves[nmoves] = '\0';
  900. X    return new;
  901. }
  902. X
  903. /* Interactively write a position to file */
  904. void
  905. save()
  906. {
  907. X    FILE *fp;
  908. X    char *name = getstring("Save file name: ");
  909. X
  910. X    if (name == NULL || strlen(name) == 0) return;
  911. X    if ((fp = fopen(name, "w")) == NULL) {
  912. X    message("Can't open %s");
  913. X    return;
  914. X    }
  915. X
  916. X    writemoves(fp);
  917. X    fclose(fp);
  918. }
  919. X
  920. /* Write moves of current level to output stream */
  921. void
  922. writemoves(FILE *fp)
  923. {
  924. X    struct path *p = movepath();
  925. X    int col = 0, i = 0;
  926. X
  927. X    /* Write header */
  928. X    fprintf(fp, "%d %d\n", p->level, p->score);
  929. X
  930. X    /* Write moves */
  931. X    while (p->moves[i] != NULL) {
  932. X    fputc(p->moves[i++], fp);
  933. X    if (++col == LINESIZE) {
  934. X        col = 0;
  935. X        fputc('\n', fp);
  936. X    }
  937. X    }
  938. X
  939. X    if (col > 0) fputc('\n', fp);
  940. X    DEALLOC(p->moves);
  941. X    DEALLOC(p);
  942. }
  943. X
  944. /* Restore a move path */
  945. void
  946. restore()
  947. {
  948. X    char *name = getstring("Restore file name: ");
  949. X
  950. X    if (name == NULL) return;
  951. X
  952. X    redrawscreen = query("Replay moves on screen? ", 0);
  953. X    restorefile(name);
  954. X    if (!redrawscreen) recentre();
  955. X    redrawscreen = 1;
  956. }
  957. X
  958. /* Restore a move path from file */
  959. void
  960. restorefile(char *name)
  961. {
  962. X    FILE *fp = fopen(name, "r");
  963. X    int flevel, fscore, dir, c, mini;
  964. X    char buf[BUFSIZ];
  965. X    double delay = DELAY;
  966. X
  967. X    if (fp == NULL) {
  968. X    message("Can't open %s", name);
  969. X    beep();
  970. X    return;
  971. X    }
  972. X
  973. X    /* Read header */
  974. X    if (fgets(buf, BUFSIZ, fp) == NULL) {
  975. X    message("Error reading %s", name);
  976. X    beep();
  977. X    return;
  978. X    }
  979. X
  980. X    if (sscanf(buf, "%d %d", &flevel, &fscore) != 2) {
  981. X    message("%s is not a wander save file", name);
  982. X    beep();
  983. X    return;
  984. X    }
  985. X
  986. X    if (!testlevel) {
  987. X    if (flevel != 0 && flevel != level) {
  988. X        message("%s is not a save file for this level", name);
  989. X        beep();
  990. X        return;
  991. X    }
  992. X    }
  993. X
  994. X    /* Replay it */
  995. X    curpos = firstpos;
  996. X    mini = minidisplay;
  997. X    exited = 0;
  998. X
  999. X    while ((c = fgetc(fp)) != EOF) {
  1000. X    if (c == '\n') continue;
  1001. X
  1002. X    switch (c) {
  1003. X    case 'N':
  1004. X        dir = NORTH;
  1005. X        break;
  1006. X    case 'E':
  1007. X        dir = EAST;
  1008. X        break;
  1009. X    case 'S':
  1010. X        dir = SOUTH;
  1011. X        break;
  1012. X    case 'W':
  1013. X        dir = WEST;
  1014. X        break;
  1015. X    case '.':
  1016. X        dir = NONE;
  1017. X        break;
  1018. X    default:
  1019. X        message("Invalid character in save file: '%c'", c);
  1020. X        goto finish;
  1021. X    }
  1022. X
  1023. X    if (canmove(dir)) {
  1024. X        /* Do the move */
  1025. X        domove(dir);
  1026. X        scroll();
  1027. X        if (exited) goto finish;
  1028. X
  1029. X        /* Update screen */
  1030. X        drawpos(curpos);
  1031. X
  1032. X        /* If displaying moves, pause and check for keypress */
  1033. X        if (redrawscreen) {
  1034. X        freeze(delay);
  1035. X        if (waitch(WAIT)) {
  1036. X            c = getakey(0);
  1037. X            switch (c) {
  1038. X            case '0':
  1039. X            case '1':
  1040. X            case '2':
  1041. X            case '3':
  1042. X            case '4':
  1043. X            case '5':
  1044. X            case '6':
  1045. X            case '7':
  1046. X            case '8':
  1047. X            case '9':
  1048. X            delay = (c-'0')/10.0;
  1049. X            break;
  1050. X            case TOGGLEWIN:
  1051. X            minidisplay = !minidisplay;
  1052. X            break;
  1053. X            case QUIT:
  1054. X            if (query("Abort replay? ", 0)) goto finish;
  1055. X            break;
  1056. X            default:
  1057. X            message("Paused...press a key to continue");
  1058. X            drawpos(curpos);
  1059. X            getakey(0);
  1060. X            break;
  1061. X            }
  1062. X        }
  1063. X        }
  1064. X    } else {
  1065. X        message("Oops!  Duff move in %s", name);
  1066. X        beep();
  1067. X        goto finish;
  1068. X    }
  1069. X
  1070. X    if (curpos->dead) goto finish;
  1071. X    }
  1072. X
  1073. X finish:
  1074. X    minidisplay = mini;
  1075. X    fclose(fp);
  1076. }
  1077. X
  1078. /* Display the solution to a level */
  1079. void
  1080. showsolution()
  1081. {
  1082. X    /* Check solution exists */
  1083. X    if (!solexists(level)) {
  1084. X    message("Hints for this level are not available");
  1085. X    return;
  1086. X    }
  1087. X
  1088. X    /* Ask them if they're REALLY sure */
  1089. X    if (!query("Hints for this level - are you sure? ", 0)) return;
  1090. X    if (!query("Are you REALLY REALLY sure? ", 0)) return;
  1091. X
  1092. X    /* Do the replay */
  1093. X    restorefile(solpath(level));
  1094. X    query("Press any key to finish: ", 0);
  1095. X
  1096. X    /* Reset to start position */
  1097. X    curpos = firstpos;
  1098. X    recentre();
  1099. }
  1100. SHAR_EOF
  1101.   $shar_touch -am 0629152894 'save.c' &&
  1102.   chmod 0444 'save.c' ||
  1103.   echo 'restore of save.c failed'
  1104.   shar_count="`wc -c < 'save.c'`"
  1105.   test 5346 -eq "$shar_count" ||
  1106.     echo "save.c: original size 5346, current size $shar_count"
  1107. fi
  1108. # ============= keys.c ==============
  1109. if test -f 'keys.c' && test X"$1" != X"-c"; then
  1110.   echo 'x - skipping keys.c (File already exists)'
  1111. else
  1112.   echo 'x - extracting keys.c (text)'
  1113.   sed 's/^X//' << 'SHAR_EOF' > 'keys.c' &&
  1114. /*
  1115. X *  Wander version 1.0, Copyright (C) 1994 G. Hutchings
  1116. X *  Wander comes with ABSOLUTELY NO WARRANTY.
  1117. X *  This is free software, and you are welcome to redistribute it
  1118. X *  under certain conditions; see the file COPYING for details.
  1119. X */
  1120. X
  1121. /* Keypress functions */
  1122. X
  1123. #if defined(BSDCURSES) || defined(SYSVR3)
  1124. #include <curses.h>
  1125. #else
  1126. #include <cursesX.h>
  1127. #endif
  1128. X
  1129. #include "defs.h"
  1130. X
  1131. /* VT100 cursor escape characters */
  1132. #define ARROW_PREFIX_1    '\033'
  1133. #define ARROW_PREFIX_2A    '['
  1134. #define ARROW_PREFIX_2B    'O'
  1135. #define ARROW_UP    'A'
  1136. #define ARROW_DOWN    'B'
  1137. #define ARROW_RIGHT    'C'
  1138. #define ARROW_LEFT    'D'
  1139. X
  1140. /* Return the value of a pressed key, dealing with cursor keys */
  1141. int
  1142. keypress()
  1143. {
  1144. X    int c;
  1145. X
  1146. X    switch ((c = getakey(1))) {
  1147. X    case ARROW_PREFIX_1:
  1148. X    switch ((c = getakey(1))) {
  1149. X    case ARROW_PREFIX_2A:
  1150. X    case ARROW_PREFIX_2B:
  1151. X        switch ((c = getakey(1))) {
  1152. X        case ARROW_UP:
  1153. X        return GONORTH;
  1154. X        case ARROW_DOWN:
  1155. X        return GOSOUTH;
  1156. X        case ARROW_RIGHT:
  1157. X        return GOEAST;
  1158. X        case ARROW_LEFT:
  1159. X        return GOWEST;
  1160. X        default:
  1161. X        return c;
  1162. X        }
  1163. X    default:
  1164. X        return c;
  1165. X    }
  1166. X    default:
  1167. X    return c;
  1168. X    }
  1169. X
  1170. X    /* NOTREACHED */
  1171. }
  1172. X
  1173. /* Return a pressed key */
  1174. int
  1175. getakey(int flag)
  1176. {
  1177. X    int c;
  1178. X
  1179. X    if (flag) nl();
  1180. #ifdef BSDCURSES
  1181. X    c = getchar();
  1182. #else
  1183. X    c = getch();
  1184. #endif
  1185. X    if (flag) nonl();
  1186. X
  1187. X    return c;
  1188. }
  1189. SHAR_EOF
  1190.   $shar_touch -am 0623155694 'keys.c' &&
  1191.   chmod 0444 'keys.c' ||
  1192.   echo 'restore of keys.c failed'
  1193.   shar_count="`wc -c < 'keys.c'`"
  1194.   test 1318 -eq "$shar_count" ||
  1195.     echo "keys.c: original size 1318, current size $shar_count"
  1196. fi
  1197. # ============= timer.c ==============
  1198. if test -f 'timer.c' && test X"$1" != X"-c"; then
  1199.   echo 'x - skipping timer.c (File already exists)'
  1200. else
  1201.   echo 'x - extracting timer.c (text)'
  1202.   sed 's/^X//' << 'SHAR_EOF' > 'timer.c' &&
  1203. /*
  1204. X *  Wander version 1.0, Copyright (C) 1994 G. Hutchings
  1205. X *  Wander comes with ABSOLUTELY NO WARRANTY.
  1206. X *  This is free software, and you are welcome to redistribute it
  1207. X *  under certain conditions; see the file COPYING for details.
  1208. X */
  1209. X
  1210. /* Timing functions */
  1211. X
  1212. #include <stdio.h>
  1213. #include <sys/time.h>
  1214. #include "defs.h"
  1215. X
  1216. #ifdef BSD42
  1217. #include <sys/timeb.h>
  1218. #endif
  1219. X
  1220. #ifdef SYSVR3
  1221. #include <sys/ioctl.h>
  1222. #endif
  1223. X
  1224. #ifdef XCURSES
  1225. #ifdef BSD42
  1226. #include <cursesX.h>
  1227. #else
  1228. #include <curses.h>
  1229. #endif
  1230. #endif
  1231. X
  1232. /* Wait a while */
  1233. void
  1234. freeze(double delay)
  1235. {
  1236. X    int sec = (int) delay;
  1237. X    int msec = (int) (1000 * (delay - sec));
  1238. X
  1239. X    /* If delay is a whole number of seconds, use sleep() */
  1240. X    if (msec < 5) {
  1241. X    sleep(sec);
  1242. X    } else if (msec > 995) {
  1243. X    sleep(sec + 1);
  1244. X    } else {
  1245. #ifdef BSDCURSES
  1246. #ifdef BSD42
  1247. X    /* Keep checking the time using ftime().  This should really */
  1248. X    /* use setitimer() but I couldn't get it to work properly for */
  1249. X    /* intervals less than a second. */
  1250. X
  1251. X    double now, future;
  1252. X    struct timeb tb;
  1253. X
  1254. X    ftime(&tb);
  1255. X    future = tb.time + ((double) tb.millitm) / 1000 + delay;
  1256. X
  1257. X    while (1) {
  1258. X        ftime(&tb);
  1259. X        now = tb.time + ((double) tb.millitm) / 1000;
  1260. X        if (now >= future)
  1261. X        return;
  1262. X    }
  1263. #else  /* SYSVR3 */
  1264. X    /* BSD curses and SYSV? Is this combination even possible? */
  1265. X
  1266. X    /* No ftime() - just sleep an integer no. */
  1267. X    /* of seconds (rounded down) */
  1268. X
  1269. X    sleep(sec);
  1270. #endif
  1271. #else  /* XCURSES */
  1272. X    sleep(sec);
  1273. X    napms(msec);
  1274. #endif
  1275. X    }
  1276. }
  1277. X
  1278. /*
  1279. X * Wait up to 'delay' microseconds for input to appear.
  1280. X * Returns 1 if input is ready, 0 otherwise.
  1281. X */
  1282. int
  1283. waitch(long delay)
  1284. {
  1285. #ifdef BSD42
  1286. X    int fdbits;
  1287. X    struct timeval duration;
  1288. X
  1289. X    duration.tv_sec = 0L;
  1290. X    duration.tv_usec = delay;
  1291. X    fdbits = 1;
  1292. X
  1293. X    return (select(32, &fdbits, 0, 0, &duration));
  1294. #else  /* BSD42 */
  1295. #ifdef SYSVR3
  1296. X    int nchars;
  1297. X
  1298. X    if (ioctl(fileno(stdin), FIONREAD, &nchars) < 0) {
  1299. X    perror("ioctl():");
  1300. X    exit(1);
  1301. X    }
  1302. X
  1303. X    return (nchars > 0);
  1304. #else  /* SYSVR3 */
  1305. X    return 0;
  1306. #endif
  1307. #endif
  1308. }
  1309. SHAR_EOF
  1310.   $shar_touch -am 0623155694 'timer.c' &&
  1311.   chmod 0444 'timer.c' ||
  1312.   echo 'restore of timer.c failed'
  1313.   shar_count="`wc -c < 'timer.c'`"
  1314.   test 1987 -eq "$shar_count" ||
  1315.     echo "timer.c: original size 1987, current size $shar_count"
  1316. fi
  1317. # ============= help.c ==============
  1318. if test -f 'help.c' && test X"$1" != X"-c"; then
  1319.   echo 'x - skipping help.c (File already exists)'
  1320. else
  1321.   echo 'x - extracting help.c (text)'
  1322.   sed 's/^X//' << 'SHAR_EOF' > 'help.c' &&
  1323. /*
  1324. X *  Wander version 1.0, Copyright (C) 1994 G. Hutchings
  1325. X *  Wander comes with ABSOLUTELY NO WARRANTY.
  1326. X *  This is free software, and you are welcome to redistribute it
  1327. X *  under certain conditions; see the file COPYING for details.
  1328. X */
  1329. X
  1330. /* Help functions */
  1331. X
  1332. #ifndef lint
  1333. static char rcsid[] = "$Id: help.c,v 1.7 1994/06/23 14:56:13 glen Exp $";
  1334. #endif
  1335. X
  1336. #if defined(BSDCURSES) || defined(SYSVR3)
  1337. #include <curses.h>
  1338. #else
  1339. #include <cursesX.h>
  1340. #endif
  1341. X
  1342. #include "defs.h"
  1343. #include "data.h"
  1344. #include "proto.h"
  1345. #include "config.h"
  1346. X
  1347. #define PAGESIZE    20    /* Max page size */
  1348. #define DELIM        "%%"    /* Page delimiter */
  1349. #define PROMPT        "Type 'q' to quit, any other key to continue: "
  1350. X
  1351. /* Display help file on screen */
  1352. static void
  1353. helpfile(char *file)
  1354. {
  1355. X    int dlen = strlen(DELIM);
  1356. X    int plen = strlen(PROMPT);
  1357. X    int pcol = (COLS-2-plen)/2;
  1358. X    int key, curline = 0;
  1359. X    char buf[BUFSIZ];
  1360. X    FILE *fp;
  1361. X
  1362. X    /* Get pathname of help file */
  1363. X    if (!wizard)
  1364. X    sprintf(buf, "%s/%s", LIBDIR, file);
  1365. X    else
  1366. X    strcpy(buf, file);
  1367. X
  1368. X    /* Open it */
  1369. X    if ((fp = fopen(buf, "r")) == NULL) {
  1370. X    message("Can't open %s", buf);
  1371. X    beep();
  1372. X    return;
  1373. X    }
  1374. X
  1375. X    /* Read and display file one page at a time */
  1376. X    erase();
  1377. X    while (fgets(buf, BUFSIZ, fp) != NULL) {
  1378. X    buf[strlen(buf)-1] = '\0'; /* Strip newline */
  1379. X    if (++curline == PAGESIZE || !strncmp(buf, DELIM, dlen)) {
  1380. X        move(LINES-1, pcol);
  1381. X        addstr(PROMPT);
  1382. X        move(LINES-1, pcol+plen);
  1383. X        refresh();
  1384. X
  1385. X        key = keypress();
  1386. X        switch (key) {
  1387. X        case 'q':
  1388. X        case 'Q':
  1389. X        fclose(fp);
  1390. X        return;
  1391. X        default:
  1392. X        curline = 0;
  1393. X        erase();
  1394. X        break;
  1395. X        }
  1396. X    } else {
  1397. X        move(curline, 0);
  1398. X        addstr(buf);
  1399. X    }
  1400. X    }
  1401. X
  1402. X    move(LINES-1, pcol);
  1403. X    addstr(PROMPT);
  1404. X    move(LINES-1, pcol+plen);
  1405. X    refresh();
  1406. X    key = keypress();
  1407. X
  1408. X    fclose(fp);
  1409. }
  1410. X
  1411. /* Give help on commands */
  1412. void
  1413. cmdinfo()
  1414. {
  1415. X    helpfile("cmds.help");
  1416. }
  1417. X
  1418. /* Give help on display items */
  1419. void
  1420. displayinfo()
  1421. {
  1422. X    helpfile(minidisplay ? "mini.help" : "full.help");
  1423. }
  1424. SHAR_EOF
  1425.   $shar_touch -am 0623155894 'help.c' &&
  1426.   chmod 0444 'help.c' ||
  1427.   echo 'restore of help.c failed'
  1428.   shar_count="`wc -c < 'help.c'`"
  1429.   test 1983 -eq "$shar_count" ||
  1430.     echo "help.c: original size 1983, current size $shar_count"
  1431. fi
  1432. # ============= will.c ==============
  1433. if test -f 'will.c' && test X"$1" != X"-c"; then
  1434.   echo 'x - skipping will.c (File already exists)'
  1435. else
  1436.   echo 'x - extracting will.c (text)'
  1437.   sed 's/^X//' << 'SHAR_EOF' > 'will.c' &&
  1438. /*
  1439. X *  Wander version 1.0, Copyright (C) 1994 G. Hutchings
  1440. X *  Wander comes with ABSOLUTELY NO WARRANTY.
  1441. X *  This is free software, and you are welcome to redistribute it
  1442. X *  under certain conditions; see the file COPYING for details.
  1443. X */
  1444. X
  1445. /* Humorous Shakespeare insult generator nicked from the net */
  1446. /* Use it in your own programs for added user-friendliness!  8-) */
  1447. X
  1448. #ifndef lint
  1449. static char rcsid[] = "$Id: will.c,v 1.3 1994/06/02 08:20:05 glen Exp $";
  1450. #endif
  1451. X
  1452. #include <stdio.h>
  1453. #include <stdlib.h>
  1454. #include "config.h"
  1455. X
  1456. #define VECLEN(vec) (sizeof(vec)/sizeof(char *))
  1457. X
  1458. static char *adjv1[] = {
  1459. X    "artless", "bawdy", "beslubbering", "bootless", "churlish",
  1460. X    "cockered", "clouted", "craven", "currish", "dankish",
  1461. X    "dissembling", "droning", "errant", "fawning", "fobbing",
  1462. X    "froward", "frothy", "gleeking", "goatish", "gorbellied",
  1463. X    "impertinent", "infectious", "jarring", "loggerheaded", "lumpish",
  1464. X    "mammering", "mangled", "mewling", "paunchy", "pribbling",
  1465. X    "puking", "puny", "quailing", "rank", "reeky", "roguish",
  1466. X    "ruttish", "saucy", "spleeny", "spongy", "surly", "tottering",
  1467. X    "unmuzzled", "vain", "venomed", "villainous", "warped", "wayward",
  1468. X    "weedy", "yeasty",
  1469. };
  1470. X
  1471. static char *adjv2[] = {
  1472. X    "base-court", "bat-fowling", "beef-witted", "beetle-headed",
  1473. X    "boil-brained", "clapper-clawed", "clay-brained",
  1474. X    "common-kissing", "crook-pated", "dismal-dreaming", "dizzy-eyed",
  1475. X    "doghearted", "dread-bolted", "earth-vexing", "elf-skinned",
  1476. X    "fat-kidneyed", "fen-sucked", "flap-mouthed", "fly-bitten",
  1477. X    "folly-fallen", "fool-born", "full-gorged", "guts-griping",
  1478. X    "half-faced", "hasty-witted", "hedge-born", "hell-hated",
  1479. X    "idle-headed", "ill-breeding", "ill-nurtured", "knotty-pated",
  1480. X    "milk-livered", "motley-minded", "onion-eyed", "plume-plucked",
  1481. X    "pottle-deep", "pox-marked", "reeling-ripe", "rough-hewn",
  1482. X    "rude-growing", "rump-fed", "shard-borne", "sheep-biting",
  1483. X    "spur-galled", "swag-bellied", "tardy-gaited", "tickle-brained",
  1484. X    "toad-spotted", "unchin-snouted", "weather-bitten",
  1485. };
  1486. X
  1487. static char *nounv[] = {
  1488. X    "apple-john", "baggage", "barnacle", "bladder", "boar-pig",
  1489. X    "bugbear", "bum-bailey", "canker-blossom", "clack-dish",
  1490. X    "clotpole", "coxcomb", "codpiece", "death-token", "dewberry",
  1491. X    "flap-dragon", "flax-wench", "flirt-gill", "foot-licker",
  1492. X    "fustilarian", "giglet", "gudgeon", "haggard", "harpy",
  1493. X    "hedge-pig", "horn-beast", "hugger-mugger", "jolthead",
  1494. X    "lewdster", "lout", "maggot-pie", "malt-worm", "mammet", "measle",
  1495. X    "minnow", "miscreant", "moldwarp", "mumble-news", "nut-hook",
  1496. X    "pigeon-egg", "pignut", "puttock", "pumpion", "ratsbane", "scut",
  1497. X    "skainsmate", "strumpet", "varlot", "vassal", "whey-face",
  1498. X    "wagtail"
  1499. };
  1500. X
  1501. static char *
  1502. word(char *list[], int len)
  1503. {
  1504. X    return list[RANDOM(len)];
  1505. }
  1506. X
  1507. char *
  1508. willie_phrase(void)
  1509. {
  1510. X    static char buf[BUFSIZ];
  1511. X
  1512. X    char *adj1 = word(adjv1, VECLEN(adjv1));
  1513. X    char *adj2 = word(adjv2, VECLEN(adjv2));
  1514. X    char *noun = word(nounv, VECLEN(nounv));
  1515. X
  1516. X    sprintf(buf, "%s %s %s", adj1, adj2, noun);
  1517. X    return buf;
  1518. }
  1519. SHAR_EOF
  1520.   $shar_touch -am 0602092194 'will.c' &&
  1521.   chmod 0444 'will.c' ||
  1522.   echo 'restore of will.c failed'
  1523.   shar_count="`wc -c < 'will.c'`"
  1524.   test 3094 -eq "$shar_count" ||
  1525.     echo "will.c: original size 3094, current size $shar_count"
  1526. fi
  1527. # ============= misc.c ==============
  1528. if test -f 'misc.c' && test X"$1" != X"-c"; then
  1529.   echo 'x - skipping misc.c (File already exists)'
  1530. else
  1531.   echo 'x - extracting misc.c (text)'
  1532.   sed 's/^X//' << 'SHAR_EOF' > 'misc.c' &&
  1533. /*
  1534. X *  Wander version 1.0, Copyright (C) 1994 G. Hutchings
  1535. X *  Wander comes with ABSOLUTELY NO WARRANTY.
  1536. X *  This is free software, and you are welcome to redistribute it
  1537. X *  under certain conditions; see the file COPYING for details.
  1538. X */
  1539. X
  1540. /* Miscellaneous functions */
  1541. X
  1542. #ifndef lint
  1543. static char rcsid[] = "$Id: misc.c,v 1.7 1994/06/29 14:27:42 glen Exp $";
  1544. #endif
  1545. X
  1546. #include <stdio.h>
  1547. #include <unistd.h>
  1548. #include <sys/types.h>
  1549. #include <sys/stat.h>
  1550. #include <fcntl.h>
  1551. #include "defs.h"
  1552. #include "data.h"
  1553. #include "proto.h"
  1554. #include "config.h"
  1555. X
  1556. #define LOCKMODE    0666    /* Lock file permissions */
  1557. #define WAITTIME    0.5    /* Time between lock checks (sec) */
  1558. #define WAITCOUNT    10    /* Lock checks done before giving up */
  1559. X
  1560. /* Return the pathname of the score file */
  1561. char *
  1562. scorefile()
  1563. {
  1564. X    static char buf[BUFSIZ];
  1565. X
  1566. X    if (!wizard)
  1567. X    sprintf(buf, "%s/scores", LIBDIR);
  1568. X    else
  1569. X    strcpy(buf, "scores");
  1570. X    return buf;
  1571. }
  1572. X
  1573. /* Return pathname of the lock file */
  1574. static char *
  1575. lockfile()
  1576. {
  1577. X    static char buf[BUFSIZ];
  1578. X
  1579. X    if (!wizard)
  1580. X    sprintf(buf, "%s/lock", LIBDIR);
  1581. X    else
  1582. X    strcpy(buf, "lock");
  1583. X    return buf;
  1584. }
  1585. X
  1586. /* Return whether the score file is locked */
  1587. static int
  1588. scoreslocked()
  1589. {
  1590. X    struct stat statbuf;
  1591. X    char *path = lockfile();
  1592. X
  1593. X    return (!stat(path, &statbuf));
  1594. }
  1595. X
  1596. /* Lock the score file if possible */
  1597. int
  1598. lockscores()
  1599. {
  1600. X    int waitcount = 0, msg = 0;
  1601. X
  1602. X    while (scoreslocked()) {
  1603. X    if (!msg) {
  1604. X        message("Locking score file...");
  1605. X        drawpos(curpos);
  1606. X        msg = 1;
  1607. X    }
  1608. X
  1609. X    freeze(WAITTIME);
  1610. X
  1611. X    if (waitcount++ == WAITCOUNT) {
  1612. X        message("Lock file is stuck - go and moan at %s", WIZARD);
  1613. X        drawpos(curpos);
  1614. X        freeze(2.0);
  1615. X        return 0;
  1616. X    }
  1617. X    }
  1618. X
  1619. X    creat(lockfile(), LOCKMODE);
  1620. X    return 1;
  1621. }
  1622. X
  1623. /* Unlock the score file */
  1624. void
  1625. unlockscores()
  1626. {
  1627. X    char *path = lockfile();
  1628. X
  1629. X    unlink(path);
  1630. }
  1631. X
  1632. /* Return the pathname of a level file */
  1633. char *
  1634. levelpath(int num)
  1635. {
  1636. X    static char buf[BUFSIZ];
  1637. X
  1638. X    if (!wizard)
  1639. X    sprintf(buf, "%s/screens/screen.%d", LIBDIR, num);
  1640. X    else
  1641. X    sprintf(buf, "screens/screen.%d", num);
  1642. X    return buf;
  1643. }
  1644. X
  1645. /* Return the pathname of a solution file */
  1646. char *
  1647. solpath(int num)
  1648. {
  1649. X    static char buf[BUFSIZ];
  1650. X
  1651. X    if (!wizard)
  1652. X    sprintf(buf, "%s/sol/sol.%d", LIBDIR, num);
  1653. X    else
  1654. X    sprintf(buf, "sol/sol.%d", num);
  1655. X    return buf;
  1656. }
  1657. X
  1658. /* Return whether a level number is valid */
  1659. int
  1660. validlevel(int num)
  1661. {
  1662. X    struct stat statbuf;
  1663. X    char *path = levelpath(num);
  1664. X
  1665. X    return (!stat(path, &statbuf));
  1666. }
  1667. X
  1668. /* Return whether a level solution exists */
  1669. int
  1670. solexists(int num)
  1671. {
  1672. X    struct stat statbuf;
  1673. X    char *path = solpath(num);
  1674. X
  1675. X    return (!stat(path, &statbuf));
  1676. }
  1677. X
  1678. /* Return the number of available levels to play */
  1679. int
  1680. numlevels()
  1681. {
  1682. X    int num = 1;
  1683. X
  1684. X    while (validlevel(num)) num++;
  1685. X
  1686. X    return num-1;
  1687. }
  1688. X
  1689. /* Return user ID of the player */
  1690. int
  1691. userid()
  1692. {
  1693. X    return (int) getuid();
  1694. }
  1695. SHAR_EOF
  1696.   $shar_touch -am 0629152894 'misc.c' &&
  1697.   chmod 0444 'misc.c' ||
  1698.   echo 'restore of misc.c failed'
  1699.   shar_count="`wc -c < 'misc.c'`"
  1700.   test 2846 -eq "$shar_count" ||
  1701.     echo "misc.c: original size 2846, current size $shar_count"
  1702. fi
  1703. # ============= defs.h ==============
  1704. if test -f 'defs.h' && test X"$1" != X"-c"; then
  1705.   echo 'x - skipping defs.h (File already exists)'
  1706. else
  1707.   echo 'x - extracting defs.h (text)'
  1708.   sed 's/^X//' << 'SHAR_EOF' > 'defs.h' &&
  1709. /*
  1710. X *  Wander version 1.0, Copyright (C) 1994 G. Hutchings
  1711. X *  Wander comes with ABSOLUTELY NO WARRANTY.
  1712. X *  This is free software, and you are welcome to redistribute it
  1713. X *  under certain conditions; see the file COPYING for details.
  1714. X */
  1715. X
  1716. /* Player movement commands */
  1717. #define GONORTH        'k'
  1718. #define GOSOUTH        'j'
  1719. #define GOEAST        'l'
  1720. #define GOWEST        'h'
  1721. X
  1722. /* Other player commands */
  1723. #define RECENTRE    'r'
  1724. #define REDRAW        ' '
  1725. #define STAYPUT        ' '
  1726. #define RESTART        's'
  1727. #define TOGGLEWIN    'w'
  1728. #define SAVE        'S'
  1729. #define RESTORE        'R'
  1730. #define NEXTLEVEL    'N'
  1731. #define SOLUTION    'H'
  1732. #define CMDHELP        '?'
  1733. #define DISPHELP    '/'
  1734. #define QUIT        'q'
  1735. X
  1736. /* Wizard commands */
  1737. #define JUMPLEVEL    'L'
  1738. #define FORWARD        '+'
  1739. #define BACKWARD    '-'
  1740. #define FIRSTPOS    '<'
  1741. #define LASTPOS        '>'
  1742. X
  1743. /* Screen dimensions */
  1744. #define MINWIDTH    10
  1745. #define MINHEIGHT    10
  1746. #define MAXWIDTH    60
  1747. #define MAXHEIGHT    20
  1748. #define WINLINES    8
  1749. #define WINCOLS        18
  1750. X
  1751. /* Extra moves gained by eating time capsule */
  1752. #define CAPSULEMOVES    250
  1753. X
  1754. /* Special effects */
  1755. enum {
  1756. X    APPEAR, BLOWNUP, CAUGHT, EATEN, GAVEUP, SHOT, SQUASHED, TIMEUP,
  1757. X    VANISH, WINNER,
  1758. };
  1759. X
  1760. /* Enums here must be in the same order as the entries in the */
  1761. /* obj[] array */
  1762. enum {
  1763. X    ARRIVE, BABY, BABYNORTH, BABYEAST, BABYSOUTH, BABYWEST, BLANK,
  1764. X    BOULDER, CAGE, CAPSULE, EARTH, EXIT, FILLER, LANDMINE, LARROW,
  1765. X    LSLOPE, MONSTER, PLAYER, RARROW, ROCK1, ROCK2, ROCKET, RSLOPE,
  1766. X    TELEPORT, TREASURE,
  1767. };
  1768. X
  1769. /* Order here determines baby monster movement (left-hand rule) */
  1770. enum {
  1771. X    NONE = -1, NORTH, EAST, SOUTH, WEST,
  1772. };
  1773. X
  1774. struct object {
  1775. X    int type;            /* Symbol type */
  1776. X    int sym;            /* Symbol */
  1777. X    char *bigsym[2];        /* Large symbol */
  1778. X    int movedir;        /* Direction it moves */
  1779. X    int movepri;        /* Movement priority */
  1780. X    int bold;            /* Display it in bold? */
  1781. X    int kill;            /* Kills you if you touch it? */
  1782. X    int block;            /* Blocks your move? */
  1783. X    int push;            /* Can you push it? */
  1784. X    int sloped;            /* Will things roll off it? */
  1785. X    int eat;            /* Can you eat it? */
  1786. X    int score;            /* Score if you eat it */
  1787. };
  1788. X
  1789. struct monster {
  1790. X    int line, col;        /* Position */
  1791. X    int type;            /* Monster type */
  1792. X    int heading;        /* Direction last moved in */
  1793. X    int under;            /* Symbol type underneath it */
  1794. X    int dead;            /* Is it dead? */
  1795. X    struct monster *next;    /* Next nasty in list */
  1796. };
  1797. X
  1798. struct pos {
  1799. X    int **data;            /* Screen layout */
  1800. X    int pline, pcol;        /* Where you are */
  1801. X    struct monster *ml;        /* List of monsters */
  1802. X    int score;            /* Score for this screen */
  1803. X    int diamonds;        /* No. of diamonds left */
  1804. X    int monsters;        /* No. of monsters left */
  1805. X    int nmoves;            /* No. of moves left */
  1806. X    int dead;            /* Are you dead? */
  1807. X    int dir;            /* Direction moved to get here */
  1808. X    struct pos *prev, *next;    /* Links */
  1809. };
  1810. X
  1811. struct loc {
  1812. X    int line, col;        /* Position */
  1813. X    int type;            /* What symbol it is */
  1814. };
  1815. X
  1816. struct slope {
  1817. X    int lsdir, rsdir;        /* Left/right slope directions */
  1818. };
  1819. X
  1820. struct dir {
  1821. X    int line, col;        /* Line/column offset */
  1822. };
  1823. SHAR_EOF
  1824.   $shar_touch -am 0629135094 'defs.h' &&
  1825.   chmod 0444 'defs.h' ||
  1826.   echo 'restore of defs.h failed'
  1827.   shar_count="`wc -c < 'defs.h'`"
  1828.   test 2998 -eq "$shar_count" ||
  1829.     echo "defs.h: original size 2998, current size $shar_count"
  1830. fi
  1831. # ============= data.h ==============
  1832. if test -f 'data.h' && test X"$1" != X"-c"; then
  1833.   echo 'x - skipping data.h (File already exists)'
  1834. else
  1835.   echo 'x - extracting data.h (text)'
  1836.   sed 's/^X//' << 'SHAR_EOF' > 'data.h' &&
  1837. /*
  1838. X *  Wander version 1.0, Copyright (C) 1994 G. Hutchings
  1839. X *  Wander comes with ABSOLUTELY NO WARRANTY.
  1840. X *  This is free software, and you are welcome to redistribute it
  1841. X *  under certain conditions; see the file COPYING for details.
  1842. X */
  1843. X
  1844. /* Global data declarations */
  1845. X
  1846. #ifdef MAIN
  1847. X
  1848. /* 
  1849. X * Object type flags
  1850. X * 
  1851. X *    1    Direction it moves in (if it moves)
  1852. X *    2    Movement priority (if it moves)
  1853. X *    3    Whether to display it in bold (if possible)
  1854. X *    4    Does it kill you if you touch it?
  1855. X *    5    Does it block your move?
  1856. X *    6    Can you push it?
  1857. X *    7    Will things roll off it?
  1858. X *    8    Can you eat it?
  1859. X *    9    Score if you eat or kill it
  1860. X */
  1861. struct object obj[] = {             /*   1     2  3  4  5  6  7  8  9 */
  1862. X    ARRIVE,    'A',    "   ",    "   ",    NONE,    0, 0, 0, 0, 0, 0, 0, 0,
  1863. X    BABY,    'B',    "-o-",    "/*\\",    NONE,    0, 0, 1, 0, 0, 0, 0, 50,
  1864. X    BABYNORTH,    'N',    "   ",    "   ",    NONE,    0, 0, 0, 0, 0, 0, 0, 0,
  1865. X    BABYEAST,    'E',    "   ",    "   ",    NONE,    0, 0, 0, 0, 0, 0, 0, 0,
  1866. X    BABYSOUTH,    'S',    "   ",    "   ",    NONE,    0, 0, 0, 0, 0, 0, 0, 0,
  1867. X    BABYWEST,    'W',    "   ",    "   ",    NONE,    0, 0, 0, 0, 0, 0, 0, 0,
  1868. X    BLANK,    ' ',    "   ",    "   ",    NONE,    0, 0, 0, 0, 0, 0, 0, 0,
  1869. X    BOULDER,    'O',    "/^\\",    "\\_/",    SOUTH,    1, 0, 0, 0, 1, 1, 0, 0,
  1870. X    CAGE,    '+',    "TTT",    "III",    NONE,    0, 0, 0, 1, 0, 0, 0, 0,
  1871. X    CAPSULE,    'C',    "   ",    "<O>",    NONE,    0, 1, 0, 0, 0, 0, 1, 5,
  1872. X    EARTH,    ':',    ". .",    " . ",    NONE,    0, 0, 0, 0, 0, 0, 1, 1,
  1873. X    EXIT,    'X',    "Way",    "Out",    NONE,    0, 1, 0, 0, 0, 0, 1, 250,
  1874. X    FILLER,    '-',    "   ",    "   ",    NONE,    0, 0, 0, 0, 0, 0, 0, 0,
  1875. X    LANDMINE,    '!',    " I ",    " o ",    NONE,    0, 0, 1, 0, 0, 0, 0, 0,
  1876. X    LARROW,    '<',    "<--",    "<--",    WEST,    3, 0, 0, 0, 1, 0, 0, 0,
  1877. X    LSLOPE,    '\\',    "\\_ ",    "  \\",    NONE,    0, 0, 0, 1, 0, 1, 0, 0,
  1878. X    MONSTER,    'M',    "}o{",    "/^\\",    NONE,    0, 0, 1, 0, 0, 0, 0, 100,
  1879. X    PLAYER,    '@',    " o ",    "<|>",    NONE,    0, 0, 0, 0, 0, 0, 0, 0,
  1880. X    RARROW,    '>',    "-->",    "-->",    EAST,    3, 0, 0, 0, 1, 0, 0, 0,
  1881. X    ROCK1,    '#',    "###",    "###",    NONE,    0, 0, 0, 1, 0, 0, 0, 0,
  1882. X    ROCK2,    '=',    "-=-",    "=-=",    NONE,    0, 0, 0, 1, 0, 0, 0, 0,
  1883. X    ROCKET,    '^',    " ^ ",    "/^\\",    NORTH,    2, 0, 0, 0, 1, 1, 0, 0,
  1884. X    RSLOPE,    '/',    " _/",    "/  ",    NONE,    0, 0, 0, 1, 0, 1, 0, 0,
  1885. X    TELEPORT,    'T',    "(*)",    "(*)",    NONE,    0, 1, 0, 0, 0, 0, 1, 50,
  1886. X    TREASURE,    '*',    "/$\\",    "\\$/",    NONE,    0, 1, 0, 0, 0, 0, 1, 10,
  1887. };
  1888. X
  1889. /* Order corresponds to order of direction enums */
  1890. struct dir dirs[] = {
  1891. X    { -1, 0 }, { 0, 1 }, { 1, 0}, { 0, -1 },
  1892. };
  1893. X
  1894. /* Order corresponds to order of direction enums */
  1895. struct slope slopes[] = {
  1896. X    WEST,    EAST,
  1897. X    SOUTH,    NORTH,
  1898. X    EAST,    WEST,
  1899. X    NORTH,    SOUTH,
  1900. };
  1901. X
  1902. int numobj = sizeof(obj)/sizeof(obj[0]); /* No. of object types */
  1903. int numdir = sizeof(dirs)/sizeof(dirs[0]); /* No. of directions */
  1904. X
  1905. int bordersize = 1;        /* Distance to screen edge before scrolling */
  1906. int donelevel;            /* Whether you've already done this level */
  1907. int redrawscreen = 1;        /* Whether to update screen when replaying */
  1908. int exited;            /* Whether current level is finished */
  1909. int minidisplay = 0;        /* Whether to display whole level */
  1910. int hidescore = 0;        /* Whether to hide score on main table */
  1911. int level;            /* Current level */
  1912. int maxlevel;            /* Biggest level reached so far */
  1913. int myuid;            /* Player's UID */
  1914. int nlevels;            /* No. of levels available */
  1915. int nlines, ncols;        /* Screen dimensions */
  1916. int screeninit = 0;        /* Whether screen initialized */
  1917. int testlevel = 0;        /* Whether testing a level file */
  1918. int tline, tcol;        /* Teleport destination */
  1919. int wizard;            /* Whether in wizard mode */
  1920. int wline, wcol;        /* Your window position */
  1921. int xchars = 0;            /* Whether to use extended character set */
  1922. X
  1923. struct pos *firstpos = NULL;    /* Initial screen position */
  1924. struct pos *curpos;        /* Current screen position */
  1925. struct pos *lastpos = NULL;    /* Latest screen position */
  1926. X
  1927. #else
  1928. X
  1929. extern int nlines, ncols, tline, tcol, myuid, donelevel;
  1930. extern int wline, wcol, level, screeninit, maxlevel;
  1931. extern int minidisplay, numobj, exited, numdir, nlevels;
  1932. extern int maxlevel, wizard, redrawscreen, testlevel;
  1933. extern int bordersize, xchars, hidescore;
  1934. X
  1935. extern struct pos *firstpos, *curpos, *lastpos;
  1936. extern struct dir dirs[];
  1937. extern struct slope slopes[];
  1938. extern struct object obj[];
  1939. X
  1940. #endif
  1941. SHAR_EOF
  1942.   $shar_touch -am 0616155094 'data.h' &&
  1943.   chmod 0444 'data.h' ||
  1944.   echo 'restore of data.h failed'
  1945.   shar_count="`wc -c < 'data.h'`"
  1946.   test 4115 -eq "$shar_count" ||
  1947.     echo "data.h: original size 4115, current size $shar_count"
  1948. fi
  1949. : || echo 'restore of effect.h failed'
  1950. echo 'End of part 2, continue with part 3'
  1951. exit 0
  1952.