Rog-O-Matic XIV (part 02 of 10)
Michael Mauldin
mlm at cmu-cs-cad.ARPA
Sat Feb 2 04:33:28 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 02 of 10:'
echo 'x - explore.c'
sed 's/^X//' > explore.c << '/'
X/*
X * explore.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:14:30 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 are used to search out
X * paths to explore, pick up something, or run away.
X */
X
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
X# define SEARCHES(r,c) \
X (onrc(DEADEND,r,c) ? \
X ((version < RV53A || !isexplored (r,c)) ? \
X (timestosearch + k_door / 5) : \
X (timestosearch - k_door / 5 + 5)) : \
X timestosearch)
X
Xstatic int expDor, expavoidval;
Xstatic int avdmonsters[24][80];
X
Xint connect[9][4] = {
X /* Room top bot left right*/
X /* 0 */ {-1, 3, -1, 1},
X /* 1 */ {-1, 4, 0, 2},
X /* 2 */ {-1, 5, 1, -1},
X /* 3 */ { 0, 6, -1, 4},
X /* 4 */ { 1, 7, 3, 5},
X /* 5 */ { 2, 8, 4, -1},
X /* 6 */ { 3, -1, -1, 7},
X /* 7 */ { 4, -1, 6, 8},
X /* 8 */ { 5, -1, 7, -1}
X};
X
X/*
X * genericinit: Initialize a 'standard' movement search. MLM
X */
X
Xgenericinit ()
X{ expavoidval = avoid();
X return (1);
X}
X
X/* Secret door search values and continuance tables:
X *
X * Number of unsearched walls adjacent.
X *
X * Vert Horiz Value Cont Explanation
X * ---------------------------------------------------
X * 0 0 0 0 Valueless
X * 0 1 N-24-dep 16 Prefer (0,2) 1 move later
X * 0 2 N-22-dep 15 Prefer (0,3) 1 move later
X * 0 3 N-20-dep 14 Prefer (1,0) 10 moves later
X * 1 0 N-9-dep 4 Prefer (1,1) 2 moves later
X * 1 1 N-6-dep 2 Prefer (2,0) 1 move later
X * 1 2 N-5-dep 2 Prefer (2,0) 1 move later
X * 1 3 N-5-dep 2 Impossible
X * 2 0 N-3-dep 1 Prefer (3,0) 1 move later
X * 2 1 N-2-dep 0
X * 2 2 N-1-dep 0
X * 2 3 N-1-dep 0 Impossible
X * 3 0 N 0 Best possible
X * 3 1 N 0 Impossible
X * 3 2 N 0 Impossible
X * 3 3 N 0 Impossible
X */
X
X# define N 100
Xstatic int secretvalues[16]= { 0, N-24, N-22, N-20,
X N-9, N-6, N-5, N-5,
X N-3, N-2, N-1, N-1,
X N, N, N, N };
X
Xstatic int secretcont[16] = { 0, 16, 15, 14,
X 4, 2, 2, 2,
X 1, 0, 0, 0,
X 0, 0, 0, 0 };
X
X/*
X * gotowards: Move toward a square.
X */
X
Xint gotorow = NONE, gotocol = NONE;
X
Xgotowards (row, col, running)
Xint row, col, running;
X{ int gotoinit(), gotovalue();
X
X gotorow = row; gotocol = col;
X return (makemove (running ? RUNAWAY:GOTOMOVE, gotoinit, gotovalue, REUSE));
X}
X
X/*
X * gotoinit: Initialize a gotowards move.
X */
X
Xgotoinit ()
X{ expavoidval = avoid();
X return (1);
X}
X
X/*
X * gotovalue: Only the current target square has a value.
X */
X
Xgotovalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{
X *avd = onrc (SAFE, r, c) ? 0 :
X onrc (ARROW, r, c) ? 50 :
X onrc (TRAPDOR, r, c) ? 175 :
X onrc (TELTRAP, r, c) ? 50 :
X onrc (GASTRAP, r, c) ? 50 :
X onrc (BEARTRP, r, c) ? 50 :
X onrc (DARTRAP, r, c) ? 200 :
X onrc (WATERAP, r, c) ? 50 :
X onrc (MONSTER, r, c) ? 150 :
X expavoidval;
X
X if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X *avd += 200;
X
X *val = r == gotorow && c == gotocol ? 1 : 0;
X /* *cont = 0; // default value when called // */
X return (1);
X}
X
X/*
X * sleepvalue: Squares with sleeping monsters have value.
X * Use genericinit. MLM
X */
X
Xsleepvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{
X *avd = onrc (SAFE, r, c) ? 0 :
X onrc (ARROW, r, c) ? 50 :
X onrc (TRAPDOR, r, c) ? 175 :
X onrc (TELTRAP, r, c) ? 50 :
X onrc (GASTRAP, r, c) ? 50 :
X onrc (BEARTRP, r, c) ? 50 :
X onrc (DARTRAP, r, c) ? 200 :
X onrc (WATERAP, r, c) ? 50 :
X onrc (MONSTER, r, c) ? 150 :
X expavoidval;
X
X if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X *avd += 200;
X
X if (onrc (SLEEPER, r, c))
X { *val = 1;
X *avd = 0;
X /* *cont = 0; // default value when called // */
X }
X
X return (1);
X}
X
X/*
X * wallkind: given a row and column, determine which kind of wall if any
X * is there. Part of doorinit Guy Jacobson 5/82
X */
X
Xint wallkind (r, c)
Xint r, c;
X{
X switch (screen[r][c])
X { case '|': if (onrc (ROOM, r, c+1)) return (LEFTW);
X else return (RIGHTW);
X case '-': if (onrc (ROOM, r+1, c)) return (TOPW);
X else if (onrc (ROOM, r-1, c)) return (BOTW);
X else return (CORNERW);
X case '+': return (DOORW);
X default: return (NOTW);
X }
X}
X
X/*
X * setpsd: Initialize secret door search
X *
X * Guy Jacobson 5/82
X * Modified to allow searching even when there are cango bits. MLM. 10/82
X * Modified to reuse existing map while it is valid. LGCH. 10/82
X * Modified to understand maze room secret doors. MLM. 10/83
X */
X
Xsetpsd (print)
X{ register int i, j, k, whereto, numberpsd=0;
X
X if (!print && reusepsd > 0) return (reusepsd-1);
X
X /* find what rooms are missing */
X markmissingrooms ();
X
X /* Changed loop boundaries to ignore border around screen -- mlm 5/18/82 */
X for (i=2; i<22; i++) for (j=1; j<79; j++)
X { unsetrc (PSD|DEADEND,i,j);
X
X /* If attempt > 3, allow ANYTHING to be a secret door! */
X if (attempt > 3 && ! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) &&
X nextto (CANGO, i, j))
X { if (!onrc (PSD, i, j)) numberpsd++; setrc(PSD,i,j); }
X
X /* Set Possible Secret Door for maze room secret doors */
X else if (attempt > 0 && ! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) &&
X mazedoor (i, j))
X { if (!onrc (PSD, i, j)) numberpsd++; setrc(PSD,i,j); }
X
X /* Set Possible Secret Door for corridor secret door */
X else if (version >= RV53A &&
X ! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) &&
X nextto (DOOR, i, j))
X { if (!onrc (PSD, i, j)) numberpsd++; setrc(PSD,i,j); }
X
X /* Set Possible Secret Door for dead end corridors */
X else if (! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) &&
X (onrc (HALL, i-1, j) + onrc (HALL, i+1, j) +
X onrc (HALL, i, j-1) + onrc (HALL, i, j+1) == HALL) &&
X !(onrc(HALL|DOOR, i-1, j-1) || onrc(HALL|DOOR, i+1, j+1) ||
X onrc(HALL|DOOR, i-1, j+1) || onrc(HALL | DOOR, i+1, j-1)) &&
X canbedoor (i, j))
X { if (!onrc (PSD, i, j)) numberpsd++;
X setrc(DEADEND,i,j); setrc(PSD,i,j);
X }
X
X /* Set PSD for walls which connect to empty space */
X
X /* Modified to allow PSD for !ROOM (including the old CANGO des.) */
X /* since potions and scrolls of detection can cause the CANGO bit */
X /* to be set for a square on which we have never been. */
X /* mlm 10/8/82 */
X
X /* If attempt > 2, then relax the constraint about empty space, */
X /* since we might have teleported into a disconnected part of the */
X /* level. This means after we have searched twice, we look for */
X /* ANY possible door, not just doors leading to empty space. */
X /* mlm 10/11/82 */
X
X else
X { if ((k = wallkind (i,j)) >= 0)
X { /* A legit sort of wall */
X whereto = connect[whichroom (i,j)][k];
X if (whereto >= 0 && (attempt > 1 || room[whereto] == 0))
X { if (!onrc (PSD, i, j)) numberpsd++;
X setrc (PSD,i,j);
X }
X }
X }
X }
X
X /* Now remove PSD bits from walls which already have doors */
X for (i=2; i<22; i++) for (j=1; j<79; j++)
X { if (onrc (DOOR, i, j))
X { for (k = i-1; onrc (WALL, k, j); k--)
X { if (onrc (PSD, k, j)) numberpsd--; unsetrc (PSD, k, j);}
X for (k = i+1; onrc (WALL, k, j); k++)
X { if (onrc (PSD, k, j)) numberpsd--; unsetrc (PSD, k, j);}
X for (k = j-1; onrc (WALL, i, k); k--)
X { if (onrc (PSD, i, k)) numberpsd--; unsetrc (PSD, i, k);}
X for (k = j+1; onrc (WALL, i, k); k++)
X { if (onrc (PSD, i, k)) numberpsd--; unsetrc (PSD, i, k);}
X }
X }
X
X if (print || debug (D_SCREEN))
X for (i=0; i<24; i++) for (j=0; j<80; j++)
X if (onrc (PSD,i,j)) { at (i,j); addch ('P'); }
X
X reusepsd = numberpsd+1;
X return (numberpsd);
X}
X
X/*
X * downvalue: find nearest stairs or trapdoor (use genericinit for init).
X */
X
Xdownvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{
X *avd = onrc (SAFE, r, c) ? 0 :
X onrc (ARROW, r, c) ? 50 :
X onrc (TRAPDOR, r, c) ? 175 :
X onrc (TELTRAP, r, c) ? 50 :
X onrc (GASTRAP, r, c) ? 50 :
X onrc (BEARTRP, r, c) ? 50 :
X onrc (DARTRAP, r, c) ? 200 :
X onrc (WATERAP, r, c) ? 50 :
X onrc (MONSTER, r, c) ? 150 :
X expavoidval;
X
X if (onrc (STAIRS | TRAPDOR, r, c)) { *val = 1; *avd = 0; }
X else { *val = 0; }
X
X return (1);
X}
X
X/*
X * expruninit: same as expinit but don't bias against doors.
X */
X
Xexpruninit ()
X{ dwait (D_CONTROL | D_SEARCH, "expruninit called.");
X expinit();
X expDor = 0;
X avoidmonsters ();
X return (1);
X}
X
X/*
X * exprunvalue: When running, avoid monsters.
X *
X * Try to see a new square when running.
X */
X
Xexprunvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ if (r == atrow && c == atcol) /* Current square useless MLM */
X *val = 0;
X else if (onrc (MONSTER | TRAP, r, c)) /* Added TRAP useless MLM */
X *val = 0;
X else if (!zigzagvalue (r, c, depth, val, avd, cont))
X return (0);
X
X if (*val > 0) { *val = *val * 1000 + depth; *cont = INFINITY; }
X *avd += avdmonsters[r][c];
X return (1);
X}
X
X/*
X * expunpininit: same as exprunnit but try to unpin.
X */
X
Xexpunpininit ()
X{ dwait (D_CONTROL | D_SEARCH, "expunpininit called.");
X expinit();
X expDor = 0;
X pinavoid ();
X return (1);
X}
X
X/*
X * expunpinvalue: When unpinning, avoid monsters.
X *
X * Try to see a new square when unpinning, but unpin anywhere if need be.
X */
X
Xexpunpinvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ if (r == atrow && c == atcol) /* Current square useless MLM */
X *val = 0;
X else if (onrc (MONSTER | TRAP, r, c)) /* Added TRAP useless MLM */
X *val = 0;
X else if (!zigzagvalue (r, c, depth, val, avd, cont))
X return (0);
X
X if (*val > 0) { *val = *val * 1000 + depth; *cont = INFINITY; }
X *avd += avdmonsters[r][c];
X return (1);
X}
X
X/*
X * runinit: R U N A W A Y S E A R C H
X */
X
Xruninit ()
X{ avoidmonsters();
X return (1);
X}
X
X/*
X * runvalue:
X *
X * Evaluate square for running away. Targets, in priority order are:
X *
X * STAIRS TRAPDOR TELTRAP
X * RUNOK (cycle door)
X * DOOR
X * ANYWHERE
X *
X * Traps are avoided for a variable number of moves, except for target traps
X * Gave GasTraps and BearTraps infinite avoidance. MLM 10/11/83
X */
X
Xrunvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ *avd = onrc (ARROW, r, c) ? 50 :
X onrc (TRAPDOR, r, c) ? 0 :
X onrc (TELTRAP, r, c) ? 0 :
X onrc (GASTRAP, r, c) ? INFINITY :
X onrc (BEARTRP, r, c) ? INFINITY :
X onrc (DARTRAP, r, c) ? 100 :
X onrc (WATERAP, r, c) ? 100 :
X onrc (MONSTER, r, c) ? 150 :
X 0;
X
X if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X *avd += 200;
X
X if (onrc (MONSTER, r, c))
X { *val = 0; }
X if (onrc (STAIRS+TRAPDOR+TELTRAP, r, c))
X { *val = 5000; *avd = 0; /* *cont = 0; */ }
X else if (r == atrow && c == atcol) /* If we are running, our current */
X { *val = 0;} /* cant be that great -- MLM */
X else if (onrc (RUNOK, r, c))
X { *val = 4000; *cont = INFINITY;}
X else if (onrc (DOOR | BEEN, r, c) == DOOR)
X { *val = 2000+depth; *cont = INFINITY;}
X else if (onrc (DOOR, r, c))
X { *val = 1000+depth; *cont = INFINITY;}
X else if (onrc (HALL, r, c))
X { *val = depth; *cont = INFINITY;}
X /* ----------------------------------------------------------------
X else if (onrc (CANGO | TRAP, r, c) == CANGO)
X { *val = 1+depth; *cont = INFINITY;}
X ---------------------------------------------------------------- */
X else
X { *val = 0; }
X
X *avd += avdmonsters[r][c];
X}
X
X/*
X * unpininit: U N P I N S E A R C H
X *
X * Same as runint, but we are willing to take one hit to get away.
X */
X
Xunpininit ()
X{ pinavoid();
X return (1);
X}
X
X/*
X * rundoorinit: Standard initialization routine.
X */
X
Xrundoorinit()
X{ avoidmonsters();
X return (1);
X}
X
X/*
X * rundoorvalue:
X *
X * Evaluate square for running into doorway.
X *
X * Targets, in priority order are:
X *
X * RUNOK (cycle door)
X * DOOR
X *
X * Traps are avoided for a variable number of moves, except for target traps
X * Gave GasTraps and BearTraps infinite avoidance. MLM 10/11/83
X */
X
Xrundoorvalue (r, c, depth, val, avd, cont)
Xint r, c, depth;
Xint *val, *avd, *cont;
X{ *avd = onrc (ARROW, r, c) ? 50 :
X onrc (TRAPDOR, r, c) ? 0 :
X onrc (TELTRAP, r, c) ? 0 :
X onrc (GASTRAP, r, c) ? INFINITY :
X onrc (BEARTRP, r, c) ? INFINITY :
X onrc (DARTRAP, r, c) ? 100 :
X onrc (WATERAP, r, c) ? 100 :
X onrc (MONSTER, r, c) ? 50 : 0;
X
X if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X *avd += 200;
X
X if (onrc (RUNOK, r, c)) { *val = 2;}
X else if (onrc (DOOR, r, c)) { *val = 1; *cont = INFINITY;}
X else { *val = 0;}
X
X *avd += avdmonsters[r][c];
X}
X
X/*
X * E X P L O R A T I O N S E A R C H
X */
X
Xexpinit ()
X{ /* avoidance values for doors */
X expDor = 0;
X expavoidval = avoid();
X return (1);
X}
X
Xroominit ()
X{ expinit ();
X expDor = INFINITY;
X return (1);
X}
X
X/*
X * expvalue: evaluation function for exploration. LGCH
X *
X * In order to prevent leaving orphan unseen squares, we have heuritics
X * which cause rogomatic to use the three-step pattern to scan along the
X * boundary of a room, and also have tests which detect any orphans (e.g.
X * corners and when an object interrupts the search pattern) and cause them
X * to be seen.
X *
X * Three-step pattern:
X *
X * @@ @@
X * @ @ @
X * bbbbbbbbb
X */
X
Xexpvalue (r, c, depth, val, avd, cont)
Xint r, c, depth;
Xint *val, *avd, *cont;
X{ register int k, nr, nc, l;
X int a, v = 0, nunseenb = 0, nseenb = 0, nearb = 0;
X
X a = onrc (SAFE|DOOR|STAIRS|HALL, r, c) ? 0 :
X onrc (ARROW, r, c) ? 50 :
X onrc (TRAPDOR, r, c) ? 300 :
X onrc (TELTRAP, r, c) ? 100 :
X onrc (GASTRAP, r, c) ? 50 :
X onrc (BEARTRP, r, c) ? 50 :
X onrc (DARTRAP, r, c) ? 200 :
X onrc (TRAP, r, c) ? 100 :
X onrc (MONSTER, r, c) ? 150 :
X expavoidval;
X
X if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X { *avd = a+1000; *val=0; return (1); }
X
X if (onrc (BEEN+SEEN, r, c) == SEEN) /* If been or not seen, not a target */
X { for (k=0; k<8; k++)
X { nr = r + deltr[k];
X nc = c + deltc[k];
X
X /* For each unseen neighbour: add 10 to value. */
X if (nr >= 1 && nr <= 22 && nc >= 0 && nc <= 80 &&
X !onrc (SEEN, nr, nc))
X { v += 10;
X
X if (onrc (BOUNDARY, nr, nc))
X { /* Count unseen boundary neighbours. */
X nunseenb++;
X
X /* Count seen boundaries horiz/vert adjacent to unseen boundary */
X for (l=0; l<8; l+=2)
X if (onrc (SEEN+BOUNDARY, nr+deltr[l], nc+deltc[l]) ==
X SEEN+BOUNDARY)
X nseenb++;
X
X }
X else
X { /* Check for unseen boundary horiz/vert */
X /* adjacent to neighbour and not a neighbour. */
X l = k / 2 * 2; /* horizontal/vertical */
X if (onrc (BOUNDARY+SEEN, nr+deltr[l], nc+deltc[l]) == BOUNDARY)
X nearb = 1;
X else
X { l = ((k+1) / 2 * 2) % 8;
X if (onrc (BOUNDARY+SEEN, nr+deltr[l], nc+deltc[l]) == BOUNDARY)
X nearb = 1;
X }
X }
X }
X }
X
X /* To zig-zag: add number of unseen boundary neighbours * 6 */
X v += nunseenb * 6;
X
X /* To do the three-step: add 29 if an unseen neighbour had an unseen
X * boundary horiz/vert adjacent */
X if (nearb)
X v += 29;
X
X /* To prevent orphans: if three unseen neighbours are boundary and one
X * has a seen boundary horiz/vert adjacent, add 200 */
X if (nunseenb >= 3 && nseenb >= 1)
X v += 200;
X
X /* To clean up any orphans: if two seen boundaries are adjacent to any
X * unseen boundary neighbours, add 400. */
X if (nseenb >= 2)
X v += 400;
X }
X
X if (onrc (DOOR, r, c))
X a += expDor;
X /* else if (onrc (BEEN+BOUNDARY, r, c) == BOUNDARY)
X a++; // Avoid running along the untrodden boundary. // */
X
X *avd = a;
X *val = v;
X if (v < 50)
X *cont = 4; /* Look for something better */
X if (debug (D_SCREEN) && v > 0)
X { mvaddch (r, c, 'o'); dwait (D_SCREEN, "Value %d", v); }
X
X return (1);
X}
X
X/*
X * zigzagvalue: evaluation function for exploration. LGCH
X *
X * This is a copy of expvalue with the three-step code and the code to
X * detect orphans removed. It is used when running away and unpinning
X * to find a useful exploration move. The boundary moves must zig-zag
X * rather than three-step so that the door can be entered when it is seen
X * without taking a hit from the monster chasing us.
X *
X * Gave GasTraps and BearTraps infinite avoidance. MLM 10/11/83
X */
X
Xzigzagvalue (r, c, depth, val, avd, cont)
Xint r, c, depth;
Xint *val, *avd, *cont;
X{ register int k, nr, nc, l;
X int a, v = 0, nunseenb = 0, nseenb = 0, nearb = 0;
X
X a = onrc (SAFE|DOOR|STAIRS|HALL, r, c) ? 0 :
X onrc (ARROW, r, c) ? 50 :
X onrc (TRAPDOR, r, c) ? 300 :
X onrc (TELTRAP, r, c) ? 100 :
X onrc (GASTRAP, r, c) ? 50 :
X onrc (BEARTRP, r, c) ? 50 :
X onrc (DARTRAP, r, c) ? 200 :
X onrc (TRAP, r, c) ? 100 :
X onrc (MONSTER, r, c) ? 150 :
X expavoidval;
X
X if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X { *avd = a+1000; *val=0; return (1); }
X
X if (onrc (BEEN+SEEN, r, c) == SEEN) /* If been or not seen, not a target */
X { for (k=0; k<8; k++)
X { nr = r + deltr[k];
X nc = c + deltc[k];
X
X /* For each unseen neighbour: add 10 to value. */
X if (nr >= 1 && nr <= 22 && nc >= 0 && nc <= 80 &&
X !onrc (SEEN, nr, nc))
X { v += 10;
X
X if (onrc (BOUNDARY, nr, nc))
X { /* Count unseen boundary neighbours. */
X nunseenb++;
X }
X if (debug (D_SCREEN)) mvaddch (nr, nc, 'o');
X }
X }
X
X /* To zig-zag: add number of unseen boundary neighbours * 6 */
X v += nunseenb * 6;
X }
X
X if (onrc (DOOR, r, c))
X a += expDor;
X /* else if (onrc (BEEN+BOUNDARY, r, c) == BOUNDARY)
X a++; // Avoid running along the untrodden boundary. // */
X
X *avd = a;
X *val = v;
X *cont = 0; /* Look for orphans */
X
X return (1);
X}
X
X/*
X * S E C R E T D O O R S E A R C H
X */
X
Xsecretinit ()
X{ expinit ();
X if (setpsd ())
X return (1);
X return (0);
X}
X
Xsecretvalue (r, c, depth, val, avd, cont)
Xint r, c, depth;
Xint *val, *avd, *cont;
X{ register int v, a, k;
X
X *val=0;
X v = 0; /* establish value of square */
X a = onrc (SAFE, r, c) ? 0 :
X onrc (ARROW, r, c) ? 50 :
X onrc (TRAPDOR, r, c) ? 175 :
X onrc (TELTRAP, r, c) ? 50 :
X onrc (GASTRAP, r, c) ? 50 :
X onrc (BEARTRP, r, c) ? 50 :
X onrc (DARTRAP, r, c) ? 200 :
X onrc (WATERAP, r, c) ? 50 :
X onrc (MONSTER, r, c) ? 150 :
X expavoidval;
X
X if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X a += 200;
X
X for (k=0; k<8; k++) /* examine adjacent squares */
X { register int nr = r + deltr[k];
X register int nc = c + deltc[k];
X if (nr >= 1 && nr <= 22 &&
X nc >= 0 && nc <= 80 &&
X onrc (PSD, nr, nc) && timessearched[nr][nc] < SEARCHES(nr,nc))
X { /* If adjacent square is on the screen */
X /* and if it has PSD set but has not been searched completely */
X /* count useful neighbours */
X if (screen[nr][nc] == '|') v += 4;
X else v ++;
X if (debug (D_SCREEN | D_INFORM)) mvaddch (nr, nc, 'S');
X }
X }
X
X if (v>0)
X { if (version >= RV53A &&
X onrc (DOOR|BEEN, r, c) == DOOR|BEEN &&
X (onrc (CANGO|WALL, r+1, c) == 0 || onrc (CANGO|WALL, r-1, c) == 0 ||
X onrc (CANGO|WALL, r, c+1) == 0 || onrc (CANGO|WALL, r, c-1) == 0))
X { *val = v+100; *cont = 5; }
X else
X { v = min (15, v);
X *val = secretvalues[v]; *cont = secretcont[v];
X if (onrc (DOOR, r, c)) a += expDor;
X }
X }
X *avd = a;
X
X return (1);
X}
X
X/*
X * E S T A B L I S H A V O I D A N C E M A P to avoid monsters.
X */
X
X# define AVOID(r,c,ch) \
X { avdmonsters[r][c] = INFINITY; \
X if (debug (D_SCREEN)) { at((r),(c)); addch(ch); at(row,col); }}
X
Xavoidmonsters ()
X{ register int i, r, c, wearingstealth;
X
X /* Clear old avoid monster values */
X for (i = 24*80; i--; ) avdmonsters[0][i] = 0;
X
X /* Set stealth status */
X wearingstealth = (wearing ("stealth") != NONE);
X
X /* Avoid each monster in turn */
X for (i=0; i<mlistlen; i++)
X { /* First check whether this monster is really wimpy */
X if (maxhit(i) < Hp/2)
X { AVOID (mlist[i].mrow, mlist[i].mcol, '$')
X }
X /* If not a wimp and awake, avoid him all together */
X else if (mlist[i].q == AWAKE)
X { int d, dr, dc, mr = mlist[i].mrow, mc = mlist[i].mcol;
X d = direc (searchstartr-mr,searchstartc-mc);
X dr = (searchstartr-mr)/2+mr; dc=(searchstartc-mc)/2+mc;
X if (d & 1)
X { caddycorner (dr, dc, (d-1) & 7, (d-3)&7, '$');
X caddycorner (dr, dc, (d+1) & 7, (d+3)&7, '$');
X }
X else
X { caddycorner (dr, dc, (d-2) & 7, d, '$');
X caddycorner (dr, dc, (d+2) & 7, d, '$');
X }
X }
X /* If he'll wake up, give him a wide berth */
X else if (!wearingstealth)
X { for (r = mlist[i].mrow-1; r<= mlist[i].mrow+1; r++)
X for (c = mlist[i].mcol-1; c<= mlist[i].mcol+1; c++)
X AVOID (r, c, '$')
X }
X /* He's asleep, don't try to run through him */
X else
X AVOID (mlist[i].mrow, mlist[i].mcol, '$')
X }
X
X /* Don't avoid current position */
X avdmonsters[searchstartr][searchstartc] = 0;
X dwait (D_SEARCH, "Avoidmonsters: avoiding the $s");
X}
X
X/*
X * caddycorner: Find sqaures the monster can reach before we can and mark
X * them for avoidance
X */
X
Xcaddycorner (r, c, d1, d2, ch)
Xint r,c,d1,d2;
Xchar ch;
X{ while (onrc (CANGO, r, c))
X { AVOID (r, c, ch);
X r += deltr[d1]; c += deltc[d1];
X if (!onrc (CANGO, r, c)) break;
X AVOID (r, c, ch);
X r += deltr[d2]; c += deltc[d2];
X }
X}
X
X/*
X * E S T A B L I S H A V O I D A N C E M A P when pinned
X *
X * This routine is basically the same as avoidmonsters, except that
X * the value are calculated to allow the monster one hit instead of
X * avoiding him entirely. This allows us to escape from situations where
X * we are pinned, but could get free if we had an extra turn. MLM
X */
X
Xpinavoid ()
X{ register int i;
X
X /* Clear old avoid monster values */
X for (i = 24*80; i--; ) avdmonsters[0][i] = 0;
X
X /* Avoid each monster in turn */
X for (i=0; i<mlistlen; i++)
X { if (mlist[i].q == AWAKE)
X { register int d, dr, dc, mr = mlist[i].mrow, mc = mlist[i].mcol;
X d = direc (searchstartr-mr,searchstartc-mc);
X dr = (searchstartr-mr)/2+mr - deltr[d]; /* MLM */
X dc=(searchstartc-mc)/2+mc - deltc[d]; /* MLM */
X if (d & 1)
X { caddycorner (dr, dc, (d-1) & 7, (d-3)&7, '&');
X caddycorner (dr, dc, (d+1) & 7, (d+3)&7, '&');
X }
X else
X { caddycorner (dr, dc, (d-2) & 7, (d-4) & 7, '&'); /* MLM */
X caddycorner (dr, dc, (d+2) & 7, (d+4) & 7, '&'); /* MLM */
X }
X }
X AVOID (mlist[i].mrow, mlist[i].mcol, '&');
X }
X
X /* Don't avoid current position */
X avdmonsters[searchstartr][searchstartc] = 0;
X dwait (D_SEARCH, "Pinavoid: avoiding the &s");
X}
X
X/*
X * S E C R E T : Search dead ends for secret doors.
X */
X
Xsecret ()
X{ int secretinit(), secretvalue();
X
X /* Secret passage adjacent to door? */
X if (version >= RV53A && on (DOOR) && !blinded &&
X (seerc (' ',atrow+1,atcol) || seerc (' ',atrow-1,atcol) ||
X seerc (' ',atrow,atcol+1) || seerc (' ',atrow,atcol-1)) &&
X SEARCHES (atrow, atcol) < timestosearch+20)
X { int count = timessearched[atrow][atcol]+1;
X saynow ("Searching dead end door (%d,%d) for the %d%s time...",
X atrow, atcol, count, ordinal (count));
X command (T_DOORSRCH, "s"); return (1);
X }
X
X /* Verify that we are actually at a dead end */
X if (onrc (CANGO,atrow-1,atcol) + onrc (CANGO,atrow,atcol-1) +
X onrc (CANGO,atrow+1,atcol) + onrc (CANGO,atrow,atcol+1) != CANGO)
X return (0);
X
X /* If Level 1 or edge of screen: dead end cannot be room, mark and return */
X if (Level == 1 && attempt == 0 ||
X version < RV53A && (atrow<=1 || atrow>=22 || atcol<=0 || atcol>=79))
X { markexplored (atrow, atcol); return (0); }
X
X /* Have we mapped this level? */
X if (Level == didreadmap) return (0);
X
X /* Found a dead end, should we search it? */
X if (nexttowall (atrow, atcol) ||
X canbedoor (atrow, atcol) &&
X (version >= RV53A || !isexplored (atrow, atcol)))
X { setrc (DEADEND, atrow, atcol);
X
X if ((SEARCHES (atrow, atcol) - timessearched[atrow][atcol]) > 0)
X { int count = timessearched[atrow][atcol]+1;
X saynow ("Searching dead end (%d,%d) for the %d%s time...",
X atrow, atcol, count, ordinal (count));
X command (T_DOORSRCH, "s");
X return (1);
X }
X else
X { markexplored (atrow, atcol);
X return (0);
X }
X }
X
X return (0);
X}
X
X/*
X * F I N D R O O M : Try to find another room.
X */
X
Xfindroom ()
X{ int expinit(), expvalue(); /* LGCH */
X
X if (new_findroom)
X { if (!on (ROOM) && secret ()) return (1);
X if (makemove (EXPLORE, expinit, expvalue, REUSE)) return (1);
X }
X
X new_findroom = 0;
X dwait (D_SEARCH, "findroom failed.");
X return (0);
X}
X
X/*
X * E X P L O R E R O O M : Explore the current room.
X */
X
Xexploreroom ()
X{ int roominit(), expvalue(); /* LGCH */
X
X if (!on (ROOM) || isexplored (atrow, atcol)) return (0);
X if (makemove (EXPLOREROOM, roominit, expvalue, REUSE)) return (1);
X markexplored (atrow, atcol);
X
X dwait (D_SEARCH, "exploreroom failed.");
X return (0);
X}
X
X/*
X * D O O R E X P L O R E : look for secret doors
X */
X
Xdoorexplore()
X{ static searchcount = 0;
X int secretinit(), secretvalue();
X
X /* If no new squares or read map, dont bother */
X if (! new_search || Level == didreadmap)
X { searchcount = 0; return (0); }
X
X if (makemove (SECRETDOOR, secretinit, secretvalue, REUSE)) /* move */
X { searchcount = 0; return (1); }
X
X if (searchcount > 20)
X { new_search = 0; return (0); }
X
X if (ontarget) /* Moved to a possible secret door, search it */
X { searchcount++;
X saynow ("Searching square (%d,%d) for the %d%s time...",
X atrow, atcol, searchcount, ordinal (searchcount));
X command (T_DOORSRCH, "s");
X return (1);
X }
X
X new_search = searchcount = 0;
X return (0);
X}
X
X/*
X * S A F E S Q U A R E S E A R C H Use genericinit.
X */
X
Xsafevalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ register int k, v;
X
X *avd = onrc (SAFE, r, c) ? 0 :
X onrc (TRAPDOR | BEARTRP | GASTRAP, r, c) ? INFINITY :
X onrc (ARROW, r, c) ? 50 :
X onrc (TELTRAP, r, c) ? 50 :
X onrc (DARTRAP, r, c) ? 200 :
X onrc (WATERAP, r, c) ? 50 :
X onrc (MONSTER, r, c) ? 150 :
X expavoidval;
X *val = 0;
X
X if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X *avd += 500;
X
X if (onrc(CANGO, r, c))
X { v = 0;
X for (k=0; k<8; k++)
X if (onrc(CANGO, r+deltr[k], c+deltc[k]) &&
X onrc(CANGO, r+deltr[k], c) &&
X onrc(CANGO, r, c+deltc[k])) v++;
X if (v < 3)
X *val = 1; /* *cont = 0; // default // */
X }
X return (1);
X}
X
X/* findsafe: find a spot with 2 or fewer moves, for when blinded */
X
Xfindsafe()
X{
X return (makemove (FINDSAFE, genericinit, safevalue, REEVAL));
X}
X
X/* How scared are we of hitting a trap? */
X
Xavoid ()
X{ if (cheat && !foundarrowtrap && !usingarrow) return (0);
X else if (Level < 5) return (0); /* Don't bother */
X else return (2); /* Avoid a little */
X}
X
X/*
X * archery: Initialize a archery move. We find a good place to
X * shoot from and stand there. Then mark the monster as awake, and
X * battlestations will handle firing at him.
X */
X
Xstatic int archrow = NONE, archcol = NONE, archturns = NONE, archval[24][80];
X
Xarchmonster (m, turns)
Xregister int m; /* Monster to attack */
Xregister int turns; /* Minimum number of arrows to make it worthwhile */
X{ int archeryinit(), archeryvalue();
X register int mr, mc;
X
X dwait (D_CONTROL | D_BATTLE, "archmonster: m=%d, turns=%d", m, turns);
X
X if (! new_arch) return (0);
X
X /* Useless without arrows */
X if (havemult (missile, "", turns) < 0)
X { dwait (D_BATTLE, "archmonster, fewer than %d missiles", turns);
X return (0); }
X
X /* For now, only work for sleeping monsters */
X if (mlist[m].q != ASLEEP)
X { dwait (D_BATTLE, "archmonster, monster not asleep"); return (0); }
X
X /* Save globals */
X archrow = mlist[m].mrow; archcol = mlist[m].mcol; archturns = turns;
X
X /* Can we get to a suitable square */
X if (makemove (ARCHERYMOVE, archeryinit, archeryvalue, REUSE))
X { dwait (D_BATTLE, "archmonster, made a move"); return (1); }
X
X /* If no move made and not on target, no path to monster */
X if (!ontarget) { new_arch = 0; return (0); }
X
X /* On target: wake him up and set darkdir/turns if necessary */
X mr = mlist[m].mrow; mc = mlist[m].mcol; targetmonster = mlist[m].chr;
X mlist[m].q = AWAKE; dwait (D_BATTLE, "archmonster, waking him up");
X
X /* Set dark room archery variables, add goal of standing on square */
X if (darkroom ())
X { darkdir = direc (mr-atrow, mc-atcol);
X darkturns = max (abs (mr-atrow), abs (mc-atcol));
X agoalr = mr; agoalc = mc; /* Go here to pick up what (s)he drops */
X }
X
X /* Tell the user about it */
X saynow ("Arching at %s", monname (mlist[m].chr));
X
X return (1);
X}
X
X/*
X * archeryinit: Initialize a archery move. Must avoid monsters to avoid
X * waking our potential victim up.
X */
X
Xarcheryinit ()
X{ register int dir, r, c, dr, dc, dist;
X
X /* Clear the archery value array */
X for (r = 24*80; r--; ) archval[0][r] = 0;
X
X /* Scan around monster to see how far away we can shoot from */
X for (dir = 0; dir < 8; dir++)
X { dr = deltr[dir]; dc = deltc[dir];
X for (dist = 1, r = archrow+dr, c = archcol+dc;
X onrc (CANGO | HALL | MONSTER, r, c) == CANGO;
X r += dr, c += dc, dist++)
X if (dist > archturns && !onrc (TRAP, r, c))
X { archval[r][c] = dist - 1; /* number of arrows we get to shoot */
X if (debug (D_SCREEN)) { at (r, c); addch ('='); at (row, col); }
X }
X }
X
X expavoidval = avoid();
X avoidmonsters ();
X return (1);
X}
X
X/*
X * archeryvalue: Get the value of the square from the archery array.
X * Value is non-zero only if we can fire arrows at beast and value is
X * number of shots we can fire.
X */
X
Xarcheryvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{
X *avd = (onrc (SAFE, r, c) ? 0 :
X onrc (TRAPDOR, r, c) ? INFINITY :
X onrc (HALL, r, c) ? INFINITY :
X onrc (ARROW, r, c) ? 50 :
X onrc (TELTRAP, r, c) ? 50 :
X onrc (GASTRAP, r, c) ? 50 :
X onrc (BEARTRP, r, c) ? 50 :
X onrc (DARTRAP, r, c) ? 200 :
X onrc (WATERAP, r, c) ? 50 :
X onrc (MONSTER, r, c) ? 150 :
X expavoidval) + avdmonsters[r][c];
X
X if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X *avd += 500;
X
X *val = archval[r][c];
X *cont = INFINITY;
X
X return (1);
X}
X
X/*
X * M O V E T O R E S T : Find a safe square to rest up on.
X */
X
Xstatic restinlight = 0; /* True only in lit rooms */
Xstatic restinroom = 0; /* True only in a room */
Xstatic restr = NONE, restc = NONE; /* Square to rest on */
X
X/* Set new resting goal */
Xunrest ()
X{ restr = restc = NONE;
X}
X
X/* Move to a good square to rest up on */
Xmovetorest ()
X{ int restinit(), restvalue(); /* LGCH */
X
X if (markcycles (NOPRINT))
X unrest ();
X
X /* If we are where we want to rest, do so */
X if (restr >= 0 && atrow == restr && atcol == restc)
X { dwait (D_SEARCH, "movetorest: already on square"); return (0); }
X
X /* Try to move to a better square (remember position) */
X if (makemove (RESTMOVE, restinit, restvalue, REUSE))
X { dwait (D_SEARCH, "movetorest wins.");
X restr = targetrow; restc = targetcol;
X return (1);
X }
X
X /* Cant move anywhere better, stay here */
X dwait (D_SEARCH, "movetorest fails.");
X restr = atrow; restc = atcol;
X
X return (0);
X}
X
Xrestinit ()
X{ expavoidval = avoid();
X restinlight = (on (ROOM) && !darkroom ());
X restinroom = on (ROOM);
X return (1);
X}
X
Xrestvalue (r, c, depth, val, avd, cont)
Xregister int r, c;
Xint depth, *val, *avd, *cont;
X{ register int dr, dc, ar, ac;
X int count, dir, rm;
X
X /* Find room number for diagonal selection */
X if ((rm = whichroom (r, c)) < 0) rm = 4;
X
X /* Default is no value, no avoidance */
X *avd = *val = 0;
X
X /* Set base value of square */
X if (onrc (TRAP|MONSTER,r, c)) { *avd = INFINITY; return (0); }
X else if (restinroom && onrc (DOOR,r, c)) { *avd = INFINITY; return (0); }
X else if (onrc (SCAREM, r, c))
X { if (objcount == maxobj || version >= RV53A) { *val = 500; return (1); }
X else { *avd = INFINITY; return (0); }
X }
X else if (onrc (STAIRS, r, c)) { *val = 400; return (1); }
X else if (onrc (ROOM, r, c)) { *val = 1; *cont = 99;}
X else if (!onrc (SAFE|BEEN|STUFF, r, c)) { *avd = 5; }
X
X /* Give bonus for being next to a trap door or a teleport trap */
X if (onrc (TRAPDOR|TELTRAP, r-1, c-1) || onrc (TRAPDOR|TELTRAP, r+1, c-1) ||
X onrc (TRAPDOR|TELTRAP, r-1, c+1) || onrc (TRAPDOR|TELTRAP, r+1, c+1))
X { *val += 80; *cont = 99;}
X
X if (onrc (TRAPDOR|TELTRAP, r-1, c) || onrc (TRAPDOR|TELTRAP, r+1, c) ||
X onrc (TRAPDOR|TELTRAP, r, c-1) || onrc (TRAPDOR|TELTRAP, r, c+1))
X { *val += 30; *cont = 99;}
X
X /* In lit rooms (with ammo) stay away from doors, this gives us time */
X /* to shoot arrows at monsters coming in at us MLM 06/21/83 */
X if (restinlight && ammo)
X { for (dir = 0; dir < 8; dir += 2)
X { dr = deltr[dir]; dc = deltc[dir];
X for (count = 0, ar = r+dr, ac = c+dc;
X onrc (CANGO | HALL | MONSTER, ar, ac) == CANGO;
X ar += dr, ac += dc, count++)
X { /* Bonus of 'count' if this square covers a door */
X if (onrc(DOOR,ar+deltr[(dir+2)%8],ac+deltc[(dir+2)%8])) *val += count;
X if (onrc(DOOR,ar+deltr[(dir+6)%8],ac+deltc[(dir+6)%8])) *val += count;
X if (onrc(DOOR,ar,ac)) *val += count;
X }
X }
X }
X
X /* In dark rooms, stand diagonally away from doors (1 extra turn) */
X else if (onrc (ROOM, r, c))
X { if (onrc (DOOR,r-1,c-1) && (rm!=0 && rm!=1 && rm!=3)) {*val+=80;*cont=99;}
X if (onrc (DOOR,r+1,c-1) && (rm!=3 && rm!=6 && rm!=7)) {*val+=80;*cont=99;}
X if (onrc (DOOR,r-1,c+1) && (rm!=1 && rm!=2 && rm!=5)) {*val+=80;*cont=99;}
X if (onrc (DOOR,r+1,c+1) && (rm!=5 && rm!=7 && rm!=8)) {*val+=80;*cont=99;}
X
X /* Bonus for door also orthogonally away */
X if(onrc(DOOR,r,c-1)||onrc(DOOR,r-1,c)||onrc(DOOR,r,c+1)||onrc(DOOR,r+1,c))
X { *val+=30; *cont=99; }
X }
X
X return (1);
X}
/
echo 'x - utility.c'
sed 's/^X//' > utility.c << '/'
X/*
X * utility.c: Rog-O-Matic XIV (CMU) Thu Jan 31 18:18:22 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains all of the miscellaneous system functions which
X * determine the baud rate, time of day, etc.
X */
X
X# include <sgtty.h>
X# include <stdio.h>
X# include <signal.h>
X# include <sys/types.h>
X# include <sys/stat.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# define TRUE 1
X# define FALSE 0
X
X/*
X * baudrate: Determine the baud rate of the terminal
X */
X
Xbaudrate ()
X{ static short baud_convert[] =
X { 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600 };
X static struct sgttyb sg;
X static short baud_rate;
X
X gtty (fileno (stdin), &sg);
X baud_rate = sg.sg_ospeed == 0 ? 1200
X : sg.sg_ospeed < sizeof baud_convert / sizeof baud_convert[0]
X ? baud_convert[sg.sg_ospeed] : 9600;
X
X return (baud_rate);
X}
X
X/*
X * stlmatch -- match leftmost part of string
X *
X * Usage: i = stlmatch (big,small)
X * int i;
X * char *small, *big;
X *
X * Returns 1 iff initial characters of big match small exactly;
X * else 0.
X *
X * HISTORY
X * 18-May-82 Michael Mauldin (mlm) at Carnegie-Mellon University
X * Ripped out of CMU lib for Rog-O-Matic portability
X * 20-Nov-79 Steven Shafer (sas) at Carnegie-Mellon University
X * Rewritten for VAX from Ken Greer's routine.
X *
X * Originally from klg (Ken Greer) on IUS/SUS UNIX
X */
X
Xint stlmatch (big, small)
Xchar *small, *big;
X{ register char *s, *b;
X s = small;
X b = big;
X do
X { if (*s == '\0')
X return (1);
X }
X while (*s++ == *b++);
X return (0);
X}
X
X/*
X * getname: get userid of player.
X */
X
Xchar *getname ()
X{ static char name[100];
X int i;
X
X getpw (getuid (), name);
X i = 0;
X while (name[i] != ':' && name[i] != ',')
X i++;
X name[i] = '\0';
X
X return (name);
X}
X
X/*
X * putenv -- put value into environment
X *
X * Usage: i = putenv (name,value)
X * int i;
X * char *name, *value;
X *
X * Putenv associates "value" with the environment parameter "name".
X * If "value" is 0, then "name" will be deleted from the environment.
X * Putenv returns 0 normally, -1 on error (not enough core for malloc).
X *
X * Putenv may need to add a new name into the environment, or to
X * associate a value longer than the current value with a particular
X * name. So, to make life simpler, putenv() copies your entire
X * environment into the heap (i.e. malloc()) from the stack
X * (i.e. where it resides when your process is initiated) the first
X * time you call it.
X *
X * HISTORY
X * 25-Nov-82 Michael Mauldin (mlm) at Carnegie-Mellon University
X * Ripped out of CMU lib for Rog-O-Matic portability
X * 20-Nov-79 Steven Shafer (sas) at Carnegie-Mellon University
X * Created for VAX. Too bad Bell Labs didn't provide this. It's
X * unfortunate that you have to copy the whole environment onto the
X * heap, but the bookkeeping-and-not-so-much-copying approach turns
X * out to be much hairier. So, I decided to do the simple thing,
X * copying the entire environment onto the heap the first time you
X * call putenv(), then doing realloc() uniformly later on.
X * Note that "putenv(name,getenv(name))" is a no-op; that's the reason
X * for the use of a 0 pointer to tell putenv() to delete an entry.
X *
X */
X
X#define EXTRASIZE 5 /* increment to add to env. size */
X
Xchar *index (), *malloc (), *realloc ();
Xint strlen ();
X
Xstatic int envsize = -1; /* current size of environment */
Xextern char **environ; /* the global which is your env. */
X
Xstatic int findenv (); /* look for a name in the env. */
Xstatic int newenv (); /* copy env. from stack to heap */
Xstatic int moreenv (); /* incr. size of env. */
X
Xint putenv (name, value)
Xchar *name, *value;
X{ register int i, j;
X register char *p;
X
X if (envsize < 0)
X { /* first time putenv called */
X if (newenv () < 0) /* copy env. to heap */
X return (-1);
X }
X
X i = findenv (name); /* look for name in environment */
X
X if (value)
X { /* put value into environment */
X if (i < 0)
X { /* name must be added */
X for (i = 0; environ[i]; i++);
X if (i >= (envsize - 1))
X { /* need new slot */
X if (moreenv () < 0)
X return (-1);
X }
X p = malloc (strlen (name) + strlen (value) + 2);
X if (p == 0) /* not enough core */
X return (-1);
X environ[i + 1] = 0; /* new end of env. */
X }
X else
X { /* name already in env. */
X p = realloc (environ[i],
X strlen (name) + strlen (value) + 2);
X if (p == 0)
X return (-1);
X }
X sprintf (p, "%s=%s", name, value);/* copy into env. */
X environ[i] = p;
X }
X else
X { /* delete name from environment */
X if (i >= 0)
X { /* name is currently in env. */
X free (environ[i]);
X for (j = i; environ[j]; j++);
X environ[i] = environ[j - 1];
X environ[j - 1] = 0;
X }
X }
X
X return (0);
X}
X
Xstatic int findenv (name)
Xchar *name;
X{ register char *namechar, *envchar;
X register int i, found;
X
X found = 0;
X for (i = 0; environ[i] && !found; i++)
X { envchar = environ[i];
X namechar = name;
X while (*namechar && (*namechar == *envchar))
X { namechar++;
X envchar++;
X }
X found = (*namechar == '\0' && *envchar == '=');
X }
X return (found ? i - 1 : -1);
X}
X
Xstatic int newenv ()
X{ register char **env, *elem;
X register int i, esize;
X
X for (i = 0; environ[i]; i++);
X esize = i + EXTRASIZE + 1;
X env = (char **) malloc (esize * sizeof (elem));
X if (env == 0)
X return (-1);
X
X for (i = 0; environ[i]; i++)
X { elem = malloc (strlen (environ[i]) + 1);
X if (elem == 0)
X return (-1);
X env[i] = elem;
X strcpy (elem, environ[i]);
X }
X
X env[i] = 0;
X environ = env;
X envsize = esize;
X return (0);
X}
X
Xstatic int moreenv ()
X{ register int esize;
X register char **env;
X
X esize = envsize + EXTRASIZE;
X env = (char **) realloc (environ, esize * sizeof (*env));
X if (env == 0)
X return (-1);
X environ = env;
X envsize = esize;
X return (0);
X}
X
X/*
X * wopen: Open a file for world access.
X */
X
XFILE *wopen(fname, mode)
Xchar *fname, *mode;
X{ int oldmask;
X FILE *newlog;
X
X oldmask = umask (0111);
X newlog = fopen (fname, mode);
X umask (oldmask);
X
X return (newlog);
X}
X
X/*
X * fexists: return a boolean if the named file exists
X */
X
Xfexists (fn)
Xchar *fn;
X{ struct stat pbuf;
X
X return (stat (fn, &pbuf) == 0);
X}
X
X/*
X * filelength: Do a stat and return the length of a file.
X */
X
Xint filelength (f)
X{ struct stat sbuf;
X
X if (stat (f, &sbuf) == 0)
X return (sbuf.st_size);
X else
X return (-1);
X}
X
X/*
X * critical: Disable interrupts
X */
X
Xstatic int (*hstat)(), (*istat)(), (*qstat)();
X
Xcritical ()
X{
X hstat = signal (SIGHUP, SIG_IGN);
X istat = signal (SIGINT, SIG_IGN);
X qstat = signal (SIGQUIT, SIG_IGN);
X}
X
X/*
X * uncritical: Enable interrupts
X */
X
Xuncritical ()
X{
X signal (SIGHUP, hstat);
X signal (SIGINT, istat);
X signal (SIGQUIT, qstat);
X}
X
X/*
X * reset_int: Set all interrupts to default
X */
X
Xreset_int ()
X{
X signal (SIGHUP, SIG_DFL);
X signal (SIGINT, SIG_DFL);
X signal (SIGQUIT, SIG_DFL);
X}
X
X/*
X * int_exit: Set up a function to call if we get an interrupt
X */
X
Xint_exit (exitproc)
Xint (*exitproc)();
X{
X if (signal (SIGINT, SIG_IGN) != SIG_IGN) signal (SIGINT, exitproc);
X if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) signal (SIGPIPE, exitproc);
X if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) signal (SIGQUIT, exitproc);
X}
X
X/*
X * lock_file: lock a file for a maximum number of seconds.
X * Based on the method used in Rogue 5.2.
X */
X
X# define NOWRITE 0
X
Xlock_file (lokfil, maxtime)
Xchar *lokfil;
Xint maxtime;
X{ int try;
X struct stat statbuf;
X time_t time ();
X
X start:
X if (creat (lokfil, NOWRITE) > 0)
X return TRUE;
X
X for (try = 0; try < 60; try++)
X { sleep (1);
X if (creat (lokfil, NOWRITE) > 0)
X return TRUE;
X }
X
X if (stat (lokfil, &statbuf) < 0)
X { creat (lokfil, NOWRITE);
X return TRUE;
X }
X
X if (time (NULL) - statbuf.st_mtime > maxtime)
X { if (unlink (lokfil) < 0)
X return FALSE;
X goto start;
X }
X else
X return FALSE;
X}
X
X/*
X * unlock_file: Unlock a lock file.
X */
X
Xunlock_file (lokfil)
Xchar *lokfil;
X{ unlink (lokfil);
X}
X
X/*
X * quit: Defined for compatibility with Berkeley 4.2 system
X */
X
Xquit (code, fmt, a1, a2, a3, a4)
Xint code, a1, a2, a3, a4;
Xchar *fmt;
X{
X fprintf (stderr, fmt, a1, a2, a3, a4);
X exit (code);
X}
/
echo 'Part 02 of Rog-O-Matic XIV complete.'
exit
More information about the Comp.sources.unix
mailing list