|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T e
Length: 34719 (0x879f) Types: TextFile Names: »explore.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Rog-O-Matic/explore.c«
/* * explore.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:14:30 1985 - mlm * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin * * This file contains all of the functions which are used to search out * paths to explore, pick up something, or run away. */ # include <curses.h> # include "types.h" # include "globals.h" # define SEARCHES(r,c) \ (onrc(DEADEND,r,c) ? \ ((version < RV53A || !isexplored (r,c)) ? \ (timestosearch + k_door / 5) : \ (timestosearch - k_door / 5 + 5)) : \ timestosearch) static int expDor, expavoidval; static int avdmonsters[24][80]; int connect[9][4] = { /* Room top bot left right*/ /* 0 */ {-1, 3, -1, 1}, /* 1 */ {-1, 4, 0, 2}, /* 2 */ {-1, 5, 1, -1}, /* 3 */ { 0, 6, -1, 4}, /* 4 */ { 1, 7, 3, 5}, /* 5 */ { 2, 8, 4, -1}, /* 6 */ { 3, -1, -1, 7}, /* 7 */ { 4, -1, 6, 8}, /* 8 */ { 5, -1, 7, -1} }; /* * genericinit: Initialize a 'standard' movement search. MLM */ genericinit () { expavoidval = avoid(); return (1); } /* Secret door search values and continuance tables: * * Number of unsearched walls adjacent. * * Vert Horiz Value Cont Explanation * --------------------------------------------------- * 0 0 0 0 Valueless * 0 1 N-24-dep 16 Prefer (0,2) 1 move later * 0 2 N-22-dep 15 Prefer (0,3) 1 move later * 0 3 N-20-dep 14 Prefer (1,0) 10 moves later * 1 0 N-9-dep 4 Prefer (1,1) 2 moves later * 1 1 N-6-dep 2 Prefer (2,0) 1 move later * 1 2 N-5-dep 2 Prefer (2,0) 1 move later * 1 3 N-5-dep 2 Impossible * 2 0 N-3-dep 1 Prefer (3,0) 1 move later * 2 1 N-2-dep 0 * 2 2 N-1-dep 0 * 2 3 N-1-dep 0 Impossible * 3 0 N 0 Best possible * 3 1 N 0 Impossible * 3 2 N 0 Impossible * 3 3 N 0 Impossible */ # define N 100 static int secretvalues[16]= { 0, N-24, N-22, N-20, N-9, N-6, N-5, N-5, N-3, N-2, N-1, N-1, N, N, N, N }; static int secretcont[16] = { 0, 16, 15, 14, 4, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0 }; /* * gotowards: Move toward a square. */ int gotorow = NONE, gotocol = NONE; gotowards (row, col, running) int row, col, running; { int gotoinit(), gotovalue(); gotorow = row; gotocol = col; return (makemove (running ? RUNAWAY:GOTOMOVE, gotoinit, gotovalue, REUSE)); } /* * gotoinit: Initialize a gotowards move. */ gotoinit () { expavoidval = avoid(); return (1); } /* * gotovalue: Only the current target square has a value. */ gotovalue (r, c, depth, val, avd, cont) int r, c, depth, *val, *avd, *cont; { *avd = onrc (SAFE, r, c) ? 0 : onrc (ARROW, r, c) ? 50 : onrc (TRAPDOR, r, c) ? 175 : onrc (TELTRAP, r, c) ? 50 : onrc (GASTRAP, r, c) ? 50 : onrc (BEARTRP, r, c) ? 50 : onrc (DARTRAP, r, c) ? 200 : onrc (WATERAP, r, c) ? 50 : onrc (MONSTER, r, c) ? 150 : expavoidval; if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj) *avd += 200; *val = r == gotorow && c == gotocol ? 1 : 0; /* *cont = 0; // default value when called // */ return (1); } /* * sleepvalue: Squares with sleeping monsters have value. * Use genericinit. MLM */ sleepvalue (r, c, depth, val, avd, cont) int r, c, depth, *val, *avd, *cont; { *avd = onrc (SAFE, r, c) ? 0 : onrc (ARROW, r, c) ? 50 : onrc (TRAPDOR, r, c) ? 175 : onrc (TELTRAP, r, c) ? 50 : onrc (GASTRAP, r, c) ? 50 : onrc (BEARTRP, r, c) ? 50 : onrc (DARTRAP, r, c) ? 200 : onrc (WATERAP, r, c) ? 50 : onrc (MONSTER, r, c) ? 150 : expavoidval; if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj) *avd += 200; if (onrc (SLEEPER, r, c)) { *val = 1; *avd = 0; /* *cont = 0; // default value when called // */ } return (1); } /* * wallkind: given a row and column, determine which kind of wall if any * is there. Part of doorinit Guy Jacobson 5/82 */ int wallkind (r, c) int r, c; { switch (screen[r][c]) { case '|': if (onrc (ROOM, r, c+1)) return (LEFTW); else return (RIGHTW); case '-': if (onrc (ROOM, r+1, c)) return (TOPW); else if (onrc (ROOM, r-1, c)) return (BOTW); else return (CORNERW); case '+': return (DOORW); default: return (NOTW); } } /* * setpsd: Initialize secret door search * * Guy Jacobson 5/82 * Modified to allow searching even when there are cango bits. MLM. 10/82 * Modified to reuse existing map while it is valid. LGCH. 10/82 * Modified to understand maze room secret doors. MLM. 10/83 */ setpsd (print) { register int i, j, k, whereto, numberpsd=0; if (!print && reusepsd > 0) return (reusepsd-1); /* find what rooms are missing */ markmissingrooms (); /* Changed loop boundaries to ignore border around screen -- mlm 5/18/82 */ for (i=2; i<22; i++) for (j=1; j<79; j++) { unsetrc (PSD|DEADEND,i,j); /* If attempt > 3, allow ANYTHING to be a secret door! */ if (attempt > 3 && ! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) && nextto (CANGO, i, j)) { if (!onrc (PSD, i, j)) numberpsd++; setrc(PSD,i,j); } /* Set Possible Secret Door for maze room secret doors */ else if (attempt > 0 && ! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) && mazedoor (i, j)) { if (!onrc (PSD, i, j)) numberpsd++; setrc(PSD,i,j); } /* Set Possible Secret Door for corridor secret door */ else if (version >= RV53A && ! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) && nextto (DOOR, i, j)) { if (!onrc (PSD, i, j)) numberpsd++; setrc(PSD,i,j); } /* Set Possible Secret Door for dead end corridors */ else if (! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) && (onrc (HALL, i-1, j) + onrc (HALL, i+1, j) + onrc (HALL, i, j-1) + onrc (HALL, i, j+1) == HALL) && !(onrc(HALL|DOOR, i-1, j-1) || onrc(HALL|DOOR, i+1, j+1) || onrc(HALL|DOOR, i-1, j+1) || onrc(HALL | DOOR, i+1, j-1)) && canbedoor (i, j)) { if (!onrc (PSD, i, j)) numberpsd++; setrc(DEADEND,i,j); setrc(PSD,i,j); } /* Set PSD for walls which connect to empty space */ /* Modified to allow PSD for !ROOM (including the old CANGO des.) */ /* since potions and scrolls of detection can cause the CANGO bit */ /* to be set for a square on which we have never been. */ /* mlm 10/8/82 */ /* If attempt > 2, then relax the constraint about empty space, */ /* since we might have teleported into a disconnected part of the */ /* level. This means after we have searched twice, we look for */ /* ANY possible door, not just doors leading to empty space. */ /* mlm 10/11/82 */ else { if ((k = wallkind (i,j)) >= 0) { /* A legit sort of wall */ whereto = connect[whichroom (i,j)][k]; if (whereto >= 0 && (attempt > 1 || room[whereto] == 0)) { if (!onrc (PSD, i, j)) numberpsd++; setrc (PSD,i,j); } } } } /* Now remove PSD bits from walls which already have doors */ for (i=2; i<22; i++) for (j=1; j<79; j++) { if (onrc (DOOR, i, j)) { for (k = i-1; onrc (WALL, k, j); k--) { if (onrc (PSD, k, j)) numberpsd--; unsetrc (PSD, k, j);} for (k = i+1; onrc (WALL, k, j); k++) { if (onrc (PSD, k, j)) numberpsd--; unsetrc (PSD, k, j);} for (k = j-1; onrc (WALL, i, k); k--) { if (onrc (PSD, i, k)) numberpsd--; unsetrc (PSD, i, k);} for (k = j+1; onrc (WALL, i, k); k++) { if (onrc (PSD, i, k)) numberpsd--; unsetrc (PSD, i, k);} } } if (print || debug (D_SCREEN)) for (i=0; i<24; i++) for (j=0; j<80; j++) if (onrc (PSD,i,j)) { at (i,j); addch ('P'); } reusepsd = numberpsd+1; return (numberpsd); } /* * downvalue: find nearest stairs or trapdoor (use genericinit for init). */ downvalue (r, c, depth, val, avd, cont) int r, c, depth, *val, *avd, *cont; { *avd = onrc (SAFE, r, c) ? 0 : onrc (ARROW, r, c) ? 50 : onrc (TRAPDOR, r, c) ? 175 : onrc (TELTRAP, r, c) ? 50 : onrc (GASTRAP, r, c) ? 50 : onrc (BEARTRP, r, c) ? 50 : onrc (DARTRAP, r, c) ? 200 : onrc (WATERAP, r, c) ? 50 : onrc (MONSTER, r, c) ? 150 : expavoidval; if (onrc (STAIRS | TRAPDOR, r, c)) { *val = 1; *avd = 0; } else { *val = 0; } return (1); } /* * expruninit: same as expinit but don't bias against doors. */ expruninit () { dwait (D_CONTROL | D_SEARCH, "expruninit called."); expinit(); expDor = 0; avoidmonsters (); return (1); } /* * exprunvalue: When running, avoid monsters. * * Try to see a new square when running. */ exprunvalue (r, c, depth, val, avd, cont) int r, c, depth, *val, *avd, *cont; { if (r == atrow && c == atcol) /* Current square useless MLM */ *val = 0; else if (onrc (MONSTER | TRAP, r, c)) /* Added TRAP useless MLM */ *val = 0; else if (!zigzagvalue (r, c, depth, val, avd, cont)) return (0); if (*val > 0) { *val = *val * 1000 + depth; *cont = INFINITY; } *avd += avdmonsters[r][c]; return (1); } /* * expunpininit: same as exprunnit but try to unpin. */ expunpininit () { dwait (D_CONTROL | D_SEARCH, "expunpininit called."); expinit(); expDor = 0; pinavoid (); return (1); } /* * expunpinvalue: When unpinning, avoid monsters. * * Try to see a new square when unpinning, but unpin anywhere if need be. */ expunpinvalue (r, c, depth, val, avd, cont) int r, c, depth, *val, *avd, *cont; { if (r == atrow && c == atcol) /* Current square useless MLM */ *val = 0; else if (onrc (MONSTER | TRAP, r, c)) /* Added TRAP useless MLM */ *val = 0; else if (!zigzagvalue (r, c, depth, val, avd, cont)) return (0); if (*val > 0) { *val = *val * 1000 + depth; *cont = INFINITY; } *avd += avdmonsters[r][c]; return (1); } /* * runinit: R U N A W A Y S E A R C H */ runinit () { avoidmonsters(); return (1); } /* * runvalue: * * Evaluate square for running away. Targets, in priority order are: * * STAIRS TRAPDOR TELTRAP * RUNOK (cycle door) * DOOR * ANYWHERE * * Traps are avoided for a variable number of moves, except for target traps * Gave GasTraps and BearTraps infinite avoidance. MLM 10/11/83 */ runvalue (r, c, depth, val, avd, cont) int r, c, depth, *val, *avd, *cont; { *avd = onrc (ARROW, r, c) ? 50 : onrc (TRAPDOR, r, c) ? 0 : onrc (TELTRAP, r, c) ? 0 : onrc (GASTRAP, r, c) ? INFINITY : onrc (BEARTRP, r, c) ? INFINITY : onrc (DARTRAP, r, c) ? 100 : onrc (WATERAP, r, c) ? 100 : onrc (MONSTER, r, c) ? 150 : 0; if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj) *avd += 200; if (onrc (MONSTER, r, c)) { *val = 0; } if (onrc (STAIRS+TRAPDOR+TELTRAP, r, c)) { *val = 5000; *avd = 0; /* *cont = 0; */ } else if (r == atrow && c == atcol) /* If we are running, our current */ { *val = 0;} /* cant be that great -- MLM */ else if (onrc (RUNOK, r, c)) { *val = 4000; *cont = INFINITY;} else if (onrc (DOOR | BEEN, r, c) == DOOR) { *val = 2000+depth; *cont = INFINITY;} else if (onrc (DOOR, r, c)) { *val = 1000+depth; *cont = INFINITY;} else if (onrc (HALL, r, c)) { *val = depth; *cont = INFINITY;} /* ---------------------------------------------------------------- else if (onrc (CANGO | TRAP, r, c) == CANGO) { *val = 1+depth; *cont = INFINITY;} ---------------------------------------------------------------- */ else { *val = 0; } *avd += avdmonsters[r][c]; } /* * unpininit: U N P I N S E A R C H * * Same as runint, but we are willing to take one hit to get away. */ unpininit () { pinavoid(); return (1); } /* * rundoorinit: Standard initialization routine. */ rundoorinit() { avoidmonsters(); return (1); } /* * rundoorvalue: * * Evaluate square for running into doorway. * * Targets, in priority order are: * * RUNOK (cycle door) * DOOR * * Traps are avoided for a variable number of moves, except for target traps * Gave GasTraps and BearTraps infinite avoidance. MLM 10/11/83 */ rundoorvalue (r, c, depth, val, avd, cont) int r, c, depth; int *val, *avd, *cont; { *avd = onrc (ARROW, r, c) ? 50 : onrc (TRAPDOR, r, c) ? 0 : onrc (TELTRAP, r, c) ? 0 : onrc (GASTRAP, r, c) ? INFINITY : onrc (BEARTRP, r, c) ? INFINITY : onrc (DARTRAP, r, c) ? 100 : onrc (WATERAP, r, c) ? 100 : onrc (MONSTER, r, c) ? 50 : 0; if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj) *avd += 200; if (onrc (RUNOK, r, c)) { *val = 2;} else if (onrc (DOOR, r, c)) { *val = 1; *cont = INFINITY;} else { *val = 0;} *avd += avdmonsters[r][c]; } /* * E X P L O R A T I O N S E A R C H */ expinit () { /* avoidance values for doors */ expDor = 0; expavoidval = avoid(); return (1); } roominit () { expinit (); expDor = INFINITY; return (1); } /* * expvalue: evaluation function for exploration. LGCH * * In order to prevent leaving orphan unseen squares, we have heuritics * which cause rogomatic to use the three-step pattern to scan along the * boundary of a room, and also have tests which detect any orphans (e.g. * corners and when an object interrupts the search pattern) and cause them * to be seen. * * Three-step pattern: * * @@ @@ * @ @ @ * bbbbbbbbb */ expvalue (r, c, depth, val, avd, cont) int r, c, depth; int *val, *avd, *cont; { register int k, nr, nc, l; int a, v = 0, nunseenb = 0, nseenb = 0, nearb = 0; a = onrc (SAFE|DOOR|STAIRS|HALL, r, c) ? 0 : onrc (ARROW, r, c) ? 50 : onrc (TRAPDOR, r, c) ? 300 : onrc (TELTRAP, r, c) ? 100 : onrc (GASTRAP, r, c) ? 50 : onrc (BEARTRP, r, c) ? 50 : onrc (DARTRAP, r, c) ? 200 : onrc (TRAP, r, c) ? 100 : onrc (MONSTER, r, c) ? 150 : expavoidval; if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj) { *avd = a+1000; *val=0; return (1); } if (onrc (BEEN+SEEN, r, c) == SEEN) /* If been or not seen, not a target */ { for (k=0; k<8; k++) { nr = r + deltr[k]; nc = c + deltc[k]; /* For each unseen neighbour: add 10 to value. */ if (nr >= 1 && nr <= 22 && nc >= 0 && nc <= 80 && !onrc (SEEN, nr, nc)) { v += 10; if (onrc (BOUNDARY, nr, nc)) { /* Count unseen boundary neighbours. */ nunseenb++; /* Count seen boundaries horiz/vert adjacent to unseen boundary */ for (l=0; l<8; l+=2) if (onrc (SEEN+BOUNDARY, nr+deltr[l], nc+deltc[l]) == SEEN+BOUNDARY) nseenb++; } else { /* Check for unseen boundary horiz/vert */ /* adjacent to neighbour and not a neighbour. */ l = k / 2 * 2; /* horizontal/vertical */ if (onrc (BOUNDARY+SEEN, nr+deltr[l], nc+deltc[l]) == BOUNDARY) nearb = 1; else { l = ((k+1) / 2 * 2) % 8; if (onrc (BOUNDARY+SEEN, nr+deltr[l], nc+deltc[l]) == BOUNDARY) nearb = 1; } } } } /* To zig-zag: add number of unseen boundary neighbours * 6 */ v += nunseenb * 6; /* To do the three-step: add 29 if an unseen neighbour had an unseen * boundary horiz/vert adjacent */ if (nearb) v += 29; /* To prevent orphans: if three unseen neighbours are boundary and one * has a seen boundary horiz/vert adjacent, add 200 */ if (nunseenb >= 3 && nseenb >= 1) v += 200; /* To clean up any orphans: if two seen boundaries are adjacent to any * unseen boundary neighbours, add 400. */ if (nseenb >= 2) v += 400; } if (onrc (DOOR, r, c)) a += expDor; /* else if (onrc (BEEN+BOUNDARY, r, c) == BOUNDARY) a++; // Avoid running along the untrodden boundary. // */ *avd = a; *val = v; if (v < 50) *cont = 4; /* Look for something better */ if (debug (D_SCREEN) && v > 0) { mvaddch (r, c, 'o'); dwait (D_SCREEN, "Value %d", v); } return (1); } /* * zigzagvalue: evaluation function for exploration. LGCH * * This is a copy of expvalue with the three-step code and the code to * detect orphans removed. It is used when running away and unpinning * to find a useful exploration move. The boundary moves must zig-zag * rather than three-step so that the door can be entered when it is seen * without taking a hit from the monster chasing us. * * Gave GasTraps and BearTraps infinite avoidance. MLM 10/11/83 */ zigzagvalue (r, c, depth, val, avd, cont) int r, c, depth; int *val, *avd, *cont; { register int k, nr, nc, l; int a, v = 0, nunseenb = 0, nseenb = 0, nearb = 0; a = onrc (SAFE|DOOR|STAIRS|HALL, r, c) ? 0 : onrc (ARROW, r, c) ? 50 : onrc (TRAPDOR, r, c) ? 300 : onrc (TELTRAP, r, c) ? 100 : onrc (GASTRAP, r, c) ? 50 : onrc (BEARTRP, r, c) ? 50 : onrc (DARTRAP, r, c) ? 200 : onrc (TRAP, r, c) ? 100 : onrc (MONSTER, r, c) ? 150 : expavoidval; if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj) { *avd = a+1000; *val=0; return (1); } if (onrc (BEEN+SEEN, r, c) == SEEN) /* If been or not seen, not a target */ { for (k=0; k<8; k++) { nr = r + deltr[k]; nc = c + deltc[k]; /* For each unseen neighbour: add 10 to value. */ if (nr >= 1 && nr <= 22 && nc >= 0 && nc <= 80 && !onrc (SEEN, nr, nc)) { v += 10; if (onrc (BOUNDARY, nr, nc)) { /* Count unseen boundary neighbours. */ nunseenb++; } if (debug (D_SCREEN)) mvaddch (nr, nc, 'o'); } } /* To zig-zag: add number of unseen boundary neighbours * 6 */ v += nunseenb * 6; } if (onrc (DOOR, r, c)) a += expDor; /* else if (onrc (BEEN+BOUNDARY, r, c) == BOUNDARY) a++; // Avoid running along the untrodden boundary. // */ *avd = a; *val = v; *cont = 0; /* Look for orphans */ return (1); } /* * S E C R E T D O O R S E A R C H */ secretinit () { expinit (); if (setpsd ()) return (1); return (0); } secretvalue (r, c, depth, val, avd, cont) int r, c, depth; int *val, *avd, *cont; { register int v, a, k; *val=0; v = 0; /* establish value of square */ a = onrc (SAFE, r, c) ? 0 : onrc (ARROW, r, c) ? 50 : onrc (TRAPDOR, r, c) ? 175 : onrc (TELTRAP, r, c) ? 50 : onrc (GASTRAP, r, c) ? 50 : onrc (BEARTRP, r, c) ? 50 : onrc (DARTRAP, r, c) ? 200 : onrc (WATERAP, r, c) ? 50 : onrc (MONSTER, r, c) ? 150 : expavoidval; if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj) a += 200; for (k=0; k<8; k++) /* examine adjacent squares */ { register int nr = r + deltr[k]; register int nc = c + deltc[k]; if (nr >= 1 && nr <= 22 && nc >= 0 && nc <= 80 && onrc (PSD, nr, nc) && timessearched[nr][nc] < SEARCHES(nr,nc)) { /* If adjacent square is on the screen */ /* and if it has PSD set but has not been searched completely */ /* count useful neighbours */ if (screen[nr][nc] == '|') v += 4; else v ++; if (debug (D_SCREEN | D_INFORM)) mvaddch (nr, nc, 'S'); } } if (v>0) { if (version >= RV53A && onrc (DOOR|BEEN, r, c) == DOOR|BEEN && (onrc (CANGO|WALL, r+1, c) == 0 || onrc (CANGO|WALL, r-1, c) == 0 || onrc (CANGO|WALL, r, c+1) == 0 || onrc (CANGO|WALL, r, c-1) == 0)) { *val = v+100; *cont = 5; } else { v = min (15, v); *val = secretvalues[v]; *cont = secretcont[v]; if (onrc (DOOR, r, c)) a += expDor; } } *avd = a; return (1); } /* * E S T A B L I S H A V O I D A N C E M A P to avoid monsters. */ # define AVOID(r,c,ch) \ { avdmonsters[r][c] = INFINITY; \ if (debug (D_SCREEN)) { at((r),(c)); addch(ch); at(row,col); }} avoidmonsters () { register int i, r, c, wearingstealth; /* Clear old avoid monster values */ for (i = 24*80; i--; ) avdmonsters[0][i] = 0; /* Set stealth status */ wearingstealth = (wearing ("stealth") != NONE); /* Avoid each monster in turn */ for (i=0; i<mlistlen; i++) { /* First check whether this monster is really wimpy */ if (maxhit(i) < Hp/2) { AVOID (mlist[i].mrow, mlist[i].mcol, '$') } /* If not a wimp and awake, avoid him all together */ else if (mlist[i].q == AWAKE) { int d, dr, dc, mr = mlist[i].mrow, mc = mlist[i].mcol; d = direc (searchstartr-mr,searchstartc-mc); dr = (searchstartr-mr)/2+mr; dc=(searchstartc-mc)/2+mc; if (d & 1) { caddycorner (dr, dc, (d-1) & 7, (d-3)&7, '$'); caddycorner (dr, dc, (d+1) & 7, (d+3)&7, '$'); } else { caddycorner (dr, dc, (d-2) & 7, d, '$'); caddycorner (dr, dc, (d+2) & 7, d, '$'); } } /* If he'll wake up, give him a wide berth */ else if (!wearingstealth) { for (r = mlist[i].mrow-1; r<= mlist[i].mrow+1; r++) for (c = mlist[i].mcol-1; c<= mlist[i].mcol+1; c++) AVOID (r, c, '$') } /* He's asleep, don't try to run through him */ else AVOID (mlist[i].mrow, mlist[i].mcol, '$') } /* Don't avoid current position */ avdmonsters[searchstartr][searchstartc] = 0; dwait (D_SEARCH, "Avoidmonsters: avoiding the $s"); } /* * caddycorner: Find sqaures the monster can reach before we can and mark * them for avoidance */ caddycorner (r, c, d1, d2, ch) int r,c,d1,d2; char ch; { while (onrc (CANGO, r, c)) { AVOID (r, c, ch); r += deltr[d1]; c += deltc[d1]; if (!onrc (CANGO, r, c)) break; AVOID (r, c, ch); r += deltr[d2]; c += deltc[d2]; } } /* * E S T A B L I S H A V O I D A N C E M A P when pinned * * This routine is basically the same as avoidmonsters, except that * the value are calculated to allow the monster one hit instead of * avoiding him entirely. This allows us to escape from situations where * we are pinned, but could get free if we had an extra turn. MLM */ pinavoid () { register int i; /* Clear old avoid monster values */ for (i = 24*80; i--; ) avdmonsters[0][i] = 0; /* Avoid each monster in turn */ for (i=0; i<mlistlen; i++) { if (mlist[i].q == AWAKE) { register int d, dr, dc, mr = mlist[i].mrow, mc = mlist[i].mcol; d = direc (searchstartr-mr,searchstartc-mc); dr = (searchstartr-mr)/2+mr - deltr[d]; /* MLM */ dc=(searchstartc-mc)/2+mc - deltc[d]; /* MLM */ if (d & 1) { caddycorner (dr, dc, (d-1) & 7, (d-3)&7, '&'); caddycorner (dr, dc, (d+1) & 7, (d+3)&7, '&'); } else { caddycorner (dr, dc, (d-2) & 7, (d-4) & 7, '&'); /* MLM */ caddycorner (dr, dc, (d+2) & 7, (d+4) & 7, '&'); /* MLM */ } } AVOID (mlist[i].mrow, mlist[i].mcol, '&'); } /* Don't avoid current position */ avdmonsters[searchstartr][searchstartc] = 0; dwait (D_SEARCH, "Pinavoid: avoiding the &s"); } /* * S E C R E T : Search dead ends for secret doors. */ secret () { int secretinit(), secretvalue(); /* Secret passage adjacent to door? */ if (version >= RV53A && on (DOOR) && !blinded && (seerc (' ',atrow+1,atcol) || seerc (' ',atrow-1,atcol) || seerc (' ',atrow,atcol+1) || seerc (' ',atrow,atcol-1)) && SEARCHES (atrow, atcol) < timestosearch+20) { int count = timessearched[atrow][atcol]+1; saynow ("Searching dead end door (%d,%d) for the %d%s time...", atrow, atcol, count, ordinal (count)); command (T_DOORSRCH, "s"); return (1); } /* Verify that we are actually at a dead end */ if (onrc (CANGO,atrow-1,atcol) + onrc (CANGO,atrow,atcol-1) + onrc (CANGO,atrow+1,atcol) + onrc (CANGO,atrow,atcol+1) != CANGO) return (0); /* If Level 1 or edge of screen: dead end cannot be room, mark and return */ if (Level == 1 && attempt == 0 || version < RV53A && (atrow<=1 || atrow>=22 || atcol<=0 || atcol>=79)) { markexplored (atrow, atcol); return (0); } /* Have we mapped this level? */ if (Level == didreadmap) return (0); /* Found a dead end, should we search it? */ if (nexttowall (atrow, atcol) || canbedoor (atrow, atcol) && (version >= RV53A || !isexplored (atrow, atcol))) { setrc (DEADEND, atrow, atcol); if ((SEARCHES (atrow, atcol) - timessearched[atrow][atcol]) > 0) { int count = timessearched[atrow][atcol]+1; saynow ("Searching dead end (%d,%d) for the %d%s time...", atrow, atcol, count, ordinal (count)); command (T_DOORSRCH, "s"); return (1); } else { markexplored (atrow, atcol); return (0); } } return (0); } /* * F I N D R O O M : Try to find another room. */ findroom () { int expinit(), expvalue(); /* LGCH */ if (new_findroom) { if (!on (ROOM) && secret ()) return (1); if (makemove (EXPLORE, expinit, expvalue, REUSE)) return (1); } new_findroom = 0; dwait (D_SEARCH, "findroom failed."); return (0); } /* * E X P L O R E R O O M : Explore the current room. */ exploreroom () { int roominit(), expvalue(); /* LGCH */ if (!on (ROOM) || isexplored (atrow, atcol)) return (0); if (makemove (EXPLOREROOM, roominit, expvalue, REUSE)) return (1); markexplored (atrow, atcol); dwait (D_SEARCH, "exploreroom failed."); return (0); } /* * D O O R E X P L O R E : look for secret doors */ doorexplore() { static searchcount = 0; int secretinit(), secretvalue(); /* If no new squares or read map, dont bother */ if (! new_search || Level == didreadmap) { searchcount = 0; return (0); } if (makemove (SECRETDOOR, secretinit, secretvalue, REUSE)) /* move */ { searchcount = 0; return (1); } if (searchcount > 20) { new_search = 0; return (0); } if (ontarget) /* Moved to a possible secret door, search it */ { searchcount++; saynow ("Searching square (%d,%d) for the %d%s time...", atrow, atcol, searchcount, ordinal (searchcount)); command (T_DOORSRCH, "s"); return (1); } new_search = searchcount = 0; return (0); } /* * S A F E S Q U A R E S E A R C H Use genericinit. */ safevalue (r, c, depth, val, avd, cont) int r, c, depth, *val, *avd, *cont; { register int k, v; *avd = onrc (SAFE, r, c) ? 0 : onrc (TRAPDOR | BEARTRP | GASTRAP, r, c) ? INFINITY : onrc (ARROW, r, c) ? 50 : onrc (TELTRAP, r, c) ? 50 : onrc (DARTRAP, r, c) ? 200 : onrc (WATERAP, r, c) ? 50 : onrc (MONSTER, r, c) ? 150 : expavoidval; *val = 0; if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj) *avd += 500; if (onrc(CANGO, r, c)) { v = 0; for (k=0; k<8; k++) if (onrc(CANGO, r+deltr[k], c+deltc[k]) && onrc(CANGO, r+deltr[k], c) && onrc(CANGO, r, c+deltc[k])) v++; if (v < 3) *val = 1; /* *cont = 0; // default // */ } return (1); } /* findsafe: find a spot with 2 or fewer moves, for when blinded */ findsafe() { return (makemove (FINDSAFE, genericinit, safevalue, REEVAL)); } /* How scared are we of hitting a trap? */ avoid () { if (cheat && !foundarrowtrap && !usingarrow) return (0); else if (Level < 5) return (0); /* Don't bother */ else return (2); /* Avoid a little */ } /* * archery: Initialize a archery move. We find a good place to * shoot from and stand there. Then mark the monster as awake, and * battlestations will handle firing at him. */ static int archrow = NONE, archcol = NONE, archturns = NONE, archval[24][80]; archmonster (m, turns) register int m; /* Monster to attack */ register int turns; /* Minimum number of arrows to make it worthwhile */ { int archeryinit(), archeryvalue(); register int mr, mc; dwait (D_CONTROL | D_BATTLE, "archmonster: m=%d, turns=%d", m, turns); if (! new_arch) return (0); /* Useless without arrows */ if (havemult (missile, "", turns) < 0) { dwait (D_BATTLE, "archmonster, fewer than %d missiles", turns); return (0); } /* For now, only work for sleeping monsters */ if (mlist[m].q != ASLEEP) { dwait (D_BATTLE, "archmonster, monster not asleep"); return (0); } /* Save globals */ archrow = mlist[m].mrow; archcol = mlist[m].mcol; archturns = turns; /* Can we get to a suitable square */ if (makemove (ARCHERYMOVE, archeryinit, archeryvalue, REUSE)) { dwait (D_BATTLE, "archmonster, made a move"); return (1); } /* If no move made and not on target, no path to monster */ if (!ontarget) { new_arch = 0; return (0); } /* On target: wake him up and set darkdir/turns if necessary */ mr = mlist[m].mrow; mc = mlist[m].mcol; targetmonster = mlist[m].chr; mlist[m].q = AWAKE; dwait (D_BATTLE, "archmonster, waking him up"); /* Set dark room archery variables, add goal of standing on square */ if (darkroom ()) { darkdir = direc (mr-atrow, mc-atcol); darkturns = max (abs (mr-atrow), abs (mc-atcol)); agoalr = mr; agoalc = mc; /* Go here to pick up what (s)he drops */ } /* Tell the user about it */ saynow ("Arching at %s", monname (mlist[m].chr)); return (1); } /* * archeryinit: Initialize a archery move. Must avoid monsters to avoid * waking our potential victim up. */ archeryinit () { register int dir, r, c, dr, dc, dist; /* Clear the archery value array */ for (r = 24*80; r--; ) archval[0][r] = 0; /* Scan around monster to see how far away we can shoot from */ for (dir = 0; dir < 8; dir++) { dr = deltr[dir]; dc = deltc[dir]; for (dist = 1, r = archrow+dr, c = archcol+dc; onrc (CANGO | HALL | MONSTER, r, c) == CANGO; r += dr, c += dc, dist++) if (dist > archturns && !onrc (TRAP, r, c)) { archval[r][c] = dist - 1; /* number of arrows we get to shoot */ if (debug (D_SCREEN)) { at (r, c); addch ('='); at (row, col); } } } expavoidval = avoid(); avoidmonsters (); return (1); } /* * archeryvalue: Get the value of the square from the archery array. * Value is non-zero only if we can fire arrows at beast and value is * number of shots we can fire. */ archeryvalue (r, c, depth, val, avd, cont) int r, c, depth, *val, *avd, *cont; { *avd = (onrc (SAFE, r, c) ? 0 : onrc (TRAPDOR, r, c) ? INFINITY : onrc (HALL, r, c) ? INFINITY : onrc (ARROW, r, c) ? 50 : onrc (TELTRAP, r, c) ? 50 : onrc (GASTRAP, r, c) ? 50 : onrc (BEARTRP, r, c) ? 50 : onrc (DARTRAP, r, c) ? 200 : onrc (WATERAP, r, c) ? 50 : onrc (MONSTER, r, c) ? 150 : expavoidval) + avdmonsters[r][c]; if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj) *avd += 500; *val = archval[r][c]; *cont = INFINITY; return (1); } /* * M O V E T O R E S T : Find a safe square to rest up on. */ static restinlight = 0; /* True only in lit rooms */ static restinroom = 0; /* True only in a room */ static restr = NONE, restc = NONE; /* Square to rest on */ /* Set new resting goal */ unrest () { restr = restc = NONE; } /* Move to a good square to rest up on */ movetorest () { int restinit(), restvalue(); /* LGCH */ if (markcycles (NOPRINT)) unrest (); /* If we are where we want to rest, do so */ if (restr >= 0 && atrow == restr && atcol == restc) { dwait (D_SEARCH, "movetorest: already on square"); return (0); } /* Try to move to a better square (remember position) */ if (makemove (RESTMOVE, restinit, restvalue, REUSE)) { dwait (D_SEARCH, "movetorest wins."); restr = targetrow; restc = targetcol; return (1); } /* Cant move anywhere better, stay here */ dwait (D_SEARCH, "movetorest fails."); restr = atrow; restc = atcol; return (0); } restinit () { expavoidval = avoid(); restinlight = (on (ROOM) && !darkroom ()); restinroom = on (ROOM); return (1); } restvalue (r, c, depth, val, avd, cont) register int r, c; int depth, *val, *avd, *cont; { register int dr, dc, ar, ac; int count, dir, rm; /* Find room number for diagonal selection */ if ((rm = whichroom (r, c)) < 0) rm = 4; /* Default is no value, no avoidance */ *avd = *val = 0; /* Set base value of square */ if (onrc (TRAP|MONSTER,r, c)) { *avd = INFINITY; return (0); } else if (restinroom && onrc (DOOR,r, c)) { *avd = INFINITY; return (0); } else if (onrc (SCAREM, r, c)) { if (objcount == maxobj || version >= RV53A) { *val = 500; return (1); } else { *avd = INFINITY; return (0); } } else if (onrc (STAIRS, r, c)) { *val = 400; return (1); } else if (onrc (ROOM, r, c)) { *val = 1; *cont = 99;} else if (!onrc (SAFE|BEEN|STUFF, r, c)) { *avd = 5; } /* Give bonus for being next to a trap door or a teleport trap */ if (onrc (TRAPDOR|TELTRAP, r-1, c-1) || onrc (TRAPDOR|TELTRAP, r+1, c-1) || onrc (TRAPDOR|TELTRAP, r-1, c+1) || onrc (TRAPDOR|TELTRAP, r+1, c+1)) { *val += 80; *cont = 99;} if (onrc (TRAPDOR|TELTRAP, r-1, c) || onrc (TRAPDOR|TELTRAP, r+1, c) || onrc (TRAPDOR|TELTRAP, r, c-1) || onrc (TRAPDOR|TELTRAP, r, c+1)) { *val += 30; *cont = 99;} /* In lit rooms (with ammo) stay away from doors, this gives us time */ /* to shoot arrows at monsters coming in at us MLM 06/21/83 */ if (restinlight && ammo) { for (dir = 0; dir < 8; dir += 2) { dr = deltr[dir]; dc = deltc[dir]; for (count = 0, ar = r+dr, ac = c+dc; onrc (CANGO | HALL | MONSTER, ar, ac) == CANGO; ar += dr, ac += dc, count++) { /* Bonus of 'count' if this square covers a door */ if (onrc(DOOR,ar+deltr[(dir+2)%8],ac+deltc[(dir+2)%8])) *val += count; if (onrc(DOOR,ar+deltr[(dir+6)%8],ac+deltc[(dir+6)%8])) *val += count; if (onrc(DOOR,ar,ac)) *val += count; } } } /* In dark rooms, stand diagonally away from doors (1 extra turn) */ else if (onrc (ROOM, r, c)) { if (onrc (DOOR,r-1,c-1) && (rm!=0 && rm!=1 && rm!=3)) {*val+=80;*cont=99;} if (onrc (DOOR,r+1,c-1) && (rm!=3 && rm!=6 && rm!=7)) {*val+=80;*cont=99;} if (onrc (DOOR,r-1,c+1) && (rm!=1 && rm!=2 && rm!=5)) {*val+=80;*cont=99;} if (onrc (DOOR,r+1,c+1) && (rm!=5 && rm!=7 && rm!=8)) {*val+=80;*cont=99;} /* Bonus for door also orthogonally away */ if(onrc(DOOR,r,c-1)||onrc(DOOR,r-1,c)||onrc(DOOR,r,c+1)||onrc(DOOR,r+1,c)) { *val+=30; *cont=99; } } return (1); }