1:
2: # ifdef OTTO
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46: #include <sys/cdefs.h>
47: #ifndef lint
48: __RCSID("$NetBSD: otto.c,v 1.8 2004/11/05 21:30:32 dsl Exp $");
49: #endif
50:
51: # include <sys/time.h>
52: # include <curses.h>
53: # include <ctype.h>
54: # include <signal.h>
55: # include <stdlib.h>
56: # include <unistd.h>
57: # include "hunt.h"
58:
59: # undef WALL
60: # undef NORTH
61: # undef SOUTH
62: # undef WEST
63: # undef EAST
64: # undef FRONT
65: # undef LEFT
66: # undef BACK
67: # undef RIGHT
68:
69: # ifdef HPUX
70: # define random rand
71: # endif
72:
73: # ifndef USE_CURSES
74: extern char screen[SCREEN_HEIGHT][SCREEN_WIDTH2];
75: # define SCREEN(y, x) screen[y][x]
76: # else
77: # define SCREEN(y, x) mvinch(y, x)
78: # endif
79:
80: # ifndef DEBUG
81: # define STATIC static
82: # else
83: # define STATIC
84: # endif
85:
86: # define OPPONENT "{}i!"
87: # define PROPONENT "^v<>"
88: # define WALL "+\\/#*-|"
89: # define PUSHOVER " bg;*#&"
90: # define SHOTS "$@Oo:"
91:
92:
93: # define NUMDIRECTIONS 4
94:
95:
96: # define NORTH 0
97: # define WEST 1
98: # define SOUTH 2
99: # define EAST 3
100: # define ALLDIRS 0xf
101:
102:
103: # define FRONT 0
104: # define LEFT 1
105: # define BACK 2
106: # define RIGHT 3
107:
108: # define ABSCHARS "NWSE"
109: # define RELCHARS "FLBR"
110: # define DIRKEYS "khjl"
111:
112: STATIC char command[BUFSIZ];
113: STATIC int comlen;
114:
115: # ifdef DEBUG
116: STATIC FILE *debug = NULL;
117: # endif
118:
119: # define DEADEND 0x1
120: # define ON_LEFT 0x2
121: # define ON_RIGHT 0x4
122: # define ON_SIDE (ON_LEFT|ON_RIGHT)
123: # define BEEN 0x8
124: # define BEEN_SAME 0x10
125:
126: struct item {
127: char what;
128: int distance;
129: int flags;
130: };
131:
132: STATIC struct item flbr[NUMDIRECTIONS];
133:
134: # define fitem flbr[FRONT]
135: # define litem flbr[LEFT]
136: # define bitem flbr[BACK]
137: # define ritem flbr[RIGHT]
138:
139: STATIC int facing;
140: STATIC int row, col;
141: STATIC int num_turns;
142: STATIC char been_there[HEIGHT][WIDTH2];
143: STATIC struct itimerval pause_time = { { 0, 0 }, { 0, 55000 }};
144:
145: STATIC void attack(int, struct item *);
146: STATIC void duck(int);
147: STATIC void face_and_move_direction(int, int);
148: STATIC int go_for_ammo(char);
149: STATIC void ottolook(int, struct item *);
150: STATIC void look_around(void);
151: STATIC SIGNAL_TYPE nothing(int);
152: STATIC int stop_look(struct item *, char, int, int);
153: STATIC void wander(void);
154:
155: extern int Otto_count;
156:
157: STATIC SIGNAL_TYPE
158: nothing(dummy)
159: int dummy __attribute__((__unused__));
160: {
161: }
162:
163: void
164: otto(y, x, face)
165: int y, x;
166: char face;
167: {
168: int i;
169: int old_mask;
170:
171: # ifdef DEBUG
172: if (debug == NULL) {
173: debug = fopen("bug", "w");
174: setbuf(debug, NULL);
175: }
176: fprintf(debug, "\n%c(%d,%d)", face, y, x);
177: # endif
178: (void) signal(SIGALRM, nothing);
179: old_mask = sigblock(sigmask(SIGALRM));
180: setitimer(ITIMER_REAL, &pause_time, NULL);
181: sigpause(old_mask);
182: sigsetmask(old_mask);
183:
184:
185: switch (face) {
186: case '^': facing = NORTH; break;
187: case '<': facing = WEST; break;
188: case 'v': facing = SOUTH; break;
189: case '>': facing = EAST; break;
190: default: abort();
191: }
192: row = y; col = x;
193: been_there[row][col] |= 1 << facing;
194:
195:
196: comlen = 0;
197:
198:
199: look_around();
200: for (i = 0; i < NUMDIRECTIONS; i++) {
201: if (strchr(OPPONENT, flbr[i].what) != NULL) {
202: attack(i, &flbr[i]);
203: memset(been_there, 0, sizeof been_there);
204: goto done;
205: }
206: }
207:
208: if (strchr(SHOTS, bitem.what) != NULL && !(bitem.what & ON_SIDE)) {
209: duck(BACK);
210: memset(been_there, 0, sizeof been_there);
211: # ifdef BOOTS
212: } else if (go_for_ammo(BOOT_PAIR)) {
213: memset(been_there, 0, sizeof been_there);
214: } else if (go_for_ammo(BOOT)) {
215: memset(been_there, 0, sizeof been_there);
216: # endif
217: } else if (go_for_ammo(GMINE))
218: memset(been_there, 0, sizeof been_there);
219: else if (go_for_ammo(MINE))
220: memset(been_there, 0, sizeof been_there);
221: else
222: wander();
223:
224: done:
225: (void) write(Socket, command, comlen);
226: Otto_count += comlen;
227: # ifdef DEBUG
228: (void) fwrite(command, 1, comlen, debug);
229: # endif
230: }
231:
232: # define direction(abs,rel) (((abs) + (rel)) % NUMDIRECTIONS)
233:
234: STATIC int
235: stop_look(itemp, c, dist, side)
236: struct item *itemp;
237: char c;
238: int dist;
239: int side;
240: {
241: switch (c) {
242:
243: case SPACE:
244: if (side)
245: itemp->flags &= ~DEADEND;
246: return 0;
247:
248: case MINE:
249: case GMINE:
250: # ifdef BOOTS
251: case BOOT:
252: case BOOT_PAIR:
253: # endif
254: if (itemp->distance == -1) {
255: itemp->distance = dist;
256: itemp->what = c;
257: if (side < 0)
258: itemp->flags |= ON_LEFT;
259: else if (side > 0)
260: itemp->flags |= ON_RIGHT;
261: }
262: return 0;
263:
264: case SHOT:
265: case GRENADE:
266: case SATCHEL:
267: case BOMB:
268: # ifdef OOZE
269: case SLIME:
270: # endif
271: if (itemp->distance == -1 || (!side
272: && (itemp->flags & ON_SIDE
273: || itemp->what == GMINE || itemp->what == MINE))) {
274: itemp->distance = dist;
275: itemp->what = c;
276: itemp->flags &= ~ON_SIDE;
277: if (side < 0)
278: itemp->flags |= ON_LEFT;
279: else if (side > 0)
280: itemp->flags |= ON_RIGHT;
281: }
282: return 0;
283:
284: case '{':
285: case '}':
286: case 'i':
287: case '!':
288: itemp->distance = dist;
289: itemp->what = c;
290: itemp->flags &= ~(ON_SIDE|DEADEND);
291: if (side < 0)
292: itemp->flags |= ON_LEFT;
293: else if (side > 0)
294: itemp->flags |= ON_RIGHT;
295: return 1;
296:
297: default:
298:
299: if (side)
300: return 0;
301: if (itemp->distance == -1) {
302: itemp->distance = dist;
303: itemp->what = c;
304: }
305: return 1;
306: }
307: }
308:
309: STATIC void
310: ottolook(rel_dir, itemp)
311: int rel_dir;
312: struct item *itemp;
313: {
314: int r, c;
315: char ch;
316:
317: r = 0;
318: itemp->what = 0;
319: itemp->distance = -1;
320: itemp->flags = DEADEND|BEEN;
321:
322: switch (direction(facing, rel_dir)) {
323:
324: case NORTH:
325: if (been_there[row - 1][col] & NORTH)
326: itemp->flags |= BEEN_SAME;
327: for (r = row - 1; r >= 0; r--)
328: for (c = col - 1; c < col + 2; c++) {
329: ch = SCREEN(r, c);
330: if (stop_look(itemp, ch, row - r, c - col))
331: goto cont_north;
332: if (c == col && !been_there[r][c])
333: itemp->flags &= ~BEEN;
334: }
335: cont_north:
336: if (itemp->flags & DEADEND) {
337: itemp->flags |= BEEN;
338: been_there[r][col] |= NORTH;
339: for (r = row - 1; r > row - itemp->distance; r--)
340: been_there[r][col] = ALLDIRS;
341: }
342: break;
343:
344: case SOUTH:
345: if (been_there[row + 1][col] & SOUTH)
346: itemp->flags |= BEEN_SAME;
347: for (r = row + 1; r < HEIGHT; r++)
348: for (c = col - 1; c < col + 2; c++) {
349: ch = SCREEN(r, c);
350: if (stop_look(itemp, ch, r - row, col - c))
351: goto cont_south;
352: if (c == col && !been_there[r][c])
353: itemp->flags &= ~BEEN;
354: }
355: cont_south:
356: if (itemp->flags & DEADEND) {
357: itemp->flags |= BEEN;
358: been_there[r][col] |= SOUTH;
359: for (r = row + 1; r < row + itemp->distance; r++)
360: been_there[r][col] = ALLDIRS;
361: }
362: break;
363:
364: case WEST:
365: if (been_there[row][col - 1] & WEST)
366: itemp->flags |= BEEN_SAME;
367: for (c = col - 1; c >= 0; c--)
368: for (r = row - 1; r < row + 2; r++) {
369: ch = SCREEN(r, c);
370: if (stop_look(itemp, ch, col - c, row - r))
371: goto cont_west;
372: if (r == row && !been_there[r][c])
373: itemp->flags &= ~BEEN;
374: }
375: cont_west:
376: if (itemp->flags & DEADEND) {
377: itemp->flags |= BEEN;
378: been_there[r][col] |= WEST;
379: for (c = col - 1; c > col - itemp->distance; c--)
380: been_there[row][c] = ALLDIRS;
381: }
382: break;
383:
384: case EAST:
385: if (been_there[row][col + 1] & EAST)
386: itemp->flags |= BEEN_SAME;
387: for (c = col + 1; c < WIDTH; c++)
388: for (r = row - 1; r < row + 2; r++) {
389: ch = SCREEN(r, c);
390: if (stop_look(itemp, ch, c - col, r - row))
391: goto cont_east;
392: if (r == row && !been_there[r][c])
393: itemp->flags &= ~BEEN;
394: }
395: cont_east:
396: if (itemp->flags & DEADEND) {
397: itemp->flags |= BEEN;
398: been_there[r][col] |= EAST;
399: for (c = col + 1; c < col + itemp->distance; c++)
400: been_there[row][c] = ALLDIRS;
401: }
402: break;
403:
404: default:
405: abort();
406: }
407: }
408:
409: STATIC void
410: look_around()
411: {
412: int i;
413:
414: for (i = 0; i < NUMDIRECTIONS; i++) {
415: ottolook(i, &flbr[i]);
416: # ifdef DEBUG
417: fprintf(debug, " ottolook(%c)=%c(%d)(0x%x)",
418: RELCHARS[i], flbr[i].what, flbr[i].distance, flbr[i].flags);
419: # endif
420: }
421: }
422:
423:
424:
425:
426:
427: STATIC void
428: face_and_move_direction(rel_dir, distance)
429: int rel_dir, distance;
430: {
431: int old_facing;
432: char cmd;
433:
434: old_facing = facing;
435: cmd = DIRKEYS[facing = direction(facing, rel_dir)];
436:
437: if (rel_dir != FRONT) {
438: int i;
439: struct item items[NUMDIRECTIONS];
440:
441: command[comlen++] = toupper((unsigned char)cmd);
442: if (distance == 0) {
443:
444: for (i = 0; i < NUMDIRECTIONS; i++)
445: items[i] =
446: flbr[(i + old_facing) % NUMDIRECTIONS];
447: memcpy(flbr, items, sizeof flbr);
448: }
449: }
450: while (distance--) {
451: command[comlen++] = cmd;
452: switch (facing) {
453:
454: case NORTH: row--; break;
455: case WEST: col--; break;
456: case SOUTH: row++; break;
457: case EAST: col++; break;
458: }
459: if (distance == 0)
460: look_around();
461: }
462: }
463:
464: STATIC void
465: attack(rel_dir, itemp)
466: int rel_dir;
467: struct item *itemp;
468: {
469: if (!(itemp->flags & ON_SIDE)) {
470: face_and_move_direction(rel_dir, 0);
471: command[comlen++] = 'o';
472: command[comlen++] = 'o';
473: duck(FRONT);
474: command[comlen++] = ' ';
475: } else if (itemp->distance > 1) {
476: face_and_move_direction(rel_dir, 2);
477: duck(FRONT);
478: } else {
479: face_and_move_direction(rel_dir, 1);
480: if (itemp->flags & ON_LEFT)
481: rel_dir = LEFT;
482: else
483: rel_dir = RIGHT;
484: (void) face_and_move_direction(rel_dir, 0);
485: command[comlen++] = 'f';
486: command[comlen++] = 'f';
487: duck(FRONT);
488: command[comlen++] = ' ';
489: }
490: }
491:
492: STATIC void
493: duck(rel_dir)
494: int rel_dir;
495: {
496: int dir;
497:
498: switch (dir = direction(facing, rel_dir)) {
499:
500: case NORTH:
501: case SOUTH:
502: if (strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
503: command[comlen++] = 'h';
504: else if (strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
505: command[comlen++] = 'l';
506: else if (dir == NORTH
507: && strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL)
508: command[comlen++] = 'j';
509: else if (dir == SOUTH
510: && strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL)
511: command[comlen++] = 'k';
512: else if (dir == NORTH)
513: command[comlen++] = 'k';
514: else
515: command[comlen++] = 'j';
516: break;
517:
518: case WEST:
519: case EAST:
520: if (strchr(PUSHOVER, SCREEN(row -