Mercurial > hg > early-roguelike
view srogue/chase.c @ 110:5f51f7d9805f
arogue5: fix some save/restore-related crashes.
The save/restore code took the pointer intended as an argument for the
doctor() daemon and wrote it to the savefile as an int. I don't know
why it took so long to fail horribly. The problem has been avoided by
replacing the value with &player when restoring. That seems to be the
only argument ever actually used.
The code also writes only four bytes for an unsigned long; if
sizeof(long) == 8, it casts to unsigned int first. It failed to do the
cast when reading back, with the result that four bytes were read and
the other half of the number was effectively uninitialized.
It apparently works now, but the save/restore code ought still to be
regarded as decidedly unfortunate.
author | John "Elwin" Edwards |
---|---|
date | Mon, 06 Jan 2014 15:57:17 -0500 |
parents | 2128c7dc8a40 |
children | 94a0d9dd5ce1 |
line wrap: on
line source
/* * Code for one object to chase another * * @(#)chase.c 9.0 (rdk) 7/17/84 * * Super-Rogue * Copyright (C) 1984 Robert D. Kindelberger * All rights reserved. * * Based on "Rogue: Exploring the Dungeons of Doom" * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman * All rights reserved. * * See the file LICENSE.TXT for full copyright and licensing information. */ #include "rogue.h" #include "rogue.ext" #define FARAWAY 32767 #define RDIST(a, b) (DISTANCE((a)->y, (a)->x, (b).y, (b).x)) struct coord ch_ret; /* Where chasing takes you */ /* * runners: * Make all the running monsters move. */ runners() { reg struct thing *tp; reg struct linked_list *mon,*nextmon; for (mon = mlist; mon != NULL; mon = nextmon) { tp = THINGPTR(mon); nextmon = next(mon); if (off(*tp, ISHELD) && on(*tp, ISRUN)) { if (tp->t_nomove > 0) if (--tp->t_nomove > 0) continue; if (on(*tp, ISHASTE)) if (do_chase(mon) == -1) continue; if (off(*tp, ISSLOW) || tp->t_turn) if (do_chase(mon) == -1) continue; tp->t_turn ^= TRUE; } } } /* * do_chase: * Make one thing chase another. */ do_chase(mon) struct linked_list *mon; { reg struct thing *th; reg struct room *rer, *ree, *rxx; reg int mindist, i, dist; struct stats *st; bool stoprun = FALSE, ondoor = FALSE, link = FALSE; char runaway, dofight, wound, sch, ch; struct coord this; struct trap *trp; th = THINGPTR(mon); wound = th->t_flags & ISWOUND; if (wound) mindist = 0; else mindist = FARAWAY; runaway = wound; dofight = !runaway; rer = th->t_room; if (th->t_type == 'V') { if (rer != NULL && !rf_on(rer, ISDARK)) { /* * Vampires can't stand the light */ if (cansee(th->t_pos.y, th->t_pos.x)) msg("The vampire vaporizes into thin air !"); killed(mon, FALSE); return(-1); } } ree = roomin(th->t_dest); /* room of chasee */ this = *th->t_dest; /* * If the object of our desire is in a different * room, then run to the door nearest to our goal. */ if (mvinch(th->t_pos.y, th->t_pos.x) == DOOR) ondoor = TRUE; rxx = NULL; if (rer != NULL || ree != NULL) { /* * Monster not in room, hero in room. Run to closest door * in hero's room if not wounded. Run away if wounded. */ if (rer == NULL && ree != NULL) { if (!wound) rxx = ree; } /* * Monster in a room, hero not in room. If on a door, * then use closest distance. If not on a door, then * run to closest door in monsters room. */ else if (rer != NULL && ree == NULL) { if (!ondoor) { rxx = rer; if (wound) runaway = FALSE; } } /* * Both hero and monster in a DIFFERENT room. Set flag to * check for links between the monster's and hero's rooms. * If no links are found, then the closest door in the * monster's room is used. */ else if (rer != ree) { if (!wound) { link = TRUE; if (ondoor) rxx = ree; /* if on door, run to heros room */ else rxx = rer; /* else to nearest door this room */ } } /* * Both hero and monster in same room. If monster is * wounded, find the best door to run to. */ else if (wound) { struct coord *ex; int poss, mdtd, hdtd, ghdtd, nx, gx = 0, best; best = ghdtd = -FARAWAY; for (nx = 0; nx < ree->r_nexits; nx++) { ex = &ree->r_exit[nx]; if (mvinch(ex->y, ex->x) == SECRETDOOR) continue; gx += 1; mdtd = abs(th->t_pos.y - ex->y) + abs(th->t_pos.x - ex->x); hdtd = abs(hero.y - ex->y) + abs(hero.x - ex->x); poss = hdtd - mdtd; /* possible move */ if (poss > best) { best = poss; this = *ex; } else if (poss == best && hdtd > ghdtd) { ghdtd = hdtd; best = poss; this = *ex; } } runaway = FALSE; /* go for target */ if (best < 1) dofight = TRUE; /* fight if we must */ mdtd = (gx <= 1 && best < 1); if (ondoor || mdtd) { this = hero; runaway = TRUE; if (!mdtd) dofight = FALSE; } } if (rxx != NULL) { for (i = 0; i < rxx->r_nexits; i += 1) { dist = RDIST(th->t_dest, rxx->r_exit[i]); if (link && rxx->r_ptr[i] == ree) dist = -1; if ((!wound && dist < mindist) || (wound && dist > mindist)) { this = rxx->r_exit[i]; mindist = dist; } } } } else if (DISTANCE(hero.y, hero.x, th->t_pos.y, th->t_pos.x) <= 3) dofight = TRUE; /* * this now contains what we want to run to this time * so we run to it. If we hit it we either want to * fight it or stop running. */ if (chase(th, &this, runaway, dofight) == FIGHT) { return( attack(th) ); } else if ((th->t_flags & (ISSTUCK | ISPARA))) return(0); /* if paralyzed or stuck */ if ((trp = trap_at(ch_ret.y, ch_ret.x)) != NULL) { ch = be_trapped(&ch_ret, th); if (ch == GONER || nlmove) { if (ch == GONER) remove_monster(&th->t_pos, mon); nlmove = FALSE; return((ch == GONER) ? -1 : 0); } } if (pl_off(ISBLIND)) mvwaddch(cw,th->t_pos.y,th->t_pos.x,th->t_oldch); sch = mvwinch(cw, ch_ret.y, ch_ret.x); if (rer != NULL && rf_on(rer,ISDARK) && sch == FLOOR && DISTANCE(ch_ret.y,ch_ret.x,th->t_pos.y,th->t_pos.x) < 3 && pl_off(ISBLIND)) th->t_oldch = ' '; else th->t_oldch = sch; if (cansee(unc(ch_ret)) && off(*th, ISINVIS)) mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type); mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type); th->t_oldpos = th->t_pos; th->t_pos = ch_ret; th->t_room = roomin(&ch_ret); i = 5; if (th->t_flags & ISREGEN) i = 40; st = &th->t_stats; if (rnd(100) < i) { if (++st->s_hpt > st->s_maxhp) st->s_hpt = st->s_maxhp; if (!monhurt(th)) th->t_flags &= ~ISWOUND; } if (stoprun && ce(th->t_pos, *(th->t_dest))) th->t_flags &= ~ISRUN; return CHASE; } /* * chase: * Find the spot for the chaser to move closer to the * chasee. Returns TRUE if we want to keep on chasing * later FALSE if we reach the goal. */ chase(tp, ee, runaway, dofight) struct thing *tp; struct coord *ee; bool runaway, dofight; { reg int x, y, ch; reg int dist, thisdist, closest; reg struct coord *er = &tp->t_pos; struct coord try, closecoord; int numsteps, onscare; /* * If the thing is confused, let it move randomly. */ ch = CHASE; onscare = FALSE; if (on(*tp, ISHUH)) { ch_ret = *rndmove(tp); dist = DISTANCE(hero.y, hero.x, ch_ret.y, ch_ret.x); if (rnd(1000) < 5) tp->t_flags &= ~ISHUH; if (dist == 0) ch = FIGHT; } else { /* * Otherwise, find the the best spot to run to * in order to get to your goal. */ numsteps = 0; if (runaway) closest = 0; else closest = FARAWAY; ch_ret = *er; closecoord = tp->t_oldpos; for (y = er->y - 1; y <= er->y + 1; y += 1) { for (x = er->x - 1; x <= er->x + 1; x += 1) { if (!cordok(y, x)) continue; try.x = x; try.y = y; if (!diag_ok(er, &try)) continue; ch = winat(y, x); if (step_ok(ch)) { struct trap *trp; if (isatrap(ch)) { trp = trap_at(y, x); if (trp != NULL && off(*tp, ISHUH)) { /* * Dont run over found traps unless * the hero is standing on it. If confused, * then he can run into them. */ if (trp->tr_flags & ISFOUND) { if (trp->tr_type == POOL && rnd(100) < 80) continue; else if (y != hero.y || x != hero.x) continue; } } } /* * Check for scare monster scrolls. */ if (ch == SCROLL) { struct linked_list *item; item = find_obj(y, x); if (item != NULL) if ((OBJPTR(item))->o_which == S_SCARE) { if (ce(hero, try)) onscare = TRUE; continue; } } /* * Vampires will not run into a lit room. */ if (tp->t_type == 'V') { struct room *lr; lr = roomin(&try); if (lr != NULL && !rf_on(lr, ISDARK)) continue; } /* * This is a valid place to step */ if (y == hero.y && x == hero.x) { if (dofight) { ch_ret = try; /* if fighting */ return FIGHT; /* hit hero */ } else continue; } thisdist = DISTANCE(y, x, ee->y, ee->x); if (thisdist <= 0) { ch_ret = try; /* got here but */ return CHASE; /* dont fight */ } numsteps += 1; if ((!runaway && thisdist < closest) || (runaway && thisdist > closest)) { /* * dont count the monsters last position as * the closest spot, unless running away and * in the same room. */ if (!ce(try, tp->t_oldpos) || (runaway && player.t_room == tp->t_room && tp->t_room != NULL)) { closest = thisdist; closecoord = try; } } } } } /* * If dead end, then go back from whence you came. * Otherwise, pick the closest of the remaining spots. */ if (numsteps > 0) /* move to best spot */ ch_ret = closecoord; else { /* nowhere to go */ if (DISTANCE(tp->t_pos.y, tp->t_pos.x, hero.y, hero.x) < 2) if (!onscare) ch_ret = hero; } if (ce(hero, ch_ret)) ch = FIGHT; } return ch; } /* * runto: * Set a monster running after something */ runto(runner, spot) struct coord *runner; struct coord *spot; { reg struct linked_list *item; reg struct thing *tp; if ((item = find_mons(runner->y, runner->x)) == NULL) return; tp = THINGPTR(item); if (tp->t_flags & ISPARA) return; tp->t_dest = spot; tp->t_flags |= ISRUN; tp->t_flags &= ~ISHELD; } /* * roomin: * Find what room some coordinates are in. * NULL means they aren't in any room. */ struct room * roomin(cp) struct coord *cp; { reg struct room *rp; if (cordok(cp->y, cp->x)) { for (rp = rooms; rp < &rooms[MAXROOMS]; rp += 1) if (inroom(rp, cp)) return rp; } return NULL; } /* * find_mons: * Find the monster from his coordinates */ struct linked_list * find_mons(y, x) int y, x; { reg struct linked_list *item; reg struct thing *th; for (item = mlist; item != NULL; item = next(item)) { th = THINGPTR(item); if (th->t_pos.y == y && th->t_pos.x == x) return item; } return NULL; } /* * diag_ok: * Check to see if the move is legal if it is diagonal */ diag_ok(sp, ep) struct coord *sp, *ep; { if (ep->x == sp->x || ep->y == sp->y) return TRUE; if (step_ok(mvinch(ep->y,sp->x)) && step_ok(mvinch(sp->y,ep->x))) return TRUE; return FALSE; } /* * cansee: * returns true if the hero can see a certain coordinate. */ cansee(y, x) int y, x; { reg struct room *rer; struct coord tp; if (pl_on(ISBLIND)) return FALSE; /* * We can only see if the hero in the same room as * the coordinate and the room is lit or if it is close. */ if (DISTANCE(y, x, hero.y, hero.x) < 3) return TRUE; tp.y = y; tp.x = x; rer = roomin(&tp); if (rer != NULL && levtype != MAZELEV) if (rer == player.t_room && !rf_on(rer,ISDARK)) return TRUE; return FALSE; }