|
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 m
Length: 23004 (0x59dc) Types: TextFile Names: »monsters.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Pm/Sys3-SysV/monsters.c«
/* ** monsters.c - ** This file contains the necessary functions ** to deal with the monsters and how they move. ** If the flag variable is TRUE, then they are after ** you, else you are after them. ** ** ** [pm by Peter Costantinidis, Jr. @ University of California at Davis] */ #include "pm.h" /* ** harpo - will try his best to get you, but is slow ** - smart, slow ** ** groucho - is always behind you, it is hard to shake him ** - smart, fast ** ** chico - he's fast ** - fast ** ** zeppo - terribly shy and will actually run away from you ** - medium, dumb */ /* ** p_monsters() - place and initialize the monsters for new screens */ void p_monsters () { reg int i; for (i = 0; i < MAX_MONS; i++) m_init(&ghosts[i]); h->mo_pos.x = 26; h->mo_pos.y = 11; g->mo_pos.x = 26; g->mo_pos.y = 9; c->mo_pos.x = 28; c->mo_pos.y = 11; z->mo_pos.x = 24; z->mo_pos.y = 11; h->mo_name = HARPO; g->mo_name = GROUCHO; c->mo_name = CHICO; z->mo_name = ZEPPO; g->mo_inside = FALSE; for (i = 0; i < MAX_MONS; i++) { move(ghosts[i].mo_pos.y, ghosts[i].mo_pos.x); addch(ghosts[i].mo_name); } } /* ** m_move() - move the monsters ** - if they are eatable, then skip them half the time ** - if they are inside, skip them a third of the time */ void m_move () { reg int i; for (i = 0; i < MAX_MONS; i++) { if (ghosts[i].mo_run && (demon % 4L)) continue; mv_mon(&ghosts[i]); if (pm_eaten) return; } } /* ** mv_mon() - make the given monster move ** - maybe change the "mod 5"'s to randomness ** - intelligence is simulated by choosing the best ** possible move, and then occasionally doing some- ** thing random. occasionally is defined relative ** to the intelligence of the monster! ** - when a monster is in the tunnel, it continues ** moving in its original direction ** - returns FALSE if pm is eaten (everything must stop!) */ void mv_mon (m) reg mons *m; { #ifdef FASTER reg int once = FALSE; #endif #ifdef FASTER top: #endif if (!get_move(m)) { m->mo_ch = moves[rnd(0, 3)]; m->mo_cnt = 0; } /* ** take care of slow monsters */ if ((!(demon % SPEED)) && (m->mo_attrib & SLOW) && !m->mo_run && !m->mo_tunn) return; #ifdef FASTER /* ** take care of fast monsters */ if (!(demon % SPEED) && (m->mo_attrib & FAST) && !once && !m->mo_run && !m->mo_tunn) once = TRUE; else if (once) once = FALSE; #endif /* ** take care of dumb monsters ** - 25% of time they move randomly, and if they are inside, ** then 50% of the time they move wrong */ if ((m->mo_attrib & DUMB) && !m->mo_tunn) { if (rnd(1,100) < 25) { if ((m->mo_ch = gen_mv(m)) != MSTOP) m->mo_cnt = DIST(); else m->mo_cnt = 0; } else if (m->mo_inside && (rnd(1, 100) < 45)) { m->mo_ch = opposite(m->mo_ch); m->mo_cnt = 2; } } /* ** take care of medium monsters */ else if ((m->mo_attrib & NORMAL) && !m->mo_tunn) { if (rnd(1,100) < 10) { if ((m->mo_ch = gen_mv(m)) != MSTOP) m->mo_cnt = DIST(); else m->mo_cnt = 0; } else if (m->mo_inside && (rnd(1, 100) < 37)) { m->mo_ch = opposite(m->mo_ch); m->mo_cnt = 2; } else if ((rnd(1, 100) < 15) && (m->mo_ch != MSTOP)) m->mo_cnt = rnd(2, 4); } else if (m->mo_attrib & SMART) { if (m->mo_inside && (rnd(1, 100) < 27)) { m->mo_ch = opposite(m->mo_ch); m->mo_cnt = 2; } } if (!_mv_mon(m)) return; #ifdef FASTER if (once) goto top; #endif } /* ** p_info() - prints information about the given monster */ void p_info (name) reg char name; { reg mons *m; m = wh_mons(name); if (m == NULL) msg("No such monster: %s", punctrl(name)); doclear(); fprintf(stderr, "Name: %c\n", m->mo_name); fprintf(stderr, "Place: (%d,%d)\n", m->mo_pos.x, m->mo_pos.y); fprintf(stderr, "Inch: %c\n", m->mo_inch); fprintf(stderr, "Run: %s\n", TF(m->mo_run)); fprintf(stderr, "Tunn: %s\n", TF(m->mo_tunn)); fprintf(stderr, "Eaten: %s\n", TF(m->mo_eaten)); fprintf(stderr, "Inside: %s\n", TF(m->mo_inside)); fprintf(stderr, "Move: %c\n", m->mo_ch); fprintf(stderr, "Count: %d\n", m->mo_cnt); fprintf(stderr, "Attrib: %o\n\n", m->mo_attrib); printf("[Press return to continue]"); trash(getchar()); /* no need to add fcntl here */ redraw(); } /* ** _mv_mon() - lower level routine to move a monster ** - checks for barriers and stuff... ** - returns FALSE if pm is eaten (everything must stop!) ** - if in tunnel, it will only move half as fast */ _mv_mon (m) reg mons *m; { reg char what; auto coord pos; Above: if (m->mo_tunn) { if (!(demon % 4)) { pos.x = m->mo_pos.x; pos.y = m->mo_pos.y; switch (m->mo_ch) { when MLEFT: if (--pos.x < LEFT) pos.x = RIGHT; when MRIGHT: if (++pos.x > RIGHT) pos.x = LEFT; otherwise: msg("Bad move in tunn"); } } else /* not moving this time around */ return(TRUE); switch (what = tunn_look(&pos)) { case PM: m->mo_pos.x = pos.x; m->mo_pos.y = pos.y; if (OUTOFTUNN(&m->mo_pos)) m->mo_tunn = FALSE; if (m->mo_run) { pm_eat_m(m->mo_name); return(FALSE); } m_eat_pm(m); return(FALSE); case EMPTY: if (!OUTOFTUNN(&pos)) msg("Lost out of tunn"); m->mo_tunn = FALSE; goto ok; case TUNNEL: m->mo_pos.x = pos.x; m->mo_pos.y = pos.y; m->mo_inch = what; return(TRUE); default: /* ** ran into another monster? */ m->mo_ch = opposite(m->mo_ch); msg("Ran into another monster"); return(TRUE); } } else { if (move_to(m->mo_ch, &m->mo_pos, &pos) == -1) return(-1); move(pos.y, pos.x); what = INCH(); } switch (what) { when PM: mvaddch(m->mo_pos.y, m->mo_pos.x, m->mo_inch); draw(); m->mo_pos.x = pos.x; m->mo_pos.y = pos.y; if (m->mo_run) return(pm_eat_m(m->mo_name), FALSE); mvaddch(pos.y, pos.x, m->mo_name); draw(); m->mo_inch = EMPTY; m_eat_pm(m); return(FALSE); when BLOCK: m->mo_cnt = 0; when DOT: case ENERGY: case EMPTY: ok: mvaddch(m->mo_pos.y, m->mo_pos.x, m->mo_inch); #ifdef MAX_UPDATE draw(); #endif mvaddch(pos.y, pos.x, m->mo_name); m->mo_pos.x = pos.x; m->mo_pos.y = pos.y; m->mo_inch = what; when DOOR: if (!m->mo_inside) /* can only exit, not enter */ { m->mo_cnt = 0; break; } mvaddch(m->mo_pos.y, m->mo_pos.x, m->mo_inch); #ifdef MAX_UPDATE draw(); #endif mvaddch(pos.y, pos.x, m->mo_name); m->mo_pos.x = pos.x; m->mo_pos.y = pos.y; m->mo_inch = what; m->mo_inside = FALSE; when TUNNEL: if (tunn_look(&pos) != TUNNEL) break; mvaddch(m->mo_pos.y, m->mo_pos.x, m->mo_inch); m->mo_inch = TUNNEL; m->mo_tunn = TRUE; m->mo_pos.x = pos.x; m->mo_pos.y = pos.y; goto Above; otherwise: if (IS_FRUIT(what)) goto ok; if (!is_mons(what)) { msg("_mv_mon(): default"); break; } m->mo_cnt = 0; } draw(); return(TRUE); } /* ** get_move() - find a smart move for the given monster ** - return FALSE if none was determined */ int get_move (m) reg mons *m; { reg int i, dist = 0; auto char tmp; if (m->mo_cnt > 0) m->mo_cnt--; /* ** must always move up when on the door!!! */ if (m->mo_inch == DOOR) { m->mo_ch = MUP; m->mo_cnt = 0; return(TRUE); } if (m->mo_tunn) { /* if in tunnel, keep moving */ #ifdef DEBUG if (!m->mo_ch) msg("m's in tunn, & mo_ch is null"); #endif return(TRUE); } if (m->mo_inside) { /* ** still inside their little cave (box) ** make them move to space under the door if they ** are not there already */ if (m->mo_pos.x > DOOR_COL) { m->mo_ch = MLEFT; m->mo_cnt = 1; return(TRUE); } if (m->mo_pos.x < DOOR_COL) { m->mo_ch = MRIGHT; m->mo_cnt = 1; return(TRUE); } /* ** they're under the door, try to move up! */ m->mo_ch = MUP; m->mo_cnt = 1; return(TRUE); } tmp = m->mo_ch; for (i = 0; i < 4; i++) { m->mo_ch = int_dir(i); if (dist = can_see(m, &pm_pos)) break; } if (m->mo_run && dist) /* running away from him */ { m->mo_cnt = 0; if (m_is_safe(m, opposite(m->mo_ch))) return(m->mo_ch = opposite(m->mo_ch), TRUE); m->mo_ch = tmp; if ((m->mo_ch = gen_mv(m)) != MSTOP) return(TRUE); m->mo_ch = (rnd(0, 1) ? lturn(m->mo_ch) : rturn(m->mo_ch)); return(FALSE); } if (dist) return(m->mo_cnt = dist, TRUE); m->mo_ch = tmp; if (m->mo_cnt) /* check for predetermination */ return(TRUE); m->mo_cnt = 0; if ((m->mo_ch = gen_mv(m)) != MSTOP) return(TRUE); m->mo_ch = tmp; if (m_is_safe(m, m->mo_ch)) return(TRUE); return(FALSE); } /* ** gen_mv() - generate a move when no heuristics are available ** - turn 80% of the time, 50% of that left, 50% right ** - 20% of the time just keep going */ char gen_mv (m) reg mons *m; { if (rnd(0, 99) < 40) { if (m_is_safe(m, rturn(m->mo_ch))) return(rturn(m->mo_ch)); if (m_is_safe(m, lturn(m->mo_ch))) return(lturn(m->mo_ch)); return(MSTOP); } if (rnd(0, 59) < 40) { if (m_is_safe(m, lturn(m->mo_ch))) return(lturn(m->mo_ch)); if (m_is_safe(m, rturn(m->mo_ch))) return(rturn(m->mo_ch)); return(MSTOP); } if (m_is_safe(m, m->mo_ch)) return(m->mo_ch); if (rnd(0, 1)) { if (m_is_safe(m, rturn(m->mo_ch))) return(rturn(m->mo_ch)); if (m_is_safe(m, lturn(m->mo_ch))) return(lturn(m->mo_ch)); return(MSTOP); } if (m_is_safe(m, lturn(m->mo_ch))) return(lturn(m->mo_ch)); if (m_is_safe(m, rturn(m->mo_ch))) return(rturn(m->mo_ch)); return(MSTOP); } /* ** m_is_safe() - return TRUE if monster can move in the indicated ** direction */ int m_is_safe (m, dir) reg mons *m; reg char dir; { reg char what; auto coord pos; if (move_to(dir, &m->mo_pos, &pos)) return(FALSE); move(pos.y, pos.x); switch (what = INCH()) { case HARPO: case _HARPO: case GROUCHO: case _GROUCHO: case CHICO: case _CHICO: case ZEPPO: case _ZEPPO: case BLOCK: case DOOR: return(FALSE); case DOT: case ENERGY: case EMPTY: case TUNNEL: return(TRUE); case PM: if (m->mo_run) return(FALSE); return(TRUE); default: if (IS_FRUIT(what)) return(TRUE); msg("m_is_safe default"); return(FALSE); } } /* ** can_see() - returns distance the monster is from the pm if ** the pm can be seen ** - look in the direction the monster is facing ** - special case for when pm is in tunnel, then the ** monster must be facing the tunnel */ int can_see (m, pos) reg mons *m; reg coord *pos; { auto int dist = 0; auto coord mv; switch (m->mo_ch) { when MUP: if (m->mo_pos.x != pos->x) /* not in line */ return(FALSE); if ((m->mo_pos.y == TUNN_ROW) && pm_tunn) break; if (m->mo_pos.y < pos->y) /* not facing */ return(FALSE); when MDOWN: if (m->mo_pos.x != pos->x) /* not in line */ return(FALSE); if ((m->mo_pos.y == TUNN_ROW) && pm_tunn) break; if (m->mo_pos.y > pos->y) /* not facing */ return(FALSE); when MLEFT: if (m->mo_pos.y != pos->y) /* not in line */ return(FALSE); if ((m->mo_pos.y == TUNN_ROW) && pm_tunn) break; if (m->mo_pos.x < pos->x) /* not facing */ return(FALSE); when MRIGHT: if (m->mo_pos.y != pos->y) /* not in line */ return(FALSE); if ((m->mo_pos.y == TUNN_ROW) && pm_tunn) break; if (m->mo_pos.x > pos->x) /* not facing */ return(FALSE); otherwise: msg("default in can_see: \%03o", m->mo_ch); return(FALSE); } /* ** at this point, they are in direct line and ** facing in the right direction, we need to ** see if anything is in the way */ mv.x = m->mo_pos.x; mv.y = m->mo_pos.y; do { reg char what; if (move_to(m->mo_ch, &mv, &mv) == -1) return(msg("move_to=-1"), FALSE); move(mv.y, mv.x); switch (what = INCH()) { case PM: case HARPO: case _HARPO: case GROUCHO: case _GROUCHO: case CHICO: case _CHICO: case ZEPPO: case _ZEPPO: case DOT: case ENERGY: case DOOR: case EMPTY: break; case TUNNEL: if (pm_tunn) return(dist); else msg("can_see(): what???"); case BLOCK: return(0); default: if (IS_FRUIT(what)) /* its the fruit */ break; msg("can_see(): case (2)"); return(0); } dist++; } while ((mv.x != pos->x) || (mv.y != pos->y)); return(dist); } /* ** move_to() - */ int move_to (dir, pos1, pos2) reg int dir; /* declared int to pacify lint */ reg coord *pos1, *pos2; { static int offset[2][4] = { {0, 0, -1, 1}, {-1, 1, 0, 0} }; if ((dir = dir_int((char) dir)) == -1) return(-1); pos2->x = pos1->x + offset[0][dir]; pos2->y = pos1->y + offset[1][dir]; return(0); } /* ** wh_mons() - return pointer to ch's monster struct */ mons *wh_mons (mch) reg char mch; { switch (mch) { case HARPO: case _HARPO: return(h); case GROUCHO: case _GROUCHO: return(g); case CHICO: case _CHICO: return(c); case ZEPPO: case _ZEPPO: return(z); default: msg("Unknown monster!!!"); return((mons *) NULL); } } /* ** m_eat_pm() - a monster has eaten the pm */ void m_eat_pm (m) reg mons *m; { eat_pm(); sleep(1); if (!--pms_left) /* if no more pm's then quit immediately */ die(m->mo_name); #if !SYSV && !SYSIII flush(); /* this totally destroys crmode on System V */ #endif old_screen(); pm_eaten = FALSE; ch = ' '; oldch = '\0'; newch = '\0'; } /* ** eat_pm() - make the pm look eaten */ void eat_pm () { reg int i; if (pm_tunn) return; for (i = 0; i < 5; i++) { mvaddch(pm_pos.y, pm_pos.x, 'O'); draw(); /* msleep(EAT_PAUSE); */ mvaddch(pm_pos.y, pm_pos.x, '='); draw(); /* msleep(EAT_PAUSE); */ mvaddch(pm_pos.y, pm_pos.x, 'O'); draw(); /* msleep(EAT_PAUSE); */ mvaddch(pm_pos.y, pm_pos.x, '='); draw(); /* msleep(EAT_PAUSE); */ } sleep(2); mvaddch(pm_pos.y, pm_pos.x, EMPTY); draw(); } /* ** is_mons() - return TRUE if ch is a monster */ int is_mons (whoru) reg char whoru; { switch (whoru) { case HARPO: case _HARPO: case GROUCHO: case _GROUCHO: case CHICO: case _CHICO: case ZEPPO: case _ZEPPO: return(TRUE); } return(FALSE); } /* ** place_m() - put a monster back in its box ** - an infinite loop can occur if the box is full! ** - the box should never be full!!! */ void place_m (m) reg mons *m; { reg int xx; m->mo_pos.y = 11; while (TRUE) { move(m->mo_pos.y, (xx = rnd(19, 33))); if (INCH() == EMPTY) break; } m->mo_pos.x = xx; move(m->mo_pos.y, m->mo_pos.x); addch(m->mo_name); }